Compare commits

..

2 Commits

Author SHA1 Message Date
olin-shivers 838b110f01 Integrated srfi-13 (string lib)& srfi-14 (char-set lib)
- Ported sources to use these libs instead of older string & cset libs
- Wrote backwards-compatibility libs for now-deprecated procs in the
  scsh API
- Hacked the makefile/package/interfaces glue
Whew.
2001-03-11 03:47:00 +00:00
bdc e5a2148d4a scsh 0.4.x prerelease 1995-10-14 03:34:21 +00:00
52 changed files with 1992 additions and 3396 deletions

149
RELEASE
View File

@ -9,6 +9,12 @@ release 0.5.3. (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).)
This release is the first new release of scsh in over a year. We've been
using it, and have had no problems. However, we only recommend eager users
download it. We'll upgrade it to a 0.5.3 release after a week or two, when
this release has been shaken out.
* Contents
==========
What is scsh
@ -21,7 +27,6 @@ The World-Wide What?
New in this release
Scsh is now "open source."
Scsh is now on Win32
Scsh is now on Mac OS X
CVS repository will be public-readable
New char-sets and char-set operations
New regular expression system
@ -34,8 +39,7 @@ Thanks
* What is scsh
==============
Scsh is a broad-spectrum systems-programming environment for Unix embedded
in R4RS Scheme. It has an open-source copyright, and runs on most major
Unix systems.
in R4RS Scheme.
** Scsh as a scripting language
-------------------------------
@ -103,12 +107,12 @@ Unix platforms. We currently have scsh implementations for:
IRIX
Linux
NetBSD
NeXTStep
Solaris
SunOS
Ultrix
Win32
Darwin/Mac OS X
Scsh code should run without change across these systems.
Porting to new platforms is usually not difficult.
@ -149,56 +153,74 @@ at MIT.
Bugs can be reported to
scsh-bugs@zurich.ai.mit.edu
or via the Scsh project's bugs section on SourceForge:
http://sourceforge.net/projects/scsh/
If you do not netnews hierarchy, or wish to join the mailing
If you do not receive the alt netnews hierarchy, or wish to join the mailing
list for other reasons, send mail to
scsh-request@zurich.ai.mit.edu
* The World-Wide What?
======================
We even have one of those dot-com cyberweb things:
http://www.swiss.ai.mit.edu/ftpdir/scsh/
We now manage the project using SourceForge:
http://sourceforge.net/projects/scsh/
We even have one of those URL things:
http://www-swiss.ai.mit.edu/scsh/
* New in this release
=====================
** Scsh is now "open source."
We finally got around to tacking an ideologically hip copyright
onto the source. (Not that we ever cared before what you did with
the system...) The Scheme 48 authors have also graciously retrofitted
a BSD-style open-source copyright onto the underlying Scheme 48 0.36
platform for us. The whole system is now open source, top-to-bottom.
Take all the code you like; we'll just write more.
** Scsh is now on Win32
Scsh will now build and run using Cygwin 1.1. This was tested
on Windows NT 4.0 and Windows 2000, but presumably things could work
on other Cygwin platforms such as Win95 or Win98. Cygwin is available
from:
Scsh will now build and run using Cygwin B20.1. This was only tested
on Windows NT 4.0, but presumably things could work on other Cygwin
platforms such as Win95 or Win98. Cygwin is available from:
http://sourceware.cygnus.com/cygwin/
** Scsh is now on Mac OS X
Scsh does now support Darwin and thus Mac OS X. This was simply
achived by treating Darwin as a BSD platform.
** CVS repository will be public-readable
We will add further information to the web-site as soon as possible.
** CVS repository is now publically accessable
The scsh sources have moved to scsh.sourceforge.net, and the
the CVS repository is publically readable. Here's the magic:
** New char-sets and char-set operations
See the manual for more information on using character sets
for text processing. Also, see the ccp package in scsh/scsh/lib
for a new library providing character->character partial maps,
which are also useful for general string processing.
cvs -d:pserver:anonymous@cvs.scsh.sourceforge.net:/cvsroot/scsh co scsh
cvs -d:pserver:anonymous@cvs.scsh.sourceforge.net:/cvsroot/scsh co scsh-0.6
** New regular expression system
There's a whole new regexp package in scsh. There's a new,
s-expression-based notation for regexps, called SRE's. The new
notation has been integrated into the AWK macro and field-parser functions.
The older Posix notation is still supported for backwards compatibility.
There's a whole chapter on regexps in the new manual; it has full details.
(The 0.6 source tree builds with a modern Scheme 48 and thread support.
It has not been released.)
The previous AWK and field-reader system is provided in a
backwards-compatibility package. See package obsolete-awk-package
in scsh-package.scm.
** New libraries
Scsh now provides the SRFI-1, SRFI-13 and SRFI-14 libraries, giving
portable support for list, string and character-set operations.
The SRFI-1 list library is available, in the list-lib package.
There is a large, powerful string-processing library available
in the string-lib package. See the directory scsh/scsh/lib/ for
documentation and source.
These libraries make basic list and string hacking very straightforward.
** Database access via ODBC
Brian Carlstrom, Sam Thiebault and Olin Shivers have designed and
implemented a portable interface to relational databases. The code
back-ends to ODBC drivers for portability.
** Renaming
We are shifting from a reduce-foo convention to a more standard
foo-fold convention. This has caused the following renamings:
reduce-char-set => char-set-fold
reduce-port => port-fold
The older names are still bound, but are deprecated and will likely
go away in a future release.
String utilities INDEX and RINDEX are gone. Use the string-lib procedures
instead.
** Bugfixes
Over a year's worth of bug fixes. In particular, the old problems with the
@ -213,25 +235,54 @@ 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.
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
Alan Bawden
Jim Blandy
Per Bothner
Tom Breton
Christopher Browne
Sean Doran
Ray Dillinger
Allyn Dimock
Scott Draves
Lutz Euler
Kevin Esler
Jeremy Fitzhardinge
Noah Friedman
Martin Gasbichler
Andy Gaynor
Ian Grant
Eric Hanchrow
Karl Hegbloom
Johann Hibschman
Ian Horswill & the Northwestern Scheme wizards
Gary Houston
Graham Hughes
Jarmo Hurri
Lars Kellogg-Stedman
Andre Koehoerst
Hannu Koivisto
Shriram Krishnamurthi
Jakob Lichtenberg
Eric Marsden
Peter C. Olsen
Willliam Pippin
David Rush
Michael Schinz
Manuel Serrano
Mark Shirle
Bill Somerfeld
Mike Sperber
Harvey J. Stein
Pawel Turnau
Rob Warnock
Kenneth R. Westerback
We'd like to thank everyone else for their patience; this release seemed like
a long time coming.
Brought to you by the Scheme Underground. Go forth and write elegant systems
programs.
-Olin Shivers, Brian Carlstrom, Martin Gasbichler & Mike Sperber
-Olin Shivers, Brian Carlstrom & Martin Gasbichler
Cambridge
29 September 1999

3
Thanks
View File

@ -10,6 +10,3 @@ Post-0.5.2-release bug reports:
Andy Gaynor
Francisco Vides Fernandez
Tim Burgess
Brian Denheyer
Harvey Stein
Eric Hilsdale

View File

@ -16,11 +16,10 @@
# rm /zu/bdc/ftp/scsh/README~
#
VERSION=-0.5.3
FTPDIR=${HOME}/ftp/pub/scsh
FTPDIR=${HOME}/ftp/pub/users/bdc
FTPDIR=${HOME}/ftp/users/bdc
#CVSROOT=/projects/express/scsh-cvs
#export CVSROOT
CVSROOT=/projects/express/scsh-cvs
export CVSROOT
TMPSPACE=${HOME}/tmp
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

1008
config.guess vendored

File diff suppressed because it is too large Load Diff

603
config.sub vendored
View File

@ -1,10 +1,6 @@
#! /bin/sh
# Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
# Free Software Foundation, Inc.
timestamp='2001-03-09'
# Configuration validation subroutine script, version 1.1.
# Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
# can handle that machine. It does not imply ALL GNU software can.
@ -29,8 +25,6 @@ timestamp='2001-03-09'
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Please send patches to <config-patches@gnu.org>.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1.
@ -51,73 +45,30 @@ timestamp='2001-03-09'
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.
me=`echo "$0" | sed -e 's,.*/,,'`
if [ x$1 = x ]
then
echo Configuration name missing. 1>&2
echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
echo "or $0 ALIAS" 1>&2
echo where ALIAS is a recognized configuration type. 1>&2
exit 1
fi
usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS
$0 [OPTION] ALIAS
Canonicalize a configuration name.
Operation modes:
-h, --help print this help, then exit
-t, --time-stamp print date of last modification, then exit
-v, --version print version number, then exit
Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help="
Try \`$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
case $1 in
--time-stamp | --time* | -t )
echo "$timestamp" ; exit 0 ;;
--version | -v )
echo "$version" ; exit 0 ;;
--help | --h* | -h )
echo "$usage"; exit 0 ;;
-- ) # Stop option processing
shift; break ;;
- ) # Use stdin as input.
break ;;
-* )
echo "$me: invalid option $1$help"
exit 1 ;;
*local*)
# First pass through any local machine types.
echo $1
exit 0;;
* )
break ;;
esac
done
case $# in
0) echo "$me: missing argument$help" >&2
exit 1;;
1) ;;
*) echo "$me: too many arguments$help" >&2
exit 1;;
# First pass through any local machine types.
case $1 in
*local*)
echo $1
exit 0
;;
*)
;;
esac
# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | storm-chaos* | os2-emx*)
linux-gnu*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
@ -143,25 +94,15 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-apple | -axis)
-apple)
os=
basic_machine=$1
;;
-sim | -cisco | -oki | -wec | -winbond)
os=
basic_machine=$1
;;
-scout)
;;
-wrs)
os=-vxworks
basic_machine=$1
;;
-hiux*)
os=-hiuxwe2
;;
-sco5)
os=-sco3.2v5
os=sco3.2v5
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco4)
@ -180,9 +121,6 @@ case $os in
os=-sco3.2v2
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-udk*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-isc)
os=-isc2.2
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@ -205,101 +143,50 @@ case $os in
-psos*)
os=-psos
;;
-mint | -mint[0-9]*)
basic_machine=m68k-atari
os=-mint
;;
esac
# Decode aliases for certain CPU-COMPANY combinations.
case $basic_machine in
# Recognize the basic CPU types without company name.
# Some are omitted here because they have special meanings below.
tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc \
| arm | arme[lb] | arm[bl]e | armv[2345] | armv[345][lb] | strongarm | xscale \
| pyramid | mn10200 | mn10300 | tron | a29k \
| 580 | i960 | h8300 \
| x86 | ppcbe | mipsbe | mipsle | shbe | shle \
| hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
| hppa64 \
| alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
| alphaev6[78] \
| we32k | ns16k | clipper | i370 | sh | sh[34] \
| powerpc | powerpcle \
| 1750a | dsp16xx | pdp10 | pdp11 \
| mips16 | mips64 | mipsel | mips64el \
| mips64orion | mips64orionel | mipstx39 | mipstx39el \
| mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
| mips64vr5000 | miprs64vr5000el | mcore | s390 | s390x \
| sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
| thumb | d10v | d30v | fr30 | avr | openrisc)
basic_machine=$basic_machine-unknown
;;
m6811 | m68hc11 | m6812 | m68hc12)
# Motorola 68HC11/12.
basic_machine=$basic_machine-unknown
os=-none
;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl)
;;
tahoe | i860 | m68k | m68000 | m88k | ns32k | arm \
| arme[lb] | pyramid \
| tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
| alpha | we32k | ns16k | clipper | i370 | sh \
| powerpc | powerpcle | 1750a | dsp16xx | mips64 | mipsel \
| pdp11 | mips64el | mips64orion | mips64orionel \
| sparc | sparclet | sparclite | sparc64)
basic_machine=$basic_machine-unknown
;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users.
i[234567]86 | x86_64)
i[3456]86)
basic_machine=$basic_machine-pc
;;
# Object if more than one company name word.
*-*-*)
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1
;;
# Recognize the basic CPU types with company name.
# FIXME: clean up the formatting here.
vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
| m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | c[123]* \
| arm-* | armbe-* | armle-* | armv*-* | strongarm-* | xscale-* \
| mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
| power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
| xmp-* | ymp-* \
| x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* \
| hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
| hppa2.0n-* | hppa64-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
| alphaev6[78]-* \
| we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
| clipper-* | orion-* \
| sparclite-* | pdp10-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
| sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
| mips64el-* | mips64orion-* | mips64orionel-* \
| mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
| mipstx39-* | mipstx39el-* | mcore-* \
| f30[01]-* | f700-* | s390-* | s390x-* | sv1-* | t3e-* \
| [cjt]90-* \
| m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
| thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \
| bs2000-* | tic54x-* | c54x-* | x86_64-*)
vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \
| sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
| mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \
| none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
| hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
| pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
| pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \
| mips64el-* | mips64orion-* | mips64orionel-*)
;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
386bsd)
basic_machine=i386-unknown
os=-bsd
;;
3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
basic_machine=m68000-att
;;
3b*)
basic_machine=we32k-att
;;
a29khif)
basic_machine=a29k-amd
os=-udi
;;
adobe68k)
basic_machine=m68010-adobe
os=-scout
;;
alliant | fx80)
basic_machine=fx80-alliant
;;
@ -315,24 +202,20 @@ case $basic_machine in
os=-sysv
;;
amiga | amiga-*)
basic_machine=m68k-unknown
basic_machine=m68k-cbm
;;
amigaos | amigados)
basic_machine=m68k-unknown
os=-amigaos
amigados)
basic_machine=m68k-cbm
os=-amigados
;;
amigaunix | amix)
basic_machine=m68k-unknown
basic_machine=m68k-cbm
os=-sysv4
;;
apollo68)
basic_machine=m68k-apollo
os=-sysv
;;
apollo68bsd)
basic_machine=m68k-apollo
os=-bsd
;;
aux)
basic_machine=m68k-apple
os=-aux
@ -369,16 +252,13 @@ case $basic_machine in
basic_machine=cray2-cray
os=-unicos
;;
[cjt]90)
basic_machine=${basic_machine}-cray
[ctj]90-cray)
basic_machine=c90-cray
os=-unicos
;;
crds | unos)
basic_machine=m68k-crds
;;
cris | cris-* | etrax*)
basic_machine=cris-axis
;;
da30 | da30-*)
basic_machine=m68k-da30
;;
@ -412,10 +292,6 @@ case $basic_machine in
encore | umax | mmax)
basic_machine=ns32k-encore
;;
es1800 | OSE68k | ose68k | ose | OSE)
basic_machine=m68k-ericsson
os=-ose
;;
fx2800)
basic_machine=i860-alliant
;;
@ -426,10 +302,6 @@ case $basic_machine in
basic_machine=tron-gmicro
os=-sysv
;;
go32)
basic_machine=i386-pc
os=-go32
;;
h3050r* | hiux*)
basic_machine=hppa1.1-hitachi
os=-hiuxwe2
@ -438,14 +310,6 @@ case $basic_machine in
basic_machine=h8300-hitachi
os=-hms
;;
h8300xray)
basic_machine=h8300-hitachi
os=-xray
;;
h8500hms)
basic_machine=h8500-hitachi
os=-hms
;;
harris)
basic_machine=m88k-harris
os=-sysv3
@ -461,74 +325,39 @@ case $basic_machine in
basic_machine=m68k-hp
os=-hpux
;;
hp3k9[0-9][0-9] | hp9[0-9][0-9])
basic_machine=hppa1.0-hp
;;
hp9k2[0-9][0-9] | hp9k31[0-9])
basic_machine=m68000-hp
;;
hp9k3[2-9][0-9])
basic_machine=m68k-hp
;;
hp9k6[0-9][0-9] | hp6[0-9][0-9])
basic_machine=hppa1.0-hp
;;
hp9k7[0-79][0-9] | hp7[0-79][0-9])
basic_machine=hppa1.1-hp
;;
hp9k78[0-9] | hp78[0-9])
# FIXME: really hppa2.0-hp
basic_machine=hppa1.1-hp
;;
hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
# FIXME: really hppa2.0-hp
basic_machine=hppa1.1-hp
;;
hp9k8[0-9][13679] | hp8[0-9][13679])
hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
basic_machine=hppa1.1-hp
;;
hp9k8[0-9][0-9] | hp8[0-9][0-9])
basic_machine=hppa1.0-hp
;;
hppa-next)
os=-nextstep3
;;
hppaosf)
basic_machine=hppa1.1-hp
os=-osf
;;
hppro)
basic_machine=hppa1.1-hp
os=-proelf
;;
i370-ibm* | ibm*)
basic_machine=i370-ibm
os=-mvs
;;
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
i[34567]86v32)
i[3456]86v32)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32
;;
i[34567]86v4*)
i[3456]86v4*)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv4
;;
i[34567]86v)
i[3456]86v)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv
;;
i[34567]86sol2)
i[3456]86sol2)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-solaris2
;;
i386mach)
basic_machine=i386-mach
os=-mach
;;
i386-vsta | vsta)
basic_machine=i386-unknown
os=-vsta
;;
iris | iris4d)
basic_machine=mips-sgi
case $os in
@ -554,59 +383,19 @@ case $basic_machine in
basic_machine=ns32k-utek
os=-sysv
;;
mingw32)
basic_machine=i386-pc
os=-mingw32
;;
miniframe)
basic_machine=m68000-convergent
;;
*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
basic_machine=m68k-atari
os=-mint
;;
mipsel*-linux*)
basic_machine=mipsel-unknown
os=-linux-gnu
;;
mips*-linux*)
basic_machine=mips-unknown
os=-linux-gnu
;;
mips3*-*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
;;
mips3*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
;;
mmix*)
basic_machine=mmix-knuth
os=-mmixware
;;
monitor)
basic_machine=m68k-rom68k
os=-coff
;;
msdos)
basic_machine=i386-pc
os=-msdos
;;
mvs)
basic_machine=i370-ibm
os=-mvs
;;
ncr3000)
basic_machine=i486-ncr
os=-sysv4
;;
netbsd386)
basic_machine=i386-unknown
os=-netbsd
;;
netwinder)
basic_machine=armv4l-rebel
os=-linux
;;
news | news700 | news800 | news900)
basic_machine=m68k-sony
os=-newsos
@ -619,10 +408,6 @@ case $basic_machine in
basic_machine=mips-sony
os=-newsos
;;
necv70)
basic_machine=v70-nec
os=-sysv
;;
next | m*-next )
basic_machine=m68k-next
case $os in
@ -648,32 +433,9 @@ case $basic_machine in
basic_machine=i960-intel
os=-nindy
;;
mon960)
basic_machine=i960-intel
os=-mon960
;;
nonstopux)
basic_machine=mips-compaq
os=-nonstopux
;;
np1)
basic_machine=np1-gould
;;
nsr-tandem)
basic_machine=nsr-tandem
;;
op50n-* | op60c-*)
basic_machine=hppa1.1-oki
os=-proelf
;;
OSE68000 | ose68000)
basic_machine=m68000-ericsson
os=-ose
;;
os68k)
basic_machine=m68k-none
os=-os68k
;;
pa-hitachi)
basic_machine=hppa1.1-hitachi
os=-hiuxwe2
@ -691,28 +453,30 @@ case $basic_machine in
pc532 | pc532-*)
basic_machine=ns32k-pc532
;;
pentium | p5 | k5 | k6 | nexgen)
basic_machine=i586-pc
pentium | p5)
basic_machine=i586-intel
;;
pentiumpro | p6 | 6x86 | athlon)
basic_machine=i686-pc
pentiumpro | p6)
basic_machine=i686-intel
;;
pentiumii | pentium2)
basic_machine=i686-pc
;;
pentium-* | p5-* | k5-* | k6-* | nexgen-*)
pentium-* | p5-*)
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentiumpro-* | p6-* | 6x86-* | athlon-*)
pentiumpro-* | p6-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentiumii-* | pentium2-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
k5)
# We don't have specific support for AMD's K5 yet, so just call it a Pentium
basic_machine=i586-amd
;;
nexen)
# We don't have specific support for Nexgen yet, so just call it a Pentium
basic_machine=i586-nexgen
;;
pn)
basic_machine=pn-gould
;;
power) basic_machine=power-ibm
power) basic_machine=rs6000-ibm
;;
ppc) basic_machine=powerpc-unknown
;;
@ -727,24 +491,12 @@ case $basic_machine in
ps2)
basic_machine=i386-ibm
;;
pw32)
basic_machine=i586-unknown
os=-pw32
;;
rom68k)
basic_machine=m68k-rom68k
os=-coff
;;
rm[46]00)
basic_machine=mips-siemens
;;
rtpc | rtpc-*)
basic_machine=romp-ibm
;;
sa29200)
basic_machine=a29k-amd
os=-udi
;;
sequent)
basic_machine=i386-sequent
;;
@ -752,10 +504,6 @@ case $basic_machine in
basic_machine=sh-hitachi
os=-hms
;;
sparclite-wrs)
basic_machine=sparclite-wrs
os=-vxworks
;;
sps7)
basic_machine=m68k-bull
os=-sysv2
@ -763,13 +511,6 @@ case $basic_machine in
spur)
basic_machine=spur-unknown
;;
st2000)
basic_machine=m68k-tandem
;;
stratus)
basic_machine=i860-stratus
os=-sysv4
;;
sun2)
basic_machine=m68000-sun
;;
@ -810,28 +551,10 @@ case $basic_machine in
sun386 | sun386i | roadrunner)
basic_machine=i386-sun
;;
sv1)
basic_machine=sv1-cray
os=-unicos
;;
symmetry)
basic_machine=i386-sequent
os=-dynix
;;
t3e)
basic_machine=t3e-cray
os=-unicos
;;
tic54x | c54x*)
basic_machine=tic54x-unknown
os=-coff
;;
tx39)
basic_machine=mipstx39-unknown
;;
tx39el)
basic_machine=mipstx39el-unknown
;;
tower | tower-32)
basic_machine=m68k-ncr
;;
@ -843,10 +566,6 @@ case $basic_machine in
basic_machine=a29k-nyu
os=-sym1
;;
v810 | necv810)
basic_machine=v810-nec
os=-none
;;
vaxv)
basic_machine=vax-dec
os=-sysv
@ -855,9 +574,6 @@ case $basic_machine in
basic_machine=vax-dec
os=-vms
;;
vpp*|vx|vx-*)
basic_machine=f301-fujitsu
;;
vxworks960)
basic_machine=i960-wrs
os=-vxworks
@ -870,14 +586,6 @@ case $basic_machine in
basic_machine=a29k-wrs
os=-vxworks
;;
w65*)
basic_machine=w65-wdc
os=-none
;;
w89k-*)
basic_machine=hppa1.1-winbond
os=-proelf
;;
xmp)
basic_machine=xmp-cray
os=-unicos
@ -885,10 +593,6 @@ case $basic_machine in
xps | xps100)
basic_machine=xps100-honeywell
;;
z8k-*-coff)
basic_machine=z8k-unknown
os=-sim
;;
none)
basic_machine=none-none
os=-none
@ -896,21 +600,8 @@ case $basic_machine in
# Here we handle the default manufacturer of certain CPU types. It is in
# some cases the only manufacturer, in others, it is the most popular.
w89k)
basic_machine=hppa1.1-winbond
;;
op50n)
basic_machine=hppa1.1-oki
;;
op60c)
basic_machine=hppa1.1-oki
;;
mips)
if [ x$os = x-linux-gnu ]; then
basic_machine=mips-unknown
else
basic_machine=mips-mips
fi
basic_machine=mips-mips
;;
romp)
basic_machine=romp-ibm
@ -921,20 +612,13 @@ case $basic_machine in
vax)
basic_machine=vax-dec
;;
pdp10)
# there are many clones, so DEC is not a safe bet
basic_machine=pdp10-unknown
;;
pdp11)
basic_machine=pdp11-dec
;;
we32k)
basic_machine=we32k-att
;;
sh3 | sh4)
basic_machine=sh-unknown
;;
sparc | sparcv9)
sparc)
basic_machine=sparc-sun
;;
cydra)
@ -946,16 +630,6 @@ case $basic_machine in
orion105)
basic_machine=clipper-highlevel
;;
mac | mpw | mac-mpw)
basic_machine=m68k-apple
;;
pmac | pmac-mpw)
basic_machine=powerpc-apple
;;
c4x*)
basic_machine=c4x-none
os=-coff
;;
*)
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1
@ -988,12 +662,9 @@ case $os in
-solaris)
os=-solaris2
;;
-svr4*)
-unixware* | svr4*)
os=-sysv4
;;
-unixware*)
os=-sysv4.2uw
;;
-gnu/linux*)
os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
;;
@ -1004,40 +675,17 @@ case $os in
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -amigados* | -msdos* | -newsos* | -unicos* | -aof* | -aos* \
| -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
| -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -os2*)
| -cygwin32* | -pe* | -psos* | -moss* | -proelf* \
| -linux-gnu*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
case $basic_machine in
x86-* | i[34567]86-*)
;;
*)
os=-nto$os
;;
esac
;;
-nto*)
os=-nto-qnx
;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
;;
-mac*)
os=`echo $os | sed -e 's|mac|macos|'`
;;
-linux*)
os=`echo $os | sed -e 's|linux|linux-gnu|'`
;;
@ -1047,12 +695,6 @@ case $os in
-sunos6*)
os=`echo $os | sed -e 's|sunos6|solaris3|'`
;;
-opened*)
os=-openedition
;;
-wince*)
os=-wince
;;
-osfrose*)
os=-osfrose
;;
@ -1068,18 +710,12 @@ case $os in
-acis*)
os=-aos
;;
-386bsd)
os=-bsd
;;
-ctix* | -uts*)
os=-sysv
;;
-ns2 )
os=-nextstep2
;;
-nsk*)
os=-nsk
;;
# Preserve the version number of sinix5.
-sinix5.*)
os=`echo $os | sed -e 's|sinix|sysv|'`
@ -1105,18 +741,9 @@ case $os in
# This must come after -sysvr4.
-sysv*)
;;
-ose*)
os=-ose
;;
-es1800*)
os=-ose
;;
-xenix)
os=-xenix
;;
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
os=-mint
;;
-none)
;;
*)
@ -1142,15 +769,9 @@ case $basic_machine in
*-acorn)
os=-riscix1.2
;;
arm*-rebel)
os=-linux
;;
arm*-semi)
os=-aout
;;
pdp10-*)
os=-tops20
;;
pdp11-*)
os=-none
;;
@ -1169,36 +790,15 @@ case $basic_machine in
# default.
# os=-sunos4
;;
m68*-cisco)
os=-aout
;;
mips*-cisco)
os=-elf
;;
mips*-*)
os=-elf
;;
*-tti) # must be before sparc entry or we get the wrong os.
os=-sysv3
;;
sparc-* | *-sun)
os=-sunos4.1.1
;;
*-be)
os=-beos
;;
*-ibm)
os=-aix
;;
*-wec)
os=-proelf
;;
*-winbond)
os=-proelf
;;
*-oki)
os=-proelf
;;
*-hp)
os=-hpux
;;
@ -1209,7 +809,7 @@ case $basic_machine in
os=-sysv
;;
*-cbm)
os=-amigaos
os=-amigados
;;
*-dg)
os=-dgux
@ -1259,21 +859,6 @@ case $basic_machine in
*-masscomp)
os=-rtu
;;
f30[01]-fujitsu | f700-fujitsu)
os=-uxpv
;;
*-rom68k)
os=-coff
;;
*-*bug)
os=-coff
;;
*-apple)
os=-macos
;;
*-atari*)
os=-mint
;;
*)
os=-none
;;
@ -1292,18 +877,15 @@ case $basic_machine in
-sunos*)
vendor=sun
;;
-lynxos*)
vendor=lynx
;;
-aix*)
vendor=ibm
;;
-beos*)
vendor=be
;;
-hpux*)
vendor=hp
;;
-mpeix*)
vendor=hp
;;
-hiux*)
vendor=hitachi
;;
@ -1319,38 +901,21 @@ case $basic_machine in
-genix*)
vendor=ns
;;
-mvs* | -opened*)
-mvs*)
vendor=ibm
;;
-ptx*)
vendor=sequent
;;
-vxsim* | -vxworks*)
-vxworks*)
vendor=wrs
;;
-aux*)
vendor=apple
;;
-hms*)
vendor=hitachi
;;
-mpw* | -macos*)
vendor=apple
;;
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
vendor=atari
;;
esac
basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
;;
esac
echo $basic_machine$os
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:

6
configure vendored
View File

@ -1294,7 +1294,7 @@ fi
;;
## NetBSD and FreeBSD ( and maybe 386BSD also)
*-*-*bsd*|*-*-darwin* )
*-*-*bsd* )
dir=bsd
echo $ac_n "checking for ELF""... $ac_c" 1>&6
@ -1375,8 +1375,8 @@ EOF
;;
## NT - cygwin
*-*-cygwin* )
## NT - cygwin32
*-*-cygwin32* )
dir=cygwin32
;;

View File

@ -292,7 +292,7 @@ case "$host" in
;;
## NetBSD and FreeBSD ( and maybe 386BSD also)
*-*-*bsd*|*-*-darwin* )
*-*-*bsd* )
dir=bsd
SCSH_ELF
;;
@ -322,8 +322,8 @@ case "$host" in
AC_DEFINE(HAVE_NLIST)
;;
## NT - cygwin
*-*-cygwin* )
## NT - cygwin32
*-*-cygwin32* )
dir=cygwin32
;;

View File

@ -1 +0,0 @@
html

View File

@ -18,16 +18,13 @@ man.ind: man.idx
makeindex $<
clean:
-rm *.log
rm -rf html
-rm *.log
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:

View File

@ -76,7 +76,6 @@ characters.
\subsection{Parsing fields}
\label{sec:field-splitter}
\defun {field-splitter} {[field num-fields]} \proc
\defunx {infix-splitter} {[delim num-fields handle-delim]} \proc

297
doc/scsh-manual/changes.tex Normal file
View File

@ -0,0 +1,297 @@
%&latex -*- latex -*-
\chapter{Changes from previous releases}
\label{sec:changes}
\newcommand{\itam}[1]{\item {#1} \\}
\section{Changes from the previous release}
This section details changes that have been made in scsh since
the previous release.
Scsh is now much more robust.
All known bugs have been fixed.
There have been many improvements and extensions made.
These new features and changes are listed below, in no particular order;
the relevant sections of the manual give the full details.
Scsh now supports complete {\Posix}, including signal handlers.
Early autoreaping of child processes is now handled by a \ex{SIGCHLD}
signal handler, so children are reaped as early as possible with no
user intervention required.
A functional static heap linker is included in this release.
It is ugly, limited in functionality, and extremely slow, but it works.
It can be used to build scsh binaries that start up instantly.
The regular expression system has been sped up.
Regular-expression compilation is now provided,
and the \ex{awk} macro has been rewritten to pre-compile
regexps used in rules outside the loop.
It is still, however, slower than it should be.
Execing programs should be faster in this release, since we now use the
\ex{CLOEXEC} status bit to get automatic closing of unrevealed
port file descriptors.
{scm}'s floating point support was inadvertently omitted from the last
release. It has been reinstated.
There is now a new command-line switch, \ex{-sfd \var{num}},
which causes scsh to read its script from file descriptor \var{num}.
\section{Changes from the penultimate release}
This section details changes that have been made in scsh since
the penultimate release.
Scsh is now much more robust.
All known bugs have been fixed.
There have been many improvements and extensions made.
We have also made made some incompatible changes.
The sections below briefly describe these new features and changes;
the relevant sections of the manual give the full details.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{New features}
This release incorporates several new features into scsh.
\begin{itemize}
\itam{Control of buffered I/O}
Scsh now allows you to control the buffering policy used for doing I/O
on a Scheme port.
\itam{Here-strings}
Scsh now has a new lexical feature, \verb|#<<|, that provides
the ability to enter long, multi-line string constants in scsh programs.
Such a string is called a ``here string,'' by analogy to the common
shell ``here document'' \ex{<<} redirection.
\itam{Delimited readers and read-line}
Scsh now has a powerful set of delimited readers.
These can be used to read input delimited by
a newline character (\ex{read-line}),
a blank line (\ex{read-paragraph}),
or the occurrence of any character in an arbitrary set (\ex{read-delimited}).
While these procedures can be applied to any Scheme input port,
there is native-code support for performing delimited reads on
Unix input sources, so doing block input with these procedures should be
much faster than the equivalent character-at-a-time Scheme code.
\itam{New system calls}
With the sole exception of signal handlers, scsh now has all of {\Posix}.
This release introduces
\begin{itemize}
\item \ex{select},
\item full terminal device control,
\item support for pseudo-terminal ``pty'' devices,
\item file locking,
\item process timing,
\item \ex{set-file-times},
\item \ex{seek} and \ex{tell}.
\end{itemize}
Note that having \ex{select}, pseudo-terminals, and tty device control means
that it is now possible to implement interesting network protocols, such as
telnet servers and clients, directly in Scheme.
\itam{New command-line switches}
There is a new set of command-line switches that make it possible
to write shell scripts using the {\scm} module system.
Scripts can use the new command-line switches to open dependent
modules and load dependent source code.
Scripts can also be written in the {\scm} module language,
which allows you to use it both as a standalone shell script,
and as a code module that can be loaded and used by other Scheme programs.
\itam{Static heap linking}
There is a new facility that allows you to compile a heap image
to a \ex{.o} file that can be linked with the scsh virtual machine.
This produces a standalone executable binary, makes startup time
near-instantaneous, and greatly improves memory performance---the
initial heap image is placed in the process' text pages,
where it is shared by different scsh processes, and does not occupy
space in the run-time heap.
\oops{The static heap linker was not documented and installed in time
for this release.}
\end{itemize}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Incompatible improvements}
Some features of scsh have been improved in ways that are
not backwards-compatible with previous releases.
These changes should not affect most code;
however, please note the changes and modify your code accordingly.
\begin{itemize}
\itam{New process-object data-type returned by \ex{fork}}
Previous releases were prone to fill up the kernel's process table
if a program forked large numbers of processes and subsequently failed
to use \ex{wait} to reclaim the entries in the kernel's process table.
(This is a problem in standard C environments, as well.)
Scsh 0.4 introduces a new mechanism for automatically managing subprocesses.
Processes are no longer represented by an integer process id,
which is impossible to garbage-collect, but by an
abstract process data type that encapsulates the process id.
All processes are represented using the new data structures;
see the relevant section of the manual for further details.
\itam{Better stdio/current-port synchronisation}
The \ex{(begin \ldots)} process form now does a \ex{stdio->stdports}
call before executing its body.
This means that the Scheme code in the body ``sees'' any external
redirections.
For example, it means that if a \ex{begin} form in the middle of a pipeline
performs I/O on the current input and output ports, it will be communicating
with its upstream and downstream pipes.
\Eg, this code works as intended without the need for explicit synchronisation:
\begin{verbatim}
(run (| (gunzip)
;; Kill line 1 and insert doubled-sided
;; code at head of Postscript.
(begin (read-line) ; Eat first line.
(display "%!PS-Adobe-2.0\\n")
(display "statusdict /setduplexmode known ")
(display "{statusdict begin true ")
(display "setduplexmode end} if\n")
(exec-epf (cat)))
(lpr))
(< paper.ps))\end{verbatim}
Arranging for the \ex{begin} process form to synchronise
the current I/O ports with stdio means that all process forms now
see their epf's redirections.
\itam{\ex{file-match} more robust}
The \ex{file-match} procedure now catches any error condition
signalled by a match procedure,
and treats it as if the procedure had simply returned {\sharpf},
\ie, match failure.
This means \ex{file-match} no longer gets blown out of the water by
trying to apply a function like \ex{file-directory?} to a dangling symlink,
and other related OS errors.
\itam{Standard input now unbuffered}
Scsh's startup code now makes the initial current input port
(corresponding to file descriptor 0) unbuffered.
This keeps the shell from ``stealing'' input meant for subprocesses.
However, it does slow down character-at-a-time input processing.
If you are writing a program that is tolerant of buffered input,
and wish the efficiency gains, you can reset the buffering policy
yourself.
\itam{``writeable'' now spelled ``writable''}
We inconsistently spelled \ex{file-writable?} and \ex{file-not-writable?}
in the manual and the implementation.
We have now standardised on the common spelling ``writable'' in both.
The older bindings still exist in release 0.4, but will go away in future
releases.
\itam{\protect\ex{char-set-member?} replaced}
We have de-released the \ex{char-set-member?} procedure.
The scsh 0.3 version of this procedure took arguments
in the following order:
\codex{(char-set-member? \var{char} \var{char-set})}
This argument order is in accordance with standard mathematical useage
(\ie, $x \in S$), and also consistent with the R4RS
\ex{member}, \ex{memq} and \ex{memv} procedures.
It is, however, exactly opposite from the argument order
used by the \ex{char-set-member?} in MIT Scheme's character-set library.
If we left things as they were, we risked problems with code
ported over from MIT Scheme.
On the other hand, changing to conformance with MIT Scheme meant
inconsistency with common mathematical notation and other long-standing
Scheme procedures.
Either way was bound to introduce confusion.
We've taken the approach of simply removing the \ex{char-set-member?}
procedure altogether, and replacing it with a new procedure:
\codex{(char-set-contains? \var{cset} \var{char})}
Note that the argument order is consistent with the name.
\itam{\ex{file-attributes} now \ex{file-info}}
In keeping with the general convention in scsh of naming procedures
that retrieve information about system resources \ex{\ldots-info}
(\eg, \ex{tty-info}, \ex{user-info}, \ex{group-info}),
the \ex{file-attributes} procedure is now named \ex{file-info}.
We continue to export a \ex{file-attributes} binding for the current
release, but it will go away in future releases.
\itam{Renaming of I/O synchronisation procedures}
The \ex{(stdio->stdports \var{thunk})} procedure has been
renamed \ex{with-stdio-ports*};
there is now a corresponding \ex{with-stdio-ports} special form.
The \ex{stdio->stdports} procedure is now a nullary procedure
that side-effects the current set of current I/O port bindings.
\itam{New meta-arg line-two syntax}
Scsh now uses a simplified grammar for describing command-line
arguments read by the ``meta-arg'' switch from line two of a shell script.
If you were using this feature in previous releases, the three incompatible
changes of which to be aware are:
(1) tab is no longer allowed as an argument delimiter,
(2) a run of space characters is not equivalent to a single space,
(3) empty arguments are written a different way.
\end{itemize}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Backwards-compatible improvements}
Some existing features in scsh have been improved in ways that will
not effect existing code.
\begin{itemize}
\itam{Improved error reporting}
Exception handlers that print out error messages and warnings now
print their messages on the error output port,
instead of the current output port.
Previous releases used the current output port,
a problem inherited from Scheme 48.
Previous scsh releases flushed the Scheme 48 debugging tables when
creating the standard scsh heap image.
This trimmed the size of the heap image, but made error messages much
less comprehensible.
We now retain the debugging tables.
This bloats the heap image up by about 600kb. And worth it, too.
(We also have some new techniques for eliminating the run-time memory
penalty imposed by these large heap images.
Scsh's new static-heap technology allows for this data to be linked
into the text pages of the vm's binary, where it will not be touched
by the GC or otherwise affect the memory system until it is referenced.)
Finally, scsh now generates more informative error messages for syscall
errors.
For example, a file-open error previously told you what the error was
(\eg, ``Permission denied,'' or ``No such file or directory''),
but not which file you had tried to open.
We've improved this.
\itam{Closing a port twice allowed}
Scsh used to generate an error if you attempted to close a port
that had already been closed.
This is now allowed.
The close procedure returns a boolean to indicate whether the port had
already been closed or not.
\itam{Better time precision}
The \ex{time+ticks} procedure now returns sub-second precision on OS's
that support it.
\itam{Nicer print-methods for basic data-types}
Scsh's standard record types now print more informatively.
For example, a process object includes the process id in its
printed representation: the process object for process id 2653
prints as \verb|#{proc 2653}|.
\end{itemize}

View File

@ -1,105 +0,0 @@
% css.t2p
% Dorai Sitaram
% 19 Jan 2001
% A basic style for HTML documents generated
% with tex2page.
\cssblock
body {
color: black;
background-color: #e5e5e5;
/*background-color: beige;*/
margin-top: 2em;
margin-left: 8%;
margin-right: 8%;
}
h1,h2,h3,h4,h5,h6 {
margin-top: .5em;
}
.partheading {
font-size: 70%;
}
.chapterheading {
font-size: 70%;
}
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;
}
.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

View File

@ -23,8 +23,6 @@
\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%

View File

@ -3,17 +3,11 @@
\title{Scsh Reference Manual}
\subtitle{For scsh release 0.5.3}
\author{Olin Shivers and Brian D.~Carlstrom}
\date{June 2001}
\date{September 1999}
\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,

View File

@ -18,30 +18,6 @@ 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.
For years, scsh's underlying Scheme implementation, Scheme 48, did not have an
open-source copyright. However, around 1999/2000, the Scheme 48 authors
graciously retrofitted a BSD-style open-source copyright onto the system.
Swept up by the fervor, we tacked an ideologically hip license onto scsh
source, ourselves (BSD-style, as well). Not that we ever cared before what you
did with the system.
As a result, the whole system is now open source, top-to-bottom.
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.
@ -49,9 +25,9 @@ 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-swiss.ai.mit.edu/pub/su/}{ftp://ftp-swiss.ai.mit.edu/pub/su/}} \\
\ex{\urlh{http://www-swiss.ai.mit.edu/scsh/scsh.html}{http://www-swiss.ai.mit.edu/scsh/scsh.html}} \\
\ex{\urlh{http://www.cs.indiana.edu/scheme-repository/}{http://www.cs.indiana.edu/scheme-repository/}} \\
\ex{ftp://ftp-swiss.ai.mit.edu/pub/su/} \\
\ex{http://www-swiss.ai.mit.edu/scsh/scsh.html}
\ex{http://www.cs.indiana.edu/scheme-repository/} \\
\end{flushleft}
\end{inset}
These sites are
@ -124,11 +100,14 @@ but the system as-released does not currently provide these features.
In the current release, the system has some rough edges.
It is quite slow to start up---loading the initial image into the
{\scm} virtual machine induces a noticeable delay.
{\scm} virtual machine takes about a cpu second.
This can be fixed with the static heap linker provided with this release.
We welcome parties interested in porting the manual to a more portable
XML or SGML format; please contact us if you are interested in doing so.
This manual is very, very rough.
At some point, we hope to polish it up, finish it off, and re-typeset it
using markup, so we can generate html, info nodes, and {\TeX} output from
the single source without having to deal with Texinfo.
But it's all there is, for now.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Naming conventions}
@ -396,17 +375,11 @@ All told, the \ex{define-record} form above defines the following procedures:
(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:y \var{ship} \var{new-y}) & Assign the \var{x} 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}
%
@ -414,9 +387,7 @@ All told, the \ex{define-record} form above defines the following procedures:
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.
exports the single syntax form \ex{define-record}.
You must open this package to access the form.
Scsh does not export a record-definition package by default as there are
@ -446,9 +417,21 @@ 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.
standards, {\Posix}, as far as I have been able to determine,
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
Scsh sticks to {\Posix} when at all possible; it's major departure is
symbolic links, which aren't in {\Posix} (see---it
really \emph{is} a least common denominator).
However, just because {\Posix} is the l.c.d. standard doesn't mean everyone
supports all of it.
The guerilla PC {\Unix} implementations that have been springing up on
the net (\eg, NetBSD, Linux, FreeBSD, and so forth) are only recently coming
into compliance with the standard---although they are getting there.
We have been able to implement scsh completely on all of these systems,
however---the single exception is NeXTSTEP, whose buggy {\Posix} libraries
restricts us to partial support (these lacunae are indicated where relevant
in the rest of the manual).\footnote{Feel like porting scsh from {\Posix} to
NeXT's BSD API? Send us your fixes; we'll fold them in.}

View File

@ -1,126 +0,0 @@
% 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
\dontuseimgforhtmlmath
\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`\&}#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\dfnix#1#2#3#4{\leftline{{\tt(#1\spaceifnotempty{#2}{\it#2})} \quad $\longrightarrow$ \quad {\it #3} \qquad (#4)} \index}
\def\ex#1{{\tt #1}}
\def\l#1{lambda (#1)}
\def\lx#1{lambda {#1}}
%\def\notenum#1{}
%\def\project#1{}
\def\var#1{{\it #1\/}}
\def\vari#1#2{\mbox{{\it #1\/}\undefcsactive\$$_{#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}\bgroup\setupcode\GOBBLEOPTARG}
{\egroup\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}}
}

View File

@ -1,19 +1,16 @@
% -*- latex -*-
%&latex -*- 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}
headings,mantitle,array,matter,mysize10}
\texonly
\let\url\relax
\usepackage[dvipdfm,hyperindex,hypertex,
pdftitle={scsh manual, release 0.5.3},
pdfauthor={Olin Shivers and Brian D.~Carlstrom}
colorlinks=true,linkcolor=blue,pagecolor=blue,urlcolor=blue,
pdfstartview=FitH,pdfview=FitH]{hyperref}
\endtexonly
pdftitle={scsh manual, release 0.5.3},
pdfauthor={Olin Shivers and Brian D.~Carlstrom}
colorlinks=true,linkcolor=blue,pagecolor=blue,urlcolor=blue,
pdfstartview=FitH,pdfview=FitH]{hyperref}
% 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
@ -25,19 +22,19 @@
%\renewcommand{\ttdefault}{pcr}
% Style issues
\parskip = 3pt plus 3pt
\sloppy
\parskip = 3pt plus 3pt
\sloppy
%\includeonly{syscalls}
\input{decls}
\makeindex
\makeindex
%%% End preamble
\begin{document}
\frontmatter
\include{front}
\frontmatter
\include{front}
\mainmatter
\include{intro}
@ -50,6 +47,7 @@
\include{awk}
\include{miscprocs}
\include{running}
\include{changes}
\include{todo}
\backmatter

View File

@ -50,8 +50,7 @@
\vskip -0.3\baselineskip
\wideline{\leaders\hrule height 4pt\hfill}
\wideline{\hfill\subtitlefont\begin{tabular}[t]{@{}r@{}}\@subtitle%
\\\@date%
\end{tabular}} % subtitle
\end{tabular}\hskip 1in} % subtitle
%
% author
\vskip 0pt plus 1filll

View File

@ -11,7 +11,7 @@ The basic elements of this notation are \emph{process forms},
\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 $)}
\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}
@ -140,7 +140,7 @@ 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
\ex{Exec-path} is the version of the \ex{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.
@ -438,7 +438,7 @@ 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.
\ex{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

View File

@ -398,7 +398,7 @@ would implement a simple-minded version of the Unix \ex{echo} program:
%
The idea would be that the command
\codex{ekko Hi there.}
would by expanded by the \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=exec&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{exec(2)}} kernel call into
would by expanded by the \ex{exec(2)} kernel call into
%
\begin{code}
/usr/local/bin/scsh -e main -s ekko Hi there.\end{code}
@ -408,7 +408,7 @@ call the entry point on the command-line list
\codex{(main '("ekko" "Hi" "there."))}
and exit.
Unfortunately, the {\Unix} \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=exec&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{exec(2)}} syscall's support for scripts is
Unfortunately, the {\Unix} \ex{exec(2)} syscall's support for scripts is
not very general or well-designed.
It will not handle multiple arguments;
the \ex{\#!} line is usually required to contain no more than 32 characters;
@ -555,7 +555,7 @@ Writing it this way makes it possible to compile the program
(for-each (\l{arg} (display arg) (display " "))
(cdr args)))\end{code}
%
The \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=exec&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{exec(2)}} expansion of the \ex{\#!} line together with
The \ex{exec(2)} expansion of the \ex{\#!} line together with
the scsh expansion of the ``\verb|\ ekko|'' meta-argument
(see section~\ref{sec:meta-arg}) gives the following command-line expansion:
\begin{code}

View File

@ -1,71 +1,27 @@
% -*- 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.
Scsh provides a set of procedures for processing strings and characters.
The procedures provided match regular expressions, search strings,
parse file-names, and manipulate sets of characters.
\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}
Also see chapters \ref{chapt:sre}, \ref{chapt:rdelim} and \ref{chapt:fr-awk}
on regular-expressions, record I/O, field parsing, and the awk loop.
The procedures documented there allow you to search and pattern-match strings,
read character-delimited records from ports,
use regular expressions to split the records into fields
(for example, splitting a string at every occurrence of colon or white-space),
and loop over streams of these records in a convenient way.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Manipulating file names}
\section{String manipulation}
\label{sec:stringmanip}
Strings are the basic communication medium for {\Unix} processes, so a
shell language must have reasonable facilities for manipulating them.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Manipulating file-names}
\label{sec:filenames}
These procedures do not access the file-system at all; they merely operate
@ -74,7 +30,7 @@ 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}
\subsubsection{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.
@ -139,7 +95,7 @@ interpreted in file-name form, \ie, as root.
\subsection{Procedures}
\subsubsection{Procedures}
\defun {file-name-directory?} {fname} \boolean
\defunx {file-name-non-directory?} {fname} \boolean
@ -399,7 +355,38 @@ is also frequently useful for expanding file-names.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Other string manipulation facilities}
\subsection{Other string manipulation facilities}
\defun {index} {string char [start]} {{\fixnum} or false}
\defunx {rindex} {string char [start]} {{\fixnum} or false}
\begin{desc}
These procedures search through \var{string} looking for an occurrence
of character \var{char}. \ex{index} searches left-to-right; \ex{rindex}
searches right-to-left.
\ex{index} returns the smallest index $i$ of \var{string} greater
than or equal to \var{start} such that $\var{string}[i] = \var{char}$.
The default for \var{start} is zero. If there is no such match,
\ex{index} returns false.
\ex{rindex} returns the largest index $i$ of \var{string} less than
\var{start} such that $\var{string}[i] = \var{char}$.
The default for \var{start} is \ex{(string-length \var{string})}.
If there is no such match, \ex{rindex} returns false.
\end{desc}
I should probably snarf all the MIT Scheme string functions, and stick them
in a package. {\Unix} programs need to mung character strings a lot.
MIT string match commands:
\begin{tightcode}
[sub]string-match-{forward,backward}[-ci]
[sub]string-{prefix,suffix}[-ci]?
[sub]string-find-{next,previous}-char[-ci]
[sub]string-find-{next,previous}-char-in-set
[sub]string-replace[!]
\ldots\etc\end{tightcode}
These are not currently provided.
\begin{defundesc} {substitute-env-vars} {fname} \str
Replace occurrences of environment variables with their values.
@ -425,72 +412,315 @@ is also frequently useful for expanding file-names.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Character predicates}
\section{Character sets}
\label{sec:char-sets}
\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
Scsh provides a \ex{char-set} type for expressing sets of characters.
These sets are used by some of the delimited-input procedures
(section~\ref{sec:field-reader}).
Scsh's character set package was adapted and extended from
Project Mac's MIT Scheme package.
Note that the character type used in the current implementation corresponds
to the ASCII character set---but you would be wise not to build this
assumption into your code if you can help it.\footnote{
Actually, it's slightly uglier than that, albeit somewhat more
useful. The current character type corresponds to an eight-bit
superset of ASCII. The \ex{ascii->char} and \ex{char->ascii}
functions will preserve this eighth bit. However, none of the
the high 128 characters appear in any of the standard character
sets defined in section~\ref{sec:std-csets}, except for
\ex{char-set:full}. If someone would email the authors a listing
of the full Latin-1 definition, we'll be happy to upgrade these
sets' definitions to make them Latin-1 compliant.}
\defun{char-set?}{x}\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 {R5RS}
compatibility:
\begin{inset}
\begin{tabular}{ll}
{R5RS} 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}
Is the object \var{x} a character set?
\end{desc}
\defun{char-set=}{\vari{cs}1 \vari{cs}2\ldots}\boolean
\begin{desc}
Are the character sets equal?
\end{desc}
\defun{char-set<=}{\vari{cs}1 \vari{cs}2\ldots}\boolean
\begin{desc}
Returns true if every character set \vari{cs}{i} is
a subset of character set \vari{cs}{i+1}.
\end{desc}
\defun{char-set-fold}{kons knil cs}\object
\begin{desc}
This is the fundamental iterator for character sets.
Applies the function \var{kons} across the character set \var{cs} using
initial state value \var{knil}.
That is, if \var{cs} is the empty set, the procedure returns \var{knil}.
Otherwise, some element \var{c} of \var{cs} is chosen; let \var{cs'} be
the remaining, unchosen characters.
The procedure returns
\begin{tightcode}
(char-set-fold \var{kons} (\var{kons} \var{c} \var{knil}) \var{cs'})\end{tightcode}
For example, we could define \ex{char-set-members} (see below)
as
\begin{tightcode}
(lambda (cs) (char-set-fold cons '() cs))\end{tightcode}
\remark{This procedure was formerly named \texttt{\indx{reduce-char-set}}.
The old binding is still provided, but is deprecated and will
probably vanish in a future release.}
\end{desc}
\defun{char-set-for-each}{p cs}{\undefined}
\begin{desc}
Apply procedure \var{p} to each character in the character set \var{cs}.
Note that the order in which \var{p} is applied to the characters in the
set is not specified, and may even change from application to application.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Creating character sets}
\defun{char-set}{\vari{char}1\ldots}{char-set}
\begin{desc}
Return a character set containing the given characters.
\end{desc}
\defun{chars->char-set}{chars}{char-set}
\begin{desc}
Return a character set containing the characters in the list \var{chars}.
\end{desc}
\defun{string->char-set}{s}{char-set}
\begin{desc}
Return a character set containing the characters in the string \var{s}.
\end{desc}
\defun{predicate->char-set}{pred}{char-set}
\begin{desc}
Returns a character set containing every character \var{c} such that
\ex{(\var{pred} \var{c})} returns true.
\end{desc}
\defun{ascii-range->char-set}{lower upper}{char-set}
\begin{desc}
Returns a character set containing every character whose {\Ascii}
code lies in the half-open range $[\var{lower},\var{upper})$.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Querying character sets}
\defun {char-set-members}{char-set}{character-list}
\begin{desc}
This procedure returns a list of the members of \var{char-set}.
\end{desc}
\defunx{char-set-contains?}{char-set char}\boolean
\begin{desc}
This procedure tests \var{char} for membership in set \var{char-set}.
\remark{Previous releases of scsh called this procedure \ex{char-set-member?},
reversing the order of the arguments.
This made sense, but was unfortunately the reverse order in which the
arguments appear in MIT Scheme.
A reasonable argument order was not backwards-compatible with MIT Scheme;
on the other hand, the MIT Scheme argument order was counter-intuitive
and at odds with common mathematical notation and the \ex{member} family
of R4RS procedures.
We sought to escape the dilemma by shifting to a new name.}
\end{desc}
\defun{char-set-size}{cs}\integer
\begin{desc}
Returns the number of elements in character set \var{cs}.
\end{desc}
\defun{char-set-every?}{pred cs}\boolean
\defunx{char-set-any?}{pred cs}\object
\begin{desc}
The \ex{char-set-every?} procedure returns true if predicate \var{pred}
returns true of every character in the character set \var{cs}.
Likewise, \ex{char-set-any?} applies \var{pred} to every character in
character set \var{cs}, and returns the first true value it finds.
If no character produces a true value, it returns false.
The order in which these procedures sequence through the elements of
\var{cs} is not specified.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Deprecated character-set procedures}
\label{sec:char-sets}
\subsection{Character-set algebra}
\defun {char-set-invert}{char-set}{char-set}
\defunx{char-set-union}{\vari{char-set}1\ldots}{char-set}
\defunx{char-set-intersection}{\vari{char-set}1 \vari{char-set}2\ldots}{char-set}
\defunx{char-set-difference}{\vari{char-set}1 \vari{char-set}2\ldots}{char-set}
\begin{desc}
These procedures implement set complement, union, intersection, and difference
for character sets.
The union, intersection, and difference operations are n-ary, associating
to the left; the difference function requires at least one argument, while
union and intersection may be applied to zero arguments.
\end{desc}
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
\defun {char-set-adjoin}{cs \vari{char}1\ldots}{char-set}
\defunx{char-set-delete}{cs \vari{char}1\ldots}{char-set}
\begin{desc}
Add/delete the \vari{char}i characters to/from character set \var{cs}.
\end{desc}
\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}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Standard character sets}
\label{sec:std-csets}
Several character sets are predefined for convenience:
\begin{center}
\newcommand{\entry}[1]{\ex{#1}\index{#1}}
\begin{tabular}{|ll|}
\hline
\entry{char-set:lower-case} & Lower-case alphabetic chars \\
\entry{char-set:upper-case} & Upper-case alphabetic chars \\
\entry{char-set:alphabetic} & Alphabetic chars \\
\entry{char-set:numeric} & Decimal digits: 0--9 \\
\entry{char-set:alphanumeric} & Alphabetic or numeric \\
\entry{char-set:graphic} & Printing characters except space \\
\entry{char-set:printing} & Printing characters including space \\
\entry{char-set:whitespace} & Whitespace characters \\
\entry{char-set:control} & Control characters \\
\entry{char-set:punctuation} & Punctuation characters \\
\entry{char-set:hex-digit} & A hexadecimal digit: 0--9, A--F, a--f \\
\entry{char-set:blank} & Blank characters \\
\entry{char-set:ascii} & A character in the ASCII set. \\
\entry{char-set:empty} & Empty set \\
\entry{char-set:full} & All characters \\
\hline
\end{tabular}
\end{inset}
Note also that the \ex{->char-set} procedure no longer handles a predicate
argument.
\end{center}
The first eleven of these correspond to the character classes defined in
Posix.
Note that there may be characters in \ex{char-set:alphabetic} that are
neither upper or lower case---this might occur in implementations that
use a character type richer than ASCII, such as Unicode.
A ``graphic character'' is one that would put ink on your page.
While the exact composition of these sets may vary depending upon the
character type provided by the Scheme system upon which scsh is running,
here are the definitions for some of the sets in an ASCII character set:
\begin{center}
\newcommand{\entry}[1]{\ex{#1}\index{#1}}
\begin{tabular}{|ll|}
\hline
char-set:alphabetic & A--Z and a--z \\
char-set:lower-case & a--z \\
char-set:upper-case & A--Z \\
char-set:graphic & Alphanumeric + punctuation \\
char-set:whitespace & Space, newline, tab, page,
vertical tab, carriage return \\
char-set:blank & Space and tab \\
char-set:control & ASCII 0--31 and 127 \\
char-set:punctuation & \verb|!"#$%&'()*+,-./:;<=>|\verb#?@[\]^_`{|}~# \\
\hline
\end{tabular}
\end{center}
\defun {char-alphabetic?}\character\boolean
\defunx{char-lower-case?}\character\boolean
\defunx{char-upper-case?}\character\boolean
\defunx{char-numeric? }\character\boolean
\defunx{char-alphanumeric?}\character\boolean
\defunx{char-graphic?}\character\boolean
\defunx{char-printing?}\character\boolean
\defunx{char-whitespace?}\character\boolean
\defunx{char-blank?}\character\boolean
\defunx{char-control?}\character\boolean
\defunx{char-punctuation?}\character\boolean
\defunx{char-hex-digit?}\character\boolean
\defunx{char-ascii?}\character\boolean
\begin{desc}
These predicates are defined in terms of the above character sets.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Linear-update character-set operations}
These procedures have a hybrid pure-functional/side-effecting semantics:
they are allowed, but not required, to side-effect one of their parameters
in order to construct their result.
An implementation may legally implement these procedures as pure,
side-effect-free functions, or it may implement them using side effects,
depending upon the details of what is the most efficient or simple to
implement in terms of the underlying representation.
What this means is that clients of these procedures \emph{may not} rely
upon these procedures working by side effect.
For example, this is not guaranteed to work:
\begin{verbatim}
(let ((cs (char-set #\a #\b #\c)))
(char-set-adjoin! cs #\d)
cs) ; Could be either {a,b,c} or {a,b,c,d}.
\end{verbatim}
However, this is well-defined:
\begin{verbatim}
(let ((cs (char-set #\a #\b #\c)))
(char-set-adjoin! cs #\d)) ; {a,b,c,d}
\end{verbatim}
So clients of these procedures write in a functional style, but must
additionally be sure that, when the procedure is called, there are no
other live pointers to the potentially-modified character set (hence the term
``linear update'').
There are two benefits to this convention:
\begin{itemize}
\item Implementations are free to provide the most efficient possible
implementation, either functional or side-effecting.
\item Programmers may nonetheless continue to assume that character sets
are purely functional data structures: they may be reliably shared
without needing to be copied, uniquified, and so forth.
\end{itemize}
In practice, these procedures are most useful for efficiently constructing
character sets in a side-effecting manner, in some limited local context,
before passing the character set outside the local construction scope to be
used in a functional manner.
Scsh provides no assistance in checking the linearity of the potentially
side-effected parameters passed to these functions --- there's no linear
type checker or run-time mechanism for detecting violations.
\defun{char-set-copy}{cs}{char-set}
\begin{desc}
Returns a copy of the character set \var{cs}.
``Copy'' means that if either the input parameter or the
result value of this procedure is passed to one of the linear-update
procedures described below, the other character set is guaranteed
not to be altered.
(A system that provides pure-functional implementations of the rest of
the linear-operator suite could implement this procedure as the
identity function.)
\end{desc}
\defun{char-set-adjoin!}{cs \vari{char}1\ldots}{char-set}
\begin{desc}
Add the \vari{char}i characters to character set \var{cs}, and
return the result.
This procedure is allowed, but not required, to side-effect \var{cs}.
\end{desc}
\defun{char-set-delete!}{cs \vari{char}1\ldots}{char-set}
\begin{desc}
Remove the \vari{char}i characters to character set \var{cs}, and
return the result.
This procedure is allowed, but not required, to side-effect \var{cs}.
\end{desc}
\defun {char-set-invert!}{char-set}{char-set}
\defunx{char-set-union!}{\vari{char-set}1 \vari{char-set}2\ldots}{char-set}
\defunx{char-set-intersection!}{\vari{char-set}1 \vari{char-set}2\ldots}{char-set}
\defunx{char-set-difference!}{\vari{char-set}1 \vari{char-set}2\ldots}{char-set}
\begin{desc}
These procedures implement set complement, union, intersection, and difference
for character sets.
They are allowed, but not required, to side-effect their first parameter.
The union, intersection, and difference operations are n-ary, associating
to the left.
\end{desc}

View File

@ -49,7 +49,7 @@ Programs can use \ex{with-errno-handler*} to establish
handlers for these exceptions.
If a {\Unix} error arises while \var{thunk} is executing,
\var{handler} is called on two arguments like this:
\var{handler} is called on two arguments:
\codex{(\var{handler} \var{errno} \var{packet})}
\var{packet} is a list of the form
$$\var{packet} = \ex{(\var{errno-msg} \var{syscall} . \var{data})},$$
@ -375,7 +375,7 @@ descriptor to a port with \ex{fdes->outport} or \ex{fdes->inport}, the port
has its revealed field incremented.
Not all file descriptors are created by requests to make ports. Some are
inherited on process invocation via \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=exec&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{exec(2)}}, and are simply part of the
inherited on process invocation via \ex{exec(2)}, and are simply part of the
global environment. Subprocesses may depend upon them, so if a port is later
allocated for these file descriptors, is should be considered as a revealed
port. For example, when the {\Scheme} shell's process starts up, it opens ports
@ -388,7 +388,7 @@ port.
Unrevealed file ports have the nice property that they can be closed when all
pointers to the port are dropped. This can happen during gc, or at an
\ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=exec&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{exec()}}---since all memory is dropped at an \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=exec&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{exec()}}. No one knows the
\ex{exec()}---since all memory is dropped at an \ex{exec()}. No one knows the
file descriptor associated with the port, so the exec'd process certainly
can't refer to it.
@ -399,11 +399,11 @@ the garbage collector. This is critical, since shell programming
absolutely requires access to the {\Unix} file descriptors, as their
numerical values are a critical part of the process interface.
A port's underlying file descriptor can be shifted around with \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=dup&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{dup(2)}}
A port's underlying file descriptor can be shifted around with \ex{dup(2)}
when convenient. That is, the actual file descriptor on top of which a port is
constructed can be shifted around underneath the port by the scsh kernel when
necessary. This is important, because when the user is setting up file
descriptors prior to a \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=exec&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{exec(2)}}, he may explicitly use a file descriptor
descriptors prior to a \ex{exec(2)}, he may explicitly use a file descriptor
that has already been allocated to some port. In this case, the scsh kernel
just shifts the port's file descriptor to some new location with \ex{dup},
freeing up its old descriptor. This prevents errors from happening in the
@ -431,8 +431,8 @@ alive and well so that it can subsequently be dup'd into descriptor 0 for
\ex{prog}'s stdin.
The port-shifting machinery makes the following guarantee: a port is only
moved when the underlying file descriptor is closed, either by a \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=close&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{close()}}
or a \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=dup2&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{dup2()}} operation. Otherwise a port/file-descriptor association is
moved when the underlying file descriptor is closed, either by a \ex{close()}
or a \ex{dup2()} operation. Otherwise a port/file-descriptor association is
stable.
Under normal circumstances, all this machinery just works behind the scenes to
@ -524,17 +524,17 @@ Decrement the port's revealed count.
\defunx{dup->outport} {fd/port [newfd]} {port}
\defunx{dup->fdes} {fd/port [newfd]} {fd}
\begin{desc}
These procedures provide the functionality of C's \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=dup&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{dup()}} and \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=dup2&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{dup2()}}.
These procedures provide the functionality of C's \ex{dup()} and \ex{dup2()}.
The different routines return different types of values:
\ex{dup->inport}, \ex{dup->outport}, and \ex{dup->fdes} return
input ports, output ports, and integer file descriptors, respectively.
\ex{dup}'s return value depends on on the type of
\var{fd/port}---it maps fd$\rightarrow$fd and port$\rightarrow$port.
These procedures use the {\Unix} \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=dup&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{dup()}} syscall to replicate
These procedures use the {\Unix} \ex{dup()} syscall to replicate
the file descriptor or file port \var{fd/port}.
If a \var{newfd} file descriptor is given, it is used as the target of
the dup operation, \ie, the operation is a \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=dup2&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{dup2()}}.
the dup operation, \ie, the operation is a \ex{dup2()}.
In this case, procedures that return a port (such as \ex{dup->inport})
will return one with the revealed count set to one.
For example, \ex{(dup (current-input-port) 5)} produces
@ -646,8 +646,8 @@ These procedures allow reading and writing of an open file's status flags
%
\begin{tabular}[t]{@{}>{\ttfamily}l@{}}
%% These are gettable and settable
open/append \\
open/non-blocking \\
open/append \\
open/non-blocking \\
open/async \textrm{(Non-\Posix)} \\
open/fsync \textrm{(Non-\Posix)}
\end{tabular}
@ -659,9 +659,9 @@ These procedures allow reading and writing of an open file's status flags
%
\begin{tabular}[t]{@{}>{\ttfamily}l@{}}
%% These are gettable, not settable
open/read \\
open/write \\
open/read+write \\
open/read \\
open/write \\
open/read+write \\
open/access-mask
\end{tabular}
\\\cline{2-3}
@ -673,21 +673,21 @@ These procedures allow reading and writing of an open file's status flags
%
\begin{tabular}[t]{@{}>{\ttfamily}l@{}}
%% These are neither gettable nor settable.
open/create \\
open/exclusive \\
open/no-control-tty \\
open/truncate
open/create \\
open/exclusive \\
open/no-control-tty \\
open/truncate
\end{tabular}
\end{tabular}
\end{center}
\caption{Status flags for \texttt{open-file},
\texttt{fdes-status} and \texttt{set-fdes-status}.
Only {\Posix} flags are guaranteed to be present;
your operating system may define others.
The \texttt{open/access-mask} value is not an actual flag,
but a bit mask used to select the field for the \texttt{open/read},
\texttt{open/write} and \texttt{open/read+write} bits.
}
\texttt{fdes-status} and \texttt{set-fdes-status}.
Only {\Posix} flags are guaranteed to be present;
your operating system may define others.
The \texttt{open/access-mask} value is not an actual flag,
but a bit mask used to select the field for the \texttt{open/read},
\texttt{open/write} and \texttt{open/read+write} bits.
}
\label{table:fdes-status-flags}
\end{table}
@ -703,7 +703,7 @@ Returns two ports, the read and write end-points of a {\Unix} pipe.
\defun{read-string}{nbytes [fd/port]} {{\str} or \sharpf}
\dfnix{read-string!} {str [fd/port start end]} {nread or \sharpf}{procedure}
{read-string"!@\texttt{read-string"!}}
{read-string"!@\texttt{read-string"!}}
\begin{desc}
These calls read exactly as much data as you requested, unless
there is not enough data (eof).
@ -731,7 +731,7 @@ Returns two ports, the read and write end-points of a {\Unix} pipe.
\defun {read-string/partial} {nbytes [fd/port]} {{\str} or \sharpf}
\dfnix{read-string!/partial} {str [fd/port start end]} {nread or \sharpf}
{procedure}{read-string"!/partial@\texttt{read-string"!/partial}}
{procedure}{read-string"!/partial@\texttt{read-string"!/partial}}
\begin{desc}
%
These are atomic best-effort/forward-progress calls.
@ -816,7 +816,7 @@ allowed to contain {\sharpf} values as well as integers and ports.
\remark{I have found the \ex{select!} interface to be the more
useful of the two. After the system call, it allows you
to check a specific I/O channel in constant time.}
to check a specific I/O channel in constant time.}
\end{desc}
@ -901,13 +901,13 @@ This procedure allows the programmer to assign a particular I/O buffering
policy to a port, and to choose the size of the associated buffer.
It may only be used on new ports, \ie, before I/O is performed on the port.
There are three buffering policies that may be chosen:
\begin{inset}
\begin{tabular}{l@{\qquad}l}
\ex{bufpol/block} & General block buffering (general default) \\
\ex{bufpol/line} & Line buffering (tty default) \\
\ex{bufpol/none} & Direct I/O---no buffering
\end{tabular}
\end{inset}
\begin{inset}
\begin{tabular}{l@{\qquad}l}
\ex{bufpol/block} & General block buffering (general default) \\
\ex{bufpol/line} & Line buffering (tty default) \\
\ex{bufpol/none} & Direct I/O---no buffering
\end{tabular}
\end{inset}
The line buffering policy flushes output whenever a newline is output;
whenever the buffer is full; or whenever an input is read from stdin.
Line buffering is the default for ports open on terminal devices.
@ -953,16 +953,21 @@ It is not without reason that the FreeBSD man pages refer to {\Posix}
file locking as ``completely stupid.''
Scsh moves Scheme ports from file descriptor to file descriptor with
\ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=dup&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{dup()}} and \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=close&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{close()}} as required by the runtime,
\ex{dup()} and \ex{close()} as required by the runtime,
so it is impossible to keep file locks open across one of these shifts.
Hence we can only offer {\Posix} advisory file locking directly on raw
integer file descriptors;
regrettably, there are no facilities for locking Scheme ports.
Note that once a Scheme port is revealed in scsh, the runtime will not
shift the port around with \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=dup&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{dup()}} and \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=close&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{close()}}.
shift the port around with \ex{dup()} and \ex{close()}.
This means the file-locking procedures can then be applied to the port's
associated file descriptor.
NeXTSTEP users should also note that even minimalist {\Posix} file locking
is not supported for NFS-mounted files in NeXTSTEP; NeXT claims they will
fix this in NS release 4.
We'd appreciate hearing from users when and if this happens.
}
{\Posix} allows the user to lock a region of a file with either
@ -1117,7 +1122,7 @@ while \ex{delete-filesys-object} simply returns.
If you override an existing object, then \var{old-fname}
and \var{new-fname} must type-match---either both directories,
or both non-directories.
This is required by the semantics of {\Unix} \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=rename&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{rename()}}.
This is required by the semantics of {\Unix} \ex{rename()}.
\remark{
There is an unfortunate atomicity problem with the \ex{rename-file}
@ -1125,7 +1130,7 @@ while \ex{delete-filesys-object} simply returns.
specify no-override, but create file \ex{new-fname} sometime between
\ex{rename-file}'s existence check and the actual rename operation,
your file will be clobbered with \ex{old-fname}. There is no way to fix
this problem, given the semantics of {\Unix} \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=rename&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{rename()}};
this problem, given the semantics of {\Unix} \ex{rename()};
at least it is highly unlikely to occur in practice.
}
\end{defundescx}
@ -1165,7 +1170,7 @@ while \ex{delete-filesys-object} simply returns.
These procedures are not {\Posix}.
Interestingly enough, \ex{sync\=file\=system} doesn't actually
do what it is claimed to do. We just threw it in for humor value.
See the \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=sync&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{sync(2)}} man page for {\Unix} enlightenment.
See the \ex{sync(2)} man page for {\Unix} enlightenment.
\end{desc}
\begin{defundesc} {truncate-file} {fname/fd/port len} \undefined
@ -1237,12 +1242,12 @@ Example:
\remark{\ex{file-info} was named \ex{file-attributes} in releases of scsh
prior to release 0.4. We changed the name to \ex{file-info} for
consistency with the other information-retrieval procedures in
scsh: \ex{user-info}, \ex{group-info}, \ex{host-info},
\ex{network-info }, \ex{service-info}, and \ex{protocol-info}.
consistency with the other information-retrieval procedures in
scsh: \ex{user-info}, \ex{group-info}, \ex{host-info},
\ex{network-info }, \ex{service-info}, and \ex{protocol-info}.
The \ex{file-attributes} binding is still supported in the current
release of scsh, but is deprecated, and may go away in a future
The \ex{file-attributes} binding is still supported in the current
release of scsh, but is deprecated, and may go away in a future
release.}
\end{defundesc}
@ -1290,7 +1295,7 @@ For example,
calls do not take a \var{chase?} flag.
Note that these procedures use the process' \emph{effective} user
and group ids for permission checking. {\Posix} defines an \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=access&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{access()}}
and group ids for permission checking. {\Posix} defines an \ex{access()}
function that uses the process' real uid and gids. This is handy
for setuid programs that would like to find out if the actual user
has specific rights; scsh ought to provide this functionality (but doesn't
@ -1310,7 +1315,7 @@ For example,
These should be disentangled.
Some of these problems could be avoided if {\Posix} had a real-uid
variant of the \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=access&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{access()}} call we could use, but the atomicity
variant of the \ex{access()} call we could use, but the atomicity
issue is still a problem. In the final analysis, the only way to
find out if you have the right to perform an operation on a file
is to try and open it for the desired operation. These permission-checking
@ -1387,8 +1392,8 @@ Returns:
Note that the rules of backslash for {\Scheme} strings and glob patterns
work together to require four backslashes in a row to specify a
single literal backslash. Fortunately, it is very rare that a backslash
occurs in a Unix file name.
single literal backslash. Fortunately, this should be a rare
occurrence.
A glob subpattern will not match against dot files unless the first
character of the subpattern is a literal ``\ex{.}''.
@ -1460,14 +1465,14 @@ All wild-card characters in \var{str} are quoted with a backslash.
\begin{defundesc}{file-match}{root dot-files? \vari{pat}1 \vari{pat}2 {\ldots} \vari{pat}n}{string list}
\note{This procedure is deprecated, and will probably either go away or
be substantially altered in a future release. New code should not
call this procedure. The problem is that it relies upon
Posix-notation regular expressions; the rest of scsh has been
converted over to the new SRE notation.}
be substantially altered in a future release. New code should not
call this procedure. The problem is that it relies upon
Posix-notation regular expressions; the rest of scsh has been
converted over to the new SRE notation.}
\ex{file-match} provides a more powerful file-matching service, at the
expense of a less convenient notation. It is intermediate in
power between most shell matching machinery and recursive \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=find&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{find(1)}}.
power between most shell matching machinery and recursive \ex{find(1)}.
Each pattern is a regexp. The procedure searches from \var{root},
matching the first-level files against pattern \vari{pat}1, the
@ -1716,7 +1721,7 @@ a slash character---it is used directly. So a program with a name like
\ex{"bin/prog"} always executes the program \ex{bin/prog} in the current working
directory. See \verb|$path| and \verb|exec-path-list|, below.
Note that there is no analog to the C function \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=execv&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{execv()}}.
Note that there is no analog to the C function \ex{execv()}.
To get the effect just do
\codex{(apply exec prog arglist)}
@ -1724,7 +1729,7 @@ All of these procedures flush buffered output and close unrevealed ports
before executing the new binary.
To avoid flushing buffered output, see \verb|%exec| below.
Note that the C \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=exec&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{exec()}} procedure allows the zeroth element of the
Note that the C \ex{exec()} procedure allows the zeroth element of the
argument vector to be different from the file being executed, \eg
%
\begin{inset}
@ -1802,7 +1807,7 @@ Suspend the current process with a SIGSTOP signal.
\defun {fork} {[thunk]} {proc or \sharpf}
\defunx {\%fork} {[thunk]} {proc or \sharpf}
\begin{desc}
\ex{fork} with no arguments is like C \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=fork&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{fork()}}.
\ex{fork} with no arguments is like C \ex{fork()}.
In the parent process, it returns the child's \emph{process object}
(see below for more information on process objects).
In the child process, it returns {\sharpf}.
@ -1869,7 +1874,7 @@ Suspend the current process with a SIGSTOP signal.
(display "Hello, world.\\n"))))
(set-current-input-port! (fdes->inport 0)
(read-line) ; Read the string output by the child.\end{code}
(read-line) ; Read the string output by the child.\end{code}
None of this is necessary when the I/O is performed by an exec'd
program in the child or parent process, only when the pipe will
be referenced by Scheme code through one of the default current I/O
@ -1893,7 +1898,7 @@ They are created by the \ex{fork} procedure, and have the following
exposed structure:
\begin{code}
(define-record proc
pid)\end{code}
pid)\end{code}
\index{proc}\index{proc?}\index{proc:pid}
The only exposed slot in a proc record is the process' pid,
the integer id assigned by Unix to the process.
@ -1911,10 +1916,10 @@ If there is no process object in the system indexed by the given pid,
\begin{center}
\begin{tabular}{|l|l|}
\hline
\var{probe?} & Return \\ \hline\hline
\sharpf & \emph{signal error condition.} \\ \hline
\ex{'create} & Create new proc object. \\ \hline
True value & \sharpf \\ \hline
\var{probe?} & Return \\ \hline\hline
\sharpf & \emph{signal error condition.} \\ \hline
\ex{'create} & Create new proc object. \\ \hline
True value & \sharpf \\ \hline
\end{tabular}
\end{center}
\end{defundesc}
@ -1970,29 +1975,29 @@ The policy is determined by applying this procedure to one of the
values \ex{'early}, \ex{'late}, or {\sharpf} (\ie, no autoreap).
\begin{description}
\item [early]
The child is reaped from the {\Unix} kernel's process table
into scsh as soon as it dies. This is done by having a
The child is reaped from the {\Unix} kernel's process table
into scsh as soon as it dies. This is done by having a
signal handler for the \ex{SIGCHLD} signal reap the process.
\emph{
If a scsh program sets its own handler for the \ex{SIGCHLD}
signal, the handler must reap dead children
by calling \ex{wait}, \ex{wait-any}, or \ex{reap-zombies}.}
We deprecate interrupt-driven code, and hope to provide
alternative tools in a future, multi-threaded release of scsh.
\emph{
If a scsh program sets its own handler for the \ex{SIGCHLD}
signal, the handler must reap dead children
by calling \ex{wait}, \ex{wait-any}, or \ex{reap-zombies}.}
We deprecate interrupt-driven code, and hope to provide
alternative tools in a future, multi-threaded release of scsh.
\item [late]
The child is not autoreaped until it dies \emph{and} the scsh program
drops all pointers to its process object. That is, the process
table is cleaned out during garbage collection.
\oops{The \ex{late} policy is not supported under the current
release of scsh. It requires more sophisticated gc hooks than
we can get from the release of {\scm} that we use.}
The child is not autoreaped until it dies \emph{and} the scsh program
drops all pointers to its process object. That is, the process
table is cleaned out during garbage collection.
\oops{The \ex{late} policy is not supported under the current
release of scsh. It requires more sophisticated gc hooks than
we can get from the release of {\scm} that we use.}
\item [\sharpf]
If autoreaping is turned off, process reaping is completely under
control of the programmer, who can force outstanding zombies to
be reaped by manually calling the \ex{reap-zombies} procedure
(see below).
If autoreaping is turned off, process reaping is completely under
control of the programmer, who can force outstanding zombies to
be reaped by manually calling the \ex{reap-zombies} procedure
(see below).
\end{description}
Note that under any of the autoreap policies, a particular process $p$ can
be manually reaped into scsh by simply calling \ex{(wait $p$)}.
@ -2072,34 +2077,34 @@ forms, or use \ex{wait-any} to wait for the children to exit.
The \var{flags} argument is an integer whose bits specify
additional options. It is composed by or'ing together the following
flags:
\begin{center}
\begin{tabular}{|l|l|}
\hline
Flag & Meaning \\ \hline \hline
\ex{wait/poll} & Return {\sharpf} immediately if
child still active. \\ \hline
\ex{wait/stopped-children} & Wait for suspend as well as exit. \\ \hline
\end{tabular}
\end{center}
\begin{center}
\begin{tabular}{|l|l|}
\hline
Flag & Meaning \\ \hline \hline
\ex{wait/poll} & Return {\sharpf} immediately if
child still active. \\ \hline
\ex{wait/stopped-children} & Wait for suspend as well as exit. \\ \hline
\end{tabular}
\end{center}
\end{desc}
\begin{defundesc} {wait-any} {[flags]} {[proc status]}
The optional \var{flags} argument is as for \ex{wait}.
This procedure waits for any child process to exit (or stop, if the
\ex{wait/stopped-children} flag is used)
\ex{wait/stopped-children} flag is used)
It returns the process' process object and status code.
If there are no children left for which to wait, the two values
\ex{[{\sharpf} {\sharpt}]} are returned.
\ex{[{\sharpf} {\sharpt}]} are returned.
If the \ex{wait/poll} flag is used, and none of the children
are immediately eligble for waiting,
then the values \ex{[{\sharpf} {\sharpf}]} are returned:
\begin{center}
\begin{tabular}{|l|l|}
\hline
[{\sharpf} {\sharpf}] & Poll, none ready \\ \hline
[{\sharpf} {\sharpt}] & No children \\ \hline
\end{tabular}
\end{center}
then the values \ex{[{\sharpf} {\sharpf}]} are returned:
\begin{center}
\begin{tabular}{|l|l|}
\hline
[{\sharpf} {\sharpf}] & Poll, none ready \\ \hline
[{\sharpf} {\sharpt}] & No children \\ \hline
\end{tabular}
\end{center}
\ex{Wait-any} will not return a process that has been previously waited
by any other process-wait procedure (\ex{wait}, \ex{wait-any},
@ -2167,7 +2172,7 @@ Otherwise, this function returns false.
%This procedure, ported from early T implementations,
%returns true iff \ex{(\var{proc})} returns at all.
%\remark{The current implementation is a constant function returning {\sharpt},
% which suffices for all {\Unix} implementations of which we are aware.}
% which suffices for all {\Unix} implementations of which we are aware.}
%\end{desc}
\section{Process state}
@ -2242,7 +2247,7 @@ I can't remember how \ex{set-priority} and \ex{priority} work, so no
\begin{desc}
These routines get and set the effective and real user and group ids.
The \ex{set-uid} and \ex{set-gid} routines correspond to the {\Posix}
\ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=setuid&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{setuid()}} and \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=setgid&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{setgid()}} procedures.
\ex{setuid()} and \ex{setgid()} procedures.
\end{desc}
@ -2453,39 +2458,39 @@ asynchronous {\Unix} signals (table~\ref{table:signals-and-interrupts}).
\begin{tabular}{lll}\hline
Interrupt & Unix signal & OS Variant \\ \hline\hline
\kwd{interrupt/alrm}\footnote{Also bound to {\scm} interrupt
\kwd{interrupt/alarm}.}
& \kwd{signal/alrm} & \Posix \\
\kwd{interrupt/alarm}.}
& \kwd{signal/alrm} & \Posix \\
%
\kwd{interrupt/int}\footnote{Also bound to {\scm} interrupt
\kwd{interrupt/keyboard}.}
& \kwd{signal/int} & \Posix \\
\kwd{interrupt/keyboard}.}
& \kwd{signal/int} & \Posix \\
%
\kwd{interrupt/memory-shortage} & N/A & \\
\kwd{interrupt/chld} & \kwd{signal/chld} & \Posix \\
\kwd{interrupt/cont} & \kwd{signal/cont} & \Posix \\
\kwd{interrupt/hup} & \kwd{signal/hup} & \Posix \\
\kwd{interrupt/quit} & \kwd{signal/quit} & \Posix \\
\kwd{interrupt/term} & \kwd{signal/term} & \Posix \\
\kwd{interrupt/tstp} & \kwd{signal/tstp} & \Posix \\
\kwd{interrupt/usr1} & \kwd{signal/usr1} & \Posix \\
\kwd{interrupt/usr2} & \kwd{signal/usr2} & \Posix \\
\kwd{interrupt/memory-shortage} & N/A & \\
\kwd{interrupt/chld} & \kwd{signal/chld} & \Posix \\
\kwd{interrupt/cont} & \kwd{signal/cont} & \Posix \\
\kwd{interrupt/hup} & \kwd{signal/hup} & \Posix \\
\kwd{interrupt/quit} & \kwd{signal/quit} & \Posix \\
\kwd{interrupt/term} & \kwd{signal/term} & \Posix \\
\kwd{interrupt/tstp} & \kwd{signal/tstp} & \Posix \\
\kwd{interrupt/usr1} & \kwd{signal/usr1} & \Posix \\
\kwd{interrupt/usr2} & \kwd{signal/usr2} & \Posix \\
\\
\kwd{interrupt/info} & \kwd{signal/info} & BSD only \\
\kwd{interrupt/io} & \kwd{signal/io} & BSD + SVR4 \\
\kwd{interrupt/poll} & \kwd{signal/poll} & SVR4 only \\
\kwd{interrupt/prof} & \kwd{signal/prof} & BSD + SVR4 \\
\kwd{interrupt/pwr} & \kwd{signal/pwr} & SVR4 only \\
\kwd{interrupt/urg} & \kwd{signal/urg} & BSD + SVR4 \\
\kwd{interrupt/vtalrm} & \kwd{signal/vtalrm} & BSD + SVR4 \\
\kwd{interrupt/winch} & \kwd{signal/winch} & BSD + SVR4 \\
\kwd{interrupt/xcpu} & \kwd{signal/xcpu} & BSD + SVR4 \\
\kwd{interrupt/xfsz} & \kwd{signal/xfsz} & BSD + SVR4 \\
\kwd{interrupt/info} & \kwd{signal/info} & BSD only \\
\kwd{interrupt/io} & \kwd{signal/io} & BSD + SVR4 \\
\kwd{interrupt/poll} & \kwd{signal/poll} & SVR4 only \\
\kwd{interrupt/prof} & \kwd{signal/prof} & BSD + SVR4 \\
\kwd{interrupt/pwr} & \kwd{signal/pwr} & SVR4 only \\
\kwd{interrupt/urg} & \kwd{signal/urg} & BSD + SVR4 \\
\kwd{interrupt/vtalrm} & \kwd{signal/vtalrm} & BSD + SVR4 \\
\kwd{interrupt/winch} & \kwd{signal/winch} & BSD + SVR4 \\
\kwd{interrupt/xcpu} & \kwd{signal/xcpu} & BSD + SVR4 \\
\kwd{interrupt/xfsz} & \kwd{signal/xfsz} & BSD + SVR4 \\
\end{tabular}
\end{center}
\caption{{\scm} virtual-machine interrupts and related {\Unix} signals.
Only the {\Posix} signals are guaranteed to be defined; however,
your implementation and OS may define other signals and
interrupts not listed here.}
Only the {\Posix} signals are guaranteed to be defined; however,
your implementation and OS may define other signals and
interrupts not listed here.}
\end{minipage}
\label{table:signals-and-interrupts}
\end{table}
@ -2495,31 +2500,31 @@ Interrupt & Unix signal & OS Variant \\ \hline\hline
\begin{center}
\begin{tabular}{lll}\hline
Unix signal & Type & OS Variant \\ \hline\hline
\kwd{signal/stop} & Uncatchable & \Posix \\
\kwd{signal/kill} & Uncatchable & \Posix \\
\kwd{signal/stop} & Uncatchable & \Posix \\
\kwd{signal/kill} & Uncatchable & \Posix \\
\\
\kwd{signal/abrt} & Synchronous & \Posix \\
\kwd{signal/fpe} & Synchronous & \Posix \\
\kwd{signal/ill} & Synchronous & \Posix \\
\kwd{signal/pipe} & Synchronous & \Posix \\
\kwd{signal/segv} & Synchronous & \Posix \\
\kwd{signal/ttin} & Synchronous & \Posix \\
\kwd{signal/ttou} & Synchronous & \Posix \\
\kwd{signal/abrt} & Synchronous & \Posix \\
\kwd{signal/fpe} & Synchronous & \Posix \\
\kwd{signal/ill} & Synchronous & \Posix \\
\kwd{signal/pipe} & Synchronous & \Posix \\
\kwd{signal/segv} & Synchronous & \Posix \\
\kwd{signal/ttin} & Synchronous & \Posix \\
\kwd{signal/ttou} & Synchronous & \Posix \\
\\
\kwd{signal/bus} & Synchronous & BSD + SVR4 \\
\kwd{signal/emt} & Synchronous & BSD + SVR4 \\
\kwd{signal/iot} & Synchronous & BSD + SVR4 \\
\kwd{signal/sys} & Synchronous & BSD + SVR4 \\
\kwd{signal/trap} & Synchronous & BSD + SVR4 \\
\kwd{signal/bus} & Synchronous & BSD + SVR4 \\
\kwd{signal/emt} & Synchronous & BSD + SVR4 \\
\kwd{signal/iot} & Synchronous & BSD + SVR4 \\
\kwd{signal/sys} & Synchronous & BSD + SVR4 \\
\kwd{signal/trap} & Synchronous & BSD + SVR4 \\
\end{tabular}
\end{center}
\caption{Uncatchable and synchronous {\Unix} signals. While these signals
may be sent with \texttt{signal-process} or
\texttt{signal-process-group},
\texttt{signal-process-group},
there are no corresponding scsh interrupt handlers.
Only the {\Posix} signals are guaranteed to be defined; however,
your implementation and OS may define other signals not listed
here.}
your implementation and OS may define other signals not listed
here.}
\label{table:uncatchable-signals}
\end{table}
Note that scsh does \emph{not} support signal handlers for ``synchronous''
@ -2604,8 +2609,8 @@ A handler is either \ex{\#f} (ignore), \ex{\#t} (default), or a
procedure taking an integer argument.
\end{defundesc}
% %set-unix-signal-handler
% %unix-signal-handler
% %set-unix-signal-handler
% %unix-signal-handler
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Time}
@ -2618,6 +2623,9 @@ all of the complexity is optional,
and defaulting all the optional arguments reduces the system
to a simple interface.
\remark{This time package does not currently work with NeXTSTEP, as NeXTSTEP
does not provide a {\Posix}-compliant time library that will even link.}
\subsection{Terminology}
``UTC'' and ``UCT'' stand for ``universal coordinated time,'' which is the
official name for what is colloquially referred to as ``Greenwich Mean
@ -2714,13 +2722,13 @@ This is described for each procedure below.
can be one of:
\begin{inset}
\begin{tabular}{lp{0.7\linewidth}}
\ex{\#f} & Local time \\
Integer & Seconds of offset from UTC. For example,
New York City is -18000 (-5 hours), San Francisco
is -28800 (-8 hours). \\
String & A {\Posix} time zone string understood by the OS
(\ie., the sort of time zone assigned to the \ex{\$TZ}
environment variable).
\ex{\#f} & Local time \\
Integer & Seconds of offset from UTC. For example,
New York City is -18000 (-5 hours), San Francisco
is -28800 (-8 hours). \\
String & A {\Posix} time zone string understood by the OS
(\ie., the sort of time zone assigned to the \ex{\$TZ}
environment variable).
\end{tabular}
\end{inset}
An integer time zone gives the number of seconds you must add to UTC
@ -2750,25 +2758,25 @@ String & A {\Posix} time zone string understood by the OS
is always 0, and \ex{(ticks/sec)} returns 1.
\begin{remarkenv}
I chose to represent system clock resolution as ticks/sec
instead of sec/tick to increase the odds that the value could
be represented as an exact integer, increasing efficiency and
I chose to represent system clock resolution as ticks/sec
instead of sec/tick to increase the odds that the value could
be represented as an exact integer, increasing efficiency and
making it easier for Scheme implementations that don't have
sophisticated numeric support to deal with the quantity.
sophisticated numeric support to deal with the quantity.
You can convert seconds and ticks to seconds with the expression
\codex{(+ \var{secs} (/ \var{ticks} (ticks/sec)))}
Given that, why not have the fine-grain time procedure just
return a non-integer real for time? Following Common Lisp, I chose to
allow the system clock to report sub-second time in its own units to
lower the overhead of determining the time. This would be important
for a system that wanted to precisely time the duration of some
event. Time stamps could be collected with little overhead, deferring
the overhead of precisely calculating with them until after collection.
You can convert seconds and ticks to seconds with the expression
\codex{(+ \var{secs} (/ \var{ticks} (ticks/sec)))}
Given that, why not have the fine-grain time procedure just
return a non-integer real for time? Following Common Lisp, I chose to
allow the system clock to report sub-second time in its own units to
lower the overhead of determining the time. This would be important
for a system that wanted to precisely time the duration of some
event. Time stamps could be collected with little overhead, deferring
the overhead of precisely calculating with them until after collection.
This is all a bit academic for the {\scm} implementation, where
we determine time with a heavyweight system call, but it's nice
to plan for the future.
This is all a bit academic for the {\scm} implementation, where
we determine time with a heavyweight system call, but it's nice
to plan for the future.
\end{remarkenv}
\end{desc}
@ -2787,13 +2795,13 @@ String & A {\Posix} time zone string understood by the OS
``\ex{UTC+\emph{hh}:\emph{mm}:\emph{ss}}'';
the trailing \ex{:\emph{mm}:\emph{ss}} portion is deleted if it is zeroes.
\oops{The Posix facility for converting dates to times, \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=mktime&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{mktime()}},
\oops{The Posix facility for converting dates to times, \ex{mktime()},
has a broken design: it indicates an error by returning -1, which
is also a legal return value (for date 23:59:59 UCT, 12/31/1969).
Scsh resolves the ambiguity in a paranoid fashion: it always
reports an error if the underlying Unix facility returns -1.
We feel your pain.
}
We feel your pain.
}
\end{desc}
\defun {time} {} \integer
@ -2815,8 +2823,8 @@ String & A {\Posix} time zone string understood by the OS
\ex{summer?} field is used to resolve ambiguities:
\begin{tightinset}
\begin{tabular}{ll}
\ex{\#f} & Resolve an ambiguous time in favor of non-summer time. \\
true & Resolve an ambiguous time in favor of summer time.
\ex{\#f} & Resolve an ambiguous time in favor of non-summer time. \\
true & Resolve an ambiguous time in favor of summer time.
\end{tabular}
\end{tightinset}
This is useful in boundary cases during the change-over. For example,
@ -2840,7 +2848,7 @@ true & Resolve an ambiguous time in favor of summer time.
\ex{Date->string} formats the date as a 24-character string of the
form:
\begin{tightinset}
Sun Sep 16 01:03:52 1973
Sun Sep 16 01:03:52 1973
\end{tightinset}
\ex{Format-date} formats the date according to the format string
@ -2858,28 +2866,28 @@ true & Resolve an ambiguous time in favor of summer time.
\verb|~b| & abbreviated month name \\
\verb|~B| & full month name \\
\verb|~c| & time and date using the time and date representation
for the locale (\verb|~X ~x|) \\
for the locale (\verb|~X ~x|) \\
\verb|~d| & day of the month as a decimal number (01-31) \\
\verb|~H| & hour based on a 24-hour clock
as a decimal number (00-23) \\
as a decimal number (00-23) \\
\verb|~I| & hour based on a 12-hour clock
as a decimal number (01-12) \\
as a decimal number (01-12) \\
\verb|~j| & day of the year as a decimal number (001-366) \\
\verb|~m| & month as a decimal number (01-12) \\
\verb|~M| & minute as a decimal number (00-59) \\
\verb|~p| & AM/PM designation associated with a 12-hour clock \\
\verb|~S| & second as a decimal number (00-61) \\
\verb|~U| & week number of the year;
Sunday is first day of week (00-53) \\
Sunday is first day of week (00-53) \\
\verb|~w| & weekday as a decimal number (0-6), where Sunday is 0 \\
\verb|~W| & week number of the year;
Monday is first day of week (00-53) \\
Monday is first day of week (00-53) \\
\verb|~x| & date using the date representation for the locale \\
\verb|~X| & time using the time representation for the locale \\
\verb|~y| & year without century (00-99) \\
\verb|~Y| & year with century (\eg 1990) \\
\verb|~Z| & time zone name or abbreviation, or no characters
if no time zone is determinable
if no time zone is determinable
\end{tabular}
\caption{\texttt{format-date} conversion specifiers}
@ -2909,10 +2917,10 @@ true & Resolve an ambiguous time in favor of summer time.
% (\eg, ``EST'' and ``EDT'')\@. \var{Summer?} is interpreted as follows:
% \begin{inset}
% \begin{tabular}{lp{0.7\linewidth}}
% Integer & A time value.
% The variant in use at that time is returned. \\
% \ex{\#f} & The standard time name is returned. \\
% \emph{Otherwise} & The summer time name is returned.
% Integer & A time value.
% The variant in use at that time is returned. \\
% \ex{\#f} & The standard time name is returned. \\
% \emph{Otherwise} & The summer time name is returned.
% \end{tabular}
% \end{inset}
% \ex{Summer?} defaults to the case that pertains at the time of the call.
@ -2920,7 +2928,7 @@ true & Resolve an ambiguous time in favor of summer time.
%\end{desc}
\dfni {fill-in-date!}{date}{date}{procedure}
{fill-in-date"!@\texttt{fill-in-date"!}}
{fill-in-date"!@\texttt{fill-in-date"!}}
\begin{desc}
This procedure fills in missing, redundant slots in a date record.
In decreasing order of priority:
@ -2984,8 +2992,7 @@ If \var{val} is {\sharpf}, then any entry for \var{var} is deleted.
an alist, \eg,
\begin{code}
(("TERM" . "vt100")
("SHELL" . "/usr/local/bin/scsh")
("PATH" . "/sbin:/usr/sbin:/bin:/usr/bin")
("SHELL" . "/bin/csh")
("EDITOR" . "emacs")
\ldots)\end{code}
\end{desc}
@ -2998,21 +3005,6 @@ If \var{val} is {\sharpf}, then any entry for \var{var} is deleted.
environment (\ie, converted to a null-terminated C vector of
\ex{"\var{var}=\var{val}"} strings which is assigned to the global
\ex{char **environ}).
\begin{code}
;;; Note $PATH entry is converted
;;; to /sbin:/usr/sbin:/bin:/usr/bin.
(alist->env '(("TERM" . "vt100")
("PATH" "/sbin" "/usr/sbin" "/bin")
("SHELL" . "/usr/local/bin/scsh")))
\end{code}
Note that \ex{env->alist} and \ex{alist->env} are not exact
inverses---\ex{alist->env} will convert a list value into a single
colon-separated string, but \ex{env->alist} will not parse colon-separated
values into lists. (See the \ex{\$PATH} element in the examples given for
each procedure.)
\end{desc}
The following three functions help the programmer manipulate alist
@ -3090,30 +3082,18 @@ Example: These four pieces of code all run the mailer with special
\subsection{Path lists and colon lists}
When environment variables such as \ex{\$PATH} need to encode a list of
strings (such as a list of directories to be searched),
the common Unix convention is to separate the list elements with
colon delimiters.\footnote{\ldots and hope the individual list elements
don't contain colons themselves.}
Environment variables such as \ex{\$PATH} encode a list of strings
by separating the list elements with colon delimiters.
Once parsed into actual lists, these ordered lists can be manipulated
with the following two functions.
To convert between the colon-separated string encoding and the
list-of-strings representation, see the \ex{infix-splitter} function
(section~\ref{sec:field-splitter}) and the string library's
\ex{string-join} function.
For example,
\begin{code}
(define split (infix-splitter (rx ":")))
(split "/sbin:/bin::/usr/bin") {\evalsto}
'("/sbin" "/bin" "" "/usr/bin")
(string-join ":" '("/sbin" "/bin" "" "/usr/bin")) {\evalsto}
"/sbin:/bin::/usr/bin"\end{code}
The following two functions are useful for manipulating these ordered lists,
once they have been parsed from their colon-separated form.
list-of-strings representation, see the \ex{field-reader} and
\ex{join-strings} functions in section~\ref{sec:field-reader}.
\remark{An earlier release of scsh provided the \ex{split-colon-list}
and \ex{string-list->colon-list} functions. These have been
removed from scsh, and are replaced by the more general
parsers and unparsers of the field-reader module.}
%\remark{An earlier release of scsh provided the \ex{split-colon-list}
% and \ex{string-list->colon-list} functions. These have been
% removed from scsh, and are replaced by the more general
% parsers and unparsers of the field-reader module.}
%
%\defun {split-colon-list} {string} {{\str} list}
%\defunx {string-list->colon-list} {string-list} \str
%\begin{desc}
@ -3166,18 +3146,15 @@ Scsh never uses \cd{$USER} at all.
It computes \ex{(user-login-name)} from the system call \ex{(user-uid)}.
\defvar {home-directory} \str
\defvarx {exec-path-list} {{\str} list fluid}
\defvarx {exec-path-list} {{\str} list}
\begin{desc}
Scsh accesses \cd{$HOME} at start-up time, and stores the value in the
global variable \ex{home-directory}. It uses this value for \ex{\~}
lookups and for returning to home on \ex{(chdir)}.
Scsh accesses \cd{$PATH} at start-up time, colon-splits the path list, and
stores the value in the fluid \ex{exec-path-list}. This list is
stores the value in the global variable \ex{exec-path-list}. This list is
used for \ex{exec-path} and \ex{exec-path/env} searches.
To access, rebind or side-effect fluid cells, you must open
the \ex{fluids} package.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View File

@ -1,9 +0,0 @@
% tex2page.sty
% Dorai Sitaram
% Loading this file in a LaTeX document
% gives it all the macros of tex2page.tex,
% but via a more LaTeX-convenient filename.
\input{tex2page}

View File

@ -7,10 +7,8 @@ made to scsh.
We invite interested hackers to do any of them, and send us the code;
we'll put you on the team.
Visit the Scheme Underground Web page for more information on good hacks at
\begin{inset} \begin{flushleft}
\ex{\urlh{http://www.ai.mit.edu/projects/su/}{http://www.ai.mit.edu/projects/su/}}
\end{flushleft}
\end{inset}
\begin{tightinset}\verb|http://www.ai.mit.edu/projects/su/|
\end{tightinset}
Scsh is a tool that lets you write fun programs that do real things in
an elegant language; go wild.
@ -19,8 +17,19 @@ an elegant language; go wild.
\item An X gui interface. (Needs threads.)
\item A better C function/data-structure interface. This is not easy.
\item More network protocols. Telnet and ftp would be the most important.
\item An ILU interface.
\item An RPC system, with ``tail-recursion.''
\item Interfaces to relational db's.
This would be quite useful for Web servers.
An s-expression embedding of SQL would be a key design component
of such a system, along the lines of scsh's process notation or
\ex{awk} notation.
\item Port Edwin, and emacs text editor written in MIT Scheme, to scsh.
Combine it with scsh's OS interfaces to make a visual shell.
\item An \ex{expect} knock-off.
\item A \ex{make} replacement, using scsh's process notation in the build
rules.
\item Manual hacking.
\begin{itemize}
\item The {\LaTeX} hackery needs yet another serious pass. Most importantly,

View File

@ -4,7 +4,7 @@
\documentclass[twoside]{report}
\usepackage{code,boxedminipage,draftfooters,makeidx,palatino,ct,
headings,mantitle,array,matter,a4,tex2page}
headings,mantitle,array,matter,a4}
% Style issues
\parskip = 3pt plus 3pt

View File

@ -1,4 +1,4 @@
.TH LSCSH 1
.TH LS48 1
.\" File scsh.man: Manual page template for scsh.
.\" Replace LSCSH with the name of your default image and LLIB with the
.\" directory containing scshvm and default image.
@ -22,7 +22,8 @@ The
.B LSCSH
command loop reads Scheme expressions,
evaluates them, and prints their results.
The Scheme 48 system is an R5RS system.
The Scheme 48 system is an R4RS system, and also provides features from
the draft R5RS standard.
It also executes commands, which are identified by an initial comma character.
Type the command
.I ,help
@ -41,7 +42,7 @@ argument can be one of
Either of these switches terminates argument parsing; following arguments
are available from scsh as the string list produced by
.nf
(command-line)
(command-line-arguments)
.fi
The
.B \-s
@ -62,12 +63,9 @@ The
.B \-\-
switch is used to pass arguments to an interactive scsh.
It simply terminates argument parsing, causing following
arguments to be made available by
arguments to be bound to
.nf
(command-line)
There are other command-line switches. For detailed documentation,
see the manual, which comes with the distribution.
(command-line-arguments)
.SH FILES
.TP

View File

@ -1,4 +0,0 @@
/* Exports from signals1.c */
const int sig2int[];
const int max_sig;

View File

@ -1,2 +1,6 @@
/* Cygwin seems to have TZNAME but they forgot to define it */
#define HAVE_TZNAME
#define tzname _tzname
/* Cygwin's adds _'s but making configure.in know about dlltool seemed evil */
#define DLSYM_ADDS_USCORE

View File

@ -40,7 +40,7 @@
(let ((uid (user-effective-uid)))
(with-errno-handler ((err data)
((errno/acces) 'search-denied)
((errno/notdir) 'no-directory)
((errno/notdir) 'not-directory)
;; If the file doesn't exist, we usually return
;; 'nonexistent, but we special-case writability

View File

@ -69,7 +69,7 @@
(define (->delim-matcher x)
(if (procedure? x) x ; matcher proc
(let ((re (cond ((string? x) (posix-string->regexp x))
(let ((re (cond ((string? x) (re-string x))
((char-set? x) (re-char-set x))
((char? x) (re-string (string x)))
((regexp? x) x)

View File

@ -122,9 +122,10 @@
(cons re-any (str-cons chars res))
i))
((#\[) (receive (re i) (parse-glob-bracket pat i)
((#\[) (receive (cset i) (parse-glob-bracket pat i)
(lp '()
(cons re (str-cons chars res))
(cons (re-char-set cset)
(str-cons chars res))
i)))
(else (lp (cons c chars) res i))))))))))

View File

@ -1,7 +1,7 @@
;;; These defs are things for characters *not* in SRFIs 13 & 14.
;;; It includes some R5RS defs that are not correct in S48 in a Latin-1 world.
(define-interface char-predicates-interface
(define-interface char-set-predicates-interface
(export
((char-lower-case? ; R5RS
char-upper-case? ; R5RS
@ -24,7 +24,7 @@
char-ascii?) (proc (:char) :boolean))))
(define-structure char-predicates-lib char-predicates-interface
(define-structure char-set-predicates-lib char-set-predicates-interface
(open error-package ; ERROR
scsh-utilities ; DEPRECATED-PROC
char-set-lib

View File

@ -6,9 +6,8 @@
chars->char-set ; list->char-set
ascii-range->char-set ; ucs-range->char-set (not exact)
predicate->char-set ; char-set-filter (not exact)
;->char-set ; no longer handles a predicate
->char-set ; no longer handles a predicate
char-set-every? ; char-set-every
char-set-any? ; char-set-any
char-set-invert ; char-set-complement
char-set-invert! ; char-set-complement!
@ -39,16 +38,13 @@
"Change code to use CHAR-SET-FILTER."))
(define char-set-every?
(deprecated-proc char-set-every 'char-set-every?
"Use CHAR-SET-EVERY instead."))
(define char-set-any?
(deprecated-proc char-set-every 'char-set-any?
"Use CHAR-SET-ANY instead."))
"Use CHAR-SET-EVERYyn instead."))
(define char-set-invert
(deprecated-proc char-set-complement 'char-set-invert
"Use CHAR-SET-COMPLEMENT instead."))
"Use CHAR-SET-COMPLEMENTyn instead."))
(define char-set-invert!
(deprecated-proc char-set-complement! 'char-set-invert!
"Use CHAR-SET-COMPLEMENT! instead."))
"Use CHAR-SET-COMPLEMENT!yn instead."))
(define char-set:alphabetic char-set:letter)
(define char-set:numeric char-set:digit)

View File

@ -62,7 +62,7 @@
(char-set-size (proc (:value) :exact-integer))
(char-set-count (proc ((proc (:char) :boolean) :value) :exact-integer))
(char-set-contains? (proc (:value :value) :boolean))
(char-set-contains? (proc (:char :value) :boolean))
(char-set-every (proc ((proc (:char) :boolean) :value) :boolean))
(char-set-any (proc ((proc (:char) :boolean) :value) :value))

View File

@ -1130,7 +1130,7 @@
;;; string-index-right string char/char-set/pred [start end]
;;; string-skip string char/char-set/pred [start end]
;;; string-skip-right string char/char-set/pred [start end]
;;; string-count string char/char-set/pred [start end]
;;; string-count char/char-set/pred string [start end]
;;; There's a lot of replicated code here for efficiency.
;;; For example, the char/char-set/pred discrimination has
;;; been lifted above the inner loop of each proc.
@ -1220,7 +1220,7 @@
string-skip-right criterion)))))
(define (string-count s criterion . maybe-start+end)
(define (string-count criterion s . maybe-start+end)
(let-string-start+end (start end) string-count s maybe-start+end
(cond ((char? criterion)
(do ((i start (+ i 1))

View File

@ -1,315 +0,0 @@
;;; string-lib
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; string-map string-map!
;;; string-fold string-fold-right
;;; string-unfold string-tabulate
;;; string-for-each string-iter
;;; string-every string-any
;;; string-compare string-compare-ci
;;; substring-compare substring-compare-ci
;;; string= string< string> string<= string>= string<>
;;; string-ci= string-ci< string-ci> string-ci<= string-ci>= string-ci<>
;;; substring= substring<> substring-ci= substring-ci<>
;;; substring< substring> substring-ci< substring-ci>
;;; substring<= substring>= substring-ci<= substring-ci>=
;;; string-upper-case? string-lower-case?
;;; capitalize-string capitalize-words string-downcase string-upcase
;;; capitalize-string! capitalize-words! string-downcase! string-upcase!
;;; string-take string-drop
;;; string-pad string-pad-right
;;; string-trim string-trim-right string-trim-both
;;; string-filter string-delete
;;; string-index string-index-right string-skip string-skip-right
;;; string-prefix-count string-prefix-count-ci
;;; string-suffix-count string-suffix-count-ci
;;; substring-prefix-count substring-prefix-count-ci
;;; substring-suffix-count substring-suffix-count-ci
;;; string-prefix? string-prefix-ci?
;;; string-suffix? string-suffix-ci?
;;; substring-prefix? substring-prefix-ci?
;;; substring-suffix? substring-suffix-ci?
;;; substring? substring-ci?
;;; string-fill! string-copy! string-copy substring
;;; string-reverse string-reverse! reverse-list->string
;;; string->list
;;; string-concat string-concat/shared string-append/shared
;;; xsubstring string-xcopy!
;;; string-null?
;;; join-strings
;;;
;;; string? make-string string string-length string-ref string-set!
;;; string-append list->string
(define-interface string-lib-interface
(export
;; string-map proc s [start end] -> s
(string-map (proc ((proc (:char) :char)
:string
&opt :exact-integer :exact-integer)
:string))
;; string-map! proc s [start end] -> unspecific
(string-map! (proc ((proc (:char) :values)
:string
&opt :exact-integer :exact-integer)
:unspecific))
;; string-fold kons knil s [start end] -> value
;; string-fold-right kons knil s [start end] -> value
((string-fold string-fold-right)
(proc ((proc (:char :value) :value)
:value :string
&opt :exact-integer :exact-integer)
:value))
;; string-unfold p f g seed -> string
(string-unfold (proc ((proc (:value) :boolean)
(proc (:value) :char)
(proc (:value) :value)
:value)
:string))
; Enough is enough.
; ;; string-unfoldn p f g seed ... -> string
; (string-unfoldn (proc ((procedure :values :boolean)
; (procedure :values :char)
; (procedure :values :values)
; &rest :value)
; :string))
;; string-tabulate proc len -> string
(string-tabulate (proc ((proc (:exact-integer) :char) :exact-integer)
:string))
;; string-for-each proc s [start end] -> unspecific
;; string-iter proc s [start end] -> unspecific
((string-for-each string-iter)
(proc ((proc (:char) :values) :string &opt :exact-integer :exact-integer)
:unspecific))
;; string-every pred s [start end]
;; string-any pred s [start end]
(string-every
(proc ((proc (:char) :boolean) :string &opt :exact-integer :exact-integer)
:boolean))
(string-any
(proc ((proc (:char) :boolean) :string &opt :exact-integer :exact-integer)
:value))
;; string-compare string1 string2 lt-proc eq-proc gt-proc
;; string-compare-ci string1 string2 lt-proc eq-proc gt-proc
((string-compare string-compare-ci)
(proc (:string :string (proc (:exact-integer) :values)
(proc (:exact-integer) :values)
(proc (:exact-integer) :values))
:values))
;; substring-compare string1 start1 end1 string2 start2 end2 lt eq gt
;; substring-compare-ci string1 start1 end1 string2 start2 end2 lt eq gt
((substring-compare substring-compare-ci)
(proc (:string :exact-integer :exact-integer
:string :exact-integer :exact-integer
(proc (:exact-integer) :values)
(proc (:exact-integer) :values)
(proc (:exact-integer) :values))
:values))
;; string< string1 string2
((string= string< string> string<= string>= string<>
string-ci= string-ci< string-ci> string-ci<= string-ci>= string-ci<>)
(proc (&rest :string) :value))
;; substring< string1 start1 end1 string2 start2 end2
((substring= substring<> substring-ci= substring-ci<>
substring< substring> substring-ci< substring-ci>
substring<= substring>= substring-ci<= substring-ci>=)
(proc (:string :exact-integer :exact-integer
:string :exact-integer :exact-integer)
:value))
;; string-upper-case? string [start end]
;; string-lower-case? string [start end]
((string-upper-case? string-lower-case?)
(proc (:string &opt :exact-integer :exact-integer) :boolean))
;; capitalize-string string [start end]
;; capitalize-words string [start end]
;; string-downcase string [start end]
;; string-upcase string [start end]
;; capitalize-string! string [start end]
;; capitalize-words! string [start end]
;; string-downcase! string [start end]
;; string-upcase! string [start end]
((capitalize-string capitalize-words string-downcase string-upcase)
(proc (:string &opt :exact-integer :exact-integer) :string))
((capitalize-string! capitalize-words! string-downcase! string-upcase!)
(proc (:string &opt :exact-integer :exact-integer) :unspecific))
;; string-take string nchars
;; string-drop string nchars
((string-take string-drop) (proc (:string :exact-integer) :string))
;; string-pad string k [char start end]
;; string-pad-right string k [char start end]
((string-pad string-pad-right)
(proc (:string :exact-integer &opt :char :exact-integer :exact-integer)
:string))
;; string-trim string [char/char-set/pred start end]
;; string-trim-right string [char/char-set/pred start end]
;; string-trim-both string [char/char-set/pred start end]
((string-trim string-trim-right string-trim-both)
(proc (:string &opt :value :exact-integer :exact-integer)
:string))
;; string-filter char/char-set/pred string [start end]
;; string-delete char/char-set/pred string [start end]
((string-filter string-delete)
(proc (:value :string &opt :exact-integer :exact-integer) :string))
;; string-index string char/char-set/pred [start end]
;; string-index-right string char/char-set/pred [end start]
;; string-skip string char/char-set/pred [start end]
;; string-skip-right string char/char-set/pred [end start]
((string-index string-index-right string-skip string-skip-right)
(proc (:string :value &opt :exact-integer :exact-integer)
:value))
;; string-prefix-count string1 string2
;; string-suffix-count string1 string2
;; string-prefix-count-ci string1 string2
;; string-suffix-count-ci string1 string2
((string-prefix-count string-prefix-count-ci
string-suffix-count string-suffix-count-ci)
(proc (:string :string) :exact-integer))
;; substring-prefix-count string1 start1 end1 string2 start2 end2
;; substring-suffix-count string1 start1 end1 string2 start2 end2
;; substring-prefix-count-ci string1 start1 end1 string2 start2 end2
;; substring-suffix-count-ci string1 start1 end1 string2 start2 end2
((substring-prefix-count substring-prefix-count-ci
substring-suffix-count substring-suffix-count-ci)
(proc (:string :exact-integer :exact-integer
:string :exact-integer :exact-integer)
:exact-integer))
;; string-prefix? string1 string2
;; string-suffix? string1 string2
;; string-prefix-ci? string1 string2
;; string-suffix-ci? string1 string2
((string-prefix? string-prefix-ci?
string-suffix? string-suffix-ci?)
(proc (:string :string) :boolean))
;; substring-prefix? string1 start1 end1 string2 start2 end2
;; substring-suffix? string1 start1 end1 string2 start2 end2
;; substring-prefix-ci? string1 start1 end1 string2 start2 end2
;; substring-suffix-ci? string1 start1 end1 string2 start2 end2
((substring-prefix? substring-prefix-ci?
substring-suffix? substring-suffix-ci?)
(proc (:string :exact-integer :exact-integer
:string :exact-integer :exact-integer)
:boolean))
;; substring? pattern string [start end]
;; substring-ci? pattern string [start end]
((substring? substring-ci?)
(proc (:string :string &opt :exact-integer :exact-integer)
:value))
;; string-fill! string char [start end]
(string-fill! (proc (:string :char &opt :exact-integer :exact-integer)
:unspecific))
;; string-copy! to tstart from [fstart fend]
(string-copy! (proc (:string :exact-integer :string
&opt :exact-integer :exact-integer)
:unspecific))
;; string-copy s [start end] -> string
;; substring s start [end] -> string
(string-copy (proc (:string &opt :exact-integer :exact-integer) :string))
(substring (proc (:string :exact-integer &opt :exact-integer) :string))
;; string-reverse s [start end]
;; string-reverse! s [start end]
(string-reverse (proc (:string &opt :exact-integer :exact-integer) :string))
(string-reverse! (proc (:string &opt :exact-integer :exact-integer) :unspecific))
;; reverse-list->string char-list
;; string->list s [start end]
;; string-concat string-list
;; string-concat/shared string-list
;; string-append/shared s ...
(reverse-list->string (proc (:value) :string))
(string->list (proc (:string &opt :exact-integer :exact-integer) :value))
((string-concat string-concat/shared) (proc (:value) :string))
(string-append/shared (proc (&rest :string) :string))
;; xsubstring s from [to start end]
;; string-xcopy! target tstart s from [to start end]
(xsubstring (proc (:string :exact-integer &opt
:exact-integer :exact-integer :exact-integer)
:string))
(string-xcopy! (proc (:string :exact-integer :string :exact-integer &opt
:exact-integer :exact-integer :exact-integer)
:unspecific))
;; string-null? s
(string-null? (proc (:string) :boolean))
(join-strings (proc (:value &opt :string :symbol) :string))
;; Here are the R4RS procs
(string? (proc (:value) :boolean))
(make-string (proc (:exact-integer &opt :char) :string))
(string (proc (&rest :char) :string))
(string-length (proc (:string) :exact-integer))
(string-ref (proc (:string :exact-integer) :char))
(string-set! (proc (:string :exact-integer :char) :unspecific))
; Not provided by string-lib.
;((string=? string-ci=? string<? string-ci<?
; string>? string-ci>? string<=? string-ci<=?
; string>=? string-ci>=?) (proc (:string :string) :boolean))
;; These are the R4RS types for SUBSTRING, STRING-COPY, STRING-FILL!,
;; and STRING->LIST. The string-lib types are different -- extended.
;(substring (proc (:string :exact-integer :exact-integer) :string))
;(string-copy (proc (:string) :string))
;(string-fill! (proc (:string :char) :unspecific))
;(string->list (proc (:string) :value))
(string-append (proc (&rest :string) :string))
(list->string (proc (:value) :string))
))
;;; make-kmp-restart-vector
;;; parse-final-start+end
;;; parse-start+end
;;; check-substring-spec
(define-interface string-lib-internals-interface
(export
(parse-final-start+end (proc ((procedure :values :values) :string :value)
(some-values :exact-integer :exact-integer)))
(parse-start+end (proc ((procedure :values :values) :string :value)
(some-values :exact-integer :exact-integer :value)))
(check-substring-spec (proc ((procedure :values :values) :string :exact-integer :exact-integer)
:unspecific))
(make-kmp-restart-vector (proc (:string (proc (:char :char) :boolean))
:vector))))
(define-structures ((string-lib string-lib-interface)
(string-lib-internals string-lib-internals-interface))
(access scheme) ; Get at R5RS SUBSTRING
(open receiving ; RECEIVE
char-set-package; Various
error-package ; ERROR
let-opt ; LET-OPTIONALS :OPTIONAL
structure-refs ; STRUCTURE-REF
scheme)
(files string-lib))

578
scsh/lib/strings.txt Normal file
View File

@ -0,0 +1,578 @@
Todo:
parse-start+end parse-final-start+end need "string" in the name
Also, export macro binder.
What's up w/quotient? (quotient -1 3) = 0.
regexp-foldl
type regexp interface
land*
Let-optional:
A let-optional that parses a prefix of the args.
Arg checking forms that get used if it parses, but are not
applied to the default.
The Scheme Underground string library includes a rich set of operations
for manipulating strings. These are frequently useful for scripting and
other text-manipulation applications.
The library's design was influenced by the string libraries found in MIT
Scheme, Gambit, RScheme, MzScheme, slib, Common Lisp, Bigloo, guile, APL and
the SML standard basis. Some of the code bears a distant family relation to
the MIT Scheme implementation, and being derived from that code, is covered by
the MIT Scheme copyright (which is a fairly generic "free" copyright -- see
the source file for details). The fast KMP string-search code used in
SUBSTRING? was loosely adapted from old slib code by Stephen Bevan.
The library has the following design principles:
- *All* procedures involving character comparison are available in
both case-sensitive and case-insensitive forms.
- *All* functionality is available in substring and full-string forms.
- The procedures are spec'd so as to permit efficient implementation in a
Scheme that provided shared-text substrings (e.g., guile). This means that
you should not rely on many of the substring-selecting procedures to return
freshly-allocated strings. Careful attention is paid to the issue of which
procedures allocate fresh storage, and which are permitted to return results
that share storage with the arguments.
- Common Lisp theft:
+ inequality functions return mismatch index.
I generalised this so that this "protocol" is extended even to
the equality functions. This means that clients can be handed any generic
string-comparison function and rely on the meaning of the true value.
+ Common Lisp capitalisation definition
The library addresses some problems with the R5RS string procedures:
- Question marks after string-comparison functions (string=?, etc.)
This is inconsistent with numeric comparison functions, and ugly, too.
- String-comparison functions do not provide useful true value.
- STRING-COPY should have optional start/end args;
SUBSTRING shouldn't specify if it copies or returns shared bits.
- STRING-FILL! and STRING->LIST should take optional start/end args.
- No <> function provided.
In the following procedure specifications:
- Any S parameter is a string;
- START and END parameters are half-open string indices specifying
a substring within a string parameter; when optional, they default
to 0 and the length of the string, respectively. When specified, it
must be the case that 0 <= START <= END <= (string-length S), for
the corresponding parameter S. They typically restrict a procedure's
action to the indicated substring.
- A CHAR/CHAR-SET/PRED parameter is a value used to select/search
for a character in a string. If it is a character, it is used in
an equality test; if it is a character set, it is used as a
membership test; if it is a procedure, it is applied to the
characters as a test predicate.
This library contains a large number of procedures, but they follow
a consistent naming scheme. The names are composed of smaller lexemes
in a regular way that exposes the structure and relationships between the
procedures. This should help the programmer to recall or reconstitute the name
of the particular procedure that he needs when writing his own code. In
particular
- Procedures whose names end in "-ci" are case-insensitive variants.
- Procedures whose names end in "!" are side-effecting variants.
These procedures generally return an unspecified value.
- The order of common parameters is fairly consistent across the
different procedures.
For more text-manipulation functionality, see also the regular expression,
file-name, character set, and character->character partial map packages.
-------------------------------------------------------------------------------
* R4RS/R5RS procedures
The R4RS and R5RS reports define 22 string procedures. The string-lib
package includes 8 of these exactly as defined, 4 in an extended,
backwards-compatible way, and drops the remaining 10 (whose functionality
is available via other bindings).
The 8 procedures provided exactly as documented in the reports are
string?
make-string
string
string-length
string-ref
string-set!
string-append
list->string
The ten functions not included are the R4RS string-comparison functions:
string=? string-ci=?
string<? string-ci<?
string>? string-ci>?
string<=? string-ci<=?
string>=? string-ci>=?
The string-lib package provides alternate bindings.
Additionally, the four extended procedures are
string-fill! s char [start end] -> unspecific
string->list s [start end] -> char-list
substring s start [end] -> string
string-copy s [start end] -> string
These procedures are documented in the following section. In brief, they are
extended to take optional start/end parameters specifying substring ranges;
Additionally, SUBSTRING is allowed to return a value that shares storage with
its argument.
* Procedures
These procedures are contained in the Scheme 48 package "string-lib",
which is open in the default user package. They are not found in the
"scsh" package; script writers and other programmers that use the Scheme
48 module system must open string-lib explicitly.
string-map proc s [start end] -> string
string-map! proc s [start end] -> unspecified
PROC is a char->char procedure; it is mapped over S.
Note: no sequence order is specified.
string-fold kons knil s [start end] -> value
string-fold-right kons knil s [start end] -> value
These are the fundamental iterators for strings.
The left-fold operator maps the KONS procedure across the
string from left to right
(... (kons s[2] (kons s[1] (kons s[0] knil))))
In other words, string-fold obeys the recursion
(string-fold kons knil s start end) =
(string-fold kons (kons s[start] knil) start+1 end)
The right-fold operator maps the KONS procedure across the
string from right to left
(kons s[0] (... (kons s[end-3] (kons s[end-2] (kons s[end-1] knil)))))
obeying the recursion
(string-fold-right kons knil s start end) =
(string-fold-right kons (kons s[end-1] knil) start end-1)
Examples:
To convert a string to a list of chars:
(string-fold-right cons '() s)
To count the number of lower-case characters in a string:
(string-fold (lambda (c count)
(if (char-set-contains? char-set:lower c)
(+ count 1)
count))
0
s)
string-unfold p f g seed -> string
This is the fundamental constructor for strings.
- G is used to generate a series of "seed" values from the initial seed:
SEED, (G SEED), (G^2 SEED), (G^3 SEED), ...
- P tells us when to stop -- when it returns true when applied to one
of these seed values.
- F maps each seed value to the corresponding character
in the result string.
More precisely, the following (simple, inefficient) definition holds:
(define (string-unfold p f g seed)
(if (p seed) ""
(string-append (string (f seed))
(string-unfold p f g (g seed)))))
STRING-UNFOLD is a fairly powerful constructor -- you can use it to
reverse a string, copy a string, convert a list to a string, read
a port into a string, and so forth. Examples:
(port->string p) = (string-unfold eof-object? values
(lambda (x) (read-char p))
(read-char p))
(list->string lis) = (string-unfold null? car cdr lis)
(tabulate-string f size) = (string-unfold (lambda (i) (= i size)) f add1 0)
To map F over a list LIS, producing a string:
(string-unfold null? (compose f car) cdr lis)
string-tabulate proc len -> string
PROC is an integer->char procedure. Construct a string of size LEN
by applying PROC to each index to produce the corresponding string
element. The order in which PROC is applied to the indices is not
specified.
string-for-each proc s [start end] -> unspecified
string-iter proc s [start end] -> unspecified
Apply PROC to each character in S.
STRING-FOR-EACH has no specified iteration order.
STRING-ITER is required to iterate from START to END
in increasing order.
string-every? pred s [start end] -> boolean
string-any? pred s [start end] -> value
Note: no sequence order specified.
Checks to see if predicate PRED is true of every / any character in S.
STRING-ANY? is witness-generating -- it applies PRED to the elements
of S, returning the first true value it finds, otherwise false.
string-compare s1 s2 lt-proc eq-proc gt-proc -> values
string-compare-ci s1 s2 lt-proc eq-proc gt-proc -> values
Apply LT-PROC, EQ-PROC, GT-PROC to the mismatch index, depending
upon whether S1 is less than, equal to, or greater than S2.
The "mismatch index" is the largest index i such that for
every 0 <= j < i, s1[j] = s2[j] -- that is, I is the first
position that doesn't match. If S1 = S2, the mismatch index
is simply the length of the strings; we observe the protocol
in this redundant case for uniformity.
substring-compare s1 start1 end1 s2 start2 end2 lt-proc eq-proc gt-proc -> values
substring-compare-ci s1 start1 end1 s2 start2 end2 lt-proc eq-proc gt-proc -> values
The continuation procedures are applied to S1's mismatch index (as defined
above). In the case of EQ-PROC, this is always END1.
string= s1 s2 -> #f or integer
string<> s1 s2 -> #f or integer
string< s1 s2 -> #f or integer
string> s1 s2 -> #f or integer
string<= s1 s2 -> #f or integer
string>= s1 s2 -> #f or integer
If the comparison operation is true, the function returns the
mismatch index (as defined for the previous comparator functions).
string-ci= s1 s2 -> #f or integer
string-ci<> s1 s2 -> #f or integer
string-ci< s1 s2 -> #f or integer
string-ci> s1 s2 -> #f or integer
string-ci<= s1 s2 -> #f or integer
string-ci>= s1 s2 -> #f or integer
Case-insensitive variants.
substring= s1 start1 end1 s2 start2 end2 -> #f or integer
substring<> s1 start1 end1 s2 start2 end2 -> #f or integer
substring< s1 start1 end1 s2 start2 end2 -> #f or integer
substring> s1 start1 end1 s2 start2 end2 -> #f or integer
substring<= s1 start1 end1 s2 start2 end2 -> #f or integer
substring>= s1 start1 end1 s2 start2 end2 -> #f or integer
substring-ci= s1 start1 end1 s2 start2 end2 -> #f or integer
substring-ci<> s1 start1 end1 s2 start2 end2 -> #f or integer
substring-ci< s1 start1 end1 s2 start2 end2 -> #f or integer
substring-ci> s1 start1 end1 s2 start2 end2 -> #f or integer
substring-ci<= s1 start1 end1 s2 start2 end2 -> #f or integer
substring-ci>= s1 start1 end1 s2 start2 end2 -> #f or integer
These variants restrict the comparison to the indicated
substrings of S1 and S2.
string-upper-case? s [start end] -> boolean
string-lower-case? s [start end] -> boolean
STRING-UPPER-CASE? returns true iff the string contains
no lower-case characters. STRING-LOWER-CASE returns true
iff the string contains no upper-case characters.
(string-upper-case? "") => #t
(string-lower-case? "") => #t
(string-upper-case? "FOOb") => #f
(string-upper-case? "U.S.A.") => #t
capitalize-string s [start end] -> string
capitalize-string! s [start end] -> unspecified
Capitalize the string: upcase the first alphanumeric character,
and downcase the rest of the string. CAPITALIZE-STRING returns
a freshly allocated string.
(capitalize-string "--capitalize tHIS sentence.") =>
"--Capitalize this sentence."
(capitalize-string "see Spot run. see Nix run.") =>
"See spot run. see nix run."
(capitalize-string "3com makes routers.") =>
"3com makes routers."
capitalize-words s [start end] -> string
capitalize-words! s [start end] -> unspecified
A "word" is a maximal contiguous sequence of alphanumeric characters.
Upcase the first character of every word; downcase the rest of the word.
CAPITALIZE-WORDS returns a freshly allocated string.
(capitalize-words "HELLO, 3THErE, my nAME IS olin") =>
"Hello, 3there, My Name Is Olin"
More sophisticated capitalisation procedures can be synthesized
using CAPITALIZE-STRING and pattern matchers. In this context,
the REGEXP-SUBSTITUTE/GLOBAL procedure may be useful for picking
out the units to be capitalised and applying CAPITALIZE-STRING to
their components.
string-upcase s [start end] -> string
string-upcase! s [start end] -> unspecified
string-downcase s [start end] -> string
string-downcase! s [start end] -> unspecified
Raise or lower the case of the alphabetic characters in the string.
STRING-UPCASE and STRING-DOWNCASE return freshly allocated strings.
string-take s nchars -> string
string-drop s nchars -> string
string-take-right s nchars -> string
string-drop-right s nchars -> string
STRING-TAKE returns the first NCHARS of STRING;
STRING-DROP returns all but the first NCHARS of STRING.
STRING-TAKE-RIGHT returns the last NCHARS of STRING;
STRING-DROP-RIGHT returns all but the last NCHARS of STRING.
These generalise MIT Scheme's HEAD & TAIL functions.
If these procedures produce the entire string, they may return either
S or a copy of S; in some implementations, proper substrings may share
memory with S.
string-pad s k [char start end] -> string
string-pad-right s k [char start end] -> string
Build a string of length K comprised of S padded on the left (right)
by as many occurences of the character CHAR as needed. If S has more
than K chars, it is truncated on the left (right) to length k. CHAR
defaults to #\space.
If K is exactly the length of S, these functions may return
either S or a copy of S.
string-trim s [char/char-set/pred start end] -> string
string-trim-right s [char/char-set/pred start end] -> string
string-trim-both s [char/char-set/pred start end] -> string
Trim S by skipping over all characters on the left / on the right /
on both sides that satisfy the second parameter CHAR/CHAR-SET/PRED:
- If it is a character CHAR, characters equal to CHAR are trimmed.
- If it is a char set CHAR-SET, characters contained in CHAR-SET
are trimmed.
- If it is a predicate PRED, it is a test predicate that is applied
to the characters in S; a character causing it to return true
is skipped.
CHAR/CHAR/SET-PRED defaults to CHAR-SET:WHITESPACE.
If no trimming occurs, these functions may return either S or a copy of S;
in some implementations, proper substrings may share memory with S.
(string-trim-both " The outlook wasn't brilliant, \n\r")
=> "The outlook wasn't brilliant,"
string-filter s char/char-set/pred [start end] -> string
string-delete s char/char-set/pred [start end] -> string
Filter the string S, retaining only those characters that
satisfy / do not satisfy the CHAR/CHAR-SET/PRED argument. If
this argument is a procedure, it is applied to the character
as a predicate; if it is a char-set, the character is tested
for membership; if it is a character, it is used in an equality test.
If the string is unaltered by the filtering operation, these
functions may return either S or a copy of S.
string-index s char/char-set/pred [start end] -> integer or #f
string-index-right s char/char-set/pred [end start] -> integer or #f
string-skip s char/char-set/pred [start end] -> integer or #f
string-skip-right s char/char-set/pred [end start] -> integer or #f
Note the inverted start/end ordering of index-right and skip-right's
parameters.
Index (index-right) searches through the string from the left (right),
returning the index of the first occurence of a character which
- equals CHAR/CHAR-SET/PRED (if it is a character);
- is in CHAR/CHAR-SET/PRED (if it is a char-set);
- satisfies the predicate CHAR/CHAR-SET/PRED (if it is a procedure).
If no match is found, the functions return false.
The skip functions are similar, but use the complement of the criteria:
they search for the first char that *doesn't* satisfy the test. E.g.,
to skip over initial whitespace, say
(cond ((string-skip s char-set:whitespace) =>
(lambda (i)
;; (string-ref s i) is not whitespace.
...)))
string-prefix-count s1 s2 -> integer
string-suffix-count s1 s2 -> integer
string-prefix-count-ci s1 s2 -> integer
string-suffix-count-ci s1 s2 -> integer
Return the length of the longest common prefix/suffix of the two strings.
This is equivalent to the "mismatch index" for the strings.
substring-prefix-count s1 start1 end1 s2 start2 end2 -> integer
substring-suffix-count s1 start1 end1 s2 start2 end2 -> integer
substring-prefix-count-ci s1 start1 end1 s2 start2 end2 -> integer
substring-suffix-count-ci s1 start1 end1 s2 start2 end2 -> integer
Substring variants.
string-prefix? s1 s2 -> boolean
string-suffix? s1 s2 -> boolean
string-prefix-ci? s1 s2 -> boolean
string-suffix-ci? s1 s2 -> boolean
Is S1 a prefix/suffix of S2?
substring-prefix? s1 start1 end1 s2 start2 end2 -> boolean
substring-suffix? s1 start1 end1 s2 start2 end2 -> boolean
substring-prefix-ci? s1 start1 end1 s2 start2 end2 -> boolean
substring-suffix-ci? s1 start1 end1 s2 start2 end2 -> boolean
Substring variants.
substring? s1 s2 [start end] -> integer or false
substring-ci? s1 s2 [start end] -> integer or false
Return the index in S2 where S1 occurs as a substring, or false.
The returned index is in the range [start,end).
The current implementation uses the Knuth-Morris-Pratt algorithm.
string-fill! s char [start end] -> unspecified
Store CHAR into the elements of S.
This is the R4RS procedure extended to have optional START/END parameters.
string-copy! target tstart s [start end] -> unspecified
Copy the sequence of characters from index range [START,END) in
string S to string TARGET, beginning at index TSTART. The characters
are copied left-to-right or right-to-left as needed -- the copy is
guaranteed to work, even if TARGET and S are the same string.
substring s start [end] -> string
string-copy s [start end] -> string
These R4RS procedures are extended to have optional START/END parameters.
Use STRING-COPY when you want to indicate explicitly in your code that you
wish to allocate new storage; use SUBSTRING when you don't care if you
get a fresh copy or share storage with the original string.
E.g.:
(string-copy "Beta substitution") => "Beta substitution"
(string-copy "Beta substitution" 1 10)
=> "eta subst"
(string-copy "Beta substitution" 5) => "substitution"
SUBSTRING may return a value with shares memory with S.
string-reverse s [start end] -> string
string-reverse! s [start end] -> unspecific
Reverse the string.
reverse-list->string char-list -> string
An efficient implementation of (compose string->list reverse):
(reverse-list->string '(#\a #\B #\c)) -> "cBa"
This is a common idiom in the epilog of string-processing loops
that accumulate an answer in a reverse-order list.
string-concat string-list -> string
Append the elements of STRING-LIST together into a single list.
Guaranteed to return a freshly allocated list. Appears sufficiently
often as to warrant being named.
string-concat/shared string-list -> string
string-append/shared s ... -> string
These two procedures are variants of STRING-CONCAT and STRING-APPEND
that are permitted to return results that share storage with their
parameters. In particular, if STRING-APPEND/SHARED is applied to just
one argument, it may return exactly that argument, whereas STRING-APPEND
is required to allocate a fresh string.
string->list s [start end] -> char-list
The R5RS STRING->LIST procedure is extended to take optional START/END
arguments.
string-null? s -> bool
Is S the empty string?
xsubstring s from [to start end] -> string
This is the "extended substring" procedure that implements replicated
copying of a substring of some string.
S is a string; START and END are optional arguments that demarcate
a substring of S, defaulting to 0 and the length of S (e.g., the whole
string). Replicate this substring up and down index space, in both the
positive and negative directions. For example, if S = "abcdefg", START=3,
and END=6, then we have the conceptual bidirectionally-infinite string
... d e f d e f d e f d e f d e f d e f d e f ...
... -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 ...
XSUBSTRING returns the substring of this string beginning at index FROM,
and ending at TO (which defaults to FROM+(END-START)).
You can use XSUBSTRING to perform a variety of tasks:
- To rotate a string left: (xsubstring "abcdef" 2) => "cdefab"
- To rotate a string right: (xsubstring "abcdef" -2) => "efabcd"
- To replicate a string: (xsubstring "abc" 0 7) => "abcabca"
Note that
- The FROM/TO indices give a half-open range -- the characters from
index FROM up to, but not including, index TO.
- The FROM/TO indices are not in terms of the index space for string S.
They are in terms of the replicated index space of the substring
defined by S, START, and END.
It is an error if START=END -- although this is allowed by special
dispensation when FROM=TO.
string-xcopy! target tstart s sfrom [sto start end] -> unspecific
Exactly the same as XSUBSTRING, but the extracted text is written
into the string TARGET starting at index TSTART.
This operation is not defined if (EQ? TARGET S) -- you cannot copy
a string on top of itself.
* Lower-level procedures
The following procedures are useful for writing other string-processing
functions, and are contained in the string-lib-internals package.
parse-start+end proc s args -> [start end rest]
parse-final-start+end proc s args -> [start end]
PARSE-START+END may be used to parse a pair of optional START/END arguments
from an argument list, defaulting them to 0 and the length of some string
S, respectively. Let the length of string S be SLEN.
- If ARGS = (), the function returns (values 0 slen '())
- If ARGS = (i), I is checked to ensure it is an integer, and
that 0 <= i <= slen. Returns (values i slen (cdr rest)).
- If ARGS = (i j ...), I and J are checked to ensure they are
integers, and that 0 <= i <= j <= slen. Returns (values i j (cddr rest)).
If any of the checks fail, an error condition is raised, and PROC is used
as part of the error condition -- it should be the name of the client
procedure whose argument list PARSE-START+END is parsing.
parse-final-start+end is exactly the same, except that the args list
passed to it is required to be of length two or less; if it is longer,
an error condition is raised. It may be used when the optional START/END
parameters are final arguments to the procedure.
check-substring-spec proc s start end -> unspecific
Check values START and END to ensure they specify a valid substring
in S. This means that START and END are exact integers, and
0 <= START <= END <= (STRING-LENGTH S)
If this is not the case, an error condition is raised. PROC is used
as part of error condition, and should be the procedure whose START/END
parameters we are checking.
make-kmp-restart-vector s c= -> vector
Build the Knuth-Morris-Pratt "restart vector," which is useful
for quickly searching character sequences for the occurrence of
string S. C= is a character-equality function used to construct
the restart vector; it is usefully CHAR=? or CHAR-CI=?.
The definition of the restart vector RV for string S is:
If we have matched chars 0..i-1 of S against some search string SS, and
S[i] doesn't match SS[k], then reset i := RV[i], and try again to
match SS[k]. If RV[i] = -1, then punt SS[k] completely, and move on to
SS[k+1] and S[0].
In other words, if you have matched the first i chars of S, but
the i+1'th char doesn't match, RV[i] tells you what the next-longest
prefix of PATTERN is that you have matched.
The following string-search function shows how a restart vector
is used to search. It can be easily adapted to search other character
sequences (such as ports).
(define (find-substring pattern source start end)
(let ((plen (string-length pattern))
(rv (make-kmp-restart-vector pattern char=?)))
;; The search loop. SJ & PJ are redundant state.
(let lp ((si start) (pi 0)
(sj (- end start)) ; (- end si) -- how many chars left.
(pj plen)) ; (- plen pi) -- how many chars left.
(if (= pi plen) (- si plen) ; Win.
(and (<= pj sj) ; Lose.
(if (char=? (string-ref source si) ; Search.
(string-ref pattern pi))
(lp (+ 1 si) (+ 1 pi) (- sj 1) (- pj 1)) ; Advance.
(let ((pi (vector-ref rv pi))) ; Retreat.
(if (= pi -1)
(lp (+ si 1) 0 (- sj 1) plen) ; Punt.
(lp si pi sj (- plen pi))))))))))

View File

@ -80,23 +80,9 @@
(set-socket-option sock level/socket socket/reuse-address #t)
(bind-socket sock addr)
(listen-socket sock 5)
(with-handler
(lambda (condition more)
(with-handler
(lambda (condition ignore) (more))
(lambda () (close-socket sock)))
(more))
(lambda ()
(let loop ()
(with-errno-handler
;; ECONNABORTED we just ignore
((errno packet)
((errno/connaborted) (loop)))
(call-with-values
(lambda () (accept-connection sock))
proc)
(loop)))))))
(let loop ()
(call-with-values (lambda () (accept-connection sock)) proc)
(loop))))
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; Socket Record Structure
@ -421,9 +407,8 @@
reader sockfd flags
s start end from))
(let ((addr (make-addr from)))
(let loop ((i start) (remote #f))
(if (>= i end)
(values (- i start) remote)
(let loop ((i start))
(if (>= i end) (- i start)
(receive (err nread)
(reader sockfd flags s i end addr)
(cond (err (if (= err errno/intr) (loop i)
@ -436,7 +421,7 @@
(let ((result (- i start)))
(and (not (zero? result)) result))
from))
(else (loop (+ i nread) from))))))))
(else (loop (+ i nread)))))))))
(define (receive-message/partial socket len . maybe-flags)
(let ((flags (:optional maybe-flags 0)))

View File

@ -22,7 +22,7 @@
/* Make sure our exports match up w/the implementation: */
#include "network1.h"
#if !defined(__CYGWIN__) && !defined(_AIX)
#ifndef __CYGWIN__
extern int h_errno;
#endif
@ -42,9 +42,7 @@ int scheme_bind(int sockfd, int family, scheme_value scheme_name)
{
struct sockaddr_un name;
int scheme_length=STRING_LENGTH(scheme_name);
memset(&name, 0, sizeof(name));
name.sun_family=AF_UNIX;
if (scheme_length>=(108-1)) /* save space for \0 */
return(-1);
@ -62,9 +60,6 @@ int scheme_bind(int sockfd, int family, scheme_value scheme_name)
u_long addr=GET_LONG(scheme_name,0);
u_short port=htons((u_short)ntohl(GET_LONG(scheme_name,1)));
memset(&name, 0, sizeof(name));
name.sin_family=AF_INET;
name.sin_addr.s_addr=addr;
name.sin_port=port;
@ -87,8 +82,6 @@ int scheme_connect(int sockfd, int family, scheme_value scheme_name)
struct sockaddr_un name;
int scheme_length=STRING_LENGTH(scheme_name);
memset(&name, 0, sizeof(name));
name.sun_family=AF_UNIX;
if (scheme_length>=(108-1)) /* save space for \0 */
return(-1);
@ -107,8 +100,6 @@ int scheme_connect(int sockfd, int family, scheme_value scheme_name)
u_long addr=GET_LONG(scheme_name,0);
u_short port=htons((u_short)ntohl(GET_LONG(scheme_name,1)));
memset(&name, 0, sizeof(name));
name.sin_family=AF_INET;
name.sin_addr.s_addr=addr;
name.sin_port=port;
@ -279,8 +270,6 @@ int send_substring(int s,
struct sockaddr_un name;
int scheme_length=STRING_LENGTH(scheme_name);
memset(&name, 0, sizeof(name));
name.sun_family=AF_UNIX;
if (scheme_length>=(108-1)) /* save space for \0 */
return(-1);
@ -300,9 +289,6 @@ int send_substring(int s,
struct sockaddr_in name;
u_long addr=GET_LONG(scheme_name,0);
u_short port=htons((u_short)ntohl(GET_LONG(scheme_name,1)));
memset(&name, 0, sizeof(name));
name.sin_family=AF_INET;
name.sin_addr.s_addr=addr;
name.sin_port=port;

View File

@ -1,568 +0,0 @@
;;; Field and record parsing utilities for scsh.
;;; Copyright (c) 1994 by Olin Shivers.
;;; Notes:
;;; - Comment on the dependencies here...
;;; - Redefine READ-LINE using READ-DELIMITED.
;;; - Awk should deal with case-insensitivity.
;;; - Should I change the field-splitters to return lists? It's the
;;; right thing, and costs nothing in terms of efficiency.
;;; Looping primitives:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; It is nicer for loops that loop over a bunch of different things
;;; if you can encapsulate the idea of iterating over a data structure
;;; with a
;;; (next-element state) -> elt next-state
;;; (more-elements? state) -? #t/#f
;;; generator/termination-test pair. You can use the generator with REDUCE
;;; to make a list; you can stick it into a loop macro to loop over the
;;; elements. For example, if we had an extensible Yale-loop style loop macro,
;;; we could have a loop clause like
;;;
;;; (loop (for field in-infix-delimited-string ":" path)
;;; (do (display field) (newline)))
;;;
;;; and it would be simple to expand this into code using the generator.
;;; With procedural inlining, you can get pretty optimal loops over data
;;; structures this way.
;;;
;;; As of now, you are forced to parse fields into a buffer, and loop
;;; over that. This is inefficient of time and space. If I ever manage to do
;;; an extensible loop macro for Scheme 48, I'll have to come back to this
;;; package and rethink how to provide this functionality.
;;; Forward-progress guarantees and empty string matches.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; A loop that pulls text off a string by matching a regexp against
;;; that string can conceivably get stuck in an infinite loop if the
;;; regexp matches the empty string. For example, the regexps
;;; ^, $, .*, foo|[^f]* can all match the empty string.
;;;
;;; The regexp-loop routines in this code are careful to handle this 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 -- there's the rub), 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 they 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.
;;;
;;; So 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:
;;; ((suffix-splitter "") "foo") -> #("" "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:
;;; ((field-splitter ".") "foo") -> #("f" "o" "o")
;;; (join-strings string-list [delimiter grammar]) => string
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Paste strings together using the delimiter string.
;;;
;;; (join-strings '("foo" "bar" "baz") ":") => "foo:bar:baz"
;;;
;;; DELIMITER defaults to a single space " "
;;; GRAMMAR is one of the symbols {infix, suffix} and defaults to 'infix.
;;; (join-strings strings [delim grammar])
(define (join-strings strings . args)
(if (pair? strings)
(receive (delim grammar) (parse-optionals args " " 'infix)
(check-arg string? delim join-strings)
(let ((strings (reverse strings)))
(let lp ((strings (cdr strings))
(ans (case grammar
((infix) (list (car strings)))
((suffix) (list (car strings) delim))
(else (error "Illegal grammar" grammar)))))
(if (pair? strings)
(lp (cdr strings)
(cons (car strings) (cons delim ans)))
; All done
(apply string-append ans)))))
"")) ; Special-cased for infix grammar.
;;; FIELD PARSERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; This section defines routines to split a string into fields.
;;; You can parse by specifying a pattern that *separates* fields,
;;; a pattern that *terminates* fields, or a pattern that *matches*
;;; fields.
(define (->delim-matcher x)
(if (procedure? x) x ; matcher proc
(let ((re (cond ((regexp? x) x) ; regexp pattern
((string? x) (make-regexp x)) ; regexp string
(else (error "Illegal pattern/parser" x)))))
;; The matcher proc.
(lambda (s i)
(cond ((regexp-exec re s i) =>
(lambda (m) (values (match:start m 0) (match:end m 0))))
(else (values #f #f)))))))
;;; (infix-splitter [re num-fields handle-delim]) -> parser
;;; (suffix-splitter [re num-fields handle-delim]) -> parser
;;; (sloppy-suffix-splitter [re num-fields handle-delim]) -> parser
;;; (field-splitter [re num-fields]) -> parser
;;;
;;; (parser string [start]) -> string-list
(define (make-field-parser-generator default-delim-matcher loop-proc)
;; This is the parser-generator
(lambda args
(receive (delim-spec num-fields handle-delim)
(parse-optionals args default-delim-matcher #f 'trim)
;; Process and error-check the args
(let ((match-delim (->delim-matcher delim-spec))
(cons-field (case handle-delim ; Field is s[i,j).
((trim) ; Delimiter is s[j,k).
(lambda (s i j k fields)
(cons (substring s i j) fields)))
((split)
(lambda (s i j k fields)
(cons (substring s j k)
(cons (substring s i j) fields))))
((concat)
(lambda (s i j k fields)
(cons (substring s i k)
fields)))
(else
(error "Illegal handle-delim spec"
handle-delim)))))
(receive (num-fields nfields-exact?)
(cond ((not num-fields) (values #f #f))
((not (integer? num-fields))
(error "Illegal NUM-FIELDS value" num-fields))
((<= num-fields 0) (values (- num-fields) #f))
(else (values num-fields #t)))
;; This is the parser.
(lambda (s . maybe-start)
(reverse (loop-proc s (optional-arg maybe-start 0)
match-delim cons-field
num-fields nfields-exact?))))))))
(define default-field-matcher (->delim-matcher "[^ \t\n]+"))
;;; (field-splitter [field-spec num-fields])
(define (field-splitter . args)
(receive (field-spec num-fields)
(parse-optionals args default-field-matcher #f)
;; Process and error-check the args
(let ((match-field (->delim-matcher field-spec)))
(receive (num-fields nfields-exact?)
(cond ((not num-fields) (values #f #f))
((not (integer? num-fields))
(error "Illegal NUM-FIELDS value"
field-splitter num-fields))
((<= num-fields 0) (values (- num-fields) #f))
(else (values num-fields #t)))
;; This is the parser procedure.
(lambda (s . maybe-start)
(reverse (fieldspec-field-loop s (optional-arg maybe-start 0)
match-field num-fields nfields-exact?)))))))
;;; These four procedures implement the guts of each parser
;;; (field, infix, suffix, and sloppy-suffix).
;;;
;;; The CONS-FIELD argument is a procedure that parameterises the
;;; HANDLE-DELIM action for the field parser.
;;;
;;; The MATCH-DELIM argument is used to match a delimiter.
;;; (MATCH-DELIM S I) returns two integers [start, end] marking
;;; the next delimiter after index I in string S. If no delimiter is
;;; found, it returns [#f #f].
;;; In the main loop of each parser, the loop variable LAST-NULL? tells if the
;;; previous delimiter-match matched the empty string. If it did, we start our
;;; next delimiter search one character to the right of the match, so we won't
;;; loop forever. This means that an empty delimiter regexp "" simply splits
;;; the string at each character, which is the correct thing to do.
;;;
;;; These routines return the answer as a reversed list.
(define (fieldspec-field-loop s start match-field num-fields nfields-exact?)
(let ((end (string-length s)))
(let lp ((i start) (nfields 0) (fields '()) (last-null? #f))
(let ((j (if last-null? (+ i 1) i)) ; Where to start next delim search.
;; Check to see if we made our quota before returning answer.
(finish-up (lambda ()
(if (and num-fields (< nfields num-fields))
(error "Too few fields in record." num-fields s)
fields))))
(cond ((> j end) (finish-up)) ; We are done. Finish up.
;; Read too many fields. Bomb out.
((and nfields-exact? (> nfields num-fields))
(error "Too many fields in record." num-fields s))
;; Made our lower-bound quota. Quit early.
((and num-fields (= nfields num-fields) (not nfields-exact?))
(if (= i end) fields ; Special case hackery.
(cons (substring s i end) fields)))
;; Match off another field & loop.
(else (receive (m0 m1) (match-field s j)
(if m0 (lp m1 (+ nfields 1)
(cons (substring s m0 m1) fields)
(= m0 m1))
(finish-up))))))))) ; No more matches. Finish up.
(define (infix-field-loop s start match-delim cons-field
num-fields nfields-exact?)
(let ((end (string-length s)))
(if (= start end) '() ; Specially hack empty string.
(let lp ((i start) (nfields 0) (fields '()) (last-null? #f))
(let ((finish-up (lambda ()
;; s[i,end) is the last field. Terminate the loop.
(cond ((and num-fields (< (+ nfields 1) num-fields))
(error "Too few fields in record."
num-fields s))
((and nfields-exact?
(>= nfields num-fields))
(error "Too many fields in record."
num-fields s))
(else
(cons (substring s i end) fields)))))
(j (if last-null? (+ i 1) i))) ; Where to start next search.
(cond
;; If we've read NUM-FIELDS fields, quit early .
((and num-fields (= nfields num-fields))
(if nfields-exact?
(error "Too many fields in record." num-fields s)
(cons (substring s i end) fields)))
((<= j end) ; Match off another field.
(receive (m0 m1) (match-delim s j)
(if m0
(lp m1 (+ nfields 1)
(cons-field s i m0 m1 fields)
(= m0 m1))
(finish-up)))) ; No more delimiters - finish up.
;; We've run off the end of the string. This is a weird
;; boundary case occuring with empty-string delimiters.
(else (finish-up))))))))
;;; Match off an optional initial delimiter,
;;; then jump off to the suffix parser.
(define (sloppy-suffix-field-loop s start match-delim cons-field
num-fields nfields-exact?)
;; If sloppy-suffix, skip an initial delimiter if it's there.
(let ((start (receive (i j) (match-delim s start)
(if (and i (zero? i)) j start))))
(suffix-field-loop s start match-delim cons-field
num-fields nfields-exact?)))
(define (suffix-field-loop s start match-delim cons-field
num-fields nfields-exact?)
(let ((end (string-length s)))
(let lp ((i start) (nfields 0) (fields '()) (last-null? #f))
(let ((j (if last-null? (+ i 1) i))) ; Where to start next delim search.
(cond ((= i end) ; We are done.
(if (and num-fields (< nfields num-fields)) ; Didn't make quota.
(error "Too few fields in record." num-fields s)
fields))
;; Read too many fields. Bomb out.
((and nfields-exact? (= nfields num-fields))
(error "Too many fields in record." num-fields s))
;; Made our lower-bound quota. Quit early.
((and num-fields (= nfields num-fields) (not nfields-exact?))
(cons (substring s i end) fields))
(else ; Match off another field.
(receive (m0 m1) (match-delim s j)
(if m0 (lp m1 (+ nfields 1)
(cons-field s i m0 m1 fields)
(= m0 m1))
(error "Missing field terminator" s)))))))))
;;; Now, build the exported procedures: {infix,suffix,sloppy-suffix}-splitter.
(define default-suffix-matcher (->delim-matcher "[ \t\n]+|$"))
(define default-infix-matcher (->delim-matcher "[ \t\n]+"))
(define infix-splitter
(make-field-parser-generator default-infix-matcher infix-field-loop))
(define suffix-splitter
(make-field-parser-generator default-suffix-matcher suffix-field-loop))
(define sloppy-suffix-splitter
(make-field-parser-generator default-suffix-matcher sloppy-suffix-field-loop))
;;; Delimited readers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; We repeatedly allocate a buffer and fill it with READ-DELIMITED!
;;; until we hit a delimiter or EOF. Each time through the loop, we
;;; double the total buffer space, so the loop terminates with a log
;;; number of reads, but uses at most double the optimal buffer space.
(define (read-delimited delims . maybe-port)
(let ((smart-substring (lambda (s end)
(if (= end (string-length s)) s
(substring s 0 end))))
(delims (->char-set delims)))
;; BUFLEN is total amount of buffer space allocated to date.
(let lp ((strs '()) (buflen 80) (buf (make-string 80)))
(cond ((apply read-delimited! delims buf maybe-port) =>
(lambda (i)
(if (null? strs) ; Gratuitous optimisation.
(smart-substring buf i)
(apply string-append
(reverse (if (eof-object? i)
strs
(cons (smart-substring buf i)
strs)))))))
(else (lp (cons buf strs)
(+ buflen buflen)
(make-string buflen)))))))
;;; (read-delimited! delims buf [port start end])
(define (read-delimited! delims buf . args) ; [port start end]
(receive (port start end)
(parse-optionals args (current-input-port) 0 (string-length buf))
(check-arg input-port? port read-delimited!)
(let ((delims (->char-set delims)))
; (if (fd-inport? port) ; ???
;
; ;; Handle fdports in C code for speed.
; (receive (err val)
; (%read-delimited-fdport!/errno delims buf port start end)
; (if err
; (errno-error err read-delimited!)
; val))
;; This is the code for other kinds of ports.
(let lp ((i start))
(and (< i end)
(let ((c (peek-char port)))
(if (or (eof-object? c)
(char-set-contains? delims c))
(- i start)
(begin (string-set! buf i (read-char port))
(lp (+ i 1))))))))))
;)
;(define-foreign %read-delimited-fdport!/errno (read_delim (string-desc delims)
; (string-desc buf)
; (desc port) ;???
; (fixnum start)
; (fixnum end))
; desc ; errno or #f
; desc) ; nread or #f or eof-object
(define (skip-char-set cset . maybe-port)
(let ((port (optional-arg maybe-port (current-input-port))))
(let lp ()
(let ((c (peek-char port)))
(cond ((and (char? c) (char-set-contains? cset c))
(read-char port)
(lp))
(else c))))))
;;; Reading records
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define default-record-delims (char-set #\newline))
;;; (record-reader [delims elide? handle-delim]) -> reader
;;; (reader [port]) -> string or eof
(define (record-reader . args)
(receive (delims elide? handle-delim)
(parse-optionals args default-record-delims #f 'trim)
(let ((delims (->char-set delims)))
(case handle-delim
((trim) ; TRIM-delimiter reader.
(lambda maybe-port
(let ((s (apply read-delimited delims maybe-port)))
(if (not (eof-object? s))
(if elide?
(apply skip-char-set delims maybe-port) ; Snarf delims.
(apply read-char maybe-port))) ; Just snarf one.
s)))
((concat split) ; CONCAT-delimiter & SPLIT-delimiter reader.
(let ((not-delims (char-set-invert delims)))
(lambda maybe-port
(let ((s (apply read-delimited delims maybe-port)))
(if (eof-object? s) s
(let ((delim (if elide?
(apply read-delimited not-delims maybe-port)
(string (apply read-char maybe-port)))))
(if (eq? handle-delim 'split)
(values s delim)
(if (eof-object? delim) s
(string-append s delim)))))))))
(else
(error "Illegal delimiter-action" handle-delim))))))
;;; {string, char, char-set, char predicate} -> char-set
(define (->char-set x)
(cond ((char-set? x) x)
((string? x) (string->char-set x))
((char? x) (char-set x))
((procedure? x) (predicate->char-set x))
(else (error "->char-set: Not a charset, string, char, or predicate."
x))))
(define blank-line-regexp (make-regexp "^[ \t]*\n$"))
;;; (read-paragraph [port])
(define (read-paragraph . maybe-port)
(let ((port (optional-arg maybe-port (current-input-port))))
;; First, skip all blank lines.
(let lp ()
(let ((line (read-line port #t)))
(cond ((eof-object? line) line)
((regexp-exec blank-line-regexp line) (lp))
;; Then, read in non-blank lines.
(else (let ((lines (let lp ((lines (list line)))
(let ((line (read-line port #t)))
(cond ((or (eof-object? line)
(regexp-exec blank-line-regexp
line))
lines)
(else (lp (cons line lines))))))))
;; Return the paragraph
(apply string-append (reverse lines)))))))))
;;; Reading and parsing records
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; (field-reader [field-parser rec-reader]) -> reader
;;; (reader [port]) -> [raw-record parsed-record] or [eof #()]
;;;
;;; This is the field reader, which is basically just a composition of
;;; RECORD-READER and FIELD-PARSER.
(define default-field-parser (field-splitter))
(define (field-reader . args)
(receive (parser rec-reader)
(parse-optionals args default-field-parser read-line)
(lambda maybe-port
(let ((record (apply rec-reader maybe-port)))
(if (eof-object? record)
(values record '#())
(values record (parser record)))))))
;;; Parse fields by regexp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; This code parses up a record into fields by matching a regexp specifying
;;; the field against the record. The regexp describes the *field*. In the
;;; other routines, the regexp describes the *delimiters*. They are
;;; complimentary.
;;; Repeatedly do (APPLY PROC M STATE) to generate new state values,
;;; where M is a regexp match structure made from matching against STRING.
;(define (regexp-reduce string start regexp proc . state)
; (let ((end (string-length string))
; (regexp (if (string? regexp)
; (make-regexp regexp)
; regexp)))
;
; (let lp ((i start) (state state) (last-null? #f))
; (let ((j (if last-null? (+ i 1) i)))
; (cond ((and (<= j end) (regexp-exec regexp string j)) =>
; (lambda (m)
; (receive state (apply proc m state)
; (lp (match:end m) state (= (match:start m) (match:end m))))))
; (else (apply values state)))))))
;
;(define (all-regexp-matches regexp string)
; (reverse (regexp-reduce string 0 regexp
; (lambda (m ans) (cons (match:substring m 0) ans))
; '())))
;;; Previously in newports.scm
;;; Read in a line of data. Input is terminated by either a newline or EOF.
;;; The newline is trimmed from the string.
(define (read-line . rest)
(let ((port (if (null? rest) (current-input-port) (car rest))) ; Optional arg
(retain-newline? (and (not (null? rest)) ; parsing.
(not (null? (cdr rest)))
(cadr rest)))
;; S[I] := C. If this overflows S, grow it.
(deposit (lambda (s i c)
(let ((s (if (< i (string-length s)) s
(string-append s s)))) ; doubling hack
(string-set! s i c)
s)))
;; Precisely resize S to size NUMCHARS.
(trim (lambda (s numchars)
(if (= numchars (string-length s)) s
(substring s 0 numchars)))))
(let lp ((s (make-string 81)) (numchars 0))
(let ((c (read-char port)))
(cond ((eof-object? c)
(if (zero? numchars) c
(trim s numchars)))
((char=? c #\newline)
(if retain-newline?
(trim (deposit s numchars c)
(+ numchars 1))
(trim s numchars)))
(else (lp (deposit s numchars c)
(+ numchars 1))))))))

View File

@ -1,100 +0,0 @@
;;; Here documents in Scheme for scsh scripts.
;;; These are like "here documents" for sh and csh shell scripts
;;; (i.e., the <<EOF redirection).
;;; Copyright (c) 1995 by Olin Shivers.
;;; #<EOF
;;; Hello, there.
;;; This is read by Scheme as a string,
;;; terminated by the first occurrence
;;; of newline-E-O-F.
;;; EOF
;;; Thus,
;;; #<foo
;;; Hello, world.
;;; foo
;;; is the same thing as
;;; "Hello, world."
;;; These are useful for writing down long, constant strings -- such
;;; as long, multi-line FORMAT strings, or arguments to Unix programs, e.g.
;;; ;; Free up some disk space for my netnews files.
;;; (run (csh -c #<EOF
;;; cd ~bdc
;;; rm -rf .
;;; echo All done.
;;;
;;; EOF))
;;; The syntax is as follows: the three characters "#<" introduce the
;;; here-string. The characters between the second "<" and the next newline
;;; are the *delimiter word." *All* chars between the second "<" and the next
;;; newline comprise the delimiter word -- including any white space. The
;;; newline char separates the delimiter word from the body of the string. The
;;; string body is terminated by a newline followed by the delimiter string.
;;; Absolutely *no* interpretation is done on the input string, except for
;;; scanning for the terminating delimiter word. Control chars, white space,
;;; quotes, backslash chars -- everything is copied as-is.
;;;
;;; If EOF is encountered before reading the end of the here string, an
;;; error is signalled.
(define (read-here-string port)
;; First, read in the delimiter.
(let ((delim (read-line port)))
(cond ((eof-object? delim)
(reading-error port "EOF while reading #< here-string delimiter."))
((zero? (string-length delim))
(reading-error port "#< here-string empty delimiter"))
;; This loop works as follows. We enter the loop after having
;; read a newline. We scan into the text until we discover
;; delimiter match/no-match. If match, we exit the loop;
;; if no match, we read in the rest of the line and iterate.
;; TEXT is the text we've read so far -- a list of strings in
;; reverse order.
(else
(let lp ((text '()))
(cond ((delimiter-scan delim port) =>
(lambda (line-start)
(let ((text (cons line-start text))
(ls-len (string-length line-start)))
(lp (if (char=? #\newline (string-ref line-start
(- ls-len 1)))
text
(let ((line-rest (read-line port 'concat)))
(if (eof-object? line-rest)
(reading-error port
"EOF while reading #< here-string.")
(cons line-rest text))))))))
;; We're done. The last line, tho, needs its newline
;; stripped off.
((null? text) "")
(else (let* ((last-chunk (car text))
(lc-len (string-length last-chunk))
(last-chunk (substring last-chunk 0 (- lc-len 1)))
(text (cons last-chunk (cdr text))))
(make-immutable! (apply string-append
(reverse text)))))))))))
;;; If the next chars read from PORT match DELIM, return false.
;;; Otherwise, return the string you read from PORT to determine the non-match.
;;; If EOF is encountered, report an error.
(define (delimiter-scan delim port)
(let ((len (string-length delim)))
(let lp ((i 0))
(and (< i len)
(let ((c (read-char port)))
(cond ((eof-object? c)
(reading-error port "EOF while reading #< here string."))
((char=? c (string-ref delim i))
(lp (+ i 1)))
(else (string-append (substring delim 0 i)
(string c)))))))))
;(define-sharp-macro #\<
; (lambda (c port) (read-here-string port)))

View File

@ -301,7 +301,7 @@
(cons wptr result)
result)))
'()
lis))
list))
;;; Add a newly-reaped proc to the list.
(define (add-reaped-proc! pid status)

View File

@ -150,12 +150,12 @@
&opt (proc (:exact-integer :value) :value)
:exact-integer)
:value))
(regexp-fold-right (proc (:value (proc (:value :exact-integer :value) :value)
:value
:string
&opt (proc (:exact-integer :value) :value)
:exact-integer)
:value))
(regexp-fold (proc (:value (proc (:value :exact-integer :value) :value)
:value
:string
&opt (proc (:exact-integer :value) :value)
:exact-integer)
:value))
(regexp-for-each (proc (:value (proc (:value) :unspecific)
:string &opt :exact-integer)
:unspecific))))
@ -164,9 +164,9 @@
(compound-interface posix-re-interface
basic-re-interface
(export (regexp-match? (proc (:value) :boolean))
(match:start (proc (:value &opt :exact-integer) :value))
(match:end (proc (:value &opt :exact-integer) :value))
(match:substring (proc (:value &opt :exact-integer) :value))
(match:start (proc (:value :exact-integer) :value))
(match:end (proc (:value :exact-integer) :value))
(match:substring (proc (:value :exact-integer) :value))
(clean-up-cres (proc () :unspecific))
(regexp-search (proc (:value :string &opt :exact-integer)
:value))

View File

@ -162,149 +162,138 @@
((c sre %word) (non-cset) re-word)
((pair? sre)
(let ((hygn-eq? (lambda (the-sym) (c (car sre) (r the-sym)))))
(cond
((hygn-eq? '*) (non-cset) (re-repeat 0 #f (parse-seq (cdr sre))))
((hygn-eq? '+) (non-cset) (re-repeat 1 #f (parse-seq (cdr sre))))
((hygn-eq? '?) (non-cset) (re-repeat 0 1 (parse-seq (cdr sre))))
((hygn-eq? '=) (non-cset) (let ((n (cadr sre)))
(re-repeat n n (parse-seq (cddr sre)))))
((hygn-eq? '>=) (non-cset) (re-repeat (cadr sre) #f (parse-seq (cddr sre))))
((hygn-eq? '**) (non-cset) (re-repeat (cadr sre) (caddr sre)
(parse-seq (cdddr sre))))
;; Choice is special wrt cset? because it's "polymorphic".
;; Note that RE-CHOICE guarantees to construct a char-set
;; or single-char string regexp if all of its args are char
;; classes.
((or (hygn-eq? '|)
(hygn-eq? 'or))
(let ((elts (map (lambda (sre)
(recur sre case-sensitive? cset?))
(cdr sre))))
(if cset?
(assoc-cset-op char-set-union 'char-set-union elts r)
(re-choice elts))))
((or (hygn-eq? ':)
(hygn-eq? 'seq))
(non-cset) (parse-seq (cdr sre)))
((hygn-eq? 'word) (non-cset) (parse-seq `(,%bow ,@(cdr sre) ,%eow)))
((hygn-eq? 'word+)
(recur `(,(r 'word) (,(r '+) (,(r '&) (,(r '|) ,(r 'alphanum) "_")
(,(r '|) . ,(cdr sre)))))
case-sensitive?
cset?))
((hygn-eq? 'submatch) (non-cset) (re-submatch (parse-seq (cdr sre))))
((hygn-eq? 'dsm) (non-cset) (re-dsm (parse-seq (cdddr sre))
(cadr sre)
(caddr sre)))
;; We could be more aggressive and push the uncase op down into
;; partially-static regexps, but enough is enough.
((hygn-eq? 'uncase)
(let ((re-or-cset (parse-seq (cdr sre)))) ; Depending on CSET?.
(if cset?
(if (re-char-set? re-or-cset) ; A char set or code
(uncase-char-set re-or-cset) ; producing a char set.
`(,(r 'uncase) ,re-or-cset))
(if (static-regexp? re-or-cset) ; A regexp or code
(uncase re-or-cset) ; producing a regexp.
`(,(r 'uncase)
,(regexp->scheme (simplify-regexp re-or-cset) r))))))
;; These just change the lexical case-sensitivity context.
((hygn-eq? 'w/nocase) (parse-seq/context (cdr sre) #f))
((hygn-eq? 'w/case) (parse-seq/context (cdr sre) #t))
;; ,<exp> and ,@<exp>
((hygn-eq? 'unquote)
(case (car sre)
((*) (non-cset) (re-repeat 0 #f (parse-seq (cdr sre))))
((+) (non-cset) (re-repeat 1 #f (parse-seq (cdr sre))))
((?) (non-cset) (re-repeat 0 1 (parse-seq (cdr sre))))
((=) (non-cset) (let ((n (cadr sre)))
(re-repeat n n (parse-seq (cddr sre)))))
((>=) (non-cset) (re-repeat (cadr sre) #f (parse-seq (cddr sre))))
((**) (non-cset) (re-repeat (cadr sre) (caddr sre)
(parse-seq (cdddr sre))))
;; Choice is special wrt cset? because it's "polymorphic".
;; Note that RE-CHOICE guarantees to construct a char-set
;; or single-char string regexp if all of its args are char
;; classes.
((| or) (let ((elts (map (lambda (sre)
(recur sre case-sensitive? cset?))
(cdr sre))))
(if cset?
(assoc-cset-op char-set-union 'char-set-union elts r)
(re-choice elts))))
((: seq) (non-cset) (parse-seq (cdr sre)))
((word) (non-cset) (parse-seq `(,%bow ,@(cdr sre) ,%eow)))
((word+)
(recur `(,(r 'word) (,(r '+) (,(r '&) (,(r '|) ,(r 'alphanum) "_")
(,(r '|) . ,(cdr sre)))))
case-sensitive?
cset?))
((submatch) (non-cset) (re-submatch (parse-seq (cdr sre))))
((dsm) (non-cset) (re-dsm (parse-seq (cdddr sre))
(cadr sre)
(caddr sre)))
;; We could be more aggressive and push the uncase op down into
;; partially-static regexps, but enough is enough.
((uncase)
(let ((re-or-cset (parse-seq (cdr sre)))) ; Depending on CSET?.
(if cset?
(if (re-char-set? re-or-cset) ; A char set or code
(uncase-char-set re-or-cset) ; producing a char set.
`(,(r 'uncase) ,re-or-cset))
(if (static-regexp? re-or-cset) ; A regexp or code
(uncase re-or-cset) ; producing a regexp.
`(,(r 'uncase)
,(regexp->scheme (simplify-regexp re-or-cset) r))))))
;; These just change the lexical case-sensitivity context.
((w/nocase) (parse-seq/context (cdr sre) #f))
((w/case) (parse-seq/context (cdr sre) #t))
;; ,<exp> and ,@<exp>
((unquote)
(let ((exp (cadr sre)))
(if cset?
`(,%coerce-dynamic-charset ,exp)
`(,%flush-submatches (,%coerce-dynamic-regexp ,exp)))))
((hygn-eq? 'unquote-splicing)
(let ((exp (cadr sre)))
(if cset?
`(,%coerce-dynamic-charset ,exp)
`(,%coerce-dynamic-regexp ,exp))))
((hygn-eq? '~) (let* ((cs (assoc-cset-op char-set-union 'char-set-union
(map parse-char-class (cdr sre))
r))
(cs (if (char-set? cs)
((unquote-splicing)
(let ((exp (cadr sre)))
(if cset?
`(,%coerce-dynamic-charset ,exp)
`(,%coerce-dynamic-regexp ,exp))))
((~) (let* ((cs (assoc-cset-op char-set-union 'char-set-union
(map parse-char-class (cdr sre))
r))
(cs (if (char-set? cs)
(char-set-complement cs)
`(,(r 'char-set-complement) ,cs))))
(if cset? cs (make-re-char-set cs))))
((hygn-eq? '&) (let ((cs (assoc-cset-op char-set-intersection 'char-set-intersection
(map parse-char-class (cdr sre))
r)))
(if cset? cs (make-re-char-set cs))))
((hygn-eq? '-) (if (pair? (cdr sre))
(let* ((cs1 (parse-char-class (cadr sre)))
(cs2 (assoc-cset-op char-set-union 'char-set-union
(if cset? cs (make-re-char-set cs))))
((&) (let ((cs (assoc-cset-op char-set-intersection 'char-set-intersection
(map parse-char-class (cdr sre))
r)))
(if cset? cs (make-re-char-set cs))))
((-) (if (pair? (cdr sre))
(let* ((cs1 (parse-char-class (cadr sre)))
(cs2 (assoc-cset-op char-set-union 'char-set-union
(map parse-char-class (cddr sre))
r))
(cs (if (and (char-set? cs1) (char-set? cs2))
(char-set-difference cs1 cs2)
`(,(r 'char-set-difference)
,(if (char-set? cs1)
(char-set->scheme cs1 r)
(cs (if (and (char-set? cs1) (char-set? cs2))
(char-set-difference cs1 cs2)
`(,(r 'char-set-difference)
,(if (char-set? cs1)
(char-set->scheme cs1 r)
cs1)
. ,(if (char-set? cs2)
(list (char-set->scheme cs2 r))
(cdr cs2))))))
(if cset? cs (make-re-char-set cs)))
(error "SRE set-difference operator (- ...) requires at least one argument")))
((hygn-eq? '/) (let ((cset (range-class->char-set (cdr sre) case-sensitive?)))
. ,(if (char-set? cs2)
(list (char-set->scheme cs2 r))
(cdr cs2))))))
(if cset? cs (make-re-char-set cs)))
(error "SRE set-difference operator (- ...) requires at least one argument")))
((/) (let ((cset (range-class->char-set (cdr sre) case-sensitive?)))
(if cset? cset (make-re-char-set cset))))
((hygn-eq? 'posix-string)
((posix-string)
(if (and (= 1 (length (cdr sre)))
(string? (cadr sre)))
(posix-string->regexp (cadr sre))
(error "Illegal (posix-string ...) SRE body." sre)))
(else (if (every string? sre) ; A set spec -- ("wxyz").
(let* ((cs (apply char-set-union
(map string->char-set sre)))
(cs (if case-sensitive? cs (uncase-char-set cs))))
(if cset? cs (make-re-char-set cs)))
(error "Illegal SRE" sre))))))
(else (if (every string? sre) ; A set spec -- ("wxyz").
(let* ((cs (apply char-set-union
(map string->char-set sre)))
(cs (if case-sensitive? cs (uncase-char-set cs))))
(if cset? cs (make-re-char-set cs)))
(error "Illegal SRE" sre)))))
;; It must be a char-class name (ANY, ALPHABETIC, etc.)
(else
(letrec ((hygn-memq? (lambda (sym-list)
(if (null? sym-list)
#f
(or (c sre (r (car sym-list)))
(hygn-memq? (cdr sym-list)))))))
(let ((cs (cond
((hygn-memq? '(any)) char-set:full)
((hygn-memq? '(nonl)) nonl-chars)
((hygn-memq? '(lower-case lower)) char-set:lower-case)
((hygn-memq? '(upper-case upper)) char-set:upper-case)
((hygn-memq? '(alphabetic alpha)) char-set:letter)
((hygn-memq? '(numeric digit num)) char-set:digit)
((hygn-memq? '(alphanumeric alnum alphanum)) char-set:letter+digit)
((hygn-memq? '(punctuation punct)) char-set:punctuation)
((hygn-memq? '(graphic graph)) char-set:graphic)
((hygn-memq? '(blank)) char-set:blank)
((hygn-memq? '(whitespace space white)) char-set:whitespace)
((hygn-memq? '(printing print)) char-set:printing)
((hygn-memq? '(control cntrl)) char-set:iso-control)
((hygn-memq? '(hex-digit xdigit hex)) char-set:hex-digit)
((hygn-memq? '(ascii)) char-set:ascii)
(else (error "Illegal regular expression" sre)))))
(if cset? cs (make-re-char-set cs)))))))))
(else (let ((cs (case sre
((any) char-set:full)
((nonl) nonl-chars)
((lower-case lower) char-set:lower-case)
((upper-case upper) char-set:upper-case)
((alphabetic alpha) char-set:letter)
((numeric digit num) char-set:digit)
((alphanumeric alnum alphanum) char-set:letter+digit)
((punctuation punct) char-set:punctuation)
((graphic graph) char-set:graphic)
((blank) char-set:blank)
((whitespace space white) char-set:whitespace)
((printing print) char-set:printing)
((control cntrl) char-set:iso-control)
((hex-digit xdigit hex) char-set:hex-digit)
((ascii) char-set:ascii)
(else (error "Illegal regular expression" sre)))))
(if cset? cs (make-re-char-set cs))))))))
;;; In a CSET? true context, S must be a 1-char string; convert to a char set

View File

@ -498,7 +498,7 @@
(values re #f))))
((re-submatch? re)
(receive (new-body body-changed?) (recur (re-submatch:body re))
(receive (new-body body-changed?) (recur (re-submatch? re))
(if body-changed?
(values (%make-re-submatch new-body
(re-submatch:pre-dsm re)

View File

@ -140,8 +140,7 @@
;; Regular letter -- either alone, or startpoint of a range.
(else (if (and (< (+ i1 1) len)
(char=? #\- (string-ref s i1))
(not (char=? #\] (string-ref s (+ i1 1)))))
(char=? #\- (string-ref s i1)))
;; Range
(let* ((i-tochar (+ i1 1))

View File

@ -171,8 +171,7 @@
string-lib
fluids ; For exec-path-list
loopholes ; For my bogus CALL-TERMINALLY implementation.
loopholes ; For my bogus CALL-TERMINALLY implementation.
scheme
)
@ -248,8 +247,6 @@
command-processor ; command-output
filenames ; translate
scheme-level-2-internal ; usual-resumer
package-commands-internal ;user-environment
environments ; with-interaction-environment
scheme)
(files startup)
(optimize auto-integrate)
@ -359,7 +356,7 @@
(export repl)
awk-interface
odbc-interface
char-predicates-interface; Urk -- Some of this is R5RS!
char-set-predicates-interface; Urk -- Some of this is R5RS!
obsolete-char-set-interface
)
@ -375,7 +372,7 @@
awk-package
odbc-package
field-reader-package
char-predicates-lib ; Urk -- Some of this is R5RS!
char-set-predicates-lib ; Urk -- Some of this is R5RS!
scheme)
(access scsh-top-package)

View File

@ -297,8 +297,7 @@
(close-fdes (open-fdes fname oflags #o600))
fname)
(if (null? maybe-prefix) '()
(list (string-append (constant-format-string (car maybe-prefix))
".~a"))))))
(list (string-append (car maybe-prefix) ".~a"))))))
(define *temp-file-template*
(make-fluid (string-append "/usr/tmp/" (number->string (pid)) ".~a")))
@ -317,23 +316,6 @@
(loop (+ i 1)))))))))
;; Double tildes in S.
;; Using the return value as a format string will output exactly S.
(define (constant-format-string s) ; Ugly code. Would be much clearer
(let* ((len (string-length s)) ; if written with string SRFI.
(tilde? (lambda (s i) (char=? #\~ (string-ref s i))))
(newlen (do ((i (- len 1) (- i 1))
(ans 0 (+ ans (if (tilde? s i) 2 1))))
((< i 0) ans)))
(fs (make-string newlen)))
(let lp ((i 0) (j 0))
(cond ((< i len)
(let ((j (cond ((tilde? s i) (string-set! fs j #\~) (+ j 1))
(else j))))
(string-set! fs j (string-ref s i))
(lp (+ i 1) (+ j 1))))))
fs))
;;; Roughly equivalent to (pipe).
;;; Returns two file ports [iport oport] open on a temp file.
@ -682,7 +664,7 @@
(%exec prog (cons prog arglist) env))
;(define (exec-path/env prog env . arglist)
; (cond ((exec-path-search (stringify prog) (fluid exec-path-list)) =>
; (cond ((exec-path-search (stringify prog) exec-path-list) =>
; (lambda (binary)
; (apply exec/env binary env arglist)))
; (else (error "No executable found." prog arglist))))
@ -704,7 +686,7 @@
(for-each (lambda (dir)
(let ((binary (string-append dir "/" prog)))
(%%exec/errno binary argv env)))
(fluid exec-path-list)))))
exec-path-list))))
(error "No executable found." prog arglist))
@ -764,7 +746,7 @@
;;; Some globals:
(define home-directory "")
(define exec-path-list (make-fluid '()))
(define exec-path-list '())
(define (init-scsh-vars quietly?)
(set! home-directory
@ -772,11 +754,11 @@
(else (if (not quietly?)
(warn "Starting up with no home directory ($HOME)."))
"/")))
(set-fluid! exec-path-list
(cond ((getenv "PATH") => split-colon-list)
(else (if (not quietly?)
(warn "Starting up with no path ($PATH)."))
'()))))
(set! exec-path-list
(cond ((getenv "PATH") => split-colon-list)
(else (if (not quietly?)
(warn "Starting up with no path ($PATH)."))
'()))))
; SIGTSTP blows s48 away. ???

View File

@ -42,20 +42,10 @@
;;; This is what we export to the user for his programs.
(define (dump-scsh-program start filename)
(let ((context (user-context)))
(really-dump-scsh-program
(lambda (args)
(with-new-session context ; "Log in" user.
(current-input-port) (current-output-port)
args
#f
(lambda ()
(with-interaction-environment
(user-environment) ; <-- from CONTEXT.
(lambda ()
(init-scsh-vars #t) ; Do it quietly.
(start args))))))
filename)))
(really-dump-scsh-program (lambda (args)
(init-scsh-vars #t) ; Do it quietly.
(start args))
filename))
(define (scsh-stand-alone-resumer start)

View File

@ -891,10 +891,7 @@
(define (alist->env-vec alist)
(list->vector (map (lambda (var.val)
(string-append (car var.val) "="
(let ((val (cdr var.val)))
(if (string? val) val
(string-join val ":")))))
(string-append (car var.val) "=" (cdr var.val)))
alist)))
;;; ENV->ALIST

View File

@ -217,7 +217,7 @@ scheme_value date2time(int sec, int min, int hour,
d.tm_sec = sec; d.tm_min = min; d.tm_hour = hour;
d.tm_mday = mday; d.tm_mon = month; d.tm_year = year;
d.tm_wday = 0; d.tm_yday = 0;
d.tm_wday = 0; d.tm_yday = 0; d.tm_isdst = summer;
if( FIXNUMP(tz_secs) ) { /* Offset from GMT in seconds. */
char **oldenv = environ; /* Set TZ to UTC */
@ -232,16 +232,12 @@ scheme_value date2time(int sec, int min, int hour,
environ = oldenv;
}
/* ### Note that we *still* don't implement the manual paragraph
with "When calcultating with time-zones, the date's SUMMER?
field is used to resolve ambiguities. */
else if( STRINGP(tz_name) ) { /* Time zone */
char *newenv[2];
char **oldenv = make_newenv(tz_name, newenv);
if( !oldenv ) return ENTER_FIXNUM(errno);
tzset(); /* NetBSD, SunOS POSIX-noncompliance requires this. */
errno = 0;
d.tm_isdst = -1;
t = mktime(&d);
if( t == -1 ) return ENTER_FIXNUM(errno ? errno : -1);
revert_env(oldenv);
@ -250,7 +246,6 @@ scheme_value date2time(int sec, int min, int hour,
else { /* Local time */
tzset(); /* NetBSD, SunOS POSIX-noncompliance requires this. */
errno = 0;
d.tm_isdst = -1;
t = mktime(&d);
if( t == -1) return ENTER_FIXNUM(errno ? errno : -1);
}

2
unix.c
View File

@ -523,7 +523,7 @@ fill_the_table(void)
entry.n_scnum != N_UNDEF &&
entry.n_scnum != N_DEBUG)
{
extern char *ldgetname(LDFILE *, void *);
extern char *ldgetname(LDFILE *, SYMENT *);
char *p = ldgetname(f, &entry);
if (p != NULL && p[0] == '.') {