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 + -
显示快捷键?