Compare commits
2 Commits
main
...
srfi13and1
Author | SHA1 | Date |
---|---|---|
![]() |
838b110f01 | |
![]() |
e5a2148d4a |
149
RELEASE
149
RELEASE
|
@ -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
3
Thanks
|
@ -10,6 +10,3 @@ Post-0.5.2-release bug reports:
|
|||
Andy Gaynor
|
||||
Francisco Vides Fernandez
|
||||
Tim Burgess
|
||||
Brian Denheyer
|
||||
Harvey Stein
|
||||
Eric Hilsdale
|
||||
|
|
|
@ -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
|
||||
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
;;
|
||||
|
||||
|
|
|
@ -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
|
||||
;;
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
html
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
|
@ -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
|
|
@ -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%
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.}
|
||||
|
|
|
@ -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}}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -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}
|
||||
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
14
scsh.man
14
scsh.man
|
@ -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
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
/* Exports from signals1.c */
|
||||
|
||||
const int sig2int[];
|
||||
const int max_sig;
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))))))))))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
|
@ -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))))))))))
|
|
@ -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)))
|
||||
|
|
|
@ -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;
|
||||
|
|
568
scsh/oldfr.scm
568
scsh/oldfr.scm
|
@ -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))))))))
|
||||
|
100
scsh/oldhere.scm
100
scsh/oldhere.scm
|
@ -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)))
|
|
@ -301,7 +301,7 @@
|
|||
(cons wptr result)
|
||||
result)))
|
||||
'()
|
||||
lis))
|
||||
list))
|
||||
|
||||
;;; Add a newly-reaped proc to the list.
|
||||
(define (add-reaped-proc! pid status)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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. ???
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue