Go to the first, previous, next, last section, table of contents.
The Scheme standard provides a simple mechanism for reading and writing files: file ports. MIT Scheme provides additional tools for dealing with other aspects of the operating system:
MIT Scheme programs need to use names to designate files. The main difficulty in dealing with names of files is that different file systems have different naming formats for files. For example, here is a table of several file systems (actually, operating systems that provide file systems) and what equivalent file names might look like for each one:
System File Name ------ --------- TOPS-20 <LISPIO>FORMAT.FASL.13 TOPS-10 FORMAT.FAS[1,4] ITS LISPIO;FORMAT FASL MULTICS >udd>LispIO>format.fasl TENEX <LISPIO>FORMAT.FASL;13 VAX/VMS [LISPIO]FORMAT.FAS;13 UNIX /usr/lispio/format.fasl DOS C:\USR\LISPIO\FORMAT.FAS
It would be impossible for each program that deals with file names to know about each different file name format that exists; a new operating system to which Scheme was ported might use a format different from any of its predecessors. Therefore, MIT Scheme provides two ways to represent file names: filenames (also called namestrings), which are strings in the implementation-dependent form customary for the file system, and pathnames, which are special abstract data objects that represent file names in an implementation-independent way. Procedures are provided to convert between these two representations, and all manipulations of files can be expressed in machine-independent terms by using pathnames.
In order to allow MIT Scheme programs to operate in a network environment that may have more than one kind of file system, the pathname facility allows a file name to specify which file system is to be used. In this context, each file system is called a host, in keeping with the usual networking terminology.(22)
Note that the examples given in this section are specific to unix pathnames. Pathnames for other operating systems have different external representations.
Pathname objects are usually created by parsing filenames (character strings) into component parts. MIT Scheme provides operations that convert filenames into pathnames and vice versa.
(parse-namestring object #f #f)
.
(->pathname "foo") => #[pathname 65 "foo"] (->pathname "/usr/morris") => #[pathname 66 "/usr/morris"]
This procedure does not do defaulting of pathname components.
The optional arguments are used to determine what syntax should be used
for parsing the string. In general this is only really useful if your
implementation of MIT Scheme supports more than one file system,
otherwise you would use ->pathname
. If given, host must be
a host object or #f
, and defaults must be a pathname.
Host specifies the syntax used to parse the string. If host
is not given or #f
, the host component from defaults is
used instead; if defaults is not given, the host component from
*default-pathname-defaults*
is used.
->namestring
returns a newly allocated string that is the
filename corresponding to pathname.
(->namestring (->pathname "/usr/morris/minor.van")) => "/usr/morris/minor.van"
pathname-simplify
might not always be able to simplify the
pathname, e.g. on unix with symbolic links the directory
`/usr/morris/../' need not be the same as `/usr/'. In cases
of uncertainty the behavior is conservative, returning the original or a
partly simplified pathname.
(pathname-simplify "/usr/morris/../morris/dance") => #[pathname "/usr/morris/dance"]
A pathname object always has six components, described below. These components are the common interface that allows programs to work the same way with different file systems; the mapping of the pathname components into the concepts peculiar to each file system is taken care of by the Scheme implementation.
#f
or the value of the variable
local-host
.
Note that a pathname is not necessarily the name of a specific file.
Rather, it is a specification (possibly only a partial specification) of
how to access a file. A pathname need not correspond to any file that
actually exists, and more than one pathname can refer to the same file.
For example, the pathname with a version of newest
may refer to
the same file as a pathname with the same components except a certain
number as the version. Indeed, a pathname with version newest
may refer to different files as time passes, because the meaning of such
a pathname depends on the state of the file system. In file systems
with such facilities as "links", multiple file names, logical devices,
and so on, two pathnames that look quite different may turn out to
address the same file. To access a file given a pathname, one must do a
file-system operation such as open-input-file
.
Two important operations involving pathnames are parsing and merging. Parsing is the conversion of a filename (which might be something supplied interactively by the users when asked to supply the name of a file) into a pathname object. This operation is implementation-dependent, because the format of filenames is implementation-dependent. Merging takes a pathname with missing components and supplies values for those components from a source of default values.
Not all of the components of a pathname need to be specified. If a
component of a pathname is missing, its value is #f
.
Before the file system interface can do anything interesting with a
file, such as opening the file, all the missing components of a pathname
must be filled in. Pathnames with missing components are used
internally for various purposes; in particular, parsing a namestring
that does not specify certain components will result in a pathname with
missing components.
Any component of a pathname may be the symbol unspecific
, meaning
that the component simply does not exist, for file systems in which such
a value makes no sense. For example, unix, Windows, and OS/2 file
systems usually do not support version numbers, so the version component
for such a host might be unspecific
.(23)
In addition to #f
and unspecific
, the components of a
pathname may take on the following meaningful values:
host?
predicate.
absolute
or the symbol
relative
. If the first element in the list is the symbol
absolute
, then the directory component (and subsequently the
pathname) is absolute; the first component in the sequence is to
be found at the "root" of the file system. If the directory is
relative then the first component is to be found in some as yet
unspecified directory; typically this is later specified to be the
current working directory.
Aside from absolute
and relative
, which may only appear as
the first element of the list, each subsequent element in the list is
either: a string, which is a literal component; the symbol wild
,
meaningful only when used in conjunction with the directory reader; or
the symbol up
, meaning the next directory is the "parent" of
the previous one. up
corresponds to the file `..' in unix
and PC file systems.
(The following note does not refer to any file system currently
supported by MIT Scheme, but is included for completeness.) In file
systems that do not have "hierarchical" structure, a specified
directory component will always be a list whose first element is
absolute
. If the system does not support directories other than
a single global directory, the list will have no other elements. If the
system supports "flat" directories, i.e. a global set of directories
with no subdirectories, then the list will contain a second element,
which is either a string or wild
. In other words, a
non-hierarchical file system is treated as if it were hierarchical, but
the hierarchical features are unused. This representation is somewhat
inconvenient for such file systems, but it discourages programmers from
making code depend on the lack of a file hierarchy.
wild
,
meaningful only when used in conjunction with the directory reader.
wild
,
meaningful only when used in conjunction with the directory reader.
newest
, which means to choose the largest available version
number for that file; the symbol oldest
, which means to choose
the smallest version number; or the symbol wild
, meaningful only
when used in conjunction with the directory reader. In the future some
other possible values may be added, e.g. installed
. Note that
currently no file systems support version numbers; thus this component
is not used and should be specified as #f
.
(make-pathname #f #f '(absolute "usr" "morris") "foo" "scm" #f) => #[pathname 67 "/usr/morris/foo.scm"]
(define x (->pathname "/usr/morris/foo.scm")) (pathname-host x) => #[host 1] (pathname-device x) => unspecific (pathname-directory x) => (absolute "usr" "morris") (pathname-name x) => "foo" (pathname-type x) => "scm" (pathname-version x) => unspecific
unspecific
because this might not be permitted in some
situations.
(define p (->pathname "/usr/blisp/rel15")) p => #[pathname 71 "/usr/blisp/rel15"] (pathname-new-name p "rel100") => #[pathname 72 "/usr/blisp/rel100"] (pathname-new-directory p '(relative "test" "morris")) => #[pathname 73 "test/morris/rel15"] p => #[pathname 71 "/usr/blisp/rel15"]
pathname-new-component
operations, except that they only change the specified component
if it has the value #f
in pathname.
#t
if object is a pathname; otherwise returns
#f
.
#t
if pathname1 is equivalent to pathname2;
otherwise returns #f
.
Pathnames are equivalent if all of their components are equivalent,
hence two pathnames that are equivalent must identify the same file or
equivalent partial pathnames.
However, the converse is not true: non-equivalent pathnames may specify
the same file (e.g. via absolute and relative directory components),
and pathnames that specify no file at all (e.g. name and directory
components unspecified) may be equivalent.
#t
if pathname is an absolute rather than relative
pathname object; otherwise returns #f
. Specifically, this
procedure returns #t
when the directory component of
pathname is a list starting with the symbol absolute
, and
returns #f
in all other cases. All pathnames are either absolute
or relative, so if this procedure returns #f
, the argument is a
relative pathname.
#t
if pathname contains any wildcard components;
otherwise returns #f
.
*default-pathname-defaults*
and default-version defaults
to newest
.
The pathnames are combined by components: if pathname has a
non-missing component, that is the resulting component, otherwise the
component from defaults is used.
The default version can be #f
to preserve the information that
the component was missing from pathname.
The directory component is handled specially: if both pathnames have
directory components that are lists, and the directory component from
pathname is relative (i.e. starts with relative
), then the
resulting directory component is formed by appending pathname's
component to defaults's component.
For example:
(define path1 (->pathname "scheme/foo.scm")) (define path2 (->pathname "/usr/morris")) path1 => #[pathname 74 "scheme/foo.scm"] path2 => #[pathname 75 "/usr/morris"] (merge-pathnames path1 path2) => #[pathname 76 "/usr/scheme/foo.scm"] (merge-pathnames path2 path1) => #[pathname 77 "/usr/morris.scm"]
The merging rules for the version are more complex and depend on whether pathname specifies a name. If pathname does not specify a name, then the version, if not provided, will come from defaults. However, if pathname does specify a name then the version is not affected by defaults. The reason is that the version "belongs to" some other file name and is unlikely to have anything to do with the new one. Finally, if this process leaves the version missing, then default-version is used.
The net effect is that if the user supplies just a name, then the host, device, directory and type will come from defaults, but the version will come from default-version. If the user supplies nothing, or just a directory, the name, type and version will come over from defaults together.
set-working-directory-pathname!
sets this variable to a new
value, computed by merging the new working directory with the variable's
old value.
(define (pathname-default pathname device directory name type version) (make-pathname (pathname-host pathname) (or (pathname-device pathname) device) (or (pathname-directory pathname) directory) (or (pathname-name pathname) name) (or (pathname-type pathname) type) (or (pathname-version pathname) version)))
file-namestring
returns a string
representing just the name, type and version
components of pathname; the result of directory-namestring
represents just the host, device, and directory
components; and host-namestring
returns a string for just the
host portion.
enough-namestring
takes another argument, defaults.
It returns an abbreviated namestring that is just sufficient to identify
the file named by pathname when considered relative to the
defaults (which defaults to *default-pathname-defaults*
).
(file-namestring "/usr/morris/minor.van") => "minor.van" (directory-namestring "/usr/morris/minor.van") => "/usr/morris/" (enough-namestring "/usr/morris/men") => "men" ;perhaps
file-pathname
returns a pathname with just the
name, type and version components of pathname.
The result of directory-pathname
is a pathname containing the
host, device and directory components of pathname.
enough-pathname
takes another argument, defaults.
It returns an abbreviated pathname that is just sufficient to identify
the file named by pathname when considered relative to the
defaults (which defaults to *default-pathname-defaults*
).
These procedures are similar to file-namestring
,
directory-namestring
and enough-namestring
, but they
return pathnames instead of strings.
pathname-as-directory
.
(directory-pathname-as-file (->pathname "/usr/blisp/")) => #[pathname "/usr/blisp"]
directory-pathname-as-file
.
(pathname-as-directory (->pathname "/usr/blisp/rel5")) => #[pathname "/usr/blisp/rel5/"]
This section gives some standard operations on host objects, and some procedures that return some useful pathnames.
#t
if object is a pathname host; otherwise returns
#f
.
#t
if host1 and host2 denote the same
pathname host; otherwise returns #f
.
local-host
. If
the initialization file does not exist this procedure returns #f
.
Under unix, the init file is called `.scheme.init'; under Windows
and OS/2, the init file is called `scheme.ini'. In either
case, it is located in the user's home directory, which is computed by
user-homedir-pathname
.
local-host
. The
concept of a "home directory" is itself somewhat
implementation-dependent, but it should be the place where the user
keeps personal files, such as initialization files and mail.
Under unix, the user's home directory is specified by the HOME
environment variable. If this variable is undefined, the user name is
computed using the getlogin
system call, or if that fails, the
getuid
system call. The resulting user name is passed to the
getpwnam
system call to obtain the home directory.
Under OS/2, several heuristics are tried to find the user's home
directory. First, if the environment variable HOME
is defined,
that is the home directory. If HOME
is undefined, but the
USERDIR
and USER
environment variables are defined and
the directory `%USERDIR%\%USER%' exists, then it is used. Failing
that, if the directory `%USER%' exists on the OS/2 system
drive, then it is used. As a last resort, the OS/2 system drive is
the home directory.
Like OS/2, the Windows implementation uses heuristics based on environment variables. The user's home directory is computed by examining several environment variables, in the following order:
HOMEDRIVE
and HOMEPATH
are both defined and
`%HOMEDRIVE%%HOMEPATH%' is an existing directory. (These variables
are automatically defined by Windows NT.)
HOME
is defined and `%HOME%' is an existing directory.
USERDIR
and USERNAME
are defined and
`%USERDIR%\%USERNAME%' is an existing directory.
USERDIR
and USER
are defined and
`%USERDIR%\%USER%' is an existing directory.
USERNAME
is defined and `%USERNAME%' is an existing
directory on the Windows system drive.
USER
is defined and `%USER%' is an existing directory on the
Windows system drive.
condition-type:file-operation-error
is signalled if
pathname cannot be located on the library search path.
(system-library-pathname "compiler.com") => #[pathname 45 "/usr/local/lib/mit-scheme/compiler.com"]
condition-type:file-operation-error
is signalled if
pathname cannot be located on the library search path.
(system-library-directory-pathname "options") => #[pathname 44 "/usr/local/lib/mit-scheme/options/"]
When MIT Scheme is started, the current working
directory (or simply, working directory) is initialized in an
operating-system dependent manner; usually, it is the directory in which
Scheme was invoked. The working directory can be determined from within
Scheme by calling the pwd
procedure, and changed by calling the
cd
procedure. Each REP loop has its own working directory,
and inferior REP loops initialize their working directory from the
value in effect in their superior at the time they are created.
pwd
is an alias for
working-directory-pathname
; the long name is intended for
programs and the short name for interactive use.
pathname-as-directory
. cd
is an alias for
set-working-directory-pathname!
; the long name is intended for
programs and the short name for interactive use.
Additionally, set-working-directory-pathname!
modifies the value
of
*default-pathname-defaults*
by merging the new working
directory into it.
When this procedure is executed in the top-level REP loop, it changes the working directory of the running Scheme executable.
(set-working-directory-pathname! "/usr/morris/blisp") => #[pathname "/usr/morris/blisp/"] (set-working-directory-pathname! "~") => #[pathname "/usr/morris/"]
This procedure signals an error if filename does not refer to an existing directory.
If filename describes a relative rather than absolute pathname, this procedure interprets it as relative to the current working directory, before changing the working directory.
(working-directory-pathname) => #[pathname "/usr/morris/"] (set-working-directory-pathname! "foo") => #[pathname "/usr/morris/foo/"]
pathname-as-directory
. In addition to binding the working
directory, with-working-directory-pathname
also binds the
variable *default-pathname-defaults*
, merging the old value of
that variable with the new working directory pathname. Both bindings
are performed in exactly the same way as dynamic binding of a variable
(see section Dynamic Binding).
This section describes procedures that manipulate files and directories.
Any of these procedures can signal a number of errors for many reasons.
The specifics of these errors are much too operating-system dependent to
document here. However, if such an error is signalled by one of
these procedures, it will be of type
condition-type:file-operation-error
.
#t
if filename is an existing file
or directory; otherwise they return #f
. In operating systems
that support symbolic links, if the file is a symbolic link,
file-exists-direct?
tests for the existence of the link, while
file-exists-indirect?
and file-exists?
test for the
existence of the file pointed to by the link.
delete-file
, but returns a boolean value indicating whether
an error occurred during the deletion. If no errors occurred, #t
is returned. If an error of type condition-type:file-error
or
condition-type:port-error
is signalled, #f
is returned.
condition-type:file-operation-error
is signalled if the
appropriate file cannot be located within the file system.
temporary-file-pathname
to create a temporary file, then
calls procedure with one argument, the pathname referring to that
file. When procedure returns, if the temporary file still exists,
it is deleted; then, the value yielded by procedure is returned.
If procedure escapes from its continuation, and the file still
exists, it is deleted.
If directory is specified, the temporary file will be stored
there. If it is not specified, or if it is #f
, the temporary
file will be stored in the directory returned by
temporary-directory-pathname
.
TMPDIR
,
TEMP
, or TMP
.
*default-pathname-defaults*
.
#t
if the file named filename exists and is a
directory. Otherwise returns #f
. In operating systems that
support symbolic links, if filename names a symbolic link, this
examines the file linked to, not the link itself.
#f
.
#t
if filename names a file that can be opened for
input; i.e. a readable file. Otherwise returns #f
.
#t
if filename names a file that can be opened for
output; i.e. a writeable file. Otherwise returns #f
.
#t
if filename names a file that can be executed.
Otherwise returns #f
. Under unix, an executable file is
identified by its mode bits. Under OS/2, an executable file has
one of the file extensions `.exe', `.com', `.cmd', or
`.bat'. Under Windows, an executable file has one of the file
extensions `.exe', `.com', or `.bat'.
0
and 7
inclusive; it is a bitwise-encoded predicate selector with 1
meaning "executable", 2
meaning "writeable", and 4
meaning "readable". file-access
returns #t
if
filename exists and satisfies the predicates selected by
mode. For example, if mode is 5
, then filename
must be both readable and executable. If filename doesn't exist,
or if it does not satisfy the selected predicates, #f
is
returned.
file-modes
returns an
exact non-negative integer encoding the file's permissions. The
encoding of this integer is operating-system dependent. Under unix, it
is the least-significant 12 bits of the st_mode
element of the
struct stat
structure. Under OS/2 and Windows, it is the file
attribute bits, which are described below. If filename does not
name an existing file, #f
is returned.
file-modes
. set-file-modes!
modifies the file's
permissions to be those encoded by modes.
file-modes
under OS/2. These bits are small
integers that are combined by adding to form a complete set of modes.
The integer zero represents a set of modes in which none of these bits
are set.
file-modes
under Windows. These bits are small
integers that are combined by adding to form a complete set of modes.
The integer zero represents a set of modes in which none of these bits
are set.
file-modification-time
returns #f
.
In operating systems that support symbolic links, if filename
names a symbolic link, file-modification-time
returns the
modification time of the file linked to. An alternate procedure,
file-modification-time-direct
, returns the modification time of
the link itself; in all other respects it is identical to
file-modification-time
. For symmetry,
file-modification-time-indirect
is a synonym of
file-modification-time
.
file-access-time
returns #f
.
In operating systems that support symbolic links, if filename
names a symbolic link, file-access-time
returns the access time
of the file linked to. An alternate procedure,
file-access-time-direct
, returns the access time of the link
itself; in all other respects it is identical to
file-access-time
. For symmetry, file-access-time-indirect
is a synonym of file-access-time
.
file-access-time
and file-modification-time
,
respectively. set-file-times!
alters the access and modification
times of the file specified by filename to the values given by
access-time and modification-time, respectively. For
convenience, either of the time arguments may be specified as #f
;
in this case the corresponding time is not changed.
set-file-times!
returns an unspecified value.
#f
is returned. Otherwise, the file is created and #t
is
returned. This is an atomic test-and-set operation, so it is useful as
a synchronization mechanism.
#f
.
In operating systems that support symbolic links, if filename
names a symbolic link, file-attributes
returns the attributes of
the link itself. An alternate procedure,
file-attributes-indirect
, returns the attributes of the file
linked to; in all other respects it is identical to
file-attributes
. For symmetry, file-attributes-direct
is
a synonym of file-attributes
.
The information returned by file-attributes
is decoded by
accessor procedures. The following accessors are defined in all
operating systems:
#t
if the file is a directory, a character string
(the name linked to) if a symbolic link, or #f
for all other
types of file.
1
.
The following additional accessors are defined under unix:
The following additional accessor is defined under OS/2 and Windows:
The following additional accessor is defined under OS/2:
->pathname
. The directory specified by directory is
read, and the contents of the directory is returned as a newly allocated
list of absolute pathnames. The result is sorted according to the usual
sorting conventions for directories, unless sort? is specified as
#f
. If directory has name, type, or version components,
the returned list contains only those pathnames whose name, type, and
version components match those of directory; wild
or
#f
as one of these components means "match anything".
The OS/2 and Windows implementations support "globbing", in which the
characters *
and ?
are interpreted to mean "match
anything" and "match any character", respectively. This "globbing"
is supported only in the file part of directory.
MIT Scheme provides a simple set of procedures for manipulating date and time information. There are four time representations, each of which serves a different purpose. Each representation may be converted to any of the others.
The primary time representation, universal time, is an exact
non-negative integer counting the number of seconds that have elapsed
since midnight January 1, 1900 UTC. (UTC stands for Coordinated
Universal Time, and is the modern name for Greenwich Mean Time.) This
format is produced by get-universal-time
and
decoded-time->universal-time
.
The second representation, decoded time, is a record structure in
which the time is broken down into components, such as month, minute,
etc. Decoded time is always relative to a particular time zone, which
is a component of the structure. This format is produced by
global-decoded-time
and local-decoded-time
.
The third representation, file time, is an exact non-negative
integer that is larger for increasing time. Unlike universal time,
this representation is operating-system dependent. This format is
produced by all of the file-attribute procedures, for example
file-modification-time
and file-attributes
.
The fourth representation, the time string, is an external representation for time. This format is defined by RFC-822, Standard for the format of ARPA Internet text messages, with the modification that years are represented as four-digit numbers rather than two-digit numbers. This format is the standard format for Internet email and numerous other network protocols.
Within this section, argument variables named universal-time, decoded-time, file-time, and time-string are respectively required to be of the corresponding format.
(get-universal-time) => 3131453078
epoch
is the representation of midnight January 1, 1970 UTC in
universal-time format.
epoch => 2208988800
Objects representing standard time components, such as seconds and
minutes, are required to be exact non-negative integers. Seconds and
minutes must be inclusively between 0
and 59
; hours
between 0
and 23
; days between 1
and 31
;
months between 1
and 12
; years are represented in
"four-digit" form, in which 1999 is represented as 1999
---
not 99
.
(pp (local-decoded-time)) -| #[decoded-time 76] -| (second 2) -| (minute 12) -| (hour 11) -| (day 27) -| (month 4) -| (year 1999) -| (day-of-week 1) -| (daylight-savings-time 1) -| (zone 5)
(pp (global-decoded-time)) -| #[decoded-time 77] -| (second 8) -| (minute 12) -| (hour 15) -| (day 27) -| (month 4) -| (year 1999) -| (day-of-week 1) -| (daylight-savings-time 0) -| (zone 0)
If zone is not supplied or is #f
, the resulting decoded
time will be represented in the local time zone. Otherwise, zone
must be a valid time zone, and the result will be represented in that
zone.
Warning: because this procedure depends on the operating system's runtime library, it is not capable of representing all dates. In particular, on most unix systems, it is not possible to encode dates that occur prior to midnight, January 1, 1970 UTC. Attempting to do this will signal an error.
(pp (make-decoded-time 0 9 11 26 3 1999)) -| #[decoded-time 19] -| (second 0) -| (minute 9) -| (hour 11) -| (day 26) -| (month 3) -| (year 1999) -| (day-of-week 4) -| (daylight-savings-time 0) -| (zone 5) (pp (make-decoded-time 0 9 11 26 3 1999 3)) -| #[decoded-time 80] -| (second 0) -| (minute 9) -| (hour 11) -| (day 26) -| (month 3) -| (year 1999) -| (day-of-week 4) -| (daylight-savings-time 0) -| (zone 3)
(decoded-time/second (local-decoded-time)) => 17 (decoded-time/year (local-decoded-time)) => 1999 (decoded-time/day (local-decoded-time)) => 26
0
(Monday) and 6
(Sunday),
inclusive.
(decoded-time/day-of-week (local-decoded-time)) => 4
#t
if decoded-time is represented using daylight
savings time. Otherwise return #f
.
(decoded-time/daylight-savings-time? (local-decoded-time)) => #f
-24
and +24
inclusive,
that when multiplied by 3600
is an integer. The value is the
number of hours west of UTC.
(decoded-time/zone (local-decoded-time)) => 5
#t
if object is an exact number between -24
and +24
inclusive, that when multiplied by 3600
is an
integer.
(time-zone? -5) => #t (time-zone? 11/2) => #t (time-zone? 11/7) => #f
1
and 12
inclusive.
(month/max-days 2) => 29 (month/max-days 3) => 31 (month/max-days 4) => 30
As stated above, file time is operating-system dependent. As of this writing, two formats are used. For unix and Windows systems, file time is the number of seconds since midnight January 1, 1970 UTC (the standard unix time convention).
OS/2 represents file time as a 32-bit unsigned integer, in which the time components are broken down into unsigned bit fields. The components are always stated in local time. The fields, from MSB to LSB, are:
The following procedures generate their results in file-time format:
file-access-time file-access-time-direct file-access-time-indirect file-modification-time file-modification-time-direct file-modification-time-indirect file-attributes/access-time file-attributes/modification-time file-attributes/change-time
Additionally, set-file-times!
accepts its time arguments in
file-time format.
The procedures described in this section convert times from one format to another.
(pp (universal-time->local-decoded-time (get-universal-time))) -| #[decoded-time 21] -| (second 23) -| (minute 57) -| (hour 17) -| (day 29) -| (month 4) -| (year 1999) -| (day-of-week 3) -| (daylight-savings-time 1) -| (zone 5) (pp (universal-time->global-decoded-time (get-universal-time))) -| #[decoded-time 22] -| (second 27) -| (minute 57) -| (hour 21) -| (day 29) -| (month 4) -| (year 1999) -| (day-of-week 3) -| (daylight-savings-time 0) -| (zone 0)
(universal-time->file-time (get-universal-time)) => 925422988
(universal-time->local-time-string (get-universal-time)) => "Thu, 29 Apr 1999 17:55:31 -0400" (universal-time->global-time-string (get-universal-time)) => "Thu, 29 Apr 1999 21:55:51 +0000"
(decoded-time->universal-time (local-decoded-time)) => 3134411942 (decoded-time->universal-time (global-decoded-time)) => 3134411947
(decoded-time->file-time (local-decoded-time)) => 925423191 (decoded-time->file-time (global-decoded-time)) => 925423195
(decoded-time->string (local-decoded-time)) => "Thu, 29 Apr 1999 18:00:43 -0400" (decoded-time->string (global-decoded-time)) => "Thu, 29 Apr 1999 22:00:46 +0000"
(file-time->universal-time (file-modification-time "/")) => 3133891907
(pp (file-time->local-decoded-time (file-modification-time "/"))) -| #[decoded-time 26] -| (second 47) -| (minute 31) -| (hour 17) -| (day 23) -| (month 4) -| (year 1999) -| (day-of-week 4) -| (daylight-savings-time 1) -| (zone 5) (pp (file-time->global-decoded-time (file-modification-time "/"))) -| #[decoded-time 27] -| (second 47) -| (minute 31) -| (hour 21) -| (day 23) -| (month 4) -| (year 1999) -| (day-of-week 4) -| (daylight-savings-time 0) -| (zone 0)
(file-time->local-time-string (file-modification-time "/")) => "Fri, 23 Apr 1999 17:31:47 -0400" (file-time->global-time-string (file-modification-time "/")) => "Fri, 23 Apr 1999 21:31:47 +0000"
(string->universal-time "Fri, 23 Apr 1999 21:31:47 +0000") => 3133888307 (string->universal-time "Fri, 23 Apr 1999 17:31:47 -0400") => 3133888307
(pp (string->decoded-time "Fri, 23 Apr 1999 17:31:47 -0400")) -| #[decoded-time 30] -| (second 47) -| (minute 31) -| (hour 17) -| (day 23) -| (month 4) -| (year 1999) -| (day-of-week 4) -| (daylight-savings-time 0) -| (zone 4)
(string->file-time "Fri, 23 Apr 1999 17:31:47 -0400") => 924899507
The normal external representation for time is the time string, as described above. The procedures in this section generate alternate external representations of time which are more verbose and may be more suitable for presentation to human readers.
(decoded-time/date-string (local-decoded-time)) => "Tuesday March 30, 1999" (decoded-time/time-string (local-decoded-time)) => "11:22:38 AM"
0
and 6
inclusive. day-of-week/long-string
returns a long string that
fully spells out the name of the day. day-of-week/short-string
returns a shortened string that abbreviates the day to three letters.
(day-of-week/long-string 0) => "Monday" (day-of-week/short-string 0) => "Mon" (day-of-week/short-string 3) => "Thu"
1
and 12
inclusive. month/long-string
returns a long string that fully
spells out the name of the month. month/short-string
returns a
shortened string that abbreviates the month to three letters.
(month/long-string 1) => "January" (month/short-string 1) => "Jan" (month/short-string 10) => "Oct"
(time-zone->string 5) => "-0500" (time-zone->string -4) => "+0400" (time-zone->string 11/2) => "-0530"
The previous section dealt with procedures that manipulate clock time. This section describes procedures that deal with computer time: elapsed CPU time, elapsed real time, and so forth. These procedures are useful for measuring the amount of time it takes to execute code.
Some of the procedures in this section manipulate a time representation called ticks. A tick is a unit of time that is unspecified here but can be converted to and from seconds by supplied procedures. A count in ticks is represented as an exact integer. At present each tick is one millisecond, but this may change in the future.
(process-time-clock) => 21290
(real-time-clock) => 33474836
(internal-time/ticks->seconds 21290) => 21.29 (internal-time/ticks->seconds 33474836) => 33474.836
(internal-time/seconds->ticks 20.88) => 20880 (internal-time/seconds->ticks 20.83) => 20830
(internal-time/ticks->seconds (process-time-clock))
Example:
(system-clock) => 20.88
(runtime) => 20.83
This procedure is most useful for doing performance measurements, and is designed to have relatively low overhead.
(with-timings (lambda () ...hairy computation...) (lambda (run-time gc-time real-time) (write (internal-time/ticks->seconds run-time)) (write-char #\space) (write (internal-time/ticks->seconds gc-time)) (write-char #\space) (write (internal-time/ticks->seconds real-time)) (newline)))
If runtime? is #f
, the elapsed time is deducted from the
elapsed system time returned by runtime
.
While this procedure can be used for time measurement, its interface is
somewhat clumsy for that purpose. We recommend that you use
with-timings
instead, because it is more convenient and has lower
overhead.
(measure-interval #t (lambda (start-time) (let ((v ...hairy computation...)) (lambda (end-time) (write (- end-time start-time)) (newline) v))))
MIT Scheme provides the ability to run and control subprocesses. This support is divided into two parts: a low-level set of primitives that maps onto the underlying operating system's process-control primitives, and a high-level set of procedures for starting a subprocess and running it to completion in a single call. Subprocesses that are run in the latter fashion are referred to as synchronous, because they are started and stopped in synchrony with a Scheme procedure call.
This chapter documents Scheme's high-level synchronous-subprocess support. The low-level support is not documented but is available for those who are willing to read the source code.
Synchronous-subprocess support is a run-time-loadable option. To use it, execute
(load-option 'synchronous-subprocess)
once before calling it.
There are two commands for running synchronous subprocesses under
Scheme. run-shell-command
is very simple to use, provides access
to all shell features, and is to be preferred in most situations.
run-synchronous-subprocess
allows direct execution of a program
and precise control of the command-line arguments passed to the program,
but does not provide file globbing, I/O redirection, or other shell
features.
The options are a sequence of keyword/value pairs that specify optional behavior. See below for more information about options.
run-shell-command
waits until the subprocess completes its
execution and returns the exit code from the subprocess. If the
subprocess is killed or stopped, an error is signalled and the procedure
does not return.
The options are a sequence of keyword/value pairs that specify optional behavior. See below for more information about options.
run-synchronous-subprocess
waits until the subprocess completes
its execution and returns the exit code from the subprocess. If the
subprocess is killed or stopped, an error is signalled and the procedure
does not return.
If a subprocess spawned by one of the above procedures is killed or suspended, then one of the following errors will be signalled.
condition-type:subprocess-abnormal-termination
. It is signalled
when the subprocess is killed.
Subprocess is an object that represents the subprocess involved. The internals of this object can be accessed but the interface is not documented at this time; see the source code for details.
Reason is interesting only on unix systems, where it is the signal that killed the process. On other systems it has a fixed value that conveys no useful information.
condition-type:subprocess-abnormal-termination
. It is signalled
when the subprocess is stopped or suspended.
Subprocess is an object that represents the subprocess involved. The internals of this object can be accessed but the interface is not documented at this time; see the source code for details.
Reason is interesting only on unix systems, where it is the signal that stopped the process. On other systems it has a fixed value that conveys no useful information.
condition-type:error
. This
is an abstract type that is never signalled. It is provided so that
condition handlers can be bound to it.
The following subprocess options may be passed to
run-shell-command
or run-synchronous-subprocess
. These
options are passed as alternating keyword/value pairs, for example:
(run-shell-command "ls /" 'output my-output-port 'output-buffer-size 8192)
The example shows a shell command being run with two options specified:
output
and output-buffer-size
.
#f
, indicating that the subprocess has no
standard input.
The default value of this option is #f
.
(call-with-input-file "foo.in" (lambda (port) (run-shell-command "cat > /dev/null" 'input port)))
input
option is #f
.
Line-ending must be either a string specifying the line ending, or
the symbol default
, meaning to use the operating system's
standard line ending. In either case, newline characters to be written
to the input
port are translated to the specified line ending
before being written.
The default value of this option is default
.
(call-with-input-file "foo.in" (lambda (port) (run-shell-command "cat > /dev/null" 'input port 'input-line-translation "\r\n")))
input
option is #f
. N must be an exact positive
integer specifying the number of characters the buffer can hold.
The default value of this option is 512
.
(call-with-input-file "foo.in" (lambda (port) (run-shell-command "cat > /dev/null" 'input port 'input-buffer-size 4096)))
#f
, indicating that the
subprocess has no standard output or standard error.
The default value of this option is the value of
(current-output-port)
.
(call-with-output-file "foo.out" (lambda (port) (run-shell-command "ls -la /etc" 'output port)))
output
option is #f
. Line-ending must be either a
string specifying the line ending, or the symbol default
, meaning
to use the operating system's standard line ending. In either case,
newline characters read from the subprocess port are translated to the
specified line ending.
The default value of this option is default
.
(call-with-output-file "foo.out" (lambda (port) (run-shell-command "ls -la /etc" 'output port 'output-line-translation "\r\n")))
output
option is #f
. N must be an exact positive
integer specifying the number of characters the buffer can hold.
The default value of this option is 512
.
(call-with-output-file "foo.out" (lambda (port) (run-shell-command "ls -la /etc" 'output port 'output-buffer-size 4096)))
#f
indicating that no hook is supplied. This
option is mostly useful for interactive systems. For example, the Edwin
text editor uses this to update output buffers when running some
subprocesses.
The default value of this option is #f
.
(run-shell-command "ls -la /etc" 'redisplay-hook (lambda () (update-buffer-contents buffer)))
#f
indicating the default environment. If it is a vector of
strings, each string must be a name/value pair where the name and value
are separated by an equal sign, for example, "foo=bar"
. To
define a variable with no value, just omit the value, as in "foo="
.
Note that the variable scheme-subprocess-environment
is bound to
the default subprocess environment.
The default value of this option is #f
.
(run-shell-command "ls -la /etc" 'environment (let* ((v scheme-subprocess-environment) (n (vector-length v)) (v (vector-grow v (+ n 1)))) (vector-set! v n "TERM=none") v))
The default value of this option is (working-directory-pathname)
.
(run-shell-command "ls -la" 'working-directory "/etc/")
The default value of this option is #f
.
(run-shell-command "ls -la /etc" 'use-pty? #t)
run-shell-command
.
The default value of this option is (os/shell-file-name)
. This
is the value of the environment variable SHELL
, or if
SHELL
is not set, the value is operating-system dependent as
follows:
COMSPEC
is
used, or if that is not set, `cmd.exe' on the current path.
COMSPEC
is used. If that is not set, `cmd.exe' is used for Windows NT, or
`command.com' is used for Windows 9x; in each case the shell is
found by searching the path.
(run-shell-command "ls -la /etc" 'shell-file-name "/usr/local/bin/bash")
MIT Scheme provides access to sockets, which are a mechanism for inter-process communication. TCP stream sockets are supported, which communicate between computers over a TCP/IP network. TCP sockets are supported on all operating systems.
TCP sockets have two distinct interfaces: one interface to implement a client and another to implement a server. The basic protocol is that servers set up a listening port and wait for connections from clients. Implementation of clients is simpler and will be treated first.
The socket procedures accept two special arguments, called
host-name and service. Host-name is a string which
must be the name of an internet host. It is looked up using the
ordinary lookup rules for your computer. For example, if your host is
foo.mit.edu
and host-name is "bar"
, then it
specifies bar.mit.edu
.
Service specifies the service to which you will connect. A
networked computer normally provides several different services, such as
telnet or FTP. Each service is associated with a unique port
number; for example, the "www"
service is associated with port
80
. The service argument specifies the port number, either
by a string, or directly as an exact non-negative integer. Port strings
are decoded by the operating system using a table; for example, on unix
the table is in `/etc/services'. Usually you will use a port
string rather than a number.
open-tcp-stream-socket
opens a connection to the host specified
by host-name. Host-name is looked up using the ordinary
lookup rules for your computer. The connection is established to the
service specified by service. The returned value is an I/O
port, to which you can read and write characters using ordinary Scheme
I/O procedures such as read-char
and write-char
.
Buffer-size specifies the size of the read and write buffers used
by the port; if this is unspecified or #f
, the buffers will hold
4096
bytes.
Line-translation specifies how end-of-line characters will be
translated when reading or writing to the socket. If this is
unspecified or #f
, then lines will be terminated by CR-LF,
which is the standard for most internet protocols. Otherwise, it must
be a string, which specifies the line-ending character sequence to use.
When you wish to close the connection, just use close-port
.
As an example, here is how you can open a connection to a web server:
(open-tcp-stream-socket "web.mit.edu" "www")
Next we will treat setting up a TCP server, which is slightly more complicated. Creating a server is a two-part process. First, you must open a server socket, which causes the operating system to listen to the network on a port that you specify. Once the server socket is opened, the operating system will allow clients to connect to your computer on that port.
In the second step of the process, you accept the connection, which completes the connection initiated by the client, and allows you to communicate with the client. Accepting a connection does not affect the server socket; it continues to listen for additional client connections. You can have multiple client connections to the same server socket open simultaneously.
An error is signalled if another process is already listening on the
service. Additionally, ports whose number is less than 1024
are
privileged on many operating systems, and cannot be used by
non-privileged processes; attempting to open a server socket to one of
these ports will signal an error if you do not have administrative
privileges.
read-char
and
write-char
.
The argument block? says what to do if no client has connected at
the time of the call. If #f
, it says to return immediately with
two values of #f
. Otherwise, the call waits until a client
connects.
The argument peer-address is either #f
or an IP
address as allocated by allocate-host-address
. If it is an
IP address, the address is modified to be the address of the client
making the connection.
Note that closing the port returned by this procedure does not affect
server-socket; it just closes the particular client connection
that was opened by the call. To close server-socket, use
close-tcp-server-socket
.
This section contains assorted operating-system facilities that don't fit into other categories.
microcode-id/operating-system
is bound to a symbol that specifies
the type of operating system that Scheme is running under. There are
three possible values: unix
, os/2
, or nt
.
microcode-id/operating-system-name
is a string containing the
same name as microcode-id/operating-system
; the latter is created
by interning the former as a symbol.
"GNU/Linux" "FreeBSD" "HP-UX" "SunOS" "OS/2 2.1" "OS/2 4.0" "Microsoft Windows NT 4.0 (Build 1381; Service Pack 3)" "Microsoft Windows 98 (Build 410)"
For Windows systems, it is recommended that you match on the prefix of
this string and ignore the "Build"
suffix. This is because the
suffix may contain information about service packs or fixes, while the
prefix will be constant for a particular version of Windows.
The next few procedures provide access to the domain name service
(DNS), which maintains associations between internet host names
such as "www.swiss.ai.mit.edu"
and IP addresses, such as
18.23.0.16
. In MIT Scheme, we represent an internet host name as
a string, and an IP address as a byte vector of length 4 (byte
vectors are just character strings that are accessed using
vector-8b-ref
rather than string-ref
). The bytes in an
IP address read in the same order as they do when written out:
(get-host-by-name "www.swiss") => #("\022\027\000\020")
#f
if there is no such host. Usually the returned vector has
only one element, but if a host has more than one network interface, the
vector might have more than one element.
(get-host-by-name "www.swiss") => #("\022\027\000\020")
#f
if there
is no such host.
(get-host-by-address "\022\027\000\020") => "swissnet.ai.mit.edu"
(canonical-host-name "zurich") => "zurich.ai.mit.edu" (canonical-host-name "www.swiss") => "swissnet.ai.mit.edu"
In both examples, the default internet domain `ai.mit.edu' is added
to host-name. In the second example, "www.swiss"
is an
alias for another computer named "swissnet"
.
(get-host-name) => "aarau"
get-host-name
:
(os/hostname) => "aarau.ai.mit.edu"
tcp-server-connection-accept
.
Go to the first, previous, next, last section, table of contents.