uri.zc

来自「实现树形结构」· ZC 代码 · 共 690 行

ZC
690
字号
//[of]:imports
//[c]
import "base/types"
import "base/memory"
import "base/memory-allocator"
import "text/string"
import "text/string-buffer"
//[cf]
//[of]:structures
//[c]
public struct uri argument
	
	public next : uri argument
	private arg name : string
	private arg value : string

end
//[c]
public struct uri

	scheme : string
	net loc : string
	path : string
	query : string
	params : string
	fragment : string

end
//[cf]
//[c]
//[of]:uri
//[of]:initialize - release
//[of]:initialize (uri)
//[c]
public func initialize (m: uri)

	scheme (m) = empty string
	net loc (m) = empty string
	path (m) = empty string
	query (m) = empty string
	params (m) = empty string
	fragment (m) = empty string

end
//[cf]
//[of]:initialize (uri, string)
//[c]
public func initialize (m: uri, s: string)

	initialize (m)
	set (m, s)

end
//[cf]
//[of]:release (uri)
//[c]
public func release (m: uri)

	delete (scheme (m))
	delete (net loc (m))
	delete (path (m))
	delete (query (m))
	delete (params (m))
	delete (fragment (m))

end
//[cf]
//[cf]
//[of]:output
//[of]:append (string buffer, uri)
//[c]
public func append (s: string buffer, m: uri)

	s << scheme (m) << "://" << net loc (m) << path (m)
	if has params (m)
		s << $; << params (m)
	end
	if has query (m)
		s << $? << query (m)
	end
	if has fragment (m)
		s << $# << fragment (m)
	end
	return s

end
//[cf]
//[of]:@shl (string buffer, uri)
//[c]
public equ @shl (s: string buffer, m: uri) = 
	append (s, m)
//[cf]
//[cf]
//[of]:accessing
//[c]accessing
//[c]
//[of]:set scheme (uri, string)
//[c]
public func set scheme (m: uri, s: string)

	if s : mem <> scheme (m)
		delete (scheme (m))
		scheme (m) = new string (s)
	end

end
//[cf]
//[of]:set path (uri, string)
//[c]
public func set path (m: uri, s: string)

	if s : mem <> path (m)
		delete (path (m))
		path (m) = new string (s)
	end

end
//[cf]
//[of]:set net loc (uri, string)
//[c]
public func set net loc (m: uri, s: string)

	if s : mem <> net loc (m)
		delete (net loc (m))
		net loc (m) = new string (s)
	end

end
//[cf]
//[of]:set query (uri, string)
//[c]
public func set query (m: uri, s: string)

	if s : mem <> query (m)
		delete (query (m))
		query (m) = new string (s)
	end

end
//[cf]
//[of]:set params (uri, string)
//[c]
public func set params (m: uri, s: string)

	if s : mem <> params (m)
		delete (params (m))
		params (m) = new string (s)
	end

end
//[cf]
//[of]:set fragment (uri, string)
//[c]
public func set fragment (m: uri, s: string)

	if s : mem <> fragment (m)
		delete (fragment (m))
		fragment (m) = new string (s)
	end

end
//[cf]
//[c]
//[of]:resolve (uri, base)
//[c]Resolves a relative URL
//[c]
public func resolve (m: uri, base: uri)

	// if the embedded URL is entierly empty, it intherits the entire
	// base URL and we are done.
	if is empty (m)

		set scheme (m, scheme (base))
		set net loc (m, net loc (base))
		set path (m, path (base))
		set params (m, params (base))
		set query (m, query (base))
		set fragment (m, fragment (base))
		return
	
	end

	// if the embedded URL has a scheme, it is an absolute URL
	// and we are done.
	if has scheme (m)
		return
	end

	// otherwise, the embedded URL inherits the scheme of the base URL.
	set scheme (m, scheme (base))

	//
	if has net loc (m)
		return // go step 7
	end

	// otherwise, the embedded URL inherits the <net_loc> (if any)
	// of the base URL.
	set net loc (m, net loc (base))

	if path (m) [0] == $/
		return // go step 7
	end

	// If the embedded URL path is empty (and not preceded by a
	// slash), then the embedded URL inherits the base URL path,
	// and
	//
	// a) if the embedded URL's <params> is non-empty, we skip to
	//    step 7; otherwise, it inherits the <params> of the base
	//    URL (if any) and
	//
	// b) if the embedded URL's <query> is non-empty, we skip to
	//    step 7; otherwise, it inherits the <query> of the base
	//    URL (if any) and we skip to step 7.
	if is empty (path (m))

		set path (m, path (base))
		
		if is empty (params (m))

			set params (m, params (base))
			if is empty (query (m))
				set query (m, query (base))
			end

		end
		
		return //go step 7

	end

	// The last segment of the base URL's path (anything
	// following the rightmost slash "/", or the entire path if no
	// slash is present) is removed and the embedded URL's path is
	// appended in its place.
	def slash = last occurrence (path (base), $/)
	if not nil (slash)
		def t := temp string buffer
		append (t, path (base), slash - path (base) + 1)
		append (t, path (m))
		set path (m, as string (t))
		release (t)
	end

	// The following operations are then applied, in order, to the new path:
	//
	// a) All occurrences of "./", where "." is a complete path
	//    segment, are removed.
	//
	// b) If the path ends with "." as a complete path segment,
	//    that "." is removed.
	//
	// c) All occurrences of "<segment>/../", where <segment> is a
	//    complete path segment not equal to "..", are removed.
	//    Removal of these path segments is performed iteratively,
	//    removing the leftmost matching pattern on each iteration,
	//    until no matching pattern remains.
	//
	// d) If the path ends with "<segment>/..", where <segment> is a
	//    complete path segment not equal to "..", that
	//    "<segment>/.." is removed.
	def sb := temp string buffer
	sb << path (m)

	def i = 0
	while i:dword < size (sb) - 1
		if sb[i] == $. && sb[i+1]==$/ && (i==0 || sb[i-1]==$/)
			remove (sb, i, 2)
		else
			++i
		end
	end

	def s = size (sb) : int
	if ends with(as string (sb), ".") && (s==1 || sb[s - 2]==$/)
		remove (sb, s - 1, 1)
	end

	i = 0
	while i:dword < size (sb)

		if sb[i] ==$/ &&
			sb[i+1]==$. &&
			sb[i+2]==$. &&
			sb[i+3]==$/ && 
			i > 0
	
			def j = i - 1
			while j >= 0 && sb[j] <> $/
				--j
			end
			remove (sb, j+1, i-j+3)
			i  = j
	
		else
			++i
		end
	end
	
	if ends with(as string (sb), "/..")

		i = size (sb) : int - 3
		def j = i - 1
		while j>=0 && sb[j] <> $/
			--j
		end
		remove (sb, j+1, i-j+2)

	end
	
	set path (m, as string (sb))
	release (sb)

end
//[cf]
//[of]:set (uri, string)
//[c]Sets the new location
//[c]
public func set (m: uri, s: string)

	// copy the string
	def size = size (s)
	def buf = allocate memory (size + 1) : string
	copy (buf : mem, s, size+1)
	
	def start = buf
//[c]
//[of]:	Retrieve the fragment
//[c]
	def p = start
	while p[] <> nul char && p[] <> $#
		++p
	end

	if p[] == $#

		// copy the fragment
		set fragment (m, p+1)

		// remove the fragment
		p[] = nul char

	else
		set fragment (m, empty string)
	end
//[cf]
//[of]:	Retrieve the scheme
//[c]
	set scheme (m, empty string)
	p = start
	if p[] <> nul char

		++p
		while p[] <> nul char && p[] <> $:
			++p
		end

		// found a colon
		if p[] == $:

			// check the scheme is valid
			def q = start
			def ok = true
			while q : []byte < p : []byte

				if ~ is scheme char (q[])

					ok = false
					break
				end
				++q
			end

			// the scheme is valid
			if ok

				// copy the scheme
				delete (scheme (m))
				scheme (m) = new string (start, p)
				to lower (scheme (m))

				// set the parsing point
				start = p+1

			end

		end

	end
//[cf]
//[of]:	Retrieve the net-location
//[c]
	if start[] == $/ && (start+1) [] == $/

		p = start+2
		while p[] <> nul char && p[] <> $/
			++p
		end
	
		// copy the net-loc
		delete (net loc (m))
		net loc (m) = new string (start+2, p)

		// continue parsing at the '/' or the end of the string
		start = p
	else
		set net loc (m,  empty string)
	end
//[cf]
//[of]:	Extract the query
//[c]
	p = start
	while p[] <> nul char && p[] <> $?
		++p
	end
	
	if p[] == $?

		// copy the query
		set query (m, p+1)
	
		// remove the query
		p[] = nul char

	else
		set query (m, empty string)
	end
//[cf]
//[of]:	Extract the parameters
//[c]
	p = start
	while p[] <> nul char && p [] <> $;
		++p
	end

	if p[] == $;

		// copy the query
		set params (m, p+1)
	
		// remove the query
		p[] = nul char

	else
		set params (m, empty string)
	end
//[cf]
//[of]:	Retrieve the path
//[c]
	set path (m, start)
//[cf]
//[c]
	free memory (buf)

end
//[cf]
//[of]:read all arguments (uri)
//[c]Reads all attributes
//[c]
//[c]	The returned argument must be deleted when it is no longer
//[c]	used.
//[c]
public func read all arguments (m: uri)

	def p : [1] string
	p [] = query (m)
	
	def first = nil : uri argument
	def last = nil : uri argument
	def a = nil : uri argument
	repeat
		a = read argument (p)
		if not nil (a)
			if not nil (last)
				next (last) = a
			else
				first = a
			end
			last = a
		else
			break
		end
	end
	return first

end
//[c]
//[c]Sub-functions:
//[of]:	read argument ([] string)
//[c]Reads one attribute
//[c]
func read argument(q: [] string)

	def key buffer := temp string buffer
	def value buffer := temp string buffer
	
	def p = q []
	def c = p++ []
	
	// read the name
	while c <> nul char && c <> $=
		key buffer << c
		c = p++ []
	end
	
	// read value
	if c == $=

		// skip the equal sign
		c = p++ []
	
		while c <> nul char && c <> $&
			value buffer << c
			c = p++ []
		end

	end
	
	if c == nul char
		-- p
	end
	q [] = p

	def a = nil : uri argument	
	if not empty (key buffer)
		a = new uri argument (as string (key buffer), as string (value buffer))
	end
	
	release (key buffer)
	release (value buffer)
	return a

end
//[cf]
//[cf]
//[cf]
//[of]:testing
//[c]testing
//[c]
//[of]:has scheme (uri)
//[c]
public func has scheme (m: uri)

	return not empty (scheme (m))

end
//[cf]
//[of]:has net loc (uri)
//[c]
public func has net loc (m: uri)

	return not empty (net loc (m))

end
//[cf]
//[of]:has path (uri)
//[c]
public func has path (m: uri)

	return not empty (path (m))

end
//[cf]
//[of]:has params (uri)
//[c]
public func has params (m: uri)

	return not empty (params (m))

end
//[cf]
//[of]:has scheme (uri)
//[c]
public func has query (m: uri)

	return not empty (query (m))

end
//[cf]
//[of]:has scheme (uri)
//[c]
public func has fragment  (m: uri)

	return not empty (fragment (m))

end
//[cf]
//[c]
//[of]:is empty (uri)
//[c]
public func is empty (m: uri)

	return ~(
		has scheme (m) ||
		has net loc (m) ||
		has path (m) ||
		has params (m) ||
		has query (m) ||
		has fragment (m))

end
//[cf]
//[cf]
//[of]:debugging
//[of]:inspect (uri)
//[c]
public func inspect (m: uri, s: string buffer)

	s << "scheme...: " << scheme (m) << "\n"
	s << "net_loc..: " << net loc (m) << "\n"
	s << "path.....: " << path (m) << "\n"
	s << "query....: " << query (m) << "\n"
	s << "params...: " << params (m) << "\n"
	s << "fragment.: " << fragment (m) << "\n"

	s << m

end
//[cf]
//[cf]
//[c]
//[of]:private
//[of]:is scheme char (char)
//[c]Tests for parsing
//[c]
private func is scheme char (c: char)

	return (c>=$A && c<=$Z) ||
		(c>=$a && c<=$z) ||
		(c>=$0 && c<=$9) ||
		c==$+ ||
		c==$- ||
		c==$.

end
//[cf]
//[cf]
//[cf]
//[of]:uri argument
//[of]:accessing
//[of]:name (argument)
//[c]
public equ name (m: uri argument) =

	arg name (m)

//[cf]
//[of]:value (argument)
//[c]
public equ value (m: uri argument) =

	arg value (m)

//[cf]
//[cf]
//[c]
//[of]:private
//[of]:new uri argument (name, value)
//[c]Creates a new argument
//[c]
private func new uri argument (n: string, v: string)

	def m = allocate memory (sizeof local uri argument) : uri argument
	next (m) = nil
	arg name (m) = new string (n)
	arg value (m) = new string (v)
	return m

end
//[cf]
//[of]:delete (argument)
//[c]
public func delete (m: uri argument) : void

	delete (arg name (m))
	delete (arg value (m))
	
	def next = next (m)
	if not nil (next)
		delete (next)
	end

	free memory (m)

end
//[cf]
//[cf]
//[cf]

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?