scsh-0.5/doc/scsh-manual/syscalls.tex

2313 lines
96 KiB
TeX
Raw Normal View History

1995-10-13 23:34:21 -04:00
%&latex -*- latex -*-
\chapter{System Calls}
\label{chapter:syscalls}
Scsh provides (almost) complete access to the basic {\Unix} kernel services:
processes, files, signals and so forth. These procedures comprise a first cut
at a {\Scheme} binding for {\Posix}, with a few extras thrown in (\eg,
symbolic links, \ex{fchown}, \ex{fstat}). A few have been punted for the
current release (tty control, ioctl, and a few others.)
\section{Errors}
Scsh syscalls never return error codes, and do not use a global
\ex{errno} variable to report errors.
Errors are consistently reported by raising exceptions.
This frees up the procedures to return useful values,
and allows the programmer to assume that
\emph{if a syscall returns, it succeeded.}
This greatly simplifies the flow of the code from the programmer's point
of view.
Since {\Scheme} does not yet have a standard exception system, the scsh
definition remains somewhat vague on the actual form of exceptions
and exception handlers. When a standard exception system is defined,
scsh will move to it. For now, scsh uses the {\scm} exception system,
with a simple sugaring on top to hide the details in the common case.
System call error exceptions contain the {\Unix} \ex{errno} code reported by
the system call. Unlike C, the \ex{errno} value is a part of the exception
packet, it is \emph{not} accessed through a global variable.
For reference purposes, the {\Unix} \ex{errno} numbers
are bound to the variables \ex{errno/perm}, \ex{errno/noent}, {\etc}
System calls never return \ex{error/intr}---they
automatically retry. (Currently only true for I/O calls.)
\begin{dfndesc}
{errno-error}{errno syscall .\ data}{\noreturn}{procedure}
Raises a {\Unix} error exception for {\Unix} error number \var{errno}.
The \var{syscall} and \var{data} arguments are packaged up in the exception
packet passed to the exception handler.
\end{dfndesc}
\defunx{with-errno-handler*}{handler thunk}{value(s) of thunk}
\begin{dfndescx}
{with-errno-handler}{handler-spec . body}{\valueofbody}{syntax}
{\Unix} syscalls raise error exceptions by calling \ex{errno-error}.
Programs can use \ex{with-errno-handler*} to establish
handlers for these exceptions.
If a {\Unix} error arises while \var{thunk} is executing,
\var{handler} is called on two arguments:
\codex{(\var{handler} \var{errno} \var{packet})}
\var{packet} is a list of the form
$$\var{packet} = \ex{(\var{errno-msg} \var{syscall} . \var{data})},$$
where \var{errno-msg} is the standard {\Unix} error message for the error,
\var{syscall} is the procedure that generated the error,
and \var{data} is a list of information generated by the error,
which varies from syscall to syscall.
If \var{handler} returns, the handler search continues upwards.
\var{Handler} can acquire the exception by invoking a saved continuation.
This procedure can be sugared over with the following syntax:
%
\begin{code}
(with-errno-handler
((\var{errno} \var{packet}) \var{clause} \ldots)
\var{body1}
\var{body2}
\ldots)\end{code}
%
This form executes the body forms with a particular errno handler installed.
When an errno error is raised, the handler search machinery will
bind variable \var{errno} to the error's integer code, and variable
\var{packet} to the error's auxiliary data packet.
Then, the clauses will be checked for a match.
The first clause that matches is executed, and its value is the
value of the entire \ex{with-errno-handler} form.
If no clause matches, the handler search continues.
Error clauses have two forms
%
\begin{code}
((\var{errno} \ldots) \var{body} \ldots)
(else \var{body} \ldots)\end{code}
%
In the first type of clause, the \var{errno} forms are integer expressions.
They are evaluated and compared to the error's errno value.
An \ex{else} clause matches any errno value.
Note that the \var{errno} and \var{data}
variables are lexically visible to the error clauses.
Example:
\begin{code}
(with-errno-handler
((errno packet) ; Only handle 3 particular errors.
((errno/wouldblock errno/again)
(loop))
((errno/acces)
(format #t "Not allowed access!")
#f))
(foo frobbotz)
(blatz garglemumph))\end{code}
%
It is not defined what dynamic context the handler executes in,
so fluid variables cannot reliably be referenced.
Note that Scsh system calls always retry when interrupted, so that
the \ex{errno/intr} exception is never raised.
If the programmer wishes to abort a system call on an interrupt, he
should have the interrupt handler explicitly raise an exception or
invoke a stored continuation to throw out of the system call.
\remark{This is not strictly true in the current implementation---only
some of the i/o syscalls loop.
But BSD variants never return \ex{EINTR} anyway, unless you explicitly
request it, so we'll live w/it for now.}
\end{dfndescx}
\subsection{Interactive mode and error handling}
Scsh runs in two modes: interactive and script mode. It starts up in
interactive mode if the scsh interpreter is started up with no script
argument. Otherwise, scsh starts up in script mode. The mode determines
whether scsh prints prompts in between reading and evaluating forms, and it
affects the default error handler. In interactive mode, the default error
handler will report the error, and generate an interactive breakpoint so that
the user can interact with the system to examine, fix, or dismiss from the
error. In script mode, the default error handler causes the scsh process to
exit.
When scsh forks a child with \ex{(fork)}, the child resets to script mode.
This can be overridden if the programmer wishes.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{I/O}
\subsection{Standard {\R4RS} I/O procedures}
In scsh, most standard {\R4RS} i/o operations (such as \ex{display} or
\ex{read-char}) work on both integer file descriptors and {\Scheme} ports.
When doing i/o with a file descriptor, the i/o operation is done
directly on the file, bypassing any buffered data that may have
accumulated in an associated port.
Note that character-at-a-time operations
(\eg, \ex{read-char} and \ex{read-line})
are likely to be quite slow when performed directly upon file
descriptors.
The standard {\R4RS} procedures \ex{read-char}, \ex{char-ready?}, \ex{write},
\ex{display}, \ex{newline},
and \ex{write-char} are all generic, accepting integer file descriptor
arguments as well as ports.
Scsh also mandates the availability of \ex{format}, and further requires
\ex{format} to accept file descriptor arguments as well as ports.
The procedures \ex{peek-char} and \ex{read} do \emph{not} accept
file descriptor arguments, since these functions require the ability to
read ahead in the input stream, a feature not supported by {\Unix} I/O.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Port manipulation and standard ports}
\defun {close-after} {port consumer} {value(s) of consumer}
\begin{desc}
Returns \ex{(\var{consumer} \var{port})}, but closes the port on return.
No dynamic-wind magic. \remark{Is there a less-awkward name?}
\end{desc}
\defun {error-output-port}{} {port}
\begin{desc}
This procedure is analogous to \ex{current-output-port}, but produces
a port used for error messages---the scsh equivalent of stderr.
\end{desc}
\defun {with-current-input-port*} {port thunk} {value(s) of thunk}
\defunx {with-current-output-port*} {port thunk} {value(s) of thunk}
\defunx {with-error-output-port*} {port thunk} {value(s) of thunk}
\begin{desc}
These procedures install \var{port} as the current input, current output,
and error output port, respectively, for the duration of a call to
\var{thunk}.
\end{desc}
\dfn {with-current-input-port} {port . body} {value(s) of body} {syntax}
\dfnx {with-current-output-port} {port . body} {value(s) of body} {syntax}
\dfnx {with-error-output-port} {port . body} {value(s) of body} {syntax}
\begin{desc}
These special forms are simply syntactic sugar for the
{\ttt with\=current\=input\=port*} procedure and friends.
\end{desc}
\defun {close} {port/fd} {\undefined}
\begin{desc}
Close the port or file descriptor.
If \var{port/fd} is a file descriptor, and it has a port allocated to it,
the port is shifted to a new file descriptor created with \ex{(dup
port/fd)} before closing \ex{port/fd}. The port then has its revealed
count set to zero. This reflects the design criteria that ports are not
associated with file descriptors, but with open files.
To close a file descriptor, and any associated port it might have, you
must instead say one of (as appropriate):
\begin{code}
(close (fdes->inport fd))
(close (fdes->outport fd))\end{code}
\end{desc}
\defun {stdports->stdio}{} {\undefined}
\defunx {stdio->stdports} {thunk} {value(s) of thunk}
\begin{desc}
\ex{(stdports->stdio)} is exactly equivalent to the series of
redirections:\footnote{Why not \ex{move->fdes}?
Because the current output port and error port
might be the same port.}
\begin{code}
(dup (current-input-port) 0)
(dup (current-output-port) 1)
(dup (error-output-port) 2)\end{code}
%
\ex{stdio->stdports} binds the standard ports \ex{(current-input-port)},
\ex{(current-output-port)}, and \ex{(error-output-port)} to be ports
on file descriptors 0, 1, 2, and then calls \var{thunk}.
It is equivalent to:
\begin{code}
(with-current-input-port (fdes->inport 0)
(with-current-output-port (fdes->inport 1)
(with-error-output-port (fdes->outport 2)
(thunk))))\end{code}
\end{desc}
\subsection{String ports}
{\scm} has string ports, which you can use. Scsh has not committed to the
particular interface or names that {\scm} uses, so be warned that the
interface described herein may be liable to change.
\defun {make-string-input-port} {string} {\port}
\begin{desc}
Returns a port that reads characters from the supplied string.
\end{desc}
\defun {make-string-output-port} {} {\port}
\defunx {string-output-port-output} {port} {\port}
\begin{desc}
A string output port is a port collects the characters given to it into
a string.
The accumulated string is retrieved by applying \ex{string-output-port-output}
to the port.
\end{desc}
\defun {call-with-string-output-port} {procedure} {\str}
\begin{desc}
The procedure is called on a port. When it returns,
\ex{call-with-string-output-port} returns a string containing the
characters written to the port.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Revealed ports and file descriptors}
The material in this section and the following one is not critical for most
applications.
You may safely skim or completely skip this section on a first reading.
Dealing with {\Unix} file descriptors in a {\Scheme} environment is difficult.
In {\Unix}, open files are part of the process environment, and are referenced
by small integers called \emph{file descriptors}. Open file descriptors are
the fundamental way i/o redirections are passed to subprocesses, since
file descriptors are preserved across fork's and exec's.
{\Scheme}, on the other hand, uses ports for specifying i/o sources. Ports are
garbage-collected {\Scheme} objects, not integers. Ports can be garbage
collected; when a port is collected, it is also closed. Because file
descriptors are just integers, it's impossible to garbage collect them---you
wouldn't be able to close file descriptor 3 unless there were no 3's in the
system, and you could further prove that your program would never again
compute a 3. This is difficult at best.
If a {\Scheme} program only used {\Scheme} ports, and never actually used
file descriptors, this would not be a problem. But {\Scheme} code
must descend to the file descriptor level in at least two circumstances:
%
\begin{itemize}
\item when interfacing to foreign code
\item when interfacing to a subprocess.
\end{itemize}
%
This causes a problem. Suppose we have a {\Scheme} port constructed
on top of file descriptor 2. We intend to fork off a program that
will inherit this file descriptor. If we drop references to the port,
the garbage collector may prematurely close file 2 before we fork
the subprocess. The interface described below is intended to fix this and
other problems arising from the mismatch between ports and file descriptors.
The {\Scheme} kernel maintains a port table that maps a file descriptor
to the {\Scheme} port allocated for it (or, {\sharpf} if there is no port
allocated for this file descriptor). This is used to ensure that
there is at most one open port for each open file descriptor.
The port data structure for file ports has two fields besides the descriptor:
revealed and closed?. When a file port is closed with \ex{(close port)}, the
port's file descriptor is closed, its entry in the port table is cleared, and
the port's closed? field is set to true.
When a file descriptor is closed with \ex{(close fdes)}, any associated
port is shifted to a new file descriptor created with \ex{(dup fdes)}.
The port has its revealed count reset to zero. See discussion below.
To really put a stake through a descriptor's heart, you must say one of
%
\begin{code}
(close (fdes->inport fdes))
(close (fdes->output fdes))\end{code}
The revealed field is an aid to garbage collection. It is an integer
semaphore. If it is zero, the port's file descriptor can be closed when
the port is collected. Essentially, the revealed field reflects whether
or not the port's file descriptor has escaped to the {\Scheme} user. If
the {\Scheme} user doesn't know what file descriptor is associated with
a given port, then he can't possibly retain an ``integer handle'' on the
port after dropping pointers to the port itself, so the garbage collector
is free to close the file.
Ports allocated with \ex{open-output-file} and \ex{open-input-file} are
unrevealed ports---\ie, revealed is initialised to 0. No one knows the port's
file descriptor, so the file descriptor can be closed when the port is
collected.
The functions \ex{fdes->output-port}, \ex{fdes->input-port}, \ex{port->fdes}
are used to shift back and forth between file descriptors and ports. When
\ex{port->fdes} reveals a port's file descriptor, it increments the port's
revealed field. When the user is through with the file descriptor, he can
call \ex{(release-port-handle port)}, which decrements the count. The function
\ex{(call/fdes fdes/port proc)} automates this protocol. \ex{call/fdes} uses
\ex{dynamic-wind} to enforce the protocol. If \ex{proc} throws out of the
\ex{call/fdes}, unwind handler releases the descriptor handle; if the user
subsequently tries to throw \emph{back} into \ex{proc}'s context, the wind handler
raises an error. When the user maps a file descriptor to a port with
\ex{fdes->outport} or \ex{fdes->inport}, the port has its revealed field
incremented.
Not all file descriptors are created by requests to make ports. Some are
inherited on process invocation via \ex{exec(2)}, and are simply part of the
global environment. Subprocesses may depend upon them, so if a port is later
allocated for these file descriptors, is should be considered as a revealed
port. For example, when the {\Scheme} shell's process starts up, it opens ports
on file descriptors 0, 1, and 2 for the initial values of
\ex{(current-input-port)}, \ex{(current-output-port)}, and
\ex{(error-output-port)}. These ports are initialised with revealed set to 1,
so that stdin, stdout, and stderr are not closed even if the user drops the
port. A fine point: the stdin file descriptor is allocated an unbuffered
port. Because shells frequently share stdin with subprocesses, if the shell
does buffered reads, it might ``steal'' input intended for a subprocess. For
this reason, all shells, including sh, csh, and scsh, read stdin unbuffered.
Responsibility for deciding which other files must be opened unbuffered rests
with the shell programmer.
Unrevealed file ports have the nice property that they can be closed when all
pointers to the port are dropped. This can happen during gc, or at an
\ex{exec()}---since all memory is dropped at an \ex{exec()}. No one knows the
file descriptor associated with the port, so the exec'd process certainly
can't refer to it.
This facility preserves the transparent close-on-collect property
for file ports that are used in straightforward ways, yet allows
access to the underlying {\Unix} substrate without interference from
the garbage collector. This is critical, since shell programming
absolutely requires access to the {\Unix} file descriptors, as their
numerical values are a critical part of the process interface.
A port's underlying file descriptor can be shifted around with \ex{dup(2)} when
convenient. That is, the actual fd on top of which a port is constructed can be
shifted around underneath the port by the scsh kernel when necessary. This is
important, because when the user is setting up file descriptors prior to a
\ex{exec(2)}, he may explicitly use a file descriptor that has already been
allocated to some port. In this case, the scsh kernel just shifts the port's
file descriptor to some new location with \ex{dup}, freeing up its old
descriptor. This prevents errors from happening in the following scenario.
Suppose we have a file open on port \ex{f}. Now we want to run a program that
reads input on file 0, writes output to file 1, errors to file 2, and logs
execution information on file 3. We want to run this program with input from
\ex{f}. So we write:
%
\begin{code}
(run (/usr/shivers/bin/prog)
(> 1 output.txt)
(> 2 error.log)
(> 3 trace.log)
(= 0 ,f))\end{code}
%
Now, suppose by ill chance that, unbeknownst to us, when the operating system
opened \ex{f}'s file, it allocated descriptor 3 for it. If we blindly redirect
\ex{trace.log} into file descriptor 3, we'll clobber \ex{f}! However, the
port-shuffling machinery saves us: when the \ex{run} form tries to dup
\ex{trace.log}'s file descriptor to 3, \ex{dup} will notice that file
descriptor 3 is already associated with an unrevealed port (\ie, \ex{f}). So,
it will first move \ex{f} to some other file descriptor. This keeps \ex{f}
alive and well so that it can subsequently be dup'd into descriptor 0 for
\ex{prog}'s stdin.
The port-shifting machinery makes the following guarantee: a port is only
moved when the underlying file descriptor is closed, either by a \ex{close()}
or a \ex{dup2()} operation. Otherwise a port/file-descriptor association is
stable.
Under normal circumstances, all this machinery just works behind the scenes to
keep things straightened out. The only time the user has to think about it is
when he starts accessing file descriptors from ports, which he should almost
never have to do. If a user starts asking what file descriptors have been
allocated to what ports, he has to take responsibility for managing this
information.
\subsection{Port-mapping machinery}
The procedures provided in this section are almost never needed.
You may safely skim or completely skip this section on a first reading.
Here are the routines for manipulating ports in scsh. The important
points to remember are:
\begin{itemize}
\item A file port is associated with an open file, not a particular file
descriptor.
\item The association between a file port and a particular file descriptor
is never changed \emph{except} when the file descriptor is explicitly
closed. ``Closing'' includes being used as the target of a \ex{dup2}, so
the set of procedures below that close their targets are
\ex{close}, two-argument \ex{dup}, and \ex{move->fdes}.
If the target file descriptor of one of these routines has an
allocated port, the port will be shifted to another freshly-allocated
file descriptor, and marked as unrevealed, thus preserving the port
but freeing its old file descriptor.
\end{itemize}
These rules are what is necessary to ``make things work out'' with no
surprises in the general case.
\defun {fdes->inport} {fd} {port}
\defunx {fdes->outport} {fd} {port}
\defunx {port->fdes} {port} {\fixnum}
\begin{desc}
These increment the port's revealed count.
\end{desc}
\defun {port-revealed} {port} {{\integer} or \sharpf}
\begin{desc}
Return the port's revealed count if positive, otherwise \sharpf.
\end{desc}
\defun{release-port-handle} {port} {\undefined}
\begin{desc}
Decrement the port's revealed count.
\end{desc}
\defun {call/fdes} {fd/port consumer} {value(s) of consumer}
\begin{desc}
Calls \var{consumer} on a file descriptor;
takes care of revealed bookkeeping.
If \var{fd/port} is a file descriptor, this is just
\ex{(\var{consumer} \var{fd/port})}.
If \var{fd/port} is a port,
calls \var{consumer} on its underlying file descriptor.
While \var{consumer} is running, the port's revealed count is incremented.
When \ex{call/fdes} is called with port argument, you are not allowed to
throw into \var{consumer} with a stored continuation, as that would violate
the revealed-count bookkeeping.
\end{desc}
\defun{move->fdes} {fd/port target-fd} {port or fdes}
\begin{desc}
Maps fd$\rightarrow$fd and port$\rightarrow$port.
If \var{fd/port} is a file-descriptor not equal to \var{target-fd},
dup it to \var{target-fd} and close it. Returns \var{target-fd}.
If \var{fd/port} is a port, it is shifted to \var{target-fd},
by duping its underlying file-descriptor if necessary.
\var{Fd/port}'s original file descriptor is
closed (if it was different from \var{target-fd}).
Returns the port.
This operation resets \var{fd/port}'s revealed count to 1.
In all cases when \var{fd/port} is actually shifted, if there is a port
already using \var{target-fd}, it is first relocated to some other file
descriptor.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{{\Unix} I/O}
\defun {dup} {port/fd [newfd]} {port/fd}
\defunx{dup->inport} {port/fd [newfd]} {port}
\defunx{dup->outport} {port/fd [newfd]} {port}
\defunx{dup->fdes} {port/fd [newfd]} {fd}
\begin{desc}
These procedures subsume the functionality of C's \ex{dup()} and \ex{dup2()}.
The different routines return different types of values:
\ex{dup->inport}, \ex{dup->outport}, and \ex{dup->fdes} return
input ports, output ports, and integer file descriptors, respectively.
\ex{dup}'s return value depends on on the type of
\var{port/fd}---it maps fd$\rightarrow$fd and port$\rightarrow$port.
These procedures use the {\Unix} \ex{dup()} syscall to replicate
the file descriptor or file port \var{port/fd}.
If a \var{newfd} file descriptor is given, it is used as the target of
the dup operation, \ie, the operation is a \ex{dup2()}.
In this case, procedures that return a port (such as \ex{dup->inport})
will return one with the revealed count set to one.
For example, \ex{(dup (current-input-port) 5)} produces
a new port with underlying file descriptor 5, whose revealed count is 1.
If \var{newfd} is not specified,
then the operating system chooses the file descriptor,
and any returned port is marked as unrevealed.
If the \var{newfd} target is given,
and some port is already using that file descriptor,
the port is first quietly shifted (with another \ex{dup})
to some other file descriptor (zeroing its revealed count).
Since {\Scheme} doesn't provide read/write ports,
\ex{dup->inport} and \ex{dup->outport} can be useful for
getting an output version of an input port, or \emph{vice versa}.
For example, if \ex{p} is an input port open on a tty, and
we would like to do output to that tty, we can simply use
\ex{(dup->outport p)} to produce an equivalent output port for the tty.
\end{desc}
\begin{defundesc} {file-seek} {fd/port offset whence} {\undefined}
\var{whence} is one of \{\ex{seek/set}, \ex{seek/delta}, \ex{seek/end}\}.
\oops{The current implementation doesn't handle \var{offset} arguments
that are not immediate integers (\ie, representable in 30 bits).}
\end{defundesc}
\begin{defundesc} {open-file} {fname flags [perms]} {\port}
\var{Perms} defaults to \cd{#o666}.
\var{Flags} is an integer bitmask, composed by or'ing together the following
constants:
\begin{code}\codeallowbreaks
open/read ; You may only
open/write ; choose one
open/read+write ; of these three
open/no-control-tty
open/nonblocking
open/append
open/create
open/truncate
open/exclusive
. ; Your Unix may have
. ; a few more.\end{code}
%
Returns a port. The port is an input port if the \ex{flags} permit it,
otherwise an output port. \R4RS/\scm/scsh do not have input/output ports,
so it's one or the other. This should be fixed. (You can hack simultaneous
i/o on a file by opening it r/w, taking the result input port,
and duping it to an output port with \ex{dup->outport}.)
\end{defundesc}
\defun{open-input-file}{fname [flags]}\port
\begin{defundescx}{open-output-file}{fname [flags perms]}\port
These are equivalent to \ex{open-file}, after first setting the
read/write bits of the \var{flags} argument to \ex{open/read} or
\ex{open/write}, respectively.
\var{Flags} defaults to zero for \ex{open-input-file},
and
\codex{(bitwise-ior open/create open/truncate)}
for \ex{open-output-file}.
These defaults make the procedures backwards-compatible with their
unary {\R4RS} definitions.
\end{defundescx}
\begin{defundesc} {open-fdes} {fname flags [perms]} \integer
Returns a file descriptor.
\end{defundesc}
\begin{defundesc}{pipe}{} {[\var{rport} \var{wport}]}
Returns two ports, the read and write end-points of a {\Unix} pipe.
\end{defundesc}
\begin{defundesc} {read-line} {[fd/port retain-newline?]} {{\str} or eof-object}
Reads and returns one line of text; on eof, returns the eof object.
A line is terminated by newline or eof.
\var{retain-newline?}\
defaults to {\sharpf}; if true, a terminating newline is included in the
result string, otherwise it is trimmed.
Using this argument allows one to tell whether or not the last line of
input in a file is newline terminated.
\end{defundesc}
\defun{read-string}{nbytes [fd/port]} {{\str} or \sharpf}
\begin{defundescx}
{read-string!} {str [fd/port start end]} {nread or \sharpf}
These calls read exactly as much data as you requested, unless
there is not enough data (eof).
\ex{read-string!} reads the data into string \var{str}
at the indices in the half-open interval $[\var{start},\var{end})$;
the default interval is the whole string: $\var{start}=0$ and
$\var{end}=\ex{(string-length \var{string})}$.
They will persistently retry on partial reads and when interrupted
until (1) error, (2) eof, or (3) the input request is completely
satisfied.
Partial reads can occur when reading from an intermittent source,
such as a pipe or tty.
\ex{read-string} returns the string read; \ex{read-string!} returns
the number of characters read. They both return false at eof.
A request to read zero bytes returns immediately, with no eof check.
The values of \var{start} and \var{end} must specify a well-defined
interval in \var{str},
\ie, $0 \le \var{start} \le \var{end} \le \ex{(string-length \var{str})}$.
Any partially-read data is included in the error exception packet.
Error returns on non-blocking input are considered an error.
\end{defundescx}
\defun {read-string/partial} {nbytes [fd/port]} {{\str} or \sharpf}
\begin{defundescx}
{read-string!/partial} {str [fd/port start end]} {nread or \sharpf}
%
These are atomic best-effort/forward-progress calls.
Best effort: they may read less than you request if there is a
lesser amount of data immediately available (\eg, because you
are reading from a pipe or a tty).
Forward progress: if no data is immediately available
(\eg, empty pipe), they will block.
Therefore, if you request an $n>0$ byte read,
while you may not get everything you asked for, you will always get something
(barring eof).
There is one case in which the forward-progress guarantee is cancelled:
when the programmer explicitly sets the port to non-blocking i/o.
In this case, if no data is immediately available,
the procedure will not block, but will immediately return a zero-byte read.
\ex{read-string/partial} reads the data into a freshly allocated string,
which it returns as its value.
\ex{read-string!/partial} reads the data into string \var{str}
at the indices in the half-open interval $[\var{start},\var{end})$;
the default interval is the whole string: $\var{start}=0$ and
$\var{end}=\ex{(string-length \var{string})}$.
The values of \var{start} and \var{end} must specify a well-defined
interval in \var{str},
\ie, $0 \le \var{start} \le \var{end} \le \ex{(string-length \var{str})}$.
It returns the number of bytes read.
A request to read zero bytes returns immediatedly, with no eof check.
In sum, there are only three ways you can get a zero-byte read:
(1) you request one, (2) you turn on non-blocking i/o, or (3) you
try to read at eof.
These are the routines to use for non-blocking input.
They are also useful when you wish to efficiently process data
in large blocks, and your algorithm is insensitive to the block size
of any particular read operation.
\end{defundescx}
\begin{defundesc}
{select}{readfds writefds exceptfds timeout}{rfds wfds efds}
%
\remark{Unimplemented. Should we implement a set-of abstraction first,
Or just use a twos-complement bitvector encoding with bignums?}
\end{defundesc}
\begin{defundescx}{write-string}{string [fd/port start end]}\undefined
This procedure writes all the data requested.
If the procedure cannot perform the write with a single kernel call
(due to interrupts or partial writes),
it will perform multiple write operations until all the data is written
or an error has occurred.
A non-blocking i/o error is considered an error.
(Error exception packets for this syscall include the amount of
data partially transferred before the error occurred.)
The data written are the characters of \var{string} in the half-open
interval $[\var{start},\var{end})$.
The default interval is the whole string: $\var{start}=0$ and
$\var{end}=\ex{(string-length \var{string})}$.
The values of \var{start} and \var{end} must specify a well-defined
interval in \var{str},
\ie, $0 \le \var{start} \le \var{end} \le \ex{(string-length \var{str})}$.
A zero-byte write returns immediately, with no error.
Output to buffered ports: \ex{write-string}'s efforts end as soon
as all the data has been placed in the output buffer.
Errors and true output may not happen until a later time, of course.
\end{defundescx}
\begin{defundescx}{write-string/partial}{string [fd/port start end]}{nwritten}
This routine is the atomic best-effort/forward-progress analog
to \ex{write-string}.
It returns the number of bytes written, which may be less than you
asked for.
Partial writes can occur when (1) we write off the physical end of
the media, (2) the write is interrrupted, or (3) the file descriptor
is set for non-blocking i/o.
If the file descriptor is not set up for non-blocking i/o, then
a successful return from these procedures makes a forward progress
guarantee---that is, a partial write took place of at least one byte:
\begin{itemize}
\item If we are at the end of physical media, and no write takes place,
an error exception is raised.
So a return implies we wrote \emph{something}.
\item If the call is interrupted after a partial transfer, it returns
immediately. But if the call is interrupted before any data transfer,
then the write is retried.
\end{itemize}
If we request a zero-byte write, then the call immediately returns 0.
If the file descriptor is set for non-blocking i/o, then the call
may return 0 if it was unable to immediately write anything
(\eg, full pipe).
Barring these two cases, a write either returns $\var{nwritten} > 0$,
or raises an error exception.
Non-blocking i/o is only available on file descriptors and unbuffered
ports. Doing non-blocking i/o to a buffered port is not well-defined,
and is an error (the problem is the subsequent flush operation).
\end{defundescx}
\begin{defundesc}{force-output} {[fd/port]}{\noreturn}
This procedure does nothing when applied to an integer file descriptor
or unbuffered port.
It flushes buffered output when applied to a buffered port,
and raises a write-error exception on error. Returns no value.
\end{defundesc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{File system}
Besides the following procedures, which allow access to the
computer's file system, scsh also provides a set of procedures
which manipulate file \emph{names}. These string-processing
procedures are documented in section \ref{sec:filenames}.
\defun {create-directory} {fname [perms override?]} {\undefined}
\defunx{create-fifo} {fname [perms override?]} {\undefined}
\defunx{create-hard-link} {oldname newname [override?]} {\undefined}
\begin{defundescx}
{create-symlink} {old-name new-name [override?]} {\undefined}
These procedures create objects of various kinds in the file system.
The \var{override?} argument controls the action if there is already an
object in the file system with the new name:
\begin{optiontable}
\sharpf & signal an error (default) \\
'query & prompt the user \\
\textnormal{\emph{other}}& \parbox[t]{0.7\linewidth}{
delete the old object (with \ex{delete-file}
or \ex{delete-directory,} as appropriate) before
creating the new object.}
\end{optiontable}
\var{Perms} defaults to \cd{#o777} (but is masked by the current umask).
\remark{Currently, if you try to create a hard or symbolic link from a
file to itself, you will error out with \var{override?} false, and simply
delete your file with \var{override?} true. Catching this will require
some sort of true-name procedure, which I currently do not have.}
\end{defundescx}
\defun {delete-directory} {fname} \undefined
\defunx{delete-file} {fname} \undefined
\begin{defundescx} {delete-filesys-object} {fname} \undefined
These procedures delete objects from the file system.
The {\ttt delete\=filesys\=object} procedure will delete an object
of any type from the file system: files, (empty) directories, symlinks, fifos,
\etc.
\end{defundescx}
\begin{defundescx}{read-symlink}{fname} \str
Return the filename referenced by symbolic link \ex{fname}.
\end{defundescx}
\begin{defundescx} {rename-file} {old-fname new-fname [override?]} \undefined
If you override an existing object, then \var{old-fname}
and \var{new-fname} must type-match---either both directories,
or both non-directories.
This is required by the semantics of {\Unix} \ex{rename()}.
\remark{
There is an unfortunate atomicity problem with the \ex{rename-file}
procedure: if you
specify no-override, but create file \ex{new-fname} sometime between
\ex{rename-file}'s existence check and the actual rename operation,
your file will be clobbered with \ex{old-fname}. There is no way to fix
this problem, given the semantics of {\Unix} \ex{rename()};
at least it is highly unlikely to occur in practice.
}
\end{defundescx}
\defun {set-file-mode} {fname/fd/port mode} \undefined
\defunx{set-file-owner} {fname/fd/port uid} {\undefined}
\defunx{set-file-group} {fname/fd/port gid} {\undefined}
\begin{desc}
These procedures set the permission bits, owner id, and group id of a
file, respectively.
The file can be specified by giving the file name, or either an
integer file descriptor or a port open on the file.
Setting file user or group ownership usually requires root privileges.
\end{desc}
\defun {sync-file} {fd/port} \undefined
\defunx{sync-file-system}{} \undefined
\begin{desc}
Calling \ex{sync-file}
causes {\Unix} to update the disk data structures for a given file.
If \var{fd/port} is a port, any buffered data it may have is first
flushed.
Calling \ex{sync-file-system} synchronises the kernel's entire file
system with the disk.
These procedures are not {\Posix}.
Interestingly enough, \ex{sync\=file\=system} doesn't actually
do what it is claimed to do. We just threw it in for humor value.
See the \ex{sync(2)} man page for {\Unix} enlightenment.
\end{desc}
\begin{defundesc} {truncate-file} {fname/fd/port len} \undefined
The specified file is truncated to \var{len} bytes in length.
\end{defundesc}
\begin{defundesc}{file-attributes} {fname/fd/port [chase?]} {file-info-record}
The \ex{file-attributes} procedure
returns a record structure containing everything
there is to know about a file. If the \var{chase?} flag is true
(the default), then the procedure chases symlinks and reports on
the files to which they refer. If \var{chase?} is false, then
the procedure checks the actual file itself, even if it's a symlink.
The \var{chase?} flag is ignored if the file argument is a file descriptor
or port.
The value returned is a \emph{file-info record}, defined to have the
following structure:
\begin{code}
(define-record file-info
type ; \{block-special, char-special, directory,
; fifo, regular, socket, symlink\}
device ; Device file resides on.
inode ; File's inode.
mode ; File's mode bits: permissions, setuid, setgid
nlinks ; Number of hard links to this file.
uid ; Owner of file.
gid ; File's group id.
size ; Size of file, in bytes.
atime ; Last access time.
mtime ; Last status-change time.
ctime) ; Creation time.\end{code}
\index{file-info}
\index{file-info:type}\index{file-info:device}\index{file-info:inode}%
\index{file-info:mode}\index{file-info:nlinks}\index{file-info:uid}%
\index{file-info:gid}\index{file-info:size}\index{file-info:atime}%
\index{file-info:mtime}\index{file-info:ctime}%
%
The uid field of a file-info record is accessed with the procedure
\codex{(file-info:uid x)}
and similarly for the other fields.
The \ex{type} field is a symbol; all other fields are integers.
A file-info record is discriminated with the \ex{file-info?} predicate.
The following procedures all return selected information about
a file; they are built on top of \ex{file-attributes}, and are
called with the same arguments that are passed to it.
\begin{inset}
\newcommand{\Ex}[1]{\ex{#1}\index{\tt{#1}}}
\begin{tabular}{ll}
Procedure & returns \\\hline
\Ex{file-type} & type \\
\Ex{file-inode} & inode \\
\Ex{file-mode} & mode \\
\Ex{file-nlinks} & nlinks \\
\Ex{file-owner} & uid \\
\Ex{file-group} & gid \\
\Ex{file-size} & size \\
\Ex{file-last-access} & atime \\
\Ex{file-last-mod} & mtime \\
\Ex{file-last-status-change} & ctime
\end{tabular}
\end{inset}
%
Example:
\begin{code}
;; All my files in /usr/tmp:
(filter (\l{f} (= (file-owner f) (user-uid)))
(directory-files "/usr/tmp")))\end{code}
\end{defundesc}
\defun {file-directory?}{fname/fd/port [chase?]}{\boolean}
\defunx {file-fifo?}{fname/fd/port [chase?]}{\boolean}
\defunx {file-regular?}{fname/fd/port [chase?]}{\boolean}
\defunx {file-socket?}{fname/fd/port [chase?]}{\boolean}
\defunx {file-special?}{fname/fd/port [chase?]}{\boolean}
\defunx {file-symlink?}{fname/fd/port}{\boolean}
\begin{desc}
These procedures are file-type predicates that test the
type of a given file.
The are applied to the same arguments to which \ex{file-attributes} is applied;
the sole exception is \ex{file-symlink?}, which does not take
the optional \var{chase?} second argument.
\begin{inset}
\newcommand{\Ex}[1]{\ex{#1}\index{\tt{#1}}}
\begin{tabular}{l@{\qquad}l}
\end{tabular}
\end{inset}
For example,
\codex{(file-directory? "/usr/dalbertz")\qquad\evalto\qquad\sharpt}
\end{desc}
\defun {file-not-readable?} {fname} \boolean
\defunx{file-not-writeable?} {fname} \boolean
\defunx{file-not-executable?} {fname} \boolean
\begin{desc}
Returns:
\begin{optiontable}
\textnormal{Value} & meaning \\ \hline
\sharpf & Access permitted \\
'search-denied & {\renewcommand{\arraystretch}{1}%
\begin{tabular}[t]{@{}l@{}}
Can't stat---a protected directory \\
is blocking access.\end{tabular}} \\
'permission & Permission denied. \\
'no-directory & Some directory doesn't exist. \\
'nonexistent & File doesn't exist.
\end{optiontable}
%
A file is considered writeable if either (1) it exists and is writeable
or (2) it doesn't exist and the directory is writeable.
Since symlink permission bits are ignored by the filesystem, these
calls do not take a \var{chase?} flag.
\oops{\ex{file-not-writeable?} does not currently do the directory
check.}
\end{desc}
\defun {file-readable?} {fname} \boolean
\defunx {file-writable?} {fname} \boolean
\defunx {file-executable?} {fname} \boolean
\begin{desc}
These procedures are the logical negation of the
preceding \ex{file-not-\ldots?} procedures.
\end{desc}
\begin{defundesc}{file-not-exists?} {fname [chase?]} \object
Returns:
\begin{optiontable}
\sharpf & Exists. \\
\sharpt & Doesn't exist. \\
'search-denied & \parbox[t]{0.5\linewidth}{\sloppy\raggedright
Some protected directory
is blocking the search.}
\end{optiontable}
\end{defundesc}
\begin{defundesc}{file-exists?} {fname [chase?]} \boolean
This is simply
\ex{(not (file-not-exists? \var{fname} \var{[chase?]}))}
\end{defundesc}
\defun {directory-files} {[dir dotfiles?]} {string list}
\begin{desc}
Return the list of files in directory \var{dir},
which defaults to the current working directory.
The \var{dotfiles?} flag (default {\sharpf}) causes dot files to be
included in the list.
Regardless of the value of \var{dotfiles?}, the two files \ex{.} and
\ex{..} are \emph{never} returned.
The directory \var{dir} is not prepended to each file name in the
result list. That is,
\codex{(directory-files "/etc")}
returns
\codex{("chown" "exports" "fstab" \ldots)}
\emph{not}
\codex{("/etc/chown" "/etc/exports" "/etc/fstab" \ldots)}
To use the files in returned list, the programmer can either manually
prepend the directory:
\codex{(map (\l{f} (string-append dir "/" f)) files)}
or cd to the directory before using the file names:
%
\begin{code}
(with-cwd dir
(for-each delete-file (directory-files)))\end{code}
%
or use the \ex{glob} procedure, defined below.
A directory list can be generated by \ex{(run/strings (ls))}, but this
is unreliable, as filenames with whitespace in their names will be
split into separate entries. Using \ex{directory-files} is reliable.
\end{desc}
\defun {glob} {\vari{pat}1 \ldots} {string list}
\begin{desc}
Glob each pattern against the filesystem and return the sorted list.
Duplicates are not removed. Patterns matching nothing are not included
literally.\footnote{Why bother to mention such a silly possibility?
Because that is what sh does.}
C shell \verb|{a,b,c}| patterns are expanded. Backslash quotes
characters, turning off the special meaning of
\verb|{|, \verb|}|, \cd{*}, \verb|[|, \verb|]|, and \verb|?|.
Note that the rules of backslash for {\Scheme} strings and glob patterns
work together to require four backslashes in a row to specify a
single literal backslash. Fortunately, this should be a rare
occurrence.
A glob subpattern will not match against dot files unless the first
character of the subpattern is a literal ``\ex{.}''.
Further, a dot subpattern will not match the files \ex{.} or \ex{..}
unless it is a constant pattern, as in \ex{(glob "../*/*.c")}.
So a directory's dot files can be reliably generated
with the simple glob pattern \ex{".*"}.
Some examples:
\begin{inset}
\begin{verbatim}
(glob "*.c" "*.h")
;; All the C and #include files in my directory.
(glob "*.c" "*/*.c")
;; All the C files in this directory and
;; its immediate subdirectories.
(glob "lexer/*.c" "parser/*.c")
(glob "{lexer,parser}/*.c")
;; All the C files in the lexer and parser dirs.
(glob "\\{lexer,parser\\}/*.c")
;; All the C files in the strange
;; directory "{lexer,parser}".
(glob "*\\*")
;; All the files ending in "*", e.g.
;; ("foo*" "bar*")
(glob "*lexer*")
("mylexer.c" "lexer1.notes")
;; All files containing the string "lexer".
(glob "lexer")
;; Either ("lexer") or ().\end{verbatim}
\end{inset}
%
If the first character of the pattern (after expanding braces) is a slash,
the search begins at root; otherwise, the search begins in the current
working directory.
If the last character of the pattern (after expanding braces) is a slash,
then the result matches must be directories, \eg,
\begin{code}
(glob "/usr/man/man?/") \evalto
("/usr/man/man1/" "/usr/man/man2/" \ldots)\end{code}
Globbing can sometimes be useful when we need a list of a directory's files
where each element in the list includes the pathname for the file.
Compare:
\begin{code}
(directory-files "../include") \evalto
("cig.h" "decls.h" \ldots)
(glob "../include/*") \evalto
("../include/cig.h" "../include/decls.h" \ldots)\end{code}
\end{desc}
\defun{glob-quote}{str}\str
\begin{desc}
Returns a constant glob pattern that exactly matches \var{str}.
All wild-card characters in \var{str} are quoted with a backslash.
\begin{code}
(glob-quote "Any *.c files?")
{\evalto}"Any \\*.c files\\?"\end{code}
\end{desc}
\begin{defundesc}{file-match}{root dot-files? \vari{pat}1 \vari{pat}2 {\ldots} \vari{pat}n}{string list}
\ex{file-match} provides a more powerful file-matching service, at the
expense of a less convenient notation. It is intermediate in
power between most shell matching machinery and recursive \ex{find(1)}.
Each pattern is a regexp. The procedure searches from \var{root},
matching the first-level files against pattern \vari{pat}1, the
second-level files against \vari{pat}2, and so forth.
The list of files matching the whole path pattern is returned,
in sorted order.
The matcher uses Spencer's regular expression package.
The files \ex{.} and \ex{..} are never matched. Other dot files are only
matched if the \var{dot-files?} argument is \sharpt.
A given \vari{pat}i pattern is matched as a regexp, so it is not forced
to match the entire file name. \Eg, pattern \ex{"t"} matches any
file containing a ``t'' in its name, while pattern \verb|"^t$"| matches
only a file whose entire name is ``\ex{t}''.
The \vari{pat}i patterns can be more general than stated above.
\begin{itemize}
\item A single pattern can specify multiple levels of the path by
embedding \ex{/} characters within the pattern. For example,
the pattern \ex{"a/b/c"} gives a match equivalent to the
list of patterns \ex{"a" "b" "c"}.
\item A \vari{pat}i pattern can be a procedure,
which is used as a match predicate.
It will be repeatedly called with a candidate file-name to test.
The file-name will be the entire path accumulated.
\end{itemize}
Some examples:
%% UGH. Because we are using code instead of verbatim, we have to
%% double up on backslashes.
\begin{tightleftinset}
\begin{code}
(file-match "/usr/lib" #f "m$" "^tab") \evalto
("/usr/lib/term/tab300" "/usr/lib/term/tab300-12" \ldots)
\cb
(file-match "." #f "^lex|parse|codegen$" "\\\\.c$") \evalto
("lex/lex.c" "lex/lexinit.c" "lex/test.c"
"parse/actions.c" "parse/error.c" parse/test.c"
"codegen/io.c" "codegen/walk.c")
\cb
(file-match "." #f "^lex|parse|codegen$/\\\\.c$")
;; The same.
\cb
(file-match "." #f file-directory?)
;; Return all subdirs of the current directory.
\cb
(file-match "/" #f file-directory?) \evalto
("/bin" "/dev" "/etc" "/tmp" "/usr")
;; All subdirs of root.
\cb
(file-match "." #f "\\\\.c")
;; All the C files in my directory.
\cb
(define (ext extension)
(\l{fn} (string-suffix? fn extension)))
\cb
(define (true . x) #t)
\cb
(file-match "." #f "./\\\\.c")
(file-match "." #f "" "\\\\.c")
(file-match "." #f true "\\\\.c")
(file-match "." #f true (ext "c"))
;; All the C files of all my immediate subdirs.
\cb
(file-match "." #f "lexer") \evalto
("mylexer.c" "lexer.notes")
;; Compare with (glob "lexer"), above.\end{code}
\end{tightleftinset}
Note that when \var{root} is the current working directory (\ex{"."}),
when it is converted to directory form, it becomes \ex{""}, and doesn't
show up in the result file-names.
It is regrettable that the regexp wild card char, ``\ex{.}'',
is such an important file name literal, as dot-file prefix and extension
delimiter.
\end{defundesc}
\begin{defundesc} {create-temp-file} {[prefix]} \str
\ex{Create-temp-file} creates a new temporary file and return its name.
The optional argument specifies the filename prefix to use, and defaults
to \ex{"/usr/tmp/\var{pid}"}, where \var{pid} is the current process' id.
The procedure generates a sequence of filenames that have \var{prefix} as
a common prefix, looking for a filename that doesn't already exist in the
file system. When it finds one, it creates it, with permission \cd{#o600}
and returns the filename. (The file permission can be changed to a more
permissive permission with \ex{set-file-mode} after being created).
This file is guaranteed to be brand new. No other process will have it
open. This procedure does not simply return a filename that is very
likely to be unused. It returns a filename that definitely did not exist
at the moment \ex{create-temp-file} created it.
It is not necessary for the process' pid to be a part of the filename
for the uniqueness guarantees to hold. The pid component of the default
prefix simply serves to scatter the name searches into sparse regions, so
that collisions are less likely to occur. This speeds things up, but does
not affect correctness.
Security note: doing i/o to files created this way in \ex{/usr/tmp/} is
not necessarily secure. General users have write access to \ex{/usr/tmp/},
so even if an attacker cannot access the new temp file, he can delete it
and replace it with one of his own. A subsequent open of this filename
will then give you his file, to which he has access rights. There are
several ways to defeat this attack,
\begin{enumerate}
\item Use \ex{temp-file-iterate}, below, to return the file descriptor
allocated when the file is opened. This will work if the file
only needs to be opened once.
\item If the file needs to be opened twice or more, create it in a
protected directory, \ex, \verb|$HOME|.
\item Ensure that \ex{/usr/tmp} has its sticky bit set. This
requires system administrator privileges.
\end{enumerate}
The actual default prefix used is controlled by the dynamic variable
\ex{*temp-file-template*}, and can be overridden for increased security.
See \ex{temp-file-iterate}.
\end{defundesc}
\defunx {temp-file-iterate} {maker [template]} {\object\+}
\defvarx {*temp-file-template*} \str
\begin{desc}
This procedure can be used to perform certain atomic transactions on
the file system involving filenames. Some examples:
\begin{itemize}
\item Linking a file to a fresh backup temp name.
\item Creating and opening an unused, secure temp file.
\item Creating an unused temporary directory.
\end{itemize}
This procedure uses \var{template} to generate a series of trial file
names.
\var{Template} is a \ex{format} control string, and defaults to
\codex{"/usr/tmp/\var{pid}.\~a"}
where \var{pid} is the current process' process id.
File names are generated by calling \ex{format} to instantiate the
template's \verb|~a| field with a varying string.
\var{Maker} is a procedure which is serially called on each file name
generated. It must return at least one value; it may return multiple
values. If the first return value is {\sharpf} or if \var{maker} raises the
\ex{errno/exist} errno exception, \ex{temp-file-iterate} will loop,
generating a new file name and calling \var{maker} again. If the first
return value is true, the loop is terminated, returning whatever value(s)
\var{maker} returned.
After a number of unsuccessful trials, \ex{temp-file-iterate} may give up
and signal an error.
Thus, if we ignore its optional \var{prefix} argument,
\ex{create-temp-file} could be defined as:
\begin{code}
(define (create-temp-file)
(let ((flags (bitwise-ior open/create open/exclusive)))
(temp-file-iterate
(\l{f}
(close (open-output-file f flags #o600))
f))))\end{code}
To rename a file to a temporary name:
\begin{code}
(temp-file-iterate (\l{backup}
(create-hard-link old-file backup)
backup)
".#temp.\~a") ; Keep link in cwd.
(delete-file old-file)\end{code}
Recall that scsh reports syscall failure by raising an error
exception, not by returning an error code. This is critical to
to this example---the programmer can assume that if the
\ex{temp-file-iterate} call returns, it returns successully.
So the following \ex{delete-file} call can be reliably invoked,
safe in the knowledge that the backup link has definitely been established.
To create a unique temporary directory:
\begin{code}
(temp-file-iterate (\l{dir} (create-directory dir) dir)
"/usr/tmp/tempdir.\~a")\end{code}
%
Similar operations can be used to generate unique symlinks and fifos,
or to return values other than the new filename (\eg, an open file
descriptor or port).
The default template is in fact taken from the value of the dynamic
variable \ex{*temp-file-template*}, which itself defaults to
\ex{"/usr/tmp/\var{pid}.\~a"}, where \var{pid} is the scsh process'
pid.
For increased security, a user may wish to change the template
to use a directory not allowing world write access
(\eg, his home directory).
\end{desc}
\defun{temp-file-channel}{} {[inp outp]}
\begin{desc}
This procedure can be used to provide an interprocess communications
channel with arbitrary-sized buffering. It returns two values, an input
port and an output port, both open on a new temp file. The temp file
itself is deleted from the {\Unix} file tree before \ex{temp-file-channel}
returns, so the file is essentially unnamed, and its disk storage is
reclaimed as soon as the two ports are closed.
\ex{Temp-file-channel} is analogous to \ex{port-pipe} with two exceptions:
\begin{itemize}
\item If the writer process gets ahead of the reader process, it will
not hang waiting for some small pipe buffer to drain. It will simply
buffer the data on disk. This is good.
\item If the reader process gets ahead of the writer process, it will
also not hang waiting for data from the writer process. It will
simply see and report an end of file. This is bad.
In order to ensure that an end-of-file returned to the reader is
legitimate, the reader and writer must serialise their i/o. The
simplest way to do this is for the reader to delay doing input
until the writer has completely finished doing output, or exited.
\end{itemize}
\end{desc}
\section{Processes}
\defun {exec} {prog arg1 \ldots argn} \noreturn
\defunx {exec-path} {prog arg1 \ldots argn} \noreturn
\defunx {exec/env} {prog env arg1 \ldots argn} \noreturn
\defunx {exec-path/env} {prog env arg1 \ldots argn} \noreturn
\begin{desc}
The \ex{\ldots/env} variants take an environment specified as a
string$\rightarrow$string alist.
An environment of {\sharpt} is taken to mean the current process' environment
(\ie, the value of the external char \ex{**environ}).
[Rationale: {\sharpf} is a more convenient marker for the current environment
than {\sharpt}, but would cause an ambiguity on Schemes that identify
{\sharpf} and \ex{()}.]
The path-searching variants search the directories in the list
{\ttt exec\=path\=list} for the program.
A path-search is not performed if the program name contains
a slash character---it is used directly. So a program with a name like
\ex{"bin/prog"} always executes the program \ex{bin/prog} in the current working
directory. See \verb|$path| and \verb|exec-path-list|, below.
Note that there is no analog to the C function \ex{execv()}.
To get the effect just do
\codex{(apply exec prog arglist)}
All of these procedures flush buffered output and close unrevealed ports
before executing the new binary.
To avoid flushing buffered output, see \verb|%exec| below.
Note that the C \ex{exec()} procedure allows the zeroth element of the
argument vector to be different from the file being executed, \eg
%
\begin{inset}
\begin{verbatim}
char *argv[] = {"-", "-f", 0};
exec("/bin/csh", argv, envp);\end{verbatim}
\end{inset}
%
The scsh \ex{exec}, \ex{exec-path}, \ex{exec/env}, and \ex{exec-path/env}
procedures do not give this functionality---element 0 of the arg vector is
always identical to the \ex{prog} argument. In the rare case the user wishes
to differentiate these two items, he can use the low-level \verb|%exec| and
\verb|exec-path-search| procedures.
These procedures never return under any circumstances.
As with any other system call, if there is an error, they raise
an exception.
\end{desc}
\defun {\%exec} {prog arglist env} \undefined
\defunx {exec-path-search} {fname pathlist} \str
\begin{desc}
\var{Arglist} is a list of arguments;
\var{env} is either a string$\rightarrow$string alist or {\sharpt}.
The new program's \cd{argv[0]} will be taken from \ex{(car \var{arglist})},
\emph{not} from \var{prog}.
An environment of {\sharpt} means the current process' environment.
\verb|%exec| does not flush buffered output
(see \ex{flush-all-ports}).
\ex{exec-path-search} searches the directories of \var{pathlist} looking for
an occurrence of file \ex{fname}. If no executable file is found, it returns
{\sharpf}. If \ex{fname} contains a slash character, the path search is
short-circuited, but the procedure still checks to ensure that the file exists
and is executable---if not, it still returns {\sharpf}.
See \cd{$path} and \ex{exec-path-list}, below.
All exec procedures, including \verb|%exec|, coerce the \cd{prog} and \cd{arg}
values to strings using the usual conversion rules: numbers are converted to
decimal numerals, and symbols converted to their print-names.
\end{desc}
\defun {exit} {[status]} \noreturn
\defunx {\%exit} {[status]} \noreturn
\begin{desc}
These procedures terminate the current process with a given exit status.
The default exit status is 0.
The low-level \verb|%exit| procedure immediately terminates the process
without flushing buffered output.
\end{desc}
\begin{defundesc}{suspend}{} \undefined
Suspend the current process with a SIGSTOP signal.
\end{defundesc}
\defun {fork} {[thunk]} {pid or \sharpf}
\defunx {\%fork} {[thunk]} {pid or \sharpf}
\begin{desc}
\ex{fork} with no arguments is like C \ex{fork()}.
In the parent process, it returns
the child's pid. In the child process, it returns {\sharpf}.
\ex{fork} with an argument only returns in the parent process, returning
the child pid. The child process calls \var{thunk} and then exits.
\ex{fork} flushes buffered output before forking, and sets the child
process to non-interactive. \verb|%fork| does not perform this bookkeeping;
it simply forks.
\end{desc}
\defun {fork/pipe} {[thunk]} {pid or \sharpf}
\defunx{\%fork/pipe} {[thunk]} {pid or \sharpf}
\begin{desc}
Like \ex{fork} and \ex{\%fork}, but the parent and child communicate via a
pipe connecting the parent's stdin to the child's stdout. These procedures
side-effect the parent by changing his stdin.
In effect, \ex{fork/pipe} splices a process into the data stream
immediately upstream of the current process.
This is the basic function for creating pipelines.
Long pipelines are built by performing a sequence of \ex{fork/pipe} calls.
For example, to create a background two-process pipe \ex{a | b}, we write:
%
\begin{code}
(fork (\l{} (fork/pipe a) (b)))\end{code}
%
which returns the pid of \ex{b}'s process.
To create a background three-process pipe \ex{a | b | c}, we write:
%
\begin{code}
(fork (\l{} (fork/pipe a)
(fork/pipe b)
(c)))\end{code}
%
which returns the pid of \ex{c}'s process.
\end{desc}
\defun {fork/pipe+} {conns [thunk]} {pid or \sharpf}
\defunx {\%fork/pipe+} {conns [thunk]} {pid or \sharpf}
\begin{desc}
Like \ex{fork/pipe}, but the pipe connections between the child and parent
are specified by the connection list \var{conns}.
See the
\codex{(|+ \var{conns} \vari{pf}{\!1} \ldots{} \vari{pf}{\!n})}
process form for a description of connection lists.
\end{desc}
\begin{defundesc} {wait} {[pid]} {status [pid]}
Simply calling \ex{(wait)} will wait for any child to die, then
return the child's exit status and pid as multiple values.
With an argument, \ex{(wait \var{pid})} waits for that specific process,
then returns its exit status as a single value.
If a candidate child has already exited but not yet been waited for,
\ex{wait} returns immediately.
\remark{Describe the way that wait reaps defunct processes into
the internal table. Document all the architected wait machinery.}
\end{defundesc}
When a child process dies, its parent can call the \ex{wait} procedure
to recover the exit status of the child.
The exit status is a small integer that can be encodes information
describing how the child terminated.
The bit-level format of the exit status is not defined by {\Posix}
(you must use the following three functions to decode one).
However, if a child terminates normally with exit code 0,
{\Posix} does require \ex{wait} to return an exit status that is exactly
zero.
So \ex{(zero? \var{status})} is a correct way to test for non-error,
normal termination.
\defun {status:exit-val}{status}{{\integer} or \sharpf}
\defunx{status:stop-sig}{status}{{\integer} or \sharpf}
\defunx{status:term-sig}{status}{{\integer} or \sharpf}
\begin{desc}
For a given status value produced by calling \ex{wait},
exactly one of these routines will return a true value.
If the child process exited normally, \ex{status:exit-val} returns the
exit code for the child process (\ie, the value the child passed to \ex{exit}
or returned from \ex{main}). Otherwise, this function returns false.
If the child process was suspended by a signal, \ex{status:stop-sig}
returns the signal that suspended the child.
Otherwise, this function returns false.
If the child process terminated abnormally, \ex{status:term-sig}
returns the signal that terminated the child.
Otherwise, this function returns false.
\end{desc}
\begin{defundesc} {call-terminally} {thunk} \noreturn
\ex{call-terminally} calls its thunk. When the thunk returns, the process
exits. Although \ex{call-terminally} could be implemented as
\codex{(\l{thunk} (thunk) (exit 0))}
an implementation can take advantage of the fact that this procedure never
returns. For example, the runtime can start with a fresh stack and also
start with a fresh dynamic environment, where shadowed bindings are
discarded. This can allow the old stack and dynamic environment to be
collected (assuming this data is not reachable through some live
continuation).
\end{defundesc}
%% Dereleased until we have a more portable implementation.
%\defun{halts?}{proc}\boolean
%\begin{desc}
%This procedure, ported from early T implementations,
%returns true iff \ex{(\var{proc})} returns at all.
%\remark{The current implementation is a constant function returning {\sharpt},
% which suffices for all {\Unix} implementations of which we are aware.}
%\end{desc}
\section{Process state}
\defun {umask}{} \fixnum
\defunx {set-umask} {perms} \undefined
\defunx {with-umask*} {perms thunk} {values of thunk}
\dfnx {with-umask} {perms . body} {values of body} {syntax}
\begin{desc}
The process' current umask is retrieved with \ex{umask}, and set with
\ex{(set-umask \var{perms})}. Calling \ex{with-umask*} changes the umask
to \var{perms} for the duration of the call to \var{thunk}. If the
program throws out of \var{thunk} by invoking a continuation, the umask is
reset to its external value. If the program throws back into \var{thunk}
by calling a stored continuation, the umask is restored to the \var{perms}
value. The special form \ex{with-umask} is equivalent in effect to
the procedure \ex{with-umask*}, but does not require the programmer
to explicitly wrap a \ex{(\l{} \ldots)} around the body of the code
to be executed.
\end{desc}
\defun {chdir} {[fname]} \undefined
\defunx {cwd}{} \str
\defunx {with-cwd*} {fname thunk} {value(s) of thunk}
\dfnx {with-cwd} {fname . body} {value(s) of body} {syntax}
\begin{desc}
These forms manipulate the current working directory.
The cwd can be changed with \ex{chdir}
(although in most cases, \ex{with-cwd} is preferrable).
If \ex{chdir} is called with no arguments, it changes the cwd to
the user's home directory.
The \ex{with-cwd*} procedure calls \ex{thunk} with the cwd temporarily
set to \var{fname}; when \var{thunk} returns, or is exited in a non-local
fashion (\eg, by raising an exception or by invoking a continuation),
the cwd is returned to its original value.
The special form \ex{with-cwd} is simply syntactic sugar for \ex{with-cwd*}.
\end{desc}
\defun {pid}{} \fixnum
\defunx {parent-pid}{} \fixnum
\defunx {process-group} {[pid]} \fixnum
\defunx {set-process-group} {[pid] pgrp} \undefined % [not implemented]
\begin{desc}
\ex{(pid)} and \ex{(parent-pid)} retrieve the process id for the
current process and its parent.
If the OS supports process groups, a process' process group can be
retrieved and set with \ex{process-group} and \ex{set-process-group}.
The affected process for these two procedures defaults to the current
process.
\end{desc}
\defun {set-priority} {which who priority} \undefined %; priority stuff unimplemented
\defunx {priority} {which who} \fixnum % ; not implemented
\defunx {nice} {[pid delta]} \undefined %; not implemented
\begin{desc}
These procedures set and access the priority of processes.
I can't remember how \ex{set-priority} and \ex{priority} work, so no
documentation, and besides, they aren't implemented yet, anyway.
\end{desc}
\defunx {user-login-name}{} \str
\defunx {user-uid}{} \fixnum
\defunx {user-effective-uid}{} \fixnum
\defunx {user-gid}{} \fixnum
\defunx {user-effective-gid}{} \fixnum
\defunx {user-supplementary-gids}{} {{\fixnum} list}
\defunx {set-uid} {uid} \undefined
\defunx {set-gid} {gid} \undefined
\begin{desc}
These routines get and set the effective and real user and group ids.
The \ex{set-uid} and \ex{set-gid} routines correspond to the {\Posix}
\ex{setuid()} and \ex{setgid()} procedures.
\end{desc}
\defun {process-times} {} {[{\fixnum} {\fixnum} {\fixnum} \fixnum]}
\begin{desc}
Returns four values:
\begin{tightinset}
\begin{tabular}{l}
user CPU time in clock-ticks \\
system CPU time in clock-ticks \\
user CPU time of all descendant processes \\
system CPU time of all descendant processes
\end{tabular}
\end{tightinset}
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{User and group db access}
These procedures are used to access the user and group database
(\eg, the ones traditionally stored in \ex{/etc/passwd} and \ex{/etc/group}.)
\defun {user-info} {uid/name} {record}
\begin{desc}
Return a \ex{user-info} record giving the recorded information for a
particular user:
\index{user-info}
\index{user-info:name}
\index{user-info:uid}
\index{user-info:gid}
\index{user-info:home-dir}
\index{user-info:shell}
\begin{code}
(define-record user-info
name uid gid home-dir shell)\end{code}
The \var{uid/name} argument is either an integer uid or a string user-name.
\end{desc}
\defun {->uid} {uid/name} \fixnum
\defunx {->username} {uid/name} \str
\begin{desc}
These two procedures coerce integer uid's and user names to a particular
form.
\end{desc}
\defun {group-info} {gid/name} {record}
\begin{desc}
Return a \ex{group-info} record giving the recorded information for a
particular user:
\index{group-info}
\index{group-info:name}
\index{group-info:gid}
\index{group-info:members}
\begin{code}
(define-record group-info
name gid members)\end{code}
The \var{gid/name} argument is either an integer gid or a string user-name.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Accessing command-line arguments}
\defvar {command-line-arguments}{{\str} list}
\defunx {command-line}{} {{\str} list}
\begin{desc}
The list of strings \ex{command-line-arguments} contains the arguments
passed to the scsh process on the command line.
Calling \ex{(command-line)} returns the complete \ex{argv}
string list, including the program. So if we run a shell script
\codex{/usr/shivers/bin/myls -CF src}
then \ex{command-line-arguments} is
\codex{("-CF" "src")}
and \ex{(command-line)} returns
\codex{("/usr/shivers/bin/myls" "-CF" "src")}
\ex{command-line} returns a fresh list each time it is called.
In this way, the programmer can get a fresh copy of the original
argument list if \ex{command-line-arguments} has been modified or is lexically
shadowed.
\end{desc}
\defun {arg} {arglist n [default]} \str
\defunx {arg*} {arglist n [default-thunk]} \str
\defunx {argv} {n [default]} \str
\begin{desc}
These procedures are useful for accessing arguments from argument
lists.
\ex{arg} returns the $n^{\rm{th}}$ element of \var{arglist}.
The index is 1-based.
If \var{n} is too large, \var{default} is returned;
if no \var{default}, then an error is signaled.
\ex{arg*} is similar, except that the \var{default-thunk} is called to generate
the default value.
\ex{(argv \var{n})} is simply \ex{(arg (command-line) (+ \var{n} 1))}.
The +1 offset ensures that the two forms
%
\begin{code}
(arg command-line-arguments \var{n})
(argv \var{n})\end{code}
%
return the same argument
(assuming the user has not rebound or modified \ex{command-line-arguments}).
Example:
%
\begin{code}
(if (null? command-line-arguments)
(& (xterm -n ,host -title ,host
-name ,(string-append "xterm_" host)))
(let* ((progname (file-name-nondirectory (argv 1)))
(title (string-append host ":" progname)))
(& (xterm -n ,title
-title ,title
-e ,@command-line-arguments))))\end{code}
%
A subtlety: there are two ways to invoke a scsh program.
One is as a simple binary,
the other is as an interpreted script via the {\Unix}
\ex{\#!} \ex{exec(2)} feature.
When a binary is running with scsh code, \ex{(command-line)} returns exactly
the command line.
However, when the scsh interpreter is invoked with a scsh script
specified on the command line, then the scsh startup code doctors the list
returned by \ex{(command-line)} to make the shell script itself be the program
(\ie, \ex{(argv 0)}), instead of the string \ex{"scsh"},
or whatever the real \ex{(argv 0)} value is.
In addition, scsh will delete scsh-specific flags from the argument
list.
So if we have a shell script in file \ex{fullecho}:
\begin{code}
#!/usr/local/bin/scsh -s
!#
(for-each (\l{arg} (display arg) (display " "))
(command-line))\end{code}
and we run the program
\codex{fullecho hello world}
the program will print out
\codex{fullecho hello world}
not
\codex{/usr/local/bin/scsh -s fullecho hello world}
This argument line processing ensures that if a scsh script is subsequently
compiled into a standalone executable, that its semantics will be
unchanged---the arglist processing is invariant. In effect, the
\codex{/usr/local/bin/scsh -s}
is not part of the program;
it's a specification for the machine to execute the program on, so it is
not properly part of the program's argument list.
\remark{The truth:
The above discussion assumes some things that don't exist:
\begin{itemize}
\item An implementation of scsh that allows scsh scripts to
be compiled to native code binaries.
\item A native code binary implementation of the scsh interpreter.
\end{itemize}
What there is right now is just the {\scm} virtual machine,
invoked with a scsh heap image.
}
\end{desc}
\section{System parameters}
\defun {maximum-fds}{}\fixnum
\defunx {page-size}{} \fixnum
\defunx {system-name}{} \str
\begin{desc}
Only \ex{system-name} is implemented.
\end{desc}
\section{Signal system}
Signal numbers are bound to the variables \ex{signal/hup}, \ex{signal/int},
\ldots
\defun {signal-process} {pid sig} \undefined
\defunx {signal-procgroup} {prgrp sig} \undefined
\begin{desc}
These two procedures send signals to a specific process, and all the processes
in a specific process group, respectively.
\end{desc}
I haven't done signal handlers yet. Should be straightforward: a mechanism
to assign procedures to signals.
\defun{itimer}{???} \undefined
\defunx{pause-until-interrupt}{} \undefined
\defun{sleep}{secs} \undefined
\begin{desc}
Sleeping is defined, but we don't offer a way to sleep for a more precise
interval (\eg, a microsecond timer), as this is not in {\Posix}.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Time}
This time package, does not currently work with NeXTSTEP, as NeXTSTEP
does not provide a Posix-compliant time interface that will successfully
link.
Scsh's time system is fairly sophisticated, particularly with respect
to its careful treatment of time zones.
However, casual users shouldn't be intimidated;
most of the complexity is optional,
and defaulting all the optional arguments reduces the system
to a simple interface.
\subsection{Terminology}
``UTC'' and ``UCT'' stand for ``universal coordinated time,'' which is the
official name for what is colloquially referred to as ``Greenwich Mean
Time.''
Posix allows a single time zone to specify \emph{two} different offsets from
UTC: one standard one, and one for ``summer time.'' Summer time is frequently
some sort of daylight savings time.
The scsh time package consistently uses this terminology: we never say
``gmt'' or ``dst;'' we always say ``utc'' and ``summer time.''
\subsection{Basic data types}
We have two types: \emph{time} and \emph{date}.
\index{time}
A \emph{time} specifies an instant in the history of the universe.
It is location and time-zone independent. A time is a real value
giving the number of elapsed seconds since the Unix ``epoch''
(Midnight, January 1, 1970 UTC).
Time values provide arbitrary time resolution,
limited only by the number system of the underlying Scheme system.
\index{date}
A \emph{date} is a name for an instant in time that is specified
relative to some location/time-zone in the world, \eg:
\begin{tightinset}
Friday October 31, 1994 3:47:21 pm EST.
\end{tightinset}
Dates provide one-second resolution,
and are expressed with the following record type:
%
\begin{code}\index{date}
(define-record date ; A Posix tm struct
seconds ; Seconds after the minute [0-59]
minute ; Minutes after the hour [0-59]
hour ; Hours since midnight [0-23]
month-day ; Day of the month [1-31]
month ; Months since January [0-11]
year ; Years since 1900
tz-name ; Time-zone name: #f or a string.
tz-secs ; Time-zone offset: #f or an integer.
summer? ; Summer (Daylight Savings) time in effect?
week-day ; Days since Sunday [0-6]
year-day) ; Days since Jan. 1 [0-365]\end{code}
%
If the \ex{tz-secs} field is given, it specifies the time-zone's offset from
UTC in seconds. If it is specified, the \ex{tz-name} and \ex{summer?}
fields are ignored when using the date structure to determine a specific
instant in time.
If the \ex{tz-name} field is given, it is a time-zone string such as
\ex{"EST"} or \ex{"HKT"} understood by the OS.
Since Posix time-zone strings can specify dual standard/summer time-zones
(e.g., "EST5EDT" specifies U.S. Eastern Standard/Eastern Daylight Time),
the value of the \ex{summer?} field is used to resolve the amiguous
boundary cases. For example, on the morning of the Fall daylight savings
change-over, 1:00am--2:00am happens twice. Hence the date 1:30 am
on this morning can specify two different seconds;
the \ex{summer?} flag says which one.
A date with $\ex{tz-name} = \ex{tz-secs} = \ex{\#f}$ is a date that
is specified in terms of the system's current time zone.
There is redundancy in the \ex{date} data structure.
For example, the \ex{year-day} field is redundant
with the \ex{month-day} and \ex{month} fields.
Either of these implies the values of the \ex{week-day} field.
The \ex{summer?} and \ex{tz-name} fields are redundant with the \ex{tz-secs}
field in terms of specifying an instant in time.
This redundancy is provided because consumers of dates may want it broken out
in different ways.
The scsh procedures that produce date records fill them out completely.
However, when date records produced by the programmer are passed to
scsh procedures, the redundancy is resolved by ignoring some of the
secondary fields.
This is described for each procedure below.
\defun{make-date} {s min h mday mon y [tzn tzs summ? wday yday]} {date}
\begin{desc}
When making a \ex{date} record, the last five elements of the record
are optional, and default to \ex{\#f}, \ex{\#f}, \ex{\#f}, 0,
and 0 respectively.
This is useful when creating a \ex{date} record to pass as an
argument to \ex{time}.
\end{desc}
\subsection{Time zones}
Several time procedures take time zones as arguments. When optional,
the time zone defaults to local time zone. Otherwise the time zone
can be one of:
\begin{inset}
\begin{tabular}{lp{0.7\linewidth}}
\ex{\#f} & Local time \\
Integer & Seconds of offset from UTC. For example,
New York City is -18000 (-5 hours), San Francisco
is -28800 (-8 hours). \\
String & A Posix time zone string understood by the OS
(\ie., the sort of time zone assigned to the \ex{\$TZ}
environment variable).
\end{tabular}
\end{inset}
An integer time zone gives the number of seconds you must add to UTC
to get time in that zone. It is \emph{not} ``seconds west'' of UTC---that
flips the sign.
To get UTC time, use a time zone of either 0 or \ex{"UCT0"}.
\subsection{Procedures}
\defun {time+ticks} {} {[secs ticks]}
\defunx{ticks/sec} {} \real
\begin{desc}
The current time, with sub-second resolution.
Sub-second resolution is not provided by Posix,
but is available on many systems.
The time is returned as elapsed seconds since the Unix epoch, plus
a number of sub-second ``ticks.''
The length of a tick may vary from implementation to implementation;
it can be determined from \ex{(ticks/sec)}.
The system clock is not required to report time at the full resolution
given by \ex{(ticks/sec)}. For example, on BSD, time is reported at
$1\mu$s resolution, so \ex{(ticks/sec)} is 1,000,000. That doesn't mean
the system clock has micro-second resolution.
If the OS does not support sub-second resolution, the \var{ticks} value
is always 0, and \ex{(ticks/sec)} returns 1.
\begin{remarkenv}
I chose to represent system clock resolution as ticks/sec
instead of sec/tick to increase the odds that the value could
be represented as an exact integer, increasing efficiency and
making it easier for Scheme implementations that don't have
sophisticated numeric support to deal with the quantity.
You can convert seconds and ticks to seconds with the expression
\codex{(+ \var{secs} (/ \var{ticks} (ticks/sec)))}
Given that, why not have the fine-grain time procedure just
return a non-integer real for time? Following Common Lisp, I chose to
allow the system clock to report sub-second time in its own units to
lower the overhead of determining the time. This would be important
for a system that wanted to precisely time the duration of some
event. Time stamps could be collected with little overhead, deferring
the overhead of precisely calculating with them until after collection.
This is all a bit academic for the {\scm} implementation, where
we determine time with a heavyweight system call, but it's nice
to plan for the future.
\end{remarkenv}
\end{desc}
\defun {date} {} {date-record}
\defunx{date} {[time tz]} {date-record}
\begin{desc}
Simple \ex{(date)} returns the current date, in the local time zone.
With the optional arguments, \ex{date} converts the time to the date as
specified by the time zone \var{tz}.
\var{Time} defaults to the current time; \var{tz} defaults to local time,
and is as described in the time-zone section.
If the \var{tz} argument is an integer, the date's \ex{tz-name}
field is a Posix time zone of the form
``\ex{UTC+\emph{hh}:\emph{mm}:\emph{ss}}'';
the trailing \ex{:\emph{mm}:\emph{ss}} portion is deleted if it is zeroes.
\end{desc}
\defun {time} {} \integer
\defunx{time} {[date]} \integer
\begin{desc}
Simple \ex{(time)} returns the current time.
With the optional date argument, \ex{time} converts a date to a time.
\var{Date} defaults to the current date.
Note that the input \var{date} record is overconstrained.
\ex{time} ignores \var{date}'s \ex{week-day} and \ex{year-day} fields.
If the date's \ex{tz-secs} field is set, the \ex{tz-name} and
\ex{summer?} fields are ignored.
If the \ex{tz-secs} field is \ex{\#f}, then the time-zone is taken
from the \ex{tz-name} field. A false \ex{tz-name} means the system's
current time zone. When calculating with time-zones, the date's
\ex{summer?} field is used to resolve ambiguities:
\begin{tightinset}
\begin{tabular}{ll}
\ex{\#f} & Resolve an ambiguous time in favor of non-summer time. \\
true & Resolve an ambiguous time in favor of summer time.
\end{tabular}
\end{tightinset}
This is useful in boundary cases during the change-over. For example,
in the Fall, when US daylight savings time changes over at 2:00 am,
1:30 am happens twice---it names two instants in time, an hour apart.
Outside of these boundary cases, the \ex{summer?} flag is ignored. For
example, if the standard/summer change-overs happen in the Fall and the
Spring, then the value of \ex{summer?} is ignored for a January or
July date. A January date would be resolved with standard time, and a
July date with summer time, regardless of the \ex{summer?} value.
The \ex{summer?} flag is also ignored if the time zone doesn't have
a summer time---for example, simple UTC.
\end{desc}
\defun {date->string} {date} \str
\defunx{format-date} {fmt date} \str
\begin{desc}
\ex{Date->string} formats the date as a 24-character string of the
form:
\begin{tightinset}
Sun Sep 16 01:03:52 1973
\end{tightinset}
\ex{Format-date} formats the date according to the format string
\var{fmt}. The format string is copied verbatim, except that tilde
characters indicate conversion specifiers that are replaced by fields from
the date record. Figure \ref{fig:dateconv} gives the full set of
conversion specifiers supported by \ex{format-date}.
\begin{boxedfigure}{tbp}
\renewcommand{\arraystretch}{1.25}
\begin{tabular}{l>{\raggedrightparbox}p{0.9\linewidth}}
\verb|~~| & Converted to the \verb|~| character. \\
\verb|~a| & abbreviated weekday name \\
\verb|~A| & full weekday name \\
\verb|~b| & abbreviated month name \\
\verb|~B| & full month name \\
\verb|~c| & time and date using the time and date representation
for the locale (\verb|~X ~x|) \\
\verb|~d| & day of the month as a decimal number (01-31) \\
\verb|~H| & hour based on a 24-hour clock
as a decimal number (00-23) \\
\verb|~I| & hour based on a 12-hour clock
as a decimal number (01-12) \\
\verb|~j| & day of the year as a decimal number (001-366) \\
\verb|~m| & month as a decimal number (01-12) \\
\verb|~M| & minute as a decimal number (00-59) \\
\verb|~p| & AM/PM designation associated with a 12-hour clock \\
\verb|~S| & second as a decimal number (00-61) \\
\verb|~U| & week number of the year;
Sunday is first day of week (00-53) \\
\verb|~w| & weekday as a decimal number (0-6), where Sunday is 0 \\
\verb|~W| & week number of the year;
Monday is first day of week (00-53) \\
\verb|~x| & date using the date representation for the locale \\
\verb|~X| & time using the time representation for the locale \\
\verb|~y| & year without century (00-99) \\
\verb|~Y| & year with century (\eg 1990) \\
\verb|~Z| & time zone name or abbreviation, or no characters
if no time zone is determinable
\end{tabular}
\caption{\texttt{format-date} conversion specifiers}
\label{fig:dateconv}
\end{boxedfigure}
\end{desc}
%\defun{utc-offset} {[time tz]} \integer
%\begin{desc}
% Returns the offset from UTC of time zone \var{tz} at instant \var{time}.
% \var{time} defaults to the current time; \var{tz} defaults to local time,
% and is as described in the time-zone section.
%
% The offset is the number of seconds you add to UTC time to get
% local time.
%
% Note: Be aware that other time interfaces (\eg, the BSD C interface)
% give offsets as seconds \emph{west} of UTC, which flips the sign. The scsh
% definition is chosen for arithmetic simplicity. It's easy to remember
% the definition of the offset: what you add to UTC to get local.
%\end{desc}
%
%\defun{time-zone} {[summer? tz]} \str
%\begin{desc}
% Returns the name of the time zone as a string. \var{Summer?} is
% used to choose between the summer name and the standard name
% (\eg, ``EST'' and ``EDT'')\@. \var{Summer?} is interpreted as follows:
% \begin{inset}
% \begin{tabular}{lp{0.7\linewidth}}
% Integer & A time value.
% The variant in use at that time is returned. \\
% \ex{\#f} & The standard time name is returned. \\
% \emph{Otherwise} & The summer time name is returned.
% \end{tabular}
% \end{inset}
% \ex{Summer?} defaults to the case that pertains at the time of the call.
% It is ignored if the time zone doesn't have a summer variant.
%\end{desc}
\defun {fill-in-date!}{date}{date}
\begin{desc}
This procedure fills in missing, redundant slots in a date record.
In decreasing order of priority:
\begin{itemize}
\itum{year, month, month-day $\Rightarrow$ year-day}
If the \ex{year}, \ex{month}, and \ex{month-day} fields are all
defined (are all integers), the \ex{year-day}
field is set to the corresponding value.
\itum{year, year-day $\Rightarrow$ month, month-day}
If the \ex{month} and \ex{month-day} fields aren't set, but
the \ex{year} and \ex{year-day} fields are set, then
\ex{month} and \ex{month-day} are calculated.
\itum{year, month, month-day, year-day $\Rightarrow$ week-day}
If either of the above rules is able to determine what day it is,
the \ex{week-day} field is then set.
\itum{tz-secs $\Rightarrow$ tz-name}
If \ex{tz-secs} is defined, but \ex{tz-name} is not, it is assigned
a time-zone name of the form ``\ex{UTC+\emph{hh}:\emph{mm}:\emph{ss}}'';
the trailing \ex{:\emph{mm}:\emph{ss}} portion is deleted if it
is zeroes.
\itum{tz-name, date, summer? $\Rightarrow$ tz-secs, summer?}
If the date information is provided up to second resolution,
\ex{tz-name} is also provided, and \ex{tz-secs} is not set,
then \ex{tz-secs} and \ex{summer?} are set to their correct values.
Summer-time ambiguities are resolved using the original value of
\ex{summer?}. If the time zone doesn't have a
summer time variant, then \ex{summer?} is set to \ex{\#f}.
\itum{local time, date, summer? $\Rightarrow$ tz-name, tz-secs, summer?}
If the date information is provided up to second resolution,
but no time zone information is provided (both \ex{tz-name} and
\ex{tz-secs} aren't set), then we proceed as in the above case,
except the system's current time zone is used.
\end{itemize}
These rules allow one particular ambiguity to escape:
if both \ex{tz-name} and \ex{tz-secs} are set, they are not brought
into agreement. It isn't clear how to do this, nor is it clear which
one should take precedence.
\oops{\ex{fill-in-date!} isn't implemented yet.}
\end{desc}
\section{Environment variables}
\defun {setenv} {var val} \undefined
\defunx {getenv} {var} \str
\begin{desc}
These functions get and set the process environment, stored in the
external C variable \ex{char **environ}.
An environment variable \var{var} is a string.
If an environment variable is set to a string \var{val},
then the process' global environment structure is altered with an entry
of the form \ex{"\var{var}=\var{val}"}.
If \var{val} is {\sharpf}, then any entry for \var{var} is deleted.
\end{desc}
\defun {env->alist}{} {{\str$\rightarrow$\str} alist}
\begin{desc}
The \ex{env->alist} procedure converts the entire environment into
an alist, \eg,
\begin{code}
(("TERM" . "vt100")
("SHELL" . "/bin/csh")
("EDITOR" . "emacs")
\ldots)\end{code}
\end{desc}
\defun {alist->env} {alist} \undefined
\begin{desc}
\var{Alist} must be an alist whose keys are all strings, and whose values
are all either strings or string lists. String lists are converted to
colon lists (see below). The alist is installed as the current {\Unix}
environment (\ie, converted to a null-terminated C vector of
\ex{"\var{var}=\var{val}"} strings which is assigned to the global
\ex{char **environ}).
\end{desc}
The following three functions help the programmer manipulate alist
tables in some generally useful ways. They are all defined using
\ex{equal?} for key comparison.
\begin{defundesc} {alist-delete} {key alist} {alist}
Delete any entry labelled by value \var{key}.
\end{defundesc}
\begin{defundesc} {alist-update} {key val alist} {alist}
Delete \var{key} from \var{alist}, then cons on a
\ex{(\var{key} . \var{val})} entry.
\end{defundesc}
\defun{alist-compress} {alist} {alist}
\begin{desc}
Compresses \var{alist} by removing shadowed entries.
Example:
\begin{code}
;;; Shadowed (1 . c) entry removed.
(alist-compress '( (1 . a) (2 . b) (1 . c) (3 . d) ))
{\evalto} ((1 . a) (2 . b) (3 . d))\end{code}
\end{desc}
\defun {with-env*} {env-alist-delta thunk} {value(s) of thunk}
\defunx {with-total-env*} {env-alist thunk} {value(s) of thunk}
\begin{desc}
These procedures call \var{thunk} in the context of an altered
environment. They return whatever values \var{thunk} returns.
Non-local returns restore the environment to its outer value;
throwing back into the thunk by invoking a stored continuation
restores the environment back to its inner value.
The \var{env-alist-delta} argument specifies
a \emph{modification} to the current en\-vi\-ron\-ment---\var{thunk}'s
environment is the original environment overridden with the
bindings specified by the alist delta.
The \var{env-alist} argument specifies a complete environment
that is installed for \var{thunk}.
\end{desc}
\dfn {with-env} {env-alist-delta . body} {value(s) of body} {syntax}
\dfnx {with-total-env} {env-alist . body} {value(s) of body} {syntax}
\begin{desc}
These special forms provide syntactic sugar for \ex{with-env*}
and {\ttt with\=total\=env*}.
The env alists are not evaluated positions, but are implicitly backquoted.
In this way, they tend to resemble binding lists for \ex{let} and
\ex{let*} forms.
\end{desc}
Example: These four pieces of code all run the mailer with special
\cd{$TERM} and \cd{$EDITOR} values.
{\small
\begin{code}
(with-env (("TERM" . "xterm") ("EDITOR" . ,my-editor))
(run (mail shivers@lcs.mit.edu)))
\cb
(with-env* `(("TERM" . "xterm") ("EDITOR" . ,my-editor))
(\l{} (run (mail shivers@csd.hku.hk))))
\cb
(run (begin (setenv "TERM" "xterm") ; Env mutation happens
(setenv "EDITOR" my-editor) ; in the subshell.
(exec-epf (mail shivers@research.att.com))))
\cb
;; In this example, we compute an alternate environment ENV2
;; as an alist, and install it with an explicit call to the
;; EXEC-PATH/ENV procedure.
(let* ((env (env->alist)) ; Get the current environment,
(env1 (alist-update env "TERM" "xterm")) ; and compute
(env2 (alist-update env1 "EDITOR" my-editor))) ; the new env.
(run (begin (exec-path/env "mail" env2 "shivers@cs.cmu.edu"))))\end{code}}
\subsection{Path lists and colon lists}
Environment variables such as \ex{\$PATH} encode a list of strings
by separating the list elements with colon delimiters.
Once parsed into actual lists, these ordered lists can be manipulated
with the following two functions.
To convert between the colon-separated string encoding and the
list-of-strings representation, see the \ex{field-reader} and
\ex{join-strings} functions in section~\ref{sec:field-reader}.
\remark{An earlier release of scsh provided the \ex{split-colon-list}
and \ex{string-list->colon-list} functions. These have been
removed from scsh, and are replaced by the more general
parsers and unparsers of the field-reader module.}
%\defun {split-colon-list} {string} {{\str} list}
%\defunx {string-list->colon-list} {string-list} \str
%\begin{desc}
% Many {\Unix} lists, such as the \cd{$PATH} search path,
% are stored as ``colon lists.''
% A colon list is a string containing elements delimited by colon characters.
% These functions provide conversions between colon lists and true
% {\Scheme} lists.
%%
%\begin{code}
%(split-colon-list "/foo:/bar::/usr/tmp") \evalto
% ("/foo" "/bar" "" "/usr/tmp")\end{code}
%%
% \ex{string-list->colon-list} is the inverse function.
%
% \ex{with-env*}, \ex{with-total-env*}, and \ex{alist->env} all coerce
% string lists to colon lists where appropriate.
%\end{desc}
\defun {add-before} {elt before list} {list}
\defunx {add-after} {elt after list} {list}
\begin{desc}
These functions are for modifying search-path lists, where element order
is significant.
\ex{add-before} adds \var{elt} to the list immediately
before the first occurrence of \var{before} in the list.
If \var{before} is not in the list, \var{elt} is added to the end
of the list.
\ex{add-after} is similar:
\var{elt} is added after the last occurrence of \var{after}.
If \var{after} is not found,
\var{elt} is added to the beginning of the list.
Neither function destructively alters the original path-list.
The result may share structure with the original list.
Both functions use \ex{equal?} for comparing elements.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{\protect{\tt\$USER}, \protect{\tt\$HOME}, and \protect{\tt\$PATH}}
Like sh and unlike csh, scsh has \emph{no} interactive dependencies on
environment variables.
It does, however, initialise certain internal values at startup time from the
initial process environment, in particular \cd{$HOME} and \cd{$PATH}.
Scsh never uses \cd{$USER} at all.
It computes \ex{(user-login-name)} from the system call \ex{(user-uid)}.
\defvar {home-directory} \str
\defvarx {exec-path-list} {{\str} list}
\begin{desc}
Scsh accesses \cd{$HOME} at start-up time, and stores the value in the
global variable \ex{home-directory}. It uses this value for \ex{\~}
lookups and for returning to home on \ex{(chdir)}.
Scsh accesses \cd{$PATH} at start-up time, colon-splits the path list, and
stores the value in the global variable \ex{exec-path-list}. This list is
used for \ex{exec-path} and \ex{exec-path/env} searches.
\end{desc}