doc work, epseciall I/O and OS reference

svn: r6808
This commit is contained in:
Matthew Flatt 2007-07-03 12:41:11 +00:00
parent 4bf593ddc4
commit cec0624357
13 changed files with 1665 additions and 86 deletions

View File

@ -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 "#<procedure:") (decode-content str) (list ">"))))

View File

@ -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*]")])))))

View File

@ -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

View File

@ -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))
]
}

View File

@ -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.}

View File

@ -13,3 +13,4 @@
@include-section["reader.scrbl"]
@include-section["printer.scrbl"]
@include-section["readtables.scrbl"]
@include-section["custom-write.scrbl"]

View File

@ -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.)}

View File

@ -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"]

View File

@ -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"]

View File

@ -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

View File

@ -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\" * >")))
]]
]]
@;------------------------------------------------------------------------
@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.}

View File

@ -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.

View File

@ -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