📄 uri.tcl
字号:
upvar \#0 [namespace current]::basic::user user upvar \#0 [namespace current]::basic::password password upvar \#0 [namespace current]::basic::hostname hostname upvar \#0 [namespace current]::basic::hostnumber hostnumber upvar \#0 [namespace current]::basic::port port upvar $urlvar url array set parts {user {} pwd {} host {} port {}} # syntax # "//" [ <user> [":" <password> ] "@"] <host> [":" <port>] "/" # "//" already cut off by caller set upPattern "^(${user})(:(${password}))?@" if {[regexp -indices -- $upPattern $url match theUser c d thePassword]} { set fu [lindex $theUser 0] set tu [lindex $theUser 1] set fp [lindex $thePassword 0] set tp [lindex $thePassword 1] set parts(user) [string range $url $fu $tu] set parts(pwd) [string range $url $fp $tp] set matchEnd [lindex $match 1] incr matchEnd set url [string range $url $matchEnd end] } set hpPattern "^($hostname|$hostnumber)(:($port))?" if {[regexp -indices -- $hpPattern $url match theHost c d e f g h thePort]} { set fh [lindex $theHost 0] set th [lindex $theHost 1] set fp [lindex $thePort 0] set tp [lindex $thePort 1] set parts(host) [string range $url $fh $th] set parts(port) [string range $url $fp $tp] set matchEnd [lindex $match 1] incr matchEnd set url [string range $url $matchEnd end] } return [array get parts]}proc ::uri::GetHostPort {urlvar} { # @c Parse host and port out of the url stored in variable <a urlvar>. # @d Side effect: The extracted information is removed from the given url. # @r List containing the extracted information in a format suitable for # @r 'array set'. # @a urlvar: Name of the variable containing the url to parse. upvar #0 [namespace current]::basic::hostname hostname upvar #0 [namespace current]::basic::hostnumber hostnumber upvar #0 [namespace current]::basic::port port upvar $urlvar url set pattern "^(${hostname}|${hostnumber})(:(${port}))?" if {[regexp -indices -- $pattern $url match host c d e f g h thePort]} { set fromHost [lindex $host 0] set toHost [lindex $host 1] set fromPort [lindex $thePort 0] set toPort [lindex $thePort 1] set parts(host) [string range $url $fromHost $toHost] set parts(port) [string range $url $fromPort $toPort] set matchEnd [lindex $match 1] incr matchEnd set url [string range $url $matchEnd end] } return [array get parts]}# ::uri::resolve --## Resolve an arbitrary URL, given a base URL## Arguments:# base base URL (absolute)# url arbitrary URL## Results:# Returns a URLproc ::uri::resolve {base url} { if {[string length $url]} { if {[isrelative $url]} { array set baseparts [split $base] switch -- $baseparts(scheme) { http - https - ftp - file { array set relparts [split $url] if { [string match /* $url] } { catch { set baseparts(path) $relparts(path) } } elseif { [string match */ $baseparts(path)] } { set baseparts(path) "$baseparts(path)$relparts(path)" } else { if { [string length $relparts(path)] > 0 } { set path [lreplace [::split $baseparts(path) /] end end] set baseparts(path) "[::join $path /]/$relparts(path)" } } catch { set baseparts(query) $relparts(query) } catch { set baseparts(fragment) $relparts(fragment) } return [eval [linsert [array get baseparts] 0 join]] } default { return -code error "unable to resolve relative URL \"$url\"" } } } else { return $url } } else { return $base }}# ::uri::isrelative --## Determines whether a URL is absolute or relative## Arguments:# url URL to check## Results:# Returns 1 if the URL is relative, 0 otherwiseproc ::uri::isrelative url { return [expr {![regexp -- {^[a-z0-9+-.][a-z0-9+-.]*:} $url]}]}# ::uri::geturl --## Fetch the data from an arbitrary URL.## This package provides a handler for the file:# scheme, since this conflicts with the file command.## Arguments:# url address of data resource# args configuration options## Results:# Depends on schemeproc ::uri::geturl {url args} { array set urlparts [split $url] switch -- $urlparts(scheme) { file { return [eval [linsert $args 0 file_geturl $url]] } default { # Load a geturl package for the scheme first and only if # that fails the scheme package itself. This prevents # cyclic dependencies between packages. if {[catch {package require $urlparts(scheme)::geturl}]} { package require $urlparts(scheme) } return [eval [linsert $args 0 $urlparts(scheme)::geturl $url]] } }}# ::uri::file_geturl --## geturl implementation for file: scheme## TODO:# This is an initial, basic implementation.# Eventually want to support all options for geturl.## Arguments:# url URL to fetch# args configuration options## Results:# Returns data from fileproc ::uri::file_geturl {url args} { variable file:counter set var [namespace current]::file[incr file:counter] upvar #0 $var state array set state {data {}} array set parts [split $url] set ch [open $parts(path)] # Could determine text/binary from file extension, # except on Macintosh # fconfigure $ch -translation binary set state(data) [read $ch] close $ch return $var}# ::uri::join --## Format a URL## Arguments:# args components, key-value format## Results:# A URLproc ::uri::join args { array set components $args return [eval [linsert $args 0 Join[string totitle $components(scheme)]]]}# ::uri::canonicalize --## Canonicalize a URL## Acknowledgements:# Andreas Kupries <andreas_kupries@users.sourceforge.net>## Arguments:# uri URI (which contains a path component)## Results:# The canonical form of the URIproc ::uri::canonicalize uri { # Make uri canonical with respect to dots (path changing commands) # # Remove single dots (.) => pwd not changing # Remove double dots (..) => gobble previous segment of path # # Fixes for this command: # # * Ignore any url which cannot be split into components by this # module. Just assume that such urls do not have a path to # canonicalize. # # * Ignore any url which could be split into components, but does # not have a path component. # # In the text above 'ignore' means # 'return the url unchanged to the caller'. if {[catch {array set u [uri::split $uri]}]} { return $uri } if {![info exists u(path)]} { return $uri } set uri $u(path) # Remove leading "./" "../" "/.." (and "/../") regsub -all -- {^(\./)+} $uri {} uri regsub -all -- {^/(\.\./)+} $uri {/} uri regsub -all -- {^(\.\./)+} $uri {} uri # Remove inner /./ and /../ while {[regsub -all -- {/\./} $uri {/} uri]} {} while {[regsub -all -- {/[^/]+/\.\./} $uri {/} uri]} {} while {[regsub -all -- {^[^/]+/\.\./} $uri {} uri]} {} # Munge trailing /.. while {[regsub -all -- {/[^/]+/\.\.} $uri {/} uri]} {} if { $uri == ".." } { set uri "/" } set u(path) $uri set uri [eval [linsert [array get u] 0 uri::join]] return $uri}# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# regular expressions covering various url schemes# Currently known URL schemes:## (RFC 1738)# ------------------------------------------------# scheme basic syntax of scheme specific part# ------------------------------------------------# ftp //<user>:<password>@<host>:<port>/<cwd1>/.../<cwdN>/<name>;type=<typecode>## http //<host>:<port>/<path>?<searchpart>## gopher //<host>:<port>/<gophertype><selector># <gophertype><selector>%09<search># <gophertype><selector>%09<search>%09<gopher+_string>## mailto <rfc822-addr-spec># news <newsgroup-name># <message-id># nntp //<host>:<port>/<newsgroup-name>/<article-number># telnet //<user>:<password>@<host>:<port>/# wais //<host>:<port>/<database># //<host>:<port>/<database>?<search># //<host>:<port>/<database>/<wtype>/<wpath># file //<host>/<path># prospero //<host>:<port>/<hsoname>;<field>=<value># ------------------------------------------------## (RFC 2111)# ------------------------------------------------# scheme basic syntax of scheme specific part# ------------------------------------------------# mid message-id# message-id/content-id# cid content-id# ------------------------------------------------# FTPuri::register ftp { variable escape [set [namespace parent [namespace current]]::basic::escape] variable login [set [namespace parent [namespace current]]::basic::login] variable charN {[a-zA-Z0-9$_.+!*'(,)?:@&=-]} variable char "(${charN}|${escape})" variable segment "${char}*" variable path "${segment}(/${segment})*" variable type {[AaDdIi]} variable typepart ";type=(${type})" variable schemepart \ "//${login}(/${path}(${typepart})?)?" variable url "ftp:${schemepart}"}# FILEuri::register file { variable host [set [namespace parent [namespace current]]::basic::host] variable path [set [namespace parent [namespace current]]::ftp::path] variable schemepart "//(${host}|localhost)?/${path}" variable url "file:${schemepart}"}# HTTPuri::register http { variable escape \ [set [namespace parent [namespace current]]::basic::escape] variable hostOrPort \ [set [namespace parent [namespace current]]::basic::hostOrPort] variable charN {[a-zA-Z0-9$_.+!*'(,);:@&=-]} variable char "($charN|${escape})" variable segment "${char}*" variable path "${segment}(/${segment})*" variable search $segment variable schemepart \ "//${hostOrPort}(/${path}(\\?${search})?)?" variable url "http:${schemepart}"}# GOPHERuri::register gopher { variable xChar \ [set [namespace parent [namespace current]]::basic::xChar] variable hostOrPort \ [set [namespace parent [namespace current]]::basic::hostOrPort] variable search \ [set [namespace parent [namespace current]]::http::search] variable type $xChar variable selector "$xChar*" variable string $selector variable schemepart \ "//${hostOrPort}(/(${type}(${selector}(%09${search}(%09${string})?)?)?)?)?" variable url "gopher:${schemepart}"}# MAILTOuri::register mailto { variable xChar [set [namespace parent [namespace current]]::basic::xChar] variable host [set [namespace parent [namespace current]]::basic::host] variable schemepart "$xChar+(@${host})?" variable url "mailto:${schemepart}"}# NEWSuri::register news { variable escape [set [namespace parent [namespace current]]::basic::escape] variable alpha [set [namespace parent [namespace current]]::basic::alpha] variable host [set [namespace parent [namespace current]]::basic::host] variable aCharN {[a-zA-Z0-9$_.+!*'(,);/?:&=-]} variable aChar "($aCharN|${escape})" variable gChar {[a-zA-Z0-9$_.+-]} variable newsgroup-name "${alpha}${gChar}*" variable message-id "${aChar}+@${host}" variable schemepart "\\*|${newsgroup-name}|${message-id}" variable url "news:${schemepart}"}# WAISuri::register wais { variable uChar \ [set [namespace parent [namespace current]]::basic::xChar] variable hostOrPort \ [set [namespace parent [namespace current]]::basic::hostOrPort] variable search \ [set [namespace parent [namespace current]]::http::search] variable db "${uChar}*" variable type "${uChar}*" variable path "${uChar}*" variable database "//${hostOrPort}/${db}" variable index "//${hostOrPort}/${db}\\?${search}" variable doc "//${hostOrPort}/${db}/${type}/${path}" #variable schemepart "${doc}|${index}|${database}" variable schemepart \ "//${hostOrPort}/${db}((\\?${search})|(/${type}/${path}))?" variable url "wais:${schemepart}"}# PROSPEROuri::register prospero { variable escape \ [set [namespace parent [namespace current]]::basic::escape] variable hostOrPort \ [set [namespace parent [namespace current]]::basic::hostOrPort] variable path \ [set [namespace parent [namespace current]]::ftp::path] variable charN {[a-zA-Z0-9$_.+!*'(,)?:@&-]} variable char "(${charN}|$escape)" variable fieldname "${char}*" variable fieldvalue "${char}*" variable fieldspec ";${fieldname}=${fieldvalue}" variable schemepart "//${hostOrPort}/${path}(${fieldspec})*" variable url "prospero:$schemepart"}package provide uri 1.1.5
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -