From cec062435723057d425708b4849d450a80b08378 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Tue, 3 Jul 2007 12:41:11 +0000 Subject: [PATCH] doc work, epseciall I/O and OS reference svn: r6808 --- collects/scribble/manual.ss | 11 +- collects/scribble/reader.ss | 7 +- .../scribblings/reference/custom-ports.scrbl | 39 +- .../scribblings/reference/custom-write.scrbl | 70 +++ .../scribblings/reference/filesystem.scrbl | 358 ++++++++++++ collects/scribblings/reference/io.scrbl | 1 + .../scribblings/reference/networking.scrbl | 553 ++++++++++++++++++ collects/scribblings/reference/os.scrbl | 4 +- collects/scribblings/reference/paths.scrbl | 482 +++++++++++++++ collects/scribblings/reference/reader.scrbl | 3 +- .../scribblings/reference/readtables.scrbl | 101 +++- .../scribblings/reference/unix-paths.scrbl | 60 ++ ...atform-paths.scrbl => windows-paths.scrbl} | 62 +- 13 files changed, 1665 insertions(+), 86 deletions(-) create mode 100644 collects/scribblings/reference/custom-write.scrbl create mode 100644 collects/scribblings/reference/filesystem.scrbl create mode 100644 collects/scribblings/reference/networking.scrbl create mode 100644 collects/scribblings/reference/paths.scrbl create mode 100644 collects/scribblings/reference/unix-paths.scrbl rename collects/scribblings/reference/{platform-paths.scrbl => windows-paths.scrbl} (83%) diff --git a/collects/scribble/manual.ss b/collects/scribble/manual.ss index fdfd02a9bc..fcc6d4eda7 100644 --- a/collects/scribble/manual.ss +++ b/collects/scribble/manual.ss @@ -14,6 +14,9 @@ (provide PLaneT) (define PLaneT "PLaneT") + (provide etc) + (define etc "etc.") ; so we can fix the latex space, one day + (define-code schemeblock0 to-paragraph) (define-code schemeblock (to-paragraph/prefix (hspace 2) (hspace 2) @@ -95,7 +98,7 @@ (provide onscreen menuitem defterm schemefont schemevalfont schemeresultfont schemeidfont schemeparenfont schemekeywordfont schememetafont schememodfont - file exec + file exec envvar Flag DFlag link procedure idefterm) @@ -128,6 +131,12 @@ (make-element 'tt (append (list "\"") (decode-content str) (list "\"")))) (define (exec . str) (make-element 'tt (decode-content str))) + (define (Flag . str) + (make-element 'tt (cons "-" (decode-content str)))) + (define (DFlag . str) + (make-element 'tt (cons "--" (decode-content str)))) + (define (envvar . str) + (make-element 'tt (decode-content str))) (define (procedure . str) (make-element "schemeresult" (append (list "#")))) diff --git a/collects/scribble/reader.ss b/collects/scribble/reader.ss index 1c76e41131..55f7cde364 100644 --- a/collects/scribble/reader.ss +++ b/collects/scribble/reader.ss @@ -396,10 +396,9 @@ r)))] [(*peek #rx#"^$") (if end-token - (read-error 'eof "missing closing `~a'~a" end-token - (if start-line - (format " (started at ~a:~a)" start-line start-col) - "")) + (read-error* start-line start-col start-pos + (and pos start-pos (- pos start-pos)) + 'eof "missing closing `~a'" end-token) (done-lines r))] [else (read-error "internal error [get-lines*]")]))))) diff --git a/collects/scribblings/reference/custom-ports.scrbl b/collects/scribblings/reference/custom-ports.scrbl index e19b1482ac..5f809c31f0 100644 --- a/collects/scribblings/reference/custom-ports.scrbl +++ b/collects/scribblings/reference/custom-ports.scrbl @@ -313,21 +313,34 @@ The arguments implement the port as follows: } - When @scheme[read-in] or @scheme[peek] (or an event produced by one of - these) returns a procedure, and the procedure is used to obtain a + When @scheme[read-in] or @scheme[peek] (or an event produced by one + of these) returns a procedure, and the procedure is used to obtain a non-byte result. (This non-byte result is @italic{not} intended to return a character or @scheme[eof]; in particular, @scheme[read-char] - raises an exception if it encounters a non-byte from a port.) The - procedure is called by @scheme[read], @scheme[read-syntax], - @scheme[read-honu], @scheme[read-honu-syntax], - @scheme[read-byte-or-special], @scheme[read-char-or-special], - @scheme[peek-byte-or-special], or @scheme[peek-char-or-special]---or, - more precisely, by the default port read handler (see - @secref["mz:portreadhandler"]). The special-value procedure can return - an arbitrary value, and it will be called zero or one times (not - necessarily before further reads or peeks from the port). See - @secref["mz:reader-procs"] for more details on the procedure's - arguments and result. + raises an exception if it encounters a special-result procedure, even + if the procedure produces a byte.) A special-result procedure must + accept four arguments, and it can optionally accept zero arguments: + + @itemize{ + + @item{When the special read is triggered by @scheme[read-syntax], + @scheme[read-honu-syntax], or @scheme[read-syntax/recursive], the + procedure is passed four arguments that represent a source + location.} + + @item{When the special read is triggered by @scheme[read], + @scheme[read-honu], @scheme[read-byte-or-special], + @scheme[read-char-or-special], @scheme[peek-byte-or-special], or + @scheme[peek-char-or-special], the procedure is passed no arguments + if it accepts zero arguments, otherwise it is passed four arguments + that are all @scheme[#f].} + + } + + The special-value procedure can return an arbitrary value, and it + will be called zero or one times (not necessarily before further + reads or peeks from the port). See @secref["mz:reader-procs"] for + more details on the procedure's result. If @scheme[read-in] or @scheme[peek] returns a special procedure when called by any reading procedure other than diff --git a/collects/scribblings/reference/custom-write.scrbl b/collects/scribblings/reference/custom-write.scrbl new file mode 100644 index 0000000000..df1f76a541 --- /dev/null +++ b/collects/scribblings/reference/custom-write.scrbl @@ -0,0 +1,70 @@ +#reader(lib "docreader.ss" "scribble") +@require["mz.ss"] + +@title{Printer Extension} + +@defthing[prop:custom-write struct-type-property?]{ + +Associates a procedure to a structure type to used by the default +printer to @scheme[display] or @scheme[write] (or @scheme[print]) +instances of the structure type. + +@moreref["mz:structprops"]{structure type properties} + +The procedure for a @scheme[prop:custom-write] value takes three +arguments: the structure to be printed, the target port, and a boolean +that is @scheme[#t] for @scheme[write] mode and @scheme[#f] for +@scheme[display] mode. The procedure should print the value to the +given port using @scheme[write], @scheme[display], @scheme[fprintf], +@scheme[write-special], etc. + +The write handler, display handler, and print handler are specially +configured for a port given to a custom-write procedure. Printing to +the port through @scheme[display], @scheme[write], or @scheme[print] +prints a value recursively with sharing annotations. To avoid a +recursive print (i.e., to print without regard to sharing with a value +currently being printed), print instead to a string or pipe and +transfer the result to the target port using @scheme[write-string] and +@scheme[write-special]. To recursively print but to a port other than +the one given to the custom-write procedure, copy the given port's +write handler, display handler, and print handler to the other port. + +The port given to a custom-write handler is not necessarily the actual +target port. In particular, to detect cycles and sharing, the printer +invokes a custom-write procedure with a port that records recursive +prints, and does not retain any other output. + +Recursive print operations may trigger an escape from the call to the +custom-write procedure (e.g., for pretty-printing where a tentative +print attempt overflows the line, or for printing error output of a +limited width). + +The following example definition of a @scheme[tuple] type includes +custom-write procedures that print the tuple's list content using +angle brackets in @scheme[write] mode and no brackets in +@scheme[display] mode. Elements of the tuple are printed recursively, +so that graph and cycle structure can be represented. + +@defexamples[ +(define (tuple-print tuple port write?) + (when write? (write-string "<" port)) + (let ([l (tuple-ref tuple 0)]) + (unless (null? l) + ((if write? write display) (car l) port) + (for-each (lambda (e) + (write-string ", " port) + ((if write? write display) e port)) + (cdr l)))) + (when write? (write-string ">" port))) + +(define-values (s:tuple make-tuple tuple? tuple-ref tuple-set!) + (make-struct-type 'tuple #f 1 0 #f + (list (cons prop:custom-write tuple-print)))) + +(display (make-tuple '(1 2 "a"))) + +(let ([t (make-tuple (list 1 2 "a"))]) + (set-car! (tuple-ref t 0) t) + (write t)) +] +} diff --git a/collects/scribblings/reference/filesystem.scrbl b/collects/scribblings/reference/filesystem.scrbl new file mode 100644 index 0000000000..a3fa81252c --- /dev/null +++ b/collects/scribblings/reference/filesystem.scrbl @@ -0,0 +1,358 @@ +#reader(lib "docreader.ss" "scribble") +@require["mz.ss"] + +@title{Filesystem} + +@;------------------------------------------------------------------------ +@section[#:tag "mz:findpaths"]{Locating Paths} + +@defproc[(find-system-path [kind symbol?]) path?]{ + +Returns a machine-specific path for a standard type of path specified +by @scheme[kind], which must be one of the following: + +@itemize{ + + @item{@scheme['home-dir] --- the current user's home directory. + + Under Unix and Mac OS X, this directory is determined by expanding + the path @file{~}, which is expanded by first checking for a + @envvar{HOME} environment variable. If none is defined, the + @envvar{USER} and @envvar{LOGNAME} environment variables are + consulted (in that order) to find a user name, and then system files + are consulted to locate the user's home directory. + + Under Windows, the user's home directory is the user-specific profile + directory as determined by the Windows registry. If the registry + cannot provide a directory for some reason, the value of the + @envvar{USERPROFILE} environment variable is used instead, as long as + it refers to a directory that exists. If @envvar{USERPROFILE} also + fails, the directory is the one specified by the @envvar{HOMEDRIVE} + and @envvar{HOMEPATH} environment variables. If those environment + variables are not defined, or if the indicated directory still does + not exist, the directory containing the current executable is used as + the home directory.} + + @item{@scheme['pref-dir] --- the standard directory for storing the + current user's preferences. Under Unix, the directory is + @file{.plt-scheme} in the user's home directory. Under Windows, it + is @file{PLT Scheme} in the user's application-data folder as + specified by the Windows registry; the application-data folder is + usually @file{Application Data} in the user's profile + directory. Under Mac OS X, it is @file{Library/Preferences} in the + user's home directory. This directory might not exist.} + + @item{@scheme['pref-file] --- a file that contains a symbol-keyed + association list of preference values. The file's directory path + always matches the result returned for @scheme['pref-dir]. The file + name is @file{plt-prefs.ss} under Unix and Windows, and it is + @file{org.plt-scheme.prefs.ss} under Mac OS X. The file's directory + might not exist. See also @scheme[get-preference].} + + @item{@scheme['temp-dir] --- the standard directory for storing + temporary files. Under @|AllUnix|, this is the directory specified by + the @envvar{TMPDIR} environment variable, if it is defined.} + + @item{@scheme['init-dir] --- the directory containing the + initialization file used by stand-alone @exec{mzscheme} executable. + It is the same as the current user's home directory.} + + @item{@scheme['init-file] --- the file loaded at start-up + by the stand-alone @exec{mzscheme} executable. The directory part + of the path is the same path as returned for @scheme['init-dir]. + The file name is platform-specific: + + @itemize{ + + @item{@|AllUnix|: @file{.mzschemerc}} + + @item{Windows: @file{mzschemerc.ss}} + + }} + + @item{@scheme['addon-dir] --- a directory for installing PLT Scheme + extensions. It's the same as @scheme['pref-dir], except under Mac OS + X, where it is @file{Library/PLT Scheme} in the user's home + directory. This directory might not exist.} + + @item{@scheme['doc-dir] --- the standard directory for storing the + current user's documents. It's the same as @scheme['home-dir] under + @|AllUnix|. Under Windows, it is the user's documents folder as + specified by the Windows registry; the documents folder is usually + @file{My Documents} in the user's home directory.} + + @item{@scheme['desk-dir] --- the directory for the current user's + desktop. Under Unix, it's the same as @scheme['home-dir]. Under + Windows, it is the user's desktop folder as specified by the Windows + registry; the documents folder is usually @file{Desktop} in the + user's home directory. Under Mac OS X, it is the desktop directory, + which is specifically @file{~/Desktop} under Mac OS X.} + + @item{@scheme['sys-dir] --- the directory containing the + operating system for Windows. Under @|AllUnix|, the + result is @scheme["/"].} + + @item{@scheme['exec-file] --- the path of the @exec{mzscheme} + executable as provided by the operating system for the current + invocation. + + @margin-note{For MrEd, the executable path is the name of a MrEd + executable.}} + + @item{@scheme['run-file] --- the path of the current executable; this + may be different from result for @scheme['exec-file] because an + alternate path was provided through a @DFlag{name} or @Flag{N} + command-line flag to the @exec{mzscheme} (or @exec{mred}) + executable, or because an embedding executable installed an + alternate path. In particular a ``launcher'' script created by + @scheme[make-mzscheme-launcher] sets this path to the script's + path. In the @exec{mzscheme} executable, this path is also bound + initially to @scheme[program].} + + @item{@scheme['collects-dir] --- a path to the main collection + of libraries (see @secref["mz:mzlib"]). If this path is relative, it's + relative to the directory of @scheme[(find-system-path 'exec-file)]. + This path is normally embedded in the @exec{mzscheme} executable, + but it can be overridden by the @DFlag{collects} or @Flag{X} + command-line flag.} + + @item{@scheme['orig-dir] --- the current directory at start-up, which + can be useful in converting a relative-path result from + @scheme[(find-system-path 'exec-file)] or @scheme[(find-system-path + 'run-file)] to a complete path.} + + }} + +@defproc[(path-list-string->path-list [str (or/c string? bytes?)] + [default-path-list (listof path?)]) + (listof path?)]{ + + +Parses a string or byte string containing a list of paths, and returns +a list of path strings. Under @|AllUnix|, paths in a path list are +separated by a @litchar{:}; under Windows, paths are separated by a +@litchar{;}. Whenever the path list contains an empty path, the list +@scheme[default-path-list] is spliced into the returned list of +paths. Parts of @scheme[str] that do not form a valid path are not +included in the returned list.} + + +@defproc[(find-executable-path [program-sub path-string?][related-sub path-string?][deepest? any/c #f]) + (or/c path? false/c)]{ + +Finds a path for the executable @scheme[program-sub], returning +@scheme[#f] if the path cannot be found. + +If @scheme[related-sub] is not @scheme[#f], then it must be a relative +path string, and the path found for @scheme[program-sub] must be such +that the file or directory @scheme[related-sub] exists in the same +directory as the executable. The result is then the full path for the +found @scheme[related-sub], instead of the path for the executable. + +This procedure is used by the @exec{mzscheme} executable to find the +standard library collection directory (see @secref["mz:mzlib"]). In +this case, @scheme[program] is the name used to start MzScheme and +@scheme[related] is @scheme["collects"]. The @scheme[related-sub] +argument is used because, under @|AllUnix|, @scheme[program-sub] may +involve to a sequence of soft links; in this case, +@scheme[related-sub] determines which link in the chain is relevant. + +If @scheme[related-sub] is not @scheme[#f], then when +@scheme[find-executable-path] does not finds a @scheme[program-sub] +that is a link to another file path, the search can continue with the +destination of the link. Further links are inspected until +@scheme[related-sub] is found or the end of the chain of links is +reached. If @scheme[deepest?] is @scheme[#f] (the default), then the +result corresponds to the first path in a chain of links for which +@scheme[related-sub] is found (and further links are not actually +explored); otherwise, the result corresponds to the last link in the +chain for which @scheme[related-sub] is found. + +If @scheme[program-sub] is a pathless name, +@scheme[find-executable-path] gets the value of the @envvar{PATH} +environment variable; if this environment variable is defined, +@scheme[find-executable-path] tries each path in @envvar{PATH} as a +prefix for @scheme[program-sub] using the search algorithm described +above for path-containing @scheme[program-sub]s. If the @envvar{PATH} +environment variable is not defined, @scheme[program-sub] is prefixed +with the current directory and used in the search algorithm +above. (Under Windows, the current directory is always implicitly the +first item in @envvar{PATH}, so @scheme[find-executable-path] checks +the current directory first under Windows.)} + +@;------------------------------------------------------------------------ +@section[#:tag "mz:fileutils"]{Files} + +@defproc[(file-exists? [path path-string?]) boolean?]{ + +Returns @scheme[#t] if a file (not a directory) @scheme[path] exists, +@scheme[#f] otherwise. + +Under Windows, @scheme[file-exists?] reports @scheme[#t] for all +variations of the special filenames (e.g., @scheme["LPT1"], +@scheme["x:/baddir/LPT1"]).} + +@defproc[(link-exists? [path path-string?]) boolean?]{ + +Returns @scheme[#t] if a link @scheme[path] exists (@|AllUnix|), +@scheme[#f] otherwise. + +The predicates @scheme[file-exists?] or @scheme[directory-exists?] +work on the final destination of a link or series of links, while +@scheme[link-exists?] only follows links to resolve the base part of +@scheme[path] (i.e., everything except the last name in the +path). + +This procedure never raises the @scheme[exn:fail:filesystem] +exception.} + + +@defproc[(delete-file [path path-string?]) void?]{ + +Feletes the file with path @scheme[path] if it exists, otherwise the +@exnraise[exn:fail:filesystem]. If @scheme[path] is a link, the link +is deleted rather than the destination of the link.} + +@defproc[(rename-file-or-directory [old path-string?] + [new path-string?] + [exists-ok? any/c #f]) + void?]{ + +Renames the file or directory with path @scheme[old]---if it +exists---to the path @scheme[new]. If the file or directory is not +renamed successfully, the @exnraise[exn:fail:filesystem]. + +This procedure can be used to move a file/directory to a different +directory (on the same disk) as well as rename a file/directory within +a directory. Unless @scheme[exists-ok?] is provided as a true value, +@scheme[new] cannot refer to an existing file or directory. Even if +@scheme[exists-ok?] is true, @scheme[new] cannot refer to an existing +file when @scheme[old] is a directory, and vice versa. (If +@scheme[new] exists and is replaced, the replacement is atomic in the +filesystem, except under Windows 95, 98, or Me. However, the check for +existence is not included in the atomic action, which means that race +conditions are possible when @scheme[exists-ok?] is false or not +supplied.) + +If @scheme[old] is a link, the link is renamed rather than the +destination of the link, and it counts as a file for replacing any +existing @scheme[new].} + + +@defproc[(file-or-directory-modify-seconds [path path-string?] + [secs-n (or/c exact-integer? false/c) #f] + [fail-thunk (-> any) (lambda () (raise (make-exn:fail:filesystem ....)))]) + any]{ + +Returns the file or directory's last modification date as +platform-specific seconds (see also @secref["mz:time"]) when +@scheme[secs-n] is not provided or is @scheme[#f]. (For FAT +filesystems under Windows, directories do not have modification +dates. Therefore, the creation date is returned for a directory (but +the modification date is returned for a file).) + +If @scheme[secs-n] is provided and not @scheme[#f], the access and +modification times of @scheme[path] are set to the given time. + +On error (e.g., if no such file exists), @scheme[fail-thunk] is +called, and the default @scheme[fail-thunk] raises +@scheme[exn:fail:filesystem].} + + +@defproc[(file-or-directory-permissions [path path-string?]) (listof symbol?)]{ + +Returns a list containing @scheme['read], @scheme['write], and/or +@scheme['execute] for the given file or directory path. On error +(e.g., if no such file exists), the +@exnraise[exn:fail:filesystem]. Under @|AllUnix|, permissions are +checked for the current effective user instead of the real user.} + +@defproc[(file-size [path path-string?]) nonnegative-exact-integer?]{ + +Returns the (logical) size of the specified file in bytes. Under Mac +OS X, this size excludes the resource-fork size. On error (e.g., if no +such file exists), the @exnraise[exn:fail:filesystem].} + + +@defproc[(copy-file [src path-string?][dest path-string?]) void?]{ + +Creates the file @scheme[dest] as a copy of @scheme[src]. If the file +is not successfully copied, the @exnraise[exn:fail:filesystem]. If +@scheme[dest] already exists, the copy will fail. File permissions are +preserved in the copy. Under Mac OS X, the resource fork is also +preserved in the copy. If @scheme[src] refers to a link, the target of +the link is copied, rather than the link itself.} + +@defproc[(make-file-or-directory-link [to path-string?][path path-string?]) + void?]{ + +Creates a link @scheme[path] to @scheme[to] under @|AllUnix|. The +creation will fail if @scheme[path] already exists. The @scheme[to] +need not refer to an existing file or directory, and @scheme[to] is +not expanded before writing the link. If the link is not created +successfully,the @exnraise[exn:fail:filesystem]. Under Windows, the +@exnraise[exn:fail:unsupported] always.} + +@;------------------------------------------------------------------------ +@section[#:tag "mz:directories"]{Directories} + +See also: @scheme[rename-file-or-directory], +@scheme[file-or-directory-modify-seconds], +@scheme[file-or-directory-permissions]. + +@defparam[current-directory path path-string?]{ + +A parameter that determines the current directory for resolving +relative paths. + +When the parameter procedure is called to set the current directory, +the path argument is expanded using @scheme[expand-path], simplified +using @scheme[simplify-path], and then converted to a directory path +with @scheme[path->directory-path]; expansion and simplification raise +an exception if the path is ill-formed. Thus, the current value of +@scheme[current-directory] is always an expanded, simplified, +complete, directory path. + +The path is not checked for existence when the parameter is set.} + + +@defproc[(current-drive) path?]{ + +Returns the current drive name Windows. For other platforms, the +@exnraise[exn:fail:unsupported]. The current drive is always the drive +of the current directory.} + + +@defproc[(directory-exists? [path path-string?]) boolean?]{ + +Returns @scheme[#t] if @scheme[path] refers to a directory, +@scheme[#f] otherwise.} + +@defproc[(make-directory [path path-string?]) void?]{ + +Creates a new directory with the path @scheme[path]. If the directory +is not created successfully, the @exnraise[exn:fail:filesystem].} + + +@defproc[(delete-directory [path path-string?]) void?]{ + +Deletes an existing directory with the path @scheme[path]. If the +directory is not deleted successfully, the +@exnraise[exn:fail:filesystem].} + + +@defproc[(directory-list [path path-string? (current-directory)]) + (listof path?)]{ + +Returns a list of all files and directories in the directory specified +by @scheme[path]. If @scheme[path] is omitted, a list of files and +directories in the current directory is returned. Under @|AllUnix|, an +element of the list can start with @litchar{./~} if it would otherwise +start with @litchar{~}. Under Windows, an element of the list may +start with @litchar["\\\\?\\REL\\\\"].} + + +@defproc[(filesystem-root-list) (listof path?)]{ + +Returns a list of all current root directories. Obtaining this list +can be particularly slow under Windows.} diff --git a/collects/scribblings/reference/io.scrbl b/collects/scribblings/reference/io.scrbl index 81cc0fe4fc..dafda07a6d 100644 --- a/collects/scribblings/reference/io.scrbl +++ b/collects/scribblings/reference/io.scrbl @@ -13,3 +13,4 @@ @include-section["reader.scrbl"] @include-section["printer.scrbl"] @include-section["readtables.scrbl"] +@include-section["custom-write.scrbl"] diff --git a/collects/scribblings/reference/networking.scrbl b/collects/scribblings/reference/networking.scrbl new file mode 100644 index 0000000000..c38226ae43 --- /dev/null +++ b/collects/scribblings/reference/networking.scrbl @@ -0,0 +1,553 @@ +#reader(lib "docreader.ss" "scribble") +@require["mz.ss"] + +@title[#:tag "mz:networking" #:style 'toc]{Networking} + +@local-table-of-contents[] + +@;------------------------------------------------------------------------ +@section[#:tag "mz:tcp"]{TCP} + +For information about TCP in general, see @italic{TCP/IP Illustrated, + Volume 1} by W. Richard Stevens. + +@defproc[(tcp-listen [port-no (and/c nonnegative-exact-integer? + (integer-in 1 65535))] + [max-allow-wait nonnegative-exact-integer? 4] + [reuse? any/c #f] + [hostname (or/c string? false/c) #f]) + tcp-listener?] + +Creates a ``listening'' server on the local machine at the port number +specified by @scheme[port-no]. The @scheme[max-allow-wait] argument +determines the maximum number of client connections that can be +waiting for acceptance. (When @scheme[max-allow-wait] clients are +waiting acceptance, no new client connections can be made.) + +If the @scheme[reuse?] argument is true, then @scheme[tcp-listen] will +create a listener even if the port is involved in a @tt{TIME_WAIT} +state. Such a use of @scheme[reuse?] defeats certain guarantees of the +TCP protocol; see Stevens's book for details. Furthermore, on many +modern platforms, a true value for @scheme[reuse?] overrides +@tt{TIME_WAIT} only if the listener was previously created with a true +value for @scheme[reuse?]. + +If @scheme[hostname] is @scheme[#f] (the default), then the listener +accepts connections to all of the listening machine's addresses. +Otherwise, the listener accepts connections only at the interface(s) +associated with the given hostname. For example, providing +@scheme["127.0.0.1"] as @scheme[hostname] creates a listener that +accepts only connections to @scheme["127.0.0.1"] (the loopback +interface) from the local machine. + +(Scheme implements a listener with multiple sockets, if necessary, to +accomodate multiple addresses with different protocol families. Under +Linux, if @scheme[hostname] maps to both IPv4 and IPv6 addresses, then +the behavior depends on whether IPv6 is supported and IPv6 sockets can +be configured to listen to only IPv6 connections: if IPv6 is not +supported or IPv6 sockets are not configurable, then the IPv6 +addresses are ignored; otherwise, each IPv6 listener accepts only IPv6 +connections.) + +The return value of @scheme[tcp-listen] is a TCP listener value. This +value can be used in future calls to @scheme[tcp-accept], +@scheme[tcp-accept-ready?], and @scheme[tcp-close]. Each new TCP +listener value is placed into the management of the current custodian +(see @secref["mz:custodians"]). + +If the server cannot be started by @scheme[tcp-listen], the +@exnraise[exn:fail:network].} + + +@defproc[(tcp-connect [hostname string?] + [port-no (and/c nonnegative-exact-integer? + (integer-in 1 65535))] + [local-hostname (or/c string? false/c) #f] + [local-port-no (or/c (and/c nonnegative-exact-integer? + (integer-in 1 65535)) + false/c)]) + (values input-port? output-port?)]{ + +Attempts to connect as a client to a listening server. The +@scheme[hostname] argument is the server host's Internet address name, +and @scheme[port-no] is the port number where the server is listening. + +(If @scheme[hostname] is associated with multiple addresses, they are +tried one at a time until a connection succeeds. The name +@scheme["localhost"] generally specifies the local machine.) + +The optional @scheme[local-hostname] and @scheme[local-port-no] +specify the client's address and port. If both are @scheme[#f] (the +default), the client's address and port are selected automatically. If +@scheme[local-hostname] is not @scheme[#f], then +@scheme[local-port-no] must be non-@scheme[#f]. If +@scheme[local-port-no] is non-@scheme[#f] and @scheme[local-hostname] +is @scheme[#f], then the given port is used but the address is +selected automatically. + +Two values are returned by @scheme[tcp-connect]: an input port and an +output port. Data can be received from the server through the input +port and sent to the server through the output port. If the server is +a @exec{mzscheme} process, it can obtain ports to communicate to the +client with @scheme[tcp-accept]. These ports are placed into the +management of the current custodian (see @secref["mz:custodians"]). + +Initially, the returned input port is block-buffered, and the returned +output port is block-buffered. Change the buffer mode using +@scheme[file-stream-buffer-mode]. + +Both of the returned ports must be closed to terminate the TCP +connection. When both ports are still open, closing the output port +with @scheme[close-output-port] sends a TCP close to the server (which +is seen as an end-of-file if the server reads the connection through a +port). In contrast, @scheme[tcp-abandon-port] (see below) closes the +output port, but does not send a TCP close until the input port is +also closed. + +Note that the TCP protocol does not support a state where one end is +willing to send but not read, nor does it include an automatic message +when one end of a connection is fully closed. Instead, the other end +of a connection discovers that one end is fully closed only as a +response to sending data; in particular, some number of writes on the +still-open end may appear to succeed, though writes will eventually +produce an error. + +If a connection cannot be established by @scheme[tcp-connect], the +@exnraise[exn:fail:network].} + +@defproc[(tcp-connect/enable-break [hostname string?] + [port-no (and/c nonnegative-exact-integer? + (integer-in 1 65535))] + [local-hostname (or/c string? false/c) #f] + [local-port-no (or/c (and/c nonnegative-exact-integer? + (integer-in 1 65535)) + false/c)]) + (values input-port? output-port?)]{ + +Like @scheme[tcp-connect], but breaking is enabled (see +@secref["mz:breakhandler"]) while trying to connect. If breaking is +disabled when @scheme[tcp-connect/enable-break] is called, then either +ports are returned or the @scheme[exn:break] exception is raised, but +not both.} + +@defproc[(tcp-accept [listener tcp-listener?]) + (values input-port? output-port?)]{ + +Accepts a client connection for the server associated with +@scheme[listener], which is a TCP listener value returned by +@scheme[tcp-listen]. If no client connection is waiting on the +listening port, the call to @scheme[tcp-accept] will block. (See also +@scheme[tcp-accept-ready?].) + +Two values are returned by @scheme[tcp-accept]: an input port and an +output port. Data can be received from the client through the input +port and sent to the client through the output port. These ports are +placed into the management of the current custodian (see +@secref["mz:custodians"]). + +In terms of buffering and connection states, the ports act the same as +ports from @scheme[tcp-connect]. + +If a connection cannot be accepted by @scheme[tcp-accept], or if the +listener has been closed, the @exnraise[exn:fail:network].} + + +@defproc[(tcp-accept/enable-break [listener tcp-listener?]) + (values input-port? output-port?)]{ + +Like @scheme[tcp-accept], but breaking is enabled (see +@secref["mz:breakhandler"]) while trying to accept a connection. If +breaking is disabled when @scheme[tcp-accept/enable-break] is called, +then either ports are returned or the @scheme[exn:break] exception is +raised, but not both.} + + +@defproc[(tcp-accept-ready? [listener tcp-listener?]) boolean?]{ + +Tests whether an unaccepted client has connected to the server +associated with @scheme[listener]. The @scheme[listener] argument is a +TCP listener value returned by @scheme[tcp-listen]. If a client is +waiting, the return value is @scheme[#t], otherwise it is +@scheme[#f]. A client is accepted with the @scheme[tcp-accept] +procedure, which returns ports for communicating with the client and +removes the client from the list of unaccepted clients. + +If the listener has been closed, the @exnraise[exn:fail:network].} + + +@defproc[(tcp-close [listener tcp-listener?]) void?]{ + +Shuts down the server associated with @scheme[listener]. The +@scheme[listener] argument is a TCP listener value returned by +@scheme[tcp-listen]. All unaccepted clients receive an end-of-file +from the server; connections to accepted clients are unaffected. + +If the listener has already been closed, the @exnraise[exn:fail:network]. + +The listener's port number may not become immediately available for +new listeners (with the default @scheme[reuse?] argument of +@scheme[tcp-listen]). For further information, see Stevens's +explanation of the @tt{TIME\_WAIT} TCP state.} + + +@defproc[(tcp-listener? [v any/c]) boolean?]{ + +Returns @scheme[#t] if @scheme[v] is a TCP listener value created by +@scheme[tcp-listen], @scheme[#f] otherwise.} + + +@defproc[(tcp-accept-evt [listener tcp-listener?]) evt?]{ + +Returns a @tech{synchronizable event} (see @secref["mz:sync"]) that is +in a blocking state when @scheme[tcp-accept] on @scheme[listener] +would block. If the event is chosen in a synchronization, the result +is a list of two items, which correspond to the two results of +@scheme[tcp-accept]. (If the event is not chosen, no connections are +accepted.)} + + +@defproc[(tcp-abandon-port [tcp-port tcp-port?]) void?]{ + +Like @scheme[close-output-port] or @scheme[close-input-port] +(depending on whether @scheme[tcp-port] is an input or output port), +but if @scheme[tcp-port] is an output port and its associated input +port is not yet closed, then the other end of the TCP connection does +not receive a TCP close message until the input port is also +closed. + +The TCP protocol does not include a ``no longer reading'' state on +connections, so @scheme[tcp-abandon-port] is equivalent to +@scheme[close-input-port] on input TCP ports.} + + +@defproc[(tcp-addresses [tcp-port tcp-port?] + [port-numbers? any/c #f]) + (or/c (values string? string?) + (values string? (integer-in 1 65535) + string? (integer-in 1 65535)))]{ + +Returns two strings when @scheme[port-numbers?] is @scheme[#f] (the +default). The first string is the Internet address for the local +machine a viewed by the given TCP port's connection. (For most +machines, the answer corresponds to the current machine's only +Internet address, but when a machine serves multiple addresses, the +result is connection-specific.) The second string is the Internet +address for the other end of the connection. + +If @scheme[port-numbers?] is true, then four results are returned: a +string for the local machine's address, an exact integer between +@scheme[1] and @scheme[65535] for the local machine's port number, a +string for the remote machine's address, and an exact integer between +@scheme[1] and @scheme[65535] for the remote machine's port number. + +If the given port has been closed, the @exnraise[exn:fail:network].} + + +@defproc[(tcp-port? [v any/c]) boolean?]{ + +Returns @scheme[#t] if @scheme[v] is a port returned by +@scheme[tcp-accept], @scheme[tcp-connect], +@scheme[tcp-accept/enable-break], or +@scheme[tcp-connect/enable-break], @scheme[#f] otherwise.} + +@;------------------------------------------------------------------------ +@section[#:tag "mz:udp"]{UDP} + +For information about UDP in general, see @italic{TCP/IP Illustrated, +Volume 1} by W. Richard Stevens. + +@defproc[(udp-open-socket [family-hostname (or/c string? false/c) #f] + [family-port-no (or/c string? false/c) #f]) + udp?]{ + +Creates and returns a UDP socket to send and receive +datagrams (broadcasting is allowed). Initially, the socket is not +bound or connected to any address or port. + +If @scheme[family-hostname] or @scheme[family-port-no] is not +@scheme[#f], then the socket's protocol family is determined from +these arguments. The socket is @italic{not} bound to the hostname +or port number. For example, the arguments might be the hostname +and port to which messages will be sent through the socket, which +ensures that the socket's protocol family is consistent with the +destination. Alternately, the arguments might be the same as for +a future call to @scheme[udp-bind!], which ensures that the +socket's protocol family is consistent with the binding. If +neither @scheme[family-hostname] nor @scheme[family-port-no] is +non-@scheme[#f], then the socket's protocol family is IPv4.} + +@defproc[(udp-bind! [udp-socket udp?] + [hostname-string (or/c string? false/c)] + [port-no (and/c nonnegative-exact-integer? + (integer-in 1 65535))]) + void?]{ + +Binds an unbound @scheme[udp-socket] to the local port number +@scheme[port-no]. + +If @scheme[hostname-string] is @scheme[#f], then the socket +accepts connections to all of the listening machine's IP +addresses at @scheme[port-no]. Otherwise, the socket accepts +connections only at the IP address associated with the given +name. For example, providing @scheme["127.0.0.1"] as +@scheme[hostname-string] typically creates a listener that +accepts only connections to @scheme["127.0.0.1"] from the local +machine. + +A socket cannot receive datagrams until it is bound to a local address +and port. If a socket is not bound before it is used with a sending +procedure @scheme[udp-send], @scheme[udp-send-to], etc., the sending +procedure binds the socket to a random local port. Similarly, if an +event from @scheme[udp-send-evt] or @scheme[udp-send-to-evt] is chosen +for a synchronization (see @secref["mz:sync"]), the socket is bound; +if the event is not chosen, the socket may or may not become +bound. The binding of a bound socket cannot be changed. + +If @scheme[udp-socket] is already bound or closed, the +@exnraise[exn:fail:network].} + + +@defproc[(udp-connect! [udp-socket udp?] + [hostname-string (or/c string? false/c)] + [port-no (or/c (and/c nonnegative-exact-integer? + (integer-in 1 65535)) + false/c)]) + void?]{ + +Connects the socket to the indicated remote address and port if +@scheme[hostname-string] is a string and @scheme[port-no] is an exact +integer. + +If @scheme[hostname-string] is @scheme[#f], then @scheme[port-no] also +must be @scheme[#f], and the port is disconnected (if connected). If +one of @scheme[hostname-string] or @scheme[port-no] is @scheme[#f] and +the other is not, the @exnraise[exn:fail:contract]. + +A connected socket can be used with @scheme[udp-send] (not +@scheme[udp-send-to]), and it accepts datagrams only from the +connected address and port. A socket need not be connected to receive +datagrams. A socket can be connected, re-connected, and disconnected +any number of times. + +If @scheme[udp-socket] is closed, the @exnraise[exn:fail:network].} + + +@defproc[(udp-send-to [udp-socket udp?] + [hostname string?] + [port-no (and/c nonnegative-exact-integer? + (integer-in 1 65535))] + [bstr bytes?] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + void]{ + +Sends @scheme[(subbytes bytes start-pos end-pos)] as a datagram from +the unconnected @scheme[udp-socket] to the socket at the remote +machine @scheme[hostname-address] on the port @scheme[port-no]. The +@scheme[udp-socket] need not be bound or connected; if it is not +bound, @scheme[udp-send-to] binds it to a random local port. If the +socket's outgoing datagram queue is too full to support the send, +@scheme[udp-send-to] blocks until the datagram can be queued. + +If @scheme[start-pos] is greater than the length of @scheme[bstr], or +if @scheme[end-pos] is less than @scheme[start-pos] or greater than +the length of @scheme[bstr], the @exnraise[exn:fail:contract]. + +If @scheme[udp-socket] is closed or connected, the +@exnraise[exn:fail:network].} + +@defproc[(udp-send [udp-socket udp?] + [bstr bytes?] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + void]{ + +Like @scheme[udp-send-to], except that @scheme[udp-socket] must be +connected, and the datagram goes to the connection target. If +@scheme[udp-socket] is closed or unconnected, the +@exnraise[exn:fail:network].} + +@defproc[(udp-send-to* [udp-socket udp?] + [hostname string?] + [port-no (and/c nonnegative-exact-integer? + (integer-in 1 65535))] + [bstr bytes?] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + boolean?]{ + +Like @scheme[udp-send-to], but never blocks; if the socket's outgoing +queue is too full to support the send, @scheme[#f] is returned, +otherwise the datagram is queued and the result is @scheme[#t].} + +@defproc[(udp-send* [udp-socket udp?] + [bstr bytes?] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + boolean?]{ + +Like @scheme[udp-send], except that (like @scheme[udp-send-to]) it +never blocks and returns @scheme[#f] or @scheme[#t].} + +@defproc[(udp-send-to/enable-break [udp-socket udp?] + [hostname string?] + [port-no (and/c nonnegative-exact-integer? + (integer-in 1 65535))] + [bstr bytes?] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + void]{ + +Like @scheme[udp-send-to], but breaking is enabled (see +@secref["mz:breakhandler"]) while trying to send the datagram. If +breaking is disabled when @scheme[udp-send-to/enable-break] is called, +then either the datagram is sent or the @scheme[exn:break] exception +is raised, but not both.} + + +@defproc[(udp-send/enable-break [udp-socket udp?] + [bstr bytes?] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + void]{ + +Like @scheme[udp-send], except that breaks are enabled like +@scheme[udp-send-to/enable-break].} + + +@defproc[(udp-receive! [udp-socket udp?] + [bstr (and/c bytes? (not immutable?))] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + (values nonnegative-exact-integer? + string? + (integer-in 1 65535))]{ + +Accepts up to @math{@scheme[end-pos]-@scheme[start-pos]} bytes of +@scheme[udp-socket]'s next incoming datagram into @scheme[bstr], +writing the datagram bytes starting at position @scheme[start-pos] +within @scheme[bstr]. The @scheme[udp-socket] must be bound to a local +address and port (but need not be connected). If no incoming datagram +is immediately available, @scheme[udp-receive!] blocks until one is +available. + +Three values are returned: the number of received bytes (between +@scheme[0] and @math{@scheme[end-pos]-@scheme[start-pos]}, a hostname +string indicating the source address of the datagram, and an integer +indicating the source port of the datagram. If the received datagram +is longer than @math{@scheme[end-pos]-@scheme[start-pos]} bytes, the +remainder is discarded. + +If @scheme[start-pos] is greater than the length of @scheme[bstr], or +if @scheme[end-pos] is less than @scheme[start-pos] or greater than +the length of @scheme[bstr], the @exnraise[exn:fail:contract].} + +@defproc[(udp-receive!* [udp-socket udp?] + [bstr (and/c bytes? (not immutable?))] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + (values (or/c nonnegative-exact-integer? false/c) + (or/c string? false/c) + (or/c (integer-in 1 65535) false/c))]{ + +Like @scheme[udp-receive!], except that it never blocks. If no +datagram is available, the three result values are all @scheme[#f].} + +@defproc[(udp-receive!/enable-break [udp-socket udp?] + [bstr (and/c bytes? (not immutable?))] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + (values nonnegative-exact-integer? + string? + (integer-in 1 65535))]{ + +Like @scheme[udp-receive!], but breaking is enabled (see +@secref["mz:breakhandler"]) while trying to receive the datagram. If +breaking is disabled when @scheme[udp-receive!/enable-break] is +called, then either a datagram is received or the @scheme[exn:break] +exception is raised, but not both.} + + +@defproc[(udp-close [udp-socket udp?]) void?]{ + +Closes @scheme[udp-socket], discarding unreceived datagrams. If the +socket is already closed, the @exnraise[exn:fail:network].} + + +@defproc[(udp? [v any/c]) boolean?]{ + +Returns @scheme[#t] if @scheme[v] is a socket created by +@scheme[udp-open-socket], @scheme[#f] otherwise.} + + +@defproc[(udp-bound? [udp-socket udp?]) boolean?]{ + +Returns @scheme[#t] if @scheme[udp-socket] is bound to a local address +and port, @scheme[#f] otherwise.} + + +@defproc[(udp-connected? [udp-socket udp?]) boolean?]{ + +Returns @scheme[#t] if @scheme[udp-socket] is connected to a remote +address and port, @scheme[#f] otherwise.} + + +@defproc[(udp-send-ready-evt [udp-socket udp?]) evt?]{ + +Returns a @tech{synchronizable event} (see @secref["mz:sync"]) that is +in a blocking state when @scheme[udp-send-to] on @scheme[udp-socket] +would block.} + + +@defproc[(udp-receive-ready-evt [udp-socket udp?]) evt?]{ + +Returns a @tech{synchronizable event} (see @secref["mz:sync"]) that is +in a blocking state when @scheme[udp-receive!] on @scheme[udp-socket] +would block.} + +@defproc[(udp-send-to-evt [udp-socket udp?] + [hostname string?] + [port-no (and/c nonnegative-exact-integer? + (integer-in 1 65535))] + [bstr bytes?] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + evt?]{ + +Returns a @tech{synchronizable event}. The event is in a blocking +state when @scheme[udp-send-to] on @scheme[udp-socket] would +block. Otherwise, if the event is chosen in a synchronization, data is +sent as for @scheme[(udp-send-to udp-socket hostname-address port-no +bstr start-pos end-pos)], and the synchronization result is +@|void-const|. (No bytes are sent if the event is not chosen.)} + + +@defproc[(udp-send-evt [udp-socket udp?] + [bstr bytes?] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + evt?]{ + +Returns a @tech{synchronizable event}. The event is in a blocking +state when @scheme[udp-send] on @scheme[udp-socket] would +block. Otherwise, if the event is chosen in a synchronization, data is +sent as for @scheme[(udp-send-to udp-socket bstr start-pos end-pos)], +and the synchronization result is @|void-const|. (No bytes are sent if +the event is not chosen.) If @scheme[udp-socket] is closed or +unconnected, the @exnraise[exn:fail:network] during a synchronization +attempt.} + +@defproc[(udp-receive!-evt [udp-socket udp?] + [bstr (and/c bytes? (not immutable?))] + [start-pos nonnegative-exact-integer? 0] + [end-pos nonnegative-exact-integer? (bytes-length bstr)]) + evt?]{ + +Returns a @tech{synchronizable event}. The event is in a blocking +state when @scheme[udp-receive] on @scheme[udp-socket] would +block. Otherwise, if the event is chosen in a synchronization, data is +received into @scheme[bstr] as for @scheme[(udp-receive! udp-socket +bytes start-pos end-pos)], and the synchronization result is a list of +three values, corresponding to the three results from +@scheme[udp-receive!]. (No bytes are received and the @scheme[bstr] +content is not modified if the event is not chosen.)} diff --git a/collects/scribblings/reference/os.scrbl b/collects/scribblings/reference/os.scrbl index ef106222ac..5a99cec09b 100644 --- a/collects/scribblings/reference/os.scrbl +++ b/collects/scribblings/reference/os.scrbl @@ -5,4 +5,6 @@ @local-table-of-contents[] -@include-section["platform-paths.scrbl"] +@include-section["paths.scrbl"] +@include-section["filesystem.scrbl"] +@include-section["networking.scrbl"] diff --git a/collects/scribblings/reference/paths.scrbl b/collects/scribblings/reference/paths.scrbl new file mode 100644 index 0000000000..c911466a91 --- /dev/null +++ b/collects/scribblings/reference/paths.scrbl @@ -0,0 +1,482 @@ +#reader(lib "docreader.ss" "scribble") +@require["mz.ss"] + +@title[#:tag "mz:pathutils" #:style 'toc]{Paths} + +When a Scheme procedure takes a filesystem path as an argument, the +path can be provided either as a string or as an instance of the +@deftech{path} datatype. If a string is provided, it is converted to a +path using @scheme[string->path]. A Scheme procedure that generates a +filesystem path always generates a @tech{path} value. + +By default, paths are created and manipulated for the current +platform, but procedures that merely manipulate paths (without using +the filesystem) can manipulate paths using conventions for other +supported platforms. The @scheme[bytes->path] procedure accepts an +optional argument that indicates the platform for the path, either +@scheme['unix] or @scheme['windows]. For other functions, such as +@scheme[build-path] or @scheme[simplify-path], the behavior is +sensitive to the kind of path that is supplied. Unless otherwise +specified, a procedure that requires a path accepts only paths for the +current platform. + +Two @tech{path} values are @scheme[equal?] when they are use the same +convention type and when their byte-string representations are +@scheme[equal?]. A path string (or byte string) cannot be empty, and +it cannot contain a nul character or byte. When an empty string or a +string containing nul is provided as a path to any procedure except +@scheme[absolute-path?], @scheme[relative-path?], or +@scheme[complete-path?], the @exnraise[exn:fail:contract]. + +Most Scheme primitives that accept paths first @deftech{path-expand} +the path before using it. Procedures that build paths or merely check +the form of a path do not perform this expansion, with the exception +of @scheme[simplify-path] for Windows paths. For more information +about path expansion and other platform-specific details, see +@secref["mz:unixpaths"] for @|AllUnix| paths and +@secref["mz:windowspaths"] for Windows paths. + +@;------------------------------------------------------------------------ +@section{Manipulating Paths} + +@defproc[(path? [v any/c]) boolean?]{ + +Returns @scheme[#t] if @scheme[v] is a path value for the current +platform (not a string, and not a path for a different platform), +@scheme[#f] otherwise.} + +@defproc[(path-string? [v any/c]) boolean?]{ + +Return @scheme[#t] if @scheme[v] is either a path value for the +current platform or a non-empty string without nul characters, +@scheme[#f] otherwise.} + +@defproc[(path-for-some-system? [v any/c]) boolean?]{ + +Returns @scheme[#t] if @scheme[v] is a path value for some platform +(not a string), @scheme[#f] otherwise.} + +@defproc[(string->path [str string?]) path?]{ + +Produces a path whose byte-string name is +@scheme[(string->bytes/locale string (char->integer #\?))]. + +Beware that the current locale might not encode every string, in which +case @scheme[string->path] can produce the same path for different +@scheme[str]s. See also @scheme[string->path-element], which should be +used instead of @scheme[string->path] when a string represents a +single path element.} + +@defproc[(bytes->path [bstr bytes?] + [type (one-of/c 'unix 'windows) (system-path-convention-type)]) + path?]{ + +Produces a path (for some platform) whose byte-string name is +@scheme[bstr]. The optional @scheme[type] specifies the convention to +use for the path. + +For converting relative path elements from literals, use instead +@scheme[bytes->path-element], which applies a suitable encoding for +individual elements.} + +@defproc[(path->string [path path?]) string?]{ + +Produces a string that represents @scheme[path] by decoding +@scheme[path]'s byte-string name using the current locale's encoding; +@litchar{?} is used in the result string where encoding fails, and if +the encoding result is the empty string, then the result is +@scheme["?"]. + +The resulting string is suitable for displaying to a user, +string-ordering comparisons, etc., but it is not suitable for +re-creating a path (possibly modified) via @scheme[string->path], +since decoding and re-encoding the path's byte string may lose +information. + +Furthermore, for display and sorting based on individual path elements +(such as pathless file names), use @scheme[path-element->string], +instead, to avoid special encodings use to represent some relative +paths. See @secref["mz:windowspaths"] for specific information about +the conversion of Windows paths.} + +@defproc[(path->bytes [path path?]) bytes?]{ + +Produces @scheme[path]'s byte string representation. No information is +lost in this translation, so that @scheme[(bytes->path (path->bytes +path) (path-convention-type path))] always produces a path is that is +@scheme[equal?] to @scheme[path]. The @scheme[path] argument can be a +path for any platform. + +Conversion to and from byte values is useful for marshaling and +unmarshaling paths, but manipulating the byte form of a path is +generally a mistake. In particular, the byte string may start with a +@litchar{\\?\REL} encoding for Windows paths or a @litchar{./~} +encoding for @|AllUnix| paths. Instead of @scheme[path->bytes], use +@scheme[split-path] and @scheme[path-element->bytes] to manipulate +individual path elements.} + +@defproc[(string->path-element [str string?]) path?]{ + +Like @scheme[string->path], except that @scheme[str] corresponds to a +single relative element in a path, and it is encoded as necessary to +convert it to a path. See @secref["mz:unixpaths"] for more information +on the conversion for @|AllUnix| paths, and see +@secref["mz:windowspaths"] for more information on the conversion for +Windows paths. + +If @scheme[str] does not correspond to any path element +(e.g., it is an absolute path, or it can be split), or if it +corresponds to an up-directory or same-directory indicator under +@|AllUnix|, then @exnraise[exn:fail:contract]. + +As for @scheme[path->string], information can be lost from +@scheme[str] in the locale-specific conversion to a path.} + + +@defproc[(bytes->path-element [bstr bytes?] + [type (one-of/c 'unix 'windows) (system-path-convention-type)]) + path?]{ + +Like @scheme[bytes->path], except that @scheme[bstr] corresponds to a +single relative element in a path. In terms of conversions and +restrictions on @scheme[bstr], @scheme[bytes->path-element] is like +@scheme[string->path-element]. + +The @scheme[bytes->path-element] procedure is generally the best +choice for reconstructing a path based on another path (where the +other path is deconstructed with @scheme[split-path] and +@scheme[path-element->bytes]) when ASCII-level manipulation of path +elements is necessary.} + +@defproc[(path-element->string [path path?]) string?]{ + +Like @scheme[path->string], except any encoding prefix is removed. See +@secref["mz:unixpaths"] for more information on the conversion for +@|AllUnix| paths, and see @secref["mz:windowspaths"] for more +information on the conversion for Windows paths. +In addition, trailing path separators are removed, as by +@scheme[split-path]. + +The @scheme[path] argument must be such that @scheme[split-path] +applied to @scheme[path] would return @scheme['relative] as its first +result and a path as its second result, otherwise the +@exnraise[exn:fail:contract]. + +The @scheme[path-element->string] procedure is generally the best +choice for presenting a pathless file or directory name to a user.} + +@defproc[(path-element->bytes [path path-string?]) bytes?]{ + +Like @scheme[path->bytes], except that any encoding prefix is removed, +etc., as for @scheme[path-element->string]. + +For any reasonable locale, consecutive ASCII characters in the printed +form of @scheme[path] are mapped to consecutive byte values that match +each character's code-point value, and a leading or trailing ASCII +character is mapped to a leading or trailing byte, respectively. The +@scheme[path] argument can be a path for any platform. + +The @scheme[path-element->bytes] procedure is generally the right +choice (in combination with @scheme[split-path]) for extracting the +content of a path to manipulate it at the ASCII level (then +reassembling the result with @scheme[bytes->path-element] and +@scheme[build-path]).} + + +@defproc[(path-convention-type [path path?]) + (one-of 'unix 'windows)]{ + +Accepts a path value (not a string) and returns its convention +type.} + + +@defproc[(system-path-convention-type) + (one-of 'unix 'windows)]{ + +Returns the path convention type of the current platform: +@scheme['unix] for @|AllUnix|, @scheme['windows] for Windows.} + + +@defproc[(build-path [base path-string?] + [sub (or/c path-string? + (one-of/c 'up 'same))] ...) + path?]{ + +Creates a path given a base path and any number of sub-path +extensions. If @scheme[base] is an absolute path, the result is an +absolute path; if @scheme[base] is a relative path, the result is a +relative path. + +Each @scheme[sub] must be either a relative path, the symbol +@scheme['up] (indicating the relative parent directory), or the symbol +@scheme['same] (indicating the relative current directory). For +Windows paths, if @scheme[base] is a drive specification (with or +without a trailing slash) the first @scheme[sub] can be an absolute +(driveless) path. For all platforms, the last @scheme[sub] can be a +filename. + +The @scheme[base] and @scheme[sub-paths] arguments can be paths for +any platform. The platform for the resulting path is inferred from the +@scheme[base] and @scheme[sub] arguments, where string arguments imply +a path for the current platform. If different arguments are for +different platforms, the @exnraise[exn:fail:contract]. If no argument +implies a platform (i.e., all are @scheme['up] or @scheme['same]), the +generated path is for the current platform. + +Each @scheme[sub] and @scheme[base] can optionally end in a directory +separator. If the last @scheme[sub] ends in a separator, it is +included in the resulting path. + +If @scheme[base] or @scheme[sub] is an illegal path string (because it +is empty or contains a nul character), the +@exnraise[exn:fail:contract]. + +The @scheme[build-path] procedure builds a path @italic{without} +checking the validity of the path or accessing the filesystem. + +See @secref["mz:unixpaths"] for more information on the construction +of @|AllUnix| paths, and see @secref["mz:windowspaths"] for more +information on the construction of Windows paths. + +The following examples assume that the current directory is +\File{/home/joeuser} for Unix examples and \File{C:\Joe's Files} for +Windows examples. + +@schemeblock[ +(define p1 (build-path (current-directory) "src" "scheme")) + (code:comment #, @t{Unix: @scheme[p1] is @scheme["/home/joeuser/src/scheme"]}) + (code:comment #, @t{Windows: @scheme[p1] is @scheme["C:\\Joe's Files\\src\\scheme"]}) +(define p2 (build-path 'up 'up "docs" "Scheme")) + (code:comment #, @t{Unix: @scheme[p2] is @scheme["../../docs/Scheme"]}) + (code:comment #, @t{Windows: @scheme[p2] is @scheme["..\\..\\docs\\Scheme"]}) +(build-path p2 p1) + (code:comment #, @t{Unix and Windows: raises @scheme[exn:fail:contract]; @scheme[p1] is absolute}) +(build-path p1 p2) + (code:comment #, @t{Unix: is @scheme["/home/joeuser/src/scheme/../../docs/Scheme"]}) + (code:comment #, @t{Windows: is @scheme["C:\\Joe's Files\\src\\scheme\\..\\..\\docs\\Scheme"]}) +]} + + +@defproc[(build-path/convention-type [type (one-of/c 'unix 'windows)] + [base path-string?] + [sub (or/c path-string? + (one-of/c 'up 'same))] ...) + path?]{ + +Like @scheme[build-path], except a path convention type is specified +explicitly.} + +@defproc[(absolute-path? [path path-string?]) boolean?]{ + +Returns @scheme[#t] if @scheme[path] is an absolute path, @scheme[#f] +otherwise. The @scheme[path] argument can be a path for any +platform. If @scheme[path] is not a legal path string (e.g., it +contains a nul character), @scheme[#f] is returned. This procedure +does not access the filesystem.} + + +@defproc[(relative-path? [path path-string?]) boolean?]{ + +Returns @scheme[#t] if @scheme[path] is a relative path, @scheme[#f] +otherwise. The @scheme[path] argument can be a path for any +platform. If @scheme[path] is not a legal path string (e.g., it +contains a nul character), @scheme[#f] is returned. This procedure +does not access the filesystem.} + + +@defproc[(complete-path? [path path-string?]) boolean?]{ + +Returns @scheme[#t] if @scheme[path] is a completely determined path +(@italic{not} relative to a directory or drive), @scheme[#f] +otherwise. The @scheme[path] argument can be a path for any +platform. Note that for Windows paths, an absolute path can omit the +drive specification, in which case the path is neither relative nor +complete. If @scheme[path] is not a legal path string (e.g., it +contains a nul character), @scheme[#f] is returned. + +This procedure does not access the filesystem.} + + +@defproc[(path->complete-path [path path-string?] + [base path-string? (current-directory)]) + path?]{ + +Returns @scheme[path] as a complete path. If @scheme[path] is already +a complete path, it is returned as the result. Otherwise, +@scheme[path] is resolved with respect to the complete path +@scheme[base]. If @scheme[base] is not a complete path, the +@exnraise[exn:fail:contract]. + +The @scheme[path] and @scheme[base] arguments can paths for any +platform; if they are for different +platforms, the @exnraise[exn:fail:contract]. + +This procedure does not access the filesystem.} + + +@defproc[(path->directory-path [path path-string?]) path?]{ + +Returns @scheme[path] if @scheme[path] syntactically refers to a +directory and ends in a separator, otherwise it returns an extended +version of @scheme[path] that specifies a directory and ends with a +separator. For example, under @|AllUnix|, the path @file{x/y/} +syntactically refers to a directory and ends in a separator, but +@file{x/y} would be extended to @file{x/y/}, and @file{x/..} would be +extended to @file{x/../}. The @scheme[path] argument can be a path for +any platform, and the result will be for the same platform. + +This procedure does not access the filesystem.} + + +@defproc[(resolve-path [path path-string?]) path?]{ + +@tech{Path-expands} @scheme[path] and returns a path that references +the same file or directory as @scheme[path]. Under @|AllUnix|, if +@scheme[path] is a soft link to another path, then the referenced path +is returned (this may be a relative path with respect to the directory +owning @scheme[path]), otherwise @scheme[path] is returned (after +expansion).} + + +@defproc[(expand-path [path path-string?]) path]{ + +@tech{Path-expands} @scheme[path] (as described at the beginning of +this section). The filesystem might be accessed, but the source or +expanded path might be a non-existent path.} + + +@defproc[(simplify-path [path path-string?][use-filesystem? boolean? #t]) path?]{ + +Eliminates redundant path separators (except for a single trailing +separator), up-directory @litchar{..}, and same-directory @litchar{.} +indicators in @scheme[path], and changes @litchar{/} separators to +@litchar["\\"] separators in Windows paths, such that the result +accesses the same file or directory (if it exists) as @scheme[path]. + +In general, the pathname is normalized as much as possible --- without +consulting the filesystem if @scheme[use-filesystem?] is @scheme[#f], +and (under Windows) without changing the case of letters within the +path. If @scheme[path] syntactically refers to a directory, the +result ends with a directory separator. + +When @scheme[path] is simplified and @scheme[use-filesystem?] is true +(the default), a complete path is returned; if @scheme[path] is +relative, it is resolved with respect to the current directory, and +up-directory indicators are removed taking into account soft links (so +that the resulting path refers to the same directory as before). + +When @scheme[use-filesystem?] is @scheme[#f], up-directory indicators +are removed by deleting a preceding path element, and the result can +be a relative path with up-directory indicators remaining at the +beginning of the path or, for @|AllUnix| paths, after an initial path +element that starts with @litchar{~}; otherwise, up-directory +indicators are dropped when they refer to the parent of a root +directory. Similarly, the result can be the same as +@scheme[(build-path 'same)] (but with a trailing separator) if +eliminating up-directory indicators leaves only same-directory +indicators, and the result can start with a same-directory indicator +for @|AllUnix| paths if eliminating it would make the result start +with a @litchar{~}. + +The @scheme[path] argument can be a path for any platform when +@scheme[use-filesystem?] is @scheme[#f], and the resulting path is for +the same platform. + +The filesystem might be accessed when @scheme[use-filesystem?] is +true, but the source or expanded path might be a non-existent path. If +@scheme[path] cannot be simplified due to a cycle of links, the +@exnraise[exn:fail:filesystem] (but a successfully simplified path may +still involve a cycle of links if the cycle did not inhibit the +simplification). + +See @secref["mz:unixpaths"] for more information on simplifying +@|AllUnix| paths, and see @secref["mz:windowspaths"] for more +information on simplifying Windows paths.} + + +@defproc[(normal-case-path [path path-string?]) path?]{ + +Returns @scheme[path] with ``normalized'' case letters. For @|AllUnix| +paths, this procedure always returns the input path, because +filesystems for these platforms can be case-sensitive. For Windows +paths, if @scheme[path] does not start @litchar["\\\\?\\"], the +resulting string uses only lowercase letters, based on the current +locale. In addition, for Windows paths when the path does not start +@litchar["\\\\?\\"], all @litchar{/}s are converted to +@litchar["\\"]s, and trailing spaces and @litchar{.}s are removed. + +The @scheme[path] argument can be a path for any platform, but beware +that local-sensitive decoding and conversion of the path may be +different on the current platform than for the path's platform. + +This procedure does not access the filesystem.} + + +@defproc[(split-path [path path-string?]) + (values (or/c path? + (one-of/c 'relative #f)) + (or/c path? + (one-of/c 'up 'same)) + boolean?)]{ + +Deconstructs @scheme[path] into a smaller path and an immediate +directory or file name. Three values are returned: + +@itemize{ + + @item{@scheme[base] is either + + @itemize{ + @item{a path,} + @item{@scheme['relative] if @scheme[path] is an immediate relative directory + or filename, or} + @item{@scheme[#f] if @scheme[path] is a root directory.} + }} + + @item{@scheme[name] is either + @itemize{ + @item{a directory-name path,} + @item{a filename,} + @item{@scheme['up] if the last part of @scheme[path] specifies the parent + directory of the preceding path (e.g., @litchar{..} under Unix), or} + @item{@scheme['same] if the last part of @scheme[path] specifies the + same directory as the preceding path (e.g., @litchar{.} under Unix).} + }} + + @item{@scheme[must-be-dir?] is @scheme[#t] if @scheme[path] explicitly + specifies a directory (e.g., with a trailing separator), @scheme[#f] + otherwise. Note that @scheme[must-be-dir?] does not specify whether + @scheme[name] is actually a directory or not, but whether @scheme[path] + syntactically specifies a directory.} + + } + +Compared to @scheme[path], redundant separators (if any) are removed +in the result @scheme[base] and @scheme[name]. If @scheme[base] is +@scheme[#f], then @scheme[name] cannot be @scheme['up] or +@scheme['same]. The @scheme[path] argument can be a path for any +platform, and resulting paths for the same platform. + +This procedure does not access the filesystem. + +See @secref["mz:unixpaths"] for more information on splitting +@|AllUnix| paths, and see @secref["mz:windowspaths"] for more +information on splitting Windows paths.} + + +@defproc[(path-replace-suffix [path path-string?] + [suffix (or/c string? bytes?)]) + path?]{ + +Returns a path that is the same as @scheme[path], except that the +suffix for the last element of the path is changed to +@scheme[suffix]. If the last element of @scheme[path] has no suffix, +then @scheme[suffix] is added to the path. A suffix is defined as a +period followed by any number of non-period characters/bytes at the +end of the path element. The @scheme[path] argument can be a path for +any platform, and the result is for the same platform. If +@scheme[path] represents a root, the @exnraise[exn:fail:contract].} + +@;------------------------------------------------------------------------ +@include-section["unix-paths.scrbl"] +@include-section["windows-paths.scrbl"] diff --git a/collects/scribblings/reference/reader.scrbl b/collects/scribblings/reference/reader.scrbl index 71ac79aac9..7dfab70c47 100644 --- a/collects/scribblings/reference/reader.scrbl +++ b/collects/scribblings/reference/reader.scrbl @@ -727,8 +727,7 @@ the result is a syntax object in @scheme[read] mode, then it is converted to a datum using @scheme[syntax-object->datum]; if the result is not a syntax object in @scheme[read-syntax] mode, then it is converted to one using @scheme[datum->syntax-object]. See also -@secref["special-comments"] and @secref["recursive-reads"] for -information on special-comment results and recursive reads. +@secref["mz:reader-procs"] for information on the procedure's results. If the @scheme[read-accept-reader] @tech{parameter} is set to @scheme[#f], then if the reader encounters @litchar{#reader}, the diff --git a/collects/scribblings/reference/readtables.scrbl b/collects/scribblings/reference/readtables.scrbl index df306007aa..7795217358 100644 --- a/collects/scribblings/reference/readtables.scrbl +++ b/collects/scribblings/reference/readtables.scrbl @@ -2,7 +2,22 @@ @require[(lib "bnf.ss" "scribble")] @require["mz.ss"] -@title[#:tag "mz:readtables"]{Readtables} +@title[#:style 'toc]{Reader Extension} + +Scheme's reader can be extended in three ways: through a reader-macro +procedure in a readtable (see @secref["mz:readtables"]), through a +@litchar{#reader} form (see @secref["mz:parse-reader"]), or through a +custom-port byte reader that returns a ``special'' result procedure +(see @secref["mz:customport"]). All three kinds of @deftech{reader +extension procedures} accept similar arguments, and their results are +treated in the same way by @scheme[read] and @scheme[read-syntax] (or, +more precisely, by the default read handler; see +@scheme[port-read-handler]). + +@local-table-of-contents[] + +@;------------------------------------------------------------------------ +@section[#:tag "mz:readtables"]{Readtables} The dispatch table in @secref["mz:default-readtable-dispatch"] corresponds to the default @deftech{readtable}. By creating a new @@ -119,8 +134,16 @@ multiple non-@scheme['dispatch-macro] mappings are provided for a single @scheme[_char], all but the last one are ignored. A reader macro @scheme[_proc] must accept six arguments, and it can -optionally accept two arguments. See @secref["mz:reader-procs"] for -information on the procedure's arguments and results. +optionally accept two arguments. The first two arguments are always +the character that triggered the reader macro and the input port for +reading. When the reader macro is triggered by @scheme[read-syntax] +(or @scheme[read-syntax/recursive]), the procedure is passed four +additional arguments that represent a source location. When the reader +macro is triggered by @scheme[read] (or @scheme[read/recursive]), the +procedure is passed only two arguments if it accepts two arguments, +otherwise it is passed six arguments where the last four are all +@scheme[#f]. See @secref["mz:reader-procs"] for information on the +procedure's results. A reader macro normally reads characters from the given input port to produce a value to be used as the ``reader macro-expansion'' of the @@ -290,4 +313,74 @@ character and the @scheme[#f] readtable.} #\_ #\space #f)) (parameterize ([current-readtable tuple-readtable+]) (read (open-input-string "< * 1 __,__ 2 __,__ * \"a\" * >"))) -]] \ No newline at end of file +]] + +@;------------------------------------------------------------------------ +@section[#:tag "mz:reader-procs"]{Reader-Extension Procedures} + +Calls to @techlink{reader extension procedures} can be triggered +through @scheme[read], @scheme[read/recursive], @scheme[read-syntax], +or @scheme[read-honu-syntax]. In addition, a special-read procedure +can be triggered by calls to @scheme[read-honu], +@scheme[read-honu/recursive], @scheme[read-honu-syntax], +@scheme[read-honu-syntax/recursive], @scheme[read-char-or-special], or +by the context of @scheme[read-bytes-avail!], +@scheme[read-bytes-avail!*], @scheme[read-bytes-avail!], and +@scheme[peek-bytes-avail!*]. + +Optional arities for reader-macro and special-result procedures allow +them to distinguish reads via @scheme[read], @|etc| from reads via +@scheme[read-syntax], @|etc| (where the source value is @scheme[#f] and +no other location information is available). + +When a reader-extension procedure is called in syntax-reading mode +(via @scheme[read-syntax], @|etc|), it should generally return a syntax +object that has no lexical context (e.g., a syntax object created +using @scheme[datum->syntax-object] with @scheme[#f] as the first +argument and with the given location information as the third +argument). Another possible result is a special-comment value (see +@secref["mz:special-comments"]). If the procedure's result is not a +syntax object and not a special-comment value, it is converted to one +using @scheme[datum->syntax-object]. + +When a reader-extension procedure is called in non-syntax-reading +modes, it should generally not return a syntax object. If a syntax +object is returned, it is converted to a plain value using +@scheme[syntax-object->datum]. + +In either context, when the result from a reader-extension procedure +is a special-comment value (see @secref["mz:special-comments"]), then +@scheme[read], @scheme[read-syntax], @|etc| treat the value as a +delimiting comment and otherwise ignore it. + +Also, in either context, the result may be copied to prevent mutation +to pairs, vectors, or boxes before the read result is completed, and +to support the construction of graphs with cycles. Mutable pairs, +boxes, and vectors are copied, along with any pairs, boxes, or vectors +that lead to such mutable values, to placeholders produced by a +recursive read (see @scheme[read/recursive]), or to references of a +shared value. Graph structure (including cycles) is preserved in the +copy. + +@;------------------------------------------------------------------------ +@section[#:tag "mz:special-comments"]{Special Comments} + +@defproc[(make-special-comment [v any/c]) special-comment?]{ + +Creates a special-comment value that encapsulates @scheme[v]. The +@scheme[read], @scheme[read-syntax], @|etc| procedures treat values +constructed with @scheme[make-special-comment] as delimiting +whitespace when returned by a reader-extension procedure (see +@secref["mz:reader-procs"]).} + +@defproc[(special-comment? [v any/c]) boolean?]{ + +Returns @scheme[#t] if @scheme[v] is the result of +@scheme[make-special-comment], @scheme[#f] otherwise.} + +@defproc[(special-comment-value [sc special-comment?]) any]{ + +Returns the value encapsulated by the special-comment value +@scheme[sc]. This value is never used directly by a reader, but it +might be used by the context of a @scheme[read-char-or-special], @|etc| +call that detects a special comment.} diff --git a/collects/scribblings/reference/unix-paths.scrbl b/collects/scribblings/reference/unix-paths.scrbl new file mode 100644 index 0000000000..196981168c --- /dev/null +++ b/collects/scribblings/reference/unix-paths.scrbl @@ -0,0 +1,60 @@ +#reader(lib "docreader.ss" "scribble") +@require[(lib "bnf.ss" "scribble")] +@require["mz.ss"] + +@title[#:tag "mz:unixpaths"]{@|AllUnix| Paths} + +In @|AllUnix| paths, a @litchar{/} separates elements of the path, +@litchar{.} as a path element always means the directory indicated by +preceding path, and @litchar{..} as a path element always means the +parent of the directory indicated by the preceding path. A path that +starts with a @litchar{~} indicates a user's home directory; the +username follows the @litchar{~} (before a @litchar{/} or the end of +the path), where @litchar{~} by itself indicates the home directory of +the current user. No other character or byte has a special meaning +within a path. Multiple adjacent @litchar{/} are equivalent to a +single @litchar{/} (i.e., they act as a single path separator). + +A path root is either @litchar{/} or a home-directory specification +starting with @litchar{~}. A relative path whose first element starts +with a @litchar{~} is encoded by prefixing the path with @litchar{./}. + +Any pathname that ends with a @litchar{/} syntactically refers to a +directory, as does any path whose last element is @litchar{.} or +@litchar{..}, or any path that contains only a root. + +A @|AllUnix| path is @tech{path-expand}ed by replacing a +home-directory specification (starting with @litchar{~}) with an +absolute path, and by replacing multiple adjacent @litchar{/}s with a +single @litchar{/}. + +For @scheme[(bytes->path-element _bstr)], @scheme[bstr] can start with +a @litchar{~}, and it is encoded as a literal part of the path element +using a @litchar{./} prefix. The @scheme[_bstr] argument must not +contain @litchar{/}, otherwise the @exnraise[exn:fail:contract]. + +For @scheme[(path-element->bytes _path)] or +@scheme[(path-element->string _path)], if the bytes form of +@scheme[_path] starts with @litchar{~/.}, the @litchar{./} prefix is +not included in the result. + +For @scheme[(build-path _base-path _sub-path ...)], when a +@scheme[_sub-path] starts with @litchar{./~}, the @litchar{./} is +removed before adding the path. This conversion is performed because +an initial sequence @litchar{./~} is the canonical way of representing +relative paths whose first element's name starts with @litchar{~}. + +For @scheme[(simplify-path _path _use-filesystem?)], if @scheme[_path] +starts @litchar{./~}, the leading period is the only indicator, and +there are no redundant @litchar{/}s, then @scheme[_path] is returned. + +For @scheme[(split-path _path)] producing @scheme[_base], +@scheme[_name], and @scheme[_must-be-dir?], the result @scheme[name] +can start with @litchar{./~} if the result would otherwise start with +@litchar{~} and it is not the start of @scheme[_path]. Furthermore, if +@scheme[path] starts with @litchar{./~} with any non-zero number of +@litchar{/}s between @litchar{.} and @litchar{~}, then the +@litchar{./} is kept with the following element (i.e., they are not +split separately). + +Under Mac OS X, Finder aliases are zero-length files. diff --git a/collects/scribblings/reference/platform-paths.scrbl b/collects/scribblings/reference/windows-paths.scrbl similarity index 83% rename from collects/scribblings/reference/platform-paths.scrbl rename to collects/scribblings/reference/windows-paths.scrbl index a76a6307ce..5a35ceeb86 100644 --- a/collects/scribblings/reference/platform-paths.scrbl +++ b/collects/scribblings/reference/windows-paths.scrbl @@ -5,66 +5,7 @@ @define[(fileFirst s) (index (list s) (file s))] @define[MzAdd (italic "Scheme-specific:")] -@title{Platform-Specific Path Conventions} - -@section[#:tag "mz:unixpaths"]{@|AllUnix| Paths} - -In @|AllUnix| paths, a @litchar{/} separates elements of the path, -@litchar{.} as a path element always means the directory indicated by -preceding path, and @litchar{..} as a path element always means the -parent of the directory indicated by the preceding path. A path that -starts with a @litchar{~} indicates a user's home directory; the -username follows the @litchar{~} (before a @litchar{/} or the end of -the path), where @litchar{~} by itself indicates the home directory of -the current user. No other character or byte has a special meaning -within a path. Multiple adjacent @litchar{/} are equivalent to a -single @litchar{/} (i.e., they act as a single path separator). - -A path root is either @litchar{/} or a home-directory specification -starting with @litchar{~}. A relative path whose first element starts -with a @litchar{~} is encoded by prefixing the path with @litchar{./}. - -Any pathname that ends with a @litchar{/} syntactically refers to a -directory, as does any path whose last element is @litchar{.} or -@litchar{..}, or any path that contains only a root. - -A @|AllUnix| path is @tech{expanded} by replacing a home-directory -specification (starting with @litchar{~}) with an absolute path, and by -replacing multiple adjacent @litchar{/}s with a single @litchar{/}. - -For @scheme[(bytes->path-element _bstr)], @scheme[bstr] can start with -a @litchar{~}, and it is encoded as a literal part of the path element -using a @litchar{./} prefix. The @scheme[_bstr] argument must not -contain @litchar{/}, otherwise the @exnraise[exn:fail:contract]. - -For @scheme[(path-element->bytes _path)] or -@scheme[(path-element->string _path)], if the bytes form of -@scheme[_path] starts with @litchar{~/.}, the @litchar{./} prefix is -not included in the result. - -For @scheme[(build-path _base-path _sub-path ...)], when a -@scheme[_sub-path] starts with @litchar{./~}, the @litchar{./} is -removed before adding the path. This conversion is performed because -an initial sequence @litchar{./~} is the canonical way of representing -relative paths whose first element's name starts with @litchar{~}. - -For @scheme[(simplify-path _path _use-filesystem?)], if @scheme[_path] -starts @litchar{./~}, the leading period is the only indicator, and -there are no redundant @litchar{/}s, then @scheme[_path] is returned. - -For @scheme[(split-path _path)] producing @scheme[_base], -@scheme[_name], and @scheme[_must-be-dir?], the result @scheme[name] -can start with @litchar{./~} if the result would otherwise start with -@litchar{~} and it is not the start of @scheme[_path]. Furthermore, if -@scheme[path] starts with @litchar{./~} with any non-zero number of -@litchar{/}s between @litchar{.} and @litchar{~}, then the -@litchar{./} is kept with the following element (i.e., they are not -split separately). - -Under Mac OS X, Finder aliases are zero-length files. - -@;------------------------------------------------------------------------ -@section[#:tag "mz:windowspaths"]{Windows Path Conventions} +@title[#:tag "mz:windowspaths"]{Windows Path Conventions} In general, a Windows pathname consists of an optional drive specifier and a drive-specific path. As noted in @secref["mz:filesystem"], a @@ -101,7 +42,6 @@ parameter). Consequently, Scheme implicitly converts a path like } - Otherwise, Scheme follows standard Windows path conventions, but also adds @litchar["\\\\?\\REL"] and @litchar["\\\\?\\RED"] conventions to deal with paths inexpressible in the standard conventsion, plus