Compare commits
199 Commits
main
...
r0-6-stabl
| Author | SHA1 | Date |
|---|---|---|
|
|
d125af1559 | |
|
|
71a747b4f2 | |
|
|
3ee7a21884 | |
|
|
d8b1c64044 | |
|
|
640281efcb | |
|
|
0e0faad5e1 | |
|
|
b4a1ae5533 | |
|
|
c46c84f66c | |
|
|
bf9dc18cc6 | |
|
|
5940d19ff4 | |
|
|
a3e4aad42f | |
|
|
4a80163ecf | |
|
|
97ed3425cd | |
|
|
da739b9032 | |
|
|
8f234fc733 | |
|
|
9a7d5fb8dd | |
|
|
1ab6384c63 | |
|
|
d21779c9ba | |
|
|
e76661aadd | |
|
|
5db687eae1 | |
|
|
3b4becd2ba | |
|
|
329e4539b0 | |
|
|
45acda7c3f | |
|
|
2e37299496 | |
|
|
89d3cc13e5 | |
|
|
086e0d434c | |
|
|
d5dc6c5b45 | |
|
|
4cd8cffe81 | |
|
|
2d4ce713b7 | |
|
|
d11a09044c | |
|
|
e1bcf389b6 | |
|
|
8246b41681 | |
|
|
bbcf682f5b | |
|
|
bfbb3e31ea | |
|
|
d18adb9c2b | |
|
|
c965536804 | |
|
|
fbfe81aa85 | |
|
|
842fc396b8 | |
|
|
2e4f79161c | |
|
|
2ec9c3d879 | |
|
|
6abcd34721 | |
|
|
cc0c0cf571 | |
|
|
809b1bc022 | |
|
|
c1eac4922d | |
|
|
cc5bfef76e | |
|
|
364eb89dd8 | |
|
|
d6d422006f | |
|
|
4702963425 | |
|
|
a3f0a3ffb9 | |
|
|
0698e636f1 | |
|
|
ed254f1366 | |
|
|
abd81132dc | |
|
|
5f3c53746f | |
|
|
ec4ec22eac | |
|
|
f4fbe4c986 | |
|
|
cfcb6a1b05 | |
|
|
525f13a82b | |
|
|
7dbf2eca7c | |
|
|
e28875cd51 | |
|
|
a049a71641 | |
|
|
ac0edb679b | |
|
|
89db21acf6 | |
|
|
03d11e2576 | |
|
|
354188c3c5 | |
|
|
0628b66c3e | |
|
|
6aa549d288 | |
|
|
fc88c1907a | |
|
|
da3caf4f5b | |
|
|
9da5680d55 | |
|
|
027ce1b9d7 | |
|
|
99f77e2c06 | |
|
|
e7585fb617 | |
|
|
90cf44f3b9 | |
|
|
ce9da610e6 | |
|
|
43e5f6fb8c | |
|
|
1e6d6d0841 | |
|
|
8218b146f8 | |
|
|
2bc4c06457 | |
|
|
3c4a6c7c46 | |
|
|
11299af1a4 | |
|
|
5107390fe2 | |
|
|
c7d103da99 | |
|
|
290104da0a | |
|
|
9174add359 | |
|
|
e42ed5864e | |
|
|
5c0ff0293b | |
|
|
f2e92c652a | |
|
|
fa7910c741 | |
|
|
89aeaf3d14 | |
|
|
8ddb1f619c | |
|
|
142b393ab8 | |
|
|
66b2cd8a13 | |
|
|
e534395099 | |
|
|
287a829cbd | |
|
|
55ffeb22d8 | |
|
|
52ac78e0aa | |
|
|
05e38a42da | |
|
|
8b334402ae | |
|
|
a41eb3da04 | |
|
|
069f638d8f | |
|
|
491c83cae7 | |
|
|
0358d6bb0e | |
|
|
7b13b9bebb | |
|
|
622ef7a99f | |
|
|
bcbd16ff0a | |
|
|
69248ecad2 | |
|
|
84f85be750 | |
|
|
523b402079 | |
|
|
90ba284584 | |
|
|
388d2f7b2b | |
|
|
bd890a7338 | |
|
|
47f074ba5c | |
|
|
f344e2be87 | |
|
|
e603ebb626 | |
|
|
6ad71da933 | |
|
|
fbbf31a1d8 | |
|
|
6f771517e1 | |
|
|
5e52592084 | |
|
|
47b9d6028e | |
|
|
f5833ad272 | |
|
|
bdf5f8e09f | |
|
|
1e098d1ced | |
|
|
57fbec4ef2 | |
|
|
0562f3301d | |
|
|
2b2fee0632 | |
|
|
0a899ac0fd | |
|
|
8fd66025f0 | |
|
|
bc7e37593c | |
|
|
3ff781f491 | |
|
|
780da3558f | |
|
|
a3d560c2ba | |
|
|
252e390354 | |
|
|
d1b1c3dee3 | |
|
|
6582c616a3 | |
|
|
11880601dd | |
|
|
ba76b7a3cc | |
|
|
e8a662ea1b | |
|
|
9a22e55080 | |
|
|
3f108f501f | |
|
|
d772a5df84 | |
|
|
cb9f440657 | |
|
|
33fe47abca | |
|
|
90ea0cf502 | |
|
|
b7388740b9 | |
|
|
03ab628c93 | |
|
|
eb9410cc44 | |
|
|
af976ddde2 | |
|
|
da53963d82 | |
|
|
5330ba06e0 | |
|
|
065d686d21 | |
|
|
655a2e5cc2 | |
|
|
1fa4ea33ac | |
|
|
8df6b631e1 | |
|
|
9742102f34 | |
|
|
c46ec9118a | |
|
|
dfa05a0c5c | |
|
|
bcf88c05d0 | |
|
|
6b5e75bd3f | |
|
|
2aac5914d6 | |
|
|
9378e2ff27 | |
|
|
b85d581f25 | |
|
|
8dfdf2c868 | |
|
|
ba5cdcf6fb | |
|
|
442559a708 | |
|
|
2336171f47 | |
|
|
9b29fff8e1 | |
|
|
903fdad089 | |
|
|
43f16f70e9 | |
|
|
327d7a6dfc | |
|
|
312d54708a | |
|
|
37e4f027eb | |
|
|
a2b0bea3ad | |
|
|
b1cc92b55f | |
|
|
ed3cc365b0 | |
|
|
acb0c8265f | |
|
|
e60e77997f | |
|
|
9d206dae0c | |
|
|
3198c650f8 | |
|
|
1f1081b8bf | |
|
|
1521521116 | |
|
|
be8a63dbe8 | |
|
|
37b31fc65a | |
|
|
ca97d21195 | |
|
|
f376ab6d8e | |
|
|
b7bb1fa2e5 | |
|
|
9d93d5a61e | |
|
|
b036a6da1c | |
|
|
c350288e41 | |
|
|
a54b97b81f | |
|
|
3c92196d13 | |
|
|
1f31b70242 | |
|
|
ce90c83263 | |
|
|
29258b6adc | |
|
|
7bc10a0d0e | |
|
|
cbfa04d530 | |
|
|
7b9606a7bc | |
|
|
8805f7b7cc | |
|
|
3e397f65c5 | |
|
|
37210efdc5 |
|
|
@ -26,3 +26,11 @@ _$*
|
|||
*.ln
|
||||
core
|
||||
# CVS default ignores end
|
||||
Makefile
|
||||
configure
|
||||
config.log
|
||||
config.cache
|
||||
config.status
|
||||
scsh.image
|
||||
scshvm
|
||||
go
|
||||
|
|
|
|||
7
COPYING
7
COPYING
|
|
@ -1,4 +1,8 @@
|
|||
Copyright (c) 1993-1999 Richard Kelsey and Jonathan Rees
|
||||
Copyright (c) 1993-2003 Richard Kelsey and Jonathan Rees
|
||||
Copyright (c) 1994-2003 by Olin Shivers and Brian D. Carlstrom.
|
||||
Copyright (c) 1999-2003 by Martin Gasbichler.
|
||||
Copyright (c) 2001-2003 by Michael Sperber.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -23,7 +27,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
Distributing Autoconf Output
|
||||
****************************
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
|
||||
|
||||
Welcome to the Scsh CVS Repository !!!
|
||||
|
||||
|
||||
|
||||
This file contains some instructions about how to build Scsh after you
|
||||
freshly checked out the "scsh-0.6" module. These instructions do *not*
|
||||
apply to the module named "scsh" or the Scsh distribution itself.
|
||||
|
||||
There is currently no scheme to tag working snapshots of the
|
||||
repository, so anything may happen during the build process. The scsh
|
||||
team does in general *not* provide support for code obtained from the
|
||||
CVS repository.
|
||||
|
||||
During the build process a number of auto-generated files not included
|
||||
in the CVS repository are built. It is highly recommended to follow
|
||||
these instructions carefully as otherwise incompatible versions of
|
||||
generated files may result. Note that you need GNU make for this
|
||||
process.
|
||||
|
||||
To build Scsh, proceed as follows:
|
||||
|
||||
1.) You must have a working version of Scheme 48, version 0.53. Nothing
|
||||
older, nothing newer. Just 0.53. If you don't have, get it from
|
||||
http://www.s48.org/0.53/scheme48-0.53.tgz and install Scheme
|
||||
48. Change the value of the variable BUILD_RUNNABLE in Makefile.in
|
||||
so that it will point to the Scheme 48 executable.
|
||||
|
||||
2.) "cd" into the directory which contains the source code (normally
|
||||
scsh-0.6) and run the script autogen.sh:
|
||||
|
||||
./autogen.sh
|
||||
|
||||
This will take several minutes and generate the source code for
|
||||
the virtual machine and two images the Makefile relies
|
||||
on. Furthermore the configure file will be generated. This script
|
||||
calls autoheader and autoconf from the GNU Autoconf package. You
|
||||
will need a recent version of Autoconf. Version 2.52 is okay,
|
||||
version 2.13 is too old.
|
||||
|
||||
3.) Configure the system:
|
||||
|
||||
./configure
|
||||
|
||||
You presumably want to add the --prefix flag here to determine the
|
||||
installation directory. This will generate the Makefile.
|
||||
|
||||
4.) Build the system:
|
||||
|
||||
make
|
||||
|
||||
If anything fails here, fix the problem and/or contact the authors.
|
||||
|
||||
5.) You should have a runnable version of the system that can be
|
||||
started in the main directory like this:
|
||||
|
||||
./go
|
||||
|
||||
6.) To install Scsh, type:
|
||||
|
||||
make install
|
||||
|
||||
Note that it is not recommended to have a CVS version of Scsh for
|
||||
daily use.
|
||||
|
||||
7.) If you intend to build on a different platform later, do a
|
||||
|
||||
make distclean
|
||||
|
||||
and restart at step 3.
|
||||
|
||||
|
||||
You should repeat the whole build process whenever there are changes
|
||||
to files in the directories scheme/vm, scheme/rts or
|
||||
scheme/bcomp. Watch the run of cvs update carefully and/or subscribe
|
||||
to the list scsh-checkins@lists.sourceforge.net.
|
||||
|
||||
|
||||
Enjoy!!!
|
||||
|
||||
|
||||
The Scsh developers
|
||||
|
||||
137
INSTALL
137
INSTALL
|
|
@ -1,120 +1,49 @@
|
|||
This is a generic INSTALL file for utilities distributions.
|
||||
If this package does not come with, e.g., installable documentation or
|
||||
data files, please ignore the references to them below.
|
||||
Installing scsh
|
||||
|
||||
[For information specific to Scheme 48, see doc/install.txt.]
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation, and
|
||||
creates the Makefile(s) (one in each subdirectory of the source
|
||||
directory). In some packages it creates a C header file containing
|
||||
system-dependent definitions. It also creates a file `config.status'
|
||||
that you can run in the future to recreate the current configuration.
|
||||
|
||||
To compile this package:
|
||||
This file describes how to install scsh from the source package. If
|
||||
you have obtained the source tree from CVS refer to the file
|
||||
CVS_README.
|
||||
|
||||
1. Configure the package for your system.
|
||||
|
||||
Normally, you just `cd' to the directory containing the package's
|
||||
source code and type `./configure'. If you're using `csh' on an old
|
||||
version of System V, you might need to type `sh configure' instead to
|
||||
prevent `csh' from trying to execute `configure' itself.
|
||||
Just `cd' to the directory containing this README file and type
|
||||
|
||||
Running `configure' takes a minute or two. While it is running, it
|
||||
prints some messages that tell what it is doing. If you don't want to
|
||||
see the messages, run `configure' with its standard output redirected
|
||||
to `/dev/null'; for example, `./configure >/dev/null'.
|
||||
./configure
|
||||
|
||||
You can pass some additional options to the configure script, along
|
||||
them the installation directory with the
|
||||
--prefix=/my/install/location option. Type ./configure --help to
|
||||
get a list of all switches.
|
||||
Running `configure' takes a minute or two. While it is running, it
|
||||
prints some messages that tell what it is doing. Consult the file
|
||||
config.log if anything went wrong.
|
||||
|
||||
To compile the package in a different directory from the one
|
||||
containing the source code, you must use a version of `make' that
|
||||
supports the `VPATH' variable, such as GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'. If
|
||||
for some reason `configure' is not in the source code directory that
|
||||
you are configuring, then it will report that it can't find the source
|
||||
code. In that case, run `configure' with the option `--srcdir=DIR',
|
||||
where DIR is the directory that contains the source code.
|
||||
2. Type
|
||||
|
||||
By default, `make install' will install the package's files in
|
||||
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||
installation prefix other than `/usr/local' by giving `configure' the
|
||||
option `--prefix=PATH'. Alternately, you can do so by consistently
|
||||
giving a value for the `prefix' variable when you run `make', e.g.,
|
||||
make prefix=/usr/gnu
|
||||
make prefix=/usr/gnu install
|
||||
make
|
||||
|
||||
to compile scsh.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
give `configure' the option `--exec-prefix=PATH' or set the `make'
|
||||
variable `exec_prefix' to PATH, the package will use PATH as the prefix
|
||||
for installing programs and libraries. Data files and documentation
|
||||
will still use the regular prefix. Normally, all files are installed
|
||||
using the same prefix.
|
||||
3. After a successful build you can invoke scsh by typing
|
||||
|
||||
Some packages pay attention to `--with-PACKAGE' options to
|
||||
`configure', where PACKAGE is something like `gnu-as' or `x' (for the X
|
||||
Window System). The README should mention any `--with-' options that
|
||||
the package recognizes.
|
||||
./go
|
||||
|
||||
`configure' ignores any other arguments that you give it.
|
||||
You should see the command prompt of scsh which you can exit by
|
||||
typing `,exit'.
|
||||
|
||||
On systems that require unusual options for compilation or linking
|
||||
that the package's `configure' script does not know about, you can give
|
||||
`configure' initial values for variables by setting them in the
|
||||
environment. In Bourne-compatible shells, you can do that on the
|
||||
command line like this:
|
||||
4. Type
|
||||
|
||||
CC='gcc -traditional' LIBS=-lposix ./configure
|
||||
make install
|
||||
|
||||
Here are the `make' variables that you might want to override with
|
||||
environment variables when running `configure'.
|
||||
|
||||
For these variables, any value given in the environment overrides the
|
||||
value that `configure' would choose:
|
||||
|
||||
- Variable: CC
|
||||
C compiler program. The default is `cc'.
|
||||
|
||||
- Variable: INSTALL
|
||||
Program to use to install files. The default is `install' if you
|
||||
have it, `cp' otherwise.
|
||||
|
||||
For these variables, any value given in the environment is added to
|
||||
the value that `configure' chooses:
|
||||
|
||||
- Variable: DEFS
|
||||
Configuration options, in the form `-Dfoo -Dbar...'. Do not use
|
||||
this variable in packages that create a configuration header file.
|
||||
|
||||
- Variable: LIBS
|
||||
Libraries to link with, in the form `-lfoo -lbar...'.
|
||||
|
||||
If you need to do unusual things to compile the package, we encourage
|
||||
you to figure out how `configure' could check whether to do them, and
|
||||
mail diffs or instructions to the address given in the README so we
|
||||
can include them in the next release.
|
||||
|
||||
2. Type `make' to compile the package. If you want, you can override
|
||||
the `make' variables CFLAGS and LDFLAGS like this:
|
||||
|
||||
make CFLAGS=-O2 LDFLAGS=-s
|
||||
|
||||
3. If the package comes with self-tests and you want to run them,
|
||||
type `make check'. If you're not sure whether there are any, try it;
|
||||
if `make' responds with something like
|
||||
make: *** No way to make target `check'. Stop.
|
||||
then the package does not come with self-tests.
|
||||
|
||||
4. Type `make install' to install programs, data files, and
|
||||
documentation.
|
||||
to install programs, data files, and documentation.
|
||||
|
||||
5. You can remove the program binaries and object files from the
|
||||
source directory by typing `make clean'. To also remove the
|
||||
Makefile(s), the header file containing system-dependent definitions
|
||||
(if the package uses one), and `config.status' (all the files that
|
||||
`configure' created), type `make distclean'.
|
||||
source directory by typing `make clean'. To also remove the
|
||||
Makefile, the header file containing system-dependent definitions
|
||||
, `config.status' and `config.cache' (all the files that
|
||||
`configure' created), type `make distclean'.
|
||||
|
||||
The file `configure.in' is used to create `configure' by a program
|
||||
called `autoconf'. You only need it if you want to regenerate
|
||||
`configure' using a newer version of `autoconf'.
|
||||
For more information about scsh have a look into the README file and
|
||||
the documentation in the `doc/' directory. There you can also read
|
||||
documentation about Scheme 48, the Scheme implementation scsh is based
|
||||
on.
|
||||
|
|
|
|||
601
Makefile.in
601
Makefile.in
|
|
@ -1,4 +1,4 @@
|
|||
# Scheme 48 Makefile
|
||||
# Scsh Makefile
|
||||
# Documentation in files INSTALL and doc/install.txt
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
|
@ -17,15 +17,23 @@ INSTALL_DATA = @INSTALL_DATA@
|
|||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
|
||||
RM = rm -f
|
||||
|
||||
AR = @AR@
|
||||
RANLIB = @RANLIB@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
incdir = @includedir@
|
||||
manext = 1
|
||||
mandir = @mandir@/man$(manext)
|
||||
lib_dirs_list = @lib_dirs_list@
|
||||
host = @host@
|
||||
### End of `configure' section###
|
||||
|
||||
bindir = $(exec_prefix)/bin
|
||||
libdir = $(exec_prefix)/lib
|
||||
incdir = $(exec_prefix)/include
|
||||
manext = 1
|
||||
mandir = $(prefix)/man/man$(manext)
|
||||
htmldir = $(libdir)/scsh/doc/scsh-manual/html
|
||||
|
||||
# HP 9000 series, if you don't have gcc
|
||||
# CC = cc
|
||||
|
|
@ -36,10 +44,13 @@ mandir = $(prefix)/man/man$(manext)
|
|||
# LDFLAGS = -N
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CPPFLAGS) $(DEFS) -I$(srcdir)/c $(CFLAGS) -o $@ $<
|
||||
$(CC) -c $(DEFS) -I ./c -I$(srcdir)/c -I$(srcdir)/cig $(CPPFLAGS) $(CFLAGS) -o $@ $<
|
||||
|
||||
# You might want to change RUNNABLE to "s48"
|
||||
RUNNABLE = scheme48
|
||||
# BUILD_RUNNABLE has to be Scheme 48 0.53. This is used for builds directly
|
||||
# out of the CVS repository.
|
||||
# We cannot use Scsh here since -i is not understood.
|
||||
BUILD_RUNNABLE = /afs/wsi/i386_fbsd32/bin/scheme48
|
||||
RUNNABLE = scsh
|
||||
MANPAGE = $(RUNNABLE).$(manext)
|
||||
LIB = $(libdir)/$(RUNNABLE)
|
||||
|
||||
|
|
@ -68,13 +79,19 @@ include $(srcdir)/build/filenames.make
|
|||
# LINKER_RUNNABLE = $(RUNNABLE)
|
||||
# These settings requires you to already have a $(RUNNABLE)
|
||||
# command. This is desirable if you are making changes to the
|
||||
# system that might break scheme48vm and/or scheme48.image. But it
|
||||
# system that might break scshvm and/or scsh/scsh.image. But it
|
||||
# requires you to have squirreled away a previous working version
|
||||
# of scheme48.
|
||||
# of scsh.
|
||||
|
||||
BIG_HEAP = -h 5500000
|
||||
# 1. is broken if you build from CVS
|
||||
# LINKER_VM = ./$(VM) $(BIG_HEAP)
|
||||
# LINKER_RUNNABLE = $(LINKER_VM) -i $(IMAGE)
|
||||
|
||||
# therefore according to 2. but we cannot use scsh since -i is not understood
|
||||
LINKER_VM = $(BUILD_RUNNABLE) $(BIG_HEAP)
|
||||
LINKER_RUNNABLE = $(BUILD_RUNNABLE)
|
||||
|
||||
BIG_HEAP = -h 5000000
|
||||
LINKER_VM = ./$(VM) $(BIG_HEAP)
|
||||
LINKER_RUNNABLE = $(LINKER_VM) -i $(IMAGE)
|
||||
LINKER_IMAGE = build/linker.image
|
||||
LINKER = $(LINKER_VM) -i $(LINKER_IMAGE)
|
||||
START_LINKER = echo ',batch' && echo ',bench on'
|
||||
|
|
@ -85,11 +102,57 @@ START_LINKER = echo ',batch' && echo ',bench on'
|
|||
|
||||
# Targets:
|
||||
|
||||
IMAGE = scheme48.image
|
||||
IMAGE = scsh.image
|
||||
INITIAL = build/initial.image
|
||||
VM = scheme48vm
|
||||
VM = scshvm
|
||||
LIBCIG = cig/lib$(VM).a
|
||||
CIG = cig/cig
|
||||
CIGOBJS = cig/libcig.o cig/libcig1.o
|
||||
|
||||
#scsh-lib
|
||||
LIBSCSHVM = scsh/lib$(VM).a
|
||||
LIBSCSH = scsh/libscsh.a
|
||||
SCSHVMHACKS = scsh/proc2.o
|
||||
|
||||
#
|
||||
#
|
||||
SCSHOBJS = \
|
||||
scsh/cstuff.o \
|
||||
scsh/dirstuff1.o \
|
||||
scsh/fdports1.o \
|
||||
scsh/flock1.o \
|
||||
scsh/machine/time_dep1.o \
|
||||
scsh/signals1.o \
|
||||
scsh/machine/libansi.o \
|
||||
scsh/network1.o \
|
||||
scsh/putenv.o \
|
||||
scsh/rx/regexp1.o \
|
||||
scsh/sleep1.o \
|
||||
scsh/syscalls1.o \
|
||||
scsh/syslog1.o \
|
||||
scsh/time1.o \
|
||||
scsh/tty1.o \
|
||||
scsh/userinfo1.o \
|
||||
scsh/sighandlers1.o \
|
||||
scsh/libscsh.o \
|
||||
scsh/md5.o
|
||||
|
||||
SCSH_INITIALIZERS = s48_init_syslog s48_init_posix_regexp \
|
||||
s48_init_userinfo s48_init_sighandlers \
|
||||
s48_init_syscalls s48_init_network s48_init_flock \
|
||||
s48_init_dirstuff s48_init_time s48_init_tty \
|
||||
s48_init_cig s48_init_libscsh s48_init_md5
|
||||
|
||||
UNIX_OBJS = c/unix/misc.o c/unix/io.o c/unix/fd-io.o c/unix/event.o
|
||||
OBJS = c/scheme48vm.o c/scheme48heap.o c/extension.o c/external.o
|
||||
|
||||
SRFI_OBJS = c/srfi/srfi-27.o
|
||||
|
||||
SRFI_INITIALIZERS = s48_init_srfi_27
|
||||
|
||||
S48OBJS = c/scheme48vm.o c/scheme48heap.o c/extension.o c/external.o
|
||||
OBJS = scsh/process_args.o c/init.o $(S48OBJS) $(CIGOBJS) $(SCSHOBJS) \
|
||||
$(SCSHVMHACKS) $(SRFI_OBJS)
|
||||
|
||||
FAKEHS = c/fake/dlfcn.h c/fake/sigact.h c/fake/strerror.h \
|
||||
c/fake/sys-select.h
|
||||
|
||||
|
|
@ -102,7 +165,7 @@ CONFIG_FILES = scheme/interfaces.scm scheme/low-packages.scm \
|
|||
|
||||
# The following is the first rule and therefore the "make" command's
|
||||
# default target.
|
||||
enough: $(VM) $(IMAGE) go .notify
|
||||
enough: $(VM) $(IMAGE) go $(LIBCIG) scsh $(LIBSCSH) $(LIBSCSHVM)
|
||||
|
||||
# --------------------
|
||||
# External code to include in the VM
|
||||
|
|
@ -110,7 +173,11 @@ enough: $(VM) $(IMAGE) go .notify
|
|||
|
||||
EXTERNAL_OBJECTS = $(SOCKET_OBJECTS) $(LOOKUP_OBJECTS)
|
||||
EXTERNAL_FLAGS = $(SOCKET_FLAGS)
|
||||
EXTERNAL_INITIALIZERS = $(SOCKET_INITIALIZERS) $(LOOKUP_INITIALIZERS)
|
||||
EXTERNAL_INITIALIZERS = $(ADDITIONAL_INITIALIZER) $(SOCKET_INITIALIZERS) \
|
||||
$(LOOKUP_INITIALIZERS) \
|
||||
$(SCSH_INITIALIZERS) $(SRFI_INITIALIZERS) \
|
||||
s48_init_cig
|
||||
|
||||
|
||||
# Rules for any external code.
|
||||
|
||||
|
|
@ -132,30 +199,95 @@ LOOKUP_OBJECTS = c/unix/dynamo.o
|
|||
LOOKUP_INITIALIZERS = s48_init_external_lookup
|
||||
|
||||
# End of lookup rules
|
||||
|
||||
# Initializer for s48_add_external_init
|
||||
|
||||
ADDITIONAL_INITIALIZER = s48_init_additional_inits
|
||||
|
||||
# End of external rules
|
||||
# --------------------
|
||||
|
||||
# The developers are curious to know. Don't be concerned if this fails.
|
||||
.notify: build/minor-version-number
|
||||
touch .notify
|
||||
-echo Another 0.`cat $(srcdir)/build/minor-version-number` \
|
||||
installation. \
|
||||
| mail scheme-48-notifications@martigny.ai.mit.edu
|
||||
-echo SCSH 0.`cat $(srcdir)/scsh/minor-version-number` \
|
||||
Scheme48 0.`cat $(srcdir)/minor-version-number` infestation. \
|
||||
| mail scheme-48-notifications@zurich.ai.mit.edu
|
||||
-echo Another scsh 0.`cat $(srcdir)/scsh/minor-version-number` \
|
||||
infestation. | mail scsh-notifications@zurich.ai.mit.edu
|
||||
|
||||
|
||||
# This says how to process .scm files with cig to make .c stubs.
|
||||
#.SUFFIXES: .scm
|
||||
#.scm.c:
|
||||
# $(srcdir)/$(VM) -o $(srcdir)/$(VM) -i $(CIG) < $< > $*.c
|
||||
|
||||
# These .h files mediate between the code exported from foo1.c
|
||||
# and imported into foo.scm's stub foo.c.
|
||||
|
||||
scsh/dirstuff1.o: scsh/dirstuff1.h
|
||||
scsh/userinfo1.o: scsh/userinfo1.h
|
||||
scsh/network1o: scsh/network1.h
|
||||
scsh/flock1.o: scsh/flock1.h
|
||||
|
||||
scsh/fdports1.o scsh/fdports.o: scsh/fdports1.h
|
||||
|
||||
scsh/rx/regexp1.o: c/scheme48.h
|
||||
|
||||
scsh/sighandlers1.o: scsh/sighandlers1.h
|
||||
|
||||
scsh/syslog1.o: c/scheme48.h
|
||||
|
||||
include $(srcdir)/scsh/machine/Makefile.inc
|
||||
# Berkeley make wants to see this instead: (or use GNU make on BSD. -bri)
|
||||
#.include "$(srcdir)/scsh/machine/Makefile.inc"
|
||||
|
||||
$(VM): c/main.o $(OBJS) $(UNIX_OBJS) $(LIBOBJS) $(EXTERNAL_OBJECTS)
|
||||
rm -f /tmp/s48_external_$$$$.c && \
|
||||
build/build-external-modules /tmp/s48_external_$$$$.c \
|
||||
$(srcdir)/build/build-external-modules /tmp/s48_external_$$$$.c \
|
||||
$(EXTERNAL_INITIALIZERS) && \
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ c/main.o $(OBJS) $(UNIX_OBJS) \
|
||||
/tmp/s48_external_$$$$.c \
|
||||
$(LIBOBJS) $(LIBS) \
|
||||
$(EXTERNAL_OBJECTS) $(EXTERNAL_LD_FLAGS) && \
|
||||
$(EXTERNAL_OBJECTS) $(EXTERNAL_LD_FLAGS) \
|
||||
$(LIBOBJS) $(LIBS) && \
|
||||
rm -f /tmp/s48_external_$$$$.c
|
||||
|
||||
c/main.o: c/main.c c/scheme48vm.h c/scheme48heap.h
|
||||
|
||||
|
||||
|
||||
#JMG: again cig and scsh-lib
|
||||
$(LIBCIG): c/main.o $(OBJS)
|
||||
# $(CC) -r -o $@ main.o $(OBJS)
|
||||
$(RM) $@
|
||||
$(AR) $@ c/main.o $(OBJS)
|
||||
$(RANLIB) $@
|
||||
|
||||
$(LIBSCSHVM): c/smain.o $(OBJS)
|
||||
$(RM) $@
|
||||
$(AR) $@ c/smain.o $(OBJS)
|
||||
$(RANLIB) $@
|
||||
|
||||
$(LIBSCSH): $(OBJS) $(UNIX_OBJS) $(LIBOBJS) $(EXTERNAL_OBJECTS)
|
||||
$(RM) $@ \
|
||||
rm -f /tmp/s48_external_$$$$.c && \
|
||||
$(srcdir)/build/build-external-modules /tmp/s48_external_$$$$.c \
|
||||
$(EXTERNAL_INITIALIZERS) && \
|
||||
$(CC) -c $(CFLAGS) -o /tmp/s48_external_$$$$.o \
|
||||
/tmp/s48_external_$$$$.c && \
|
||||
$(AR) $@ $(OBJS) $(UNIX_OBJS) $(LIBOBJS) $(EXTERNAL_OBJECTS) \
|
||||
/tmp/s48_external_$$$$.o && \
|
||||
$(RANLIB) $@ && \
|
||||
rm -f /tmp/s48_external_$$$$.c /tmp/s48_external_$$$$.o
|
||||
|
||||
c/main.o: c/main.c
|
||||
$(CC) -c $(CFLAGS) -o $@ \
|
||||
-DDEFAULT_IMAGE_NAME=\"$(LIB)/$(IMAGE)\" \
|
||||
$(CPPFLAGS) $(DEFS) c/main.c
|
||||
$(CPPFLAGS) $(DEFS) $(srcdir)/c/main.c
|
||||
|
||||
c/init.o: c/init.c c/scheme48vm.h c/scheme48heap.h
|
||||
$(CC) -c $(CFLAGS) -o $@ \
|
||||
-DDEFAULT_IMAGE_NAME=\"$(LIB)/$(IMAGE)\" \
|
||||
$(CPPFLAGS) $(DEFS) $(srcdir)/c/init.c
|
||||
|
||||
c/scheme48vm.o: c/prescheme.h c/scheme48vm.h c/scheme48heap.h c/event.h \
|
||||
c/io.h c/fd-io.h c/scheme48vm-prelude.h
|
||||
|
|
@ -182,50 +314,87 @@ c/fake/strerror.o: c/fake/strerror.h
|
|||
$(IMAGE): $(VM) scheme/env/init-defpackage.scm scheme/more-interfaces.scm \
|
||||
scheme/link-packages.scm scheme/more-packages.scm \
|
||||
$(usual-files) build/initial.debug build/build-usual-image
|
||||
build/build-usual-image . "`pwd`/scheme" '$(IMAGE)' './$(VM)' \
|
||||
'$(INITIAL)'
|
||||
$(srcdir)/build/build-usual-image $(srcdir) "$(srcdir)/scheme" '$(IMAGE)' './$(VM)' \
|
||||
'$(srcdir)/$(INITIAL)'
|
||||
|
||||
### Fake targets: all clean install man dist
|
||||
|
||||
install: enough dirs inst-script inst-vm inst-misc inst-man inst-inc inst-image
|
||||
install: enough dirs inst-script inst-vm inst-misc inst-man inst-inc \
|
||||
inst-doc install-scsh
|
||||
|
||||
inst-vm:
|
||||
$(INSTALL_PROGRAM) $(VM) $(LIB)
|
||||
|
||||
inst-image:
|
||||
rm -f '/tmp/$(IMAGE)' && \
|
||||
build/build-usual-image . '$(LIB)' '/tmp/$(IMAGE)' './$(VM)' \
|
||||
'$(INITIAL)' && \
|
||||
$(INSTALL_DATA) /tmp/$(IMAGE) $(LIB) && \
|
||||
rm /tmp/$(IMAGE)
|
||||
inst-vm: $(VM)
|
||||
$(INSTALL_PROGRAM) $(VM) $(DESTDIR)$(LIB)
|
||||
|
||||
inst-man:
|
||||
if [ -d $(mandir) -a -w $(mandir) ]; then \
|
||||
sed 's=LBIN=$(bindir)=g' doc/scheme48.man | \
|
||||
if [ -d $(DESTDIR)$(mandir) -a -w $(DESTDIR)$(mandir) ]; then \
|
||||
sed 's=LBIN=$(bindir)=g' doc/scsh.man | \
|
||||
sed 's=LLIB=$(LIB)=g' | \
|
||||
sed 's=LS48=$(RUNNABLE)=g' >$(MANPAGE) && \
|
||||
$(INSTALL_DATA) $(MANPAGE) $(mandir) && \
|
||||
rm $(MANPAGE); \
|
||||
sed 's=LSCSH=$(RUNNABLE)=g' >$(MANPAGE) && \
|
||||
$(INSTALL_DATA) $(MANPAGE) $(DESTDIR)$(mandir) && \
|
||||
$(RM) $(MANPAGE); \
|
||||
else \
|
||||
echo "$(mandir) not writable dir, not installing man page" \
|
||||
>&2; \
|
||||
fi
|
||||
|
||||
inst-inc:
|
||||
$(INSTALL_DATA) c/scheme48.h $(incdir)
|
||||
$(INSTALL_DATA) $(srcdir)/c/scheme48.h $(DESTDIR)$(incdir)
|
||||
$(INSTALL_DATA) $(srcdir)/c/write-barrier.h $(DESTDIR)$(incdir)
|
||||
|
||||
install-cig: cig
|
||||
$(INSTALL_PROGRAM) $(srcdir)/$(CIG) $(DESTDIR)$(LIB)/cig
|
||||
$(INSTALL_PROGRAM) $(srcdir)/$(CIG).image $(DESTDIR)$(LIB)/cig
|
||||
$(INSTALL_DATA) $(srcdir)/$(LIBCIG) $(DESTDIR)$(LIB)/cig
|
||||
$(INSTALL_DATA) $(srcdir)/cig/libcig.h $(DESTDIR)$(LIB)/cig
|
||||
|
||||
inst-misc:
|
||||
for stub in env big opt misc link; do \
|
||||
for f in scheme/$$stub/*.scm; do \
|
||||
$(INSTALL_DATA) $$f $(LIB)/$$stub || exit 1; \
|
||||
for stub in env big opt misc link srfi; do \
|
||||
for f in $(srcdir)/scheme/$$stub/*.scm; do \
|
||||
$(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/$$stub || exit 1; \
|
||||
done; \
|
||||
done && \
|
||||
for f in scheme/rts/*num.scm scheme/rts/jar-defrecord.scm; do \
|
||||
$(INSTALL_DATA) $$f $(LIB)/rts || exit 1; \
|
||||
for f in $(srcdir)/scheme/rts/*num.scm $(srcdir)/scheme/rts/jar-defrecord.scm; do \
|
||||
$(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/rts || exit 1; \
|
||||
done
|
||||
|
||||
inst-doc:
|
||||
for f in $(srcdir)/doc/*.txt $(srcdir)/doc/*.ps; do \
|
||||
$(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/; \
|
||||
done && \
|
||||
for f in $(srcdir)/doc/src/*.tex \
|
||||
$(srcdir)/doc/src/*.dvi \
|
||||
$(srcdir)/doc/src/*.ps; \
|
||||
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/s48-manual/; \
|
||||
done && \
|
||||
for f in $(srcdir)/doc/src/manual/*.html; \
|
||||
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/s48-manual/html/; \
|
||||
done && \
|
||||
for f in $(srcdir)/doc/scsh-manual/*.tex \
|
||||
$(srcdir)/doc/scsh-manual/*.sty \
|
||||
$(srcdir)/doc/scsh-manual/*.dvi \
|
||||
$(srcdir)/doc/scsh-manual/*.ps \
|
||||
$(srcdir)/doc/scsh-manual/*.pdf; \
|
||||
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/scsh-manual/; \
|
||||
done && \
|
||||
for f in $(srcdir)/doc/scsh-manual/html/*.html \
|
||||
$(srcdir)/doc/scsh-manual/html/*.gif \
|
||||
$(srcdir)/doc/scsh-manual/html/*.css; \
|
||||
do $(INSTALL_DATA) $$f $(DESTDIR)$(htmldir)/; \
|
||||
done && \
|
||||
for f in $(srcdir)/doc/scsh-paper/*.tex \
|
||||
$(srcdir)/doc/scsh-paper/*.sty \
|
||||
$(srcdir)/doc/scsh-paper/*.dvi \
|
||||
$(srcdir)/doc/scsh-paper/*.ps; \
|
||||
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/scsh-paper/; \
|
||||
done && \
|
||||
for f in $(srcdir)/doc/scsh-paper/html/*.html \
|
||||
$(srcdir)/doc/scsh-paper/html/*.css; \
|
||||
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/scsh-paper/html; \
|
||||
done
|
||||
|
||||
|
||||
inst-script:
|
||||
script=$(bindir)/$(RUNNABLE) && \
|
||||
script=$(DESTDIR)$(bindir)/$(RUNNABLE) && \
|
||||
echo '#!/bin/sh' >$$script && \
|
||||
echo >>$$script && \
|
||||
echo 'lib=$(LIB)' >>$$script && \
|
||||
|
|
@ -233,46 +402,52 @@ inst-script:
|
|||
>>$$script && \
|
||||
chmod +x $$script
|
||||
|
||||
# Script to run scheme48 in this directory.
|
||||
# Script to run scsh in this directory.
|
||||
go:
|
||||
echo '#!/bin/sh' >$@ && \
|
||||
echo >>$@ && \
|
||||
echo "lib=`pwd`" >>$@ && \
|
||||
echo 'exec $$lib/$(VM) -o $$lib/$(VM) -i $$lib/$(IMAGE) "$$@"' \
|
||||
echo 'exec $$lib/$(VM) -o $$lib/$(VM) -i $$lib/scsh/scsh.image "$$@"' \
|
||||
>>$@ && \
|
||||
chmod +x $@
|
||||
|
||||
dirs:
|
||||
for dir in $(libdir) $(bindir) $(incdir); do \
|
||||
[ -d $$dir -a -w $$dir ] || { \
|
||||
echo "$$dir not a writable directory" >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
done
|
||||
{ mkdir -p $(LIB) && [ -w $(LIB) ]; } || { \
|
||||
echo "$(LIB) not a writable directory" >&2; \
|
||||
exit 1; \
|
||||
}
|
||||
for dir in rts env big opt misc link; do \
|
||||
{ mkdir -p $(LIB)/$$dir && [ -w $(LIB)/$$dir ]; } || { \
|
||||
echo "$(LIB)/$$dir not a writable directory" >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
for dir in $(libdir) $(bindir) $(incdir) $(LIB) $(mandir) $(htmldir); do\
|
||||
{ mkdir -p $(DESTDIR)$$dir && [ -w $(DESTDIR)$$dir ]; } || { \
|
||||
echo "$(DESTDIR)$$dir not a writable directory" >&2; \
|
||||
exit 1; \
|
||||
} \
|
||||
done && \
|
||||
for dir in \
|
||||
rts env big opt misc link srfi scsh doc/scsh-manual \
|
||||
doc/s48-manual/html doc/scsh-paper/html cig; do \
|
||||
{ mkdir -p $(DESTDIR)$(LIB)/$$dir && [ -w $(DESTDIR)$(LIB)/$$dir ]; } || { \
|
||||
echo "$(DESTDIR)$(LIB)/$$dir not a writable directory" >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
done
|
||||
|
||||
configure: configure.in
|
||||
autoheader && autoconf
|
||||
|
||||
clean:
|
||||
-rm -f $(VM) *.o c/unix/*.o c/*.o c/fake/*.o \
|
||||
TAGS $(IMAGE) \
|
||||
clean: clean-cig clean-scsh
|
||||
-rm -f $(VM) *.o c/*/*.o c/*.o \
|
||||
$(IMAGE) \
|
||||
build/*.tmp $(MANPAGE) build/linker.image \
|
||||
scheme/debug/*.image scheme/debug/*.debug config.cache \
|
||||
scheme/debug/*.image scheme/debug/*.debug \
|
||||
scheme/vm/scheme48vm.c scheme/vm/scheme48heap.c \
|
||||
go $(distname)
|
||||
|
||||
clean-cig:
|
||||
-rm -f cig/*.o $(CIG) $(CIG).image $(LIBCIG)
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile config.log config.status c/sysdep.h
|
||||
rm -f Makefile config.log config.status c/sysdep.h config.cache \
|
||||
scsh/machine \
|
||||
scsh/endian.scm \
|
||||
exportlist.aix scsh-config
|
||||
$(RM) a.exe $(VM).base $(VM).def $(VM).exp
|
||||
-find . -name '*~' -o -name '#*' -o -name core -exec rm {} \;
|
||||
|
||||
check: $(VM) $(IMAGE) scheme/debug/check.scm
|
||||
( \
|
||||
|
|
@ -296,18 +471,17 @@ image: $(INITIAL)
|
|||
$(MAKE) $(IMAGE)
|
||||
|
||||
tags:
|
||||
etags scheme/vm/arch.scm scheme/rts/*.scm scheme/bcomp/*.scm \
|
||||
scheme/*.scm scheme/env/*.scm scheme/big/*.scm scheme/link/*.scm \
|
||||
scheme/opt/*.scm scheme/debug/*.scm scheme/misc/*.scm
|
||||
find . -name "*.scm" -o -name "*.c" -o -name "*.h" | etags -
|
||||
|
||||
# --------------------
|
||||
# Distribution...
|
||||
|
||||
# DISTFILES should include all sources.
|
||||
DISTFILES = README COPYING INSTALL configure \
|
||||
acconfig.h configure.in Makefile.in install-sh \
|
||||
doc/*.ps doc/*.txt doc/html/*.html doc/scheme48.man \
|
||||
doc/src/*.tex doc/src/*.sty \
|
||||
DISTFILES = README COPYING INSTALL RELEASE configure config.sub config.guess \
|
||||
scsh-config.in configure.in Makefile.in install-sh \
|
||||
doc/*.ps doc/*.txt \
|
||||
doc/src/*.tex doc/src/*.sty doc/src/manual.dvi \
|
||||
doc/src/manual.ps \
|
||||
emacs/README build/*-version-number build/*.exec \
|
||||
build/*.lisp build/build-usual-image build/filenames.make \
|
||||
build/filenames.scm build/initial.debug \
|
||||
|
|
@ -316,14 +490,40 @@ DISTFILES = README COPYING INSTALL configure \
|
|||
c/*.[ch] c/*/*.[ch] c/scheme48.h.in \
|
||||
emacs/*.el gdbinit \
|
||||
scheme/*.scm scheme/*/*.scm \
|
||||
ps-compiler \
|
||||
c/sysdep.h.in
|
||||
ps-compiler/*.scm ps-compiler/minor-version-number \
|
||||
ps-compiler/doc/*.txt ps-compiler/*/*.scm \
|
||||
ps-compiler/*/*/*.scm \
|
||||
ps-compiler/prescheme/test/fact.cps \
|
||||
ps-compiler/prescheme/test/prescheme.h \
|
||||
ps-compiler/prescheme/c-stuff \
|
||||
c/sysdep.h.in \
|
||||
scsh/*.scm scsh/*/*.scm \
|
||||
scsh/*.[ch] scsh/*/*.[ch] \
|
||||
scsh/*.scm.in scsh/*/Makefile.inc \
|
||||
cig/*.scm cig/*.[ch] \
|
||||
doc/scsh.man \
|
||||
doc/scsh-manual/*.tex doc/scsh-manual/*.sty \
|
||||
doc/scsh-manual/man.ps doc/scsh-manual/man.pdf \
|
||||
doc/scsh-manual/man.dvi doc/scsh-manual/Makefile \
|
||||
doc/scsh-manual/THANKS doc/scsh-manual/html/*.html \
|
||||
doc/scsh-manual/html/*.gif doc/scsh-manual/html/*.css \
|
||||
doc/src/manual/*.html \
|
||||
doc/scsh-paper/*.sty doc/scsh-paper/*.tex \
|
||||
doc/scsh-paper/mitlogo.ps doc/scsh-paper/scsh-paper.ps \
|
||||
doc/scsh-paper/scsh-paper.dvi \
|
||||
doc/scsh-paper/html/*.html doc/scsh-paper/html/*.css
|
||||
|
||||
|
||||
distname = $(RUNNABLE)-0.`cat build/minor-version-number`
|
||||
|
||||
dist: build/initial.image
|
||||
dist: build/initial.image distclean
|
||||
(cd doc/src && latex manual.tex && latex manual.tex && \
|
||||
dvips manual -o manual.ps && hyperlatex manual.tex) && \
|
||||
(cd doc/scsh-manual && makeindex man && make man.ps && \
|
||||
make man.pdf && make html) && \
|
||||
(cd doc/scsh-paper && make scsh-paper.ps && make html) && \
|
||||
distname=$(distname) && \
|
||||
distfile=$(distdir)/$$distname.tgz && \
|
||||
distfile=$(distdir)/$$distname.tar.gz && \
|
||||
if [ -d $(distdir) ] && \
|
||||
[ -w $$distfile -o -w $(distdir) ]; then \
|
||||
rm -f $$distname && \
|
||||
|
|
@ -378,9 +578,7 @@ PACKAGES=scheme/packages.scm scheme/rts-packages.scm scheme/alt-packages.scm \
|
|||
build/filenames.scm
|
||||
|
||||
build/filenames.make: $(PACKAGES)
|
||||
$(MAKE) $(VM) PACKAGES=
|
||||
./$(VM) -i $(srcdir)/$(INITIAL) -a batch <build/filenames.scm
|
||||
# or: $(RUNNABLE) -a batch <build/filenames.scm
|
||||
$(BUILD_RUNNABLE) -a batch <build/filenames.scm
|
||||
|
||||
# --------------------
|
||||
# Static linker
|
||||
|
|
@ -418,7 +616,8 @@ link/linker-in-lucid: build/lucid-script.lisp $(linker-files) \
|
|||
# Scheme, the byte-code compiler, and a minimal command processor, but
|
||||
# no debugging environment to speak of.
|
||||
|
||||
$(INITIAL): $(LINKER_IMAGE) $(CONFIG_FILES) build/initial.scm $(initial-files)
|
||||
$(INITIAL): $(LINKER_IMAGE) $(CONFIG_FILES) build/initial.scm $(initial-files) \
|
||||
scsh/here.scm # gross and Olin hates it -bri
|
||||
($(START_LINKER); \
|
||||
echo '(load-configuration "scheme/interfaces.scm")'; \
|
||||
echo '(load-configuration "scheme/packages.scm")'; \
|
||||
|
|
@ -466,9 +665,9 @@ scheme/debug/medium.image: $(LINKER_IMAGE) $(CONFIG_FILES)
|
|||
# The following have not been updated for the new directory organization
|
||||
|
||||
c/smain.o: c/main.c
|
||||
$(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) -DSTATIC_AREAS -o $@ c/main.c
|
||||
$(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) -DSTATIC_AREAS -o $@ $(srcdir)/c/main.c
|
||||
|
||||
mini: mini-heap.o smain.o
|
||||
mini: mini-heap.o c/smain.o
|
||||
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ c/smain.o mini-heap.o $(OBJS) $(LIBS)
|
||||
|
||||
mini-heap.o: mini-heap.c
|
||||
|
|
@ -477,7 +676,7 @@ mini-heap.o: mini-heap.c
|
|||
mini-heap.c: scheme/debug/mini1.image
|
||||
(echo ,exec ,load misc/load-static.scm; \
|
||||
echo \(do-it 150000 \"$(srcdir)/scheme/debug/mini1.image\" \"$@\"\)) \
|
||||
| $(RUNNABLE) -h 3000000 -a batch
|
||||
| $(BUILD_RUNNABLE) -h 3000000 -a batch
|
||||
|
||||
scheme/debug/mini1.image: $(VM) scheme/debug/mini.image
|
||||
echo "(write-image \"scheme/debug/mini1.image\" \
|
||||
|
|
@ -496,13 +695,13 @@ c/scheme48.h: c/scheme48.h.in scheme/vm/arch.scm scheme/vm/data.scm \
|
|||
echo ',batch'; \
|
||||
echo ',load-package big-scheme'; \
|
||||
echo ',open big-scheme'; \
|
||||
echo ',load scheme/link/generate-c-header.scm'; \
|
||||
echo ',load $(srcdir)/scheme/link/generate-c-header.scm'; \
|
||||
echo "(make-c-header-file \"$@\" \
|
||||
\"$(srcdir)/c/scheme48.h.in\" \
|
||||
\"$(srcdir)/scheme/vm/arch.scm\" \
|
||||
\"$(srcdir)/scheme/vm/data.scm\" \
|
||||
\"$(srcdir)/scheme/rts/record.scm\")" \
|
||||
) | $(RUNNABLE)
|
||||
) | $(BUILD_RUNNABLE)
|
||||
|
||||
# An old version of the above for legacy code.
|
||||
|
||||
|
|
@ -516,7 +715,7 @@ c/old-scheme48.h: scheme/vm/arch.scm scheme/vm/data.scm \
|
|||
echo "(make-c-header-file \"$@\" \
|
||||
\"$(srcdir)/scheme/vm/arch.scm\" \
|
||||
\"$(srcdir)/scheme/vm/data.scm\")" \
|
||||
) | $(RUNNABLE)
|
||||
) | $(BUILD_RUNNABLE)
|
||||
|
||||
# Generate vm (scheme48vm.c and scheme48heap.c) from VM sources.
|
||||
# Never called automatically. Do not use unless you are sure you
|
||||
|
|
@ -531,5 +730,217 @@ i-know-what-i-am-doing:
|
|||
echo ',exec ,load compile-vm-no-gc.scm'; \
|
||||
echo ',exec ,load compile-gc.scm'; \
|
||||
echo ',exit' \
|
||||
) | $(RUNNABLE) -h 8000000 && \
|
||||
) | $(BUILD_RUNNABLE) -h 5000000 && \
|
||||
mv ../scheme/vm/scheme48vm.c ../scheme/vm/scheme48heap.c ../c
|
||||
|
||||
cig: $(CIG) $(CIG).image $(LIBCIG)
|
||||
|
||||
|
||||
$(CIG): $(VM) $(IMAGE) $(srcdir)/cig/cig.scm $(srcdir)/cig/libcig.scm
|
||||
(echo ",batch"; \
|
||||
echo ",translate =scheme48/ $(srcdir)/scheme/"; \
|
||||
echo ",config ,load $(srcdir)/cig/cig.scm"; \
|
||||
echo ",config ,load $(srcdir)/cig/libcig.scm"; \
|
||||
echo ",load-package cig-standalone"; \
|
||||
echo ",in cig-standalone"; \
|
||||
echo ",translate =scheme48/ $(LIB)/"; \
|
||||
echo ",build cig-standalone-toplevel /tmp/cig") \
|
||||
| ./$(VM) -i ./$(IMAGE)
|
||||
$(srcdir)/cig/image2script $(LIB)/$(VM) </tmp/cig > $(CIG)
|
||||
-chmod +x $(CIG)
|
||||
mv /tmp/cig $(srcdir)/cig/cig_bootstrap
|
||||
$(RM) /tmp/cig
|
||||
|
||||
$(CIG).image: $(IMAGE) $(VM) $(srcdir)/cig/cig.scm $(srcdir)/cig/libcig.scm
|
||||
(echo ",batch"; \
|
||||
echo ",translate =scheme48/ $(srcdir)/scheme/"; \
|
||||
echo ",config ,load $(srcdir)/cig/cig.scm"; \
|
||||
echo ",config ,load $(srcdir)/cig/libcig.scm"; \
|
||||
echo ",load-package cig-aux"; \
|
||||
echo ",open define-foreign-syntax"; \
|
||||
echo ",translate =scheme48/ $(LIB)/"; \
|
||||
echo ",dump /tmp/cig \"(CIG Preloaded -bri)\"") \
|
||||
| ./$(VM) -o ./$(VM) -i ./$(IMAGE)
|
||||
$(srcdir)/cig/image2script $(LIB)/$(VM) \
|
||||
-o $(LIB)/$(VM) \
|
||||
</tmp/cig > $(CIG).image
|
||||
-chmod +x $(CIG).image
|
||||
$(RM) /tmp/cig
|
||||
|
||||
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
# SCSH Specifics
|
||||
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
scsh: scsh/scsh scsh/scsh.image
|
||||
|
||||
SCHEME =scsh/awk.scm \
|
||||
scsh/configure.scm \
|
||||
scsh/defrec.scm \
|
||||
scsh/endian.scm \
|
||||
scsh/enumconst.scm \
|
||||
scsh/event.scm \
|
||||
scsh/low-interrupt.scm \
|
||||
scsh/fdports.scm \
|
||||
scsh/fileinfo.scm \
|
||||
scsh/filemtch.scm \
|
||||
scsh/filesys.scm \
|
||||
scsh/flock.scm \
|
||||
scsh/fname.scm \
|
||||
scsh/fr.scm \
|
||||
scsh/glob.scm \
|
||||
scsh/dot-locking.scm \
|
||||
scsh/here.scm \
|
||||
scsh/lib-dirs.scm \
|
||||
scsh/libscsh.scm \
|
||||
scsh/machine/bufpol.scm \
|
||||
scsh/machine/errno.scm \
|
||||
scsh/machine/fdflags.scm \
|
||||
scsh/machine/netconst.scm \
|
||||
scsh/machine/packages.scm \
|
||||
scsh/machine/signals.scm \
|
||||
scsh/machine/time_dep.scm \
|
||||
scsh/machine/tty-consts.scm \
|
||||
scsh/machine/waitcodes.scm \
|
||||
scsh/md5.scm \
|
||||
scsh/meta-arg.scm \
|
||||
scsh/network.scm \
|
||||
scsh/newports.scm \
|
||||
scsh/procobj.scm \
|
||||
scsh/pty.scm \
|
||||
scsh/rdelim.scm \
|
||||
scsh/rw.scm \
|
||||
scsh/scsh-condition.scm \
|
||||
scsh/scsh-interfaces.scm \
|
||||
scsh/scsh-package.scm \
|
||||
scsh/scsh-read.scm \
|
||||
scsh/scsh-version.scm \
|
||||
scsh/scsh.scm \
|
||||
scsh/sighandlers.scm \
|
||||
scsh/startup.scm \
|
||||
scsh/stringcoll.scm \
|
||||
scsh/syntax-helpers.scm \
|
||||
scsh/syntax.scm \
|
||||
scsh/syscalls.scm \
|
||||
scsh/time.scm \
|
||||
scsh/top.scm \
|
||||
scsh/tty.scm \
|
||||
scsh/utilities.scm \
|
||||
scsh/weaktables.scm \
|
||||
scsh/rx/packages.scm \
|
||||
scsh/rx/re-match-syntax.scm \
|
||||
scsh/rx/rx-lib.scm \
|
||||
scsh/rx/parse.scm \
|
||||
scsh/rx/re-subst.scm \
|
||||
scsh/rx/simp.scm \
|
||||
scsh/rx/posixstr.scm \
|
||||
scsh/rx/re-syntax.scm \
|
||||
scsh/rx/spencer.scm \
|
||||
scsh/rx/oldfuns.scm \
|
||||
scsh/rx/re-fold.scm \
|
||||
scsh/rx/re.scm \
|
||||
scsh/rx/test.scm \
|
||||
scsh/rx/re-high.scm \
|
||||
scsh/rx/regexp.scm \
|
||||
scsh/rx/re-low.scm \
|
||||
scsh/rx/regress.scm
|
||||
# scsh/dbm.scm db.scm ndbm.scm
|
||||
# jcontrol
|
||||
|
||||
# Bogus, but it makes the scm->c->o two-ply dependency work.
|
||||
# Explicitly giving the .o/.c dependency also makes it go.
|
||||
############################################################
|
||||
cig/libcig.c: cig/libcig.scm
|
||||
|
||||
scsh/scsh: scsh/scsh-tramp.c
|
||||
$(CC) -o $@ $(CPPFLAGS) $(CFLAGS) \
|
||||
-DVM=\"$(LIB)/$(VM)\" \
|
||||
-DIMAGE=\"$(LIB)/scsh.image\" \
|
||||
$(srcdir)/scsh/scsh-tramp.c
|
||||
|
||||
bs: build/build-scsh-image
|
||||
sh $(srcdir)/build/build-scsh-image "$(srcdir)" "$(LIB)" "$(IMAGE)" \
|
||||
"$(VM)" cig/cig.image
|
||||
|
||||
loads = $(srcdir)/scsh/let-opt.scm $(srcdir)/scsh/scsh-interfaces.scm \
|
||||
$(srcdir)/scsh/machine/packages.scm \
|
||||
$(srcdir)/scsh/rx/packages.scm \
|
||||
$(srcdir)/scsh/scsh-package.scm \
|
||||
$(srcdir)/scsh/lib/ccp-pack.scm \
|
||||
$(srcdir)/scsh/lib/char-package.scm
|
||||
|
||||
opens = floatnums scsh ccp-lib scsh-top-package scsh-here-string-hax \
|
||||
srfi-1 srfi-13 srfi-14 # srfi-14 is also exported by scsh
|
||||
|
||||
# Doing ,load-package scheme-with-scsh here gives us much better start-up times
|
||||
scsh/scsh.image: $(VM) $(SCHEME) $(IMAGE)
|
||||
(echo ",translate =scheme48/ $(srcdir)/scheme/"; \
|
||||
echo ",translate $(srcdir)/scsh/endian.scm `pwd`/scsh/endian.scm"; \
|
||||
echo ",translate $(srcdir)/scsh/configure.scm `pwd`/scsh/configure.scm"; \
|
||||
echo ",batch on"; \
|
||||
echo ",config ,load $(loads)"; \
|
||||
echo ",open $(opens)"; \
|
||||
echo ",load-package scheme-with-scsh"; \
|
||||
echo "(dump-scsh \"$@\")"; \
|
||||
) \
|
||||
| ./$(VM) -o ./$(VM) -i $(IMAGE) -h 10000000
|
||||
|
||||
# ,flush files => 0k
|
||||
# ,flush names => -= 17k
|
||||
# ,flush maps => -= 350K
|
||||
# ,flush source => -= 1117k
|
||||
# ,flush => 550k
|
||||
scsh/stripped-scsh.image: $(VM) $(SCHEME) $(IMAGE)
|
||||
(echo ",flush maps source";\
|
||||
echo ",translate =scheme48/ $(srcdir)/scheme/"; \
|
||||
echo ",translate $(srcdir)/scsh/endian.scm `pwd`/scsh/endian.scm"; \
|
||||
echo ",translate $(srcdir)/scsh/configure.scm `pwd`/scsh/configure.scm"; \
|
||||
echo ",batch on"; \
|
||||
echo ",config ,load $(loads)"; \
|
||||
echo ",open $(opens)"; \
|
||||
echo ",load-package scheme-with-scsh"; \
|
||||
echo ",flush"; \
|
||||
echo "(dump-scsh \"$@\")";) \
|
||||
| ./$(VM) -o ./$(VM) -i $(IMAGE) -h 10000000
|
||||
|
||||
install-scsh: scsh install-scsh-image install-stripped-scsh-image
|
||||
$(RM) $(DESTDIR)$(bindir)/$(RUNNABLE)
|
||||
$(INSTALL_PROGRAM) scsh/scsh $(DESTDIR)$(bindir)/$(RUNNABLE)
|
||||
$(INSTALL_PROGRAM) $(LIBSCSHVM) $(DESTDIR)$(libdir)/$(LIBSCSHVM)
|
||||
$(INSTALL_PROGRAM) $(LIBSCSH) $(DESTDIR)$(libdir)/$(LIBSCSH)
|
||||
$(RANLIB) $(DESTDIR)$(libdir)/$(LIBSCSH)
|
||||
for f in $(srcdir)/scsh/*.scm $(srcdir)/scsh/*/*.scm; \
|
||||
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/scsh/; done
|
||||
|
||||
install-scsh-image: $(VM) scsh/scsh.image
|
||||
( echo ',translate =scheme48 $(LIB)'; \
|
||||
echo ',in lib-dirs (set-default-lib-dirs! (quote $(lib_dirs_list)))'; \
|
||||
echo '(dump-scsh "$(DESTDIR)$(LIB)/scsh.image")'; \
|
||||
echo ',exit'; \
|
||||
) | ./$(VM) -i scsh/scsh.image
|
||||
|
||||
install-stripped-scsh-image: $(VM) scsh/stripped-scsh.image
|
||||
( echo ',translate =scheme48 $(LIB)'; \
|
||||
echo ',in lib-dirs (set-default-lib-dirs! (quote $(lib_dirs_list)))'; \
|
||||
echo '(dump-scsh "$(DESTDIR)$(LIB)/stripped-scsh.image")'; \
|
||||
echo ',exit'; \
|
||||
) | ./$(VM) -i scsh/stripped-scsh.image
|
||||
|
||||
clean-scsh:
|
||||
$(RM) scsh/*.o scsh/rx/*.o scsh/machine/*.o
|
||||
$(RM) scsh/*.image
|
||||
$(RM) scsh/configure.scm
|
||||
$(RM) $(LIBSCSHVM) $(LIBSCSH) scsh/scsh$(EXEEXT)
|
||||
|
||||
scsh/configure.scm: $(srcdir)/scsh/configure.scm.in
|
||||
sed -e 's|@scsh_host@|$(host)|g' \
|
||||
-e 's|@scsh_prefix@|$(prefix)|g' \
|
||||
-e 's|@scsh_exec_prefix@|$(exec_prefix)|g' \
|
||||
-e 's|@scsh_bindir@|$(bindir)|g' \
|
||||
-e 's|@scsh_libdir@|$(libdir)|g' \
|
||||
-e 's|@scsh_includedir@|$(incdir)|g' \
|
||||
-e 's|@scsh_mandir@|$(mandir)|g' \
|
||||
-e 's|@scsh_lib_dirs_list@|$(lib_dirs_list)|g' \
|
||||
-e 's|@scsh_LIBS@|$(LIBS)|g' \
|
||||
-e 's|@scsh_DEFS@|$(DEFS)|g' \
|
||||
-e 's|@scsh_CFLAGS@|$(CFLAGS)|g' \
|
||||
-e 's|@scsh_CPPFLAGS@|$(CPPFLAGS)|g' \
|
||||
-e 's|@scsh_LDFLAGS@|$(LDFLAGS)|g' $(srcdir)/scsh/configure.scm.in > $@
|
||||
|
|
|
|||
92
README
92
README
|
|
@ -1,93 +1,19 @@
|
|||
; Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees. See file COPYING.
|
||||
-*- Mode: Text; -*-
|
||||
|
||||
Please report bugs to scheme-48-bugs@martigny.ai.mit.edu, and include
|
||||
Copyright (c) 1994 Brian D. Carlstrom
|
||||
See file COPYING for copying information.
|
||||
|
||||
Please report bugs to scsh-users@scsh.net, and include
|
||||
the version number in your message.
|
||||
|
||||
Installation instructions in file INSTALL.
|
||||
|
||||
A user's guide is in file doc/user-guide.txt.
|
||||
A scsh manual is in directory doc/scsh-manual/.
|
||||
A scsh paper is in directory doc/scsh-paper/.
|
||||
A scsh quick reference is in file doc/cheat.txt.
|
||||
|
||||
Recent changes are listed in file doc/news.txt.
|
||||
|
||||
Known bugs and things to do in the future are listed in doc/todo.txt.
|
||||
|
||||
Send mail to scheme-48-request@martigny.ai.mit.edu to be put on a
|
||||
Send mail to scsh-users-request@scsh.net to be put on a
|
||||
mailing list for announcements, discussion, bug reports, and bug
|
||||
fixes.
|
||||
|
||||
-----
|
||||
|
||||
When running "make", don't worry if the ".notify" target fails. Its
|
||||
only purpose is to send an email message to
|
||||
scheme-48-notifications@martigny.ai.mit.edu, so that we can get a
|
||||
rough idea of how much Scheme 48 is being used and by whom. We
|
||||
promise not to use your name or email address for any commercial
|
||||
purpose. If you don't want us to know, just do "make -t .notify"
|
||||
first (after running "configure").
|
||||
|
||||
-----
|
||||
|
||||
The Scheme 48 root directory is organized as follows (not all files are
|
||||
listed here):
|
||||
|
||||
README this file
|
||||
INSTALL installation instructions
|
||||
COPYING copyright notice
|
||||
configure configuration script
|
||||
Makefile.in input to configure
|
||||
doc/ some documentation
|
||||
scheme48.man a Unix-style manual page
|
||||
user-guide.txt general guide to using Scheme 48
|
||||
todo.txt list of improvements we hope to make someday
|
||||
news.txt list of improvements we have already made
|
||||
module.ps description of Scheme 48's module system
|
||||
big-scheme.txt extensions to Scheme
|
||||
threads.txt multiprocessing
|
||||
io.txt how the I/O system works
|
||||
scheme/ scheme source files
|
||||
packages.scm meta-module definitions
|
||||
interfaces.scm system interface definitions
|
||||
more-interfaces.scm system interface definitions
|
||||
*-packages.scm module definitions
|
||||
bcomp/ the byte-code compiler
|
||||
vm/ virtual machine sources (written in Pre-Scheme)
|
||||
rts/ run-time system sources
|
||||
link/ static linker
|
||||
env/ development environment modules (debugger, etc.)
|
||||
big/ useful Scheme libraries and extensions ("Big Scheme")
|
||||
alt/ portable implementations of some Scheme 48 features
|
||||
opt/ optional code optimizer for the byte-code compiler
|
||||
prescheme/ code for running the VM using Scheme 48
|
||||
debug/ debugging utilities, tests, etc.
|
||||
misc/ very miscellaneous things (e.g. AMB operator)
|
||||
posix/ unfinished interface to POSIX system calls
|
||||
ps-compiler/ Pre-Scheme -> C compiler
|
||||
c/ c source files
|
||||
sysdep.h.in input to configure
|
||||
scheme48vm.c most of the VM (generated by Pre-Scheme compiler)
|
||||
scheme48vm.h extern declarations for scheme48vm.c
|
||||
scheme48heap.c storage management (generated by Pre-Scheme compiler)
|
||||
scheme48heap.h extern declarations for scheme48heap.c
|
||||
main.c entry point for the VM
|
||||
prescheme.h part of the VM
|
||||
extension.c default definition of vm_extension()
|
||||
scheme48.h C declarations and macros for Scheme 48 data structures
|
||||
old-scheme48.h old version, included for compatibility
|
||||
c-mods.h minor additions to the C language
|
||||
event.h header file for OS interface
|
||||
io.h ditto
|
||||
fd-io.h ditto
|
||||
socket.c socket support
|
||||
dynamo.c dynamic loading support
|
||||
unix/ Unix-specific source files
|
||||
posix/ C half of an unfinished interface to POSIX system calls
|
||||
fake/ C files for insufficiently POSIX-compliant systems
|
||||
build/ code for building the system
|
||||
filenames.make included by Makefile, generated automatically
|
||||
filenames.scm code for generating filenames.make
|
||||
initial.image an image file containing a minimal Scheme system
|
||||
initial.debug debugging database for same
|
||||
initial.scm script for creating initial.image
|
||||
build-usual-image script for creating scheme48.image
|
||||
build-external-modules script for creating external-module initializer
|
||||
emacs/ gnu emacs support
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
; Copyright (c) 1993-2001 by Richard Kelsey and Jonathan Rees.
|
||||
; Copyright (c) 1994-2000 by Olin Shivers and Brian D. Carlstrom.
|
||||
; Copyright (c) 1999-2000 by Martin Gasbichler.
|
||||
See file COPYING.
|
||||
|
||||
Please report bugs to scsh-bugs@zurich.ai.mit.edu, and include
|
||||
the version number in your message.
|
||||
|
||||
Installation instructions in file INSTALL.
|
||||
|
||||
A user's guide is in file doc/user-guide.txt.
|
||||
|
||||
Recent changes are listed in file doc/news.txt.
|
||||
|
||||
Known bugs and things to do in the future are listed in doc/todo.txt.
|
||||
|
||||
Send mail to scheme-48-request@martigny.ai.mit.edu to be put on a
|
||||
mailing list for announcements, discussion, bug reports, and bug
|
||||
fixes.
|
||||
|
||||
-----
|
||||
|
||||
The Scheme 48 root directory is organized as follows (not all files are
|
||||
listed here):
|
||||
|
||||
README this file
|
||||
INSTALL installation instructions
|
||||
COPYING copyright notice
|
||||
configure configuration script
|
||||
Makefile.in input to configure
|
||||
doc/ some documentation
|
||||
scheme48.man a Unix-style manual page
|
||||
user-guide.txt general guide to using Scheme 48
|
||||
todo.txt list of improvements we hope to make someday
|
||||
news.txt list of improvements we have already made
|
||||
module.ps description of Scheme 48's module system
|
||||
big-scheme.txt extensions to Scheme
|
||||
threads.txt multiprocessing
|
||||
io.txt how the I/O system works
|
||||
scheme/ scheme source files
|
||||
packages.scm meta-module definitions
|
||||
interfaces.scm system interface definitions
|
||||
more-interfaces.scm system interface definitions
|
||||
*-packages.scm module definitions
|
||||
bcomp/ the byte-code compiler
|
||||
vm/ virtual machine sources (written in Pre-Scheme)
|
||||
rts/ run-time system sources
|
||||
link/ static linker
|
||||
env/ development environment modules (debugger, etc.)
|
||||
big/ useful Scheme libraries and extensions ("Big Scheme")
|
||||
alt/ portable implementations of some Scheme 48 features
|
||||
opt/ optional code optimizer for the byte-code compiler
|
||||
prescheme/ code for running the VM using Scheme 48
|
||||
debug/ debugging utilities, tests, etc.
|
||||
misc/ very miscellaneous things (e.g. AMB operator)
|
||||
posix/ unfinished interface to POSIX system calls
|
||||
ps-compiler/ Pre-Scheme -> C compiler
|
||||
c/ c source files
|
||||
sysdep.h.in input to configure
|
||||
scheme48vm.c most of the VM (generated by Pre-Scheme compiler)
|
||||
scheme48vm.h extern declarations for scheme48vm.c
|
||||
scheme48heap.c storage management (generated by Pre-Scheme compiler)
|
||||
scheme48heap.h extern declarations for scheme48heap.c
|
||||
main.c entry point for the VM
|
||||
prescheme.h part of the VM
|
||||
extension.c default definition of vm_extension()
|
||||
scheme48.h C declarations and macros for Scheme 48 data structures
|
||||
old-scheme48.h old version, included for compatibility
|
||||
c-mods.h minor additions to the C language
|
||||
event.h header file for OS interface
|
||||
io.h ditto
|
||||
fd-io.h ditto
|
||||
socket.c socket support
|
||||
dynamo.c dynamic loading support
|
||||
unix/ Unix-specific source files
|
||||
posix/ C half of an unfinished interface to POSIX system calls
|
||||
fake/ C files for insufficiently POSIX-compliant systems
|
||||
build/ code for building the system
|
||||
filenames.make included by Makefile, generated automatically
|
||||
filenames.scm code for generating filenames.make
|
||||
initial.image an image file containing a minimal Scheme system
|
||||
initial.debug debugging database for same
|
||||
initial.scm script for creating initial.image
|
||||
build-usual-image script for creating scheme48.image
|
||||
build-external-modules script for creating external-module initializer
|
||||
emacs/ gnu emacs support
|
||||
|
|
@ -0,0 +1,525 @@
|
|||
Scsh 0.6.7 Release notes -*- outline -*-
|
||||
|
||||
We are pleased to release scsh version 0.6.7.
|
||||
|
||||
The text below gives a general description of scsh, instructions for obtaining
|
||||
it, pointers to discussion forums, and a description of the new features in
|
||||
release 0.6.7. (Emacs should display this document is in outline mode. Say
|
||||
c-h m for instructions on how to move through it by sections (e.g., c-c c-n,
|
||||
c-c c-p).)
|
||||
|
||||
* Contents
|
||||
==========
|
||||
What is scsh
|
||||
Scsh as a scripting language
|
||||
Scsh as a systems-programming language
|
||||
Scsh is a portable programming environment
|
||||
Obtaining and installing scsh
|
||||
Getting in touch
|
||||
The World-Wide What?
|
||||
New in this release
|
||||
New in 0.6.6
|
||||
New in 0.6.5
|
||||
New in 0.6.4
|
||||
New in 0.6.3
|
||||
New in 0.6.2
|
||||
New in 0.6.1
|
||||
New in 0.6.0
|
||||
Thanks
|
||||
|
||||
|
||||
* What is scsh
|
||||
==============
|
||||
Scsh is a broad-spectrum systems-programming environment for Unix embedded
|
||||
in R5RS Scheme. It has an open-source copyright, and runs on most major
|
||||
Unix systems.
|
||||
|
||||
** Scsh as a scripting language
|
||||
-------------------------------
|
||||
Scsh has a high-level process notation for doing shell-script like tasks:
|
||||
running programs, establishing pipelines and I/O redirection. For example, the
|
||||
shell pipeline
|
||||
|
||||
gunzip < paper.tex.gz | detex | spell | lpr -Ppulp &
|
||||
|
||||
would be written in scsh as
|
||||
|
||||
(& (| (gunzip) (detex) (spell) (lpr -Ppulp)) ; Background a pipeline
|
||||
(< paper.tex.gz)) ; with this redirection
|
||||
|
||||
Scsh embeds this process notation within a full Scheme implementation.
|
||||
The process notation is realized as a set of macro definitions, and is
|
||||
carefully designed to allow full integration with standard Scheme code.
|
||||
Scsh isn't Scheme-like; it is Scheme.
|
||||
|
||||
At the scripting level, scsh also has an Awk design, also implemented
|
||||
as a macro that can be embedded inside general Scheme code.
|
||||
|
||||
Scripts can be written as standalone Scheme source files, with a leading
|
||||
#!/usr/local/bin/scsh -s
|
||||
trigger line.
|
||||
|
||||
|
||||
** Scsh as a systems-programming language
|
||||
-----------------------------------------
|
||||
Scsh additionally provides the low-level access to the operating system
|
||||
normally associated with C. The current release provides full access to Posix,
|
||||
plus important non-Posix extensions, such as complete sockets support.
|
||||
"Complete Posix" means: fork, exec & wait, sockets, full read, write, open &
|
||||
close, seek & tell, complete file-system access, including stat,
|
||||
chmod/chgrp/chown, symlink, FIFO & directory access, tty & pty support, file
|
||||
locking, pipes, select, file-name pattern-matching, time & date, environment
|
||||
variables, signal handlers, and more.
|
||||
|
||||
In brief, you can now write Unix systems programs in Scheme instead of C.
|
||||
For example, we have implemented an extensible HTTP server at MIT entirely
|
||||
in scsh.
|
||||
|
||||
As important as full access to the OS is the manner in which it is provided.
|
||||
Scsh integrates the OS support into Scheme in a manner which respects the
|
||||
general structure of the language. The details of the design are discussed
|
||||
in a joint MIT Lab for Computer Science/University of Hong Kong technical
|
||||
report, "A Scheme Shell," also to appear in a revised format in the "Journal
|
||||
syof Lisp and Symbolic Computation." This paper is also available by ftp:
|
||||
ftp://ftp.scsh.net/pub/scsh/papers/scsh-paper.ps
|
||||
|
||||
|
||||
** Scsh is a portable programming environment
|
||||
---------------------------------------------
|
||||
Scsh is designed for portability. It is implemented on top of Scheme 48,
|
||||
a byte-code-interpreter Scheme implementation. The Scheme 48 virtual machine
|
||||
can be compiled on any system with a C compiler; the rest of Scheme 48 is
|
||||
machine-independent across 32-bit processors. Scsh's OS interface is
|
||||
also quite portable, providing a consistent interface across different
|
||||
Unix platforms. We currently have scsh implementations for:
|
||||
AIX
|
||||
BSD/OS
|
||||
CXUX
|
||||
FreeBSD
|
||||
HP-UX
|
||||
IRIX
|
||||
Linux
|
||||
NetBSD
|
||||
OpenBSD
|
||||
Solaris
|
||||
SunOS
|
||||
Win32
|
||||
Darwin/Mac OS X
|
||||
GNU Hurd
|
||||
|
||||
Scsh code should run without change across these systems.
|
||||
Porting to new platforms is usually not difficult.
|
||||
|
||||
|
||||
* Obtaining and installing scsh
|
||||
===============================
|
||||
You can get a copy of scsh via anonymous ftp, from
|
||||
ftp://ftp.scsh.net/pub/scsh/scsh.tar.gz
|
||||
The tar file includes a detailed manual and a paper describing
|
||||
the design of the system.
|
||||
|
||||
For the lazily curious, we also have the manual separately available as
|
||||
ftp://ftp.scsh.net/pub/scsh/0.6/scsh-manual.ps
|
||||
Just click 'n view.
|
||||
|
||||
You *should* be able to build scsh on the standard platforms with exactly five
|
||||
commands: gunzip, tar, cd, ./configure, and make. The configure script figures
|
||||
out the special flags and switches needed to make the build work (thanks to
|
||||
the GNU project for the autoconfig tool that makes this possible).
|
||||
|
||||
After doing the make, you can start up a Scheme shell and try it out
|
||||
by saying
|
||||
./go
|
||||
See the manual for full details on the command-line switches.
|
||||
|
||||
If it's harder than this, and your system is standard, we'd like to know
|
||||
about it.
|
||||
|
||||
|
||||
* Getting in touch
|
||||
==================
|
||||
|
||||
Currently, there is a mailing-list which is mirrored to a newsgroup.
|
||||
|
||||
To (un)subscribe to the mailing-list, send a message to
|
||||
scsh-users-request@scsh.net. To submit a message to the
|
||||
mailing-list, send it to scsh-users@scsh.net.
|
||||
|
||||
The mailing-list is also readable as a standard newsgroup, thanks to
|
||||
gmane, a mail-to-news gateway. More information is available at the
|
||||
following URL:
|
||||
http://gmane.org/info.php?group=gmane.lisp.scheme.scsh
|
||||
|
||||
There used to be a newsgroup dedicated to scsh, called
|
||||
comp.lang.scheme.scsh but it is now deprecated.
|
||||
|
||||
Bugs can be reported to the same list
|
||||
scsh-users@scsh.net
|
||||
or via the Scsh project's bugs section on SourceForge:
|
||||
http://sourceforge.net/projects/scsh/
|
||||
|
||||
* The World-Wide What?
|
||||
======================
|
||||
We even have one of those dot-com cyberweb things:
|
||||
http://www.scsh.net
|
||||
We manage the project using SourceForge:
|
||||
http://sourceforge.net/projects/scsh/
|
||||
|
||||
* New in this release
|
||||
=====================
|
||||
|
||||
** Support for interix
|
||||
|
||||
** Ignoring of synchronous signals
|
||||
The procedures IGNORE-SIGNAL and HANDLE-SIGNAL-DEFAULT have been
|
||||
added.
|
||||
|
||||
** Support for gcc 4.0
|
||||
|
||||
** 0.6 for module path
|
||||
The standard module path now contains
|
||||
${prefix}/lib/scsh/modules/0.6 in addition to
|
||||
$prefix/lib/scsh/modules for compatibility with install-lib
|
||||
|
||||
** New implementation of open-pty
|
||||
Instead of search for /dev/pty??, scsh now tries a wide variety of
|
||||
ways to aquire a new pty and the corresponding tty.
|
||||
|
||||
** Bug fixes
|
||||
argv[0] is now the first element of command-line
|
||||
Fixes found by new test suite
|
||||
Regexp for empty string
|
||||
Argument checking for COPY-BYTES!
|
||||
GC_PROTECTs for send_substring
|
||||
format_date support for #f timezone
|
||||
Added predicates for user-info and group-info
|
||||
Reaping of stopped processes: Do not mark stopped processes as dead
|
||||
md5-digest-for-port
|
||||
| regexps return char-sets
|
||||
standard-let in srfi-5
|
||||
(%)read-delimited! checks for mutable buffer
|
||||
leap second for srfi-19
|
||||
The default image for the scshvm is now the installed scsh.image.
|
||||
|
||||
* New in 0.6.6
|
||||
===============
|
||||
|
||||
** Removed or replaced non-free code
|
||||
Some files in the previous versions of scsh did not conform to
|
||||
scsh's BSD-style license. We therefore removed the directory
|
||||
scheme/infix and asked the copyright holders of the rest of the
|
||||
code to put their code under a compatible license. The code of the
|
||||
sort package has been replaced by a new version (see below).
|
||||
|
||||
** New code for sorting
|
||||
The old package SORT from Scheme 48 has been replaced by a
|
||||
sophisticated library written by Olin Shivers for the withdrawn
|
||||
SRFI 32.
|
||||
|
||||
** Separate documentation of the library directories search facility
|
||||
The manual now contains a separate section that describes the
|
||||
library directories search facility. The description of the
|
||||
respective switches has been adapted accordingly.
|
||||
|
||||
** New module CONFIGURE
|
||||
The new module CONFIGURE permits access to some of the values
|
||||
obtained during the run of the configure script.
|
||||
|
||||
** Argument processing more robust
|
||||
Any number of whitespaces may now occur between the arguments to
|
||||
the VM.
|
||||
|
||||
** Ultrix is no longer supported
|
||||
The Ultrix platform is lacking support for POSIX regular
|
||||
expressions and is therefore no longer supported.
|
||||
|
||||
** Bug fixes
|
||||
Fix WITH-LOCk
|
||||
Ensure that the exit value is 1 if scsh exits due to an error
|
||||
Load the package scheme-with-scsh before dumping images to get
|
||||
better start-up times
|
||||
Fix two bugs in GLOB related to quotation
|
||||
The optmizer AUTO-INTEGRATE can now inline procedures with
|
||||
macro-generated arguments
|
||||
The optmizer FLAT-ENVIRONMENTS now works if invoked after AUTO-INTEGRATE
|
||||
Fixed a bug in the parser of "-" sre forms
|
||||
Removed accidentally committed expansion of paths in SCSH_LIB_DIR
|
||||
Fix the various SELECT-like procedures for 0 timeouts
|
||||
Let PATH-LIST->FILE-NAME return "/" for '("").
|
||||
Fix bug in S48_RECORD_TYPE: third parameter to s48_stob_ref was missing.
|
||||
Fixed check for -rdynamic
|
||||
FIELD-READER returns (values EOF '()) on an empty port
|
||||
Fixed STRING-CONTAINS and STRING-CONCATENATE-REVERSE/SHARED from SRFI-13
|
||||
|
||||
* New in 0.6.5
|
||||
==============
|
||||
|
||||
** New platform: GNU Hurd
|
||||
Andreas Vögele ported scsh to GNU Hurd.
|
||||
|
||||
** ./configure option to set default scsh library directories
|
||||
The ./configure script now accepts the option --with-lib-dirs-list
|
||||
to specify a list of default scsh library directories. In
|
||||
previous versions of scsh this list was hardwired to
|
||||
/usr/local/lib/scsh/modules.
|
||||
|
||||
** Support for DESTDIR for easier packaging
|
||||
The install target of the Makefile now respects the environment
|
||||
variable DESTDIR to allow package maintainers to use a staging
|
||||
directory.
|
||||
|
||||
** New SRFI
|
||||
This release adds support for SRFI 42.
|
||||
|
||||
** Switch to load exec scripts from library path
|
||||
The new switch -lel searches the library path for a file and loads
|
||||
the file into the exec package.
|
||||
|
||||
** Removed scheme/infix/
|
||||
The directory scheme/infix/ had a non-free copyright licence and
|
||||
has been removed.
|
||||
|
||||
** Bug fixes
|
||||
- SEEK currently works on unbuffered ports only. Check this in the
|
||||
implementation and oopsify it in the manual.
|
||||
- Adjust documentation of some low-level regexp procedures
|
||||
- Removed message argument form errno-error
|
||||
- After fork/pipe, make the ports returned by the pipe the
|
||||
current-in/output-ports
|
||||
- Get the names of MAKE-STRING-PORT-FILTER and
|
||||
MAKE-CHAR-PORT-FILTER right in the doc
|
||||
- Fixed memory leak in scheme_cwd
|
||||
- Fixed memory leak in format_date
|
||||
- Avoid calling SOCKET-OPTION twice in case of an error
|
||||
- Fix for (rx (|)) by Peter Wang
|
||||
- Fix for (posix-string->regexp "$") by Peter Wang
|
||||
|
||||
** API changes
|
||||
None known.
|
||||
|
||||
* New in 0.6.4
|
||||
==============
|
||||
|
||||
** Switches to load exec scripts
|
||||
The new switch -le loads a file into the exec package, the new
|
||||
switch -de loads the "-s" script into the exec package.
|
||||
|
||||
** New SRFIs
|
||||
This release adds support for SRFI 25, 26, 27, 28 and 30.
|
||||
|
||||
** Bug fixes
|
||||
- Other select bug
|
||||
- Timeout for select is in seconds, not milliseconds
|
||||
- Load package md5 before dumping scsh.image
|
||||
- Revised implementation of SRFI-19
|
||||
- -sfd switch called bogus procedures
|
||||
- Ooopsify write-string/partial
|
||||
- Clean up get_groups
|
||||
- Check for "." in file-name-{sans-}extension
|
||||
- Bug fix for let-match: variables may be #f
|
||||
- Fix some problems with WAIT-FOR-CHANNELS
|
||||
- Fixes in the time zone code
|
||||
- Fix a bug in SEND-MESSAGE: There is such a thing as an empty datagram
|
||||
- Renamed string-filter to make-string-port-filter and char-filter to
|
||||
make-char-port-filter
|
||||
|
||||
** API changes
|
||||
pause-until-interrupt has been removed because it is not compatible
|
||||
with the thread system
|
||||
|
||||
* New in 0.6.3
|
||||
==============
|
||||
|
||||
** Shorter startup times
|
||||
By a couple of small fixes we could diminish the startup
|
||||
time by 10-30%.
|
||||
|
||||
** stripped-scsh.image
|
||||
In addition to the standard heap image scsh.image, scsh now ships
|
||||
with an additional image stripped-scsh.image. This image contains
|
||||
the same code as the standard image but has almost all debugging
|
||||
information removed. It is therefore much smaller (2.5 MB vs. 4.5
|
||||
MB) which also allows shorter startup times. The image is intended
|
||||
for use in scripts but not for interactive development. See the
|
||||
manual for more information.
|
||||
|
||||
** MD5 support
|
||||
The package md5 contains a bunch of procedures to compute MD5
|
||||
checksums.
|
||||
|
||||
** New SRFIs
|
||||
This release adds support for SRFI 25, 26, 27, 28 and 30.
|
||||
|
||||
** API changes
|
||||
select and select! are supported again.
|
||||
Note however, that we recommend to use the new select-ports and
|
||||
select-port-channels procedures instead whenever possible.
|
||||
New interface to the uname function.
|
||||
New direct interface to the directory stream operations
|
||||
New structure scheme-with-scsh which combines the exports of the
|
||||
modules scsh and scheme, avoiding duplicates
|
||||
New procdures to work directly on file-info records
|
||||
The repl procedure has been removed
|
||||
New procedures connect-socket-no-wait, connect-socket-successful?
|
||||
Add lookup-external from recent S48
|
||||
|
||||
** Bugfixes
|
||||
LET-MATCH, IF-MATCH, and COND-MATCH now behave according to the
|
||||
documentation.
|
||||
Many bug fixes for the SRE system, specifically for dynamic
|
||||
submatches.
|
||||
PORT->SOCKET uses dups both ports of the socket
|
||||
Added missing process resource alignments
|
||||
No reaping for stopped children
|
||||
Initialize t.c_lflag before reading it.
|
||||
Fix to allow single character here strings.
|
||||
Add a whole bunch of S48_GC_PROTECT against s48_extract_integer.
|
||||
Added MAP, FOR-EACH, MEMBER, ASSOC to SRFI 1 interface
|
||||
Fixed a subtle bug in the macro for the << redirection
|
||||
Use "compare" und "rename" to compare symbols in lots of macros
|
||||
Fixed the close method for string-input-ports
|
||||
... and many others.
|
||||
|
||||
* New in 0.6.2
|
||||
==============
|
||||
|
||||
** SRFIs
|
||||
In addition to SRFIs 1, 8, 13, 14 and 23 scsh now features SRFIs 2,
|
||||
5, 6, 7, 9, 11, 16, 17 and 19. See http://srfi.schemers.org/ for a
|
||||
detailed description. The SRFIs are available in packages srfi-N
|
||||
where N is the number of the SRFI.
|
||||
|
||||
** port->socket
|
||||
New procedure port->socket to turn a port into a socket object was
|
||||
added to the network code.
|
||||
|
||||
** New forms in the module language
|
||||
The module language supports the new forms modify, subset and
|
||||
with-prefix from Scheme 48 version 0.57.
|
||||
|
||||
** API changes
|
||||
Fork, fork/pipe, fork/pipe+ take an optional argument
|
||||
continue-threads? to determine whether all threads should continue
|
||||
to run in the child.
|
||||
|
||||
exec-path-list is now a preseved thread fluid
|
||||
|
||||
** PDF version of the manual
|
||||
There is now a PDF version of the manual generated by pdflatex.
|
||||
|
||||
** Bugfixes
|
||||
- Added default argument to tty-info as described in the manual
|
||||
- Conversion to s48_value in tty1.c
|
||||
- Fixed another hygiene problem in SRE
|
||||
- Plugged space leak in bind-listen-accept-loop
|
||||
- Aligned CWD and umask in various file operations
|
||||
- Better releasing of port locks
|
||||
- Corrected exception of time
|
||||
- Set-cloexec to #t for unrevealed ports.
|
||||
- Included scsh paper in the distribution.
|
||||
- Fixed accept for AF_UNIX
|
||||
- (setenv var #f) now deletes var from environment
|
||||
- Quoted { and } within literal strings of regexps
|
||||
|
||||
* New in 0.6.1
|
||||
==============
|
||||
|
||||
** API changes
|
||||
For sre's, BOW, EOW, WORD, and WORD+ (which were already unsupported
|
||||
in 0.6.0 on most platforms) are gone for good.
|
||||
|
||||
** Bugfixes
|
||||
Most of the known bugs of version 0.6.0 have been fixed, many thanks for
|
||||
the precise reports! See the project page on SourceForge for a list
|
||||
of the remaining known bugs. Here is a brief overview of the fixes:
|
||||
|
||||
- GC_PROTECT'ed the necessary variables (specifically, where >1 arg to
|
||||
a function 'may GC') (Thanks to Steven Jenkins for dealing with this)
|
||||
- Fixed various race conditons in the signal handling and process reaping code
|
||||
- Fixed bug in set-process-group
|
||||
- If $HOME is unset, consult (user-info (user-uid)) for the value of
|
||||
home-directory
|
||||
- Fix external-call-from-callback problem leading to spurious
|
||||
gc-protection-mismatch exceptions.
|
||||
- Let s48-do-gc return 0 so the PreScheme compiler will emit the correct
|
||||
signature of the function.
|
||||
- scsh/linux/tty-consts.scm: num-ttychars seems to be 32 not 19.
|
||||
- scsh/top.scm: Return 0 exit status for -c and -e.
|
||||
- *.c: Replaced // comments.
|
||||
- scsh/syslog1.c: Remove LOG_LPR from list of syslog levels.
|
||||
- scsh/network1.c: Pass SYSCALL argument to ERRNO-ERROR.
|
||||
- scsh/syscalls1.c: Disable timer interrupts before execve
|
||||
- scsh/network.scm: Correct name extraction in bind-socket
|
||||
- Added export for with-error-output-port
|
||||
- Install HTML version of manual under $(libdir)
|
||||
- ./configure is more rebost wrt $(srcdir)
|
||||
- Fixed installation of the S48 manual
|
||||
- Replaced several /tmp by /var/tmp
|
||||
- Catch EISDIR in delete-filesys-object
|
||||
- flush-all-ports is now non-blocking
|
||||
|
||||
* New in 0.6.0
|
||||
==============
|
||||
|
||||
** Scsh is now based on Scheme 48 0.53
|
||||
With the move from Scheme 48 version 0.36 to version 0.53 in this
|
||||
release the underlying system received a massive update. The most
|
||||
significant changes include:
|
||||
User level threads
|
||||
Advanced garbage collector
|
||||
Improved foreign function interface to C
|
||||
|
||||
The most significant change for Scsh users is the addition of a
|
||||
user-level thread system. Scsh provides various features to deal
|
||||
with this new power in a system programming environment: An event
|
||||
based interface to interrupts, thread local process state and
|
||||
thread-safe system calls.
|
||||
|
||||
** A manual for Scheme 48 has been included
|
||||
Richard Kelsey, the author of Scheme 48, has graciously allowed us
|
||||
to retrofit the current Scheme 48 manual for inclusion in this scsh
|
||||
release.
|
||||
|
||||
** Interfaces to dot-locking, crypt and syslog
|
||||
Scsh now provides advisory file locking via the dot-locking scheme
|
||||
and a direct binding to the crypt function. Furthermore we added
|
||||
a complete, system-independent and thread-safe interface to syslog.
|
||||
|
||||
** API changes
|
||||
Some features of the previous releases are currently not
|
||||
supported as we did not have the time to implement them. Please tell
|
||||
us, if you can't get along without them. Here is a listing of these
|
||||
currently dereleased features:
|
||||
select
|
||||
select!
|
||||
ODBC support
|
||||
bufpol/line
|
||||
|
||||
The following procedures received new names in this release:
|
||||
sleep (now process-sleep)
|
||||
sleep-until (now process-sleep-until)
|
||||
|
||||
network-info, service-info and protocol-info now return #f on non-success.
|
||||
|
||||
The default directory for creating temporary files has changed: It's
|
||||
now the value of $TMPDIR if set and /var/tmp otherwise.
|
||||
|
||||
The nth procedure is still there but is now officially obsolete. It
|
||||
will go away in a future release.
|
||||
|
||||
** HTML version of the manual
|
||||
There is now a HTML version of the scsh manual generated by tex2page
|
||||
|
||||
* Thanks
|
||||
========
|
||||
|
||||
We would like to thank the members of local-resistance cells for the
|
||||
Underground everywhere for bug reports, bug fixes, design review and comments
|
||||
that were incorporated into this release. We really appreciate their help,
|
||||
particularly in the task of porting scsh to new platforms.
|
||||
|
||||
|
||||
Brought to you by the Scheme Underground. Go forth and write elegant systems
|
||||
programs.
|
||||
-Olin Shivers, Brian Carlstrom, Martin Gasbichler & Mike Sperber
|
||||
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
0.6.1 release-critical:
|
||||
=======================
|
||||
|
||||
Non-critical: [Martin]
|
||||
=============
|
||||
S48_EXTRACT_BOOLEAN is defined several times
|
||||
|
||||
create-file-thing should report a better error message.
|
||||
|
||||
/* Sorry, we only have a version with 5 arguments..*/.
|
||||
s48_raise_os_error_5 (errno, sec, min, hour, mday, month);
|
||||
|
||||
|
||||
how do i make the scheme48 heap larger? preferably without having to write
|
||||
scripts that start like this:
|
||||
|
||||
#!/usr/local/lib/scsh/scshvm \
|
||||
-o /usr/local/lib/scsh/scshvm -i /usr/local/lib/scsh/scsh.image -h <large-value>
|
||||
-s
|
||||
!#
|
||||
|
||||
Check whether we have remove the extern char *tzname[] declaration in time1.c
|
||||
|
||||
implement bufpol/line's flush on stdin
|
||||
|
||||
|
||||
Move the code of time_plus_ticks to time1.c as it is not machine dependent
|
||||
|
||||
--->
|
||||
The module system doesn't maintain a cwd of its own:
|
||||
|
||||
> ,config ,load ../sunet/xml/xml-packages.scm
|
||||
../sunet/xml/xml-packages.scm
|
||||
> (chdir "/tmp")
|
||||
> ,open xml
|
||||
Load structure xml (y/n)? y
|
||||
[plt-compat
|
||||
Error: exception
|
||||
cannot-open-channel
|
||||
(open-channel "../sunet/xml/plt.scm" 1)
|
||||
<---
|
||||
|
||||
split up newports.scm (part that overwrites s48 defs, port-buffering, ...)
|
||||
|
||||
disallow cig to produce more than 12 arguments
|
||||
|
||||
libcig1.c : cig_string_body is probably extract_string
|
||||
IsChar is used nowhere
|
||||
|
||||
Add .h.c rule to Makefile
|
||||
|
||||
--->
|
||||
(define-syntax bla
|
||||
(syntax-rules ()
|
||||
((bla)
|
||||
(rx any))))
|
||||
> (bla)
|
||||
|
||||
Error: Illegal regular expression
|
||||
#{Generated any 1276}
|
||||
|
||||
(Because "any" is imported from scsh-utilities in rx/parse.scm)
|
||||
<---
|
||||
|
||||
Set port policy for input to bufpol/line via isatty
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
Post-0.5.2-release bug reports:
|
||||
Friedrich Dominicus
|
||||
Jay Nietling
|
||||
Tim Bradshaw
|
||||
Robert Brown
|
||||
Eric Marsden
|
||||
Paul Emsley
|
||||
Pawel Turnau
|
||||
Hannu Koivisto
|
||||
Andy Gaynor
|
||||
Francisco Vides Fernandez
|
||||
Tim Burgess
|
||||
Brian Denheyer
|
||||
Harvey Stein
|
||||
Eric Hilsdale
|
||||
Andreas Bernauer
|
||||
Chris Beggy
|
||||
Ed Kademan
|
||||
Michal Maruska
|
||||
Noel Hunt
|
||||
David Reiss
|
||||
Chad R Dougherty
|
||||
Michel Schinz
|
||||
Alan Bawden
|
||||
Bengt Kleberg
|
||||
RT Happe
|
||||
Dorai Sitaram
|
||||
Peter Wang
|
||||
Stephen Ma
|
||||
stktrc
|
||||
Jan Alleman
|
||||
Taylor Campbell
|
||||
32
acconfig.h
32
acconfig.h
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* HAVE_SIGACTION is defined iff sigaction() is available.
|
||||
*/
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/*
|
||||
* HAVE_STRERROR is defined iff the standard libraries provide strerror().
|
||||
*/
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/*
|
||||
* NLIST_HAS_N_NAME is defined iff a struct nlist has an n_name member.
|
||||
* If it doesn't then we assume it has an n_un member which, in turn,
|
||||
* has an n_name member.
|
||||
*/
|
||||
#undef NLIST_HAS_N_NAME
|
||||
|
||||
/*
|
||||
* HAVE_SYS_SELECT_H is defined iff we have the include file sys/select.h.
|
||||
*/
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/*
|
||||
* USCORE is defined iff C externals are prepended with an underscore.
|
||||
*/
|
||||
#undef USCORE
|
||||
|
||||
@BOTTOM@
|
||||
|
||||
#include "fake/sigact.h"
|
||||
#include "fake/strerror.h"
|
||||
#include "fake/sys-select.h"
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#! /bin/sh
|
||||
|
||||
autoheader &&
|
||||
autoconf &&
|
||||
./configure &&
|
||||
touch scsh/*.c &&
|
||||
touch build/filenames.scm &&
|
||||
rm -f scheme48.image cig/cig.image scsh/scsh.image &&
|
||||
rm -f build/linker.image build/initial.image &&
|
||||
rm -f c/scheme48.h &&
|
||||
make build/filenames.make &&
|
||||
make i-know-what-i-am-doing &&
|
||||
make c/scheme48.h&&
|
||||
make linker &&
|
||||
make build/initial.image &&
|
||||
make distclean
|
||||
|
|
@ -9,11 +9,12 @@ vm=$4
|
|||
initial=$5
|
||||
USER=${USER-`logname 2>/dev/null || echo '*GOK*'`}
|
||||
|
||||
$vm -i $initial -a batch <<EOF
|
||||
./$vm -o ./$vm -i $initial batch <<EOF
|
||||
,load $srcdir/scheme/env/init-defpackage.scm
|
||||
((*structure-ref filenames 'set-translation!)
|
||||
"=scheme48/" "$srcdir/scheme/")
|
||||
,load =scheme48/more-interfaces.scm =scheme48/link-packages.scm
|
||||
,load =scheme48/more-interfaces.scm =scheme48/sort/interfaces.scm
|
||||
,load =scheme48/link-packages.scm
|
||||
,load =scheme48/more-packages.scm
|
||||
(ensure-loaded command-processor)
|
||||
(ensure-loaded usual-commands)
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
#### This file was generated automatically. ####
|
||||
|
||||
initial-files = scheme/rts/low.scm scheme/rts/signal.scm scheme/rts/base.scm scheme/rts/util.scm scheme/rts/number.scm scheme/rts/lize.scm scheme/rts/record.scm scheme/rts/jar-defrecord.scm scheme/rts/method.scm scheme/rts/numio.scm scheme/rts/fluid.scm scheme/rts/defenum.scm scheme/vm/arch.scm scheme/big/queue.scm scheme/rts/condition.scm scheme/rts/session.scm scheme/rts/interrupt.scm scheme/rts/wind.scm scheme/rts/template.scm scheme/rts/continuation.scm scheme/rts/exception.scm scheme/rts/thread.scm scheme/rts/sleep.scm scheme/rts/lock.scm scheme/rts/port.scm scheme/rts/current-port.scm scheme/rts/write.scm scheme/rts/read.scm scheme/rts/channel.scm scheme/rts/channel-port.scm scheme/rts/channel-io.scm scheme/big/general-table.scm scheme/rts/population.scm scheme/bcomp/mtype.scm scheme/bcomp/interface.scm scheme/bcomp/binding.scm scheme/bcomp/name.scm scheme/bcomp/transform.scm scheme/bcomp/cenv.scm scheme/bcomp/thingie.scm scheme/bcomp/package.scm scheme/bcomp/package-undef.scm scheme/rts/env.scm scheme/big/filename.scm scheme/bcomp/read-form.scm scheme/bcomp/node.scm scheme/bcomp/schemify.scm scheme/bcomp/var-util.scm scheme/bcomp/syntax.scm scheme/bcomp/primop.scm scheme/bcomp/ddata.scm scheme/bcomp/stack-check.scm scheme/bcomp/state.scm scheme/bcomp/segment.scm scheme/bcomp/recon.scm scheme/bcomp/comp-exp.scm scheme/bcomp/comp-prim.scm scheme/bcomp/comp.scm scheme/rts/eval.scm scheme/env/dispcond.scm scheme/debug/mini-command.scm scheme/rts/scheduler.scm scheme/rts/root-scheduler.scm scheme/rts/init.scm scheme/env/start.scm scheme/bcomp/usual.scm scheme/bcomp/rules.scm scheme/bcomp/type.scm scheme/bcomp/module-language.scm scheme/bcomp/config.scm scheme/bcomp/scan-package.scm scheme/bcomp/optimize.scm scheme/bcomp/comp-package.scm scheme/env/load-package.scm scheme/big/strong.scm scheme/opt/usage.scm scheme/opt/sort.scm scheme/opt/inline.scm scheme/bcomp/for-reify.scm
|
||||
|
||||
usual-files = scheme/opt/analyze.scm scheme/env/disclosers.scm scheme/env/command-level.scm scheme/env/version-info.scm scheme/env/command.scm scheme/env/read-command.scm scheme/env/debuginfo.scm scheme/rts/xnum.scm scheme/rts/bignum.scm scheme/rts/ratnum.scm scheme/rts/recnum.scm scheme/rts/innum.scm scheme/env/basic-command.scm scheme/env/build.scm scheme/env/shadow.scm scheme/env/pedit.scm scheme/env/pacman.scm scheme/rts/time.scm scheme/env/debug.scm scheme/env/inspect.scm scheme/env/disasm.scm
|
||||
|
||||
linker-files = scheme/rts/util.scm scheme/alt/fluid.scm scheme/rts/defenum.scm scheme/vm/arch.scm scheme/alt/jar-defrecord.scm scheme/big/general-table.scm scheme/bcomp/mtype.scm scheme/alt/locations.scm scheme/bcomp/binding.scm scheme/bcomp/name.scm scheme/bcomp/transform.scm scheme/bcomp/node.scm scheme/bcomp/schemify.scm scheme/bcomp/var-util.scm scheme/bcomp/primop.scm scheme/alt/template.scm scheme/rts/template.scm scheme/bcomp/ddata.scm scheme/bcomp/thingie.scm scheme/bcomp/stack-check.scm scheme/bcomp/state.scm scheme/bcomp/segment.scm scheme/bcomp/recon.scm scheme/bcomp/comp-exp.scm scheme/bcomp/comp-prim.scm scheme/bcomp/comp.scm scheme/alt/closure.scm scheme/link/data.scm scheme/link/transport.scm scheme/link/write-image.scm scheme/alt/weak.scm scheme/rts/population.scm scheme/bcomp/interface.scm scheme/bcomp/cenv.scm scheme/bcomp/package.scm scheme/bcomp/package-undef.scm scheme/bcomp/syntax.scm scheme/env/debuginfo.scm scheme/big/filename.scm scheme/bcomp/read-form.scm scheme/bcomp/scan-package.scm scheme/bcomp/optimize.scm scheme/bcomp/usual.scm scheme/bcomp/rules.scm scheme/bcomp/comp-package.scm scheme/big/strong.scm scheme/opt/usage.scm scheme/opt/sort.scm scheme/opt/inline.scm scheme/link/reify.scm scheme/link/link.scm scheme/alt/loophole.scm scheme/bcomp/type.scm scheme/alt/low.scm scheme/bcomp/module-language.scm scheme/bcomp/config.scm scheme/opt/analyze.scm scheme/alt/environments.scm scheme/link/loadc.scm scheme/env/flatload.scm
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
; Define DEFINE-STRUCTURE and friends
|
||||
(for-each load
|
||||
'("scheme/bcomp/module-language.scm"
|
||||
"scheme/alt/dummy-interface.scm"
|
||||
"scheme/alt/config.scm"
|
||||
"scheme/env/flatload.scm"))
|
||||
|
||||
|
|
|
|||
6351
build/initial.debug
6351
build/initial.debug
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
|
@ -1,4 +1,4 @@
|
|||
; Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees. See file COPYING.
|
||||
; Copyright (c) 1993-2000 by Richard Kelsey and Jonathan Rees. See file COPYING.
|
||||
|
||||
; Link script.
|
||||
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
(l '()))
|
||||
(for-each (lambda (int)
|
||||
(for-each-declaration
|
||||
(lambda (name type)
|
||||
(lambda (name package-name type)
|
||||
(if (not (assq name l))
|
||||
(let ((s (eval name env)))
|
||||
(if (structure? s)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
53
|
||||
6.7
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
sysdep.h
|
||||
sysdep.h.in
|
||||
|
|
@ -1,4 +1,10 @@
|
|||
|
||||
#ifndef TRUE
|
||||
#define TRUE (0 == 0)
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE (0 == 1)
|
||||
#endif
|
||||
|
||||
#define bool char /* boolean type */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
enum event_enum { KEYBOARD_INTERRUPT_EVENT, IO_COMPLETION_EVENT, ALARM_EVENT,
|
||||
OS_SIGNAL_EVENT, ERROR_EVENT, NO_EVENT };
|
||||
enum event_enum { KEYBOARD_INTERRUPT_EVENT,
|
||||
IO_READ_COMPLETION_EVENT, IO_WRITE_COMPLETION_EVENT,
|
||||
ALARM_EVENT,
|
||||
OS_SIGNAL_EVENT, ERROR_EVENT, NO_EVENT };
|
||||
|
||||
extern bool s48_add_pending_fd(int fd, bool is_input);
|
||||
extern bool s48_remove_fd(int fd);
|
||||
|
|
|
|||
465
c/external.c
465
c/external.c
|
|
@ -127,6 +127,8 @@ s48_value
|
|||
s48_external_call(s48_value sch_proc, s48_value proc_name,
|
||||
long nargs, char *char_argv)
|
||||
{
|
||||
volatile char *gc_marker; /* volatile to survive longjumps */
|
||||
char *gc_marker_temp; /* C wants it so */
|
||||
volatile char *gc_roots_marker; /* volatile to survive longjumps */
|
||||
volatile s48_value name = proc_name; /* volatile to survive longjumps */
|
||||
|
||||
|
|
@ -144,7 +146,8 @@ s48_external_call(s48_value sch_proc, s48_value proc_name,
|
|||
S48_CHECK_VALUE(sch_proc);
|
||||
S48_CHECK_STRING(name);
|
||||
|
||||
gc_roots_marker = s48_set_gc_roots_baseB();
|
||||
gc_roots_marker = s48_set_gc_roots_baseB(&gc_marker_temp);
|
||||
gc_marker = gc_marker_temp;
|
||||
|
||||
/* fprintf(stderr, "[external_call at depth %d]\n", depth); */
|
||||
|
||||
|
|
@ -209,7 +212,7 @@ s48_external_call(s48_value sch_proc, s48_value proc_name,
|
|||
|
||||
/* Raise an exception if the user neglected to pop off some gc roots. */
|
||||
|
||||
if (! s48_release_gc_roots_baseB((char *)gc_roots_marker)) {
|
||||
if (! s48_release_gc_roots_baseB((char *)gc_roots_marker, (char *)gc_marker)) {
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_GC_PROTECTION_MISMATCH, 0);
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +245,7 @@ s48_external_call(s48_value sch_proc, s48_value proc_name,
|
|||
depth,
|
||||
callback_depth());
|
||||
fprintf(stderr, "[throw unrolling to %ld]\n", gc_roots_marker); */
|
||||
s48_release_gc_roots_baseB((char *)gc_roots_marker);
|
||||
s48_release_gc_roots_baseB((char *)gc_roots_marker, (char *)gc_marker);
|
||||
}
|
||||
|
||||
/* Check to see if a thread is waiting to return to the next block down. */
|
||||
|
|
@ -301,7 +304,7 @@ s48_call_scheme(s48_value proc, long nargs, ...)
|
|||
|
||||
/* It would be nice to push a list of the arguments, but we have no way
|
||||
of preserving them across a cons. */
|
||||
if (nargs < 0 || 10 < nargs) { /* DO NOT INCREASE THIS NUMBER */
|
||||
if (nargs < 0 || 12 < nargs) { /* DO NOT INCREASE THIS NUMBER */
|
||||
s48_value sch_nargs = s48_enter_integer(nargs); /* `proc' is protected */
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_TOO_MANY_ARGUMENTS_IN_CALLBACK,
|
||||
2, proc, sch_nargs);
|
||||
|
|
@ -473,12 +476,12 @@ s48_raise_scheme_exception(long why, long nargs, ...)
|
|||
/* Specific exceptions */
|
||||
|
||||
void
|
||||
s48_raise_argtype_error(s48_value value) {
|
||||
s48_raise_argument_type_error(s48_value value) {
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_WRONG_TYPE_ARGUMENT, 1, value);
|
||||
}
|
||||
|
||||
void
|
||||
s48_raise_argnumber_error(s48_value value, s48_value min, s48_value max) {
|
||||
s48_raise_argument_number_error(s48_value value, s48_value min, s48_value max) {
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_WRONG_NUMBER_OF_ARGUMENTS,
|
||||
3, value, min, max);
|
||||
}
|
||||
|
|
@ -497,10 +500,132 @@ s48_raise_closed_channel_error() {
|
|||
void
|
||||
s48_raise_os_error(int the_errno) {
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 2,
|
||||
s48_enter_fixnum(the_errno),
|
||||
s48_enter_integer(the_errno),
|
||||
s48_enter_string(strerror(the_errno)));
|
||||
}
|
||||
|
||||
void
|
||||
s48_raise_os_error_1(int the_errno, s48_value arg1) {
|
||||
|
||||
s48_value sch_errno = S48_UNSPECIFIC;
|
||||
|
||||
S48_DECLARE_GC_PROTECT(2);
|
||||
S48_GC_PROTECT_2 (arg1, sch_errno);
|
||||
|
||||
sch_errno = s48_enter_integer(the_errno);
|
||||
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 3,
|
||||
sch_errno,
|
||||
s48_enter_string(strerror(the_errno)),
|
||||
arg1);
|
||||
|
||||
S48_GC_UNPROTECT();
|
||||
}
|
||||
|
||||
void
|
||||
s48_raise_os_error_2(int the_errno, s48_value arg1, s48_value arg2) {
|
||||
|
||||
s48_value sch_errno = S48_UNSPECIFIC;
|
||||
|
||||
S48_DECLARE_GC_PROTECT(3);
|
||||
S48_GC_PROTECT_3 (arg1, arg2, sch_errno);
|
||||
|
||||
sch_errno = s48_enter_integer(the_errno);
|
||||
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 4,
|
||||
sch_errno,
|
||||
s48_enter_string(strerror(the_errno)),
|
||||
arg1, arg2);
|
||||
S48_GC_UNPROTECT();
|
||||
}
|
||||
|
||||
void
|
||||
s48_raise_os_error_3(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3) {
|
||||
|
||||
s48_value sch_errno = S48_UNSPECIFIC;
|
||||
|
||||
S48_DECLARE_GC_PROTECT(4);
|
||||
S48_GC_PROTECT_4 (arg1, arg2, arg3, sch_errno);
|
||||
|
||||
sch_errno = s48_enter_integer(the_errno);
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 5,
|
||||
sch_errno,
|
||||
s48_enter_string(strerror(the_errno)),
|
||||
arg1, arg2, arg3);
|
||||
S48_GC_UNPROTECT();
|
||||
}
|
||||
|
||||
void
|
||||
s48_raise_os_error_4(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3, s48_value arg4) {
|
||||
|
||||
s48_value sch_errno = S48_UNSPECIFIC;
|
||||
|
||||
S48_DECLARE_GC_PROTECT(5);
|
||||
S48_GC_PROTECT_5 (arg1, arg2, arg3, arg4, sch_errno);
|
||||
|
||||
sch_errno = s48_enter_integer(the_errno);
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 6,
|
||||
sch_errno,
|
||||
s48_enter_string(strerror(the_errno)),
|
||||
arg1, arg2, arg3, arg4);
|
||||
S48_GC_UNPROTECT();
|
||||
}
|
||||
|
||||
void
|
||||
s48_raise_os_error_5(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3, s48_value arg4, s48_value arg5) {
|
||||
|
||||
s48_value sch_errno = S48_UNSPECIFIC;
|
||||
|
||||
S48_DECLARE_GC_PROTECT(6);
|
||||
S48_GC_PROTECT_6 (arg1, arg2, arg3, arg4, arg5, sch_errno);
|
||||
|
||||
sch_errno = s48_enter_integer(the_errno);
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 7,
|
||||
sch_errno,
|
||||
s48_enter_string(strerror(the_errno)),
|
||||
arg1, arg2, arg3, arg4, arg5);
|
||||
S48_GC_UNPROTECT();
|
||||
}
|
||||
|
||||
void
|
||||
s48_raise_os_error_6(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3, s48_value arg4, s48_value arg5,
|
||||
s48_value arg6) {
|
||||
|
||||
s48_value sch_errno = S48_UNSPECIFIC;
|
||||
|
||||
S48_DECLARE_GC_PROTECT(7);
|
||||
S48_GC_PROTECT_7 (arg1, arg2, arg3, arg4, arg5, arg6, sch_errno);
|
||||
|
||||
sch_errno = s48_enter_integer(the_errno);
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 8,
|
||||
sch_errno,
|
||||
s48_enter_string(strerror(the_errno)),
|
||||
arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
S48_GC_UNPROTECT();
|
||||
}
|
||||
|
||||
void
|
||||
s48_raise_os_error_7(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3, s48_value arg4, s48_value arg5,
|
||||
s48_value arg6, s48_value arg7) {
|
||||
|
||||
s48_value sch_errno = S48_UNSPECIFIC;
|
||||
|
||||
S48_DECLARE_GC_PROTECT(8);
|
||||
S48_GC_PROTECT_8 (arg1, arg2, arg3, arg4, arg5, arg6, arg7, sch_errno);
|
||||
|
||||
sch_errno = s48_enter_integer(the_errno);
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 9,
|
||||
sch_errno,
|
||||
s48_enter_string(strerror(the_errno)),
|
||||
arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
S48_GC_UNPROTECT();
|
||||
}
|
||||
|
||||
void
|
||||
s48_raise_string_os_error(char *reason) {
|
||||
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 1,
|
||||
|
|
@ -529,7 +654,7 @@ long
|
|||
s48_stob_length(s48_value thing, int type)
|
||||
{
|
||||
if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
|
||||
s48_raise_argtype_error(thing);
|
||||
s48_raise_argument_type_error(thing);
|
||||
|
||||
return S48_STOB_DESCRIPTOR_LENGTH(thing);
|
||||
}
|
||||
|
|
@ -538,7 +663,7 @@ long
|
|||
s48_stob_byte_length(s48_value thing, int type)
|
||||
{
|
||||
if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
|
||||
s48_raise_argtype_error(thing);
|
||||
s48_raise_argument_type_error(thing);
|
||||
|
||||
if (type == S48_STOBTYPE_STRING)
|
||||
return S48_STOB_BYTE_LENGTH(thing) - 1;
|
||||
|
|
@ -552,7 +677,7 @@ s48_stob_ref(s48_value thing, int type, long offset)
|
|||
long length;
|
||||
|
||||
if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
|
||||
s48_raise_argtype_error(thing);
|
||||
s48_raise_argument_type_error(thing);
|
||||
|
||||
length = S48_STOB_DESCRIPTOR_LENGTH(thing);
|
||||
|
||||
|
|
@ -572,7 +697,7 @@ s48_stob_set(s48_value thing, int type, long offset, s48_value value)
|
|||
if (!(S48_STOB_P(thing) &&
|
||||
(S48_STOB_TYPE(thing) == type) &&
|
||||
!S48_STOB_IMMUTABLEP(thing)))
|
||||
s48_raise_argtype_error(thing);
|
||||
s48_raise_argument_type_error(thing);
|
||||
|
||||
length = S48_STOB_DESCRIPTOR_LENGTH(thing);
|
||||
|
||||
|
|
@ -585,12 +710,12 @@ s48_stob_set(s48_value thing, int type, long offset, s48_value value)
|
|||
}
|
||||
|
||||
char
|
||||
s48_byte_ref(s48_value thing, int type, long offset)
|
||||
s48_stob_byte_ref(s48_value thing, int type, long offset)
|
||||
{
|
||||
long length;
|
||||
|
||||
if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
|
||||
s48_raise_argtype_error(thing);
|
||||
s48_raise_argument_type_error(thing);
|
||||
|
||||
length = (type == S48_STOBTYPE_STRING) ?
|
||||
S48_STOB_BYTE_LENGTH(thing) - 1 :
|
||||
|
|
@ -605,12 +730,12 @@ s48_byte_ref(s48_value thing, int type, long offset)
|
|||
}
|
||||
|
||||
void
|
||||
s48_byte_set(s48_value thing, int type, long offset, char value)
|
||||
s48_stob_byte_set(s48_value thing, int type, long offset, char value)
|
||||
{
|
||||
long length;
|
||||
|
||||
if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
|
||||
s48_raise_argtype_error(thing);
|
||||
s48_raise_argument_type_error(thing);
|
||||
|
||||
length = (type == S48_STOBTYPE_STRING) ?
|
||||
S48_STOB_BYTE_LENGTH(thing) - 1 :
|
||||
|
|
@ -645,7 +770,7 @@ s48_value
|
|||
s48_enter_fixnum(long value)
|
||||
{
|
||||
if (value < S48_MIN_FIXNUM_VALUE || S48_MAX_FIXNUM_VALUE < value)
|
||||
s48_raise_argtype_error(s48_enter_integer(value));
|
||||
s48_raise_argument_type_error(s48_enter_integer(value));
|
||||
|
||||
return S48_UNSAFE_ENTER_FIXNUM(value);
|
||||
}
|
||||
|
|
@ -654,7 +779,7 @@ long
|
|||
s48_extract_fixnum(s48_value value)
|
||||
{
|
||||
if (! S48_FIXNUM_P(value))
|
||||
s48_raise_argtype_error(value);
|
||||
s48_raise_argument_type_error(value);
|
||||
|
||||
return S48_UNSAFE_EXTRACT_FIXNUM(value);
|
||||
}
|
||||
|
|
@ -689,6 +814,22 @@ s48_enter_integer(long value)
|
|||
}
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_enter_unsigned_integer(unsigned long value)
|
||||
{
|
||||
if (value <= S48_MAX_FIXNUM_VALUE)
|
||||
return S48_UNSAFE_ENTER_FIXNUM(value);
|
||||
else {
|
||||
S48_SHARED_BINDING_CHECK(long_to_bignum_binding);
|
||||
|
||||
return s48_call_scheme(S48_SHARED_BINDING_REF(long_to_bignum_binding),
|
||||
3,
|
||||
S48_FALSE, /* this is ok */
|
||||
S48_UNSAFE_ENTER_FIXNUM(value >> 16),
|
||||
S48_UNSAFE_ENTER_FIXNUM(value & 0xFFFF));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a fixnum we just extract it. Bignums require a call back into
|
||||
* Scheme 48. (BIGNUM-TO-LONG n) returns a vector containing the sign and the
|
||||
|
|
@ -717,7 +858,7 @@ s48_extract_integer(s48_value value)
|
|||
S48_GC_UNPROTECT();
|
||||
|
||||
if (stuff == S48_FALSE)
|
||||
s48_raise_argtype_error(value);
|
||||
s48_raise_argument_type_error(value);
|
||||
|
||||
/* The first VECTOR_REF does the type checking for the rest. */
|
||||
{
|
||||
|
|
@ -728,7 +869,7 @@ s48_extract_integer(s48_value value)
|
|||
|
||||
if ((! S48_FIXNUM_P(boxed_high)) ||
|
||||
high > (pos_p ? 0x7FFF : 0x8000))
|
||||
s48_raise_argtype_error(value);
|
||||
s48_raise_argument_type_error(value);
|
||||
|
||||
{
|
||||
long magnitude = ((- high) << 16) - low;
|
||||
|
|
@ -738,6 +879,49 @@ s48_extract_integer(s48_value value)
|
|||
}
|
||||
}
|
||||
|
||||
unsigned long
|
||||
s48_extract_unsigned_integer(s48_value value)
|
||||
{
|
||||
long temp;
|
||||
if (S48_FIXNUM_P(value)){
|
||||
temp = S48_UNSAFE_EXTRACT_FIXNUM(value);
|
||||
if (temp < 0)
|
||||
s48_raise_argument_type_error(value);
|
||||
else return (unsigned long) temp;
|
||||
}
|
||||
else {
|
||||
s48_value stuff;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(value);
|
||||
|
||||
S48_SHARED_BINDING_CHECK(bignum_to_long_binding);
|
||||
|
||||
stuff = s48_call_scheme(S48_SHARED_BINDING_REF(bignum_to_long_binding),
|
||||
1,
|
||||
value);
|
||||
|
||||
S48_GC_UNPROTECT();
|
||||
|
||||
if (stuff == S48_FALSE)
|
||||
s48_raise_argument_type_error(value);
|
||||
|
||||
/* The first VECTOR_REF does the type checking for the rest. */
|
||||
{
|
||||
long low = S48_UNSAFE_EXTRACT_FIXNUM(S48_VECTOR_REF(stuff, 2));
|
||||
s48_value boxed_high = S48_UNSAFE_VECTOR_REF(stuff, 1);
|
||||
long high = S48_UNSAFE_EXTRACT_FIXNUM(boxed_high);
|
||||
int pos_p = S48_EXTRACT_BOOLEAN(S48_UNSAFE_VECTOR_REF(stuff, 0));
|
||||
|
||||
if ((!pos_p) ||
|
||||
(! S48_FIXNUM_P(boxed_high)) ||
|
||||
(high > 0xFFFF))
|
||||
s48_raise_argument_type_error(value);
|
||||
else return ((((unsigned long) high) << 16) + low);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Doubles and characters are straightforward.
|
||||
*/
|
||||
|
|
@ -757,7 +941,7 @@ double
|
|||
s48_extract_double(s48_value s48_double)
|
||||
{
|
||||
if (! S48_DOUBLE_P(s48_double))
|
||||
s48_raise_argtype_error(s48_double);
|
||||
s48_raise_argument_type_error(s48_double);
|
||||
|
||||
return S48_UNSAFE_EXTRACT_DOUBLE(s48_double);
|
||||
}
|
||||
|
|
@ -777,7 +961,7 @@ unsigned char
|
|||
s48_extract_char(s48_value a_char)
|
||||
{
|
||||
if (! S48_CHAR_P(a_char))
|
||||
s48_raise_argtype_error(a_char);
|
||||
s48_raise_argument_type_error(a_char);
|
||||
|
||||
return S48_UNSAFE_EXTRACT_CHAR(a_char);
|
||||
}
|
||||
|
|
@ -812,6 +996,164 @@ s48_cons(s48_value v1, s48_value v2)
|
|||
return obj;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_1(s48_value v1)
|
||||
{
|
||||
return (s48_cons (v1, S48_NULL));
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_2(s48_value v1, s48_value v2)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_1 (v2);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_3(s48_value v1, s48_value v2, s48_value v3)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_2 (v2, v3);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_4(s48_value v1, s48_value v2, s48_value v3, s48_value v4)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_3 (v2, v3, v4);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_5(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_4 (v2, v3, v4, v5);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_6(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
|
||||
s48_value v6)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_5 (v2, v3, v4, v5, v6);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_7(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
|
||||
s48_value v6, s48_value v7)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_6 (v2, v3, v4, v5, v6, v7);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_8(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
|
||||
s48_value v6, s48_value v7, s48_value v8)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_7 (v2, v3, v4, v5, v6, v7, v8);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_9(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
|
||||
s48_value v6, s48_value v7, s48_value v8, s48_value v9)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_8 (v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_10(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
|
||||
s48_value v6, s48_value v7, s48_value v8, s48_value v9, s48_value v10)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_9 (v2, v3, v4, v5, v6, v7, v8, v9, v10);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_11(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
|
||||
s48_value v6, s48_value v7, s48_value v8, s48_value v9, s48_value v10,
|
||||
s48_value v11)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_10 (v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_list_12(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
|
||||
s48_value v6, s48_value v7, s48_value v8, s48_value v9, s48_value v10,
|
||||
s48_value v11, s48_value v12)
|
||||
{
|
||||
s48_value list = S48_UNSPECIFIC;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(v1);
|
||||
list = s48_list_11 (v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
|
||||
list = s48_cons (v1, list);
|
||||
S48_GC_UNPROTECT();
|
||||
return list;
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_make_weak_pointer(s48_value value)
|
||||
{
|
||||
|
|
@ -831,7 +1173,7 @@ s48_value
|
|||
s48_enter_substring(char *str, int length)
|
||||
{
|
||||
s48_value obj = s48_allocate_stob(S48_STOBTYPE_STRING, length + 1);
|
||||
strncpy(S48_UNSAFE_EXTRACT_STRING(obj), str, length);
|
||||
memcpy(S48_UNSAFE_EXTRACT_STRING(obj), str, length);
|
||||
*(S48_UNSAFE_EXTRACT_STRING(obj) + length) = '\0';
|
||||
return obj;
|
||||
}
|
||||
|
|
@ -878,9 +1220,31 @@ s48_make_vector(int length, s48_value init)
|
|||
}
|
||||
|
||||
s48_value
|
||||
s48_make_byte_vector(int length)
|
||||
s48_enter_byte_vector(char *bvec, int length)
|
||||
{
|
||||
return s48_allocate_stob(S48_STOBTYPE_BYTE_VECTOR, length);
|
||||
s48_value obj = s48_allocate_stob(S48_STOBTYPE_BYTE_VECTOR, length);
|
||||
memcpy(S48_UNSAFE_EXTRACT_BYTE_VECTOR(obj), bvec, length);
|
||||
return obj;
|
||||
}
|
||||
|
||||
char *
|
||||
s48_extract_byte_vector(s48_value bvec)
|
||||
{
|
||||
S48_CHECK_BYTE_VECTOR(bvec);
|
||||
|
||||
return S48_UNSAFE_EXTRACT_BYTE_VECTOR(bvec);
|
||||
}
|
||||
|
||||
s48_value
|
||||
s48_make_byte_vector(int length, int init)
|
||||
{
|
||||
int i;
|
||||
s48_value obj = s48_allocate_stob(S48_STOBTYPE_BYTE_VECTOR, length);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
S48_BYTE_VECTOR_SET(obj, i, init);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
s48_value
|
||||
|
|
@ -929,7 +1293,7 @@ s48_check_record_type(s48_value record, s48_value type_binding)
|
|||
if ((! S48_RECORD_P(record)) ||
|
||||
(S48_UNSAFE_SHARED_BINDING_REF(type_binding) !=
|
||||
S48_UNSAFE_RECORD_REF(record, -1)))
|
||||
s48_raise_argtype_error(record);
|
||||
s48_raise_argument_type_error(record);
|
||||
}
|
||||
|
||||
long
|
||||
|
|
@ -945,3 +1309,54 @@ s48_length(s48_value list)
|
|||
return S48_UNSAFE_ENTER_FIXNUM(i);
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
** Support for libscsh.a: add external initializers without the Makefile
|
||||
**
|
||||
*/
|
||||
|
||||
struct simple_list{
|
||||
void (*init)(); /* pointer to init-function */
|
||||
struct simple_list* next;
|
||||
};
|
||||
|
||||
struct simple_list* additional_inits = 0;
|
||||
|
||||
/*
|
||||
* This function is part of EXTERNAL_INITIALIZERS in the scsh Makefile.
|
||||
* It calls the init-functions in additional_inits.
|
||||
*/
|
||||
|
||||
void s48_init_additional_inits(){
|
||||
|
||||
struct simple_list* ptr = additional_inits;
|
||||
struct simple_list* free_me;
|
||||
|
||||
while (ptr != 0){
|
||||
ptr->init();
|
||||
free_me = ptr;
|
||||
ptr = ptr->next;
|
||||
free (free_me);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Actual API function: argument is an init-function. You have to
|
||||
* ensure, that all s48_add_external_inits are called before you call
|
||||
* s48_main.
|
||||
*/
|
||||
|
||||
int s48_add_external_init(void (*init)()){
|
||||
|
||||
struct simple_list *new_list;
|
||||
|
||||
new_list = (struct simple_list *) malloc(sizeof (struct simple_list));
|
||||
|
||||
if (new_list == 0) return 0;
|
||||
|
||||
new_list->init = init;
|
||||
new_list->next = additional_inits;
|
||||
additional_inits = new_list;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
/*
|
||||
* This include file is for systems which do not have dynamic loading.
|
||||
*/
|
||||
#if ! defined(HAVE_DLOPEN)
|
||||
|
||||
extern void *dlopen(char *filename, int flags);
|
||||
extern char *dlerror(void);
|
||||
extern void *dlsym(void *lib, char *name);
|
||||
extern int dlclose(void *lib);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,12 +5,18 @@
|
|||
* (whose name is pointed to by object_file).
|
||||
*/
|
||||
#include "sysdep.h"
|
||||
#include <stdlib.h>
|
||||
#include <nlist.h>
|
||||
|
||||
#ifdef USCORE
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DLOPEN)
|
||||
#include <dlfcn.h>
|
||||
#else
|
||||
#include "../fake/dlfcn.h"
|
||||
#endif
|
||||
|
||||
#if ! defined(NLIST_HAS_N_NAME)
|
||||
#define n_name n_un.n_name
|
||||
#endif
|
||||
|
|
@ -64,7 +70,7 @@ dlsym(void *lib, char *name)
|
|||
lasterror = "Bad library pointer passed to dlsym()";
|
||||
return (NULL);
|
||||
}
|
||||
if (object_file == NULL) {
|
||||
if (s48_object_file == NULL) {
|
||||
lasterror = "I don't know the name of my executable";
|
||||
return (NULL);
|
||||
}
|
||||
|
|
@ -87,7 +93,7 @@ dlsym(void *lib, char *name)
|
|||
names[0].n_value = 0; /* for Linux */
|
||||
names[0].n_type = 0; /* for Linux */
|
||||
names[1].n_name = NULL;
|
||||
status = nlist(object_file, names);
|
||||
status = nlist(s48_object_file, names);
|
||||
#ifdef USCORE
|
||||
if (tmp != buff)
|
||||
free((void *)tmp);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ extern int ps_open_fd(char *in_filename, bool is_input, long *status);
|
|||
|
||||
extern int ps_close_fd(long fd_as_long);
|
||||
|
||||
extern bool ps_check_fd(long fd_as_long, bool is_read, long *status);
|
||||
|
||||
extern long ps_read_fd(long fd_as_long, char *buf_as_long, long max, bool waitp,
|
||||
bool *eofp, bool *pending, long *status);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
/* Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees.
|
||||
See file COPYING. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "scheme48vm.h"
|
||||
#include "scheme48heap.h"
|
||||
|
||||
extern void s48_sysdep_init(void);
|
||||
extern void s48_initialize_external_modules(void);
|
||||
|
||||
/* JMG: s48_object_file is obsolete according to s48 manual */
|
||||
char *s48_object_file; /* specified via a command line argument */
|
||||
|
||||
char *s48_reloc_file; /* dynamic loading will set this */
|
||||
|
||||
void *heap, *stack;
|
||||
|
||||
int s48_main (long heap_size, long stack_size,
|
||||
char *image_name, int argc, char** argv)
|
||||
{
|
||||
int ret = internal_s48_main(heap_size, stack_size, "libscsh", "libscsh",
|
||||
image_name, argc, argv);
|
||||
free(heap);
|
||||
free(stack);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
internal_s48_main(long heap_size, long stack_size,
|
||||
char* object_file, char *image_name, int argc, char** argv)
|
||||
{
|
||||
long return_value;
|
||||
long required_heap_size;
|
||||
int warn_undefined_imported_bindings_p = 0;
|
||||
|
||||
#if defined(STATIC_AREAS)
|
||||
extern long static_entry;
|
||||
extern long static_symbol_table;
|
||||
extern long static_imported_binding_table, static_exported_binding_table;
|
||||
extern long p_count, *p_areas[], p_sizes[];
|
||||
extern long i_count, *i_areas[], i_sizes[];
|
||||
#endif
|
||||
|
||||
|
||||
s48_object_file = object_file;
|
||||
s48_reloc_file = NULL;
|
||||
|
||||
|
||||
s48_sysdep_init();
|
||||
s48_heap_init();
|
||||
s48_init();
|
||||
|
||||
if (image_name == NULL)
|
||||
required_heap_size = 0;
|
||||
else {
|
||||
/* check_image_header returns number of bytes; required_heap_size
|
||||
is number of cells. */
|
||||
required_heap_size =
|
||||
s48_check_image_header((unsigned char *)image_name) >> 2;
|
||||
if (-1 == required_heap_size) {
|
||||
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
|
||||
return 1; }
|
||||
}
|
||||
|
||||
/* two semi-spaces, plus we want some room to maneuver */
|
||||
if (heap_size < 4 * required_heap_size) {
|
||||
fprintf(stderr, "heap size %ld is too small, using %ld\n",
|
||||
heap_size, 4 * required_heap_size);
|
||||
heap_size = 4 * required_heap_size; }
|
||||
|
||||
heap = (void *) malloc(heap_size * sizeof(long));
|
||||
stack = (void *) malloc(stack_size * sizeof(long));
|
||||
|
||||
if (!heap || !stack) {
|
||||
fprintf(stderr, "system is out of memory\n");
|
||||
return 1; }
|
||||
|
||||
s48_initialize_heap((long)heap, heap_size);
|
||||
|
||||
#if defined(STATIC_AREAS)
|
||||
if (image_name == NULL) {
|
||||
s48_register_static_areas(p_count, p_areas, p_sizes,
|
||||
i_count, i_areas, i_sizes);
|
||||
s48_set_image_valuesB(static_entry,
|
||||
static_symbol_table,
|
||||
static_imported_binding_table,
|
||||
static_exported_binding_table);
|
||||
} else if (s48_read_image() == -1) {
|
||||
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
|
||||
return 1; }
|
||||
#else
|
||||
if (s48_read_image() == -1) {
|
||||
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
|
||||
return 1; }
|
||||
#endif
|
||||
|
||||
s48_initialize_vm(stack, stack_size);
|
||||
|
||||
s48_initialize_external_modules();
|
||||
|
||||
if (warn_undefined_imported_bindings_p)
|
||||
s48_warn_about_undefined_imported_bindings();
|
||||
|
||||
return_value = s48_call_startup_procedure(argv, argc);
|
||||
|
||||
if (s48_reloc_file != NULL)
|
||||
if (0 != unlink(s48_reloc_file))
|
||||
fprintf(stderr, "unable to delete file %s\n", s48_reloc_file);
|
||||
|
||||
return(return_value);
|
||||
}
|
||||
|
||||
163
c/main.c
163
c/main.c
|
|
@ -4,12 +4,13 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "scheme48vm.h"
|
||||
#include "scheme48heap.h"
|
||||
|
||||
/* I bumped this up from 1.5 Mcell because the debugging info put us over
|
||||
** the top. -Olin
|
||||
*/
|
||||
#if !defined(DEFAULT_HEAP_SIZE)
|
||||
/* 1.5 megacell = 6 megabytes (3 meg per semispace) */
|
||||
#define DEFAULT_HEAP_SIZE 1500000L
|
||||
/* 5 megacell = 20 megabytes (10 meg per semispace) */
|
||||
#define DEFAULT_HEAP_SIZE 5000000L
|
||||
#endif
|
||||
|
||||
#if !defined(DEFAULT_STACK_SIZE)
|
||||
|
|
@ -23,29 +24,34 @@
|
|||
|
||||
/* DEFAULT_IMAGE_NAME should be defined using the -D switch to cc. */
|
||||
#if !defined(DEFAULT_IMAGE_NAME)
|
||||
#define DEFAULT_IMAGE_NAME "scheme48.image"
|
||||
#define DEFAULT_IMAGE_NAME "scsh.image"
|
||||
#endif
|
||||
|
||||
#endif /* STATIC_AREAS */
|
||||
|
||||
extern void s48_sysdep_init(void);
|
||||
extern void s48_initialize_external_modules(void);
|
||||
|
||||
char *s48_object_file; /* specified via a command line argument */
|
||||
char *s48_reloc_file; /* dynamic loading will set this */
|
||||
|
||||
char ** process_args(char **argv,
|
||||
long *heap_size,
|
||||
long *stack_size,
|
||||
char **object_file,
|
||||
char **image_name);
|
||||
|
||||
extern int
|
||||
internal_s48_main(long heap_size, long stack_size,
|
||||
char* object_file, char* image_name,
|
||||
int argc, char** argv);
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc; char **argv;
|
||||
{
|
||||
char **argp; /* JMG */
|
||||
char *image_name = DEFAULT_IMAGE_NAME;
|
||||
long heap_size = DEFAULT_HEAP_SIZE; /* in numbers of cells */
|
||||
long stack_size = DEFAULT_STACK_SIZE; /* in numbers of cells */
|
||||
int errors = 0;
|
||||
long return_value;
|
||||
void *heap, *stack;
|
||||
long required_heap_size;
|
||||
int warn_undefined_imported_bindings_p = 1;
|
||||
char *object_file = NULL; /* specified via a command line argument */
|
||||
char *prog_name;
|
||||
|
||||
#if defined(STATIC_AREAS)
|
||||
extern long static_entry;
|
||||
|
|
@ -56,126 +62,13 @@ main(argc, argv)
|
|||
#endif
|
||||
|
||||
long vm_argc = 0;
|
||||
char *me = *argv; /* Save program name. */
|
||||
prog_name = *argv++;/* Save program name. */
|
||||
|
||||
s48_object_file = s48_reloc_file = NULL;
|
||||
|
||||
argv++; argc--; /* Skip program name. */
|
||||
|
||||
for (; argc > 0; argc--, argv++)
|
||||
if (argv[0][0] == '-')
|
||||
switch (argv[0][1]) {
|
||||
case 'h':
|
||||
argc--; argv++;
|
||||
if (argc == 0) { errors++; break; }
|
||||
heap_size = atoi(*argv);
|
||||
if (heap_size <= 0) errors++;
|
||||
break;
|
||||
case 's':
|
||||
argc--; argv++;
|
||||
if (argc == 0) { errors++; break; }
|
||||
stack_size = atoi(*argv);
|
||||
if (stack_size <= 0) errors++;
|
||||
break;
|
||||
case 'i':
|
||||
argc--; argv++;
|
||||
if (argc == 0) { errors++; break; }
|
||||
image_name = *argv;
|
||||
break;
|
||||
case 'a':
|
||||
argc--;
|
||||
vm_argc = argc; /* remaining args are passed to the VM */
|
||||
argc = 0;
|
||||
break;
|
||||
case 'o':
|
||||
argc--; argv++;
|
||||
if (argc == 0) { errors++; break; }
|
||||
s48_object_file = *argv;
|
||||
break;
|
||||
case 'u':
|
||||
argc--; argv++;
|
||||
warn_undefined_imported_bindings_p = 0;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid argument: %s\n", *argv);
|
||||
errors++;
|
||||
}
|
||||
else
|
||||
if (argv[0][0] != '\0') {
|
||||
fprintf(stderr, "Invalid argument: %s\n", *argv);
|
||||
errors++; }
|
||||
if (errors != 0) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s [options] [-a arguments]\n\
|
||||
Options: -h <total heap size in words>\n\
|
||||
-s <stack buffer size in words>\n\
|
||||
-i <image file name>\n\
|
||||
-o <object file name>\n\
|
||||
-u [don't warn on unbound external identifiers]",
|
||||
me);
|
||||
return 1;
|
||||
}
|
||||
|
||||
s48_sysdep_init();
|
||||
s48_heap_init();
|
||||
s48_init();
|
||||
|
||||
if (image_name == NULL)
|
||||
required_heap_size = 0;
|
||||
else {
|
||||
/* check_image_header returns number of bytes; required_heap_size
|
||||
is number of cells. */
|
||||
required_heap_size =
|
||||
s48_check_image_header((unsigned char *)image_name) >> 2;
|
||||
if (-1 == required_heap_size) {
|
||||
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
|
||||
return 1; }
|
||||
}
|
||||
|
||||
/* two semi-spaces, plus we want some room to maneuver */
|
||||
if (heap_size < 4 * required_heap_size) {
|
||||
fprintf(stderr, "heap size %ld is too small, using %ld\n",
|
||||
heap_size, 4 * required_heap_size);
|
||||
heap_size = 4 * required_heap_size; }
|
||||
|
||||
heap = (void *) malloc(heap_size * sizeof(long));
|
||||
stack = (void *) malloc(stack_size * sizeof(long));
|
||||
|
||||
if (!heap || !stack) {
|
||||
fprintf(stderr, "system is out of memory\n");
|
||||
return 1; }
|
||||
|
||||
s48_initialize_heap((long)heap, heap_size);
|
||||
|
||||
#if defined(STATIC_AREAS)
|
||||
if (image_name == NULL) {
|
||||
s48_register_static_areas(p_count, p_areas, p_sizes,
|
||||
i_count, i_areas, i_sizes);
|
||||
s48_set_image_valuesB(static_entry,
|
||||
static_symbol_table,
|
||||
static_imported_binding_table,
|
||||
static_exported_binding_table);
|
||||
} else if (s48_read_image() == -1) {
|
||||
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
|
||||
return 1; }
|
||||
#else
|
||||
if (s48_read_image() == -1) {
|
||||
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
|
||||
return 1; }
|
||||
#endif
|
||||
|
||||
s48_initialize_vm(stack, stack_size);
|
||||
|
||||
s48_initialize_external_modules();
|
||||
|
||||
if (warn_undefined_imported_bindings_p)
|
||||
s48_warn_about_undefined_imported_bindings();
|
||||
|
||||
return_value = s48_call_startup_procedure(argv, vm_argc);
|
||||
|
||||
if (s48_reloc_file != NULL)
|
||||
if (0 != unlink(s48_reloc_file))
|
||||
fprintf(stderr, "unable to delete file %s\n", s48_reloc_file);
|
||||
|
||||
return(return_value);
|
||||
argv=process_args(argv,
|
||||
&heap_size, &stack_size,
|
||||
&object_file, &image_name);
|
||||
argv--;
|
||||
argv[0] = prog_name;
|
||||
for(argc=0, argp=argv; *argp; argc++, argp++); /* Recompute argc. */
|
||||
return internal_s48_main(heap_size, stack_size, object_file, image_name, argc, argv);
|
||||
}
|
||||
|
|
|
|||
189
c/scheme48.h
189
c/scheme48.h
|
|
@ -13,9 +13,16 @@ typedef long s48_value;
|
|||
|
||||
#define NO_ERRORS 0 /* errno value */
|
||||
|
||||
extern int s48_main (long heap_size, long stack_size,
|
||||
char *image_name, int argc, char** argv);
|
||||
|
||||
extern int s48_add_external_init(void (*init)());
|
||||
|
||||
/* Misc stuff */
|
||||
|
||||
#define S48_EQ(v1, v2) ((v1) == (v2))
|
||||
#define S48_EQ_P(v1, v2) ((v1) == (v2))
|
||||
/* Superceded name for the above definition, retained for compatibility. */
|
||||
#define S48_EQ(v1, v2) ((v1) == (v2))
|
||||
|
||||
#define S48_MAX_FIXNUM_VALUE ((1 << 29) - 1)
|
||||
#define S48_MIN_FIXNUM_VALUE (-1 << 29)
|
||||
|
|
@ -39,15 +46,43 @@ extern s48_value s48_enter_fixnum(long);
|
|||
extern long s48_extract_fixnum(s48_value);
|
||||
extern s48_value s48_enter_integer(long);
|
||||
extern long s48_extract_integer(s48_value);
|
||||
extern s48_value s48_enter_unsigned_integer(unsigned long);
|
||||
extern unsigned long s48_extract_unsigned_integer(s48_value);
|
||||
extern s48_value s48_enter_double(double);
|
||||
extern double s48_extract_double(s48_value);
|
||||
extern s48_value s48_cons(s48_value, s48_value);
|
||||
extern s48_value s48_list_1(s48_value);
|
||||
extern s48_value s48_list_2(s48_value, s48_value);
|
||||
extern s48_value s48_list_3(s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_list_4(s48_value, s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_list_5(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value);
|
||||
extern s48_value s48_list_6(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value);
|
||||
extern s48_value s48_list_7(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_list_8(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_list_9(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value);
|
||||
extern s48_value s48_list_10(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value);
|
||||
extern s48_value s48_list_11(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_list_12(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_enter_string(char *);
|
||||
extern char * s48_extract_string(s48_value);
|
||||
extern s48_value s48_enter_substring(char *, int);
|
||||
extern s48_value s48_make_string(int, char);
|
||||
extern s48_value s48_make_vector(int, s48_value);
|
||||
extern s48_value s48_make_byte_vector(int);
|
||||
extern s48_value s48_enter_byte_vector(char *, int);
|
||||
extern char * s48_extract_byte_vector(s48_value);
|
||||
extern s48_value s48_make_byte_vector(int, int);
|
||||
extern s48_value s48_make_record(s48_value);
|
||||
extern s48_value s48_make_weak_pointer(s48_value);
|
||||
extern void s48_check_record_type(s48_value, s48_value);
|
||||
|
|
@ -64,7 +99,7 @@ extern s48_value s48_call_scheme(s48_value proc, long nargs, ...);
|
|||
|
||||
#define S48_EXPORT_FUNCTION(p) (s48_define_exported_binding(#p, s48_enter_pointer(p)))
|
||||
|
||||
#define S48_MAKE_VALUE(type) (s48_make_byte_vector(sizeof(type)))
|
||||
#define S48_MAKE_VALUE(type) (s48_make_byte_vector(sizeof(type),0))
|
||||
extern void * s48_value_pointer(s48_value);
|
||||
|
||||
#define S48_EXTRACT_VALUE_POINTER(x, type) ((type *) s48_value_pointer(x))
|
||||
|
|
@ -177,28 +212,46 @@ extern void * s48_value_pointer(s48_value);
|
|||
/* Exceptions */
|
||||
|
||||
extern void s48_raise_scheme_exception(long type, long nargs, ...);
|
||||
extern void s48_raise_argtype_error(s48_value value);
|
||||
extern void s48_raise_argnumber_error(s48_value value,
|
||||
s48_value min, s48_value max);
|
||||
extern void s48_raise_argument_type_error(s48_value value);
|
||||
extern void s48_raise_argument_number_error(s48_value value,
|
||||
s48_value min,
|
||||
s48_value max);
|
||||
extern void s48_raise_range_error(s48_value value,
|
||||
s48_value min, s48_value max);
|
||||
extern void s48_raise_closed_channel_error();
|
||||
extern void s48_raise_os_error(int the_errno);
|
||||
extern void s48_raise_os_error_1(int the_errno, s48_value arg1);
|
||||
extern void s48_raise_os_error_2(int the_errno, s48_value arg1, s48_value arg2);
|
||||
extern void s48_raise_os_error_3(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3);
|
||||
extern void s48_raise_os_error_4(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3, s48_value arg4);
|
||||
extern void s48_raise_os_error_5(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3, s48_value arg4, s48_value arg5);
|
||||
extern void s48_raise_os_error_6(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3, s48_value arg4, s48_value arg5,
|
||||
s48_value arg6);
|
||||
extern void s48_raise_string_os_error(char *reason);
|
||||
extern void s48_raise_out_of_memory_error();
|
||||
|
||||
/* Type checking */
|
||||
|
||||
#define S48_CHECK_PAIR(v) do { if (!S48_PAIR_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_FIXNUM(v) do { if (!S48_FIXNUM_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_STRING(v) do { if (!S48_STRING_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_CHANNEL(v) do { if (!S48_CHANNEL_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_RECORD(v) do { if (!S48_RECORD_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_VALUE(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_EXPORT_BINDING(v) do { if (!S48_EXPORT_BINDING_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_PAIR(v) do { if (!S48_PAIR_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_FIXNUM(v) do { if (!S48_FIXNUM_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_STRING(v) do { if (!S48_STRING_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_BYTE_VECTOR(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_CHANNEL(v) do { if (!S48_CHANNEL_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_RECORD(v) do { if (!S48_RECORD_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_VALUE(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_EXPORT_BINDING(v) do { if (!S48_EXPORT_BINDING_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
|
||||
#define S48_VALUE_P(v) (S48_BYTE_VECTOR_P(v))
|
||||
|
||||
#define S48_TRUE_P(v) ((v) == S48_TRUE)
|
||||
#define S48_FALSE_P(v) ((v) == S48_FALSE)
|
||||
#define S48_EXTRACT_BOOLEAN(v) ((v) != S48_FALSE)
|
||||
#define S48_ENTER_BOOLEAN(v) ((v) ? S48_TRUE : S48_FALSE)
|
||||
|
||||
extern void s48_check_record_type(s48_value record, s48_value type_binding);
|
||||
|
||||
#define S48_SHARED_BINDING_CHECK(binding) \
|
||||
|
|
@ -207,6 +260,7 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
|
|||
S48_SHARED_BINDING_NAME(binding)); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define S48_FIXNUM_TAG 0
|
||||
#define S48_FIXNUM_P(x) (((long)(x) & 3L) == S48_FIXNUM_TAG)
|
||||
#define S48_IMMEDIATE_TAG 1
|
||||
|
|
@ -228,9 +282,6 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
|
|||
#define S48_EOF (S48_MISC_IMMEDIATE(5))
|
||||
#define S48_NULL (S48_MISC_IMMEDIATE(6))
|
||||
|
||||
#define S48_ENTER_BOOLEAN(n) ((n) ? S48_TRUE : S48_FALSE)
|
||||
#define S48_EXTRACT_BOOLEAN(x) ((x) != S48_FALSE)
|
||||
|
||||
#define S48_UNSAFE_ENTER_CHAR(c) (S48_CHAR | ((c) << 8))
|
||||
#define S48_UNSAFE_EXTRACT_CHAR(x) ((x) >> 8)
|
||||
#define S48_CHAR_P(x) ((((long) (x)) & 0xff) == S48_CHAR)
|
||||
|
|
@ -238,8 +289,8 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
|
|||
#define S48_ADDRESS_AFTER_HEADER(x, type) ((type *)((x) - S48_STOB_TAG))
|
||||
#define S48_STOB_REF(x, i) (S48_ADDRESS_AFTER_HEADER(x, s48_value)[i])
|
||||
#define S48_STOB_BYTE_REF(x, i) (((char *)S48_ADDRESS_AFTER_HEADER(x, s48_value))[i])
|
||||
#define S48_STOB_SET(x, i, v) do { s48_value __stob_set_x = (x); long __stob_set_i = (i); s48_value __stob_set_v = (v); if (S48_STOB_IMMUTABLEP(__stob_set_x)) s48_raise_argtype_error(__stob_set_x); else { S48_WRITE_BARRIER((__stob_set_x), (char *) (&S48_STOB_REF((__stob_set_x), (__stob_set_i))),(__stob_set_v)); *(&S48_STOB_REF((__stob_set_x), (__stob_set_i))) = (__stob_set_v); } } while (0)
|
||||
#define S48_STOB_BYTE_SET(x, i, v) do { char __stob_set_x = (x); long __stob_set_i = (i); s48_value __stob_set_v = (v); if (S48_STOB_IMMUTABLEP(__stob_set_x)) s48_raise_argtype_error(__stob_set_x); else *(&S48_STOB_BYTE_REF((__stob_set_x), (__stob_set_i))) = (__stob_set_v); } while (0)
|
||||
#define S48_STOB_SET(x, i, v) do { s48_value __stob_set_x = (x); long __stob_set_i = (i); s48_value __stob_set_v = (v); if (S48_STOB_IMMUTABLEP(__stob_set_x)) s48_raise_argument_type_error(__stob_set_x); else { S48_WRITE_BARRIER((__stob_set_x), (char *) (&S48_STOB_REF((__stob_set_x), (__stob_set_i))),(__stob_set_v)); *(&S48_STOB_REF((__stob_set_x), (__stob_set_i))) = (__stob_set_v); } } while (0)
|
||||
#define S48_STOB_BYTE_SET(x, i, v) do { s48_value __stob_set_x = (x); long __stob_set_i = (i); char __stob_set_v = (v); if (S48_STOB_IMMUTABLEP(__stob_set_x)) s48_raise_argument_type_error(__stob_set_x); else *(&S48_STOB_BYTE_REF((__stob_set_x), (__stob_set_i))) = (__stob_set_v); } while (0)
|
||||
#define S48_STOB_TYPE(x) ((S48_STOB_HEADER(x)>>2)&31)
|
||||
#define S48_STOB_HEADER(x) (S48_STOB_REF((x),-1))
|
||||
#define S48_STOB_ADDRESS(x) (&(S48_STOB_HEADER(x)))
|
||||
|
|
@ -258,46 +309,48 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
|
|||
#define S48_CLOSURE_P(x) (s48_stob_has_type(x, 3))
|
||||
#define S48_STOBTYPE_LOCATION 4
|
||||
#define S48_LOCATION_P(x) (s48_stob_has_type(x, 4))
|
||||
#define S48_STOBTYPE_CHANNEL 5
|
||||
#define S48_CHANNEL_P(x) (s48_stob_has_type(x, 5))
|
||||
#define S48_STOBTYPE_PORT 6
|
||||
#define S48_PORT_P(x) (s48_stob_has_type(x, 6))
|
||||
#define S48_STOBTYPE_RATNUM 7
|
||||
#define S48_RATNUM_P(x) (s48_stob_has_type(x, 7))
|
||||
#define S48_STOBTYPE_RECORD 8
|
||||
#define S48_RECORD_P(x) (s48_stob_has_type(x, 8))
|
||||
#define S48_STOBTYPE_CONTINUATION 9
|
||||
#define S48_CONTINUATION_P(x) (s48_stob_has_type(x, 9))
|
||||
#define S48_STOBTYPE_EXTENDED_NUMBER 10
|
||||
#define S48_EXTENDED_NUMBER_P(x) (s48_stob_has_type(x, 10))
|
||||
#define S48_STOBTYPE_TEMPLATE 11
|
||||
#define S48_TEMPLATE_P(x) (s48_stob_has_type(x, 11))
|
||||
#define S48_STOBTYPE_WEAK_POINTER 12
|
||||
#define S48_WEAK_POINTER_P(x) (s48_stob_has_type(x, 12))
|
||||
#define S48_STOBTYPE_SHARED_BINDING 13
|
||||
#define S48_SHARED_BINDING_P(x) (s48_stob_has_type(x, 13))
|
||||
#define S48_STOBTYPE_UNUSED_D_HEADER1 14
|
||||
#define S48_UNUSED_D_HEADER1_P(x) (s48_stob_has_type(x, 14))
|
||||
#define S48_STOBTYPE_UNUSED_D_HEADER2 15
|
||||
#define S48_UNUSED_D_HEADER2_P(x) (s48_stob_has_type(x, 15))
|
||||
#define S48_STOBTYPE_STRING 16
|
||||
#define S48_STRING_P(x) (s48_stob_has_type(x, 16))
|
||||
#define S48_STOBTYPE_BYTE_VECTOR 17
|
||||
#define S48_BYTE_VECTOR_P(x) (s48_stob_has_type(x, 17))
|
||||
#define S48_STOBTYPE_DOUBLE 18
|
||||
#define S48_DOUBLE_P(x) (s48_stob_has_type(x, 18))
|
||||
#define S48_STOBTYPE_BIGNUM 19
|
||||
#define S48_BIGNUM_P(x) (s48_stob_has_type(x, 19))
|
||||
#define S48_STOBTYPE_CELL 5
|
||||
#define S48_CELL_P(x) (s48_stob_has_type(x, 5))
|
||||
#define S48_STOBTYPE_CHANNEL 6
|
||||
#define S48_CHANNEL_P(x) (s48_stob_has_type(x, 6))
|
||||
#define S48_STOBTYPE_PORT 7
|
||||
#define S48_PORT_P(x) (s48_stob_has_type(x, 7))
|
||||
#define S48_STOBTYPE_RATNUM 8
|
||||
#define S48_RATNUM_P(x) (s48_stob_has_type(x, 8))
|
||||
#define S48_STOBTYPE_RECORD 9
|
||||
#define S48_RECORD_P(x) (s48_stob_has_type(x, 9))
|
||||
#define S48_STOBTYPE_CONTINUATION 10
|
||||
#define S48_CONTINUATION_P(x) (s48_stob_has_type(x, 10))
|
||||
#define S48_STOBTYPE_EXTENDED_NUMBER 11
|
||||
#define S48_EXTENDED_NUMBER_P(x) (s48_stob_has_type(x, 11))
|
||||
#define S48_STOBTYPE_TEMPLATE 12
|
||||
#define S48_TEMPLATE_P(x) (s48_stob_has_type(x, 12))
|
||||
#define S48_STOBTYPE_WEAK_POINTER 13
|
||||
#define S48_WEAK_POINTER_P(x) (s48_stob_has_type(x, 13))
|
||||
#define S48_STOBTYPE_SHARED_BINDING 14
|
||||
#define S48_SHARED_BINDING_P(x) (s48_stob_has_type(x, 14))
|
||||
#define S48_STOBTYPE_UNUSED_D_HEADER1 15
|
||||
#define S48_UNUSED_D_HEADER1_P(x) (s48_stob_has_type(x, 15))
|
||||
#define S48_STOBTYPE_UNUSED_D_HEADER2 16
|
||||
#define S48_UNUSED_D_HEADER2_P(x) (s48_stob_has_type(x, 16))
|
||||
#define S48_STOBTYPE_STRING 17
|
||||
#define S48_STRING_P(x) (s48_stob_has_type(x, 17))
|
||||
#define S48_STOBTYPE_BYTE_VECTOR 18
|
||||
#define S48_BYTE_VECTOR_P(x) (s48_stob_has_type(x, 18))
|
||||
#define S48_STOBTYPE_DOUBLE 19
|
||||
#define S48_DOUBLE_P(x) (s48_stob_has_type(x, 19))
|
||||
#define S48_STOBTYPE_BIGNUM 20
|
||||
#define S48_BIGNUM_P(x) (s48_stob_has_type(x, 20))
|
||||
|
||||
#define S48_CAR_OFFSET 0
|
||||
#define S48_CAR(x) (s48_stob_ref((x), S48_STOBTYPE_PAIR, 0))
|
||||
#define S48_UNSAFE_CAR(x) (S48_STOB_REF((x), 0))
|
||||
#define S48_SET_CAR(x, v) (s48_stob_ref((x), S48_STOBTYPE_PAIR, 0, (v)))
|
||||
#define S48_SET_CAR(x, v) (s48_stob_set((x), S48_STOBTYPE_PAIR, 0, (v)))
|
||||
#define S48_UNSAFE_SET_CAR(x, v) S48_STOB_SET((x), 0, (v))
|
||||
#define S48_CDR_OFFSET 1
|
||||
#define S48_CDR(x) (s48_stob_ref((x), S48_STOBTYPE_PAIR, 1))
|
||||
#define S48_UNSAFE_CDR(x) (S48_STOB_REF((x), 1))
|
||||
#define S48_SET_CDR(x, v) (s48_stob_ref((x), S48_STOBTYPE_PAIR, 1, (v)))
|
||||
#define S48_SET_CDR(x, v) (s48_stob_set((x), S48_STOBTYPE_PAIR, 1, (v)))
|
||||
#define S48_UNSAFE_SET_CDR(x, v) S48_STOB_SET((x), 1, (v))
|
||||
#define S48_SYMBOL_TO_STRING_OFFSET 0
|
||||
#define S48_SYMBOL_TO_STRING(x) (s48_stob_ref((x), S48_STOBTYPE_SYMBOL, 0))
|
||||
|
|
@ -305,13 +358,18 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
|
|||
#define S48_LOCATION_ID_OFFSET 0
|
||||
#define S48_LOCATION_ID(x) (s48_stob_ref((x), S48_STOBTYPE_LOCATION, 0))
|
||||
#define S48_UNSAFE_LOCATION_ID(x) (S48_STOB_REF((x), 0))
|
||||
#define S48_SET_LOCATION_ID(x, v) (s48_stob_ref((x), S48_STOBTYPE_LOCATION, 0, (v)))
|
||||
#define S48_SET_LOCATION_ID(x, v) (s48_stob_set((x), S48_STOBTYPE_LOCATION, 0, (v)))
|
||||
#define S48_UNSAFE_SET_LOCATION_ID(x, v) S48_STOB_SET((x), 0, (v))
|
||||
#define S48_CONTENTS_OFFSET 1
|
||||
#define S48_CONTENTS(x) (s48_stob_ref((x), S48_STOBTYPE_LOCATION, 1))
|
||||
#define S48_UNSAFE_CONTENTS(x) (S48_STOB_REF((x), 1))
|
||||
#define S48_SET_CONTENTS(x, v) (s48_stob_ref((x), S48_STOBTYPE_LOCATION, 1, (v)))
|
||||
#define S48_SET_CONTENTS(x, v) (s48_stob_set((x), S48_STOBTYPE_LOCATION, 1, (v)))
|
||||
#define S48_UNSAFE_SET_CONTENTS(x, v) S48_STOB_SET((x), 1, (v))
|
||||
#define S48_CELL_REF_OFFSET 0
|
||||
#define S48_CELL_REF(x) (s48_stob_ref((x), S48_STOBTYPE_CELL, 0))
|
||||
#define S48_UNSAFE_CELL_REF(x) (S48_STOB_REF((x), 0))
|
||||
#define S48_CELL_SET(x, v) (s48_stob_set((x), S48_STOBTYPE_CELL, 0, (v)))
|
||||
#define S48_UNSAFE_CELL_SET(x, v) S48_STOB_SET((x), 0, (v))
|
||||
#define S48_CLOSURE_TEMPLATE_OFFSET 0
|
||||
#define S48_CLOSURE_TEMPLATE(x) (s48_stob_ref((x), S48_STOBTYPE_CLOSURE, 0))
|
||||
#define S48_UNSAFE_CLOSURE_TEMPLATE(x) (S48_STOB_REF((x), 0))
|
||||
|
|
@ -330,50 +388,52 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
|
|||
#define S48_SHARED_BINDING_REF_OFFSET 2
|
||||
#define S48_SHARED_BINDING_REF(x) (s48_stob_ref((x), S48_STOBTYPE_SHARED_BINDING, 2))
|
||||
#define S48_UNSAFE_SHARED_BINDING_REF(x) (S48_STOB_REF((x), 2))
|
||||
#define S48_SHARED_BINDING_SET(x, v) (s48_stob_ref((x), S48_STOBTYPE_SHARED_BINDING, 2, (v)))
|
||||
#define S48_SHARED_BINDING_SET(x, v) (s48_stob_set((x), S48_STOBTYPE_SHARED_BINDING, 2, (v)))
|
||||
#define S48_UNSAFE_SHARED_BINDING_SET(x, v) S48_STOB_SET((x), 2, (v))
|
||||
#define S48_PORT_HANDLER_OFFSET 0
|
||||
#define S48_PORT_HANDLER(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 0))
|
||||
#define S48_UNSAFE_PORT_HANDLER(x) (S48_STOB_REF((x), 0))
|
||||
#define S48_SET_PORT_HANDLER(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 0, (v)))
|
||||
#define S48_UNSAFE_SET_PORT_HANDLER(x, v) S48_STOB_SET((x), 0, (v))
|
||||
#define S48_PORT_STATUS_OFFSET 1
|
||||
#define S48_PORT_STATUS(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 1))
|
||||
#define S48_UNSAFE_PORT_STATUS(x) (S48_STOB_REF((x), 1))
|
||||
#define S48_SET_PORT_STATUS(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 1, (v)))
|
||||
#define S48_SET_PORT_STATUS(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 1, (v)))
|
||||
#define S48_UNSAFE_SET_PORT_STATUS(x, v) S48_STOB_SET((x), 1, (v))
|
||||
#define S48_PORT_LOCK_OFFSET 2
|
||||
#define S48_PORT_LOCK(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 2))
|
||||
#define S48_UNSAFE_PORT_LOCK(x) (S48_STOB_REF((x), 2))
|
||||
#define S48_SET_PORT_LOCK(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 2, (v)))
|
||||
#define S48_SET_PORT_LOCK(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 2, (v)))
|
||||
#define S48_UNSAFE_SET_PORT_LOCK(x, v) S48_STOB_SET((x), 2, (v))
|
||||
#define S48_PORT_LOCKEDP_OFFSET 3
|
||||
#define S48_PORT_LOCKEDP(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 3))
|
||||
#define S48_UNSAFE_PORT_LOCKEDP(x) (S48_STOB_REF((x), 3))
|
||||
#define S48_SET_PORT_LOCKEDP(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 3, (v)))
|
||||
#define S48_SET_PORT_LOCKEDP(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 3, (v)))
|
||||
#define S48_UNSAFE_SET_PORT_LOCKEDP(x, v) S48_STOB_SET((x), 3, (v))
|
||||
#define S48_PORT_DATA_OFFSET 4
|
||||
#define S48_PORT_DATA(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 4))
|
||||
#define S48_UNSAFE_PORT_DATA(x) (S48_STOB_REF((x), 4))
|
||||
#define S48_SET_PORT_DATA(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 4, (v)))
|
||||
#define S48_SET_PORT_DATA(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 4, (v)))
|
||||
#define S48_UNSAFE_SET_PORT_DATA(x, v) S48_STOB_SET((x), 4, (v))
|
||||
#define S48_PORT_BUFFER_OFFSET 5
|
||||
#define S48_PORT_BUFFER(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 5))
|
||||
#define S48_UNSAFE_PORT_BUFFER(x) (S48_STOB_REF((x), 5))
|
||||
#define S48_SET_PORT_BUFFER(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 5, (v)))
|
||||
#define S48_SET_PORT_BUFFER(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 5, (v)))
|
||||
#define S48_UNSAFE_SET_PORT_BUFFER(x, v) S48_STOB_SET((x), 5, (v))
|
||||
#define S48_PORT_INDEX_OFFSET 6
|
||||
#define S48_PORT_INDEX(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 6))
|
||||
#define S48_UNSAFE_PORT_INDEX(x) (S48_STOB_REF((x), 6))
|
||||
#define S48_SET_PORT_INDEX(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 6, (v)))
|
||||
#define S48_SET_PORT_INDEX(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 6, (v)))
|
||||
#define S48_UNSAFE_SET_PORT_INDEX(x, v) S48_STOB_SET((x), 6, (v))
|
||||
#define S48_PORT_LIMIT_OFFSET 7
|
||||
#define S48_PORT_LIMIT(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 7))
|
||||
#define S48_UNSAFE_PORT_LIMIT(x) (S48_STOB_REF((x), 7))
|
||||
#define S48_SET_PORT_LIMIT(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 7, (v)))
|
||||
#define S48_SET_PORT_LIMIT(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 7, (v)))
|
||||
#define S48_UNSAFE_SET_PORT_LIMIT(x, v) S48_STOB_SET((x), 7, (v))
|
||||
#define S48_PORT_PENDING_EOFP_OFFSET 8
|
||||
#define S48_PORT_PENDING_EOFP(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 8))
|
||||
#define S48_UNSAFE_PORT_PENDING_EOFP(x) (S48_STOB_REF((x), 8))
|
||||
#define S48_SET_PORT_PENDING_EOFP(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 8, (v)))
|
||||
#define S48_SET_PORT_PENDING_EOFP(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 8, (v)))
|
||||
#define S48_UNSAFE_SET_PORT_PENDING_EOFP(x, v) S48_STOB_SET((x), 8, (v))
|
||||
#define S48_CHANNEL_STATUS_OFFSET 0
|
||||
#define S48_CHANNEL_STATUS(x) (s48_stob_ref((x), S48_STOBTYPE_CHANNEL, 0))
|
||||
|
|
@ -397,21 +457,22 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
|
|||
#define S48_RECORD_SET(x, i, v) (s48_stob_set((x), S48_STOBTYPE_RECORD, (i) + 1, (v)))
|
||||
#define S48_UNSAFE_RECORD_REF(x, i) (S48_STOB_REF((x), (i) + 1))
|
||||
#define S48_UNSAFE_RECORD_SET(x, i, v) S48_STOB_SET((x), (i) + 1, (v))
|
||||
#define S48_RECORD_TYPE(x) (s48_stob_ref((x), S48_STOBTYPE_RECORD))
|
||||
#define S48_RECORD_TYPE(x) (s48_stob_ref((x), S48_STOBTYPE_RECORD, 0))
|
||||
#define S48_UNSAFE_RECORD_TYPE(x) (STOB_REF((x), 0))
|
||||
#define S48_BYTE_VECTOR_LENGTH(x) (s48_stob_byte_length((x), S48_STOBTYPE_BYTE_VECTOR))
|
||||
#define S48_BYTE_VECTOR_REF(x, i) (s48_stob_byte_ref((x), S48_STOBTYPE_BYTE_VECTOR, (i)))
|
||||
#define S48_BYTE_VECTOR_SET(x, i, v) (s48_stob_byte_set((x), S48_STOBTYPE_BYTE_VECTOR, (i), (v)))
|
||||
#define S48_UNSAFE_BYTE_VECTOR_REF(x, i) (S48_STOB_BYTE_REF((x), (i)))
|
||||
#define S48_UNSAFE_BYTE_VECTOR_SET(x, i, v) S48_BYTE_STOB_SET((x), (i), (v))
|
||||
#define S48_UNSAFE_BYTE_VECTOR_SET(x, i, v) S48_STOB_BYTE_SET((x), (i), (v))
|
||||
#define S48_STRING_LENGTH(x) (s48_stob_byte_length((x), S48_STOBTYPE_STRING))
|
||||
#define S48_STRING_REF(x, i) (s48_stob_byte_ref((x), S48_STOBTYPE_STRING, (i)))
|
||||
#define S48_STRING_SET(x, i, v) (s48_stob_byte_set((x), S48_STOBTYPE_STRING, (i), (v)))
|
||||
#define S48_UNSAFE_STRING_REF(x, i) (S48_STOB_BYTE_REF((x), (i)))
|
||||
#define S48_UNSAFE_STRING_SET(x, i, v) S48_BYTE_STOB_SET((x), (i), (v))
|
||||
#define S48_UNSAFE_STRING_SET(x, i, v) S48_STOB_BYTE_SET((x), (i), (v))
|
||||
#define S48_UNSAFE_BYTE_VECTOR_LENGTH(x) (S48_STOB_BYTE_LENGTH(x))
|
||||
#define S48_UNSAFE_STRING_LENGTH(x) (S48_STOB_BYTE_LENGTH(x) - 1)
|
||||
#define S48_UNSAFE_EXTRACT_STRING(x) (S48_ADDRESS_AFTER_HEADER((x), char))
|
||||
#define S48_UNSAFE_EXTRACT_BYTE_VECTOR(x) (S48_ADDRESS_AFTER_HEADER((x), char))
|
||||
#define S48_EXTRACT_EXTERNAL_OBJECT(x, type) ((type *)(S48_ADDRESS_AFTER_HEADER(x, long)+1))
|
||||
|
||||
#define S48_RECORD_TYPE_RESUMER(x) S48_RECORD_REF((x), 0)
|
||||
|
|
|
|||
|
|
@ -7,9 +7,16 @@ typedef long s48_value;
|
|||
|
||||
#define NO_ERRORS 0 /* errno value */
|
||||
|
||||
extern int s48_main (long heap_size, long stack_size,
|
||||
char *image_name, int argc, char** argv);
|
||||
|
||||
extern int s48_add_external_init(void (*init)());
|
||||
|
||||
/* Misc stuff */
|
||||
|
||||
#define S48_EQ(v1, v2) ((v1) == (v2))
|
||||
#define S48_EQ_P(v1, v2) ((v1) == (v2))
|
||||
/* Superceded name for the above definition, retained for compatibility. */
|
||||
#define S48_EQ(v1, v2) ((v1) == (v2))
|
||||
|
||||
#define S48_MAX_FIXNUM_VALUE ((1 << 29) - 1)
|
||||
#define S48_MIN_FIXNUM_VALUE (-1 << 29)
|
||||
|
|
@ -33,15 +40,43 @@ extern s48_value s48_enter_fixnum(long);
|
|||
extern long s48_extract_fixnum(s48_value);
|
||||
extern s48_value s48_enter_integer(long);
|
||||
extern long s48_extract_integer(s48_value);
|
||||
extern s48_value s48_enter_unsigned_integer(unsigned long);
|
||||
extern unsigned long s48_extract_unsigned_integer(s48_value);
|
||||
extern s48_value s48_enter_double(double);
|
||||
extern double s48_extract_double(s48_value);
|
||||
extern s48_value s48_cons(s48_value, s48_value);
|
||||
extern s48_value s48_list_1(s48_value);
|
||||
extern s48_value s48_list_2(s48_value, s48_value);
|
||||
extern s48_value s48_list_3(s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_list_4(s48_value, s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_list_5(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value);
|
||||
extern s48_value s48_list_6(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value);
|
||||
extern s48_value s48_list_7(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_list_8(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_list_9(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value);
|
||||
extern s48_value s48_list_10(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value);
|
||||
extern s48_value s48_list_11(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_list_12(s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value,
|
||||
s48_value, s48_value, s48_value, s48_value);
|
||||
extern s48_value s48_enter_string(char *);
|
||||
extern char * s48_extract_string(s48_value);
|
||||
extern s48_value s48_enter_substring(char *, int);
|
||||
extern s48_value s48_make_string(int, char);
|
||||
extern s48_value s48_make_vector(int, s48_value);
|
||||
extern s48_value s48_make_byte_vector(int);
|
||||
extern s48_value s48_enter_byte_vector(char *, int);
|
||||
extern char * s48_extract_byte_vector(s48_value);
|
||||
extern s48_value s48_make_byte_vector(int, int);
|
||||
extern s48_value s48_make_record(s48_value);
|
||||
extern s48_value s48_make_weak_pointer(s48_value);
|
||||
extern void s48_check_record_type(s48_value, s48_value);
|
||||
|
|
@ -58,7 +93,7 @@ extern s48_value s48_call_scheme(s48_value proc, long nargs, ...);
|
|||
|
||||
#define S48_EXPORT_FUNCTION(p) (s48_define_exported_binding(#p, s48_enter_pointer(p)))
|
||||
|
||||
#define S48_MAKE_VALUE(type) (s48_make_byte_vector(sizeof(type)))
|
||||
#define S48_MAKE_VALUE(type) (s48_make_byte_vector(sizeof(type),0))
|
||||
extern void * s48_value_pointer(s48_value);
|
||||
|
||||
#define S48_EXTRACT_VALUE_POINTER(x, type) ((type *) s48_value_pointer(x))
|
||||
|
|
@ -171,28 +206,46 @@ extern void * s48_value_pointer(s48_value);
|
|||
/* Exceptions */
|
||||
|
||||
extern void s48_raise_scheme_exception(long type, long nargs, ...);
|
||||
extern void s48_raise_argtype_error(s48_value value);
|
||||
extern void s48_raise_argnumber_error(s48_value value,
|
||||
s48_value min, s48_value max);
|
||||
extern void s48_raise_argument_type_error(s48_value value);
|
||||
extern void s48_raise_argument_number_error(s48_value value,
|
||||
s48_value min,
|
||||
s48_value max);
|
||||
extern void s48_raise_range_error(s48_value value,
|
||||
s48_value min, s48_value max);
|
||||
extern void s48_raise_closed_channel_error();
|
||||
extern void s48_raise_os_error(int the_errno);
|
||||
extern void s48_raise_os_error_1(int the_errno, s48_value arg1);
|
||||
extern void s48_raise_os_error_2(int the_errno, s48_value arg1, s48_value arg2);
|
||||
extern void s48_raise_os_error_3(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3);
|
||||
extern void s48_raise_os_error_4(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3, s48_value arg4);
|
||||
extern void s48_raise_os_error_5(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3, s48_value arg4, s48_value arg5);
|
||||
extern void s48_raise_os_error_6(int the_errno, s48_value arg1, s48_value arg2,
|
||||
s48_value arg3, s48_value arg4, s48_value arg5,
|
||||
s48_value arg6);
|
||||
extern void s48_raise_string_os_error(char *reason);
|
||||
extern void s48_raise_out_of_memory_error();
|
||||
|
||||
/* Type checking */
|
||||
|
||||
#define S48_CHECK_PAIR(v) do { if (!S48_PAIR_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_FIXNUM(v) do { if (!S48_FIXNUM_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_STRING(v) do { if (!S48_STRING_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_CHANNEL(v) do { if (!S48_CHANNEL_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_RECORD(v) do { if (!S48_RECORD_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_VALUE(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_EXPORT_BINDING(v) do { if (!S48_EXPORT_BINDING_P(v)) s48_raise_argtype_error(v); } while (0)
|
||||
#define S48_CHECK_PAIR(v) do { if (!S48_PAIR_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_FIXNUM(v) do { if (!S48_FIXNUM_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_STRING(v) do { if (!S48_STRING_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_BYTE_VECTOR(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_CHANNEL(v) do { if (!S48_CHANNEL_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_RECORD(v) do { if (!S48_RECORD_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_VALUE(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
#define S48_CHECK_EXPORT_BINDING(v) do { if (!S48_EXPORT_BINDING_P(v)) s48_raise_argument_type_error(v); } while (0)
|
||||
|
||||
#define S48_VALUE_P(v) (S48_BYTE_VECTOR_P(v))
|
||||
|
||||
#define S48_TRUE_P(v) ((v) == S48_TRUE)
|
||||
#define S48_FALSE_P(v) ((v) == S48_FALSE)
|
||||
#define S48_EXTRACT_BOOLEAN(v) ((v) != S48_FALSE)
|
||||
#define S48_ENTER_BOOLEAN(v) ((v) ? S48_TRUE : S48_FALSE)
|
||||
|
||||
extern void s48_check_record_type(s48_value record, s48_value type_binding);
|
||||
|
||||
#define S48_SHARED_BINDING_CHECK(binding) \
|
||||
|
|
@ -200,3 +253,4 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
|
|||
s48_raise_scheme_exception(S48_EXCEPTION_UNBOUND_EXTERNAL_NAME, 1, \
|
||||
S48_SHARED_BINDING_NAME(binding)); \
|
||||
} while(0)
|
||||
|
||||
|
|
|
|||
1057
c/scheme48heap.c
1057
c/scheme48heap.c
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h> /* memcpy, strlen */
|
||||
|
||||
#include "c-mods.h"
|
||||
#include "write-barrier.h"
|
||||
|
|
|
|||
14374
c/scheme48vm.c
14374
c/scheme48vm.c
File diff suppressed because it is too large
Load Diff
|
|
@ -23,7 +23,7 @@ extern char s48_Spending_eventsPS;
|
|||
extern char s48_Spending_interruptPS;
|
||||
extern void s48_disable_interruptsB(void);
|
||||
extern void s48_enable_interruptsB(void);
|
||||
extern void s48_set_os_signal(s48_value type, s48_value argument);
|
||||
extern void s48_set_os_signals(s48_value list);
|
||||
|
||||
/* imported and exported bindings */
|
||||
extern void s48_define_exported_binding(char *, s48_value);
|
||||
|
|
@ -56,6 +56,6 @@ extern s48_value s48_add_channel(s48_value, s48_value, long);
|
|||
extern s48_value s48_allocate_stob(long type, long size);
|
||||
extern void s48_push_gc_rootsB(char *, long);
|
||||
extern char s48_pop_gc_rootsB(void);
|
||||
extern char * s48_set_gc_roots_baseB(void);
|
||||
extern char s48_release_gc_roots_baseB(char *);
|
||||
extern char * s48_set_gc_roots_baseB(char **);
|
||||
extern char s48_release_gc_roots_baseB(char *, char*);
|
||||
extern void s48_register_gc_rootB(char *marker);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,240 @@
|
|||
/* 54-BIT (double) IMPLEMENTATION IN C OF THE "MRG32K3A" GENERATOR
|
||||
===============================================================
|
||||
|
||||
Sebastian.Egner@philips.com, Mar-2002, in ANSI-C and Scheme 48 0.57
|
||||
|
||||
This code is a C-implementation of Pierre L'Ecuyer's MRG32k3a generator.
|
||||
The code uses (double)-arithmetics, assuming that it covers the range
|
||||
{-2^53..2^53-1} exactly (!). The code of the generator is based on the
|
||||
L'Ecuyer's own implementation of the generator. Please refer to the
|
||||
file 'mrg32k3a.scm' for more information about the method.
|
||||
|
||||
The method provides the following functions via the C/Scheme
|
||||
interface of Scheme 48 0.57 to 'mrg32k3a-b.scm':
|
||||
|
||||
s48_value mrg32k3a_pack_state1(s48_value state);
|
||||
s48_value mrg32k3a_unpack_state1(s48_value state);
|
||||
s48_value mrg32k3a_random_range();
|
||||
s48_value mrg32k3a_random_integer(s48_value state, s48_value range);
|
||||
s48_value mrg32k3a_random_real(s48_value state);
|
||||
|
||||
As Scheme48 FIXNUMs cannot cover the range {0..m1-1}, we break up
|
||||
all values x in the state into x0+x1*w, where w = 2^16 = 65536.
|
||||
The procedures in Scheme correct for that.
|
||||
|
||||
compile this file with:
|
||||
gcc -c -I $SCHEME48 mrg32k3a-b.c
|
||||
|
||||
history of this file:
|
||||
SE, 18-Mar-2002: initial version
|
||||
SE, 22-Mar-2002: interface changed
|
||||
SE, 25-Mar-2002: tested with Scheme 48 0.57 in c/srfi-27
|
||||
SE, 27-Mar-2002: cleaned
|
||||
SE, 13-May-2002: bug found by Shiro Kawai removed
|
||||
*/
|
||||
|
||||
#include "scheme48.h" /* $SCHEME48/c/scheme48.h */
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
/* maximum value for random_integer: min(S48_MAX_FIXNUM_VALUE, m1) */
|
||||
#define m_max (((long)1 << 29) - 1)
|
||||
|
||||
/* The Generator
|
||||
=============
|
||||
*/
|
||||
|
||||
/* moduli of the components */
|
||||
#define m1 4294967087.0
|
||||
#define m2 4294944443.0
|
||||
|
||||
/* representation of the state in C */
|
||||
typedef struct {
|
||||
double
|
||||
x10, x11, x12,
|
||||
x20, x21, x22;
|
||||
} state_t;
|
||||
|
||||
/* recursion coefficients of the components */
|
||||
#define a12 1403580.0
|
||||
#define a13n 810728.0
|
||||
#define a21 527612.0
|
||||
#define a23n 1370589.0
|
||||
|
||||
/* normalization factor 1/(m1 + 1) */
|
||||
#define norm 2.328306549295728e-10
|
||||
|
||||
|
||||
/* the actual generator */
|
||||
|
||||
static double mrg32k3a(state_t *s) { /* (double), in {0..m1-1} */
|
||||
double x10, x20, y;
|
||||
long k10, k20;
|
||||
|
||||
/* #define debug 1 */
|
||||
|
||||
#if defined(debug)
|
||||
printf(
|
||||
"state = {%g %g %g %g %g %g};\n",
|
||||
s->x10, s->x11, s->x12,
|
||||
s->x20, s->x21, s->x22
|
||||
);
|
||||
#endif
|
||||
|
||||
/* component 1 */
|
||||
x10 = a12*(s->x11) - a13n*(s->x12);
|
||||
k10 = x10 / m1;
|
||||
x10 -= k10 * m1;
|
||||
if (x10 < 0.0)
|
||||
x10 += m1;
|
||||
s->x12 = s->x11;
|
||||
s->x11 = s->x10;
|
||||
s->x10 = x10;
|
||||
|
||||
/* component 2 */
|
||||
x20 = a21*(s->x20) - a23n*(s->x22);
|
||||
k20 = x20 / m2;
|
||||
x20 -= k20 * m2;
|
||||
if (x20 < 0.0)
|
||||
x20 += m2;
|
||||
s->x22 = s->x21;
|
||||
s->x21 = s->x20;
|
||||
s->x20 = x20;
|
||||
|
||||
/* combination of component */
|
||||
y = x10 - x20;
|
||||
if (y < 0.0)
|
||||
y += m1;
|
||||
return y;
|
||||
}
|
||||
|
||||
/* Exported Interface
|
||||
==================
|
||||
*/
|
||||
|
||||
s48_value mrg32k3a_pack_state1(s48_value state) {
|
||||
s48_value result;
|
||||
state_t s;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
|
||||
S48_GC_PROTECT_1(state); /* s48_extract_integer may GC */
|
||||
|
||||
#define REF(i) (double)s48_extract_integer(S48_VECTOR_REF(state, (long)(i)))
|
||||
|
||||
/* copy the numbers from state into s */
|
||||
s.x10 = REF( 0) + 65536.0 * REF( 1);
|
||||
s.x11 = REF( 2) + 65536.0 * REF( 3);
|
||||
s.x12 = REF( 4) + 65536.0 * REF( 5);
|
||||
s.x20 = REF( 6) + 65536.0 * REF( 7);
|
||||
s.x21 = REF( 8) + 65536.0 * REF( 9);
|
||||
s.x22 = REF(10) + 65536.0 * REF(11);
|
||||
|
||||
#undef REF
|
||||
|
||||
S48_GC_UNPROTECT();
|
||||
|
||||
/* box s into a Scheme object */
|
||||
result = S48_MAKE_VALUE(state_t);
|
||||
S48_SET_VALUE(result, state_t, s);
|
||||
return result;
|
||||
}
|
||||
|
||||
s48_value mrg32k3a_unpack_state1(s48_value state) {
|
||||
s48_value result = S48_UNSPECIFIC;
|
||||
state_t s;
|
||||
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
S48_GC_PROTECT_1(result);
|
||||
|
||||
/* unbox s from the Scheme object */
|
||||
s = S48_EXTRACT_VALUE(state, state_t);
|
||||
|
||||
/* make and fill a Scheme vector with the numbers */
|
||||
result = s48_make_vector((long)12, S48_FALSE);
|
||||
|
||||
#define SET(i, x) { \
|
||||
long x1 = (long)((x) / 65536.0); \
|
||||
long x0 = (long)((x) - 65536.0 * (double)x1); \
|
||||
S48_VECTOR_SET(result, (long)(i+0), s48_enter_integer(x0)); \
|
||||
S48_VECTOR_SET(result, (long)(i+1), s48_enter_integer(x1)); }
|
||||
|
||||
SET( 0, s.x10);
|
||||
SET( 2, s.x11);
|
||||
SET( 4, s.x12);
|
||||
SET( 6, s.x20);
|
||||
SET( 8, s.x21);
|
||||
SET(10, s.x22);
|
||||
|
||||
#undef SET
|
||||
|
||||
S48_GC_UNPROTECT();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s48_value mrg32k3a_random_range(void) {
|
||||
return s48_enter_fixnum(m_max);
|
||||
}
|
||||
|
||||
s48_value mrg32k3a_random_integer(s48_value state, s48_value range) {
|
||||
long result;
|
||||
state_t s;
|
||||
long n;
|
||||
double x, q, qn, xq;
|
||||
|
||||
s = S48_EXTRACT_VALUE(state, state_t);
|
||||
n = s48_extract_integer(range);
|
||||
if (!( ((long)1 <= n) && (n <= m_max) ))
|
||||
s48_raise_range_error(n, (long)1, m_max);
|
||||
|
||||
/* generate result in {0..n-1} using the rejection method */
|
||||
q = (double)( (unsigned long)(m1 / (double)n) );
|
||||
qn = q * n;
|
||||
do {
|
||||
x = mrg32k3a(&s);
|
||||
} while (x >= qn);
|
||||
xq = x / q;
|
||||
|
||||
/* check the range */
|
||||
if (!( (0.0 <= xq) && (xq < (double)m_max) ))
|
||||
s48_raise_range_error((long)xq, (long)0, m_max);
|
||||
|
||||
/* return result */
|
||||
result = (long)xq;
|
||||
S48_SET_VALUE(state, state_t, s);
|
||||
return s48_enter_fixnum(result);
|
||||
}
|
||||
|
||||
s48_value mrg32k3a_random_real(s48_value state) {
|
||||
state_t s;
|
||||
double x;
|
||||
|
||||
s = S48_EXTRACT_VALUE(state, state_t);
|
||||
x = (mrg32k3a(&s) + 1.0) * norm;
|
||||
S48_SET_VALUE(state, state_t, s);
|
||||
return s48_enter_double(x);
|
||||
}
|
||||
|
||||
/* Kludge for scsh */
|
||||
static s48_value current_time(void){
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return s48_enter_integer(tv.tv_sec);
|
||||
}
|
||||
|
||||
|
||||
/* Exporting the C values to Scheme
|
||||
================================
|
||||
*/
|
||||
|
||||
void s48_init_srfi_27(void) {
|
||||
S48_EXPORT_FUNCTION(mrg32k3a_pack_state1);
|
||||
S48_EXPORT_FUNCTION(mrg32k3a_unpack_state1);
|
||||
S48_EXPORT_FUNCTION(mrg32k3a_random_range);
|
||||
S48_EXPORT_FUNCTION(mrg32k3a_random_integer);
|
||||
S48_EXPORT_FUNCTION(mrg32k3a_random_real);
|
||||
S48_EXPORT_FUNCTION(current_time);
|
||||
}
|
||||
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
/* c/sysdep.h.in. Generated automatically from configure.in by autoheader. */
|
||||
|
||||
/* Define to empty if the keyword does not work. */
|
||||
#undef const
|
||||
|
||||
/* Define if you need to in order for stat and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
||||
|
||||
/* Define as the return type of signal handlers (int or void). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/*
|
||||
* HAVE_SIGACTION is defined iff sigaction() is available.
|
||||
*/
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/*
|
||||
* HAVE_STRERROR is defined iff the standard libraries provide strerror().
|
||||
*/
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/*
|
||||
* NLIST_HAS_N_NAME is defined iff a struct nlist has an n_name member.
|
||||
* If it doesn't then we assume it has an n_un member which, in turn,
|
||||
* has an n_name member.
|
||||
*/
|
||||
#undef NLIST_HAS_N_NAME
|
||||
|
||||
/*
|
||||
* USCORE is defined iff C externals are prepended with an underscore.
|
||||
*/
|
||||
#undef USCORE
|
||||
|
||||
/* Define if you have the chroot function. */
|
||||
#undef HAVE_CHROOT
|
||||
|
||||
/* Define if you have the dlopen function. */
|
||||
#undef HAVE_DLOPEN
|
||||
|
||||
/* Define if you have the ftime function. */
|
||||
#undef HAVE_FTIME
|
||||
|
||||
/* Define if you have the gettimeofday function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define if you have the nlist function. */
|
||||
#undef HAVE_NLIST
|
||||
|
||||
/* Define if you have the select function. */
|
||||
#undef HAVE_SELECT
|
||||
|
||||
/* Define if you have the setitimer function. */
|
||||
#undef HAVE_SETITIMER
|
||||
|
||||
/* Define if you have the sigaction function. */
|
||||
#undef HAVE_SIGACTION
|
||||
|
||||
/* Define if you have the socket function. */
|
||||
#undef HAVE_SOCKET
|
||||
|
||||
/* Define if you have the <libgen.h> header file. */
|
||||
#undef HAVE_LIBGEN_H
|
||||
|
||||
/* Define if you have the <posix/time.h> header file. */
|
||||
#undef HAVE_POSIX_TIME_H
|
||||
|
||||
/* Define if you have the <sys/select.h> header file. */
|
||||
#undef HAVE_SYS_SELECT_H
|
||||
|
||||
/* Define if you have the <sys/timeb.h> header file. */
|
||||
#undef HAVE_SYS_TIMEB_H
|
||||
|
||||
/* Define if you have the dl library (-ldl). */
|
||||
#undef HAVE_LIBDL
|
||||
|
||||
/* Define if you have the elf library (-lelf). */
|
||||
#undef HAVE_LIBELF
|
||||
|
||||
/* Define if you have the gen library (-lgen). */
|
||||
#undef HAVE_LIBGEN
|
||||
|
||||
/* Define if you have the m library (-lm). */
|
||||
#undef HAVE_LIBM
|
||||
|
||||
/* Define if you have the mld library (-lmld). */
|
||||
#undef HAVE_LIBMLD
|
||||
|
||||
/* Define if you have the nsl library (-lnsl). */
|
||||
#undef HAVE_LIBNSL
|
||||
|
||||
/* Define if you have the socket library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Define if you have the sun library (-lsun). */
|
||||
#undef HAVE_LIBSUN
|
||||
|
||||
#include "fake/sigact.h"
|
||||
#include "fake/strerror.h"
|
||||
#include "fake/sys-select.h"
|
||||
|
|
@ -7,8 +7,12 @@
|
|||
#include <unistd.h>
|
||||
#include "sysdep.h"
|
||||
#include "scheme48.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
#if defined(HAVE_DLOPEN)
|
||||
#include <dlfcn.h>
|
||||
#else
|
||||
#include "../fake/dlfcn.h"
|
||||
#endif
|
||||
|
||||
#if defined(RTLD_NOW)
|
||||
#define DLOPEN_MODE RTLD_NOW
|
||||
|
|
|
|||
220
c/unix/event.c
220
c/unix/event.c
|
|
@ -1,6 +1,7 @@
|
|||
/* Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees.
|
||||
See file COPYING. */
|
||||
|
||||
#include "sysdep.h"
|
||||
#include <signal.h> /* for sigaction() (POSIX.1) */
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -9,20 +10,34 @@
|
|||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <errno.h> /* for errno, (POSIX?/ANSI) */
|
||||
#include "sysdep.h"
|
||||
#include "c-mods.h"
|
||||
#include "scheme48vm.h"
|
||||
#include "event.h"
|
||||
#include "../scsh/scsh_aux.h"
|
||||
#include "../scsh/signals1.h"
|
||||
|
||||
/* turning interrupts and I/O readiness into events */
|
||||
sigset_t full_sigset;
|
||||
|
||||
#define block_interrupts()
|
||||
#define allow_interrupts()
|
||||
#define block_interrupts(){sigprocmask (SIG_BLOCK, &full_sigset, 0);}
|
||||
#define allow_interrupts(){sigprocmask (SIG_UNBLOCK, &full_sigset, 0);}
|
||||
|
||||
|
||||
static void when_keyboard_interrupt();
|
||||
static void when_alarm_interrupt();
|
||||
static void when_sigpipe_interrupt();
|
||||
|
||||
/* JMG:*/
|
||||
static void when_scsh_interrupt();
|
||||
/* JMG: for scsh */
|
||||
#define INTERRUPT_QUEUE_LENGTH 32
|
||||
|
||||
static int interrupt_queue [INTERRUPT_QUEUE_LENGTH];
|
||||
static int next_interrupt = 0;
|
||||
static int s48_os_signal_pending(void);
|
||||
static bool s48_os_signal_happend(void);
|
||||
|
||||
|
||||
bool s48_setcatcher(int signum, void (*catcher)(int));
|
||||
void s48_start_alarm_interrupts(void);
|
||||
|
||||
|
|
@ -38,6 +53,47 @@ s48_sysdep_init(void)
|
|||
errno);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sigfillset (&full_sigset);
|
||||
|
||||
/* JMG: for scsh */
|
||||
s48_setcatcher(SIGCHLD, when_scsh_interrupt);
|
||||
s48_setcatcher(SIGCONT, when_scsh_interrupt);
|
||||
s48_setcatcher(SIGHUP, when_scsh_interrupt);
|
||||
s48_setcatcher(SIGQUIT, when_scsh_interrupt);
|
||||
s48_setcatcher(SIGTERM, when_scsh_interrupt);
|
||||
s48_setcatcher(SIGTSTP, when_scsh_interrupt);
|
||||
s48_setcatcher(SIGUSR1, when_scsh_interrupt);
|
||||
s48_setcatcher(SIGUSR2, when_scsh_interrupt);
|
||||
#ifdef SIGINFO
|
||||
s48_setcatcher(SIGINFO, when_scsh_interrupt);
|
||||
#endif
|
||||
#ifdef SIGIO
|
||||
s48_setcatcher(SIGIO, when_scsh_interrupt);
|
||||
#endif
|
||||
#if defined SIGPOLL && ((defined SIGIO && SIGPOLL != SIGIO) || \
|
||||
!defined SIGIO)
|
||||
s48_setcatcher(SIGPOLL, when_scsh_interrupt);
|
||||
#endif
|
||||
#ifdef SIGPROF
|
||||
s48_setcatcher(SIGPROF, when_scsh_interrupt);
|
||||
#endif
|
||||
#ifdef SIGPWR
|
||||
s48_setcatcher(SIGPWR, when_scsh_interrupt);
|
||||
#endif
|
||||
#ifdef SIGVTALRM
|
||||
s48_setcatcher(SIGVTALRM, when_scsh_interrupt);
|
||||
#endif
|
||||
#ifdef SIGWINCH
|
||||
s48_setcatcher(SIGWINCH, when_scsh_interrupt);
|
||||
#endif
|
||||
#ifdef SIGXCPU
|
||||
s48_setcatcher(SIGXCPU, when_scsh_interrupt);
|
||||
#endif
|
||||
#ifdef SIGXFSZ
|
||||
s48_setcatcher(SIGXFSZ, when_scsh_interrupt);
|
||||
#endif
|
||||
|
||||
s48_start_alarm_interrupts();
|
||||
}
|
||||
|
||||
|
|
@ -51,15 +107,21 @@ s48_setcatcher(int signum, void (*catcher)(int))
|
|||
{
|
||||
struct sigaction sa;
|
||||
|
||||
if (sigaction(signum, (struct sigaction *)NULL, &sa) != 0)
|
||||
return (FALSE);
|
||||
if (sa.sa_handler == SIG_IGN)
|
||||
return (TRUE);
|
||||
if (sigaction(signum, (struct sigaction *)NULL, &sa) != 0){
|
||||
fprintf(stderr, "Failed to get sigaction for signal %d\n", signum);
|
||||
exit(1);
|
||||
}
|
||||
/* JMG: what's the point of not setting the handler in this case?
|
||||
if (sa.sa_handler == SIG_IGN)
|
||||
return (TRUE);*/
|
||||
sa.sa_handler = catcher;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
if (sigaction(signum, &sa, (struct sigaction *)NULL) != 0)
|
||||
return (FALSE);
|
||||
if (sigaction(signum, &sa, (struct sigaction *)NULL) != 0){
|
||||
fprintf(stderr, "Failed to define handler for signal %d\n", signum);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +168,8 @@ when_alarm_interrupt(int ign)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define USEC_PER_POLL (1000000 / POLLS_PER_SECOND)
|
||||
|
||||
/* delta is in ticks, 0 cancels current alarm */
|
||||
|
|
@ -222,7 +286,7 @@ s48_stop_alarm_interrupts(void)
|
|||
* (queue-ready-ports)
|
||||
* (set! *poll-time* (+ *time* *poll-interval*))))
|
||||
* (cond ((not (queue-empty? ready-ports))
|
||||
* (values (enum event-type i/o-completion)
|
||||
* (values (enum event-type i/o-{read/write}-completion)
|
||||
* (dequeue! ready-ports)))
|
||||
* ((>= *current_time* *alarm-time*)
|
||||
* (set! *alarm-time* max-integer)
|
||||
|
|
@ -237,9 +301,20 @@ s48_stop_alarm_interrupts(void)
|
|||
* (values (enum event-type no-event) #f))))))
|
||||
*/
|
||||
|
||||
static bool there_are_ready_ports(void);
|
||||
static int next_ready_port(void);
|
||||
static int queue_ready_ports(bool wait, long seconds, long ticks);
|
||||
#define FD_QUIESCENT 0 /* idle */
|
||||
#define FD_READY 1 /* I/O ready to be performed */
|
||||
#define FD_PENDING 2 /* waiting */
|
||||
|
||||
typedef struct fd_struct {
|
||||
int fd, /* file descriptor */
|
||||
status; /* one of the FD_* constants */
|
||||
bool is_input; /* iff input */
|
||||
struct fd_struct *next; /* next on same queue */
|
||||
} fd_struct;
|
||||
|
||||
static bool there_are_ready_ports(void);
|
||||
static fd_struct *next_ready_fd_struct(void);
|
||||
static int queue_ready_ports(bool wait, long seconds, long ticks);
|
||||
|
||||
int
|
||||
s48_get_next_event(long *ready_fd, long *status)
|
||||
|
|
@ -249,6 +324,8 @@ s48_get_next_event(long *ready_fd, long *status)
|
|||
*/
|
||||
|
||||
int io_poll_status;
|
||||
fd_struct *f;
|
||||
|
||||
/*
|
||||
fprintf(stderr, "[poll at %d (waiting for %d)]\n", s48_current_time, alarm_time);
|
||||
*/
|
||||
|
|
@ -269,21 +346,25 @@ s48_get_next_event(long *ready_fd, long *status)
|
|||
}
|
||||
}
|
||||
if (there_are_ready_ports()) {
|
||||
*ready_fd = next_ready_port();
|
||||
f = next_ready_fd_struct();
|
||||
*ready_fd = f->fd;
|
||||
*status = 0; /* chars read or written */
|
||||
/* fprintf(stderr, "[i/o completion]\n"); */
|
||||
return (IO_COMPLETION_EVENT);
|
||||
if (f->is_input)
|
||||
return (IO_READ_COMPLETION_EVENT);
|
||||
else
|
||||
return (IO_WRITE_COMPLETION_EVENT);
|
||||
}
|
||||
if (alarm_time != -1 && s48_current_time >= alarm_time) {
|
||||
alarm_time = -1;
|
||||
/* fprintf(stderr, "[alarm]\n"); */
|
||||
return (ALARM_EVENT);
|
||||
}
|
||||
/*
|
||||
block_interrupts();
|
||||
/* JMG: scsh should handle this */
|
||||
if (s48_os_signal_pending())
|
||||
return (OS_SIGNAL_EVENT);
|
||||
*/
|
||||
block_interrupts();
|
||||
|
||||
if ((keyboard_interrupt_count == 0)
|
||||
&& (alarm_time == -1 || s48_current_time < alarm_time)
|
||||
&& (poll_time == -1 || s48_current_time < poll_time))
|
||||
|
|
@ -299,17 +380,6 @@ s48_get_next_event(long *ready_fd, long *status)
|
|||
* the pending ports and move any that are ready onto the other queue and
|
||||
* signal an event.
|
||||
*/
|
||||
#define FD_QUIESCENT 0 /* idle */
|
||||
#define FD_READY 1 /* I/O ready to be performed */
|
||||
#define FD_PENDING 2 /* waiting */
|
||||
|
||||
typedef struct fd_struct {
|
||||
int fd, /* file descriptor */
|
||||
status; /* one of the FD_* constants */
|
||||
bool is_input; /* iff input */
|
||||
struct fd_struct *next; /* next on same queue */
|
||||
} fd_struct;
|
||||
|
||||
|
||||
/*
|
||||
* A queue of fd_structs is empty iff the first field is NULL. In
|
||||
|
|
@ -394,14 +464,14 @@ there_are_ready_ports(void)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
next_ready_port(void)
|
||||
static fd_struct *
|
||||
next_ready_fd_struct(void)
|
||||
{
|
||||
fd_struct *p;
|
||||
|
||||
p = rmque(&ready.first, &ready);
|
||||
p->status = FD_QUIESCENT;
|
||||
return (p->fd);
|
||||
return (p);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -508,6 +578,8 @@ s48_wait_for_event(long max_wait, bool is_minutes)
|
|||
}
|
||||
if (keyboard_interrupt_count > 0)
|
||||
status = NO_ERRORS;
|
||||
else if (s48_os_signal_happend ())
|
||||
status = NO_ERRORS;
|
||||
else {
|
||||
status = queue_ready_ports(TRUE, seconds, ticks);
|
||||
if (there_are_ready_ports())
|
||||
|
|
@ -552,8 +624,9 @@ queue_ready_ports(bool wait, long seconds, long ticks)
|
|||
}
|
||||
tvp = &tv;
|
||||
if (wait)
|
||||
if (seconds == -1)
|
||||
if (seconds == -1){
|
||||
tvp = NULL;
|
||||
}
|
||||
else {
|
||||
tv.tv_sec = seconds;
|
||||
tv.tv_usec = ticks * (1000000 / TICKS_PER_SECOND);
|
||||
|
|
@ -561,6 +634,9 @@ queue_ready_ports(bool wait, long seconds, long ticks)
|
|||
else
|
||||
timerclear(&tv);
|
||||
while(TRUE) {
|
||||
if ((keyboard_interrupt_count > 0) || s48_os_signal_happend ())
|
||||
return NO_ERRORS;
|
||||
/* time gap */
|
||||
left = select(limfd, &reads, &writes, &alls, tvp);
|
||||
if (left > 0) {
|
||||
fdpp = &pending.first;
|
||||
|
|
@ -587,3 +663,81 @@ queue_ready_ports(bool wait, long seconds, long ticks)
|
|||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds `signum' to the queue of received signals.
|
||||
*/
|
||||
|
||||
static void
|
||||
queue_interrupt(int signum)
|
||||
{
|
||||
if (next_interrupt == INTERRUPT_QUEUE_LENGTH){
|
||||
perror("Interrupt queue overflow -- report to Scheme 48 maintainers.");
|
||||
exit(-1);
|
||||
}
|
||||
interrupt_queue[next_interrupt] = signum;
|
||||
next_interrupt++;
|
||||
}
|
||||
|
||||
/* JMG: for scsh */
|
||||
static void when_scsh_interrupt(int signo)
|
||||
{
|
||||
queue_interrupt(sig2int[signo]);
|
||||
NOTE_EVENT;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This procedure is called periodically by the VM .
|
||||
*
|
||||
* s48_set_os_signal() is a VM procedure. The two arguments are the type
|
||||
* of interrupt and one other value which can be used to return whatever
|
||||
* associated information is desired. The two values, along with the
|
||||
* current enabled-interrupts mask, are passed to the handler for os-signal
|
||||
* interrupts.
|
||||
*
|
||||
* A handler can be installed by doing
|
||||
(set-interrupt-handler! (enum interrupt os-signal)
|
||||
(lambda (type arg enabled-interrupts)
|
||||
(display type)
|
||||
(newline)
|
||||
(display arg)
|
||||
(newline)
|
||||
(display enabled-interrupts)
|
||||
(newline)))
|
||||
* The handler is called with all interrupts disabled. They are
|
||||
* reenabled when the handler returns (or if done by hand).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Returns TRUE if there is a signal to be delivered up to Scheme.
|
||||
* Needs no be called with interrupts blocked.
|
||||
*/
|
||||
|
||||
int
|
||||
s48_os_signal_pending(void) {
|
||||
int i;
|
||||
s48_value interrupt_list = S48_NULL;
|
||||
block_interrupts();
|
||||
|
||||
if (next_interrupt == 0) {
|
||||
allow_interrupts();
|
||||
return FALSE; }
|
||||
else {
|
||||
/* turn the queue into a scheme list and preserve the order */
|
||||
for (i = next_interrupt; i > 0 ; i--)
|
||||
interrupt_list = s48_cons (s48_enter_fixnum (interrupt_queue [i - 1]),
|
||||
interrupt_list);
|
||||
s48_set_os_signals(interrupt_list);
|
||||
|
||||
next_interrupt = 0;
|
||||
allow_interrupts();
|
||||
return TRUE; }
|
||||
}
|
||||
|
||||
bool
|
||||
s48_os_signal_happend(void) {
|
||||
return (next_interrupt != 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees.
|
||||
See file COPYING. */
|
||||
|
||||
#include "sysdep.h"
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
|
@ -8,7 +9,6 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h> /* for errno, (POSIX?/ANSI) */
|
||||
#include "sysdep.h"
|
||||
#include "c-mods.h"
|
||||
#include "scheme48vm.h"
|
||||
#include "event.h"
|
||||
|
|
@ -82,6 +82,45 @@ ps_close_fd(long fd_as_long)
|
|||
}
|
||||
}
|
||||
|
||||
bool ps_check_fd(long fd_as_long, bool is_read, long *status)
|
||||
{
|
||||
int fd = (int)fd_as_long;
|
||||
int ready;
|
||||
|
||||
struct timeval timeout;
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
timerclear(&timeout);
|
||||
|
||||
*status = NO_ERRORS;
|
||||
|
||||
while(TRUE) {
|
||||
ready = select(fd + 1,
|
||||
is_read ? &fds : NULL,
|
||||
is_read ? NULL : &fds,
|
||||
&fds,
|
||||
&timeout);
|
||||
if (ready == 0)
|
||||
return FALSE;
|
||||
else if (ready == 1)
|
||||
return TRUE;
|
||||
else if (errno != EINTR) {
|
||||
*status = errno;
|
||||
return FALSE; } }
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if successful, and FALSE otherwise.
|
||||
*/
|
||||
|
||||
bool
|
||||
ps_add_pending_fd(long fd_as_long, bool is_input)
|
||||
{
|
||||
return s48_add_pending_fd((int) fd_as_long, is_input);
|
||||
}
|
||||
|
||||
long
|
||||
ps_read_fd(long fd_as_long, char *buffer, long max, bool waitp,
|
||||
bool *eofp, bool *pending, long *status)
|
||||
|
|
@ -172,7 +211,7 @@ long
|
|||
ps_abort_fd_op(long fd_as_long)
|
||||
{
|
||||
int fd = (int)fd_as_long;
|
||||
|
||||
fprintf(stderr, "aborting %d\n", fd);
|
||||
if (!s48_remove_fd(fd))
|
||||
fprintf(stderr, "Error: ps_abort_fd_op, no pending operation on fd %d\n",
|
||||
fd);
|
||||
|
|
|
|||
38
c/unix/io.c
38
c/unix/io.c
|
|
@ -146,26 +146,6 @@ ps_write_char(char ch, FILE *port)
|
|||
return 0; }
|
||||
}
|
||||
|
||||
long
|
||||
ps_write_integer(long n, FILE *port)
|
||||
{
|
||||
int status;
|
||||
|
||||
static long write_integer(unsigned long n, FILE *port);
|
||||
|
||||
if (n == 0) {
|
||||
WRITE_CHAR('0', port, status);
|
||||
return status; }
|
||||
else if (n > 0)
|
||||
return write_integer(n, port);
|
||||
else {
|
||||
WRITE_CHAR('-', port, status);
|
||||
if (status == 0)
|
||||
return write_integer(- n, port);
|
||||
else
|
||||
return status; }
|
||||
}
|
||||
|
||||
static long
|
||||
write_integer(unsigned long n, FILE *port)
|
||||
{
|
||||
|
|
@ -182,6 +162,24 @@ write_integer(unsigned long n, FILE *port)
|
|||
return status;
|
||||
}
|
||||
|
||||
long
|
||||
ps_write_integer(long n, FILE *port)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (n == 0) {
|
||||
WRITE_CHAR('0', port, status);
|
||||
return status; }
|
||||
else if (n > 0)
|
||||
return write_integer(n, port);
|
||||
else {
|
||||
WRITE_CHAR('-', port, status);
|
||||
if (status == 0)
|
||||
return write_integer(- n, port);
|
||||
else
|
||||
return status; }
|
||||
}
|
||||
|
||||
long
|
||||
ps_write_string(char *string, FILE *port)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,9 +36,23 @@ static s48_value s48_socket(s48_value server_p),
|
|||
s48_value input_p),
|
||||
s48_get_host_name(void);
|
||||
|
||||
s48_value s48_add_pending_channel (s48_value channel)
|
||||
{
|
||||
int socket_fd;
|
||||
|
||||
S48_CHECK_CHANNEL(channel);
|
||||
socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
|
||||
|
||||
if (! s48_add_pending_fd(socket_fd, 1)) /* 1 for: yes, is input */
|
||||
s48_raise_out_of_memory_error();
|
||||
|
||||
return S48_UNSPECIFIC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Install all exported functions in Scheme48.
|
||||
*/
|
||||
|
||||
void
|
||||
s48_init_socket(void)
|
||||
{
|
||||
|
|
@ -50,6 +64,7 @@ s48_init_socket(void)
|
|||
S48_EXPORT_FUNCTION(s48_connect);
|
||||
S48_EXPORT_FUNCTION(s48_close_socket_half);
|
||||
S48_EXPORT_FUNCTION(s48_get_host_name);
|
||||
S48_EXPORT_FUNCTION(s48_add_pending_channel);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -235,7 +250,7 @@ s48_accept(s48_value channel)
|
|||
* and return #F to tell the Scheme procedure to wait.
|
||||
*/
|
||||
|
||||
if ((errno != EWOULDBLOCK) && (errno != EINTR) && (errno == EAGAIN))
|
||||
if ((errno != EWOULDBLOCK) && (errno != EINTR) && (errno != EAGAIN))
|
||||
s48_raise_os_error(errno);
|
||||
|
||||
if (! s48_add_pending_fd(socket_fd, TRUE))
|
||||
|
|
@ -366,11 +381,38 @@ s48_close_socket_half(s48_value channel, s48_value input_p)
|
|||
static s48_value
|
||||
s48_get_host_name(void)
|
||||
{
|
||||
char mbuff[MAXHOSTNAMELEN];
|
||||
char *mbuff = NULL;
|
||||
size_t mbuff_len = 0;
|
||||
int status = 0;
|
||||
s48_value name;
|
||||
|
||||
if (gethostname(mbuff, sizeof(mbuff)) < 0)
|
||||
do {
|
||||
char *tmp;
|
||||
|
||||
mbuff_len += 256; /* Initial guess */
|
||||
tmp = (char *) realloc(mbuff, mbuff_len);
|
||||
|
||||
if (tmp == NULL) {
|
||||
free(mbuff);
|
||||
s48_raise_os_error(ENOMEM);
|
||||
}
|
||||
else
|
||||
mbuff = tmp;
|
||||
} while (((status = gethostname(mbuff, mbuff_len)) == 0
|
||||
&& !memchr(mbuff, '\0', mbuff_len))
|
||||
#ifdef ENAMETOOLONG
|
||||
|| errno == ENAMETOOLONG
|
||||
#endif
|
||||
);
|
||||
|
||||
if (status != 0 && errno != 0) {
|
||||
/* gethostname failed, abort. */
|
||||
free(mbuff);
|
||||
s48_raise_os_error(errno);
|
||||
|
||||
return s48_enter_string(mbuff);
|
||||
}
|
||||
|
||||
name = s48_enter_string(mbuff);
|
||||
free(mbuff);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
cig
|
||||
cig.image
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/sh -
|
||||
|
||||
binary=$1
|
||||
shift
|
||||
|
||||
if [ `echo $binary | wc -c` -gt 28 ] ; then
|
||||
echo "#!/bin/sh -"
|
||||
echo exec $binary $* -i '"$0"' '"$@"'
|
||||
|
||||
elif [ $# -gt 0 ] ; then
|
||||
echo '#!'$binary \\
|
||||
echo $* -i
|
||||
|
||||
else echo '#!'$binary -i
|
||||
fi
|
||||
|
||||
exec cat
|
||||
|
||||
|
||||
# This program reads an S48 image from stdin and turns it into
|
||||
# an executable by prepending a #! prefix. The vm and its
|
||||
# args are passed to this program on the command line.
|
||||
#
|
||||
# If the vm binary is 27 chars or less, then we can directly
|
||||
# execute the vm with one of these scripts:
|
||||
# No args:
|
||||
# image2script /usr/local/bin/svm <image
|
||||
# outputs this script:
|
||||
# #!/usr/local/bin/svm -i
|
||||
# ...image bits follow...
|
||||
#
|
||||
# Args:
|
||||
# image2script /usr/bin/svm -h 4000000 -o /usr/bin/svm <image
|
||||
# outputs this script:
|
||||
# #!/usr/bin/svm \
|
||||
# -h 4000000 -o /usr/bin/svm -i
|
||||
# ...image bits follow...
|
||||
#
|
||||
# The exec system call won't handle the #! line if it contains more than
|
||||
# 32 chars, so if the vm binary is over 28 chars, we have to use a /bin/sh
|
||||
# trampoline.
|
||||
# image2script /user1/lecturer/shivers/vc/scsh/s48/lib/svm -h 4000000 < ...
|
||||
# outputs this script:
|
||||
# #!/bin/sh -
|
||||
# exec /user1/lecturer/shivers/vc/scsh/s48/lib/svm -h 4000000 -i $0 $*
|
||||
# ...image bits follow...
|
||||
#
|
||||
# -Olin
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/* This is an Scheme48/C interface file,
|
||||
** automatically generated by a hacked version of cig 3.0.
|
||||
step 4
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* For malloc. */
|
||||
#include "libcig.h"
|
||||
|
||||
s48_value df_strlen_or_false(s48_value g1)
|
||||
{
|
||||
extern s48_value strlen_or_false(const char * );
|
||||
s48_value ret1 = S48_FALSE;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
s48_value r1;
|
||||
|
||||
|
||||
|
||||
S48_GC_PROTECT_1(ret1);
|
||||
r1 = strlen_or_false((const char * )AlienVal(g1));
|
||||
ret1 = r1;
|
||||
S48_GC_UNPROTECT();
|
||||
return ret1;
|
||||
}
|
||||
|
||||
s48_value df_cstring_nullp(s48_value g1)
|
||||
{
|
||||
extern int cstring_nullp(const char * );
|
||||
s48_value ret1 = S48_FALSE;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
int r1;
|
||||
|
||||
|
||||
|
||||
S48_GC_PROTECT_1(ret1);
|
||||
r1 = cstring_nullp((const char * )AlienVal(g1));
|
||||
ret1 = ENTER_BOOLEAN(r1);
|
||||
S48_GC_UNPROTECT();
|
||||
return ret1;
|
||||
}
|
||||
|
||||
s48_value df_c2scheme_strcpy_free(s48_value g1, s48_value g2)
|
||||
{
|
||||
extern int c2scheme_strcpy_free(s48_value , char* );
|
||||
s48_value ret1 = S48_FALSE;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
int r1;
|
||||
|
||||
|
||||
|
||||
S48_GC_PROTECT_1(ret1);
|
||||
r1 = c2scheme_strcpy_free(g1, (char* )AlienVal(g2));
|
||||
ret1 = ENTER_BOOLEAN(r1);
|
||||
S48_GC_UNPROTECT();
|
||||
return ret1;
|
||||
}
|
||||
|
||||
s48_value df_c2scheme_strcpy(s48_value g1, s48_value g2)
|
||||
{
|
||||
extern int c2scheme_strcpy(s48_value , char* );
|
||||
s48_value ret1 = S48_FALSE;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
int r1;
|
||||
|
||||
|
||||
|
||||
S48_GC_PROTECT_1(ret1);
|
||||
r1 = c2scheme_strcpy(g1, (char* )AlienVal(g2));
|
||||
ret1 = ENTER_BOOLEAN(r1);
|
||||
S48_GC_UNPROTECT();
|
||||
return ret1;
|
||||
}
|
||||
|
||||
s48_value df_c_veclen(s48_value g1)
|
||||
{
|
||||
extern s48_value c_veclen(long* );
|
||||
s48_value ret1 = S48_FALSE;
|
||||
S48_DECLARE_GC_PROTECT(1);
|
||||
s48_value r1;
|
||||
|
||||
|
||||
|
||||
S48_GC_PROTECT_1(ret1);
|
||||
r1 = c_veclen((long* )AlienVal(g1));
|
||||
ret1 = r1;
|
||||
S48_GC_UNPROTECT();
|
||||
return ret1;
|
||||
}
|
||||
|
||||
s48_value df_free(s48_value g1)
|
||||
{
|
||||
|
||||
|
||||
|
||||
free((void* )AlienVal(g1));
|
||||
return S48_FALSE;
|
||||
}
|
||||
|
||||
s48_value df_set_strvec_carriers(s48_value g1, s48_value g2)
|
||||
{
|
||||
extern void set_strvec_carriers(s48_value , char** );
|
||||
|
||||
|
||||
set_strvec_carriers(g1, (char** )AlienVal(g2));
|
||||
return S48_FALSE;
|
||||
}
|
||||
|
||||
void s48_init_cig(void)
|
||||
{
|
||||
S48_EXPORT_FUNCTION(df_strlen_or_false);
|
||||
S48_EXPORT_FUNCTION(df_cstring_nullp);
|
||||
S48_EXPORT_FUNCTION(df_c2scheme_strcpy_free);
|
||||
S48_EXPORT_FUNCTION(df_c2scheme_strcpy);
|
||||
S48_EXPORT_FUNCTION(df_c_veclen);
|
||||
S48_EXPORT_FUNCTION(df_free);
|
||||
S48_EXPORT_FUNCTION(df_set_strvec_carriers);
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#include "scheme48.h"
|
||||
|
||||
/* StobData is used by fdports.c. It should be changed over to STOB_REF
|
||||
** by removing the extra indirection. */
|
||||
#define StobData(x) (S48_ADDRESS_AFTER_HEADER(x, s48_value))
|
||||
|
||||
#define IsChar(x) ((((long) x) & 0xff) == S48_CHAR)
|
||||
/* JMG: untested !! */
|
||||
|
||||
#define StrByte(x, i) ((i) + S48_ADDRESS_AFTER_HEADER((x), char))
|
||||
#define cig_string_body(x) (S48_ADDRESS_AFTER_HEADER((x), char))
|
||||
|
||||
#define AlienVal(x) (S48_STOB_REF((x),0))
|
||||
/* JMG: no () around this, because it's a do..while(0) */
|
||||
#define SetAlienVal(x, v) S48_STOB_SET((x), 0, (v))
|
||||
|
||||
/* JMG: some hacks to leave to old sources untouched */
|
||||
#define ENTER_BOOLEAN(x) (x ? S48_TRUE : S48_FALSE)
|
||||
#define EXTRACT_BOOLEAN(x) ((x==S48_TRUE) ? 1 : 0)
|
||||
/* #define ENTER_FIXNUM(x) (s48_enter_fixnum(x)) */
|
||||
/* #define SCHFALSE S48_FALSE */
|
||||
|
||||
extern char *scheme2c_strcpy(s48_value sstr);
|
||||
|
||||
extern s48_value strlen_or_false(const char *s);
|
||||
|
||||
extern char *copystring_or_die(const char *);
|
||||
extern char *copystring(char *, const char *);
|
||||
|
||||
extern s48_value strlen_or_false(const char *);
|
||||
|
||||
extern void cig_check_nargs(int arity, int nargs, const char *fn);
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
;;; (DEFINE-FOREIGN ...) forms are expanded by Cig into Scheme stubs.
|
||||
;;; These stubs reference some support procedures to rep-convert the
|
||||
;;; standard reps (e.g., string). This structure provides these support
|
||||
;;; procedures.
|
||||
;;;
|
||||
;;; We export three kinds of things:
|
||||
;;; - Type predicates that aren't in the R4RS env (e.g., FIXNUM?).
|
||||
;;; - Carrier makers for making boxes to return things in.
|
||||
;;; - Scheme-side rep-converters for return values.
|
||||
|
||||
(define-structure cig-aux
|
||||
(export cstring-null?
|
||||
C->scheme-string
|
||||
C->scheme-string-w/len
|
||||
C->scheme-string-w/len-no-free
|
||||
C-string-vec->Scheme&free
|
||||
C-string-vec->Scheme ; Bogus, because clients not reentrant.
|
||||
string-carrier->string
|
||||
string-carrier->string-no-free
|
||||
fixnum?
|
||||
make-string-carrier
|
||||
make-alien
|
||||
alien?
|
||||
)
|
||||
(open scheme code-vectors define-foreign-syntax)
|
||||
|
||||
(begin
|
||||
(define min-fixnum (- (expt 2 29)))
|
||||
(define max-fixnum (- (expt 2 29) 1))
|
||||
(define (fixnum? x) (and (integer? x) (<= min-fixnum x max-fixnum)))
|
||||
|
||||
;; Internal utility.
|
||||
(define (mapv! f v)
|
||||
(let ((len (vector-length v)))
|
||||
(do ((i 0 (+ i 1)))
|
||||
((= i len) v)
|
||||
(vector-set! v i (f (vector-ref v i))))))
|
||||
|
||||
;; Make a carrier for returning strings.
|
||||
;; It holds a raw C string and a fixnum giving the length of the string.
|
||||
(define (make-string-carrier) (cons (make-alien) 0))
|
||||
|
||||
(define (make-alien) (make-code-vector 4 0))
|
||||
(define (alien? x) (and (code-vector? x) (= 4 (code-vector-length x)))) ; BOGUS
|
||||
|
||||
|
||||
;;; C/Scheme string and vector conversion
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; Generally speaking, in the following routines,
|
||||
;;; a NULL C string param causes a function to return #f.
|
||||
(foreign-init-name "cig")
|
||||
|
||||
(define-foreign %cstring-length-or-false
|
||||
(strlen_or_false ((C "const char * ~a") cstr))
|
||||
desc)
|
||||
|
||||
(define-foreign cstring-null?
|
||||
(cstring_nullp ((C "const char * ~a") cstr))
|
||||
bool)
|
||||
|
||||
(define-foreign %copy-c-string&free
|
||||
(c2scheme_strcpy_free (string-desc sstr) ((C char*) cstr))
|
||||
bool)
|
||||
|
||||
(define-foreign %copy-c-string
|
||||
(c2scheme_strcpy (string-desc sstr) ((C char*) cstr))
|
||||
bool)
|
||||
|
||||
(define (C->scheme-string cstr)
|
||||
(cond ((%cstring-length-or-false cstr)
|
||||
=> (lambda (strlen)
|
||||
(let ((str (make-string strlen)))
|
||||
(%copy-c-string&free str cstr)
|
||||
str)))
|
||||
(else #f)))
|
||||
|
||||
(define (C->scheme-string-w/len cstr len)
|
||||
(and (integer? len)
|
||||
(let ((str (make-string len)))
|
||||
(%copy-c-string&free str cstr)
|
||||
str)))
|
||||
|
||||
(define (C->scheme-string-w/len-no-free cstr len)
|
||||
(and (integer? len)
|
||||
(let ((str (make-string len)))
|
||||
(%copy-c-string str cstr)
|
||||
str)))
|
||||
|
||||
(define (string-carrier->string carrier)
|
||||
(C->scheme-string-w/len (car carrier) (cdr carrier)))
|
||||
|
||||
(define (string-carrier->string-no-free carrier)
|
||||
(C->scheme-string-w/len-no-free (car carrier) (cdr carrier)))
|
||||
|
||||
;;; Return the length of a null-terminated C word vector.
|
||||
;;; Does not count the null word as part of the length.
|
||||
;;; If vector is NULL, returns #f.
|
||||
|
||||
(define-foreign %c-veclen-or-false
|
||||
(c_veclen ((C long*) c-vec))
|
||||
desc) ; integer or #f if arg is NULL.
|
||||
|
||||
;;; CVEC is a C vector of char* strings, length VECLEN.
|
||||
;;; This procedure converts a C vector of strings into a Scheme vector of
|
||||
;;; strings. The C vector and its strings are all assumed to come from
|
||||
;;; the malloc heap; they are returned to the heap when the rep-conversion
|
||||
;;; is done.
|
||||
;;;
|
||||
;;; Hack: if VECLEN is #f, CVEC is assumed to be NULL terminated, and
|
||||
;;; its length is calculated thusly.
|
||||
|
||||
(define (C-string-vec->Scheme&free cvec veclen)
|
||||
(let ((vec (make-vector (or veclen (%c-veclen-or-false cvec) 0))))
|
||||
(mapv! (lambda (ignore) (make-string-carrier)) vec)
|
||||
(%set-string-vector-carriers! vec cvec)
|
||||
(C-free cvec)
|
||||
(mapv! string-carrier->string vec)))
|
||||
|
||||
(define (C-string-vec->Scheme cvec veclen) ; No free.
|
||||
(let ((vec (make-vector (or veclen (%c-veclen-or-false cvec) 0))))
|
||||
(mapv! (lambda (ignore) (make-string-carrier)) vec)
|
||||
(%set-string-vector-carriers! vec cvec)
|
||||
(mapv! string-carrier->string-no-free vec)))
|
||||
|
||||
|
||||
(define-foreign C-free (free ((C void*) ptr)) no-declare ; for SunOS 4.x
|
||||
ignore)
|
||||
|
||||
(define-foreign %set-string-vector-carriers!
|
||||
(set_strvec_carriers (vector-desc svec) ((C char**) cvec))
|
||||
ignore)
|
||||
|
||||
)) ; egakcap
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
/* Generic routines for Scheme48/C interfacing -- mostly for converting
|
||||
** strings and null-terminated vectors back and forth.
|
||||
** Copyright (c) 1993 by Olin Shivers.
|
||||
*/
|
||||
|
||||
#include "libcig.h"
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define Malloc(type,n) ((type *) malloc(sizeof(type)*(n)))
|
||||
#define Free(p) (free((char *)(p)))
|
||||
|
||||
/* (c2scheme_strcpy dest_scheme_string source_C_string)
|
||||
** Copies C string's chars into Scheme string. Return #t.
|
||||
** If C string is NULL, do nothing and return #f.
|
||||
*/
|
||||
|
||||
int c2scheme_strcpy(s48_value sstr, const char *cstr)
|
||||
{
|
||||
if( cstr ) {
|
||||
strncpy( (char*) StobData(sstr), cstr, S48_STRING_LENGTH(sstr) );
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Same as above, but free the C string when we are done. */
|
||||
int c2scheme_strcpy_free(s48_value sstr, const char *cstr)
|
||||
{
|
||||
if( cstr ) {
|
||||
strncpy( (char*) StobData(sstr), cstr, S48_STRING_LENGTH(sstr) );
|
||||
Free(cstr);
|
||||
return 1;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
char *scheme2c_strcpy(s48_value sstr)
|
||||
{
|
||||
char *result;
|
||||
int slen;
|
||||
|
||||
slen = S48_STRING_LENGTH(sstr);
|
||||
result = Malloc(char, slen+1);
|
||||
|
||||
if( result == NULL ) {
|
||||
fprintf(stderr,
|
||||
"Fatal error: C stub tried to copy Scheme string,\n"
|
||||
"but malloc failed on arg 0x%x, errno %d.\n",
|
||||
sstr, errno);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
memcpy(result, cig_string_body(sstr), slen);
|
||||
result[slen] = '\000';
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* One arg, a zero-terminated C word vec. Returns length.
|
||||
** The terminating null is not counted. Returns #f on NULL.
|
||||
*/
|
||||
|
||||
s48_value c_veclen(const long *vec)
|
||||
{
|
||||
const long *vptr = vec;
|
||||
if( !vptr ) return S48_FALSE;
|
||||
while( *vptr ) vptr++;
|
||||
return s48_enter_fixnum(vptr - vec);
|
||||
}
|
||||
|
||||
|
||||
/* Copy string from into string to. If to is NULL, malloc a fresh string
|
||||
** (if the malloc loses, return NULL).
|
||||
** If from is NULL, then
|
||||
** - if to is NULL, do nothing and return NULL.
|
||||
** - Otherwise, deposit a single nul byte.
|
||||
** Under normal conditions, this routine returns the destination string.
|
||||
**
|
||||
** The little boundary cases of this procedure are a study in obfuscation
|
||||
** because C doesn't have a reasonable string data type. Give me a break.
|
||||
*/
|
||||
char *copystring(char *to, const char *from)
|
||||
{
|
||||
if( from ) {
|
||||
int slen = strlen(from)+1;
|
||||
if( !to && !(to = Malloc(char, slen)) ) return NULL;
|
||||
else return memcpy(to, from, slen);
|
||||
}
|
||||
|
||||
else
|
||||
return to ? *to = '\000', to : NULL;
|
||||
}
|
||||
|
||||
/* As in copystring, but if malloc loses, print out an error msg and croak. */
|
||||
char *copystring_or_die(const char *str ) /* Note: NULL -> NULL. */
|
||||
{
|
||||
if( str ) {
|
||||
int len = strlen(str)+1;
|
||||
char *new_str = Malloc(char, len);
|
||||
if( ! new_str ) {
|
||||
fprintf(stderr, "copystring: Malloc failed.\n");
|
||||
exit(-1);
|
||||
}
|
||||
return memcpy(new_str, str, len);
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
int cstring_nullp( const char *s ) { return ! s; }
|
||||
|
||||
s48_value strlen_or_false(const char *s)
|
||||
{ return s ? s48_enter_fixnum(strlen(s)) : S48_FALSE; }
|
||||
|
||||
|
||||
|
||||
/* svec is a Scheme vector of C string carriers. Scan over the C strings
|
||||
** in cvec, and initialise the corresponding string carriers in svec.
|
||||
*/
|
||||
void set_strvec_carriers(s48_value svec, char const * const * cvec)
|
||||
{
|
||||
int svec_len = S48_VECTOR_LENGTH(svec);
|
||||
char const * const * cv = cvec;
|
||||
int i = 0;
|
||||
|
||||
/* JMG: now using normal array access, instead of pointer++ on a s48_value */
|
||||
for(; svec_len > 0; i++, cv++, svec_len-- ) {
|
||||
s48_value carrier, alien;
|
||||
int strl;
|
||||
|
||||
/* *sv is a (cons (make-alien <c-string>) <string-length>). */
|
||||
carrier = S48_VECTOR_REF(svec,i);
|
||||
alien = S48_CAR(carrier);
|
||||
strl = strlen(*cv);
|
||||
S48_SET_CDR(carrier, s48_enter_fixnum(strl));
|
||||
SetAlienVal(alien, (long) *cv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function for arg checking. Why bother, actually? */
|
||||
void cig_check_nargs(int arity, int nargs, const char *fn)
|
||||
{
|
||||
if( arity != nargs ) {
|
||||
fprintf(stderr,
|
||||
"Cig fatal error (%s) -- C stub expected %d arg%s, "
|
||||
"but got %d.\n",
|
||||
fn, arity, (arity == 1) ? "" : "s", nargs);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
/* void ciginit(){ */
|
||||
/* S48_EXPORT_FUNCTION (df_strlen_or_false); */
|
||||
/* S48_EXPORT_FUNCTION (df_c_veclen); */
|
||||
/* S48_EXPORT_FUNCTION (df_set_strvec_carriers); */
|
||||
/* S48_EXPORT_FUNCTION (df_c2scheme_strcpy_free); */
|
||||
/* S48_EXPORT_FUNCTION (df_cstring_nullp); */
|
||||
/* S48_EXPORT_FUNCTION (df_free); */
|
||||
/* S48_EXPORT_FUNCTION (df_c2scheme_strcpy); */
|
||||
/* } */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
431
configure.in
431
configure.in
|
|
@ -3,26 +3,7 @@ dnl
|
|||
dnl We might want AC_WORDS_BIGENDIAN in the future.
|
||||
dnl We might want AC_CHAR_UNSIGNED in the future.
|
||||
dnl
|
||||
dnl The -cckr (K&R) flag is for the IRIX C compiler. If this is left
|
||||
dnl out, scheme48vm.c breaks because the rather pedantic SGI compiler
|
||||
dnl decides that a char is not the same thing as an unsigned char.
|
||||
dnl - Bryan O'Sullivan 3/94
|
||||
dnl Note, this test didn't work correctly on Sun's which take -cckr as a
|
||||
dnl synonym for -c. (HCC)
|
||||
define(S48_CFLAG_CKR, [dnl
|
||||
if test "z$GCC" = z; then
|
||||
AC_MSG_CHECKING([-cckr])
|
||||
oldCFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -cckr"
|
||||
AC_TRY_RUN([int main() { return 0;}],
|
||||
[AC_MSG_RESULT(yes)],
|
||||
[AC_MSG_RESULT(no)
|
||||
CFLAGS="$oldCFLAGS"],
|
||||
[AC_MSG_RESULT(no)
|
||||
CFLAGS="$oldCFLAGS"])
|
||||
fi
|
||||
])dnl
|
||||
dnl
|
||||
|
||||
define(S48_POSIX_LIBC, [dnl
|
||||
echo checking for RISC/OS POSIX library lossage
|
||||
if test -f /usr/posix/usr/lib/libc.a; then
|
||||
|
|
@ -52,10 +33,39 @@ dnl Note, on some Sun's, you can link with -rdynamic but the resulting
|
|||
dnl a.out always core dumps.
|
||||
define(S48_RDYNAMIC, [dnl
|
||||
AC_MSG_CHECKING([link with -rdynamic])
|
||||
AC_TRY_COMPILE([],
|
||||
[#if defined(__linux__) && defined(__ELF__)
|
||||
this must not compile
|
||||
#endif],
|
||||
AC_RUN_IFELSE(AC_LANG_PROGRAM([
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
int export_test = 0;],
|
||||
[
|
||||
#ifndef RTLD_LAZY
|
||||
#define RTLD_LAZY 0
|
||||
#endif
|
||||
|
||||
#ifndef RTLD_GLOBAL
|
||||
#define RTLD_GLOBAL 0
|
||||
#endif
|
||||
|
||||
void *dlhandle;
|
||||
void *intp;
|
||||
char *err;
|
||||
|
||||
dlhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
|
||||
|
||||
if ((err = dlerror()) != NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
(void *)intp = dlsym(dlhandle, "export_test");
|
||||
|
||||
if ((err = dlerror()) != NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
]),
|
||||
[AC_MSG_RESULT(no)],
|
||||
[AC_MSG_RESULT(yes)
|
||||
LDFLAGS="$LDFLAGS -rdynamic"])
|
||||
|
|
@ -64,24 +74,263 @@ dnl
|
|||
define(S48_USCORE, [dnl
|
||||
AC_MSG_CHECKING([underscore before symbols])
|
||||
echo 'main() { return 0; } fnord() {}' >conftest.c
|
||||
if ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} conftest.c ${LIBS} &&
|
||||
if ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} -o a.out conftest.c ${LIBS} &&
|
||||
nm a.out | grep _fnord >/dev/null; then
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE(USCORE)
|
||||
AC_DEFINE(USCORE, 1, [Define to 1 if symbols start with _])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
rm -f conftest.c a.out
|
||||
])dnl
|
||||
dnl
|
||||
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
AC_DEFUN(SCSH_TZNAME,[
|
||||
AC_MSG_CHECKING(for tzname)
|
||||
AC_CACHE_VAL(scsh_cv_tzname,[
|
||||
AC_TRY_COMPILE([#include <time.h>],
|
||||
[return (int) tzname;],
|
||||
scsh_cv_tzname=yes,
|
||||
scsh_cv_tzname=no)])
|
||||
AC_MSG_RESULT($scsh_cv_tzname)
|
||||
if test $scsh_cv_tzname = yes; then
|
||||
AC_DEFINE(HAVE_TZNAME)
|
||||
fi
|
||||
])
|
||||
|
||||
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
AC_DEFUN(SCSH_ELF, [
|
||||
AC_MSG_CHECKING(for ELF)
|
||||
AC_CACHE_VAL(scsh_cv_elf,[
|
||||
touch conftest.c
|
||||
if ${CC} -v -o a.out conftest.c 2>&1 | grep -q __ELF__ ; then
|
||||
scsh_cv_elf=yes
|
||||
else
|
||||
scsh_cv_elf=no
|
||||
fi])
|
||||
AC_MSG_RESULT($scsh_cv_elf)
|
||||
rm -f conftest.c a.out
|
||||
])
|
||||
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
AC_DEFUN(SCSH_SIG_NRS, [
|
||||
AC_MSG_RESULT([defining signal constants])
|
||||
${CC} -o scsh_aux ${srcdir}/scsh/scsh_aux.c
|
||||
AC_DEFINE_UNQUOTED(SIGNR_1, `./scsh_aux 1`, [scsh interrupt for signal 1])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_2, `./scsh_aux 2`, [scsh interrupt for signal 2])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_3, `./scsh_aux 3`, [scsh interrupt for signal 3])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_4, `./scsh_aux 4`, [scsh interrupt for signal 4])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_5, `./scsh_aux 5`, [scsh interrupt for signal 5])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_6, `./scsh_aux 6`, [scsh interrupt for signal 6])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_7, `./scsh_aux 7`, [scsh interrupt for signal 7])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_8, `./scsh_aux 8`, [scsh interrupt for signal 8])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_9, `./scsh_aux 9`, [scsh interrupt for signal 9])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_10, `./scsh_aux 10`, [scsh interrupt for signal 10])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_11, `./scsh_aux 11`, [scsh interrupt for signal 11])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_12, `./scsh_aux 12`, [scsh interrupt for signal 12])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_13, `./scsh_aux 13`, [scsh interrupt for signal 13])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_14, `./scsh_aux 14`, [scsh interrupt for signal 14])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_15, `./scsh_aux 15`, [scsh interrupt for signal 15])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_16, `./scsh_aux 16`, [scsh interrupt for signal 16])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_17, `./scsh_aux 17`, [scsh interrupt for signal 17])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_18, `./scsh_aux 18`, [scsh interrupt for signal 18])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_19, `./scsh_aux 19`, [scsh interrupt for signal 19])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_20, `./scsh_aux 20`, [scsh interrupt for signal 20])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_21, `./scsh_aux 21`, [scsh interrupt for signal 21])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_22, `./scsh_aux 22`, [scsh interrupt for signal 22])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_23, `./scsh_aux 23`, [scsh interrupt for signal 23])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_24, `./scsh_aux 24`, [scsh interrupt for signal 24])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_25, `./scsh_aux 25`, [scsh interrupt for signal 25])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_26, `./scsh_aux 26`, [scsh interrupt for signal 26])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_27, `./scsh_aux 27`, [scsh interrupt for signal 27])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_28, `./scsh_aux 28`, [scsh interrupt for signal 28])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_29, `./scsh_aux 29`, [scsh interrupt for signal 29])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_30, `./scsh_aux 30`, [scsh interrupt for signal 30])
|
||||
AC_DEFINE_UNQUOTED(SIGNR_31, `./scsh_aux 31`, [scsh interrupt for signal 31])
|
||||
rm -f scsh_aux scsh_aux.exe
|
||||
])
|
||||
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
AC_DEFUN(SCSH_LINUX_STATIC_DEBUG, [
|
||||
case "$host" in
|
||||
*-*-linux* )
|
||||
AC_MSG_CHECKING(for broken Linux that needs -static with -g)
|
||||
AC_CACHE_VAL(scsh_cv_linux_static_debug,[
|
||||
AC_TRY_LINK([],
|
||||
[],
|
||||
scsh_cv_linux_static_debug=no,
|
||||
scsh_cv_linux_static_debug=yes)])
|
||||
AC_MSG_RESULT($scsh_cv_linux_static_debug)
|
||||
if test $scsh_cv_linux_static_debug = yes; then
|
||||
LDFLAGS="-static ${LDFLAGS}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
])
|
||||
|
||||
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
AC_DEFUN(SCSH_CONST_SYS_ERRLIST,[
|
||||
AC_MSG_CHECKING(for const sys_errlist)
|
||||
AC_CACHE_VAL(scsh_cv_const_sys_errlist,[
|
||||
AC_TRY_COMPILE([#include <errno.h>
|
||||
#include <unistd.h>],
|
||||
[const extern char *sys_errlist[];],
|
||||
scsh_cv_const_sys_errlist=yes,
|
||||
scsh_cv_const_sys_errlist=no)])
|
||||
AC_MSG_RESULT($scsh_cv_const_sys_errlist)
|
||||
if test $scsh_cv_const_sys_errlist = yes; then
|
||||
AC_DEFINE(HAVE_CONST_SYS_ERRLIST, 1, [const char* sys_errlist])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
AC_DEFUN(SCSH_SOCKLEN_T,[
|
||||
AC_MSG_CHECKING(for socklen_t)
|
||||
AC_TRY_COMPILE([#include <sys/socket.h>
|
||||
socklen_t x;
|
||||
],[],[AC_MSG_RESULT(yes)],[
|
||||
AC_TRY_COMPILE([#include <sys/socket.h>
|
||||
int accept (int, struct sockaddr *, size_t *);
|
||||
],[],[
|
||||
AC_MSG_RESULT(size_t)
|
||||
AC_DEFINE(socklen_t,
|
||||
size_t, [Define to type of socklen_t])], [
|
||||
AC_MSG_RESULT(int)
|
||||
AC_DEFINE(socklen_t,int)])])
|
||||
])
|
||||
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
define(SCSH_CREATE_BUILD_DIRS, [dnl
|
||||
mkdir -p cig
|
||||
mkdir -p scsh/machine
|
||||
mkdir -p scsh/rx
|
||||
mkdir -p c/srfi
|
||||
mkdir -p c/unix
|
||||
])dnl
|
||||
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
AC_INIT(c/scheme48vm.c)
|
||||
AC_CONFIG_HEADER(c/sysdep.h)
|
||||
SCSH_CREATE_BUILD_DIRS
|
||||
AC_CANONICAL_HOST
|
||||
S48_PROG_CC
|
||||
SCSH_SIG_NRS
|
||||
AC_ISC_POSIX
|
||||
SCSH_LINUX_STATIC_DEBUG
|
||||
dnl set the cross-compile flag before we try anything.
|
||||
AC_TRY_RUN([int main() { return 0;}], [], [], [true])
|
||||
S48_CFLAG_CKR
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_RANLIB
|
||||
AC_C_CONST
|
||||
|
||||
AC_C_BIGENDIAN
|
||||
if test $ac_cv_c_bigendian = no ; then
|
||||
ENDIAN=little
|
||||
else
|
||||
ENDIAN=big
|
||||
fi
|
||||
|
||||
AR=${AR-"ar cq"}
|
||||
TMPDIR=${TMPDIR-"/var/tmp"}
|
||||
case "$host" in
|
||||
## CX/UX
|
||||
m88k-harris-cxux* )
|
||||
dir=cxux
|
||||
CC="cc -Xa"
|
||||
CFLAGS="-O"
|
||||
LDFLAGS="-O -Wl,-Bexport"
|
||||
AC_DEFINE(HAVE_HARRIS, 1, [Define to 1 on m88k-harris-cxux])
|
||||
;;
|
||||
|
||||
## DEC Ultrix
|
||||
mips-dec-ultrix* )
|
||||
AC_MSG_ERROR("Ultrix is not supported.")
|
||||
;;
|
||||
|
||||
## HP 9000 series 700 and 800, running HP/UX
|
||||
hppa*-hp-hpux* )
|
||||
dir=hpux
|
||||
LDFLAGS="-Wl,-E"
|
||||
if test ${CC} = cc; then
|
||||
CFLAGS="-Ae -O +Obb1800"
|
||||
fi
|
||||
AC_DEFINE(_HPUX_SOURCE, 1, [Define to 1 to compile on HP/UX])
|
||||
AC_DEFINE(hpux, 1, [Define to 1 on HP/UX])
|
||||
AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Define to 1 to compile on HP/UX])
|
||||
;;
|
||||
|
||||
## IBM AIX
|
||||
rs6000-ibm-aix*|powerpc-ibm-aix* )
|
||||
dir=aix
|
||||
LDFLAGS="-O"
|
||||
if test ${CC} = gcc; then
|
||||
LDFLAGS_AIX="-Xlinker -bexport:exportlist.aix"
|
||||
else
|
||||
LDFLAGS_AIX="-bexport:exportlist.aix"
|
||||
fi
|
||||
CFLAGS="-O"
|
||||
AIX_P="exportlist.aix"
|
||||
;;
|
||||
|
||||
## Linux
|
||||
*-*-linux* )
|
||||
dir=linux
|
||||
# gross, but needed for some older a.out systems for 0.4.x
|
||||
LIBS=-lc
|
||||
SCSH_ELF
|
||||
;;
|
||||
|
||||
## NetBSD and FreeBSD ( and maybe 386BSD also)
|
||||
*-*-*bsd*|*-*-darwin* )
|
||||
dir=bsd
|
||||
SCSH_ELF
|
||||
;;
|
||||
|
||||
## NeXT
|
||||
*-next-* )
|
||||
dir=next
|
||||
CC="$CC -posix"
|
||||
AC_DEFINE(HAVE_SIGACTION)
|
||||
;;
|
||||
|
||||
## SGI IRIX
|
||||
mips-sgi-irix* )
|
||||
dir=irix
|
||||
S48_CFLAG_CKR
|
||||
INSTALL='$(srcdir)/install-sh'
|
||||
;;
|
||||
|
||||
## SunOS
|
||||
sparc*-sun-sunos* )
|
||||
dir=sunos
|
||||
;;
|
||||
|
||||
## Solaris - Sparc and i386
|
||||
*-*-solaris* )
|
||||
dir=solaris
|
||||
AC_DEFINE(HAVE_NLIST)
|
||||
;;
|
||||
|
||||
## NT - cygwin32
|
||||
*-*-cygwin* )
|
||||
AC_DEFINE(CYGWIN, 1, [Define to 1 on cygwin])
|
||||
dir=cygwin32
|
||||
EXEEXT=".exe"
|
||||
;;
|
||||
|
||||
## The GNU Hurd
|
||||
*-*-gnu* )
|
||||
dir=gnu
|
||||
SCSH_ELF
|
||||
;;
|
||||
|
||||
## Generic Configuration
|
||||
* )
|
||||
dir=generic
|
||||
echo "WARNING: "
|
||||
echo "WARNING: Using generic configuration."
|
||||
echo "WARNING: See doc/porting.txt for more information."
|
||||
echo "WARNING: "
|
||||
;;
|
||||
esac
|
||||
(cd $srcdir/scsh && rm -rf machine && ln -s $dir machine)
|
||||
|
||||
AC_CHECK_LIB(m, main)
|
||||
AC_CHECK_LIB(dl, main)
|
||||
AC_CHECK_LIB(mld, main)
|
||||
|
|
@ -89,27 +338,44 @@ AC_INIT(c/scheme48vm.c)
|
|||
AC_CHECK_LIB(gen, main)
|
||||
AC_CHECK_LIB(socket, main)
|
||||
AC_CHECK_LIB(sun, getpwnam)
|
||||
AC_CHECK_LIB(c, crypt, [true], AC_CHECK_LIB(crypt, crypt))
|
||||
dnl Solaris 2.3 seems to need -lelf for nlist(). (tnx Bryan O'Sullivan)
|
||||
AC_CHECK_LIB(elf, main)
|
||||
S48_POSIX_LIBC
|
||||
AC_CONST
|
||||
AC_RETSIGTYPE
|
||||
AC_CHECK_HEADERS(libgen.h sys/timeb.h posix/time.h)
|
||||
AC_CHECK_HEADERS(sys/select.h)
|
||||
AC_CHECK_FUNCS(gettimeofday ftime nlist select setitimer sigaction)
|
||||
AC_CHECK_FUNC(dlopen, AC_DEFINE(HAVE_DLOPEN),
|
||||
AC_CHECK_FUNC(nlist, [LIBOBJS="$LIBOBJS c/fake/libdl1.c],
|
||||
[LIBOBJS="$LIBOBJS c/fake/libdl2.c]))
|
||||
AC_CHECK_HEADERS(libgen.h sys/timeb.h posix/time.h sys/select.h nlist.h)
|
||||
AC_CHECK_HEADERS(sys/un.h)
|
||||
AC_CHECK_HEADERS(crypt.h)
|
||||
AC_CHECK_FUNCS(gettimeofday ftime nlist select setitimer sigaction vasprintf)
|
||||
SCSH_SOCKLEN_T
|
||||
AC_CHECK_FUNC(dlopen, [AC_DEFINE(HAVE_DLOPEN,
|
||||
1, [Define to 1 if the interface to the dynamic linker exists])
|
||||
have_dlopen="yes"],
|
||||
[AC_CHECK_FUNC(nlist, [AC_LIBOBJ([c/fake/libdl1])],
|
||||
[AC_LIBOBJ([c/fake/libdl2])])
|
||||
have_dlopen="no"])
|
||||
AC_CHECK_FUNCS(socket chroot)
|
||||
AC_CHECK_FUNC(strerror, AC_DEFINE(HAVE_STRERROR),
|
||||
[LIBOBJS="$LIBOBJS c/fake/strerror.o"])
|
||||
AC_MSG_CHECKING([n_name])
|
||||
AC_TRY_LINK([#include <nlist.h>],
|
||||
[struct nlist name_list;
|
||||
name_list.n_name = "foo";],
|
||||
AC_DEFINE(NLIST_HAS_N_NAME)
|
||||
AC_MSG_RESULT([yes]),
|
||||
AC_MSG_RESULT([no]))
|
||||
AC_CHECK_FUNC(strerror, AC_DEFINE(HAVE_STRERROR,
|
||||
1, [Define to 1 if you have the strerror function]),
|
||||
[AC_LIBOBJ([c/fake/strerror])])
|
||||
|
||||
AC_CHECK_FUNC(seteuid, [AC_DEFINE(HAVE_SETEUID,
|
||||
1, [Define to 1 if you have the seteuid function])],
|
||||
[AC_CHECK_FUNC(setreuid, [AC_DEFINE(HAVE_SETREUID,
|
||||
1, [Define to 1 if you have the setreuid function])],
|
||||
[AC_MSG_ERROR("Neither setegid nor setregid defined. Cannot continue.")])])
|
||||
|
||||
AC_CHECK_FUNC(setegid, [AC_DEFINE(HAVE_SETEGID,
|
||||
1, [Define to 1 if you have the setegid function])],
|
||||
[AC_CHECK_FUNC(setregid, [AC_DEFINE(HAVE_SETREGID,
|
||||
1, [Define to 1 if you have the setregid function])],
|
||||
[AC_MSG_ERROR("Neither setegid nor setregid defined. Cannot continue.")])])
|
||||
|
||||
|
||||
AC_CHECK_MEMBER(struct nlist.n_name,
|
||||
[AC_DEFINE(NLIST_HAS_N_NAME, 1, [Define to 1 if struct nlist.n_name exists])],,
|
||||
[#include <nlist.h>])
|
||||
AC_MSG_CHECKING([__NEXT__])
|
||||
AC_TRY_LINK(,[
|
||||
#ifdef __NeXT__
|
||||
|
|
@ -123,8 +389,83 @@ fail
|
|||
AC_MSG_RESULT([yes]),
|
||||
AC_MSG_RESULT([no]))
|
||||
S48_USCORE
|
||||
S48_RDYNAMIC
|
||||
if test $have_dlopen = yes; then
|
||||
S48_RDYNAMIC
|
||||
fi
|
||||
AC_STRUCT_TIMEZONE
|
||||
AC_CHECK_MEMBER(struct tm.tm_gmtoff,
|
||||
AC_DEFINE(HAVE_GMTOFF, 1, [Define to 1 if struct tm has member tm_gmtoff]))
|
||||
|
||||
dnl ----------------------------------------------------------------
|
||||
dnl Check for pty support
|
||||
dnl ----------------------------------------------------------------
|
||||
|
||||
dnl There is no "standard" pty allocation method. Every system is different.
|
||||
dnl getpt() is the preferred pty allocation method on glibc systems.
|
||||
dnl _getpty() is the preferred pty allocation method on SGI systems.
|
||||
dnl grantpt(), unlockpt(), ptsname() are defined by Unix98.
|
||||
AC_CHECK_FUNCS(getpt _getpty grantpt unlockpt ptsname killpg tcgetpgrp)
|
||||
|
||||
dnl openpty() is the preferred pty allocation method on BSD and Tru64 systems.
|
||||
dnl openpty() might be declared in:
|
||||
dnl - pty.h (Tru64 or Linux)
|
||||
dnl - libutil.h (FreeBSD)
|
||||
dnl - util.h (NetBSD)
|
||||
AC_CHECK_FUNC(openpty, have_openpty=yes, [
|
||||
AC_CHECK_LIB(util, openpty, have_openpty=yes need_libutil=yes)])
|
||||
if test "$have_openpty" = "yes"; then
|
||||
AC_DEFINE(HAVE_OPENPTY, 1, [Define to 1 if you have the 'openpty' function])
|
||||
AC_CHECK_HEADERS(libutil.h util.h, break)
|
||||
if test "$need_libutil" = "yes"; then
|
||||
LIBS="${LIBS} -lutil"
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Check for system-specific pty header files
|
||||
dnl Often the TIOCSIG* symbols are hiding there.
|
||||
case "$opsys" in
|
||||
dnl HPUX pty.h #defines TRUE and FALSE, so just use ptyio.h there.
|
||||
hpux*) AC_CHECK_HEADERS(sys/ptyio.h) ;;
|
||||
*) AC_CHECK_HEADERS(pty.h)
|
||||
test "$ac_cv_header_pty_h" = "no" && AC_CHECK_HEADERS(sys/pty.h)
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
dnl Check for System V STREAM support functions.
|
||||
AC_CHECK_HEADERS(stropts.h)
|
||||
AC_CHECK_FUNCS(isastream)
|
||||
|
||||
|
||||
SCSH_CONST_SYS_ERRLIST
|
||||
CFLAGS1=${CFLAGS}
|
||||
|
||||
lib_dirs_list='("${prefix}/lib/scsh/modules" "${prefix}/lib/scsh/modules/0.6")'
|
||||
AC_ARG_WITH(lib-dirs-list,
|
||||
AC_HELP_STRING([--with-lib-dirs-list],
|
||||
[list of default scsh library directories (default ("$prefix/lib/scsh/modules" "${prefix}/lib/scsh/modules/0.6"))]),
|
||||
lib_dirs_list="$withval")
|
||||
|
||||
AC_SUBST(lib_dirs_list)
|
||||
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(LIBOBJS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_OUTPUT(Makefile)
|
||||
|
||||
|
||||
AC_SUBST(AIX_P)
|
||||
AC_SUBST(AR)
|
||||
AC_SUBST(CC)
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CFLAGS1)
|
||||
AC_SUBST(EXEEXT)
|
||||
AC_SUBST(ENDIAN)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_SUBST(LDFLAGS_AIX)
|
||||
AC_SUBST(LIBS)
|
||||
AC_SUBST(TMPDIR)
|
||||
|
||||
|
||||
AC_CONFIG_FILES(Makefile scsh/endian.scm scsh-config)
|
||||
AC_CONFIG_COMMANDS([scsh-config+x],[chmod +x scsh-config])
|
||||
AC_OUTPUT
|
||||
|
||||
|
|
|
|||
|
|
@ -1,309 +0,0 @@
|
|||
|
||||
Documentation for Big Scheme
|
||||
|
||||
|
||||
Big Scheme is a set of generally useful facilities.
|
||||
|
||||
Easiest way to access these things:
|
||||
|
||||
> ,open big-scheme
|
||||
Load structure big-scheme (y/n)? y
|
||||
...
|
||||
|
||||
A better way is to use the module system.
|
||||
|
||||
-----
|
||||
|
||||
Ascii conversions
|
||||
|
||||
(CHAR->ASCII <char>) => <integer>
|
||||
(ASCII->CHAR <integer>) => <char>
|
||||
These are identical to CHAR->INTEGER and INTEGER->CHAR except that
|
||||
they use the ASCII encoding.
|
||||
|
||||
-----
|
||||
|
||||
Bitwise operations
|
||||
|
||||
(BITWISE-NOT <integer>) => <integer>
|
||||
(BITWISE-AND <integer> <integer>) => <integer>
|
||||
(BITWISE-IOR <integer> <integer>) => <integer>
|
||||
(BITWISE-XOR <integer> <integer>) => <integer>
|
||||
These perform various logical operations on integers on a bit-by-bit
|
||||
basis, using a two's-complement representation.
|
||||
|
||||
(ARITHMETIC-SHIFT <integer> <bit-count>) => <integer>
|
||||
Shift the integer by the given bit count, shifting left for positive
|
||||
counts and right for negative ones. A two's complement
|
||||
representation is used.
|
||||
|
||||
-----
|
||||
|
||||
Hash tables
|
||||
|
||||
(MAKE-TABLE) => <table>
|
||||
(MAKE-STRING-TABLE) => <string-table>
|
||||
Make a new, empty table. MAKE-TABLE returns a table that uses EQ?
|
||||
for comparing keys and an ad-hoc hash function. String tables uses
|
||||
strings for keys.
|
||||
|
||||
(MAKE-TABLE-MAKER <comparison-procedure> <hash-procedure>) => <procedure>
|
||||
Returns a procedure of no arguments that makes tables that use the
|
||||
given comparison and hash procedures.
|
||||
(<comparison-procedure> <key1> <key2>) => <boolean>
|
||||
(<hash-procedure> <key>) => <non-negative-integer>
|
||||
|
||||
(TABLE? <x>) => <boolean>
|
||||
True if <x> is a table.
|
||||
|
||||
(TABLE-REF <table> <key>) => <x>
|
||||
Return the value for <key> in <table>, or #F if there is none.
|
||||
<key> should be of a type appropriate for <table>.
|
||||
|
||||
(TABLE-SET! <table> <key> <value>) => <undefined>
|
||||
Make <value> be the value of <key> in <table>. <key> should be of a
|
||||
type appropriate for <table>.
|
||||
|
||||
(TABLE-WALK <procedure> <table>) => <undefined>
|
||||
Apply <procedure>, which must accept two arguments, to every
|
||||
associated key and value in <table>.
|
||||
|
||||
-----
|
||||
|
||||
Enumerations
|
||||
|
||||
(DEFINE-ENUMERATION <type-name> (<name0> <name1> ...)) *SYNTAX*
|
||||
Defines <type-name> to be an enumeration with components <name0>
|
||||
<name1> .... Also defines <type-name>-COUNT to be the number of
|
||||
components.
|
||||
|
||||
(ENUM <type-name> <component-name>) => <integer> *SYNTAX*
|
||||
Evaluates to the value of <component-name> within the enumeration
|
||||
<type-name>. For example, if (DEFINE-ENUMERATION COLOR (GREEN
|
||||
RED)), then (ENUM COLOR GREEN) is zero and (ENUM COLOR RED) is one.
|
||||
The mapping from name to integer is done at macro-expansion time, so
|
||||
there is no run-time overhead.
|
||||
|
||||
(ENUMERAND->NAME <integer> <enumeration>) => <symbol>
|
||||
Returns the name associated with <integer> within <enumeration>.
|
||||
E.g. (ENUMERAND->NAME 1 COLOR) => 'RED.
|
||||
|
||||
(NAME->ENUMERAND <symbol> <enumeration>) => <integer>
|
||||
Returns the integer associated with <symbol> within <enumeration>.
|
||||
E.g. (ENUMERAND->NAME 'GREEN COLOR) => 0.
|
||||
|
||||
-----
|
||||
|
||||
Port extensions
|
||||
|
||||
(MAKE-TRACKING-INPUT-PORT <input-port>) => <input-port>
|
||||
(MAKE-TRACKING-OUTPUT-PORT <output-port>) => <output-port>
|
||||
These return ports that keep track of the current row and column and
|
||||
are otherwise identical to their arguments.
|
||||
|
||||
(MAKE-STRING-INPUT-PORT <string>) => <input-port>
|
||||
Returns a port that reads characters from the supplied string.
|
||||
|
||||
(CALL-WITH-STRING-OUTPUT-PORT <procedure>) => <string>
|
||||
The procedure is called on a port. When it returns, CALL-WITH-STRING-
|
||||
OUTPUT-PORT returns a string containing the characters written to the port.
|
||||
|
||||
(WRITE-ONE-LINE <output-port> <character-count> <procedure>) => <unspecified>
|
||||
The procedure is called on an output port. Output written to that
|
||||
port is copied to <output-port> until <character-count> characters
|
||||
have been written, at which point WRITE-ONE-LINE returns.
|
||||
|
||||
(CURRENT-ROW <port>) => <integer> or #f
|
||||
(CURRENT-COLUMN <port>) => <integer> or #f
|
||||
These return the current read or write location of the port. #F is
|
||||
returned if the port does not keep track of its location.
|
||||
|
||||
(FRESH-LINE <output-port>) => <undefined>
|
||||
Write a newline character to <output-port> if its current column is not 0.
|
||||
|
||||
(INPUT-PORT? <any>) => <boolean>
|
||||
(OUTPUT-PORT? <any>) => <boolean>
|
||||
These are versions of the standard Scheme predicates that answer true for
|
||||
extended ports.
|
||||
|
||||
-----
|
||||
|
||||
Queues
|
||||
|
||||
(MAKE-QUEUE) => <queue>
|
||||
Returns a new, empty queue.
|
||||
|
||||
(ENQUEUE! <queue> <x>) => <undefined>
|
||||
Puts <x> on the queue.
|
||||
|
||||
(DEQUEUE! <queue>) => <x>
|
||||
Removes and returns the first element of the queue.
|
||||
|
||||
(QUEUE-EMPTY? <queue>) => <boolean>
|
||||
True if the queue is empty.
|
||||
|
||||
(QUEUE? <x>) => <boolean>
|
||||
True if <x> is a queue.
|
||||
|
||||
(QUEUE->LIST <queue>) => <list>
|
||||
Returns a list of the elements of the queue, in order.
|
||||
|
||||
(QUEUE-LENGTH <queue>) => <integer>
|
||||
The number of elements currently on the queue.
|
||||
|
||||
(DELETE-FROM-QUEUE! <queue> <x>) => <boolean>
|
||||
Removes the first occurance of <x> from the queue, returning true if
|
||||
it was found and false otherwise.
|
||||
|
||||
-----
|
||||
|
||||
Little utility procedures
|
||||
|
||||
(ATOM? <any>) => <boolean>
|
||||
(ATOM? x) == (NOT (PAIR? x))
|
||||
|
||||
(NULL-LIST? <list>) => <boolean>
|
||||
Returns #t for the empty list, #f for a pair, and signals an error
|
||||
otherwise.
|
||||
|
||||
(NEQ? <any> <any>) => <boolean>
|
||||
(NEQ? x y) is the same as (NOT (EQ? x y)).
|
||||
|
||||
(N= <number> <number>) => <boolean>
|
||||
(N= x y) is the same as (NOT (= x y)).
|
||||
|
||||
(IDENTITY <any>) => <any>
|
||||
(NO-OP <any>) => <any>
|
||||
These both just return their argument. NO-OP is guaranteed not to
|
||||
be compiled in-line, IDENTITY may be.
|
||||
|
||||
-----
|
||||
|
||||
List utilities
|
||||
|
||||
(MEMQ? <element> <list>) => <boolean>
|
||||
Returns true if <element> is in <list>, false otherwise.
|
||||
|
||||
(ANY? <predicate> <list>) => <boolean>
|
||||
Returns true if <predicate> is true for any element of <list>.
|
||||
|
||||
(EVERY? <predicate> <list>) => <boolean>
|
||||
Returns true if <predicate> is true for every element of <list>.
|
||||
|
||||
(ANY <predicate> <list>)
|
||||
(FIRST <predicate> <list>)
|
||||
ANY returns some element of <list> for which <predicate> is true, or
|
||||
#F if there are none. FIRST does the same except that it returns
|
||||
the first element for which <predicate> is true.
|
||||
|
||||
(FILTER <predicate> <list>)
|
||||
(FILTER! <predicate> <list>)
|
||||
Returns a list containing all of the elements of <list> for which
|
||||
<predicate> is true. The order of the elements is preserved.
|
||||
FILTER! may reuse the storage of <list>.
|
||||
|
||||
(FILTER-MAP <procedure> <list>)
|
||||
The same as FILTER except the returned list contains the results of
|
||||
applying <procedure> instead of elements of <list>. (FILTER-MAP p
|
||||
l) is the same as (FILTER IDENTITY (MAP p l)).
|
||||
|
||||
(PARTITION-LIST <predicate> <list>) => <list> <list>
|
||||
(PARTITION-LIST! <predicate> <list>) => <list> <list>
|
||||
The first return value contains those elements <list> for which
|
||||
<predicate> is true, the second contains the remaining elements.
|
||||
The order of the elements is preserved. PARTITION-LIST! may resuse
|
||||
the storage of the <list>.
|
||||
|
||||
(REMOVE-DUPLICATES <list>) => <list>
|
||||
Returns its argument with all duplicate elements removed. The first
|
||||
instance of each element is preserved.
|
||||
|
||||
(DELQ <element> <list>) => <list>
|
||||
(DELQ! <element> <list>) => <list>
|
||||
(DELETE <predicate> <list>) => <list>
|
||||
All three of these return <list> with some elements removed. DELQ
|
||||
removes all elements EQ? to <element>. DELQ! does the same and may
|
||||
modify the list argument. DELETE removes all elements for which
|
||||
<predicate> is true. Both DELQ and DELETE may reuse some of the
|
||||
storage in the list argument, but won't modify it.
|
||||
|
||||
(REVERSE! <list>) => <list>
|
||||
Destructively reverses <list>.
|
||||
|
||||
(SORT-LIST <list> <a<b-procedure>) => <list>
|
||||
(SORT-LIST! <list> <a<b-procedure>) => <list>
|
||||
Returns a sorted copy of <list>. The sorting algorithm is stable.
|
||||
(SORT-LIST '(6 5 1 3 2 4) <) => '(1 2 3 4 5 6)
|
||||
|
||||
-----
|
||||
|
||||
Additional syntax
|
||||
|
||||
(DESTRUCTURE ((<pattern> <init>) ...) <body> ...) *SYNTAX*
|
||||
The <init>s are evaluated and their values are dissasembled
|
||||
according to the corresponding patterns, with identifiers in the
|
||||
patterns being bound to fresh locations holding the corresponding
|
||||
part, and the body is evaluated in the extended environment.
|
||||
Patterns may be any of the following:
|
||||
|
||||
#f Discard the corresponding part.
|
||||
<identifier> Bind the <indentifier> to the part.
|
||||
(<pattern> ...) The part must be a list at least as long as the
|
||||
pattern.
|
||||
(<pattern1> ... . <patternN>)
|
||||
The same thing, except that the final CDR of the
|
||||
part is dissasembled according to <patternN>.
|
||||
#(<pattern> ...) The part must be a vector at least as long as the
|
||||
pattern.
|
||||
|
||||
(RECEIVE <identifiers> <exp> <body> ...) *SYNTAX*
|
||||
=> (CALL-WITH-VALUES (LAMBDA () <exp>) (LAMBDA <identifiers> <body> ...))
|
||||
Bind <identifiers> to the values returned by <exp>, and evaluate the
|
||||
body in the resulting environment.
|
||||
|
||||
-----
|
||||
|
||||
Printing and related procedures
|
||||
|
||||
(CONCATENATE-SYMBOL . <components>)
|
||||
Returns the symbol whose name is produced by concatenating the DISPLAYed
|
||||
representations of <components>.
|
||||
(CONCATENATE-SYMBOL 'abc "-" 4) => 'abc-4
|
||||
|
||||
(FORMAT <port-spec> <format-string> . <arguments>) => <string> or <undefined>
|
||||
Prints the arguments to the port as directed by the string. <port-spec>
|
||||
should be either:
|
||||
An output port. The output is written directly to the port. The result
|
||||
of the call to FORMAT is undefined.
|
||||
#T. The output is written to the current output port. The result of the
|
||||
call to FORMAT is undefined.
|
||||
#F. The output is written to a string, which is then the value returned
|
||||
from the call to FORMAT.
|
||||
Characters in <format-string> which are not preceded by a ~ are written
|
||||
directly to the output. Characters preceded by a ~ have the following
|
||||
meaning (case is irrelevant; ~a and ~A have the same meaning):
|
||||
~~ prints a single ~
|
||||
~A prints the next argument using DISPLAY
|
||||
~D prints the next argument as a decimal number
|
||||
~S prints the next argument using WRITE
|
||||
~% prints a newline character
|
||||
~& prints a NEWLINE character if the previous printed character was not one
|
||||
(this is implemented using FRESH-LINE)
|
||||
~? performs a recursive call to FORMAT using the next two arguments as the
|
||||
string and the list of arguments
|
||||
|
||||
(ERROR <format-string> . <format-arguments>)
|
||||
(BREAKPOINT <format-string> . <format-arguments>)
|
||||
Signals an error or breakpoint condition, passing it the result of
|
||||
applying FORMAT to the arguments.
|
||||
|
||||
(P <thing>)
|
||||
(P <thing> <output-port>)
|
||||
(PRETTY-PRINT <thing> <output-port> <position>)
|
||||
Pretty-print <thing>. The current output port is used if no port is
|
||||
specified. <position> is the starting offset. <thing> will be
|
||||
pretty-printed to the right of this column.
|
||||
|
||||
|
||||
Original by RK, 26 Jan 1993.
|
||||
Minor changes by JAR, 5 Dec 1993.
|
||||
|
|
@ -0,0 +1,740 @@
|
|||
Scsh cheat sheet
|
||||
Olin Shivers
|
||||
November 1996
|
||||
|
||||
This cheat sheet is intentionally kept brief and minimalist.
|
||||
It is intended to function as an ASCII-format reminder for the
|
||||
full manual, not as the definition. It can be read using GNU Emacs's
|
||||
outline mode.
|
||||
|
||||
It is also not entirely up-to-date. I'd appreciate getting updates from users.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* High-level forms
|
||||
|
||||
Extended process form:
|
||||
(PF [REDIR1 ...])
|
||||
|
||||
Redirection:
|
||||
(< [FDES] FILE-NAME)
|
||||
(> [FDES] FILE-NAME)
|
||||
(<< [FDES] OBJECT)
|
||||
(= FDES FDES/PORT)
|
||||
(- FDES/PORT)
|
||||
stdports
|
||||
Subforms are implicitly backquoted.
|
||||
|
||||
Process form:
|
||||
(| PF1 ...) ; pipeline
|
||||
(|+ CONNECT-LIST PF1 ...) ; complex pipeline
|
||||
(begin . BODY) ; Scheme form
|
||||
(epf . EPF) ; Embedded extended process form
|
||||
(PROG ARG1 ... ARGn) ; Exec a program
|
||||
Subforms are implicitly backquoted.
|
||||
|
||||
Using process forms in Scheme:
|
||||
(exec-epf . EPF) ; Nuke the current process.
|
||||
(& . EPF) ; Fork process in background. Return proc object.
|
||||
(run . EPF) ; Run process. Return exit code.
|
||||
|
||||
(& . EPF) = (fork (lambda () (exec-epf . EPF)))
|
||||
(run . EPF) = (wait (& . EPF))
|
||||
|
||||
Interfacing to subprocess I/O:
|
||||
(run/port . EPF) -> port
|
||||
(run/file . EPF) -> string
|
||||
(run/string . EPF) -> string
|
||||
(run/strings . EPF) -> string list
|
||||
(run/sexp . EPF) -> object
|
||||
(run/sexps . EPF) -> list
|
||||
|
||||
There are procedural equivalents for each of these, e.g., run/port* and
|
||||
run/file*, that take thunk arguments for the subprocess.
|
||||
|
||||
(port->string PORT) -> string
|
||||
Read until EOF on PORT, return data as a string.
|
||||
|
||||
(port->string-list PORT) -> string list
|
||||
Repeatedly apply READ-LINE to PORT until EOF. Return list of lines read.
|
||||
|
||||
(port->sexp-list PORT) -> list
|
||||
Repeatedly apply READ to PORT until EOF. Return list of items read.
|
||||
|
||||
(port->list READER PORT)
|
||||
Repeatedly apply READER to PORT until EOF. Return list of items read.
|
||||
|
||||
(reduce-port PORT READER OP . SEEDS)
|
||||
Evaluate (OP (READER PORT) . SEEDS) to get a new set of seeds
|
||||
(OP must return as many values as there are SEEDS). When
|
||||
a port read returns EOF, the current set of seed values are
|
||||
returned as multiple values.
|
||||
|
||||
(run/port+proc . EPF) -> [port proc]
|
||||
(run/port+proc* THUNK) -> [port proc]
|
||||
|
||||
(run/collecting FDS . EPF) -> [port ...]
|
||||
(run/collecting* FDS THUNK) -> [port ...]
|
||||
RUN/COLLECTING implicitly backquotes FDS.
|
||||
|
||||
(|| PF1 ... PFn)
|
||||
(&& PF1 ... PFn)
|
||||
Conditionally execute processes.
|
||||
|
||||
(char-filter filter) -> procedure
|
||||
(string-filter filter [buflen]) -> procedure
|
||||
|
||||
* System calls
|
||||
|
||||
** Errors
|
||||
|
||||
(errno-error errno SYSCALL . DATA)
|
||||
(with-errno-handler* HANDLER THUNK) -> value of thunk
|
||||
HANDLER is called on two arguments: (HANDLER ERRNO PACKET)
|
||||
where PACKET is a list of the form (ERRNO-MSG SYSCALL . DATA)
|
||||
If HANDLER returns at all, the handler search continues upwards.
|
||||
|
||||
(with-errno-handler HANDLER-SPEC . BODY)
|
||||
HANDLER-SPEC is of the form
|
||||
((ERRNO PACKET) CLAUSE ...)
|
||||
ERRNO and PACKET are variables bound to the errno error being raised.
|
||||
There are two forms for handler clauses:
|
||||
((ERRNO ...) . BODY)
|
||||
(else . BODY)
|
||||
ERRNO are expressions evaluating to errno integers.
|
||||
|
||||
** I/O
|
||||
*** Port Manipulation
|
||||
(close-after PORT CONSUMER) -> value(s) of consumer
|
||||
(error-output-port) -> port
|
||||
|
||||
(with-current-input-port port . body) -> value(s) of body
|
||||
(with-current-output-port port . body) -> value(s) of body
|
||||
(with-error-output-port port . body) -> value(s) of body
|
||||
|
||||
(with-current-input-port* port thunk) -> value(s) of thunk
|
||||
(with-current-output-port* port thunk) -> value(s) of thunk
|
||||
(with-error-output-port* port thunk) -> value(s) of thunk
|
||||
|
||||
(close fd/port)
|
||||
|
||||
(stdports->stdio)
|
||||
(stdio->stdports)
|
||||
|
||||
(with-stdio-ports* thunk) -> value(s) of thunk
|
||||
(with-stdio-ports . body) -> value(s) of body
|
||||
|
||||
(make-string-input-port) -> port
|
||||
(string-output-port-output port) -> port
|
||||
(call-with-string-output-port proc) -> str
|
||||
|
||||
** Port and file descriptors
|
||||
(fdes->inport fd) -> port
|
||||
(fdes->outport fd) -> port
|
||||
(port->fdes port) -> fixnum
|
||||
Increment port's revealed count.
|
||||
|
||||
(port-revealed port) -> integer or #f
|
||||
(release-port-handle port)
|
||||
(call/fdes fd/port consumer) -> value(s) of consumer
|
||||
|
||||
(move->fdes fd/port target-fd) -> port or fdes
|
||||
|
||||
** Unix I/O
|
||||
|
||||
(dup fd/port [newfd]) -> fd/port
|
||||
(dup->inport fd/port [newfd]) -> port
|
||||
(dup->outport fd/port [newfd]) -> port
|
||||
(dup->fdes fd/port [newfd]) -> fd
|
||||
|
||||
(file-seek fd/port offset whence)
|
||||
|
||||
(open-file fname flags [perms]) -> port
|
||||
(open-input-file fname [flags]) -> port
|
||||
(open-output-file fname [flags perms]) -> port
|
||||
(open-fdes fname flags [perms]) -> integer
|
||||
|
||||
(fdes-flags fd/port)
|
||||
(set-fdes-flags fd/port flags)
|
||||
Only Posix flag defined is FDFLAGS/CLOSE-ON-EXEC, which you should
|
||||
not ever have to use -- scsh manages this automatically.
|
||||
|
||||
(fdes-status fd/port)
|
||||
(set-fdes-flags fd/port flags)
|
||||
|
||||
Operations allowed Flags
|
||||
------------------ -----
|
||||
Open+get+set open/append, open/non-blocking
|
||||
open/async, open/fsync (non-Posix)
|
||||
|
||||
Open+get open/read, open/write, open/read+write
|
||||
open/access-mask
|
||||
|
||||
Open only open/create, open/exclusive,
|
||||
open/no-control-tty, open/truncate
|
||||
|
||||
(pipe) -> [rport wport]
|
||||
(read-line [fd/port retain-newline?]) -> string or eof-object
|
||||
|
||||
(read-string nbytes [fd/port]) -> string or #f
|
||||
(read-string! str [fd/port start end]) -> [nread or #f]
|
||||
(read-string/partial nbytes [fd/port]) -> string or #f
|
||||
(read-string!/partial str [fd/port start end]) -> [nread or #f]
|
||||
|
||||
(write-string string [fd/port start end])
|
||||
(write-string/partial string [fd/port start end]) -> nwritten
|
||||
(force-output [fd/port])
|
||||
|
||||
** File locking
|
||||
(define-record lock-region
|
||||
exclusive? ; write or read lock?
|
||||
start ; integer: start, end & whence
|
||||
end ; integer: define the region being locked.
|
||||
whence ; The value of SEEK/SET, SEEK/DELTA, or SEEK/END.
|
||||
proc) ; A proc object for the process locking the region.
|
||||
|
||||
(make-lock-region exclusive? start len [whence]) -> lock-region
|
||||
WHENCE defaults to the value of SEEK/SET.
|
||||
|
||||
(lock-region fdes lock)
|
||||
(lock-region/no-block fdes lock)
|
||||
|
||||
(get-lock-region fdes lock) -> lock-region or #f
|
||||
|
||||
(unlock-region fdes lock)
|
||||
|
||||
(with-region-lock* fdes lock thunk)
|
||||
(with-region-lock fdes lock body ...) Syntax
|
||||
|
||||
** File system
|
||||
(create-directory fname [perms override?])
|
||||
(create-fifo fname [perms override?])
|
||||
(create-hard-link oldname newname [override?])
|
||||
OVERRIDE? one of {#f, QUERY, other true value}
|
||||
|
||||
(delete-directory fname)
|
||||
(delete-file fname)
|
||||
(delete-filesys-object fname)
|
||||
|
||||
(read-symlink fname) -> string
|
||||
|
||||
(rename-file old-fname new-fname [override?])
|
||||
|
||||
(set-file-mode fname/fd/port mode)
|
||||
(set-file-owner fname/fd/port uid)
|
||||
(set-file-group fname/fd/port gid)
|
||||
|
||||
(sync-file fd/port)
|
||||
(sync-file-system)
|
||||
|
||||
(truncate-file fname/fd/port len)
|
||||
|
||||
(file-attributes fname/fd/port [chase?]) -> file-info
|
||||
|
||||
(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 permission bits.
|
||||
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.
|
||||
|
||||
Derived procedures:
|
||||
file-type type
|
||||
file-inode inode
|
||||
file-mode mode
|
||||
file-nlinks nlinks
|
||||
file-owner uid
|
||||
file-group gid
|
||||
file-size size
|
||||
file-last-access atime
|
||||
file-last-mod mtime
|
||||
file-last-status-change ctime
|
||||
|
||||
(file-not-readable? fname) -> boolean
|
||||
(file-not-writable? fname) -> boolean
|
||||
(file-not-executable? fname) -> boolean
|
||||
|
||||
Returns one of
|
||||
#f Access permitted
|
||||
SEARCH-DENIED Can't stat---a protected directory
|
||||
is blocking access.
|
||||
PERMISSION Permission denied.
|
||||
NO-DIRECTORY Some directory doesn't exist.
|
||||
NONEXISTENT File doesn't exist.
|
||||
|
||||
(file-readable? fname) -> boolean
|
||||
(file-writable? fname) -> boolean
|
||||
(file-executable? fname) -> boolean
|
||||
|
||||
(file-not-exists? fname [chase?]) -> boolean
|
||||
#f Exists.
|
||||
SEARCH-DENIED Some protected directory
|
||||
is blocking the search.
|
||||
#t Doesn't exist.
|
||||
|
||||
(file-exists? fname [chase?]) -> boolean
|
||||
|
||||
(directory-files [dir dotfiles?]) -> string list
|
||||
(glob pat1 ...) -> string list
|
||||
(glob-quote string) -> string
|
||||
(file-match root dot-files? pat1 ...) -> string list
|
||||
|
||||
(create-temp-file [prefix]) -> string
|
||||
(temp-file-iterate maker [template]) -> [object ...]
|
||||
TEMPLATE defaults to the value of *TEMP-FILE-TEMPLATE*.
|
||||
|
||||
(temp-file-channel) -> [inport outport]
|
||||
|
||||
** Processes
|
||||
(exec prog arg1 ...)
|
||||
(exec-path prog arg1 ...)
|
||||
(exec/env prog env arg1 ...)
|
||||
(exec-path/env prog env arg1 ...)
|
||||
|
||||
(%exec prog arglist env)
|
||||
(exec-path-search fname pathlist) -> string
|
||||
|
||||
(exit [status])
|
||||
(%exit [status])
|
||||
|
||||
(suspend)
|
||||
|
||||
(fork [thunk]) -> proc or #d
|
||||
(%fork [thunk]) -> proc or #f
|
||||
|
||||
(fork/pipe [thunk]) -> proc or #f
|
||||
(%fork/pipe [thunk]) -> proc or #f
|
||||
|
||||
(fork/pipe+ conns [thunk]) proc or #f
|
||||
(%fork/pipe+ conns [thunk]) proc or #f
|
||||
|
||||
(wait proc/pid [flags]) -> status [proc]
|
||||
|
||||
(call-terminally thunk)
|
||||
|
||||
** Process state
|
||||
|
||||
(umask) -> fixnum
|
||||
(set-umask perms)
|
||||
(with-umask* perms thunk) -> values of thunk
|
||||
(with-umask perms . body) -> values of body
|
||||
|
||||
(chdir [fname])
|
||||
(cwd) -> string
|
||||
(with-cwd* fname thunk) -> value(s) of thunk
|
||||
(with-cwd fname . body) -> value(s) of body
|
||||
|
||||
(pid) -> fixnum
|
||||
(parent-pid) -> fixnum
|
||||
(process-group) -> fixnum
|
||||
(set-process-group [proc/pid] pgrp)
|
||||
|
||||
(user-login-name) -> string
|
||||
(user-uid) -> fixnum
|
||||
(user-effective-uid) -> fixnum
|
||||
(user-gid) -> fixnum
|
||||
(user-effective-gid) -> fixnum
|
||||
(user-supplementary-gids) -> fixnum list
|
||||
(set-uid uid)
|
||||
(set-gid gid)
|
||||
|
||||
(process-times) -> [ucpu scpu uchildren schildren]
|
||||
|
||||
** User and group db access
|
||||
|
||||
(user-info uid-or-name) -> user-info
|
||||
|
||||
(define-record user-info
|
||||
name
|
||||
uid
|
||||
gid
|
||||
home-dir
|
||||
shell)
|
||||
|
||||
(->uid uid/name) -> fixnum
|
||||
(->username uid/name) -> string
|
||||
|
||||
(group-info gid-or-name) -> record
|
||||
|
||||
(define-record group-info
|
||||
name
|
||||
gid
|
||||
members) ; List of uids
|
||||
|
||||
(->gid gid/name) -> fixnum
|
||||
(->group gid/name) -> string
|
||||
|
||||
** Accessing command-line arguments
|
||||
|
||||
command-line-arguments
|
||||
Does not include program name
|
||||
|
||||
(command-line) -> string list
|
||||
Includes program name in list.
|
||||
|
||||
(arg arglist n [default]) -> string
|
||||
(arg* arglist n [default-thunk]) -> string
|
||||
(argv n [default]) -> string
|
||||
ARG is 1-based access to ARGLIST
|
||||
ARGV is 0-based access to prog + args
|
||||
|
||||
** System parameters
|
||||
|
||||
(system-name) -> string
|
||||
|
||||
** Signal system
|
||||
|
||||
(signal-process proc/pid sig)
|
||||
(signal-procgroup prgrp sig)
|
||||
(pause-until-interrupt)
|
||||
(sleep secs)
|
||||
|
||||
Non-signal S48 interrupts
|
||||
-------------------------
|
||||
interrupt/memory-shortage
|
||||
|
||||
Posix signals with S48 interrupts
|
||||
------------------------------
|
||||
signal/alrm interrupt/alrm (aka interrupt/alarm)
|
||||
signal/int interrupt/int (aka interrupt/int)
|
||||
signal/chld interrupt/chld
|
||||
signal/cont interrupt/cont
|
||||
signal/hup interrupt/hup
|
||||
signal/quit interrupt/quit
|
||||
signal/term interrupt/term
|
||||
signal/tstp interrupt/tstp
|
||||
signal/usr1 interrupt/usr1
|
||||
signal/usr2 interrupt/usr2
|
||||
|
||||
signal/info interrupt/info Non-Posix
|
||||
signal/io interrupt/io Non-Posix
|
||||
signal/poll interrupt/poll Non-Posix
|
||||
signal/prof interrupt/prof Non-Posix
|
||||
signal/pwr interrupt/pwr Non-Posix
|
||||
signal/urg interrupt/urg Non-Posix
|
||||
signal/vtalrm interrupt/vtalrm Non-Posix
|
||||
signal/winch interrupt/winch Non-Posix
|
||||
signal/xcpu interrupt/xcpu Non-Posix
|
||||
signal/xfsz interrupt/xfsz Non-Posix
|
||||
|
||||
Synchronous and uncatchable signals
|
||||
-----------------------------------
|
||||
signal/stop Uncatchable Posix
|
||||
signal/kill Uncatchable Posix
|
||||
|
||||
signal/abrt Synchronous Posix
|
||||
signal/fpe Synchronous Posix
|
||||
signal/ill Synchronous Posix
|
||||
signal/pipe Synchronous Posix
|
||||
signal/segv Synchronous Posix
|
||||
signal/ttin Synchronous Posix
|
||||
signal/ttou Synchronous Posix
|
||||
|
||||
signal/bus Synchronous BSD + SVR4
|
||||
signal/emt Synchronous BSD + SVR4
|
||||
signal/iot Synchronous BSD + SVR4
|
||||
signal/sys Synchronous BSD + SVR4
|
||||
signal/trap Synchronous BSD + SVR4
|
||||
|
||||
** Interrupt handlers
|
||||
(signal->interrupt sig) -> interrupt
|
||||
(interrupt-set integer1 ...) -> integer
|
||||
|
||||
(enabled-interrupts) -> integer
|
||||
(set-enabled-interrupts! integer) -> integer
|
||||
|
||||
(with-enabled-interrupts interrupt-set body ...) Syntax
|
||||
(with-enabled-interrupts* interrupt-set thunk)
|
||||
|
||||
(set-interrupt-handler! interrupt handler) -> old-handler
|
||||
(interrupt-handler interrupt) -> handler
|
||||
HANDLER is #f (ignored), #t (default), or (lambda (enabled-ints) ...) proc.
|
||||
|
||||
** Time
|
||||
|
||||
(define-record date
|
||||
seconds minute hour month-day month year
|
||||
tz-name tz-secs summer?
|
||||
week-day year-day)
|
||||
|
||||
(make-date sec min hour mday month year [tz-name tz-secs summer? wday yday])
|
||||
|
||||
(time+ticks)
|
||||
(ticks/sec)
|
||||
|
||||
(date [time tz])
|
||||
(time [date])
|
||||
|
||||
(date->string date)
|
||||
(format-date fmt date)
|
||||
|
||||
** Environment variables
|
||||
|
||||
(setenv var val)
|
||||
(getenv var) -> string
|
||||
|
||||
(env->alist) -> string->string alist
|
||||
(alist->env alist)
|
||||
|
||||
(alist-delete key alist) -> alist
|
||||
(alist-update key val alist) -> alist
|
||||
(alist-compress alist) -> alist
|
||||
|
||||
(with-env* env-alist-delta thunk) -> value(s) of thunk
|
||||
(with-total-env* env-alist thunk) -> value(s) of thunk
|
||||
|
||||
(with-env env-alist-delta . body) -> value(s) of body
|
||||
(with-total-env env-alist . body) -> value(s) of body
|
||||
|
||||
(add-before elt before list) -> list
|
||||
(add-after elt after list) -> list
|
||||
|
||||
** $USER $HOME, and $PATH
|
||||
|
||||
home-directory
|
||||
exec-path-list
|
||||
|
||||
* Networking
|
||||
|
||||
** High Level Socket Routines
|
||||
|
||||
*** clients
|
||||
(socket-connect protocol-family/internet socket-type name port) -> socket
|
||||
(socket-connect protocol-family/unix socket-type pathname) -> socket
|
||||
|
||||
*** server
|
||||
(bind-listen-accept-loop protocol-family/internet proc port) -> does-not-return
|
||||
(bind-listen-accept-loop protocol-family/unix proc pathname) -> does-not-return
|
||||
|
||||
proc is a procedure of two arguments: a socket and a socket-address
|
||||
|
||||
** Sockets
|
||||
(create-socket protocol-family type [protocol]) -> socket
|
||||
(create-socket-pair type) -> [socket1 socket2]
|
||||
(close-socket socket) -> undefined
|
||||
|
||||
protocol-family/unix
|
||||
protocol-family/internet
|
||||
|
||||
socket-type/stream
|
||||
socket-type/datagram
|
||||
|
||||
for protocol see protocol-info
|
||||
|
||||
(define-record socket family inport outport)
|
||||
|
||||
** Socket Addresses
|
||||
(define-record socket-address family)
|
||||
|
||||
(unix-address->socket-address pathname) -> socket-address
|
||||
(internet-address->socket-address host-address service-port)-> socket-address
|
||||
|
||||
internet-address/any
|
||||
internet-address/loopback
|
||||
internet-address/broadcast
|
||||
|
||||
(socket-address->unix-address socket-address) -> pathname
|
||||
(socket-address->internet-address socket-address) ->
|
||||
[host-address service-port]
|
||||
|
||||
** Low Level Socket Routines
|
||||
|
||||
(connect-socket socket socket-address) -> undefined
|
||||
(bind-socket socket socket-address) -> undefined
|
||||
(listen-socket socket backlog) -> undefined
|
||||
(accept-connection socket) -> [new-socket socket-address]
|
||||
|
||||
(socket-local-address socket) -> socket-address
|
||||
(socket-remote-address socket) -> socket-address
|
||||
|
||||
(shutdown-socket socket how-to) -> undefined
|
||||
how-to:
|
||||
shutdown/receives
|
||||
shutdown/sends
|
||||
shutdown/sends+receives
|
||||
|
||||
** Socket Specific I/O
|
||||
see read-string/write-string for info on arguments
|
||||
|
||||
(receive-message socket length [flags]) ->
|
||||
[string-or-#f socket-address]
|
||||
(receive-message! socket string [start] [end] [flags]) ->
|
||||
[count-or-#f socket-address]
|
||||
(receive-message/partial socket length [flags]) ->
|
||||
[string-or-#f socket-address]
|
||||
(receive-message!/partial socket string [start] [end] [flags]) ->
|
||||
[count-or-#f socket-address]
|
||||
|
||||
(send-message socket string [start] [end] [flags] [socket-address] ->
|
||||
undefined
|
||||
(send-message/partial socket string [start] [end] [flags] [socket-address]) ->
|
||||
count
|
||||
|
||||
** Socket Options
|
||||
(socket-option socket level option) -> value
|
||||
(set-socket-option socket level option value) -> undefined
|
||||
|
||||
boolean:
|
||||
socket/debug
|
||||
socket/accept-connect
|
||||
socket/reuse-address
|
||||
socket/keep-alive
|
||||
socket/dont-route
|
||||
socket/broadcast
|
||||
socket/use-loop-back
|
||||
socket/oob-inline
|
||||
socket/use-privileged
|
||||
socket/cant-signal
|
||||
tcp/no-delay
|
||||
|
||||
value:
|
||||
socket/send-buffer
|
||||
socket/receive-buffer
|
||||
socket/send-low-water
|
||||
socket/receive-low-water
|
||||
socket/error
|
||||
socket/type
|
||||
ip/time-to-live
|
||||
tcp/max-segment
|
||||
|
||||
socket/linger is #f or integer seconds
|
||||
|
||||
real number with microsecond resolution:
|
||||
socket/send-timeout
|
||||
socket/receive-timeout
|
||||
|
||||
|
||||
** Database-information entries
|
||||
|
||||
(host-info name-or-socket-address) -> host-info
|
||||
(network-info name-or-socket-address) -> network-info
|
||||
(service-info name-or-number [protocol-name]) -> service-info
|
||||
(protocol-info name-or-number) -> protocol-info
|
||||
|
||||
(define-record host-info name aliases addresses)
|
||||
(define-record network-info name aliases net)
|
||||
(define-record service-info name aliases port protocol)
|
||||
(define-record protocol-info name aliases number)
|
||||
|
||||
* String manipulation
|
||||
|
||||
** Regular expressions
|
||||
|
||||
(string-match regexp string [start]) -> match or false
|
||||
(regexp-match? obj) -> boolean
|
||||
(match:start match [match-number]) -> fixnum
|
||||
(match:end match [match-number]) -> fixnum
|
||||
(match:substring match [match-number]) -> string
|
||||
(make-regexp str) -> re
|
||||
(regexp? obj) -> boolean
|
||||
(regexp-exec regexp str [start]) -> match or false
|
||||
(regexp-quote str) -> string
|
||||
|
||||
** Other string manipulation facilities
|
||||
|
||||
(index string char [start]) -> fixnum or false
|
||||
(rindex string char [start]) -> fixnum or false
|
||||
|
||||
(substitute-env-vars fname) -> string
|
||||
|
||||
** Manipulating file-names
|
||||
|
||||
** Record I/O and field parsing
|
||||
|
||||
(read-delimited char-set [port]) -> string or eof
|
||||
(read-delimited! char-set buf [port start end]) -> nchars or #f or eof
|
||||
|
||||
((record-reader [delims elide-delims? handle-delim]) [port]) -> string or eof
|
||||
HANDLE-DELIM one of {trim, split, concat}
|
||||
|
||||
(read-paragraph [port delimiter?])
|
||||
|
||||
** Parsing fields
|
||||
|
||||
(field-splitter [regexp num-fields]) -> parser
|
||||
(infix-splitter [delim num-fields handle-delim]) -> parser
|
||||
(suffix-splitter [delim num-fields handle-delim]) -> parser
|
||||
(sloppy-suffix-splitter [delim num-fields handle-delim]) -> parser
|
||||
Where (parser string [start])
|
||||
HANDLE-DELIM one of {trim, concat, split}
|
||||
|
||||
(join-strings strings [delimiter grammar])
|
||||
GRAMMAR one of {infix, suffix}
|
||||
|
||||
** Field readers
|
||||
|
||||
(field-reader [field-parser record-reader])
|
||||
|
||||
* Awk
|
||||
|
||||
(awk <reader-exp> <rec&field-vars> [<rec-counter>] <state-var-inits>
|
||||
<clause>
|
||||
.
|
||||
.
|
||||
)
|
||||
|
||||
* Miscellaneous routines
|
||||
|
||||
** Integer bitwise ops
|
||||
|
||||
(arithmetic-shift i j) -> integer
|
||||
(bitwise-and i j) -> integer
|
||||
(bitwise-ior i j) -> integer
|
||||
(bitwise-not i) -> integer
|
||||
(bitwise-xor i j) -> integer
|
||||
|
||||
** ASCII encoding
|
||||
|
||||
(char->ascii \character) -> integer
|
||||
(ascii->char \integer) -> character
|
||||
|
||||
** Top level
|
||||
|
||||
(repl)
|
||||
|
||||
* Running scsh
|
||||
|
||||
scsh [meta-arg] [switch1 ...] [end-option arg1 ...]
|
||||
meta-arg: \ <script-file-name>
|
||||
|
||||
switch: -e <entry-point> Top-level entry point
|
||||
-o <structure> Open structure in current package.
|
||||
-m <structure> Switch to package.
|
||||
-n <new-package> Switch to new package.
|
||||
|
||||
-lm <module> <file-name> Load module into config package.
|
||||
-l <file-name> Load file into current package.
|
||||
-dm Do script module.
|
||||
-ds Do script.
|
||||
|
||||
end-option: -s <script> Specifies script to load.
|
||||
-sfd <num> Script from file descriptor <num>.
|
||||
-c <expression> Eval <expression> and exit.
|
||||
--
|
||||
|
||||
scshvm [meta-arg] [vm-options] [end-option arg1 ...]
|
||||
meta-arg: \ <fname>
|
||||
|
||||
vm-options: -h heap-size
|
||||
-s stack-size
|
||||
-o object-file
|
||||
|
||||
end-option: -i image-file
|
||||
--
|
||||
(dump-scsh-program main fname)
|
||||
|
||||
** File locations
|
||||
/usr/local/bin/scsh
|
||||
|
||||
/usr/local/lib/scsh/
|
||||
scshvm
|
||||
scsh
|
||||
scsh.image
|
||||
doc/
|
||||
|
||||
4430
doc/external.ps
4430
doc/external.ps
File diff suppressed because it is too large
Load Diff
|
|
@ -1,690 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<!-- HTML file produced from file: external.tex --
|
||||
-- using Hyperlatex v 2.3.1 (c) Otfried Cheong--
|
||||
-- on Emacs 19.34.1, Tue Feb 23 18:21:44 1999 -->
|
||||
<HEAD>
|
||||
<TITLE>Mixing Scheme 48 and C</TITLE>
|
||||
|
||||
</HEAD><BODY>
|
||||
|
||||
|
||||
<H1 ALIGN=CENTER>Using C code with Scheme 48</H1>
|
||||
<H2 ALIGN=CENTER>Mike Sperber<BR><TT><FONT SIZE=-1>sperber@informatik.uni-tuebingen.de</FONT></TT><BR>Richard Kelsey<BR><TT><FONT SIZE=-1>kelsey@research.nj.nec.com</FONT></TT>
|
||||
</H2>
|
||||
<H3 ALIGN=CENTER>February 23, 1999</H3>
|
||||
<H3 ALIGN=CENTER>Abstract</H3>
|
||||
<BLOCKQUOTE>
|
||||
This document describes an interface for calling C functions
|
||||
from Scheme, calling Scheme functions from C, and allocating
|
||||
storage in the Scheme heap.
|
||||
These facilities are designed to link
|
||||
existing C libraries into Scheme 48 in order to use them from Scheme.
|
||||
To this end, Scheme 48 manages stub functions in C that
|
||||
negotiate between the calling conventions of Scheme and C and the
|
||||
memory allocation policies of both worlds.
|
||||
No stub generator is available yet, but writing them is a straightforward task.
|
||||
</BLOCKQUOTE>
|
||||
<H1><A NAME="1">Available Facilities</A></H1>
|
||||
|
||||
<P>The following facilities are available for interfacing between
|
||||
Scheme 48 and C:
|
||||
<UL><LI>Scheme code can call C functions.
|
||||
<LI>The external interface provides full introspection for all
|
||||
Scheme objects. External code may inspect, modify, and allocate
|
||||
Scheme objects arbitrarily.
|
||||
<LI>External code may raise exceptions back to Scheme 48 to
|
||||
signal errors.
|
||||
<LI>External code may call back into Scheme. Scheme 48
|
||||
correctly unrolls the process stack on non-local exits.
|
||||
<LI>External modules may register bindings of names to values with a
|
||||
central registry accessible from
|
||||
Scheme. Conversely, Scheme code can register shared
|
||||
bindings for access by C code.
|
||||
</UL>
|
||||
This document has three parts: the first describes how bindings are
|
||||
moved from Scheme to C and vice versa, the second tells how to call
|
||||
C functions from Scheme, and the third covers the C interface
|
||||
to Scheme objects, including calling Scheme procedures, using the
|
||||
Scheme heap, and so forth.
|
||||
<H2><A NAME="2">Scheme structures</A></H2>
|
||||
<P>The structure <CODE>external-calls</CODE> has
|
||||
most of the Scheme functions described here.
|
||||
The others are in
|
||||
<CODE>dynamic-externals</CODE>, which has the functions for dynamic loading and
|
||||
name lookup from
|
||||
|
||||
the section on <A HREF="#dynamic-externals">Dynamic Loading</A>,
|
||||
and <CODE>shared-bindings</CODE>, which has the additional shared-binding functions
|
||||
described in
|
||||
|
||||
the section on the <A HREF="#more-shared-bindings">complete shared-binding interface</A>.
|
||||
<H2><A NAME="3">C naming conventions</A></H2>
|
||||
<P>The names of all of Scheme 48's visible C bindings begin
|
||||
with `<CODE>s48_</CODE>' (for procedures and variables) or
|
||||
`<CODE>S48_</CODE>' (for macros).
|
||||
Whenever a C name is derived from a Scheme identifier, we
|
||||
replace `<CODE>-</CODE>' with `<CODE>_</CODE>' and convert letters to lowercase
|
||||
for procedures and uppercase for macros.
|
||||
A final `<CODE>?</CODE>' converted to `<CODE>_p</CODE>' (`<CODE>_P</CODE>' in C macro names).
|
||||
A final `<CODE>!</CODE>' is dropped.
|
||||
Thus the C macro for Scheme's <CODE>pair?</CODE> is <CODE>S48_PAIR_P</CODE> and
|
||||
the one for <CODE>set-car!</CODE> is <CODE>S48_SET_CAR</CODE>.
|
||||
Procedures and macros that do not check the types of their arguments
|
||||
have `<CODE>unsafe</CODE>' in their names.
|
||||
<P>All of the C functions and macros described have prototypes or definitions
|
||||
in the file <CODE>c/scheme48.h</CODE>.
|
||||
The C type for Scheme values is defined there to be <CODE>s48_value</CODE>.
|
||||
<H1><A NAME="4">Shared bindings</A></H1>
|
||||
|
||||
<P>Shared bindings are the means by which named values are shared between Scheme
|
||||
code and C code.
|
||||
There are two separate tables of shared bindings, one for values defined in
|
||||
Scheme and accessed from C and the other for values going the other way.
|
||||
Shared bindings actually bind names to cells, to allow a name to be looked
|
||||
up before it has been assigned.
|
||||
This is necessary because C initialization code may be run before or after
|
||||
the corresponding Scheme code, depending on whether the Scheme code is in
|
||||
the resumed image or is run in the current session.
|
||||
<H2><A NAME="5">Exporting Scheme values to C</A></H2>
|
||||
<UL><LI><CODE>(define-exported-binding<I> name value</I>) -> <I>shared-binding</I></CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>s48_value s48_get_imported_binding(char *name)</CODE>
|
||||
<LI><CODE>s48_value S48_SHARED_BINDING_REF(s48_value shared_binding)</CODE>
|
||||
</UL>
|
||||
<P><CODE>Define-exported-binding</CODE> makes <CODE><I>value</I></CODE> available to C code
|
||||
under as <CODE><I>name</I></CODE> which must be a <CODE><I>string</I></CODE>, creating a new shared
|
||||
binding if necessary.
|
||||
The C function <CODE>s48_get_imported_binding</CODE> returns the shared binding
|
||||
defined for <CODE>name</CODE>, again creating it if necessary.
|
||||
The C macro <CODE>S48_SHARED_BINDING_REF</CODE> dereferences a shared binding,
|
||||
returning its current value.
|
||||
<H2><A NAME="6">Exporting C values to Scheme</A></H2>
|
||||
<UL><LI><CODE>void s48_define_exported_binding(char *name, s48_value value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>(lookup-imported-binding<I> string</I>) -> <I>shared-binding</I></CODE>
|
||||
<LI><CODE>(shared-binding-ref<I> shared-binding</I>) -> <I>value</I></CODE>
|
||||
</UL>
|
||||
<P>These are used to define shared bindings from C and to access them
|
||||
from Scheme.
|
||||
Again, if a name is looked up before it has been defined, a new binding is
|
||||
created for it.
|
||||
<P>The common case of exporting a C function to Scheme can be done using
|
||||
the macro <CODE>S48_EXPORT_FUNCTION(<EM>name</EM>)</CODE>.
|
||||
This expands into
|
||||
<P><CODE>s48_define_exported_binding("<CODE><I>name</I></CODE>", s48_enter_pointer(<CODE><I>name</I></CODE>))</CODE>
|
||||
<P>which boxes the function into a Scheme byte vector and then
|
||||
exports it.
|
||||
Note that <CODE>s48_enter_pointer</CODE> allocates space in the Scheme heap
|
||||
and might trigger a
|
||||
<A HREF="#gc">garbage collection</A>.
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>(import-definition <CODE><I>name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>(import-definition <CODE><I>name c-name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
|
||||
</UL>
|
||||
These macros simplify importing definitions from C to Scheme.
|
||||
They expand into
|
||||
<P><CODE>(define <CODE><I>name</I></CODE> (lookup-imported-binding <CODE><I>c-name</I></CODE>))</CODE>
|
||||
<P>where <CODE><I>c-name</I></CODE> is as supplied for the second form.
|
||||
For the first form <CODE><I>c-name</I></CODE> is derived from <CODE><I>name</I></CODE> by
|
||||
replacing `<CODE>-</CODE>' with `<CODE>_</CODE>' and converting letters to lowercase.
|
||||
For example, <CODE>(import-definition my-foo)</CODE> expands into
|
||||
<P><CODE>(define my-foo (lookup-imported-binding "my_foo"))</CODE>
|
||||
<H2><A NAME="more-shared-bindings">Complete shared binding interface</A></H2>
|
||||
|
||||
<P>There are a number of other Scheme functions related to shared bindings;
|
||||
these are in the structure <CODE>shared-bindings</CODE>.
|
||||
<UL><LI><CODE>(shared-binding?<I> x</I>) -> <I>boolean</I></CODE>
|
||||
<LI><CODE>(shared-binding-name<I> shared-binding</I>) -> <I>string</I></CODE>
|
||||
<LI><CODE>(shared-binding-is-import?<I> shared-binding</I>) -> <I>boolean</I></CODE>
|
||||
<LI><CODE>(shared-binding-set!<I> shared-binding value</I>)</CODE>
|
||||
<LI><CODE>(define-imported-binding<I> string value</I>)</CODE>
|
||||
<LI><CODE>(lookup-exported-binding<I> string</I>)</CODE>
|
||||
<LI><CODE>(undefine-imported-binding<I> string</I>)</CODE>
|
||||
<LI><CODE>(undefine-exported-binding<I> string</I>)</CODE>
|
||||
</UL>
|
||||
<P><CODE>Shared-binding?</CODE> is the predicate for shared-bindings.
|
||||
<CODE>Shared-binding-name</CODE> returns the name of a binding.
|
||||
<CODE>Shared-binding-is-import?</CODE> is true if the binding was defined from C.
|
||||
<CODE>Shared-binding-set!</CODE> changes the value of a binding.
|
||||
<CODE>Define-imported-binding</CODE> and <CODE>lookup-exported-binding</CODE> are
|
||||
Scheme versions of <CODE>s48_define_exported_binding</CODE>
|
||||
and <CODE>s48_lookup_imported_binding</CODE>.
|
||||
The two <CODE>undefine-</CODE> procedures remove bindings from the two tables.
|
||||
They do nothing if the name is not found in the table.
|
||||
<P>The following C macros correspond to the Scheme functions above.
|
||||
<UL><LI><CODE>int S48_SHARED_BINDING_P(x)</CODE>
|
||||
<LI><CODE>int S48_SHARED_BINDING_IS_IMPORT_P(s48_value s_b)</CODE>
|
||||
<LI><CODE>s48_value S48_SHARED_BINDING_NAME(s48_value s_b)</CODE>
|
||||
<LI><CODE>void S48_SHARED_BINDING_SET(s48_value s_b, s48_value value)</CODE>
|
||||
</UL>
|
||||
<H1><A NAME="8">Calling C Functions from Scheme</A></H1>
|
||||
|
||||
<P>There are three different ways to call C functions from Scheme, depending on
|
||||
how the C function was obtained.
|
||||
<UL><LI><CODE>(call-imported-binding<I> binding arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||||
<LI><CODE>(call-external<I> external arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||||
<LI><CODE>(call-external-value<I> value name arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||||
</UL>
|
||||
Each of these applies its first argument, a C function, to the rest of
|
||||
the arguments.
|
||||
For <CODE>call-imported-binding</CODE> the function argument must be an
|
||||
imported binding.
|
||||
For <CODE>call-external</CODE> the function argument must be an external
|
||||
bound in the current process
|
||||
(see
|
||||
|
||||
the section on <A HREF="#dynamic-externals">Dynamic Loading</A>).
|
||||
For <CODE>call-external-value</CODE> <CODE><I>value</I></CODE> must be a byte vector
|
||||
whose contents is a pointer to a C function and <CODE><I>name</I></CODE> should be
|
||||
a string naming the function.
|
||||
The <CODE><I>name</I></CODE> argument is used only for printing error messages.
|
||||
<P>For all of these, the C function is passed the <CODE><I>arg<I><sub>i</sub></I></I></CODE> values
|
||||
and the value returned is that returned by C procedure.
|
||||
Up to twelve arguments may be passed.
|
||||
There is no method supplied for returning multiple values to
|
||||
Scheme from C (or vice versa) (mainly because C does not have multiple return
|
||||
values).
|
||||
<P>Keyboard interrupts that occur during a call to a C function are ignored
|
||||
until the function returns to Scheme (this is clearly a
|
||||
problem; we are working on a solution).
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>(import-lambda-definition <CODE><I>name</I></CODE> (<CODE><I>formal</I></CODE> ...))</CODE></td> <td align=right>syntax</td></tr></table>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>(import-lambda-definition <CODE><I>name</I></CODE> (<CODE><I>formal</I></CODE> ...) <CODE><I>c-name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
|
||||
</UL>
|
||||
These macros simplify importing functions from C.
|
||||
They define <CODE><I>name</I></CODE> to be a function with the given formals that
|
||||
applies those formals to the corresponding C binding.
|
||||
<CODE><I>C-name</I></CODE>, if supplied, should be a string.
|
||||
These expand into
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define temp (lookup-imported-binding <CODE><I>c-name</I></CODE>))
|
||||
(define <CODE><I>name</I></CODE>
|
||||
(lambda (<CODE><I>formal</I></CODE> ...)
|
||||
(external-apply temp <CODE><I>formal</I></CODE> ...)))
|
||||
</PRE></BLOCKQUOTE>
|
||||
<P>
|
||||
If <CODE><I>c-name</I></CODE> is not supplied, it is derived from <CODE><I>name</I></CODE> by converting
|
||||
all letters to lowercase and replacing `<CODE>-</CODE>' with `<CODE>_</CODE>'.
|
||||
<H1><A NAME="9">Adding external modules to the <CODE>Makefile</CODE></A></H1>
|
||||
|
||||
<P>Getting access to C bindings from Scheme requires that the C code be
|
||||
compiled an linked in with the Scheme 48 virtual machine and that the
|
||||
relevent shared-bindings be created.
|
||||
The Scheme 48 makefile has rules for compiling and linking external code
|
||||
and for specifying initialization functions that should be called on
|
||||
startup.
|
||||
There are three Makefile variables that control which external modules are
|
||||
included in the executable for the virutal machine (<CODE>scheme48vm</CODE>).
|
||||
<CODE>EXTERNAL_OBJECTS</CODE> lists the object files to be included in
|
||||
<CODE>scheme48vm</CODE>,
|
||||
<CODE>EXTERNAL_FLAGS</CODE> is a list of <CODE>ld</CODE> flags to be used when
|
||||
creating <CODE>scheme48vm</CODE>, and
|
||||
<CODE>EXTERNAL_INITIALIZERS</CODE> is a list of C procedures to be called
|
||||
on startup.
|
||||
The procedures listed in <CODE>EXTERNAL_INITIALIZERS</CODE> should take no
|
||||
arguments and have a return type of <CODE>void</CODE>.
|
||||
After changing the definitions of any of these variables you should
|
||||
do <CODE>make scheme48vm</CODE> to rebuild the virtual machine.
|
||||
<H1><A NAME="dynamic-externals">Dynamic Loading</A></H1>
|
||||
|
||||
<P>External code can be loaded into a running Scheme 48 process
|
||||
and C object-file bindings can be dereferenced at runtime and
|
||||
their values called
|
||||
(although not all versions of Unix support all of this).
|
||||
The required Scheme functions are in the structure <CODE>dynamic-externals</CODE>.
|
||||
<UL><LI><CODE>(dynamic-load<I> string</I>)</CODE>
|
||||
</UL>
|
||||
<CODE>Dynamic-load</CODE> loads the named file into the current
|
||||
process, raising an exception if the file cannot be found or if dynamic
|
||||
loading is not supported by the operating system.
|
||||
The file must have been compiled and linked appropriately.
|
||||
For Linux, the following commands compile <CODE>foo.c</CODE> into a
|
||||
file <CODE>foo.so</CODE> that can be loaded dynamically.
|
||||
<BLOCKQUOTE><PRE>
|
||||
% gcc -c -o foo.o foo.c
|
||||
% ld -shared -o foo.so foo.o
|
||||
</PRE></BLOCKQUOTE>
|
||||
<UL><LI><CODE>(get-external<I> string</I>) -> <I>external</I></CODE>
|
||||
<LI><CODE>(external?<I> x</I>) -> <I>boolean</I></CODE>
|
||||
<LI><CODE>(external-name<I> external</I>) -> <I>string</I></CODE>
|
||||
<LI><CODE>(external-value<I> external</I>) -> <I>byte-vector</I></CODE>
|
||||
</UL>
|
||||
These functions give access to values bound in the current process, and
|
||||
are used for retrieving values from dynamically-loaded files.
|
||||
<CODE>Get-external</CODE> returns an <I>external</I> object that contains the
|
||||
value of <CODE><I>name</I></CODE>, raising an exception if there is no such
|
||||
value in the current process.
|
||||
<CODE>External?</CODE> is the predicate for externals, and
|
||||
<CODE>external-name</CODE> and <CODE>external-value</CODE> return the name and
|
||||
value of an external.
|
||||
The value is returned as byte vector of length four (on 32-bit
|
||||
architectures).
|
||||
The value is that which was extant when <CODE>get-external</CODE> was
|
||||
called.
|
||||
The following two functions can be used to update the values of
|
||||
externals.
|
||||
<UL><LI><CODE>(lookup-external<I> external</I>) -> <I>boolean</I></CODE>
|
||||
<LI><CODE>(lookup-all-externals<I></I>) -> <I>boolean</I></CODE>
|
||||
</UL>
|
||||
<CODE>Lookup-external</CODE> updates the value of <CODE><I>external</I></CODE> by looking its
|
||||
name in the current process, returning <CODE>#t</CODE> if it is bound and <CODE>#f</CODE>
|
||||
if it is not.
|
||||
<CODE>Lookup-all-externals</CODE> calls <CODE>lookup-external</CODE> on all extant
|
||||
externals, returning <CODE>#f</CODE> any are unbound.
|
||||
<UL><LI><CODE>(call-external<I> external arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||||
</UL>
|
||||
An external whose value is a C procedure can be called using
|
||||
<CODE>call-external</CODE>.
|
||||
See
|
||||
|
||||
the section on <A HREF="#8">calling C functions from Scheme</A>
|
||||
for more information.
|
||||
<P>In some versions of Unix retrieving a value from the current
|
||||
process may require a non-trivial amount of computation.
|
||||
We recommend that a dynamically-loaded file contain a single initialization
|
||||
procedure that creates shared bindings for the values exported by the file.
|
||||
<H1><A NAME="11">Compatibility</A></H1>
|
||||
<P>Scheme 48's old <CODE>external-call</CODE> function is still available in the structure
|
||||
<CODE>externals</CODE>, which now also includes <CODE>external-name</CODE> and
|
||||
<CODE>external-value</CODE>.
|
||||
The old <CODE>scheme48.h</CODE> file has been renamed <CODE>old-scheme48.h</CODE>.
|
||||
<H1><A NAME="12">Accessing Scheme data from C</A></H1>
|
||||
|
||||
<P>The C header file <CODE>scheme48.h</CODE> provides
|
||||
access to Scheme 48 data structures
|
||||
(for compatibility, the old <CODE>scheme48.h</CODE> file is available
|
||||
as <CODE>old-scheme48.h</CODE>).
|
||||
The type <CODE>s48_value</CODE> is used for Scheme values.
|
||||
When the type of a value is known, such as the integer returned
|
||||
by <CODE>vector-length</CODE> or the boolean returned by <CODE>pair?</CODE>,
|
||||
the corresponding C procedure returns a C value of the appropriate
|
||||
type, and not a <CODE>s48_value</CODE>.
|
||||
Predicates return <CODE>1</CODE> for true and <CODE>0</CODE> for false.
|
||||
<H2><A NAME="13">Constants</A></H2>
|
||||
|
||||
<P>The following macros denote Scheme constants:
|
||||
<DL><DT><B><CODE>S48_FALSE</CODE></B><DD> is <CODE>#f</CODE>.
|
||||
<DT><B><CODE>S48_TRUE</CODE></B><DD> is <CODE>#t</CODE>.
|
||||
<DT><B><CODE>S48_NULL</CODE></B><DD> is the empty list.
|
||||
<DT><B><CODE>S48_UNSPECIFIC</CODE></B><DD> is a value used for functions which have no
|
||||
meaningful return value
|
||||
(in Scheme this value returned by the nullary procedure <CODE>unspecific</CODE>
|
||||
in the structure <CODE>util</CODE>).
|
||||
<DT><B><CODE>S48_EOF</CODE></B><DD> is the end-of-file object
|
||||
(in Scheme this value is returned by the nullary procedure <CODE>eof-object</CODE>
|
||||
in the structure <CODE>i/o-internal</CODE>).
|
||||
</DL>
|
||||
<H2><A NAME="14">Converting values</A></H2>
|
||||
<P>The following functions convert values between Scheme and C
|
||||
representations.
|
||||
The `extract' ones convert from Scheme to C and the `enter's go the other
|
||||
way.
|
||||
<UL><LI><CODE>unsigned char s48_extract_char(s48_value)</CODE>
|
||||
<LI><CODE>char * s48_extract_string(s48_value)</CODE>
|
||||
<LI><CODE>long s48_extract_integer(s48_value)</CODE>
|
||||
<LI><CODE>double s48_extract_double(s48_value)</CODE>
|
||||
<LI><CODE>s48_value s48_enter_char(unsigned char)</CODE>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_enter_string(char *)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_enter_integer(long)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_enter_double(double)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
</UL>
|
||||
<P>The value returned by <CODE>s48_extract_string</CODE> points to the actual
|
||||
storage used by the string; it is valid only until the next
|
||||
<A HREF="#gc">garbage collection</A>.
|
||||
<P><CODE>s48_enter_integer()</CODE> needs to allocate storage when
|
||||
its argument is too large to fit in a Scheme 48 fixnum.
|
||||
In cases where the number is known to fit within a fixnum (currently 30 bits
|
||||
including the sign), the following procedures can be used.
|
||||
These have the disadvantage of only having a limited range, but
|
||||
the advantage of never causing a garbage collection.
|
||||
<UL><LI><CODE>long s48_extract_fixnum(s48_value)</CODE>
|
||||
<LI><CODE>s48_value s48_enter_fixnum(long)</CODE>
|
||||
<LI><CODE>long S48_MAX_FIXNUM_VALUE</CODE>
|
||||
<LI><CODE>long S48_MIN_FIXNUM_VALUE</CODE>
|
||||
</UL>
|
||||
<P>An error is signalled if <CODE>s48_extract_fixnum</CODE>'s argument
|
||||
is not a fixnum or if the argument to <CODE>s48_enter_fixnum</CODE> is less than
|
||||
<CODE>S48_MIN_FIXNUM_VALUE</CODE> or greater than <CODE>S48_MAX_FIXNUM_VALUE</CODE>
|
||||
(<I>-2<sup>29</sup></I> and <I>2<sup>29</sup>-1</I> in the current system).
|
||||
<H2><A NAME="15">C versions of Scheme procedures</A></H2>
|
||||
<P>The following macros and procedures are C versions of Scheme procedures.
|
||||
The names were derived by replacing `<CODE>-</CODE>' with `<CODE>_</CODE>',
|
||||
`<CODE>?</CODE>' with `<CODE>p</CODE>', and dropping `<CODE>!</CODE>.
|
||||
<UL><LI><CODE>int S48_EQ_P(s48_value)</CODE>
|
||||
<LI><CODE>int S48_CHAR_P(s48_value)</CODE>
|
||||
<LI><CODE>int S48_INTEGER_P(s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>int S48_PAIR_P(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_CAR(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_CDR(s48_value)</CODE>
|
||||
<LI><CODE>void S48_SET_CAR(s48_value, s48_value)</CODE>
|
||||
<LI><CODE>void S48_SET_CDR(s48_value, s48_value)</CODE>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_cons(s48_value, s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
<LI><CODE>long s48_length(s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>int S48_VECTOR_P(s48_value)</CODE>
|
||||
<LI><CODE>long S48_VECTOR_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_VECTOR_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_VECTOR_SET(s48_value, long, s48_value)</CODE>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_make_vector(long, s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
</UL>
|
||||
<UL><LI><CODE>int S48_STRING_P(s48_value)</CODE>
|
||||
<LI><CODE>long S48_STRING_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>char S48_STRING_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_STRING_SET(s48_value, long, char)</CODE>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_make_string(long, char)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
</UL>
|
||||
<UL><LI><CODE>int S48_SYMBOL_P(s48_value)</CODE>
|
||||
<LI><CODE>s48_value s48_SYMBOL_TO_STRING(s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>int S48_BYTE_VECTOR_P(s48_value)</CODE>
|
||||
<LI><CODE>long S48_BYTE_VECTOR_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>char S48_BYTE_VECTOR_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_BYTE_VECTOR_SET(s48_value, long, int)</CODE>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value s48_make_byte_vector(long, int)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
</UL>
|
||||
<H1><A NAME="16">Calling Scheme functions from C</A></H1>
|
||||
|
||||
<P>External code that has been called from Scheme can call back to Scheme
|
||||
procedures using the following function.
|
||||
<UL><LI><CODE>scheme_value s48_call_scheme(s48_value proc, long nargs, ...)</CODE>
|
||||
</UL>
|
||||
This calls the Scheme procedure <CODE>proc</CODE> on <CODE>nargs</CODE>
|
||||
arguments, which are passed as additional arguments to <CODE>s48_call_scheme</CODE>.
|
||||
There may be at most ten arguments.
|
||||
The value returned by the Scheme procedure is returned by the C procedure.
|
||||
Invoking any Scheme procedure may potentially cause a garbage collection.
|
||||
<P>There are some complications that occur when mixing calls from C to Scheme
|
||||
with continuations and threads.
|
||||
C only supports downward continuations (via <CODE>longjmp()</CODE>).
|
||||
Scheme continuations that capture a portion of the C stack have to follow the
|
||||
same restriction.
|
||||
For example, suppose Scheme procedure <CODE>s0</CODE> captures continuation <CODE>a</CODE>
|
||||
and then calls C procedure <CODE>c0</CODE>, which in turn calls Scheme procedure
|
||||
<CODE>s1</CODE>.
|
||||
Procedure <CODE>s1</CODE> can safely call the continuation <CODE>a</CODE>, because that
|
||||
is a downward use.
|
||||
When <CODE>a</CODE> is called Scheme 48 will remove the portion of the C stack used
|
||||
by the call to <CODE>c0</CODE>.
|
||||
On the other hand, if <CODE>s1</CODE> captures a continuation, that continuation
|
||||
cannot be used from <CODE>s0</CODE>, because by the time control returns to
|
||||
<CODE>s0</CODE> the C stack used by <CODE>c0</CODE> will no longer be valid.
|
||||
An attempt to invoke an upward continuation that is closed over a portion
|
||||
of the C stack will raise an exception.
|
||||
<P>In Scheme 48 threads are implemented using continuations, so the downward
|
||||
restriction applies to them as well.
|
||||
An attempt to return from Scheme to C at a time when the appropriate
|
||||
C frame is not on top of the C stack will cause the current thread to
|
||||
block until the frame is available.
|
||||
For example, suppose thread <CODE>t0</CODE> calls a C procedure which calls back
|
||||
to Scheme, at which point control switches to thread <CODE>t1</CODE>, which also
|
||||
calls C and then back to Scheme.
|
||||
At this point both <CODE>t0</CODE> and <CODE>t1</CODE> have active calls to C on the
|
||||
C stack, with <CODE>t1</CODE>'s C frame above <CODE>t0</CODE>'s.
|
||||
If thread <CODE>t0</CODE> attempts to return from Scheme to C it will block,
|
||||
as its frame is not accessable.
|
||||
Once <CODE>t1</CODE> has returned to C and from there to Scheme, <CODE>t0</CODE> will
|
||||
be able to resume.
|
||||
The return to Scheme is required because context switches can only occur while
|
||||
C code is running.
|
||||
<CODE>T0</CODE> will also be able to resume if <CODE>t1</CODE> uses a continuation to
|
||||
throw past its call to C.
|
||||
<H1><A NAME="gc">Interacting with the Scheme Heap</A></H1>
|
||||
|
||||
|
||||
<P>Scheme 48 uses a copying, precise garbage collector.
|
||||
Any procedure that allocates objects within the Scheme 48 heap may trigger
|
||||
a garbage collection.
|
||||
Variables bound to values in the Scheme 48 heap need to be registered with
|
||||
the garbage collector so that the value will be retained and so that the
|
||||
variables will be updated if the garbage collector moves the object.
|
||||
The garbage collector has no facility for updating pointers to the interiors
|
||||
of objects, so such pointers, for example the ones returned by
|
||||
<CODE>EXTRACT_STRING</CODE>, will likely become invalid when a garbage collection
|
||||
occurs.
|
||||
<H2><A NAME="18">Registering Objects with the GC</A></H2>
|
||||
|
||||
<P>A set of macros are used to manage the registration of local variables with the
|
||||
garbage collector.
|
||||
<UL><LI><CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>
|
||||
<LI><CODE>void S48_GC_PROTECT_<I>n</I>(s48_value<I><sub>1</sub></I>, <I>...</I>, s48_value<I><sub>n</sub></I>)</CODE>
|
||||
<LI><CODE>void S48_GC_UNPROTECT()</CODE>
|
||||
</UL>
|
||||
<P><CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>, where <I>1 <= n <= 9</I>, allocates
|
||||
storage for registering <I>n</I> variables.
|
||||
At most one use of <CODE>S48_DECLARE_GC_PROTECT</CODE> may occur in a block.
|
||||
<CODE>S48_GC_PROTECT_<I>n</I>(<I>v<sub>1</sub></I>, <I>...</I>, <I>v<sub>n</sub></I>)</CODE> registers the
|
||||
<I>n</I> variables (l-values) with the garbage collector.
|
||||
It must be within scope of a <CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>
|
||||
and be before any code which can cause a GC.
|
||||
<CODE>S48_GC_UNPROTECT</CODE> removes the block's protected variables from
|
||||
the garbage collectors list.
|
||||
It must be called at the end of the block after
|
||||
any code which may cause a garbage collection.
|
||||
Omitting any of the three may cause serious and
|
||||
hard-to-debug problems.
|
||||
Notably, the garbage collector may relocate an object and
|
||||
invalidate <CODE>s48_value</CODE> variables which are not protected.
|
||||
<P>A <CODE>gc-protection-mismatch</CODE> exception is raised if, when a C
|
||||
procedure returns to Scheme, the calls
|
||||
to <CODE>S48_GC_PROTECT()</CODE> have not been matched by an equal number of
|
||||
calls to <CODE>S48_GC_UNPROTECT()</CODE>.
|
||||
<P>Global variables may also be registered with the garbage collector.
|
||||
<UL><LI><CODE>void S48_GC_PROTECT_GLOBAL(<CODE><I>value</I></CODE>)</CODE>
|
||||
</UL>
|
||||
<P><CODE>S48_GC_PROTECT_GLOBAL</CODE> permanently registers the
|
||||
variable <CODE><I>value</I></CODE> (an l-value) with the garbage collector.
|
||||
There is no way to unregister the variable.
|
||||
<H2><A NAME="19">Keeping C data structures in the Scheme heap</A></H2>
|
||||
|
||||
<P>C data structures can be kept in the Scheme heap by embedding them
|
||||
inside byte vectors.
|
||||
The following macros can be used to create and access embedded C objects.
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value S48_MAKE_VALUE(type)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
<LI><CODE>type S48_EXTRACT_VALUE(s48_value, type)</CODE>
|
||||
<LI><CODE>type * S48_EXTRACT_VALUE_POINTER(s48_value, type)</CODE>
|
||||
<LI><CODE>void S48_SET_VALUE(s48_value, type, value)</CODE>
|
||||
</UL>
|
||||
<P><CODE>S48_MAKE_VALUE</CODE> makes a byte vector large enough to hold an object
|
||||
whose type is <CODE><I>type</I></CODE>.
|
||||
<CODE>S48_EXTRACT_VALUE</CODE> returns the contents of a byte vector cast to
|
||||
<CODE><I>type</I></CODE>, and <CODE>S48_EXTRACT_VALUE_POINTER</CODE> returns a pointer
|
||||
to the contents of the byte vector.
|
||||
The value returned by <CODE>S48_EXTRACT_VALUE_POINTER</CODE> is valid only until
|
||||
the next <A HREF="#gc">garbage collection</A>.
|
||||
<P><CODE>S48_SET_VALUE</CODE> stores <CODE>value</CODE> into the byte vector.
|
||||
<H2><A NAME="20">C code and heap images</A></H2>
|
||||
|
||||
<P>Scheme 48 uses dumped heap images to restore a previous system state.
|
||||
The Scheme 48 heap is written into a file in a machine-independent and
|
||||
operating-system-independent format.
|
||||
The procedures described above may be used to create objects in the
|
||||
Scheme heap that contain information specific to the current
|
||||
machine, operating system, or process.
|
||||
A heap image containing such objects may not work correctly on
|
||||
when resumed.
|
||||
<P>To address this problem, a record type may be given a `resumer'
|
||||
procedure.
|
||||
On startup, the resumer procedure for a type is applied to each record of
|
||||
that type in the image being restarted.
|
||||
This procedure can update the record in a manner appropriate to
|
||||
the machine, operating system, or process used to resume the
|
||||
image.
|
||||
<UL><LI><CODE>(define-record-resumer<I> record-type procedure</I>)</CODE>
|
||||
</UL>
|
||||
<P><CODE>Define-record-resumer</CODE> defines <CODE><I>procedure</I></CODE>,
|
||||
which should accept one argument, to be the resumer for
|
||||
<I>record-type</I>.
|
||||
The order in which resumer procedures are called is not specified.
|
||||
<P>The <CODE><I>procedure</I></CODE> argument to <CODE>define-record-resumer</CODE> may
|
||||
be <CODE>#f</CODE>, in which case records of the given type are
|
||||
not written out in heap images.
|
||||
When writing a heap image any reference to such a record is replaced by
|
||||
the value of the record's first field, and an exception is raised
|
||||
after the image is written.
|
||||
<H1><A NAME="21">Using Scheme records in C code</A></H1>
|
||||
<P>External modules can create records and access their slots
|
||||
positionally.
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>s48_value S48_MAKE_RECORD(s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||||
<LI><CODE>int S48_RECORD_P(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_RECORD_TYPE(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_RECORD_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_RECORD_SET(s48_value, long, s48_value)</CODE>
|
||||
</UL>
|
||||
The argument to <CODE>S48_MAKE_RECORD</CODE> should be a shared binding
|
||||
whose value is a record type.
|
||||
In C the fields of Scheme records are only accessible via offsets,
|
||||
with the first field having offset zero, the second offset one, and
|
||||
so forth.
|
||||
If the order of the fields is changed in the Scheme definition of the
|
||||
record type the C code must be updated as well.
|
||||
<P>For example, given the following record-type definition
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-record-type thing :thing
|
||||
(make-thing a b)
|
||||
thing?
|
||||
(a thing-a)
|
||||
(b thing-b))
|
||||
</PRE></BLOCKQUOTE>
|
||||
the identifier <CODE>:thing</CODE> is bound to the record type and can
|
||||
be exported to C:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-exported-binding "thing-record-type" :thing)
|
||||
</PRE></BLOCKQUOTE>
|
||||
<CODE>Thing</CODE> records can then be made in C:
|
||||
<BLOCKQUOTE><PRE>
|
||||
static scheme_value thing_record_type_binding = SCHFALSE;
|
||||
|
||||
void initialize_things(void)
|
||||
{
|
||||
S48_GC_PROTECT_GLOBAL(thing_record_type_binding);
|
||||
thing_record_type_binding =
|
||||
s48_get_imported_binding("thing-record-type");
|
||||
}
|
||||
|
||||
scheme_value make_thing(scheme_value a, scheme_value b)
|
||||
{
|
||||
s48_value thing;
|
||||
s48_DECLARE_GC_PROTECT(2);
|
||||
|
||||
S48_GC_PROTECT_2(a, b);
|
||||
|
||||
thing = s48_make_record(thing_record_type_binding);
|
||||
S48_RECORD_SET(thing, 0, a);
|
||||
S48_RECORD_SET(thing, 1, b);
|
||||
|
||||
S48_GC_UNPROTECT();
|
||||
|
||||
return thing;
|
||||
}
|
||||
</PRE></BLOCKQUOTE>
|
||||
Note that the variables <CODE>a</CODE> and <CODE>b</CODE> must be protected
|
||||
against the possibility of a garbage collection occuring during
|
||||
the call to <CODE>s48_make_record()</CODE>.
|
||||
<H1><A NAME="22">Raising exceptions from external code</A></H1>
|
||||
|
||||
<P>The following macros explicitly raise certain errors, immediately
|
||||
returning to Scheme 48.
|
||||
Raising an exception performs all
|
||||
necessary clean-up actions to properly return to Scheme 48, including
|
||||
adjusting the stack of protected variables.
|
||||
<UL><LI><CODE>s48_raise_scheme_exception(int type, int nargs, ...)</CODE>
|
||||
</UL>
|
||||
<P><CODE>s48_raise_scheme_exception</CODE> is the base procedure for
|
||||
raising exceptions.
|
||||
<CODE>type</CODE> is the type of exception, and should be one of the
|
||||
<CODE>S48_EXCEPTION_</CODE>...constants defined in <CODE>scheme48arch.h</CODE>.
|
||||
<CODE>nargs</CODE> is the number of additional values to be included in the
|
||||
exception; these follow the <CODE>nargs</CODE> argument and should all have
|
||||
type <CODE>s48_value</CODE>.
|
||||
<CODE>s48_raise_scheme_exception</CODE> never returns.
|
||||
<P>The following procedures are available for raising particular
|
||||
types of exceptions.
|
||||
Like <CODE>s48_raise_scheme_exception</CODE> these never return.
|
||||
<UL><LI><CODE>s48_raise_argument_type_error(scheme_value)</CODE>
|
||||
<LI><CODE>s48_raise_argument_number_error(int nargs, int min, int max)</CODE>
|
||||
<LI><CODE>s48_raise_index_range_error(long value, long min, long max)</CODE>
|
||||
<LI><CODE>s48_raise_closed_channel_error()</CODE>
|
||||
<LI><CODE>s48_raise_os_error(int errno)</CODE>
|
||||
<LI><CODE>s48_raise_out_of_memory_error()</CODE>
|
||||
</UL>
|
||||
<P>An argument type error indicates that the given value is of the wrong
|
||||
type.
|
||||
An argument number error is raised when the number of arguments, <CODE>nargs</CODE>,
|
||||
should be, but isn't, between <CODE>min</CODE> and <CODE>max</CODE>, inclusive.
|
||||
Similarly, and index range error is raised when <CODE>value</CODE> is not between
|
||||
between <CODE>min</CODE> and <CODE>max</CODE>, inclusive.
|
||||
<P>The following macros raise argument type errors if their argument does not
|
||||
have the required type.
|
||||
<UL><LI><CODE>void S48_CHECK_SYMBOL(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_PAIR(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_STRING(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_INTEGER(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_CHANNEL(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_BYTE_VECTOR(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_RECORD(s48_value)</CODE>
|
||||
<LI><CODE>void S48_CHECK_SHARED_BINDING(s48_value)</CODE>
|
||||
</UL>
|
||||
<H1><A NAME="23">Unsafe functions and macros</A></H1>
|
||||
<P>All of the C procedures and macros described above check that their
|
||||
arguments have the appropriate types and that indexes are in range.
|
||||
The following procedures and macros are identical to those described
|
||||
above, except that they do not perform type and range checks.
|
||||
They are provided for the purpose of writing more efficient code;
|
||||
their general use is not recommended.
|
||||
<UL><LI><CODE>char S48_UNSAFE_EXTRACT_CHAR(s48_value)</CODE>
|
||||
<LI><CODE>char * S48_UNSAFE_EXTRACT_STRING(s48_value)</CODE>
|
||||
<LI><CODE>long S48_UNSAFE_EXTRACT_INTEGER(s48_value)</CODE>
|
||||
<LI><CODE>long S48_UNSAFE_EXTRACT_DOUBLE(s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>long S48_UNSAFE_EXTRACT_FIXNUM(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_UNSAFE_ENTER_FIXNUM(long)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>s48_value S48_UNSAFE_CAR(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_UNSAFE_CDR(s48_value)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_SET_CAR(s48_value, s48_value)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_SET_CDR(s48_value, s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>long S48_UNSAFE_VECTOR_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_UNSAFE_VECTOR_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_VECTOR_SET(s48_value, long, s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>long S48_UNSAFE_STRING_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>char S48_UNSAFE_STRING_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_STRING_SET(s48_value, long, char)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>s48_value S48_UNSAFE_SYMBOL_TO_STRING(s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>long S48_UNSAFE_BYTE_VECTOR_LENGTH(s48_value)</CODE>
|
||||
<LI><CODE>char S48_UNSAFE_BYTE_VECTOR_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_BYTE_VECTOR_SET(s48_value, long, int)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>s48_value S48_UNSAFE_SHARED_BINDING_REF(s48_value s_b)</CODE>
|
||||
<LI><CODE>int S48_UNSAFE_SHARED_BINDING_P(x)</CODE>
|
||||
<LI><CODE>int S48_UNSAFE_SHARED_BINDING_IS_IMPORT_P(s48_value s_b)</CODE>
|
||||
<LI><CODE>s48_value S48_UNSAFE_SHARED_BINDING_NAME(s48_value s_b)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_SHARED_BINDING_SET(s48_value s_b, s48_value value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>s48_value S48_UNSAFE_RECORD_TYPE(s48_value)</CODE>
|
||||
<LI><CODE>s48_value S48_UNSAFE_RECORD_REF(s48_value, long)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_RECORD_SET(s48_value, long, s48_value)</CODE>
|
||||
</UL>
|
||||
<UL><LI><CODE>type S48_UNSAFE_EXTRACT_VALUE(s48_value, type)</CODE>
|
||||
<LI><CODE>type * S48_UNSAFE_EXTRACT_VALUE_POINTER(s48_value, type)</CODE>
|
||||
<LI><CODE>void S48_UNSAFE_SET_VALUE(s48_value, type, value)</CODE>
|
||||
</UL>
|
||||
<HR ><ADDRESS><a href="http://www-pu.informatik.uni-tuebingen.de/users/sperber/">Mike
|
||||
Sperber</a>, <a href="http://www.neci.nj.nec.com/homepages/kelsey/">Richard Kelsey</a></ADDRESS><BR>
|
||||
</BODY></HTML>
|
||||
|
|
@ -1,315 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<!-- HTML file produced from file: utilities.tex --
|
||||
-- using Hyperlatex v 2.3.1 (c) Otfried Cheong--
|
||||
-- on Emacs 19.34.1, Tue Feb 23 18:25:11 1999 -->
|
||||
<HEAD>
|
||||
<TITLE>Untitled</TITLE>
|
||||
|
||||
</HEAD><BODY>
|
||||
|
||||
|
||||
<H1 ALIGN=CENTER>Scheme 48 User's Guide</H1>
|
||||
<H2 ALIGN=CENTER>Richard A. Kelsey</H2>
|
||||
<H3 ALIGN=CENTER>February 23, 1999</H3>
|
||||
<H1><A NAME="1">ASCII character encoding</A></H1>
|
||||
<P>These are in the structure <CODE>ascii</CODE>.
|
||||
<UL><LI><CODE>(char->ascii<VAR> char</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
<LI><CODE>(ascii->char<VAR> integer</VAR>) -> <VAR>char</VAR></CODE>
|
||||
</UL>
|
||||
These are identical to <CODE>char->integer</CODE> and <CODE>integer->char</CODE> except that
|
||||
they use the ASCII encoding.
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>ascii-limit</CODE></td> <td align=right>integer</td></tr></table>
|
||||
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE>ascii-whitespaces</CODE></td> <td align=right>list of integers</td></tr></table>
|
||||
</UL>
|
||||
<CODE>Ascii-limit</CODE> is one more than the largest value that <CODE>char->ascii</CODE>
|
||||
may return.
|
||||
<CODE>Ascii-whitespaces</CODE> is a list of the ASCII values of whitespace characters
|
||||
(space, tab, line feed, form feed, and carriage return).
|
||||
<H1><A NAME="2">Bitwise integer operations</A></H1>
|
||||
<P>These functions use the two's-complement representation for integers.
|
||||
There is no limit to the number of bits in an integer.
|
||||
They are in the structures <CODE>bitwise</CODE> and <CODE>big-scheme</CODE>.
|
||||
<UL><LI><CODE>(bitwise-and<VAR> integer integer</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
<LI><CODE>(bitwise-ior<VAR> integer integer</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
<LI><CODE>(bitwise-xor<VAR> integer integer</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
<LI><CODE>(bitwise-not<VAR> integer</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
</UL>
|
||||
These perform various logical operations on integers on a bit-by-bit
|
||||
basis. `<CODE>ior</CODE>' is inclusive OR and `<CODE>xor</CODE>' is exclusive OR.
|
||||
<UL><LI><CODE>(arithmetic-shift<VAR> integer bit-count</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
</UL>
|
||||
Shifts the integer by the given bit count, which must be an integer,
|
||||
shifting left for positive counts and right for negative ones.
|
||||
Shifting preserves the integer's sign.
|
||||
<H1><A NAME="3">Arrays</A></H1>
|
||||
<P>These are N-dimensional, zero-based arrays and
|
||||
are in the structure <CODE>arrays</CODE>.
|
||||
<P>The array interface is derived from one written by Alan Bawden.
|
||||
<UL><LI><CODE>(make-array<VAR> value dimension<I><sub>0</sub></I> ...</VAR>) -> <VAR>array</VAR></CODE>
|
||||
<LI><CODE>(array<VAR> dimensions element<I><sub>0</sub></I> ...</VAR>) -> <VAR>array</VAR></CODE>
|
||||
<LI><CODE>(copy-array<VAR> array</VAR>) -> <VAR>array</VAR></CODE>
|
||||
</UL>
|
||||
<CODE>Make-array</CODE> makes a new array with the given dimensions, each of which
|
||||
must be a non-negative integer.
|
||||
Every element is initially set to <CODE><VAR>value</VAR></CODE>.
|
||||
<CODE>Array</CODE> Returns a new array with the given dimensions and elements.
|
||||
<CODE><VAR>Dimensions</VAR></CODE> must be a list of non-negative integers,
|
||||
The number of elements should be the equal to the product of the
|
||||
dimensions.
|
||||
The elements are stored in row-major order.
|
||||
<BLOCKQUOTE><PRE>
|
||||
(make-array 'a 2 3) <CODE>-></CODE> {Array 2 3}
|
||||
|
||||
(array '(2 3) 'a 'b 'c 'd 'e 'f)
|
||||
<CODE>-></CODE> {Array 2 3}
|
||||
</PRE></BLOCKQUOTE>
|
||||
<P><CODE>Copy-array</CODE> returns a copy of <CODE><VAR>array</VAR></CODE>.
|
||||
The copy is identical to the <CODE><VAR>array</VAR></CODE> but does not share storage with it.
|
||||
<UL><LI><CODE>(array?<VAR> value</VAR>) -> <VAR>boolean</VAR></CODE>
|
||||
</UL>
|
||||
Returns <CODE>#t</CODE> if <CODE><VAR>value</VAR></CODE> is an array.
|
||||
<UL><LI><CODE>(array-ref<VAR> array index<I><sub>0</sub></I> ...</VAR>) -> <VAR>value</VAR></CODE>
|
||||
<LI><CODE>(array-set!<VAR> array value index<I><sub>0</sub></I> ...</VAR>)</CODE>
|
||||
<LI><CODE>(array->vector<VAR> array</VAR>) -> <VAR>vector</VAR></CODE>
|
||||
<LI><CODE>(array-dimensions<VAR> array</VAR>) -> <VAR>list</VAR></CODE>
|
||||
</UL>
|
||||
<CODE>Array-ref</CODE> returns the specified array element and <CODE>array-set!</CODE>
|
||||
replaces the element with <CODE><VAR>value</VAR></CODE>.
|
||||
<BLOCKQUOTE><PRE>
|
||||
(let ((a (array '(2 3) 'a 'b 'c 'd 'e 'f)))
|
||||
(let ((x (array-ref a 0 1)))
|
||||
(array-set! a 'g 0 1)
|
||||
(list x (array-ref a 0 1))))
|
||||
<CODE>-></CODE> '(b g)
|
||||
</PRE></BLOCKQUOTE>
|
||||
<P><CODE>Array->vector</CODE> returns a vector containing the elements of <CODE><VAR>array</VAR></CODE>
|
||||
in row-major order.
|
||||
<CODE>Array-dimensions</CODE> returns the dimensions of
|
||||
the array as a list.
|
||||
<UL><LI><CODE>(make-shared-array<VAR> array linear-map dimension<I><sub>0</sub></I> ...</VAR>) -> <VAR>array</VAR></CODE>
|
||||
</UL>
|
||||
<CODE>Make-shared-array</CODE> makes a new array that shares storage with <CODE><VAR>array</VAR></CODE>
|
||||
and uses <CODE><VAR>linear-map</VAR></CODE> to map indicies to elements.
|
||||
<CODE><VAR>Linear-map</VAR></CODE> must accept as many arguments as the number of
|
||||
<CODE><VAR>dimension</VAR></CODE>s given and must return a list of non-negative integers
|
||||
that are valid indicies into <CODE><VAR>array</VAR></CODE>.
|
||||
<BLOCKQUOTE><PRE>
|
||||
(array-ref (make-shared-array a f i0 i1 ...)
|
||||
j0 j1 ...)
|
||||
</PRE></BLOCKQUOTE>
|
||||
is equivalent to
|
||||
<BLOCKQUOTE><PRE>
|
||||
(apply array-ref a (f j0 j1 ...))
|
||||
</PRE></BLOCKQUOTE>
|
||||
<P>As an example, the following function makes the transpose of a two-dimensional
|
||||
array:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define (transpose array)
|
||||
(let ((dimensions (array-dimensions array)))
|
||||
(make-shared-array array
|
||||
(lambda (x y)
|
||||
(list y x))
|
||||
(cadr dimensions)
|
||||
(car dimensions))))
|
||||
|
||||
(array->vector
|
||||
(transpose
|
||||
(array '(2 3) 'a 'b 'c 'd 'e 'f)))
|
||||
<CODE>-></CODE> '(a d b e c f)
|
||||
</PRE></BLOCKQUOTE>
|
||||
<H1><A NAME="4">Records</A></H1>
|
||||
<P>New types can be constructed using the <CODE>define-record-type</CODE> macro
|
||||
from the <CODE>define-record-types</CODE> structure
|
||||
The general syntax is:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-record-type <CODE><VAR>tag</VAR></CODE> <CODE><VAR>type-name</VAR></CODE>
|
||||
(<CODE><VAR>constructor-name</VAR></CODE> <CODE><VAR>field-tag</VAR></CODE> ...)
|
||||
<CODE><VAR>predicate-name</VAR></CODE>
|
||||
(<CODE><VAR>field-tag</VAR></CODE> <CODE><VAR>accessor-name</VAR></CODE> [<CODE><VAR>modifier-name</VAR></CODE>])
|
||||
...)
|
||||
</PRE></BLOCKQUOTE>
|
||||
This makes the following definitions:
|
||||
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||||
<tr> <td><CODE><CODE><VAR>type-name</VAR></CODE></CODE></td> <td align=right>type</td></tr></table>
|
||||
<LI><CODE>(<CODE><VAR>constructor-name</VAR></CODE><VAR> field-init ...</VAR>) -> <VAR>type-name</VAR></CODE>
|
||||
<LI><CODE>(<CODE><VAR>predicate-name</VAR></CODE><VAR> value</VAR>) -> <VAR>boolean</VAR></CODE>
|
||||
<LI><CODE>(<CODE><VAR>accessor-name</VAR></CODE><VAR> type-name</VAR>) -> <VAR>value</VAR></CODE>
|
||||
<LI><CODE>(<CODE><VAR>modifier-name</VAR></CODE><VAR> type-name value</VAR>)</CODE>
|
||||
</UL>
|
||||
<CODE><VAR>Type-name</VAR></CODE> is the record type itself, and can be used to
|
||||
specify a print method (see below).
|
||||
<CODE><VAR>Constructor-name</VAR></CODE> is a constructor that accepts values
|
||||
for the fields whose tags are specified.
|
||||
<CODE><VAR>Predicate-name</VAR></CODE> to a predicate that can returns <CODE>#t</CODE> for
|
||||
elements of the type and <CODE>#f</CODE> for everything else.
|
||||
The <CODE><VAR>accessor-name</VAR></CODE>s retrieve the values of fields,
|
||||
and the <CODE><VAR>modifier-name</VAR></CODE>'s update them.
|
||||
The <CODE><VAR>tag</VAR></CODE> is used in printing instances of the record type and
|
||||
the field tags are used in the inspector and to match
|
||||
constructor arguments with fields.
|
||||
<UL><LI><CODE>(define-record-discloser<VAR> type discloser</VAR>)</CODE>
|
||||
</UL>
|
||||
<CODE>Define-record-discloser</CODE> determines how
|
||||
records of type <CODE><VAR>type</VAR></CODE> are printed.
|
||||
<CODE><VAR>Discloser</VAR></CODE> should be procedure which takes a single
|
||||
record of type <CODE><VAR>type</VAR></CODE> and returns a list whose car is
|
||||
a symbol.
|
||||
The record will be printed as the value returned by <CODE><VAR>discloser</VAR></CODE>
|
||||
with curly braces used instead of the usual parenthesis.
|
||||
<P>For example
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-record-type pare :pare
|
||||
(kons x y)
|
||||
pare?
|
||||
(x kar set-kar!)
|
||||
(y kdr))
|
||||
</PRE></BLOCKQUOTE>
|
||||
defines <CODE>kons</CODE> to be a constructor, <CODE>kar</CODE> and <CODE>kdr</CODE> to be
|
||||
accessors, <CODE>set-kar!</CODE> to be a modifier, and <CODE>pare?</CODE> to be a predicate
|
||||
for a new type of object.
|
||||
The type itself is named <CODE>:pare</CODE>.
|
||||
<CODE>Pare</CODE> is a tag used in printing the new objects.
|
||||
<P>By default, the new objects print as <CODE>#Pare</CODE>.
|
||||
The print method can be modified using DEFINE-RECORD-DISCLOSER:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-record-discloser :pare
|
||||
(lambda (p) `(pare ,(kar p) ,(kdr p))))
|
||||
</PRE></BLOCKQUOTE>
|
||||
will cause the result of <CODE>(kons 1 2)</CODE> to print as
|
||||
<CODE>#{pare 1 2}</CODE>.
|
||||
<H1><A NAME="5">Finite record types</A></H1>
|
||||
<P>The structure <CODE>finite-types</CODE> has
|
||||
two macros for defining `finite' record types.
|
||||
These are record types for which there are a fixed number of instances,
|
||||
which are created when the record type is defined.
|
||||
The syntax for the defining a finite type is:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-finite-type <CODE><VAR>tag</VAR></CODE> <CODE><VAR>type-name</VAR></CODE>
|
||||
(<CODE><VAR>field-tag</VAR></CODE> ...)
|
||||
<CODE><VAR>predicate-name</VAR></CODE>
|
||||
<CODE><VAR>vector-of-elements-name</VAR></CODE>
|
||||
<CODE><VAR>name-accessor</VAR></CODE>
|
||||
<CODE><VAR>index-accessor</VAR></CODE>
|
||||
(<CODE><VAR>field-tag</VAR></CODE> <CODE><VAR>accessor-name</VAR></CODE> [<CODE><VAR>modifier-name</VAR></CODE>])
|
||||
...
|
||||
((<CODE><VAR>element-name</VAR></CODE> <CODE><VAR>field-value</VAR></CODE> ...)
|
||||
...))
|
||||
</PRE></BLOCKQUOTE>
|
||||
This differs from <CODE>define-record-type</CODE> in the following ways:
|
||||
<UL><LI>No name is specified for the constructor, but the field arguments
|
||||
to the constructor are listed.
|
||||
<LI>The <CODE><VAR>vector-of-elements-name</VAR></CODE> is added; it will be bound
|
||||
to a vector containing all of the elements of the type.
|
||||
These are constructed by applying the (unnamed) constructor to the
|
||||
initial field values at the end of the form.
|
||||
<LI>There are names for accessors for two required fields, name
|
||||
and index.
|
||||
These fields are not settable, and are not to be included
|
||||
in the argument list for the constructor.
|
||||
<LI>The form ends with the names and the initial field values for
|
||||
the elements of the type.
|
||||
The name must be first.
|
||||
The remaining values must match the <CODE><VAR>field-tag</VAR></CODE>s in the constructor's
|
||||
argument list.
|
||||
<LI><CODE><VAR>Tag</VAR></CODE> is bound to a macro that maps <CODE><VAR>element-name</VAR></CODE>s to the
|
||||
the corresponding element of the vector.
|
||||
The name lookup is done at macro-expansion time.
|
||||
</UL>
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-finite-type color :color
|
||||
(red green blue)
|
||||
color?
|
||||
colors
|
||||
color-name
|
||||
color-index
|
||||
(red color-red)
|
||||
(green color-green)
|
||||
(blue color-blue)
|
||||
((white 255 255 255)
|
||||
(black 0 0 0)
|
||||
(yellow 255 255 0)
|
||||
(maroon 176 48 96)))
|
||||
|
||||
(color-name (vector-ref colors 0)) <CODE>-></CODE> white
|
||||
(color-name (color black)) <CODE>-></CODE> black
|
||||
(color-index (color yellow)) <CODE>-></CODE> 2
|
||||
(color-red (color maroon)) <CODE>-></CODE> 176
|
||||
</PRE></BLOCKQUOTE>
|
||||
<P>Enumerated types are finite types whose only fields are the name
|
||||
and the index.
|
||||
The syntax for defining an enumerated type is:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-enumerated-type <CODE><VAR>tag</VAR></CODE> <CODE><VAR>type-name</VAR></CODE>
|
||||
<CODE><VAR>predicate-name</VAR></CODE>
|
||||
<CODE><VAR>vector-of-elements-name</VAR></CODE>
|
||||
<CODE><VAR>name-accessor</VAR></CODE>
|
||||
<CODE><VAR>index-accessor</VAR></CODE>
|
||||
(<CODE><VAR>element-name</VAR></CODE> ...))
|
||||
</PRE></BLOCKQUOTE>
|
||||
In the absence of any additional fields, both the constructor argument
|
||||
list and the initial field values are not required.
|
||||
<P>The above example of a finite type can be pared down to the following
|
||||
enumerated type:
|
||||
<BLOCKQUOTE><PRE>
|
||||
(define-enumerated-type color :color
|
||||
color?
|
||||
colors
|
||||
color-name
|
||||
color-index
|
||||
(white black yellow maroon))
|
||||
|
||||
(color-name (vector-ref colors 0)) <CODE>-></CODE> white
|
||||
(color-name (color black)) <CODE>-></CODE> black
|
||||
(color-index (color yellow)) <CODE>-></CODE> 2
|
||||
</PRE></BLOCKQUOTE>
|
||||
<H1><A NAME="6">Hash tables</A></H1>
|
||||
<P>These are generic hash tables, and are in the structure <CODE>tables</CODE>.
|
||||
Strictly speaking they are more maps than tables, as every table has a
|
||||
value for every possible key (for that type of table).
|
||||
All but a finite number of those values are <CODE>#f</CODE>.
|
||||
<UL><LI><CODE>(make-table<VAR></VAR>) -> <VAR>table</VAR></CODE>
|
||||
<LI><CODE>(make-symbol-table<VAR></VAR>) -> <VAR>symbol-table</VAR></CODE>
|
||||
<LI><CODE>(make-string-table<VAR></VAR>) -> <VAR>string-table</VAR></CODE>
|
||||
<LI><CODE>(make-integer-table<VAR></VAR>) -> <VAR>integer-table</VAR></CODE>
|
||||
<LI><CODE>(make-table-maker<VAR> compare-proc hash-proc</VAR>) -> <VAR>procedure</VAR></CODE>
|
||||
<LI><CODE>(make-table-immutable!<VAR> table</VAR>)</CODE>
|
||||
</UL>
|
||||
The first four functions listed make various kinds of tables.
|
||||
<CODE>Make-table</CODE> returns a table whose keys may be symbols, integer,
|
||||
characters, booleans, or the empty list (these are also the values
|
||||
that may be used in <CODE>case</CODE> expressions).
|
||||
As with <CODE>case</CODE>, comparison is done using <CODE>eqv?</CODE>.
|
||||
The comparison procedures used in symbol, string, and integer tables are
|
||||
<CODE>eq?</CODE>, <CODE>string=?</CODE>, and <CODE>=</CODE>.
|
||||
<P><CODE>Make-table-maker</CODE> takes two procedures as arguments and returns
|
||||
a nullary table-making procedure.
|
||||
<CODE><VAR>Compare-proc</VAR></CODE> should be a two-argument equality predicate.
|
||||
<CODE><VAR>Hash-proc</VAR></CODE> should be a one argument procedure that takes a key
|
||||
and returns a non-negative integer hash value.
|
||||
If <CODE>(<CODE><VAR>compare-proc</VAR></CODE> <CODE><VAR>x</VAR></CODE> <CODE><VAR>y</VAR></CODE>)</CODE> returns true,
|
||||
then <CODE>(= (<CODE><VAR>hash-proc</VAR></CODE> <CODE><VAR>x</VAR></CODE>) (<CODE><VAR>hash-proc</VAR></CODE> <CODE><VAR>y</VAR></CODE>))</CODE>
|
||||
must also return true.
|
||||
For example, <CODE>make-integer-table</CODE> could be defined
|
||||
as <CODE>(make-table-maker = abs)</CODE>.
|
||||
<P><CODE>Make-table-immutable!</CODE> prohibits future modification to its argument.
|
||||
<UL><LI><CODE>(table?<VAR> value</VAR>) -> <VAR>boolean</VAR></CODE>
|
||||
<LI><CODE>(table-ref<VAR> table key</VAR>) -> <VAR>value or <CODE>#f</CODE></VAR></CODE>
|
||||
<LI><CODE>(table-set!<VAR> table key value</VAR>)</CODE>
|
||||
<LI><CODE>(table-walk<VAR> procedure table</VAR>)</CODE>
|
||||
</UL>
|
||||
<CODE>Table?</CODE> is the predicate for tables.
|
||||
<CODE>Table-ref</CODE> and <CODE>table-set!</CODE> access and modify the value of <CODE><VAR>key</VAR></CODE>
|
||||
in <CODE><VAR>table</VAR></CODE>.
|
||||
<CODE>Table-walk</CODE> applies <CODE><VAR>procedure</VAR></CODE>, which must accept two arguments,
|
||||
to every associated key and non-<CODE>#f</CODE> value in <CODE>table</CODE>.
|
||||
<UL><LI><CODE>(default-hash-function<VAR> value</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
<LI><CODE>(string-hash<VAR> string</VAR>) -> <VAR>integer</VAR></CODE>
|
||||
</UL>
|
||||
<CODE>default-hash-function</CODE> is the hash function used in the tables
|
||||
returned by <CODE>make-table</CODE>, and <CODE>string-hash</CODE> it the one used
|
||||
by <CODE>make-string-table</CODE>.
|
||||
<HR >
|
||||
</BODY></HTML>
|
||||
1417
doc/module.ps
1417
doc/module.ps
File diff suppressed because it is too large
Load Diff
|
|
@ -1,81 +0,0 @@
|
|||
-- this file is probably obsolete --
|
||||
|
||||
The package system interface. Much too complicated.
|
||||
|
||||
Signatures
|
||||
|
||||
make-simple-signature
|
||||
make-compound-signature
|
||||
signature?
|
||||
signature-ref
|
||||
signature-walk
|
||||
|
||||
Structures
|
||||
|
||||
make-structure
|
||||
structure?
|
||||
structure-signature
|
||||
structure-package
|
||||
structure-name
|
||||
|
||||
Packages
|
||||
|
||||
make-package
|
||||
make-simple-package ;start.scm
|
||||
|
||||
Lookup and definition operations
|
||||
|
||||
package-lookup
|
||||
package-lookup-type ;comp.scm
|
||||
package-find-location ;rts/env.scm
|
||||
package-lookup-location ;segment.scm
|
||||
probe-package
|
||||
package-check-assigned
|
||||
package-check-variable
|
||||
|
||||
package-define!
|
||||
package-define-type! ;hmm.
|
||||
package-ensure-defined!
|
||||
|
||||
Things needed by the form/file/package scanner
|
||||
|
||||
for-each-definition ;for integrate-all-primitives!
|
||||
package-accesses ;for scan-package
|
||||
package-clauses ;for scan-package
|
||||
package-file-name ;for scan-package
|
||||
package-opens ;for scan-package
|
||||
package-evaluator ;for define-syntax
|
||||
package-for-syntax ;for define-syntax
|
||||
|
||||
Miscellaneous
|
||||
|
||||
$note-undefined ;eval.scm
|
||||
noting-undefined-variables ;eval.scm, etc.
|
||||
package-uid ;eval.scm
|
||||
set-shadow-action! ;eval.scm
|
||||
verify-later! ;for the define-structures macro
|
||||
reset-packages-state! ;Makefile - for linker
|
||||
initialize-reified-package! ;for reification
|
||||
transform-for-structure-ref ;for reification ?
|
||||
|
||||
Inessential (for package mutation, programming environment)
|
||||
|
||||
check-structure
|
||||
package-integrate? ;env/debug.scm
|
||||
set-package-integrate?! ;env/debug.scm
|
||||
package-loaded? ;env/load-package.scm
|
||||
set-package-loaded?! ;env/load-package.scm
|
||||
package-name ;env/command.scm
|
||||
package-name-table ;env/debuginfo.scm
|
||||
package-open! ;env/debug.scm
|
||||
package-system-sentinel ;env/command.scm
|
||||
package-unstable? ;env/pacman.scm
|
||||
package? ;env/command.scm
|
||||
undefined-variables ;env/debug.scm
|
||||
|
||||
Location names (also inessential)
|
||||
|
||||
flush-location-names
|
||||
location-name
|
||||
location-name-table
|
||||
location-package-name
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
What to do when your system isn't supported
|
||||
|
||||
First of all: DON'T PANIC. It's easy to get scsh to work on a new
|
||||
system. Besides, you'll be a hero to the masses waiting for the Scheme
|
||||
Shell on your platform. There is a sample "generic" system in
|
||||
scsh/generic which you can copy as a base to modify. The modifications
|
||||
mainly involve pulling some constants in from C header files and hacking
|
||||
a few lines of C based on your standard I/O internals. I know, its C and
|
||||
all, together we can survive. If you need some hand holding, feel free
|
||||
to write to the scsh mailing list at scsh@zurich.ai.mit.edu.
|
||||
|
||||
stdio_dep.c:
|
||||
This is the one C file you have to actually deal with. The code in here
|
||||
defines two or three simple operations on stdio FILE*'s that are not
|
||||
part of the stdio.h interface. The main things it needs to be able
|
||||
to do is see if there is input ready, how much is ready, and to change
|
||||
the file descriptor associated with a FILE*. Usually how to do this
|
||||
is fairly obvious from <stdio.h>. Check out the other platforms for ideas.
|
||||
|
||||
errno.scm:
|
||||
Scheme defines for C header values found in <errno.h>.
|
||||
|
||||
fdflags.scm:
|
||||
Scheme defines for C header values found in <fcntl.h>.
|
||||
|
||||
netconst.scm:
|
||||
Scheme defines for C header values found in socket and network includes.
|
||||
|
||||
signals.scm:
|
||||
Scheme defines for C header values found in <sys/signal.h>.
|
||||
|
||||
waitcodes.scm:
|
||||
Scheme defines for C header values and macros found in <sys/wait.h>.
|
||||
|
||||
packages.scm:
|
||||
Scheme48 module definitions for the values in the above scheme files.
|
||||
|
||||
load-scsh.scm:
|
||||
The script of commands and expressions used to build scsh.
|
||||
|
||||
After you've hacked these files together, it'd be nice to also hack
|
||||
config.scsh to support your new machine. Run config.guess to see what it
|
||||
thinks your machine is. Then, send us the info, and we'll make sure it
|
||||
gets in a future release. (That means you, Jonathan.)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
*.aux *.log *.out
|
||||
*.idx *.ilg *.ind *.dvi
|
||||
.,*
|
||||
*.toc
|
||||
thumb*.png
|
||||
man.ps man.pdf
|
||||
|
|
@ -0,0 +1 @@
|
|||
html
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
.SUFFIXES: .tex .dvi .ps .pdf $(.SUFFIXES)
|
||||
|
||||
TEX= front.tex intro.tex procnotation.tex syscalls.tex network.tex \
|
||||
strings.tex awk.tex miscprocs.tex running.tex
|
||||
|
||||
TEX2PAGE=tex2page
|
||||
|
||||
man.dvi: $(TEX)
|
||||
man.pdf: $(TEX)
|
||||
|
||||
.dvi.ps:
|
||||
dvips -j0 -o $@ $<
|
||||
|
||||
.tex.dvi:
|
||||
latex $< && latex $<
|
||||
makeindex $(<:.tex=.idx)
|
||||
rm $*.log
|
||||
|
||||
.tex.pdf:
|
||||
pdflatex $< && thumbpdf $@ && pdflatex $<
|
||||
makeindex $(<:.tex=.idx)
|
||||
rm $*.log
|
||||
|
||||
clean:
|
||||
-rm -f *.log *.png man.out man.dvi man.ps man.pdf thumb*.png
|
||||
rm -rf html
|
||||
|
||||
INSTALL_DATA= install -c -m 644
|
||||
|
||||
tar:
|
||||
tar cf - *.tex sty | gzip > man.tar.gz
|
||||
|
||||
html: $(TEX)
|
||||
$(TEX2PAGE) man && $(TEX2PAGE) man
|
||||
|
||||
install: man.ps
|
||||
@echo WARNING:
|
||||
@echo WARNING: this depends on /u/su/scsh/scsh
|
||||
@echo WARNING: pointing to the current release
|
||||
@echo WARNING:
|
||||
$(INSTALL_DATA) cheat.txt /u/su/scsh/scsh/doc/
|
||||
$(INSTALL_DATA) man.ps /u/su/scsh/scsh/doc/scsh-manual.ps
|
||||
$(INSTALL_DATA) $(TEX) /u/su/scsh/scsh/doc/scsh-manual/
|
||||
$(INSTALL_DATA) sty/* /u/su/scsh/scsh/doc/scsh-manual/sty/
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
Michel.Schinz@studi.epfl.ch
|
||||
Documentation error in STRING-OUTPUT-PORT-OUTPUT.
|
||||
Reported 12/19.
|
||||
|
||||
Victor Zandy
|
||||
character-gobbling in (record-reader) caused by 'trim / 'peek
|
||||
default misunderstanding in delimited readers. Fixed 4/5/96
|
||||
|
||||
Michael Becker
|
||||
reap-policy = early can still lose if you loop and fork.
|
||||
fork now reaps & retries if it loses and the policy is early reap.
|
||||
This is a kludge until I have sigchld handlers.
|
||||
Fixed 4/5/96
|
||||
|
||||
Tod Olson
|
||||
Reported painfully slow delimited-reader I/O in November.
|
||||
|
||||
Michel.Schinz@studi.epfl.ch
|
||||
Reported some picky little typos in the manual.
|
||||
|
||||
Shriram
|
||||
Doc bugs in defrec.scm
|
||||
|
||||
euler@lavielle.COM (Lutz Euler) 2/24/97
|
||||
Manual bugs and a bug in stdio->stdports.
|
||||
|
||||
Alan Bawden 4/97
|
||||
Lots of good bug reports and fixes.
|
||||
|
||||
Jim Blandy 4/97
|
||||
Fixes for meta.scm
|
||||
|
||||
Kevin Esler 4/97
|
||||
Updated Irix port
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
Acknowledgements
|
||||
|
||||
Who should I thank? My so-called "colleagues," who laugh at me behind my
|
||||
back, all the while becoming famous on *my* work? My worthless graduate
|
||||
students, whose computer skills appear to be limited to downloading bitmaps
|
||||
off of netnews? My parents, who are still waiting for me to quit "fooling
|
||||
around with computers," go to med school, and become a radiologist? My
|
||||
department chairman, a manager who gives one new insight into and sympathy for
|
||||
disgruntled postal workers?
|
||||
|
||||
My God, no one could blame me--no one!--if I went off the edge and just lost
|
||||
it completely one day. I couldn't get through the day as it is without the
|
||||
Prozac and Jack Daniels I keep on the shelf, behind my Tops-20 JSYS manuals.
|
||||
I start getting the shakes real bad around 10am, right before my advisor
|
||||
meetings. A 10 oz. Jack 'n Zac helps me get through the meetings without one
|
||||
of my students winding up with his severed head in a bowling-ball bag. They
|
||||
look at me funny; they think I twitch a lot. I'm not twitching. I'm
|
||||
controlling my impulse to snag my 9mm Sig-Sauer out from my day-pack and make
|
||||
a few strong points about the quality of undergraduate education in Amerika.
|
||||
|
||||
If I thought anyone cared, if I thought anyone would even be reading this, I'd
|
||||
probably make an effort to keep up appearances until the last possible
|
||||
moment. But no one does, and no one will. So I can pretty much say exactly
|
||||
what I think.
|
||||
|
||||
Oh, yes, the *acknowledgements.* I think not. I did it. I did it all,
|
||||
by myself.
|
||||
|
||||
Olin Shivers
|
||||
Cambridge
|
||||
September 4, 1994
|
||||
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
%%
|
||||
%% This is file `/usr2/distrib/latex209/nfss/array.sty' generated
|
||||
%% on <1991/11/22> with the docstrip utility (v1.1k).
|
||||
%%
|
||||
%% The original source files were:
|
||||
%%
|
||||
%% /usr2/users/latex3/source/array/array.doc
|
||||
|
||||
%%
|
||||
%% Copyright (C) 1989,1990,1991 by Frank Mittelbach, Rainer Schoepf.
|
||||
%% All rights reserved.
|
||||
%%
|
||||
%% This file is part of the NFSS (New Font Selection Scheme) package.
|
||||
%%
|
||||
%% IMPORTANT NOTICE:
|
||||
%%
|
||||
%% You are not allowed to change this file. You may however copy this file
|
||||
%% to a file with a different name and then change the copy if you obey
|
||||
%% the restrictions on file changes described in readme.mz.
|
||||
%%
|
||||
%% You are allowed to distribute this file under the condition that it is
|
||||
%% distributed together with all files mentioned in readme.mz3. If you
|
||||
%% receive only some of these files from someone, complain!
|
||||
%%
|
||||
%% You are NOT ALLOWED to distribute this file alone. You are NOT ALLOWED
|
||||
%% to take money for the distribution or use of either this file or a
|
||||
%% changed version, except for a nominal charge for copying etc.
|
||||
%%
|
||||
%% For error reports in case of UNCHANGED versions see readme files.
|
||||
%%
|
||||
%% Please do not request updates from us directly. Distribution is done
|
||||
%% through Mail-Servers and TeX organizations.
|
||||
%%
|
||||
|
||||
\def\fileversion{v2.0e}
|
||||
\def\filedate{91/02/07}
|
||||
\def\docdate {90/08/20}
|
||||
|
||||
%% \CheckSum{681}
|
||||
%% \CharacterTable
|
||||
%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
|
||||
%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
|
||||
%% Digits \0\1\2\3\4\5\6\7\8\9
|
||||
%% Exclamation \! Double quote \" Hash (number) \#
|
||||
%% Dollar \$ Percent \% Ampersand \&
|
||||
%% Acute accent \' Left paren \( Right paren \)
|
||||
%% Asterisk \* Plus \+ Comma \,
|
||||
%% Minus \- Point \. Solidus \/
|
||||
%% Colon \: Semicolon \; Less than \<
|
||||
%% Equals \= Greater than \> Question mark \?
|
||||
%% Commercial at \@ Left bracket \[ Backslash \\
|
||||
%% Right bracket \] Circumflex \^ Underscore \_
|
||||
%% Grave accent \` Left brace \{ Vertical bar \|
|
||||
%% Right brace \} Tilde \~}
|
||||
%%
|
||||
\@ifundefined{d@llar}{}{\endinput}
|
||||
\typeout{Style-Option: `array' \fileversion
|
||||
\space\space <\filedate> (F.M.)}
|
||||
\typeout{English documentation dated \space <\docdate> (F.M.)}
|
||||
\def\@addtopreamble#1{\xdef\@preamble{\@preamble #1}}
|
||||
\def\@testpach#1{\@chclass
|
||||
\ifnum \@lastchclass=6 \@ne \@chnum \@ne \else
|
||||
\ifnum \@lastchclass=7 5 \else
|
||||
\ifnum \@lastchclass=8 \tw@ \else
|
||||
\ifnum \@lastchclass=9 \thr@@
|
||||
\else \z@
|
||||
\ifnum \@lastchclass = 10 \else
|
||||
\@chnum
|
||||
\if #1c\z@ \else
|
||||
\if #1l\@ne \else
|
||||
\if #1r\tw@ \else
|
||||
\z@ \@chclass
|
||||
\if#1|\@ne \else
|
||||
\if #1!6 \else
|
||||
\if #1@7 \else
|
||||
\if #1<8 \else
|
||||
\if #1>9 \else
|
||||
10
|
||||
\@chnum
|
||||
\if #1m\thr@@\else
|
||||
\if #1p4 \else
|
||||
\if #1b5 \else
|
||||
\z@ \@chclass \z@ \@preamerr \z@ \fi \fi \fi \fi
|
||||
\fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi}
|
||||
\def\@xexpast#1*#2#3#4\@@{%
|
||||
\@tempcnta #2
|
||||
\toks@={#1}\@temptokena={#3}%
|
||||
\let\the@toksz\relax \let\the@toks\relax
|
||||
\def\@tempa{\the@toksz}%
|
||||
\ifnum\@tempcnta >0 \@whilenum\@tempcnta >0\do
|
||||
{\edef\@tempa{\@tempa\the@toks}\advance \@tempcnta \m@ne}%
|
||||
\let \@tempb \@xexpast \else
|
||||
\let \@tempb \@xexnoop \fi
|
||||
\def\the@toksz{\the\toks@}\def\the@toks{\the\@temptokena}%
|
||||
\edef\@tempa{\@tempa}%
|
||||
\expandafter \@tempb \@tempa #4\@@}
|
||||
\def\prepnext@tok{\advance \count@ \@ne
|
||||
\toks\count@={}}
|
||||
\def\save@decl{\toks\count@ \expandafter{\@nextchar}}
|
||||
\def\insert@column{%
|
||||
\the@toks \the \@tempcnta
|
||||
{\ignorespaces \@sharp \unskip}%
|
||||
\the@toks \the \count@ \relax}
|
||||
\newdimen\col@sep
|
||||
\def\@acol{\@addtopreamble{\hskip\col@sep}}
|
||||
\def\@mkpream#1{\gdef\@preamble{}\@lastchclass 4 \@firstamptrue
|
||||
\let\@sharp\relax \let\@startpbox\relax \let\@endpbox\relax
|
||||
\@xexpast #1*0x\@@
|
||||
\count@\m@ne
|
||||
\let\the@toks\relax
|
||||
\prepnext@tok
|
||||
\expandafter \@tfor \expandafter \@nextchar
|
||||
\expandafter :\expandafter =\@tempa \do
|
||||
{\@testpach\@nextchar
|
||||
\ifcase \@chclass \@classz \or \@classi \or \@classii
|
||||
\or \save@decl \or \or \@classv \or \@classvi
|
||||
\or \@classvii \or \@classviii \or \@classix
|
||||
\or \@classx \fi
|
||||
\@lastchclass\@chclass}%
|
||||
\ifcase\@lastchclass
|
||||
\@acol \or
|
||||
\or
|
||||
\@acol \or
|
||||
\@preamerr \thr@@ \or
|
||||
\@preamerr \tw@ \@addtopreamble\@sharp \or
|
||||
\or
|
||||
\else \@preamerr \@ne \fi
|
||||
\def\the@toks{\the\toks}}
|
||||
\def\@classx{%
|
||||
\ifcase \@lastchclass
|
||||
\@acolampacol \or
|
||||
\@addamp \@acol \or
|
||||
\@acolampacol \or
|
||||
\or
|
||||
\@acol \@firstampfalse \or
|
||||
\@addamp
|
||||
\fi}
|
||||
\def\@classz{\@classx
|
||||
\@tempcnta \count@
|
||||
\prepnext@tok
|
||||
\@addtopreamble{\ifcase \@chnum
|
||||
\hfil
|
||||
\d@llar
|
||||
\insert@column
|
||||
\d@llar \hfil \or
|
||||
\d@llar \insert@column \d@llar \hfil \or
|
||||
\hfil\kern\z@ \d@llar \insert@column \d@llar \or
|
||||
$\vcenter
|
||||
\@startpbox{\@nextchar}\insert@column \@endpbox $\or
|
||||
\vtop \@startpbox{\@nextchar}\insert@column \@endpbox \or
|
||||
\vbox \@startpbox{\@nextchar}\insert@column \@endpbox
|
||||
\fi}\prepnext@tok}
|
||||
\def\@classix{\ifnum \@lastchclass = \thr@@
|
||||
\@preamerr \thr@@ \fi
|
||||
\@classx}
|
||||
\def\@classviii{\ifnum \@lastchclass >\z@
|
||||
\@preamerr 4\@chclass 6 \@classvi \fi}
|
||||
\def\@arrayrule{\@addtopreamble \vline}
|
||||
\def\@classvii{\ifnum \@lastchclass = \thr@@
|
||||
\@preamerr \thr@@ \fi}
|
||||
\def\@classvi{\ifcase \@lastchclass
|
||||
\@acol \or
|
||||
\@addtopreamble{\hskip \doublerulesep}\or
|
||||
\@acol \or
|
||||
\@classvii
|
||||
\fi}
|
||||
\def\@classii{\advance \count@ \m@ne
|
||||
\save@decl\prepnext@tok}
|
||||
\def\@classv{\save@decl
|
||||
\@addtopreamble{\d@llar\the@toks\the\count@\relax\d@llar}%
|
||||
\prepnext@tok}
|
||||
\def\@classi{\@classvi
|
||||
\ifcase \@chnum \@arrayrule \or
|
||||
\@classv \fi}
|
||||
\def\@startpbox#1{\bgroup
|
||||
\hsize #1 \@arrayparboxrestore
|
||||
\vrule \@height \ht\@arstrutbox \@width \z@}
|
||||
\def\@endpbox{\vrule \@width \z@ \@depth \dp \@arstrutbox \egroup}
|
||||
\def\@array[#1]#2{%
|
||||
\@tempdima \ht \strutbox
|
||||
\advance \@tempdima by\extrarowheight
|
||||
\setbox \@arstrutbox \hbox{\vrule
|
||||
\@height \arraystretch \@tempdima
|
||||
\@depth \arraystretch \dp \strutbox
|
||||
\@width \z@}%
|
||||
\begingroup
|
||||
\@mkpream{#2}%
|
||||
\xdef\@preamble{\ialign \@halignto
|
||||
\bgroup \@arstrut \@preamble
|
||||
\tabskip \z@ \cr}%
|
||||
\endgroup
|
||||
\if #1t\vtop \else \if#1b\vbox \else \vcenter \fi \fi
|
||||
\bgroup
|
||||
\let \@sharp ##\let \protect \relax
|
||||
\lineskip \z@
|
||||
\baselineskip \z@
|
||||
\m@th
|
||||
\let\\ \@arraycr \let\par\@empty \@preamble}
|
||||
\newdimen \extrarowheight
|
||||
\extrarowheight=0pt
|
||||
\def\@arstrut{\unhcopy\@arstrutbox}
|
||||
\def\@arraycr{{\ifnum 0=`}\fi
|
||||
\@ifstar \@xarraycr \@xarraycr}
|
||||
\def\@xarraycr{\@ifnextchar [%
|
||||
\@argarraycr {\ifnum 0=`{\fi}\cr}}
|
||||
\def\@argarraycr[#1]{\ifnum0=`{\fi}\ifdim #1>\z@
|
||||
\@xargarraycr{#1}\else \@yargarraycr{#1}\fi}
|
||||
\def\@xargarraycr#1{\unskip
|
||||
\@tempdima #1\advance\@tempdima \dp\@arstrutbox
|
||||
\vrule \@depth\@tempdima \@width\z@ \cr}
|
||||
\def\@yargarraycr#1{\cr\noalign{\vskip #1}}
|
||||
\def\multicolumn#1#2#3{%
|
||||
\multispan{#1}\begingroup
|
||||
\def\@addamp{\if@firstamp \@firstampfalse \else
|
||||
\@preamerr 5\fi}%
|
||||
\@mkpream{#2}\@addtopreamble\@empty
|
||||
\endgroup
|
||||
\def\@sharp{#3}%
|
||||
\@arstrut \@preamble \ignorespaces}
|
||||
\def\array{\col@sep\arraycolsep
|
||||
\def\d@llar{$}\gdef\@halignto{}%
|
||||
\@tabarray}
|
||||
\def\@tabarray{\@ifnextchar[{\@array}{\@array[c]}}
|
||||
\def\tabular{\gdef\@halignto{}\@tabular}
|
||||
\expandafter\def\csname tabular*\endcsname#1{%
|
||||
\gdef\@halignto{to#1}\@tabular}
|
||||
\def\@tabular{%
|
||||
\leavevmode
|
||||
\hbox \bgroup $\col@sep\tabcolsep \let\d@llar\@empty
|
||||
\@tabarray}
|
||||
\def\endarray{\crcr \egroup \egroup \gdef\@preamble{}}
|
||||
\def\endtabular{\endarray $\egroup}
|
||||
\expandafter\let\csname endtabular*\endcsname=\endtabular
|
||||
\let\@ampacol=\relax \let\@expast=\relax
|
||||
\let\@arrayclassiv=\relax \let\@arrayclassz=\relax
|
||||
\let\@tabclassiv=\relax \let\@tabclassz=\relax
|
||||
\let\@arrayacol=\relax \let\@tabacol=\relax
|
||||
\let\@tabularcr=\relax \let\@@endpbox=\relax
|
||||
\let\@argtabularcr=\relax \let\@xtabularcr=\relax
|
||||
\def\@preamerr#1{\def\@tempd{{..} at wrong position: }%
|
||||
\@latexerr{%
|
||||
\ifcase #1 Illegal pream-token (\@nextchar): `c' used\or %0
|
||||
Missing arg: token ignored\or %1
|
||||
Empty preamble: `l' used\or %2
|
||||
>\@tempd token ignored\or %3
|
||||
<\@tempd changed to !{..}\or %4
|
||||
Only one colum-spec. allowed.\fi}\@ehc} %5
|
||||
\def\@tfor#1:=#2\do#3{\def\@fortmp{#2}\ifx\@fortmp\@empty
|
||||
\else\@tforloop#2\@nil\@nil\@@#1{#3}\fi}
|
||||
\endinput
|
||||
%%
|
||||
%% End of file `/usr2/distrib/latex209/nfss/array.sty'.
|
||||
|
|
@ -0,0 +1,672 @@
|
|||
%&latex -*- latex -*-
|
||||
|
||||
\chapter{Awk, record I/O, and field parsing}
|
||||
\label{chapt:fr-awk}
|
||||
|
||||
{\Unix} programs frequently process streams of records,
|
||||
where each record is delimited by a newline,
|
||||
and records are broken into fields with other delimiters
|
||||
(for example, the colon character in \ex{/etc/passwd}).
|
||||
Scsh has procedures that allow the programmer to easily
|
||||
do this kind of processing.
|
||||
Scsh's field parsers can also be used to parse other kinds
|
||||
of delimited strings, such as colon-separated \verb|$PATH| lists.
|
||||
These routines can be used with scsh's \ex{awk} loop construct
|
||||
to conveniently perform pattern-directed computation over streams
|
||||
of records.
|
||||
|
||||
|
||||
\section{Record I/O and field parsing}
|
||||
\label{sec:field-reader}
|
||||
|
||||
The procedures in this section are used to read records from
|
||||
I/O streams and parse them into fields.
|
||||
A record is defined as text terminated by some delimiter (usually a newline).
|
||||
A record can be split into fields by using regular expressions in
|
||||
one of several ways: to \emph{match} fields, to \emph{separate} fields,
|
||||
or to \emph{terminate} fields.
|
||||
The field parsers can be applied to arbitrary strings (one common use is
|
||||
splitting environment variables such as \ex{\$PATH} at colons into its
|
||||
component elements).
|
||||
|
||||
The general delimited-input procedures described in
|
||||
chapter~\ref{chapt:rdelim} are also useful for reading simple records,
|
||||
such as single lines, paragraphs of text, or strings terminated by specific
|
||||
characters.
|
||||
|
||||
\subsection{Reading records}
|
||||
|
||||
\defun{record-reader} {[delims elide-delims? handle-delim]} {\proc}
|
||||
\begin{desc}
|
||||
Returns a procedure that reads records from a port. The
|
||||
procedure is invoked as follows:
|
||||
%
|
||||
\codex{(\var{reader} \var{[port]}) $\longrightarrow$
|
||||
\textrm{\textit{{\str} or eof}}}
|
||||
%
|
||||
A record is a sequence of characters terminated by one of the characters
|
||||
in \var{delims} or eof. If \var{elide-delims?} is true, then a contiguous
|
||||
sequence of delimiter chars are taken as a single record delimiter. If
|
||||
\var{elide-delims?} is false, then a delimiter char coming immediately
|
||||
after a delimiter char produces an empty-string record. The reader
|
||||
consumes the delimiting char(s) before returning from a read.
|
||||
|
||||
The \var{delims} set defaults to the set $\{\mbox{newline}\}$.
|
||||
It may be a charset, string, character, or character predicate,
|
||||
and is coerced to a charset.
|
||||
The \var{elide-delims?} flag defaults to \ex{\#f}.
|
||||
|
||||
The \var{handle-delim} argument controls what is done with the record's
|
||||
terminating delimiter.
|
||||
\begin{inset}
|
||||
\begin{tabular}{lp{0.6\linewidth}}
|
||||
\ex{'trim} & Delimiters are trimmed. (The default)\\
|
||||
\ex{'split}& Reader returns delimiter string as a second argument.
|
||||
If record is terminated by EOF, then the eof object is
|
||||
returned as this second argument. \\
|
||||
\ex{'concat} & The record and its delimiter are returned as
|
||||
a single string.
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
|
||||
The reader procedure returned takes one optional argument, the port
|
||||
from which to read, which defaults to the current input port. It returns
|
||||
a string or eof.
|
||||
\end{desc}
|
||||
|
||||
|
||||
\subsection{Parsing fields}
|
||||
\label{sec:field-splitter}
|
||||
|
||||
\defun {field-splitter} {[field num-fields]} \proc
|
||||
\defunx {infix-splitter} {[delim num-fields handle-delim]} \proc
|
||||
\defunx {suffix-splitter} {[delim num-fields handle-delim]} \proc
|
||||
\defunx {sloppy-suffix-splitter} {[delim num-fields handle-delim]} \proc
|
||||
\begin{desc}
|
||||
These functions return a parser function that can be used as follows:
|
||||
\codex{(\var{parser} \var{string} \var{[start]}) $\longrightarrow$
|
||||
\var{string-list}}
|
||||
|
||||
The returned parsers split strings into fields defined
|
||||
by regular expressions. You can parse by specifying a pattern that
|
||||
\emph{separates} fields, a pattern that \emph{terminates} fields, or
|
||||
a pattern that \emph{matches} fields:
|
||||
\begin{inset}
|
||||
\begin{tabular}{l@{\qquad}l}
|
||||
Procedure & Pattern \\ \hline
|
||||
\ex{field-splitter} & matches fields \\
|
||||
\ex{infix-splitter} & separates fields \\
|
||||
\ex{suffix-splitter}& terminates fields \\
|
||||
\ex{sloppy-suffix-splitter} & terminates fields
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
|
||||
These parser generators are controlled by a range of options, so that you
|
||||
can precisely specify what kind of parsing you want. However, these
|
||||
options default to reasonable values for general use.
|
||||
|
||||
Defaults:
|
||||
\begin{tightinset}
|
||||
\begin{tabular}{l@{\quad=\quad }ll}
|
||||
\var{delim} & \ex{(rx (| (+ white) eos))} & (suffix delimiter: white space or eos) \\
|
||||
\multicolumn{1}{l}{} & \ex{(rx (+ white))} & (infix delimiter: white space) \\
|
||||
|
||||
\var{field} & \verb|(rx (+ (~ white)))| & (non-white-space) \\
|
||||
|
||||
\var{num-fields} & \verb|#f| & (as many fields as possible) \\
|
||||
|
||||
\var{handle-delim} & \verb|'trim| & (discard delimiter chars)
|
||||
\end{tabular}
|
||||
\end{tightinset}
|
||||
{\ldots}which means: break the string at white space, discarding the
|
||||
white space, and parse as many fields as possible.
|
||||
|
||||
The \var{delim} parameter is a regular expression matching the text
|
||||
that occurs between fields.
|
||||
See chapter~\ref{chapt:sre} for information on regular expressions,
|
||||
and the \ex{rx} form used to specify them.
|
||||
In the separator case,
|
||||
it defaults to a pattern matching white space;
|
||||
in the terminator case,
|
||||
it defaults to white space or end-of-string.
|
||||
|
||||
The \var{field} parameter is a regular expression used
|
||||
to match fields. It defaults to non-white-space.
|
||||
|
||||
The \var{delim} patterns may also be given as a string,
|
||||
character, or char-set, which are coerced to regular expressions.
|
||||
So the following expressions are all equivalent,
|
||||
each producing a function that splits strings apart at colons:
|
||||
\begin{inset}
|
||||
\begin{verbatim}
|
||||
(infix-splitter (rx ":"))
|
||||
(infix-splitter ":")
|
||||
(infix-splitter #\:)
|
||||
(infix-splitter (char-set #\:))\end{verbatim}
|
||||
\end{inset}
|
||||
|
||||
The boolean \var{handle-delim} determines what to do with delimiters.
|
||||
\begin{tightinset}\begin{tabular}{ll}
|
||||
\ex{'trim} & Delimiters are thrown away after parsing. (default) \\
|
||||
\ex{'concat} & Delimiters are appended to the field preceding them. \\
|
||||
\ex{'split} & Delimiters are returned as separate elements in
|
||||
the field list.
|
||||
\end{tabular}
|
||||
\end{tightinset}
|
||||
|
||||
The \var{num-fields} argument used to create the parser specifies how many
|
||||
fields to parse. If \ex{\#f} (the default), the procedure parses them all.
|
||||
If a positive integer $n$, exactly that many fields are parsed; it is an
|
||||
error if there are more or fewer than $n$ fields in the record. If
|
||||
\var{num-fields} is a negative integer or zero, then $|n|$ fields
|
||||
are parsed, and the remainder of the string is returned in the last
|
||||
element of the field list; it is an error if fewer than $|n|$ fields
|
||||
can be parsed.
|
||||
|
||||
The field parser produced is a procedure that can be employed as
|
||||
follows:
|
||||
\codex{(\var{parse} \var{string} \var{[start]}) \evalto \var{string-list}}
|
||||
The optional \var{start} argument (default 0) specifies where in the string
|
||||
to begin the parse. It is an error if
|
||||
$\var{start} > \ex{(string-length \var{string})}$.
|
||||
|
||||
The parsers returned by the four parser generators implement different
|
||||
kinds of field parsing:
|
||||
\begin{description}
|
||||
\item[\ex{field-splitter}]
|
||||
The regular expression specifies the actual field.
|
||||
|
||||
|
||||
\item[\ex{suffix-splitter}]
|
||||
Delimiters are interpreted as element \emph{terminators}.
|
||||
If vertical-bar is the the delimiter, then the string \ex{""}
|
||||
is the empty record \ex{()}, \ex{"foo|"} produces a one-field record
|
||||
\ex{("foo")}, and \ex{"foo"} is an error.
|
||||
|
||||
The syntax of suffix-delimited records is:
|
||||
\begin{inset}
|
||||
\begin{tabular}{lcll}
|
||||
\synvar{record} & ::= & \ex{""} \qquad (Empty record) \\
|
||||
& $|$ & \synvar{element} \synvar{delim}
|
||||
\synvar{record}
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
|
||||
It is an error if a non-empty record does not end with a delimiter.
|
||||
To make the last delimiter optional, make sure the delimiter regexp
|
||||
matches the end-of-string (sre \ex{eos}).
|
||||
|
||||
\item [\ex{infix-splitter}]
|
||||
Delimiters are interpreted as element \emph{separators}. If comma is the
|
||||
delimiter, then the string \ex{"foo,"} produces a two-field
|
||||
record \ex{("foo" "")}.
|
||||
|
||||
The syntax of infix-delimited records is:
|
||||
\begin{inset}
|
||||
\begin{tabular}{lcll}
|
||||
\synvar{record} & ::= & \ex{""} \qquad (Forced to be empty record) \\
|
||||
& $|$ & \synvar{real-infix-record} \\
|
||||
\\
|
||||
\synvar{real-infix-record} & ::= & \synvar{element} \synvar{delim}
|
||||
\synvar{real-infix-record} \\
|
||||
& $|$ & \synvar{element}
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
|
||||
Note that separator semantics doesn't really allow for empty
|
||||
records---the straightforward grammar (\ie, \synvar{real-infix-record})
|
||||
parses an empty string as a singleton list whose one field is the empty
|
||||
string, \ex{("")}, not as the empty record \ex{()}. This is unfortunate,
|
||||
since it means that infix string parsing doesn't make \ex{string-append}
|
||||
and \ex{append} isomorphic. For example,
|
||||
\codex{((infix-splitter ":") (string-append \var{x} ":" \var{y}))}
|
||||
doesn't always equal
|
||||
\begin{code}
|
||||
(append ((infix-splitter ":") \var{x})
|
||||
((infix-splitter ":") \var{y}))\end{code}
|
||||
It fails when \var{x} or \var{y} are the empty string.
|
||||
Terminator semantics \emph{does} preserve a similar isomorphism.
|
||||
|
||||
However, separator semantics is frequently what other Unix software
|
||||
uses, so to parse their strings, we need to use it. For example,
|
||||
Unix \verb|$PATH| lists have separator semantics. The path list
|
||||
\ex{"/bin:"} is broken up into \ex{("/bin" "")}, not \ex{("/bin")}.
|
||||
Comma-separated lists should also be parsed this way.
|
||||
|
||||
\item[\ex{sloppy-suffix}]
|
||||
The same as the \ex{suffix} case, except that the parser will skip an
|
||||
initial delimiter string if the string begins with one instead of parsing
|
||||
an initial empty field. This can be used, for example, to field-split a
|
||||
sequence of English text at white-space boundaries, where the string may
|
||||
begin or end with white space, by using regex
|
||||
\begin{code}{(rx (| (+ white) eos))}\end{code}
|
||||
(But you would be better off using \ex{field-splitter} in this case.)
|
||||
\end{description}
|
||||
\end{desc}
|
||||
|
||||
Figure~\ref{fig:splitters} shows how the different parser grammars
|
||||
split apart the same strings.
|
||||
%
|
||||
\begin{boxedfigure}{tbp}
|
||||
\begin{center}\small
|
||||
\begin{tabular}{lllll}
|
||||
Record & : suffix & \verb!:|$! suffix & : infix & non-: field \\
|
||||
\hline
|
||||
\ex{""} & \ex{()} & \ex{()} & \ex{()} & \ex{()} \\
|
||||
\ex{":"} & \ex{("")} & \ex{("")} & \ex{("" "")} & \ex{()} \\
|
||||
\ex{"foo:"} & \ex{("foo")} & \ex{("foo")} & \ex{("foo" "")} & \ex{("foo")} \\
|
||||
\ex{":foo"}& \emph{error} & \ex{("" "foo")}& \ex{("" "foo")}& \ex{("foo")} \\
|
||||
\ex{"foo:bar"} & \emph{error} & \ex{("foo" "bar")} & \ex{("foo" "bar")} & \ex{("foo" "bar")}
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
\caption{Using different grammars to split records into fields.}
|
||||
\label{fig:splitters}
|
||||
\end{boxedfigure}
|
||||
%
|
||||
Having to choose between the different grammars requires you to decide
|
||||
what you want, but at least you can be precise about what you are parsing.
|
||||
Take fifteen seconds and think it out. Say what you mean; mean what you
|
||||
say.
|
||||
|
||||
|
||||
\defun{join-strings} {string-list [delimiter grammar]} \str
|
||||
\begin{desc}
|
||||
This procedure is a simple unparser---it pastes strings together using
|
||||
the delimiter string.
|
||||
|
||||
The \var{grammar} argument is one of the symbols \ex{infix} (the default)
|
||||
or \ex{suffix}; it determines whether the
|
||||
delimiter string is used as a separator or as a terminator.
|
||||
|
||||
The delimiter is the string used to delimit elements; it defaults to
|
||||
a single space \ex{" "}.
|
||||
|
||||
Example:
|
||||
\begin{code}
|
||||
(join-strings '("foo" "bar" "baz") ":")
|
||||
\qquad{\evalto} "foo:bar:baz"\end{code}
|
||||
\end{desc}
|
||||
|
||||
\subsection{Field readers}
|
||||
|
||||
\defun{field-reader} {[field-parser rec-reader]} \proc
|
||||
\begin{desc}
|
||||
This utility returns a procedure that reads records with field structure
|
||||
from a port.
|
||||
The reader's interface is designed to make it useful in the \ex{awk}
|
||||
loop macro (section~\ref{sec:awk}).
|
||||
The reader is used as follows:
|
||||
\codex{(\var{reader} \var{[port]}) {\evalto} \var{[raw-record parsed-record]} or \var{[eof ()]}}
|
||||
|
||||
When the reader is applied to an input port (default: the current
|
||||
input port), it reads a record using \var{rec-reader}. If this record isn't
|
||||
the eof object, it is parsed with \var{field-parser}. These two
|
||||
values---the record, and its parsed representation---are returned
|
||||
as multiple values from the reader.
|
||||
|
||||
When called at eof, the reader returns [eof-object \ex{()}].
|
||||
|
||||
Although the record reader typically returns a string, and
|
||||
the field-parser typically takes a string argument, this is not
|
||||
required. The record reader can produce, and the field-parser consume,
|
||||
values of any type. However, the empty list returned as the
|
||||
parsed value on eof is hardwired into the field reader.
|
||||
|
||||
For example, if port \ex{p} is open on \ex{/etc/passwd}, then
|
||||
\codex{((field-reader (infix-splitter ":" 7)) p)}
|
||||
returns two values:
|
||||
{\small
|
||||
\begin{widecode}
|
||||
"dalbertz:mx3Uaqq0:107:22:David Albertz:/users/dalbertz:/bin/csh"
|
||||
("dalbertz" "mx3Uaqq0" "107" "22" "David Albertz" "/users/dalbertz"
|
||||
"/bin/csh")\end{widecode}}
|
||||
The \var{field-parser} defaults to the value of \ex{(field-splitter)},
|
||||
a parser that picks out sequences of non-white-space strings.
|
||||
|
||||
The \var{rec-reader} defaults to \ex{read-line}.
|
||||
|
||||
Figure~\ref{fig:field-readers} shows \ex{field-reader} being
|
||||
used to read different kinds of Unix records.
|
||||
|
||||
\begin{boxedfigure}{tbhp}
|
||||
\begin{centercode}
|
||||
;;; /etc/passwd reader
|
||||
(field-reader (infix-splitter ":" 7))
|
||||
; wandy:3xuncWdpKhR.:73:22:Wandy Saetan:/usr/wandy:/bin/csh
|
||||
|
||||
;;; Two ls -l output readers
|
||||
(field-reader (infix-splitter (rx (+ white)) 8))
|
||||
(field-reader (infix-splitter (rx (+ white)) -7))
|
||||
; -rw-r--r-- 1 shivers 22880 Sep 24 12:45 scsh.scm
|
||||
|
||||
;;; Internet hostname reader
|
||||
(field-reader (field-splitter (rx (+ (~ ".")))))
|
||||
; stat.sinica.edu.tw
|
||||
|
||||
;;; Internet IP address reader
|
||||
(field-reader (field-splitter (rx (+ (~ "."))) 4))
|
||||
; 18.24.0.241
|
||||
|
||||
;;; Line of integers
|
||||
(let ((parser (field-splitter (rx (? ("+-")) (+ digit)))))
|
||||
(field-reader (\l{s} (map string->number (parser s))))
|
||||
; 18 24 0 241
|
||||
|
||||
;;; Same as above.
|
||||
(let ((reader (field-reader (field-splitter (rx (? ("+-"))
|
||||
(+ digit))))))
|
||||
(\lx{maybe-port} (map string->number (apply reader maybe-port))))
|
||||
; Yale beat harvard 26 to 7.\end{centercode}
|
||||
\caption{Some examples of \protect\ex{field-reader}}
|
||||
\label{fig:field-readers}
|
||||
\end{boxedfigure}
|
||||
|
||||
\end{desc}
|
||||
|
||||
|
||||
\subsection{Forward-progress guarantees and empty-string matches}
|
||||
A loop that pulls text off a string by repeatedly matching a regexp
|
||||
against that string can conceivably get stuck in an infinite loop if
|
||||
the regexp matches the empty string. For example, the SREs
|
||||
\ex{bos}, \ex{eos}, \ex{(* any)}, and \ex{(| "foo" (* (~ "f")))}
|
||||
can all match the empty string.
|
||||
|
||||
The routines in this package that iterate through strings with regular
|
||||
expressions are careful to handle this empty-string case.
|
||||
If a regexp matches the empty string, the next search starts, not from
|
||||
the end of the match (which in the empty string case is also the
|
||||
beginning---that's the problem), but from the next character over.
|
||||
This is the correct behaviour. Regexps match the longest possible
|
||||
string at a given location, so if the regexp matched the empty string
|
||||
at location $i$, then it is guaranteed it could not have matched
|
||||
a longer pattern starting with character $i$. So we can safely begin
|
||||
our search for the next match at char $i+1$.
|
||||
|
||||
With this provision, every iteration through the loop makes some forward
|
||||
progress, and the loop is guaranteed to terminate.
|
||||
|
||||
This has the effect you want with field parsing. For example, if you split
|
||||
a string with the empty pattern, you will explode the string into its
|
||||
individual characters:
|
||||
\codex{((suffix-splitter (rx)) "foo") {\evalto} ("" "f" "o" "o")}
|
||||
However, even though this boundary case is handled correctly, we don't
|
||||
recommend using it. Say what you mean---just use a field splitter:
|
||||
\codex{((field-splitter (rx any)) "foo") {\evalto} ("f" "o" "o")}
|
||||
Or, more efficiently,
|
||||
\codex{((\l{s} (map string (string->list s))) "foo")}
|
||||
|
||||
|
||||
\subsection{Reader limitations}
|
||||
Since all of the readers in this package require the ability to peek
|
||||
ahead one char in the input stream, they cannot be applied to raw
|
||||
integer file descriptors, only Scheme input ports. This is because
|
||||
Unix doesn't support peeking ahead into input streams.
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Awk}
|
||||
\label{sec:awk}
|
||||
|
||||
Scsh provides a loop macro and a set of field parsers that can
|
||||
be used to perform text processing very similar to the Awk programming
|
||||
language.
|
||||
The basic functionality of Awk is factored in scsh into its component
|
||||
parts.
|
||||
The control structure is provided by the \ex{awk} loop macro;
|
||||
the text I/O and parsers are provided by the field-reader subroutine library
|
||||
(section~\ref{sec:field-reader}).
|
||||
This factoring allows the programmer to compose the basic loop structure
|
||||
with any parser or input mechanism at all.
|
||||
If the parsers provided by the field-reader package are insufficient,
|
||||
the programmer can write a custom parser in Scheme and use it with
|
||||
equal ease in the awk framework.
|
||||
|
||||
Awk-in-scheme is given by a loop macro called \ex{awk}. It looks like
|
||||
this:
|
||||
\begin{code}\cdmath
|
||||
(awk \synvar{next-record} \synvar{record\&field-vars}
|
||||
{\rm[\synvar{counter}]} \synvar{state-var-decls}
|
||||
\synvar{clause$_1$} \ldots)\index{awk}\end{code}
|
||||
|
||||
The body of the loop is a series of clauses, each one representing
|
||||
a kind of condition/action pair. The loop repeatedly reads a record,
|
||||
and then executes each clause whose condition is satisfied by the record.
|
||||
|
||||
Here's an example that reads lines from port \ex{p}
|
||||
and prints the line number and line of every line containing the
|
||||
string ``\ex{Church-Rosser}'':
|
||||
\begin{code}
|
||||
(awk (read-line) (ln) lineno ()
|
||||
("Church-Rosser" (format #t "~d: ~s~%" lineno ln)))\end{code}
|
||||
This example has just one clause in the loop body, the one that
|
||||
tests for matches against the regular expression ``\ex{Church-Rosser}''.
|
||||
|
||||
The \synvar{next-record} form is an expression that is evaluated each time
|
||||
through the loop to produce a record to process.
|
||||
This expression can return multiple values;
|
||||
these values are bound to the variables given in the
|
||||
\synvar{record\&field-vars} list of variables.
|
||||
The first value returned is assumed to be the record;
|
||||
when it is the end-of-file object, the loop terminates.
|
||||
|
||||
For example, let's suppose we want to read items from \ex{/etc/password},
|
||||
and we use the \ex{field-reader} procedure to define a record parser for
|
||||
\ex{/etc/passwd} entries:
|
||||
\codex{(define read-passwd (field-reader (infix-splitter ":" 7)))}
|
||||
binds \ex{read-passwd} to a procedure that reads in a line of text when
|
||||
it is called, and splits the text at colons. It returns two values:
|
||||
the entire line read, and a seven-element list of the split-out fields.
|
||||
(See section~\ref{sec:field-reader} for more on \ex{field-reader} and
|
||||
\ex{infix-splitter}.)
|
||||
|
||||
So if the \synvar{next-record} form in an \ex{awk} expression is
|
||||
\ex{(read-passwd)}, then \synvar{record\&field-vars} must be a list of
|
||||
two variables, \eg,
|
||||
\codex{(record field-vec)}
|
||||
since \ex{read-passwd} returns two values.
|
||||
|
||||
Note that \ex{awk} allows us to use \emph{any} record reader we want in the
|
||||
loop, returning whatever number of values we like. These values
|
||||
don't have to be strings or string lists. The only requirement
|
||||
is that the record reader return the eof object as its first value
|
||||
when the loop should terminate.
|
||||
|
||||
The \ex{awk} loop allows the programmer to have loop variables. These are
|
||||
declared and initialised by the \synvar{state-var-decls} form, a
|
||||
\codex{((\var{var} \var{init-exp}) (\var{var} \var{init-exp}) \ldots)}
|
||||
list rather like the \ex{let} form. Whenever a clause in the loop body
|
||||
executes, it evaluates to as many values as there are state variables,
|
||||
updating them.
|
||||
|
||||
The optional \synvar{counter} variable is an iteration counter.
|
||||
It is bound to 0 when the loop starts.
|
||||
The counter is incremented each time a non-eof record is read.
|
||||
|
||||
There are several kinds of loop clause. When evaluating the body of the
|
||||
loop, \ex{awk} evaluates \emph{all} the clauses sequentially.
|
||||
Unlike \ex{cond}, it does not stop after the first clause is satisfied;
|
||||
it checks them all.
|
||||
|
||||
\begin{itemize}
|
||||
|
||||
\itum{\ex{(\var{test} \vari{body}1 \vari{body}2 \ldots)}}
|
||||
If \var{test} is true, execute the body forms. The last body form
|
||||
is the value of the clause. The test and body forms are evaluated
|
||||
in the scope of the record and state variables.
|
||||
|
||||
The \var{test} form can be one of:
|
||||
\begin{inset}
|
||||
\begin{tabular}{lp{0.6\linewidth}}
|
||||
\var{integer}: & The test is true for that iteration of the loop.
|
||||
The first iteration is \#1. \\
|
||||
|
||||
\var{sre}: & A regular expression, in SRE notation
|
||||
(see chapter~\ref{chapt:sre}) can be used as
|
||||
a test. The test is successful if the pattern
|
||||
matches the record.
|
||||
In particular, note that any string is an SRE. \\
|
||||
|
||||
\ex{(when \var{expr})}: &
|
||||
The body of a \ex{when} test is evaluated as a
|
||||
Scheme boolean expression in the inner scope of the
|
||||
\ex{awk} form. \\
|
||||
|
||||
\var{expr}: & If the form is none of the above, it is treated as
|
||||
a Scheme expression---in practice, the \ex{when}
|
||||
keyword is only needed in cases where SRE/Scheme
|
||||
expression ambiguity might occur.
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
|
||||
|
||||
\itum{\begin{tabular}[t]{l}
|
||||
\ex{(range\ \ \ \var{start-test} \var{stop-test} \vari{body}1 \ldots)} \\
|
||||
\ex{(:range\ \ \var{start-test} \var{stop-test} \vari{body}1 \ldots)} \\
|
||||
\ex{(range:\ \ \var{start-test} \var{stop-test} \vari{body}1 \ldots)} \\
|
||||
\ex{(:range:\ \var{start-test} \var{stop-test} \vari{body}1 \ldots)}
|
||||
\end{tabular}}
|
||||
%
|
||||
These clauses become activated when \var{start-test} is true;
|
||||
they stay active on all further iterations until \var{stop-test}
|
||||
is true.
|
||||
|
||||
So, to print out the first ten lines of a file, we use the clause:
|
||||
\codex{(:range: 1 10 (display record))}
|
||||
|
||||
The colons control whether or not the start and stop lines
|
||||
are processed by the clause. For example:
|
||||
\begin{inset}\begin{tabular}{l@{\qquad}l}
|
||||
\ex{(range\ \ \ 1 5\ \ \ldots)} & Lines \phantom{1} 2 3 4 \\
|
||||
\ex{(:range\ \ 1 5\ \ \ldots)} & Lines 1 2 3 4 \\
|
||||
\ex{(range:\ \ 1 5\ \ \ldots)} & Lines \phantom{1} 2 3 4 5 \\
|
||||
\ex{(:range: 1 5\ \ \ldots)} & Lines 1 2 3 4 5
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
|
||||
A line can trigger both tests, either simultaneously starting and
|
||||
stopping an active region, or simultaneously stopping one and starting
|
||||
a new one, so ranges can abut seamlessly.
|
||||
|
||||
\itum{\ex{(else \vari{body}1 \vari{body}2 \ldots)}}
|
||||
If no other clause has executed since the top of the loop, or
|
||||
since the last \ex{else} clause, this clause executes.
|
||||
|
||||
\itum{\ex{(\var{test} => \var{exp})}}
|
||||
If evaluating \ex{test} produces a true value,
|
||||
apply \var{exp} to that value.
|
||||
If \var{test} is a regular expression, then \var{exp} is applied
|
||||
to the match data structure returned by the regexp match routine.
|
||||
|
||||
\itum{\ex{(after \vari{body}1 \ldots)}}
|
||||
This clause executes when the loop encounters EOF. The body forms
|
||||
execute in the scope of the state vars and the record-count var,
|
||||
if there are any. The value of the last body form is the value
|
||||
of the entire awk form.
|
||||
|
||||
If there is no \ex{after} clause, \ex{awk} returns the loop's state
|
||||
variables as multiple values.
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Examples}
|
||||
Here are some examples of \ex{awk} being used to process various types
|
||||
of input stream.
|
||||
|
||||
\begin{code}
|
||||
(define $ list-ref) ; Saves typing.
|
||||
|
||||
;;; Print out the name and home-directory of everyone in /etc/passwd:
|
||||
(let ((read-passwd (field-reader (infix-splitter ":" 7))))
|
||||
(call-with-input-file "/etc/passwd"
|
||||
(lambda (port)
|
||||
(awk (read-passwd port) (record fields) ()
|
||||
(#t (format #t "~a's home directory is ~a~%"
|
||||
($ fields 0)
|
||||
($ fields 5)))))))\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; Print out the user-name and home-directory of everyone whose
|
||||
;;; name begins with "S"
|
||||
(let ((read-passwd (field-reader (infix-splitter ":" 7))))
|
||||
(call-with-input-file "/etc/passwd"
|
||||
(lambda (port)
|
||||
(awk (read-passwd port) (record fields) ()
|
||||
((: bos "S")
|
||||
(format #t "~a's home directory is ~a~%"
|
||||
($ fields 0)
|
||||
($ fields 5)))))))\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; Read a series of integers from stdin. This expression evaluates
|
||||
;;; to the number of positive numbers that were read. Note our
|
||||
;;; "record-reader" is the standard Scheme READ procedure.
|
||||
(awk (read) (i) ((npos 0))
|
||||
((> i 0) (+ npos 1)))\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; Filter -- pass only lines containing my name.
|
||||
(awk (read-line) (line) ()
|
||||
("Olin" (display line) (newline)))\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; Count the number of non-comment lines of code in my Scheme source.
|
||||
(awk (read-line) (line) ((nlines 0))
|
||||
((: bos (* white) ";") nlines) ; A comment line.
|
||||
(else (+ nlines 1))) ; Not a comment line.\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; Read numbers, counting the evens and odds.
|
||||
(awk (read) (val) ((evens 0) (odds 0))
|
||||
((> val 0) (display "pos ") (values evens odds)) ; Tell me about
|
||||
((< val 0) (display "neg ") (values evens odds)) ; sign, too.
|
||||
(else (display "zero ") (values evens odds))
|
||||
|
||||
((even? val) (values (+ evens 1) odds))
|
||||
(else (values evens (+ odds 1))))\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; Determine the max length of all the lines in the file.
|
||||
(awk (read-line) (line) ((max-len 0))
|
||||
(#t (max max-len (string-length line))))\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; (This could also be done with PORT-FOLD:)
|
||||
(port-fold (current-input-port) read-line
|
||||
(lambda (line maxlen) (max (string-length line) maxlen))
|
||||
0)\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; Print every line longer than 80 chars.
|
||||
;;; Prefix each line with its line #.
|
||||
(awk (read-line) (line) lineno ()
|
||||
((> (string-length line) 80)
|
||||
(format #t "~d: ~s~%" lineno line)))\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; Strip blank lines from input.
|
||||
(awk (read-line) (line) ()
|
||||
((~ white) (display line) (newline)))\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; Sort the entries in /etc/passwd by login name.
|
||||
(for-each (lambda (entry) (display (cdr entry)) (newline)) ; Out
|
||||
(sort (lambda (x y) (string<? (car x) (car y))) ; Sort
|
||||
(let ((read (field-reader (infix-splitter ":" 7)))) ; In
|
||||
(awk (read) (line fields) ((ans '()))
|
||||
(#t (cons (cons ($ fields 0) line) ans))))))\end{code}
|
||||
|
||||
\begin{code}
|
||||
;;; Prefix line numbers to the input stream.
|
||||
(awk (read-line) (line) lineno ()
|
||||
(#t (format #t "~d:\\t~a~%" lineno line)))\end{code}
|
||||
|
||||
|
||||
\section{Backwards compatibility}
|
||||
|
||||
Previous scsh releases provided an \ex{awk} form with a different syntax,
|
||||
designed around regular expressions written in Posix notation as strings,
|
||||
rather than SREs.
|
||||
|
||||
This form is still available in a separate module for old code.
|
||||
It'll be documented in the next release of this manual. Dig around
|
||||
in the sources for it.
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
% boxedminipage.sty
|
||||
%
|
||||
% adds the boxedminipage environment---just like minipage, but has a
|
||||
% box round it!
|
||||
%
|
||||
% The thickneess of the rules around the box is controlled by
|
||||
% \fboxrule, and the distance between the rules and the edges of the
|
||||
% inner box is governed by \fboxsep.
|
||||
%
|
||||
% This code is based on Lamport's minipage code.
|
||||
|
||||
\def\boxedminipage{\@ifnextchar [{\@iboxedminipage}{\@iboxedminipage[c]}}
|
||||
|
||||
\def\@iboxedminipage[#1]#2{\leavevmode \@pboxswfalse
|
||||
\if #1b\vbox
|
||||
\else \if #1t\vtop
|
||||
\else \ifmmode \vcenter
|
||||
\else \@pboxswtrue $\vcenter
|
||||
\fi
|
||||
\fi
|
||||
\fi\bgroup % start of outermost vbox/vtop/vcenter
|
||||
\hsize #2
|
||||
\hrule\@height\fboxrule
|
||||
\hbox\bgroup % inner hbox
|
||||
\vrule\@width\fboxrule \hskip\fboxsep \vbox\bgroup % innermost vbox
|
||||
\advance\hsize -2\fboxrule \advance\hsize-2\fboxsep
|
||||
\textwidth\hsize \columnwidth\hsize
|
||||
\@parboxrestore
|
||||
\def\@mpfn{mpfootnote}\def\thempfn{\thempfootnote}\c@mpfootnote\z@
|
||||
\let\@footnotetext\@mpfootnotetext
|
||||
\let\@listdepth\@mplistdepth \@mplistdepth\z@
|
||||
\@minipagerestore\@minipagetrue
|
||||
\everypar{\global\@minipagefalse\everypar{}}}
|
||||
|
||||
\def\endboxedminipage{%
|
||||
\par\vskip-\lastskip
|
||||
\ifvoid\@mpfootins\else
|
||||
\vskip\skip\@mpfootins\footnoterule\unvbox\@mpfootins\fi
|
||||
\egroup % ends the innermost \vbox
|
||||
\hskip\fboxsep \vrule\@width\fboxrule
|
||||
\egroup % ends the \hbox
|
||||
\hrule\@height\fboxrule
|
||||
\egroup% ends the vbox/vtop/vcenter
|
||||
\if@pboxsw $\fi}
|
||||
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
% code.sty: -*- latex -*-
|
||||
% Latex macros for a "weak" verbatim mode.
|
||||
% -- like verbatim, except \, {, and } have their usual meanings.
|
||||
|
||||
% Environments: code, tightcode, codeaux, codebox, centercode
|
||||
% Commands: \dcd, \cddollar, \cdmath, \cd, \codeallowbreaks, \codeskip, \^
|
||||
% Already defined in LaTeX, but of some relevance: \#, \$, \%, \&, \_, \{, \}
|
||||
|
||||
% Changelog at the end of the file.
|
||||
|
||||
% These commands give you an environment, code, that is like verbatim
|
||||
% except that you can still insert commands in the middle of the environment:
|
||||
% \begin{code}
|
||||
% for(x=1; x<loop_bound; x++)
|
||||
% y += x^3; /* {\em Add in {\tt x} cubed} */
|
||||
% \end{code}
|
||||
%
|
||||
% All characters are ordinary except \{}. To get \{} in your text,
|
||||
% you use the commands \\, \{, and \}.
|
||||
|
||||
% These macros mess with the definition of the special chars (e.g., ^_~%).
|
||||
% The characters \{} are left alone, so you can still have embedded commands:
|
||||
% \begin{code} f(a,b,\ldots,y,z) \end{code}
|
||||
% However, if your embedded commands use the formerly-special chars, as in
|
||||
% \begin{code} x := x+1 /* \mbox{\em This is $y^3$} */ \end{code}
|
||||
% then you lose. The $ and ^ chars are scanned in as non-specials,
|
||||
% so they don't work. If the chars are scanned *outside* the code env,
|
||||
% then you have no problem:
|
||||
% \def\ycube{$y^3$}
|
||||
% \begin{code} x := x+1 /* {\em This is \ycube} */ \end{code}
|
||||
% If you must put special chars inside the code env, you do it by
|
||||
% prefixing them with the special \dcd ("decode") command, that
|
||||
% reverts the chars to back to special status:
|
||||
% \begin{code} x := x+1 /* {\dcd\em This is $y^3$} */ \end{code}
|
||||
% \dcd's scope is bounded by its enclosing braces. It is only defined within
|
||||
% the code env. You can also turn on just $ with the \cddollar command;
|
||||
% you can turn on just $^_ with the \cdmath command. See below.
|
||||
%
|
||||
% Alternatively, just use \(...\) for $...$, \sp for ^, and \sb for _.
|
||||
|
||||
% WARNING:
|
||||
% Like \verb, you cannot put a \cd{...} inside an argument to a macro
|
||||
% or a command. If you try, for example,
|
||||
% \mbox{\cd{$x^y$}}
|
||||
% you will lose. That is because the text "\cd{$x^y$}" gets read in
|
||||
% as \mbox's argument before the \cd executes. But the \cd has to
|
||||
% have a chance to run before LaTeX ever reads the $x^y$ so it can
|
||||
% turn off the specialness of $ and ^. So, \cd has to appear at
|
||||
% top level, not inside an argument. Similarly, you can't have
|
||||
% a \cd or a \code inside a macro (Although you could use \gdef to
|
||||
% define a macro *inside* a \cd, which you could then use outside.
|
||||
% Don't worry about this if you don't understand it.)
|
||||
|
||||
% BUG: In the codebox env, the effect of a \dcd, \cddollar, or \cdmath
|
||||
% command is reset at the end of each line. This can be hacked by
|
||||
% messing with the \halign's preamble, if you feel up to it.
|
||||
|
||||
% Useage note: the initial newline after the \begin{code} or
|
||||
% \begin{codebox} is eaten, but the last newline is not.
|
||||
% So,
|
||||
% \begin{code}
|
||||
% foo
|
||||
% bar
|
||||
% \end{code}
|
||||
% leaves one more blank line after bar than does
|
||||
% \begin{code}
|
||||
% foo
|
||||
% bar\end{code}
|
||||
% Moral: get in the habit of terminating code envs without a newline
|
||||
% (as in the second example).
|
||||
%
|
||||
|
||||
% All this stuff tweaks the meaning of space, tab, and newline.
|
||||
%===============================================================================
|
||||
% \cd@obeyspaces
|
||||
% Turns all spaces into non-breakable spaces.
|
||||
% Note: this is like \@vobeyspaces except without spurious space in defn.
|
||||
% @xobeysp is basically a space; it's defined in latex.tex.
|
||||
%
|
||||
{\catcode`\ =\active\gdef\cd@obeyspaces{\catcode`\ =\active\let =\@xobeysp}}
|
||||
|
||||
|
||||
|
||||
% \cd@obeytabs
|
||||
% Turns all tabs into 8 non-breakable spaces (which is bogus).
|
||||
%
|
||||
{\catcode`\^^I=\active %
|
||||
\gdef\cd@obeytabs{\catcode`\^^I=\active\let^^I=\cd@tab}}
|
||||
|
||||
\def\cd@tab{\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp}
|
||||
|
||||
|
||||
|
||||
% \cd@obeylines
|
||||
% Turns all cr's into linebreaks. Pagebreaks are not permitted between lines.
|
||||
% This is copied from lplain.tex's \obeylines, with the cr def'n changed.
|
||||
%
|
||||
{\catcode`\^^M=\active % these lines must end with %
|
||||
\gdef\cd@obeylines{\catcode`\^^M=\active\let^^M=\cd@cr}}
|
||||
|
||||
% What ^M turns into. This def'n keeps blank lines from being compressed out.
|
||||
\def\cd@cr{\par\penalty10000\leavevmode} % TeX magicness
|
||||
%\def\cd@cr{\par\penalty10000\mbox{}} % LaTeX
|
||||
|
||||
|
||||
% \codeallowbreaks
|
||||
% Same as \cd@obeylines, except pagebreaks are allowed.
|
||||
% Put this command inside a code env to allow pagebreaks.
|
||||
|
||||
{\catcode`\^^M=\active % these lines must end with %
|
||||
\gdef\codeallowbreaks{\catcode`\^^M\active\let^^M\cd@crbr}}
|
||||
|
||||
%\def\cd@crbr{\leavevmode\endgraf} % What ^M turns into.
|
||||
\def\cd@crbr{\par\leavevmode} % What ^M turns into.
|
||||
|
||||
|
||||
% \cd@obeycrsp
|
||||
% Turns cr's into non-breakable spaces. Used by \cd.
|
||||
|
||||
{\catcode`\^^M=\active % these lines must end with %
|
||||
\gdef\cd@obeycrsp{\catcode`\^^M=\active\let^^M=\@xobeysp}}
|
||||
|
||||
% =============================================================================
|
||||
|
||||
% Set up code environment, in which most of the common special characters
|
||||
% appearing in code are treated verbatim, namely: $&#^_~%
|
||||
% \ { } are still enabled so that macros can be called in this
|
||||
% environment. Use \\, \{, and \} to use these characters verbatim
|
||||
% in this environment.
|
||||
%
|
||||
% Inside a group, you can make
|
||||
% all the hacked chars special with the \dcd command
|
||||
% $ special with the \cddollar command
|
||||
% $^_ special with the \cdmath command.
|
||||
% If you have a bunch of math $..$'s in your code env, then a global \cddollar
|
||||
% or \cdmath at the beginning of the env can save a lot of trouble.
|
||||
% When chars are special (e.g., after a \dcd), you can still get #$%&_{} with
|
||||
% \#, \$, \%, \&, \_, \{, and \} -- this is standard LaTeX.
|
||||
% Additionally, \\ gives \ inside the code env, and when \cdmath
|
||||
% makes ^ special, it also defines \^ to give ^.
|
||||
|
||||
%The hacked characters can be made special again
|
||||
% within a group by using the \dcd command.
|
||||
|
||||
% Note: this environment allows no breaking of lines whatsoever; not
|
||||
% at spaces or hypens. To arrange for a break use the standard \- command,
|
||||
% or a \discretionary{}{}{} which breaks, but inserts nothing. This is useful,
|
||||
% for example for allowing hypenated identifiers to be broken, e.g.
|
||||
% \def\={\discretionary{}{}{}} %optional break
|
||||
% FOO-\=BAR.
|
||||
|
||||
\def\setupcode{\parsep=0pt\parindent=0pt%
|
||||
\normalfont\ttfamily\frenchspacing\catcode``=13\@noligs%
|
||||
\def\\{\char`\\}%
|
||||
\let\dcd=\cd@dcd\let\cddollar=\cd@dollarspecial\let\cdmath=\cd@mathspecial%
|
||||
\@makeother\$\@makeother\&\@makeother\#%
|
||||
\@makeother\^\@makeother\_\@makeother\~%
|
||||
\@makeother\%\cd@obeytabs\cd@obeyspaces}
|
||||
% other: $&#^_~%
|
||||
% left special: \{}
|
||||
% unnecessary: @`'"
|
||||
|
||||
|
||||
%% codebox, centercode
|
||||
%%=============================================================================
|
||||
%% The codebox env makes a box exactly as wide as it needs to be
|
||||
%% (i.e., as wide as the longest line of code is). This is useful
|
||||
%% if you want to center a chunk of code, or flush it right, or
|
||||
%% something like that. The optional argument to the environment,
|
||||
%% [t], [c], or [b], specifies how to vertically align the codebox,
|
||||
%% just as with arrays or other boxes. Default is [c].
|
||||
|
||||
%% Must be a newline immediately after "\begin{codebox}[t]"!
|
||||
|
||||
{\catcode`\^^M=\active % these lines must end with %
|
||||
\gdef\cd@obeycr{\catcode`\^^M=\active\let^^M=\cr}}
|
||||
|
||||
% If there is a [<letter>] option, then the following newline will
|
||||
% be read *after* ^M is bound to \cr, so we're cool. If there isn't
|
||||
% an option given (i.e., default to [c]), then the @\ifnextchar will
|
||||
% gobble up the newline as it gobbles whitespace. So we insert the
|
||||
% \cr explicitly. Isn't TeX fun?
|
||||
\def\codebox{\leavevmode\@ifnextchar[{\@codebox}{\@codebox[c]\cr}} %]
|
||||
|
||||
\def\@codebox[#1]%
|
||||
{\hbox\bgroup$\if #1t\vtop \else \if#1b\vbox \else \vcenter \fi\fi\bgroup%
|
||||
\tabskip\z@\setupcode\cd@obeycr% just before cd@obey
|
||||
\halign\bgroup##\hfil\span}
|
||||
|
||||
\def\endcodebox{\crcr\egroup\egroup\m@th$\egroup}
|
||||
|
||||
% Center the box on the page:
|
||||
\newenvironment{centercode}%
|
||||
{\begin{center}\begin{codebox}[c]}%
|
||||
{\end{codebox}\end{center}}
|
||||
|
||||
|
||||
%% code, codeaux, tightcode
|
||||
%%=============================================================================
|
||||
%% Code environment as described above. Lines are kept on one page.
|
||||
%% This actually works by setting a huge penalty for breaking
|
||||
%% between lines of code. Code is indented same as other displayed paras.
|
||||
%% Note: to increase left margin, use \begin{codeaux}{\leftmargin=1in}.
|
||||
|
||||
% To allow pagebreaks, say \codeallowbreaks immediately inside the env.
|
||||
% You can allow breaks at specific lines with a \pagebreak form.
|
||||
|
||||
%% N.B.: The \global\@ignoretrue command must be performed just inside
|
||||
%% the *last* \end{...} before the following text. If not, you will
|
||||
%% get an extra space on the following line. Blech.
|
||||
|
||||
%% This environment takes two arguments.
|
||||
%% The second, required argument is the \list parameters to override the
|
||||
%% \@listi... defaults.
|
||||
%% - Usefully set by clients: \topsep \leftmargin
|
||||
%% - Possible, but less useful: \partopsep
|
||||
%% The first, optional argument is the extra \parskip glue that you get around
|
||||
%% \list environments. It defaults to the value of \parskip.
|
||||
\def\codeaux{\@ifnextchar[{\@codeaux}{\@codeaux[\parskip]}} %]
|
||||
\def\@codeaux[#1]#2{%
|
||||
\bgroup\parskip#1%
|
||||
\begin{list}{}%
|
||||
{\parsep\z@\rightskip\z@\listparindent\z@\itemindent\z@#2}%
|
||||
\item[]\setupcode\cd@obeylines}%
|
||||
\def\endcodeaux{\end{list}\leavevmode\egroup\ignorespaces\global\@ignoretrue}
|
||||
|
||||
%% Code env is codeaux with the default margin and spacing \list params:
|
||||
\def\code{\codeaux{}} \let\endcode=\endcodeaux
|
||||
|
||||
%% Like code, but with no extra vertical space above and below.
|
||||
\def\tightcode{\codeaux[=0pt]{\topsep\z@}}%
|
||||
\let\endtightcode\endcodeaux
|
||||
% {\vspace{-1\parskip}\begin{codeaux}{\partopsep\z@\topsep\z@}}%
|
||||
% {\end{codeaux}\vspace{-1\parskip}}
|
||||
|
||||
|
||||
|
||||
% Reasonable separation between lines of code
|
||||
\newcommand{\codeskip}{\penalty0\vspace{2ex}}
|
||||
|
||||
|
||||
% \cd is used to build a code environment in the middle of text.
|
||||
% Note: only difference from display code is that cr's are taken
|
||||
% as unbreakable spaces instead of linebreaks.
|
||||
|
||||
\def\cd{\leavevmode\begingroup\ifmmode\let\startcode=\startmcode\else%
|
||||
\let\startcode\starttcode\fi%
|
||||
\setupcode\cd@obeycrsp\startcode}
|
||||
|
||||
\def\starttcode#1{#1\endgroup}
|
||||
\def\startmcode#1{\hbox{#1}\endgroup}
|
||||
|
||||
|
||||
% Restore $&#^_~% to their normal catcodes
|
||||
% Define \^ to give the ^ char.
|
||||
% \dcd points to this guy inside a code env.
|
||||
\def\cd@dcd{\catcode`\$=3\catcode`\&=4\catcode`\#=6\catcode`\^=7%
|
||||
\catcode`\_=8\catcode`\~=13\catcode`\%=14\def\^{\char`\^}}
|
||||
|
||||
% Selectively enable $, and $^_ as special.
|
||||
% \cd@mathspecial also defines \^ give the ^ char.
|
||||
% \cddollar and \cdmath point to these guys inside a code env.
|
||||
\def\cd@dollarspecial{\catcode`\$=3}
|
||||
\def\cd@mathspecial{\catcode`\$=3\catcode`\^=7\catcode`\_=8%
|
||||
\def\^{\char`\^}}
|
||||
|
||||
|
||||
% Change log:
|
||||
% Started off as some macros found in C. Rich's library.
|
||||
% Olin 1/90:
|
||||
% Removed \makeatletter, \makeatother's -- they shouldn't be there,
|
||||
% because style option files are read with makeatletter. The terminal
|
||||
% makeatother screwed things up for the following style options.
|
||||
% Olin 3/91:
|
||||
% Rewritten.
|
||||
% - Changed things so blank lines don't get compressed out (the \leavevmove
|
||||
% in \cd@cr and \cd@crwb).
|
||||
% - Changed names to somewhat less horrible choices.
|
||||
% - Added lots of doc, so casual hackers can more easily mess with all this.
|
||||
% - Removed `'"@ from the set of hacked chars, since they are already
|
||||
% non-special.
|
||||
% - Removed the bigcode env, which effect can be had with the \codeallowbreaks
|
||||
% command.
|
||||
% - Removed the \@noligs command, since it's already defined in latex.tex.
|
||||
% - Win big with the new \dcd, \cddollar, and \cdmath commands.
|
||||
% - Now, *only* the chars \{} are special inside the code env. If you need
|
||||
% more, use the \dcd command inside a group.
|
||||
% - \cd now works inside math mode. (But if you use it in a superscript,
|
||||
% it still comes out full size. You must explicitly put a \scriptsize\tt
|
||||
% inside the \cd: $x^{\cd{\scriptsize\tt...}}$. A \leavevmode was added
|
||||
% so that if you begin a paragraph with a \cd{...}, TeX realises you
|
||||
% are starting a paragraph.
|
||||
% - Added the codebox env. Tricky bit involving the first line hacked
|
||||
% with help from David Long.
|
||||
% Olin 8/94
|
||||
% Changed the font commands for LaTeX2e.
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
% css.t2p
|
||||
% Dorai Sitaram
|
||||
% 19 Jan 2001
|
||||
% A basic style for HTML documents generated
|
||||
% with tex2page.
|
||||
|
||||
\ifx\shipout\UNDEFINED
|
||||
\cssblock
|
||||
|
||||
body {
|
||||
color: black;
|
||||
/* background-color: #e5e5e5;*/
|
||||
background-color: #ffffff;
|
||||
/*background-color: beige;*/
|
||||
margin-top: 2em;
|
||||
margin-left: 8%;
|
||||
margin-right: 8%;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
.partheading {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.chapterheading {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
ol ol {
|
||||
list-style-type: lower-alpha;
|
||||
}
|
||||
|
||||
ol ol ol {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
|
||||
ol ol ol ol {
|
||||
list-style-type: upper-alpha;
|
||||
}
|
||||
|
||||
.scheme {
|
||||
color: brown;
|
||||
}
|
||||
|
||||
.scheme .keyword {
|
||||
color: #990000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.scheme .builtin {
|
||||
color: #990000;
|
||||
}
|
||||
|
||||
.scheme .variable {
|
||||
color: navy;
|
||||
}
|
||||
|
||||
.scheme .global {
|
||||
color: purple;
|
||||
}
|
||||
|
||||
.scheme .selfeval {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.scheme .comment {
|
||||
color: teal;
|
||||
}
|
||||
|
||||
.schemeresponse {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.navigation {
|
||||
color: red;
|
||||
text-align: right;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.disable {
|
||||
/* color: #e5e5e5; */
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.smallcaps {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
.smallprint {
|
||||
color: gray;
|
||||
font-size: 75%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.smallprint hr {
|
||||
text-align: left;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
\endcssblock
|
||||
\fi
|
||||
|
||||
% ex:ft=css
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
% Loads cmtt fonts in on \tt. -*- latex -*-
|
||||
% I prefer these to the Courier fonts that latex gives you w/postscript styles.
|
||||
% Courier is too spidery and too wide -- it's hard to get 80 chars on a line.
|
||||
% -Olin
|
||||
|
||||
\renewcommand{\ttdefault}{cmtt}
|
||||
|
|
@ -0,0 +1,278 @@
|
|||
\makeatletter
|
||||
\def\ie{\mbox{\emph{i.e.}}} % \mbox keeps the last period from
|
||||
\def\Ie{\mbox{\emph{I.e.}}} % looking like an end-of-sentence.
|
||||
\def\eg{\mbox{\emph{e.g.}}}
|
||||
\def\Eg{\mbox{\emph{E.g.}}}
|
||||
\def\etc{{\em etc.}}
|
||||
|
||||
\def\Lisp{\textsc{Lisp}}
|
||||
\def\CommonLisp{\textsc{Common Lisp}}
|
||||
\def\Ascii{\textsc{Ascii}}
|
||||
\def\Ansi{\textsc{Ansi}}
|
||||
\def\Unix{{Unix}} % Not smallcaps, according to Bart.
|
||||
\def\Scheme{{Scheme}}
|
||||
\def\scm{{Scheme 48}}
|
||||
\def\RnRS{R5RS}
|
||||
\def\Posix{\textsc{Posix}}
|
||||
|
||||
\def\sharpf{\textnormal{\texttt{\#f}}}
|
||||
\def\sharpt{\textnormal{\texttt{\#t}}}
|
||||
\newcommand{\synteq}{\textnormal{::=}}
|
||||
|
||||
\def\maketildeother{\catcode`\~=12}
|
||||
\def\maketildeactive{\catcode`\~=13}
|
||||
\def\~{\char`\~}
|
||||
|
||||
\newcommand{\evalsto}{\ensuremath{\Rightarrow}}
|
||||
|
||||
% One-line code examples
|
||||
%\newcommand{\codex}[1]% One line, centred. Tight spacing.
|
||||
% {$$\abovedisplayskip=.75ex plus 1ex minus .5ex%
|
||||
% \belowdisplayskip=\abovedisplayskip%
|
||||
% \abovedisplayshortskip=0ex plus .5ex%
|
||||
% \belowdisplayshortskip=\abovedisplayshortskip%
|
||||
% \hbox{\ttt #1}$$}
|
||||
%\newcommand{\codex}[1]{\begin{tightinset}\ex{#1}\end{tightinset}\ignorespaces}
|
||||
\newcommand{\codex}[1]{\begin{leftinset}\ex{#1}\end{leftinset}\ignorespaces}
|
||||
|
||||
\def\widecode{\codeaux{\leftmargin=0pt\topsep=0pt}}
|
||||
\def\endwidecode{\endcodeaux}
|
||||
|
||||
% For multiletter vars in math mode:
|
||||
\newcommand{\var}[1]{\mbox{\frenchspacing\it{#1}}}
|
||||
\newcommand{\vari}[2]{\ensuremath{\mbox{\it{#1}}_{#2}}}
|
||||
|
||||
%% What you frequently want when you say \tt:
|
||||
\def\ttchars{\catcode``=13\@noligs\frenchspacing}
|
||||
\def\ttt{\normalfont\ttfamily\ttchars}
|
||||
|
||||
% Works in math mode; all special chars remain special; cheaper than \cd.
|
||||
% Will not be correct size in super and subscripts, though.
|
||||
\newcommand{\ex}[1]{{\normalfont\texttt{\ttchars #1}}}
|
||||
|
||||
\newenvironment{inset}
|
||||
{\bgroup\parskip=1ex plus 1ex\begin{list}{}%
|
||||
{\topsep=0pt\rightmargin\leftmargin}%
|
||||
\item[]}%
|
||||
{\end{list}\leavevmode\egroup\global\@ignoretrue}
|
||||
|
||||
\newenvironment{leftinset}
|
||||
{\bgroup\parskip=1ex plus 1ex\begin{list}{}%
|
||||
{\topsep=0pt}%
|
||||
\item[]}%
|
||||
{\end{list}\leavevmode\egroup\global\@ignoretrue}
|
||||
|
||||
\newenvironment{tightinset}
|
||||
{\bgroup\parskip=0pt\begin{list}{}%
|
||||
{\topsep=0pt\rightmargin\leftmargin}%
|
||||
\item[]}%
|
||||
{\end{list}\leavevmode\egroup\global\@ignoretrue}
|
||||
|
||||
\newenvironment{tightleftinset}
|
||||
{\bgroup\parskip=0pt\begin{list}{}%
|
||||
{\topsep=0pt}%
|
||||
\item[]}%
|
||||
{\end{list}\leavevmode\egroup\global\@ignoretrue}
|
||||
|
||||
\long\def\remark#1{\bgroup\small\begin{quote}\textsl{Remark: } #1\end{quote}\egroup}
|
||||
\newenvironment{remarkenv}{\bgroup\small\begin{quote}\textsl{Remark: }}%
|
||||
{\end{quote}\egroup}
|
||||
\newcommand{\oops}[1]{\bgroup\small\begin{quote}\textsl{Oops: } #1\end{quote}\egroup}
|
||||
|
||||
\newcommand{\note}[1]{\{Note #1\}}
|
||||
|
||||
\newcommand{\itum}[1]{\item{\bf #1}\\*}
|
||||
|
||||
% For use in code. The \llap magicness makes the lambda exactly as wide as
|
||||
% the other chars in \tt; the \hskip shifts it right a bit so it doesn't
|
||||
% crowd the left paren -- which is necessary if \tt is cmtt.
|
||||
% Note that (\l{x y} (+ x y)) uses the same number of columns in TeX form
|
||||
% as it produces when typeset. This makes it easy to line up the columns
|
||||
% in your input. \l is bound to some useless command in LaTeX, so we have to
|
||||
% define it w/renewcommand.
|
||||
\let\oldl\l %Save the old \l on \oldl
|
||||
\renewcommand{\l}[1]{\ \llap{$\lambda$\hskip-.05em}\ (#1)}
|
||||
|
||||
% This one is for the rare (lambda x ...) case -- it doesn't have the
|
||||
% column-invariant property. Oh, well.
|
||||
\newcommand{\lx}[1]{\ \llap{$\lambda$\hskip-.05em}\ {#1}}
|
||||
|
||||
% For subcaptions
|
||||
\newcommand{\subcaption}[1]
|
||||
{\unskip\vspace{-2mm}\begin{center}\unskip\em#1\end{center}}
|
||||
|
||||
%%% T release notes stuff
|
||||
\newlength{\notewidth}
|
||||
\setlength{\notewidth}{\textwidth}
|
||||
\addtolength{\notewidth}{-1.25in}
|
||||
|
||||
%\newcommand{\remark} [1]
|
||||
% {\par\vspace{\parskip}
|
||||
% \parbox[t]{.75in}{\sc Remark:}
|
||||
% \parbox[t]{\notewidth}{\em #1}
|
||||
% \vspace{\parskip}
|
||||
% }
|
||||
|
||||
\newenvironment{optiontable}%
|
||||
{\begin{tightinset}\renewcommand{\arraystretch}{1.5}%
|
||||
\begin{tabular}{@{}>{\ttt}ll@{}}}%
|
||||
{\end{tabular}\end{tightinset}}%
|
||||
|
||||
\newenvironment{desctable}[1]%
|
||||
{\begin{inset}\renewcommand{\arraystretch}{1.5}%
|
||||
\begin{tabular}{lp{#1}}}%
|
||||
{\end{tabular}\end{inset}}
|
||||
|
||||
\def\*{{\ttt *}}
|
||||
|
||||
% Names of things
|
||||
|
||||
\newcommand{\keyword} [1]{\index{#1}{\normalfont\textsf{#1}}}
|
||||
|
||||
% \ex{#1} and also generates an index entry.
|
||||
\newcommand{\exi}[1]{\index{#1@\texttt{#1}}\ex{#1}}
|
||||
\newcommand{\indextt}[1]{\index{#1@\texttt{#1}}}
|
||||
|
||||
|
||||
\newcommand{\evalto}{$\Longrightarrow$\ }
|
||||
\renewcommand{\star}{$^*$\/}
|
||||
\newcommand{\+}{$^+$}
|
||||
|
||||
% Semantic domains, used to indicate the type of a value
|
||||
|
||||
\newcommand{\sem}{\normalfont\itshape} %semantic font
|
||||
\newcommand{\semvar}[1]{\textit{#1}} %semantic font
|
||||
\newcommand{\synvar}[1]{\textrm{\textit{$\left<\right.$#1$\left.\right>$}}} %syntactic font
|
||||
\newcommand{\type}{\sem}
|
||||
\newcommand{\zeroormore}[1]{{\sem #1$_1$ \ldots #1$_n$}}
|
||||
\newcommand{\oneormore}[1]{{\sem #1$_1$ #1$_2$ \ldots #1$_n$}}
|
||||
|
||||
\newcommand{\proc} {{\sem procedure}}
|
||||
\newcommand{\boolean} {{\sem boolean}}
|
||||
\newcommand{\true} {{\sem true}}
|
||||
\newcommand{\false} {{\sem false}}
|
||||
|
||||
\newcommand{\num} {{\sem number}}
|
||||
\newcommand{\fixnum} {{\sem fixnum}}
|
||||
\newcommand{\integer} {{\sem integer}}
|
||||
\newcommand{\real} {{\sem real}}
|
||||
|
||||
\newcommand{\character} {{\sem character}}
|
||||
\newcommand{\str} {{\sem string}}
|
||||
\newcommand{\sym} {{\sem symbol}}
|
||||
|
||||
\newcommand{\location} {{\sem location}}
|
||||
\newcommand{\object} {{\sem object}}
|
||||
|
||||
\newcommand{\error} {{\sem error}}
|
||||
\newcommand{\syntaxerror} {{\sem syntax error}}
|
||||
\newcommand{\readerror} {{\sem read error}}
|
||||
\newcommand{\undefined} {{\sem undefined}}
|
||||
\newcommand{\noreturn} {{\sem no return value}}
|
||||
|
||||
\newcommand{\port} {{\sem port}}
|
||||
|
||||
% semantic variables
|
||||
|
||||
\newcommand{\identifier} {{\sem identifier}}
|
||||
\newcommand{\identifiers} {\zeroormore{\<ident>}}
|
||||
\newcommand{\expr} {{\sem expression}}
|
||||
\newcommand{\body} {{\sem body}}
|
||||
\newcommand{\valueofbody} {{\sem value~of~body}}
|
||||
\newcommand{\emptylist} {{\sem empty~list}}
|
||||
\newcommand{\car} {\keyword{car}}
|
||||
\newcommand{\cdr} {\keyword{cdr}}
|
||||
\newcommand{\TMPDIR}{\texttt{\$TMPDIR}}
|
||||
|
||||
% generally useful things
|
||||
|
||||
% For line-breaking \tt stuff.
|
||||
\renewcommand{\=}{\discretionary{-}{}{-}}
|
||||
\newcommand{\ob}{\discretionary{}{}{}} % Optional break.
|
||||
|
||||
\newcommand{\indx}[1]{#1 \index{ #1 }}
|
||||
%\newcommand{\gloss}[1]{#1 \glossary{ #1 }}
|
||||
|
||||
% This lossage produces #2 if #1 is zero length, otw #3.
|
||||
% We use it to conditionally add a space between the procedure and
|
||||
% the args in procedure prototypes, but only if there are any args--
|
||||
% we want to produce "(read)", not "(read )".
|
||||
\newlength{\voidlen}
|
||||
\newcommand{\testvoid}[3]{\settowidth\voidlen{#1}\ifdim\voidlen>0in{#3}\else{#2}\fi}
|
||||
|
||||
|
||||
% Typeset a definition prototype line, e.g.:
|
||||
% (cons <arg1> <arg2>) -> pair procedure
|
||||
%
|
||||
% Five args are: proc-name args ret-value(s) type index-entry
|
||||
\newcommand{\dfnix}[5]
|
||||
{\hbox to \linewidth{\ttchars%
|
||||
{\ttt(#1\testvoid{#2}{}{\ }{\sem{#2}}\testvoid{#2}{}{\/})\hskip 1em minus
|
||||
0.5em$\longrightarrow$\hskip 1em minus 0.5em{\sem{#3}}\hfill\quad\textnormal{#4}}}\index{#5}}
|
||||
|
||||
\newcommand{\dfnx}[4] {\dfnix{#1}{#2}{#3}{#4}{#1@\texttt{#1}}}
|
||||
|
||||
\newcommand{\dfn} {\par\medskip\dfnx} % Takes 4 args, actually.
|
||||
\newcommand{\dfni} {\par\medskip\dfnix} % Takes 5 args, actually.
|
||||
|
||||
\newcommand{\defvar} {\par\medskip\defvarx} % Takes 4 args, actually.
|
||||
\newcommand{\defvarx}[2]%
|
||||
{\index{#1}
|
||||
\hbox to \linewidth{\ttchars{{\ttt{#1}} \hfill #2}}}%
|
||||
|
||||
% Typeset the protocol line, then do the following descriptive text indented.
|
||||
% If you want to group two procs together, do the first one with a \dfn,
|
||||
% then the second one, and the documentation, with a \defndescx.
|
||||
|
||||
% This one doesn't put whitespace above. Use it immediately after a \dfn
|
||||
% to group two prototype lines together.
|
||||
\newenvironment{dfndescx}[4]%
|
||||
{\dfnx{#1}{#2}{#3}{#4}\begin{desc}}{\end{desc}}
|
||||
|
||||
\newenvironment{dfndesc}[4] % This one puts whitespace above.
|
||||
{\par\medskip\begin{dfndescx}{#1}{#2}{#3}{#4}}
|
||||
{\end{dfndescx}}
|
||||
|
||||
\newenvironment{desc}%
|
||||
{\nopagebreak[2]%
|
||||
\smallskip
|
||||
\bgroup\begin{list}{}{\topsep=0pt\parskip=0pt}\item[]}
|
||||
{\end{list}\leavevmode\egroup\global\@ignoretrue}
|
||||
|
||||
\def\defun#1#2#3{\dfn{#1}{#2}{#3}{procedure}} % preskip
|
||||
\newcommand{\defunx}[3]{\dfnx{#1}{#2}{#3}{procedure}} % no skip
|
||||
|
||||
\newenvironment{defundescx}[3]%
|
||||
{\begin{dfndescx}{#1}{#2}{#3}{procedure}}
|
||||
{\end{dfndescx}}
|
||||
|
||||
\newenvironment{defundesc}[3]%
|
||||
{\begin{dfndesc}{#1}{#2}{#3}{procedure}}
|
||||
{\end{dfndesc}}
|
||||
|
||||
|
||||
\newenvironment{column}{\begin{tabular}[t]{@{}l@{}}}{\end{tabular}}
|
||||
|
||||
\newenvironment{exampletable}%
|
||||
{\begin{leftinset}%
|
||||
\newcommand{\header}[1]{\multicolumn{2}{@{}l@{}}{##1}\\}%
|
||||
\newcommand{\splitline}[2]%
|
||||
{\multicolumn{2}{@{}l@{}}{##1}\\\multicolumn{2}{@{}l@{}}{\qquad\evalto\quad{##2}}}
|
||||
\begin{tabular}{@{}l@{\quad\evalto\quad}l@{}}}%
|
||||
{\end{tabular}\end{leftinset}}
|
||||
|
||||
% Put on blank lines in a code env to allow a pagebreak.
|
||||
\newcommand{\cb}{\pagebreak[0]}
|
||||
|
||||
\newenvironment{boxedcode}
|
||||
{\begin{inset}\tabular{|l|}\hline}
|
||||
{\\ \hline \end{tabular}\end{inset}}
|
||||
|
||||
% A ragged-right decl that doesn't redefine \\ -- for use in tables.
|
||||
\newcommand{\raggedrightparbox}{\let\temp=\\\raggedright\let\\=\temp}
|
||||
|
||||
\newenvironment{boxedfigure}[1]%
|
||||
{\begin{figure}[#1]\begin{boxedminipage}{\linewidth}\vskip 1.5ex}
|
||||
{\end{boxedminipage}\end{figure}}
|
||||
|
||||
\makeatother
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
% Document style option "draftfooter"
|
||||
% -- usage: \documentstyle[...,draftfooter,...]{...}
|
||||
% -- puts "DRAFT" with date and time in page footer
|
||||
%
|
||||
% Olin Shivers 1/17/94
|
||||
% - Hacked from code I used in my dissertation and from code in a
|
||||
% drafthead.sty package written by Stephen Page sdpage@uk.ac.oxford.prg.
|
||||
%----------------------------------------------------------------------------
|
||||
|
||||
%
|
||||
% compute the time in hours and minutes; make new variables \timehh and \timemm
|
||||
%
|
||||
\newcount\timehh\newcount\timemm
|
||||
\timehh=\time
|
||||
\divide\timehh by 60 \timemm=\time
|
||||
\count255=\timehh\multiply\count255 by -60 \advance\timemm by \count255
|
||||
%
|
||||
|
||||
\def\draftbox{{\protect\small\bf \fbox{DRAFT}}}
|
||||
\def\drafttime{%
|
||||
{\protect\small\sl\today\ -- \ifnum\timehh<10 0\fi%
|
||||
\number\timehh\,:\,\ifnum\timemm<10 0\fi\number\timemm}}
|
||||
\def\drafttimer{\protect\makebox[0pt][r]{\drafttime}}
|
||||
\def\drafttimel{\protect\makebox[0pt][l]{\drafttime}}
|
||||
|
||||
\def\thepagel{\protect\makebox[0pt][l]{\rm\thepage}}
|
||||
\def\thepager{\protect\makebox[0pt][r]{\rm\thepage}}
|
||||
|
||||
% Header is empty.
|
||||
% Footer is "date DRAFT pageno"
|
||||
\def\ps@plain{
|
||||
\let\@mkboth\@gobbletwo
|
||||
\let\@oddhead\@empty \let\@evenhead\@empty
|
||||
|
||||
\def\@oddfoot{\reset@font\rm\drafttimel\hfil\draftbox\hfil\thepager}
|
||||
\if@twoside
|
||||
\def\@evenfoot{\reset@font\rm\thepagel\hfil\draftbox\hfil\drafttimer}
|
||||
\else \let\@evenfoot\@oddfoot
|
||||
\fi
|
||||
}
|
||||
|
||||
% Aux macro -- sets footer to be "date DRAFT".
|
||||
\def\@draftfooters{
|
||||
\def\@oddfoot{\reset@font\rm\drafttimel\hfil\draftbox}
|
||||
\if@twoside
|
||||
\def\@evenfoot{\reset@font\rm\draftbox\hfil\drafttimer}
|
||||
\else \let\@evenfoot\@oddfoot
|
||||
\fi
|
||||
}
|
||||
|
||||
% Header is empty.
|
||||
% Footer is "date DRAFT".
|
||||
\def\ps@empty{
|
||||
\let\@mkboth\@gobbletwo
|
||||
\let\@oddhead\@empty \let\@evenhead\@empty
|
||||
\@draftfooters
|
||||
}
|
||||
|
||||
% Header is defined by the document style (article, book, etc.).
|
||||
% Footer is "date DRAFT".
|
||||
\let\@draftoldhead\ps@headings
|
||||
\def\ps@headings{
|
||||
\@draftoldhead % Do the default \pagestyle{headings} stuff.
|
||||
\@draftfooters % Then define the draft footers:
|
||||
}
|
||||
|
||||
% Header is defined by the document style (article, book, etc.),
|
||||
% and filled in by user's \markboth and \markright commands.
|
||||
% Footer is "date DRAFT".
|
||||
\let\@draftoldmyhead\ps@myheadings
|
||||
\def\ps@myheadings{
|
||||
\@draftoldmyhead % Do the default \pagestyle{myheadings} stuff.
|
||||
\@draftfooters % Then define the draft footers:
|
||||
}
|
||||
|
||||
\ps@plain
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
%&latex -*- latex -*-
|
||||
|
||||
\title{Scsh Reference Manual}
|
||||
\subtitle{For scsh release 0.6.7}
|
||||
\author{Olin Shivers, Brian D.~Carlstrom, Martin Gasbichler, and Mike Sperber}
|
||||
\date{May 2006}
|
||||
|
||||
\maketitle
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Some code-changes for tex2page and latex output. NF
|
||||
\texonly
|
||||
\chapter*{Acknowledgements}
|
||||
\endtexonly
|
||||
\htmlonly
|
||||
\\ \ex{Acknowledgements} \\ \\
|
||||
\endhtmlonly
|
||||
|
||||
Who should I thank?
|
||||
My so-called ``colleagues,'' who laugh at me behind my back,
|
||||
all the while becoming famous on {\em my\/} work?
|
||||
My worthless graduate students, whose computer skills appear to
|
||||
be limited to downloading bitmaps off of netnews?
|
||||
My parents, who are still waiting for me to quit ``fooling around with
|
||||
computers,'' go to med school, and become a radiologist?
|
||||
My department chairman, a manager who gives one new insight into
|
||||
and sympathy for disgruntled postal workers?
|
||||
|
||||
My God, no one could blame me---no one!---if I went off the edge and just
|
||||
lost it completely one day.
|
||||
I couldn't get through the day as it is without the Prozac and Jack Daniels
|
||||
I keep on the shelf, behind my Tops-20 JSYS manuals.
|
||||
I start getting the shakes real bad around 10am, right before my
|
||||
advisor meetings. A 10 oz.\ Jack 'n Zac helps me get through the
|
||||
meetings without one of my students winding up with his severed head
|
||||
in a bowling-ball bag. They look at me funny; they think I twitch a
|
||||
lot. I'm not twitching. I'm controlling my impulse to snag my 9mm
|
||||
Sig-Sauer out from my day-pack and make a few strong points about
|
||||
the quality of undergraduate education in Amerika.
|
||||
|
||||
If I thought anyone cared, if I thought anyone would even be reading this,
|
||||
I'd probably make an effort to keep up appearances until the last possible
|
||||
moment. But no one does, and no one will. So I can pretty much say exactly
|
||||
what I think.
|
||||
|
||||
Oh, yes, the {\em acknowledgements.}
|
||||
I think not. I did it. I did it all, by myself.
|
||||
\begin{flushright}
|
||||
\begin{tabular}{l}
|
||||
Olin Shivers \\
|
||||
Cambridge \\
|
||||
September 4, 1994
|
||||
\end{tabular}
|
||||
\end{flushright}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\tableofcontents
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
% headings.tex -*- latex -*-
|
||||
% Quieter headings that the ones used in article.sty.
|
||||
% This is not a style option. Don't say [headings].
|
||||
% Instead, say \input{headings} after the \documentstyle.
|
||||
% -Olin 7/91
|
||||
|
||||
\makeatletter
|
||||
|
||||
\def\section{\@startsection {section}{1}{\z@}{-3.5ex plus -1ex minus
|
||||
-.2ex}{2.3ex plus .2ex}{\large\normalfont\bfseries}}
|
||||
\def\subsection{\@startsection{subsection}{2}{\z@}{-3.25ex plus -1ex minus
|
||||
-.2ex}{1.5ex plus .2ex}{\normalsize\normalfont\bfseries}}
|
||||
\def\subsubsection{\@startsection{subsubsection}{3}{\z@}{-3.25ex plus
|
||||
-1ex minus -.2ex}{1.5ex plus .2ex}{\normalsize\normalfont\bfseries}}
|
||||
|
||||
\makeatother
|
||||
|
|
@ -0,0 +1,435 @@
|
|||
%&latex -*- latex -*-
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\chapter{Introduction}
|
||||
|
||||
This is the reference manual for scsh,
|
||||
a {\Unix} shell that is embedded within {\Scheme}.
|
||||
Scsh is a Scheme system designed for writing useful standalone Unix
|
||||
programs and shell scripts---it spans a wide range of application,
|
||||
from ``script'' applications usually handled with perl or sh,
|
||||
to more standard systems applications usually written in C.
|
||||
|
||||
Scsh comes built on top of {\scm}, and has two components:
|
||||
a process notation for running programs and setting up pipelines
|
||||
and redirections,
|
||||
and a complete syscall library for low-level access to the operating system.
|
||||
This manual gives a complete description of scsh.
|
||||
A general discussion of the design principles behind scsh can be found
|
||||
in a companion paper, ``A Scheme Shell.''
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Copyright \& source-code license}
|
||||
Scsh is open source. The complete sources come with the standard
|
||||
distribution, which can be downloaded off the net.
|
||||
Scsh has an ideologically hip, BSD-style license.
|
||||
|
||||
We note that the code is a rich source for other Scheme implementations
|
||||
to mine. Not only the \emph{code}, but the \emph{APIs} are available
|
||||
for implementors working on Scheme environments for systems programming.
|
||||
These APIs represent years of work, and should provide a big head-start
|
||||
on any related effort. (Just don't call it ``scsh,'' unless it's
|
||||
\emph{exactly} compliant with the scsh interfaces.)
|
||||
|
||||
Take all the code you like; we'll just write more.
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Obtaining scsh}
|
||||
Scsh is distributed via net publication.
|
||||
We place new releases at well-known network sites,
|
||||
and allow them to propagate from there.
|
||||
We currently release scsh to the following Internet sites:
|
||||
\begin{inset}\begin{flushleft}
|
||||
\ex{\urlh{ftp://ftp.scsh.net/pub/scsh}{ftp://ftp.scsh.net/pub/scsh}} \\
|
||||
\ex{\urlh{http://prdownloads.sourceforge.net/scsh/}{http://prdownloads.sourceforge.net/scsh/}} \\
|
||||
\end{flushleft}
|
||||
\end{inset}
|
||||
%
|
||||
Each should have a compressed tar file of the entire scsh release,
|
||||
which includes all the source code and the manual,
|
||||
and a separate file containing just this manual in Postscript form,
|
||||
for those who simply wish to read about the system.
|
||||
|
||||
However, nothing is certain for long on the Net.
|
||||
Probably the best way to get a copy of scsh is to use a network
|
||||
resource-discovery tool, such as archie,
|
||||
to find ftp servers storing scsh tar files.
|
||||
Take the set of sites storing the most recent release of scsh,
|
||||
choose one close to your site, and download the tar file.
|
||||
|
||||
\section{Building scsh}
|
||||
Scsh currently runs on a fairly large set of Unix systems, including
|
||||
Linux, FreeBSD, OpenBSD, NetBSD, MacOS X, SunOS, Solaris, AIX, NeXTSTEP, Irix, and HP-UX.
|
||||
We use the Gnu project's autoconfig tool to generate self-configuring
|
||||
shell scripts that customise the scsh Makefile for different OS variants.
|
||||
This means that if you use one of the common Unix implementations,
|
||||
building scsh should require exactly the following steps:
|
||||
\begin{inset}
|
||||
\begin{tabular}{l@{\qquad}l}
|
||||
\ex{gunzip scsh.tar.gz} & \emph{Uncompress the release tar file.} \\
|
||||
\ex{untar xfv scsh.tar} & \emph{Unpack the source code.} \\
|
||||
\ex{cd scsh-0.6.x} & \emph{Move to the source directory.} \\
|
||||
\ex{./configure} & \emph{Examine host; build Makefile.} \\
|
||||
\ex{make} & \emph{Build system.}
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
When you are done, you should have a virtual machine compiled in
|
||||
file \ex{scshvm}, and a heap image in file \ex{scsh/scsh.image}.
|
||||
Typing
|
||||
\begin{code}
|
||||
make install
|
||||
\end{code}
|
||||
will install these programs in your installation directory
|
||||
(by default, \ex{/usr/local}), along with a small stub startup
|
||||
binary, \ex{scsh}.
|
||||
|
||||
If you don't have the patience to do this, you can start up
|
||||
a Scheme shell immediately after the initial make by simply
|
||||
saying
|
||||
\codex{./scshvm -o ./scshvm -i scsh/scsh.image}
|
||||
See chapter~\ref{chapt:running} for full details on installation
|
||||
locations and startup options.
|
||||
|
||||
It is not too difficult to port scsh to another Unix platform if your
|
||||
OS is not supported by the current release.
|
||||
See the release notes for more details on how to do this.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Caveats}
|
||||
|
||||
It is important to note what scsh is \emph{not}, as well as what it is.
|
||||
Scsh, in the current release, is primarily designed for the writing of
|
||||
shell scripts---programming.
|
||||
It is not a very comfortable system for interactive command use:
|
||||
the current release lacks job control, command-line editing, a terse,
|
||||
convenient command syntax, and it does not read in an initialisation
|
||||
file analogous to \ex{.login} or \ex{.profile}.
|
||||
We hope to address all of these issues in future releases;
|
||||
we even have designs for several of these features;
|
||||
but the system as-released does not currently provide these features.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Naming conventions}
|
||||
Scsh follows a general naming scheme that consistently employs a set of
|
||||
abbreviations.
|
||||
This is intended to make it easier to remember the names of things.
|
||||
Some of the common ones are:
|
||||
\begin{description}
|
||||
\item [\ex{fdes}]
|
||||
Means ``file descriptor,'' a small integer used in {\Unix}
|
||||
to represent I/O channels.
|
||||
|
||||
\item [\ex{\ldots*}]
|
||||
A given bit of functionality sometimes comes in two related forms,
|
||||
the first being a \emph{special form} that contains a body of
|
||||
{\Scheme} code to be executed in some context,
|
||||
and the other being a \emph{procedure} that takes a procedural
|
||||
argument (a ``thunk'') to be called in the same context.
|
||||
The procedure variant is named by taking the name of the special form,
|
||||
and appending an asterisk. For example:
|
||||
\begin{code}
|
||||
;;; Special form:
|
||||
(with-cwd "/etc"
|
||||
(for-each print-file (directory-files))
|
||||
(display "All done"))
|
||||
|
||||
;;; Procedure:
|
||||
(with-cwd* "/etc"
|
||||
(lambda ()
|
||||
(for-each print-file (directory-files))
|
||||
(display "All done")))\end{code}
|
||||
|
||||
\item [\ex{\var{action}/\var{modifier}}]
|
||||
The infix ``\ex{/}'' is pronounced ``with,'' as in
|
||||
\ex{exec/env}---``exec with environment.''
|
||||
|
||||
\item [\ex{call/\ldots}]
|
||||
Procedures that call their argument on some computed value
|
||||
are usually named ``\ex{call/\ldots},'' \eg,
|
||||
\ex{(call/fdes \var{port} \var{proc})}, which calls \var{proc}
|
||||
on \var{port}'s file descriptor, returning whatever \var{proc}
|
||||
returns. The abbreviated name means ``call with file descriptor.''
|
||||
|
||||
\item [\ex{with-\ldots}]
|
||||
Procedures that call their argument, and special forms that execute
|
||||
their bodies in some special dynamic context frequently have
|
||||
names of the form \ex{with-\ldots}. For example,
|
||||
\ex{(with-env \var{env} \vari{body}1 \ldots)} and
|
||||
\ex{(with-env* \var{env} \var{thunk})}. These forms set
|
||||
the process environment body, execute their body or thunk,
|
||||
and then return after resetting the environment to its original
|
||||
state.
|
||||
|
||||
\item[\ex{create-}]
|
||||
Procedures that create objects in the file system (files, directories,
|
||||
temp files, fifos, \etc), begin with \ex{create-\ldots}.
|
||||
|
||||
\item [\ex{delete-}]
|
||||
Procedures that delete objects from the file system (files,
|
||||
directories, temp files, fifos, \etc), begin with \ex{delete-\ldots}.
|
||||
|
||||
\item[ \ex{\var{record}:\var{field}} ]
|
||||
Procedures that access fields of a record are usually written
|
||||
with a colon between the name of the record and the name of the
|
||||
field, as in \ex{user-info:home-dir}.
|
||||
|
||||
\item[\ex{\%\ldots}]
|
||||
A percent sign is used to prefix lower-level scsh primitives
|
||||
that are not commonly used.
|
||||
|
||||
\item[\ex{-info}]
|
||||
Data structures packaging up information about various OS
|
||||
entities frequently end in \ldots\ex{-info}. Examples:
|
||||
\ex{user-info}, \ex{file-info}, \ex{group-info}, and \ex{host-info}.
|
||||
|
||||
\end{description}
|
||||
%
|
||||
Enumerated constants from some set \var{s} are usually named
|
||||
\ex{\var{s}/\vari{const}1}, \ex{\var{s}/\vari{const}2}, \ldots.
|
||||
For example, the various {\Unix} signal integers have the names
|
||||
\ex{signal/cont}, \ex{signal/kill}, \ex{signal/int}, \ex{signal/hup},
|
||||
and so forth.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Lexical issues}
|
||||
Scsh's lexical syntax is just {\RnRS} {\Scheme}, with the following
|
||||
exceptions.
|
||||
|
||||
\subsection{Extended symbol syntax}
|
||||
Scsh's symbol syntax differs from {\RnRS} {\Scheme} in the following ways:
|
||||
\begin{itemize}
|
||||
\item In scsh, symbol case is preserved by \ex{read} and is significant on
|
||||
symbol comparison. This means
|
||||
\codex{(run (less Readme))}
|
||||
displays the right file.
|
||||
|
||||
\item ``\ex{-}'' and ``\ex{+}'' are allowed to begin symbols.
|
||||
So the following are legitimate symbols:
|
||||
\codex{-O2 -geometry +Wn}
|
||||
|
||||
\item ``\ex{|}'' and ``\ex{.}'' are symbol constituents.
|
||||
This allows \ex{|} for the pipe symbol, and \ex{..} for the parent-directory
|
||||
symbol. (Of course, ``\ex{.}'' alone is not a symbol, but a
|
||||
dotted-pair marker.)
|
||||
|
||||
\item A symbol may begin with a digit.
|
||||
So the following are legitimate symbols:
|
||||
\codex{9x15 80x36-3+440}
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Extended string syntax}
|
||||
Scsh strings are allowed to contain the {\Ansi} C escape sequences
|
||||
such as \verb|\n| and \verb|\161|.
|
||||
|
||||
\subsection{Block comments and executable interpreter-triggers}
|
||||
Scsh allows source files to begin with a header of the form
|
||||
\codex{\#!/usr/local/bin/scsh -s}
|
||||
The Unix operating system treats source files beginning with the headers
|
||||
of this form specially;
|
||||
they can be directly executed by the operating system
|
||||
(see chapter~\ref{chapt:running} for information on how to use this feature).
|
||||
The scsh interpreter ignores this special header by treating \ex{\#!} as a
|
||||
comment marker similar to \ex{;}.
|
||||
When the scsh reader encounters \ex{\#!}, it skips characters until it finds
|
||||
the closing sequence
|
||||
new\-line/{\ob}ex\-cla\-ma\-tion-{\ob}point/{\ob}sharp-{\ob}sign/{\ob}new\-line.
|
||||
|
||||
Although the form of the \ex{\#!} read-macro was chosen to support
|
||||
interpreter-triggers for executable Unix scripts,
|
||||
it is a general block-comment sequence and can be used as such
|
||||
anywhere in a scsh program.
|
||||
|
||||
\subsection{Here-strings}
|
||||
The read macro \ex{\#<} is used to introduce ``here-strings''
|
||||
in programs, similar to the \ex{<<} ``here document'' redirections
|
||||
provided by sh and csh.
|
||||
There are two kinds of here-string, character-delimited and line-delimited;
|
||||
they are both introduced by the \ex{\#<} sequence.
|
||||
|
||||
\subsubsection{Character-delimited here-strings}
|
||||
A \emph{character-delimited} here-string has the form
|
||||
\codex{\#<\emph{x}...stuff...\emph{x}}
|
||||
where \emph{x} is any single character
|
||||
(except \ex{<}, see below),
|
||||
which is used to delimit the string bounds.
|
||||
Some examples:
|
||||
\begin{inset}
|
||||
\begin{tabular}{ll}
|
||||
Here-string syntax & Ordinary string syntax \\ \hline
|
||||
\verb:#<|Hello, world.|: & \verb:"Hello, world.": \\
|
||||
\verb:#<!"Ouch," he said.!: & \verb:"\"Ouch,\" he said.":
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
%
|
||||
There is no interpretation of characters within the here-string;
|
||||
the characters are all copied verbatim.
|
||||
|
||||
\subsubsection{Line-delimited here-strings}
|
||||
If the sequence begins "\ex{\#<<}" then it introduces a \emph{line-delimited}
|
||||
here-string.
|
||||
These are similar to the ``here documents'' of sh and csh.
|
||||
Line-delimited here-strings are delimited by the rest of the text line that
|
||||
follows the "\ex{\#<<}" sequence.
|
||||
For example:
|
||||
|
||||
\begin{code}
|
||||
#<<FOO
|
||||
Hello, there.
|
||||
This is read by Scheme as a string,
|
||||
terminated by the first occurrence
|
||||
of newline-F-O-O-newline or newline-F-O-O-eof.
|
||||
FOO\end{code}
|
||||
%
|
||||
Thus,
|
||||
\begin{code}
|
||||
#<<foo
|
||||
Hello, world.
|
||||
foo\end{code}
|
||||
%
|
||||
is the same thing as
|
||||
\codex{"Hello, world."}
|
||||
|
||||
Line-delimited here-strings are useful for writing down long, constant
|
||||
strings---such as long, multi-line \ex{format} strings,
|
||||
or arguments to Unix programs, \eg,
|
||||
\begin{code}
|
||||
;; Free up some disk space for my netnews files.
|
||||
(run (csh -c #<<EOF
|
||||
cd /urops
|
||||
rm -rf *
|
||||
echo All done.
|
||||
|
||||
EOF
|
||||
))\end{code}
|
||||
|
||||
The advantage they have over the double-quote syntax
|
||||
(\eg, \ex{"Hello, world."})
|
||||
is that there is no need to backslash-quote special characters internal
|
||||
to the string, such as the double-quote or backslash characters.
|
||||
|
||||
The detailed syntax of line-delimited here-strings is as follows.
|
||||
The characters "\ex{\#<<}" begin the here-string.
|
||||
The characters between the "\ex{\#<<}" and the next newline are the
|
||||
\emph{delimiter line}.
|
||||
All characters between the "\ex{\#<<}" and the next newline comprise the
|
||||
delimiter line---including any white space.
|
||||
The body of the string begins on the following line,
|
||||
and is terminated by a line of text which exactly matches the
|
||||
delimiter line.
|
||||
This terminating line can be ended by either a newline or end-of-file.
|
||||
Absolutely no interpretation is done on the input string.
|
||||
Control characters, white space, quotes, backslash---everything
|
||||
is copied as-is.
|
||||
The newline immediately preceding the terminating delimiter line is
|
||||
not included in the result string
|
||||
(leave an extra blank line if you need to put a final
|
||||
newline in the here-string---see the example above).
|
||||
If EOF is encountered before reading the end of the here-string,
|
||||
an error is signalled.
|
||||
|
||||
\subsection{Dot}
|
||||
It is unfortunate that the single-dot token, ``\ex{.}'', is both
|
||||
a fundamental {\Unix} file name and a deep, primitive syntactic token
|
||||
in {\Scheme}---it means the following will not parse correctly in scsh:
|
||||
\codex{(run/strings (find . -name *.c -print))}
|
||||
You must instead quote the dot:
|
||||
\codex{(run/strings (find "." -name *.c -print))}
|
||||
|
||||
When you write shell scripts that manipulate the file system,
|
||||
keep in mind the special status of the dot token.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Record types and the \texttt{define-record} form}
|
||||
\label{sec:defrec}
|
||||
\index{define-record@\texttt{define-record}}
|
||||
|
||||
Scsh's interfaces occasionally provide data in structured record types;
|
||||
an example is the \ex{file-info} record whose various fields describe the size,
|
||||
protection, last date of modification, and other pertinent data for a
|
||||
particular file.
|
||||
These record types are described in this manual using the \ex{define-record}
|
||||
notation, which looks like the following:
|
||||
%
|
||||
\begin{code}
|
||||
(define-record ship
|
||||
x
|
||||
y
|
||||
(size 100))\end{code}
|
||||
%
|
||||
This form defines a \var{ship} record, with three fields:
|
||||
its x and y coordinates, and its size.
|
||||
The values of the \var{x} and \var{y} fields are specified as parameters
|
||||
to the ship-building procedure, \ex{(make-ship \var{x} \var{y})},
|
||||
and the \var{size} field is initialised to 100.
|
||||
All told, the \ex{define-record} form above defines the following procedures:
|
||||
%
|
||||
\begin{center}
|
||||
\begin{tabular}{|ll|}
|
||||
\multicolumn{1}{l}{Procedure} & \multicolumn{1}{l}{Definition} \\
|
||||
\hline
|
||||
(make-ship \var{x} \var{y}) & Create a new \var{ship} record. \\
|
||||
\hline
|
||||
(ship:x \var{ship}) & Retrieve the \var{x} field. \\
|
||||
(ship:y \var{ship}) & Retrieve the \var{y} field. \\
|
||||
(ship:size \var{ship}) & Retrieve the \var{size} field. \\
|
||||
\hline
|
||||
(set-ship:x \var{ship} \var{new-x}) & Assign the \var{x} field. \\
|
||||
(set-ship:y \var{ship} \var{new-y}) & Assign the \var{y} field. \\
|
||||
(set-ship:size \var{ship} \var{new-size}) & Assign the \var{size} field. \\
|
||||
\hline
|
||||
(modify-ship:x \var{ship} \var{xfun}) & Modify \var{x} field with \var{xfun}. \\
|
||||
(modify-ship:y \var{ship} \var{yfun}) & Modify \var{y} field with \var{yfun}. \\
|
||||
(modify-ship:size \var{ship} \var{sizefun}) & Modify \var{size} field with \var{sizefun}. \\
|
||||
\hline
|
||||
(ship? \var{object}) & Type predicate. \\
|
||||
\hline
|
||||
(copy-ship \var{ship}) & Shallow-copy of the record. \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
%
|
||||
|
||||
An implementation of \ex{define-record} is available as a macro for Scheme
|
||||
programmers to define their own record types;
|
||||
the syntax is accessed by opening the package \ex{defrec-package}, which
|
||||
exports the single syntax form \ex{define-record}.
|
||||
See the source code for the \ex{defrec-package} module
|
||||
for further details of the macro.
|
||||
|
||||
You must open this package to access the form.
|
||||
Scsh does not export a record-definition package by default as there are
|
||||
several from which to choose.
|
||||
Besides the \ex{define-record} macro, which Shivers prefers\footnote{He wrote
|
||||
it.}, you might instead wish to employ the notationally-distinct
|
||||
\ex{define-record-type} macro that Jonathan Rees
|
||||
prefers\footnote{He wrote it.}.
|
||||
It can be found in the
|
||||
\ex{define-record-types} structure.
|
||||
|
||||
Alternatively, you may define your own, of course.
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{A word about {\Unix} standards}
|
||||
``The wonderful thing about {\Unix} standards is that there are so many
|
||||
to choose from.''
|
||||
You may be totally bewildered about the multitude of various standards that
|
||||
exist.
|
||||
Rest assured that nowhere in this manual will you encounter an attempt
|
||||
to spell it all out for you;
|
||||
you could not read and internalise such a twisted account without
|
||||
bleeding from the nose and ears.
|
||||
|
||||
However, you might keep in mind the following simple fact: of all the
|
||||
standards, {\Posix} is the least common denominator.
|
||||
So when this manual repeatedly refers to {\Posix}, the point is ``the
|
||||
thing we are describing should be portable just about anywhere.''
|
||||
Scsh sticks to {\Posix} when at all possible; its major departure is
|
||||
symbolic links, which aren't in {\Posix} (see---it
|
||||
really \emph{is} a least common denominator).
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: latex
|
||||
%%% TeX-master: "man"
|
||||
%%% End:
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
% man.t2p
|
||||
% Dorai Sitaram
|
||||
% Feb 6, 2000
|
||||
|
||||
% This file contains the tex2page macros needed to process
|
||||
% the scsh LaTeX document scsh-n.n.n/doc/scsh-manual/man.tex.
|
||||
% Copy (or link) this file alongside man.tex and run
|
||||
%
|
||||
% tex2page man
|
||||
|
||||
\input css.t2p
|
||||
\htmlmathstyle{no-image}
|
||||
|
||||
\let\pagebreak\relax
|
||||
|
||||
\let\small\relax
|
||||
|
||||
%\let\PRIMtableofcontents\tableofcontents
|
||||
%\def\tableofcontents{\chapter*{Contents}\PRIMtableofcontents}
|
||||
|
||||
\def\subtitle#1{\def\savesubtitle{#1}}
|
||||
|
||||
\def\maketitle{
|
||||
\subject{\TIIPtitle}
|
||||
{\bf \hr}
|
||||
\rightline{\savesubtitle}
|
||||
\bigskip\bigskip
|
||||
\bigskip\bigskip
|
||||
{\bf\TIIPauthor}
|
||||
{\bf\hr}
|
||||
}
|
||||
|
||||
\let\PRIMdocument\document
|
||||
|
||||
\def\document{\PRIMdocument
|
||||
|
||||
\let\ttchars\relax
|
||||
\let\ttt\tt
|
||||
|
||||
%\def\~{\rawhtml~\endrawhtml}
|
||||
\def\~{\char`\~}
|
||||
\def\cd#1{{\tt\def\\{\char`\\}\defcsactive\${\char`\$}\defcsactive\~{\char`\~}\defcsactive\&{\char`\&}#1}}
|
||||
\def\cddollar{\undefcsactive\$}
|
||||
\def\cdmath{\undefcsactive\$}
|
||||
\def\codeallowbreaks{\relax}
|
||||
\def\defvarx#1#2{\index{#1}\leftline{{\tt #1} \qquad #2}}
|
||||
|
||||
\let\PRIMflushright\flushright
|
||||
|
||||
\def\flushright{\PRIMflushright\TIIPtabularborder=0 }
|
||||
|
||||
\let\PRIMfigure\figure
|
||||
\let\PRIMendfigure\endfigure
|
||||
|
||||
\def\figure{\par\hrule\PRIMfigure}
|
||||
\def\endfigure{\PRIMendfigure\hrule\par}
|
||||
|
||||
\let\PRIMtable\table
|
||||
\let\PRIMendtable\endtable
|
||||
|
||||
\def\table{\par\hrule\PRIMtable}
|
||||
\def\endtable{\PRIMendtable\hrule\par}
|
||||
|
||||
\imgdef\vdots{\bf.\par.\par.}
|
||||
|
||||
%\evalh{
|
||||
%
|
||||
%(define all-blanks?
|
||||
% (lambda (s)
|
||||
% (andmap
|
||||
% char-whitespace?
|
||||
% (string->list s))))
|
||||
%
|
||||
%}
|
||||
%
|
||||
%
|
||||
%\def\spaceifnotempty{\evalh{
|
||||
%
|
||||
%(let ((x (ungroup (get-token))))
|
||||
% (unless (all-blanks? x)
|
||||
% (emit #\space)))
|
||||
%
|
||||
%}}
|
||||
|
||||
\def\spaceifnotempty#1{%
|
||||
\def\TEMP{#1}%
|
||||
\ifx\TEMP\empty\else\ \fi}
|
||||
|
||||
\def\dfnix#1#2#3#4#5{\index{#5}\leftline{{\tt(#1\spaceifnotempty{#2}{\it#2})} \quad $\longrightarrow$ \quad {\it #3} \qquad (#4)}}
|
||||
|
||||
%\def\ex#1{{\tt #1}}
|
||||
%\let\ex\texttt
|
||||
\def\l#1{lambda (#1)}
|
||||
\def\lx#1{lambda {#1}}
|
||||
%\def\notenum#1{}
|
||||
%\def\project#1{}
|
||||
%\def\var#1{{\it #1\/}}
|
||||
%\let\var\textit
|
||||
%\def\vari#1#2{\mbox{{\it #1\/}\undefcsactive\$$_{#2}$}}
|
||||
%\def\vari#1#2{\textit{#1}$_{#2}$}
|
||||
|
||||
\renewenvironment{boxedfigure}{\def\srecomment#1{\\#1\\}%
|
||||
\begin{figure}\pagestyle}{\end{figure}}
|
||||
|
||||
\newenvironment{centercode}{\begin{code}}{\end{code}}
|
||||
|
||||
\def\setupcode{\tt%
|
||||
\def\\{\char`\\}%
|
||||
\defcsactive\${\$}%
|
||||
\def\evalto{==> }%
|
||||
\defcsactive\%{\%}\obeywhitespace}
|
||||
|
||||
\newenvironment{code}{\begin{quote}\setupcode\GOBBLEOPTARG}
|
||||
{\end{quote}}
|
||||
|
||||
\newenvironment{codebox}{\begin{tableplain}\bgroup\setupcode\GOBBLEOPTARG}
|
||||
{\egroup\end{tableplain}}
|
||||
|
||||
\renewenvironment{desc}{\begin{quote}}{\end{quote}}
|
||||
|
||||
\renewenvironment{exampletable}{%
|
||||
\def\header#1{\\\leftline{#1}\\}%
|
||||
\def\splitline#1#2{\\\leftline{#1}\\\leftline{#2}}%
|
||||
\begin{tabular}{}}{\end{tabular}}
|
||||
|
||||
\newenvironment{tightcode}{\begin{code}}{\end{code}}
|
||||
\renewenvironment{widecode}{\begin{code}}{\end{code}}
|
||||
|
||||
\renewenvironment{inset}{\begin{quote}}{\end{quote}}
|
||||
\renewenvironment{leftinset}{\begin{quote}}{\end{quote}}
|
||||
\renewenvironment{tightinset}{\begin{quote}}{\end{quote}}
|
||||
\renewenvironment{tightleftinset}{\begin{quote}}{\end{quote}}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
% -*- latex -*-
|
||||
|
||||
% This is the reference manual for the Scheme Shell.
|
||||
|
||||
\documentclass[twoside]{report}
|
||||
\usepackage{code,boxedminipage,makeidx,palatino,ct,
|
||||
headings,mantitle,array,matter,mysize10,tex2page}
|
||||
|
||||
\texonly
|
||||
% tex2page defines \url and hyperref loads the package url
|
||||
% but setting \url to \relax satisfies \newcommand
|
||||
\let\url\relax
|
||||
\input{pdfcond}
|
||||
\ifpdf
|
||||
\usepackage[pdftex,hyperindex,
|
||||
pdftitle={scsh manual, release 0.6.7},
|
||||
pdfauthor={Olin Shivers, Brian D.~Carlstrom, Martin Gasbichler,
|
||||
and Mike Sperber}
|
||||
colorlinks=true,linkcolor=blue,pagecolor=blue,urlcolor=blue,
|
||||
pdfstartview=FitH,pdfview=FitH]{hyperref}
|
||||
\usepackage{thumbpdf}
|
||||
\usepackage{tocbibind}
|
||||
\else
|
||||
\usepackage[dvipdfm,hyperindex,hypertex,
|
||||
colorlinks=true,linkcolor=blue,pagecolor=blue,urlcolor=blue]{hyperref}
|
||||
\fi
|
||||
\endtexonly
|
||||
|
||||
% These fonts are good choices for screen-readable pdf, but the man needs
|
||||
% a pass over the layout, since the this tt font will blow out the width
|
||||
% of some examples, making them wrap and generally screwing them up. Maybe this
|
||||
% should also be a LaTeX option, so we can get palatino on the hardcopy
|
||||
% runs and these fonts on pdf runs...
|
||||
%\renewcommand{\rmdefault}{phv}
|
||||
%\renewcommand{\sfdefault}{phv}
|
||||
%\renewcommand{\ttdefault}{pcr}
|
||||
|
||||
% Style issues
|
||||
\parskip = 3pt plus 3pt
|
||||
\sloppy
|
||||
|
||||
%\includeonly{miscprocs}
|
||||
|
||||
\input{decls}
|
||||
\makeindex
|
||||
%%% End preamble
|
||||
|
||||
|
||||
\begin{document}
|
||||
|
||||
\frontmatter
|
||||
\include{front}
|
||||
|
||||
\mainmatter
|
||||
\include{intro}
|
||||
\include{procnotation}
|
||||
\include{syscalls}
|
||||
\include{network}
|
||||
\include{strings}
|
||||
\include{sre}
|
||||
\include{rdelim}
|
||||
\include{awk}
|
||||
\include{threads}
|
||||
\include{miscprocs}
|
||||
\include{running}
|
||||
|
||||
\backmatter
|
||||
\printindex
|
||||
|
||||
\end{document}
|
||||
|
||||
% General things to do when converting ASCII text to LaTeX:
|
||||
% Build a set of \breakondash, \breakondot, \breakonslash commands
|
||||
% that will enable breaking in \tt. This is better than \=, etc.
|
||||
%
|
||||
% Check for ..., quote char, double-dashes --
|
||||
% Double-word check
|
||||
% lambda -> \l
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
% This is the title page style stolen from the Texinfo design,
|
||||
% and expressed as a LaTeX style option. It is useful for manuals.
|
||||
%
|
||||
% Note that I play some *really* revolting games here to override
|
||||
% the vertical and horizontal margins temporarily for the title page.
|
||||
% The layout assumes you have 8.5" x 11" paper. You'd have to redo this
|
||||
% for A4 or another size.
|
||||
% -Olin 7/94
|
||||
|
||||
|
||||
% Fonts for title page:
|
||||
\DeclareFixedFont{\titlefont}%
|
||||
{\encodingdefault}{\familydefault}{bx}{\shapedefault}{20.5pt}
|
||||
\DeclareFixedFont{\authorfnt}%
|
||||
{\encodingdefault}{\familydefault}{bx}{\shapedefault}{14.4pt}
|
||||
\DeclareFixedFont{\subtitlefnt}%
|
||||
{\encodingdefault}{\familydefault}{m}{\shapedefault}{11}
|
||||
|
||||
%\def\authorrm{\normalfont\selectfont\fontseries{bx}\fontsize{14.4}{14.4}}
|
||||
%\def\subtitlefnt{\normalfont\selectfont\fontsize{11}{11}}
|
||||
|
||||
\newskip\titlepagetopglue \titlepagetopglue = 2.5in
|
||||
|
||||
|
||||
\newlength{\widewidth}
|
||||
\setlength{\widewidth}{6.5in}
|
||||
\newlength{\negwidemargin}
|
||||
\setlength{\negwidemargin}{-\oddsidemargin} % Reset the margin
|
||||
\addtolength{\negwidemargin}{-1in} % to edge of page
|
||||
\addtolength{\negwidemargin}{1in} % Then move right one inch.
|
||||
|
||||
%\def\wideline#1{\hbox to 0pt{\hspace\negwidemargin\hbox to\widewidth{#1}}}
|
||||
\def\wideline#1{\hbox{\makebox[0pt][l]{\hspace\negwidemargin\hbox to\widewidth{#1}}}}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\def\maketitle{\begin{titlepage}
|
||||
\thispagestyle{empty}
|
||||
\let\footnotesize\small \let\footnoterule\relax
|
||||
\null
|
||||
\parindent=0pt
|
||||
\def\subtitlefont{\normalbaselineskip = 13pt \normalbaselines \subtitlefnt}%
|
||||
\def\authorfont{\normalbaselineskip = 16pt \normalbaselines \authorfnt}%
|
||||
%
|
||||
% Leave some space at the very top of the page.
|
||||
\vspace*{-1in}\vspace*{-\topmargin}\vspace*{-\headheight}\vspace*{-\headsep}
|
||||
\vglue\titlepagetopglue
|
||||
%
|
||||
\wideline{\titlefont \@title \hfill} % title
|
||||
% \vskip4pt
|
||||
\vskip -0.3\baselineskip
|
||||
\wideline{\leaders\hrule height 4pt\hfill}
|
||||
\wideline{\hfill\subtitlefont\begin{tabular}[t]{@{}r@{}}\@subtitle%
|
||||
\\\@date%
|
||||
\end{tabular}} % subtitle
|
||||
%
|
||||
% author
|
||||
\vskip 0pt plus 1filll
|
||||
\wideline{\authorfont \begin{tabular}[t]{@{}c@{}}\@author
|
||||
\end{tabular}\hfill}
|
||||
%
|
||||
% \vskip4pt
|
||||
\vskip -0.3\baselineskip
|
||||
\wideline{\leaders\hrule height 2pt\hfill}
|
||||
|
||||
% This weirdness puts the bottom line 2.75 in from the bottom of
|
||||
% an 11in page.
|
||||
\vskip \textheight \vskip \headsep \vskip \headheight
|
||||
\vskip \topmargin \vskip 1in \vskip -11in \vskip 2.75in
|
||||
|
||||
\gdef\@author{}\gdef\@title{}\gdef\@subtitle{}\let\maketitle\relax
|
||||
\end{titlepage}
|
||||
\setcounter{page}{2}
|
||||
}
|
||||
|
||||
\def\subtitle#1{\gdef\@subtitle{#1}}
|
||||
\def\@subtitle{}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
%&latex -*- latex -*-
|
||||
% Implement the \frontmatter, \mainmatter, and \backmatter macros,
|
||||
% so I can use them in reports, not just books.
|
||||
|
||||
\newif\if@mainmatter \@mainmattertrue
|
||||
|
||||
\newcommand\frontmatter{%
|
||||
\cleardoublepage\@mainmatterfalse\pagenumbering{roman}}
|
||||
|
||||
\newcommand\mainmatter{%
|
||||
\cleardoublepage\@mainmattertrue%
|
||||
\pagenumbering{arabic}\setcounter{page}{1}}
|
||||
|
||||
\newcommand\backmatter{%
|
||||
\if@openright\cleardoublepage\else\clearpage\fi%
|
||||
\@mainmatterfalse}
|
||||
|
|
@ -0,0 +1,457 @@
|
|||
%&latex -*- latex -*-
|
||||
|
||||
\chapter{Miscellaneous routines}
|
||||
|
||||
\section{Integer bitwise ops}
|
||||
\label{sec:bitwise}
|
||||
\defun{arithmetic-shift} {i j} \integer
|
||||
\defunx {bitwise-and} {i j} \integer
|
||||
\defunx {bitwise-ior} {i j} \integer
|
||||
\defunx {bitwise-not} {i} \integer
|
||||
\defunx {bitwise-xor} {i j} \integer
|
||||
\begin{desc}
|
||||
These operations operate on integers representing semi-infinite
|
||||
bit strings, using a 2's-complement encoding.
|
||||
|
||||
\ex{arithmetic-shift} shifts \var{i} by \var{j} bits.
|
||||
A left shift is $j > 0$; a right shift is $j < 0$.
|
||||
\end{desc}
|
||||
|
||||
\section{Password encryption}
|
||||
|
||||
\defun {crypt} {key salt} {encrypted value}
|
||||
|
||||
Decrypts \var{key} by directly calling the \texttt{crypt} function
|
||||
using \var{salt} to perturb the hashing algorithm. \var{Salt} must be
|
||||
a two-character string consisting of digits, alphabetic characters,
|
||||
``.'' or ``\verb+\+''. The length of \var{key} may be at most eight.
|
||||
|
||||
\section{Dot-Locking}
|
||||
Section \ref{sec:filelocking} already points out that {\Posix}'s file
|
||||
locks are almost useless in practice. To bypass this restriction other
|
||||
advisory locking mechanisms, based only on standard file operations,
|
||||
where invented. One of them is the so-called \emph{dot-locking} scheme
|
||||
where the lock of \textit{file-name} is represented by the file
|
||||
\textit{file-name}\texttt{.lock}. Care is taken that only one process
|
||||
may generate the lock for a given file.
|
||||
|
||||
Here is scsh's interface to dot-locking:
|
||||
|
||||
\defun {obtain-dot-lock} {file-name [interval retry-number stale-time]} {\boolean}
|
||||
|
||||
\begin{desc}
|
||||
Tries to obtain the lock for \var{file-name}. If the file is already
|
||||
locked, the thread sleeps for \var{interval} seconds (default is 1)
|
||||
before it retries. If the lock cannot be obtained after
|
||||
\var{retry-number} attempts, the procedure returns \sharpf,
|
||||
otherwise \sharpt. The default value of \var{retry-number} is
|
||||
\sharpf{} which corresponds to an infinite number of retires.
|
||||
|
||||
If \var{stale-time} is non-\sharpf, it specifies the minimum age a
|
||||
lock may have (in seconds) before it is considered \textit{stale}.
|
||||
\ex{Obtain-dot-lock} attempts to delete stale locks. If it was
|
||||
succcessful obtaining a lock after breaking it, \ex{obtain-dot-lock}
|
||||
returns \ex{broken}. If \var{stale-time} is \sharpf,
|
||||
\ex{obtain-dot-lock} never considers a lock stale. The default for
|
||||
\var{stale-time} is 300.
|
||||
|
||||
Note that it is possible that \ex{obtain-dot-lock} breaks a lock
|
||||
but nevertheless fails to obtain it otherwise. If it is necessary
|
||||
to handle this case specially, use \ex{break-dot-lock} directly
|
||||
(see below) rather than specifying a non-\sharpf{} \var{stale-time}
|
||||
\end{desc}
|
||||
|
||||
\defun {break-dot-lock} {file-name} {undefined}
|
||||
|
||||
\begin{desc}
|
||||
Breaks the lock for \var{file-name} if one exists. Note that
|
||||
breaking a lock does \emph{not} imply a subsequent
|
||||
\ex{obtain-dot-lock} will succeed, as another party may have
|
||||
acquired the lock between \ex{break-dot-lock} and
|
||||
\ex{obtain-dot-lock}.
|
||||
\end{desc}
|
||||
|
||||
\defun {release-dot-lock} {file-name} {\boolean}
|
||||
|
||||
\begin{desc}
|
||||
Releases the lock for \var{file-name}. On success,
|
||||
\ex{release-dot-lock} returns \sharpt, otherwise \sharpf. Note that
|
||||
this procedure can also be used to break the lock for
|
||||
\var{file-name}.
|
||||
\end{desc}
|
||||
|
||||
|
||||
\defun{with-dot-lock*} {file-name thunk} {value(s) of thunk}
|
||||
\dfnx{with-dot-lock} {file-name body \ldots} {value(s) of body}{syntax}
|
||||
|
||||
\begin{desc}
|
||||
The procedure \ex{with-dot-lock*} obtains the requested lock, and
|
||||
then calls \ex{(\var{thunk})}. When \var{thunk} returns, the lock is
|
||||
released. A non-local exit (\eg, throwing to a saved continuation
|
||||
or raising an exception) also causes the lock to be released.
|
||||
|
||||
After a normal return from \var{thunk}, its return values are
|
||||
returned by \ex{with-dot-lock*}. The \ex{with-dot-lock} special
|
||||
form is equivalent syntactic sugar.
|
||||
\end{desc}
|
||||
|
||||
\section{Syslog facility}
|
||||
\label{syslog-facility}
|
||||
|
||||
(Note: the functionality presented in this section is still somewhat
|
||||
experimental and thus subject to interface changes.)
|
||||
|
||||
The procedures in this section provide access to the 4.2BSD syslog
|
||||
facility present in most POSIX systems. The functionality is in a
|
||||
structure called \ex{syslog}. There's an additional structure
|
||||
\ex{syslog-channels} documented below. The scsh interface to
|
||||
the syslog facility differs significantly from that of the Unix
|
||||
library functionality in order to support multiple simultaneous
|
||||
connections to the syslog facility.
|
||||
|
||||
Log messages carry a variety of parameters beside the text of the
|
||||
message itself, namely a set of options controlling the output format
|
||||
and destination, the facility identifying the class of programs the
|
||||
message is coming from, an identifier specifying the conrete program,
|
||||
and the level identifying the importance of the message. Moreover, a
|
||||
log mask can prevent messages at certain levels to be actually sent to
|
||||
the syslog daemon.
|
||||
|
||||
\subsection*{Log options}
|
||||
|
||||
A log option specifies details of the I/O behavior of the syslog
|
||||
facility. A syslog option is an element of a finite type (see
|
||||
the \scm~manual) constructed by the
|
||||
\ex{syslog-option} macro. The syslog facility works with sets of
|
||||
options which are represented as enum sets (see
|
||||
the \scm~manual).
|
||||
|
||||
\dfn{syslog-option}{option-name}{option}{syntax}
|
||||
|
||||
\defun{syslog-option?}{x}{boolean}
|
||||
|
||||
\defun{make-syslog-options}{list}{options}
|
||||
|
||||
\dfn{syslog-options}{option-name \ldots}{options}{syntax}
|
||||
|
||||
\defun{syslog-options?}{x}{boolean}
|
||||
|
||||
\begin{desc}
|
||||
\ex{Syslog-option} constructs a log option from the name of an
|
||||
option. (The possible names are listed below.) \ex{Syslog-option?}
|
||||
is a predicate for log options. Options are comparable using
|
||||
\ex{eq?}. \ex{Make-syslog-options} constructs a set of options
|
||||
from a list of options. \ex{Syslog-options} is a macro which
|
||||
expands into an expression returning a set of options from names.
|
||||
\ex{Syslog-options?} is a predicate for sets of options.
|
||||
\end{desc}
|
||||
%
|
||||
Here is a list of possible names of syslog options:
|
||||
|
||||
\begin{description}
|
||||
\item[\ex{console}]
|
||||
If syslog cannot pass the message to syslogd it will attempt to
|
||||
write the message to the console.
|
||||
|
||||
\item[\ex{delay}]
|
||||
Delay opening the connection to syslogd immediately until the first
|
||||
message is logged.
|
||||
|
||||
\item[\ex{no-delay}]
|
||||
Open the connection to syslogd immediately. Normally
|
||||
the open is delayed until the first message is logged.
|
||||
Useful for programs that need to manage the order in which
|
||||
file descriptors are allocated.
|
||||
|
||||
\noindent\textbf{NOTA BENE:}
|
||||
The \ex{delay} and \ex{no-delay} options are included for
|
||||
completeness, but do not have the expected effect in the present
|
||||
Scheme interface: Because the Scheme interface has to multiplex
|
||||
multiple simultaneous connections to the syslog facility over a
|
||||
single one, open and close operations on that facility happen at
|
||||
unpredictable times.
|
||||
|
||||
\item[\ex{log-pid}]
|
||||
Log the process id with each message: useful for identifying
|
||||
instantiations of daemons.
|
||||
\end{description}
|
||||
|
||||
\subsection*{Log facilities}
|
||||
|
||||
A log facility identifies the originator of a log message from a
|
||||
finite set known to the system. Each originator is identified by a
|
||||
name:
|
||||
|
||||
\dfn{syslog-facility}{facility-name}{facility}{syntax}
|
||||
\defun{syslog-facility?}{x}{boolean}
|
||||
|
||||
\begin{desc}
|
||||
\ex{Syslog-facility} is macro that expands into an expression
|
||||
returning a facility for a given name. \ex{Syslog-facility?} is a
|
||||
predicate for facilities. Facilities are comparable via \ex{eq?}.
|
||||
\end{desc}
|
||||
%
|
||||
Here is a list of possible names of syslog facilities:
|
||||
|
||||
\begin{description}
|
||||
\item[\ex{authorization}]
|
||||
The authorization system: login, su, getty, etc.
|
||||
|
||||
\item[\ex{cron}]
|
||||
The cron daemon.
|
||||
|
||||
\item[\ex{daemon}]
|
||||
System daemons, such as routed, that are not provided for explicitly
|
||||
by other facilities.
|
||||
|
||||
\item[\ex{kernel}]
|
||||
Messages generated by the kernel.
|
||||
|
||||
\item[\ex{lpr}]
|
||||
The line printer spooling system: lpr, lpc, lpd, etc.
|
||||
|
||||
\item[\ex{mail}]
|
||||
The mail system.
|
||||
|
||||
\item[\ex{news}]
|
||||
The network news system.
|
||||
|
||||
\item[\ex{user}]
|
||||
Messages generated by random user processes.
|
||||
|
||||
\item[\ex{uucp}]
|
||||
The uucp system.
|
||||
|
||||
\item[\ex{local0} \ex{local1} \ex{local2} \ex{local3} \ex{local4} \ex{local5} \ex{local6} \ex{local7}]
|
||||
Reserved for local use.
|
||||
\end{description}
|
||||
|
||||
\subsection*{Log levels}
|
||||
|
||||
A log level identifies the importance of a message from a fixed set
|
||||
of possible levels.
|
||||
|
||||
\dfn{syslog-level}{level-name}{level}{syntax}
|
||||
\defun{syslog-level?}{x}{boolean}
|
||||
%
|
||||
\begin{desc}
|
||||
\ex{Syslog-level} is macro that expands into an expression returning
|
||||
a facility for a given name. \ex{Syslog-level?} is a predicate for
|
||||
facilities. Levels are comparable via \ex{eq?}.
|
||||
\end{desc}
|
||||
%
|
||||
Here is a list of possible names of syslog levels:
|
||||
|
||||
\begin{description}
|
||||
\item[\ex{emergency}]
|
||||
A panic condition. This is normally broadcast to all users.
|
||||
|
||||
\item[\ex{alert}]
|
||||
A condition that should be corrected immediately, such as a
|
||||
corrupted system database.
|
||||
|
||||
\item[\ex{critical}]
|
||||
Critical conditions, e.g., hard device errors.
|
||||
|
||||
\item[\ex{error}]
|
||||
Errors.
|
||||
|
||||
\item[\ex{warning}]
|
||||
Warning messages.
|
||||
|
||||
\item[\ex{notice}]
|
||||
Conditions that are not error conditions, but should possibly be
|
||||
handled specially.
|
||||
|
||||
\item[\ex{info}]
|
||||
Informational messages.
|
||||
|
||||
\item[\ex{debug}]
|
||||
Messages that contain information normally of use only when
|
||||
debugging a program.
|
||||
\end{description}
|
||||
|
||||
\subsection*{Log masks}
|
||||
|
||||
A log masks can mask out log messages at a set of levels. A log
|
||||
mask is an enum set of log levels.
|
||||
|
||||
\defun{make-syslog-mask}{list}{mask}
|
||||
\dfn{syslog-mask}{level-name \ldots}{mask}{syntax}
|
||||
\defvar{syslog-mask-all}{mask}
|
||||
\defun{syslog-mask-upto}{level}{mask}
|
||||
\defun{syslog-mask?}{x}{boolean}
|
||||
|
||||
\begin{desc}
|
||||
\ex{Make-syslog-mask} constructs a mask from a list of levels.
|
||||
\ex{Syslog-mask} is a macro which constructs a mask from names of
|
||||
levels. \ex{Syslog-mask-all} is a predefined log mask containing
|
||||
all levels. \ex{Syslog-mask-upto} returns a mask consisting of all
|
||||
levels up to and including a certain level, starting with
|
||||
\ex{emergency}.
|
||||
\end{desc}
|
||||
|
||||
\subsection*{Logging}
|
||||
|
||||
Scheme~48 dynamically maintains implicit connections to the syslog
|
||||
facility specifying a current identifier, current options, a current
|
||||
facility and a current log mask. This implicit connection is held in
|
||||
a thread fluid (see
|
||||
Section~\ref{sec:ps_interac}). Hence, every thread
|
||||
maintains it own implicit connection to syslog. Note that the
|
||||
connection is not implicitly preserved across a \ex{spawn}, but it
|
||||
is preserved across a \ex{fork-thread}:
|
||||
|
||||
|
||||
\defun{with-syslog-destination}{string options facility mask thunk}{value}
|
||||
\defun{set-syslog-destination!}{string options facility mask}{undefined}
|
||||
%
|
||||
\begin{desc}
|
||||
\ex{With-syslog-destination} dynamically binds parameters of the
|
||||
implicit connection to the syslog facility and runs \var{thunk}
|
||||
within those parameter bindings, returning what \var{thunk}
|
||||
returns. Each of the parameters may be \ex{\#f} in which case the
|
||||
previous values will be used. \ex{Set-syslog-destination!} sets the
|
||||
parameters of the implicit connection of the current thread.
|
||||
\end{desc}
|
||||
|
||||
\defun{syslog}{level message}{undefined}
|
||||
\defun{syslog}{level message [string options syslog-facility]}{undefined}
|
||||
%
|
||||
\begin{desc}
|
||||
\ex{Syslog} actually logs a message. Each of the parameters of the
|
||||
implicit connection (except for the log mask) can be explicitly
|
||||
specified as well for the current call to \ex{syslog}, overriding
|
||||
the parameters of the channel. The parameters revert to their
|
||||
original values after the call.
|
||||
\end{desc}
|
||||
|
||||
\subsection*{Syslog channels}
|
||||
%
|
||||
The \ex{syslog-channels} structure allows direct manipulation of
|
||||
syslog channels, the objects that represent connections to the syslog
|
||||
facility. Note that it is
|
||||
not necessary to explicitly open a syslog channel to do logging.
|
||||
|
||||
\defun{open-syslog-channel}{string options facility mask}{channel}
|
||||
\defun{close-syslog-channel}{channel}{undefined}
|
||||
\defun{syslog}{level message channel}{undefined}
|
||||
%
|
||||
\begin{desc}
|
||||
\ex{Open-syslog-channel} and \ex{close-syslog-channel} create and
|
||||
destroy a connection to the syslog facility, respectively. The
|
||||
specified form of calling \ex{syslog} logs to the specified channel.
|
||||
\end{desc}
|
||||
|
||||
|
||||
\section{MD5 interface}
|
||||
\label{sec:md5}
|
||||
|
||||
Scsh provides a direct interface to the MD5 functions to compute the
|
||||
``fingerprint'' or ``message digest'' of a file or string. It uses the
|
||||
C library written by Colin Plum.
|
||||
|
||||
\defun{md5-digest-for-string}{string}{md5-digest}
|
||||
\begin{desc}
|
||||
Calculates the MD5 digest for the given string.
|
||||
\end{desc}
|
||||
\defun{md5-digest-for-port}{port [buffer-size]}{md5-digest}
|
||||
\begin{desc}
|
||||
Reads the contents of the port and calculates the MD5 digest for it.
|
||||
The optional argument \var{buffer-size} determines the size of the
|
||||
port's input buffer in bytes. It defaults to 1024 bytes.
|
||||
\end{desc}
|
||||
|
||||
\defun{md5-digest?}{thing}{boolean}
|
||||
\begin{desc}
|
||||
The type predicate for MD5 digests: \ex{md5-digest?} returns true if
|
||||
and only if \var{thing} is a MD5 digest.
|
||||
\end{desc}
|
||||
\defun{md5-digest->number}{md5-digest}{number}
|
||||
\begin{desc}
|
||||
Returns the number corresponding to the MD5 digest.
|
||||
\end{desc}
|
||||
\defun{number->md5-digest}{number}{md5-digest}
|
||||
\begin{desc}
|
||||
Creates a MD5 digest from a number.
|
||||
\end{desc}
|
||||
|
||||
\defun{make-md5-context}{}{md5-context}
|
||||
\defunx{md5-context?}{thing}{boolean}
|
||||
\defunx{update-md5-context!}{md5-context string}\undefined
|
||||
\defunx{md5-context->md5-digest}{md5-context}{md5-digest}
|
||||
\begin{desc}
|
||||
These procedures provide a low-level interface to the library. A
|
||||
\var{md5-context} stores the state of a MD5 computation, it is
|
||||
created by \ex{make-md5-context}, its type predicate is
|
||||
\ex{md5-context?}. The procedure \ex{update-md5-context!} extends
|
||||
the \var{md5-context} by the given string. Finally,
|
||||
\ex{md5-context->md5-digest} returns the \var{md5-digest} for the
|
||||
\var{md5-context}. With these procedures it is possible to
|
||||
incrementally add strings to a \var{md5-context} before computing
|
||||
the digest.
|
||||
\end{desc}
|
||||
|
||||
\section{Configuration variables}
|
||||
\label{sec:configure}
|
||||
|
||||
This section describes procedures to access the configuration
|
||||
parameters used to compile scsh and flags needed to build C extensions
|
||||
for scsh.
|
||||
|
||||
\defun{host}{}{string}
|
||||
\defunx{machine}{}{string}
|
||||
\defunx{vendor}{}{string}
|
||||
\defunx{os}{}{string}
|
||||
\begin{desc}
|
||||
These procedures return the description of the host, scsh was built
|
||||
on, as determined by the script \texttt{config.guess}.
|
||||
\end{desc}
|
||||
%
|
||||
\defun{prefix}{}{string}
|
||||
\defunx{exec-prefix}{}{string}
|
||||
\defunx{bin-dir}{}{string}
|
||||
\defunx{lib-dir}{}{string}
|
||||
\defunx{include-dir}{}{string}
|
||||
\defunx{man-dir}{}{string}
|
||||
\begin{desc}
|
||||
These procedures return the various directories of
|
||||
the scsh installation.
|
||||
\end{desc}
|
||||
%
|
||||
\defun{lib-dirs-list}{}{symbol list}
|
||||
\begin{desc}
|
||||
Returns the default list of library directories. See
|
||||
Section~\ref{sec:scsh-switches} for more information about the
|
||||
library search facility.
|
||||
\end{desc}
|
||||
%
|
||||
\defun{libs}{}{string}
|
||||
\defunx{defs}{}{string}
|
||||
\defunx{cflags}{}{string}
|
||||
\defunx{cppflags}{}{string}
|
||||
\defunx{ldflags}{}{string}
|
||||
\begin{desc}
|
||||
The values returned by these procedures correspond to the values
|
||||
\texttt{make} used to compile scsh's C files.
|
||||
\end{desc}
|
||||
%
|
||||
\defunx{compiler-flags}{}{string}
|
||||
\begin{desc}
|
||||
The procedure \var{compiler-flags} returns flags suitable for
|
||||
running the C compiler when compiling a C file that uses scsh's
|
||||
foreign function interface.
|
||||
\end{desc}
|
||||
|
||||
\defun{linker-flags}{}{string}
|
||||
\begin{desc}
|
||||
Scsh also comes as a library that can be linked into other programs.
|
||||
The procedure \var{linker-flags} returns the appropriate flags to
|
||||
link the scsh library to another program.
|
||||
\end{desc}
|
||||
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: latex
|
||||
%%% TeX-master: "man"
|
||||
%%% End:
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
%&latex -*- latex -*-
|
||||
\if@twoside
|
||||
\oddsidemargin 44pt
|
||||
\evensidemargin 82pt
|
||||
\marginparwidth 107pt
|
||||
\else
|
||||
\oddsidemargin 63pt
|
||||
\evensidemargin 63pt
|
||||
\marginparwidth 90pt
|
||||
\fi
|
||||
\marginparsep 11pt
|
||||
|
||||
\topmargin 27pt
|
||||
\headheight 12pt
|
||||
\headsep 25pt
|
||||
\topskip = 10pt
|
||||
\footskip 30pt
|
||||
|
||||
\textheight = 43\baselineskip
|
||||
\advance\textheight by \topskip
|
||||
\textwidth 345pt
|
||||
\endinput
|
||||
|
|
@ -0,0 +1,465 @@
|
|||
%&latex -*- latex -*-
|
||||
|
||||
\chapter{Networking}
|
||||
|
||||
The Scheme Shell provides a BSD-style sockets interface.
|
||||
There is not an official standard for a network interface
|
||||
for scsh to adopt (this is the subject of the forthcoming Posix.8
|
||||
standard).
|
||||
However, Berkeley sockets are a \emph{de facto} standard,
|
||||
being found on most Unix workstations and PC operating systems.
|
||||
|
||||
It is fairly straightforward to add higher-level network protocols
|
||||
such as smtp, telnet, or http on top of the the basic socket-level
|
||||
support scsh provides.
|
||||
The Scheme Underground has also released a network library with
|
||||
many of these protocols as a companion to the current release of scsh.
|
||||
See this code for examples showing the use of the sockets interface.
|
||||
|
||||
\section{High-level interface}
|
||||
|
||||
For convenience, and to avoid some of the messy details of the socket
|
||||
interface, we provide a high level socket interface. These routines
|
||||
attempt to make it easy to write simple clients and servers without
|
||||
having to think of many of the details of initiating socket connections.
|
||||
We welcome suggested improvements to this interface, including better
|
||||
names, which right now are solely descriptions of the procedure's action.
|
||||
This might be fine for people who already understand sockets,
|
||||
but does not help the new networking programmer.
|
||||
|
||||
\defun {socket-connect} {protocol-family socket-type . args} {socket}
|
||||
\begin{desc}
|
||||
\ex{socket-connect} is intended for creating client applications.
|
||||
\var{protocol-family} is specified as either the
|
||||
\ex{protocol-family/internet} or \ex{protocol-family/unix}.
|
||||
\var{socket-type} is specified as either \ex{socket-type/stream} or
|
||||
\ex{socket-type/datagram}. See \ex{socket} for a more complete
|
||||
description of these terms.
|
||||
|
||||
The variable \var{args} list is meant to specify protocol family
|
||||
specific information. For Internet sockets, this consists of two
|
||||
arguments: a host name and a port number. For {\Unix} sockets, this
|
||||
consists of a pathname.
|
||||
|
||||
\ex{socket-connect} returns a \ex{socket} which can be used for input
|
||||
and output from a remote server. See \ex{socket} for a description of
|
||||
the \emph{socket record}.
|
||||
\end{desc}
|
||||
|
||||
\defun {bind-listen-accept-loop} {protocol-family proc arg} {does-not-return}
|
||||
\begin{desc}
|
||||
\ex{bind-listen-accept-loop} is intended for creating server
|
||||
applications. \var{protocol-family} is specified as either the
|
||||
\ex{protocol-family/internet} or \ex{protocol-family/unix}.
|
||||
\var{proc} is a procedure of two arguments: a \ex{socket} and a
|
||||
{socket-address}. \var{arg} specifies a port number for Internet sockets
|
||||
or a pathname for {\Unix} sockets. See \ex{socket} for a more complete
|
||||
description of these terms.
|
||||
|
||||
\var{proc} is called with a socket and a socket address each time there
|
||||
is a connection from a client application. The socket allows
|
||||
communications with the client. The socket address specifies the
|
||||
address of the remote client.
|
||||
|
||||
This procedure does not return, but loops indefinitely accepting
|
||||
connections from client programs.
|
||||
\end{desc}
|
||||
|
||||
\defun {bind-prepare-listen-accept-loop} {protocol-family prepare proc arg} {does-not-return}
|
||||
\begin{desc}
|
||||
Same as \ex{bind-listen-accept-loop} but runs the thunk
|
||||
\var{prepare} after binding the address and before entering the
|
||||
loop. The typical task of the \var{prepare} procedure is to change
|
||||
the user id from the superuser to some unprivileged id once the
|
||||
address has been bound.
|
||||
\end{desc}
|
||||
|
||||
\section{Sockets}
|
||||
|
||||
\defun {create-socket} {protocol-family type [protocol]} {socket}
|
||||
\defunx {create-socket-pair} {type} {[socket$_{1}$ socket$_{2}$]}
|
||||
\defunx {close-socket} {socket} \undefined
|
||||
\begin{desc}
|
||||
|
||||
A socket is one end of a network connection. Three specific properties
|
||||
of sockets are specified at creation time: the protocol-family, type,
|
||||
and protocol.
|
||||
|
||||
The \var{protocol-family} specifies the protocol family to be used with
|
||||
the socket. This also determines the address family of socket addresses,
|
||||
which are described in more detail below. Scsh currently supports the
|
||||
{\Unix} internal protocols and the Internet protocols using the
|
||||
following constants:
|
||||
\begin{code}\codeallowbreaks
|
||||
protocol-family/unspecified
|
||||
protocol-family/unix
|
||||
protocol-family/internet\end{code}
|
||||
|
||||
The \var{type} specifies the style of communication. Examples that your
|
||||
operating system probably provides are stream and datagram sockets.
|
||||
Others maybe available depending on your system. Typical values are:
|
||||
\begin{code}\codeallowbreaks
|
||||
socket-type/stream
|
||||
socket-type/datagram
|
||||
socket-type/raw\end{code}
|
||||
|
||||
The \var{protocol} specifies a particular protocol to use within a
|
||||
protocol family and type. Usually only one choice exists, but it's
|
||||
probably safest to set this explicitly. See the protocol database
|
||||
routines for information on looking up protocol constants.
|
||||
|
||||
New sockets are typically created with \ex{create-socket}. However,
|
||||
\ex{create-socket-pair} can also be used to create a pair of connected
|
||||
sockets in the \ex{protocol-family/unix} protocol-family. The value of a
|
||||
returned socket is a \emph{socket record}, defined to have the following
|
||||
structure:
|
||||
\begin{code}
|
||||
(define-record socket
|
||||
family ; protocol family
|
||||
inport ; input-port
|
||||
outport) ; output-port\end{code}
|
||||
|
||||
The \ex{family} specifies the protocol family of the socket. The
|
||||
\ex{inport} and \ex{outport} fields are ports that can be used for input
|
||||
and output, respectively. For a stream socket, they are only usable
|
||||
after a connection has been established via \ex{connect-socket} or
|
||||
\ex{accept-connection}. For a datagram socket, \var{outport} can be
|
||||
immediately using \ex{send-message}, and \var{inport} can be used after
|
||||
\ex{bind} has created a local address.
|
||||
|
||||
\ex{close-socket} provides a convenient way to close a socket's port. It
|
||||
is preferred to explicitly closing the inport and outport because using
|
||||
\ex{close} on sockets is not currently portable across operating systems.
|
||||
|
||||
\end{desc}
|
||||
|
||||
\defun {port->socket} {port protocol-family} {socket}
|
||||
\begin{desc}
|
||||
This procedure turns \var{port} into a socket object. The port's
|
||||
underlying file descriptor must be a socket with protocol family
|
||||
\var{protocol-family}. \ex{port->socket} applies \ex{dup->inport}
|
||||
and \ex{dup->outport} to \var{port} to create the ports of the
|
||||
socket object.
|
||||
|
||||
\ex{port->socket} comes in handy for writing
|
||||
servers which run as children of \texttt{inetd}: after receiving a
|
||||
connection \texttt{inetd} creates a socket and passes it as
|
||||
standard input to its child.
|
||||
\end{desc}
|
||||
|
||||
\section{Socket addresses}
|
||||
|
||||
The format of a socket-address depends on the address family of the
|
||||
socket. Address-family-specific routines are provided to convert
|
||||
protocol-specific addresses to socket addresses. The value returned by
|
||||
these routines is a \emph{socket-address record}, defined to have the
|
||||
following visible structure:
|
||||
\begin{code}
|
||||
(define-record socket-address
|
||||
family) ; address family\end{code}
|
||||
|
||||
The \ex{family} is one of the following constants:
|
||||
\begin{code}\codeallowbreaks
|
||||
address-family/unspecified
|
||||
address-family/unix
|
||||
address-family/internet\end{code}
|
||||
|
||||
\defun {unix-address->socket-address} {pathname} {socket-address}
|
||||
\begin{desc}
|
||||
\ex{unix-address->socket-address} returns a \var{socket-address} based
|
||||
on the string \var{pathname}. There is a system dependent limit on the
|
||||
length of \var{pathname}.
|
||||
\end{desc}
|
||||
|
||||
\defun {internet-address->socket-address} {host-address service-port} {socket-address}
|
||||
\begin{desc}
|
||||
\ex{internet-address->socket-address} returns a \var{socket-address} based
|
||||
on an integer \var{host-address} and an integer \var{service-port}.
|
||||
Besides being a 32-bit host address, an Internet host address can also
|
||||
be one of the following constants:
|
||||
\begin{code}\codeallowbreaks
|
||||
internet-address/any
|
||||
internet-address/loopback
|
||||
internet-address/broadcast\end{code}
|
||||
|
||||
The use of \ex{internet-address/any} is described below in
|
||||
\ex{bind-socket}. \ex{internet-address/loopback} is an address that
|
||||
always specifies the local machine. \ex{internet-address/broadcast} is
|
||||
used for network broadcast communications.
|
||||
|
||||
For information on obtaining a host's address, see the \ex{host-info}
|
||||
function.
|
||||
\end{desc}
|
||||
|
||||
\defun {socket-address->unix-address} {socket-address} {pathname}
|
||||
\defunx {socket-address->internet-address} {socket-address} {[host-address service-port]}
|
||||
\begin{desc}
|
||||
|
||||
The routines \ex{socket-address->internet-address} and
|
||||
\ex{socket-address->unix-address} return the address-family-specific addresses.
|
||||
Be aware that most implementations don't correctly return anything more
|
||||
than an empty string for addresses in the {\Unix} address-family.
|
||||
\end{desc}
|
||||
|
||||
\section{Socket primitives}
|
||||
|
||||
The procedures in this section are presented in the order in which a
|
||||
typical program will use them. Consult a text on network systems
|
||||
programming for more information on sockets.\footnote{
|
||||
Some recommended ones are:
|
||||
|
||||
\begin{itemize}
|
||||
|
||||
\item ``Unix Network Programming'' by W. Richard Stevens
|
||||
|
||||
\item ``An Introductory 4.3BSD Interprocess Communication Tutorial.''
|
||||
(reprinted in UNIX Programmer's Supplementary Documents Volume 1, PS1:7)
|
||||
|
||||
\item ``An Advanced 4.3BSD Interprocess Communication Tutorial.''
|
||||
(reprinted in UNIX Programmer's Supplementary Documents Volume 1, PS1:8)
|
||||
|
||||
\end{itemize}
|
||||
}
|
||||
The last two tutorials are freely available as part of BSD. In the
|
||||
absence of these, your {\Unix} manual pages for socket might be a good
|
||||
starting point for information.
|
||||
|
||||
\defun {connect-socket} {socket socket-address} \undefined
|
||||
\begin{desc}
|
||||
\ex{connect-socket} sets up a connection from a \var{socket}
|
||||
to a remote \var{socket-address}. A connection has different meanings
|
||||
depending on the socket type. A stream socket must be connected before
|
||||
use. A datagram socket can be connected multiple times, but need not be
|
||||
connected at all if the remote address is specified with each
|
||||
\ex{send-message}, described below. Also, datagram sockets
|
||||
may be disassociated from a remote address by connecting to a null
|
||||
remote address.
|
||||
\end{desc}
|
||||
\defun {connect-socket-no-wait} {socket socket-address} \boolean
|
||||
\defunx {connect-socket-successful?} {socket} \boolean
|
||||
\begin{desc}
|
||||
Just like \ex{connect-socket}, \ex{connect-socket-no-wait} sets up a
|
||||
connection from a \var{socket} to a remote \var{socket-address}.
|
||||
Unlike \ex{connect-socket}, \ex{connect-socket-no-wait} does not
|
||||
block if it cannot establish the connection immediately. Instead it
|
||||
will return \sharpf{} at once. In this case a subsequent \ex{select} on
|
||||
the output port of the socket will report the output port as ready
|
||||
as soon as the operation system has established the connection or as
|
||||
soon as setting up the connection led to an error. Afterwards, the
|
||||
procedure \ex{connect-socket-successful?} can be used to test
|
||||
whether the connection has been established successfully or not.
|
||||
\end{desc}
|
||||
\defun {bind-socket} {socket socket-address} \undefined
|
||||
\begin{desc}
|
||||
\ex{bind-socket} assigns a certain local \var{socket-address} to a
|
||||
\var{socket}. Binding a socket reserves the local address. To receive
|
||||
connections after binding the socket, use \ex{listen-socket} for stream
|
||||
sockets and \ex{receive-message} for datagram sockets.
|
||||
|
||||
Binding an Internet socket with a host address of
|
||||
\ex{internet-address/any} indicates that the caller does
|
||||
not care to specify from which local network interface connections are
|
||||
received. Binding an Internet socket with a service port number of zero
|
||||
indicates that the caller has no preference as to the port number
|
||||
assigned.
|
||||
|
||||
Binding a socket in the {\Unix} address family creates a socket special
|
||||
file in the file system that must be deleted before the address can be
|
||||
reused. See \ex{delete-file}.
|
||||
\end{desc}
|
||||
|
||||
\defun {listen-socket} {socket backlog} \undefined
|
||||
\begin{desc}
|
||||
\ex{listen-socket} allows a stream \var{socket} to start receiving connections,
|
||||
allowing a queue of up to \var{backlog} connection requests. Queued
|
||||
connections may be accepted by \ex{accept-connection}.
|
||||
\end{desc}
|
||||
|
||||
\defun {accept-connection} {socket} {[new-socket socket-address]}
|
||||
\begin{desc}
|
||||
\ex{accept-connection} receives a connection on a \var{socket}, returning
|
||||
a new socket that can be used for this connection and the remote socket
|
||||
address associated with the connection.
|
||||
\end{desc}
|
||||
|
||||
\defun {socket-local-address} {socket} {socket-address}
|
||||
\defunx {socket-remote-address} {socket} {socket-address}
|
||||
\begin{desc}
|
||||
Sockets can be associated with a local address or a remote address or
|
||||
both. \ex{socket-local-address} returns the local \var{socket-address}
|
||||
record associated with \var{socket}. \ex{socket-remote-address} returns
|
||||
the remote \var{socket-address} record associated with \var{socket}.
|
||||
\end{desc}
|
||||
|
||||
\defun {shutdown-socket} {socket how-to} \undefined
|
||||
\begin{desc}
|
||||
|
||||
\ex{shutdown-socket} shuts down part of a full-duplex socket.
|
||||
The method of shutting done is specified by the \var{how-to} argument,
|
||||
one of:
|
||||
\begin{code}\codeallowbreaks
|
||||
shutdown/receives
|
||||
shutdown/sends
|
||||
shutdown/sends+receives\end{code}
|
||||
\end{desc}
|
||||
|
||||
\section{Performing input and output on sockets}
|
||||
|
||||
\defun {receive-message} {socket length [flags]} {[string-or-\sharpf{} socket-address]}
|
||||
\dfnix {receive-message!} {socket string [start] [end] [flags]}
|
||||
{[count-or-\sharpf{} socket-address]}{procedure}
|
||||
{receive-message"!@\texttt{receive-message"!}}
|
||||
\defunx {receive-message/partial} {socket length [flags]}
|
||||
{[string-or-\sharpf{} socket-address]}
|
||||
\dfnix {receive-message!/partial} {socket string [start] [end] [flags]}
|
||||
{[count-or-\sharpf{} socket-address]}{procedure}
|
||||
{receive-message"!/partial@\texttt{receive-message"!/partial}}
|
||||
\defun {send-message} {socket string [start] [end] [flags] [socket-address]}
|
||||
\undefined
|
||||
\defunx {send-message/partial}
|
||||
{socket string [start] [end] [flags] [socket-address]} {count}
|
||||
|
||||
\begin{desc}
|
||||
For most uses, standard input and output routines such as
|
||||
\ex{read-string} and \ex{write-string} should suffice. However, in some
|
||||
cases an extended interface is required. The \ex{receive-message} and
|
||||
\ex{send-message} calls parallel the \ex{read-string} and
|
||||
\ex{write-string} calls with a similar naming scheme.
|
||||
|
||||
One additional feature of these routines is that \ex{receive-message}
|
||||
returns the remote \var{socket-address} and \var{send-message} takes an
|
||||
optional remote
|
||||
\ex{socket-address}. This allows a program to know the source of input
|
||||
from a datagram socket and to use a datagram socket for output without
|
||||
first connecting it.
|
||||
|
||||
All of these procedures take an optional \var{flags} field. This
|
||||
argument is an integer bit-mask, composed by or'ing together the
|
||||
following constants:
|
||||
\begin{code}\codeallowbreaks
|
||||
message/out-of-band
|
||||
message/peek
|
||||
message/dont-route\end{code}
|
||||
|
||||
See \ex{read-string} and \ex{write-string} for a more detailed
|
||||
description of the arguments and return values.
|
||||
\end{desc}
|
||||
|
||||
\section{Socket options}
|
||||
|
||||
\defun {socket-option} {socket level option} {value}
|
||||
\defunx {set-socket-option} {socket level option value} \undefined
|
||||
|
||||
\begin{desc}
|
||||
\ex{socket-option} and \ex{set-socket-option} allow the inspection and
|
||||
modification, respectively, of several options available on sockets. The
|
||||
\var{level} argument specifies what protocol level is to be examined or
|
||||
affected. A level of \ex{level/socket} specifies the highest possible
|
||||
level that is available on all socket types. A specific protocol number
|
||||
can also be used as provided by \ex{protocol-info}, described below.
|
||||
|
||||
There are several different classes of socket options. The first class
|
||||
consists of boolean options which can be either true or false. Examples
|
||||
of this option type are:
|
||||
\begin{code}\codeallowbreaks
|
||||
socket/debug
|
||||
socket/accept-connect
|
||||
socket/reuse-address
|
||||
socket/keep-alive
|
||||
socket/dont-route
|
||||
socket/broadcast
|
||||
socket/use-loop-back
|
||||
socket/oob-inline
|
||||
socket/use-privileged
|
||||
socket/cant-signal
|
||||
tcp/no-delay\end{code}
|
||||
|
||||
Value options are another category of socket options. Options of this
|
||||
type are an integer value. Examples of this option type are:
|
||||
\begin{code}\codeallowbreaks
|
||||
socket/send-buffer
|
||||
socket/receive-buffer
|
||||
socket/send-low-water
|
||||
socket/receive-low-water
|
||||
socket/error
|
||||
socket/type
|
||||
ip/time-to-live
|
||||
tcp/max-segment\end{code}
|
||||
|
||||
A third option type specifies how long for data to linger after a socket
|
||||
has been closed. There is only one option of this type:
|
||||
\ex{socket/linger}. It is set with either \sharpf to disable it or an
|
||||
integer number of seconds to linger and returns a value of the same type
|
||||
upon inspection.
|
||||
|
||||
The fourth and final option type of this time is a timeout option. There
|
||||
are two examples of this option type: \ex{socket/send-timeout} and
|
||||
\ex{socket/receive-timeout}. These are set with a real number of
|
||||
microseconds resolution and returns a value of the same type upon
|
||||
inspection.
|
||||
|
||||
\end{desc}
|
||||
|
||||
\section{Database-information entries}
|
||||
|
||||
\defun {host-info} {name-or-socket-address} {host-info}
|
||||
\defunx {network-info} {name-or-socket-address} {network-info or \sharpf}
|
||||
\defunx {service-info} {name-or-number [protocol-name]} {service-info or \sharpf}
|
||||
\defunx {protocol-info} {name-or-number} {protocol-info or \sharpf}
|
||||
|
||||
\begin{desc}
|
||||
|
||||
\ex{host-info} allows a program to look up a host entry based on either
|
||||
its string \var{name} or \var{socket-address}. The value returned by this
|
||||
routine is a \emph{host-info record}, defined to have the following
|
||||
structure:
|
||||
\begin{code}
|
||||
(define-record host-info
|
||||
name ; Host name
|
||||
aliases ; Alternative names
|
||||
addresses) ; Host addresses\end{code}
|
||||
|
||||
\ex{host-info} could fail and raise an error for one of the following
|
||||
reasons:
|
||||
\begin{code}\codeallowbreaks
|
||||
herror/host-not-found
|
||||
herror/try-again
|
||||
herror/no-recovery
|
||||
herror/no-data
|
||||
herror/no-address\end{code}
|
||||
|
||||
\ex{network-info} allows a program to look up a network entry based on either
|
||||
its string \var{name} or \var{socket-address}. The value returned by this
|
||||
routine is a \emph{network-info record}, defined to have the following
|
||||
structure:
|
||||
\begin{code}
|
||||
(define-record network-info
|
||||
name ; Network name
|
||||
aliases ; Alternative names
|
||||
net) ; Network number\end{code}
|
||||
|
||||
\ex{service-info} allows a program to look up a service entry based
|
||||
on either its string \var{name} or integer \var{port}. The value returned
|
||||
by this routine is a \emph{service-info record}, defined to have the
|
||||
following structure:
|
||||
\begin{code}
|
||||
(define-record service-info
|
||||
name ; Service name
|
||||
aliases ; Alternative names
|
||||
port ; Port number
|
||||
protocol) ; Protocol name\end{code}
|
||||
|
||||
\ex{protocol-info} allows a program to look up a protocol entry based
|
||||
on either its string \var{name} or integer \var{number}. The value returned
|
||||
by this routine is a \emph{protocol-info record}, defined to have the
|
||||
following structure:
|
||||
\begin{code}
|
||||
(define-record protocol-info
|
||||
name ; Protocol name
|
||||
aliases ; Alternative names
|
||||
number) ; Protocol number)\end{code}
|
||||
|
||||
\ex{network-info}, \ex{service-info} and \ex{protocol-info} return
|
||||
\sharpf if the specified entity was not found.
|
||||
|
||||
\end{desc}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
\newif\ifpdf
|
||||
\ifx\pdfoutput\undefined
|
||||
\pdffalse % we are not running PDFLaTeX
|
||||
\else
|
||||
\pdfoutput=1 % we are running PDFLaTeX
|
||||
\pdftrue
|
||||
\fi
|
||||
% Then use your new variable \ifpdf
|
||||
% \ifpdf
|
||||
% \usepackage[pdftex]{graphicx}
|
||||
% \pdfcompresslevel=9
|
||||
% \else
|
||||
% \usepackage{graphicx}
|
||||
% \fi
|
||||
|
|
@ -0,0 +1,543 @@
|
|||
%&latex -*- latex -*-
|
||||
|
||||
\chapter{Process notation}
|
||||
\label{sec:proc-forms}
|
||||
Scsh has a notation for controlling {\Unix} processes that takes the
|
||||
form of s-expressions; this notation can then be embedded inside of
|
||||
standard {\Scheme} code.
|
||||
The basic elements of this notation are \emph{process forms},
|
||||
\emph{extended process forms}, and \emph{redirections}.
|
||||
|
||||
\section{Extended process forms and I/O redirections}
|
||||
An \emph{extended process form} is a specification of a {\Unix} process to
|
||||
run, in a particular I/O environment:
|
||||
\codex{\var{epf} {\synteq} (\var{pf} $ \var{redir}_1$ {\ldots} $ \var{redir}_n $)}
|
||||
where \var{pf} is a process form and the $\var{redir}_i$ are redirection specs.
|
||||
A \emph{redirection spec} is one of:
|
||||
\begin{inset}
|
||||
\begin{tabular}{@{}l@{\qquad{\tt; }}l@{}}
|
||||
\ex{(< \var{[fdes]} \var{file-name})} & \ex{Open file for read.}
|
||||
\\\ex{(> \var{[fdes]} \var{file-name})} & \ex{Open file create/truncate.}
|
||||
\\\ex{(<< \var{[fdes]} \var{object})} & \ex{Use \var{object}'s printed rep.}
|
||||
\\\ex{(>> \var{[fdes]} \var{file-name})} & \ex{Open file for append.}
|
||||
\\\ex{(= \var{fdes} \var{fdes/port})} & \ex{Dup2}
|
||||
\\\ex{(- \var{fdes/port})} & \ex{Close \var{fdes/port}.}
|
||||
\\\ex{stdports} & \ex{0,1,2 dup'd from standard ports.}
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
The input redirections default to file descriptor 0;
|
||||
the output redirections default to file descriptor 1.
|
||||
|
||||
The subforms of a redirection are implicitly backquoted,
|
||||
and symbols stand for their print-names.
|
||||
So \ex{(> ,x)} means
|
||||
``output to the file named by {\Scheme} variable \ex{x},''
|
||||
and \ex{(< /usr/shivers/.login)} means ``read from \ex{/usr/shivers/.login}.''
|
||||
|
||||
\pagebreak
|
||||
Here are two more examples of I/O redirection:
|
||||
%
|
||||
\begin{center}
|
||||
\begin{codebox}
|
||||
(< ,(vector-ref fv i))
|
||||
(>> 2 /tmp/buf)\end{codebox}
|
||||
\end{center}
|
||||
%
|
||||
These two redirections cause the file \ex{fv[i]} to be opened on stdin, and
|
||||
\ex{/tmp/buf} to be opened for append writes on stderr.
|
||||
|
||||
The redirection \ex{(<< \var{object})} causes input to come from the
|
||||
printed representation of \var{object}.
|
||||
For example,
|
||||
\codex{(<< "The quick brown fox jumped over the lazy dog.")}
|
||||
causes reads from stdin to produce the characters of the above string.
|
||||
The object is converted to its printed representation using the \ex{display}
|
||||
procedure, so
|
||||
\codex{(<< (A five element list))}
|
||||
is the same as
|
||||
\codex{(<< "(A five element list)")}
|
||||
is the same as
|
||||
\codex{(<< ,(reverse '(list element five A))){\rm.}}
|
||||
(Here we use the implicit backquoting feature to compute the list to
|
||||
be printed.)
|
||||
|
||||
The redirection \ex{(= \var{fdes} \var{fdes/port})} causes \var{fdes/port}
|
||||
to be dup'd into file descriptor \var{fdes}.
|
||||
For example, the redirection
|
||||
\codex{(= 2 1)}
|
||||
causes stderr to be the same as stdout.
|
||||
\var{fdes/port} can also be a port, for example:
|
||||
\codex{(= 2 ,(current-output-port))}
|
||||
causes stderr to be dup'd from the current output port.
|
||||
In this case, it is an error if the port is not a file port
|
||||
(\eg, a string port).
|
||||
More complex redirections can be accomplished using the \ex{begin}
|
||||
process form, discussed below, which gives the programmer full control
|
||||
of I/O redirection from {\Scheme}.
|
||||
|
||||
\subsection{Port and file descriptor sync}
|
||||
\begin{sloppypar}
|
||||
It's important to remember that rebinding Scheme's current I/O ports
|
||||
(\eg, using \ex{call-with-input-file} to rebind the value of
|
||||
\ex{(current-input-port)})
|
||||
does \emph{not} automatically ``rebind'' the file referenced by the
|
||||
{\Unix} stdio file descriptors 0, 1, and 2.
|
||||
This is impossible to do in general, since some {\Scheme} ports are
|
||||
not representable as {\Unix} file descriptors.
|
||||
For example, many {\Scheme} implementations provide ``string ports,''
|
||||
that is, ports that collect characters sent to them into memory buffers.
|
||||
The accumulated string can later be retrieved from the port as a string.
|
||||
If a user were to bind \ex{(current-output-port)} to such a port, it would
|
||||
be impossible to associate file descriptor 1 with this port, as it
|
||||
cannot be represented in {\Unix}.
|
||||
So, if the user subsequently forked off some other program as a subprocess,
|
||||
that program would of course not see the {\Scheme} string port as its standard
|
||||
output.
|
||||
\end{sloppypar}
|
||||
|
||||
To keep stdio synced with the values of {\Scheme}'s current I/O ports,
|
||||
use the special redirection \ex{stdports}.
|
||||
This causes 0, 1, 2 to be redirected from the current {\Scheme} standard ports.
|
||||
It is equivalent to the three redirections:
|
||||
\begin{code}
|
||||
(= 0 ,(current-input-port))
|
||||
(= 1 ,(current-output-port))
|
||||
(= 2 ,(error-output-port))\end{code}
|
||||
%
|
||||
The redirections are done in the indicated order. This will cause an error if
|
||||
one of the current I/O ports isn't a {\Unix} port (\eg, if one is a string
|
||||
port).
|
||||
This {\Scheme}/{\Unix} I/O synchronisation can also be had in {\Scheme} code
|
||||
(as opposed to a redirection spec) with the \ex{(stdports->stdio)}
|
||||
procedure.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Process forms}
|
||||
A \emph{process form} specifies a computation to perform as an independent
|
||||
{\Unix} process. It can be one of the following:
|
||||
%
|
||||
\begin{leftinset}
|
||||
\begin{codebox}
|
||||
(begin . \var{scheme-code})
|
||||
(| \vari{pf}{\!1} {\ldots} \vari{pf}{\!n})
|
||||
(|+ \var{connect-list} \vari{pf}{\!1} {\ldots} \vari{pf}{\!n})
|
||||
(epf . \var{epf})
|
||||
(\var{prog} \vari{arg}{1} {\ldots} \vari{arg}{n})
|
||||
\end{codebox}
|
||||
\qquad
|
||||
\begin{codebox}
|
||||
; Run \var{scheme-code} in a fork.
|
||||
; Simple pipeline
|
||||
; Complex pipeline
|
||||
; An extended process form.
|
||||
; Default: exec the program.
|
||||
\end{codebox}
|
||||
\end{leftinset}
|
||||
%
|
||||
The default case \ex{(\var{prog} \vari{arg}1 {\ldots} \vari{arg}n)}
|
||||
is also implicitly backquoted.
|
||||
That is, it is equivalent to:
|
||||
%
|
||||
\codex{(begin (apply exec-path `(\var{prog} \vari{arg}1 {\ldots} \vari{arg}n)))}
|
||||
%
|
||||
\ex{Exec-path} is the version of the \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=exec&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{exec()}} system call that
|
||||
uses scsh's path list to search for an executable.
|
||||
The program and the arguments must be either strings, symbols, or integers.
|
||||
Symbols and integers are coerced to strings.
|
||||
A symbol's print-name is used.
|
||||
Integers are converted to strings in base 10.
|
||||
Using symbols instead of strings is convenient, since it suppresses the
|
||||
clutter of the surrounding \ex{"\ldots"} quotation marks.
|
||||
To aid this purpose, scsh reads symbols in a case-sensitive manner,
|
||||
so that you can say
|
||||
\codex{(more Readme)}
|
||||
and get the right file.
|
||||
|
||||
A \var{connect-list} is a specification of how two processes are to be wired
|
||||
together by pipes.
|
||||
It has the form \ex{((\vari{from}1 \vari{from}2 {\ldots} \var{to}) \ldots)}
|
||||
and is implicitly backquoted.
|
||||
For example,
|
||||
%
|
||||
\codex{(|+ ((1 2 0) (3 1)) \vari{pf}{\!1} \vari{pf}{\!2})}
|
||||
%
|
||||
runs \vari{pf}{\!1} and \vari{pf}{\!2}.
|
||||
The first clause \ex{(1 2 0)} causes \vari{pf}{\!1}'s
|
||||
stdout (1) and stderr (2) to be connected via pipe
|
||||
to \vari{pf}{\!2}'s stdin (0).
|
||||
The second clause \ex{(3 1)} causes \vari{pf}{\!1}'s file descriptor 3 to be
|
||||
connected to \vari{pf}{\!2}'s file descriptor 1.
|
||||
%---this is unusual, and not expected to occur very often.
|
||||
|
||||
The \ex{begin} process form does a \ex{stdio->stdports} synchronisation
|
||||
in the child process before executing the body of the form.
|
||||
This guarantees that the \ex{begin} form, like all other process forms,
|
||||
``sees'' the effects of any associated I/O redirections.
|
||||
|
||||
Note that {\RnRS} does not specify whether or not \ex{|} and \ex{|+}
|
||||
are readable symbols. Scsh does.
|
||||
|
||||
\section{Using extended process forms in \Scheme}
|
||||
Process forms and extended process forms are \emph{not} {\Scheme}.
|
||||
They are a different notation for expressing computation that, like {\Scheme},
|
||||
is based upon s-expressions.
|
||||
Extended process forms are used in {\Scheme} programs by embedding them inside
|
||||
special {\Scheme} forms.
|
||||
There are three basic {\Scheme} forms that use extended process forms:
|
||||
\ex{exec-epf}, \cd{&}, and \ex{run}.
|
||||
|
||||
\dfn {exec-epf} {. \var{epf}} {\noreturn} {syntax}
|
||||
\dfnx {\&} {. \var{epf}} {proc} {syntax}
|
||||
\dfnx {run} {. \var{epf}} {status} {syntax}
|
||||
\begin{desc}
|
||||
\index{exec-epf} \index{\&} \index{run}
|
||||
The \ex{(exec-epf . \var{epf})} form nukes the current process: it establishes
|
||||
the I/O redirections and then overlays the current process with the requested
|
||||
computation.
|
||||
|
||||
The \ex{(\& . \var{epf})} form is similar, except that the process is forked
|
||||
off in background. The form returns the subprocess' process object.
|
||||
|
||||
The \ex{(run . \var{epf})} form runs the process in foreground:
|
||||
after forking off the computation, it waits for the subprocess to exit,
|
||||
and returns its exit status.
|
||||
|
||||
These special forms are macros that expand into the equivalent
|
||||
series of system calls.
|
||||
The definition of the \ex{exec-epf} macro is non-trivial,
|
||||
as it produces the code to handle I/O redirections and set up pipelines.
|
||||
However, the definitions of the \cd{&} and \ex{run} macros are very simple:
|
||||
\begin{leftinset}
|
||||
\begin{tabular}{@{}l@{\quad$\equiv$\quad}l@{}}
|
||||
\cd{(& . \var{epf})} & \ex{(fork (\l{} (exec-epf . \var{epf})))} \\
|
||||
\ex{(run . \var{epf})} & \cd{(wait (& . \var{epf}))}
|
||||
\end{tabular}
|
||||
\end{leftinset}
|
||||
\end{desc}
|
||||
|
||||
\subsection{Procedures and special forms}
|
||||
It is a general design principle in scsh that all functionality
|
||||
made available through special syntax is also available in a
|
||||
straightforward procedural form.
|
||||
So there are procedural equivalents for all of the process notation.
|
||||
In this way, the programmer is not restricted by the particular details of
|
||||
the syntax.
|
||||
Here are some of the syntax/procedure equivalents:
|
||||
\begin{inset}
|
||||
\begin{tabular}{@{}|ll|@{}}
|
||||
\hline
|
||||
Notation & Procedure \\ \hline \hline
|
||||
\ex{|} & \ex{fork/pipe} \\
|
||||
\ex{|+} & \ex{fork/pipe+} \\
|
||||
\ex{exec-epf} & \ex{exec-path} \\
|
||||
redirection & \ex{open}, \ex{dup} \\
|
||||
\cd{&} & \ex{fork} \\
|
||||
\ex{run} & $\ex{wait} + \ex{fork}$ \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
%
|
||||
Having a solid procedural foundation also allows for general notational
|
||||
experimentation using {\Scheme}'s macros.
|
||||
For example, the programmer can build his own pipeline notation on top of the
|
||||
\ex{fork} and \ex{fork/pipe} procedures.
|
||||
Chapter~\ref{chapt:syscalls} gives the full story on all the procedures
|
||||
in the syscall library.
|
||||
|
||||
\subsection{Interfacing process output to {\Scheme}}
|
||||
\label{sec:io-interface}
|
||||
There is a family of procedures and special forms that can be used
|
||||
to capture the output of processes as {\Scheme} data.
|
||||
%
|
||||
\dfn {run/port} {. \var{epf}} {port} {syntax}
|
||||
\dfnx{run/file} {. \var{epf}} {\str} {syntax}
|
||||
\dfnx{run/string} {. \var{epf}} {\str} {syntax}
|
||||
\dfnx{run/strings} {. \var{epf}} {{\str} list} {syntax}
|
||||
\dfnx{run/sexp} {. \var{epf}} {object} {syntax}
|
||||
\dfnx{run/sexps} {. \var{epf}} {list} {syntax}
|
||||
\begin{desc}
|
||||
These forms all fork off subprocesses, collecting the process' output
|
||||
to stdout in some form or another.
|
||||
The subprocess runs with file descriptor 1 and the current output port
|
||||
bound to a pipe.
|
||||
\begin{desctable}{0.7\linewidth}
|
||||
\ex{run/port} & Value is a port open on process's stdout.
|
||||
Returns immediately after forking child. \\
|
||||
\ex{run/file} & Value is name of a temp file containing process's output.
|
||||
Returns when process exits. \\
|
||||
\ex{run/string} & Value is a string containing process' output.
|
||||
Returns when eof read. \\
|
||||
\ex{run/strings}& Splits process' output into a list of
|
||||
newline-delimited strings. Returns when eof read. \\
|
||||
\ex{run/sexp} & Reads a single object from process' stdout with \ex{read}.
|
||||
Returns as soon as the read completes. \\
|
||||
\ex{run/sexps} & Repeatedly reads objects from process' stdout with \ex{read}.
|
||||
Returns accumulated list upon eof.
|
||||
\end{desctable}
|
||||
The delimiting newlines are not included in the strings returned by
|
||||
\ex{run/strings}.
|
||||
|
||||
These special forms just expand into calls to the following analogous
|
||||
procedures.
|
||||
\end{desc}
|
||||
|
||||
\defun {run/port*} {thunk} {port}
|
||||
\defunx {run/file*} {thunk} {\str}
|
||||
\defunx {run/string*} {thunk} {\str}
|
||||
\defunx {run/strings*} {thunk} {{\str} list}
|
||||
\defunx {run/sexp*} {thunk} {object}
|
||||
\defunx {run/sexps*} {thunk} {object list}
|
||||
\begin{desc}
|
||||
For example, \ex{(run/port . \var{epf})} expands into
|
||||
\codex{(run/port* (\l{} (exec-epf . \var{epf}))).}
|
||||
\end{desc}
|
||||
|
||||
The following procedures are also of utility for generally parsing
|
||||
input streams in scsh:
|
||||
\defun {port->string} {port} {\str}
|
||||
\defunx {port->sexp-list} {port} {list}
|
||||
\defunx {port->string-list} {port} {{\str} list}
|
||||
\defunx {port->list} {reader port} {list}
|
||||
\begin{desc}
|
||||
\ex{Port->string} reads the port until eof,
|
||||
then returns the accumulated string.
|
||||
\ex{Port->sexp-list} repeatedly reads data from the port until eof,
|
||||
then returns the accumulated list of items.
|
||||
\ex{Port->string-list} repeatedly reads newline-terminated strings from the
|
||||
port until eof, then returns the accumulated list of strings.
|
||||
The delimiting newlines are not part of the returned strings.
|
||||
\ex{Port->list} generalises these two procedures.
|
||||
It uses \var{reader} to repeatedly read objects from a port.
|
||||
It accumulates these objects into a list, which is returned upon eof.
|
||||
The \ex{port->string-list} and \ex{port->sexp-list} procedures
|
||||
are trivial to define, being merely \ex{port->list} curried with
|
||||
the appropriate parsers:
|
||||
\begin{code}\cddollar
|
||||
(port->string-list \var{port}) $\equiv$ (port->list read-line \var{port})
|
||||
(port->sexp-list \var{port}) $\equiv$ (port->list read \var{port})\end{code}
|
||||
%
|
||||
The following compositions also hold:
|
||||
\begin{code}\cddollar
|
||||
run/string* $\equiv$ port->string $\circ$ run/port*
|
||||
run/strings* $\equiv$ port->string-list $\circ$ run/port*
|
||||
run/sexp* $\equiv$ read $\circ$ run/port*
|
||||
run/sexps* $\equiv$ port->sexp-list $\circ$ run/port*\end{code}
|
||||
\end{desc}
|
||||
|
||||
\defun{port-fold}{port reader op . seeds} {\object\star}
|
||||
\begin{desc}
|
||||
This procedure can be used to perform a variety of iterative operations
|
||||
over an input stream.
|
||||
It repeatedly uses \var{reader} to read an object from \var{port}.
|
||||
If the first read returns eof, then the entire \ex{port-fold}
|
||||
operation returns the seeds as multiple values.
|
||||
If the first read operation returns some other value $v$, then
|
||||
\var{op} is applied to $v$ and the seeds:
|
||||
\ex{(\var{op} \var{v} . \var{seeds})}.
|
||||
This should return a new set of seed values, and the reduction then loops,
|
||||
reading a new value from the port, and so forth.
|
||||
(If multiple seed values are used, then \var{op} must return multiple values.)
|
||||
|
||||
For example, \ex{(port->list \var{reader} \var{port})}
|
||||
could be defined as
|
||||
\codex{(reverse (port-fold \var{port} \var{reader} cons '()))}
|
||||
|
||||
An imperative way to look at \ex{port-fold} is to say that it
|
||||
abstracts the idea of a loop over a stream of values read from
|
||||
some port, where the seed values express the loop state.
|
||||
|
||||
\remark{This procedure was formerly named \texttt{\indx{reduce-port}}.
|
||||
The old binding is still provided, but is deprecated and will
|
||||
probably vanish in a future release.}
|
||||
\end{desc}
|
||||
|
||||
|
||||
\section{More complex process operations}
|
||||
The procedures and special forms in the previous section provide for the
|
||||
common case, where the programmer is only interested in the output of the
|
||||
process.
|
||||
These special forms and procedures provide more complicated facilities
|
||||
for manipulating processes.
|
||||
|
||||
|
||||
\subsection{Pids and ports together}
|
||||
\dfn {run/port+proc} {. \var{epf}} {[port proc]} {syntax}
|
||||
\defunx {run/port+proc*} {thunk} {[port proc]}
|
||||
\begin{desc}
|
||||
This special form and its analogous procedure can be used
|
||||
if the programmer also wishes access to the process' pid, exit status,
|
||||
or other information.
|
||||
They both fork off a subprocess, returning two values:
|
||||
a port open on the process' stdout (and current output port),
|
||||
and the subprocess's process object.
|
||||
A process object encapsulates the subprocess' process id and exit code;
|
||||
it is the value passed to the \ex{wait} system call.
|
||||
|
||||
|
||||
For example, to uncompress a tech report, reading the uncompressed
|
||||
data into scsh, and also be able to track the exit status of
|
||||
the decompression process, use the following:
|
||||
\begin{code}
|
||||
(receive (port child) (run/port+proc (zcat tr91-145.tex.Z))
|
||||
(let* ((paper (port->string port))
|
||||
(status (wait child)))
|
||||
{\rm\ldots{}use \ex{paper}, \ex{status}, and \ex{child} here\ldots}))\end{code}
|
||||
%
|
||||
Note that you must \emph{first} do the \ex{port->string} and
|
||||
\emph{then} do the wait---the other way around may lock up when the
|
||||
zcat fills up its output pipe buffer.
|
||||
\end{desc}
|
||||
|
||||
|
||||
\subsection{Multiple stream capture}
|
||||
|
||||
Occasionally, the programmer may want to capture multiple distinct output
|
||||
streams from a process. For instance, he may wish to read the stdout and
|
||||
stderr streams into two distinct strings. This is accomplished with the
|
||||
\ex{run/collecting} form and its analogous procedure, \ex{run/collecting*}.
|
||||
%
|
||||
\dfn {run/collecting} {fds . epf} {[status port\ldots]} {syntax}
|
||||
\defunx {run/collecting*} {fds thunk} {[status port\ldots]}
|
||||
\begin{desc}
|
||||
\ex{Run/collecting} and \ex{run/collecting*} run processes that produce
|
||||
multiple output streams and return ports open on these streams. To avoid
|
||||
issues of deadlock, \ex{run/collecting} doesn't use pipes. Instead, it first
|
||||
runs the process with output to temp files, then returns ports open on the
|
||||
temp files. For example,
|
||||
%
|
||||
\codex{(run/collecting (1 2) (ls))}
|
||||
%
|
||||
runs \ex{ls} with stdout (fd 1) and stderr (fd 2) redirected to temporary
|
||||
files.
|
||||
When the \ex{ls} is done, \ex{run/collecting} returns three values: the
|
||||
\ex{ls} process' exit status, and two ports open on the temporary files. The
|
||||
files are deleted before \ex{run/collecting} returns, so when the ports are
|
||||
closed, they vanish. The \ex{fds} list of file descriptors is implicitly
|
||||
backquoted by the special-form version.
|
||||
|
||||
For example, if Kaiming has his mailbox protected, then
|
||||
\begin{code}
|
||||
(receive (status out err)
|
||||
(run/collecting (1 2) (cat /usr/kmshea/mbox))
|
||||
(list status (port->string out) (port->string err)))\end{code}
|
||||
%
|
||||
might produce the list
|
||||
\codex{(256 "" "cat: /usr/kmshea/mbox: Permission denied")}
|
||||
|
||||
What is the deadlock hazard that causes \ex{run/collecting} to use temp files?
|
||||
Processes with multiple output streams can lock up if they use pipes
|
||||
to communicate with {\Scheme} I/O readers. For example, suppose
|
||||
some {\Unix} program \ex{myprog} does the following:
|
||||
\begin{enumerate}
|
||||
\item First, outputs a single ``\ex{(}'' to stderr.
|
||||
\item Then, outputs a megabyte of data to stdout.
|
||||
\item Finally, outputs a single ``\ex{)}'' to stderr, and exits.
|
||||
\end{enumerate}
|
||||
|
||||
Our scsh programmer decides to run \ex{myprog} with stdout and stderr redirected
|
||||
\emph{via {\Unix} pipes} to the ports \ex{port1} and \ex{port2}, respectively.
|
||||
He gets into trouble when he subsequently says \ex{(read port2)}.
|
||||
The {\Scheme} \ex{read} routine reads the open paren, and then hangs in a
|
||||
\ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=read&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{read()}} system call trying to read a matching close paren.
|
||||
But before \ex{myprog} sends the close paren down the stderr
|
||||
pipe, it first tries to write a megabyte of data to the stdout pipe.
|
||||
However, {\Scheme} is not reading that pipe---it's stuck waiting for input on
|
||||
stderr.
|
||||
So the stdout pipe quickly fills up, and \ex{myprog} hangs, waiting for the
|
||||
pipe to drain.
|
||||
The \ex{myprog} child is stuck in a stdout/\ex{port1} write;
|
||||
the {\Scheme} parent is stuck in a stderr/\ex{port2} read.
|
||||
Deadlock.
|
||||
|
||||
Here's a concrete example that does exactly the above:
|
||||
\begin{code}
|
||||
(receive (status port1 port2)
|
||||
(run/collecting (1 2)
|
||||
(begin
|
||||
;; Write an open paren to stderr.
|
||||
(run (echo "(") (= 1 2))
|
||||
;; Copy a lot of stuff to stdout.
|
||||
(run (cat /usr/dict/words))
|
||||
;; Write a close paren to stderr.
|
||||
(run (echo ")") (= 1 2))))
|
||||
|
||||
;; OK. Here, I have a port PORT1 built over a pipe
|
||||
;; connected to the BEGIN subproc's stdout, and
|
||||
;; PORT2 built over a pipe connected to the BEGIN
|
||||
;; subproc's stderr.
|
||||
(read port2) ; Should return the empty list.
|
||||
(port->string port1)) ; Should return a big string.\end{code}
|
||||
%
|
||||
In order to avoid this problem, \ex{run/collecting} and \ex{run/collecting*}
|
||||
first run the child process to completion, buffering all the output
|
||||
streams in temp files (using the \ex{temp-file-channel} procedure, see below).
|
||||
When the child process exits, ports open on the buffered output are returned.
|
||||
This approach has two disadvantages over using pipes:
|
||||
\begin{itemize}
|
||||
\item The total output from the child output is temporarily written
|
||||
to the disk before returning from \ex{run/collecting}. If this output
|
||||
is some large intermediate result, the disk could fill up.
|
||||
|
||||
\item The child producer and {\Scheme} consumer are serialised; there is
|
||||
no concurrency overlap in their execution.
|
||||
\end{itemize}
|
||||
%
|
||||
However, it remains a simple solution that avoids deadlock. More
|
||||
sophisticated solutions can easily be programmed up as
|
||||
needed---\ex{run/collecting*} itself is only 12 lines of simple code.
|
||||
|
||||
See \ex{temp-file-channel} for more information on creating temp files
|
||||
as communication channels.
|
||||
\end{desc}
|
||||
|
||||
\section{Conditional process sequencing forms}
|
||||
These forms allow conditional execution of a sequence of processes.
|
||||
|
||||
\dfn{||} {\vari{pf}1 \ldots \vari{pf}n} {\boolean} {syntax}
|
||||
\begin{desc}
|
||||
Run each proc until one completes successfully (\ie, exit status zero).
|
||||
Return true if some proc completes successfully; otherwise \sharpf.
|
||||
\end{desc}
|
||||
|
||||
\dfn{\&\&} {\vari{pf}1 \ldots \vari{pf}n} {\boolean} {syntax}
|
||||
\begin{desc}
|
||||
Run each proc until one fails (\ie, exit status non-zero).
|
||||
Return true if all procs complete successfully; otherwise \sharpf.
|
||||
\end{desc}
|
||||
|
||||
\section{Process filters}
|
||||
|
||||
These procedures are useful for forking off processes to filter
|
||||
text streams.
|
||||
|
||||
\begin{defundesc}{make-char-port-filter}{filter}{\proc}
|
||||
The \var{filter} argument is a character$\rightarrow$character procedure.
|
||||
Returns a procedure that when called, repeatedly reads a character
|
||||
from the current input port, applies \var{filter} to the character,
|
||||
and writes the result to the current output port.
|
||||
The procedure returns upon reaching eof on the input port.
|
||||
|
||||
For example, to downcase a stream of text in a spell-checking pipeline,
|
||||
instead of using the {\Unix} \ex{tr A-Z a-z} command, we can say:
|
||||
\begin{code}
|
||||
(run (| (delatex)
|
||||
(begin ((char-filter char-downcase))) ; tr A-Z a-z
|
||||
(spell)
|
||||
(sort)
|
||||
(uniq))
|
||||
(< scsh.tex)
|
||||
(> spell-errors.txt))\end{code}
|
||||
\end{defundesc}
|
||||
|
||||
\begin{defundesc}{make-string-port-filter}{filter [buflen]}{\proc}
|
||||
The \var{filter} argument is a string$\rightarrow$string procedure.
|
||||
Returns a procedure that when called, repeatedly reads a string
|
||||
from the current input port, applies \var{filter} to the string,
|
||||
and writes the result to the current output port.
|
||||
The procedure returns upon reaching eof on the input port.
|
||||
|
||||
The optional \var{buflen} argument controls the number of characters
|
||||
each internal read operation requests; this means that \var{filter}
|
||||
will never be applied to a string longer than \var{buflen} chars.
|
||||
The default \var{buflen} value is 1024.
|
||||
\end{defundesc}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
%&latex -*- latex -*-
|
||||
|
||||
\chapter{Reading delimited strings}
|
||||
\label{chapt:rdelim}
|
||||
|
||||
Scsh provides a set of procedures that read delimited strings from
|
||||
input ports.
|
||||
There are procedures to read a single line of text
|
||||
(terminated by a newline character),
|
||||
a single paragraph (terminated by a blank line),
|
||||
and general delimited strings
|
||||
(terminated by a character belonging to an arbitrary character set).
|
||||
|
||||
These procedures can be applied to any Scheme input port.
|
||||
However, the scsh virtual machine has native-code support for performing
|
||||
delimited reads on Unix ports, and these input operations should be
|
||||
particularly fast---much faster than doing the equivalent character-at-a-time
|
||||
operation from Scheme code.
|
||||
|
||||
All of the delimited input operations described below take a \ex{handle-delim}
|
||||
parameter, which determines what the procedure does with the terminating
|
||||
delimiter character.
|
||||
There are four possible choices for a \ex{handle-delim} parameter:
|
||||
\begin{inset}
|
||||
\begin{tabular}{|l|l|} \hline
|
||||
\ex{handle-delim} & Meaning \\ \hline\hline
|
||||
\ex{'trim} & Ignore delimiter character. \\
|
||||
\ex{'peek} & Leave delimiter character in input stream. \\
|
||||
\ex{'concat} & Append delimiter character to returned value. \\
|
||||
\ex{'split} & Return delimiter as second value. \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
The first case, \ex{'trim}, is the standard default for all the routines
|
||||
described in this section.
|
||||
The last three cases allow the programmer to distinguish between strings
|
||||
that are terminated by a delimiter character, and strings that are
|
||||
terminated by an end-of-file.
|
||||
|
||||
|
||||
\begin{defundesc} {read-line} {[port handle-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{handle-newline} determines what \ex{read-line} does with the
|
||||
newline or EOF that terminates the line; it takes the general set
|
||||
of values described for the general \ex{handle-delim} case above,
|
||||
and defaults to \ex{'trim} (discard the newline).
|
||||
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-paragraph} {[port handle-delim]} {{\str} or eof}
|
||||
\begin{desc}
|
||||
This procedure skips blank lines,
|
||||
then reads text from a port until a blank line or eof is found.
|
||||
A ``blank line'' is a (possibly empty) line composed only of white space.
|
||||
The \var{handle-delim} parameter determines how the terminating
|
||||
blank line is handled.
|
||||
It is described above, and defaults to \ex{'trim}.
|
||||
The \ex{'peek} option is not available.
|
||||
\end{desc}
|
||||
|
||||
|
||||
The following procedures read in strings from ports delimited by characters
|
||||
belonging to a specific set.
|
||||
See section~\ref{sec:char-sets} for information on character set manipulation.
|
||||
|
||||
\defun{read-delimited}{char-set [port handle-delim]} {{\str} or eof}
|
||||
\begin{desc}
|
||||
Read until we encounter one of the chars in \var{char-set} or eof.
|
||||
The \var{handle-delim} parameter determines how the terminating character
|
||||
is handled. It is described above, and defaults to \ex{'trim}.
|
||||
|
||||
The \var{char-set} argument may be a charset, a string, or a
|
||||
character; it is coerced to a charset.
|
||||
\end{desc}
|
||||
|
||||
\dfni{read-delimited!} {char-set buf [port handle-delim start end]}
|
||||
{nchars or eof or \#f}{procedure}
|
||||
{read-delimited"!@\texttt{read-delimited"!}}
|
||||
\begin{desc}
|
||||
A side-effecting variant of \ex{read-delimited}.
|
||||
|
||||
The data is written into the string \var{buf} 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{buf})}$. 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{buf})}$.
|
||||
|
||||
It returns \var{nbytes}, the number of bytes read. If the buffer filled up
|
||||
without a delimiter character being found, \ex{\#f} is returned. If
|
||||
the port is at eof when the read starts, the eof object is returned.
|
||||
|
||||
If an integer is returned (\ie, the read is successfully terminated by
|
||||
reading a delimiter character), then the \var{handle-delim} parameter
|
||||
determines how the terminating character is handled.
|
||||
It is described above, and defaults to \ex{'trim}.
|
||||
\end{desc}
|
||||
|
||||
|
||||
|
||||
\dfni{\%read-delimited!} {char-set buf gobble? [port start end]}
|
||||
{[char-or-eof-or-\#f \integer]}{procedure}
|
||||
{\%read-delimited"!@\texttt{\%read-delimited"!}}
|
||||
\begin{desc}
|
||||
This low-level delimited reader uses an alternate interface.
|
||||
It returns two values: \var{terminator} and \var{num-read}.
|
||||
\begin{description}
|
||||
\item [terminator]
|
||||
A value describing why the read was terminated:
|
||||
\begin{flushleft}
|
||||
\begin{tabular}{l@{\qquad$\Rightarrow$\qquad}l}
|
||||
Character or eof-object & Read terminated by this value. \\
|
||||
\ex{\#f} & Filled buffer without finding a delimiter.
|
||||
\end{tabular}
|
||||
\end{flushleft}
|
||||
|
||||
\item [num-read]
|
||||
Number of characters read into \var{buf}.
|
||||
\end{description}
|
||||
|
||||
If the read is successfully terminated by reading a delimiter character,
|
||||
then the \var{gobble?} parameter determines what to do with the terminating
|
||||
character.
|
||||
If true, the character is removed from the input stream;
|
||||
if false, the character is left in the input stream where a subsequent
|
||||
read operation will retrieve it.
|
||||
In either case, the character is also the first value returned by
|
||||
the procedure call.
|
||||
\end{desc}
|
||||
|
||||
%Note:
|
||||
%- Invariant: TERMINATOR = #f => NUM-READ = END - START.
|
||||
%- Invariant: TERMINATOR = eof-object and NUM-READ = 0 => at EOF.
|
||||
%- When determining the TERMINATOR return value, ties are broken
|
||||
% favoring character or the eof-object over #f. That is, if the buffer
|
||||
% fills up, %READ-DELIMITED! will peek at one more character from the
|
||||
% input stream to determine if it terminates the input. If so, that
|
||||
% is returned, not #f.
|
||||
|
||||
\begin{defundesc} {skip-char-set} {skip-chars [port]} {\integer}
|
||||
Skip characters occurring in the set \var{skip-chars};
|
||||
return the number of characters skipped.
|
||||
The \var{skip-chars} argument may be a charset, a string, or a
|
||||
character; it is coerced to a charset.
|
||||
\end{defundesc}
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: latex
|
||||
%%% TeX-master: "man"
|
||||
%%% End:
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,501 @@
|
|||
% -*- latex -*-
|
||||
\chapter{Strings and characters}
|
||||
|
||||
Strings are the basic communication medium for {\Unix} processes, so a
|
||||
Unix programming environment must have reasonable facilities for manipulating
|
||||
them.
|
||||
Scsh provides a powerful set of procedures for processing strings and
|
||||
characters.
|
||||
Besides the the facilities described in this chapter, scsh also provides
|
||||
\begin{itemize}
|
||||
\itum{Regular expressions (chapter~\ref{chapt:sre})}
|
||||
A complete regular-expression system.
|
||||
|
||||
\itum{Field parsing, delimited record I/O and the awk loop
|
||||
(chapter~\ref{chapt:fr-awk})}
|
||||
These procedures let you read in chunks of text delimited by selected
|
||||
characters, and
|
||||
parse each record into fields based on regular expressions
|
||||
(for example, splitting a string at every occurrence of colon or
|
||||
white-space).
|
||||
The \ex{awk} form allows you to loop over streams of these records
|
||||
in a convenient way.
|
||||
|
||||
\itum{The SRFI-13 string libraries}
|
||||
This pair of libraries contains procedures that create, fold, iterate over,
|
||||
search, compare, assemble, cut, hash, case-map, and otherwise manipulate
|
||||
strings.
|
||||
They are provided by the \ex{string-lib} and \ex{string-lib-internals}
|
||||
packages, and are also available in the default \ex{scsh} package.
|
||||
|
||||
More documentation on these procedures can be found at URLs
|
||||
\begin{tightinset}
|
||||
% The gratuitous mbox makes xdvi render the hyperlinks better.
|
||||
\texonly
|
||||
\mbox{\url{http://srfi.schemers.org/srfi-13/srfi-13.html}}\\
|
||||
\url{http://srfi.schemers.org/srfi-13/srfi-13.txt}
|
||||
\endtexonly
|
||||
% Changed the \mbox into \urlh for tex2page to avoid problems runing tex2page
|
||||
\htmlonly
|
||||
\urlh{http://srfi.schemers.org/srfi-13/srfi-13.html}{http://srfi.schemers.org/srfi-13/srfi-13.html}\\
|
||||
\urlh{http://srfi.schemers.org/srfi-13/srfi-13.txt}{http://srfi.schemers.org/srfi-13/srfi-13.txt}
|
||||
\endhtmlonly
|
||||
\end{tightinset}
|
||||
|
||||
\itum{The SRFI-14 character-set library}
|
||||
This library provides a set-of-characters abstraction, which is frequently
|
||||
useful when searching, parsing, filtering or otherwise operating on
|
||||
strings and character data. The SRFI is provided by the \ex{char-set-lib}
|
||||
package; it's bindings are also available in the default \ex{scsh} package.
|
||||
|
||||
More documentation on this library can be found at URLs
|
||||
\begin{tightinset}
|
||||
% The gratuitous mbox makes xdvi render the hyperlinks better.
|
||||
\texonly
|
||||
\mbox{\url{http://srfi.schemers.org/srfi-14/srfi-14.html}}\\
|
||||
\url{http://srfi.schemers.org/srfi-14/srfi-14.txt}
|
||||
\endtexonly
|
||||
% Changed the \mbox into \urlh for tex2page to avoid problems runing tex2page
|
||||
\htmlonly
|
||||
\urlh{http://srfi.schemers.org/srfi-14/srfi-14.html}{http://srfi.schemers.org/srfi-14/srfi-14.html}\\
|
||||
\urlh{http://srfi.schemers.org/srfi-14/srfi-14.txt}{http://srfi.schemers.org/srfi-14/srfi-14.txt}
|
||||
\endhtmlonly
|
||||
\end{tightinset}
|
||||
|
||||
\end{itemize}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Manipulating file names}
|
||||
\label{sec:filenames}
|
||||
|
||||
These procedures do not access the file-system at all; they merely operate
|
||||
on file-name strings. Much of this structure is patterned after the gnu emacs
|
||||
design. Perhaps a more sophisticated system would be better, something
|
||||
like the pathname abstractions of {\CommonLisp} or MIT Scheme. However,
|
||||
being {\Unix}-specific, we can be a little less general.
|
||||
|
||||
\subsection{Terminology}
|
||||
These procedures carefully adhere to the {\Posix} standard for file-name
|
||||
resolution, which occasionally entails some slightly odd things.
|
||||
This section will describe these rules, and give some basic terminology.
|
||||
|
||||
A \emph{file-name} is either the file-system root (``/''),
|
||||
or a series of slash-terminated directory components, followed by
|
||||
a a file component.
|
||||
Root is the only file-name that may end in slash.
|
||||
Some examples:
|
||||
\begin{center}
|
||||
\begin{tabular}{lll}
|
||||
File name & Dir components & File component \\\hline
|
||||
\ex{src/des/main.c} & \ex{("src" "des")} & \ex{"main.c"} \\
|
||||
\ex{/src/des/main.c} & \ex{("" "src" "des")} & \ex{"main.c"} \\
|
||||
\ex{main.c} & \ex{()} & \ex{"main.c"} \\
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
Note that the relative filename \ex{src/des/main.c} and the absolute filename
|
||||
\ex{/src/des/main.c} are distinguished by the presence of the root component
|
||||
\ex{""} in the absolute path.
|
||||
|
||||
Multiple embedded slashes within a path have the same meaning as
|
||||
a single slash.
|
||||
More than two leading slashes at the beginning of a path have the same
|
||||
meaning as a single leading slash---they indicate that the file-name
|
||||
is an absolute one, with the path leading from root.
|
||||
However, {\Posix} permits the OS to give special meaning to
|
||||
\emph{two} leading slashes.
|
||||
For this reason, the routines in this section do not simplify two leading
|
||||
slashes to a single slash.
|
||||
|
||||
A file-name in \emph{directory form} is either a file-name terminated by
|
||||
a slash, \eg, ``\ex{/src/des/}'', or the empty string, ``''.
|
||||
The empty string corresponds to the current working directory,
|
||||
whose file-name is dot (``\ex{.}'').
|
||||
Working backwards from the append-a-slash rule,
|
||||
we extend the syntax of {\Posix} file-names to define the empty string
|
||||
to be a file-name form of the root directory ``\ex{/}''.
|
||||
(However, ``\ex{/}'' is also acceptable as a file-name form for root.)
|
||||
So the empty string has two interpretations:
|
||||
as a file-name form, it is the file-system root;
|
||||
as a directory form, it is the current working directory.
|
||||
Slash is also an ambiguous form: \ex{/} is both a directory-form and
|
||||
a file-name form.
|
||||
|
||||
The directory form of a file-name is very rarely used.
|
||||
Almost all of the procedures in scsh name directories by giving
|
||||
their file-name form (without the trailing slash), not their directory form.
|
||||
So, you say ``\ex{/usr/include}'', and ``\ex{.}'', not
|
||||
``\ex{/usr/include/}'' and ``''.
|
||||
The sole exceptions are
|
||||
\ex{file-name-as-directory} and \ex{directory-as-file-name},
|
||||
whose jobs are to convert back-and-forth between these forms,
|
||||
and \ex{file-name-directory}, whose job it is to split out the
|
||||
directory portion of a file-name.
|
||||
However, most procedures that expect a directory argument will coerce
|
||||
a file-name in directory form to file-name form if it does not have
|
||||
a trailing slash.
|
||||
Bear in mind that the ambiguous case, empty string, will be
|
||||
interpreted in file-name form, \ie, as root.
|
||||
|
||||
|
||||
|
||||
\subsection{Procedures}
|
||||
|
||||
\defun {file-name-directory?} {fname} \boolean
|
||||
\defunx {file-name-non-directory?} {fname} \boolean
|
||||
\begin{desc}
|
||||
These predicates return true if the string is in directory form, or
|
||||
file-name form (see the above discussion of these two forms).
|
||||
Note that they both return true on the ambiguous case of empty string,
|
||||
which is both a directory (current working directory), and a file name
|
||||
(the file-system root).
|
||||
\begin{center}
|
||||
\begin{tabular}{lll}
|
||||
File name & \ex{\ldots-directory?} & \ex{\ldots-non-directory?} \\
|
||||
\hline
|
||||
\ex{"src/des"} & \ex{\sharpf} & \ex{\sharpt} \\
|
||||
\ex{"src/des/"} & \ex{\sharpt} & \ex{\sharpf} \\
|
||||
\ex{"/"} & \ex{\sharpt} & \ex{\sharpf} \\
|
||||
\ex{"."} & \ex{\sharpf} & \ex{\sharpt} \\
|
||||
\ex{""} & \ex{\sharpt} & \ex{\sharpt}
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
\end{desc}
|
||||
|
||||
\begin{defundesc} {file-name-as-directory} {fname} \str
|
||||
Convert a file-name to directory form.
|
||||
Basically, add a trailing slash if needed:
|
||||
\begin{exampletable}
|
||||
\ex{(file-name-as-directory "src/des")} & \ex{"src/des/"} \\
|
||||
\ex{(file-name-as-directory "src/des/")} & \ex{"src/des/"} \\[2ex]
|
||||
%
|
||||
\header{\ex{.}, \ex{/}, and \ex{""} are special:}
|
||||
\ex{(file-name-as-directory ".")} & \ex{""} \\
|
||||
\ex{(file-name-as-directory "/")} & \ex{"/"} \\
|
||||
\ex{(file-name-as-directory "")} & \ex{"/"}
|
||||
\end{exampletable}
|
||||
\end{defundesc}
|
||||
|
||||
\begin{defundesc} {directory-as-file-name} {fname} \str
|
||||
Convert a directory to a simple file-name.
|
||||
Basically, kill a trailing slash if one is present:
|
||||
\begin{exampletable}
|
||||
\ex{(directory-as-file-name "foo/bar/")} & \ex{"foo/bar"} \\[2ex]
|
||||
%
|
||||
\header{\ex{/} and \ex{""} are special:}
|
||||
\ex{(directory-as-file-name "/")} & \ex{"/"} \\
|
||||
\ex{(directory-as-file-name "")} & \ex{"."} (\ie, the cwd) \\
|
||||
\end{exampletable}
|
||||
\end{defundesc}
|
||||
|
||||
\begin{defundesc} {file-name-absolute?} {fname} \boolean
|
||||
Does \var{fname} begin with a root or \ex{\~} component?
|
||||
(Recognising \ex{\~} as a home-directory specification
|
||||
is an extension of {\Posix} rules.)
|
||||
%
|
||||
\begin{exampletable}
|
||||
\ex{(file-name-absolute? "/usr/shivers")} & {\sharpt} \\
|
||||
\ex{(file-name-absolute? "src/des")} & {\sharpf} \\
|
||||
\ex{(file-name-absolute? "\~/src/des")} & {\sharpt} \\[2ex]
|
||||
%
|
||||
\header{Non-obvious case:}
|
||||
\ex{(file-name-absolute? "")} & {\sharpt} (\ie, root)
|
||||
\end{exampletable}
|
||||
\end{defundesc}
|
||||
|
||||
|
||||
\begin{defundesc} {file-name-directory} {fname} {{\str} or false}
|
||||
Return the directory component of \var{fname} in directory form.
|
||||
If the file-name is already in directory form, return it as-is.
|
||||
%
|
||||
\begin{exampletable}
|
||||
\ex{(file-name-directory "/usr/bdc")} & \ex{"/usr/"} \\
|
||||
{\ex{(file-name-directory "/usr/bdc/")}} &
|
||||
{\ex{"/usr/bdc/"}} \\
|
||||
\ex{(file-name-directory "bdc/.login")} & \ex{"bdc/"} \\
|
||||
\ex{(file-name-directory "main.c")} & \ex{""} \\[2ex]
|
||||
%
|
||||
\header{Root has no directory component:}
|
||||
\ex{(file-name-directory "/")} & \ex{""} \\
|
||||
\ex{(file-name-directory "")} & \ex{""}
|
||||
\end{exampletable}
|
||||
\end{defundesc}
|
||||
|
||||
|
||||
\begin{defundesc} {file-name-nondirectory} {fname} \str
|
||||
Return non-directory component of fname.
|
||||
%
|
||||
\begin{exampletable}
|
||||
{\ex{(file-name-nondirectory "/usr/ian")}} &
|
||||
{\ex{"ian"}} \\
|
||||
\ex{(file-name-nondirectory "/usr/ian/")} & \ex{""} \\
|
||||
{\ex{(file-name-nondirectory "ian/.login")}} &
|
||||
{\ex{".login"}} \\
|
||||
\ex{(file-name-nondirectory "main.c")} & \ex{"main.c"} \\
|
||||
\ex{(file-name-nondirectory "")} & \ex{""} \\
|
||||
\ex{(file-name-nondirectory "/")} & \ex{"/"}
|
||||
\end{exampletable}
|
||||
\end{defundesc}
|
||||
|
||||
|
||||
\begin{defundesc} {split-file-name} {fname} {{\str} list}
|
||||
Split a file-name into its components.
|
||||
%
|
||||
\begin{exampletable}
|
||||
\splitline{\ex{(split-file-name "src/des/main.c")}}
|
||||
{\ex{("src" "des" "main.c")}} \\[1.5ex]
|
||||
%
|
||||
\splitline{\ex{(split-file-name "/src/des/main.c")}}
|
||||
{\ex{("" "src" "des" "main.c")}} \\[1.5ex]
|
||||
%
|
||||
\splitline{\ex{(split-file-name "main.c")}} {\ex{("main.c")}} \\[1.5ex]
|
||||
%
|
||||
\splitline{\ex{(split-file-name "/")}} {\ex{("")}}
|
||||
\end{exampletable}
|
||||
\end{defundesc}
|
||||
|
||||
|
||||
\begin{defundesc} {path-list->file-name} {path-list [dir]} \str
|
||||
Inverse of \ex{split-file-name}.
|
||||
\begin{code}
|
||||
(path-list->file-name '("src" "des" "main.c"))
|
||||
{\evalto} "src/des/main.c"
|
||||
(path-list->file-name '("" "src" "des" "main.c"))
|
||||
{\evalto} "/src/des/main.c"
|
||||
\cb
|
||||
{\rm{}Optional \var{dir} arg anchors relative path-lists:}
|
||||
(path-list->file-name '("src" "des" "main.c")
|
||||
"/usr/shivers")
|
||||
{\evalto} "/usr/shivers/src/des/main.c"\end{code}
|
||||
%
|
||||
The optional \var{dir} argument is usefully \ex{(cwd)}.
|
||||
\end{defundesc}
|
||||
|
||||
|
||||
\begin{defundesc} {file-name-extension} {fname} \str
|
||||
Return the file-name's extension.
|
||||
%
|
||||
\begin{exampletable}
|
||||
\ex{(file-name-extension "main.c")} & \ex{".c"} \\
|
||||
\ex{(file-name-extension "main.c.old")} & \ex{".old"} \\
|
||||
\ex{(file-name-extension "/usr/shivers")} & \ex{""}
|
||||
\end{exampletable}
|
||||
%
|
||||
\begin{exampletable}
|
||||
\header{Weird cases:}
|
||||
\ex{(file-name-extension "foo.")} & \ex{"."} \\
|
||||
\ex{(file-name-extension "foo..")} & \ex{"."}
|
||||
\end{exampletable}
|
||||
%
|
||||
\begin{exampletable}
|
||||
\header{Dot files are not extensions:}
|
||||
\ex{(file-name-extension "/usr/shivers/.login")} & \ex{""}
|
||||
\end{exampletable}
|
||||
\end{defundesc}
|
||||
|
||||
|
||||
\begin{defundesc} {file-name-sans-extension} {fname} \str
|
||||
Return everything but the extension.
|
||||
%
|
||||
\begin{exampletable}
|
||||
\ex{(file-name-sans-extension "main.c")} & \ex{"main"} \\
|
||||
\ex{(file-name-sans-extension "main.c.old")} & \ex{"main.c""} \\
|
||||
\splitline{\ex{(file-name-sans-extension "/usr/shivers")}}
|
||||
{\ex{"/usr/shivers"}}
|
||||
\end{exampletable}
|
||||
%
|
||||
\begin{exampletable}
|
||||
\header{Weird cases:}
|
||||
\ex{(file-name-sans-extension "foo.")} & \ex{"foo"} \\
|
||||
\ex{(file-name-sans-extension "foo..")} & \ex{"foo."} \\[2ex]
|
||||
%
|
||||
\header{Dot files are not extensions:}
|
||||
\splitline{\ex{(file-name-sans-extension "/usr/shivers/.login")}}
|
||||
{\ex{"/usr/shivers/.login}}
|
||||
\end{exampletable}
|
||||
|
||||
Note that appending the results of \ex{file-name-extension} and
|
||||
{\ttt file\=name\=sans\=extension} in all cases produces the original file-name.
|
||||
\end{defundesc}
|
||||
|
||||
|
||||
\begin{defundesc} {parse-file-name} {fname} {[dir name extension]}
|
||||
Let $f$ be \ex{(file-name-nondirectory \var{fname})}.
|
||||
This function returns the three values:
|
||||
\begin{itemize}
|
||||
\item \ex{(file-name-directory \var{fname})}
|
||||
\item \ex{(file-name-sans-extension \var{f}))}
|
||||
\item \ex{(file-name-extension \var{f}\/)}
|
||||
\end{itemize}
|
||||
The inverse of \ex{parse-file-name}, in all cases, is \ex{string-append}.
|
||||
The boundary case of \ex{/} was chosen to preserve this inverse.
|
||||
\end{defundesc}
|
||||
|
||||
\begin{defundesc} {replace-extension} {fname ext} \str
|
||||
This procedure replaces \var{fname}'s extension with \var{ext}.
|
||||
It is exactly equivalent to
|
||||
\codex{(string-append (file-name-sans-extension \var{fname}) \var{ext})}
|
||||
\end{defundesc}
|
||||
|
||||
\defun{simplify-file-name}{fname}\str
|
||||
\begin{desc}
|
||||
Removes leading and internal occurrences of dot.
|
||||
A trailing dot is left alone, as the parent could be a symlink.
|
||||
Removes internal and trailing double-slashes.
|
||||
A leading double-slash is left alone, in accordance with {\Posix}.
|
||||
However, triple and more leading slashes are reduced to a single slash,
|
||||
in accordance with {\Posix}.
|
||||
Double-dots (parent directory) are left alone, in case they come after
|
||||
symlinks or appear in a \ex{/../\var{machine}/\ldots} ``super-root'' form
|
||||
(which {\Posix} permits).
|
||||
\end{desc}
|
||||
|
||||
\defun{resolve-file-name}{fname [dir]}\str
|
||||
\begin{desc}
|
||||
\begin{itemize}
|
||||
\item Do \ex{\~} expansion.
|
||||
\item If \var{dir} is given,
|
||||
convert a relative file-name to an absolute file-name,
|
||||
relative to directory \var{dir}.
|
||||
\end{itemize}
|
||||
\end{desc}
|
||||
|
||||
\begin{defundesc} {expand-file-name} {fname [dir]} \str
|
||||
Resolve and simplify the file-name.
|
||||
\end{defundesc}
|
||||
|
||||
\begin{defundesc} {absolute-file-name} {fname [dir]} \str
|
||||
Convert file-name \var{fname} into an absolute file name,
|
||||
relative to directory \var{dir}, which defaults to the current
|
||||
working directory. The file name is simplified before being
|
||||
returned.
|
||||
|
||||
This procedure does not treat a leading tilde character specially.
|
||||
\end{defundesc}
|
||||
|
||||
\begin{defundesc} {home-dir} {[user]} \str
|
||||
\ex{home-dir} returns \var{user}'s home directory.
|
||||
\var{User} defaults to the current user.
|
||||
|
||||
\begin{exampletable}
|
||||
\ex{(home-dir)} & \ex{"/user1/lecturer/shivers"} \\
|
||||
\ex{(home-dir "ctkwan")} & \ex{"/user0/research/ctkwan"}
|
||||
\end{exampletable}
|
||||
\end{defundesc}
|
||||
|
||||
\begin{defundesc} {home-file} {[user] fname} \str
|
||||
Returns file-name \var{fname} relative to \var{user}'s home directory;
|
||||
\var{user} defaults to the current user.
|
||||
%
|
||||
\begin{exampletable}
|
||||
\ex{(home-file "man")} & \ex{"/usr/shivers/man"} \\
|
||||
\ex{(home-file "fcmlau" "man")} & \ex{"/usr/fcmlau/man"}
|
||||
\end{exampletable}
|
||||
\end{defundesc}
|
||||
|
||||
The general \ex{substitute-env-vars} string procedure,
|
||||
defined in the previous section,
|
||||
is also frequently useful for expanding file-names.
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Other string manipulation facilities}
|
||||
|
||||
\begin{defundesc} {substitute-env-vars} {fname} \str
|
||||
Replace occurrences of environment variables with their values.
|
||||
An environment variable is denoted by a dollar sign followed by
|
||||
alphanumeric chars and underscores, or is surrounded by braces.
|
||||
|
||||
\begin{exampletable}
|
||||
\splitline{\ex{(substitute-env-vars "\$USER/.login")}}
|
||||
{\ex{"shivers/.login"}} \\
|
||||
\cd{(substitute-env-vars "$\{USER\}_log")} & \cd{"shivers_log"}
|
||||
\end{exampletable}
|
||||
\end{defundesc}
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{ASCII encoding}
|
||||
|
||||
\defun {char->ascii}{\character} \integer
|
||||
\defunx {ascii->char}{\integer} \character
|
||||
\begin{desc}
|
||||
These are identical to \ex{char->integer} and \ex{integer->char} except that
|
||||
they use the {\Ascii} encoding.
|
||||
\end{desc}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Character predicates}
|
||||
|
||||
\defun {char-letter?}\character\boolean
|
||||
\defunx{char-lower-case?}\character\boolean
|
||||
\defunx{char-upper-case?}\character\boolean
|
||||
\defunx{char-title-case?}\character\boolean
|
||||
\defunx{char-digit?}\character\boolean
|
||||
\defunx{char-letter+digit?}\character\boolean
|
||||
\defunx{char-graphic?}\character\boolean
|
||||
\defunx{char-printing?}\character\boolean
|
||||
\defunx{char-whitespace?}\character\boolean
|
||||
\defunx{char-blank?}\character\boolean
|
||||
\defunx{char-iso-control?}\character\boolean
|
||||
\defunx{char-punctuation?}\character\boolean
|
||||
\defunx{char-hex-digit?}\character\boolean
|
||||
\defunx{char-ascii?}\character\boolean
|
||||
\begin{desc}
|
||||
Each of these predicates tests for membership in one of the standard
|
||||
character sets provided by the SRFI-14 character-set library.
|
||||
Additionally, the following redundant bindings are provided for {\RnRS}
|
||||
compatibility:
|
||||
\begin{inset}
|
||||
\begin{tabular}{ll}
|
||||
{\RnRS} name & scsh definition \\ \hline
|
||||
\ex{char-alphabetic?} & \ex{char-letter+digit?} \\
|
||||
\ex{char-numeric?} & \ex{char-digit?} \\
|
||||
\ex{char-alphanumeric?} & \ex{char-letter+digit?}
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
\end{desc}
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\section{Deprecated character-set procedures}
|
||||
\label{sec:char-sets}
|
||||
|
||||
The SRFI-13 character-set library grew out of an earlier library developed
|
||||
for scsh.
|
||||
However, the SRFI standardisation process introduced incompatibilities with
|
||||
the original scsh bindings.
|
||||
The current version of scsh provides the library
|
||||
\ex{obsolete-char-set-lib}, which contains the old bindings found in
|
||||
previous releases of scsh.
|
||||
The following table lists the members of this library, along with
|
||||
the equivalent SRFI-13 binding. This obsolete library is deprecated and
|
||||
\emph{not} open by default in the standard \ex{scsh} environment;
|
||||
new code should use the SRFI-13 bindings.
|
||||
\begin{inset}
|
||||
\begin{tabular}{ll}
|
||||
Old \ex{obsolete-char-set-lib} & SRFI-13 \ex{char-set-lib} \\ \hline
|
||||
|
||||
\ex{char-set-members} & \ex{char-set->list} \\
|
||||
\ex{chars->char-set} & \ex{list->char-set} \\
|
||||
\ex{ascii-range->char-set} & \ex{ucs-range->char-set} (not exact) \\
|
||||
\ex{predicate->char-set} & \ex{char-set-filter} (not exact) \\
|
||||
\ex{char-set-every}? & \ex{char-set-every} \\
|
||||
\ex{char-set-any}? & \ex{char-set-any} \\
|
||||
\\
|
||||
\ex{char-set-invert} & \ex{char-set-complement} \\
|
||||
\ex{char-set-invert}! & \ex{char-set-complement!} \\
|
||||
\\
|
||||
\ex{char-set:alphabetic} & \ex{char-set:letter} \\
|
||||
\ex{char-set:numeric} & \ex{char-set:digit} \\
|
||||
\ex{char-set:alphanumeric} & \ex{char-set:letter+digit} \\
|
||||
\ex{char-set:control} & \ex{char-set:iso-control}
|
||||
\end{tabular}
|
||||
\end{inset}
|
||||
Note also that the \ex{->char-set} procedure no longer handles a predicate
|
||||
argument.
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: latex
|
||||
%%% TeX-master: "man"
|
||||
%%% End:
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,33 @@
|
|||
%&latex -*- latex -*-
|
||||
|
||||
\documentclass{report}
|
||||
\usepackage{code,boxedminipage,draftfooters,palatino,ct,makeidx,
|
||||
headings,mantitle,array,matter,mysize10}
|
||||
|
||||
\parskip = 3pt plus 3pt
|
||||
\sloppy
|
||||
|
||||
\input{decls}
|
||||
%%% End preamble
|
||||
|
||||
\begin{document}
|
||||
|
||||
\begin{tabular}{ll}
|
||||
{\begin{codebox}[b]
|
||||
define structure web server
|
||||
open scsh
|
||||
scheme
|
||||
net-hax
|
||||
|
||||
file web\end{codebox}}
|
||||
&
|
||||
{\begin{codebox}[b]
|
||||
(define-structure web-server
|
||||
(open scheme
|
||||
scsh
|
||||
net-hax
|
||||
\vdots)
|
||||
(file web))\end{codebox}}\\
|
||||
\end{tabular}
|
||||
|
||||
\end{document}
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
%latex -*- latex -*-
|
||||
|
||||
\chapter{Concurrent system programming}
|
||||
|
||||
The Scheme Shell provides the user with support for concurrent programming.
|
||||
The interface consists of several parts:
|
||||
\begin{itemize}
|
||||
\item The thread system
|
||||
\item Synchronization vehicles
|
||||
\item Process state abstractions
|
||||
\end{itemize}
|
||||
Whereas the user deals with threads and synchronization explicitly,
|
||||
the process state abstractions are built into the rest of the system,
|
||||
almost transparent for the user. Section \ref{sec:ps_interac}
|
||||
describes the interaction between process state and threads.
|
||||
|
||||
\section{Threads}
|
||||
|
||||
A thread can be thought of as a procedure that can run independently of
|
||||
and concurrent to the rest of the system. The calling procedure fires
|
||||
the thread up and forgets about it.
|
||||
|
||||
The current thread interface is completely taken from Scheme\ 48. This
|
||||
documentation is an extension of the file \texttt{doc/threads.txt}.
|
||||
|
||||
The thread structure is named \texttt{threads}, it has to be opened explicitly.
|
||||
|
||||
\defun {spawn} {thunk [name]} \undefined
|
||||
|
||||
Create and schedule a new thread that will execute \var{thunk}, a
|
||||
procedure with no arguments. Note that Scsh's \ex{spawn} does
|
||||
\textbf{not} return a reference to a thread object. The optional
|
||||
argument \var{name} is used when printing the thread.
|
||||
|
||||
The new thread will not inherit the values for the process state from
|
||||
its parent, see the procedure \texttt{fork-thread} in Section
|
||||
\ref{sec:ps_interac} for a way to create a thread with
|
||||
semantics similar to process forking.
|
||||
|
||||
\defun {relinquish-timeslice} {} \undefined
|
||||
|
||||
Let other threads run for a while.
|
||||
|
||||
\defun {sleep} {time} \undefined
|
||||
|
||||
Puts the current thread into sleep for \var{time} milliseconds. The
|
||||
time at which the thread is run again may be longer of course.
|
||||
|
||||
\defun {terminate-current-thread} {} {does-not-return}
|
||||
|
||||
Kill the current thread.
|
||||
|
||||
Mainly for debugging purposes, there is also an interface to the
|
||||
internal representation of thread objects:
|
||||
|
||||
\defun {current-thread} {} {thread-object}
|
||||
|
||||
Return the object to which the current thread internally corresponds.
|
||||
Note that this procedure is exported by the package
|
||||
\texttt{threads-internal} only.
|
||||
|
||||
\defun {thread?} {thing} {\boolean}
|
||||
|
||||
Returns true iff \var{thing} is a thread object.
|
||||
|
||||
\defun {thread-name} {thread} {name}
|
||||
|
||||
\var{Name} corresponds to the second parameter that was given to
|
||||
\ex{spawn} when \var{thread} was created.
|
||||
|
||||
\defun{thread-uid} {thread} {\integer}
|
||||
|
||||
Returns a unique identifier for the current thread.
|
||||
|
||||
\section{Locks}
|
||||
|
||||
Locks are a simple mean for mutual exclusion. They implement a concept
|
||||
commonly known as \textit{semaphores}. Threads can obtain and release
|
||||
locks. If a thread tries to obtain a lock which is held by another
|
||||
thread, the first thread is blocked. To access the following
|
||||
procedures, you must open the structure \texttt{locks}.
|
||||
|
||||
\defun{make-lock} {} {lock}
|
||||
|
||||
Creates a lock.
|
||||
|
||||
\defun{lock?} {thing} {\boolean}
|
||||
|
||||
Returns true iff \var{thing} is a lock.
|
||||
|
||||
\defun{obtain-lock} {lock} {\undefined}
|
||||
|
||||
Obtain \var{lock}. Causes the thread to block if the lock is held by
|
||||
a thread.
|
||||
|
||||
\defun{maybe-obtain-lock} {lock} {\boolean}
|
||||
|
||||
Tries to obtain \var{lock}, but returns false if the lock cannot be
|
||||
obtained.
|
||||
|
||||
\defun{release-lock} {lock} {\boolean}
|
||||
|
||||
Releases \var{lock}. Returns true if the lock immediately got a new
|
||||
owner, false otherwise.
|
||||
|
||||
\defun{lock-owner-uid} {lock} {\integer}
|
||||
|
||||
Returns the uid of the thread that currently holds \var{lock} or false
|
||||
if the lock is free.
|
||||
|
||||
\section{Placeholders}
|
||||
Placeholers combine synchronization with value delivery. They can be
|
||||
thought of as special variables. After creation the value of the
|
||||
placeholder is undefined. If a thread tries to read the placeholders
|
||||
value this thread is blocked. Multiple threads are allowed to block on
|
||||
a single placeholder. They will continue running after another thread
|
||||
sets the value of the placeholder. Now all reading threads receive the
|
||||
value and continue executing. Setting a placeholder to two different
|
||||
values causes an error. The structure \texttt{placeholders} features
|
||||
the following procedures:
|
||||
|
||||
\defun {make-placeholder} {} {placeholder}
|
||||
|
||||
Creates a new placeholder.
|
||||
|
||||
\defun {placeholder?} {thing} {\boolean}
|
||||
|
||||
Returns true iff \var{thing} is a placeholder.
|
||||
|
||||
\defun {placeholder-set!} {placeholder value} {\undefined}
|
||||
|
||||
Sets the placeholders value to \var{value}. If the placeholder is
|
||||
already set to a \textit{different} value an exception is risen.
|
||||
|
||||
\defun {placeholder-value} {placeholder} {value}
|
||||
|
||||
Returns the value of the placeholder. If the placeholder is yet unset,
|
||||
the current thread is blocked until another thread sets the value by
|
||||
means of \ex{placeholder-set!}.
|
||||
|
||||
\section{The event interface to interrupts}
|
||||
\label{sec:event-interf-interr}
|
||||
Scsh provides an synchronous interface to the asynchronous signals
|
||||
delivered by the operation system\footnote{Olin's paper ``Automatic
|
||||
management of operation-system resources'' describes this system in
|
||||
detail.}. The key element in this system is an object called
|
||||
\textit{sigevent} which corresponds to the single occurrence of a
|
||||
signal. A sigevent has two fields: the Unix signal that occurred and a
|
||||
pointer to the sigevent that happened or will happen. That is, events
|
||||
are kept in a linked list in increasing-time order. Scsh's structure
|
||||
\texttt{sigevents} provides various procedures to access this list:
|
||||
|
||||
\defun {most-recent-sigevent} {} {sigevent}
|
||||
|
||||
Returns the most recent sigevent --- the head of the sigevent
|
||||
list.
|
||||
|
||||
\defun {sigevent?} {object} {\boolean}
|
||||
|
||||
The predicate for sigevents.
|
||||
|
||||
\defun {next-sigevent} {pre-event type} {event}
|
||||
|
||||
Returns the next sigevent of type \texttt{type} after sigevent
|
||||
\texttt{pre-event}. If no such event exists, the procedure blocks.
|
||||
|
||||
\defun {next-sigevent-set} {pre-event set} {event}
|
||||
|
||||
Returns the next sigevent whose type is in \texttt{set} after
|
||||
\texttt{pre-event}. If no such event exists, the procdure blocks.
|
||||
|
||||
\defun {next-sigevent/no-wait} {pre-event type} {event or \sharpf}
|
||||
|
||||
Same as \texttt{next-sigevent}, but returns \sharpf if no appropriate
|
||||
event exists.
|
||||
|
||||
\defun {next-sigevent-set/no-wait} {set pre-event} {event or \sharpf}
|
||||
|
||||
Same as \texttt{next-sigevent-set}, but returns \sharpf if no appropriate
|
||||
event exists.
|
||||
|
||||
As a small example, consider this piece of code that toggles the
|
||||
variable \texttt{state} by USR1 and USR2:
|
||||
\begin{code}
|
||||
(define state #t)
|
||||
|
||||
(let lp ((sigevent (most-recent-sigevent)))
|
||||
(let ((next (next-sigevent sigevent interrupt/usr1)))
|
||||
(set! state #f)
|
||||
(let ((next (next-sigevent next interrupt/usr2)))
|
||||
(set! state #t)
|
||||
(lp next))))
|
||||
\end{code}
|
||||
|
||||
\textbf{Warning:} The current version of scsh also defines
|
||||
asynchronous handlers for interrupts (See Section
|
||||
\ref{sec:int_handlers}). The default action of some of these handlers
|
||||
is to terminate the process in which case you will most likely not see
|
||||
an effect of the synchronous event interface described here. It is
|
||||
therefore recommended to disable the corresponding interrupt handler
|
||||
using \texttt{(set-interrupt-handler interrupt \#f)}.
|
||||
|
||||
\section{Interaction between threads and process state}
|
||||
\label{sec:ps_interac}
|
||||
|
||||
In Unix, a number of resources are global to the process: signal
|
||||
handlers, working directory, umask, environment, user and group ids.
|
||||
Modular programming is difficult in the context of this global state
|
||||
and for concurrent programming things get even worse. Section
|
||||
\ref{sec:event-interf-interr} presents how scsh turns
|
||||
the global, asynchronous signals handlers into modular, synchronous
|
||||
sigevents. Concurrent programming also benefit from sigevents as every
|
||||
thread may chase down the sigevent chain separately.
|
||||
|
||||
Scsh treats the working directory, umask, environment, and the
|
||||
effective user/group ID as thread-local resources. The initial value
|
||||
of the resources is determined by the way a thread is started:
|
||||
\texttt{spawn} assigns the initial values whereas \texttt{fork-thread}
|
||||
adopts the values of its parent. Here is a detailed description of the
|
||||
whole facility:
|
||||
|
||||
\begin{itemize}
|
||||
\item The procedures to access and modify the resources remain as
|
||||
described in the previous chapters (\texttt{cwd} and \texttt{chdir},
|
||||
\texttt{umask} and \texttt{set-umask}, \texttt{getenv} and
|
||||
\texttt{putenv}).
|
||||
\item Every thread receives its own copy of each resource.
|
||||
\item If \texttt{spawn} is used to start a new thread, the values of
|
||||
the resources are the same as they where at the start of scsh.
|
||||
\item The procedure
|
||||
|
||||
\defun {fork-thread} {thunk} \undefined
|
||||
|
||||
from the structure \texttt{thread-fluids} starts a thread which
|
||||
inherits the values of all resources from its parent. This behaviour
|
||||
is similar to what happens at process forking.
|
||||
\item The actual process state is updated only when necessary, i.e. on
|
||||
access or modification but not on context switch from one thread
|
||||
to another.
|
||||
\end{itemize}
|
||||
|
||||
\defun{spoon} {thunk} \undefined
|
||||
|
||||
This is just an alias for \ex{fork-thread} suggested by Alan Bawden.
|
||||
|
||||
For user and group identities arbitrary changing is not possible.
|
||||
Therefore they remain global process state: If a thread changes one of
|
||||
these values, all other threads see the new value. Consequently, scsh
|
||||
does not provide \texttt{with-uid} and friends.
|
||||
|
||||
%%% Local Variables:
|
||||
%%% mode: latex
|
||||
%%% TeX-master: "man"
|
||||
%%% End:
|
||||
|
|
@ -0,0 +1,747 @@
|
|||
%&latex -*- latex -*-
|
||||
% Fix OXTABS footnote bug
|
||||
% Figures should be dumped out earlier? Pack two to a page?
|
||||
|
||||
\section{Terminal device control}
|
||||
\label{sect:tty}
|
||||
|
||||
\newcommand{\fr}[1]{\makebox[0pt][r]{#1}}
|
||||
|
||||
Scsh provides a complete set of routines for manipulating terminal
|
||||
devices---putting them in ``raw'' mode, changing and querying their
|
||||
special characters, modifying their I/O speeds, and so forth.
|
||||
The scsh interface is designed both for generality and portability
|
||||
across different Unix platforms, so you don't have to rewrite your
|
||||
program each time you move to a new system.
|
||||
We've also made an effort to use reasonable, Scheme-like names for
|
||||
the multitudinous named constants involved, so when you are reading
|
||||
code, you'll have less likelihood of getting lost in a bewildering
|
||||
maze of obfuscatory constants named \ex{ICRNL}, \ex{INPCK}, \ex{IUCLC},
|
||||
and \ex{ONOCR}.
|
||||
|
||||
This section can only lay out the basic functionality of the terminal
|
||||
device interface.
|
||||
For further details, see the termios(3) man page on your system,
|
||||
or consult one of the standard {\Unix} texts.
|
||||
|
||||
\subsection{Portability across OS variants}
|
||||
Terminal-control software is inescapably complex, ugly, and low-level.
|
||||
Unix variants each provide their own way of controlling terminal
|
||||
devices, making it difficult to provide interfaces that are
|
||||
portable across different Unix systems.
|
||||
Scsh's terminal support is based primarily upon the {\Posix} termios
|
||||
interface.
|
||||
Programs that can be written using only the {\Posix} interface are likely
|
||||
to be widely portable.
|
||||
|
||||
The bulk of the documentation that follows consists of several pages worth
|
||||
of tables defining different named constants that enable and disable different
|
||||
features of the terminal driver.
|
||||
Some of these flags are {\Posix}; others are taken from the two common
|
||||
branches of Unix development, SVR4 and 4.3+ Berkeley.
|
||||
Scsh guarantees that the non-{\Posix} constants will be bound identifiers.
|
||||
\begin{itemize}
|
||||
\item If your OS supports a particular non-{\Posix} flag,
|
||||
its named constant will be bound to the flag's value.
|
||||
\item If your OS doesn't support the flag, its named constant
|
||||
will be present, but bound to \sharpf.
|
||||
\end{itemize}
|
||||
This means that if you want to use SVR4 or Berkeley features in a program,
|
||||
your program can portably test the values of the flags before using
|
||||
them---the flags can reliably be referenced without producing OS-dependent
|
||||
``unbound variable'' errors.
|
||||
|
||||
Finally, note that although {\Posix}, SVR4, and Berkeley cover the lion's
|
||||
share of the terminal-driver functionality,
|
||||
each operating system inevitably has non-standard extensions.
|
||||
While a particular scsh implementation may provide these extensions,
|
||||
they are not portable, and so are not documented here.
|
||||
|
||||
\subsection{Miscellaneous procedures}
|
||||
\defun{tty?}{fd/port}{\boolean}
|
||||
\begin{desc}
|
||||
Return true if the argument is a tty.
|
||||
\end{desc}
|
||||
|
||||
\defun{tty-file-name}{fd/port}{\str}
|
||||
\begin{desc}
|
||||
The argument \var{fd/port} must be a file descriptor or port open on a tty.
|
||||
Return the file-name of the tty.
|
||||
\end{desc}
|
||||
|
||||
\subsection{The tty-info record type}
|
||||
|
||||
The primary data-structure that describes a terminal's mode is
|
||||
a \ex{tty-info} record, defined as follows:
|
||||
\index{tty-info record type}
|
||||
\indextt{tty-info:control-chars}
|
||||
\indextt{tty-info:input-flags}
|
||||
\indextt{tty-info:output-flags}
|
||||
\indextt{tty-info:control-flags}
|
||||
\indextt{tty-info:local-flags}
|
||||
\indextt{tty-info:input-speed}
|
||||
\indextt{tty-info:output-speed}
|
||||
\indextt{tty-info:min}
|
||||
\indextt{tty-info:time}
|
||||
\indextt{tty-info?}
|
||||
\begin{code}
|
||||
(define-record tty-info
|
||||
control-chars ; String: Magic input chars
|
||||
input-flags ; Int: Input processing
|
||||
output-flags ; Int: Output processing
|
||||
control-flags ; Int: Serial-line control
|
||||
local-flags ; Int: Line-editting UI
|
||||
input-speed ; Int: Code for input speed
|
||||
output-speed ; Int: Code for output speed
|
||||
min ; Int: Raw-mode input policy
|
||||
time) ; Int: Raw-mode input policy\end{code}
|
||||
|
||||
\subsubsection{The control-characters string}
|
||||
The \ex{control-chars} field is a character string;
|
||||
its characters may be indexed by integer values taken from
|
||||
table~\ref{table:ttychars}.
|
||||
|
||||
As discussed above,
|
||||
only the {\Posix} entries in table~\ref{table:ttychars} are guaranteed
|
||||
to be legal, integer indices.
|
||||
A program can reliably test the OS to see if the non-{\Posix}
|
||||
characters are supported by checking the index constants.
|
||||
If the control-character function is supported by the terminal driver,
|
||||
then the corresponding index will be bound to an integer;
|
||||
if it is not supported, the index will be bound to \sharpf.
|
||||
|
||||
To disable a given control-character function, set its corresponding
|
||||
entry in the \ex{tty-info:control-chars} string to the
|
||||
special character \exi{disable-tty-char}
|
||||
(and then use the \ex{(set-tty-info \var{fd/port} \var{info})} procedure
|
||||
to update the terminal's state).
|
||||
|
||||
\subsubsection{The flag fields}
|
||||
The \ex{tty-info} record's \ex{input-flags}, \ex{output-flags},
|
||||
\ex{control-flags}, and \ex{local-flags} fields are all bit sets
|
||||
represented as two's-complement integers.
|
||||
Their values are composed by or'ing together values taken from
|
||||
the named constants listed in tables~\ref{table:ttyin}
|
||||
through \ref{table:ttylocal}.
|
||||
|
||||
As discussed above,
|
||||
only the {\Posix} entries listed in these tables are guaranteed
|
||||
to be legal, integer flag values.
|
||||
A program can reliably test the OS to see if the non-{\Posix}
|
||||
flags are supported by checking the named constants.
|
||||
If the feature is supported by the terminal driver,
|
||||
then the corresponding flag will be bound to an integer;
|
||||
if it is not supported, the flag will be bound to \sharpf.
|
||||
|
||||
%%%%% I managed to squeeze this into the DEFINE-RECORD's comments.
|
||||
% Here is a small table classifying the four flag fields by
|
||||
% the kind of features they determine:
|
||||
% \begin{center}
|
||||
% \begin{tabular}{|ll|}\hline
|
||||
% Field & Affects \\ \hline \hline
|
||||
% \ex{input-flags} & Processing of input chars \\
|
||||
% \ex{output-flags} & Processing of output chars \\
|
||||
% \ex{control-flags} & Controlling of terminal's serial line \\
|
||||
% \ex{local-flags} & Details of the line-editting user interface \\
|
||||
% \hline
|
||||
% \end{tabular}
|
||||
% \end{center}
|
||||
|
||||
%%%
|
||||
%%% The figures used to go here.
|
||||
%%%
|
||||
|
||||
\subsubsection{The speed fields}
|
||||
The \ex{input-speed} and \ex{output-speed} fields determine the
|
||||
I/O rate of the terminal's line.
|
||||
The value of these fields is an integer giving the speed
|
||||
in bits-per-second.
|
||||
The following speeds are supported by {\Posix}:
|
||||
\begin{center}
|
||||
\begin{tabular}{rrrr}
|
||||
0 & 134 & 600 & 4800 \\
|
||||
50 & 150 & 1200 & 9600 \\
|
||||
75 & 200 & 1800 & 19200 \\
|
||||
110 & 300 & 2400 & 38400 \\
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
Your OS may accept others; it may also allow the special symbols
|
||||
\ex{'exta} and \ex{'extb}.
|
||||
|
||||
\subsubsection{The min and time fields}
|
||||
The integer \ex{min} and \ex{time} fields determine input blocking
|
||||
behaviour during non-canonical (raw) input; otherwise, they are ignored.
|
||||
See the termios(3) man page for further details.
|
||||
|
||||
Be warned that {\Posix} allows the base system call's representation
|
||||
of the \ex{tty-info} record to share storage for the \ex{min} field
|
||||
and the \ex{ttychar/eof} element of the control-characters string,
|
||||
and for the \ex{time} field and the \ex{ttychar/eol} element
|
||||
of the control-characters string.
|
||||
Many implementations in fact do this.
|
||||
|
||||
To stay out of trouble, set the \ex{min} and \ex{time} fields only
|
||||
if you are putting the terminal into raw mode;
|
||||
set the eof and eol control-characters only if you are putting
|
||||
the terminal into canonical mode.
|
||||
It's ugly, but it's {\Unix}.
|
||||
|
||||
\subsection{Using tty-info records}
|
||||
|
||||
\defun{make-tty-info}{if of cf lf ispeed ospeed min time}
|
||||
{tty-info-record}
|
||||
\defunx{copy-tty-info}{tty-info-record}{tty-info-record}
|
||||
\begin{desc}
|
||||
These procedures make it possible to create new \ex{tty-info} records.
|
||||
The typical method for creating a new record is to copy one retrieved
|
||||
by a call to the \ex{tty-info} procedure, then modify the copy as desired.
|
||||
Note that the \ex{make-tty-info} procedure does not take a parameter
|
||||
to define the new record's control characters.\footnote{
|
||||
Why? Because the length of the string varies from Unix to Unix.
|
||||
For example, the word-erase control character (typically control-w)
|
||||
is provided by most Unixes, but not part of the {\Posix} spec.}
|
||||
Instead, it simply returns a \ex{tty-info} record whose control-character
|
||||
string has all elements initialised to {\Ascii} nul.
|
||||
You may then install the special characters by assigning to the string.
|
||||
Similarly, the control-character string in the record produced by
|
||||
\ex{copy-tty-info} does not share structure with the string in the record
|
||||
being copied, so you may mutate it freely.
|
||||
\end{desc}
|
||||
|
||||
|
||||
\defun{tty-info}{[fd/port/fname]}{tty-info-record}
|
||||
\begin{desc}
|
||||
The \var{fd/port/fname} parameter is an integer file descriptor or
|
||||
Scheme I/O port opened on a terminal device,
|
||||
or a file-name for a terminal device; it defaults to the current input port.
|
||||
This procedure returns a \ex{tty-info} record describing the terminal's
|
||||
current mode.
|
||||
\end{desc}
|
||||
|
||||
\defun {set-tty-info/now} {fd/port/fname info}{no-value}
|
||||
\defunx{set-tty-info/drain}{fd/port/fname info}{no-value}
|
||||
\defunx{set-tty-info/flush}{fd/port/fname info}{no-value}
|
||||
\begin{desc}
|
||||
The \var{fd/port/fname} parameter is an integer file descriptor or
|
||||
Scheme I/O port opened on a terminal device,
|
||||
or a file-name for a terminal device.
|
||||
The procedure chosen determines when and how the terminal's mode is altered:
|
||||
\begin{center}
|
||||
\begin{tabular}{|ll|} \hline
|
||||
Procedure & Meaning \\ \hline \hline
|
||||
\ex{set-tty-info/now} & Make change immediately. \\
|
||||
\ex{set-tty-info/drain} & Drain output, then change. \\
|
||||
\ex{set-tty-info/flush} & Drain output, flush input, then change. \\ \hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
\oops{If I had defined these with the parameters in the reverse order,
|
||||
I could have made \var{fd/port/fname} optional. Too late now.}
|
||||
\end{desc}
|
||||
|
||||
\subsection{Other terminal-device procedures}
|
||||
\defun{send-tty-break}{[fd/port/fname duration]}{no-value}
|
||||
\begin{desc}
|
||||
The \var{fd/port/fname} parameter is an integer file descriptor or
|
||||
Scheme I/O port opened on a terminal device,
|
||||
or a file-name for a terminal device; it defaults to the current output port.
|
||||
Send a break signal to the designated terminal.
|
||||
A break signal is a sequence of continuous zeros on the terminal's transmission
|
||||
line.
|
||||
|
||||
The \var{duration} argument determines the length of the break signal.
|
||||
A zero value (the default) causes a break of between
|
||||
0.25 and 0.5 seconds to be sent;
|
||||
other values determine a period in a manner that will depend upon local
|
||||
community standards.
|
||||
\end{desc}
|
||||
|
||||
\defun{drain-tty}{[fd/port/fname]}{no-value}
|
||||
\begin{desc}
|
||||
The \var{fd/port/fname} parameter is an integer file descriptor or
|
||||
Scheme I/O port opened on a terminal device,
|
||||
or a file-name for a terminal device; it defaults to the current output port.
|
||||
|
||||
This procedure waits until all the output written to the
|
||||
terminal device has been transmitted to the device.
|
||||
If \var{fd/port/fname} is an output port with buffered I/O
|
||||
enabled, then the port's buffered characters are flushed before
|
||||
waiting for the device to drain.
|
||||
\end{desc}
|
||||
|
||||
\defun {flush-tty/input} {[fd/port/fname]}{no-value}
|
||||
\defunx{flush-tty/output}{[fd/port/fname]}{no-value}
|
||||
\defunx{flush-tty/both} {[fd/port/fname]}{no-value}
|
||||
\begin{desc}
|
||||
The \var{fd/port/fname} parameter is an integer file descriptor or
|
||||
Scheme I/O port opened on a terminal device,
|
||||
or a file-name for a terminal device; it defaults to the current input
|
||||
port (\ex{flush-tty/input} and \ex{flush-tty/both}),
|
||||
or output port (\ex{flush-tty/output}).
|
||||
|
||||
These procedures discard the unread input chars or unwritten
|
||||
output chars in the tty's kernel buffers.
|
||||
\end{desc}
|
||||
|
||||
\defun {start-tty-output}{[fd/port/fname]} {no-value}
|
||||
\defunx{stop-tty-output} {[fd/port/fname]} {no-value}
|
||||
\defunx{start-tty-input} {[fd/port/fname]} {no-value}
|
||||
\defunx{stop-tty-input} {[fd/port/fname]} {no-value}
|
||||
\begin{desc}
|
||||
These procedures can be used to control a terminal's input and output flow.
|
||||
The \var{fd/port/fname} parameter is an integer file descriptor or
|
||||
Scheme I/O port opened on a terminal device,
|
||||
or a file-name for a terminal device; it defaults to the current input
|
||||
or output port.
|
||||
|
||||
The \ex{stop-tty-output} and \ex{start-tty-output} procedures suspend
|
||||
and resume output from a terminal device.
|
||||
The \ex{stop-tty-input} and \ex{start-tty-input} procedures transmit
|
||||
the special STOP and START characters to the terminal with the intention
|
||||
of stopping and starting terminal input flow.
|
||||
\end{desc}
|
||||
|
||||
% --- Obsolete ---
|
||||
% \defun {encode-baud-rate}{speed}{code}
|
||||
% \defunx{decode-baud-rate}{code}{speed}
|
||||
% \begin{desc}
|
||||
% These procedures can be used to map between the special codes
|
||||
% that are legal values for the \ex{tty-info:input-speed} and
|
||||
% \ex{tty-info:output-speed} fields, and actual integer bits-per-second speeds.
|
||||
% The codes are the values bound to the
|
||||
% \ex{baud/4800}, \ex{baud/9600}, and other named constants defined above.
|
||||
% For example:
|
||||
% \begin{code}
|
||||
% (decode-baud-rate baud/9600) {\evalto} 9600
|
||||
%
|
||||
% ;;; These two expressions are identical:
|
||||
% (set-tty-info:input-speed ti baud/14400)
|
||||
% (set-tty-info:input-speed ti (encode-baud-rate 14400))\end{code}
|
||||
% \end{desc}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\subsection{Control terminals, sessions, and terminal process groups}
|
||||
|
||||
\defun{open-control-tty}{tty-name [flags]}{port}
|
||||
\begin{desc}
|
||||
This procedure opens terminal device \var{tty-name} as the process'
|
||||
control terminal
|
||||
(see the \ex{termios} man page for more information on control terminals).
|
||||
The \var{tty-name} argument is a file-name such as \ex{/dev/ttya}.
|
||||
The \var{flags} argument is a value suitable as the second argument
|
||||
to the \ex{open-file} call; it defaults to \ex{open/read+write}, causing
|
||||
the terminal to be opened for both input and output.
|
||||
|
||||
The port returned is an input port if the \var{flags} permit it,
|
||||
otherwise an output port.
|
||||
\RnRS/\scm/scsh do not have input/output ports,
|
||||
so it's one or the other.
|
||||
However, you can get both read and write ports open on a terminal
|
||||
by opening it read/write, taking the result input port,
|
||||
and duping it to an output port with \ex{dup->outport}.
|
||||
|
||||
This procedure guarantees to make the opened terminal the
|
||||
process' control terminal only if the process does not have
|
||||
an assigned control terminal at the time of the call.
|
||||
If the scsh process already has a control terminal, the results are undefined.
|
||||
|
||||
To arrange for the process to have no control terminal prior to calling
|
||||
this procedure, use the \ex{become-session-leader} procedure.
|
||||
|
||||
%\oops{The control terminal code was added just before release time
|
||||
% for scsh release 0.4. Control terminals are one of the less-standardised
|
||||
% elements of Unix. We can't guarantee that the terminal is definitely
|
||||
% attached as a control terminal; we were only able to test this out
|
||||
% on HP-UX. If you intend to use this feature on your OS, you should
|
||||
% test it out first. If your OS requires the use of the \ex{TIOCSCTTY}
|
||||
% \ex{ioctl}, uncomment the appropriate few lines of code in the
|
||||
% file \ex{tty1.c} and send us email.}
|
||||
\end{desc}
|
||||
|
||||
\defun{become-session-leader}{}{\integer}
|
||||
\begin{desc}
|
||||
This is the C \ex{setsid()} call.
|
||||
{\Posix} job-control has a three-level hierarchy:
|
||||
session/process-group/process.
|
||||
Every session has an associated control terminal.
|
||||
This procedure places the current process into a brand new session,
|
||||
and disassociates the process from any previous control terminal.
|
||||
You may subsequently use \ex{open-control-tty} to open a new control
|
||||
terminal.
|
||||
|
||||
It is an error to call this procedure if the current process is already
|
||||
a process-group leader.
|
||||
One way to guarantee this is not the case is only to call this procedure
|
||||
after forking.
|
||||
\end{desc}
|
||||
|
||||
|
||||
\defun {tty-process-group}{fd/port/fname}{\integer}
|
||||
\defunx{set-tty-process-group}{fd/port/fname pgrp}{\undefined}
|
||||
\begin{desc}
|
||||
This pair of procedures gets and sets the process group of a given
|
||||
terminal.
|
||||
\end{desc}
|
||||
|
||||
\defun{control-tty-file-name}{}{\str}
|
||||
\begin{desc}
|
||||
Return the file-name of the process' control tty.
|
||||
On every version of Unix of which we are aware, this is just the string
|
||||
\ex{"/dev/tty"}.
|
||||
However, this procedure uses the official Posix interface, so it is more
|
||||
portable than simply using a constant string.
|
||||
\end{desc}
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\subsection{Pseudo-terminals}
|
||||
Scsh implements an interface to Berkeley-style pseudo-terminals.
|
||||
|
||||
\defun{fork-pty-session}{thunk}{[process pty-in pty-out tty-name]}
|
||||
\begin{desc}
|
||||
This procedure gives a convenient high-level interface to pseudo-terminals.
|
||||
It first allocates a pty/tty pair of devices, and then forks a child
|
||||
to execute procedure \var{thunk}.
|
||||
In the child process
|
||||
\begin{itemize}
|
||||
\item Stdio and the current I/O ports are bound to the terminal device.
|
||||
\item The child is placed in its own, new session
|
||||
(see \ex{become\=session\=leader}).
|
||||
\item The terminal device becomes the new session's controlling terminal
|
||||
(see \ex{open-control-tty}).
|
||||
\item The \ex{(error-output-port)} is unbuffered.
|
||||
\end{itemize}
|
||||
|
||||
The \ex{fork-pty-session} procedure returns four values:
|
||||
the child's process object, two ports open on the controlling pty device,
|
||||
and the name of the child's corresponding terminal device.
|
||||
\end{desc}
|
||||
|
||||
\defun{open-pty}{}{pty-inport tty-name}
|
||||
\begin{desc}
|
||||
This procedure finds a free pty/tty pair, and opens the pty device
|
||||
with read/write access.
|
||||
It returns a port on the pty,
|
||||
and the name of the corresponding terminal device.
|
||||
|
||||
The port returned is an input port---Scheme doesn't allow input/output
|
||||
ports.
|
||||
However, you can easily use \ex{(dup->outport \var{pty-inport})}
|
||||
to produce a matching output port.
|
||||
You may wish to turn off I/O buffering for this output port.
|
||||
\end{desc}
|
||||
|
||||
|
||||
\defun {pty-name->tty-name}{pty-name}{tty-name}
|
||||
\defunx{tty-name->pty-name}{tty-name}{pty-name}
|
||||
\begin{desc}
|
||||
These two procedures map between corresponding terminal and pty controller
|
||||
names.
|
||||
For example,
|
||||
\begin{code}
|
||||
(pty-name->tty-name "/dev/ptyq3") {\evalto} "/dev/ttyq3"
|
||||
(tty-name->pty-name "/dev/ttyrc") {\evalto} "/dev/ptyrc"\end{code}
|
||||
|
||||
\remark{This is rather Berkeley-specific. SVR4 ptys are rare enough that
|
||||
I've no real idea if it generalises across the Unix gap. Experts
|
||||
are invited to advise. Users feel free to not worry---the predominance
|
||||
of current popular Unix systems use Berkeley ptys.}
|
||||
\end{desc}
|
||||
|
||||
\defunx{make-pty-generator}{}{\proc}
|
||||
\begin{desc}
|
||||
This procedure returns a generator of candidate pty names.
|
||||
Each time the returned procedure is called, it produces a
|
||||
new candidate.
|
||||
Software that wishes to search through the set of available ptys
|
||||
can use a pty generator to iterate over them.
|
||||
After producing all the possible ptys, a generator returns {\sharpf}
|
||||
every time it is called.
|
||||
Example:
|
||||
\begin{code}
|
||||
(define pg (make-pty-generator))
|
||||
(pg) {\evalto} "/dev/ptyp0"
|
||||
(pg) {\evalto} "/dev/ptyp1"
|
||||
\vdots
|
||||
(pg) {\evalto} "/dev/ptyqe"
|
||||
(pg) {\evalto} "/dev/ptyqf" \textit{(Last one)}
|
||||
(pg) {\evalto} {\sharpf}
|
||||
(pg) {\evalto} {\sharpf}
|
||||
\vdots\end{code}
|
||||
\end{desc}
|
||||
|
||||
|
||||
% Flag tables
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
% Control-chars indices
|
||||
%%%%%%%%%%%%%%%%%%%%%%%
|
||||
\begin{table}[p]
|
||||
\begin{center}
|
||||
\begin{tabular}{|lll|} \hline
|
||||
Scsh & C & Typical char \\
|
||||
\hline\hline
|
||||
{\Posix} & & \\
|
||||
\exi{ttychar/delete-char} & \ex{ERASE} & del \\
|
||||
\exi{ttychar/delete-line} & \ex{KILL} & \verb|^U| \\
|
||||
\exi{ttychar/eof} & \ex{EOF} & \verb|^D| \\
|
||||
\exi{ttychar/eol} & \ex{EOL} & \\
|
||||
\exi{ttychar/interrupt} & \ex{INTR} & \verb|^C| \\
|
||||
\exi{ttychar/quit} & \ex{QUIT} & \verb|^\| \\
|
||||
\exi{ttychar/suspend} & \ex{SUSP} & \verb|^Z| \\
|
||||
\exi{ttychar/start} & \ex{START} & \verb|^Q| \\
|
||||
\exi{ttychar/stop} & \ex{STOP} & \verb|^S| \\
|
||||
|
||||
\hline\hline
|
||||
{SVR4 and 4.3+BSD} & & \\
|
||||
\exi{ttychar/delayed-suspend} & \ex{DSUSP} & \verb|^Y| \\
|
||||
\exi{ttychar/delete-word} & \ex{WERASE} & \verb|^W| \\
|
||||
\exi{ttychar/discard} & \ex{DISCARD} & \verb|^O| \\
|
||||
\exi{ttychar/eol2} & \ex{EOL2} & \\
|
||||
\exi{ttychar/literal-next} & \ex{LNEXT} & \verb|^V| \\
|
||||
\exi{ttychar/reprint} & \ex{REPRINT} & \verb|^R| \\
|
||||
|
||||
\hline\hline
|
||||
{4.3+BSD} & & \\
|
||||
\exi{ttychar/status} & \ex{STATUS} & \verb|^T| \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
\caption{Indices into the \protect\ex{tty-info} record's
|
||||
\protect\var{control-chars} string,
|
||||
and the character traditionally found at each index.
|
||||
Only the indices for the {\Posix} entries are guaranteed to
|
||||
be non-\sharpf.}
|
||||
\label{table:ttychars}
|
||||
\end{table}
|
||||
|
||||
% Input flags
|
||||
%%%%%%%%%%%%%
|
||||
\begin{table}[p]
|
||||
\begin{center}\small
|
||||
\begin{tabular}{|lll|} \hline
|
||||
Scsh & C & Meaning \\
|
||||
\hline\hline
|
||||
\Posix & & \\
|
||||
\exi{ttyin/check-parity}
|
||||
& \ex{INPCK} & Check parity. \\
|
||||
\exi{ttyin/ignore-bad-parity-chars}
|
||||
& \ex{IGNPAR} & Ignore chars with parity errors. \\
|
||||
\exi{ttyin/mark-parity-errors}
|
||||
& \ex{PARMRK} & Insert chars to mark parity errors.\\
|
||||
\exi{ttyin/ignore-break}
|
||||
& \ex{IGNBRK} & Ignore breaks. \\
|
||||
\exi{ttyin/interrupt-on-break}
|
||||
& \ex{BRKINT} & Signal on breaks. \\
|
||||
\exi{ttyin/7bits}
|
||||
& \ex{ISTRIP} & Strip char to seven bits. \\
|
||||
\exi{ttyin/cr->nl}
|
||||
& \ex{ICRNL} & Map carriage-return to newline. \\
|
||||
\exi{ttyin/ignore-cr}
|
||||
& \ex{IGNCR} & Ignore carriage-returns. \\
|
||||
\exi{ttyin/nl->cr}
|
||||
& \ex{INLCR} & Map newline to carriage-return. \\
|
||||
\exi{ttyin/input-flow-ctl}
|
||||
& \ex{IXOFF} & Enable input flow control. \\
|
||||
\exi{ttyin/output-flow-ctl}
|
||||
& \ex{IXON} & Enable output flow control. \\
|
||||
|
||||
\hline\hline
|
||||
{SVR4 and 4.3+BSD} & & \\
|
||||
\exi{ttyin/xon-any} & \ex{IXANY} & Any char restarts after stop. \\
|
||||
\exi{ttyin/beep-on-overflow} & \ex{IMAXBEL} & Ring bell when queue full. \\
|
||||
|
||||
\hline\hline
|
||||
{SVR4} & & \\
|
||||
\exi{ttyin/lowercase} & \ex{IUCLC} & Map upper case to lower case. \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
\caption{Input-flags. These are the named flags for the \protect\ex{tty-info}
|
||||
record's \protect\var{input-flags} field.
|
||||
These flags generally control the processing of input chars.
|
||||
Only the {\Posix} entries are guaranteed to be non-\sharpf.
|
||||
}
|
||||
\label{table:ttyin}
|
||||
\end{table}
|
||||
|
||||
% Output flags
|
||||
%%%%%%%%%%%%%%
|
||||
\begin{table}[p]
|
||||
\begin{center}%\small
|
||||
\begin{tabular}{|lll|} \hline
|
||||
Scsh & C & Meaning \\ \hline\hline
|
||||
|
||||
\multicolumn{3}{|l|}{\Posix} \\
|
||||
\exi{ttyout/enable} & \ex{OPOST} & Enable output processing. \\
|
||||
|
||||
\hline\hline
|
||||
\multicolumn{3}{|l|}{SVR4 and 4.3+BSD} \\
|
||||
\exi{ttyout/nl->crnl} & \ex{ONLCR} & Map nl to cr-nl. \\
|
||||
|
||||
\hline\hline
|
||||
\multicolumn{3}{|l|}{4.3+BSD} \\
|
||||
\exi{ttyout/discard-eot} & \ex{ONOEOT} & Discard EOT chars. \\
|
||||
\exi{ttyout/expand-tabs} & \ex{OXTABS}\footnote{
|
||||
Note this is distinct from the SVR4-equivalent
|
||||
\ex{ttyout/tab-delayx} flag defined in
|
||||
table~\ref{table:ttydelays}.}
|
||||
& Expand tabs. \\
|
||||
|
||||
\hline\hline
|
||||
\multicolumn{3}{|l|}{SVR4} \\
|
||||
\exi{ttyout/cr->nl} & \ex{OCRNL} & Map cr to nl. \\
|
||||
\exi{ttyout/nl-does-cr} & \ex{ONLRET}& Nl performs cr as well. \\
|
||||
\exi{ttyout/no-col0-cr} & \ex{ONOCR} & No cr output in column 0. \\
|
||||
\exi{ttyout/delay-w/fill-char} & \ex{OFILL} & Send fill char to delay. \\
|
||||
\exi{ttyout/fill-w/del} & \ex{OFDEL} & Fill char is {\Ascii} DEL. \\
|
||||
\exi{ttyout/uppercase} & \ex{OLCUC} & Map lower to upper case. \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
\caption{Output-flags. These are the named flags for the \protect\ex{tty-info}
|
||||
record's \protect\var{output-flags} field.
|
||||
These flags generally control the processing of output chars.
|
||||
Only the {\Posix} entries are guaranteed to be non-\sharpf.}
|
||||
\label{table:ttyout}
|
||||
\end{table}
|
||||
|
||||
% Delay flags
|
||||
%%%%%%%%%%%%%
|
||||
\begin{table}[p]
|
||||
\begin{tabular}{r|ll|} \cline{2-3}
|
||||
& Value & Comment \\ \cline{2-3}
|
||||
{Backspace delay} & \exi{ttyout/bs-delay} & Bit-field mask \\
|
||||
& \exi{ttyout/bs-delay0} & \\
|
||||
& \exi{ttyout/bs-delay1} & \\
|
||||
|
||||
\cline{2-3}
|
||||
{Carriage-return delay} & \exi{ttyout/cr-delay} & Bit-field mask \\
|
||||
& \exi{ttyout/cr-delay0} & \\
|
||||
& \exi{ttyout/cr-delay1} & \\
|
||||
& \exi{ttyout/cr-delay2} & \\
|
||||
& \exi{ttyout/cr-delay3} & \\
|
||||
|
||||
\cline{2-3}
|
||||
{Form-feed delay} & \exi{ttyout/ff-delay} & Bit-field mask \\
|
||||
& \exi{ttyout/ff-delay0} & \\
|
||||
& \exi{ttyout/ff-delay1} & \\
|
||||
|
||||
\cline{2-3}
|
||||
{Horizontal-tab delay} & \exi{ttyout/tab-delay} & Bit-field mask \\
|
||||
& \exi{ttyout/tab-delay0} & \\
|
||||
& \exi{ttyout/tab-delay1} & \\
|
||||
& \exi{ttyout/tab-delay2} & \\
|
||||
& \exi{ttyout/tab-delayx} & Expand tabs \\
|
||||
|
||||
\cline{2-3}
|
||||
{Newline delay} & \exi{ttyout/nl-delay} & Bit-field mask \\
|
||||
& \exi{ttyout/nl-delay0} & \\
|
||||
& \exi{ttyout/nl-delay1} & \\
|
||||
|
||||
\cline{2-3}
|
||||
{Vertical tab delay} & \exi{ttyout/vtab-delay} & Bit-field mask \\
|
||||
& \exi{ttyout/vtab-delay0} & \\
|
||||
& \exi{ttyout/vtab-delay1} & \\
|
||||
|
||||
\cline{2-3}
|
||||
{All} & \exi{ttyout/all-delay} & Total bit-field mask \\
|
||||
\cline{2-3}
|
||||
\end{tabular}
|
||||
|
||||
\caption{Delay constants. These are the named flags for the
|
||||
\protect\ex{tty-info} record's \protect\var{output-flags} field.
|
||||
These flags control the output delays associated with printing
|
||||
special characters.
|
||||
They are non-{\Posix}, and have non-{\sharpf} values
|
||||
only on SVR4 systems.}
|
||||
\label{table:ttydelays}
|
||||
\end{table}
|
||||
|
||||
% Control flags
|
||||
%%%%%%%%%%%%%%%
|
||||
\begin{table}[p]
|
||||
\begin{center}%\small
|
||||
\begin{tabular}{|lll|} \hline
|
||||
Scsh & C & Meaning \\
|
||||
|
||||
\hline\hline
|
||||
\multicolumn{3}{|l|}{\Posix} \\
|
||||
\exi{ttyc/char-size} & \ex{CSIZE} & Character size mask \\
|
||||
\exi{ttyc/char-size5} & \ex{CS5} & 5 bits \\
|
||||
\exi{ttyc/char-size6} & \ex{CS6} & 6 bits \\
|
||||
\exi{ttyc/char-size7} & \ex{CS7} & 7 bits \\
|
||||
\exi{ttyc/char-size8} & \ex{CS8} & 8 bits \\
|
||||
\exi{ttyc/enable-parity}& \ex{PARENB} & Generate and detect parity. \\
|
||||
\exi{ttyc/odd-parity} & \ex{PARODD} & Odd parity. \\
|
||||
\exi{ttyc/enable-read} & \ex{CREAD} & Enable reception of chars. \\
|
||||
\exi{ttyc/hup-on-close} & \ex{HUPCL} & Hang up on last close. \\
|
||||
\exi{ttyc/no-modem-sync}& \ex{LOCAL} & Ignore modem lines. \\
|
||||
\exi{ttyc/2-stop-bits} & \ex{CSTOPB} & Send two stop bits. \\
|
||||
|
||||
\hline\hline
|
||||
\multicolumn{3}{|l|}{4.3+BSD} \\
|
||||
\exi{ttyc/ignore-flags} & \ex{CIGNORE} & Ignore control flags. \\
|
||||
\exi{ttyc/CTS-output-flow-ctl} & \verb|CCTS_OFLOW| & CTS flow control of output \\
|
||||
\exi{ttyc/RTS-input-flow-ctl} & \verb|CRTS_IFLOW| & RTS flow control of input \\
|
||||
\exi{ttyc/carrier-flow-ctl} & \ex{MDMBUF} & \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
\caption{Control-flags. These are the named flags for the \protect\ex{tty-info}
|
||||
record's \protect\var{control-flags} field.
|
||||
These flags generally control the details of the terminal's
|
||||
serial line.
|
||||
Only the {\Posix} entries are guaranteed to be non-\sharpf.}
|
||||
\label{table:ttyctl}
|
||||
\end{table}
|
||||
|
||||
% Local flags
|
||||
%%%%%%%%%%%%%
|
||||
\begin{table}[p]
|
||||
\begin{center}\small
|
||||
\begin{tabular}{|lll|} \hline
|
||||
Scsh & C & Meaning \\
|
||||
|
||||
\hline\hline
|
||||
\multicolumn{3}{|l|}{\Posix} \\
|
||||
\exi{ttyl/canonical} & \ex{ICANON} & Canonical input processing. \\
|
||||
\exi{ttyl/echo} & \ex{ECHO} & Enable echoing. \\
|
||||
\exi{ttyl/echo-delete-line} & \ex{ECHOK} & Echo newline after line kill. \\
|
||||
\exi{ttyl/echo-nl} & \ex{ECHONL} & Echo newline even if echo is off. \\
|
||||
\exi{ttyl/visual-delete}& \ex{ECHOE} & Visually erase chars. \\
|
||||
\exi{ttyl/enable-signals} & \ex{ISIG} & Enable \verb|^|C, \verb|^|Z signalling. \\
|
||||
\exi{ttyl/extended} & \ex{IEXTEN} & Enable extensions. \\
|
||||
\exi{ttyl/no-flush-on-interrupt}
|
||||
& \ex{NOFLSH} & Don't flush after interrupt. \\
|
||||
\exi{ttyl/ttou-signal} & \ex{ITOSTOP} & \ex{SIGTTOU} on background output. \\
|
||||
|
||||
\hline\hline
|
||||
\multicolumn{3}{|l|}{SVR4 and 4.3+BSD} \\
|
||||
\exi{ttyl/echo-ctl} & \ex{ECHOCTL}
|
||||
& Echo control chars as ``\verb|^X|''. \\
|
||||
\exi{ttyl/flush-output} & \ex{FLUSHO} & Output is being flushed. \\
|
||||
\exi{ttyl/hardcopy-delete} & \ex{ECHOPRT} & Visual erase for hardcopy. \\
|
||||
\exi{ttyl/reprint-unread-chars} & \ex{PENDIN} & Retype pending input. \\
|
||||
\exi{ttyl/visual-delete-line} & \ex{ECHOKE} & Visually erase a line-kill. \\
|
||||
|
||||
\hline\hline
|
||||
\multicolumn{3}{|l|}{4.3+BSD} \\
|
||||
\exi{ttyl/alt-delete-word} & \ex{ALTWERASE} & Alternate word erase algorithm \\
|
||||
\exi{ttyl/no-kernel-status} & \ex{NOKERNINFO} & No kernel status on \verb|^T|. \\
|
||||
|
||||
\hline\hline
|
||||
\multicolumn{3}{|l|}{SVR4} \\
|
||||
\exi{ttyl/case-map} & \ex{XCASE} & Canonical case presentation \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
\caption{Local-flags. These are the named flags for the \protect\ex{tty-info}
|
||||
record's \protect\var{local-flags} field.
|
||||
These flags generally control the details of the line-editting
|
||||
user interface.
|
||||
Only the {\Posix} entries are guaranteed to be non-\sharpf.}
|
||||
\label{table:ttylocal}
|
||||
\end{table}
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
%&latex -*- latex -*-
|
||||
|
||||
% This is the reference manual for the Scheme Shell.
|
||||
|
||||
\documentclass[twoside]{report}
|
||||
\usepackage{code,boxedminipage,draftfooters,makeidx,palatino,ct,
|
||||
headings,mantitle,array,matter,a4,tex2page}
|
||||
|
||||
% Style issues
|
||||
\parskip = 3pt plus 3pt
|
||||
\sloppy
|
||||
|
||||
\input{decls}
|
||||
\makeindex
|
||||
%%% End preamble
|
||||
|
||||
\begin{document}
|
||||
|
||||
\frontmatter
|
||||
\include{front}
|
||||
|
||||
\mainmatter
|
||||
\include{intro}
|
||||
\include{procnotation}
|
||||
\include{syscalls}
|
||||
\include{network}
|
||||
\include{strings}
|
||||
\include{rdelim}
|
||||
\include{awk}
|
||||
\include{miscprocs}
|
||||
\include{running}
|
||||
\include{changes}
|
||||
\include{todo}
|
||||
|
||||
\backmatter
|
||||
\printindex
|
||||
|
||||
\end{document}
|
||||
|
|
@ -0,0 +1 @@
|
|||
html
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
.SUFFIXES: .idx .ind .tex .dvi .ps .pdf $(.SUFFIXES)
|
||||
|
||||
TEX= headings.tex scsh-paper.tex
|
||||
|
||||
TEX2PAGE=tex2page
|
||||
|
||||
scsh-paper.dvi: $(TEX)
|
||||
scsh-paper.pdf: $(TEX)
|
||||
|
||||
.dvi.ps:
|
||||
dvips -j0 -o $@ $<
|
||||
|
||||
.tex.dvi:
|
||||
latex $< && latex $<
|
||||
rm $*.log
|
||||
|
||||
.tex.pdf:
|
||||
pdflatex $< && thumbpdf $@ && pdflatex $<
|
||||
rm $*.log
|
||||
|
||||
.idx.ind:
|
||||
makeindex $<
|
||||
|
||||
clean:
|
||||
-rm -f *.log *.png scsh-paper.out scsh-paper.dvi scsh-paper.ps scsh-paper.pdf thumb*.png
|
||||
rm -rf html
|
||||
|
||||
INSTALL_DATA= install -c -m 644
|
||||
|
||||
|
||||
html: $(TEX)
|
||||
$(TEX2PAGE) scsh-paper && $(TEX2PAGE) scsh-paper
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
% boxedminipage.sty
|
||||
%
|
||||
% adds the boxedminipage environment---just like minipage, but has a
|
||||
% box round it!
|
||||
%
|
||||
% The thickneess of the rules around the box is controlled by
|
||||
% \fboxrule, and the distance between the rules and the edges of the
|
||||
% inner box is governed by \fboxsep.
|
||||
%
|
||||
% This code is based on Lamport's minipage code.
|
||||
|
||||
\def\boxedminipage{\@ifnextchar [{\@iboxedminipage}{\@iboxedminipage[c]}}
|
||||
|
||||
\def\@iboxedminipage[#1]#2{\leavevmode \@pboxswfalse
|
||||
\if #1b\vbox
|
||||
\else \if #1t\vtop
|
||||
\else \ifmmode \vcenter
|
||||
\else \@pboxswtrue $\vcenter
|
||||
\fi
|
||||
\fi
|
||||
\fi\bgroup % start of outermost vbox/vtop/vcenter
|
||||
\hsize #2
|
||||
\hrule\@height\fboxrule
|
||||
\hbox\bgroup % inner hbox
|
||||
\vrule\@width\fboxrule \hskip\fboxsep \vbox\bgroup % innermost vbox
|
||||
\advance\hsize -2\fboxrule \advance\hsize-2\fboxsep
|
||||
\textwidth\hsize \columnwidth\hsize
|
||||
\@parboxrestore
|
||||
\def\@mpfn{mpfootnote}\def\thempfn{\thempfootnote}\c@mpfootnote\z@
|
||||
\let\@footnotetext\@mpfootnotetext
|
||||
\let\@listdepth\@mplistdepth \@mplistdepth\z@
|
||||
\@minipagerestore\@minipagetrue
|
||||
\everypar{\global\@minipagefalse\everypar{}}}
|
||||
|
||||
\def\endboxedminipage{%
|
||||
\par\vskip-\lastskip
|
||||
\ifvoid\@mpfootins\else
|
||||
\vskip\skip\@mpfootins\footnoterule\unvbox\@mpfootins\fi
|
||||
\egroup % ends the innermost \vbox
|
||||
\hskip\fboxsep \vrule\@width\fboxrule
|
||||
\egroup % ends the \hbox
|
||||
\hrule\@height\fboxrule
|
||||
\egroup% ends the vbox/vtop/vcenter
|
||||
\if@pboxsw $\fi}
|
||||
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
% code.sty: -*- latex -*-
|
||||
% Latex macros for a "weak" verbatim mode.
|
||||
% -- like verbatim, except \, {, and } have their usual meanings.
|
||||
|
||||
% Environments: code, tightcode, codeaux, codebox, centercode
|
||||
% Commands: \dcd, \cddollar, \cdmath, \cd, \codeallowbreaks, \codeskip, \^
|
||||
% Already defined in LaTeX, but of some relevance: \#, \$, \%, \&, \_, \{, \}
|
||||
|
||||
% Changelog at the end of the file.
|
||||
|
||||
% These commands give you an environment, code, that is like verbatim
|
||||
% except that you can still insert commands in the middle of the environment:
|
||||
% \begin{code}
|
||||
% for(x=1; x<loop_bound; x++)
|
||||
% y += x^3; /* {\em Add in {\tt x} cubed} */
|
||||
% \end{code}
|
||||
%
|
||||
% All characters are ordinary except \{}. To get \{} in your text,
|
||||
% you use the commands \\, \{, and \}.
|
||||
|
||||
% These macros mess with the definition of the special chars (e.g., ^_~%).
|
||||
% The characters \{} are left alone, so you can still have embedded commands:
|
||||
% \begin{code} f(a,b,\ldots,y,z) \end{code}
|
||||
% However, if your embedded commands use the formerly-special chars, as in
|
||||
% \begin{code} x := x+1 /* \mbox{\em This is $y^3$} */ \end{code}
|
||||
% then you lose. The $ and ^ chars are scanned in as non-specials,
|
||||
% so they don't work. If the chars are scanned *outside* the code env,
|
||||
% then you have no problem:
|
||||
% \def\ycube{$y^3$}
|
||||
% \begin{code} x := x+1 /* {\em This is \ycube} */ \end{code}
|
||||
% If you must put special chars inside the code env, you do it by
|
||||
% prefixing them with the special \dcd ("decode") command, that
|
||||
% reverts the chars to back to special status:
|
||||
% \begin{code} x := x+1 /* {\dcd\em This is $y^3$} */ \end{code}
|
||||
% \dcd's scope is bounded by its enclosing braces. It is only defined within
|
||||
% the code env. You can also turn on just $ with the \cddollar command;
|
||||
% you can turn on just $^_ with the \cdmath command. See below.
|
||||
%
|
||||
% Alternatively, just use \(...\) for $...$, \sp for ^, and \sb for _.
|
||||
|
||||
% WARNING:
|
||||
% Like \verb, you cannot put a \cd{...} inside an argument to a macro
|
||||
% or a command. If you try, for example,
|
||||
% \mbox{\cd{$x^y$}}
|
||||
% you will lose. That is because the text "\cd{$x^y$}" gets read in
|
||||
% as \mbox's argument before the \cd executes. But the \cd has to
|
||||
% have a chance to run before LaTeX ever reads the $x^y$ so it can
|
||||
% turn off the specialness of $ and ^. So, \cd has to appear at
|
||||
% top level, not inside an argument. Similarly, you can't have
|
||||
% a \cd or a \code inside a macro (Although you could use \gdef to
|
||||
% define a macro *inside* a \cd, which you could then use outside.
|
||||
% Don't worry about this if you don't understand it.)
|
||||
|
||||
% BUG: In the codebox env, the effect of a \dcd, \cddollar, or \cdmath
|
||||
% command is reset at the end of each line. This can be hacked by
|
||||
% messing with the \halign's preamble, if you feel up to it.
|
||||
|
||||
% Useage note: the initial newline after the \begin{code} or
|
||||
% \begin{codebox} is eaten, but the last newline is not.
|
||||
% So,
|
||||
% \begin{code}
|
||||
% foo
|
||||
% bar
|
||||
% \end{code}
|
||||
% leaves one more blank line after bar than does
|
||||
% \begin{code}
|
||||
% foo
|
||||
% bar\end{code}
|
||||
% Moral: get in the habit of terminating code envs without a newline
|
||||
% (as in the second example).
|
||||
%
|
||||
|
||||
% All this stuff tweaks the meaning of space, tab, and newline.
|
||||
%===============================================================================
|
||||
% \cd@obeyspaces
|
||||
% Turns all spaces into non-breakable spaces.
|
||||
% Note: this is like \@vobeyspaces except without spurious space in defn.
|
||||
% @xobeysp is basically a space; it's defined in latex.tex.
|
||||
%
|
||||
{\catcode`\ =\active\gdef\cd@obeyspaces{\catcode`\ =\active\let =\@xobeysp}}
|
||||
|
||||
|
||||
|
||||
% \cd@obeytabs
|
||||
% Turns all tabs into 8 non-breakable spaces (which is bogus).
|
||||
%
|
||||
{\catcode`\^^I=\active %
|
||||
\gdef\cd@obeytabs{\catcode`\^^I=\active\let^^I=\cd@tab}}
|
||||
|
||||
\def\cd@tab{\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp}
|
||||
|
||||
|
||||
|
||||
% \cd@obeylines
|
||||
% Turns all cr's into linebreaks. Pagebreaks are not permitted between lines.
|
||||
% This is copied from lplain.tex's \obeylines, with the cr def'n changed.
|
||||
%
|
||||
{\catcode`\^^M=\active % these lines must end with %
|
||||
\gdef\cd@obeylines{\catcode`\^^M=\active\let^^M=\cd@cr}}
|
||||
|
||||
% What ^M turns into. This def'n keeps blank lines from being compressed out.
|
||||
\def\cd@cr{\par\penalty10000\leavevmode} % TeX magicness
|
||||
%\def\cd@cr{\par\penalty10000\mbox{}} % LaTeX
|
||||
|
||||
|
||||
% \codeallowbreaks
|
||||
% Same as \cd@obeylines, except pagebreaks are allowed.
|
||||
% Put this command inside a code env to allow pagebreaks.
|
||||
|
||||
{\catcode`\^^M=\active % these lines must end with %
|
||||
\gdef\codeallowbreaks{\catcode`\^^M\active\let^^M\cd@crbr}}
|
||||
|
||||
%\def\cd@crbr{\leavevmode\endgraf} % What ^M turns into.
|
||||
\def\cd@crbr{\par\leavevmode} % What ^M turns into.
|
||||
|
||||
|
||||
% \cd@obeycrsp
|
||||
% Turns cr's into non-breakable spaces. Used by \cd.
|
||||
|
||||
{\catcode`\^^M=\active % these lines must end with %
|
||||
\gdef\cd@obeycrsp{\catcode`\^^M=\active\let^^M=\@xobeysp}}
|
||||
|
||||
% =============================================================================
|
||||
|
||||
% Set up code environment, in which most of the common special characters
|
||||
% appearing in code are treated verbatim, namely: $&#^_~%
|
||||
% \ { } are still enabled so that macros can be called in this
|
||||
% environment. Use \\, \{, and \} to use these characters verbatim
|
||||
% in this environment.
|
||||
%
|
||||
% Inside a group, you can make
|
||||
% all the hacked chars special with the \dcd command
|
||||
% $ special with the \cddollar command
|
||||
% $^_ special with the \cdmath command.
|
||||
% If you have a bunch of math $..$'s in your code env, then a global \cddollar
|
||||
% or \cdmath at the beginning of the env can save a lot of trouble.
|
||||
% When chars are special (e.g., after a \dcd), you can still get #$%&_{} with
|
||||
% \#, \$, \%, \&, \_, \{, and \} -- this is standard LaTeX.
|
||||
% Additionally, \\ gives \ inside the code env, and when \cdmath
|
||||
% makes ^ special, it also defines \^ to give ^.
|
||||
|
||||
%The hacked characters can be made special again
|
||||
% within a group by using the \dcd command.
|
||||
|
||||
% Note: this environment allows no breaking of lines whatsoever; not
|
||||
% at spaces or hypens. To arrange for a break use the standard \- command,
|
||||
% or a \discretionary{}{}{} which breaks, but inserts nothing. This is useful,
|
||||
% for example for allowing hypenated identifiers to be broken, e.g.
|
||||
% \def\={\discretionary{}{}{}} %optional break
|
||||
% FOO-\=BAR.
|
||||
|
||||
\def\setupcode{\parsep=0pt\parindent=0pt%
|
||||
\normalfont\ttfamily\frenchspacing\catcode``=13\@noligs%
|
||||
\def\\{\char`\\}%
|
||||
\let\dcd=\cd@dcd\let\cddollar=\cd@dollarspecial\let\cdmath=\cd@mathspecial%
|
||||
\@makeother\$\@makeother\&\@makeother\#%
|
||||
\@makeother\^\@makeother\_\@makeother\~%
|
||||
\@makeother\%\cd@obeytabs\cd@obeyspaces}
|
||||
% other: $&#^_~%
|
||||
% left special: \{}
|
||||
% unnecessary: @`'"
|
||||
|
||||
|
||||
%% codebox, centercode
|
||||
%%=============================================================================
|
||||
%% The codebox env makes a box exactly as wide as it needs to be
|
||||
%% (i.e., as wide as the longest line of code is). This is useful
|
||||
%% if you want to center a chunk of code, or flush it right, or
|
||||
%% something like that. The optional argument to the environment,
|
||||
%% [t], [c], or [b], specifies how to vertically align the codebox,
|
||||
%% just as with arrays or other boxes. Default is [c].
|
||||
|
||||
%% Must be a newline immediately after "\begin{codebox}[t]"!
|
||||
|
||||
{\catcode`\^^M=\active % these lines must end with %
|
||||
\gdef\cd@obeycr{\catcode`\^^M=\active\let^^M=\cr}}
|
||||
|
||||
% If there is a [<letter>] option, then the following newline will
|
||||
% be read *after* ^M is bound to \cr, so we're cool. If there isn't
|
||||
% an option given (i.e., default to [c]), then the @\ifnextchar will
|
||||
% gobble up the newline as it gobbles whitespace. So we insert the
|
||||
% \cr explicitly. Isn't TeX fun?
|
||||
\def\codebox{\leavevmode\@ifnextchar[{\@codebox}{\@codebox[c]\cr}} %]
|
||||
|
||||
\def\@codebox[#1]%
|
||||
{\hbox\bgroup$\if #1t\vtop \else \if#1b\vbox \else \vcenter \fi\fi\bgroup%
|
||||
\tabskip\z@\setupcode\cd@obeycr% just before cd@obey
|
||||
\halign\bgroup##\hfil\span}
|
||||
|
||||
\def\endcodebox{\crcr\egroup\egroup\m@th$\egroup}
|
||||
|
||||
% Center the box on the page:
|
||||
\newenvironment{centercode}%
|
||||
{\begin{center}\begin{codebox}[c]}%
|
||||
{\end{codebox}\end{center}}
|
||||
|
||||
|
||||
%% code, codeaux, tightcode
|
||||
%%=============================================================================
|
||||
%% Code environment as described above. Lines are kept on one page.
|
||||
%% This actually works by setting a huge penalty for breaking
|
||||
%% between lines of code. Code is indented same as other displayed paras.
|
||||
%% Note: to increase left margin, use \begin{codeaux}{\leftmargin=1in}.
|
||||
|
||||
% To allow pagebreaks, say \codeallowbreaks immediately inside the env.
|
||||
% You can allow breaks at specific lines with a \pagebreak form.
|
||||
|
||||
%% N.B.: The \global\@ignoretrue command must be performed just inside
|
||||
%% the *last* \end{...} before the following text. If not, you will
|
||||
%% get an extra space on the following line. Blech.
|
||||
|
||||
%% This environment takes two arguments.
|
||||
%% The second, required argument is the \list parameters to override the
|
||||
%% \@listi... defaults.
|
||||
%% - Usefully set by clients: \topsep \leftmargin
|
||||
%% - Possible, but less useful: \partopsep
|
||||
%% The first, optional argument is the extra \parskip glue that you get around
|
||||
%% \list environments. It defaults to the value of \parskip.
|
||||
\def\codeaux{\@ifnextchar[{\@codeaux}{\@codeaux[\parskip]}} %]
|
||||
\def\@codeaux[#1]#2{%
|
||||
\bgroup\parskip#1%
|
||||
\begin{list}{}%
|
||||
{\parsep\z@\rightskip\z@\listparindent\z@\itemindent\z@#2}%
|
||||
\item[]\setupcode\cd@obeylines}%
|
||||
\def\endcodeaux{\end{list}\leavevmode\egroup\ignorespaces\global\@ignoretrue}
|
||||
|
||||
%% Code env is codeaux with the default margin and spacing \list params:
|
||||
\def\code{\codeaux{}} \let\endcode=\endcodeaux
|
||||
|
||||
%% Like code, but with no extra vertical space above and below.
|
||||
\def\tightcode{\codeaux[=0pt]{\topsep\z@}}%
|
||||
\let\endtightcode\endcodeaux
|
||||
% {\vspace{-1\parskip}\begin{codeaux}{\partopsep\z@\topsep\z@}}%
|
||||
% {\end{codeaux}\vspace{-1\parskip}}
|
||||
|
||||
|
||||
|
||||
% Reasonable separation between lines of code
|
||||
\newcommand{\codeskip}{\penalty0\vspace{2ex}}
|
||||
|
||||
|
||||
% \cd is used to build a code environment in the middle of text.
|
||||
% Note: only difference from display code is that cr's are taken
|
||||
% as unbreakable spaces instead of linebreaks.
|
||||
|
||||
\def\cd{\leavevmode\begingroup\ifmmode\let\startcode=\startmcode\else%
|
||||
\let\startcode\starttcode\fi%
|
||||
\setupcode\cd@obeycrsp\startcode}
|
||||
|
||||
\def\starttcode#1{#1\endgroup}
|
||||
\def\startmcode#1{\hbox{#1}\endgroup}
|
||||
|
||||
|
||||
% Restore $&#^_~% to their normal catcodes
|
||||
% Define \^ to give the ^ char.
|
||||
% \dcd points to this guy inside a code env.
|
||||
\def\cd@dcd{\catcode`\$=3\catcode`\&=4\catcode`\#=6\catcode`\^=7%
|
||||
\catcode`\_=8\catcode`\~=13\catcode`\%=14\def\^{\char`\^}}
|
||||
|
||||
% Selectively enable $, and $^_ as special.
|
||||
% \cd@mathspecial also defines \^ give the ^ char.
|
||||
% \cddollar and \cdmath point to these guys inside a code env.
|
||||
\def\cd@dollarspecial{\catcode`\$=3}
|
||||
\def\cd@mathspecial{\catcode`\$=3\catcode`\^=7\catcode`\_=8%
|
||||
\def\^{\char`\^}}
|
||||
|
||||
|
||||
% Change log:
|
||||
% Started off as some macros found in C. Rich's library.
|
||||
% Olin 1/90:
|
||||
% Removed \makeatletter, \makeatother's -- they shouldn't be there,
|
||||
% because style option files are read with makeatletter. The terminal
|
||||
% makeatother screwed things up for the following style options.
|
||||
% Olin 3/91:
|
||||
% Rewritten.
|
||||
% - Changed things so blank lines don't get compressed out (the \leavevmove
|
||||
% in \cd@cr and \cd@crwb).
|
||||
% - Changed names to somewhat less horrible choices.
|
||||
% - Added lots of doc, so casual hackers can more easily mess with all this.
|
||||
% - Removed `'"@ from the set of hacked chars, since they are already
|
||||
% non-special.
|
||||
% - Removed the bigcode env, which effect can be had with the \codeallowbreaks
|
||||
% command.
|
||||
% - Removed the \@noligs command, since it's already defined in latex.tex.
|
||||
% - Win big with the new \dcd, \cddollar, and \cdmath commands.
|
||||
% - Now, *only* the chars \{} are special inside the code env. If you need
|
||||
% more, use the \dcd command inside a group.
|
||||
% - \cd now works inside math mode. (But if you use it in a superscript,
|
||||
% it still comes out full size. You must explicitly put a \scriptsize\tt
|
||||
% inside the \cd: $x^{\cd{\scriptsize\tt...}}$. A \leavevmode was added
|
||||
% so that if you begin a paragraph with a \cd{...}, TeX realises you
|
||||
% are starting a paragraph.
|
||||
% - Added the codebox env. Tricky bit involving the first line hacked
|
||||
% with help from David Long.
|
||||
% Olin 8/94
|
||||
% Changed the font commands for LaTeX2e.
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
% css.t2p
|
||||
% Dorai Sitaram
|
||||
% 19 Jan 2001
|
||||
% A basic style for HTML documents generated
|
||||
% with tex2page.
|
||||
|
||||
\ifx\shipout\UNDEFINED
|
||||
\cssblock
|
||||
|
||||
body {
|
||||
color: black;
|
||||
/* background-color: #e5e5e5;*/
|
||||
background-color: #ffffff;
|
||||
/*background-color: beige;*/
|
||||
margin-top: 2em;
|
||||
margin-left: 8%;
|
||||
margin-right: 8%;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
.partheading {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.chapterheading {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
ol ol {
|
||||
list-style-type: lower-alpha;
|
||||
}
|
||||
|
||||
ol ol ol {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
|
||||
ol ol ol ol {
|
||||
list-style-type: upper-alpha;
|
||||
}
|
||||
|
||||
.scheme {
|
||||
color: brown;
|
||||
}
|
||||
|
||||
.scheme .keyword {
|
||||
color: #990000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.scheme .builtin {
|
||||
color: #990000;
|
||||
}
|
||||
|
||||
.scheme .variable {
|
||||
color: navy;
|
||||
}
|
||||
|
||||
.scheme .global {
|
||||
color: purple;
|
||||
}
|
||||
|
||||
.scheme .selfeval {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.scheme .comment {
|
||||
color: teal;
|
||||
}
|
||||
|
||||
.schemeresponse {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.navigation {
|
||||
color: red;
|
||||
text-align: right;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.disable {
|
||||
/* color: #e5e5e5; */
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.smallcaps {
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
.smallprint {
|
||||
color: gray;
|
||||
font-size: 75%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.smallprint hr {
|
||||
text-align: left;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
\endcssblock
|
||||
\fi
|
||||
|
||||
% ex:ft=css
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
% Loads cmtt fonts in on \tt. -*- latex -*-
|
||||
% I prefer these to the Courier fonts that latex gives you w/postscript styles.
|
||||
% Courier is too spidery and too wide -- it's hard to get 80 chars on a line.
|
||||
% -Olin
|
||||
|
||||
\renewcommand{\ttdefault}{cmtt}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue