Compare commits

...

199 Commits

Author SHA1 Message Date
sperber d125af1559 Move S48_GC_UNPROTECT to proper place. 2007-08-21 16:05:49 +00:00
sperber 71a747b4f2 Bug fix submitted by Taylor Campbell:
Since `s48_extract_unsigned_integer' may cause a garbage collection,
  because it calls back to Scheme, the extraction of the host and port
  in the internet address case must be GC-protected, around line 110.  A
  patch to fix this is attached.
2007-01-28 15:13:52 +00:00
sperber 3ee7a21884 Synch SRFI 19 with Scheme 48 (tuebingen/trunk, rev 2031),
incorporating various fixes submitted by Emilio Lopes.
2007-01-05 09:46:35 +00:00
sperber d8b1c64044 Merge from tuebingen/trunk (needed for upcoming fixes to SRFI 19):
r568 | sperber | 2003-12-01 22:42:06 +0100 (Mon, 01 Dec 2003) | 4 lines
Changed paths:
   M /s48/tuebingen/trunk/scheme/bcomp/comp-prim.scm
   M /s48/tuebingen/trunk/scheme/rts/xnum.scm

Subject: Make INEXACT->EXACT work on exacts and vice versa

As discussed on the Scheme 48 mailing list, and requested by jar.
2007-01-05 09:43:28 +00:00
sperber 640281efcb Emilop Lepos reported this:
As stated in the subject line:

   Welcome to scsh 0.6.7 (R6RS)
   Type ,? for help.
   > (string->number "1e2")
   #f

Apply his suggested fix, which is taken from Scheme 48.
2006-11-18 14:16:55 +00:00
sperber 0e0faad5e1 Do this:
From: Emilio Lopes <eclig@gmx.net>
Subject:  Misleading error message in `exec-path/env'
To: scsh-users@scsh.net

The procedure `exec-path/env' gives "No executable found." if it fails
to execute the given program.  This error message is misleading since
there can be other reasons for the failure, e.g. the command line was
too long.  I think something along the lines of "Failed to run
program/executable." would be more appropriate.

--
Emílio C. Lopes
Munich, Germany
2006-11-18 14:14:35 +00:00
sperber b4a1ae5533 Add missing #include <string.h>. 2006-10-31 09:37:15 +00:00
sperber c46c84f66c Fix precedence bugs in regexp code.
Submitted by: Matthew Dempsky
2006-10-31 09:35:19 +00:00
mainzelm bf9dc18cc6 0.6.7 snapshot of autogenerated files 2006-05-23 06:28:14 +00:00
mainzelm 5940d19ff4 0.6.7 release date 2006-05-23 06:27:07 +00:00
mainzelm a3e4aad42f Rearrange code 2006-05-16 13:31:41 +00:00
mainzelm 4a80163ecf 0.6.7 2006-05-16 07:23:16 +00:00
mainzelm 97ed3425cd Comment add 2006-05-16 07:22:15 +00:00
mainzelm da739b9032 Fix for Solaris: make master pty in FORK-PTY-SESSION a TTY as well. 2006-04-26 11:57:04 +00:00
mainzelm 8f234fc733 If a fork narrows the thread system to the current thread, the REPL
gets suspended. However, in an interactive session, the REPL is very
likely to hold the lock of the input port. Hence, release the locks of
the command ports in the child if NARROW? is true.
2006-04-26 09:44:26 +00:00
mainzelm 9a7d5fb8dd new files from automake 1.9.6 2006-04-20 08:19:54 +00:00
mainzelm 1ab6384c63 comment out any-test 2006-04-19 09:18:54 +00:00
mainzelm d21779c9ba more 0.6.7 stuff 2006-04-06 09:23:05 +00:00
mainzelm e76661aadd Remove some tests that didn't really make sense. 2006-04-05 08:09:51 +00:00
mainzelm 5db687eae1 Propagate argv[0] to the scheme level and use it as first element of
the command line.
2006-04-05 08:06:16 +00:00
mainzelm 3b4becd2ba Use / as target directory in cd tests 2006-04-05 07:53:03 +00:00
mainzelm 329e4539b0 Add make-pty-a-tty for System V and use it in fork-pty-session 2006-03-29 16:28:26 +00:00
mainzelm 45acda7c3f New pty tests and some small fixes 2006-03-29 13:37:58 +00:00
mainzelm 2e37299496 Use system-dependent facilities to open a new pty. 2006-03-29 13:24:43 +00:00
mainzelm 89d3cc13e5 More fixes for building outside the source tree. 2006-03-29 13:21:09 +00:00
mainzelm 086e0d434c Add missing $(srcdir) for scsh/configure.scm 2006-03-27 08:41:40 +00:00
mainzelm d5dc6c5b45 Include ./c for compiling C files to find c/sysdep.h when building
outside the source tree.
2006-03-27 08:34:31 +00:00
mainzelm 4cd8cffe81 Fix bug in test case 2006-03-23 11:07:10 +00:00
mainzelm 2d4ce713b7 level fix 2006-03-23 10:55:01 +00:00
mainzelm d11a09044c Add structures for remaining test files and add all test modules to
the opened packages of test-all.
2006-03-23 10:54:02 +00:00
mainzelm e1bcf389b6 One more test 2006-03-23 10:53:08 +00:00
mainzelm 8246b41681 Let UNCASE-CHAR-SET return a regular expression as promised in the manual. 2006-03-23 10:52:31 +00:00
mainzelm bbcf682f5b Remove test cases assuming SKIP-CHAR-SET is accepting a character
predicate - it does no longer.
2006-03-23 10:04:34 +00:00
mainzelm bfbb3e31ea Fix expr-test-test 2006-03-23 09:35:15 +00:00
mainzelm d18adb9c2b Adjust char-set tests to match 8 bit representation 2006-03-23 08:09:51 +00:00
mainzelm c965536804 Cover 8 bits instead of 7 when converting from char-sets to regexps. 2006-03-23 07:59:14 +00:00
mainzelm fbfe81aa85 Two casts to please gcc 4 2006-03-23 07:57:10 +00:00
mainzelm 842fc396b8 Another fix for read-line-split-test
Uniform test suite name
2006-03-22 13:06:29 +00:00
mainzelm 2e4f79161c Fix read-line-split-test
Fix typos
2006-03-22 13:02:22 +00:00
mainzelm 2ec9c3d879 Add missing standard header includes spotted by gcc 4 2006-03-22 08:35:14 +00:00
mainzelm 6abcd34721 Remove superfluous pdf options in dvi section 2006-03-22 08:33:32 +00:00
mainzelm cc0c0cf571 Reformat New in this release 2006-03-21 15:11:33 +00:00
mainzelm 809b1bc022 More steps towards 0.6.7 release 2006-03-08 11:50:35 +00:00
mainzelm c1eac4922d Updates for mailing lists hosted at scsh.net 2006-03-08 11:49:46 +00:00
mainzelm cc5bfef76e Fix typo 2006-03-08 11:48:59 +00:00
mainzelm 364eb89dd8 Set default image for scshvm to scsh.image (fixes #1091147) 2006-03-02 22:15:34 +00:00
mainzelm d6d422006f Search for modules in 0.6/ as well for better compatibility with
install-lib.
2006-03-02 21:33:43 +00:00
mainzelm 4702963425 Undo Brian's last commit as it was broken (removes Linux support, ...) 2006-03-02 21:32:31 +00:00
sperber a3f0a3ffb9 Add new leap second, submitted by SRFI author. 2005-12-26 10:44:34 +00:00
mainzelm 0698e636f1 Make gcc 4.0 happy by removing internal static declaration of
write_integer and moving this function above its first point of usage.
2005-10-27 07:48:44 +00:00
mainzelm ed254f1366 Remove the claim that READ-DELIMITED and SKIP-CHAR-SET accept char
predicates. SRFI-14's x->char-set does not accept them, hence we don't
do as well.

This fixed bug report #1017609
2005-10-18 15:06:33 +00:00
mainzelm abd81132dc comment fix: x->char-set does not accept char predicates 2005-10-18 15:02:46 +00:00
mainzelm 5f3c53746f Let (%)read-delimited! ensure that the buffer is mutable. 2005-10-18 14:58:11 +00:00
mainzelm ec4ec22eac Provide R5RS's let as STANDARD-LET to the implementation of SRFI 5 2005-10-18 14:07:21 +00:00
mainzelm f4fbe4c986 (rx (| numeric alphabetic)) yields a char-set: but
(rx (| ,(rx numeric) ,(rx alphabetic))) doesn't:, even
though the "type-checking rules" for char-sets says
that it should:

> (rx (| numeric alphabetic))
'#{re-char-set}
> (rx (| ,(rx numeric) ,(rx alphabetic)))
'#{Re-choice}

The following patch fixes this but I'm not sure if
make-re-choice is the right place to tackle this problem:

This fixes bug report #1063781
2005-10-18 14:01:50 +00:00
mainzelm cfcb6a1b05 Get rid of sig_t 2005-10-18 13:54:22 +00:00
mainzelm 525f13a82b Declare proper functions 2005-10-18 13:52:48 +00:00
mainzelm 7dbf2eca7c Preparations for 0.6.7 release 2005-10-18 13:34:14 +00:00
mainzelm e28875cd51 Describe IGNORE-SIGNAL and HANDLE-SIGNAL-DEFAULT 2005-10-18 12:39:32 +00:00
mainzelm a049a71641 Fix two glitches 2005-10-17 21:04:46 +00:00
eknauel ac0edb679b Fix md5-digest-for-port: Don't fail if the total number of bytes read from a port exactly matches the buffer size 2005-09-14 11:07:15 +00:00
mainzelm 89db21acf6 Don't mark stopped processes as dead 2005-09-14 11:03:24 +00:00
mainzelm 03d11e2576 + IGNORE-SIGNAL to ignore synchronous signals
+ HANDLE-DEFAULT-SIGNAL to re-install default signal handler for
  synchronous signals
2005-09-13 13:14:16 +00:00
mainzelm 354188c3c5 Export predicates for user-info? and group-info?. 2005-05-30 12:59:05 +00:00
sperber 0628b66c3e The format_date function tries to fill the (non-POSIX) tm_zone field
of struct tm, assuming the corresponding argument is a string.  By the
scsh documentation, #f is allowed, too.  So just use NULL in that case
instead of raising an argument-type exception, as was the case
previously.
2005-04-15 14:58:57 +00:00
mainzelm 6aa549d288 Fixed missing GC_PROTECTs within send_substring 2005-02-22 10:42:04 +00:00
chetz fc88c1907a most changes are cosmetical
there are few new tests
2004-10-03 11:35:21 +00:00
chetz da3caf4f5b first commit 2004-09-22 07:43:39 +00:00
mainzelm 9da5680d55 Fix argument checking of COPY-BYTES!: Previously, FROM was checked
twice, and TO never.
2004-09-17 14:04:51 +00:00
chetz 027ce1b9d7 new tests 2004-09-05 16:59:43 +00:00
chetz 99f77e2c06 first commit 2004-09-05 16:59:13 +00:00
sperber e7585fb617 Fix description of ANY to say that ASCII NUL is excluded. 2004-09-02 15:39:30 +00:00
chetz 90cf44f3b9 the state-var-test was wrong 2004-08-28 18:16:52 +00:00
sperber ce9da610e6 Handle the regexp matching the empty string specially, as POSIX
requires it to be "()", not "()".

This closes bug

[ 1005026 ] sre: (** 0 0 "foo") raises error
2004-08-22 14:22:29 +00:00
chetz 43e5f6fb8c more tests 2004-08-19 14:11:23 +00:00
chetz 1e6d6d0841 more tests 2004-08-18 13:55:35 +00:00
chetz 8218b146f8 changed a few tests 2004-08-12 20:17:35 +00:00
chetz 2bc4c06457 more test cases 2004-08-12 15:13:18 +00:00
chetz 3c4a6c7c46 some more test cases 2004-08-10 11:50:22 +00:00
chetz 11299af1a4 just some "cosmetic" changes 2004-08-10 11:48:40 +00:00
chetz 5107390fe2 added intefaces for new test-files 2004-08-10 11:47:15 +00:00
chetz c7d103da99 works with string-ports instead
of temp-files now
2004-08-09 15:24:43 +00:00
chetz 290104da0a first commit 2004-08-09 08:49:16 +00:00
chetz 9174add359 Log Message:
first commit
2004-08-09 08:46:09 +00:00
chetz e42ed5864e *** empty log message *** 2004-08-09 08:38:48 +00:00
chetz 5c0ff0293b *** empty log message *** 2004-07-07 13:37:56 +00:00
bdc f2e92c652a Add interix support 2004-04-16 18:29:51 +00:00
bdc fa7910c741 Add interix support 2004-04-16 17:36:24 +00:00
eknauel 89aeaf3d14 patch to enable building scsh outside its source directory (added some
missing $(srcdir))
2004-04-16 13:33:24 +00:00
bdc 8ddb1f619c Add interix support 2004-04-16 04:56:13 +00:00
mainzelm 142b393ab8 Export default-lib-dirs as promised in the manual. 2004-04-15 13:01:35 +00:00
mainzelm 66b2cd8a13 Adapt version number to 0.6.7 2004-04-15 12:52:06 +00:00
mainzelm e534395099 Bump version number to 0.6.7 CVS 2004-04-15 12:31:43 +00:00
mainzelm 287a829cbd 0.6 release 2004-03-31 20:08:17 +00:00
sperber 55ffeb22d8 Delete bogus version of LIST-DELETE-NEIGHBOR-DUPS from Olin's sort
libraries.  (It was redundant, not used, and buggy.)
Also remove import of FORMATS from the package---the only references
were in the removed code.
2004-03-26 17:18:11 +00:00
mainzelm 52ac78e0aa Fix WITH-LOCK: The previous version called RELEASE-LOCK in the before
thunk. Noted by Taylor Campbell.
2004-03-24 08:14:55 +00:00
mainzelm 05e38a42da Save and restore the current package for -le and -lel. 2004-03-15 15:39:21 +00:00
mainzelm 8b334402ae Removed support for Ultrix. It is lacking support for POSIX regexps. 2004-03-15 15:35:18 +00:00
mainzelm a41eb3da04 In the top-level condition handler, exit only on errors and call
the surrounding handler for all other conditions.
2004-03-14 17:21:33 +00:00
mainzelm 069f638d8f Update date. 2004-03-12 15:28:25 +00:00
mainzelm 491c83cae7 Changed forgotten copyrights. 2004-03-12 15:10:16 +00:00
mainzelm 0358d6bb0e Updates for 0.6.6 2004-03-11 10:24:03 +00:00
mainzelm 7b13b9bebb + Exit with status 1 in case of an error
+ Display the condition in the top-level scsh handler
2004-03-11 10:17:41 +00:00
mainzelm 622ef7a99f Install handler in CALL-TERMINALLY so scsh with exit with status 1 in case of an error. 2004-03-11 09:54:33 +00:00
mainzelm bcbd16ff0a + Exit with status 0 if an error occurs during exiting.
+ Minor cleanup
2004-03-09 09:20:00 +00:00
mainzelm 69248ecad2 Better error message if $SCSH_LIB_DIRS contains garbage. 2004-03-03 10:33:35 +00:00
mainzelm 84f85be750 Merge from S48 repository
Original commit message from Mike Sperber:


Subject: Add implementation of FOR-EACH to SRFI-1

This was missing from Olin's reference implementation.

Note that currently, the native versions of MAP and FOR-EACH already
implement the extended semantics specified by SRFI 1.  However, we
might want to enforce the R5RS restrictions to MAP and FOR-EACH at
some time in the future, so it still makes sense to have separate
implementations in SRFI 1.
2004-02-26 16:20:53 +00:00
mainzelm 523b402079 Don't warn about undefined imported bindings on startup. These
warnings have no meaning if we need to load a shared object.
2004-02-26 07:42:58 +00:00
mainzelm 90ba284584 Revert last check-in. Reading again through the manual, I now think that it's maybe better to complain if -e was specified without -sfd or -s. 2004-02-20 15:27:29 +00:00
mainzelm 388d2f7b2b Better checking for the inter-switch dependencies.
In particular, the code now complains if -e was used with an
end-option, switches to non-interactive-mode for -e and ensures that
-ds,-dm, and -de always get -s <script> as end-option.

In addition, better diagnostics is provided.
2004-02-20 15:03:45 +00:00
mainzelm bd890a7338 Add missing $(srcdir) to target c/scheme48.h 2004-02-17 16:11:13 +00:00
mainzelm 47f074ba5c * Let scsh.image depend on scsh/lib-dirs.scm
* ,load-package scheme-with-scsh before dumping the images to get
better start-up times when scheme-with-scsh is opened in a package
definition.
2004-02-17 08:45:31 +00:00
mainzelm f344e2be87 Fixed bug in STRING-CONCATENATE-REVERSE/SHARED reported by Francisco
Solsona at srfi-13@srfi.schemers.org on 12 Feb 2004.
2004-02-17 07:47:41 +00:00
mainzelm e603ebb626 + Preseve quotation of [],? and * while processing braces.
+ Unquote constant patterns before file existence check.
2004-02-09 12:16:02 +00:00
mainzelm 6ad71da933 Added some more people. 2004-02-09 08:57:41 +00:00
mainzelm fbbf31a1d8 Removed __ELF__ based test for rdynamic. 2004-02-09 08:48:00 +00:00
mainzelm 6f771517e1 Removed old, non-free sort code. 2004-02-09 08:45:16 +00:00
mainzelm 5e52592084 Bail out if inliner gets invoked on code that was already processed by
FLAT-ENVIRONMENTS optimizer.
2004-02-09 08:22:54 +00:00
mainzelm 47b9d6028e Use NAME->SYMBOL to generate formal arguments of lambda nodes that get inlined.
Test case is:

,config (define-structure foo (export)
  (open scheme
        finite-types)
  (optimize auto-integrate)
  (begin
   (define-enumerated-type afs-permission :afs-permission
     afs-permission?
     the-afs-permissions
     afs-permission-name
     afs-permission-index
     (read))))

> ,config (define-structure foo (export)
  (open scheme
        finite-types)
  (optimize auto-integrate)
  (begin
   (define-enumerated-type afs-permission :afs-permission
     afs-permission?
     the-afs-permissions
     afs-permission-name
     afs-permission-index
     (read))))
> ,in foo the-afs-permissions
Load structure foo (y/n)? y
[foo
Analyzing...
Calls will be compiled in line: (#{Generated maker 1408} afs-permission-index afs-permission-name)
]
'#(#{Afs-permission #{Generated name 1408}})
> ,inspect

 [0] '#{Afs-permission #{Generated name 1408}}
inspect: 0
'#{Afs-permission #{Generated name 1408}}

 [0: name] '#{Generated name 1408}
 [1: index] '#{Generated index 1408}
2004-02-09 08:21:05 +00:00
mainzelm f5833ad272 Use FORCE-NODE instead of FORCE in case a previous optmizer already
forced the nodes.
2004-02-09 08:15:48 +00:00
mainzelm bdf5f8e09f Fixed bug in MAKE-STRING-PORT-FILTER: An argument to read-string! was missing 2004-02-04 08:37:43 +00:00
mainzelm 1e098d1ced Snapshot of auto-generated file 2004-02-03 12:53:03 +00:00
mainzelm 57fbec4ef2 Renamed lib-dir-list to lib-dirs-list. 2004-02-03 12:49:40 +00:00
mainzelm 0562f3301d Use single quotes when builing scsh/configure.scm 2004-02-03 10:07:36 +00:00
mainzelm 2b2fee0632 Distclean before making dist. 2004-02-03 09:38:38 +00:00
mainzelm 0a899ac0fd Use strcmp to check for empty arguments. 2004-02-02 17:18:39 +00:00
mainzelm 8fd66025f0 Use /etc instead of /bin in tests that change dirctories. 2004-02-02 15:17:36 +00:00
mainzelm bc7e37593c Bump version number to 0.6.6 2004-02-02 10:57:29 +00:00
mainzelm 3ff781f491 Use \ex instead of \var 2004-02-02 10:56:29 +00:00
mainzelm 780da3558f First version of 0.6.6 release notes. 2004-01-29 13:52:25 +00:00
mainzelm a3d560c2ba Fix installation of scsh.image: Set the default library path in new module lib-dirs. 2004-01-29 13:44:20 +00:00
mainzelm 252e390354 Replaced the original MIT license with a new BSD-style license.
Chris Hanson from MIT Scheme granted the new license in a private
email on 12 Dec 2003.

In addition, I added a private email from Olin, saying that the MIT
code has nothing in common with MIT Scheme anymore.
2004-01-27 14:36:28 +00:00
mainzelm d1b1c3dee3 Replaced the original MIT license with a new BSD-style license.
Chris Hanson from MIT Scheme granted the new license in a private
email on 12 Dec 2003.
2004-01-27 14:33:39 +00:00
mainzelm 6582c616a3 Changed the copyright notices concerning David Albertz on behalf of
Dr. Olin Shivers. Quoting Olin: "Forget it. David was a student who
worked for me -- paid money to hack."
2004-01-27 13:50:48 +00:00
mainzelm 11880601dd + Pass prog_name from main to process_args
+ During argument processing, skip empty arguments inserted by the
meta-argument expander
2004-01-27 13:39:34 +00:00
mainzelm ba76b7a3cc Fixed check for rdynamic, provided by Stephen Ma 2004-01-27 10:38:36 +00:00
mainzelm e8a662ea1b Re-add interface of SRFI-42, which was accidentally removed on the last commit. 2004-01-27 09:51:36 +00:00
mainzelm 9a22e55080 Remove scsh/configure.scm in clean-scsh 2004-01-27 09:40:35 +00:00
sperber 3f108f501f Hook Olin's sorting code into the regular build, replacing the old T
implementation.
2004-01-26 21:30:55 +00:00
sperber d772a5df84 - fix paren typo in sort interfaces
- rename SORT to SORTING so we can hook it into the regular build
2004-01-26 21:25:22 +00:00
sperber cb9f440657 Import sort code from s48-tuebingen/trunk, rev 573. 2004-01-22 19:52:15 +00:00
sperber 33fe47abca Fix the various SELECT-like procedures for 0 timeouts. 2004-01-16 21:42:17 +00:00
mainzelm 90ea0cf502 Fixed implementation of STRING-CONTAINS by using the commented out
"slow & simple" version instead of calling the KMP searcher.

See http://srfi.schemers.org/srfi-13/post-mail-archive/msg00003.html

I fixed the mentioned "off-by-one error" by using <= instead of < at
the termination check.
2004-01-13 15:37:35 +00:00
mainzelm b7388740b9 Reworked description of the library directories. 2004-01-13 14:36:38 +00:00
mainzelm 03ab628c93 Moved the library directories facility to its own module. 2004-01-13 13:21:20 +00:00
mainzelm eb9410cc44 Fix bug in S48_RECORD_TYPE: third parameter to s48_stob_ref was missing. 2004-01-13 12:08:28 +00:00
mainzelm af976ddde2 Removed accidentally committed expansion of paths in SCSH_LIB_DIR. 2004-01-13 11:56:00 +00:00
mainzelm da53963d82 Fixed a bug in the parser of "-" sre forms. 2004-01-09 22:51:07 +00:00
mainzelm 5330ba06e0 Typo fix. 2004-01-09 14:56:05 +00:00
mainzelm 065d686d21 Minor enhancement for the configure module: Return machine, vendor and os. 2004-01-09 14:55:33 +00:00
mainzelm 655a2e5cc2 Description of the configure module. 2004-01-09 14:53:13 +00:00
mainzelm 1fa4ea33ac -> 0.6.6 CVS 2004-01-09 13:53:42 +00:00
mainzelm 8df6b631e1 Changed the copyright notice on behalf of Dr. Olin Shivers.
Quoting Olin: "What do you all want the copyright to be? What are the
issues that drive the copyright needs? You Germans have been out there
using this code in the Real World, so I'm happy to just make things be
whatever your experience has shown to be needed."
2004-01-09 13:09:26 +00:00
mainzelm 9742102f34 Changed the copyright notices concerning David Albertz on behalf of
Dr. Olin Shivers. Quoting Olin: "Forget it. David was a student who
worked for me -- paid money to hack."
2004-01-09 13:01:39 +00:00
mainzelm c46ec9118a Add a notice to the description of the signal event system: interrupt
handlers have to be disabled before using the event system.
2004-01-09 12:43:08 +00:00
mainzelm dfa05a0c5c Added structure CONFIGURE to access values from ./configure. 2003-12-19 14:08:58 +00:00
mainzelm bcf88c05d0 Better test for -rdynamic by Stephen Ma. 2003-12-19 13:44:25 +00:00
mainzelm 6b5e75bd3f Let PATH-LIST->FILE-NAME return "/" for '("").
'("") is the value returned by (split-file-name "/") and
PATH-LIST->FILE-NAME is supposed to be the inverse of SPLIT-FILE-NAME.
2003-12-19 08:27:34 +00:00
mainzelm 2aac5914d6 Fix:
FIELD-READER did return (values EOF #()) instead of (values EOF '()) on an empty port.
2003-12-17 10:08:17 +00:00
mainzelm 9378e2ff27 Correctly quote lib_dirs_list. 2003-12-09 06:16:15 +00:00
mainzelm b85d581f25 Bump the year to 2003 2003-11-24 14:11:37 +00:00
mainzelm 8dfdf2c868 Added -lel switch. There is currently no way to deal with relative
file names in the exec scripts so this might just get removed again.
2003-11-13 14:44:40 +00:00
mainzelm ba5cdcf6fb Removed infix directory. It has a non-free copyright and will
therefore be removed from S48 as well.
2003-11-12 11:11:55 +00:00
mainzelm 442559a708 Thank Peter Wang. 2003-11-12 11:08:25 +00:00
mainzelm 2336171f47 Delete scsh-config in distclean target. 2003-11-12 11:08:06 +00:00
mainzelm 9b29fff8e1 Ensure and document that SEEK works on unbuffered ports only. 2003-11-12 11:07:29 +00:00
mainzelm 903fdad089 Fix month of 0.6.5 release. 2003-11-12 11:06:29 +00:00
mainzelm 43f16f70e9 Library path defaults to $prefix/lib/scsh/modules/ 2003-11-04 14:05:11 +00:00
mainzelm 327d7a6dfc Fix intro and add bug fix 2003-10-28 12:11:11 +00:00
mainzelm 312d54708a Fix the mismatches between doc and implemenation noted in bug report
#750586 in favor of the implemenation.
2003-10-28 12:10:03 +00:00
mainzelm 37e4f027eb Document changes in 0.6.5 2003-10-24 09:01:21 +00:00
mainzelm a2b0bea3ad Increase version number 2003-10-24 08:37:44 +00:00
mainzelm b1cc92b55f Added SRFI-42 2003-10-24 08:34:38 +00:00
mainzelm ed3cc365b0 Fix for
> (regexp-search? (posix-string->regexp "$") "test")
 Error: exception
	 wrong-type-argument
	 (checked-record-ref '#{Unspecific} '#{Record-type 46 cre} 1)

by Peter Wang
2003-10-23 15:58:08 +00:00
mainzelm acb0c8265f Fix for (rx (|)) by Peter Wang 2003-10-23 15:55:55 +00:00
mainzelm e60e77997f First step towards 0.6.5. 2003-10-23 15:20:49 +00:00
mainzelm 9d206dae0c Set DEFAULT-LIB-DIRS to a useful default 2003-10-15 08:00:58 +00:00
mainzelm 3198c650f8 Avoid calling SOCKET-OPTION twice in case of an error: the first call
will already clear the error status.
2003-10-15 07:59:51 +00:00
mainzelm 1f1081b8bf Fix memory leak in format_date. 2003-10-13 09:52:30 +00:00
mainzelm 1521521116 Fixed memory leak in scheme_cwd: a temporary buffer was not freed
after entering the value in the scheme heap.
2003-10-13 09:50:30 +00:00
mainzelm be8a63dbe8 Fix typo (beginz -> begin) 2003-10-13 09:46:33 +00:00
mainzelm 37b31fc65a Better error message for socket-connect 2003-10-09 16:51:10 +00:00
mainzelm ca97d21195 Make the default library directories configurable by
--with-lib-dirs-list and let it default to $prefix/lib/scsh/modules.
2003-10-09 13:43:54 +00:00
sperber f376ab6d8e Merge revs 1.32 of RELEASE and 1.7 of doc/scsh-manual/procnotation.tex
from trunk.

Original log message:

Get the names of MAKE-STRING-PORT-FILTER and MAKE-CHAR-PORT-FILTER
right in the documentation.
2003-08-19 07:53:22 +00:00
mainzelm b7bb1fa2e5 Subject: Extend type<->sexp conversion to variable type
type->sexp was not capable of converting the variable type to a
sexp. This caused problems if the module system wanted to tell the
user that the types of exported bindings did not match:

config> (define-structure foo (export (bar :syntax)) (open scheme) (begin (define bar 1)))
; no values returned
config> ,user
> ,open foo

Error: exception
       wrong-type-argument
       (checked-record-ref '(variable #{Type :value #f #f}) '#{Record-type 14 meta-type} 1)

I've now extended TYPE->SEXP by a check for the variable type and let
it produce a list with 'VARIABLE as first and the actual type as
second element. Likewise, I extended SEXP->TYPE to produce a variable
type if 'VARIABEL is the first element of a list.

This seems to work but a second look by someone who really understands
the type system would be appreciated.

(Merge from s48 rev 423)
2003-08-04 07:31:33 +00:00
mainzelm 9d93d5a61e After fork/pipe, make the ports returned by the pipe the
current-in/output-ports. This corresponds to the intended semantics of
side-effecting the standard ports and tells the GC that the ports are
alive.
2003-07-21 12:02:55 +00:00
mainzelm b036a6da1c GC_PROTECT arguments and errnos in s48_raise_os_error_X. 2003-06-25 13:25:44 +00:00
mainzelm c350288e41 OS specific definitions for GNU Hurd by Andreas Voegele. 2003-06-25 08:34:31 +00:00
mainzelm a54b97b81f Replace static constant MAXHOSTNAMELEN by dynamic alloaction.
(Patch from Andreas Voegele)
2003-06-25 08:28:40 +00:00
mainzelm 3c92196d13 Use s48_enter_integer instead of s48_enter_fixnum for errno to please GNU Hurd.
(Patch from Andreas Voegele)
2003-06-25 08:26:06 +00:00
mainzelm 1f31b70242 Specify "%s" as format string for syslog to prevent the message from
being interpreted as a format string (Patch by Peter Wang).

This fixes #745444.
2003-06-16 16:52:48 +00:00
mainzelm ce90c83263 Fixed typo. (Merge from HEAD). 2003-05-23 07:29:18 +00:00
mainzelm 29258b6adc Removed message argument form errno-error. 2003-05-12 12:52:13 +00:00
mainzelm 7bc10a0d0e Removed accidentally committed code. 2003-05-06 14:42:07 +00:00
mainzelm cbfa04d530 Removed forgotten references to NTH. 2003-05-05 11:25:08 +00:00
mainzelm 7b9606a7bc + Support for $(DESTDIR) by Andreas Voegele.
- Accidentally committed -g options.
2003-05-05 07:19:03 +00:00
mainzelm 8805f7b7cc check-nargs= --> protocol 2003-05-05 06:37:45 +00:00
mainzelm 3e397f65c5 GC_PROTECT some variables. 2003-05-01 10:21:33 +00:00
marting 37210efdc5 Imported scheme48-0.53 sources as base 1999-09-14 12:45:00 +00:00
548 changed files with 101803 additions and 29384 deletions

8
.gitignore vendored
View File

@ -26,3 +26,11 @@ _$*
*.ln
core
# CVS default ignores end
Makefile
configure
config.log
config.cache
config.status
scsh.image
scshvm
go

View File

@ -1,4 +1,8 @@
Copyright (c) 1993-1999 Richard Kelsey and Jonathan Rees
Copyright (c) 1993-2003 Richard Kelsey and Jonathan Rees
Copyright (c) 1994-2003 by Olin Shivers and Brian D. Carlstrom.
Copyright (c) 1999-2003 by Martin Gasbichler.
Copyright (c) 2001-2003 by Michael Sperber.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -23,7 +27,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Distributing Autoconf Output
****************************

85
CVS_README Normal file
View File

@ -0,0 +1,85 @@
Welcome to the Scsh CVS Repository !!!
This file contains some instructions about how to build Scsh after you
freshly checked out the "scsh-0.6" module. These instructions do *not*
apply to the module named "scsh" or the Scsh distribution itself.
There is currently no scheme to tag working snapshots of the
repository, so anything may happen during the build process. The scsh
team does in general *not* provide support for code obtained from the
CVS repository.
During the build process a number of auto-generated files not included
in the CVS repository are built. It is highly recommended to follow
these instructions carefully as otherwise incompatible versions of
generated files may result. Note that you need GNU make for this
process.
To build Scsh, proceed as follows:
1.) You must have a working version of Scheme 48, version 0.53. Nothing
older, nothing newer. Just 0.53. If you don't have, get it from
http://www.s48.org/0.53/scheme48-0.53.tgz and install Scheme
48. Change the value of the variable BUILD_RUNNABLE in Makefile.in
so that it will point to the Scheme 48 executable.
2.) "cd" into the directory which contains the source code (normally
scsh-0.6) and run the script autogen.sh:
./autogen.sh
This will take several minutes and generate the source code for
the virtual machine and two images the Makefile relies
on. Furthermore the configure file will be generated. This script
calls autoheader and autoconf from the GNU Autoconf package. You
will need a recent version of Autoconf. Version 2.52 is okay,
version 2.13 is too old.
3.) Configure the system:
./configure
You presumably want to add the --prefix flag here to determine the
installation directory. This will generate the Makefile.
4.) Build the system:
make
If anything fails here, fix the problem and/or contact the authors.
5.) You should have a runnable version of the system that can be
started in the main directory like this:
./go
6.) To install Scsh, type:
make install
Note that it is not recommended to have a CVS version of Scsh for
daily use.
7.) If you intend to build on a different platform later, do a
make distclean
and restart at step 3.
You should repeat the whole build process whenever there are changes
to files in the directories scheme/vm, scheme/rts or
scheme/bcomp. Watch the run of cvs update carefully and/or subscribe
to the list scsh-checkins@lists.sourceforge.net.
Enjoy!!!
The Scsh developers

137
INSTALL
View File

@ -1,120 +1,49 @@
This is a generic INSTALL file for utilities distributions.
If this package does not come with, e.g., installable documentation or
data files, please ignore the references to them below.
Installing scsh
[For information specific to Scheme 48, see doc/install.txt.]
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation, and
creates the Makefile(s) (one in each subdirectory of the source
directory). In some packages it creates a C header file containing
system-dependent definitions. It also creates a file `config.status'
that you can run in the future to recreate the current configuration.
To compile this package:
This file describes how to install scsh from the source package. If
you have obtained the source tree from CVS refer to the file
CVS_README.
1. Configure the package for your system.
Normally, you just `cd' to the directory containing the package's
source code and type `./configure'. If you're using `csh' on an old
version of System V, you might need to type `sh configure' instead to
prevent `csh' from trying to execute `configure' itself.
Just `cd' to the directory containing this README file and type
Running `configure' takes a minute or two. While it is running, it
prints some messages that tell what it is doing. If you don't want to
see the messages, run `configure' with its standard output redirected
to `/dev/null'; for example, `./configure >/dev/null'.
./configure
You can pass some additional options to the configure script, along
them the installation directory with the
--prefix=/my/install/location option. Type ./configure --help to
get a list of all switches.
Running `configure' takes a minute or two. While it is running, it
prints some messages that tell what it is doing. Consult the file
config.log if anything went wrong.
To compile the package in a different directory from the one
containing the source code, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. If
for some reason `configure' is not in the source code directory that
you are configuring, then it will report that it can't find the source
code. In that case, run `configure' with the option `--srcdir=DIR',
where DIR is the directory that contains the source code.
2. Type
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'. Alternately, you can do so by consistently
giving a value for the `prefix' variable when you run `make', e.g.,
make prefix=/usr/gnu
make prefix=/usr/gnu install
make
to compile scsh.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH' or set the `make'
variable `exec_prefix' to PATH, the package will use PATH as the prefix
for installing programs and libraries. Data files and documentation
will still use the regular prefix. Normally, all files are installed
using the same prefix.
3. After a successful build you can invoke scsh by typing
Some packages pay attention to `--with-PACKAGE' options to
`configure', where PACKAGE is something like `gnu-as' or `x' (for the X
Window System). The README should mention any `--with-' options that
the package recognizes.
./go
`configure' ignores any other arguments that you give it.
You should see the command prompt of scsh which you can exit by
typing `,exit'.
On systems that require unusual options for compilation or linking
that the package's `configure' script does not know about, you can give
`configure' initial values for variables by setting them in the
environment. In Bourne-compatible shells, you can do that on the
command line like this:
4. Type
CC='gcc -traditional' LIBS=-lposix ./configure
make install
Here are the `make' variables that you might want to override with
environment variables when running `configure'.
For these variables, any value given in the environment overrides the
value that `configure' would choose:
- Variable: CC
C compiler program. The default is `cc'.
- Variable: INSTALL
Program to use to install files. The default is `install' if you
have it, `cp' otherwise.
For these variables, any value given in the environment is added to
the value that `configure' chooses:
- Variable: DEFS
Configuration options, in the form `-Dfoo -Dbar...'. Do not use
this variable in packages that create a configuration header file.
- Variable: LIBS
Libraries to link with, in the form `-lfoo -lbar...'.
If you need to do unusual things to compile the package, we encourage
you to figure out how `configure' could check whether to do them, and
mail diffs or instructions to the address given in the README so we
can include them in the next release.
2. Type `make' to compile the package. If you want, you can override
the `make' variables CFLAGS and LDFLAGS like this:
make CFLAGS=-O2 LDFLAGS=-s
3. If the package comes with self-tests and you want to run them,
type `make check'. If you're not sure whether there are any, try it;
if `make' responds with something like
make: *** No way to make target `check'. Stop.
then the package does not come with self-tests.
4. Type `make install' to install programs, data files, and
documentation.
to install programs, data files, and documentation.
5. You can remove the program binaries and object files from the
source directory by typing `make clean'. To also remove the
Makefile(s), the header file containing system-dependent definitions
(if the package uses one), and `config.status' (all the files that
`configure' created), type `make distclean'.
source directory by typing `make clean'. To also remove the
Makefile, the header file containing system-dependent definitions
, `config.status' and `config.cache' (all the files that
`configure' created), type `make distclean'.
The file `configure.in' is used to create `configure' by a program
called `autoconf'. You only need it if you want to regenerate
`configure' using a newer version of `autoconf'.
For more information about scsh have a look into the README file and
the documentation in the `doc/' directory. There you can also read
documentation about Scheme 48, the Scheme implementation scsh is based
on.

View File

@ -1,4 +1,4 @@
# Scheme 48 Makefile
# Scsh Makefile
# Documentation in files INSTALL and doc/install.txt
SHELL = /bin/sh
@ -17,15 +17,23 @@ INSTALL_DATA = @INSTALL_DATA@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
RM = rm -f
AR = @AR@
RANLIB = @RANLIB@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
incdir = @includedir@
manext = 1
mandir = @mandir@/man$(manext)
lib_dirs_list = @lib_dirs_list@
host = @host@
### End of `configure' section###
bindir = $(exec_prefix)/bin
libdir = $(exec_prefix)/lib
incdir = $(exec_prefix)/include
manext = 1
mandir = $(prefix)/man/man$(manext)
htmldir = $(libdir)/scsh/doc/scsh-manual/html
# HP 9000 series, if you don't have gcc
# CC = cc
@ -36,10 +44,13 @@ mandir = $(prefix)/man/man$(manext)
# LDFLAGS = -N
.c.o:
$(CC) -c $(CPPFLAGS) $(DEFS) -I$(srcdir)/c $(CFLAGS) -o $@ $<
$(CC) -c $(DEFS) -I ./c -I$(srcdir)/c -I$(srcdir)/cig $(CPPFLAGS) $(CFLAGS) -o $@ $<
# You might want to change RUNNABLE to "s48"
RUNNABLE = scheme48
# BUILD_RUNNABLE has to be Scheme 48 0.53. This is used for builds directly
# out of the CVS repository.
# We cannot use Scsh here since -i is not understood.
BUILD_RUNNABLE = /afs/wsi/i386_fbsd32/bin/scheme48
RUNNABLE = scsh
MANPAGE = $(RUNNABLE).$(manext)
LIB = $(libdir)/$(RUNNABLE)
@ -68,13 +79,19 @@ include $(srcdir)/build/filenames.make
# LINKER_RUNNABLE = $(RUNNABLE)
# These settings requires you to already have a $(RUNNABLE)
# command. This is desirable if you are making changes to the
# system that might break scheme48vm and/or scheme48.image. But it
# system that might break scshvm and/or scsh/scsh.image. But it
# requires you to have squirreled away a previous working version
# of scheme48.
# of scsh.
BIG_HEAP = -h 5500000
# 1. is broken if you build from CVS
# LINKER_VM = ./$(VM) $(BIG_HEAP)
# LINKER_RUNNABLE = $(LINKER_VM) -i $(IMAGE)
# therefore according to 2. but we cannot use scsh since -i is not understood
LINKER_VM = $(BUILD_RUNNABLE) $(BIG_HEAP)
LINKER_RUNNABLE = $(BUILD_RUNNABLE)
BIG_HEAP = -h 5000000
LINKER_VM = ./$(VM) $(BIG_HEAP)
LINKER_RUNNABLE = $(LINKER_VM) -i $(IMAGE)
LINKER_IMAGE = build/linker.image
LINKER = $(LINKER_VM) -i $(LINKER_IMAGE)
START_LINKER = echo ',batch' && echo ',bench on'
@ -85,11 +102,57 @@ START_LINKER = echo ',batch' && echo ',bench on'
# Targets:
IMAGE = scheme48.image
IMAGE = scsh.image
INITIAL = build/initial.image
VM = scheme48vm
VM = scshvm
LIBCIG = cig/lib$(VM).a
CIG = cig/cig
CIGOBJS = cig/libcig.o cig/libcig1.o
#scsh-lib
LIBSCSHVM = scsh/lib$(VM).a
LIBSCSH = scsh/libscsh.a
SCSHVMHACKS = scsh/proc2.o
#
#
SCSHOBJS = \
scsh/cstuff.o \
scsh/dirstuff1.o \
scsh/fdports1.o \
scsh/flock1.o \
scsh/machine/time_dep1.o \
scsh/signals1.o \
scsh/machine/libansi.o \
scsh/network1.o \
scsh/putenv.o \
scsh/rx/regexp1.o \
scsh/sleep1.o \
scsh/syscalls1.o \
scsh/syslog1.o \
scsh/time1.o \
scsh/tty1.o \
scsh/userinfo1.o \
scsh/sighandlers1.o \
scsh/libscsh.o \
scsh/md5.o
SCSH_INITIALIZERS = s48_init_syslog s48_init_posix_regexp \
s48_init_userinfo s48_init_sighandlers \
s48_init_syscalls s48_init_network s48_init_flock \
s48_init_dirstuff s48_init_time s48_init_tty \
s48_init_cig s48_init_libscsh s48_init_md5
UNIX_OBJS = c/unix/misc.o c/unix/io.o c/unix/fd-io.o c/unix/event.o
OBJS = c/scheme48vm.o c/scheme48heap.o c/extension.o c/external.o
SRFI_OBJS = c/srfi/srfi-27.o
SRFI_INITIALIZERS = s48_init_srfi_27
S48OBJS = c/scheme48vm.o c/scheme48heap.o c/extension.o c/external.o
OBJS = scsh/process_args.o c/init.o $(S48OBJS) $(CIGOBJS) $(SCSHOBJS) \
$(SCSHVMHACKS) $(SRFI_OBJS)
FAKEHS = c/fake/dlfcn.h c/fake/sigact.h c/fake/strerror.h \
c/fake/sys-select.h
@ -102,7 +165,7 @@ CONFIG_FILES = scheme/interfaces.scm scheme/low-packages.scm \
# The following is the first rule and therefore the "make" command's
# default target.
enough: $(VM) $(IMAGE) go .notify
enough: $(VM) $(IMAGE) go $(LIBCIG) scsh $(LIBSCSH) $(LIBSCSHVM)
# --------------------
# External code to include in the VM
@ -110,7 +173,11 @@ enough: $(VM) $(IMAGE) go .notify
EXTERNAL_OBJECTS = $(SOCKET_OBJECTS) $(LOOKUP_OBJECTS)
EXTERNAL_FLAGS = $(SOCKET_FLAGS)
EXTERNAL_INITIALIZERS = $(SOCKET_INITIALIZERS) $(LOOKUP_INITIALIZERS)
EXTERNAL_INITIALIZERS = $(ADDITIONAL_INITIALIZER) $(SOCKET_INITIALIZERS) \
$(LOOKUP_INITIALIZERS) \
$(SCSH_INITIALIZERS) $(SRFI_INITIALIZERS) \
s48_init_cig
# Rules for any external code.
@ -132,30 +199,95 @@ LOOKUP_OBJECTS = c/unix/dynamo.o
LOOKUP_INITIALIZERS = s48_init_external_lookup
# End of lookup rules
# Initializer for s48_add_external_init
ADDITIONAL_INITIALIZER = s48_init_additional_inits
# End of external rules
# --------------------
# The developers are curious to know. Don't be concerned if this fails.
.notify: build/minor-version-number
touch .notify
-echo Another 0.`cat $(srcdir)/build/minor-version-number` \
installation. \
| mail scheme-48-notifications@martigny.ai.mit.edu
-echo SCSH 0.`cat $(srcdir)/scsh/minor-version-number` \
Scheme48 0.`cat $(srcdir)/minor-version-number` infestation. \
| mail scheme-48-notifications@zurich.ai.mit.edu
-echo Another scsh 0.`cat $(srcdir)/scsh/minor-version-number` \
infestation. | mail scsh-notifications@zurich.ai.mit.edu
# This says how to process .scm files with cig to make .c stubs.
#.SUFFIXES: .scm
#.scm.c:
# $(srcdir)/$(VM) -o $(srcdir)/$(VM) -i $(CIG) < $< > $*.c
# These .h files mediate between the code exported from foo1.c
# and imported into foo.scm's stub foo.c.
scsh/dirstuff1.o: scsh/dirstuff1.h
scsh/userinfo1.o: scsh/userinfo1.h
scsh/network1o: scsh/network1.h
scsh/flock1.o: scsh/flock1.h
scsh/fdports1.o scsh/fdports.o: scsh/fdports1.h
scsh/rx/regexp1.o: c/scheme48.h
scsh/sighandlers1.o: scsh/sighandlers1.h
scsh/syslog1.o: c/scheme48.h
include $(srcdir)/scsh/machine/Makefile.inc
# Berkeley make wants to see this instead: (or use GNU make on BSD. -bri)
#.include "$(srcdir)/scsh/machine/Makefile.inc"
$(VM): c/main.o $(OBJS) $(UNIX_OBJS) $(LIBOBJS) $(EXTERNAL_OBJECTS)
rm -f /tmp/s48_external_$$$$.c && \
build/build-external-modules /tmp/s48_external_$$$$.c \
$(srcdir)/build/build-external-modules /tmp/s48_external_$$$$.c \
$(EXTERNAL_INITIALIZERS) && \
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ c/main.o $(OBJS) $(UNIX_OBJS) \
/tmp/s48_external_$$$$.c \
$(LIBOBJS) $(LIBS) \
$(EXTERNAL_OBJECTS) $(EXTERNAL_LD_FLAGS) && \
$(EXTERNAL_OBJECTS) $(EXTERNAL_LD_FLAGS) \
$(LIBOBJS) $(LIBS) && \
rm -f /tmp/s48_external_$$$$.c
c/main.o: c/main.c c/scheme48vm.h c/scheme48heap.h
#JMG: again cig and scsh-lib
$(LIBCIG): c/main.o $(OBJS)
# $(CC) -r -o $@ main.o $(OBJS)
$(RM) $@
$(AR) $@ c/main.o $(OBJS)
$(RANLIB) $@
$(LIBSCSHVM): c/smain.o $(OBJS)
$(RM) $@
$(AR) $@ c/smain.o $(OBJS)
$(RANLIB) $@
$(LIBSCSH): $(OBJS) $(UNIX_OBJS) $(LIBOBJS) $(EXTERNAL_OBJECTS)
$(RM) $@ \
rm -f /tmp/s48_external_$$$$.c && \
$(srcdir)/build/build-external-modules /tmp/s48_external_$$$$.c \
$(EXTERNAL_INITIALIZERS) && \
$(CC) -c $(CFLAGS) -o /tmp/s48_external_$$$$.o \
/tmp/s48_external_$$$$.c && \
$(AR) $@ $(OBJS) $(UNIX_OBJS) $(LIBOBJS) $(EXTERNAL_OBJECTS) \
/tmp/s48_external_$$$$.o && \
$(RANLIB) $@ && \
rm -f /tmp/s48_external_$$$$.c /tmp/s48_external_$$$$.o
c/main.o: c/main.c
$(CC) -c $(CFLAGS) -o $@ \
-DDEFAULT_IMAGE_NAME=\"$(LIB)/$(IMAGE)\" \
$(CPPFLAGS) $(DEFS) c/main.c
$(CPPFLAGS) $(DEFS) $(srcdir)/c/main.c
c/init.o: c/init.c c/scheme48vm.h c/scheme48heap.h
$(CC) -c $(CFLAGS) -o $@ \
-DDEFAULT_IMAGE_NAME=\"$(LIB)/$(IMAGE)\" \
$(CPPFLAGS) $(DEFS) $(srcdir)/c/init.c
c/scheme48vm.o: c/prescheme.h c/scheme48vm.h c/scheme48heap.h c/event.h \
c/io.h c/fd-io.h c/scheme48vm-prelude.h
@ -182,50 +314,87 @@ c/fake/strerror.o: c/fake/strerror.h
$(IMAGE): $(VM) scheme/env/init-defpackage.scm scheme/more-interfaces.scm \
scheme/link-packages.scm scheme/more-packages.scm \
$(usual-files) build/initial.debug build/build-usual-image
build/build-usual-image . "`pwd`/scheme" '$(IMAGE)' './$(VM)' \
'$(INITIAL)'
$(srcdir)/build/build-usual-image $(srcdir) "$(srcdir)/scheme" '$(IMAGE)' './$(VM)' \
'$(srcdir)/$(INITIAL)'
### Fake targets: all clean install man dist
install: enough dirs inst-script inst-vm inst-misc inst-man inst-inc inst-image
install: enough dirs inst-script inst-vm inst-misc inst-man inst-inc \
inst-doc install-scsh
inst-vm:
$(INSTALL_PROGRAM) $(VM) $(LIB)
inst-image:
rm -f '/tmp/$(IMAGE)' && \
build/build-usual-image . '$(LIB)' '/tmp/$(IMAGE)' './$(VM)' \
'$(INITIAL)' && \
$(INSTALL_DATA) /tmp/$(IMAGE) $(LIB) && \
rm /tmp/$(IMAGE)
inst-vm: $(VM)
$(INSTALL_PROGRAM) $(VM) $(DESTDIR)$(LIB)
inst-man:
if [ -d $(mandir) -a -w $(mandir) ]; then \
sed 's=LBIN=$(bindir)=g' doc/scheme48.man | \
if [ -d $(DESTDIR)$(mandir) -a -w $(DESTDIR)$(mandir) ]; then \
sed 's=LBIN=$(bindir)=g' doc/scsh.man | \
sed 's=LLIB=$(LIB)=g' | \
sed 's=LS48=$(RUNNABLE)=g' >$(MANPAGE) && \
$(INSTALL_DATA) $(MANPAGE) $(mandir) && \
rm $(MANPAGE); \
sed 's=LSCSH=$(RUNNABLE)=g' >$(MANPAGE) && \
$(INSTALL_DATA) $(MANPAGE) $(DESTDIR)$(mandir) && \
$(RM) $(MANPAGE); \
else \
echo "$(mandir) not writable dir, not installing man page" \
>&2; \
fi
inst-inc:
$(INSTALL_DATA) c/scheme48.h $(incdir)
$(INSTALL_DATA) $(srcdir)/c/scheme48.h $(DESTDIR)$(incdir)
$(INSTALL_DATA) $(srcdir)/c/write-barrier.h $(DESTDIR)$(incdir)
install-cig: cig
$(INSTALL_PROGRAM) $(srcdir)/$(CIG) $(DESTDIR)$(LIB)/cig
$(INSTALL_PROGRAM) $(srcdir)/$(CIG).image $(DESTDIR)$(LIB)/cig
$(INSTALL_DATA) $(srcdir)/$(LIBCIG) $(DESTDIR)$(LIB)/cig
$(INSTALL_DATA) $(srcdir)/cig/libcig.h $(DESTDIR)$(LIB)/cig
inst-misc:
for stub in env big opt misc link; do \
for f in scheme/$$stub/*.scm; do \
$(INSTALL_DATA) $$f $(LIB)/$$stub || exit 1; \
for stub in env big opt misc link srfi; do \
for f in $(srcdir)/scheme/$$stub/*.scm; do \
$(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/$$stub || exit 1; \
done; \
done && \
for f in scheme/rts/*num.scm scheme/rts/jar-defrecord.scm; do \
$(INSTALL_DATA) $$f $(LIB)/rts || exit 1; \
for f in $(srcdir)/scheme/rts/*num.scm $(srcdir)/scheme/rts/jar-defrecord.scm; do \
$(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/rts || exit 1; \
done
inst-doc:
for f in $(srcdir)/doc/*.txt $(srcdir)/doc/*.ps; do \
$(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/; \
done && \
for f in $(srcdir)/doc/src/*.tex \
$(srcdir)/doc/src/*.dvi \
$(srcdir)/doc/src/*.ps; \
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/s48-manual/; \
done && \
for f in $(srcdir)/doc/src/manual/*.html; \
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/s48-manual/html/; \
done && \
for f in $(srcdir)/doc/scsh-manual/*.tex \
$(srcdir)/doc/scsh-manual/*.sty \
$(srcdir)/doc/scsh-manual/*.dvi \
$(srcdir)/doc/scsh-manual/*.ps \
$(srcdir)/doc/scsh-manual/*.pdf; \
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/scsh-manual/; \
done && \
for f in $(srcdir)/doc/scsh-manual/html/*.html \
$(srcdir)/doc/scsh-manual/html/*.gif \
$(srcdir)/doc/scsh-manual/html/*.css; \
do $(INSTALL_DATA) $$f $(DESTDIR)$(htmldir)/; \
done && \
for f in $(srcdir)/doc/scsh-paper/*.tex \
$(srcdir)/doc/scsh-paper/*.sty \
$(srcdir)/doc/scsh-paper/*.dvi \
$(srcdir)/doc/scsh-paper/*.ps; \
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/scsh-paper/; \
done && \
for f in $(srcdir)/doc/scsh-paper/html/*.html \
$(srcdir)/doc/scsh-paper/html/*.css; \
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/doc/scsh-paper/html; \
done
inst-script:
script=$(bindir)/$(RUNNABLE) && \
script=$(DESTDIR)$(bindir)/$(RUNNABLE) && \
echo '#!/bin/sh' >$$script && \
echo >>$$script && \
echo 'lib=$(LIB)' >>$$script && \
@ -233,46 +402,52 @@ inst-script:
>>$$script && \
chmod +x $$script
# Script to run scheme48 in this directory.
# Script to run scsh in this directory.
go:
echo '#!/bin/sh' >$@ && \
echo >>$@ && \
echo "lib=`pwd`" >>$@ && \
echo 'exec $$lib/$(VM) -o $$lib/$(VM) -i $$lib/$(IMAGE) "$$@"' \
echo 'exec $$lib/$(VM) -o $$lib/$(VM) -i $$lib/scsh/scsh.image "$$@"' \
>>$@ && \
chmod +x $@
dirs:
for dir in $(libdir) $(bindir) $(incdir); do \
[ -d $$dir -a -w $$dir ] || { \
echo "$$dir not a writable directory" >&2; \
exit 1; \
}; \
done
{ mkdir -p $(LIB) && [ -w $(LIB) ]; } || { \
echo "$(LIB) not a writable directory" >&2; \
exit 1; \
}
for dir in rts env big opt misc link; do \
{ mkdir -p $(LIB)/$$dir && [ -w $(LIB)/$$dir ]; } || { \
echo "$(LIB)/$$dir not a writable directory" >&2; \
exit 1; \
}; \
for dir in $(libdir) $(bindir) $(incdir) $(LIB) $(mandir) $(htmldir); do\
{ mkdir -p $(DESTDIR)$$dir && [ -w $(DESTDIR)$$dir ]; } || { \
echo "$(DESTDIR)$$dir not a writable directory" >&2; \
exit 1; \
} \
done && \
for dir in \
rts env big opt misc link srfi scsh doc/scsh-manual \
doc/s48-manual/html doc/scsh-paper/html cig; do \
{ mkdir -p $(DESTDIR)$(LIB)/$$dir && [ -w $(DESTDIR)$(LIB)/$$dir ]; } || { \
echo "$(DESTDIR)$(LIB)/$$dir not a writable directory" >&2; \
exit 1; \
}; \
done
configure: configure.in
autoheader && autoconf
clean:
-rm -f $(VM) *.o c/unix/*.o c/*.o c/fake/*.o \
TAGS $(IMAGE) \
clean: clean-cig clean-scsh
-rm -f $(VM) *.o c/*/*.o c/*.o \
$(IMAGE) \
build/*.tmp $(MANPAGE) build/linker.image \
scheme/debug/*.image scheme/debug/*.debug config.cache \
scheme/debug/*.image scheme/debug/*.debug \
scheme/vm/scheme48vm.c scheme/vm/scheme48heap.c \
go $(distname)
clean-cig:
-rm -f cig/*.o $(CIG) $(CIG).image $(LIBCIG)
distclean: clean
rm -f Makefile config.log config.status c/sysdep.h
rm -f Makefile config.log config.status c/sysdep.h config.cache \
scsh/machine \
scsh/endian.scm \
exportlist.aix scsh-config
$(RM) a.exe $(VM).base $(VM).def $(VM).exp
-find . -name '*~' -o -name '#*' -o -name core -exec rm {} \;
check: $(VM) $(IMAGE) scheme/debug/check.scm
( \
@ -296,18 +471,17 @@ image: $(INITIAL)
$(MAKE) $(IMAGE)
tags:
etags scheme/vm/arch.scm scheme/rts/*.scm scheme/bcomp/*.scm \
scheme/*.scm scheme/env/*.scm scheme/big/*.scm scheme/link/*.scm \
scheme/opt/*.scm scheme/debug/*.scm scheme/misc/*.scm
find . -name "*.scm" -o -name "*.c" -o -name "*.h" | etags -
# --------------------
# Distribution...
# DISTFILES should include all sources.
DISTFILES = README COPYING INSTALL configure \
acconfig.h configure.in Makefile.in install-sh \
doc/*.ps doc/*.txt doc/html/*.html doc/scheme48.man \
doc/src/*.tex doc/src/*.sty \
DISTFILES = README COPYING INSTALL RELEASE configure config.sub config.guess \
scsh-config.in configure.in Makefile.in install-sh \
doc/*.ps doc/*.txt \
doc/src/*.tex doc/src/*.sty doc/src/manual.dvi \
doc/src/manual.ps \
emacs/README build/*-version-number build/*.exec \
build/*.lisp build/build-usual-image build/filenames.make \
build/filenames.scm build/initial.debug \
@ -316,14 +490,40 @@ DISTFILES = README COPYING INSTALL configure \
c/*.[ch] c/*/*.[ch] c/scheme48.h.in \
emacs/*.el gdbinit \
scheme/*.scm scheme/*/*.scm \
ps-compiler \
c/sysdep.h.in
ps-compiler/*.scm ps-compiler/minor-version-number \
ps-compiler/doc/*.txt ps-compiler/*/*.scm \
ps-compiler/*/*/*.scm \
ps-compiler/prescheme/test/fact.cps \
ps-compiler/prescheme/test/prescheme.h \
ps-compiler/prescheme/c-stuff \
c/sysdep.h.in \
scsh/*.scm scsh/*/*.scm \
scsh/*.[ch] scsh/*/*.[ch] \
scsh/*.scm.in scsh/*/Makefile.inc \
cig/*.scm cig/*.[ch] \
doc/scsh.man \
doc/scsh-manual/*.tex doc/scsh-manual/*.sty \
doc/scsh-manual/man.ps doc/scsh-manual/man.pdf \
doc/scsh-manual/man.dvi doc/scsh-manual/Makefile \
doc/scsh-manual/THANKS doc/scsh-manual/html/*.html \
doc/scsh-manual/html/*.gif doc/scsh-manual/html/*.css \
doc/src/manual/*.html \
doc/scsh-paper/*.sty doc/scsh-paper/*.tex \
doc/scsh-paper/mitlogo.ps doc/scsh-paper/scsh-paper.ps \
doc/scsh-paper/scsh-paper.dvi \
doc/scsh-paper/html/*.html doc/scsh-paper/html/*.css
distname = $(RUNNABLE)-0.`cat build/minor-version-number`
dist: build/initial.image
dist: build/initial.image distclean
(cd doc/src && latex manual.tex && latex manual.tex && \
dvips manual -o manual.ps && hyperlatex manual.tex) && \
(cd doc/scsh-manual && makeindex man && make man.ps && \
make man.pdf && make html) && \
(cd doc/scsh-paper && make scsh-paper.ps && make html) && \
distname=$(distname) && \
distfile=$(distdir)/$$distname.tgz && \
distfile=$(distdir)/$$distname.tar.gz && \
if [ -d $(distdir) ] && \
[ -w $$distfile -o -w $(distdir) ]; then \
rm -f $$distname && \
@ -378,9 +578,7 @@ PACKAGES=scheme/packages.scm scheme/rts-packages.scm scheme/alt-packages.scm \
build/filenames.scm
build/filenames.make: $(PACKAGES)
$(MAKE) $(VM) PACKAGES=
./$(VM) -i $(srcdir)/$(INITIAL) -a batch <build/filenames.scm
# or: $(RUNNABLE) -a batch <build/filenames.scm
$(BUILD_RUNNABLE) -a batch <build/filenames.scm
# --------------------
# Static linker
@ -418,7 +616,8 @@ link/linker-in-lucid: build/lucid-script.lisp $(linker-files) \
# Scheme, the byte-code compiler, and a minimal command processor, but
# no debugging environment to speak of.
$(INITIAL): $(LINKER_IMAGE) $(CONFIG_FILES) build/initial.scm $(initial-files)
$(INITIAL): $(LINKER_IMAGE) $(CONFIG_FILES) build/initial.scm $(initial-files) \
scsh/here.scm # gross and Olin hates it -bri
($(START_LINKER); \
echo '(load-configuration "scheme/interfaces.scm")'; \
echo '(load-configuration "scheme/packages.scm")'; \
@ -466,9 +665,9 @@ scheme/debug/medium.image: $(LINKER_IMAGE) $(CONFIG_FILES)
# The following have not been updated for the new directory organization
c/smain.o: c/main.c
$(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) -DSTATIC_AREAS -o $@ c/main.c
$(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) -DSTATIC_AREAS -o $@ $(srcdir)/c/main.c
mini: mini-heap.o smain.o
mini: mini-heap.o c/smain.o
$(CC) $(LDFLAGS) $(CFLAGS) -o $@ c/smain.o mini-heap.o $(OBJS) $(LIBS)
mini-heap.o: mini-heap.c
@ -477,7 +676,7 @@ mini-heap.o: mini-heap.c
mini-heap.c: scheme/debug/mini1.image
(echo ,exec ,load misc/load-static.scm; \
echo \(do-it 150000 \"$(srcdir)/scheme/debug/mini1.image\" \"$@\"\)) \
| $(RUNNABLE) -h 3000000 -a batch
| $(BUILD_RUNNABLE) -h 3000000 -a batch
scheme/debug/mini1.image: $(VM) scheme/debug/mini.image
echo "(write-image \"scheme/debug/mini1.image\" \
@ -496,13 +695,13 @@ c/scheme48.h: c/scheme48.h.in scheme/vm/arch.scm scheme/vm/data.scm \
echo ',batch'; \
echo ',load-package big-scheme'; \
echo ',open big-scheme'; \
echo ',load scheme/link/generate-c-header.scm'; \
echo ',load $(srcdir)/scheme/link/generate-c-header.scm'; \
echo "(make-c-header-file \"$@\" \
\"$(srcdir)/c/scheme48.h.in\" \
\"$(srcdir)/scheme/vm/arch.scm\" \
\"$(srcdir)/scheme/vm/data.scm\" \
\"$(srcdir)/scheme/rts/record.scm\")" \
) | $(RUNNABLE)
) | $(BUILD_RUNNABLE)
# An old version of the above for legacy code.
@ -516,7 +715,7 @@ c/old-scheme48.h: scheme/vm/arch.scm scheme/vm/data.scm \
echo "(make-c-header-file \"$@\" \
\"$(srcdir)/scheme/vm/arch.scm\" \
\"$(srcdir)/scheme/vm/data.scm\")" \
) | $(RUNNABLE)
) | $(BUILD_RUNNABLE)
# Generate vm (scheme48vm.c and scheme48heap.c) from VM sources.
# Never called automatically. Do not use unless you are sure you
@ -531,5 +730,217 @@ i-know-what-i-am-doing:
echo ',exec ,load compile-vm-no-gc.scm'; \
echo ',exec ,load compile-gc.scm'; \
echo ',exit' \
) | $(RUNNABLE) -h 8000000 && \
) | $(BUILD_RUNNABLE) -h 5000000 && \
mv ../scheme/vm/scheme48vm.c ../scheme/vm/scheme48heap.c ../c
cig: $(CIG) $(CIG).image $(LIBCIG)
$(CIG): $(VM) $(IMAGE) $(srcdir)/cig/cig.scm $(srcdir)/cig/libcig.scm
(echo ",batch"; \
echo ",translate =scheme48/ $(srcdir)/scheme/"; \
echo ",config ,load $(srcdir)/cig/cig.scm"; \
echo ",config ,load $(srcdir)/cig/libcig.scm"; \
echo ",load-package cig-standalone"; \
echo ",in cig-standalone"; \
echo ",translate =scheme48/ $(LIB)/"; \
echo ",build cig-standalone-toplevel /tmp/cig") \
| ./$(VM) -i ./$(IMAGE)
$(srcdir)/cig/image2script $(LIB)/$(VM) </tmp/cig > $(CIG)
-chmod +x $(CIG)
mv /tmp/cig $(srcdir)/cig/cig_bootstrap
$(RM) /tmp/cig
$(CIG).image: $(IMAGE) $(VM) $(srcdir)/cig/cig.scm $(srcdir)/cig/libcig.scm
(echo ",batch"; \
echo ",translate =scheme48/ $(srcdir)/scheme/"; \
echo ",config ,load $(srcdir)/cig/cig.scm"; \
echo ",config ,load $(srcdir)/cig/libcig.scm"; \
echo ",load-package cig-aux"; \
echo ",open define-foreign-syntax"; \
echo ",translate =scheme48/ $(LIB)/"; \
echo ",dump /tmp/cig \"(CIG Preloaded -bri)\"") \
| ./$(VM) -o ./$(VM) -i ./$(IMAGE)
$(srcdir)/cig/image2script $(LIB)/$(VM) \
-o $(LIB)/$(VM) \
</tmp/cig > $(CIG).image
-chmod +x $(CIG).image
$(RM) /tmp/cig
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
# SCSH Specifics
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
scsh: scsh/scsh scsh/scsh.image
SCHEME =scsh/awk.scm \
scsh/configure.scm \
scsh/defrec.scm \
scsh/endian.scm \
scsh/enumconst.scm \
scsh/event.scm \
scsh/low-interrupt.scm \
scsh/fdports.scm \
scsh/fileinfo.scm \
scsh/filemtch.scm \
scsh/filesys.scm \
scsh/flock.scm \
scsh/fname.scm \
scsh/fr.scm \
scsh/glob.scm \
scsh/dot-locking.scm \
scsh/here.scm \
scsh/lib-dirs.scm \
scsh/libscsh.scm \
scsh/machine/bufpol.scm \
scsh/machine/errno.scm \
scsh/machine/fdflags.scm \
scsh/machine/netconst.scm \
scsh/machine/packages.scm \
scsh/machine/signals.scm \
scsh/machine/time_dep.scm \
scsh/machine/tty-consts.scm \
scsh/machine/waitcodes.scm \
scsh/md5.scm \
scsh/meta-arg.scm \
scsh/network.scm \
scsh/newports.scm \
scsh/procobj.scm \
scsh/pty.scm \
scsh/rdelim.scm \
scsh/rw.scm \
scsh/scsh-condition.scm \
scsh/scsh-interfaces.scm \
scsh/scsh-package.scm \
scsh/scsh-read.scm \
scsh/scsh-version.scm \
scsh/scsh.scm \
scsh/sighandlers.scm \
scsh/startup.scm \
scsh/stringcoll.scm \
scsh/syntax-helpers.scm \
scsh/syntax.scm \
scsh/syscalls.scm \
scsh/time.scm \
scsh/top.scm \
scsh/tty.scm \
scsh/utilities.scm \
scsh/weaktables.scm \
scsh/rx/packages.scm \
scsh/rx/re-match-syntax.scm \
scsh/rx/rx-lib.scm \
scsh/rx/parse.scm \
scsh/rx/re-subst.scm \
scsh/rx/simp.scm \
scsh/rx/posixstr.scm \
scsh/rx/re-syntax.scm \
scsh/rx/spencer.scm \
scsh/rx/oldfuns.scm \
scsh/rx/re-fold.scm \
scsh/rx/re.scm \
scsh/rx/test.scm \
scsh/rx/re-high.scm \
scsh/rx/regexp.scm \
scsh/rx/re-low.scm \
scsh/rx/regress.scm
# scsh/dbm.scm db.scm ndbm.scm
# jcontrol
# Bogus, but it makes the scm->c->o two-ply dependency work.
# Explicitly giving the .o/.c dependency also makes it go.
############################################################
cig/libcig.c: cig/libcig.scm
scsh/scsh: scsh/scsh-tramp.c
$(CC) -o $@ $(CPPFLAGS) $(CFLAGS) \
-DVM=\"$(LIB)/$(VM)\" \
-DIMAGE=\"$(LIB)/scsh.image\" \
$(srcdir)/scsh/scsh-tramp.c
bs: build/build-scsh-image
sh $(srcdir)/build/build-scsh-image "$(srcdir)" "$(LIB)" "$(IMAGE)" \
"$(VM)" cig/cig.image
loads = $(srcdir)/scsh/let-opt.scm $(srcdir)/scsh/scsh-interfaces.scm \
$(srcdir)/scsh/machine/packages.scm \
$(srcdir)/scsh/rx/packages.scm \
$(srcdir)/scsh/scsh-package.scm \
$(srcdir)/scsh/lib/ccp-pack.scm \
$(srcdir)/scsh/lib/char-package.scm
opens = floatnums scsh ccp-lib scsh-top-package scsh-here-string-hax \
srfi-1 srfi-13 srfi-14 # srfi-14 is also exported by scsh
# Doing ,load-package scheme-with-scsh here gives us much better start-up times
scsh/scsh.image: $(VM) $(SCHEME) $(IMAGE)
(echo ",translate =scheme48/ $(srcdir)/scheme/"; \
echo ",translate $(srcdir)/scsh/endian.scm `pwd`/scsh/endian.scm"; \
echo ",translate $(srcdir)/scsh/configure.scm `pwd`/scsh/configure.scm"; \
echo ",batch on"; \
echo ",config ,load $(loads)"; \
echo ",open $(opens)"; \
echo ",load-package scheme-with-scsh"; \
echo "(dump-scsh \"$@\")"; \
) \
| ./$(VM) -o ./$(VM) -i $(IMAGE) -h 10000000
# ,flush files => 0k
# ,flush names => -= 17k
# ,flush maps => -= 350K
# ,flush source => -= 1117k
# ,flush => 550k
scsh/stripped-scsh.image: $(VM) $(SCHEME) $(IMAGE)
(echo ",flush maps source";\
echo ",translate =scheme48/ $(srcdir)/scheme/"; \
echo ",translate $(srcdir)/scsh/endian.scm `pwd`/scsh/endian.scm"; \
echo ",translate $(srcdir)/scsh/configure.scm `pwd`/scsh/configure.scm"; \
echo ",batch on"; \
echo ",config ,load $(loads)"; \
echo ",open $(opens)"; \
echo ",load-package scheme-with-scsh"; \
echo ",flush"; \
echo "(dump-scsh \"$@\")";) \
| ./$(VM) -o ./$(VM) -i $(IMAGE) -h 10000000
install-scsh: scsh install-scsh-image install-stripped-scsh-image
$(RM) $(DESTDIR)$(bindir)/$(RUNNABLE)
$(INSTALL_PROGRAM) scsh/scsh $(DESTDIR)$(bindir)/$(RUNNABLE)
$(INSTALL_PROGRAM) $(LIBSCSHVM) $(DESTDIR)$(libdir)/$(LIBSCSHVM)
$(INSTALL_PROGRAM) $(LIBSCSH) $(DESTDIR)$(libdir)/$(LIBSCSH)
$(RANLIB) $(DESTDIR)$(libdir)/$(LIBSCSH)
for f in $(srcdir)/scsh/*.scm $(srcdir)/scsh/*/*.scm; \
do $(INSTALL_DATA) $$f $(DESTDIR)$(LIB)/scsh/; done
install-scsh-image: $(VM) scsh/scsh.image
( echo ',translate =scheme48 $(LIB)'; \
echo ',in lib-dirs (set-default-lib-dirs! (quote $(lib_dirs_list)))'; \
echo '(dump-scsh "$(DESTDIR)$(LIB)/scsh.image")'; \
echo ',exit'; \
) | ./$(VM) -i scsh/scsh.image
install-stripped-scsh-image: $(VM) scsh/stripped-scsh.image
( echo ',translate =scheme48 $(LIB)'; \
echo ',in lib-dirs (set-default-lib-dirs! (quote $(lib_dirs_list)))'; \
echo '(dump-scsh "$(DESTDIR)$(LIB)/stripped-scsh.image")'; \
echo ',exit'; \
) | ./$(VM) -i scsh/stripped-scsh.image
clean-scsh:
$(RM) scsh/*.o scsh/rx/*.o scsh/machine/*.o
$(RM) scsh/*.image
$(RM) scsh/configure.scm
$(RM) $(LIBSCSHVM) $(LIBSCSH) scsh/scsh$(EXEEXT)
scsh/configure.scm: $(srcdir)/scsh/configure.scm.in
sed -e 's|@scsh_host@|$(host)|g' \
-e 's|@scsh_prefix@|$(prefix)|g' \
-e 's|@scsh_exec_prefix@|$(exec_prefix)|g' \
-e 's|@scsh_bindir@|$(bindir)|g' \
-e 's|@scsh_libdir@|$(libdir)|g' \
-e 's|@scsh_includedir@|$(incdir)|g' \
-e 's|@scsh_mandir@|$(mandir)|g' \
-e 's|@scsh_lib_dirs_list@|$(lib_dirs_list)|g' \
-e 's|@scsh_LIBS@|$(LIBS)|g' \
-e 's|@scsh_DEFS@|$(DEFS)|g' \
-e 's|@scsh_CFLAGS@|$(CFLAGS)|g' \
-e 's|@scsh_CPPFLAGS@|$(CPPFLAGS)|g' \
-e 's|@scsh_LDFLAGS@|$(LDFLAGS)|g' $(srcdir)/scsh/configure.scm.in > $@

92
README
View File

@ -1,93 +1,19 @@
; Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees. See file COPYING.
-*- Mode: Text; -*-
Please report bugs to scheme-48-bugs@martigny.ai.mit.edu, and include
Copyright (c) 1994 Brian D. Carlstrom
See file COPYING for copying information.
Please report bugs to scsh-users@scsh.net, and include
the version number in your message.
Installation instructions in file INSTALL.
A user's guide is in file doc/user-guide.txt.
A scsh manual is in directory doc/scsh-manual/.
A scsh paper is in directory doc/scsh-paper/.
A scsh quick reference is in file doc/cheat.txt.
Recent changes are listed in file doc/news.txt.
Known bugs and things to do in the future are listed in doc/todo.txt.
Send mail to scheme-48-request@martigny.ai.mit.edu to be put on a
Send mail to scsh-users-request@scsh.net to be put on a
mailing list for announcements, discussion, bug reports, and bug
fixes.
-----
When running "make", don't worry if the ".notify" target fails. Its
only purpose is to send an email message to
scheme-48-notifications@martigny.ai.mit.edu, so that we can get a
rough idea of how much Scheme 48 is being used and by whom. We
promise not to use your name or email address for any commercial
purpose. If you don't want us to know, just do "make -t .notify"
first (after running "configure").
-----
The Scheme 48 root directory is organized as follows (not all files are
listed here):
README this file
INSTALL installation instructions
COPYING copyright notice
configure configuration script
Makefile.in input to configure
doc/ some documentation
scheme48.man a Unix-style manual page
user-guide.txt general guide to using Scheme 48
todo.txt list of improvements we hope to make someday
news.txt list of improvements we have already made
module.ps description of Scheme 48's module system
big-scheme.txt extensions to Scheme
threads.txt multiprocessing
io.txt how the I/O system works
scheme/ scheme source files
packages.scm meta-module definitions
interfaces.scm system interface definitions
more-interfaces.scm system interface definitions
*-packages.scm module definitions
bcomp/ the byte-code compiler
vm/ virtual machine sources (written in Pre-Scheme)
rts/ run-time system sources
link/ static linker
env/ development environment modules (debugger, etc.)
big/ useful Scheme libraries and extensions ("Big Scheme")
alt/ portable implementations of some Scheme 48 features
opt/ optional code optimizer for the byte-code compiler
prescheme/ code for running the VM using Scheme 48
debug/ debugging utilities, tests, etc.
misc/ very miscellaneous things (e.g. AMB operator)
posix/ unfinished interface to POSIX system calls
ps-compiler/ Pre-Scheme -> C compiler
c/ c source files
sysdep.h.in input to configure
scheme48vm.c most of the VM (generated by Pre-Scheme compiler)
scheme48vm.h extern declarations for scheme48vm.c
scheme48heap.c storage management (generated by Pre-Scheme compiler)
scheme48heap.h extern declarations for scheme48heap.c
main.c entry point for the VM
prescheme.h part of the VM
extension.c default definition of vm_extension()
scheme48.h C declarations and macros for Scheme 48 data structures
old-scheme48.h old version, included for compatibility
c-mods.h minor additions to the C language
event.h header file for OS interface
io.h ditto
fd-io.h ditto
socket.c socket support
dynamo.c dynamic loading support
unix/ Unix-specific source files
posix/ C half of an unfinished interface to POSIX system calls
fake/ C files for insufficiently POSIX-compliant systems
build/ code for building the system
filenames.make included by Makefile, generated automatically
filenames.scm code for generating filenames.make
initial.image an image file containing a minimal Scheme system
initial.debug debugging database for same
initial.scm script for creating initial.image
build-usual-image script for creating scheme48.image
build-external-modules script for creating external-module initializer
emacs/ gnu emacs support

86
README.s48 Normal file
View File

@ -0,0 +1,86 @@
; Copyright (c) 1993-2001 by Richard Kelsey and Jonathan Rees.
; Copyright (c) 1994-2000 by Olin Shivers and Brian D. Carlstrom.
; Copyright (c) 1999-2000 by Martin Gasbichler.
See file COPYING.
Please report bugs to scsh-bugs@zurich.ai.mit.edu, and include
the version number in your message.
Installation instructions in file INSTALL.
A user's guide is in file doc/user-guide.txt.
Recent changes are listed in file doc/news.txt.
Known bugs and things to do in the future are listed in doc/todo.txt.
Send mail to scheme-48-request@martigny.ai.mit.edu to be put on a
mailing list for announcements, discussion, bug reports, and bug
fixes.
-----
The Scheme 48 root directory is organized as follows (not all files are
listed here):
README this file
INSTALL installation instructions
COPYING copyright notice
configure configuration script
Makefile.in input to configure
doc/ some documentation
scheme48.man a Unix-style manual page
user-guide.txt general guide to using Scheme 48
todo.txt list of improvements we hope to make someday
news.txt list of improvements we have already made
module.ps description of Scheme 48's module system
big-scheme.txt extensions to Scheme
threads.txt multiprocessing
io.txt how the I/O system works
scheme/ scheme source files
packages.scm meta-module definitions
interfaces.scm system interface definitions
more-interfaces.scm system interface definitions
*-packages.scm module definitions
bcomp/ the byte-code compiler
vm/ virtual machine sources (written in Pre-Scheme)
rts/ run-time system sources
link/ static linker
env/ development environment modules (debugger, etc.)
big/ useful Scheme libraries and extensions ("Big Scheme")
alt/ portable implementations of some Scheme 48 features
opt/ optional code optimizer for the byte-code compiler
prescheme/ code for running the VM using Scheme 48
debug/ debugging utilities, tests, etc.
misc/ very miscellaneous things (e.g. AMB operator)
posix/ unfinished interface to POSIX system calls
ps-compiler/ Pre-Scheme -> C compiler
c/ c source files
sysdep.h.in input to configure
scheme48vm.c most of the VM (generated by Pre-Scheme compiler)
scheme48vm.h extern declarations for scheme48vm.c
scheme48heap.c storage management (generated by Pre-Scheme compiler)
scheme48heap.h extern declarations for scheme48heap.c
main.c entry point for the VM
prescheme.h part of the VM
extension.c default definition of vm_extension()
scheme48.h C declarations and macros for Scheme 48 data structures
old-scheme48.h old version, included for compatibility
c-mods.h minor additions to the C language
event.h header file for OS interface
io.h ditto
fd-io.h ditto
socket.c socket support
dynamo.c dynamic loading support
unix/ Unix-specific source files
posix/ C half of an unfinished interface to POSIX system calls
fake/ C files for insufficiently POSIX-compliant systems
build/ code for building the system
filenames.make included by Makefile, generated automatically
filenames.scm code for generating filenames.make
initial.image an image file containing a minimal Scheme system
initial.debug debugging database for same
initial.scm script for creating initial.image
build-usual-image script for creating scheme48.image
build-external-modules script for creating external-module initializer
emacs/ gnu emacs support

525
RELEASE Normal file
View File

@ -0,0 +1,525 @@
Scsh 0.6.7 Release notes -*- outline -*-
We are pleased to release scsh version 0.6.7.
The text below gives a general description of scsh, instructions for obtaining
it, pointers to discussion forums, and a description of the new features in
release 0.6.7. (Emacs should display this document is in outline mode. Say
c-h m for instructions on how to move through it by sections (e.g., c-c c-n,
c-c c-p).)
* Contents
==========
What is scsh
Scsh as a scripting language
Scsh as a systems-programming language
Scsh is a portable programming environment
Obtaining and installing scsh
Getting in touch
The World-Wide What?
New in this release
New in 0.6.6
New in 0.6.5
New in 0.6.4
New in 0.6.3
New in 0.6.2
New in 0.6.1
New in 0.6.0
Thanks
* What is scsh
==============
Scsh is a broad-spectrum systems-programming environment for Unix embedded
in R5RS Scheme. It has an open-source copyright, and runs on most major
Unix systems.
** Scsh as a scripting language
-------------------------------
Scsh has a high-level process notation for doing shell-script like tasks:
running programs, establishing pipelines and I/O redirection. For example, the
shell pipeline
gunzip < paper.tex.gz | detex | spell | lpr -Ppulp &
would be written in scsh as
(& (| (gunzip) (detex) (spell) (lpr -Ppulp)) ; Background a pipeline
(< paper.tex.gz)) ; with this redirection
Scsh embeds this process notation within a full Scheme implementation.
The process notation is realized as a set of macro definitions, and is
carefully designed to allow full integration with standard Scheme code.
Scsh isn't Scheme-like; it is Scheme.
At the scripting level, scsh also has an Awk design, also implemented
as a macro that can be embedded inside general Scheme code.
Scripts can be written as standalone Scheme source files, with a leading
#!/usr/local/bin/scsh -s
trigger line.
** Scsh as a systems-programming language
-----------------------------------------
Scsh additionally provides the low-level access to the operating system
normally associated with C. The current release provides full access to Posix,
plus important non-Posix extensions, such as complete sockets support.
"Complete Posix" means: fork, exec & wait, sockets, full read, write, open &
close, seek & tell, complete file-system access, including stat,
chmod/chgrp/chown, symlink, FIFO & directory access, tty & pty support, file
locking, pipes, select, file-name pattern-matching, time & date, environment
variables, signal handlers, and more.
In brief, you can now write Unix systems programs in Scheme instead of C.
For example, we have implemented an extensible HTTP server at MIT entirely
in scsh.
As important as full access to the OS is the manner in which it is provided.
Scsh integrates the OS support into Scheme in a manner which respects the
general structure of the language. The details of the design are discussed
in a joint MIT Lab for Computer Science/University of Hong Kong technical
report, "A Scheme Shell," also to appear in a revised format in the "Journal
syof Lisp and Symbolic Computation." This paper is also available by ftp:
ftp://ftp.scsh.net/pub/scsh/papers/scsh-paper.ps
** Scsh is a portable programming environment
---------------------------------------------
Scsh is designed for portability. It is implemented on top of Scheme 48,
a byte-code-interpreter Scheme implementation. The Scheme 48 virtual machine
can be compiled on any system with a C compiler; the rest of Scheme 48 is
machine-independent across 32-bit processors. Scsh's OS interface is
also quite portable, providing a consistent interface across different
Unix platforms. We currently have scsh implementations for:
AIX
BSD/OS
CXUX
FreeBSD
HP-UX
IRIX
Linux
NetBSD
OpenBSD
Solaris
SunOS
Win32
Darwin/Mac OS X
GNU Hurd
Scsh code should run without change across these systems.
Porting to new platforms is usually not difficult.
* Obtaining and installing scsh
===============================
You can get a copy of scsh via anonymous ftp, from
ftp://ftp.scsh.net/pub/scsh/scsh.tar.gz
The tar file includes a detailed manual and a paper describing
the design of the system.
For the lazily curious, we also have the manual separately available as
ftp://ftp.scsh.net/pub/scsh/0.6/scsh-manual.ps
Just click 'n view.
You *should* be able to build scsh on the standard platforms with exactly five
commands: gunzip, tar, cd, ./configure, and make. The configure script figures
out the special flags and switches needed to make the build work (thanks to
the GNU project for the autoconfig tool that makes this possible).
After doing the make, you can start up a Scheme shell and try it out
by saying
./go
See the manual for full details on the command-line switches.
If it's harder than this, and your system is standard, we'd like to know
about it.
* Getting in touch
==================
Currently, there is a mailing-list which is mirrored to a newsgroup.
To (un)subscribe to the mailing-list, send a message to
scsh-users-request@scsh.net. To submit a message to the
mailing-list, send it to scsh-users@scsh.net.
The mailing-list is also readable as a standard newsgroup, thanks to
gmane, a mail-to-news gateway. More information is available at the
following URL:
http://gmane.org/info.php?group=gmane.lisp.scheme.scsh
There used to be a newsgroup dedicated to scsh, called
comp.lang.scheme.scsh but it is now deprecated.
Bugs can be reported to the same list
scsh-users@scsh.net
or via the Scsh project's bugs section on SourceForge:
http://sourceforge.net/projects/scsh/
* The World-Wide What?
======================
We even have one of those dot-com cyberweb things:
http://www.scsh.net
We manage the project using SourceForge:
http://sourceforge.net/projects/scsh/
* New in this release
=====================
** Support for interix
** Ignoring of synchronous signals
The procedures IGNORE-SIGNAL and HANDLE-SIGNAL-DEFAULT have been
added.
** Support for gcc 4.0
** 0.6 for module path
The standard module path now contains
${prefix}/lib/scsh/modules/0.6 in addition to
$prefix/lib/scsh/modules for compatibility with install-lib
** New implementation of open-pty
Instead of search for /dev/pty??, scsh now tries a wide variety of
ways to aquire a new pty and the corresponding tty.
** Bug fixes
argv[0] is now the first element of command-line
Fixes found by new test suite
Regexp for empty string
Argument checking for COPY-BYTES!
GC_PROTECTs for send_substring
format_date support for #f timezone
Added predicates for user-info and group-info
Reaping of stopped processes: Do not mark stopped processes as dead
md5-digest-for-port
| regexps return char-sets
standard-let in srfi-5
(%)read-delimited! checks for mutable buffer
leap second for srfi-19
The default image for the scshvm is now the installed scsh.image.
* New in 0.6.6
===============
** Removed or replaced non-free code
Some files in the previous versions of scsh did not conform to
scsh's BSD-style license. We therefore removed the directory
scheme/infix and asked the copyright holders of the rest of the
code to put their code under a compatible license. The code of the
sort package has been replaced by a new version (see below).
** New code for sorting
The old package SORT from Scheme 48 has been replaced by a
sophisticated library written by Olin Shivers for the withdrawn
SRFI 32.
** Separate documentation of the library directories search facility
The manual now contains a separate section that describes the
library directories search facility. The description of the
respective switches has been adapted accordingly.
** New module CONFIGURE
The new module CONFIGURE permits access to some of the values
obtained during the run of the configure script.
** Argument processing more robust
Any number of whitespaces may now occur between the arguments to
the VM.
** Ultrix is no longer supported
The Ultrix platform is lacking support for POSIX regular
expressions and is therefore no longer supported.
** Bug fixes
Fix WITH-LOCk
Ensure that the exit value is 1 if scsh exits due to an error
Load the package scheme-with-scsh before dumping images to get
better start-up times
Fix two bugs in GLOB related to quotation
The optmizer AUTO-INTEGRATE can now inline procedures with
macro-generated arguments
The optmizer FLAT-ENVIRONMENTS now works if invoked after AUTO-INTEGRATE
Fixed a bug in the parser of "-" sre forms
Removed accidentally committed expansion of paths in SCSH_LIB_DIR
Fix the various SELECT-like procedures for 0 timeouts
Let PATH-LIST->FILE-NAME return "/" for '("").
Fix bug in S48_RECORD_TYPE: third parameter to s48_stob_ref was missing.
Fixed check for -rdynamic
FIELD-READER returns (values EOF '()) on an empty port
Fixed STRING-CONTAINS and STRING-CONCATENATE-REVERSE/SHARED from SRFI-13
* New in 0.6.5
==============
** New platform: GNU Hurd
Andreas Vögele ported scsh to GNU Hurd.
** ./configure option to set default scsh library directories
The ./configure script now accepts the option --with-lib-dirs-list
to specify a list of default scsh library directories. In
previous versions of scsh this list was hardwired to
/usr/local/lib/scsh/modules.
** Support for DESTDIR for easier packaging
The install target of the Makefile now respects the environment
variable DESTDIR to allow package maintainers to use a staging
directory.
** New SRFI
This release adds support for SRFI 42.
** Switch to load exec scripts from library path
The new switch -lel searches the library path for a file and loads
the file into the exec package.
** Removed scheme/infix/
The directory scheme/infix/ had a non-free copyright licence and
has been removed.
** Bug fixes
- SEEK currently works on unbuffered ports only. Check this in the
implementation and oopsify it in the manual.
- Adjust documentation of some low-level regexp procedures
- Removed message argument form errno-error
- After fork/pipe, make the ports returned by the pipe the
current-in/output-ports
- Get the names of MAKE-STRING-PORT-FILTER and
MAKE-CHAR-PORT-FILTER right in the doc
- Fixed memory leak in scheme_cwd
- Fixed memory leak in format_date
- Avoid calling SOCKET-OPTION twice in case of an error
- Fix for (rx (|)) by Peter Wang
- Fix for (posix-string->regexp "$") by Peter Wang
** API changes
None known.
* New in 0.6.4
==============
** Switches to load exec scripts
The new switch -le loads a file into the exec package, the new
switch -de loads the "-s" script into the exec package.
** New SRFIs
This release adds support for SRFI 25, 26, 27, 28 and 30.
** Bug fixes
- Other select bug
- Timeout for select is in seconds, not milliseconds
- Load package md5 before dumping scsh.image
- Revised implementation of SRFI-19
- -sfd switch called bogus procedures
- Ooopsify write-string/partial
- Clean up get_groups
- Check for "." in file-name-{sans-}extension
- Bug fix for let-match: variables may be #f
- Fix some problems with WAIT-FOR-CHANNELS
- Fixes in the time zone code
- Fix a bug in SEND-MESSAGE: There is such a thing as an empty datagram
- Renamed string-filter to make-string-port-filter and char-filter to
make-char-port-filter
** API changes
pause-until-interrupt has been removed because it is not compatible
with the thread system
* New in 0.6.3
==============
** Shorter startup times
By a couple of small fixes we could diminish the startup
time by 10-30%.
** stripped-scsh.image
In addition to the standard heap image scsh.image, scsh now ships
with an additional image stripped-scsh.image. This image contains
the same code as the standard image but has almost all debugging
information removed. It is therefore much smaller (2.5 MB vs. 4.5
MB) which also allows shorter startup times. The image is intended
for use in scripts but not for interactive development. See the
manual for more information.
** MD5 support
The package md5 contains a bunch of procedures to compute MD5
checksums.
** New SRFIs
This release adds support for SRFI 25, 26, 27, 28 and 30.
** API changes
select and select! are supported again.
Note however, that we recommend to use the new select-ports and
select-port-channels procedures instead whenever possible.
New interface to the uname function.
New direct interface to the directory stream operations
New structure scheme-with-scsh which combines the exports of the
modules scsh and scheme, avoiding duplicates
New procdures to work directly on file-info records
The repl procedure has been removed
New procedures connect-socket-no-wait, connect-socket-successful?
Add lookup-external from recent S48
** Bugfixes
LET-MATCH, IF-MATCH, and COND-MATCH now behave according to the
documentation.
Many bug fixes for the SRE system, specifically for dynamic
submatches.
PORT->SOCKET uses dups both ports of the socket
Added missing process resource alignments
No reaping for stopped children
Initialize t.c_lflag before reading it.
Fix to allow single character here strings.
Add a whole bunch of S48_GC_PROTECT against s48_extract_integer.
Added MAP, FOR-EACH, MEMBER, ASSOC to SRFI 1 interface
Fixed a subtle bug in the macro for the << redirection
Use "compare" und "rename" to compare symbols in lots of macros
Fixed the close method for string-input-ports
... and many others.
* New in 0.6.2
==============
** SRFIs
In addition to SRFIs 1, 8, 13, 14 and 23 scsh now features SRFIs 2,
5, 6, 7, 9, 11, 16, 17 and 19. See http://srfi.schemers.org/ for a
detailed description. The SRFIs are available in packages srfi-N
where N is the number of the SRFI.
** port->socket
New procedure port->socket to turn a port into a socket object was
added to the network code.
** New forms in the module language
The module language supports the new forms modify, subset and
with-prefix from Scheme 48 version 0.57.
** API changes
Fork, fork/pipe, fork/pipe+ take an optional argument
continue-threads? to determine whether all threads should continue
to run in the child.
exec-path-list is now a preseved thread fluid
** PDF version of the manual
There is now a PDF version of the manual generated by pdflatex.
** Bugfixes
- Added default argument to tty-info as described in the manual
- Conversion to s48_value in tty1.c
- Fixed another hygiene problem in SRE
- Plugged space leak in bind-listen-accept-loop
- Aligned CWD and umask in various file operations
- Better releasing of port locks
- Corrected exception of time
- Set-cloexec to #t for unrevealed ports.
- Included scsh paper in the distribution.
- Fixed accept for AF_UNIX
- (setenv var #f) now deletes var from environment
- Quoted { and } within literal strings of regexps
* New in 0.6.1
==============
** API changes
For sre's, BOW, EOW, WORD, and WORD+ (which were already unsupported
in 0.6.0 on most platforms) are gone for good.
** Bugfixes
Most of the known bugs of version 0.6.0 have been fixed, many thanks for
the precise reports! See the project page on SourceForge for a list
of the remaining known bugs. Here is a brief overview of the fixes:
- GC_PROTECT'ed the necessary variables (specifically, where >1 arg to
a function 'may GC') (Thanks to Steven Jenkins for dealing with this)
- Fixed various race conditons in the signal handling and process reaping code
- Fixed bug in set-process-group
- If $HOME is unset, consult (user-info (user-uid)) for the value of
home-directory
- Fix external-call-from-callback problem leading to spurious
gc-protection-mismatch exceptions.
- Let s48-do-gc return 0 so the PreScheme compiler will emit the correct
signature of the function.
- scsh/linux/tty-consts.scm: num-ttychars seems to be 32 not 19.
- scsh/top.scm: Return 0 exit status for -c and -e.
- *.c: Replaced // comments.
- scsh/syslog1.c: Remove LOG_LPR from list of syslog levels.
- scsh/network1.c: Pass SYSCALL argument to ERRNO-ERROR.
- scsh/syscalls1.c: Disable timer interrupts before execve
- scsh/network.scm: Correct name extraction in bind-socket
- Added export for with-error-output-port
- Install HTML version of manual under $(libdir)
- ./configure is more rebost wrt $(srcdir)
- Fixed installation of the S48 manual
- Replaced several /tmp by /var/tmp
- Catch EISDIR in delete-filesys-object
- flush-all-ports is now non-blocking
* New in 0.6.0
==============
** Scsh is now based on Scheme 48 0.53
With the move from Scheme 48 version 0.36 to version 0.53 in this
release the underlying system received a massive update. The most
significant changes include:
User level threads
Advanced garbage collector
Improved foreign function interface to C
The most significant change for Scsh users is the addition of a
user-level thread system. Scsh provides various features to deal
with this new power in a system programming environment: An event
based interface to interrupts, thread local process state and
thread-safe system calls.
** A manual for Scheme 48 has been included
Richard Kelsey, the author of Scheme 48, has graciously allowed us
to retrofit the current Scheme 48 manual for inclusion in this scsh
release.
** Interfaces to dot-locking, crypt and syslog
Scsh now provides advisory file locking via the dot-locking scheme
and a direct binding to the crypt function. Furthermore we added
a complete, system-independent and thread-safe interface to syslog.
** API changes
Some features of the previous releases are currently not
supported as we did not have the time to implement them. Please tell
us, if you can't get along without them. Here is a listing of these
currently dereleased features:
select
select!
ODBC support
bufpol/line
The following procedures received new names in this release:
sleep (now process-sleep)
sleep-until (now process-sleep-until)
network-info, service-info and protocol-info now return #f on non-success.
The default directory for creating temporary files has changed: It's
now the value of $TMPDIR if set and /var/tmp otherwise.
The nth procedure is still there but is now officially obsolete. It
will go away in a future release.
** HTML version of the manual
There is now a HTML version of the scsh manual generated by tex2page
* Thanks
========
We would like to thank the members of local-resistance cells for the
Underground everywhere for bug reports, bug fixes, design review and comments
that were incorporated into this release. We really appreciate their help,
particularly in the task of porting scsh to new platforms.
Brought to you by the Scheme Underground. Go forth and write elegant systems
programs.
-Olin Shivers, Brian Carlstrom, Martin Gasbichler & Mike Sperber

66
TODO Normal file
View File

@ -0,0 +1,66 @@
0.6.1 release-critical:
=======================
Non-critical: [Martin]
=============
S48_EXTRACT_BOOLEAN is defined several times
create-file-thing should report a better error message.
/* Sorry, we only have a version with 5 arguments..*/.
s48_raise_os_error_5 (errno, sec, min, hour, mday, month);
how do i make the scheme48 heap larger? preferably without having to write
scripts that start like this:
#!/usr/local/lib/scsh/scshvm \
-o /usr/local/lib/scsh/scshvm -i /usr/local/lib/scsh/scsh.image -h <large-value>
-s
!#
Check whether we have remove the extern char *tzname[] declaration in time1.c
implement bufpol/line's flush on stdin
Move the code of time_plus_ticks to time1.c as it is not machine dependent
--->
The module system doesn't maintain a cwd of its own:
> ,config ,load ../sunet/xml/xml-packages.scm
../sunet/xml/xml-packages.scm
> (chdir "/tmp")
> ,open xml
Load structure xml (y/n)? y
[plt-compat
Error: exception
cannot-open-channel
(open-channel "../sunet/xml/plt.scm" 1)
<---
split up newports.scm (part that overwrites s48 defs, port-buffering, ...)
disallow cig to produce more than 12 arguments
libcig1.c : cig_string_body is probably extract_string
IsChar is used nowhere
Add .h.c rule to Makefile
--->
(define-syntax bla
(syntax-rules ()
((bla)
(rx any))))
> (bla)
Error: Illegal regular expression
#{Generated any 1276}
(Because "any" is imported from scsh-utilities in rx/parse.scm)
<---
Set port policy for input to bufpol/line via isatty

32
Thanks Normal file
View File

@ -0,0 +1,32 @@
Post-0.5.2-release bug reports:
Friedrich Dominicus
Jay Nietling
Tim Bradshaw
Robert Brown
Eric Marsden
Paul Emsley
Pawel Turnau
Hannu Koivisto
Andy Gaynor
Francisco Vides Fernandez
Tim Burgess
Brian Denheyer
Harvey Stein
Eric Hilsdale
Andreas Bernauer
Chris Beggy
Ed Kademan
Michal Maruska
Noel Hunt
David Reiss
Chad R Dougherty
Michel Schinz
Alan Bawden
Bengt Kleberg
RT Happe
Dorai Sitaram
Peter Wang
Stephen Ma
stktrc
Jan Alleman
Taylor Campbell

View File

@ -1,32 +0,0 @@
/*
* HAVE_SIGACTION is defined iff sigaction() is available.
*/
#undef HAVE_SIGACTION
/*
* HAVE_STRERROR is defined iff the standard libraries provide strerror().
*/
#undef HAVE_STRERROR
/*
* NLIST_HAS_N_NAME is defined iff a struct nlist has an n_name member.
* If it doesn't then we assume it has an n_un member which, in turn,
* has an n_name member.
*/
#undef NLIST_HAS_N_NAME
/*
* HAVE_SYS_SELECT_H is defined iff we have the include file sys/select.h.
*/
#undef HAVE_SYS_SELECT_H
/*
* USCORE is defined iff C externals are prepended with an underscore.
*/
#undef USCORE
@BOTTOM@
#include "fake/sigact.h"
#include "fake/strerror.h"
#include "fake/sys-select.h"

16
autogen.sh Executable file
View File

@ -0,0 +1,16 @@
#! /bin/sh
autoheader &&
autoconf &&
./configure &&
touch scsh/*.c &&
touch build/filenames.scm &&
rm -f scheme48.image cig/cig.image scsh/scsh.image &&
rm -f build/linker.image build/initial.image &&
rm -f c/scheme48.h &&
make build/filenames.make &&
make i-know-what-i-am-doing &&
make c/scheme48.h&&
make linker &&
make build/initial.image &&
make distclean

View File

@ -9,11 +9,12 @@ vm=$4
initial=$5
USER=${USER-`logname 2>/dev/null || echo '*GOK*'`}
$vm -i $initial -a batch <<EOF
./$vm -o ./$vm -i $initial batch <<EOF
,load $srcdir/scheme/env/init-defpackage.scm
((*structure-ref filenames 'set-translation!)
"=scheme48/" "$srcdir/scheme/")
,load =scheme48/more-interfaces.scm =scheme48/link-packages.scm
,load =scheme48/more-interfaces.scm =scheme48/sort/interfaces.scm
,load =scheme48/link-packages.scm
,load =scheme48/more-packages.scm
(ensure-loaded command-processor)
(ensure-loaded usual-commands)

View File

@ -1,7 +0,0 @@
#### This file was generated automatically. ####
initial-files = scheme/rts/low.scm scheme/rts/signal.scm scheme/rts/base.scm scheme/rts/util.scm scheme/rts/number.scm scheme/rts/lize.scm scheme/rts/record.scm scheme/rts/jar-defrecord.scm scheme/rts/method.scm scheme/rts/numio.scm scheme/rts/fluid.scm scheme/rts/defenum.scm scheme/vm/arch.scm scheme/big/queue.scm scheme/rts/condition.scm scheme/rts/session.scm scheme/rts/interrupt.scm scheme/rts/wind.scm scheme/rts/template.scm scheme/rts/continuation.scm scheme/rts/exception.scm scheme/rts/thread.scm scheme/rts/sleep.scm scheme/rts/lock.scm scheme/rts/port.scm scheme/rts/current-port.scm scheme/rts/write.scm scheme/rts/read.scm scheme/rts/channel.scm scheme/rts/channel-port.scm scheme/rts/channel-io.scm scheme/big/general-table.scm scheme/rts/population.scm scheme/bcomp/mtype.scm scheme/bcomp/interface.scm scheme/bcomp/binding.scm scheme/bcomp/name.scm scheme/bcomp/transform.scm scheme/bcomp/cenv.scm scheme/bcomp/thingie.scm scheme/bcomp/package.scm scheme/bcomp/package-undef.scm scheme/rts/env.scm scheme/big/filename.scm scheme/bcomp/read-form.scm scheme/bcomp/node.scm scheme/bcomp/schemify.scm scheme/bcomp/var-util.scm scheme/bcomp/syntax.scm scheme/bcomp/primop.scm scheme/bcomp/ddata.scm scheme/bcomp/stack-check.scm scheme/bcomp/state.scm scheme/bcomp/segment.scm scheme/bcomp/recon.scm scheme/bcomp/comp-exp.scm scheme/bcomp/comp-prim.scm scheme/bcomp/comp.scm scheme/rts/eval.scm scheme/env/dispcond.scm scheme/debug/mini-command.scm scheme/rts/scheduler.scm scheme/rts/root-scheduler.scm scheme/rts/init.scm scheme/env/start.scm scheme/bcomp/usual.scm scheme/bcomp/rules.scm scheme/bcomp/type.scm scheme/bcomp/module-language.scm scheme/bcomp/config.scm scheme/bcomp/scan-package.scm scheme/bcomp/optimize.scm scheme/bcomp/comp-package.scm scheme/env/load-package.scm scheme/big/strong.scm scheme/opt/usage.scm scheme/opt/sort.scm scheme/opt/inline.scm scheme/bcomp/for-reify.scm
usual-files = scheme/opt/analyze.scm scheme/env/disclosers.scm scheme/env/command-level.scm scheme/env/version-info.scm scheme/env/command.scm scheme/env/read-command.scm scheme/env/debuginfo.scm scheme/rts/xnum.scm scheme/rts/bignum.scm scheme/rts/ratnum.scm scheme/rts/recnum.scm scheme/rts/innum.scm scheme/env/basic-command.scm scheme/env/build.scm scheme/env/shadow.scm scheme/env/pedit.scm scheme/env/pacman.scm scheme/rts/time.scm scheme/env/debug.scm scheme/env/inspect.scm scheme/env/disasm.scm
linker-files = scheme/rts/util.scm scheme/alt/fluid.scm scheme/rts/defenum.scm scheme/vm/arch.scm scheme/alt/jar-defrecord.scm scheme/big/general-table.scm scheme/bcomp/mtype.scm scheme/alt/locations.scm scheme/bcomp/binding.scm scheme/bcomp/name.scm scheme/bcomp/transform.scm scheme/bcomp/node.scm scheme/bcomp/schemify.scm scheme/bcomp/var-util.scm scheme/bcomp/primop.scm scheme/alt/template.scm scheme/rts/template.scm scheme/bcomp/ddata.scm scheme/bcomp/thingie.scm scheme/bcomp/stack-check.scm scheme/bcomp/state.scm scheme/bcomp/segment.scm scheme/bcomp/recon.scm scheme/bcomp/comp-exp.scm scheme/bcomp/comp-prim.scm scheme/bcomp/comp.scm scheme/alt/closure.scm scheme/link/data.scm scheme/link/transport.scm scheme/link/write-image.scm scheme/alt/weak.scm scheme/rts/population.scm scheme/bcomp/interface.scm scheme/bcomp/cenv.scm scheme/bcomp/package.scm scheme/bcomp/package-undef.scm scheme/bcomp/syntax.scm scheme/env/debuginfo.scm scheme/big/filename.scm scheme/bcomp/read-form.scm scheme/bcomp/scan-package.scm scheme/bcomp/optimize.scm scheme/bcomp/usual.scm scheme/bcomp/rules.scm scheme/bcomp/comp-package.scm scheme/big/strong.scm scheme/opt/usage.scm scheme/opt/sort.scm scheme/opt/inline.scm scheme/link/reify.scm scheme/link/link.scm scheme/alt/loophole.scm scheme/bcomp/type.scm scheme/alt/low.scm scheme/bcomp/module-language.scm scheme/bcomp/config.scm scheme/opt/analyze.scm scheme/alt/environments.scm scheme/link/loadc.scm scheme/env/flatload.scm

View File

@ -6,6 +6,7 @@
; Define DEFINE-STRUCTURE and friends
(for-each load
'("scheme/bcomp/module-language.scm"
"scheme/alt/dummy-interface.scm"
"scheme/alt/config.scm"
"scheme/env/flatload.scm"))

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1,4 +1,4 @@
; Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees. See file COPYING.
; Copyright (c) 1993-2000 by Richard Kelsey and Jonathan Rees. See file COPYING.
; Link script.
@ -30,7 +30,7 @@
(l '()))
(for-each (lambda (int)
(for-each-declaration
(lambda (name type)
(lambda (name package-name type)
(if (not (assq name l))
(let ((s (eval name env)))
(if (structure? s)

View File

@ -1 +1 @@
53
6.7

2
c/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
sysdep.h
sysdep.h.in

View File

@ -1,4 +1,10 @@
#ifndef TRUE
#define TRUE (0 == 0)
#endif
#ifndef FALSE
#define FALSE (0 == 1)
#endif
#define bool char /* boolean type */

View File

@ -1,5 +1,7 @@
enum event_enum { KEYBOARD_INTERRUPT_EVENT, IO_COMPLETION_EVENT, ALARM_EVENT,
OS_SIGNAL_EVENT, ERROR_EVENT, NO_EVENT };
enum event_enum { KEYBOARD_INTERRUPT_EVENT,
IO_READ_COMPLETION_EVENT, IO_WRITE_COMPLETION_EVENT,
ALARM_EVENT,
OS_SIGNAL_EVENT, ERROR_EVENT, NO_EVENT };
extern bool s48_add_pending_fd(int fd, bool is_input);
extern bool s48_remove_fd(int fd);

View File

@ -127,6 +127,8 @@ s48_value
s48_external_call(s48_value sch_proc, s48_value proc_name,
long nargs, char *char_argv)
{
volatile char *gc_marker; /* volatile to survive longjumps */
char *gc_marker_temp; /* C wants it so */
volatile char *gc_roots_marker; /* volatile to survive longjumps */
volatile s48_value name = proc_name; /* volatile to survive longjumps */
@ -144,7 +146,8 @@ s48_external_call(s48_value sch_proc, s48_value proc_name,
S48_CHECK_VALUE(sch_proc);
S48_CHECK_STRING(name);
gc_roots_marker = s48_set_gc_roots_baseB();
gc_roots_marker = s48_set_gc_roots_baseB(&gc_marker_temp);
gc_marker = gc_marker_temp;
/* fprintf(stderr, "[external_call at depth %d]\n", depth); */
@ -209,7 +212,7 @@ s48_external_call(s48_value sch_proc, s48_value proc_name,
/* Raise an exception if the user neglected to pop off some gc roots. */
if (! s48_release_gc_roots_baseB((char *)gc_roots_marker)) {
if (! s48_release_gc_roots_baseB((char *)gc_roots_marker, (char *)gc_marker)) {
s48_raise_scheme_exception(S48_EXCEPTION_GC_PROTECTION_MISMATCH, 0);
}
@ -242,7 +245,7 @@ s48_external_call(s48_value sch_proc, s48_value proc_name,
depth,
callback_depth());
fprintf(stderr, "[throw unrolling to %ld]\n", gc_roots_marker); */
s48_release_gc_roots_baseB((char *)gc_roots_marker);
s48_release_gc_roots_baseB((char *)gc_roots_marker, (char *)gc_marker);
}
/* Check to see if a thread is waiting to return to the next block down. */
@ -301,7 +304,7 @@ s48_call_scheme(s48_value proc, long nargs, ...)
/* It would be nice to push a list of the arguments, but we have no way
of preserving them across a cons. */
if (nargs < 0 || 10 < nargs) { /* DO NOT INCREASE THIS NUMBER */
if (nargs < 0 || 12 < nargs) { /* DO NOT INCREASE THIS NUMBER */
s48_value sch_nargs = s48_enter_integer(nargs); /* `proc' is protected */
s48_raise_scheme_exception(S48_EXCEPTION_TOO_MANY_ARGUMENTS_IN_CALLBACK,
2, proc, sch_nargs);
@ -473,12 +476,12 @@ s48_raise_scheme_exception(long why, long nargs, ...)
/* Specific exceptions */
void
s48_raise_argtype_error(s48_value value) {
s48_raise_argument_type_error(s48_value value) {
s48_raise_scheme_exception(S48_EXCEPTION_WRONG_TYPE_ARGUMENT, 1, value);
}
void
s48_raise_argnumber_error(s48_value value, s48_value min, s48_value max) {
s48_raise_argument_number_error(s48_value value, s48_value min, s48_value max) {
s48_raise_scheme_exception(S48_EXCEPTION_WRONG_NUMBER_OF_ARGUMENTS,
3, value, min, max);
}
@ -497,10 +500,132 @@ s48_raise_closed_channel_error() {
void
s48_raise_os_error(int the_errno) {
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 2,
s48_enter_fixnum(the_errno),
s48_enter_integer(the_errno),
s48_enter_string(strerror(the_errno)));
}
void
s48_raise_os_error_1(int the_errno, s48_value arg1) {
s48_value sch_errno = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(2);
S48_GC_PROTECT_2 (arg1, sch_errno);
sch_errno = s48_enter_integer(the_errno);
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 3,
sch_errno,
s48_enter_string(strerror(the_errno)),
arg1);
S48_GC_UNPROTECT();
}
void
s48_raise_os_error_2(int the_errno, s48_value arg1, s48_value arg2) {
s48_value sch_errno = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(3);
S48_GC_PROTECT_3 (arg1, arg2, sch_errno);
sch_errno = s48_enter_integer(the_errno);
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 4,
sch_errno,
s48_enter_string(strerror(the_errno)),
arg1, arg2);
S48_GC_UNPROTECT();
}
void
s48_raise_os_error_3(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3) {
s48_value sch_errno = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(4);
S48_GC_PROTECT_4 (arg1, arg2, arg3, sch_errno);
sch_errno = s48_enter_integer(the_errno);
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 5,
sch_errno,
s48_enter_string(strerror(the_errno)),
arg1, arg2, arg3);
S48_GC_UNPROTECT();
}
void
s48_raise_os_error_4(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3, s48_value arg4) {
s48_value sch_errno = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(5);
S48_GC_PROTECT_5 (arg1, arg2, arg3, arg4, sch_errno);
sch_errno = s48_enter_integer(the_errno);
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 6,
sch_errno,
s48_enter_string(strerror(the_errno)),
arg1, arg2, arg3, arg4);
S48_GC_UNPROTECT();
}
void
s48_raise_os_error_5(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3, s48_value arg4, s48_value arg5) {
s48_value sch_errno = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(6);
S48_GC_PROTECT_6 (arg1, arg2, arg3, arg4, arg5, sch_errno);
sch_errno = s48_enter_integer(the_errno);
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 7,
sch_errno,
s48_enter_string(strerror(the_errno)),
arg1, arg2, arg3, arg4, arg5);
S48_GC_UNPROTECT();
}
void
s48_raise_os_error_6(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3, s48_value arg4, s48_value arg5,
s48_value arg6) {
s48_value sch_errno = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(7);
S48_GC_PROTECT_7 (arg1, arg2, arg3, arg4, arg5, arg6, sch_errno);
sch_errno = s48_enter_integer(the_errno);
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 8,
sch_errno,
s48_enter_string(strerror(the_errno)),
arg1, arg2, arg3, arg4, arg5, arg6);
S48_GC_UNPROTECT();
}
void
s48_raise_os_error_7(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3, s48_value arg4, s48_value arg5,
s48_value arg6, s48_value arg7) {
s48_value sch_errno = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(8);
S48_GC_PROTECT_8 (arg1, arg2, arg3, arg4, arg5, arg6, arg7, sch_errno);
sch_errno = s48_enter_integer(the_errno);
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 9,
sch_errno,
s48_enter_string(strerror(the_errno)),
arg1, arg2, arg3, arg4, arg5, arg6, arg7);
S48_GC_UNPROTECT();
}
void
s48_raise_string_os_error(char *reason) {
s48_raise_scheme_exception(S48_EXCEPTION_OS_ERROR, 1,
@ -529,7 +654,7 @@ long
s48_stob_length(s48_value thing, int type)
{
if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
s48_raise_argtype_error(thing);
s48_raise_argument_type_error(thing);
return S48_STOB_DESCRIPTOR_LENGTH(thing);
}
@ -538,7 +663,7 @@ long
s48_stob_byte_length(s48_value thing, int type)
{
if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
s48_raise_argtype_error(thing);
s48_raise_argument_type_error(thing);
if (type == S48_STOBTYPE_STRING)
return S48_STOB_BYTE_LENGTH(thing) - 1;
@ -552,7 +677,7 @@ s48_stob_ref(s48_value thing, int type, long offset)
long length;
if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
s48_raise_argtype_error(thing);
s48_raise_argument_type_error(thing);
length = S48_STOB_DESCRIPTOR_LENGTH(thing);
@ -572,7 +697,7 @@ s48_stob_set(s48_value thing, int type, long offset, s48_value value)
if (!(S48_STOB_P(thing) &&
(S48_STOB_TYPE(thing) == type) &&
!S48_STOB_IMMUTABLEP(thing)))
s48_raise_argtype_error(thing);
s48_raise_argument_type_error(thing);
length = S48_STOB_DESCRIPTOR_LENGTH(thing);
@ -585,12 +710,12 @@ s48_stob_set(s48_value thing, int type, long offset, s48_value value)
}
char
s48_byte_ref(s48_value thing, int type, long offset)
s48_stob_byte_ref(s48_value thing, int type, long offset)
{
long length;
if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
s48_raise_argtype_error(thing);
s48_raise_argument_type_error(thing);
length = (type == S48_STOBTYPE_STRING) ?
S48_STOB_BYTE_LENGTH(thing) - 1 :
@ -605,12 +730,12 @@ s48_byte_ref(s48_value thing, int type, long offset)
}
void
s48_byte_set(s48_value thing, int type, long offset, char value)
s48_stob_byte_set(s48_value thing, int type, long offset, char value)
{
long length;
if (!(S48_STOB_P(thing) && (S48_STOB_TYPE(thing) == type)))
s48_raise_argtype_error(thing);
s48_raise_argument_type_error(thing);
length = (type == S48_STOBTYPE_STRING) ?
S48_STOB_BYTE_LENGTH(thing) - 1 :
@ -645,7 +770,7 @@ s48_value
s48_enter_fixnum(long value)
{
if (value < S48_MIN_FIXNUM_VALUE || S48_MAX_FIXNUM_VALUE < value)
s48_raise_argtype_error(s48_enter_integer(value));
s48_raise_argument_type_error(s48_enter_integer(value));
return S48_UNSAFE_ENTER_FIXNUM(value);
}
@ -654,7 +779,7 @@ long
s48_extract_fixnum(s48_value value)
{
if (! S48_FIXNUM_P(value))
s48_raise_argtype_error(value);
s48_raise_argument_type_error(value);
return S48_UNSAFE_EXTRACT_FIXNUM(value);
}
@ -689,6 +814,22 @@ s48_enter_integer(long value)
}
}
s48_value
s48_enter_unsigned_integer(unsigned long value)
{
if (value <= S48_MAX_FIXNUM_VALUE)
return S48_UNSAFE_ENTER_FIXNUM(value);
else {
S48_SHARED_BINDING_CHECK(long_to_bignum_binding);
return s48_call_scheme(S48_SHARED_BINDING_REF(long_to_bignum_binding),
3,
S48_FALSE, /* this is ok */
S48_UNSAFE_ENTER_FIXNUM(value >> 16),
S48_UNSAFE_ENTER_FIXNUM(value & 0xFFFF));
}
}
/*
* If we have a fixnum we just extract it. Bignums require a call back into
* Scheme 48. (BIGNUM-TO-LONG n) returns a vector containing the sign and the
@ -717,7 +858,7 @@ s48_extract_integer(s48_value value)
S48_GC_UNPROTECT();
if (stuff == S48_FALSE)
s48_raise_argtype_error(value);
s48_raise_argument_type_error(value);
/* The first VECTOR_REF does the type checking for the rest. */
{
@ -728,7 +869,7 @@ s48_extract_integer(s48_value value)
if ((! S48_FIXNUM_P(boxed_high)) ||
high > (pos_p ? 0x7FFF : 0x8000))
s48_raise_argtype_error(value);
s48_raise_argument_type_error(value);
{
long magnitude = ((- high) << 16) - low;
@ -738,6 +879,49 @@ s48_extract_integer(s48_value value)
}
}
unsigned long
s48_extract_unsigned_integer(s48_value value)
{
long temp;
if (S48_FIXNUM_P(value)){
temp = S48_UNSAFE_EXTRACT_FIXNUM(value);
if (temp < 0)
s48_raise_argument_type_error(value);
else return (unsigned long) temp;
}
else {
s48_value stuff;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(value);
S48_SHARED_BINDING_CHECK(bignum_to_long_binding);
stuff = s48_call_scheme(S48_SHARED_BINDING_REF(bignum_to_long_binding),
1,
value);
S48_GC_UNPROTECT();
if (stuff == S48_FALSE)
s48_raise_argument_type_error(value);
/* The first VECTOR_REF does the type checking for the rest. */
{
long low = S48_UNSAFE_EXTRACT_FIXNUM(S48_VECTOR_REF(stuff, 2));
s48_value boxed_high = S48_UNSAFE_VECTOR_REF(stuff, 1);
long high = S48_UNSAFE_EXTRACT_FIXNUM(boxed_high);
int pos_p = S48_EXTRACT_BOOLEAN(S48_UNSAFE_VECTOR_REF(stuff, 0));
if ((!pos_p) ||
(! S48_FIXNUM_P(boxed_high)) ||
(high > 0xFFFF))
s48_raise_argument_type_error(value);
else return ((((unsigned long) high) << 16) + low);
}
}
}
/*
* Doubles and characters are straightforward.
*/
@ -757,7 +941,7 @@ double
s48_extract_double(s48_value s48_double)
{
if (! S48_DOUBLE_P(s48_double))
s48_raise_argtype_error(s48_double);
s48_raise_argument_type_error(s48_double);
return S48_UNSAFE_EXTRACT_DOUBLE(s48_double);
}
@ -777,7 +961,7 @@ unsigned char
s48_extract_char(s48_value a_char)
{
if (! S48_CHAR_P(a_char))
s48_raise_argtype_error(a_char);
s48_raise_argument_type_error(a_char);
return S48_UNSAFE_EXTRACT_CHAR(a_char);
}
@ -812,6 +996,164 @@ s48_cons(s48_value v1, s48_value v2)
return obj;
}
s48_value
s48_list_1(s48_value v1)
{
return (s48_cons (v1, S48_NULL));
}
s48_value
s48_list_2(s48_value v1, s48_value v2)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_1 (v2);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_list_3(s48_value v1, s48_value v2, s48_value v3)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_2 (v2, v3);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_list_4(s48_value v1, s48_value v2, s48_value v3, s48_value v4)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_3 (v2, v3, v4);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_list_5(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_4 (v2, v3, v4, v5);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_list_6(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
s48_value v6)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_5 (v2, v3, v4, v5, v6);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_list_7(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
s48_value v6, s48_value v7)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_6 (v2, v3, v4, v5, v6, v7);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_list_8(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
s48_value v6, s48_value v7, s48_value v8)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_7 (v2, v3, v4, v5, v6, v7, v8);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_list_9(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
s48_value v6, s48_value v7, s48_value v8, s48_value v9)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_8 (v2, v3, v4, v5, v6, v7, v8, v9);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_list_10(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
s48_value v6, s48_value v7, s48_value v8, s48_value v9, s48_value v10)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_9 (v2, v3, v4, v5, v6, v7, v8, v9, v10);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_list_11(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
s48_value v6, s48_value v7, s48_value v8, s48_value v9, s48_value v10,
s48_value v11)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_10 (v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_list_12(s48_value v1, s48_value v2, s48_value v3, s48_value v4, s48_value v5,
s48_value v6, s48_value v7, s48_value v8, s48_value v9, s48_value v10,
s48_value v11, s48_value v12)
{
s48_value list = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(v1);
list = s48_list_11 (v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
list = s48_cons (v1, list);
S48_GC_UNPROTECT();
return list;
}
s48_value
s48_make_weak_pointer(s48_value value)
{
@ -831,7 +1173,7 @@ s48_value
s48_enter_substring(char *str, int length)
{
s48_value obj = s48_allocate_stob(S48_STOBTYPE_STRING, length + 1);
strncpy(S48_UNSAFE_EXTRACT_STRING(obj), str, length);
memcpy(S48_UNSAFE_EXTRACT_STRING(obj), str, length);
*(S48_UNSAFE_EXTRACT_STRING(obj) + length) = '\0';
return obj;
}
@ -878,9 +1220,31 @@ s48_make_vector(int length, s48_value init)
}
s48_value
s48_make_byte_vector(int length)
s48_enter_byte_vector(char *bvec, int length)
{
return s48_allocate_stob(S48_STOBTYPE_BYTE_VECTOR, length);
s48_value obj = s48_allocate_stob(S48_STOBTYPE_BYTE_VECTOR, length);
memcpy(S48_UNSAFE_EXTRACT_BYTE_VECTOR(obj), bvec, length);
return obj;
}
char *
s48_extract_byte_vector(s48_value bvec)
{
S48_CHECK_BYTE_VECTOR(bvec);
return S48_UNSAFE_EXTRACT_BYTE_VECTOR(bvec);
}
s48_value
s48_make_byte_vector(int length, int init)
{
int i;
s48_value obj = s48_allocate_stob(S48_STOBTYPE_BYTE_VECTOR, length);
for (i = 0; i < length; i++)
S48_BYTE_VECTOR_SET(obj, i, init);
return obj;
}
s48_value
@ -929,7 +1293,7 @@ s48_check_record_type(s48_value record, s48_value type_binding)
if ((! S48_RECORD_P(record)) ||
(S48_UNSAFE_SHARED_BINDING_REF(type_binding) !=
S48_UNSAFE_RECORD_REF(record, -1)))
s48_raise_argtype_error(record);
s48_raise_argument_type_error(record);
}
long
@ -945,3 +1309,54 @@ s48_length(s48_value list)
return S48_UNSAFE_ENTER_FIXNUM(i);
}
/*
**
** Support for libscsh.a: add external initializers without the Makefile
**
*/
struct simple_list{
void (*init)(); /* pointer to init-function */
struct simple_list* next;
};
struct simple_list* additional_inits = 0;
/*
* This function is part of EXTERNAL_INITIALIZERS in the scsh Makefile.
* It calls the init-functions in additional_inits.
*/
void s48_init_additional_inits(){
struct simple_list* ptr = additional_inits;
struct simple_list* free_me;
while (ptr != 0){
ptr->init();
free_me = ptr;
ptr = ptr->next;
free (free_me);
}
}
/*
* Actual API function: argument is an init-function. You have to
* ensure, that all s48_add_external_inits are called before you call
* s48_main.
*/
int s48_add_external_init(void (*init)()){
struct simple_list *new_list;
new_list = (struct simple_list *) malloc(sizeof (struct simple_list));
if (new_list == 0) return 0;
new_list->init = init;
new_list->next = additional_inits;
additional_inits = new_list;
return 1;
}

View File

@ -1,11 +1,7 @@
/*
* This include file is for systems which do not have dynamic loading.
*/
#if ! defined(HAVE_DLOPEN)
extern void *dlopen(char *filename, int flags);
extern char *dlerror(void);
extern void *dlsym(void *lib, char *name);
extern int dlclose(void *lib);
#endif

View File

@ -5,12 +5,18 @@
* (whose name is pointed to by object_file).
*/
#include "sysdep.h"
#include <stdlib.h>
#include <nlist.h>
#ifdef USCORE
#include <string.h>
#endif
#if defined(HAVE_DLOPEN)
#include <dlfcn.h>
#else
#include "../fake/dlfcn.h"
#endif
#if ! defined(NLIST_HAS_N_NAME)
#define n_name n_un.n_name
#endif
@ -64,7 +70,7 @@ dlsym(void *lib, char *name)
lasterror = "Bad library pointer passed to dlsym()";
return (NULL);
}
if (object_file == NULL) {
if (s48_object_file == NULL) {
lasterror = "I don't know the name of my executable";
return (NULL);
}
@ -87,7 +93,7 @@ dlsym(void *lib, char *name)
names[0].n_value = 0; /* for Linux */
names[0].n_type = 0; /* for Linux */
names[1].n_name = NULL;
status = nlist(object_file, names);
status = nlist(s48_object_file, names);
#ifdef USCORE
if (tmp != buff)
free((void *)tmp);

View File

@ -7,6 +7,8 @@ extern int ps_open_fd(char *in_filename, bool is_input, long *status);
extern int ps_close_fd(long fd_as_long);
extern bool ps_check_fd(long fd_as_long, bool is_read, long *status);
extern long ps_read_fd(long fd_as_long, char *buf_as_long, long max, bool waitp,
bool *eofp, bool *pending, long *status);

114
c/init.c Normal file
View File

@ -0,0 +1,114 @@
/* Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees.
See file COPYING. */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "scheme48vm.h"
#include "scheme48heap.h"
extern void s48_sysdep_init(void);
extern void s48_initialize_external_modules(void);
/* JMG: s48_object_file is obsolete according to s48 manual */
char *s48_object_file; /* specified via a command line argument */
char *s48_reloc_file; /* dynamic loading will set this */
void *heap, *stack;
int s48_main (long heap_size, long stack_size,
char *image_name, int argc, char** argv)
{
int ret = internal_s48_main(heap_size, stack_size, "libscsh", "libscsh",
image_name, argc, argv);
free(heap);
free(stack);
return ret;
}
int
internal_s48_main(long heap_size, long stack_size,
char* object_file, char *image_name, int argc, char** argv)
{
long return_value;
long required_heap_size;
int warn_undefined_imported_bindings_p = 0;
#if defined(STATIC_AREAS)
extern long static_entry;
extern long static_symbol_table;
extern long static_imported_binding_table, static_exported_binding_table;
extern long p_count, *p_areas[], p_sizes[];
extern long i_count, *i_areas[], i_sizes[];
#endif
s48_object_file = object_file;
s48_reloc_file = NULL;
s48_sysdep_init();
s48_heap_init();
s48_init();
if (image_name == NULL)
required_heap_size = 0;
else {
/* check_image_header returns number of bytes; required_heap_size
is number of cells. */
required_heap_size =
s48_check_image_header((unsigned char *)image_name) >> 2;
if (-1 == required_heap_size) {
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
return 1; }
}
/* two semi-spaces, plus we want some room to maneuver */
if (heap_size < 4 * required_heap_size) {
fprintf(stderr, "heap size %ld is too small, using %ld\n",
heap_size, 4 * required_heap_size);
heap_size = 4 * required_heap_size; }
heap = (void *) malloc(heap_size * sizeof(long));
stack = (void *) malloc(stack_size * sizeof(long));
if (!heap || !stack) {
fprintf(stderr, "system is out of memory\n");
return 1; }
s48_initialize_heap((long)heap, heap_size);
#if defined(STATIC_AREAS)
if (image_name == NULL) {
s48_register_static_areas(p_count, p_areas, p_sizes,
i_count, i_areas, i_sizes);
s48_set_image_valuesB(static_entry,
static_symbol_table,
static_imported_binding_table,
static_exported_binding_table);
} else if (s48_read_image() == -1) {
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
return 1; }
#else
if (s48_read_image() == -1) {
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
return 1; }
#endif
s48_initialize_vm(stack, stack_size);
s48_initialize_external_modules();
if (warn_undefined_imported_bindings_p)
s48_warn_about_undefined_imported_bindings();
return_value = s48_call_startup_procedure(argv, argc);
if (s48_reloc_file != NULL)
if (0 != unlink(s48_reloc_file))
fprintf(stderr, "unable to delete file %s\n", s48_reloc_file);
return(return_value);
}

163
c/main.c
View File

@ -4,12 +4,13 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "scheme48vm.h"
#include "scheme48heap.h"
/* I bumped this up from 1.5 Mcell because the debugging info put us over
** the top. -Olin
*/
#if !defined(DEFAULT_HEAP_SIZE)
/* 1.5 megacell = 6 megabytes (3 meg per semispace) */
#define DEFAULT_HEAP_SIZE 1500000L
/* 5 megacell = 20 megabytes (10 meg per semispace) */
#define DEFAULT_HEAP_SIZE 5000000L
#endif
#if !defined(DEFAULT_STACK_SIZE)
@ -23,29 +24,34 @@
/* DEFAULT_IMAGE_NAME should be defined using the -D switch to cc. */
#if !defined(DEFAULT_IMAGE_NAME)
#define DEFAULT_IMAGE_NAME "scheme48.image"
#define DEFAULT_IMAGE_NAME "scsh.image"
#endif
#endif /* STATIC_AREAS */
extern void s48_sysdep_init(void);
extern void s48_initialize_external_modules(void);
char *s48_object_file; /* specified via a command line argument */
char *s48_reloc_file; /* dynamic loading will set this */
char ** process_args(char **argv,
long *heap_size,
long *stack_size,
char **object_file,
char **image_name);
extern int
internal_s48_main(long heap_size, long stack_size,
char* object_file, char* image_name,
int argc, char** argv);
int
main(argc, argv)
int argc; char **argv;
{
char **argp; /* JMG */
char *image_name = DEFAULT_IMAGE_NAME;
long heap_size = DEFAULT_HEAP_SIZE; /* in numbers of cells */
long stack_size = DEFAULT_STACK_SIZE; /* in numbers of cells */
int errors = 0;
long return_value;
void *heap, *stack;
long required_heap_size;
int warn_undefined_imported_bindings_p = 1;
char *object_file = NULL; /* specified via a command line argument */
char *prog_name;
#if defined(STATIC_AREAS)
extern long static_entry;
@ -56,126 +62,13 @@ main(argc, argv)
#endif
long vm_argc = 0;
char *me = *argv; /* Save program name. */
prog_name = *argv++;/* Save program name. */
s48_object_file = s48_reloc_file = NULL;
argv++; argc--; /* Skip program name. */
for (; argc > 0; argc--, argv++)
if (argv[0][0] == '-')
switch (argv[0][1]) {
case 'h':
argc--; argv++;
if (argc == 0) { errors++; break; }
heap_size = atoi(*argv);
if (heap_size <= 0) errors++;
break;
case 's':
argc--; argv++;
if (argc == 0) { errors++; break; }
stack_size = atoi(*argv);
if (stack_size <= 0) errors++;
break;
case 'i':
argc--; argv++;
if (argc == 0) { errors++; break; }
image_name = *argv;
break;
case 'a':
argc--;
vm_argc = argc; /* remaining args are passed to the VM */
argc = 0;
break;
case 'o':
argc--; argv++;
if (argc == 0) { errors++; break; }
s48_object_file = *argv;
break;
case 'u':
argc--; argv++;
warn_undefined_imported_bindings_p = 0;
break;
default:
fprintf(stderr, "Invalid argument: %s\n", *argv);
errors++;
}
else
if (argv[0][0] != '\0') {
fprintf(stderr, "Invalid argument: %s\n", *argv);
errors++; }
if (errors != 0) {
fprintf(stderr,
"Usage: %s [options] [-a arguments]\n\
Options: -h <total heap size in words>\n\
-s <stack buffer size in words>\n\
-i <image file name>\n\
-o <object file name>\n\
-u [don't warn on unbound external identifiers]",
me);
return 1;
}
s48_sysdep_init();
s48_heap_init();
s48_init();
if (image_name == NULL)
required_heap_size = 0;
else {
/* check_image_header returns number of bytes; required_heap_size
is number of cells. */
required_heap_size =
s48_check_image_header((unsigned char *)image_name) >> 2;
if (-1 == required_heap_size) {
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
return 1; }
}
/* two semi-spaces, plus we want some room to maneuver */
if (heap_size < 4 * required_heap_size) {
fprintf(stderr, "heap size %ld is too small, using %ld\n",
heap_size, 4 * required_heap_size);
heap_size = 4 * required_heap_size; }
heap = (void *) malloc(heap_size * sizeof(long));
stack = (void *) malloc(stack_size * sizeof(long));
if (!heap || !stack) {
fprintf(stderr, "system is out of memory\n");
return 1; }
s48_initialize_heap((long)heap, heap_size);
#if defined(STATIC_AREAS)
if (image_name == NULL) {
s48_register_static_areas(p_count, p_areas, p_sizes,
i_count, i_areas, i_sizes);
s48_set_image_valuesB(static_entry,
static_symbol_table,
static_imported_binding_table,
static_exported_binding_table);
} else if (s48_read_image() == -1) {
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
return 1; }
#else
if (s48_read_image() == -1) {
fprintf(stderr, "Image file \"%s\" is unusable.\n", image_name);
return 1; }
#endif
s48_initialize_vm(stack, stack_size);
s48_initialize_external_modules();
if (warn_undefined_imported_bindings_p)
s48_warn_about_undefined_imported_bindings();
return_value = s48_call_startup_procedure(argv, vm_argc);
if (s48_reloc_file != NULL)
if (0 != unlink(s48_reloc_file))
fprintf(stderr, "unable to delete file %s\n", s48_reloc_file);
return(return_value);
argv=process_args(argv,
&heap_size, &stack_size,
&object_file, &image_name);
argv--;
argv[0] = prog_name;
for(argc=0, argp=argv; *argp; argc++, argp++); /* Recompute argc. */
return internal_s48_main(heap_size, stack_size, object_file, image_name, argc, argv);
}

View File

@ -13,9 +13,16 @@ typedef long s48_value;
#define NO_ERRORS 0 /* errno value */
extern int s48_main (long heap_size, long stack_size,
char *image_name, int argc, char** argv);
extern int s48_add_external_init(void (*init)());
/* Misc stuff */
#define S48_EQ(v1, v2) ((v1) == (v2))
#define S48_EQ_P(v1, v2) ((v1) == (v2))
/* Superceded name for the above definition, retained for compatibility. */
#define S48_EQ(v1, v2) ((v1) == (v2))
#define S48_MAX_FIXNUM_VALUE ((1 << 29) - 1)
#define S48_MIN_FIXNUM_VALUE (-1 << 29)
@ -39,15 +46,43 @@ extern s48_value s48_enter_fixnum(long);
extern long s48_extract_fixnum(s48_value);
extern s48_value s48_enter_integer(long);
extern long s48_extract_integer(s48_value);
extern s48_value s48_enter_unsigned_integer(unsigned long);
extern unsigned long s48_extract_unsigned_integer(s48_value);
extern s48_value s48_enter_double(double);
extern double s48_extract_double(s48_value);
extern s48_value s48_cons(s48_value, s48_value);
extern s48_value s48_list_1(s48_value);
extern s48_value s48_list_2(s48_value, s48_value);
extern s48_value s48_list_3(s48_value, s48_value, s48_value);
extern s48_value s48_list_4(s48_value, s48_value, s48_value, s48_value);
extern s48_value s48_list_5(s48_value, s48_value, s48_value, s48_value,
s48_value);
extern s48_value s48_list_6(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value);
extern s48_value s48_list_7(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value);
extern s48_value s48_list_8(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value);
extern s48_value s48_list_9(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value,
s48_value);
extern s48_value s48_list_10(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value);
extern s48_value s48_list_11(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value);
extern s48_value s48_list_12(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value);
extern s48_value s48_enter_string(char *);
extern char * s48_extract_string(s48_value);
extern s48_value s48_enter_substring(char *, int);
extern s48_value s48_make_string(int, char);
extern s48_value s48_make_vector(int, s48_value);
extern s48_value s48_make_byte_vector(int);
extern s48_value s48_enter_byte_vector(char *, int);
extern char * s48_extract_byte_vector(s48_value);
extern s48_value s48_make_byte_vector(int, int);
extern s48_value s48_make_record(s48_value);
extern s48_value s48_make_weak_pointer(s48_value);
extern void s48_check_record_type(s48_value, s48_value);
@ -64,7 +99,7 @@ extern s48_value s48_call_scheme(s48_value proc, long nargs, ...);
#define S48_EXPORT_FUNCTION(p) (s48_define_exported_binding(#p, s48_enter_pointer(p)))
#define S48_MAKE_VALUE(type) (s48_make_byte_vector(sizeof(type)))
#define S48_MAKE_VALUE(type) (s48_make_byte_vector(sizeof(type),0))
extern void * s48_value_pointer(s48_value);
#define S48_EXTRACT_VALUE_POINTER(x, type) ((type *) s48_value_pointer(x))
@ -177,28 +212,46 @@ extern void * s48_value_pointer(s48_value);
/* Exceptions */
extern void s48_raise_scheme_exception(long type, long nargs, ...);
extern void s48_raise_argtype_error(s48_value value);
extern void s48_raise_argnumber_error(s48_value value,
s48_value min, s48_value max);
extern void s48_raise_argument_type_error(s48_value value);
extern void s48_raise_argument_number_error(s48_value value,
s48_value min,
s48_value max);
extern void s48_raise_range_error(s48_value value,
s48_value min, s48_value max);
extern void s48_raise_closed_channel_error();
extern void s48_raise_os_error(int the_errno);
extern void s48_raise_os_error_1(int the_errno, s48_value arg1);
extern void s48_raise_os_error_2(int the_errno, s48_value arg1, s48_value arg2);
extern void s48_raise_os_error_3(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3);
extern void s48_raise_os_error_4(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3, s48_value arg4);
extern void s48_raise_os_error_5(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3, s48_value arg4, s48_value arg5);
extern void s48_raise_os_error_6(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3, s48_value arg4, s48_value arg5,
s48_value arg6);
extern void s48_raise_string_os_error(char *reason);
extern void s48_raise_out_of_memory_error();
/* Type checking */
#define S48_CHECK_PAIR(v) do { if (!S48_PAIR_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_FIXNUM(v) do { if (!S48_FIXNUM_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_STRING(v) do { if (!S48_STRING_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_CHANNEL(v) do { if (!S48_CHANNEL_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_RECORD(v) do { if (!S48_RECORD_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_VALUE(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_EXPORT_BINDING(v) do { if (!S48_EXPORT_BINDING_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_PAIR(v) do { if (!S48_PAIR_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_FIXNUM(v) do { if (!S48_FIXNUM_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_STRING(v) do { if (!S48_STRING_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_BYTE_VECTOR(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_CHANNEL(v) do { if (!S48_CHANNEL_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_RECORD(v) do { if (!S48_RECORD_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_VALUE(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_EXPORT_BINDING(v) do { if (!S48_EXPORT_BINDING_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_VALUE_P(v) (S48_BYTE_VECTOR_P(v))
#define S48_TRUE_P(v) ((v) == S48_TRUE)
#define S48_FALSE_P(v) ((v) == S48_FALSE)
#define S48_EXTRACT_BOOLEAN(v) ((v) != S48_FALSE)
#define S48_ENTER_BOOLEAN(v) ((v) ? S48_TRUE : S48_FALSE)
extern void s48_check_record_type(s48_value record, s48_value type_binding);
#define S48_SHARED_BINDING_CHECK(binding) \
@ -207,6 +260,7 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
S48_SHARED_BINDING_NAME(binding)); \
} while(0)
#define S48_FIXNUM_TAG 0
#define S48_FIXNUM_P(x) (((long)(x) & 3L) == S48_FIXNUM_TAG)
#define S48_IMMEDIATE_TAG 1
@ -228,9 +282,6 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
#define S48_EOF (S48_MISC_IMMEDIATE(5))
#define S48_NULL (S48_MISC_IMMEDIATE(6))
#define S48_ENTER_BOOLEAN(n) ((n) ? S48_TRUE : S48_FALSE)
#define S48_EXTRACT_BOOLEAN(x) ((x) != S48_FALSE)
#define S48_UNSAFE_ENTER_CHAR(c) (S48_CHAR | ((c) << 8))
#define S48_UNSAFE_EXTRACT_CHAR(x) ((x) >> 8)
#define S48_CHAR_P(x) ((((long) (x)) & 0xff) == S48_CHAR)
@ -238,8 +289,8 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
#define S48_ADDRESS_AFTER_HEADER(x, type) ((type *)((x) - S48_STOB_TAG))
#define S48_STOB_REF(x, i) (S48_ADDRESS_AFTER_HEADER(x, s48_value)[i])
#define S48_STOB_BYTE_REF(x, i) (((char *)S48_ADDRESS_AFTER_HEADER(x, s48_value))[i])
#define S48_STOB_SET(x, i, v) do { s48_value __stob_set_x = (x); long __stob_set_i = (i); s48_value __stob_set_v = (v); if (S48_STOB_IMMUTABLEP(__stob_set_x)) s48_raise_argtype_error(__stob_set_x); else { S48_WRITE_BARRIER((__stob_set_x), (char *) (&S48_STOB_REF((__stob_set_x), (__stob_set_i))),(__stob_set_v)); *(&S48_STOB_REF((__stob_set_x), (__stob_set_i))) = (__stob_set_v); } } while (0)
#define S48_STOB_BYTE_SET(x, i, v) do { char __stob_set_x = (x); long __stob_set_i = (i); s48_value __stob_set_v = (v); if (S48_STOB_IMMUTABLEP(__stob_set_x)) s48_raise_argtype_error(__stob_set_x); else *(&S48_STOB_BYTE_REF((__stob_set_x), (__stob_set_i))) = (__stob_set_v); } while (0)
#define S48_STOB_SET(x, i, v) do { s48_value __stob_set_x = (x); long __stob_set_i = (i); s48_value __stob_set_v = (v); if (S48_STOB_IMMUTABLEP(__stob_set_x)) s48_raise_argument_type_error(__stob_set_x); else { S48_WRITE_BARRIER((__stob_set_x), (char *) (&S48_STOB_REF((__stob_set_x), (__stob_set_i))),(__stob_set_v)); *(&S48_STOB_REF((__stob_set_x), (__stob_set_i))) = (__stob_set_v); } } while (0)
#define S48_STOB_BYTE_SET(x, i, v) do { s48_value __stob_set_x = (x); long __stob_set_i = (i); char __stob_set_v = (v); if (S48_STOB_IMMUTABLEP(__stob_set_x)) s48_raise_argument_type_error(__stob_set_x); else *(&S48_STOB_BYTE_REF((__stob_set_x), (__stob_set_i))) = (__stob_set_v); } while (0)
#define S48_STOB_TYPE(x) ((S48_STOB_HEADER(x)>>2)&31)
#define S48_STOB_HEADER(x) (S48_STOB_REF((x),-1))
#define S48_STOB_ADDRESS(x) (&(S48_STOB_HEADER(x)))
@ -258,46 +309,48 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
#define S48_CLOSURE_P(x) (s48_stob_has_type(x, 3))
#define S48_STOBTYPE_LOCATION 4
#define S48_LOCATION_P(x) (s48_stob_has_type(x, 4))
#define S48_STOBTYPE_CHANNEL 5
#define S48_CHANNEL_P(x) (s48_stob_has_type(x, 5))
#define S48_STOBTYPE_PORT 6
#define S48_PORT_P(x) (s48_stob_has_type(x, 6))
#define S48_STOBTYPE_RATNUM 7
#define S48_RATNUM_P(x) (s48_stob_has_type(x, 7))
#define S48_STOBTYPE_RECORD 8
#define S48_RECORD_P(x) (s48_stob_has_type(x, 8))
#define S48_STOBTYPE_CONTINUATION 9
#define S48_CONTINUATION_P(x) (s48_stob_has_type(x, 9))
#define S48_STOBTYPE_EXTENDED_NUMBER 10
#define S48_EXTENDED_NUMBER_P(x) (s48_stob_has_type(x, 10))
#define S48_STOBTYPE_TEMPLATE 11
#define S48_TEMPLATE_P(x) (s48_stob_has_type(x, 11))
#define S48_STOBTYPE_WEAK_POINTER 12
#define S48_WEAK_POINTER_P(x) (s48_stob_has_type(x, 12))
#define S48_STOBTYPE_SHARED_BINDING 13
#define S48_SHARED_BINDING_P(x) (s48_stob_has_type(x, 13))
#define S48_STOBTYPE_UNUSED_D_HEADER1 14
#define S48_UNUSED_D_HEADER1_P(x) (s48_stob_has_type(x, 14))
#define S48_STOBTYPE_UNUSED_D_HEADER2 15
#define S48_UNUSED_D_HEADER2_P(x) (s48_stob_has_type(x, 15))
#define S48_STOBTYPE_STRING 16
#define S48_STRING_P(x) (s48_stob_has_type(x, 16))
#define S48_STOBTYPE_BYTE_VECTOR 17
#define S48_BYTE_VECTOR_P(x) (s48_stob_has_type(x, 17))
#define S48_STOBTYPE_DOUBLE 18
#define S48_DOUBLE_P(x) (s48_stob_has_type(x, 18))
#define S48_STOBTYPE_BIGNUM 19
#define S48_BIGNUM_P(x) (s48_stob_has_type(x, 19))
#define S48_STOBTYPE_CELL 5
#define S48_CELL_P(x) (s48_stob_has_type(x, 5))
#define S48_STOBTYPE_CHANNEL 6
#define S48_CHANNEL_P(x) (s48_stob_has_type(x, 6))
#define S48_STOBTYPE_PORT 7
#define S48_PORT_P(x) (s48_stob_has_type(x, 7))
#define S48_STOBTYPE_RATNUM 8
#define S48_RATNUM_P(x) (s48_stob_has_type(x, 8))
#define S48_STOBTYPE_RECORD 9
#define S48_RECORD_P(x) (s48_stob_has_type(x, 9))
#define S48_STOBTYPE_CONTINUATION 10
#define S48_CONTINUATION_P(x) (s48_stob_has_type(x, 10))
#define S48_STOBTYPE_EXTENDED_NUMBER 11
#define S48_EXTENDED_NUMBER_P(x) (s48_stob_has_type(x, 11))
#define S48_STOBTYPE_TEMPLATE 12
#define S48_TEMPLATE_P(x) (s48_stob_has_type(x, 12))
#define S48_STOBTYPE_WEAK_POINTER 13
#define S48_WEAK_POINTER_P(x) (s48_stob_has_type(x, 13))
#define S48_STOBTYPE_SHARED_BINDING 14
#define S48_SHARED_BINDING_P(x) (s48_stob_has_type(x, 14))
#define S48_STOBTYPE_UNUSED_D_HEADER1 15
#define S48_UNUSED_D_HEADER1_P(x) (s48_stob_has_type(x, 15))
#define S48_STOBTYPE_UNUSED_D_HEADER2 16
#define S48_UNUSED_D_HEADER2_P(x) (s48_stob_has_type(x, 16))
#define S48_STOBTYPE_STRING 17
#define S48_STRING_P(x) (s48_stob_has_type(x, 17))
#define S48_STOBTYPE_BYTE_VECTOR 18
#define S48_BYTE_VECTOR_P(x) (s48_stob_has_type(x, 18))
#define S48_STOBTYPE_DOUBLE 19
#define S48_DOUBLE_P(x) (s48_stob_has_type(x, 19))
#define S48_STOBTYPE_BIGNUM 20
#define S48_BIGNUM_P(x) (s48_stob_has_type(x, 20))
#define S48_CAR_OFFSET 0
#define S48_CAR(x) (s48_stob_ref((x), S48_STOBTYPE_PAIR, 0))
#define S48_UNSAFE_CAR(x) (S48_STOB_REF((x), 0))
#define S48_SET_CAR(x, v) (s48_stob_ref((x), S48_STOBTYPE_PAIR, 0, (v)))
#define S48_SET_CAR(x, v) (s48_stob_set((x), S48_STOBTYPE_PAIR, 0, (v)))
#define S48_UNSAFE_SET_CAR(x, v) S48_STOB_SET((x), 0, (v))
#define S48_CDR_OFFSET 1
#define S48_CDR(x) (s48_stob_ref((x), S48_STOBTYPE_PAIR, 1))
#define S48_UNSAFE_CDR(x) (S48_STOB_REF((x), 1))
#define S48_SET_CDR(x, v) (s48_stob_ref((x), S48_STOBTYPE_PAIR, 1, (v)))
#define S48_SET_CDR(x, v) (s48_stob_set((x), S48_STOBTYPE_PAIR, 1, (v)))
#define S48_UNSAFE_SET_CDR(x, v) S48_STOB_SET((x), 1, (v))
#define S48_SYMBOL_TO_STRING_OFFSET 0
#define S48_SYMBOL_TO_STRING(x) (s48_stob_ref((x), S48_STOBTYPE_SYMBOL, 0))
@ -305,13 +358,18 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
#define S48_LOCATION_ID_OFFSET 0
#define S48_LOCATION_ID(x) (s48_stob_ref((x), S48_STOBTYPE_LOCATION, 0))
#define S48_UNSAFE_LOCATION_ID(x) (S48_STOB_REF((x), 0))
#define S48_SET_LOCATION_ID(x, v) (s48_stob_ref((x), S48_STOBTYPE_LOCATION, 0, (v)))
#define S48_SET_LOCATION_ID(x, v) (s48_stob_set((x), S48_STOBTYPE_LOCATION, 0, (v)))
#define S48_UNSAFE_SET_LOCATION_ID(x, v) S48_STOB_SET((x), 0, (v))
#define S48_CONTENTS_OFFSET 1
#define S48_CONTENTS(x) (s48_stob_ref((x), S48_STOBTYPE_LOCATION, 1))
#define S48_UNSAFE_CONTENTS(x) (S48_STOB_REF((x), 1))
#define S48_SET_CONTENTS(x, v) (s48_stob_ref((x), S48_STOBTYPE_LOCATION, 1, (v)))
#define S48_SET_CONTENTS(x, v) (s48_stob_set((x), S48_STOBTYPE_LOCATION, 1, (v)))
#define S48_UNSAFE_SET_CONTENTS(x, v) S48_STOB_SET((x), 1, (v))
#define S48_CELL_REF_OFFSET 0
#define S48_CELL_REF(x) (s48_stob_ref((x), S48_STOBTYPE_CELL, 0))
#define S48_UNSAFE_CELL_REF(x) (S48_STOB_REF((x), 0))
#define S48_CELL_SET(x, v) (s48_stob_set((x), S48_STOBTYPE_CELL, 0, (v)))
#define S48_UNSAFE_CELL_SET(x, v) S48_STOB_SET((x), 0, (v))
#define S48_CLOSURE_TEMPLATE_OFFSET 0
#define S48_CLOSURE_TEMPLATE(x) (s48_stob_ref((x), S48_STOBTYPE_CLOSURE, 0))
#define S48_UNSAFE_CLOSURE_TEMPLATE(x) (S48_STOB_REF((x), 0))
@ -330,50 +388,52 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
#define S48_SHARED_BINDING_REF_OFFSET 2
#define S48_SHARED_BINDING_REF(x) (s48_stob_ref((x), S48_STOBTYPE_SHARED_BINDING, 2))
#define S48_UNSAFE_SHARED_BINDING_REF(x) (S48_STOB_REF((x), 2))
#define S48_SHARED_BINDING_SET(x, v) (s48_stob_ref((x), S48_STOBTYPE_SHARED_BINDING, 2, (v)))
#define S48_SHARED_BINDING_SET(x, v) (s48_stob_set((x), S48_STOBTYPE_SHARED_BINDING, 2, (v)))
#define S48_UNSAFE_SHARED_BINDING_SET(x, v) S48_STOB_SET((x), 2, (v))
#define S48_PORT_HANDLER_OFFSET 0
#define S48_PORT_HANDLER(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 0))
#define S48_UNSAFE_PORT_HANDLER(x) (S48_STOB_REF((x), 0))
#define S48_SET_PORT_HANDLER(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 0, (v)))
#define S48_UNSAFE_SET_PORT_HANDLER(x, v) S48_STOB_SET((x), 0, (v))
#define S48_PORT_STATUS_OFFSET 1
#define S48_PORT_STATUS(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 1))
#define S48_UNSAFE_PORT_STATUS(x) (S48_STOB_REF((x), 1))
#define S48_SET_PORT_STATUS(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 1, (v)))
#define S48_SET_PORT_STATUS(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 1, (v)))
#define S48_UNSAFE_SET_PORT_STATUS(x, v) S48_STOB_SET((x), 1, (v))
#define S48_PORT_LOCK_OFFSET 2
#define S48_PORT_LOCK(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 2))
#define S48_UNSAFE_PORT_LOCK(x) (S48_STOB_REF((x), 2))
#define S48_SET_PORT_LOCK(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 2, (v)))
#define S48_SET_PORT_LOCK(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 2, (v)))
#define S48_UNSAFE_SET_PORT_LOCK(x, v) S48_STOB_SET((x), 2, (v))
#define S48_PORT_LOCKEDP_OFFSET 3
#define S48_PORT_LOCKEDP(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 3))
#define S48_UNSAFE_PORT_LOCKEDP(x) (S48_STOB_REF((x), 3))
#define S48_SET_PORT_LOCKEDP(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 3, (v)))
#define S48_SET_PORT_LOCKEDP(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 3, (v)))
#define S48_UNSAFE_SET_PORT_LOCKEDP(x, v) S48_STOB_SET((x), 3, (v))
#define S48_PORT_DATA_OFFSET 4
#define S48_PORT_DATA(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 4))
#define S48_UNSAFE_PORT_DATA(x) (S48_STOB_REF((x), 4))
#define S48_SET_PORT_DATA(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 4, (v)))
#define S48_SET_PORT_DATA(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 4, (v)))
#define S48_UNSAFE_SET_PORT_DATA(x, v) S48_STOB_SET((x), 4, (v))
#define S48_PORT_BUFFER_OFFSET 5
#define S48_PORT_BUFFER(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 5))
#define S48_UNSAFE_PORT_BUFFER(x) (S48_STOB_REF((x), 5))
#define S48_SET_PORT_BUFFER(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 5, (v)))
#define S48_SET_PORT_BUFFER(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 5, (v)))
#define S48_UNSAFE_SET_PORT_BUFFER(x, v) S48_STOB_SET((x), 5, (v))
#define S48_PORT_INDEX_OFFSET 6
#define S48_PORT_INDEX(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 6))
#define S48_UNSAFE_PORT_INDEX(x) (S48_STOB_REF((x), 6))
#define S48_SET_PORT_INDEX(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 6, (v)))
#define S48_SET_PORT_INDEX(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 6, (v)))
#define S48_UNSAFE_SET_PORT_INDEX(x, v) S48_STOB_SET((x), 6, (v))
#define S48_PORT_LIMIT_OFFSET 7
#define S48_PORT_LIMIT(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 7))
#define S48_UNSAFE_PORT_LIMIT(x) (S48_STOB_REF((x), 7))
#define S48_SET_PORT_LIMIT(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 7, (v)))
#define S48_SET_PORT_LIMIT(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 7, (v)))
#define S48_UNSAFE_SET_PORT_LIMIT(x, v) S48_STOB_SET((x), 7, (v))
#define S48_PORT_PENDING_EOFP_OFFSET 8
#define S48_PORT_PENDING_EOFP(x) (s48_stob_ref((x), S48_STOBTYPE_PORT, 8))
#define S48_UNSAFE_PORT_PENDING_EOFP(x) (S48_STOB_REF((x), 8))
#define S48_SET_PORT_PENDING_EOFP(x, v) (s48_stob_ref((x), S48_STOBTYPE_PORT, 8, (v)))
#define S48_SET_PORT_PENDING_EOFP(x, v) (s48_stob_set((x), S48_STOBTYPE_PORT, 8, (v)))
#define S48_UNSAFE_SET_PORT_PENDING_EOFP(x, v) S48_STOB_SET((x), 8, (v))
#define S48_CHANNEL_STATUS_OFFSET 0
#define S48_CHANNEL_STATUS(x) (s48_stob_ref((x), S48_STOBTYPE_CHANNEL, 0))
@ -397,21 +457,22 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
#define S48_RECORD_SET(x, i, v) (s48_stob_set((x), S48_STOBTYPE_RECORD, (i) + 1, (v)))
#define S48_UNSAFE_RECORD_REF(x, i) (S48_STOB_REF((x), (i) + 1))
#define S48_UNSAFE_RECORD_SET(x, i, v) S48_STOB_SET((x), (i) + 1, (v))
#define S48_RECORD_TYPE(x) (s48_stob_ref((x), S48_STOBTYPE_RECORD))
#define S48_RECORD_TYPE(x) (s48_stob_ref((x), S48_STOBTYPE_RECORD, 0))
#define S48_UNSAFE_RECORD_TYPE(x) (STOB_REF((x), 0))
#define S48_BYTE_VECTOR_LENGTH(x) (s48_stob_byte_length((x), S48_STOBTYPE_BYTE_VECTOR))
#define S48_BYTE_VECTOR_REF(x, i) (s48_stob_byte_ref((x), S48_STOBTYPE_BYTE_VECTOR, (i)))
#define S48_BYTE_VECTOR_SET(x, i, v) (s48_stob_byte_set((x), S48_STOBTYPE_BYTE_VECTOR, (i), (v)))
#define S48_UNSAFE_BYTE_VECTOR_REF(x, i) (S48_STOB_BYTE_REF((x), (i)))
#define S48_UNSAFE_BYTE_VECTOR_SET(x, i, v) S48_BYTE_STOB_SET((x), (i), (v))
#define S48_UNSAFE_BYTE_VECTOR_SET(x, i, v) S48_STOB_BYTE_SET((x), (i), (v))
#define S48_STRING_LENGTH(x) (s48_stob_byte_length((x), S48_STOBTYPE_STRING))
#define S48_STRING_REF(x, i) (s48_stob_byte_ref((x), S48_STOBTYPE_STRING, (i)))
#define S48_STRING_SET(x, i, v) (s48_stob_byte_set((x), S48_STOBTYPE_STRING, (i), (v)))
#define S48_UNSAFE_STRING_REF(x, i) (S48_STOB_BYTE_REF((x), (i)))
#define S48_UNSAFE_STRING_SET(x, i, v) S48_BYTE_STOB_SET((x), (i), (v))
#define S48_UNSAFE_STRING_SET(x, i, v) S48_STOB_BYTE_SET((x), (i), (v))
#define S48_UNSAFE_BYTE_VECTOR_LENGTH(x) (S48_STOB_BYTE_LENGTH(x))
#define S48_UNSAFE_STRING_LENGTH(x) (S48_STOB_BYTE_LENGTH(x) - 1)
#define S48_UNSAFE_EXTRACT_STRING(x) (S48_ADDRESS_AFTER_HEADER((x), char))
#define S48_UNSAFE_EXTRACT_BYTE_VECTOR(x) (S48_ADDRESS_AFTER_HEADER((x), char))
#define S48_EXTRACT_EXTERNAL_OBJECT(x, type) ((type *)(S48_ADDRESS_AFTER_HEADER(x, long)+1))
#define S48_RECORD_TYPE_RESUMER(x) S48_RECORD_REF((x), 0)

View File

@ -7,9 +7,16 @@ typedef long s48_value;
#define NO_ERRORS 0 /* errno value */
extern int s48_main (long heap_size, long stack_size,
char *image_name, int argc, char** argv);
extern int s48_add_external_init(void (*init)());
/* Misc stuff */
#define S48_EQ(v1, v2) ((v1) == (v2))
#define S48_EQ_P(v1, v2) ((v1) == (v2))
/* Superceded name for the above definition, retained for compatibility. */
#define S48_EQ(v1, v2) ((v1) == (v2))
#define S48_MAX_FIXNUM_VALUE ((1 << 29) - 1)
#define S48_MIN_FIXNUM_VALUE (-1 << 29)
@ -33,15 +40,43 @@ extern s48_value s48_enter_fixnum(long);
extern long s48_extract_fixnum(s48_value);
extern s48_value s48_enter_integer(long);
extern long s48_extract_integer(s48_value);
extern s48_value s48_enter_unsigned_integer(unsigned long);
extern unsigned long s48_extract_unsigned_integer(s48_value);
extern s48_value s48_enter_double(double);
extern double s48_extract_double(s48_value);
extern s48_value s48_cons(s48_value, s48_value);
extern s48_value s48_list_1(s48_value);
extern s48_value s48_list_2(s48_value, s48_value);
extern s48_value s48_list_3(s48_value, s48_value, s48_value);
extern s48_value s48_list_4(s48_value, s48_value, s48_value, s48_value);
extern s48_value s48_list_5(s48_value, s48_value, s48_value, s48_value,
s48_value);
extern s48_value s48_list_6(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value);
extern s48_value s48_list_7(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value);
extern s48_value s48_list_8(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value);
extern s48_value s48_list_9(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value,
s48_value);
extern s48_value s48_list_10(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value);
extern s48_value s48_list_11(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value);
extern s48_value s48_list_12(s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value,
s48_value, s48_value, s48_value, s48_value);
extern s48_value s48_enter_string(char *);
extern char * s48_extract_string(s48_value);
extern s48_value s48_enter_substring(char *, int);
extern s48_value s48_make_string(int, char);
extern s48_value s48_make_vector(int, s48_value);
extern s48_value s48_make_byte_vector(int);
extern s48_value s48_enter_byte_vector(char *, int);
extern char * s48_extract_byte_vector(s48_value);
extern s48_value s48_make_byte_vector(int, int);
extern s48_value s48_make_record(s48_value);
extern s48_value s48_make_weak_pointer(s48_value);
extern void s48_check_record_type(s48_value, s48_value);
@ -58,7 +93,7 @@ extern s48_value s48_call_scheme(s48_value proc, long nargs, ...);
#define S48_EXPORT_FUNCTION(p) (s48_define_exported_binding(#p, s48_enter_pointer(p)))
#define S48_MAKE_VALUE(type) (s48_make_byte_vector(sizeof(type)))
#define S48_MAKE_VALUE(type) (s48_make_byte_vector(sizeof(type),0))
extern void * s48_value_pointer(s48_value);
#define S48_EXTRACT_VALUE_POINTER(x, type) ((type *) s48_value_pointer(x))
@ -171,28 +206,46 @@ extern void * s48_value_pointer(s48_value);
/* Exceptions */
extern void s48_raise_scheme_exception(long type, long nargs, ...);
extern void s48_raise_argtype_error(s48_value value);
extern void s48_raise_argnumber_error(s48_value value,
s48_value min, s48_value max);
extern void s48_raise_argument_type_error(s48_value value);
extern void s48_raise_argument_number_error(s48_value value,
s48_value min,
s48_value max);
extern void s48_raise_range_error(s48_value value,
s48_value min, s48_value max);
extern void s48_raise_closed_channel_error();
extern void s48_raise_os_error(int the_errno);
extern void s48_raise_os_error_1(int the_errno, s48_value arg1);
extern void s48_raise_os_error_2(int the_errno, s48_value arg1, s48_value arg2);
extern void s48_raise_os_error_3(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3);
extern void s48_raise_os_error_4(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3, s48_value arg4);
extern void s48_raise_os_error_5(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3, s48_value arg4, s48_value arg5);
extern void s48_raise_os_error_6(int the_errno, s48_value arg1, s48_value arg2,
s48_value arg3, s48_value arg4, s48_value arg5,
s48_value arg6);
extern void s48_raise_string_os_error(char *reason);
extern void s48_raise_out_of_memory_error();
/* Type checking */
#define S48_CHECK_PAIR(v) do { if (!S48_PAIR_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_FIXNUM(v) do { if (!S48_FIXNUM_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_STRING(v) do { if (!S48_STRING_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_CHANNEL(v) do { if (!S48_CHANNEL_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_RECORD(v) do { if (!S48_RECORD_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_VALUE(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_EXPORT_BINDING(v) do { if (!S48_EXPORT_BINDING_P(v)) s48_raise_argtype_error(v); } while (0)
#define S48_CHECK_PAIR(v) do { if (!S48_PAIR_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_FIXNUM(v) do { if (!S48_FIXNUM_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_STRING(v) do { if (!S48_STRING_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_BYTE_VECTOR(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_CHANNEL(v) do { if (!S48_CHANNEL_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_RECORD(v) do { if (!S48_RECORD_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_VALUE(v) do { if (!S48_BYTE_VECTOR_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_CHECK_EXPORT_BINDING(v) do { if (!S48_EXPORT_BINDING_P(v)) s48_raise_argument_type_error(v); } while (0)
#define S48_VALUE_P(v) (S48_BYTE_VECTOR_P(v))
#define S48_TRUE_P(v) ((v) == S48_TRUE)
#define S48_FALSE_P(v) ((v) == S48_FALSE)
#define S48_EXTRACT_BOOLEAN(v) ((v) != S48_FALSE)
#define S48_ENTER_BOOLEAN(v) ((v) ? S48_TRUE : S48_FALSE)
extern void s48_check_record_type(s48_value record, s48_value type_binding);
#define S48_SHARED_BINDING_CHECK(binding) \
@ -200,3 +253,4 @@ extern void s48_check_record_type(s48_value record, s48_value type_binding);
s48_raise_scheme_exception(S48_EXCEPTION_UNBOUND_EXTERNAL_NAME, 1, \
S48_SHARED_BINDING_NAME(binding)); \
} while(0)

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h> /* memcpy, strlen */
#include "c-mods.h"
#include "write-barrier.h"

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@ extern char s48_Spending_eventsPS;
extern char s48_Spending_interruptPS;
extern void s48_disable_interruptsB(void);
extern void s48_enable_interruptsB(void);
extern void s48_set_os_signal(s48_value type, s48_value argument);
extern void s48_set_os_signals(s48_value list);
/* imported and exported bindings */
extern void s48_define_exported_binding(char *, s48_value);
@ -56,6 +56,6 @@ extern s48_value s48_add_channel(s48_value, s48_value, long);
extern s48_value s48_allocate_stob(long type, long size);
extern void s48_push_gc_rootsB(char *, long);
extern char s48_pop_gc_rootsB(void);
extern char * s48_set_gc_roots_baseB(void);
extern char s48_release_gc_roots_baseB(char *);
extern char * s48_set_gc_roots_baseB(char **);
extern char s48_release_gc_roots_baseB(char *, char*);
extern void s48_register_gc_rootB(char *marker);

240
c/srfi/srfi-27.c Normal file
View File

@ -0,0 +1,240 @@
/* 54-BIT (double) IMPLEMENTATION IN C OF THE "MRG32K3A" GENERATOR
===============================================================
Sebastian.Egner@philips.com, Mar-2002, in ANSI-C and Scheme 48 0.57
This code is a C-implementation of Pierre L'Ecuyer's MRG32k3a generator.
The code uses (double)-arithmetics, assuming that it covers the range
{-2^53..2^53-1} exactly (!). The code of the generator is based on the
L'Ecuyer's own implementation of the generator. Please refer to the
file 'mrg32k3a.scm' for more information about the method.
The method provides the following functions via the C/Scheme
interface of Scheme 48 0.57 to 'mrg32k3a-b.scm':
s48_value mrg32k3a_pack_state1(s48_value state);
s48_value mrg32k3a_unpack_state1(s48_value state);
s48_value mrg32k3a_random_range();
s48_value mrg32k3a_random_integer(s48_value state, s48_value range);
s48_value mrg32k3a_random_real(s48_value state);
As Scheme48 FIXNUMs cannot cover the range {0..m1-1}, we break up
all values x in the state into x0+x1*w, where w = 2^16 = 65536.
The procedures in Scheme correct for that.
compile this file with:
gcc -c -I $SCHEME48 mrg32k3a-b.c
history of this file:
SE, 18-Mar-2002: initial version
SE, 22-Mar-2002: interface changed
SE, 25-Mar-2002: tested with Scheme 48 0.57 in c/srfi-27
SE, 27-Mar-2002: cleaned
SE, 13-May-2002: bug found by Shiro Kawai removed
*/
#include "scheme48.h" /* $SCHEME48/c/scheme48.h */
#include <sys/time.h>
#ifndef NULL
#define NULL 0
#endif
/* maximum value for random_integer: min(S48_MAX_FIXNUM_VALUE, m1) */
#define m_max (((long)1 << 29) - 1)
/* The Generator
=============
*/
/* moduli of the components */
#define m1 4294967087.0
#define m2 4294944443.0
/* representation of the state in C */
typedef struct {
double
x10, x11, x12,
x20, x21, x22;
} state_t;
/* recursion coefficients of the components */
#define a12 1403580.0
#define a13n 810728.0
#define a21 527612.0
#define a23n 1370589.0
/* normalization factor 1/(m1 + 1) */
#define norm 2.328306549295728e-10
/* the actual generator */
static double mrg32k3a(state_t *s) { /* (double), in {0..m1-1} */
double x10, x20, y;
long k10, k20;
/* #define debug 1 */
#if defined(debug)
printf(
"state = {%g %g %g %g %g %g};\n",
s->x10, s->x11, s->x12,
s->x20, s->x21, s->x22
);
#endif
/* component 1 */
x10 = a12*(s->x11) - a13n*(s->x12);
k10 = x10 / m1;
x10 -= k10 * m1;
if (x10 < 0.0)
x10 += m1;
s->x12 = s->x11;
s->x11 = s->x10;
s->x10 = x10;
/* component 2 */
x20 = a21*(s->x20) - a23n*(s->x22);
k20 = x20 / m2;
x20 -= k20 * m2;
if (x20 < 0.0)
x20 += m2;
s->x22 = s->x21;
s->x21 = s->x20;
s->x20 = x20;
/* combination of component */
y = x10 - x20;
if (y < 0.0)
y += m1;
return y;
}
/* Exported Interface
==================
*/
s48_value mrg32k3a_pack_state1(s48_value state) {
s48_value result;
state_t s;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(state); /* s48_extract_integer may GC */
#define REF(i) (double)s48_extract_integer(S48_VECTOR_REF(state, (long)(i)))
/* copy the numbers from state into s */
s.x10 = REF( 0) + 65536.0 * REF( 1);
s.x11 = REF( 2) + 65536.0 * REF( 3);
s.x12 = REF( 4) + 65536.0 * REF( 5);
s.x20 = REF( 6) + 65536.0 * REF( 7);
s.x21 = REF( 8) + 65536.0 * REF( 9);
s.x22 = REF(10) + 65536.0 * REF(11);
#undef REF
S48_GC_UNPROTECT();
/* box s into a Scheme object */
result = S48_MAKE_VALUE(state_t);
S48_SET_VALUE(result, state_t, s);
return result;
}
s48_value mrg32k3a_unpack_state1(s48_value state) {
s48_value result = S48_UNSPECIFIC;
state_t s;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(result);
/* unbox s from the Scheme object */
s = S48_EXTRACT_VALUE(state, state_t);
/* make and fill a Scheme vector with the numbers */
result = s48_make_vector((long)12, S48_FALSE);
#define SET(i, x) { \
long x1 = (long)((x) / 65536.0); \
long x0 = (long)((x) - 65536.0 * (double)x1); \
S48_VECTOR_SET(result, (long)(i+0), s48_enter_integer(x0)); \
S48_VECTOR_SET(result, (long)(i+1), s48_enter_integer(x1)); }
SET( 0, s.x10);
SET( 2, s.x11);
SET( 4, s.x12);
SET( 6, s.x20);
SET( 8, s.x21);
SET(10, s.x22);
#undef SET
S48_GC_UNPROTECT();
return result;
}
s48_value mrg32k3a_random_range(void) {
return s48_enter_fixnum(m_max);
}
s48_value mrg32k3a_random_integer(s48_value state, s48_value range) {
long result;
state_t s;
long n;
double x, q, qn, xq;
s = S48_EXTRACT_VALUE(state, state_t);
n = s48_extract_integer(range);
if (!( ((long)1 <= n) && (n <= m_max) ))
s48_raise_range_error(n, (long)1, m_max);
/* generate result in {0..n-1} using the rejection method */
q = (double)( (unsigned long)(m1 / (double)n) );
qn = q * n;
do {
x = mrg32k3a(&s);
} while (x >= qn);
xq = x / q;
/* check the range */
if (!( (0.0 <= xq) && (xq < (double)m_max) ))
s48_raise_range_error((long)xq, (long)0, m_max);
/* return result */
result = (long)xq;
S48_SET_VALUE(state, state_t, s);
return s48_enter_fixnum(result);
}
s48_value mrg32k3a_random_real(s48_value state) {
state_t s;
double x;
s = S48_EXTRACT_VALUE(state, state_t);
x = (mrg32k3a(&s) + 1.0) * norm;
S48_SET_VALUE(state, state_t, s);
return s48_enter_double(x);
}
/* Kludge for scsh */
static s48_value current_time(void){
struct timeval tv;
gettimeofday(&tv, NULL);
return s48_enter_integer(tv.tv_sec);
}
/* Exporting the C values to Scheme
================================
*/
void s48_init_srfi_27(void) {
S48_EXPORT_FUNCTION(mrg32k3a_pack_state1);
S48_EXPORT_FUNCTION(mrg32k3a_unpack_state1);
S48_EXPORT_FUNCTION(mrg32k3a_random_range);
S48_EXPORT_FUNCTION(mrg32k3a_random_integer);
S48_EXPORT_FUNCTION(mrg32k3a_random_real);
S48_EXPORT_FUNCTION(current_time);
}

View File

@ -1,99 +0,0 @@
/* c/sysdep.h.in. Generated automatically from configure.in by autoheader. */
/* Define to empty if the keyword does not work. */
#undef const
/* Define if you need to in order for stat and other things to work. */
#undef _POSIX_SOURCE
/* Define as the return type of signal handlers (int or void). */
#undef RETSIGTYPE
/*
* HAVE_SIGACTION is defined iff sigaction() is available.
*/
#undef HAVE_SIGACTION
/*
* HAVE_STRERROR is defined iff the standard libraries provide strerror().
*/
#undef HAVE_STRERROR
/*
* NLIST_HAS_N_NAME is defined iff a struct nlist has an n_name member.
* If it doesn't then we assume it has an n_un member which, in turn,
* has an n_name member.
*/
#undef NLIST_HAS_N_NAME
/*
* USCORE is defined iff C externals are prepended with an underscore.
*/
#undef USCORE
/* Define if you have the chroot function. */
#undef HAVE_CHROOT
/* Define if you have the dlopen function. */
#undef HAVE_DLOPEN
/* Define if you have the ftime function. */
#undef HAVE_FTIME
/* Define if you have the gettimeofday function. */
#undef HAVE_GETTIMEOFDAY
/* Define if you have the nlist function. */
#undef HAVE_NLIST
/* Define if you have the select function. */
#undef HAVE_SELECT
/* Define if you have the setitimer function. */
#undef HAVE_SETITIMER
/* Define if you have the sigaction function. */
#undef HAVE_SIGACTION
/* Define if you have the socket function. */
#undef HAVE_SOCKET
/* Define if you have the <libgen.h> header file. */
#undef HAVE_LIBGEN_H
/* Define if you have the <posix/time.h> header file. */
#undef HAVE_POSIX_TIME_H
/* Define if you have the <sys/select.h> header file. */
#undef HAVE_SYS_SELECT_H
/* Define if you have the <sys/timeb.h> header file. */
#undef HAVE_SYS_TIMEB_H
/* Define if you have the dl library (-ldl). */
#undef HAVE_LIBDL
/* Define if you have the elf library (-lelf). */
#undef HAVE_LIBELF
/* Define if you have the gen library (-lgen). */
#undef HAVE_LIBGEN
/* Define if you have the m library (-lm). */
#undef HAVE_LIBM
/* Define if you have the mld library (-lmld). */
#undef HAVE_LIBMLD
/* Define if you have the nsl library (-lnsl). */
#undef HAVE_LIBNSL
/* Define if you have the socket library (-lsocket). */
#undef HAVE_LIBSOCKET
/* Define if you have the sun library (-lsun). */
#undef HAVE_LIBSUN
#include "fake/sigact.h"
#include "fake/strerror.h"
#include "fake/sys-select.h"

View File

@ -7,8 +7,12 @@
#include <unistd.h>
#include "sysdep.h"
#include "scheme48.h"
#include <dlfcn.h>
#if defined(HAVE_DLOPEN)
#include <dlfcn.h>
#else
#include "../fake/dlfcn.h"
#endif
#if defined(RTLD_NOW)
#define DLOPEN_MODE RTLD_NOW

View File

@ -1,6 +1,7 @@
/* Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees.
See file COPYING. */
#include "sysdep.h"
#include <signal.h> /* for sigaction() (POSIX.1) */
#include <stdlib.h>
#include <unistd.h>
@ -9,20 +10,34 @@
#include <sys/time.h>
#include <sys/times.h>
#include <errno.h> /* for errno, (POSIX?/ANSI) */
#include "sysdep.h"
#include "c-mods.h"
#include "scheme48vm.h"
#include "event.h"
#include "../scsh/scsh_aux.h"
#include "../scsh/signals1.h"
/* turning interrupts and I/O readiness into events */
sigset_t full_sigset;
#define block_interrupts()
#define allow_interrupts()
#define block_interrupts(){sigprocmask (SIG_BLOCK, &full_sigset, 0);}
#define allow_interrupts(){sigprocmask (SIG_UNBLOCK, &full_sigset, 0);}
static void when_keyboard_interrupt();
static void when_alarm_interrupt();
static void when_sigpipe_interrupt();
/* JMG:*/
static void when_scsh_interrupt();
/* JMG: for scsh */
#define INTERRUPT_QUEUE_LENGTH 32
static int interrupt_queue [INTERRUPT_QUEUE_LENGTH];
static int next_interrupt = 0;
static int s48_os_signal_pending(void);
static bool s48_os_signal_happend(void);
bool s48_setcatcher(int signum, void (*catcher)(int));
void s48_start_alarm_interrupts(void);
@ -38,6 +53,47 @@ s48_sysdep_init(void)
errno);
exit(1);
}
sigfillset (&full_sigset);
/* JMG: for scsh */
s48_setcatcher(SIGCHLD, when_scsh_interrupt);
s48_setcatcher(SIGCONT, when_scsh_interrupt);
s48_setcatcher(SIGHUP, when_scsh_interrupt);
s48_setcatcher(SIGQUIT, when_scsh_interrupt);
s48_setcatcher(SIGTERM, when_scsh_interrupt);
s48_setcatcher(SIGTSTP, when_scsh_interrupt);
s48_setcatcher(SIGUSR1, when_scsh_interrupt);
s48_setcatcher(SIGUSR2, when_scsh_interrupt);
#ifdef SIGINFO
s48_setcatcher(SIGINFO, when_scsh_interrupt);
#endif
#ifdef SIGIO
s48_setcatcher(SIGIO, when_scsh_interrupt);
#endif
#if defined SIGPOLL && ((defined SIGIO && SIGPOLL != SIGIO) || \
!defined SIGIO)
s48_setcatcher(SIGPOLL, when_scsh_interrupt);
#endif
#ifdef SIGPROF
s48_setcatcher(SIGPROF, when_scsh_interrupt);
#endif
#ifdef SIGPWR
s48_setcatcher(SIGPWR, when_scsh_interrupt);
#endif
#ifdef SIGVTALRM
s48_setcatcher(SIGVTALRM, when_scsh_interrupt);
#endif
#ifdef SIGWINCH
s48_setcatcher(SIGWINCH, when_scsh_interrupt);
#endif
#ifdef SIGXCPU
s48_setcatcher(SIGXCPU, when_scsh_interrupt);
#endif
#ifdef SIGXFSZ
s48_setcatcher(SIGXFSZ, when_scsh_interrupt);
#endif
s48_start_alarm_interrupts();
}
@ -51,15 +107,21 @@ s48_setcatcher(int signum, void (*catcher)(int))
{
struct sigaction sa;
if (sigaction(signum, (struct sigaction *)NULL, &sa) != 0)
return (FALSE);
if (sa.sa_handler == SIG_IGN)
return (TRUE);
if (sigaction(signum, (struct sigaction *)NULL, &sa) != 0){
fprintf(stderr, "Failed to get sigaction for signal %d\n", signum);
exit(1);
}
/* JMG: what's the point of not setting the handler in this case?
if (sa.sa_handler == SIG_IGN)
return (TRUE);*/
sa.sa_handler = catcher;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(signum, &sa, (struct sigaction *)NULL) != 0)
return (FALSE);
if (sigaction(signum, &sa, (struct sigaction *)NULL) != 0){
fprintf(stderr, "Failed to define handler for signal %d\n", signum);
exit(1);
}
return (TRUE);
}
@ -106,6 +168,8 @@ when_alarm_interrupt(int ign)
return;
}
#define USEC_PER_POLL (1000000 / POLLS_PER_SECOND)
/* delta is in ticks, 0 cancels current alarm */
@ -222,7 +286,7 @@ s48_stop_alarm_interrupts(void)
* (queue-ready-ports)
* (set! *poll-time* (+ *time* *poll-interval*))))
* (cond ((not (queue-empty? ready-ports))
* (values (enum event-type i/o-completion)
* (values (enum event-type i/o-{read/write}-completion)
* (dequeue! ready-ports)))
* ((>= *current_time* *alarm-time*)
* (set! *alarm-time* max-integer)
@ -237,9 +301,20 @@ s48_stop_alarm_interrupts(void)
* (values (enum event-type no-event) #f))))))
*/
static bool there_are_ready_ports(void);
static int next_ready_port(void);
static int queue_ready_ports(bool wait, long seconds, long ticks);
#define FD_QUIESCENT 0 /* idle */
#define FD_READY 1 /* I/O ready to be performed */
#define FD_PENDING 2 /* waiting */
typedef struct fd_struct {
int fd, /* file descriptor */
status; /* one of the FD_* constants */
bool is_input; /* iff input */
struct fd_struct *next; /* next on same queue */
} fd_struct;
static bool there_are_ready_ports(void);
static fd_struct *next_ready_fd_struct(void);
static int queue_ready_ports(bool wait, long seconds, long ticks);
int
s48_get_next_event(long *ready_fd, long *status)
@ -249,6 +324,8 @@ s48_get_next_event(long *ready_fd, long *status)
*/
int io_poll_status;
fd_struct *f;
/*
fprintf(stderr, "[poll at %d (waiting for %d)]\n", s48_current_time, alarm_time);
*/
@ -269,21 +346,25 @@ s48_get_next_event(long *ready_fd, long *status)
}
}
if (there_are_ready_ports()) {
*ready_fd = next_ready_port();
f = next_ready_fd_struct();
*ready_fd = f->fd;
*status = 0; /* chars read or written */
/* fprintf(stderr, "[i/o completion]\n"); */
return (IO_COMPLETION_EVENT);
if (f->is_input)
return (IO_READ_COMPLETION_EVENT);
else
return (IO_WRITE_COMPLETION_EVENT);
}
if (alarm_time != -1 && s48_current_time >= alarm_time) {
alarm_time = -1;
/* fprintf(stderr, "[alarm]\n"); */
return (ALARM_EVENT);
}
/*
block_interrupts();
/* JMG: scsh should handle this */
if (s48_os_signal_pending())
return (OS_SIGNAL_EVENT);
*/
block_interrupts();
if ((keyboard_interrupt_count == 0)
&& (alarm_time == -1 || s48_current_time < alarm_time)
&& (poll_time == -1 || s48_current_time < poll_time))
@ -299,17 +380,6 @@ s48_get_next_event(long *ready_fd, long *status)
* the pending ports and move any that are ready onto the other queue and
* signal an event.
*/
#define FD_QUIESCENT 0 /* idle */
#define FD_READY 1 /* I/O ready to be performed */
#define FD_PENDING 2 /* waiting */
typedef struct fd_struct {
int fd, /* file descriptor */
status; /* one of the FD_* constants */
bool is_input; /* iff input */
struct fd_struct *next; /* next on same queue */
} fd_struct;
/*
* A queue of fd_structs is empty iff the first field is NULL. In
@ -394,14 +464,14 @@ there_are_ready_ports(void)
}
static int
next_ready_port(void)
static fd_struct *
next_ready_fd_struct(void)
{
fd_struct *p;
p = rmque(&ready.first, &ready);
p->status = FD_QUIESCENT;
return (p->fd);
return (p);
}
@ -508,6 +578,8 @@ s48_wait_for_event(long max_wait, bool is_minutes)
}
if (keyboard_interrupt_count > 0)
status = NO_ERRORS;
else if (s48_os_signal_happend ())
status = NO_ERRORS;
else {
status = queue_ready_ports(TRUE, seconds, ticks);
if (there_are_ready_ports())
@ -552,8 +624,9 @@ queue_ready_ports(bool wait, long seconds, long ticks)
}
tvp = &tv;
if (wait)
if (seconds == -1)
if (seconds == -1){
tvp = NULL;
}
else {
tv.tv_sec = seconds;
tv.tv_usec = ticks * (1000000 / TICKS_PER_SECOND);
@ -561,6 +634,9 @@ queue_ready_ports(bool wait, long seconds, long ticks)
else
timerclear(&tv);
while(TRUE) {
if ((keyboard_interrupt_count > 0) || s48_os_signal_happend ())
return NO_ERRORS;
/* time gap */
left = select(limfd, &reads, &writes, &alls, tvp);
if (left > 0) {
fdpp = &pending.first;
@ -587,3 +663,81 @@ queue_ready_ports(bool wait, long seconds, long ticks)
return errno;
}
}
/*
* Adds `signum' to the queue of received signals.
*/
static void
queue_interrupt(int signum)
{
if (next_interrupt == INTERRUPT_QUEUE_LENGTH){
perror("Interrupt queue overflow -- report to Scheme 48 maintainers.");
exit(-1);
}
interrupt_queue[next_interrupt] = signum;
next_interrupt++;
}
/* JMG: for scsh */
static void when_scsh_interrupt(int signo)
{
queue_interrupt(sig2int[signo]);
NOTE_EVENT;
return;
}
/*
* This procedure is called periodically by the VM .
*
* s48_set_os_signal() is a VM procedure. The two arguments are the type
* of interrupt and one other value which can be used to return whatever
* associated information is desired. The two values, along with the
* current enabled-interrupts mask, are passed to the handler for os-signal
* interrupts.
*
* A handler can be installed by doing
(set-interrupt-handler! (enum interrupt os-signal)
(lambda (type arg enabled-interrupts)
(display type)
(newline)
(display arg)
(newline)
(display enabled-interrupts)
(newline)))
* The handler is called with all interrupts disabled. They are
* reenabled when the handler returns (or if done by hand).
*/
/*
* Returns TRUE if there is a signal to be delivered up to Scheme.
* Needs no be called with interrupts blocked.
*/
int
s48_os_signal_pending(void) {
int i;
s48_value interrupt_list = S48_NULL;
block_interrupts();
if (next_interrupt == 0) {
allow_interrupts();
return FALSE; }
else {
/* turn the queue into a scheme list and preserve the order */
for (i = next_interrupt; i > 0 ; i--)
interrupt_list = s48_cons (s48_enter_fixnum (interrupt_queue [i - 1]),
interrupt_list);
s48_set_os_signals(interrupt_list);
next_interrupt = 0;
allow_interrupts();
return TRUE; }
}
bool
s48_os_signal_happend(void) {
return (next_interrupt != 0);
}

View File

@ -1,6 +1,7 @@
/* Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees.
See file COPYING. */
#include "sysdep.h"
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
@ -8,7 +9,6 @@
#include <fcntl.h>
#include <sys/time.h>
#include <errno.h> /* for errno, (POSIX?/ANSI) */
#include "sysdep.h"
#include "c-mods.h"
#include "scheme48vm.h"
#include "event.h"
@ -82,6 +82,45 @@ ps_close_fd(long fd_as_long)
}
}
bool ps_check_fd(long fd_as_long, bool is_read, long *status)
{
int fd = (int)fd_as_long;
int ready;
struct timeval timeout;
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
timerclear(&timeout);
*status = NO_ERRORS;
while(TRUE) {
ready = select(fd + 1,
is_read ? &fds : NULL,
is_read ? NULL : &fds,
&fds,
&timeout);
if (ready == 0)
return FALSE;
else if (ready == 1)
return TRUE;
else if (errno != EINTR) {
*status = errno;
return FALSE; } }
}
/*
* Return TRUE if successful, and FALSE otherwise.
*/
bool
ps_add_pending_fd(long fd_as_long, bool is_input)
{
return s48_add_pending_fd((int) fd_as_long, is_input);
}
long
ps_read_fd(long fd_as_long, char *buffer, long max, bool waitp,
bool *eofp, bool *pending, long *status)
@ -172,7 +211,7 @@ long
ps_abort_fd_op(long fd_as_long)
{
int fd = (int)fd_as_long;
fprintf(stderr, "aborting %d\n", fd);
if (!s48_remove_fd(fd))
fprintf(stderr, "Error: ps_abort_fd_op, no pending operation on fd %d\n",
fd);

View File

@ -146,26 +146,6 @@ ps_write_char(char ch, FILE *port)
return 0; }
}
long
ps_write_integer(long n, FILE *port)
{
int status;
static long write_integer(unsigned long n, FILE *port);
if (n == 0) {
WRITE_CHAR('0', port, status);
return status; }
else if (n > 0)
return write_integer(n, port);
else {
WRITE_CHAR('-', port, status);
if (status == 0)
return write_integer(- n, port);
else
return status; }
}
static long
write_integer(unsigned long n, FILE *port)
{
@ -182,6 +162,24 @@ write_integer(unsigned long n, FILE *port)
return status;
}
long
ps_write_integer(long n, FILE *port)
{
int status;
if (n == 0) {
WRITE_CHAR('0', port, status);
return status; }
else if (n > 0)
return write_integer(n, port);
else {
WRITE_CHAR('-', port, status);
if (status == 0)
return write_integer(- n, port);
else
return status; }
}
long
ps_write_string(char *string, FILE *port)
{

View File

@ -36,9 +36,23 @@ static s48_value s48_socket(s48_value server_p),
s48_value input_p),
s48_get_host_name(void);
s48_value s48_add_pending_channel (s48_value channel)
{
int socket_fd;
S48_CHECK_CHANNEL(channel);
socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
if (! s48_add_pending_fd(socket_fd, 1)) /* 1 for: yes, is input */
s48_raise_out_of_memory_error();
return S48_UNSPECIFIC;
}
/*
* Install all exported functions in Scheme48.
*/
void
s48_init_socket(void)
{
@ -50,6 +64,7 @@ s48_init_socket(void)
S48_EXPORT_FUNCTION(s48_connect);
S48_EXPORT_FUNCTION(s48_close_socket_half);
S48_EXPORT_FUNCTION(s48_get_host_name);
S48_EXPORT_FUNCTION(s48_add_pending_channel);
}
/*
@ -235,7 +250,7 @@ s48_accept(s48_value channel)
* and return #F to tell the Scheme procedure to wait.
*/
if ((errno != EWOULDBLOCK) && (errno != EINTR) && (errno == EAGAIN))
if ((errno != EWOULDBLOCK) && (errno != EINTR) && (errno != EAGAIN))
s48_raise_os_error(errno);
if (! s48_add_pending_fd(socket_fd, TRUE))
@ -366,11 +381,38 @@ s48_close_socket_half(s48_value channel, s48_value input_p)
static s48_value
s48_get_host_name(void)
{
char mbuff[MAXHOSTNAMELEN];
char *mbuff = NULL;
size_t mbuff_len = 0;
int status = 0;
s48_value name;
if (gethostname(mbuff, sizeof(mbuff)) < 0)
do {
char *tmp;
mbuff_len += 256; /* Initial guess */
tmp = (char *) realloc(mbuff, mbuff_len);
if (tmp == NULL) {
free(mbuff);
s48_raise_os_error(ENOMEM);
}
else
mbuff = tmp;
} while (((status = gethostname(mbuff, mbuff_len)) == 0
&& !memchr(mbuff, '\0', mbuff_len))
#ifdef ENAMETOOLONG
|| errno == ENAMETOOLONG
#endif
);
if (status != 0 && errno != 0) {
/* gethostname failed, abort. */
free(mbuff);
s48_raise_os_error(errno);
return s48_enter_string(mbuff);
}
name = s48_enter_string(mbuff);
free(mbuff);
return name;
}

3
cig/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
cig
cig.image

1171
cig/cig.scm Normal file

File diff suppressed because it is too large Load Diff

48
cig/image2script Executable file
View File

@ -0,0 +1,48 @@
#!/bin/sh -
binary=$1
shift
if [ `echo $binary | wc -c` -gt 28 ] ; then
echo "#!/bin/sh -"
echo exec $binary $* -i '"$0"' '"$@"'
elif [ $# -gt 0 ] ; then
echo '#!'$binary \\
echo $* -i
else echo '#!'$binary -i
fi
exec cat
# This program reads an S48 image from stdin and turns it into
# an executable by prepending a #! prefix. The vm and its
# args are passed to this program on the command line.
#
# If the vm binary is 27 chars or less, then we can directly
# execute the vm with one of these scripts:
# No args:
# image2script /usr/local/bin/svm <image
# outputs this script:
# #!/usr/local/bin/svm -i
# ...image bits follow...
#
# Args:
# image2script /usr/bin/svm -h 4000000 -o /usr/bin/svm <image
# outputs this script:
# #!/usr/bin/svm \
# -h 4000000 -o /usr/bin/svm -i
# ...image bits follow...
#
# The exec system call won't handle the #! line if it contains more than
# 32 chars, so if the vm binary is over 28 chars, we have to use a /bin/sh
# trampoline.
# image2script /user1/lecturer/shivers/vc/scsh/s48/lib/svm -h 4000000 < ...
# outputs this script:
# #!/bin/sh -
# exec /user1/lecturer/shivers/vc/scsh/s48/lib/svm -h 4000000 -i $0 $*
# ...image bits follow...
#
# -Olin

117
cig/libcig.c Normal file
View File

@ -0,0 +1,117 @@
/* This is an Scheme48/C interface file,
** automatically generated by a hacked version of cig 3.0.
step 4
*/
#include <stdio.h>
#include <stdlib.h> /* For malloc. */
#include "libcig.h"
s48_value df_strlen_or_false(s48_value g1)
{
extern s48_value strlen_or_false(const char * );
s48_value ret1 = S48_FALSE;
S48_DECLARE_GC_PROTECT(1);
s48_value r1;
S48_GC_PROTECT_1(ret1);
r1 = strlen_or_false((const char * )AlienVal(g1));
ret1 = r1;
S48_GC_UNPROTECT();
return ret1;
}
s48_value df_cstring_nullp(s48_value g1)
{
extern int cstring_nullp(const char * );
s48_value ret1 = S48_FALSE;
S48_DECLARE_GC_PROTECT(1);
int r1;
S48_GC_PROTECT_1(ret1);
r1 = cstring_nullp((const char * )AlienVal(g1));
ret1 = ENTER_BOOLEAN(r1);
S48_GC_UNPROTECT();
return ret1;
}
s48_value df_c2scheme_strcpy_free(s48_value g1, s48_value g2)
{
extern int c2scheme_strcpy_free(s48_value , char* );
s48_value ret1 = S48_FALSE;
S48_DECLARE_GC_PROTECT(1);
int r1;
S48_GC_PROTECT_1(ret1);
r1 = c2scheme_strcpy_free(g1, (char* )AlienVal(g2));
ret1 = ENTER_BOOLEAN(r1);
S48_GC_UNPROTECT();
return ret1;
}
s48_value df_c2scheme_strcpy(s48_value g1, s48_value g2)
{
extern int c2scheme_strcpy(s48_value , char* );
s48_value ret1 = S48_FALSE;
S48_DECLARE_GC_PROTECT(1);
int r1;
S48_GC_PROTECT_1(ret1);
r1 = c2scheme_strcpy(g1, (char* )AlienVal(g2));
ret1 = ENTER_BOOLEAN(r1);
S48_GC_UNPROTECT();
return ret1;
}
s48_value df_c_veclen(s48_value g1)
{
extern s48_value c_veclen(long* );
s48_value ret1 = S48_FALSE;
S48_DECLARE_GC_PROTECT(1);
s48_value r1;
S48_GC_PROTECT_1(ret1);
r1 = c_veclen((long* )AlienVal(g1));
ret1 = r1;
S48_GC_UNPROTECT();
return ret1;
}
s48_value df_free(s48_value g1)
{
free((void* )AlienVal(g1));
return S48_FALSE;
}
s48_value df_set_strvec_carriers(s48_value g1, s48_value g2)
{
extern void set_strvec_carriers(s48_value , char** );
set_strvec_carriers(g1, (char** )AlienVal(g2));
return S48_FALSE;
}
void s48_init_cig(void)
{
S48_EXPORT_FUNCTION(df_strlen_or_false);
S48_EXPORT_FUNCTION(df_cstring_nullp);
S48_EXPORT_FUNCTION(df_c2scheme_strcpy_free);
S48_EXPORT_FUNCTION(df_c2scheme_strcpy);
S48_EXPORT_FUNCTION(df_c_veclen);
S48_EXPORT_FUNCTION(df_free);
S48_EXPORT_FUNCTION(df_set_strvec_carriers);
}

32
cig/libcig.h Normal file
View File

@ -0,0 +1,32 @@
#include "scheme48.h"
/* StobData is used by fdports.c. It should be changed over to STOB_REF
** by removing the extra indirection. */
#define StobData(x) (S48_ADDRESS_AFTER_HEADER(x, s48_value))
#define IsChar(x) ((((long) x) & 0xff) == S48_CHAR)
/* JMG: untested !! */
#define StrByte(x, i) ((i) + S48_ADDRESS_AFTER_HEADER((x), char))
#define cig_string_body(x) (S48_ADDRESS_AFTER_HEADER((x), char))
#define AlienVal(x) (S48_STOB_REF((x),0))
/* JMG: no () around this, because it's a do..while(0) */
#define SetAlienVal(x, v) S48_STOB_SET((x), 0, (v))
/* JMG: some hacks to leave to old sources untouched */
#define ENTER_BOOLEAN(x) (x ? S48_TRUE : S48_FALSE)
#define EXTRACT_BOOLEAN(x) ((x==S48_TRUE) ? 1 : 0)
/* #define ENTER_FIXNUM(x) (s48_enter_fixnum(x)) */
/* #define SCHFALSE S48_FALSE */
extern char *scheme2c_strcpy(s48_value sstr);
extern s48_value strlen_or_false(const char *s);
extern char *copystring_or_die(const char *);
extern char *copystring(char *, const char *);
extern s48_value strlen_or_false(const char *);
extern void cig_check_nargs(int arity, int nargs, const char *fn);

139
cig/libcig.scm Normal file
View File

@ -0,0 +1,139 @@
;;; (DEFINE-FOREIGN ...) forms are expanded by Cig into Scheme stubs.
;;; These stubs reference some support procedures to rep-convert the
;;; standard reps (e.g., string). This structure provides these support
;;; procedures.
;;;
;;; We export three kinds of things:
;;; - Type predicates that aren't in the R4RS env (e.g., FIXNUM?).
;;; - Carrier makers for making boxes to return things in.
;;; - Scheme-side rep-converters for return values.
(define-structure cig-aux
(export cstring-null?
C->scheme-string
C->scheme-string-w/len
C->scheme-string-w/len-no-free
C-string-vec->Scheme&free
C-string-vec->Scheme ; Bogus, because clients not reentrant.
string-carrier->string
string-carrier->string-no-free
fixnum?
make-string-carrier
make-alien
alien?
)
(open scheme code-vectors define-foreign-syntax)
(begin
(define min-fixnum (- (expt 2 29)))
(define max-fixnum (- (expt 2 29) 1))
(define (fixnum? x) (and (integer? x) (<= min-fixnum x max-fixnum)))
;; Internal utility.
(define (mapv! f v)
(let ((len (vector-length v)))
(do ((i 0 (+ i 1)))
((= i len) v)
(vector-set! v i (f (vector-ref v i))))))
;; Make a carrier for returning strings.
;; It holds a raw C string and a fixnum giving the length of the string.
(define (make-string-carrier) (cons (make-alien) 0))
(define (make-alien) (make-code-vector 4 0))
(define (alien? x) (and (code-vector? x) (= 4 (code-vector-length x)))) ; BOGUS
;;; C/Scheme string and vector conversion
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Generally speaking, in the following routines,
;;; a NULL C string param causes a function to return #f.
(foreign-init-name "cig")
(define-foreign %cstring-length-or-false
(strlen_or_false ((C "const char * ~a") cstr))
desc)
(define-foreign cstring-null?
(cstring_nullp ((C "const char * ~a") cstr))
bool)
(define-foreign %copy-c-string&free
(c2scheme_strcpy_free (string-desc sstr) ((C char*) cstr))
bool)
(define-foreign %copy-c-string
(c2scheme_strcpy (string-desc sstr) ((C char*) cstr))
bool)
(define (C->scheme-string cstr)
(cond ((%cstring-length-or-false cstr)
=> (lambda (strlen)
(let ((str (make-string strlen)))
(%copy-c-string&free str cstr)
str)))
(else #f)))
(define (C->scheme-string-w/len cstr len)
(and (integer? len)
(let ((str (make-string len)))
(%copy-c-string&free str cstr)
str)))
(define (C->scheme-string-w/len-no-free cstr len)
(and (integer? len)
(let ((str (make-string len)))
(%copy-c-string str cstr)
str)))
(define (string-carrier->string carrier)
(C->scheme-string-w/len (car carrier) (cdr carrier)))
(define (string-carrier->string-no-free carrier)
(C->scheme-string-w/len-no-free (car carrier) (cdr carrier)))
;;; Return the length of a null-terminated C word vector.
;;; Does not count the null word as part of the length.
;;; If vector is NULL, returns #f.
(define-foreign %c-veclen-or-false
(c_veclen ((C long*) c-vec))
desc) ; integer or #f if arg is NULL.
;;; CVEC is a C vector of char* strings, length VECLEN.
;;; This procedure converts a C vector of strings into a Scheme vector of
;;; strings. The C vector and its strings are all assumed to come from
;;; the malloc heap; they are returned to the heap when the rep-conversion
;;; is done.
;;;
;;; Hack: if VECLEN is #f, CVEC is assumed to be NULL terminated, and
;;; its length is calculated thusly.
(define (C-string-vec->Scheme&free cvec veclen)
(let ((vec (make-vector (or veclen (%c-veclen-or-false cvec) 0))))
(mapv! (lambda (ignore) (make-string-carrier)) vec)
(%set-string-vector-carriers! vec cvec)
(C-free cvec)
(mapv! string-carrier->string vec)))
(define (C-string-vec->Scheme cvec veclen) ; No free.
(let ((vec (make-vector (or veclen (%c-veclen-or-false cvec) 0))))
(mapv! (lambda (ignore) (make-string-carrier)) vec)
(%set-string-vector-carriers! vec cvec)
(mapv! string-carrier->string-no-free vec)))
(define-foreign C-free (free ((C void*) ptr)) no-declare ; for SunOS 4.x
ignore)
(define-foreign %set-string-vector-carriers!
(set_strvec_carriers (vector-desc svec) ((C char**) cvec))
ignore)
)) ; egakcap

163
cig/libcig1.c Normal file
View File

@ -0,0 +1,163 @@
/* Generic routines for Scheme48/C interfacing -- mostly for converting
** strings and null-terminated vectors back and forth.
** Copyright (c) 1993 by Olin Shivers.
*/
#include "libcig.h"
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define Malloc(type,n) ((type *) malloc(sizeof(type)*(n)))
#define Free(p) (free((char *)(p)))
/* (c2scheme_strcpy dest_scheme_string source_C_string)
** Copies C string's chars into Scheme string. Return #t.
** If C string is NULL, do nothing and return #f.
*/
int c2scheme_strcpy(s48_value sstr, const char *cstr)
{
if( cstr ) {
strncpy( (char*) StobData(sstr), cstr, S48_STRING_LENGTH(sstr) );
return 1;
}
else return 0;
}
/* Same as above, but free the C string when we are done. */
int c2scheme_strcpy_free(s48_value sstr, const char *cstr)
{
if( cstr ) {
strncpy( (char*) StobData(sstr), cstr, S48_STRING_LENGTH(sstr) );
Free(cstr);
return 1;
}
else return 0;
}
char *scheme2c_strcpy(s48_value sstr)
{
char *result;
int slen;
slen = S48_STRING_LENGTH(sstr);
result = Malloc(char, slen+1);
if( result == NULL ) {
fprintf(stderr,
"Fatal error: C stub tried to copy Scheme string,\n"
"but malloc failed on arg 0x%x, errno %d.\n",
sstr, errno);
exit(-1);
}
memcpy(result, cig_string_body(sstr), slen);
result[slen] = '\000';
return result;
}
/* One arg, a zero-terminated C word vec. Returns length.
** The terminating null is not counted. Returns #f on NULL.
*/
s48_value c_veclen(const long *vec)
{
const long *vptr = vec;
if( !vptr ) return S48_FALSE;
while( *vptr ) vptr++;
return s48_enter_fixnum(vptr - vec);
}
/* Copy string from into string to. If to is NULL, malloc a fresh string
** (if the malloc loses, return NULL).
** If from is NULL, then
** - if to is NULL, do nothing and return NULL.
** - Otherwise, deposit a single nul byte.
** Under normal conditions, this routine returns the destination string.
**
** The little boundary cases of this procedure are a study in obfuscation
** because C doesn't have a reasonable string data type. Give me a break.
*/
char *copystring(char *to, const char *from)
{
if( from ) {
int slen = strlen(from)+1;
if( !to && !(to = Malloc(char, slen)) ) return NULL;
else return memcpy(to, from, slen);
}
else
return to ? *to = '\000', to : NULL;
}
/* As in copystring, but if malloc loses, print out an error msg and croak. */
char *copystring_or_die(const char *str ) /* Note: NULL -> NULL. */
{
if( str ) {
int len = strlen(str)+1;
char *new_str = Malloc(char, len);
if( ! new_str ) {
fprintf(stderr, "copystring: Malloc failed.\n");
exit(-1);
}
return memcpy(new_str, str, len);
}
else return NULL;
}
int cstring_nullp( const char *s ) { return ! s; }
s48_value strlen_or_false(const char *s)
{ return s ? s48_enter_fixnum(strlen(s)) : S48_FALSE; }
/* svec is a Scheme vector of C string carriers. Scan over the C strings
** in cvec, and initialise the corresponding string carriers in svec.
*/
void set_strvec_carriers(s48_value svec, char const * const * cvec)
{
int svec_len = S48_VECTOR_LENGTH(svec);
char const * const * cv = cvec;
int i = 0;
/* JMG: now using normal array access, instead of pointer++ on a s48_value */
for(; svec_len > 0; i++, cv++, svec_len-- ) {
s48_value carrier, alien;
int strl;
/* *sv is a (cons (make-alien <c-string>) <string-length>). */
carrier = S48_VECTOR_REF(svec,i);
alien = S48_CAR(carrier);
strl = strlen(*cv);
S48_SET_CDR(carrier, s48_enter_fixnum(strl));
SetAlienVal(alien, (long) *cv);
}
}
/* Helper function for arg checking. Why bother, actually? */
void cig_check_nargs(int arity, int nargs, const char *fn)
{
if( arity != nargs ) {
fprintf(stderr,
"Cig fatal error (%s) -- C stub expected %d arg%s, "
"but got %d.\n",
fn, arity, (arity == 1) ? "" : "s", nargs);
exit(-1);
}
}
/* void ciginit(){ */
/* S48_EXPORT_FUNCTION (df_strlen_or_false); */
/* S48_EXPORT_FUNCTION (df_c_veclen); */
/* S48_EXPORT_FUNCTION (df_set_strvec_carriers); */
/* S48_EXPORT_FUNCTION (df_c2scheme_strcpy_free); */
/* S48_EXPORT_FUNCTION (df_cstring_nullp); */
/* S48_EXPORT_FUNCTION (df_free); */
/* S48_EXPORT_FUNCTION (df_c2scheme_strcpy); */
/* } */

1463
config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

1579
config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

1925
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -3,26 +3,7 @@ dnl
dnl We might want AC_WORDS_BIGENDIAN in the future.
dnl We might want AC_CHAR_UNSIGNED in the future.
dnl
dnl The -cckr (K&R) flag is for the IRIX C compiler. If this is left
dnl out, scheme48vm.c breaks because the rather pedantic SGI compiler
dnl decides that a char is not the same thing as an unsigned char.
dnl - Bryan O'Sullivan 3/94
dnl Note, this test didn't work correctly on Sun's which take -cckr as a
dnl synonym for -c. (HCC)
define(S48_CFLAG_CKR, [dnl
if test "z$GCC" = z; then
AC_MSG_CHECKING([-cckr])
oldCFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -cckr"
AC_TRY_RUN([int main() { return 0;}],
[AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)
CFLAGS="$oldCFLAGS"],
[AC_MSG_RESULT(no)
CFLAGS="$oldCFLAGS"])
fi
])dnl
dnl
define(S48_POSIX_LIBC, [dnl
echo checking for RISC/OS POSIX library lossage
if test -f /usr/posix/usr/lib/libc.a; then
@ -52,10 +33,39 @@ dnl Note, on some Sun's, you can link with -rdynamic but the resulting
dnl a.out always core dumps.
define(S48_RDYNAMIC, [dnl
AC_MSG_CHECKING([link with -rdynamic])
AC_TRY_COMPILE([],
[#if defined(__linux__) && defined(__ELF__)
this must not compile
#endif],
AC_RUN_IFELSE(AC_LANG_PROGRAM([
#include <stdio.h>
#include <dlfcn.h>
int export_test = 0;],
[
#ifndef RTLD_LAZY
#define RTLD_LAZY 0
#endif
#ifndef RTLD_GLOBAL
#define RTLD_GLOBAL 0
#endif
void *dlhandle;
void *intp;
char *err;
dlhandle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
if ((err = dlerror()) != NULL) {
return 1;
}
(void *)intp = dlsym(dlhandle, "export_test");
if ((err = dlerror()) != NULL) {
return 1;
}
return 0;
]),
[AC_MSG_RESULT(no)],
[AC_MSG_RESULT(yes)
LDFLAGS="$LDFLAGS -rdynamic"])
@ -64,24 +74,263 @@ dnl
define(S48_USCORE, [dnl
AC_MSG_CHECKING([underscore before symbols])
echo 'main() { return 0; } fnord() {}' >conftest.c
if ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} conftest.c ${LIBS} &&
if ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} -o a.out conftest.c ${LIBS} &&
nm a.out | grep _fnord >/dev/null; then
AC_MSG_RESULT([yes])
AC_DEFINE(USCORE)
AC_DEFINE(USCORE, 1, [Define to 1 if symbols start with _])
else
AC_MSG_RESULT([no])
fi
rm -f conftest.c a.out
])dnl
dnl
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
AC_DEFUN(SCSH_TZNAME,[
AC_MSG_CHECKING(for tzname)
AC_CACHE_VAL(scsh_cv_tzname,[
AC_TRY_COMPILE([#include <time.h>],
[return (int) tzname;],
scsh_cv_tzname=yes,
scsh_cv_tzname=no)])
AC_MSG_RESULT($scsh_cv_tzname)
if test $scsh_cv_tzname = yes; then
AC_DEFINE(HAVE_TZNAME)
fi
])
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
AC_DEFUN(SCSH_ELF, [
AC_MSG_CHECKING(for ELF)
AC_CACHE_VAL(scsh_cv_elf,[
touch conftest.c
if ${CC} -v -o a.out conftest.c 2>&1 | grep -q __ELF__ ; then
scsh_cv_elf=yes
else
scsh_cv_elf=no
fi])
AC_MSG_RESULT($scsh_cv_elf)
rm -f conftest.c a.out
])
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
AC_DEFUN(SCSH_SIG_NRS, [
AC_MSG_RESULT([defining signal constants])
${CC} -o scsh_aux ${srcdir}/scsh/scsh_aux.c
AC_DEFINE_UNQUOTED(SIGNR_1, `./scsh_aux 1`, [scsh interrupt for signal 1])
AC_DEFINE_UNQUOTED(SIGNR_2, `./scsh_aux 2`, [scsh interrupt for signal 2])
AC_DEFINE_UNQUOTED(SIGNR_3, `./scsh_aux 3`, [scsh interrupt for signal 3])
AC_DEFINE_UNQUOTED(SIGNR_4, `./scsh_aux 4`, [scsh interrupt for signal 4])
AC_DEFINE_UNQUOTED(SIGNR_5, `./scsh_aux 5`, [scsh interrupt for signal 5])
AC_DEFINE_UNQUOTED(SIGNR_6, `./scsh_aux 6`, [scsh interrupt for signal 6])
AC_DEFINE_UNQUOTED(SIGNR_7, `./scsh_aux 7`, [scsh interrupt for signal 7])
AC_DEFINE_UNQUOTED(SIGNR_8, `./scsh_aux 8`, [scsh interrupt for signal 8])
AC_DEFINE_UNQUOTED(SIGNR_9, `./scsh_aux 9`, [scsh interrupt for signal 9])
AC_DEFINE_UNQUOTED(SIGNR_10, `./scsh_aux 10`, [scsh interrupt for signal 10])
AC_DEFINE_UNQUOTED(SIGNR_11, `./scsh_aux 11`, [scsh interrupt for signal 11])
AC_DEFINE_UNQUOTED(SIGNR_12, `./scsh_aux 12`, [scsh interrupt for signal 12])
AC_DEFINE_UNQUOTED(SIGNR_13, `./scsh_aux 13`, [scsh interrupt for signal 13])
AC_DEFINE_UNQUOTED(SIGNR_14, `./scsh_aux 14`, [scsh interrupt for signal 14])
AC_DEFINE_UNQUOTED(SIGNR_15, `./scsh_aux 15`, [scsh interrupt for signal 15])
AC_DEFINE_UNQUOTED(SIGNR_16, `./scsh_aux 16`, [scsh interrupt for signal 16])
AC_DEFINE_UNQUOTED(SIGNR_17, `./scsh_aux 17`, [scsh interrupt for signal 17])
AC_DEFINE_UNQUOTED(SIGNR_18, `./scsh_aux 18`, [scsh interrupt for signal 18])
AC_DEFINE_UNQUOTED(SIGNR_19, `./scsh_aux 19`, [scsh interrupt for signal 19])
AC_DEFINE_UNQUOTED(SIGNR_20, `./scsh_aux 20`, [scsh interrupt for signal 20])
AC_DEFINE_UNQUOTED(SIGNR_21, `./scsh_aux 21`, [scsh interrupt for signal 21])
AC_DEFINE_UNQUOTED(SIGNR_22, `./scsh_aux 22`, [scsh interrupt for signal 22])
AC_DEFINE_UNQUOTED(SIGNR_23, `./scsh_aux 23`, [scsh interrupt for signal 23])
AC_DEFINE_UNQUOTED(SIGNR_24, `./scsh_aux 24`, [scsh interrupt for signal 24])
AC_DEFINE_UNQUOTED(SIGNR_25, `./scsh_aux 25`, [scsh interrupt for signal 25])
AC_DEFINE_UNQUOTED(SIGNR_26, `./scsh_aux 26`, [scsh interrupt for signal 26])
AC_DEFINE_UNQUOTED(SIGNR_27, `./scsh_aux 27`, [scsh interrupt for signal 27])
AC_DEFINE_UNQUOTED(SIGNR_28, `./scsh_aux 28`, [scsh interrupt for signal 28])
AC_DEFINE_UNQUOTED(SIGNR_29, `./scsh_aux 29`, [scsh interrupt for signal 29])
AC_DEFINE_UNQUOTED(SIGNR_30, `./scsh_aux 30`, [scsh interrupt for signal 30])
AC_DEFINE_UNQUOTED(SIGNR_31, `./scsh_aux 31`, [scsh interrupt for signal 31])
rm -f scsh_aux scsh_aux.exe
])
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
AC_DEFUN(SCSH_LINUX_STATIC_DEBUG, [
case "$host" in
*-*-linux* )
AC_MSG_CHECKING(for broken Linux that needs -static with -g)
AC_CACHE_VAL(scsh_cv_linux_static_debug,[
AC_TRY_LINK([],
[],
scsh_cv_linux_static_debug=no,
scsh_cv_linux_static_debug=yes)])
AC_MSG_RESULT($scsh_cv_linux_static_debug)
if test $scsh_cv_linux_static_debug = yes; then
LDFLAGS="-static ${LDFLAGS}"
fi
;;
esac
])
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
AC_DEFUN(SCSH_CONST_SYS_ERRLIST,[
AC_MSG_CHECKING(for const sys_errlist)
AC_CACHE_VAL(scsh_cv_const_sys_errlist,[
AC_TRY_COMPILE([#include <errno.h>
#include <unistd.h>],
[const extern char *sys_errlist[];],
scsh_cv_const_sys_errlist=yes,
scsh_cv_const_sys_errlist=no)])
AC_MSG_RESULT($scsh_cv_const_sys_errlist)
if test $scsh_cv_const_sys_errlist = yes; then
AC_DEFINE(HAVE_CONST_SYS_ERRLIST, 1, [const char* sys_errlist])
fi
])
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
AC_DEFUN(SCSH_SOCKLEN_T,[
AC_MSG_CHECKING(for socklen_t)
AC_TRY_COMPILE([#include <sys/socket.h>
socklen_t x;
],[],[AC_MSG_RESULT(yes)],[
AC_TRY_COMPILE([#include <sys/socket.h>
int accept (int, struct sockaddr *, size_t *);
],[],[
AC_MSG_RESULT(size_t)
AC_DEFINE(socklen_t,
size_t, [Define to type of socklen_t])], [
AC_MSG_RESULT(int)
AC_DEFINE(socklen_t,int)])])
])
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
define(SCSH_CREATE_BUILD_DIRS, [dnl
mkdir -p cig
mkdir -p scsh/machine
mkdir -p scsh/rx
mkdir -p c/srfi
mkdir -p c/unix
])dnl
dnl -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
AC_INIT(c/scheme48vm.c)
AC_CONFIG_HEADER(c/sysdep.h)
SCSH_CREATE_BUILD_DIRS
AC_CANONICAL_HOST
S48_PROG_CC
SCSH_SIG_NRS
AC_ISC_POSIX
SCSH_LINUX_STATIC_DEBUG
dnl set the cross-compile flag before we try anything.
AC_TRY_RUN([int main() { return 0;}], [], [], [true])
S48_CFLAG_CKR
AC_PROG_INSTALL
AC_PROG_RANLIB
AC_C_CONST
AC_C_BIGENDIAN
if test $ac_cv_c_bigendian = no ; then
ENDIAN=little
else
ENDIAN=big
fi
AR=${AR-"ar cq"}
TMPDIR=${TMPDIR-"/var/tmp"}
case "$host" in
## CX/UX
m88k-harris-cxux* )
dir=cxux
CC="cc -Xa"
CFLAGS="-O"
LDFLAGS="-O -Wl,-Bexport"
AC_DEFINE(HAVE_HARRIS, 1, [Define to 1 on m88k-harris-cxux])
;;
## DEC Ultrix
mips-dec-ultrix* )
AC_MSG_ERROR("Ultrix is not supported.")
;;
## HP 9000 series 700 and 800, running HP/UX
hppa*-hp-hpux* )
dir=hpux
LDFLAGS="-Wl,-E"
if test ${CC} = cc; then
CFLAGS="-Ae -O +Obb1800"
fi
AC_DEFINE(_HPUX_SOURCE, 1, [Define to 1 to compile on HP/UX])
AC_DEFINE(hpux, 1, [Define to 1 on HP/UX])
AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Define to 1 to compile on HP/UX])
;;
## IBM AIX
rs6000-ibm-aix*|powerpc-ibm-aix* )
dir=aix
LDFLAGS="-O"
if test ${CC} = gcc; then
LDFLAGS_AIX="-Xlinker -bexport:exportlist.aix"
else
LDFLAGS_AIX="-bexport:exportlist.aix"
fi
CFLAGS="-O"
AIX_P="exportlist.aix"
;;
## Linux
*-*-linux* )
dir=linux
# gross, but needed for some older a.out systems for 0.4.x
LIBS=-lc
SCSH_ELF
;;
## NetBSD and FreeBSD ( and maybe 386BSD also)
*-*-*bsd*|*-*-darwin* )
dir=bsd
SCSH_ELF
;;
## NeXT
*-next-* )
dir=next
CC="$CC -posix"
AC_DEFINE(HAVE_SIGACTION)
;;
## SGI IRIX
mips-sgi-irix* )
dir=irix
S48_CFLAG_CKR
INSTALL='$(srcdir)/install-sh'
;;
## SunOS
sparc*-sun-sunos* )
dir=sunos
;;
## Solaris - Sparc and i386
*-*-solaris* )
dir=solaris
AC_DEFINE(HAVE_NLIST)
;;
## NT - cygwin32
*-*-cygwin* )
AC_DEFINE(CYGWIN, 1, [Define to 1 on cygwin])
dir=cygwin32
EXEEXT=".exe"
;;
## The GNU Hurd
*-*-gnu* )
dir=gnu
SCSH_ELF
;;
## Generic Configuration
* )
dir=generic
echo "WARNING: "
echo "WARNING: Using generic configuration."
echo "WARNING: See doc/porting.txt for more information."
echo "WARNING: "
;;
esac
(cd $srcdir/scsh && rm -rf machine && ln -s $dir machine)
AC_CHECK_LIB(m, main)
AC_CHECK_LIB(dl, main)
AC_CHECK_LIB(mld, main)
@ -89,27 +338,44 @@ AC_INIT(c/scheme48vm.c)
AC_CHECK_LIB(gen, main)
AC_CHECK_LIB(socket, main)
AC_CHECK_LIB(sun, getpwnam)
AC_CHECK_LIB(c, crypt, [true], AC_CHECK_LIB(crypt, crypt))
dnl Solaris 2.3 seems to need -lelf for nlist(). (tnx Bryan O'Sullivan)
AC_CHECK_LIB(elf, main)
S48_POSIX_LIBC
AC_CONST
AC_RETSIGTYPE
AC_CHECK_HEADERS(libgen.h sys/timeb.h posix/time.h)
AC_CHECK_HEADERS(sys/select.h)
AC_CHECK_FUNCS(gettimeofday ftime nlist select setitimer sigaction)
AC_CHECK_FUNC(dlopen, AC_DEFINE(HAVE_DLOPEN),
AC_CHECK_FUNC(nlist, [LIBOBJS="$LIBOBJS c/fake/libdl1.c],
[LIBOBJS="$LIBOBJS c/fake/libdl2.c]))
AC_CHECK_HEADERS(libgen.h sys/timeb.h posix/time.h sys/select.h nlist.h)
AC_CHECK_HEADERS(sys/un.h)
AC_CHECK_HEADERS(crypt.h)
AC_CHECK_FUNCS(gettimeofday ftime nlist select setitimer sigaction vasprintf)
SCSH_SOCKLEN_T
AC_CHECK_FUNC(dlopen, [AC_DEFINE(HAVE_DLOPEN,
1, [Define to 1 if the interface to the dynamic linker exists])
have_dlopen="yes"],
[AC_CHECK_FUNC(nlist, [AC_LIBOBJ([c/fake/libdl1])],
[AC_LIBOBJ([c/fake/libdl2])])
have_dlopen="no"])
AC_CHECK_FUNCS(socket chroot)
AC_CHECK_FUNC(strerror, AC_DEFINE(HAVE_STRERROR),
[LIBOBJS="$LIBOBJS c/fake/strerror.o"])
AC_MSG_CHECKING([n_name])
AC_TRY_LINK([#include <nlist.h>],
[struct nlist name_list;
name_list.n_name = "foo";],
AC_DEFINE(NLIST_HAS_N_NAME)
AC_MSG_RESULT([yes]),
AC_MSG_RESULT([no]))
AC_CHECK_FUNC(strerror, AC_DEFINE(HAVE_STRERROR,
1, [Define to 1 if you have the strerror function]),
[AC_LIBOBJ([c/fake/strerror])])
AC_CHECK_FUNC(seteuid, [AC_DEFINE(HAVE_SETEUID,
1, [Define to 1 if you have the seteuid function])],
[AC_CHECK_FUNC(setreuid, [AC_DEFINE(HAVE_SETREUID,
1, [Define to 1 if you have the setreuid function])],
[AC_MSG_ERROR("Neither setegid nor setregid defined. Cannot continue.")])])
AC_CHECK_FUNC(setegid, [AC_DEFINE(HAVE_SETEGID,
1, [Define to 1 if you have the setegid function])],
[AC_CHECK_FUNC(setregid, [AC_DEFINE(HAVE_SETREGID,
1, [Define to 1 if you have the setregid function])],
[AC_MSG_ERROR("Neither setegid nor setregid defined. Cannot continue.")])])
AC_CHECK_MEMBER(struct nlist.n_name,
[AC_DEFINE(NLIST_HAS_N_NAME, 1, [Define to 1 if struct nlist.n_name exists])],,
[#include <nlist.h>])
AC_MSG_CHECKING([__NEXT__])
AC_TRY_LINK(,[
#ifdef __NeXT__
@ -123,8 +389,83 @@ fail
AC_MSG_RESULT([yes]),
AC_MSG_RESULT([no]))
S48_USCORE
S48_RDYNAMIC
if test $have_dlopen = yes; then
S48_RDYNAMIC
fi
AC_STRUCT_TIMEZONE
AC_CHECK_MEMBER(struct tm.tm_gmtoff,
AC_DEFINE(HAVE_GMTOFF, 1, [Define to 1 if struct tm has member tm_gmtoff]))
dnl ----------------------------------------------------------------
dnl Check for pty support
dnl ----------------------------------------------------------------
dnl There is no "standard" pty allocation method. Every system is different.
dnl getpt() is the preferred pty allocation method on glibc systems.
dnl _getpty() is the preferred pty allocation method on SGI systems.
dnl grantpt(), unlockpt(), ptsname() are defined by Unix98.
AC_CHECK_FUNCS(getpt _getpty grantpt unlockpt ptsname killpg tcgetpgrp)
dnl openpty() is the preferred pty allocation method on BSD and Tru64 systems.
dnl openpty() might be declared in:
dnl - pty.h (Tru64 or Linux)
dnl - libutil.h (FreeBSD)
dnl - util.h (NetBSD)
AC_CHECK_FUNC(openpty, have_openpty=yes, [
AC_CHECK_LIB(util, openpty, have_openpty=yes need_libutil=yes)])
if test "$have_openpty" = "yes"; then
AC_DEFINE(HAVE_OPENPTY, 1, [Define to 1 if you have the 'openpty' function])
AC_CHECK_HEADERS(libutil.h util.h, break)
if test "$need_libutil" = "yes"; then
LIBS="${LIBS} -lutil"
fi
fi
dnl Check for system-specific pty header files
dnl Often the TIOCSIG* symbols are hiding there.
case "$opsys" in
dnl HPUX pty.h #defines TRUE and FALSE, so just use ptyio.h there.
hpux*) AC_CHECK_HEADERS(sys/ptyio.h) ;;
*) AC_CHECK_HEADERS(pty.h)
test "$ac_cv_header_pty_h" = "no" && AC_CHECK_HEADERS(sys/pty.h)
;;
esac
dnl Check for System V STREAM support functions.
AC_CHECK_HEADERS(stropts.h)
AC_CHECK_FUNCS(isastream)
SCSH_CONST_SYS_ERRLIST
CFLAGS1=${CFLAGS}
lib_dirs_list='("${prefix}/lib/scsh/modules" "${prefix}/lib/scsh/modules/0.6")'
AC_ARG_WITH(lib-dirs-list,
AC_HELP_STRING([--with-lib-dirs-list],
[list of default scsh library directories (default ("$prefix/lib/scsh/modules" "${prefix}/lib/scsh/modules/0.6"))]),
lib_dirs_list="$withval")
AC_SUBST(lib_dirs_list)
AC_SUBST(CFLAGS)
AC_SUBST(LIBOBJS)
AC_SUBST(LDFLAGS)
AC_OUTPUT(Makefile)
AC_SUBST(AIX_P)
AC_SUBST(AR)
AC_SUBST(CC)
AC_SUBST(CFLAGS)
AC_SUBST(CFLAGS1)
AC_SUBST(EXEEXT)
AC_SUBST(ENDIAN)
AC_SUBST(LDFLAGS)
AC_SUBST(LDFLAGS_AIX)
AC_SUBST(LIBS)
AC_SUBST(TMPDIR)
AC_CONFIG_FILES(Makefile scsh/endian.scm scsh-config)
AC_CONFIG_COMMANDS([scsh-config+x],[chmod +x scsh-config])
AC_OUTPUT

View File

@ -1,309 +0,0 @@
Documentation for Big Scheme
Big Scheme is a set of generally useful facilities.
Easiest way to access these things:
> ,open big-scheme
Load structure big-scheme (y/n)? y
...
A better way is to use the module system.
-----
Ascii conversions
(CHAR->ASCII <char>) => <integer>
(ASCII->CHAR <integer>) => <char>
These are identical to CHAR->INTEGER and INTEGER->CHAR except that
they use the ASCII encoding.
-----
Bitwise operations
(BITWISE-NOT <integer>) => <integer>
(BITWISE-AND <integer> <integer>) => <integer>
(BITWISE-IOR <integer> <integer>) => <integer>
(BITWISE-XOR <integer> <integer>) => <integer>
These perform various logical operations on integers on a bit-by-bit
basis, using a two's-complement representation.
(ARITHMETIC-SHIFT <integer> <bit-count>) => <integer>
Shift the integer by the given bit count, shifting left for positive
counts and right for negative ones. A two's complement
representation is used.
-----
Hash tables
(MAKE-TABLE) => <table>
(MAKE-STRING-TABLE) => <string-table>
Make a new, empty table. MAKE-TABLE returns a table that uses EQ?
for comparing keys and an ad-hoc hash function. String tables uses
strings for keys.
(MAKE-TABLE-MAKER <comparison-procedure> <hash-procedure>) => <procedure>
Returns a procedure of no arguments that makes tables that use the
given comparison and hash procedures.
(<comparison-procedure> <key1> <key2>) => <boolean>
(<hash-procedure> <key>) => <non-negative-integer>
(TABLE? <x>) => <boolean>
True if <x> is a table.
(TABLE-REF <table> <key>) => <x>
Return the value for <key> in <table>, or #F if there is none.
<key> should be of a type appropriate for <table>.
(TABLE-SET! <table> <key> <value>) => <undefined>
Make <value> be the value of <key> in <table>. <key> should be of a
type appropriate for <table>.
(TABLE-WALK <procedure> <table>) => <undefined>
Apply <procedure>, which must accept two arguments, to every
associated key and value in <table>.
-----
Enumerations
(DEFINE-ENUMERATION <type-name> (<name0> <name1> ...)) *SYNTAX*
Defines <type-name> to be an enumeration with components <name0>
<name1> .... Also defines <type-name>-COUNT to be the number of
components.
(ENUM <type-name> <component-name>) => <integer> *SYNTAX*
Evaluates to the value of <component-name> within the enumeration
<type-name>. For example, if (DEFINE-ENUMERATION COLOR (GREEN
RED)), then (ENUM COLOR GREEN) is zero and (ENUM COLOR RED) is one.
The mapping from name to integer is done at macro-expansion time, so
there is no run-time overhead.
(ENUMERAND->NAME <integer> <enumeration>) => <symbol>
Returns the name associated with <integer> within <enumeration>.
E.g. (ENUMERAND->NAME 1 COLOR) => 'RED.
(NAME->ENUMERAND <symbol> <enumeration>) => <integer>
Returns the integer associated with <symbol> within <enumeration>.
E.g. (ENUMERAND->NAME 'GREEN COLOR) => 0.
-----
Port extensions
(MAKE-TRACKING-INPUT-PORT <input-port>) => <input-port>
(MAKE-TRACKING-OUTPUT-PORT <output-port>) => <output-port>
These return ports that keep track of the current row and column and
are otherwise identical to their arguments.
(MAKE-STRING-INPUT-PORT <string>) => <input-port>
Returns a port that reads characters from the supplied string.
(CALL-WITH-STRING-OUTPUT-PORT <procedure>) => <string>
The procedure is called on a port. When it returns, CALL-WITH-STRING-
OUTPUT-PORT returns a string containing the characters written to the port.
(WRITE-ONE-LINE <output-port> <character-count> <procedure>) => <unspecified>
The procedure is called on an output port. Output written to that
port is copied to <output-port> until <character-count> characters
have been written, at which point WRITE-ONE-LINE returns.
(CURRENT-ROW <port>) => <integer> or #f
(CURRENT-COLUMN <port>) => <integer> or #f
These return the current read or write location of the port. #F is
returned if the port does not keep track of its location.
(FRESH-LINE <output-port>) => <undefined>
Write a newline character to <output-port> if its current column is not 0.
(INPUT-PORT? <any>) => <boolean>
(OUTPUT-PORT? <any>) => <boolean>
These are versions of the standard Scheme predicates that answer true for
extended ports.
-----
Queues
(MAKE-QUEUE) => <queue>
Returns a new, empty queue.
(ENQUEUE! <queue> <x>) => <undefined>
Puts <x> on the queue.
(DEQUEUE! <queue>) => <x>
Removes and returns the first element of the queue.
(QUEUE-EMPTY? <queue>) => <boolean>
True if the queue is empty.
(QUEUE? <x>) => <boolean>
True if <x> is a queue.
(QUEUE->LIST <queue>) => <list>
Returns a list of the elements of the queue, in order.
(QUEUE-LENGTH <queue>) => <integer>
The number of elements currently on the queue.
(DELETE-FROM-QUEUE! <queue> <x>) => <boolean>
Removes the first occurance of <x> from the queue, returning true if
it was found and false otherwise.
-----
Little utility procedures
(ATOM? <any>) => <boolean>
(ATOM? x) == (NOT (PAIR? x))
(NULL-LIST? <list>) => <boolean>
Returns #t for the empty list, #f for a pair, and signals an error
otherwise.
(NEQ? <any> <any>) => <boolean>
(NEQ? x y) is the same as (NOT (EQ? x y)).
(N= <number> <number>) => <boolean>
(N= x y) is the same as (NOT (= x y)).
(IDENTITY <any>) => <any>
(NO-OP <any>) => <any>
These both just return their argument. NO-OP is guaranteed not to
be compiled in-line, IDENTITY may be.
-----
List utilities
(MEMQ? <element> <list>) => <boolean>
Returns true if <element> is in <list>, false otherwise.
(ANY? <predicate> <list>) => <boolean>
Returns true if <predicate> is true for any element of <list>.
(EVERY? <predicate> <list>) => <boolean>
Returns true if <predicate> is true for every element of <list>.
(ANY <predicate> <list>)
(FIRST <predicate> <list>)
ANY returns some element of <list> for which <predicate> is true, or
#F if there are none. FIRST does the same except that it returns
the first element for which <predicate> is true.
(FILTER <predicate> <list>)
(FILTER! <predicate> <list>)
Returns a list containing all of the elements of <list> for which
<predicate> is true. The order of the elements is preserved.
FILTER! may reuse the storage of <list>.
(FILTER-MAP <procedure> <list>)
The same as FILTER except the returned list contains the results of
applying <procedure> instead of elements of <list>. (FILTER-MAP p
l) is the same as (FILTER IDENTITY (MAP p l)).
(PARTITION-LIST <predicate> <list>) => <list> <list>
(PARTITION-LIST! <predicate> <list>) => <list> <list>
The first return value contains those elements <list> for which
<predicate> is true, the second contains the remaining elements.
The order of the elements is preserved. PARTITION-LIST! may resuse
the storage of the <list>.
(REMOVE-DUPLICATES <list>) => <list>
Returns its argument with all duplicate elements removed. The first
instance of each element is preserved.
(DELQ <element> <list>) => <list>
(DELQ! <element> <list>) => <list>
(DELETE <predicate> <list>) => <list>
All three of these return <list> with some elements removed. DELQ
removes all elements EQ? to <element>. DELQ! does the same and may
modify the list argument. DELETE removes all elements for which
<predicate> is true. Both DELQ and DELETE may reuse some of the
storage in the list argument, but won't modify it.
(REVERSE! <list>) => <list>
Destructively reverses <list>.
(SORT-LIST <list> <a<b-procedure>) => <list>
(SORT-LIST! <list> <a<b-procedure>) => <list>
Returns a sorted copy of <list>. The sorting algorithm is stable.
(SORT-LIST '(6 5 1 3 2 4) <) => '(1 2 3 4 5 6)
-----
Additional syntax
(DESTRUCTURE ((<pattern> <init>) ...) <body> ...) *SYNTAX*
The <init>s are evaluated and their values are dissasembled
according to the corresponding patterns, with identifiers in the
patterns being bound to fresh locations holding the corresponding
part, and the body is evaluated in the extended environment.
Patterns may be any of the following:
#f Discard the corresponding part.
<identifier> Bind the <indentifier> to the part.
(<pattern> ...) The part must be a list at least as long as the
pattern.
(<pattern1> ... . <patternN>)
The same thing, except that the final CDR of the
part is dissasembled according to <patternN>.
#(<pattern> ...) The part must be a vector at least as long as the
pattern.
(RECEIVE <identifiers> <exp> <body> ...) *SYNTAX*
=> (CALL-WITH-VALUES (LAMBDA () <exp>) (LAMBDA <identifiers> <body> ...))
Bind <identifiers> to the values returned by <exp>, and evaluate the
body in the resulting environment.
-----
Printing and related procedures
(CONCATENATE-SYMBOL . <components>)
Returns the symbol whose name is produced by concatenating the DISPLAYed
representations of <components>.
(CONCATENATE-SYMBOL 'abc "-" 4) => 'abc-4
(FORMAT <port-spec> <format-string> . <arguments>) => <string> or <undefined>
Prints the arguments to the port as directed by the string. <port-spec>
should be either:
An output port. The output is written directly to the port. The result
of the call to FORMAT is undefined.
#T. The output is written to the current output port. The result of the
call to FORMAT is undefined.
#F. The output is written to a string, which is then the value returned
from the call to FORMAT.
Characters in <format-string> which are not preceded by a ~ are written
directly to the output. Characters preceded by a ~ have the following
meaning (case is irrelevant; ~a and ~A have the same meaning):
~~ prints a single ~
~A prints the next argument using DISPLAY
~D prints the next argument as a decimal number
~S prints the next argument using WRITE
~% prints a newline character
~& prints a NEWLINE character if the previous printed character was not one
(this is implemented using FRESH-LINE)
~? performs a recursive call to FORMAT using the next two arguments as the
string and the list of arguments
(ERROR <format-string> . <format-arguments>)
(BREAKPOINT <format-string> . <format-arguments>)
Signals an error or breakpoint condition, passing it the result of
applying FORMAT to the arguments.
(P <thing>)
(P <thing> <output-port>)
(PRETTY-PRINT <thing> <output-port> <position>)
Pretty-print <thing>. The current output port is used if no port is
specified. <position> is the starting offset. <thing> will be
pretty-printed to the right of this column.
Original by RK, 26 Jan 1993.
Minor changes by JAR, 5 Dec 1993.

740
doc/cheat.txt Normal file
View File

@ -0,0 +1,740 @@
Scsh cheat sheet
Olin Shivers
November 1996
This cheat sheet is intentionally kept brief and minimalist.
It is intended to function as an ASCII-format reminder for the
full manual, not as the definition. It can be read using GNU Emacs's
outline mode.
It is also not entirely up-to-date. I'd appreciate getting updates from users.
-------------------------------------------------------------------------------
* High-level forms
Extended process form:
(PF [REDIR1 ...])
Redirection:
(< [FDES] FILE-NAME)
(> [FDES] FILE-NAME)
(<< [FDES] OBJECT)
(= FDES FDES/PORT)
(- FDES/PORT)
stdports
Subforms are implicitly backquoted.
Process form:
(| PF1 ...) ; pipeline
(|+ CONNECT-LIST PF1 ...) ; complex pipeline
(begin . BODY) ; Scheme form
(epf . EPF) ; Embedded extended process form
(PROG ARG1 ... ARGn) ; Exec a program
Subforms are implicitly backquoted.
Using process forms in Scheme:
(exec-epf . EPF) ; Nuke the current process.
(& . EPF) ; Fork process in background. Return proc object.
(run . EPF) ; Run process. Return exit code.
(& . EPF) = (fork (lambda () (exec-epf . EPF)))
(run . EPF) = (wait (& . EPF))
Interfacing to subprocess I/O:
(run/port . EPF) -> port
(run/file . EPF) -> string
(run/string . EPF) -> string
(run/strings . EPF) -> string list
(run/sexp . EPF) -> object
(run/sexps . EPF) -> list
There are procedural equivalents for each of these, e.g., run/port* and
run/file*, that take thunk arguments for the subprocess.
(port->string PORT) -> string
Read until EOF on PORT, return data as a string.
(port->string-list PORT) -> string list
Repeatedly apply READ-LINE to PORT until EOF. Return list of lines read.
(port->sexp-list PORT) -> list
Repeatedly apply READ to PORT until EOF. Return list of items read.
(port->list READER PORT)
Repeatedly apply READER to PORT until EOF. Return list of items read.
(reduce-port PORT READER OP . SEEDS)
Evaluate (OP (READER PORT) . SEEDS) to get a new set of seeds
(OP must return as many values as there are SEEDS). When
a port read returns EOF, the current set of seed values are
returned as multiple values.
(run/port+proc . EPF) -> [port proc]
(run/port+proc* THUNK) -> [port proc]
(run/collecting FDS . EPF) -> [port ...]
(run/collecting* FDS THUNK) -> [port ...]
RUN/COLLECTING implicitly backquotes FDS.
(|| PF1 ... PFn)
(&& PF1 ... PFn)
Conditionally execute processes.
(char-filter filter) -> procedure
(string-filter filter [buflen]) -> procedure
* System calls
** Errors
(errno-error errno SYSCALL . DATA)
(with-errno-handler* HANDLER THUNK) -> value of thunk
HANDLER is called on two arguments: (HANDLER ERRNO PACKET)
where PACKET is a list of the form (ERRNO-MSG SYSCALL . DATA)
If HANDLER returns at all, the handler search continues upwards.
(with-errno-handler HANDLER-SPEC . BODY)
HANDLER-SPEC is of the form
((ERRNO PACKET) CLAUSE ...)
ERRNO and PACKET are variables bound to the errno error being raised.
There are two forms for handler clauses:
((ERRNO ...) . BODY)
(else . BODY)
ERRNO are expressions evaluating to errno integers.
** I/O
*** Port Manipulation
(close-after PORT CONSUMER) -> value(s) of consumer
(error-output-port) -> port
(with-current-input-port port . body) -> value(s) of body
(with-current-output-port port . body) -> value(s) of body
(with-error-output-port port . body) -> value(s) of body
(with-current-input-port* port thunk) -> value(s) of thunk
(with-current-output-port* port thunk) -> value(s) of thunk
(with-error-output-port* port thunk) -> value(s) of thunk
(close fd/port)
(stdports->stdio)
(stdio->stdports)
(with-stdio-ports* thunk) -> value(s) of thunk
(with-stdio-ports . body) -> value(s) of body
(make-string-input-port) -> port
(string-output-port-output port) -> port
(call-with-string-output-port proc) -> str
** Port and file descriptors
(fdes->inport fd) -> port
(fdes->outport fd) -> port
(port->fdes port) -> fixnum
Increment port's revealed count.
(port-revealed port) -> integer or #f
(release-port-handle port)
(call/fdes fd/port consumer) -> value(s) of consumer
(move->fdes fd/port target-fd) -> port or fdes
** Unix I/O
(dup fd/port [newfd]) -> fd/port
(dup->inport fd/port [newfd]) -> port
(dup->outport fd/port [newfd]) -> port
(dup->fdes fd/port [newfd]) -> fd
(file-seek fd/port offset whence)
(open-file fname flags [perms]) -> port
(open-input-file fname [flags]) -> port
(open-output-file fname [flags perms]) -> port
(open-fdes fname flags [perms]) -> integer
(fdes-flags fd/port)
(set-fdes-flags fd/port flags)
Only Posix flag defined is FDFLAGS/CLOSE-ON-EXEC, which you should
not ever have to use -- scsh manages this automatically.
(fdes-status fd/port)
(set-fdes-flags fd/port flags)
Operations allowed Flags
------------------ -----
Open+get+set open/append, open/non-blocking
open/async, open/fsync (non-Posix)
Open+get open/read, open/write, open/read+write
open/access-mask
Open only open/create, open/exclusive,
open/no-control-tty, open/truncate
(pipe) -> [rport wport]
(read-line [fd/port retain-newline?]) -> string or eof-object
(read-string nbytes [fd/port]) -> string or #f
(read-string! str [fd/port start end]) -> [nread or #f]
(read-string/partial nbytes [fd/port]) -> string or #f
(read-string!/partial str [fd/port start end]) -> [nread or #f]
(write-string string [fd/port start end])
(write-string/partial string [fd/port start end]) -> nwritten
(force-output [fd/port])
** File locking
(define-record lock-region
exclusive? ; write or read lock?
start ; integer: start, end & whence
end ; integer: define the region being locked.
whence ; The value of SEEK/SET, SEEK/DELTA, or SEEK/END.
proc) ; A proc object for the process locking the region.
(make-lock-region exclusive? start len [whence]) -> lock-region
WHENCE defaults to the value of SEEK/SET.
(lock-region fdes lock)
(lock-region/no-block fdes lock)
(get-lock-region fdes lock) -> lock-region or #f
(unlock-region fdes lock)
(with-region-lock* fdes lock thunk)
(with-region-lock fdes lock body ...) Syntax
** File system
(create-directory fname [perms override?])
(create-fifo fname [perms override?])
(create-hard-link oldname newname [override?])
OVERRIDE? one of {#f, QUERY, other true value}
(delete-directory fname)
(delete-file fname)
(delete-filesys-object fname)
(read-symlink fname) -> string
(rename-file old-fname new-fname [override?])
(set-file-mode fname/fd/port mode)
(set-file-owner fname/fd/port uid)
(set-file-group fname/fd/port gid)
(sync-file fd/port)
(sync-file-system)
(truncate-file fname/fd/port len)
(file-attributes fname/fd/port [chase?]) -> file-info
(define-record file-info
type ; {block-special, char-special, directory,
; fifo, regular, socket, symlink}
device ; Device file resides on.
inode ; File's inode.
mode ; File's permission bits.
nlinks ; Number of hard links to this file.
uid ; Owner of file.
gid ; File's group id.
size ; Size of file, in bytes.
atime ; Last access time.
mtime ; Last status-change time.
ctime) ; Creation time.
Derived procedures:
file-type type
file-inode inode
file-mode mode
file-nlinks nlinks
file-owner uid
file-group gid
file-size size
file-last-access atime
file-last-mod mtime
file-last-status-change ctime
(file-not-readable? fname) -> boolean
(file-not-writable? fname) -> boolean
(file-not-executable? fname) -> boolean
Returns one of
#f Access permitted
SEARCH-DENIED Can't stat---a protected directory
is blocking access.
PERMISSION Permission denied.
NO-DIRECTORY Some directory doesn't exist.
NONEXISTENT File doesn't exist.
(file-readable? fname) -> boolean
(file-writable? fname) -> boolean
(file-executable? fname) -> boolean
(file-not-exists? fname [chase?]) -> boolean
#f Exists.
SEARCH-DENIED Some protected directory
is blocking the search.
#t Doesn't exist.
(file-exists? fname [chase?]) -> boolean
(directory-files [dir dotfiles?]) -> string list
(glob pat1 ...) -> string list
(glob-quote string) -> string
(file-match root dot-files? pat1 ...) -> string list
(create-temp-file [prefix]) -> string
(temp-file-iterate maker [template]) -> [object ...]
TEMPLATE defaults to the value of *TEMP-FILE-TEMPLATE*.
(temp-file-channel) -> [inport outport]
** Processes
(exec prog arg1 ...)
(exec-path prog arg1 ...)
(exec/env prog env arg1 ...)
(exec-path/env prog env arg1 ...)
(%exec prog arglist env)
(exec-path-search fname pathlist) -> string
(exit [status])
(%exit [status])
(suspend)
(fork [thunk]) -> proc or #d
(%fork [thunk]) -> proc or #f
(fork/pipe [thunk]) -> proc or #f
(%fork/pipe [thunk]) -> proc or #f
(fork/pipe+ conns [thunk]) proc or #f
(%fork/pipe+ conns [thunk]) proc or #f
(wait proc/pid [flags]) -> status [proc]
(call-terminally thunk)
** Process state
(umask) -> fixnum
(set-umask perms)
(with-umask* perms thunk) -> values of thunk
(with-umask perms . body) -> values of body
(chdir [fname])
(cwd) -> string
(with-cwd* fname thunk) -> value(s) of thunk
(with-cwd fname . body) -> value(s) of body
(pid) -> fixnum
(parent-pid) -> fixnum
(process-group) -> fixnum
(set-process-group [proc/pid] pgrp)
(user-login-name) -> string
(user-uid) -> fixnum
(user-effective-uid) -> fixnum
(user-gid) -> fixnum
(user-effective-gid) -> fixnum
(user-supplementary-gids) -> fixnum list
(set-uid uid)
(set-gid gid)
(process-times) -> [ucpu scpu uchildren schildren]
** User and group db access
(user-info uid-or-name) -> user-info
(define-record user-info
name
uid
gid
home-dir
shell)
(->uid uid/name) -> fixnum
(->username uid/name) -> string
(group-info gid-or-name) -> record
(define-record group-info
name
gid
members) ; List of uids
(->gid gid/name) -> fixnum
(->group gid/name) -> string
** Accessing command-line arguments
command-line-arguments
Does not include program name
(command-line) -> string list
Includes program name in list.
(arg arglist n [default]) -> string
(arg* arglist n [default-thunk]) -> string
(argv n [default]) -> string
ARG is 1-based access to ARGLIST
ARGV is 0-based access to prog + args
** System parameters
(system-name) -> string
** Signal system
(signal-process proc/pid sig)
(signal-procgroup prgrp sig)
(pause-until-interrupt)
(sleep secs)
Non-signal S48 interrupts
-------------------------
interrupt/memory-shortage
Posix signals with S48 interrupts
------------------------------
signal/alrm interrupt/alrm (aka interrupt/alarm)
signal/int interrupt/int (aka interrupt/int)
signal/chld interrupt/chld
signal/cont interrupt/cont
signal/hup interrupt/hup
signal/quit interrupt/quit
signal/term interrupt/term
signal/tstp interrupt/tstp
signal/usr1 interrupt/usr1
signal/usr2 interrupt/usr2
signal/info interrupt/info Non-Posix
signal/io interrupt/io Non-Posix
signal/poll interrupt/poll Non-Posix
signal/prof interrupt/prof Non-Posix
signal/pwr interrupt/pwr Non-Posix
signal/urg interrupt/urg Non-Posix
signal/vtalrm interrupt/vtalrm Non-Posix
signal/winch interrupt/winch Non-Posix
signal/xcpu interrupt/xcpu Non-Posix
signal/xfsz interrupt/xfsz Non-Posix
Synchronous and uncatchable signals
-----------------------------------
signal/stop Uncatchable Posix
signal/kill Uncatchable Posix
signal/abrt Synchronous Posix
signal/fpe Synchronous Posix
signal/ill Synchronous Posix
signal/pipe Synchronous Posix
signal/segv Synchronous Posix
signal/ttin Synchronous Posix
signal/ttou Synchronous Posix
signal/bus Synchronous BSD + SVR4
signal/emt Synchronous BSD + SVR4
signal/iot Synchronous BSD + SVR4
signal/sys Synchronous BSD + SVR4
signal/trap Synchronous BSD + SVR4
** Interrupt handlers
(signal->interrupt sig) -> interrupt
(interrupt-set integer1 ...) -> integer
(enabled-interrupts) -> integer
(set-enabled-interrupts! integer) -> integer
(with-enabled-interrupts interrupt-set body ...) Syntax
(with-enabled-interrupts* interrupt-set thunk)
(set-interrupt-handler! interrupt handler) -> old-handler
(interrupt-handler interrupt) -> handler
HANDLER is #f (ignored), #t (default), or (lambda (enabled-ints) ...) proc.
** Time
(define-record date
seconds minute hour month-day month year
tz-name tz-secs summer?
week-day year-day)
(make-date sec min hour mday month year [tz-name tz-secs summer? wday yday])
(time+ticks)
(ticks/sec)
(date [time tz])
(time [date])
(date->string date)
(format-date fmt date)
** Environment variables
(setenv var val)
(getenv var) -> string
(env->alist) -> string->string alist
(alist->env alist)
(alist-delete key alist) -> alist
(alist-update key val alist) -> alist
(alist-compress alist) -> alist
(with-env* env-alist-delta thunk) -> value(s) of thunk
(with-total-env* env-alist thunk) -> value(s) of thunk
(with-env env-alist-delta . body) -> value(s) of body
(with-total-env env-alist . body) -> value(s) of body
(add-before elt before list) -> list
(add-after elt after list) -> list
** $USER $HOME, and $PATH
home-directory
exec-path-list
* Networking
** High Level Socket Routines
*** clients
(socket-connect protocol-family/internet socket-type name port) -> socket
(socket-connect protocol-family/unix socket-type pathname) -> socket
*** server
(bind-listen-accept-loop protocol-family/internet proc port) -> does-not-return
(bind-listen-accept-loop protocol-family/unix proc pathname) -> does-not-return
proc is a procedure of two arguments: a socket and a socket-address
** Sockets
(create-socket protocol-family type [protocol]) -> socket
(create-socket-pair type) -> [socket1 socket2]
(close-socket socket) -> undefined
protocol-family/unix
protocol-family/internet
socket-type/stream
socket-type/datagram
for protocol see protocol-info
(define-record socket family inport outport)
** Socket Addresses
(define-record socket-address family)
(unix-address->socket-address pathname) -> socket-address
(internet-address->socket-address host-address service-port)-> socket-address
internet-address/any
internet-address/loopback
internet-address/broadcast
(socket-address->unix-address socket-address) -> pathname
(socket-address->internet-address socket-address) ->
[host-address service-port]
** Low Level Socket Routines
(connect-socket socket socket-address) -> undefined
(bind-socket socket socket-address) -> undefined
(listen-socket socket backlog) -> undefined
(accept-connection socket) -> [new-socket socket-address]
(socket-local-address socket) -> socket-address
(socket-remote-address socket) -> socket-address
(shutdown-socket socket how-to) -> undefined
how-to:
shutdown/receives
shutdown/sends
shutdown/sends+receives
** Socket Specific I/O
see read-string/write-string for info on arguments
(receive-message socket length [flags]) ->
[string-or-#f socket-address]
(receive-message! socket string [start] [end] [flags]) ->
[count-or-#f socket-address]
(receive-message/partial socket length [flags]) ->
[string-or-#f socket-address]
(receive-message!/partial socket string [start] [end] [flags]) ->
[count-or-#f socket-address]
(send-message socket string [start] [end] [flags] [socket-address] ->
undefined
(send-message/partial socket string [start] [end] [flags] [socket-address]) ->
count
** Socket Options
(socket-option socket level option) -> value
(set-socket-option socket level option value) -> undefined
boolean:
socket/debug
socket/accept-connect
socket/reuse-address
socket/keep-alive
socket/dont-route
socket/broadcast
socket/use-loop-back
socket/oob-inline
socket/use-privileged
socket/cant-signal
tcp/no-delay
value:
socket/send-buffer
socket/receive-buffer
socket/send-low-water
socket/receive-low-water
socket/error
socket/type
ip/time-to-live
tcp/max-segment
socket/linger is #f or integer seconds
real number with microsecond resolution:
socket/send-timeout
socket/receive-timeout
** Database-information entries
(host-info name-or-socket-address) -> host-info
(network-info name-or-socket-address) -> network-info
(service-info name-or-number [protocol-name]) -> service-info
(protocol-info name-or-number) -> protocol-info
(define-record host-info name aliases addresses)
(define-record network-info name aliases net)
(define-record service-info name aliases port protocol)
(define-record protocol-info name aliases number)
* String manipulation
** Regular expressions
(string-match regexp string [start]) -> match or false
(regexp-match? obj) -> boolean
(match:start match [match-number]) -> fixnum
(match:end match [match-number]) -> fixnum
(match:substring match [match-number]) -> string
(make-regexp str) -> re
(regexp? obj) -> boolean
(regexp-exec regexp str [start]) -> match or false
(regexp-quote str) -> string
** Other string manipulation facilities
(index string char [start]) -> fixnum or false
(rindex string char [start]) -> fixnum or false
(substitute-env-vars fname) -> string
** Manipulating file-names
** Record I/O and field parsing
(read-delimited char-set [port]) -> string or eof
(read-delimited! char-set buf [port start end]) -> nchars or #f or eof
((record-reader [delims elide-delims? handle-delim]) [port]) -> string or eof
HANDLE-DELIM one of {trim, split, concat}
(read-paragraph [port delimiter?])
** Parsing fields
(field-splitter [regexp num-fields]) -> parser
(infix-splitter [delim num-fields handle-delim]) -> parser
(suffix-splitter [delim num-fields handle-delim]) -> parser
(sloppy-suffix-splitter [delim num-fields handle-delim]) -> parser
Where (parser string [start])
HANDLE-DELIM one of {trim, concat, split}
(join-strings strings [delimiter grammar])
GRAMMAR one of {infix, suffix}
** Field readers
(field-reader [field-parser record-reader])
* Awk
(awk <reader-exp> <rec&field-vars> [<rec-counter>] <state-var-inits>
<clause>
.
.
)
* Miscellaneous routines
** Integer bitwise ops
(arithmetic-shift i j) -> integer
(bitwise-and i j) -> integer
(bitwise-ior i j) -> integer
(bitwise-not i) -> integer
(bitwise-xor i j) -> integer
** ASCII encoding
(char->ascii \character) -> integer
(ascii->char \integer) -> character
** Top level
(repl)
* Running scsh
scsh [meta-arg] [switch1 ...] [end-option arg1 ...]
meta-arg: \ <script-file-name>
switch: -e <entry-point> Top-level entry point
-o <structure> Open structure in current package.
-m <structure> Switch to package.
-n <new-package> Switch to new package.
-lm <module> <file-name> Load module into config package.
-l <file-name> Load file into current package.
-dm Do script module.
-ds Do script.
end-option: -s <script> Specifies script to load.
-sfd <num> Script from file descriptor <num>.
-c <expression> Eval <expression> and exit.
--
scshvm [meta-arg] [vm-options] [end-option arg1 ...]
meta-arg: \ <fname>
vm-options: -h heap-size
-s stack-size
-o object-file
end-option: -i image-file
--
(dump-scsh-program main fname)
** File locations
/usr/local/bin/scsh
/usr/local/lib/scsh/
scshvm
scsh
scsh.image
doc/

File diff suppressed because it is too large Load Diff

View File

@ -1,690 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<!-- HTML file produced from file: external.tex --
-- using Hyperlatex v 2.3.1 (c) Otfried Cheong--
-- on Emacs 19.34.1, Tue Feb 23 18:21:44 1999 -->
<HEAD>
<TITLE>Mixing Scheme 48 and C</TITLE>
</HEAD><BODY>
<H1 ALIGN=CENTER>Using C code with Scheme 48</H1>
<H2 ALIGN=CENTER>Mike Sperber<BR><TT><FONT SIZE=-1>sperber@informatik.uni-tuebingen.de</FONT></TT><BR>Richard Kelsey<BR><TT><FONT SIZE=-1>kelsey@research.nj.nec.com</FONT></TT>
</H2>
<H3 ALIGN=CENTER>February 23, 1999</H3>
<H3 ALIGN=CENTER>Abstract</H3>
<BLOCKQUOTE>
This document describes an interface for calling C functions
from Scheme, calling Scheme functions from C, and allocating
storage in the Scheme heap.
These facilities are designed to link
existing C libraries into Scheme&nbsp;48 in order to use them from Scheme.
To this end, Scheme&nbsp;48 manages stub functions in C that
negotiate between the calling conventions of Scheme and C and the
memory allocation policies of both worlds.
No stub generator is available yet, but writing them is a straightforward task.
</BLOCKQUOTE>
<H1><A NAME="1">Available Facilities</A></H1>
<P>The following facilities are available for interfacing between
Scheme&nbsp;48 and C:
<UL><LI>Scheme code can call C functions.
<LI>The external interface provides full introspection for all
Scheme objects. External code may inspect, modify, and allocate
Scheme objects arbitrarily.
<LI>External code may raise exceptions back to Scheme&nbsp;48 to
signal errors.
<LI>External code may call back into Scheme. Scheme&nbsp;48
correctly unrolls the process stack on non-local exits.
<LI>External modules may register bindings of names to values with a
central registry accessible from
Scheme. Conversely, Scheme code can register shared
bindings for access by C code.
</UL>
This document has three parts: the first describes how bindings are
moved from Scheme to C and vice versa, the second tells how to call
C functions from Scheme, and the third covers the C interface
to Scheme objects, including calling Scheme procedures, using the
Scheme heap, and so forth.
<H2><A NAME="2">Scheme structures</A></H2>
<P>The structure <CODE>external-calls</CODE> has
most of the Scheme functions described here.
The others are in
<CODE>dynamic-externals</CODE>, which has the functions for dynamic loading and
name lookup from
the section on <A HREF="#dynamic-externals">Dynamic Loading</A>,
and <CODE>shared-bindings</CODE>, which has the additional shared-binding functions
described in
the section on the <A HREF="#more-shared-bindings">complete shared-binding interface</A>.
<H2><A NAME="3">C naming conventions</A></H2>
<P>The names of all of Scheme&nbsp;48's visible C bindings begin
with `<CODE>s48_</CODE>' (for procedures and variables) or
`<CODE>S48_</CODE>' (for macros).
Whenever a C name is derived from a Scheme identifier, we
replace `<CODE>-</CODE>' with `<CODE>_</CODE>' and convert letters to lowercase
for procedures and uppercase for macros.
A final `<CODE>?</CODE>' converted to `<CODE>_p</CODE>' (`<CODE>_P</CODE>' in C macro names).
A final `<CODE>!</CODE>' is dropped.
Thus the C macro for Scheme's <CODE>pair?</CODE> is <CODE>S48_PAIR_P</CODE> and
the one for <CODE>set-car!</CODE> is <CODE>S48_SET_CAR</CODE>.
Procedures and macros that do not check the types of their arguments
have `<CODE>unsafe</CODE>' in their names.
<P>All of the C functions and macros described have prototypes or definitions
in the file <CODE>c/scheme48.h</CODE>.
The C type for Scheme values is defined there to be <CODE>s48_value</CODE>.
<H1><A NAME="4">Shared bindings</A></H1>
<P>Shared bindings are the means by which named values are shared between Scheme
code and C code.
There are two separate tables of shared bindings, one for values defined in
Scheme and accessed from C and the other for values going the other way.
Shared bindings actually bind names to cells, to allow a name to be looked
up before it has been assigned.
This is necessary because C initialization code may be run before or after
the corresponding Scheme code, depending on whether the Scheme code is in
the resumed image or is run in the current session.
<H2><A NAME="5">Exporting Scheme values to C</A></H2>
<UL><LI><CODE>(define-exported-binding<I>&nbsp;name&nbsp;value</I>)&nbsp;-&gt;&nbsp;<I>shared-binding</I></CODE>
</UL>
<UL><LI><CODE>s48_value s48_get_imported_binding(char *name)</CODE>
<LI><CODE>s48_value S48_SHARED_BINDING_REF(s48_value shared_binding)</CODE>
</UL>
<P><CODE>Define-exported-binding</CODE> makes <CODE><I>value</I></CODE> available to C code
under as <CODE><I>name</I></CODE> which must be a <CODE><I>string</I></CODE>, creating a new shared
binding if necessary.
The C function <CODE>s48_get_imported_binding</CODE> returns the shared binding
defined for <CODE>name</CODE>, again creating it if necessary.
The C macro <CODE>S48_SHARED_BINDING_REF</CODE> dereferences a shared binding,
returning its current value.
<H2><A NAME="6">Exporting C values to Scheme</A></H2>
<UL><LI><CODE>void s48_define_exported_binding(char *name, s48_value value)</CODE>
</UL>
<UL><LI><CODE>(lookup-imported-binding<I>&nbsp;string</I>)&nbsp;-&gt;&nbsp;<I>shared-binding</I></CODE>
<LI><CODE>(shared-binding-ref<I>&nbsp;shared-binding</I>)&nbsp;-&gt;&nbsp;<I>value</I></CODE>
</UL>
<P>These are used to define shared bindings from C and to access them
from Scheme.
Again, if a name is looked up before it has been defined, a new binding is
created for it.
<P>The common case of exporting a C function to Scheme can be done using
the macro <CODE>S48_EXPORT_FUNCTION(<EM>name</EM>)</CODE>.
This expands into
<P><CODE>s48_define_exported_binding("<CODE><I>name</I></CODE>", s48_enter_pointer(<CODE><I>name</I></CODE>))</CODE>
<P>which boxes the function into a Scheme byte vector and then
exports it.
Note that <CODE>s48_enter_pointer</CODE> allocates space in the Scheme heap
and might trigger a
<A HREF="#gc">garbage collection</A>.
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>(import-definition <CODE><I>name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>(import-definition <CODE><I>name&nbsp;c-name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
</UL>
These macros simplify importing definitions from C to Scheme.
They expand into
<P><CODE>(define <CODE><I>name</I></CODE> (lookup-imported-binding <CODE><I>c-name</I></CODE>))</CODE>
<P>where <CODE><I>c-name</I></CODE> is as supplied for the second form.
For the first form <CODE><I>c-name</I></CODE> is derived from <CODE><I>name</I></CODE> by
replacing `<CODE>-</CODE>' with `<CODE>_</CODE>' and converting letters to lowercase.
For example, <CODE>(import-definition my-foo)</CODE> expands into
<P><CODE>(define my-foo (lookup-imported-binding "my_foo"))</CODE>
<H2><A NAME="more-shared-bindings">Complete shared binding interface</A></H2>
<P>There are a number of other Scheme functions related to shared bindings;
these are in the structure <CODE>shared-bindings</CODE>.
<UL><LI><CODE>(shared-binding?<I>&nbsp;x</I>)&nbsp;-&gt;&nbsp;<I>boolean</I></CODE>
<LI><CODE>(shared-binding-name<I>&nbsp;shared-binding</I>)&nbsp;-&gt;&nbsp;<I>string</I></CODE>
<LI><CODE>(shared-binding-is-import?<I>&nbsp;shared-binding</I>)&nbsp;-&gt;&nbsp;<I>boolean</I></CODE>
<LI><CODE>(shared-binding-set!<I>&nbsp;shared-binding&nbsp;value</I>)</CODE>
<LI><CODE>(define-imported-binding<I>&nbsp;string&nbsp;value</I>)</CODE>
<LI><CODE>(lookup-exported-binding<I>&nbsp;string</I>)</CODE>
<LI><CODE>(undefine-imported-binding<I>&nbsp;string</I>)</CODE>
<LI><CODE>(undefine-exported-binding<I>&nbsp;string</I>)</CODE>
</UL>
<P><CODE>Shared-binding?</CODE> is the predicate for shared-bindings.
<CODE>Shared-binding-name</CODE> returns the name of a binding.
<CODE>Shared-binding-is-import?</CODE> is true if the binding was defined from C.
<CODE>Shared-binding-set!</CODE> changes the value of a binding.
<CODE>Define-imported-binding</CODE> and <CODE>lookup-exported-binding</CODE> are
Scheme versions of <CODE>s48_define_exported_binding</CODE>
and <CODE>s48_lookup_imported_binding</CODE>.
The two <CODE>undefine-</CODE> procedures remove bindings from the two tables.
They do nothing if the name is not found in the table.
<P>The following C macros correspond to the Scheme functions above.
<UL><LI><CODE>int S48_SHARED_BINDING_P(x)</CODE>
<LI><CODE>int S48_SHARED_BINDING_IS_IMPORT_P(s48_value s_b)</CODE>
<LI><CODE>s48_value S48_SHARED_BINDING_NAME(s48_value s_b)</CODE>
<LI><CODE>void S48_SHARED_BINDING_SET(s48_value s_b, s48_value value)</CODE>
</UL>
<H1><A NAME="8">Calling C Functions from Scheme</A></H1>
<P>There are three different ways to call C functions from Scheme, depending on
how the C function was obtained.
<UL><LI><CODE>(call-imported-binding<I>&nbsp;binding&nbsp;arg<I><sub>0</sub></I>&nbsp;...</I>)&nbsp;-&gt;&nbsp;<I>value</I></CODE>
<LI><CODE>(call-external<I>&nbsp;external&nbsp;arg<I><sub>0</sub></I>&nbsp;...</I>)&nbsp;-&gt;&nbsp;<I>value</I></CODE>
<LI><CODE>(call-external-value<I>&nbsp;value&nbsp;name&nbsp;arg<I><sub>0</sub></I>&nbsp;...</I>)&nbsp;-&gt;&nbsp;<I>value</I></CODE>
</UL>
Each of these applies its first argument, a C function, to the rest of
the arguments.
For <CODE>call-imported-binding</CODE> the function argument must be an
imported binding.
For <CODE>call-external</CODE> the function argument must be an external
bound in the current process
(see
the section on <A HREF="#dynamic-externals">Dynamic Loading</A>).
For <CODE>call-external-value</CODE> <CODE><I>value</I></CODE> must be a byte vector
whose contents is a pointer to a C function and <CODE><I>name</I></CODE> should be
a string naming the function.
The <CODE><I>name</I></CODE> argument is used only for printing error messages.
<P>For all of these, the C function is passed the <CODE><I>arg<I><sub>i</sub></I></I></CODE> values
and the value returned is that returned by C procedure.
Up to twelve arguments may be passed.
There is no method supplied for returning multiple values to
Scheme from C (or vice versa) (mainly because C does not have multiple return
values).
<P>Keyboard interrupts that occur during a call to a C function are ignored
until the function returns to Scheme (this is clearly a
problem; we are working on a solution).
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>(import-lambda-definition <CODE><I>name</I></CODE> (<CODE><I>formal</I></CODE> ...))</CODE></td> <td align=right>syntax</td></tr></table>
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>(import-lambda-definition <CODE><I>name</I></CODE> (<CODE><I>formal</I></CODE> ...) <CODE><I>c-name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
</UL>
These macros simplify importing functions from C.
They define <CODE><I>name</I></CODE> to be a function with the given formals that
applies those formals to the corresponding C binding.
<CODE><I>C-name</I></CODE>, if supplied, should be a string.
These expand into
<BLOCKQUOTE><PRE>
(define temp (lookup-imported-binding <CODE><I>c-name</I></CODE>))
(define <CODE><I>name</I></CODE>
(lambda (<CODE><I>formal</I></CODE> ...)
(external-apply temp <CODE><I>formal</I></CODE> ...)))
</PRE></BLOCKQUOTE>
<P>
If <CODE><I>c-name</I></CODE> is not supplied, it is derived from <CODE><I>name</I></CODE> by converting
all letters to lowercase and replacing `<CODE>-</CODE>' with `<CODE>_</CODE>'.
<H1><A NAME="9">Adding external modules to the <CODE>Makefile</CODE></A></H1>
<P>Getting access to C bindings from Scheme requires that the C code be
compiled an linked in with the Scheme&nbsp;48 virtual machine and that the
relevent shared-bindings be created.
The Scheme&nbsp;48 makefile has rules for compiling and linking external code
and for specifying initialization functions that should be called on
startup.
There are three Makefile variables that control which external modules are
included in the executable for the virutal machine (<CODE>scheme48vm</CODE>).
<CODE>EXTERNAL_OBJECTS</CODE> lists the object files to be included in
<CODE>scheme48vm</CODE>,
<CODE>EXTERNAL_FLAGS</CODE> is a list of <CODE>ld</CODE> flags to be used when
creating <CODE>scheme48vm</CODE>, and
<CODE>EXTERNAL_INITIALIZERS</CODE> is a list of C procedures to be called
on startup.
The procedures listed in <CODE>EXTERNAL_INITIALIZERS</CODE> should take no
arguments and have a return type of <CODE>void</CODE>.
After changing the definitions of any of these variables you should
do <CODE>make scheme48vm</CODE> to rebuild the virtual machine.
<H1><A NAME="dynamic-externals">Dynamic Loading</A></H1>
<P>External code can be loaded into a running Scheme&nbsp;48 process
and C object-file bindings can be dereferenced at runtime and
their values called
(although not all versions of Unix support all of this).
The required Scheme functions are in the structure <CODE>dynamic-externals</CODE>.
<UL><LI><CODE>(dynamic-load<I>&nbsp;string</I>)</CODE>
</UL>
<CODE>Dynamic-load</CODE> loads the named file into the current
process, raising an exception if the file cannot be found or if dynamic
loading is not supported by the operating system.
The file must have been compiled and linked appropriately.
For Linux, the following commands compile <CODE>foo.c</CODE> into a
file <CODE>foo.so</CODE> that can be loaded dynamically.
<BLOCKQUOTE><PRE>
% gcc -c -o foo.o foo.c
% ld -shared -o foo.so foo.o
</PRE></BLOCKQUOTE>
<UL><LI><CODE>(get-external<I>&nbsp;string</I>)&nbsp;-&gt;&nbsp;<I>external</I></CODE>
<LI><CODE>(external?<I>&nbsp;x</I>)&nbsp;-&gt;&nbsp;<I>boolean</I></CODE>
<LI><CODE>(external-name<I>&nbsp;external</I>)&nbsp;-&gt;&nbsp;<I>string</I></CODE>
<LI><CODE>(external-value<I>&nbsp;external</I>)&nbsp;-&gt;&nbsp;<I>byte-vector</I></CODE>
</UL>
These functions give access to values bound in the current process, and
are used for retrieving values from dynamically-loaded files.
<CODE>Get-external</CODE> returns an <I>external</I> object that contains the
value of <CODE><I>name</I></CODE>, raising an exception if there is no such
value in the current process.
<CODE>External?</CODE> is the predicate for externals, and
<CODE>external-name</CODE> and <CODE>external-value</CODE> return the name and
value of an external.
The value is returned as byte vector of length four (on 32-bit
architectures).
The value is that which was extant when <CODE>get-external</CODE> was
called.
The following two functions can be used to update the values of
externals.
<UL><LI><CODE>(lookup-external<I>&nbsp;external</I>)&nbsp;-&gt;&nbsp;<I>boolean</I></CODE>
<LI><CODE>(lookup-all-externals<I></I>)&nbsp;-&gt;&nbsp;<I>boolean</I></CODE>
</UL>
<CODE>Lookup-external</CODE> updates the value of <CODE><I>external</I></CODE> by looking its
name in the current process, returning <CODE>#t</CODE> if it is bound and <CODE>#f</CODE>
if it is not.
<CODE>Lookup-all-externals</CODE> calls <CODE>lookup-external</CODE> on all extant
externals, returning <CODE>#f</CODE> any are unbound.
<UL><LI><CODE>(call-external<I>&nbsp;external&nbsp;arg<I><sub>0</sub></I>&nbsp;...</I>)&nbsp;-&gt;&nbsp;<I>value</I></CODE>
</UL>
An external whose value is a C procedure can be called using
<CODE>call-external</CODE>.
See
the section on <A HREF="#8">calling C functions from Scheme</A>
for more information.
<P>In some versions of Unix retrieving a value from the current
process may require a non-trivial amount of computation.
We recommend that a dynamically-loaded file contain a single initialization
procedure that creates shared bindings for the values exported by the file.
<H1><A NAME="11">Compatibility</A></H1>
<P>Scheme&nbsp;48's old <CODE>external-call</CODE> function is still available in the structure
<CODE>externals</CODE>, which now also includes <CODE>external-name</CODE> and
<CODE>external-value</CODE>.
The old <CODE>scheme48.h</CODE> file has been renamed <CODE>old-scheme48.h</CODE>.
<H1><A NAME="12">Accessing Scheme data from C</A></H1>
<P>The C header file <CODE>scheme48.h</CODE> provides
access to Scheme&nbsp;48 data structures
(for compatibility, the old <CODE>scheme48.h</CODE> file is available
as <CODE>old-scheme48.h</CODE>).
The type <CODE>s48_value</CODE> is used for Scheme values.
When the type of a value is known, such as the integer returned
by <CODE>vector-length</CODE> or the boolean returned by <CODE>pair?</CODE>,
the corresponding C procedure returns a C value of the appropriate
type, and not a <CODE>s48_value</CODE>.
Predicates return <CODE>1</CODE> for true and <CODE>0</CODE> for false.
<H2><A NAME="13">Constants</A></H2>
<P>The following macros denote Scheme constants:
<DL><DT><B><CODE>S48_FALSE</CODE></B><DD> is <CODE>#f</CODE>.
<DT><B><CODE>S48_TRUE</CODE></B><DD> is <CODE>#t</CODE>.
<DT><B><CODE>S48_NULL</CODE></B><DD> is the empty list.
<DT><B><CODE>S48_UNSPECIFIC</CODE></B><DD> is a value used for functions which have no
meaningful return value
(in Scheme this value returned by the nullary procedure <CODE>unspecific</CODE>
in the structure <CODE>util</CODE>).
<DT><B><CODE>S48_EOF</CODE></B><DD> is the end-of-file object
(in Scheme this value is returned by the nullary procedure <CODE>eof-object</CODE>
in the structure <CODE>i/o-internal</CODE>).
</DL>
<H2><A NAME="14">Converting values</A></H2>
<P>The following functions convert values between Scheme and C
representations.
The `extract' ones convert from Scheme to C and the `enter's go the other
way.
<UL><LI><CODE>unsigned char s48_extract_char(s48_value)</CODE>
<LI><CODE>char * s48_extract_string(s48_value)</CODE>
<LI><CODE>long s48_extract_integer(s48_value)</CODE>
<LI><CODE>double s48_extract_double(s48_value)</CODE>
<LI><CODE>s48_value s48_enter_char(unsigned char)</CODE>
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>s48_value s48_enter_string(char *)</CODE></td> <td align=right>(may GC)</td></tr></table>
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>s48_value s48_enter_integer(long)</CODE></td> <td align=right>(may GC)</td></tr></table>
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>s48_value s48_enter_double(double)</CODE></td> <td align=right>(may GC)</td></tr></table>
</UL>
<P>The value returned by <CODE>s48_extract_string</CODE> points to the actual
storage used by the string; it is valid only until the next
<A HREF="#gc">garbage collection</A>.
<P><CODE>s48_enter_integer()</CODE> needs to allocate storage when
its argument is too large to fit in a Scheme&nbsp;48 fixnum.
In cases where the number is known to fit within a fixnum (currently 30 bits
including the sign), the following procedures can be used.
These have the disadvantage of only having a limited range, but
the advantage of never causing a garbage collection.
<UL><LI><CODE>long s48_extract_fixnum(s48_value)</CODE>
<LI><CODE>s48_value s48_enter_fixnum(long)</CODE>
<LI><CODE>long S48_MAX_FIXNUM_VALUE</CODE>
<LI><CODE>long S48_MIN_FIXNUM_VALUE</CODE>
</UL>
<P>An error is signalled if <CODE>s48_extract_fixnum</CODE>'s argument
is not a fixnum or if the argument to <CODE>s48_enter_fixnum</CODE> is less than
<CODE>S48_MIN_FIXNUM_VALUE</CODE> or greater than <CODE>S48_MAX_FIXNUM_VALUE</CODE>
(<I>-2<sup>29</sup></I> and <I>2<sup>29</sup>-1</I> in the current system).
<H2><A NAME="15">C versions of Scheme procedures</A></H2>
<P>The following macros and procedures are C versions of Scheme procedures.
The names were derived by replacing `<CODE>-</CODE>' with `<CODE>_</CODE>',
`<CODE>?</CODE>' with `<CODE>p</CODE>', and dropping `<CODE>!</CODE>.
<UL><LI><CODE>int S48_EQ_P(s48_value)</CODE>
<LI><CODE>int S48_CHAR_P(s48_value)</CODE>
<LI><CODE>int S48_INTEGER_P(s48_value)</CODE>
</UL>
<UL><LI><CODE>int S48_PAIR_P(s48_value)</CODE>
<LI><CODE>s48_value S48_CAR(s48_value)</CODE>
<LI><CODE>s48_value S48_CDR(s48_value)</CODE>
<LI><CODE>void S48_SET_CAR(s48_value, s48_value)</CODE>
<LI><CODE>void S48_SET_CDR(s48_value, s48_value)</CODE>
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>s48_value s48_cons(s48_value, s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
<LI><CODE>long s48_length(s48_value)</CODE>
</UL>
<UL><LI><CODE>int S48_VECTOR_P(s48_value)</CODE>
<LI><CODE>long S48_VECTOR_LENGTH(s48_value)</CODE>
<LI><CODE>s48_value S48_VECTOR_REF(s48_value, long)</CODE>
<LI><CODE>void S48_VECTOR_SET(s48_value, long, s48_value)</CODE>
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>s48_value s48_make_vector(long, s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
</UL>
<UL><LI><CODE>int S48_STRING_P(s48_value)</CODE>
<LI><CODE>long S48_STRING_LENGTH(s48_value)</CODE>
<LI><CODE>char S48_STRING_REF(s48_value, long)</CODE>
<LI><CODE>void S48_STRING_SET(s48_value, long, char)</CODE>
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>s48_value s48_make_string(long, char)</CODE></td> <td align=right>(may GC)</td></tr></table>
</UL>
<UL><LI><CODE>int S48_SYMBOL_P(s48_value)</CODE>
<LI><CODE>s48_value s48_SYMBOL_TO_STRING(s48_value)</CODE>
</UL>
<UL><LI><CODE>int S48_BYTE_VECTOR_P(s48_value)</CODE>
<LI><CODE>long S48_BYTE_VECTOR_LENGTH(s48_value)</CODE>
<LI><CODE>char S48_BYTE_VECTOR_REF(s48_value, long)</CODE>
<LI><CODE>void S48_BYTE_VECTOR_SET(s48_value, long, int)</CODE>
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>s48_value s48_make_byte_vector(long, int)</CODE></td> <td align=right>(may GC)</td></tr></table>
</UL>
<H1><A NAME="16">Calling Scheme functions from C</A></H1>
<P>External code that has been called from Scheme can call back to Scheme
procedures using the following function.
<UL><LI><CODE>scheme_value s48_call_scheme(s48_value proc, long nargs, ...)</CODE>
</UL>
This calls the Scheme procedure <CODE>proc</CODE> on <CODE>nargs</CODE>
arguments, which are passed as additional arguments to <CODE>s48_call_scheme</CODE>.
There may be at most ten arguments.
The value returned by the Scheme procedure is returned by the C procedure.
Invoking any Scheme procedure may potentially cause a garbage collection.
<P>There are some complications that occur when mixing calls from C to Scheme
with continuations and threads.
C only supports downward continuations (via <CODE>longjmp()</CODE>).
Scheme continuations that capture a portion of the C stack have to follow the
same restriction.
For example, suppose Scheme procedure <CODE>s0</CODE> captures continuation <CODE>a</CODE>
and then calls C procedure <CODE>c0</CODE>, which in turn calls Scheme procedure
<CODE>s1</CODE>.
Procedure <CODE>s1</CODE> can safely call the continuation <CODE>a</CODE>, because that
is a downward use.
When <CODE>a</CODE> is called Scheme&nbsp;48 will remove the portion of the C stack used
by the call to <CODE>c0</CODE>.
On the other hand, if <CODE>s1</CODE> captures a continuation, that continuation
cannot be used from <CODE>s0</CODE>, because by the time control returns to
<CODE>s0</CODE> the C stack used by <CODE>c0</CODE> will no longer be valid.
An attempt to invoke an upward continuation that is closed over a portion
of the C stack will raise an exception.
<P>In Scheme&nbsp;48 threads are implemented using continuations, so the downward
restriction applies to them as well.
An attempt to return from Scheme to C at a time when the appropriate
C frame is not on top of the C stack will cause the current thread to
block until the frame is available.
For example, suppose thread <CODE>t0</CODE> calls a C procedure which calls back
to Scheme, at which point control switches to thread <CODE>t1</CODE>, which also
calls C and then back to Scheme.
At this point both <CODE>t0</CODE> and <CODE>t1</CODE> have active calls to C on the
C stack, with <CODE>t1</CODE>'s C frame above <CODE>t0</CODE>'s.
If thread <CODE>t0</CODE> attempts to return from Scheme to C it will block,
as its frame is not accessable.
Once <CODE>t1</CODE> has returned to C and from there to Scheme, <CODE>t0</CODE> will
be able to resume.
The return to Scheme is required because context switches can only occur while
C code is running.
<CODE>T0</CODE> will also be able to resume if <CODE>t1</CODE> uses a continuation to
throw past its call to C.
<H1><A NAME="gc">Interacting with the Scheme Heap</A></H1>
<P>Scheme&nbsp;48 uses a copying, precise garbage collector.
Any procedure that allocates objects within the Scheme&nbsp;48 heap may trigger
a garbage collection.
Variables bound to values in the Scheme&nbsp;48 heap need to be registered with
the garbage collector so that the value will be retained and so that the
variables will be updated if the garbage collector moves the object.
The garbage collector has no facility for updating pointers to the interiors
of objects, so such pointers, for example the ones returned by
<CODE>EXTRACT_STRING</CODE>, will likely become invalid when a garbage collection
occurs.
<H2><A NAME="18">Registering Objects with the GC</A></H2>
<P>A set of macros are used to manage the registration of local variables with the
garbage collector.
<UL><LI><CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>
<LI><CODE>void S48_GC_PROTECT_<I>n</I>(s48_value<I><sub>1</sub></I>, <I>...</I>, s48_value<I><sub>n</sub></I>)</CODE>
<LI><CODE>void S48_GC_UNPROTECT()</CODE>
</UL>
<P><CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>, where <I>1 &lt;= n &lt;= 9</I>, allocates
storage for registering <I>n</I> variables.
At most one use of <CODE>S48_DECLARE_GC_PROTECT</CODE> may occur in a block.
<CODE>S48_GC_PROTECT_<I>n</I>(<I>v<sub>1</sub></I>, <I>...</I>, <I>v<sub>n</sub></I>)</CODE> registers the
<I>n</I> variables (l-values) with the garbage collector.
It must be within scope of a <CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>
and be before any code which can cause a GC.
<CODE>S48_GC_UNPROTECT</CODE> removes the block's protected variables from
the garbage collectors list.
It must be called at the end of the block after
any code which may cause a garbage collection.
Omitting any of the three may cause serious and
hard-to-debug problems.
Notably, the garbage collector may relocate an object and
invalidate <CODE>s48_value</CODE> variables which are not protected.
<P>A <CODE>gc-protection-mismatch</CODE> exception is raised if, when a C
procedure returns to Scheme, the calls
to <CODE>S48_GC_PROTECT()</CODE> have not been matched by an equal number of
calls to <CODE>S48_GC_UNPROTECT()</CODE>.
<P>Global variables may also be registered with the garbage collector.
<UL><LI><CODE>void S48_GC_PROTECT_GLOBAL(<CODE><I>value</I></CODE>)</CODE>
</UL>
<P><CODE>S48_GC_PROTECT_GLOBAL</CODE> permanently registers the
variable <CODE><I>value</I></CODE> (an l-value) with the garbage collector.
There is no way to unregister the variable.
<H2><A NAME="19">Keeping C data structures in the Scheme heap</A></H2>
<P>C data structures can be kept in the Scheme heap by embedding them
inside byte vectors.
The following macros can be used to create and access embedded C objects.
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>s48_value S48_MAKE_VALUE(type)</CODE></td> <td align=right>(may GC)</td></tr></table>
<LI><CODE>type S48_EXTRACT_VALUE(s48_value, type)</CODE>
<LI><CODE>type * S48_EXTRACT_VALUE_POINTER(s48_value, type)</CODE>
<LI><CODE>void S48_SET_VALUE(s48_value, type, value)</CODE>
</UL>
<P><CODE>S48_MAKE_VALUE</CODE> makes a byte vector large enough to hold an object
whose type is <CODE><I>type</I></CODE>.
<CODE>S48_EXTRACT_VALUE</CODE> returns the contents of a byte vector cast to
<CODE><I>type</I></CODE>, and <CODE>S48_EXTRACT_VALUE_POINTER</CODE> returns a pointer
to the contents of the byte vector.
The value returned by <CODE>S48_EXTRACT_VALUE_POINTER</CODE> is valid only until
the next <A HREF="#gc">garbage collection</A>.
<P><CODE>S48_SET_VALUE</CODE> stores <CODE>value</CODE> into the byte vector.
<H2><A NAME="20">C code and heap images</A></H2>
<P>Scheme&nbsp;48 uses dumped heap images to restore a previous system state.
The Scheme&nbsp;48 heap is written into a file in a machine-independent and
operating-system-independent format.
The procedures described above may be used to create objects in the
Scheme heap that contain information specific to the current
machine, operating system, or process.
A heap image containing such objects may not work correctly on
when resumed.
<P>To address this problem, a record type may be given a `resumer'
procedure.
On startup, the resumer procedure for a type is applied to each record of
that type in the image being restarted.
This procedure can update the record in a manner appropriate to
the machine, operating system, or process used to resume the
image.
<UL><LI><CODE>(define-record-resumer<I>&nbsp;record-type&nbsp;procedure</I>)</CODE>
</UL>
<P><CODE>Define-record-resumer</CODE> defines <CODE><I>procedure</I></CODE>,
which should accept one argument, to be the resumer for
<I>record-type</I>.
The order in which resumer procedures are called is not specified.
<P>The <CODE><I>procedure</I></CODE> argument to <CODE>define-record-resumer</CODE> may
be <CODE>#f</CODE>, in which case records of the given type are
not written out in heap images.
When writing a heap image any reference to such a record is replaced by
the value of the record's first field, and an exception is raised
after the image is written.
<H1><A NAME="21">Using Scheme records in C code</A></H1>
<P>External modules can create records and access their slots
positionally.
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>s48_value S48_MAKE_RECORD(s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
<LI><CODE>int S48_RECORD_P(s48_value)</CODE>
<LI><CODE>s48_value S48_RECORD_TYPE(s48_value)</CODE>
<LI><CODE>s48_value S48_RECORD_REF(s48_value, long)</CODE>
<LI><CODE>void S48_RECORD_SET(s48_value, long, s48_value)</CODE>
</UL>
The argument to <CODE>S48_MAKE_RECORD</CODE> should be a shared binding
whose value is a record type.
In C the fields of Scheme records are only accessible via offsets,
with the first field having offset zero, the second offset one, and
so forth.
If the order of the fields is changed in the Scheme definition of the
record type the C code must be updated as well.
<P>For example, given the following record-type definition
<BLOCKQUOTE><PRE>
(define-record-type thing :thing
(make-thing a b)
thing?
(a thing-a)
(b thing-b))
</PRE></BLOCKQUOTE>
the identifier <CODE>:thing</CODE> is bound to the record type and can
be exported to C:
<BLOCKQUOTE><PRE>
(define-exported-binding "thing-record-type" :thing)
</PRE></BLOCKQUOTE>
<CODE>Thing</CODE> records can then be made in C:
<BLOCKQUOTE><PRE>
static scheme_value thing_record_type_binding = SCHFALSE;
void initialize_things(void)
{
S48_GC_PROTECT_GLOBAL(thing_record_type_binding);
thing_record_type_binding =
s48_get_imported_binding("thing-record-type");
}
scheme_value make_thing(scheme_value a, scheme_value b)
{
s48_value thing;
s48_DECLARE_GC_PROTECT(2);
S48_GC_PROTECT_2(a, b);
thing = s48_make_record(thing_record_type_binding);
S48_RECORD_SET(thing, 0, a);
S48_RECORD_SET(thing, 1, b);
S48_GC_UNPROTECT();
return thing;
}
</PRE></BLOCKQUOTE>
Note that the variables <CODE>a</CODE> and <CODE>b</CODE> must be protected
against the possibility of a garbage collection occuring during
the call to <CODE>s48_make_record()</CODE>.
<H1><A NAME="22">Raising exceptions from external code</A></H1>
<P>The following macros explicitly raise certain errors, immediately
returning to Scheme&nbsp;48.
Raising an exception performs all
necessary clean-up actions to properly return to Scheme&nbsp;48, including
adjusting the stack of protected variables.
<UL><LI><CODE>s48_raise_scheme_exception(int type, int nargs, ...)</CODE>
</UL>
<P><CODE>s48_raise_scheme_exception</CODE> is the base procedure for
raising exceptions.
<CODE>type</CODE> is the type of exception, and should be one of the
<CODE>S48_EXCEPTION_</CODE>...constants defined in <CODE>scheme48arch.h</CODE>.
<CODE>nargs</CODE> is the number of additional values to be included in the
exception; these follow the <CODE>nargs</CODE> argument and should all have
type <CODE>s48_value</CODE>.
<CODE>s48_raise_scheme_exception</CODE> never returns.
<P>The following procedures are available for raising particular
types of exceptions.
Like <CODE>s48_raise_scheme_exception</CODE> these never return.
<UL><LI><CODE>s48_raise_argument_type_error(scheme_value)</CODE>
<LI><CODE>s48_raise_argument_number_error(int nargs, int min, int max)</CODE>
<LI><CODE>s48_raise_index_range_error(long value, long min, long max)</CODE>
<LI><CODE>s48_raise_closed_channel_error()</CODE>
<LI><CODE>s48_raise_os_error(int errno)</CODE>
<LI><CODE>s48_raise_out_of_memory_error()</CODE>
</UL>
<P>An argument type error indicates that the given value is of the wrong
type.
An argument number error is raised when the number of arguments, <CODE>nargs</CODE>,
should be, but isn't, between <CODE>min</CODE> and <CODE>max</CODE>, inclusive.
Similarly, and index range error is raised when <CODE>value</CODE> is not between
between <CODE>min</CODE> and <CODE>max</CODE>, inclusive.
<P>The following macros raise argument type errors if their argument does not
have the required type.
<UL><LI><CODE>void S48_CHECK_SYMBOL(s48_value)</CODE>
<LI><CODE>void S48_CHECK_PAIR(s48_value)</CODE>
<LI><CODE>void S48_CHECK_STRING(s48_value)</CODE>
<LI><CODE>void S48_CHECK_INTEGER(s48_value)</CODE>
<LI><CODE>void S48_CHECK_CHANNEL(s48_value)</CODE>
<LI><CODE>void S48_CHECK_BYTE_VECTOR(s48_value)</CODE>
<LI><CODE>void S48_CHECK_RECORD(s48_value)</CODE>
<LI><CODE>void S48_CHECK_SHARED_BINDING(s48_value)</CODE>
</UL>
<H1><A NAME="23">Unsafe functions and macros</A></H1>
<P>All of the C procedures and macros described above check that their
arguments have the appropriate types and that indexes are in range.
The following procedures and macros are identical to those described
above, except that they do not perform type and range checks.
They are provided for the purpose of writing more efficient code;
their general use is not recommended.
<UL><LI><CODE>char S48_UNSAFE_EXTRACT_CHAR(s48_value)</CODE>
<LI><CODE>char * S48_UNSAFE_EXTRACT_STRING(s48_value)</CODE>
<LI><CODE>long S48_UNSAFE_EXTRACT_INTEGER(s48_value)</CODE>
<LI><CODE>long S48_UNSAFE_EXTRACT_DOUBLE(s48_value)</CODE>
</UL>
<UL><LI><CODE>long S48_UNSAFE_EXTRACT_FIXNUM(s48_value)</CODE>
<LI><CODE>s48_value S48_UNSAFE_ENTER_FIXNUM(long)</CODE>
</UL>
<UL><LI><CODE>s48_value S48_UNSAFE_CAR(s48_value)</CODE>
<LI><CODE>s48_value S48_UNSAFE_CDR(s48_value)</CODE>
<LI><CODE>void S48_UNSAFE_SET_CAR(s48_value, s48_value)</CODE>
<LI><CODE>void S48_UNSAFE_SET_CDR(s48_value, s48_value)</CODE>
</UL>
<UL><LI><CODE>long S48_UNSAFE_VECTOR_LENGTH(s48_value)</CODE>
<LI><CODE>s48_value S48_UNSAFE_VECTOR_REF(s48_value, long)</CODE>
<LI><CODE>void S48_UNSAFE_VECTOR_SET(s48_value, long, s48_value)</CODE>
</UL>
<UL><LI><CODE>long S48_UNSAFE_STRING_LENGTH(s48_value)</CODE>
<LI><CODE>char S48_UNSAFE_STRING_REF(s48_value, long)</CODE>
<LI><CODE>void S48_UNSAFE_STRING_SET(s48_value, long, char)</CODE>
</UL>
<UL><LI><CODE>s48_value S48_UNSAFE_SYMBOL_TO_STRING(s48_value)</CODE>
</UL>
<UL><LI><CODE>long S48_UNSAFE_BYTE_VECTOR_LENGTH(s48_value)</CODE>
<LI><CODE>char S48_UNSAFE_BYTE_VECTOR_REF(s48_value, long)</CODE>
<LI><CODE>void S48_UNSAFE_BYTE_VECTOR_SET(s48_value, long, int)</CODE>
</UL>
<UL><LI><CODE>s48_value S48_UNSAFE_SHARED_BINDING_REF(s48_value s_b)</CODE>
<LI><CODE>int S48_UNSAFE_SHARED_BINDING_P(x)</CODE>
<LI><CODE>int S48_UNSAFE_SHARED_BINDING_IS_IMPORT_P(s48_value s_b)</CODE>
<LI><CODE>s48_value S48_UNSAFE_SHARED_BINDING_NAME(s48_value s_b)</CODE>
<LI><CODE>void S48_UNSAFE_SHARED_BINDING_SET(s48_value s_b, s48_value value)</CODE>
</UL>
<UL><LI><CODE>s48_value S48_UNSAFE_RECORD_TYPE(s48_value)</CODE>
<LI><CODE>s48_value S48_UNSAFE_RECORD_REF(s48_value, long)</CODE>
<LI><CODE>void S48_UNSAFE_RECORD_SET(s48_value, long, s48_value)</CODE>
</UL>
<UL><LI><CODE>type S48_UNSAFE_EXTRACT_VALUE(s48_value, type)</CODE>
<LI><CODE>type * S48_UNSAFE_EXTRACT_VALUE_POINTER(s48_value, type)</CODE>
<LI><CODE>void S48_UNSAFE_SET_VALUE(s48_value, type, value)</CODE>
</UL>
<HR ><ADDRESS><a href="http://www-pu.informatik.uni-tuebingen.de/users/sperber/">Mike
Sperber</a>, <a href="http://www.neci.nj.nec.com/homepages/kelsey/">Richard Kelsey</a></ADDRESS><BR>
</BODY></HTML>

View File

@ -1,315 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<!-- HTML file produced from file: utilities.tex --
-- using Hyperlatex v 2.3.1 (c) Otfried Cheong--
-- on Emacs 19.34.1, Tue Feb 23 18:25:11 1999 -->
<HEAD>
<TITLE>Untitled</TITLE>
</HEAD><BODY>
<H1 ALIGN=CENTER>Scheme 48 User's Guide</H1>
<H2 ALIGN=CENTER>Richard A. Kelsey</H2>
<H3 ALIGN=CENTER>February 23, 1999</H3>
<H1><A NAME="1">ASCII character encoding</A></H1>
<P>These are in the structure <CODE>ascii</CODE>.
<UL><LI><CODE>(char-&gt;ascii<VAR> char</VAR>)&nbsp;-&gt;&nbsp;<VAR>integer</VAR></CODE>
<LI><CODE>(ascii-&gt;char<VAR> integer</VAR>)&nbsp;-&gt;&nbsp;<VAR>char</VAR></CODE>
</UL>
These are identical to <CODE>char-&gt;integer</CODE> and <CODE>integer-&gt;char</CODE> except that
they use the ASCII encoding.
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>ascii-limit</CODE></td> <td align=right>integer</td></tr></table>
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE>ascii-whitespaces</CODE></td> <td align=right>list of integers</td></tr></table>
</UL>
<CODE>Ascii-limit</CODE> is one more than the largest value that <CODE>char-&gt;ascii</CODE>
may return.
<CODE>Ascii-whitespaces</CODE> is a list of the ASCII values of whitespace characters
(space, tab, line feed, form feed, and carriage return).
<H1><A NAME="2">Bitwise integer operations</A></H1>
<P>These functions use the two's-complement representation for integers.
There is no limit to the number of bits in an integer.
They are in the structures <CODE>bitwise</CODE> and <CODE>big-scheme</CODE>.
<UL><LI><CODE>(bitwise-and<VAR> integer integer</VAR>)&nbsp;-&gt;&nbsp;<VAR>integer</VAR></CODE>
<LI><CODE>(bitwise-ior<VAR> integer integer</VAR>)&nbsp;-&gt;&nbsp;<VAR>integer</VAR></CODE>
<LI><CODE>(bitwise-xor<VAR> integer integer</VAR>)&nbsp;-&gt;&nbsp;<VAR>integer</VAR></CODE>
<LI><CODE>(bitwise-not<VAR> integer</VAR>)&nbsp;-&gt;&nbsp;<VAR>integer</VAR></CODE>
</UL>
These perform various logical operations on integers on a bit-by-bit
basis. `<CODE>ior</CODE>' is inclusive OR and `<CODE>xor</CODE>' is exclusive OR.
<UL><LI><CODE>(arithmetic-shift<VAR> integer bit-count</VAR>)&nbsp;-&gt;&nbsp;<VAR>integer</VAR></CODE>
</UL>
Shifts the integer by the given bit count, which must be an integer,
shifting left for positive counts and right for negative ones.
Shifting preserves the integer's sign.
<H1><A NAME="3">Arrays</A></H1>
<P>These are N-dimensional, zero-based arrays and
are in the structure <CODE>arrays</CODE>.
<P>The array interface is derived from one written by Alan Bawden.
<UL><LI><CODE>(make-array<VAR> value dimension<I><sub>0</sub></I> ...</VAR>)&nbsp;-&gt;&nbsp;<VAR>array</VAR></CODE>
<LI><CODE>(array<VAR> dimensions element<I><sub>0</sub></I> ...</VAR>)&nbsp;-&gt;&nbsp;<VAR>array</VAR></CODE>
<LI><CODE>(copy-array<VAR> array</VAR>)&nbsp;-&gt;&nbsp;<VAR>array</VAR></CODE>
</UL>
<CODE>Make-array</CODE> makes a new array with the given dimensions, each of which
must be a non-negative integer.
Every element is initially set to <CODE><VAR>value</VAR></CODE>.
<CODE>Array</CODE> Returns a new array with the given dimensions and elements.
<CODE><VAR>Dimensions</VAR></CODE> must be a list of non-negative integers,
The number of elements should be the equal to the product of the
dimensions.
The elements are stored in row-major order.
<BLOCKQUOTE><PRE>
(make-array 'a 2 3) <CODE>-&gt;</CODE> {Array 2 3}
(array '(2 3) 'a 'b 'c 'd 'e 'f)
<CODE>-&gt;</CODE> {Array 2 3}
</PRE></BLOCKQUOTE>
<P><CODE>Copy-array</CODE> returns a copy of <CODE><VAR>array</VAR></CODE>.
The copy is identical to the <CODE><VAR>array</VAR></CODE> but does not share storage with it.
<UL><LI><CODE>(array?<VAR> value</VAR>)&nbsp;-&gt;&nbsp;<VAR>boolean</VAR></CODE>
</UL>
Returns <CODE>#t</CODE> if <CODE><VAR>value</VAR></CODE> is an array.
<UL><LI><CODE>(array-ref<VAR> array index<I><sub>0</sub></I> ...</VAR>)&nbsp;-&gt;&nbsp;<VAR>value</VAR></CODE>
<LI><CODE>(array-set!<VAR> array value index<I><sub>0</sub></I> ...</VAR>)</CODE>
<LI><CODE>(array-&gt;vector<VAR> array</VAR>)&nbsp;-&gt;&nbsp;<VAR>vector</VAR></CODE>
<LI><CODE>(array-dimensions<VAR> array</VAR>)&nbsp;-&gt;&nbsp;<VAR>list</VAR></CODE>
</UL>
<CODE>Array-ref</CODE> returns the specified array element and <CODE>array-set!</CODE>
replaces the element with <CODE><VAR>value</VAR></CODE>.
<BLOCKQUOTE><PRE>
(let ((a (array '(2 3) 'a 'b 'c 'd 'e 'f)))
(let ((x (array-ref a 0 1)))
(array-set! a 'g 0 1)
(list x (array-ref a 0 1))))
<CODE>-&gt;</CODE> '(b g)
</PRE></BLOCKQUOTE>
<P><CODE>Array-&gt;vector</CODE> returns a vector containing the elements of <CODE><VAR>array</VAR></CODE>
in row-major order.
<CODE>Array-dimensions</CODE> returns the dimensions of
the array as a list.
<UL><LI><CODE>(make-shared-array<VAR> array linear-map dimension<I><sub>0</sub></I> ...</VAR>)&nbsp;-&gt;&nbsp;<VAR>array</VAR></CODE>
</UL>
<CODE>Make-shared-array</CODE> makes a new array that shares storage with <CODE><VAR>array</VAR></CODE>
and uses <CODE><VAR>linear-map</VAR></CODE> to map indicies to elements.
<CODE><VAR>Linear-map</VAR></CODE> must accept as many arguments as the number of
<CODE><VAR>dimension</VAR></CODE>s given and must return a list of non-negative integers
that are valid indicies into <CODE><VAR>array</VAR></CODE>.
<BLOCKQUOTE><PRE>
(array-ref (make-shared-array a f i0 i1 ...)
j0 j1 ...)
</PRE></BLOCKQUOTE>
is equivalent to
<BLOCKQUOTE><PRE>
(apply array-ref a (f j0 j1 ...))
</PRE></BLOCKQUOTE>
<P>As an example, the following function makes the transpose of a two-dimensional
array:
<BLOCKQUOTE><PRE>
(define (transpose array)
(let ((dimensions (array-dimensions array)))
(make-shared-array array
(lambda (x y)
(list y x))
(cadr dimensions)
(car dimensions))))
(array-&gt;vector
(transpose
(array '(2 3) 'a 'b 'c 'd 'e 'f)))
<CODE>-&gt;</CODE> '(a d b e c f)
</PRE></BLOCKQUOTE>
<H1><A NAME="4">Records</A></H1>
<P>New types can be constructed using the <CODE>define-record-type</CODE> macro
from the <CODE>define-record-types</CODE> structure
The general syntax is:
<BLOCKQUOTE><PRE>
(define-record-type <CODE><VAR>tag</VAR></CODE> <CODE><VAR>type-name</VAR></CODE>
(<CODE><VAR>constructor-name</VAR></CODE> <CODE><VAR>field-tag</VAR></CODE> ...)
<CODE><VAR>predicate-name</VAR></CODE>
(<CODE><VAR>field-tag</VAR></CODE> <CODE><VAR>accessor-name</VAR></CODE> [<CODE><VAR>modifier-name</VAR></CODE>])
...)
</PRE></BLOCKQUOTE>
This makes the following definitions:
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
<tr> <td><CODE><CODE><VAR>type-name</VAR></CODE></CODE></td> <td align=right>type</td></tr></table>
<LI><CODE>(<CODE><VAR>constructor-name</VAR></CODE><VAR> field-init ...</VAR>)&nbsp;-&gt;&nbsp;<VAR>type-name</VAR></CODE>
<LI><CODE>(<CODE><VAR>predicate-name</VAR></CODE><VAR> value</VAR>)&nbsp;-&gt;&nbsp;<VAR>boolean</VAR></CODE>
<LI><CODE>(<CODE><VAR>accessor-name</VAR></CODE><VAR> type-name</VAR>)&nbsp;-&gt;&nbsp;<VAR>value</VAR></CODE>
<LI><CODE>(<CODE><VAR>modifier-name</VAR></CODE><VAR> type-name value</VAR>)</CODE>
</UL>
<CODE><VAR>Type-name</VAR></CODE> is the record type itself, and can be used to
specify a print method (see below).
<CODE><VAR>Constructor-name</VAR></CODE> is a constructor that accepts values
for the fields whose tags are specified.
<CODE><VAR>Predicate-name</VAR></CODE> to a predicate that can returns <CODE>#t</CODE> for
elements of the type and <CODE>#f</CODE> for everything else.
The <CODE><VAR>accessor-name</VAR></CODE>s retrieve the values of fields,
and the <CODE><VAR>modifier-name</VAR></CODE>'s update them.
The <CODE><VAR>tag</VAR></CODE> is used in printing instances of the record type and
the field tags are used in the inspector and to match
constructor arguments with fields.
<UL><LI><CODE>(define-record-discloser<VAR> type discloser</VAR>)</CODE>
</UL>
<CODE>Define-record-discloser</CODE> determines how
records of type <CODE><VAR>type</VAR></CODE> are printed.
<CODE><VAR>Discloser</VAR></CODE> should be procedure which takes a single
record of type <CODE><VAR>type</VAR></CODE> and returns a list whose car is
a symbol.
The record will be printed as the value returned by <CODE><VAR>discloser</VAR></CODE>
with curly braces used instead of the usual parenthesis.
<P>For example
<BLOCKQUOTE><PRE>
(define-record-type pare :pare
(kons x y)
pare?
(x kar set-kar!)
(y kdr))
</PRE></BLOCKQUOTE>
defines <CODE>kons</CODE> to be a constructor, <CODE>kar</CODE> and <CODE>kdr</CODE> to be
accessors, <CODE>set-kar!</CODE> to be a modifier, and <CODE>pare?</CODE> to be a predicate
for a new type of object.
The type itself is named <CODE>:pare</CODE>.
<CODE>Pare</CODE> is a tag used in printing the new objects.
<P>By default, the new objects print as <CODE>#Pare</CODE>.
The print method can be modified using DEFINE-RECORD-DISCLOSER:
<BLOCKQUOTE><PRE>
(define-record-discloser :pare
(lambda (p) `(pare ,(kar p) ,(kdr p))))
</PRE></BLOCKQUOTE>
will cause the result of <CODE>(kons 1 2)</CODE> to print as
<CODE>#{pare 1 2}</CODE>.
<H1><A NAME="5">Finite record types</A></H1>
<P>The structure <CODE>finite-types</CODE> has
two macros for defining `finite' record types.
These are record types for which there are a fixed number of instances,
which are created when the record type is defined.
The syntax for the defining a finite type is:
<BLOCKQUOTE><PRE>
(define-finite-type <CODE><VAR>tag</VAR></CODE> <CODE><VAR>type-name</VAR></CODE>
(<CODE><VAR>field-tag</VAR></CODE> ...)
<CODE><VAR>predicate-name</VAR></CODE>
<CODE><VAR>vector-of-elements-name</VAR></CODE>
<CODE><VAR>name-accessor</VAR></CODE>
<CODE><VAR>index-accessor</VAR></CODE>
(<CODE><VAR>field-tag</VAR></CODE> <CODE><VAR>accessor-name</VAR></CODE> [<CODE><VAR>modifier-name</VAR></CODE>])
...
((<CODE><VAR>element-name</VAR></CODE> <CODE><VAR>field-value</VAR></CODE> ...)
...))
</PRE></BLOCKQUOTE>
This differs from <CODE>define-record-type</CODE> in the following ways:
<UL><LI>No name is specified for the constructor, but the field arguments
to the constructor are listed.
<LI>The <CODE><VAR>vector-of-elements-name</VAR></CODE> is added; it will be bound
to a vector containing all of the elements of the type.
These are constructed by applying the (unnamed) constructor to the
initial field values at the end of the form.
<LI>There are names for accessors for two required fields, name
and index.
These fields are not settable, and are not to be included
in the argument list for the constructor.
<LI>The form ends with the names and the initial field values for
the elements of the type.
The name must be first.
The remaining values must match the <CODE><VAR>field-tag</VAR></CODE>s in the constructor's
argument list.
<LI><CODE><VAR>Tag</VAR></CODE> is bound to a macro that maps <CODE><VAR>element-name</VAR></CODE>s to the
the corresponding element of the vector.
The name lookup is done at macro-expansion time.
</UL>
<BLOCKQUOTE><PRE>
(define-finite-type color :color
(red green blue)
color?
colors
color-name
color-index
(red color-red)
(green color-green)
(blue color-blue)
((white 255 255 255)
(black 0 0 0)
(yellow 255 255 0)
(maroon 176 48 96)))
(color-name (vector-ref colors 0)) <CODE>-&gt;</CODE> white
(color-name (color black)) <CODE>-&gt;</CODE> black
(color-index (color yellow)) <CODE>-&gt;</CODE> 2
(color-red (color maroon)) <CODE>-&gt;</CODE> 176
</PRE></BLOCKQUOTE>
<P>Enumerated types are finite types whose only fields are the name
and the index.
The syntax for defining an enumerated type is:
<BLOCKQUOTE><PRE>
(define-enumerated-type <CODE><VAR>tag</VAR></CODE> <CODE><VAR>type-name</VAR></CODE>
<CODE><VAR>predicate-name</VAR></CODE>
<CODE><VAR>vector-of-elements-name</VAR></CODE>
<CODE><VAR>name-accessor</VAR></CODE>
<CODE><VAR>index-accessor</VAR></CODE>
(<CODE><VAR>element-name</VAR></CODE> ...))
</PRE></BLOCKQUOTE>
In the absence of any additional fields, both the constructor argument
list and the initial field values are not required.
<P>The above example of a finite type can be pared down to the following
enumerated type:
<BLOCKQUOTE><PRE>
(define-enumerated-type color :color
color?
colors
color-name
color-index
(white black yellow maroon))
(color-name (vector-ref colors 0)) <CODE>-&gt;</CODE> white
(color-name (color black)) <CODE>-&gt;</CODE> black
(color-index (color yellow)) <CODE>-&gt;</CODE> 2
</PRE></BLOCKQUOTE>
<H1><A NAME="6">Hash tables</A></H1>
<P>These are generic hash tables, and are in the structure <CODE>tables</CODE>.
Strictly speaking they are more maps than tables, as every table has a
value for every possible key (for that type of table).
All but a finite number of those values are <CODE>#f</CODE>.
<UL><LI><CODE>(make-table<VAR></VAR>)&nbsp;-&gt;&nbsp;<VAR>table</VAR></CODE>
<LI><CODE>(make-symbol-table<VAR></VAR>)&nbsp;-&gt;&nbsp;<VAR>symbol-table</VAR></CODE>
<LI><CODE>(make-string-table<VAR></VAR>)&nbsp;-&gt;&nbsp;<VAR>string-table</VAR></CODE>
<LI><CODE>(make-integer-table<VAR></VAR>)&nbsp;-&gt;&nbsp;<VAR>integer-table</VAR></CODE>
<LI><CODE>(make-table-maker<VAR> compare-proc hash-proc</VAR>)&nbsp;-&gt;&nbsp;<VAR>procedure</VAR></CODE>
<LI><CODE>(make-table-immutable!<VAR> table</VAR>)</CODE>
</UL>
The first four functions listed make various kinds of tables.
<CODE>Make-table</CODE> returns a table whose keys may be symbols, integer,
characters, booleans, or the empty list (these are also the values
that may be used in <CODE>case</CODE> expressions).
As with <CODE>case</CODE>, comparison is done using <CODE>eqv?</CODE>.
The comparison procedures used in symbol, string, and integer tables are
<CODE>eq?</CODE>, <CODE>string=?</CODE>, and <CODE>=</CODE>.
<P><CODE>Make-table-maker</CODE> takes two procedures as arguments and returns
a nullary table-making procedure.
<CODE><VAR>Compare-proc</VAR></CODE> should be a two-argument equality predicate.
<CODE><VAR>Hash-proc</VAR></CODE> should be a one argument procedure that takes a key
and returns a non-negative integer hash value.
If <CODE>(<CODE><VAR>compare-proc</VAR></CODE> <CODE><VAR>x</VAR></CODE> <CODE><VAR>y</VAR></CODE>)</CODE> returns true,
then <CODE>(= (<CODE><VAR>hash-proc</VAR></CODE> <CODE><VAR>x</VAR></CODE>) (<CODE><VAR>hash-proc</VAR></CODE> <CODE><VAR>y</VAR></CODE>))</CODE>
must also return true.
For example, <CODE>make-integer-table</CODE> could be defined
as <CODE>(make-table-maker = abs)</CODE>.
<P><CODE>Make-table-immutable!</CODE> prohibits future modification to its argument.
<UL><LI><CODE>(table?<VAR> value</VAR>)&nbsp;-&gt;&nbsp;<VAR>boolean</VAR></CODE>
<LI><CODE>(table-ref<VAR> table key</VAR>)&nbsp;-&gt;&nbsp;<VAR>value or <CODE>#f</CODE></VAR></CODE>
<LI><CODE>(table-set!<VAR> table key value</VAR>)</CODE>
<LI><CODE>(table-walk<VAR> procedure table</VAR>)</CODE>
</UL>
<CODE>Table?</CODE> is the predicate for tables.
<CODE>Table-ref</CODE> and <CODE>table-set!</CODE> access and modify the value of <CODE><VAR>key</VAR></CODE>
in <CODE><VAR>table</VAR></CODE>.
<CODE>Table-walk</CODE> applies <CODE><VAR>procedure</VAR></CODE>, which must accept two arguments,
to every associated key and non-<CODE>#f</CODE> value in <CODE>table</CODE>.
<UL><LI><CODE>(default-hash-function<VAR> value</VAR>)&nbsp;-&gt;&nbsp;<VAR>integer</VAR></CODE>
<LI><CODE>(string-hash<VAR> string</VAR>)&nbsp;-&gt;&nbsp;<VAR>integer</VAR></CODE>
</UL>
<CODE>default-hash-function</CODE> is the hash function used in the tables
returned by <CODE>make-table</CODE>, and <CODE>string-hash</CODE> it the one used
by <CODE>make-string-table</CODE>.
<HR >
</BODY></HTML>

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +0,0 @@
-- this file is probably obsolete --
The package system interface. Much too complicated.
Signatures
make-simple-signature
make-compound-signature
signature?
signature-ref
signature-walk
Structures
make-structure
structure?
structure-signature
structure-package
structure-name
Packages
make-package
make-simple-package ;start.scm
Lookup and definition operations
package-lookup
package-lookup-type ;comp.scm
package-find-location ;rts/env.scm
package-lookup-location ;segment.scm
probe-package
package-check-assigned
package-check-variable
package-define!
package-define-type! ;hmm.
package-ensure-defined!
Things needed by the form/file/package scanner
for-each-definition ;for integrate-all-primitives!
package-accesses ;for scan-package
package-clauses ;for scan-package
package-file-name ;for scan-package
package-opens ;for scan-package
package-evaluator ;for define-syntax
package-for-syntax ;for define-syntax
Miscellaneous
$note-undefined ;eval.scm
noting-undefined-variables ;eval.scm, etc.
package-uid ;eval.scm
set-shadow-action! ;eval.scm
verify-later! ;for the define-structures macro
reset-packages-state! ;Makefile - for linker
initialize-reified-package! ;for reification
transform-for-structure-ref ;for reification ?
Inessential (for package mutation, programming environment)
check-structure
package-integrate? ;env/debug.scm
set-package-integrate?! ;env/debug.scm
package-loaded? ;env/load-package.scm
set-package-loaded?! ;env/load-package.scm
package-name ;env/command.scm
package-name-table ;env/debuginfo.scm
package-open! ;env/debug.scm
package-system-sentinel ;env/command.scm
package-unstable? ;env/pacman.scm
package? ;env/command.scm
undefined-variables ;env/debug.scm
Location names (also inessential)
flush-location-names
location-name
location-name-table
location-package-name

44
doc/porting.txt Normal file
View File

@ -0,0 +1,44 @@
What to do when your system isn't supported
First of all: DON'T PANIC. It's easy to get scsh to work on a new
system. Besides, you'll be a hero to the masses waiting for the Scheme
Shell on your platform. There is a sample "generic" system in
scsh/generic which you can copy as a base to modify. The modifications
mainly involve pulling some constants in from C header files and hacking
a few lines of C based on your standard I/O internals. I know, its C and
all, together we can survive. If you need some hand holding, feel free
to write to the scsh mailing list at scsh@zurich.ai.mit.edu.
stdio_dep.c:
This is the one C file you have to actually deal with. The code in here
defines two or three simple operations on stdio FILE*'s that are not
part of the stdio.h interface. The main things it needs to be able
to do is see if there is input ready, how much is ready, and to change
the file descriptor associated with a FILE*. Usually how to do this
is fairly obvious from <stdio.h>. Check out the other platforms for ideas.
errno.scm:
Scheme defines for C header values found in <errno.h>.
fdflags.scm:
Scheme defines for C header values found in <fcntl.h>.
netconst.scm:
Scheme defines for C header values found in socket and network includes.
signals.scm:
Scheme defines for C header values found in <sys/signal.h>.
waitcodes.scm:
Scheme defines for C header values and macros found in <sys/wait.h>.
packages.scm:
Scheme48 module definitions for the values in the above scheme files.
load-scsh.scm:
The script of commands and expressions used to build scsh.
After you've hacked these files together, it'd be nice to also hack
config.scsh to support your new machine. Run config.guess to see what it
thinks your machine is. Then, send us the info, and we'll make sure it
gets in a future release. (That means you, Jonathan.)

6
doc/scsh-manual/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*.aux *.log *.out
*.idx *.ilg *.ind *.dvi
.,*
*.toc
thumb*.png
man.ps man.pdf

View File

@ -0,0 +1 @@
html

44
doc/scsh-manual/Makefile Normal file
View File

@ -0,0 +1,44 @@
.SUFFIXES: .tex .dvi .ps .pdf $(.SUFFIXES)
TEX= front.tex intro.tex procnotation.tex syscalls.tex network.tex \
strings.tex awk.tex miscprocs.tex running.tex
TEX2PAGE=tex2page
man.dvi: $(TEX)
man.pdf: $(TEX)
.dvi.ps:
dvips -j0 -o $@ $<
.tex.dvi:
latex $< && latex $<
makeindex $(<:.tex=.idx)
rm $*.log
.tex.pdf:
pdflatex $< && thumbpdf $@ && pdflatex $<
makeindex $(<:.tex=.idx)
rm $*.log
clean:
-rm -f *.log *.png man.out man.dvi man.ps man.pdf thumb*.png
rm -rf html
INSTALL_DATA= install -c -m 644
tar:
tar cf - *.tex sty | gzip > man.tar.gz
html: $(TEX)
$(TEX2PAGE) man && $(TEX2PAGE) man
install: man.ps
@echo WARNING:
@echo WARNING: this depends on /u/su/scsh/scsh
@echo WARNING: pointing to the current release
@echo WARNING:
$(INSTALL_DATA) cheat.txt /u/su/scsh/scsh/doc/
$(INSTALL_DATA) man.ps /u/su/scsh/scsh/doc/scsh-manual.ps
$(INSTALL_DATA) $(TEX) /u/su/scsh/scsh/doc/scsh-manual/
$(INSTALL_DATA) sty/* /u/su/scsh/scsh/doc/scsh-manual/sty/

35
doc/scsh-manual/THANKS Normal file
View File

@ -0,0 +1,35 @@
Michel.Schinz@studi.epfl.ch
Documentation error in STRING-OUTPUT-PORT-OUTPUT.
Reported 12/19.
Victor Zandy
character-gobbling in (record-reader) caused by 'trim / 'peek
default misunderstanding in delimited readers. Fixed 4/5/96
Michael Becker
reap-policy = early can still lose if you loop and fork.
fork now reaps & retries if it loses and the policy is early reap.
This is a kludge until I have sigchld handlers.
Fixed 4/5/96
Tod Olson
Reported painfully slow delimited-reader I/O in November.
Michel.Schinz@studi.epfl.ch
Reported some picky little typos in the manual.
Shriram
Doc bugs in defrec.scm
euler@lavielle.COM (Lutz Euler) 2/24/97
Manual bugs and a bug in stdio->stdports.
Alan Bawden 4/97
Lots of good bug reports and fixes.
Jim Blandy 4/97
Fixes for meta.scm
Kevin Esler 4/97
Updated Irix port

32
doc/scsh-manual/ack.txt Normal file
View File

@ -0,0 +1,32 @@
Acknowledgements
Who should I thank? My so-called "colleagues," who laugh at me behind my
back, all the while becoming famous on *my* work? My worthless graduate
students, whose computer skills appear to be limited to downloading bitmaps
off of netnews? My parents, who are still waiting for me to quit "fooling
around with computers," go to med school, and become a radiologist? My
department chairman, a manager who gives one new insight into and sympathy for
disgruntled postal workers?
My God, no one could blame me--no one!--if I went off the edge and just lost
it completely one day. I couldn't get through the day as it is without the
Prozac and Jack Daniels I keep on the shelf, behind my Tops-20 JSYS manuals.
I start getting the shakes real bad around 10am, right before my advisor
meetings. A 10 oz. Jack 'n Zac helps me get through the meetings without one
of my students winding up with his severed head in a bowling-ball bag. They
look at me funny; they think I twitch a lot. I'm not twitching. I'm
controlling my impulse to snag my 9mm Sig-Sauer out from my day-pack and make
a few strong points about the quality of undergraduate education in Amerika.
If I thought anyone cared, if I thought anyone would even be reading this, I'd
probably make an effort to keep up appearances until the last possible
moment. But no one does, and no one will. So I can pretty much say exactly
what I think.
Oh, yes, the *acknowledgements.* I think not. I did it. I did it all,
by myself.
Olin Shivers
Cambridge
September 4, 1994

252
doc/scsh-manual/array.sty Normal file
View File

@ -0,0 +1,252 @@
%%
%% This is file `/usr2/distrib/latex209/nfss/array.sty' generated
%% on <1991/11/22> with the docstrip utility (v1.1k).
%%
%% The original source files were:
%%
%% /usr2/users/latex3/source/array/array.doc
%%
%% Copyright (C) 1989,1990,1991 by Frank Mittelbach, Rainer Schoepf.
%% All rights reserved.
%%
%% This file is part of the NFSS (New Font Selection Scheme) package.
%%
%% IMPORTANT NOTICE:
%%
%% You are not allowed to change this file. You may however copy this file
%% to a file with a different name and then change the copy if you obey
%% the restrictions on file changes described in readme.mz.
%%
%% You are allowed to distribute this file under the condition that it is
%% distributed together with all files mentioned in readme.mz3. If you
%% receive only some of these files from someone, complain!
%%
%% You are NOT ALLOWED to distribute this file alone. You are NOT ALLOWED
%% to take money for the distribution or use of either this file or a
%% changed version, except for a nominal charge for copying etc.
%%
%% For error reports in case of UNCHANGED versions see readme files.
%%
%% Please do not request updates from us directly. Distribution is done
%% through Mail-Servers and TeX organizations.
%%
\def\fileversion{v2.0e}
\def\filedate{91/02/07}
\def\docdate {90/08/20}
%% \CheckSum{681}
%% \CharacterTable
%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%% Digits \0\1\2\3\4\5\6\7\8\9
%% Exclamation \! Double quote \" Hash (number) \#
%% Dollar \$ Percent \% Ampersand \&
%% Acute accent \' Left paren \( Right paren \)
%% Asterisk \* Plus \+ Comma \,
%% Minus \- Point \. Solidus \/
%% Colon \: Semicolon \; Less than \<
%% Equals \= Greater than \> Question mark \?
%% Commercial at \@ Left bracket \[ Backslash \\
%% Right bracket \] Circumflex \^ Underscore \_
%% Grave accent \` Left brace \{ Vertical bar \|
%% Right brace \} Tilde \~}
%%
\@ifundefined{d@llar}{}{\endinput}
\typeout{Style-Option: `array' \fileversion
\space\space <\filedate> (F.M.)}
\typeout{English documentation dated \space <\docdate> (F.M.)}
\def\@addtopreamble#1{\xdef\@preamble{\@preamble #1}}
\def\@testpach#1{\@chclass
\ifnum \@lastchclass=6 \@ne \@chnum \@ne \else
\ifnum \@lastchclass=7 5 \else
\ifnum \@lastchclass=8 \tw@ \else
\ifnum \@lastchclass=9 \thr@@
\else \z@
\ifnum \@lastchclass = 10 \else
\@chnum
\if #1c\z@ \else
\if #1l\@ne \else
\if #1r\tw@ \else
\z@ \@chclass
\if#1|\@ne \else
\if #1!6 \else
\if #1@7 \else
\if #1<8 \else
\if #1>9 \else
10
\@chnum
\if #1m\thr@@\else
\if #1p4 \else
\if #1b5 \else
\z@ \@chclass \z@ \@preamerr \z@ \fi \fi \fi \fi
\fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi}
\def\@xexpast#1*#2#3#4\@@{%
\@tempcnta #2
\toks@={#1}\@temptokena={#3}%
\let\the@toksz\relax \let\the@toks\relax
\def\@tempa{\the@toksz}%
\ifnum\@tempcnta >0 \@whilenum\@tempcnta >0\do
{\edef\@tempa{\@tempa\the@toks}\advance \@tempcnta \m@ne}%
\let \@tempb \@xexpast \else
\let \@tempb \@xexnoop \fi
\def\the@toksz{\the\toks@}\def\the@toks{\the\@temptokena}%
\edef\@tempa{\@tempa}%
\expandafter \@tempb \@tempa #4\@@}
\def\prepnext@tok{\advance \count@ \@ne
\toks\count@={}}
\def\save@decl{\toks\count@ \expandafter{\@nextchar}}
\def\insert@column{%
\the@toks \the \@tempcnta
{\ignorespaces \@sharp \unskip}%
\the@toks \the \count@ \relax}
\newdimen\col@sep
\def\@acol{\@addtopreamble{\hskip\col@sep}}
\def\@mkpream#1{\gdef\@preamble{}\@lastchclass 4 \@firstamptrue
\let\@sharp\relax \let\@startpbox\relax \let\@endpbox\relax
\@xexpast #1*0x\@@
\count@\m@ne
\let\the@toks\relax
\prepnext@tok
\expandafter \@tfor \expandafter \@nextchar
\expandafter :\expandafter =\@tempa \do
{\@testpach\@nextchar
\ifcase \@chclass \@classz \or \@classi \or \@classii
\or \save@decl \or \or \@classv \or \@classvi
\or \@classvii \or \@classviii \or \@classix
\or \@classx \fi
\@lastchclass\@chclass}%
\ifcase\@lastchclass
\@acol \or
\or
\@acol \or
\@preamerr \thr@@ \or
\@preamerr \tw@ \@addtopreamble\@sharp \or
\or
\else \@preamerr \@ne \fi
\def\the@toks{\the\toks}}
\def\@classx{%
\ifcase \@lastchclass
\@acolampacol \or
\@addamp \@acol \or
\@acolampacol \or
\or
\@acol \@firstampfalse \or
\@addamp
\fi}
\def\@classz{\@classx
\@tempcnta \count@
\prepnext@tok
\@addtopreamble{\ifcase \@chnum
\hfil
\d@llar
\insert@column
\d@llar \hfil \or
\d@llar \insert@column \d@llar \hfil \or
\hfil\kern\z@ \d@llar \insert@column \d@llar \or
$\vcenter
\@startpbox{\@nextchar}\insert@column \@endpbox $\or
\vtop \@startpbox{\@nextchar}\insert@column \@endpbox \or
\vbox \@startpbox{\@nextchar}\insert@column \@endpbox
\fi}\prepnext@tok}
\def\@classix{\ifnum \@lastchclass = \thr@@
\@preamerr \thr@@ \fi
\@classx}
\def\@classviii{\ifnum \@lastchclass >\z@
\@preamerr 4\@chclass 6 \@classvi \fi}
\def\@arrayrule{\@addtopreamble \vline}
\def\@classvii{\ifnum \@lastchclass = \thr@@
\@preamerr \thr@@ \fi}
\def\@classvi{\ifcase \@lastchclass
\@acol \or
\@addtopreamble{\hskip \doublerulesep}\or
\@acol \or
\@classvii
\fi}
\def\@classii{\advance \count@ \m@ne
\save@decl\prepnext@tok}
\def\@classv{\save@decl
\@addtopreamble{\d@llar\the@toks\the\count@\relax\d@llar}%
\prepnext@tok}
\def\@classi{\@classvi
\ifcase \@chnum \@arrayrule \or
\@classv \fi}
\def\@startpbox#1{\bgroup
\hsize #1 \@arrayparboxrestore
\vrule \@height \ht\@arstrutbox \@width \z@}
\def\@endpbox{\vrule \@width \z@ \@depth \dp \@arstrutbox \egroup}
\def\@array[#1]#2{%
\@tempdima \ht \strutbox
\advance \@tempdima by\extrarowheight
\setbox \@arstrutbox \hbox{\vrule
\@height \arraystretch \@tempdima
\@depth \arraystretch \dp \strutbox
\@width \z@}%
\begingroup
\@mkpream{#2}%
\xdef\@preamble{\ialign \@halignto
\bgroup \@arstrut \@preamble
\tabskip \z@ \cr}%
\endgroup
\if #1t\vtop \else \if#1b\vbox \else \vcenter \fi \fi
\bgroup
\let \@sharp ##\let \protect \relax
\lineskip \z@
\baselineskip \z@
\m@th
\let\\ \@arraycr \let\par\@empty \@preamble}
\newdimen \extrarowheight
\extrarowheight=0pt
\def\@arstrut{\unhcopy\@arstrutbox}
\def\@arraycr{{\ifnum 0=`}\fi
\@ifstar \@xarraycr \@xarraycr}
\def\@xarraycr{\@ifnextchar [%
\@argarraycr {\ifnum 0=`{\fi}\cr}}
\def\@argarraycr[#1]{\ifnum0=`{\fi}\ifdim #1>\z@
\@xargarraycr{#1}\else \@yargarraycr{#1}\fi}
\def\@xargarraycr#1{\unskip
\@tempdima #1\advance\@tempdima \dp\@arstrutbox
\vrule \@depth\@tempdima \@width\z@ \cr}
\def\@yargarraycr#1{\cr\noalign{\vskip #1}}
\def\multicolumn#1#2#3{%
\multispan{#1}\begingroup
\def\@addamp{\if@firstamp \@firstampfalse \else
\@preamerr 5\fi}%
\@mkpream{#2}\@addtopreamble\@empty
\endgroup
\def\@sharp{#3}%
\@arstrut \@preamble \ignorespaces}
\def\array{\col@sep\arraycolsep
\def\d@llar{$}\gdef\@halignto{}%
\@tabarray}
\def\@tabarray{\@ifnextchar[{\@array}{\@array[c]}}
\def\tabular{\gdef\@halignto{}\@tabular}
\expandafter\def\csname tabular*\endcsname#1{%
\gdef\@halignto{to#1}\@tabular}
\def\@tabular{%
\leavevmode
\hbox \bgroup $\col@sep\tabcolsep \let\d@llar\@empty
\@tabarray}
\def\endarray{\crcr \egroup \egroup \gdef\@preamble{}}
\def\endtabular{\endarray $\egroup}
\expandafter\let\csname endtabular*\endcsname=\endtabular
\let\@ampacol=\relax \let\@expast=\relax
\let\@arrayclassiv=\relax \let\@arrayclassz=\relax
\let\@tabclassiv=\relax \let\@tabclassz=\relax
\let\@arrayacol=\relax \let\@tabacol=\relax
\let\@tabularcr=\relax \let\@@endpbox=\relax
\let\@argtabularcr=\relax \let\@xtabularcr=\relax
\def\@preamerr#1{\def\@tempd{{..} at wrong position: }%
\@latexerr{%
\ifcase #1 Illegal pream-token (\@nextchar): `c' used\or %0
Missing arg: token ignored\or %1
Empty preamble: `l' used\or %2
>\@tempd token ignored\or %3
<\@tempd changed to !{..}\or %4
Only one colum-spec. allowed.\fi}\@ehc} %5
\def\@tfor#1:=#2\do#3{\def\@fortmp{#2}\ifx\@fortmp\@empty
\else\@tforloop#2\@nil\@nil\@@#1{#3}\fi}
\endinput
%%
%% End of file `/usr2/distrib/latex209/nfss/array.sty'.

672
doc/scsh-manual/awk.tex Normal file
View File

@ -0,0 +1,672 @@
%&latex -*- latex -*-
\chapter{Awk, record I/O, and field parsing}
\label{chapt:fr-awk}
{\Unix} programs frequently process streams of records,
where each record is delimited by a newline,
and records are broken into fields with other delimiters
(for example, the colon character in \ex{/etc/passwd}).
Scsh has procedures that allow the programmer to easily
do this kind of processing.
Scsh's field parsers can also be used to parse other kinds
of delimited strings, such as colon-separated \verb|$PATH| lists.
These routines can be used with scsh's \ex{awk} loop construct
to conveniently perform pattern-directed computation over streams
of records.
\section{Record I/O and field parsing}
\label{sec:field-reader}
The procedures in this section are used to read records from
I/O streams and parse them into fields.
A record is defined as text terminated by some delimiter (usually a newline).
A record can be split into fields by using regular expressions in
one of several ways: to \emph{match} fields, to \emph{separate} fields,
or to \emph{terminate} fields.
The field parsers can be applied to arbitrary strings (one common use is
splitting environment variables such as \ex{\$PATH} at colons into its
component elements).
The general delimited-input procedures described in
chapter~\ref{chapt:rdelim} are also useful for reading simple records,
such as single lines, paragraphs of text, or strings terminated by specific
characters.
\subsection{Reading records}
\defun{record-reader} {[delims elide-delims? handle-delim]} {\proc}
\begin{desc}
Returns a procedure that reads records from a port. The
procedure is invoked as follows:
%
\codex{(\var{reader} \var{[port]}) $\longrightarrow$
\textrm{\textit{{\str} or eof}}}
%
A record is a sequence of characters terminated by one of the characters
in \var{delims} or eof. If \var{elide-delims?} is true, then a contiguous
sequence of delimiter chars are taken as a single record delimiter. If
\var{elide-delims?} is false, then a delimiter char coming immediately
after a delimiter char produces an empty-string record. The reader
consumes the delimiting char(s) before returning from a read.
The \var{delims} set defaults to the set $\{\mbox{newline}\}$.
It may be a charset, string, character, or character predicate,
and is coerced to a charset.
The \var{elide-delims?} flag defaults to \ex{\#f}.
The \var{handle-delim} argument controls what is done with the record's
terminating delimiter.
\begin{inset}
\begin{tabular}{lp{0.6\linewidth}}
\ex{'trim} & Delimiters are trimmed. (The default)\\
\ex{'split}& Reader returns delimiter string as a second argument.
If record is terminated by EOF, then the eof object is
returned as this second argument. \\
\ex{'concat} & The record and its delimiter are returned as
a single string.
\end{tabular}
\end{inset}
The reader procedure returned takes one optional argument, the port
from which to read, which defaults to the current input port. It returns
a string or eof.
\end{desc}
\subsection{Parsing fields}
\label{sec:field-splitter}
\defun {field-splitter} {[field num-fields]} \proc
\defunx {infix-splitter} {[delim num-fields handle-delim]} \proc
\defunx {suffix-splitter} {[delim num-fields handle-delim]} \proc
\defunx {sloppy-suffix-splitter} {[delim num-fields handle-delim]} \proc
\begin{desc}
These functions return a parser function that can be used as follows:
\codex{(\var{parser} \var{string} \var{[start]}) $\longrightarrow$
\var{string-list}}
The returned parsers split strings into fields defined
by regular expressions. You can parse by specifying a pattern that
\emph{separates} fields, a pattern that \emph{terminates} fields, or
a pattern that \emph{matches} fields:
\begin{inset}
\begin{tabular}{l@{\qquad}l}
Procedure & Pattern \\ \hline
\ex{field-splitter} & matches fields \\
\ex{infix-splitter} & separates fields \\
\ex{suffix-splitter}& terminates fields \\
\ex{sloppy-suffix-splitter} & terminates fields
\end{tabular}
\end{inset}
These parser generators are controlled by a range of options, so that you
can precisely specify what kind of parsing you want. However, these
options default to reasonable values for general use.
Defaults:
\begin{tightinset}
\begin{tabular}{l@{\quad=\quad }ll}
\var{delim} & \ex{(rx (| (+ white) eos))} & (suffix delimiter: white space or eos) \\
\multicolumn{1}{l}{} & \ex{(rx (+ white))} & (infix delimiter: white space) \\
\var{field} & \verb|(rx (+ (~ white)))| & (non-white-space) \\
\var{num-fields} & \verb|#f| & (as many fields as possible) \\
\var{handle-delim} & \verb|'trim| & (discard delimiter chars)
\end{tabular}
\end{tightinset}
{\ldots}which means: break the string at white space, discarding the
white space, and parse as many fields as possible.
The \var{delim} parameter is a regular expression matching the text
that occurs between fields.
See chapter~\ref{chapt:sre} for information on regular expressions,
and the \ex{rx} form used to specify them.
In the separator case,
it defaults to a pattern matching white space;
in the terminator case,
it defaults to white space or end-of-string.
The \var{field} parameter is a regular expression used
to match fields. It defaults to non-white-space.
The \var{delim} patterns may also be given as a string,
character, or char-set, which are coerced to regular expressions.
So the following expressions are all equivalent,
each producing a function that splits strings apart at colons:
\begin{inset}
\begin{verbatim}
(infix-splitter (rx ":"))
(infix-splitter ":")
(infix-splitter #\:)
(infix-splitter (char-set #\:))\end{verbatim}
\end{inset}
The boolean \var{handle-delim} determines what to do with delimiters.
\begin{tightinset}\begin{tabular}{ll}
\ex{'trim} & Delimiters are thrown away after parsing. (default) \\
\ex{'concat} & Delimiters are appended to the field preceding them. \\
\ex{'split} & Delimiters are returned as separate elements in
the field list.
\end{tabular}
\end{tightinset}
The \var{num-fields} argument used to create the parser specifies how many
fields to parse. If \ex{\#f} (the default), the procedure parses them all.
If a positive integer $n$, exactly that many fields are parsed; it is an
error if there are more or fewer than $n$ fields in the record. If
\var{num-fields} is a negative integer or zero, then $|n|$ fields
are parsed, and the remainder of the string is returned in the last
element of the field list; it is an error if fewer than $|n|$ fields
can be parsed.
The field parser produced is a procedure that can be employed as
follows:
\codex{(\var{parse} \var{string} \var{[start]}) \evalto \var{string-list}}
The optional \var{start} argument (default 0) specifies where in the string
to begin the parse. It is an error if
$\var{start} > \ex{(string-length \var{string})}$.
The parsers returned by the four parser generators implement different
kinds of field parsing:
\begin{description}
\item[\ex{field-splitter}]
The regular expression specifies the actual field.
\item[\ex{suffix-splitter}]
Delimiters are interpreted as element \emph{terminators}.
If vertical-bar is the the delimiter, then the string \ex{""}
is the empty record \ex{()}, \ex{"foo|"} produces a one-field record
\ex{("foo")}, and \ex{"foo"} is an error.
The syntax of suffix-delimited records is:
\begin{inset}
\begin{tabular}{lcll}
\synvar{record} & ::= & \ex{""} \qquad (Empty record) \\
& $|$ & \synvar{element} \synvar{delim}
\synvar{record}
\end{tabular}
\end{inset}
It is an error if a non-empty record does not end with a delimiter.
To make the last delimiter optional, make sure the delimiter regexp
matches the end-of-string (sre \ex{eos}).
\item [\ex{infix-splitter}]
Delimiters are interpreted as element \emph{separators}. If comma is the
delimiter, then the string \ex{"foo,"} produces a two-field
record \ex{("foo" "")}.
The syntax of infix-delimited records is:
\begin{inset}
\begin{tabular}{lcll}
\synvar{record} & ::= & \ex{""} \qquad (Forced to be empty record) \\
& $|$ & \synvar{real-infix-record} \\
\\
\synvar{real-infix-record} & ::= & \synvar{element} \synvar{delim}
\synvar{real-infix-record} \\
& $|$ & \synvar{element}
\end{tabular}
\end{inset}
Note that separator semantics doesn't really allow for empty
records---the straightforward grammar (\ie, \synvar{real-infix-record})
parses an empty string as a singleton list whose one field is the empty
string, \ex{("")}, not as the empty record \ex{()}. This is unfortunate,
since it means that infix string parsing doesn't make \ex{string-append}
and \ex{append} isomorphic. For example,
\codex{((infix-splitter ":") (string-append \var{x} ":" \var{y}))}
doesn't always equal
\begin{code}
(append ((infix-splitter ":") \var{x})
((infix-splitter ":") \var{y}))\end{code}
It fails when \var{x} or \var{y} are the empty string.
Terminator semantics \emph{does} preserve a similar isomorphism.
However, separator semantics is frequently what other Unix software
uses, so to parse their strings, we need to use it. For example,
Unix \verb|$PATH| lists have separator semantics. The path list
\ex{"/bin:"} is broken up into \ex{("/bin" "")}, not \ex{("/bin")}.
Comma-separated lists should also be parsed this way.
\item[\ex{sloppy-suffix}]
The same as the \ex{suffix} case, except that the parser will skip an
initial delimiter string if the string begins with one instead of parsing
an initial empty field. This can be used, for example, to field-split a
sequence of English text at white-space boundaries, where the string may
begin or end with white space, by using regex
\begin{code}{(rx (| (+ white) eos))}\end{code}
(But you would be better off using \ex{field-splitter} in this case.)
\end{description}
\end{desc}
Figure~\ref{fig:splitters} shows how the different parser grammars
split apart the same strings.
%
\begin{boxedfigure}{tbp}
\begin{center}\small
\begin{tabular}{lllll}
Record & : suffix & \verb!:|$! suffix & : infix & non-: field \\
\hline
\ex{""} & \ex{()} & \ex{()} & \ex{()} & \ex{()} \\
\ex{":"} & \ex{("")} & \ex{("")} & \ex{("" "")} & \ex{()} \\
\ex{"foo:"} & \ex{("foo")} & \ex{("foo")} & \ex{("foo" "")} & \ex{("foo")} \\
\ex{":foo"}& \emph{error} & \ex{("" "foo")}& \ex{("" "foo")}& \ex{("foo")} \\
\ex{"foo:bar"} & \emph{error} & \ex{("foo" "bar")} & \ex{("foo" "bar")} & \ex{("foo" "bar")}
\end{tabular}
\end{center}
\caption{Using different grammars to split records into fields.}
\label{fig:splitters}
\end{boxedfigure}
%
Having to choose between the different grammars requires you to decide
what you want, but at least you can be precise about what you are parsing.
Take fifteen seconds and think it out. Say what you mean; mean what you
say.
\defun{join-strings} {string-list [delimiter grammar]} \str
\begin{desc}
This procedure is a simple unparser---it pastes strings together using
the delimiter string.
The \var{grammar} argument is one of the symbols \ex{infix} (the default)
or \ex{suffix}; it determines whether the
delimiter string is used as a separator or as a terminator.
The delimiter is the string used to delimit elements; it defaults to
a single space \ex{" "}.
Example:
\begin{code}
(join-strings '("foo" "bar" "baz") ":")
\qquad{\evalto} "foo:bar:baz"\end{code}
\end{desc}
\subsection{Field readers}
\defun{field-reader} {[field-parser rec-reader]} \proc
\begin{desc}
This utility returns a procedure that reads records with field structure
from a port.
The reader's interface is designed to make it useful in the \ex{awk}
loop macro (section~\ref{sec:awk}).
The reader is used as follows:
\codex{(\var{reader} \var{[port]}) {\evalto} \var{[raw-record parsed-record]} or \var{[eof ()]}}
When the reader is applied to an input port (default: the current
input port), it reads a record using \var{rec-reader}. If this record isn't
the eof object, it is parsed with \var{field-parser}. These two
values---the record, and its parsed representation---are returned
as multiple values from the reader.
When called at eof, the reader returns [eof-object \ex{()}].
Although the record reader typically returns a string, and
the field-parser typically takes a string argument, this is not
required. The record reader can produce, and the field-parser consume,
values of any type. However, the empty list returned as the
parsed value on eof is hardwired into the field reader.
For example, if port \ex{p} is open on \ex{/etc/passwd}, then
\codex{((field-reader (infix-splitter ":" 7)) p)}
returns two values:
{\small
\begin{widecode}
"dalbertz:mx3Uaqq0:107:22:David Albertz:/users/dalbertz:/bin/csh"
("dalbertz" "mx3Uaqq0" "107" "22" "David Albertz" "/users/dalbertz"
"/bin/csh")\end{widecode}}
The \var{field-parser} defaults to the value of \ex{(field-splitter)},
a parser that picks out sequences of non-white-space strings.
The \var{rec-reader} defaults to \ex{read-line}.
Figure~\ref{fig:field-readers} shows \ex{field-reader} being
used to read different kinds of Unix records.
\begin{boxedfigure}{tbhp}
\begin{centercode}
;;; /etc/passwd reader
(field-reader (infix-splitter ":" 7))
; wandy:3xuncWdpKhR.:73:22:Wandy Saetan:/usr/wandy:/bin/csh
;;; Two ls -l output readers
(field-reader (infix-splitter (rx (+ white)) 8))
(field-reader (infix-splitter (rx (+ white)) -7))
; -rw-r--r-- 1 shivers 22880 Sep 24 12:45 scsh.scm
;;; Internet hostname reader
(field-reader (field-splitter (rx (+ (~ ".")))))
; stat.sinica.edu.tw
;;; Internet IP address reader
(field-reader (field-splitter (rx (+ (~ "."))) 4))
; 18.24.0.241
;;; Line of integers
(let ((parser (field-splitter (rx (? ("+-")) (+ digit)))))
(field-reader (\l{s} (map string->number (parser s))))
; 18 24 0 241
;;; Same as above.
(let ((reader (field-reader (field-splitter (rx (? ("+-"))
(+ digit))))))
(\lx{maybe-port} (map string->number (apply reader maybe-port))))
; Yale beat harvard 26 to 7.\end{centercode}
\caption{Some examples of \protect\ex{field-reader}}
\label{fig:field-readers}
\end{boxedfigure}
\end{desc}
\subsection{Forward-progress guarantees and empty-string matches}
A loop that pulls text off a string by repeatedly matching a regexp
against that string can conceivably get stuck in an infinite loop if
the regexp matches the empty string. For example, the SREs
\ex{bos}, \ex{eos}, \ex{(* any)}, and \ex{(| "foo" (* (~ "f")))}
can all match the empty string.
The routines in this package that iterate through strings with regular
expressions are careful to handle this empty-string case.
If a regexp matches the empty string, the next search starts, not from
the end of the match (which in the empty string case is also the
beginning---that's the problem), but from the next character over.
This is the correct behaviour. Regexps match the longest possible
string at a given location, so if the regexp matched the empty string
at location $i$, then it is guaranteed it could not have matched
a longer pattern starting with character $i$. So we can safely begin
our search for the next match at char $i+1$.
With this provision, every iteration through the loop makes some forward
progress, and the loop is guaranteed to terminate.
This has the effect you want with field parsing. For example, if you split
a string with the empty pattern, you will explode the string into its
individual characters:
\codex{((suffix-splitter (rx)) "foo") {\evalto} ("" "f" "o" "o")}
However, even though this boundary case is handled correctly, we don't
recommend using it. Say what you mean---just use a field splitter:
\codex{((field-splitter (rx any)) "foo") {\evalto} ("f" "o" "o")}
Or, more efficiently,
\codex{((\l{s} (map string (string->list s))) "foo")}
\subsection{Reader limitations}
Since all of the readers in this package require the ability to peek
ahead one char in the input stream, they cannot be applied to raw
integer file descriptors, only Scheme input ports. This is because
Unix doesn't support peeking ahead into input streams.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Awk}
\label{sec:awk}
Scsh provides a loop macro and a set of field parsers that can
be used to perform text processing very similar to the Awk programming
language.
The basic functionality of Awk is factored in scsh into its component
parts.
The control structure is provided by the \ex{awk} loop macro;
the text I/O and parsers are provided by the field-reader subroutine library
(section~\ref{sec:field-reader}).
This factoring allows the programmer to compose the basic loop structure
with any parser or input mechanism at all.
If the parsers provided by the field-reader package are insufficient,
the programmer can write a custom parser in Scheme and use it with
equal ease in the awk framework.
Awk-in-scheme is given by a loop macro called \ex{awk}. It looks like
this:
\begin{code}\cdmath
(awk \synvar{next-record} \synvar{record\&field-vars}
{\rm[\synvar{counter}]} \synvar{state-var-decls}
\synvar{clause$_1$} \ldots)\index{awk}\end{code}
The body of the loop is a series of clauses, each one representing
a kind of condition/action pair. The loop repeatedly reads a record,
and then executes each clause whose condition is satisfied by the record.
Here's an example that reads lines from port \ex{p}
and prints the line number and line of every line containing the
string ``\ex{Church-Rosser}'':
\begin{code}
(awk (read-line) (ln) lineno ()
("Church-Rosser" (format #t "~d: ~s~%" lineno ln)))\end{code}
This example has just one clause in the loop body, the one that
tests for matches against the regular expression ``\ex{Church-Rosser}''.
The \synvar{next-record} form is an expression that is evaluated each time
through the loop to produce a record to process.
This expression can return multiple values;
these values are bound to the variables given in the
\synvar{record\&field-vars} list of variables.
The first value returned is assumed to be the record;
when it is the end-of-file object, the loop terminates.
For example, let's suppose we want to read items from \ex{/etc/password},
and we use the \ex{field-reader} procedure to define a record parser for
\ex{/etc/passwd} entries:
\codex{(define read-passwd (field-reader (infix-splitter ":" 7)))}
binds \ex{read-passwd} to a procedure that reads in a line of text when
it is called, and splits the text at colons. It returns two values:
the entire line read, and a seven-element list of the split-out fields.
(See section~\ref{sec:field-reader} for more on \ex{field-reader} and
\ex{infix-splitter}.)
So if the \synvar{next-record} form in an \ex{awk} expression is
\ex{(read-passwd)}, then \synvar{record\&field-vars} must be a list of
two variables, \eg,
\codex{(record field-vec)}
since \ex{read-passwd} returns two values.
Note that \ex{awk} allows us to use \emph{any} record reader we want in the
loop, returning whatever number of values we like. These values
don't have to be strings or string lists. The only requirement
is that the record reader return the eof object as its first value
when the loop should terminate.
The \ex{awk} loop allows the programmer to have loop variables. These are
declared and initialised by the \synvar{state-var-decls} form, a
\codex{((\var{var} \var{init-exp}) (\var{var} \var{init-exp}) \ldots)}
list rather like the \ex{let} form. Whenever a clause in the loop body
executes, it evaluates to as many values as there are state variables,
updating them.
The optional \synvar{counter} variable is an iteration counter.
It is bound to 0 when the loop starts.
The counter is incremented each time a non-eof record is read.
There are several kinds of loop clause. When evaluating the body of the
loop, \ex{awk} evaluates \emph{all} the clauses sequentially.
Unlike \ex{cond}, it does not stop after the first clause is satisfied;
it checks them all.
\begin{itemize}
\itum{\ex{(\var{test} \vari{body}1 \vari{body}2 \ldots)}}
If \var{test} is true, execute the body forms. The last body form
is the value of the clause. The test and body forms are evaluated
in the scope of the record and state variables.
The \var{test} form can be one of:
\begin{inset}
\begin{tabular}{lp{0.6\linewidth}}
\var{integer}: & The test is true for that iteration of the loop.
The first iteration is \#1. \\
\var{sre}: & A regular expression, in SRE notation
(see chapter~\ref{chapt:sre}) can be used as
a test. The test is successful if the pattern
matches the record.
In particular, note that any string is an SRE. \\
\ex{(when \var{expr})}: &
The body of a \ex{when} test is evaluated as a
Scheme boolean expression in the inner scope of the
\ex{awk} form. \\
\var{expr}: & If the form is none of the above, it is treated as
a Scheme expression---in practice, the \ex{when}
keyword is only needed in cases where SRE/Scheme
expression ambiguity might occur.
\end{tabular}
\end{inset}
\itum{\begin{tabular}[t]{l}
\ex{(range\ \ \ \var{start-test} \var{stop-test} \vari{body}1 \ldots)} \\
\ex{(:range\ \ \var{start-test} \var{stop-test} \vari{body}1 \ldots)} \\
\ex{(range:\ \ \var{start-test} \var{stop-test} \vari{body}1 \ldots)} \\
\ex{(:range:\ \var{start-test} \var{stop-test} \vari{body}1 \ldots)}
\end{tabular}}
%
These clauses become activated when \var{start-test} is true;
they stay active on all further iterations until \var{stop-test}
is true.
So, to print out the first ten lines of a file, we use the clause:
\codex{(:range: 1 10 (display record))}
The colons control whether or not the start and stop lines
are processed by the clause. For example:
\begin{inset}\begin{tabular}{l@{\qquad}l}
\ex{(range\ \ \ 1 5\ \ \ldots)} & Lines \phantom{1} 2 3 4 \\
\ex{(:range\ \ 1 5\ \ \ldots)} & Lines 1 2 3 4 \\
\ex{(range:\ \ 1 5\ \ \ldots)} & Lines \phantom{1} 2 3 4 5 \\
\ex{(:range: 1 5\ \ \ldots)} & Lines 1 2 3 4 5
\end{tabular}
\end{inset}
A line can trigger both tests, either simultaneously starting and
stopping an active region, or simultaneously stopping one and starting
a new one, so ranges can abut seamlessly.
\itum{\ex{(else \vari{body}1 \vari{body}2 \ldots)}}
If no other clause has executed since the top of the loop, or
since the last \ex{else} clause, this clause executes.
\itum{\ex{(\var{test} => \var{exp})}}
If evaluating \ex{test} produces a true value,
apply \var{exp} to that value.
If \var{test} is a regular expression, then \var{exp} is applied
to the match data structure returned by the regexp match routine.
\itum{\ex{(after \vari{body}1 \ldots)}}
This clause executes when the loop encounters EOF. The body forms
execute in the scope of the state vars and the record-count var,
if there are any. The value of the last body form is the value
of the entire awk form.
If there is no \ex{after} clause, \ex{awk} returns the loop's state
variables as multiple values.
\end{itemize}
\subsection{Examples}
Here are some examples of \ex{awk} being used to process various types
of input stream.
\begin{code}
(define $ list-ref) ; Saves typing.
;;; Print out the name and home-directory of everyone in /etc/passwd:
(let ((read-passwd (field-reader (infix-splitter ":" 7))))
(call-with-input-file "/etc/passwd"
(lambda (port)
(awk (read-passwd port) (record fields) ()
(#t (format #t "~a's home directory is ~a~%"
($ fields 0)
($ fields 5)))))))\end{code}
\begin{code}
;;; Print out the user-name and home-directory of everyone whose
;;; name begins with "S"
(let ((read-passwd (field-reader (infix-splitter ":" 7))))
(call-with-input-file "/etc/passwd"
(lambda (port)
(awk (read-passwd port) (record fields) ()
((: bos "S")
(format #t "~a's home directory is ~a~%"
($ fields 0)
($ fields 5)))))))\end{code}
\begin{code}
;;; Read a series of integers from stdin. This expression evaluates
;;; to the number of positive numbers that were read. Note our
;;; "record-reader" is the standard Scheme READ procedure.
(awk (read) (i) ((npos 0))
((> i 0) (+ npos 1)))\end{code}
\begin{code}
;;; Filter -- pass only lines containing my name.
(awk (read-line) (line) ()
("Olin" (display line) (newline)))\end{code}
\begin{code}
;;; Count the number of non-comment lines of code in my Scheme source.
(awk (read-line) (line) ((nlines 0))
((: bos (* white) ";") nlines) ; A comment line.
(else (+ nlines 1))) ; Not a comment line.\end{code}
\begin{code}
;;; Read numbers, counting the evens and odds.
(awk (read) (val) ((evens 0) (odds 0))
((> val 0) (display "pos ") (values evens odds)) ; Tell me about
((< val 0) (display "neg ") (values evens odds)) ; sign, too.
(else (display "zero ") (values evens odds))
((even? val) (values (+ evens 1) odds))
(else (values evens (+ odds 1))))\end{code}
\begin{code}
;;; Determine the max length of all the lines in the file.
(awk (read-line) (line) ((max-len 0))
(#t (max max-len (string-length line))))\end{code}
\begin{code}
;;; (This could also be done with PORT-FOLD:)
(port-fold (current-input-port) read-line
(lambda (line maxlen) (max (string-length line) maxlen))
0)\end{code}
\begin{code}
;;; Print every line longer than 80 chars.
;;; Prefix each line with its line #.
(awk (read-line) (line) lineno ()
((> (string-length line) 80)
(format #t "~d: ~s~%" lineno line)))\end{code}
\begin{code}
;;; Strip blank lines from input.
(awk (read-line) (line) ()
((~ white) (display line) (newline)))\end{code}
\begin{code}
;;; Sort the entries in /etc/passwd by login name.
(for-each (lambda (entry) (display (cdr entry)) (newline)) ; Out
(sort (lambda (x y) (string<? (car x) (car y))) ; Sort
(let ((read (field-reader (infix-splitter ":" 7)))) ; In
(awk (read) (line fields) ((ans '()))
(#t (cons (cons ($ fields 0) line) ans))))))\end{code}
\begin{code}
;;; Prefix line numbers to the input stream.
(awk (read-line) (line) lineno ()
(#t (format #t "~d:\\t~a~%" lineno line)))\end{code}
\section{Backwards compatibility}
Previous scsh releases provided an \ex{awk} form with a different syntax,
designed around regular expressions written in Posix notation as strings,
rather than SREs.
This form is still available in a separate module for old code.
It'll be documented in the next release of this manual. Dig around
in the sources for it.

View File

@ -0,0 +1,45 @@
% boxedminipage.sty
%
% adds the boxedminipage environment---just like minipage, but has a
% box round it!
%
% The thickneess of the rules around the box is controlled by
% \fboxrule, and the distance between the rules and the edges of the
% inner box is governed by \fboxsep.
%
% This code is based on Lamport's minipage code.
\def\boxedminipage{\@ifnextchar [{\@iboxedminipage}{\@iboxedminipage[c]}}
\def\@iboxedminipage[#1]#2{\leavevmode \@pboxswfalse
\if #1b\vbox
\else \if #1t\vtop
\else \ifmmode \vcenter
\else \@pboxswtrue $\vcenter
\fi
\fi
\fi\bgroup % start of outermost vbox/vtop/vcenter
\hsize #2
\hrule\@height\fboxrule
\hbox\bgroup % inner hbox
\vrule\@width\fboxrule \hskip\fboxsep \vbox\bgroup % innermost vbox
\advance\hsize -2\fboxrule \advance\hsize-2\fboxsep
\textwidth\hsize \columnwidth\hsize
\@parboxrestore
\def\@mpfn{mpfootnote}\def\thempfn{\thempfootnote}\c@mpfootnote\z@
\let\@footnotetext\@mpfootnotetext
\let\@listdepth\@mplistdepth \@mplistdepth\z@
\@minipagerestore\@minipagetrue
\everypar{\global\@minipagefalse\everypar{}}}
\def\endboxedminipage{%
\par\vskip-\lastskip
\ifvoid\@mpfootins\else
\vskip\skip\@mpfootins\footnoterule\unvbox\@mpfootins\fi
\egroup % ends the innermost \vbox
\hskip\fboxsep \vrule\@width\fboxrule
\egroup % ends the \hbox
\hrule\@height\fboxrule
\egroup% ends the vbox/vtop/vcenter
\if@pboxsw $\fi}

296
doc/scsh-manual/code.sty Normal file
View File

@ -0,0 +1,296 @@
% code.sty: -*- latex -*-
% Latex macros for a "weak" verbatim mode.
% -- like verbatim, except \, {, and } have their usual meanings.
% Environments: code, tightcode, codeaux, codebox, centercode
% Commands: \dcd, \cddollar, \cdmath, \cd, \codeallowbreaks, \codeskip, \^
% Already defined in LaTeX, but of some relevance: \#, \$, \%, \&, \_, \{, \}
% Changelog at the end of the file.
% These commands give you an environment, code, that is like verbatim
% except that you can still insert commands in the middle of the environment:
% \begin{code}
% for(x=1; x<loop_bound; x++)
% y += x^3; /* {\em Add in {\tt x} cubed} */
% \end{code}
%
% All characters are ordinary except \{}. To get \{} in your text,
% you use the commands \\, \{, and \}.
% These macros mess with the definition of the special chars (e.g., ^_~%).
% The characters \{} are left alone, so you can still have embedded commands:
% \begin{code} f(a,b,\ldots,y,z) \end{code}
% However, if your embedded commands use the formerly-special chars, as in
% \begin{code} x := x+1 /* \mbox{\em This is $y^3$} */ \end{code}
% then you lose. The $ and ^ chars are scanned in as non-specials,
% so they don't work. If the chars are scanned *outside* the code env,
% then you have no problem:
% \def\ycube{$y^3$}
% \begin{code} x := x+1 /* {\em This is \ycube} */ \end{code}
% If you must put special chars inside the code env, you do it by
% prefixing them with the special \dcd ("decode") command, that
% reverts the chars to back to special status:
% \begin{code} x := x+1 /* {\dcd\em This is $y^3$} */ \end{code}
% \dcd's scope is bounded by its enclosing braces. It is only defined within
% the code env. You can also turn on just $ with the \cddollar command;
% you can turn on just $^_ with the \cdmath command. See below.
%
% Alternatively, just use \(...\) for $...$, \sp for ^, and \sb for _.
% WARNING:
% Like \verb, you cannot put a \cd{...} inside an argument to a macro
% or a command. If you try, for example,
% \mbox{\cd{$x^y$}}
% you will lose. That is because the text "\cd{$x^y$}" gets read in
% as \mbox's argument before the \cd executes. But the \cd has to
% have a chance to run before LaTeX ever reads the $x^y$ so it can
% turn off the specialness of $ and ^. So, \cd has to appear at
% top level, not inside an argument. Similarly, you can't have
% a \cd or a \code inside a macro (Although you could use \gdef to
% define a macro *inside* a \cd, which you could then use outside.
% Don't worry about this if you don't understand it.)
% BUG: In the codebox env, the effect of a \dcd, \cddollar, or \cdmath
% command is reset at the end of each line. This can be hacked by
% messing with the \halign's preamble, if you feel up to it.
% Useage note: the initial newline after the \begin{code} or
% \begin{codebox} is eaten, but the last newline is not.
% So,
% \begin{code}
% foo
% bar
% \end{code}
% leaves one more blank line after bar than does
% \begin{code}
% foo
% bar\end{code}
% Moral: get in the habit of terminating code envs without a newline
% (as in the second example).
%
% All this stuff tweaks the meaning of space, tab, and newline.
%===============================================================================
% \cd@obeyspaces
% Turns all spaces into non-breakable spaces.
% Note: this is like \@vobeyspaces except without spurious space in defn.
% @xobeysp is basically a space; it's defined in latex.tex.
%
{\catcode`\ =\active\gdef\cd@obeyspaces{\catcode`\ =\active\let =\@xobeysp}}
% \cd@obeytabs
% Turns all tabs into 8 non-breakable spaces (which is bogus).
%
{\catcode`\^^I=\active %
\gdef\cd@obeytabs{\catcode`\^^I=\active\let^^I=\cd@tab}}
\def\cd@tab{\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp}
% \cd@obeylines
% Turns all cr's into linebreaks. Pagebreaks are not permitted between lines.
% This is copied from lplain.tex's \obeylines, with the cr def'n changed.
%
{\catcode`\^^M=\active % these lines must end with %
\gdef\cd@obeylines{\catcode`\^^M=\active\let^^M=\cd@cr}}
% What ^M turns into. This def'n keeps blank lines from being compressed out.
\def\cd@cr{\par\penalty10000\leavevmode} % TeX magicness
%\def\cd@cr{\par\penalty10000\mbox{}} % LaTeX
% \codeallowbreaks
% Same as \cd@obeylines, except pagebreaks are allowed.
% Put this command inside a code env to allow pagebreaks.
{\catcode`\^^M=\active % these lines must end with %
\gdef\codeallowbreaks{\catcode`\^^M\active\let^^M\cd@crbr}}
%\def\cd@crbr{\leavevmode\endgraf} % What ^M turns into.
\def\cd@crbr{\par\leavevmode} % What ^M turns into.
% \cd@obeycrsp
% Turns cr's into non-breakable spaces. Used by \cd.
{\catcode`\^^M=\active % these lines must end with %
\gdef\cd@obeycrsp{\catcode`\^^M=\active\let^^M=\@xobeysp}}
% =============================================================================
% Set up code environment, in which most of the common special characters
% appearing in code are treated verbatim, namely: $&#^_~%
% \ { } are still enabled so that macros can be called in this
% environment. Use \\, \{, and \} to use these characters verbatim
% in this environment.
%
% Inside a group, you can make
% all the hacked chars special with the \dcd command
% $ special with the \cddollar command
% $^_ special with the \cdmath command.
% If you have a bunch of math $..$'s in your code env, then a global \cddollar
% or \cdmath at the beginning of the env can save a lot of trouble.
% When chars are special (e.g., after a \dcd), you can still get #$%&_{} with
% \#, \$, \%, \&, \_, \{, and \} -- this is standard LaTeX.
% Additionally, \\ gives \ inside the code env, and when \cdmath
% makes ^ special, it also defines \^ to give ^.
%The hacked characters can be made special again
% within a group by using the \dcd command.
% Note: this environment allows no breaking of lines whatsoever; not
% at spaces or hypens. To arrange for a break use the standard \- command,
% or a \discretionary{}{}{} which breaks, but inserts nothing. This is useful,
% for example for allowing hypenated identifiers to be broken, e.g.
% \def\={\discretionary{}{}{}} %optional break
% FOO-\=BAR.
\def\setupcode{\parsep=0pt\parindent=0pt%
\normalfont\ttfamily\frenchspacing\catcode``=13\@noligs%
\def\\{\char`\\}%
\let\dcd=\cd@dcd\let\cddollar=\cd@dollarspecial\let\cdmath=\cd@mathspecial%
\@makeother\$\@makeother\&\@makeother\#%
\@makeother\^\@makeother\_\@makeother\~%
\@makeother\%\cd@obeytabs\cd@obeyspaces}
% other: $&#^_~%
% left special: \{}
% unnecessary: @`'"
%% codebox, centercode
%%=============================================================================
%% The codebox env makes a box exactly as wide as it needs to be
%% (i.e., as wide as the longest line of code is). This is useful
%% if you want to center a chunk of code, or flush it right, or
%% something like that. The optional argument to the environment,
%% [t], [c], or [b], specifies how to vertically align the codebox,
%% just as with arrays or other boxes. Default is [c].
%% Must be a newline immediately after "\begin{codebox}[t]"!
{\catcode`\^^M=\active % these lines must end with %
\gdef\cd@obeycr{\catcode`\^^M=\active\let^^M=\cr}}
% If there is a [<letter>] option, then the following newline will
% be read *after* ^M is bound to \cr, so we're cool. If there isn't
% an option given (i.e., default to [c]), then the @\ifnextchar will
% gobble up the newline as it gobbles whitespace. So we insert the
% \cr explicitly. Isn't TeX fun?
\def\codebox{\leavevmode\@ifnextchar[{\@codebox}{\@codebox[c]\cr}} %]
\def\@codebox[#1]%
{\hbox\bgroup$\if #1t\vtop \else \if#1b\vbox \else \vcenter \fi\fi\bgroup%
\tabskip\z@\setupcode\cd@obeycr% just before cd@obey
\halign\bgroup##\hfil\span}
\def\endcodebox{\crcr\egroup\egroup\m@th$\egroup}
% Center the box on the page:
\newenvironment{centercode}%
{\begin{center}\begin{codebox}[c]}%
{\end{codebox}\end{center}}
%% code, codeaux, tightcode
%%=============================================================================
%% Code environment as described above. Lines are kept on one page.
%% This actually works by setting a huge penalty for breaking
%% between lines of code. Code is indented same as other displayed paras.
%% Note: to increase left margin, use \begin{codeaux}{\leftmargin=1in}.
% To allow pagebreaks, say \codeallowbreaks immediately inside the env.
% You can allow breaks at specific lines with a \pagebreak form.
%% N.B.: The \global\@ignoretrue command must be performed just inside
%% the *last* \end{...} before the following text. If not, you will
%% get an extra space on the following line. Blech.
%% This environment takes two arguments.
%% The second, required argument is the \list parameters to override the
%% \@listi... defaults.
%% - Usefully set by clients: \topsep \leftmargin
%% - Possible, but less useful: \partopsep
%% The first, optional argument is the extra \parskip glue that you get around
%% \list environments. It defaults to the value of \parskip.
\def\codeaux{\@ifnextchar[{\@codeaux}{\@codeaux[\parskip]}} %]
\def\@codeaux[#1]#2{%
\bgroup\parskip#1%
\begin{list}{}%
{\parsep\z@\rightskip\z@\listparindent\z@\itemindent\z@#2}%
\item[]\setupcode\cd@obeylines}%
\def\endcodeaux{\end{list}\leavevmode\egroup\ignorespaces\global\@ignoretrue}
%% Code env is codeaux with the default margin and spacing \list params:
\def\code{\codeaux{}} \let\endcode=\endcodeaux
%% Like code, but with no extra vertical space above and below.
\def\tightcode{\codeaux[=0pt]{\topsep\z@}}%
\let\endtightcode\endcodeaux
% {\vspace{-1\parskip}\begin{codeaux}{\partopsep\z@\topsep\z@}}%
% {\end{codeaux}\vspace{-1\parskip}}
% Reasonable separation between lines of code
\newcommand{\codeskip}{\penalty0\vspace{2ex}}
% \cd is used to build a code environment in the middle of text.
% Note: only difference from display code is that cr's are taken
% as unbreakable spaces instead of linebreaks.
\def\cd{\leavevmode\begingroup\ifmmode\let\startcode=\startmcode\else%
\let\startcode\starttcode\fi%
\setupcode\cd@obeycrsp\startcode}
\def\starttcode#1{#1\endgroup}
\def\startmcode#1{\hbox{#1}\endgroup}
% Restore $&#^_~% to their normal catcodes
% Define \^ to give the ^ char.
% \dcd points to this guy inside a code env.
\def\cd@dcd{\catcode`\$=3\catcode`\&=4\catcode`\#=6\catcode`\^=7%
\catcode`\_=8\catcode`\~=13\catcode`\%=14\def\^{\char`\^}}
% Selectively enable $, and $^_ as special.
% \cd@mathspecial also defines \^ give the ^ char.
% \cddollar and \cdmath point to these guys inside a code env.
\def\cd@dollarspecial{\catcode`\$=3}
\def\cd@mathspecial{\catcode`\$=3\catcode`\^=7\catcode`\_=8%
\def\^{\char`\^}}
% Change log:
% Started off as some macros found in C. Rich's library.
% Olin 1/90:
% Removed \makeatletter, \makeatother's -- they shouldn't be there,
% because style option files are read with makeatletter. The terminal
% makeatother screwed things up for the following style options.
% Olin 3/91:
% Rewritten.
% - Changed things so blank lines don't get compressed out (the \leavevmove
% in \cd@cr and \cd@crwb).
% - Changed names to somewhat less horrible choices.
% - Added lots of doc, so casual hackers can more easily mess with all this.
% - Removed `'"@ from the set of hacked chars, since they are already
% non-special.
% - Removed the bigcode env, which effect can be had with the \codeallowbreaks
% command.
% - Removed the \@noligs command, since it's already defined in latex.tex.
% - Win big with the new \dcd, \cddollar, and \cdmath commands.
% - Now, *only* the chars \{} are special inside the code env. If you need
% more, use the \dcd command inside a group.
% - \cd now works inside math mode. (But if you use it in a superscript,
% it still comes out full size. You must explicitly put a \scriptsize\tt
% inside the \cd: $x^{\cd{\scriptsize\tt...}}$. A \leavevmode was added
% so that if you begin a paragraph with a \cd{...}, TeX realises you
% are starting a paragraph.
% - Added the codebox env. Tricky bit involving the first line hacked
% with help from David Long.
% Olin 8/94
% Changed the font commands for LaTeX2e.

114
doc/scsh-manual/css.t2p Normal file
View File

@ -0,0 +1,114 @@
% css.t2p
% Dorai Sitaram
% 19 Jan 2001
% A basic style for HTML documents generated
% with tex2page.
\ifx\shipout\UNDEFINED
\cssblock
body {
color: black;
/* background-color: #e5e5e5;*/
background-color: #ffffff;
/*background-color: beige;*/
margin-top: 2em;
margin-left: 8%;
margin-right: 8%;
}
h1,h2,h3,h4,h5,h6 {
margin-top: .5em;
}
.partheading {
font-size: 100%;
}
.chapterheading {
font-size: 100%;
}
pre {
margin-left: 2em;
}
ol {
list-style-type: decimal;
}
ol ol {
list-style-type: lower-alpha;
}
ol ol ol {
list-style-type: lower-roman;
}
ol ol ol ol {
list-style-type: upper-alpha;
}
.scheme {
color: brown;
}
.scheme .keyword {
color: #990000;
font-weight: bold;
}
.scheme .builtin {
color: #990000;
}
.scheme .variable {
color: navy;
}
.scheme .global {
color: purple;
}
.scheme .selfeval {
color: green;
}
.scheme .comment {
color: teal;
}
.schemeresponse {
color: green;
}
.navigation {
color: red;
text-align: right;
font-style: italic;
}
.disable {
/* color: #e5e5e5; */
color: gray;
}
.smallcaps {
font-size: 75%;
}
.smallprint {
color: gray;
font-size: 75%;
text-align: right;
}
.smallprint hr {
text-align: left;
width: 40%;
}
\endcssblock
\fi
% ex:ft=css

6
doc/scsh-manual/ct.sty Normal file
View File

@ -0,0 +1,6 @@
% Loads cmtt fonts in on \tt. -*- latex -*-
% I prefer these to the Courier fonts that latex gives you w/postscript styles.
% Courier is too spidery and too wide -- it's hard to get 80 chars on a line.
% -Olin
\renewcommand{\ttdefault}{cmtt}

278
doc/scsh-manual/decls.tex Normal file
View File

@ -0,0 +1,278 @@
\makeatletter
\def\ie{\mbox{\emph{i.e.}}} % \mbox keeps the last period from
\def\Ie{\mbox{\emph{I.e.}}} % looking like an end-of-sentence.
\def\eg{\mbox{\emph{e.g.}}}
\def\Eg{\mbox{\emph{E.g.}}}
\def\etc{{\em etc.}}
\def\Lisp{\textsc{Lisp}}
\def\CommonLisp{\textsc{Common Lisp}}
\def\Ascii{\textsc{Ascii}}
\def\Ansi{\textsc{Ansi}}
\def\Unix{{Unix}} % Not smallcaps, according to Bart.
\def\Scheme{{Scheme}}
\def\scm{{Scheme 48}}
\def\RnRS{R5RS}
\def\Posix{\textsc{Posix}}
\def\sharpf{\textnormal{\texttt{\#f}}}
\def\sharpt{\textnormal{\texttt{\#t}}}
\newcommand{\synteq}{\textnormal{::=}}
\def\maketildeother{\catcode`\~=12}
\def\maketildeactive{\catcode`\~=13}
\def\~{\char`\~}
\newcommand{\evalsto}{\ensuremath{\Rightarrow}}
% One-line code examples
%\newcommand{\codex}[1]% One line, centred. Tight spacing.
% {$$\abovedisplayskip=.75ex plus 1ex minus .5ex%
% \belowdisplayskip=\abovedisplayskip%
% \abovedisplayshortskip=0ex plus .5ex%
% \belowdisplayshortskip=\abovedisplayshortskip%
% \hbox{\ttt #1}$$}
%\newcommand{\codex}[1]{\begin{tightinset}\ex{#1}\end{tightinset}\ignorespaces}
\newcommand{\codex}[1]{\begin{leftinset}\ex{#1}\end{leftinset}\ignorespaces}
\def\widecode{\codeaux{\leftmargin=0pt\topsep=0pt}}
\def\endwidecode{\endcodeaux}
% For multiletter vars in math mode:
\newcommand{\var}[1]{\mbox{\frenchspacing\it{#1}}}
\newcommand{\vari}[2]{\ensuremath{\mbox{\it{#1}}_{#2}}}
%% What you frequently want when you say \tt:
\def\ttchars{\catcode``=13\@noligs\frenchspacing}
\def\ttt{\normalfont\ttfamily\ttchars}
% Works in math mode; all special chars remain special; cheaper than \cd.
% Will not be correct size in super and subscripts, though.
\newcommand{\ex}[1]{{\normalfont\texttt{\ttchars #1}}}
\newenvironment{inset}
{\bgroup\parskip=1ex plus 1ex\begin{list}{}%
{\topsep=0pt\rightmargin\leftmargin}%
\item[]}%
{\end{list}\leavevmode\egroup\global\@ignoretrue}
\newenvironment{leftinset}
{\bgroup\parskip=1ex plus 1ex\begin{list}{}%
{\topsep=0pt}%
\item[]}%
{\end{list}\leavevmode\egroup\global\@ignoretrue}
\newenvironment{tightinset}
{\bgroup\parskip=0pt\begin{list}{}%
{\topsep=0pt\rightmargin\leftmargin}%
\item[]}%
{\end{list}\leavevmode\egroup\global\@ignoretrue}
\newenvironment{tightleftinset}
{\bgroup\parskip=0pt\begin{list}{}%
{\topsep=0pt}%
\item[]}%
{\end{list}\leavevmode\egroup\global\@ignoretrue}
\long\def\remark#1{\bgroup\small\begin{quote}\textsl{Remark: } #1\end{quote}\egroup}
\newenvironment{remarkenv}{\bgroup\small\begin{quote}\textsl{Remark: }}%
{\end{quote}\egroup}
\newcommand{\oops}[1]{\bgroup\small\begin{quote}\textsl{Oops: } #1\end{quote}\egroup}
\newcommand{\note}[1]{\{Note #1\}}
\newcommand{\itum}[1]{\item{\bf #1}\\*}
% For use in code. The \llap magicness makes the lambda exactly as wide as
% the other chars in \tt; the \hskip shifts it right a bit so it doesn't
% crowd the left paren -- which is necessary if \tt is cmtt.
% Note that (\l{x y} (+ x y)) uses the same number of columns in TeX form
% as it produces when typeset. This makes it easy to line up the columns
% in your input. \l is bound to some useless command in LaTeX, so we have to
% define it w/renewcommand.
\let\oldl\l %Save the old \l on \oldl
\renewcommand{\l}[1]{\ \llap{$\lambda$\hskip-.05em}\ (#1)}
% This one is for the rare (lambda x ...) case -- it doesn't have the
% column-invariant property. Oh, well.
\newcommand{\lx}[1]{\ \llap{$\lambda$\hskip-.05em}\ {#1}}
% For subcaptions
\newcommand{\subcaption}[1]
{\unskip\vspace{-2mm}\begin{center}\unskip\em#1\end{center}}
%%% T release notes stuff
\newlength{\notewidth}
\setlength{\notewidth}{\textwidth}
\addtolength{\notewidth}{-1.25in}
%\newcommand{\remark} [1]
% {\par\vspace{\parskip}
% \parbox[t]{.75in}{\sc Remark:}
% \parbox[t]{\notewidth}{\em #1}
% \vspace{\parskip}
% }
\newenvironment{optiontable}%
{\begin{tightinset}\renewcommand{\arraystretch}{1.5}%
\begin{tabular}{@{}>{\ttt}ll@{}}}%
{\end{tabular}\end{tightinset}}%
\newenvironment{desctable}[1]%
{\begin{inset}\renewcommand{\arraystretch}{1.5}%
\begin{tabular}{lp{#1}}}%
{\end{tabular}\end{inset}}
\def\*{{\ttt *}}
% Names of things
\newcommand{\keyword} [1]{\index{#1}{\normalfont\textsf{#1}}}
% \ex{#1} and also generates an index entry.
\newcommand{\exi}[1]{\index{#1@\texttt{#1}}\ex{#1}}
\newcommand{\indextt}[1]{\index{#1@\texttt{#1}}}
\newcommand{\evalto}{$\Longrightarrow$\ }
\renewcommand{\star}{$^*$\/}
\newcommand{\+}{$^+$}
% Semantic domains, used to indicate the type of a value
\newcommand{\sem}{\normalfont\itshape} %semantic font
\newcommand{\semvar}[1]{\textit{#1}} %semantic font
\newcommand{\synvar}[1]{\textrm{\textit{$\left<\right.$#1$\left.\right>$}}} %syntactic font
\newcommand{\type}{\sem}
\newcommand{\zeroormore}[1]{{\sem #1$_1$ \ldots #1$_n$}}
\newcommand{\oneormore}[1]{{\sem #1$_1$ #1$_2$ \ldots #1$_n$}}
\newcommand{\proc} {{\sem procedure}}
\newcommand{\boolean} {{\sem boolean}}
\newcommand{\true} {{\sem true}}
\newcommand{\false} {{\sem false}}
\newcommand{\num} {{\sem number}}
\newcommand{\fixnum} {{\sem fixnum}}
\newcommand{\integer} {{\sem integer}}
\newcommand{\real} {{\sem real}}
\newcommand{\character} {{\sem character}}
\newcommand{\str} {{\sem string}}
\newcommand{\sym} {{\sem symbol}}
\newcommand{\location} {{\sem location}}
\newcommand{\object} {{\sem object}}
\newcommand{\error} {{\sem error}}
\newcommand{\syntaxerror} {{\sem syntax error}}
\newcommand{\readerror} {{\sem read error}}
\newcommand{\undefined} {{\sem undefined}}
\newcommand{\noreturn} {{\sem no return value}}
\newcommand{\port} {{\sem port}}
% semantic variables
\newcommand{\identifier} {{\sem identifier}}
\newcommand{\identifiers} {\zeroormore{\<ident>}}
\newcommand{\expr} {{\sem expression}}
\newcommand{\body} {{\sem body}}
\newcommand{\valueofbody} {{\sem value~of~body}}
\newcommand{\emptylist} {{\sem empty~list}}
\newcommand{\car} {\keyword{car}}
\newcommand{\cdr} {\keyword{cdr}}
\newcommand{\TMPDIR}{\texttt{\$TMPDIR}}
% generally useful things
% For line-breaking \tt stuff.
\renewcommand{\=}{\discretionary{-}{}{-}}
\newcommand{\ob}{\discretionary{}{}{}} % Optional break.
\newcommand{\indx}[1]{#1 \index{ #1 }}
%\newcommand{\gloss}[1]{#1 \glossary{ #1 }}
% This lossage produces #2 if #1 is zero length, otw #3.
% We use it to conditionally add a space between the procedure and
% the args in procedure prototypes, but only if there are any args--
% we want to produce "(read)", not "(read )".
\newlength{\voidlen}
\newcommand{\testvoid}[3]{\settowidth\voidlen{#1}\ifdim\voidlen>0in{#3}\else{#2}\fi}
% Typeset a definition prototype line, e.g.:
% (cons <arg1> <arg2>) -> pair procedure
%
% Five args are: proc-name args ret-value(s) type index-entry
\newcommand{\dfnix}[5]
{\hbox to \linewidth{\ttchars%
{\ttt(#1\testvoid{#2}{}{\ }{\sem{#2}}\testvoid{#2}{}{\/})\hskip 1em minus
0.5em$\longrightarrow$\hskip 1em minus 0.5em{\sem{#3}}\hfill\quad\textnormal{#4}}}\index{#5}}
\newcommand{\dfnx}[4] {\dfnix{#1}{#2}{#3}{#4}{#1@\texttt{#1}}}
\newcommand{\dfn} {\par\medskip\dfnx} % Takes 4 args, actually.
\newcommand{\dfni} {\par\medskip\dfnix} % Takes 5 args, actually.
\newcommand{\defvar} {\par\medskip\defvarx} % Takes 4 args, actually.
\newcommand{\defvarx}[2]%
{\index{#1}
\hbox to \linewidth{\ttchars{{\ttt{#1}} \hfill #2}}}%
% Typeset the protocol line, then do the following descriptive text indented.
% If you want to group two procs together, do the first one with a \dfn,
% then the second one, and the documentation, with a \defndescx.
% This one doesn't put whitespace above. Use it immediately after a \dfn
% to group two prototype lines together.
\newenvironment{dfndescx}[4]%
{\dfnx{#1}{#2}{#3}{#4}\begin{desc}}{\end{desc}}
\newenvironment{dfndesc}[4] % This one puts whitespace above.
{\par\medskip\begin{dfndescx}{#1}{#2}{#3}{#4}}
{\end{dfndescx}}
\newenvironment{desc}%
{\nopagebreak[2]%
\smallskip
\bgroup\begin{list}{}{\topsep=0pt\parskip=0pt}\item[]}
{\end{list}\leavevmode\egroup\global\@ignoretrue}
\def\defun#1#2#3{\dfn{#1}{#2}{#3}{procedure}} % preskip
\newcommand{\defunx}[3]{\dfnx{#1}{#2}{#3}{procedure}} % no skip
\newenvironment{defundescx}[3]%
{\begin{dfndescx}{#1}{#2}{#3}{procedure}}
{\end{dfndescx}}
\newenvironment{defundesc}[3]%
{\begin{dfndesc}{#1}{#2}{#3}{procedure}}
{\end{dfndesc}}
\newenvironment{column}{\begin{tabular}[t]{@{}l@{}}}{\end{tabular}}
\newenvironment{exampletable}%
{\begin{leftinset}%
\newcommand{\header}[1]{\multicolumn{2}{@{}l@{}}{##1}\\}%
\newcommand{\splitline}[2]%
{\multicolumn{2}{@{}l@{}}{##1}\\\multicolumn{2}{@{}l@{}}{\qquad\evalto\quad{##2}}}
\begin{tabular}{@{}l@{\quad\evalto\quad}l@{}}}%
{\end{tabular}\end{leftinset}}
% Put on blank lines in a code env to allow a pagebreak.
\newcommand{\cb}{\pagebreak[0]}
\newenvironment{boxedcode}
{\begin{inset}\tabular{|l|}\hline}
{\\ \hline \end{tabular}\end{inset}}
% A ragged-right decl that doesn't redefine \\ -- for use in tables.
\newcommand{\raggedrightparbox}{\let\temp=\\\raggedright\let\\=\temp}
\newenvironment{boxedfigure}[1]%
{\begin{figure}[#1]\begin{boxedminipage}{\linewidth}\vskip 1.5ex}
{\end{boxedminipage}\end{figure}}
\makeatother

View File

@ -0,0 +1,76 @@
% Document style option "draftfooter"
% -- usage: \documentstyle[...,draftfooter,...]{...}
% -- puts "DRAFT" with date and time in page footer
%
% Olin Shivers 1/17/94
% - Hacked from code I used in my dissertation and from code in a
% drafthead.sty package written by Stephen Page sdpage@uk.ac.oxford.prg.
%----------------------------------------------------------------------------
%
% compute the time in hours and minutes; make new variables \timehh and \timemm
%
\newcount\timehh\newcount\timemm
\timehh=\time
\divide\timehh by 60 \timemm=\time
\count255=\timehh\multiply\count255 by -60 \advance\timemm by \count255
%
\def\draftbox{{\protect\small\bf \fbox{DRAFT}}}
\def\drafttime{%
{\protect\small\sl\today\ -- \ifnum\timehh<10 0\fi%
\number\timehh\,:\,\ifnum\timemm<10 0\fi\number\timemm}}
\def\drafttimer{\protect\makebox[0pt][r]{\drafttime}}
\def\drafttimel{\protect\makebox[0pt][l]{\drafttime}}
\def\thepagel{\protect\makebox[0pt][l]{\rm\thepage}}
\def\thepager{\protect\makebox[0pt][r]{\rm\thepage}}
% Header is empty.
% Footer is "date DRAFT pageno"
\def\ps@plain{
\let\@mkboth\@gobbletwo
\let\@oddhead\@empty \let\@evenhead\@empty
\def\@oddfoot{\reset@font\rm\drafttimel\hfil\draftbox\hfil\thepager}
\if@twoside
\def\@evenfoot{\reset@font\rm\thepagel\hfil\draftbox\hfil\drafttimer}
\else \let\@evenfoot\@oddfoot
\fi
}
% Aux macro -- sets footer to be "date DRAFT".
\def\@draftfooters{
\def\@oddfoot{\reset@font\rm\drafttimel\hfil\draftbox}
\if@twoside
\def\@evenfoot{\reset@font\rm\draftbox\hfil\drafttimer}
\else \let\@evenfoot\@oddfoot
\fi
}
% Header is empty.
% Footer is "date DRAFT".
\def\ps@empty{
\let\@mkboth\@gobbletwo
\let\@oddhead\@empty \let\@evenhead\@empty
\@draftfooters
}
% Header is defined by the document style (article, book, etc.).
% Footer is "date DRAFT".
\let\@draftoldhead\ps@headings
\def\ps@headings{
\@draftoldhead % Do the default \pagestyle{headings} stuff.
\@draftfooters % Then define the draft footers:
}
% Header is defined by the document style (article, book, etc.),
% and filled in by user's \markboth and \markright commands.
% Footer is "date DRAFT".
\let\@draftoldmyhead\ps@myheadings
\def\ps@myheadings{
\@draftoldmyhead % Do the default \pagestyle{myheadings} stuff.
\@draftfooters % Then define the draft footers:
}
\ps@plain

56
doc/scsh-manual/front.tex Normal file
View File

@ -0,0 +1,56 @@
%&latex -*- latex -*-
\title{Scsh Reference Manual}
\subtitle{For scsh release 0.6.7}
\author{Olin Shivers, Brian D.~Carlstrom, Martin Gasbichler, and Mike Sperber}
\date{May 2006}
\maketitle
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Some code-changes for tex2page and latex output. NF
\texonly
\chapter*{Acknowledgements}
\endtexonly
\htmlonly
\\ \ex{Acknowledgements} \\ \\
\endhtmlonly
Who should I thank?
My so-called ``colleagues,'' who laugh at me behind my back,
all the while becoming famous on {\em my\/} work?
My worthless graduate students, whose computer skills appear to
be limited to downloading bitmaps off of netnews?
My parents, who are still waiting for me to quit ``fooling around with
computers,'' go to med school, and become a radiologist?
My department chairman, a manager who gives one new insight into
and sympathy for disgruntled postal workers?
My God, no one could blame me---no one!---if I went off the edge and just
lost it completely one day.
I couldn't get through the day as it is without the Prozac and Jack Daniels
I keep on the shelf, behind my Tops-20 JSYS manuals.
I start getting the shakes real bad around 10am, right before my
advisor meetings. A 10 oz.\ Jack 'n Zac helps me get through the
meetings without one of my students winding up with his severed head
in a bowling-ball bag. They look at me funny; they think I twitch a
lot. I'm not twitching. I'm controlling my impulse to snag my 9mm
Sig-Sauer out from my day-pack and make a few strong points about
the quality of undergraduate education in Amerika.
If I thought anyone cared, if I thought anyone would even be reading this,
I'd probably make an effort to keep up appearances until the last possible
moment. But no one does, and no one will. So I can pretty much say exactly
what I think.
Oh, yes, the {\em acknowledgements.}
I think not. I did it. I did it all, by myself.
\begin{flushright}
\begin{tabular}{l}
Olin Shivers \\
Cambridge \\
September 4, 1994
\end{tabular}
\end{flushright}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\tableofcontents

View File

@ -0,0 +1,16 @@
% headings.tex -*- latex -*-
% Quieter headings that the ones used in article.sty.
% This is not a style option. Don't say [headings].
% Instead, say \input{headings} after the \documentstyle.
% -Olin 7/91
\makeatletter
\def\section{\@startsection {section}{1}{\z@}{-3.5ex plus -1ex minus
-.2ex}{2.3ex plus .2ex}{\large\normalfont\bfseries}}
\def\subsection{\@startsection{subsection}{2}{\z@}{-3.25ex plus -1ex minus
-.2ex}{1.5ex plus .2ex}{\normalsize\normalfont\bfseries}}
\def\subsubsection{\@startsection{subsubsection}{3}{\z@}{-3.25ex plus
-1ex minus -.2ex}{1.5ex plus .2ex}{\normalsize\normalfont\bfseries}}
\makeatother

435
doc/scsh-manual/intro.tex Normal file
View File

@ -0,0 +1,435 @@
%&latex -*- latex -*-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Introduction}
This is the reference manual for scsh,
a {\Unix} shell that is embedded within {\Scheme}.
Scsh is a Scheme system designed for writing useful standalone Unix
programs and shell scripts---it spans a wide range of application,
from ``script'' applications usually handled with perl or sh,
to more standard systems applications usually written in C.
Scsh comes built on top of {\scm}, and has two components:
a process notation for running programs and setting up pipelines
and redirections,
and a complete syscall library for low-level access to the operating system.
This manual gives a complete description of scsh.
A general discussion of the design principles behind scsh can be found
in a companion paper, ``A Scheme Shell.''
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Copyright \& source-code license}
Scsh is open source. The complete sources come with the standard
distribution, which can be downloaded off the net.
Scsh has an ideologically hip, BSD-style license.
We note that the code is a rich source for other Scheme implementations
to mine. Not only the \emph{code}, but the \emph{APIs} are available
for implementors working on Scheme environments for systems programming.
These APIs represent years of work, and should provide a big head-start
on any related effort. (Just don't call it ``scsh,'' unless it's
\emph{exactly} compliant with the scsh interfaces.)
Take all the code you like; we'll just write more.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Obtaining scsh}
Scsh is distributed via net publication.
We place new releases at well-known network sites,
and allow them to propagate from there.
We currently release scsh to the following Internet sites:
\begin{inset}\begin{flushleft}
\ex{\urlh{ftp://ftp.scsh.net/pub/scsh}{ftp://ftp.scsh.net/pub/scsh}} \\
\ex{\urlh{http://prdownloads.sourceforge.net/scsh/}{http://prdownloads.sourceforge.net/scsh/}} \\
\end{flushleft}
\end{inset}
%
Each should have a compressed tar file of the entire scsh release,
which includes all the source code and the manual,
and a separate file containing just this manual in Postscript form,
for those who simply wish to read about the system.
However, nothing is certain for long on the Net.
Probably the best way to get a copy of scsh is to use a network
resource-discovery tool, such as archie,
to find ftp servers storing scsh tar files.
Take the set of sites storing the most recent release of scsh,
choose one close to your site, and download the tar file.
\section{Building scsh}
Scsh currently runs on a fairly large set of Unix systems, including
Linux, FreeBSD, OpenBSD, NetBSD, MacOS X, SunOS, Solaris, AIX, NeXTSTEP, Irix, and HP-UX.
We use the Gnu project's autoconfig tool to generate self-configuring
shell scripts that customise the scsh Makefile for different OS variants.
This means that if you use one of the common Unix implementations,
building scsh should require exactly the following steps:
\begin{inset}
\begin{tabular}{l@{\qquad}l}
\ex{gunzip scsh.tar.gz} & \emph{Uncompress the release tar file.} \\
\ex{untar xfv scsh.tar} & \emph{Unpack the source code.} \\
\ex{cd scsh-0.6.x} & \emph{Move to the source directory.} \\
\ex{./configure} & \emph{Examine host; build Makefile.} \\
\ex{make} & \emph{Build system.}
\end{tabular}
\end{inset}
When you are done, you should have a virtual machine compiled in
file \ex{scshvm}, and a heap image in file \ex{scsh/scsh.image}.
Typing
\begin{code}
make install
\end{code}
will install these programs in your installation directory
(by default, \ex{/usr/local}), along with a small stub startup
binary, \ex{scsh}.
If you don't have the patience to do this, you can start up
a Scheme shell immediately after the initial make by simply
saying
\codex{./scshvm -o ./scshvm -i scsh/scsh.image}
See chapter~\ref{chapt:running} for full details on installation
locations and startup options.
It is not too difficult to port scsh to another Unix platform if your
OS is not supported by the current release.
See the release notes for more details on how to do this.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Caveats}
It is important to note what scsh is \emph{not}, as well as what it is.
Scsh, in the current release, is primarily designed for the writing of
shell scripts---programming.
It is not a very comfortable system for interactive command use:
the current release lacks job control, command-line editing, a terse,
convenient command syntax, and it does not read in an initialisation
file analogous to \ex{.login} or \ex{.profile}.
We hope to address all of these issues in future releases;
we even have designs for several of these features;
but the system as-released does not currently provide these features.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Naming conventions}
Scsh follows a general naming scheme that consistently employs a set of
abbreviations.
This is intended to make it easier to remember the names of things.
Some of the common ones are:
\begin{description}
\item [\ex{fdes}]
Means ``file descriptor,'' a small integer used in {\Unix}
to represent I/O channels.
\item [\ex{\ldots*}]
A given bit of functionality sometimes comes in two related forms,
the first being a \emph{special form} that contains a body of
{\Scheme} code to be executed in some context,
and the other being a \emph{procedure} that takes a procedural
argument (a ``thunk'') to be called in the same context.
The procedure variant is named by taking the name of the special form,
and appending an asterisk. For example:
\begin{code}
;;; Special form:
(with-cwd "/etc"
(for-each print-file (directory-files))
(display "All done"))
;;; Procedure:
(with-cwd* "/etc"
(lambda ()
(for-each print-file (directory-files))
(display "All done")))\end{code}
\item [\ex{\var{action}/\var{modifier}}]
The infix ``\ex{/}'' is pronounced ``with,'' as in
\ex{exec/env}---``exec with environment.''
\item [\ex{call/\ldots}]
Procedures that call their argument on some computed value
are usually named ``\ex{call/\ldots},'' \eg,
\ex{(call/fdes \var{port} \var{proc})}, which calls \var{proc}
on \var{port}'s file descriptor, returning whatever \var{proc}
returns. The abbreviated name means ``call with file descriptor.''
\item [\ex{with-\ldots}]
Procedures that call their argument, and special forms that execute
their bodies in some special dynamic context frequently have
names of the form \ex{with-\ldots}. For example,
\ex{(with-env \var{env} \vari{body}1 \ldots)} and
\ex{(with-env* \var{env} \var{thunk})}. These forms set
the process environment body, execute their body or thunk,
and then return after resetting the environment to its original
state.
\item[\ex{create-}]
Procedures that create objects in the file system (files, directories,
temp files, fifos, \etc), begin with \ex{create-\ldots}.
\item [\ex{delete-}]
Procedures that delete objects from the file system (files,
directories, temp files, fifos, \etc), begin with \ex{delete-\ldots}.
\item[ \ex{\var{record}:\var{field}} ]
Procedures that access fields of a record are usually written
with a colon between the name of the record and the name of the
field, as in \ex{user-info:home-dir}.
\item[\ex{\%\ldots}]
A percent sign is used to prefix lower-level scsh primitives
that are not commonly used.
\item[\ex{-info}]
Data structures packaging up information about various OS
entities frequently end in \ldots\ex{-info}. Examples:
\ex{user-info}, \ex{file-info}, \ex{group-info}, and \ex{host-info}.
\end{description}
%
Enumerated constants from some set \var{s} are usually named
\ex{\var{s}/\vari{const}1}, \ex{\var{s}/\vari{const}2}, \ldots.
For example, the various {\Unix} signal integers have the names
\ex{signal/cont}, \ex{signal/kill}, \ex{signal/int}, \ex{signal/hup},
and so forth.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Lexical issues}
Scsh's lexical syntax is just {\RnRS} {\Scheme}, with the following
exceptions.
\subsection{Extended symbol syntax}
Scsh's symbol syntax differs from {\RnRS} {\Scheme} in the following ways:
\begin{itemize}
\item In scsh, symbol case is preserved by \ex{read} and is significant on
symbol comparison. This means
\codex{(run (less Readme))}
displays the right file.
\item ``\ex{-}'' and ``\ex{+}'' are allowed to begin symbols.
So the following are legitimate symbols:
\codex{-O2 -geometry +Wn}
\item ``\ex{|}'' and ``\ex{.}'' are symbol constituents.
This allows \ex{|} for the pipe symbol, and \ex{..} for the parent-directory
symbol. (Of course, ``\ex{.}'' alone is not a symbol, but a
dotted-pair marker.)
\item A symbol may begin with a digit.
So the following are legitimate symbols:
\codex{9x15 80x36-3+440}
\end{itemize}
\subsection{Extended string syntax}
Scsh strings are allowed to contain the {\Ansi} C escape sequences
such as \verb|\n| and \verb|\161|.
\subsection{Block comments and executable interpreter-triggers}
Scsh allows source files to begin with a header of the form
\codex{\#!/usr/local/bin/scsh -s}
The Unix operating system treats source files beginning with the headers
of this form specially;
they can be directly executed by the operating system
(see chapter~\ref{chapt:running} for information on how to use this feature).
The scsh interpreter ignores this special header by treating \ex{\#!} as a
comment marker similar to \ex{;}.
When the scsh reader encounters \ex{\#!}, it skips characters until it finds
the closing sequence
new\-line/{\ob}ex\-cla\-ma\-tion-{\ob}point/{\ob}sharp-{\ob}sign/{\ob}new\-line.
Although the form of the \ex{\#!} read-macro was chosen to support
interpreter-triggers for executable Unix scripts,
it is a general block-comment sequence and can be used as such
anywhere in a scsh program.
\subsection{Here-strings}
The read macro \ex{\#<} is used to introduce ``here-strings''
in programs, similar to the \ex{<<} ``here document'' redirections
provided by sh and csh.
There are two kinds of here-string, character-delimited and line-delimited;
they are both introduced by the \ex{\#<} sequence.
\subsubsection{Character-delimited here-strings}
A \emph{character-delimited} here-string has the form
\codex{\#<\emph{x}...stuff...\emph{x}}
where \emph{x} is any single character
(except \ex{<}, see below),
which is used to delimit the string bounds.
Some examples:
\begin{inset}
\begin{tabular}{ll}
Here-string syntax & Ordinary string syntax \\ \hline
\verb:#<|Hello, world.|: & \verb:"Hello, world.": \\
\verb:#<!"Ouch," he said.!: & \verb:"\"Ouch,\" he said.":
\end{tabular}
\end{inset}
%
There is no interpretation of characters within the here-string;
the characters are all copied verbatim.
\subsubsection{Line-delimited here-strings}
If the sequence begins "\ex{\#<<}" then it introduces a \emph{line-delimited}
here-string.
These are similar to the ``here documents'' of sh and csh.
Line-delimited here-strings are delimited by the rest of the text line that
follows the "\ex{\#<<}" sequence.
For example:
\begin{code}
#<<FOO
Hello, there.
This is read by Scheme as a string,
terminated by the first occurrence
of newline-F-O-O-newline or newline-F-O-O-eof.
FOO\end{code}
%
Thus,
\begin{code}
#<<foo
Hello, world.
foo\end{code}
%
is the same thing as
\codex{"Hello, world."}
Line-delimited here-strings are useful for writing down long, constant
strings---such as long, multi-line \ex{format} strings,
or arguments to Unix programs, \eg,
\begin{code}
;; Free up some disk space for my netnews files.
(run (csh -c #<<EOF
cd /urops
rm -rf *
echo All done.
EOF
))\end{code}
The advantage they have over the double-quote syntax
(\eg, \ex{"Hello, world."})
is that there is no need to backslash-quote special characters internal
to the string, such as the double-quote or backslash characters.
The detailed syntax of line-delimited here-strings is as follows.
The characters "\ex{\#<<}" begin the here-string.
The characters between the "\ex{\#<<}" and the next newline are the
\emph{delimiter line}.
All characters between the "\ex{\#<<}" and the next newline comprise the
delimiter line---including any white space.
The body of the string begins on the following line,
and is terminated by a line of text which exactly matches the
delimiter line.
This terminating line can be ended by either a newline or end-of-file.
Absolutely no interpretation is done on the input string.
Control characters, white space, quotes, backslash---everything
is copied as-is.
The newline immediately preceding the terminating delimiter line is
not included in the result string
(leave an extra blank line if you need to put a final
newline in the here-string---see the example above).
If EOF is encountered before reading the end of the here-string,
an error is signalled.
\subsection{Dot}
It is unfortunate that the single-dot token, ``\ex{.}'', is both
a fundamental {\Unix} file name and a deep, primitive syntactic token
in {\Scheme}---it means the following will not parse correctly in scsh:
\codex{(run/strings (find . -name *.c -print))}
You must instead quote the dot:
\codex{(run/strings (find "." -name *.c -print))}
When you write shell scripts that manipulate the file system,
keep in mind the special status of the dot token.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Record types and the \texttt{define-record} form}
\label{sec:defrec}
\index{define-record@\texttt{define-record}}
Scsh's interfaces occasionally provide data in structured record types;
an example is the \ex{file-info} record whose various fields describe the size,
protection, last date of modification, and other pertinent data for a
particular file.
These record types are described in this manual using the \ex{define-record}
notation, which looks like the following:
%
\begin{code}
(define-record ship
x
y
(size 100))\end{code}
%
This form defines a \var{ship} record, with three fields:
its x and y coordinates, and its size.
The values of the \var{x} and \var{y} fields are specified as parameters
to the ship-building procedure, \ex{(make-ship \var{x} \var{y})},
and the \var{size} field is initialised to 100.
All told, the \ex{define-record} form above defines the following procedures:
%
\begin{center}
\begin{tabular}{|ll|}
\multicolumn{1}{l}{Procedure} & \multicolumn{1}{l}{Definition} \\
\hline
(make-ship \var{x} \var{y}) & Create a new \var{ship} record. \\
\hline
(ship:x \var{ship}) & Retrieve the \var{x} field. \\
(ship:y \var{ship}) & Retrieve the \var{y} field. \\
(ship:size \var{ship}) & Retrieve the \var{size} field. \\
\hline
(set-ship:x \var{ship} \var{new-x}) & Assign the \var{x} field. \\
(set-ship:y \var{ship} \var{new-y}) & Assign the \var{y} field. \\
(set-ship:size \var{ship} \var{new-size}) & Assign the \var{size} field. \\
\hline
(modify-ship:x \var{ship} \var{xfun}) & Modify \var{x} field with \var{xfun}. \\
(modify-ship:y \var{ship} \var{yfun}) & Modify \var{y} field with \var{yfun}. \\
(modify-ship:size \var{ship} \var{sizefun}) & Modify \var{size} field with \var{sizefun}. \\
\hline
(ship? \var{object}) & Type predicate. \\
\hline
(copy-ship \var{ship}) & Shallow-copy of the record. \\
\hline
\end{tabular}
\end{center}
%
An implementation of \ex{define-record} is available as a macro for Scheme
programmers to define their own record types;
the syntax is accessed by opening the package \ex{defrec-package}, which
exports the single syntax form \ex{define-record}.
See the source code for the \ex{defrec-package} module
for further details of the macro.
You must open this package to access the form.
Scsh does not export a record-definition package by default as there are
several from which to choose.
Besides the \ex{define-record} macro, which Shivers prefers\footnote{He wrote
it.}, you might instead wish to employ the notationally-distinct
\ex{define-record-type} macro that Jonathan Rees
prefers\footnote{He wrote it.}.
It can be found in the
\ex{define-record-types} structure.
Alternatively, you may define your own, of course.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{A word about {\Unix} standards}
``The wonderful thing about {\Unix} standards is that there are so many
to choose from.''
You may be totally bewildered about the multitude of various standards that
exist.
Rest assured that nowhere in this manual will you encounter an attempt
to spell it all out for you;
you could not read and internalise such a twisted account without
bleeding from the nose and ears.
However, you might keep in mind the following simple fact: of all the
standards, {\Posix} is the least common denominator.
So when this manual repeatedly refers to {\Posix}, the point is ``the
thing we are describing should be portable just about anywhere.''
Scsh sticks to {\Posix} when at all possible; its major departure is
symbolic links, which aren't in {\Posix} (see---it
really \emph{is} a least common denominator).
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "man"
%%% End:

133
doc/scsh-manual/man.t2p Normal file
View File

@ -0,0 +1,133 @@
% man.t2p
% Dorai Sitaram
% Feb 6, 2000
% This file contains the tex2page macros needed to process
% the scsh LaTeX document scsh-n.n.n/doc/scsh-manual/man.tex.
% Copy (or link) this file alongside man.tex and run
%
% tex2page man
\input css.t2p
\htmlmathstyle{no-image}
\let\pagebreak\relax
\let\small\relax
%\let\PRIMtableofcontents\tableofcontents
%\def\tableofcontents{\chapter*{Contents}\PRIMtableofcontents}
\def\subtitle#1{\def\savesubtitle{#1}}
\def\maketitle{
\subject{\TIIPtitle}
{\bf \hr}
\rightline{\savesubtitle}
\bigskip\bigskip
\bigskip\bigskip
{\bf\TIIPauthor}
{\bf\hr}
}
\let\PRIMdocument\document
\def\document{\PRIMdocument
\let\ttchars\relax
\let\ttt\tt
%\def\~{\rawhtml~\endrawhtml}
\def\~{\char`\~}
\def\cd#1{{\tt\def\\{\char`\\}\defcsactive\${\char`\$}\defcsactive\~{\char`\~}\defcsactive\&{\char`\&}#1}}
\def\cddollar{\undefcsactive\$}
\def\cdmath{\undefcsactive\$}
\def\codeallowbreaks{\relax}
\def\defvarx#1#2{\index{#1}\leftline{{\tt #1} \qquad #2}}
\let\PRIMflushright\flushright
\def\flushright{\PRIMflushright\TIIPtabularborder=0 }
\let\PRIMfigure\figure
\let\PRIMendfigure\endfigure
\def\figure{\par\hrule\PRIMfigure}
\def\endfigure{\PRIMendfigure\hrule\par}
\let\PRIMtable\table
\let\PRIMendtable\endtable
\def\table{\par\hrule\PRIMtable}
\def\endtable{\PRIMendtable\hrule\par}
\imgdef\vdots{\bf.\par.\par.}
%\evalh{
%
%(define all-blanks?
% (lambda (s)
% (andmap
% char-whitespace?
% (string->list s))))
%
%}
%
%
%\def\spaceifnotempty{\evalh{
%
%(let ((x (ungroup (get-token))))
% (unless (all-blanks? x)
% (emit #\space)))
%
%}}
\def\spaceifnotempty#1{%
\def\TEMP{#1}%
\ifx\TEMP\empty\else\ \fi}
\def\dfnix#1#2#3#4#5{\index{#5}\leftline{{\tt(#1\spaceifnotempty{#2}{\it#2})} \quad $\longrightarrow$ \quad {\it #3} \qquad (#4)}}
%\def\ex#1{{\tt #1}}
%\let\ex\texttt
\def\l#1{lambda (#1)}
\def\lx#1{lambda {#1}}
%\def\notenum#1{}
%\def\project#1{}
%\def\var#1{{\it #1\/}}
%\let\var\textit
%\def\vari#1#2{\mbox{{\it #1\/}\undefcsactive\$$_{#2}$}}
%\def\vari#1#2{\textit{#1}$_{#2}$}
\renewenvironment{boxedfigure}{\def\srecomment#1{\\#1\\}%
\begin{figure}\pagestyle}{\end{figure}}
\newenvironment{centercode}{\begin{code}}{\end{code}}
\def\setupcode{\tt%
\def\\{\char`\\}%
\defcsactive\${\$}%
\def\evalto{==> }%
\defcsactive\%{\%}\obeywhitespace}
\newenvironment{code}{\begin{quote}\setupcode\GOBBLEOPTARG}
{\end{quote}}
\newenvironment{codebox}{\begin{tableplain}\bgroup\setupcode\GOBBLEOPTARG}
{\egroup\end{tableplain}}
\renewenvironment{desc}{\begin{quote}}{\end{quote}}
\renewenvironment{exampletable}{%
\def\header#1{\\\leftline{#1}\\}%
\def\splitline#1#2{\\\leftline{#1}\\\leftline{#2}}%
\begin{tabular}{}}{\end{tabular}}
\newenvironment{tightcode}{\begin{code}}{\end{code}}
\renewenvironment{widecode}{\begin{code}}{\end{code}}
\renewenvironment{inset}{\begin{quote}}{\end{quote}}
\renewenvironment{leftinset}{\begin{quote}}{\end{quote}}
\renewenvironment{tightinset}{\begin{quote}}{\end{quote}}
\renewenvironment{tightleftinset}{\begin{quote}}{\end{quote}}
}

78
doc/scsh-manual/man.tex Normal file
View File

@ -0,0 +1,78 @@
% -*- latex -*-
% This is the reference manual for the Scheme Shell.
\documentclass[twoside]{report}
\usepackage{code,boxedminipage,makeidx,palatino,ct,
headings,mantitle,array,matter,mysize10,tex2page}
\texonly
% tex2page defines \url and hyperref loads the package url
% but setting \url to \relax satisfies \newcommand
\let\url\relax
\input{pdfcond}
\ifpdf
\usepackage[pdftex,hyperindex,
pdftitle={scsh manual, release 0.6.7},
pdfauthor={Olin Shivers, Brian D.~Carlstrom, Martin Gasbichler,
and Mike Sperber}
colorlinks=true,linkcolor=blue,pagecolor=blue,urlcolor=blue,
pdfstartview=FitH,pdfview=FitH]{hyperref}
\usepackage{thumbpdf}
\usepackage{tocbibind}
\else
\usepackage[dvipdfm,hyperindex,hypertex,
colorlinks=true,linkcolor=blue,pagecolor=blue,urlcolor=blue]{hyperref}
\fi
\endtexonly
% These fonts are good choices for screen-readable pdf, but the man needs
% a pass over the layout, since the this tt font will blow out the width
% of some examples, making them wrap and generally screwing them up. Maybe this
% should also be a LaTeX option, so we can get palatino on the hardcopy
% runs and these fonts on pdf runs...
%\renewcommand{\rmdefault}{phv}
%\renewcommand{\sfdefault}{phv}
%\renewcommand{\ttdefault}{pcr}
% Style issues
\parskip = 3pt plus 3pt
\sloppy
%\includeonly{miscprocs}
\input{decls}
\makeindex
%%% End preamble
\begin{document}
\frontmatter
\include{front}
\mainmatter
\include{intro}
\include{procnotation}
\include{syscalls}
\include{network}
\include{strings}
\include{sre}
\include{rdelim}
\include{awk}
\include{threads}
\include{miscprocs}
\include{running}
\backmatter
\printindex
\end{document}
% General things to do when converting ASCII text to LaTeX:
% Build a set of \breakondash, \breakondot, \breakonslash commands
% that will enable breaking in \tt. This is better than \=, etc.
%
% Check for ..., quote char, double-dashes --
% Double-word check
% lambda -> \l

View File

@ -0,0 +1,76 @@
% This is the title page style stolen from the Texinfo design,
% and expressed as a LaTeX style option. It is useful for manuals.
%
% Note that I play some *really* revolting games here to override
% the vertical and horizontal margins temporarily for the title page.
% The layout assumes you have 8.5" x 11" paper. You'd have to redo this
% for A4 or another size.
% -Olin 7/94
% Fonts for title page:
\DeclareFixedFont{\titlefont}%
{\encodingdefault}{\familydefault}{bx}{\shapedefault}{20.5pt}
\DeclareFixedFont{\authorfnt}%
{\encodingdefault}{\familydefault}{bx}{\shapedefault}{14.4pt}
\DeclareFixedFont{\subtitlefnt}%
{\encodingdefault}{\familydefault}{m}{\shapedefault}{11}
%\def\authorrm{\normalfont\selectfont\fontseries{bx}\fontsize{14.4}{14.4}}
%\def\subtitlefnt{\normalfont\selectfont\fontsize{11}{11}}
\newskip\titlepagetopglue \titlepagetopglue = 2.5in
\newlength{\widewidth}
\setlength{\widewidth}{6.5in}
\newlength{\negwidemargin}
\setlength{\negwidemargin}{-\oddsidemargin} % Reset the margin
\addtolength{\negwidemargin}{-1in} % to edge of page
\addtolength{\negwidemargin}{1in} % Then move right one inch.
%\def\wideline#1{\hbox to 0pt{\hspace\negwidemargin\hbox to\widewidth{#1}}}
\def\wideline#1{\hbox{\makebox[0pt][l]{\hspace\negwidemargin\hbox to\widewidth{#1}}}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\def\maketitle{\begin{titlepage}
\thispagestyle{empty}
\let\footnotesize\small \let\footnoterule\relax
\null
\parindent=0pt
\def\subtitlefont{\normalbaselineskip = 13pt \normalbaselines \subtitlefnt}%
\def\authorfont{\normalbaselineskip = 16pt \normalbaselines \authorfnt}%
%
% Leave some space at the very top of the page.
\vspace*{-1in}\vspace*{-\topmargin}\vspace*{-\headheight}\vspace*{-\headsep}
\vglue\titlepagetopglue
%
\wideline{\titlefont \@title \hfill} % title
% \vskip4pt
\vskip -0.3\baselineskip
\wideline{\leaders\hrule height 4pt\hfill}
\wideline{\hfill\subtitlefont\begin{tabular}[t]{@{}r@{}}\@subtitle%
\\\@date%
\end{tabular}} % subtitle
%
% author
\vskip 0pt plus 1filll
\wideline{\authorfont \begin{tabular}[t]{@{}c@{}}\@author
\end{tabular}\hfill}
%
% \vskip4pt
\vskip -0.3\baselineskip
\wideline{\leaders\hrule height 2pt\hfill}
% This weirdness puts the bottom line 2.75 in from the bottom of
% an 11in page.
\vskip \textheight \vskip \headsep \vskip \headheight
\vskip \topmargin \vskip 1in \vskip -11in \vskip 2.75in
\gdef\@author{}\gdef\@title{}\gdef\@subtitle{}\let\maketitle\relax
\end{titlepage}
\setcounter{page}{2}
}
\def\subtitle#1{\gdef\@subtitle{#1}}
\def\@subtitle{}

View File

@ -0,0 +1,16 @@
%&latex -*- latex -*-
% Implement the \frontmatter, \mainmatter, and \backmatter macros,
% so I can use them in reports, not just books.
\newif\if@mainmatter \@mainmattertrue
\newcommand\frontmatter{%
\cleardoublepage\@mainmatterfalse\pagenumbering{roman}}
\newcommand\mainmatter{%
\cleardoublepage\@mainmattertrue%
\pagenumbering{arabic}\setcounter{page}{1}}
\newcommand\backmatter{%
\if@openright\cleardoublepage\else\clearpage\fi%
\@mainmatterfalse}

View File

@ -0,0 +1,457 @@
%&latex -*- latex -*-
\chapter{Miscellaneous routines}
\section{Integer bitwise ops}
\label{sec:bitwise}
\defun{arithmetic-shift} {i j} \integer
\defunx {bitwise-and} {i j} \integer
\defunx {bitwise-ior} {i j} \integer
\defunx {bitwise-not} {i} \integer
\defunx {bitwise-xor} {i j} \integer
\begin{desc}
These operations operate on integers representing semi-infinite
bit strings, using a 2's-complement encoding.
\ex{arithmetic-shift} shifts \var{i} by \var{j} bits.
A left shift is $j > 0$; a right shift is $j < 0$.
\end{desc}
\section{Password encryption}
\defun {crypt} {key salt} {encrypted value}
Decrypts \var{key} by directly calling the \texttt{crypt} function
using \var{salt} to perturb the hashing algorithm. \var{Salt} must be
a two-character string consisting of digits, alphabetic characters,
``.'' or ``\verb+\+''. The length of \var{key} may be at most eight.
\section{Dot-Locking}
Section \ref{sec:filelocking} already points out that {\Posix}'s file
locks are almost useless in practice. To bypass this restriction other
advisory locking mechanisms, based only on standard file operations,
where invented. One of them is the so-called \emph{dot-locking} scheme
where the lock of \textit{file-name} is represented by the file
\textit{file-name}\texttt{.lock}. Care is taken that only one process
may generate the lock for a given file.
Here is scsh's interface to dot-locking:
\defun {obtain-dot-lock} {file-name [interval retry-number stale-time]} {\boolean}
\begin{desc}
Tries to obtain the lock for \var{file-name}. If the file is already
locked, the thread sleeps for \var{interval} seconds (default is 1)
before it retries. If the lock cannot be obtained after
\var{retry-number} attempts, the procedure returns \sharpf,
otherwise \sharpt. The default value of \var{retry-number} is
\sharpf{} which corresponds to an infinite number of retires.
If \var{stale-time} is non-\sharpf, it specifies the minimum age a
lock may have (in seconds) before it is considered \textit{stale}.
\ex{Obtain-dot-lock} attempts to delete stale locks. If it was
succcessful obtaining a lock after breaking it, \ex{obtain-dot-lock}
returns \ex{broken}. If \var{stale-time} is \sharpf,
\ex{obtain-dot-lock} never considers a lock stale. The default for
\var{stale-time} is 300.
Note that it is possible that \ex{obtain-dot-lock} breaks a lock
but nevertheless fails to obtain it otherwise. If it is necessary
to handle this case specially, use \ex{break-dot-lock} directly
(see below) rather than specifying a non-\sharpf{} \var{stale-time}
\end{desc}
\defun {break-dot-lock} {file-name} {undefined}
\begin{desc}
Breaks the lock for \var{file-name} if one exists. Note that
breaking a lock does \emph{not} imply a subsequent
\ex{obtain-dot-lock} will succeed, as another party may have
acquired the lock between \ex{break-dot-lock} and
\ex{obtain-dot-lock}.
\end{desc}
\defun {release-dot-lock} {file-name} {\boolean}
\begin{desc}
Releases the lock for \var{file-name}. On success,
\ex{release-dot-lock} returns \sharpt, otherwise \sharpf. Note that
this procedure can also be used to break the lock for
\var{file-name}.
\end{desc}
\defun{with-dot-lock*} {file-name thunk} {value(s) of thunk}
\dfnx{with-dot-lock} {file-name body \ldots} {value(s) of body}{syntax}
\begin{desc}
The procedure \ex{with-dot-lock*} obtains the requested lock, and
then calls \ex{(\var{thunk})}. When \var{thunk} returns, the lock is
released. A non-local exit (\eg, throwing to a saved continuation
or raising an exception) also causes the lock to be released.
After a normal return from \var{thunk}, its return values are
returned by \ex{with-dot-lock*}. The \ex{with-dot-lock} special
form is equivalent syntactic sugar.
\end{desc}
\section{Syslog facility}
\label{syslog-facility}
(Note: the functionality presented in this section is still somewhat
experimental and thus subject to interface changes.)
The procedures in this section provide access to the 4.2BSD syslog
facility present in most POSIX systems. The functionality is in a
structure called \ex{syslog}. There's an additional structure
\ex{syslog-channels} documented below. The scsh interface to
the syslog facility differs significantly from that of the Unix
library functionality in order to support multiple simultaneous
connections to the syslog facility.
Log messages carry a variety of parameters beside the text of the
message itself, namely a set of options controlling the output format
and destination, the facility identifying the class of programs the
message is coming from, an identifier specifying the conrete program,
and the level identifying the importance of the message. Moreover, a
log mask can prevent messages at certain levels to be actually sent to
the syslog daemon.
\subsection*{Log options}
A log option specifies details of the I/O behavior of the syslog
facility. A syslog option is an element of a finite type (see
the \scm~manual) constructed by the
\ex{syslog-option} macro. The syslog facility works with sets of
options which are represented as enum sets (see
the \scm~manual).
\dfn{syslog-option}{option-name}{option}{syntax}
\defun{syslog-option?}{x}{boolean}
\defun{make-syslog-options}{list}{options}
\dfn{syslog-options}{option-name \ldots}{options}{syntax}
\defun{syslog-options?}{x}{boolean}
\begin{desc}
\ex{Syslog-option} constructs a log option from the name of an
option. (The possible names are listed below.) \ex{Syslog-option?}
is a predicate for log options. Options are comparable using
\ex{eq?}. \ex{Make-syslog-options} constructs a set of options
from a list of options. \ex{Syslog-options} is a macro which
expands into an expression returning a set of options from names.
\ex{Syslog-options?} is a predicate for sets of options.
\end{desc}
%
Here is a list of possible names of syslog options:
\begin{description}
\item[\ex{console}]
If syslog cannot pass the message to syslogd it will attempt to
write the message to the console.
\item[\ex{delay}]
Delay opening the connection to syslogd immediately until the first
message is logged.
\item[\ex{no-delay}]
Open the connection to syslogd immediately. Normally
the open is delayed until the first message is logged.
Useful for programs that need to manage the order in which
file descriptors are allocated.
\noindent\textbf{NOTA BENE:}
The \ex{delay} and \ex{no-delay} options are included for
completeness, but do not have the expected effect in the present
Scheme interface: Because the Scheme interface has to multiplex
multiple simultaneous connections to the syslog facility over a
single one, open and close operations on that facility happen at
unpredictable times.
\item[\ex{log-pid}]
Log the process id with each message: useful for identifying
instantiations of daemons.
\end{description}
\subsection*{Log facilities}
A log facility identifies the originator of a log message from a
finite set known to the system. Each originator is identified by a
name:
\dfn{syslog-facility}{facility-name}{facility}{syntax}
\defun{syslog-facility?}{x}{boolean}
\begin{desc}
\ex{Syslog-facility} is macro that expands into an expression
returning a facility for a given name. \ex{Syslog-facility?} is a
predicate for facilities. Facilities are comparable via \ex{eq?}.
\end{desc}
%
Here is a list of possible names of syslog facilities:
\begin{description}
\item[\ex{authorization}]
The authorization system: login, su, getty, etc.
\item[\ex{cron}]
The cron daemon.
\item[\ex{daemon}]
System daemons, such as routed, that are not provided for explicitly
by other facilities.
\item[\ex{kernel}]
Messages generated by the kernel.
\item[\ex{lpr}]
The line printer spooling system: lpr, lpc, lpd, etc.
\item[\ex{mail}]
The mail system.
\item[\ex{news}]
The network news system.
\item[\ex{user}]
Messages generated by random user processes.
\item[\ex{uucp}]
The uucp system.
\item[\ex{local0} \ex{local1} \ex{local2} \ex{local3} \ex{local4} \ex{local5} \ex{local6} \ex{local7}]
Reserved for local use.
\end{description}
\subsection*{Log levels}
A log level identifies the importance of a message from a fixed set
of possible levels.
\dfn{syslog-level}{level-name}{level}{syntax}
\defun{syslog-level?}{x}{boolean}
%
\begin{desc}
\ex{Syslog-level} is macro that expands into an expression returning
a facility for a given name. \ex{Syslog-level?} is a predicate for
facilities. Levels are comparable via \ex{eq?}.
\end{desc}
%
Here is a list of possible names of syslog levels:
\begin{description}
\item[\ex{emergency}]
A panic condition. This is normally broadcast to all users.
\item[\ex{alert}]
A condition that should be corrected immediately, such as a
corrupted system database.
\item[\ex{critical}]
Critical conditions, e.g., hard device errors.
\item[\ex{error}]
Errors.
\item[\ex{warning}]
Warning messages.
\item[\ex{notice}]
Conditions that are not error conditions, but should possibly be
handled specially.
\item[\ex{info}]
Informational messages.
\item[\ex{debug}]
Messages that contain information normally of use only when
debugging a program.
\end{description}
\subsection*{Log masks}
A log masks can mask out log messages at a set of levels. A log
mask is an enum set of log levels.
\defun{make-syslog-mask}{list}{mask}
\dfn{syslog-mask}{level-name \ldots}{mask}{syntax}
\defvar{syslog-mask-all}{mask}
\defun{syslog-mask-upto}{level}{mask}
\defun{syslog-mask?}{x}{boolean}
\begin{desc}
\ex{Make-syslog-mask} constructs a mask from a list of levels.
\ex{Syslog-mask} is a macro which constructs a mask from names of
levels. \ex{Syslog-mask-all} is a predefined log mask containing
all levels. \ex{Syslog-mask-upto} returns a mask consisting of all
levels up to and including a certain level, starting with
\ex{emergency}.
\end{desc}
\subsection*{Logging}
Scheme~48 dynamically maintains implicit connections to the syslog
facility specifying a current identifier, current options, a current
facility and a current log mask. This implicit connection is held in
a thread fluid (see
Section~\ref{sec:ps_interac}). Hence, every thread
maintains it own implicit connection to syslog. Note that the
connection is not implicitly preserved across a \ex{spawn}, but it
is preserved across a \ex{fork-thread}:
\defun{with-syslog-destination}{string options facility mask thunk}{value}
\defun{set-syslog-destination!}{string options facility mask}{undefined}
%
\begin{desc}
\ex{With-syslog-destination} dynamically binds parameters of the
implicit connection to the syslog facility and runs \var{thunk}
within those parameter bindings, returning what \var{thunk}
returns. Each of the parameters may be \ex{\#f} in which case the
previous values will be used. \ex{Set-syslog-destination!} sets the
parameters of the implicit connection of the current thread.
\end{desc}
\defun{syslog}{level message}{undefined}
\defun{syslog}{level message [string options syslog-facility]}{undefined}
%
\begin{desc}
\ex{Syslog} actually logs a message. Each of the parameters of the
implicit connection (except for the log mask) can be explicitly
specified as well for the current call to \ex{syslog}, overriding
the parameters of the channel. The parameters revert to their
original values after the call.
\end{desc}
\subsection*{Syslog channels}
%
The \ex{syslog-channels} structure allows direct manipulation of
syslog channels, the objects that represent connections to the syslog
facility. Note that it is
not necessary to explicitly open a syslog channel to do logging.
\defun{open-syslog-channel}{string options facility mask}{channel}
\defun{close-syslog-channel}{channel}{undefined}
\defun{syslog}{level message channel}{undefined}
%
\begin{desc}
\ex{Open-syslog-channel} and \ex{close-syslog-channel} create and
destroy a connection to the syslog facility, respectively. The
specified form of calling \ex{syslog} logs to the specified channel.
\end{desc}
\section{MD5 interface}
\label{sec:md5}
Scsh provides a direct interface to the MD5 functions to compute the
``fingerprint'' or ``message digest'' of a file or string. It uses the
C library written by Colin Plum.
\defun{md5-digest-for-string}{string}{md5-digest}
\begin{desc}
Calculates the MD5 digest for the given string.
\end{desc}
\defun{md5-digest-for-port}{port [buffer-size]}{md5-digest}
\begin{desc}
Reads the contents of the port and calculates the MD5 digest for it.
The optional argument \var{buffer-size} determines the size of the
port's input buffer in bytes. It defaults to 1024 bytes.
\end{desc}
\defun{md5-digest?}{thing}{boolean}
\begin{desc}
The type predicate for MD5 digests: \ex{md5-digest?} returns true if
and only if \var{thing} is a MD5 digest.
\end{desc}
\defun{md5-digest->number}{md5-digest}{number}
\begin{desc}
Returns the number corresponding to the MD5 digest.
\end{desc}
\defun{number->md5-digest}{number}{md5-digest}
\begin{desc}
Creates a MD5 digest from a number.
\end{desc}
\defun{make-md5-context}{}{md5-context}
\defunx{md5-context?}{thing}{boolean}
\defunx{update-md5-context!}{md5-context string}\undefined
\defunx{md5-context->md5-digest}{md5-context}{md5-digest}
\begin{desc}
These procedures provide a low-level interface to the library. A
\var{md5-context} stores the state of a MD5 computation, it is
created by \ex{make-md5-context}, its type predicate is
\ex{md5-context?}. The procedure \ex{update-md5-context!} extends
the \var{md5-context} by the given string. Finally,
\ex{md5-context->md5-digest} returns the \var{md5-digest} for the
\var{md5-context}. With these procedures it is possible to
incrementally add strings to a \var{md5-context} before computing
the digest.
\end{desc}
\section{Configuration variables}
\label{sec:configure}
This section describes procedures to access the configuration
parameters used to compile scsh and flags needed to build C extensions
for scsh.
\defun{host}{}{string}
\defunx{machine}{}{string}
\defunx{vendor}{}{string}
\defunx{os}{}{string}
\begin{desc}
These procedures return the description of the host, scsh was built
on, as determined by the script \texttt{config.guess}.
\end{desc}
%
\defun{prefix}{}{string}
\defunx{exec-prefix}{}{string}
\defunx{bin-dir}{}{string}
\defunx{lib-dir}{}{string}
\defunx{include-dir}{}{string}
\defunx{man-dir}{}{string}
\begin{desc}
These procedures return the various directories of
the scsh installation.
\end{desc}
%
\defun{lib-dirs-list}{}{symbol list}
\begin{desc}
Returns the default list of library directories. See
Section~\ref{sec:scsh-switches} for more information about the
library search facility.
\end{desc}
%
\defun{libs}{}{string}
\defunx{defs}{}{string}
\defunx{cflags}{}{string}
\defunx{cppflags}{}{string}
\defunx{ldflags}{}{string}
\begin{desc}
The values returned by these procedures correspond to the values
\texttt{make} used to compile scsh's C files.
\end{desc}
%
\defunx{compiler-flags}{}{string}
\begin{desc}
The procedure \var{compiler-flags} returns flags suitable for
running the C compiler when compiling a C file that uses scsh's
foreign function interface.
\end{desc}
\defun{linker-flags}{}{string}
\begin{desc}
Scsh also comes as a library that can be linked into other programs.
The procedure \var{linker-flags} returns the appropriate flags to
link the scsh library to another program.
\end{desc}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "man"
%%% End:

View File

@ -0,0 +1,22 @@
%&latex -*- latex -*-
\if@twoside
\oddsidemargin 44pt
\evensidemargin 82pt
\marginparwidth 107pt
\else
\oddsidemargin 63pt
\evensidemargin 63pt
\marginparwidth 90pt
\fi
\marginparsep 11pt
\topmargin 27pt
\headheight 12pt
\headsep 25pt
\topskip = 10pt
\footskip 30pt
\textheight = 43\baselineskip
\advance\textheight by \topskip
\textwidth 345pt
\endinput

465
doc/scsh-manual/network.tex Normal file
View File

@ -0,0 +1,465 @@
%&latex -*- latex -*-
\chapter{Networking}
The Scheme Shell provides a BSD-style sockets interface.
There is not an official standard for a network interface
for scsh to adopt (this is the subject of the forthcoming Posix.8
standard).
However, Berkeley sockets are a \emph{de facto} standard,
being found on most Unix workstations and PC operating systems.
It is fairly straightforward to add higher-level network protocols
such as smtp, telnet, or http on top of the the basic socket-level
support scsh provides.
The Scheme Underground has also released a network library with
many of these protocols as a companion to the current release of scsh.
See this code for examples showing the use of the sockets interface.
\section{High-level interface}
For convenience, and to avoid some of the messy details of the socket
interface, we provide a high level socket interface. These routines
attempt to make it easy to write simple clients and servers without
having to think of many of the details of initiating socket connections.
We welcome suggested improvements to this interface, including better
names, which right now are solely descriptions of the procedure's action.
This might be fine for people who already understand sockets,
but does not help the new networking programmer.
\defun {socket-connect} {protocol-family socket-type . args} {socket}
\begin{desc}
\ex{socket-connect} is intended for creating client applications.
\var{protocol-family} is specified as either the
\ex{protocol-family/internet} or \ex{protocol-family/unix}.
\var{socket-type} is specified as either \ex{socket-type/stream} or
\ex{socket-type/datagram}. See \ex{socket} for a more complete
description of these terms.
The variable \var{args} list is meant to specify protocol family
specific information. For Internet sockets, this consists of two
arguments: a host name and a port number. For {\Unix} sockets, this
consists of a pathname.
\ex{socket-connect} returns a \ex{socket} which can be used for input
and output from a remote server. See \ex{socket} for a description of
the \emph{socket record}.
\end{desc}
\defun {bind-listen-accept-loop} {protocol-family proc arg} {does-not-return}
\begin{desc}
\ex{bind-listen-accept-loop} is intended for creating server
applications. \var{protocol-family} is specified as either the
\ex{protocol-family/internet} or \ex{protocol-family/unix}.
\var{proc} is a procedure of two arguments: a \ex{socket} and a
{socket-address}. \var{arg} specifies a port number for Internet sockets
or a pathname for {\Unix} sockets. See \ex{socket} for a more complete
description of these terms.
\var{proc} is called with a socket and a socket address each time there
is a connection from a client application. The socket allows
communications with the client. The socket address specifies the
address of the remote client.
This procedure does not return, but loops indefinitely accepting
connections from client programs.
\end{desc}
\defun {bind-prepare-listen-accept-loop} {protocol-family prepare proc arg} {does-not-return}
\begin{desc}
Same as \ex{bind-listen-accept-loop} but runs the thunk
\var{prepare} after binding the address and before entering the
loop. The typical task of the \var{prepare} procedure is to change
the user id from the superuser to some unprivileged id once the
address has been bound.
\end{desc}
\section{Sockets}
\defun {create-socket} {protocol-family type [protocol]} {socket}
\defunx {create-socket-pair} {type} {[socket$_{1}$ socket$_{2}$]}
\defunx {close-socket} {socket} \undefined
\begin{desc}
A socket is one end of a network connection. Three specific properties
of sockets are specified at creation time: the protocol-family, type,
and protocol.
The \var{protocol-family} specifies the protocol family to be used with
the socket. This also determines the address family of socket addresses,
which are described in more detail below. Scsh currently supports the
{\Unix} internal protocols and the Internet protocols using the
following constants:
\begin{code}\codeallowbreaks
protocol-family/unspecified
protocol-family/unix
protocol-family/internet\end{code}
The \var{type} specifies the style of communication. Examples that your
operating system probably provides are stream and datagram sockets.
Others maybe available depending on your system. Typical values are:
\begin{code}\codeallowbreaks
socket-type/stream
socket-type/datagram
socket-type/raw\end{code}
The \var{protocol} specifies a particular protocol to use within a
protocol family and type. Usually only one choice exists, but it's
probably safest to set this explicitly. See the protocol database
routines for information on looking up protocol constants.
New sockets are typically created with \ex{create-socket}. However,
\ex{create-socket-pair} can also be used to create a pair of connected
sockets in the \ex{protocol-family/unix} protocol-family. The value of a
returned socket is a \emph{socket record}, defined to have the following
structure:
\begin{code}
(define-record socket
family ; protocol family
inport ; input-port
outport) ; output-port\end{code}
The \ex{family} specifies the protocol family of the socket. The
\ex{inport} and \ex{outport} fields are ports that can be used for input
and output, respectively. For a stream socket, they are only usable
after a connection has been established via \ex{connect-socket} or
\ex{accept-connection}. For a datagram socket, \var{outport} can be
immediately using \ex{send-message}, and \var{inport} can be used after
\ex{bind} has created a local address.
\ex{close-socket} provides a convenient way to close a socket's port. It
is preferred to explicitly closing the inport and outport because using
\ex{close} on sockets is not currently portable across operating systems.
\end{desc}
\defun {port->socket} {port protocol-family} {socket}
\begin{desc}
This procedure turns \var{port} into a socket object. The port's
underlying file descriptor must be a socket with protocol family
\var{protocol-family}. \ex{port->socket} applies \ex{dup->inport}
and \ex{dup->outport} to \var{port} to create the ports of the
socket object.
\ex{port->socket} comes in handy for writing
servers which run as children of \texttt{inetd}: after receiving a
connection \texttt{inetd} creates a socket and passes it as
standard input to its child.
\end{desc}
\section{Socket addresses}
The format of a socket-address depends on the address family of the
socket. Address-family-specific routines are provided to convert
protocol-specific addresses to socket addresses. The value returned by
these routines is a \emph{socket-address record}, defined to have the
following visible structure:
\begin{code}
(define-record socket-address
family) ; address family\end{code}
The \ex{family} is one of the following constants:
\begin{code}\codeallowbreaks
address-family/unspecified
address-family/unix
address-family/internet\end{code}
\defun {unix-address->socket-address} {pathname} {socket-address}
\begin{desc}
\ex{unix-address->socket-address} returns a \var{socket-address} based
on the string \var{pathname}. There is a system dependent limit on the
length of \var{pathname}.
\end{desc}
\defun {internet-address->socket-address} {host-address service-port} {socket-address}
\begin{desc}
\ex{internet-address->socket-address} returns a \var{socket-address} based
on an integer \var{host-address} and an integer \var{service-port}.
Besides being a 32-bit host address, an Internet host address can also
be one of the following constants:
\begin{code}\codeallowbreaks
internet-address/any
internet-address/loopback
internet-address/broadcast\end{code}
The use of \ex{internet-address/any} is described below in
\ex{bind-socket}. \ex{internet-address/loopback} is an address that
always specifies the local machine. \ex{internet-address/broadcast} is
used for network broadcast communications.
For information on obtaining a host's address, see the \ex{host-info}
function.
\end{desc}
\defun {socket-address->unix-address} {socket-address} {pathname}
\defunx {socket-address->internet-address} {socket-address} {[host-address service-port]}
\begin{desc}
The routines \ex{socket-address->internet-address} and
\ex{socket-address->unix-address} return the address-family-specific addresses.
Be aware that most implementations don't correctly return anything more
than an empty string for addresses in the {\Unix} address-family.
\end{desc}
\section{Socket primitives}
The procedures in this section are presented in the order in which a
typical program will use them. Consult a text on network systems
programming for more information on sockets.\footnote{
Some recommended ones are:
\begin{itemize}
\item ``Unix Network Programming'' by W. Richard Stevens
\item ``An Introductory 4.3BSD Interprocess Communication Tutorial.''
(reprinted in UNIX Programmer's Supplementary Documents Volume 1, PS1:7)
\item ``An Advanced 4.3BSD Interprocess Communication Tutorial.''
(reprinted in UNIX Programmer's Supplementary Documents Volume 1, PS1:8)
\end{itemize}
}
The last two tutorials are freely available as part of BSD. In the
absence of these, your {\Unix} manual pages for socket might be a good
starting point for information.
\defun {connect-socket} {socket socket-address} \undefined
\begin{desc}
\ex{connect-socket} sets up a connection from a \var{socket}
to a remote \var{socket-address}. A connection has different meanings
depending on the socket type. A stream socket must be connected before
use. A datagram socket can be connected multiple times, but need not be
connected at all if the remote address is specified with each
\ex{send-message}, described below. Also, datagram sockets
may be disassociated from a remote address by connecting to a null
remote address.
\end{desc}
\defun {connect-socket-no-wait} {socket socket-address} \boolean
\defunx {connect-socket-successful?} {socket} \boolean
\begin{desc}
Just like \ex{connect-socket}, \ex{connect-socket-no-wait} sets up a
connection from a \var{socket} to a remote \var{socket-address}.
Unlike \ex{connect-socket}, \ex{connect-socket-no-wait} does not
block if it cannot establish the connection immediately. Instead it
will return \sharpf{} at once. In this case a subsequent \ex{select} on
the output port of the socket will report the output port as ready
as soon as the operation system has established the connection or as
soon as setting up the connection led to an error. Afterwards, the
procedure \ex{connect-socket-successful?} can be used to test
whether the connection has been established successfully or not.
\end{desc}
\defun {bind-socket} {socket socket-address} \undefined
\begin{desc}
\ex{bind-socket} assigns a certain local \var{socket-address} to a
\var{socket}. Binding a socket reserves the local address. To receive
connections after binding the socket, use \ex{listen-socket} for stream
sockets and \ex{receive-message} for datagram sockets.
Binding an Internet socket with a host address of
\ex{internet-address/any} indicates that the caller does
not care to specify from which local network interface connections are
received. Binding an Internet socket with a service port number of zero
indicates that the caller has no preference as to the port number
assigned.
Binding a socket in the {\Unix} address family creates a socket special
file in the file system that must be deleted before the address can be
reused. See \ex{delete-file}.
\end{desc}
\defun {listen-socket} {socket backlog} \undefined
\begin{desc}
\ex{listen-socket} allows a stream \var{socket} to start receiving connections,
allowing a queue of up to \var{backlog} connection requests. Queued
connections may be accepted by \ex{accept-connection}.
\end{desc}
\defun {accept-connection} {socket} {[new-socket socket-address]}
\begin{desc}
\ex{accept-connection} receives a connection on a \var{socket}, returning
a new socket that can be used for this connection and the remote socket
address associated with the connection.
\end{desc}
\defun {socket-local-address} {socket} {socket-address}
\defunx {socket-remote-address} {socket} {socket-address}
\begin{desc}
Sockets can be associated with a local address or a remote address or
both. \ex{socket-local-address} returns the local \var{socket-address}
record associated with \var{socket}. \ex{socket-remote-address} returns
the remote \var{socket-address} record associated with \var{socket}.
\end{desc}
\defun {shutdown-socket} {socket how-to} \undefined
\begin{desc}
\ex{shutdown-socket} shuts down part of a full-duplex socket.
The method of shutting done is specified by the \var{how-to} argument,
one of:
\begin{code}\codeallowbreaks
shutdown/receives
shutdown/sends
shutdown/sends+receives\end{code}
\end{desc}
\section{Performing input and output on sockets}
\defun {receive-message} {socket length [flags]} {[string-or-\sharpf{} socket-address]}
\dfnix {receive-message!} {socket string [start] [end] [flags]}
{[count-or-\sharpf{} socket-address]}{procedure}
{receive-message"!@\texttt{receive-message"!}}
\defunx {receive-message/partial} {socket length [flags]}
{[string-or-\sharpf{} socket-address]}
\dfnix {receive-message!/partial} {socket string [start] [end] [flags]}
{[count-or-\sharpf{} socket-address]}{procedure}
{receive-message"!/partial@\texttt{receive-message"!/partial}}
\defun {send-message} {socket string [start] [end] [flags] [socket-address]}
\undefined
\defunx {send-message/partial}
{socket string [start] [end] [flags] [socket-address]} {count}
\begin{desc}
For most uses, standard input and output routines such as
\ex{read-string} and \ex{write-string} should suffice. However, in some
cases an extended interface is required. The \ex{receive-message} and
\ex{send-message} calls parallel the \ex{read-string} and
\ex{write-string} calls with a similar naming scheme.
One additional feature of these routines is that \ex{receive-message}
returns the remote \var{socket-address} and \var{send-message} takes an
optional remote
\ex{socket-address}. This allows a program to know the source of input
from a datagram socket and to use a datagram socket for output without
first connecting it.
All of these procedures take an optional \var{flags} field. This
argument is an integer bit-mask, composed by or'ing together the
following constants:
\begin{code}\codeallowbreaks
message/out-of-band
message/peek
message/dont-route\end{code}
See \ex{read-string} and \ex{write-string} for a more detailed
description of the arguments and return values.
\end{desc}
\section{Socket options}
\defun {socket-option} {socket level option} {value}
\defunx {set-socket-option} {socket level option value} \undefined
\begin{desc}
\ex{socket-option} and \ex{set-socket-option} allow the inspection and
modification, respectively, of several options available on sockets. The
\var{level} argument specifies what protocol level is to be examined or
affected. A level of \ex{level/socket} specifies the highest possible
level that is available on all socket types. A specific protocol number
can also be used as provided by \ex{protocol-info}, described below.
There are several different classes of socket options. The first class
consists of boolean options which can be either true or false. Examples
of this option type are:
\begin{code}\codeallowbreaks
socket/debug
socket/accept-connect
socket/reuse-address
socket/keep-alive
socket/dont-route
socket/broadcast
socket/use-loop-back
socket/oob-inline
socket/use-privileged
socket/cant-signal
tcp/no-delay\end{code}
Value options are another category of socket options. Options of this
type are an integer value. Examples of this option type are:
\begin{code}\codeallowbreaks
socket/send-buffer
socket/receive-buffer
socket/send-low-water
socket/receive-low-water
socket/error
socket/type
ip/time-to-live
tcp/max-segment\end{code}
A third option type specifies how long for data to linger after a socket
has been closed. There is only one option of this type:
\ex{socket/linger}. It is set with either \sharpf to disable it or an
integer number of seconds to linger and returns a value of the same type
upon inspection.
The fourth and final option type of this time is a timeout option. There
are two examples of this option type: \ex{socket/send-timeout} and
\ex{socket/receive-timeout}. These are set with a real number of
microseconds resolution and returns a value of the same type upon
inspection.
\end{desc}
\section{Database-information entries}
\defun {host-info} {name-or-socket-address} {host-info}
\defunx {network-info} {name-or-socket-address} {network-info or \sharpf}
\defunx {service-info} {name-or-number [protocol-name]} {service-info or \sharpf}
\defunx {protocol-info} {name-or-number} {protocol-info or \sharpf}
\begin{desc}
\ex{host-info} allows a program to look up a host entry based on either
its string \var{name} or \var{socket-address}. The value returned by this
routine is a \emph{host-info record}, defined to have the following
structure:
\begin{code}
(define-record host-info
name ; Host name
aliases ; Alternative names
addresses) ; Host addresses\end{code}
\ex{host-info} could fail and raise an error for one of the following
reasons:
\begin{code}\codeallowbreaks
herror/host-not-found
herror/try-again
herror/no-recovery
herror/no-data
herror/no-address\end{code}
\ex{network-info} allows a program to look up a network entry based on either
its string \var{name} or \var{socket-address}. The value returned by this
routine is a \emph{network-info record}, defined to have the following
structure:
\begin{code}
(define-record network-info
name ; Network name
aliases ; Alternative names
net) ; Network number\end{code}
\ex{service-info} allows a program to look up a service entry based
on either its string \var{name} or integer \var{port}. The value returned
by this routine is a \emph{service-info record}, defined to have the
following structure:
\begin{code}
(define-record service-info
name ; Service name
aliases ; Alternative names
port ; Port number
protocol) ; Protocol name\end{code}
\ex{protocol-info} allows a program to look up a protocol entry based
on either its string \var{name} or integer \var{number}. The value returned
by this routine is a \emph{protocol-info record}, defined to have the
following structure:
\begin{code}
(define-record protocol-info
name ; Protocol name
aliases ; Alternative names
number) ; Protocol number)\end{code}
\ex{network-info}, \ex{service-info} and \ex{protocol-info} return
\sharpf if the specified entity was not found.
\end{desc}

View File

@ -0,0 +1,14 @@
\newif\ifpdf
\ifx\pdfoutput\undefined
\pdffalse % we are not running PDFLaTeX
\else
\pdfoutput=1 % we are running PDFLaTeX
\pdftrue
\fi
% Then use your new variable \ifpdf
% \ifpdf
% \usepackage[pdftex]{graphicx}
% \pdfcompresslevel=9
% \else
% \usepackage{graphicx}
% \fi

View File

@ -0,0 +1,543 @@
%&latex -*- latex -*-
\chapter{Process notation}
\label{sec:proc-forms}
Scsh has a notation for controlling {\Unix} processes that takes the
form of s-expressions; this notation can then be embedded inside of
standard {\Scheme} code.
The basic elements of this notation are \emph{process forms},
\emph{extended process forms}, and \emph{redirections}.
\section{Extended process forms and I/O redirections}
An \emph{extended process form} is a specification of a {\Unix} process to
run, in a particular I/O environment:
\codex{\var{epf} {\synteq} (\var{pf} $ \var{redir}_1$ {\ldots} $ \var{redir}_n $)}
where \var{pf} is a process form and the $\var{redir}_i$ are redirection specs.
A \emph{redirection spec} is one of:
\begin{inset}
\begin{tabular}{@{}l@{\qquad{\tt; }}l@{}}
\ex{(< \var{[fdes]} \var{file-name})} & \ex{Open file for read.}
\\\ex{(> \var{[fdes]} \var{file-name})} & \ex{Open file create/truncate.}
\\\ex{(<< \var{[fdes]} \var{object})} & \ex{Use \var{object}'s printed rep.}
\\\ex{(>> \var{[fdes]} \var{file-name})} & \ex{Open file for append.}
\\\ex{(= \var{fdes} \var{fdes/port})} & \ex{Dup2}
\\\ex{(- \var{fdes/port})} & \ex{Close \var{fdes/port}.}
\\\ex{stdports} & \ex{0,1,2 dup'd from standard ports.}
\end{tabular}
\end{inset}
The input redirections default to file descriptor 0;
the output redirections default to file descriptor 1.
The subforms of a redirection are implicitly backquoted,
and symbols stand for their print-names.
So \ex{(> ,x)} means
``output to the file named by {\Scheme} variable \ex{x},''
and \ex{(< /usr/shivers/.login)} means ``read from \ex{/usr/shivers/.login}.''
\pagebreak
Here are two more examples of I/O redirection:
%
\begin{center}
\begin{codebox}
(< ,(vector-ref fv i))
(>> 2 /tmp/buf)\end{codebox}
\end{center}
%
These two redirections cause the file \ex{fv[i]} to be opened on stdin, and
\ex{/tmp/buf} to be opened for append writes on stderr.
The redirection \ex{(<< \var{object})} causes input to come from the
printed representation of \var{object}.
For example,
\codex{(<< "The quick brown fox jumped over the lazy dog.")}
causes reads from stdin to produce the characters of the above string.
The object is converted to its printed representation using the \ex{display}
procedure, so
\codex{(<< (A five element list))}
is the same as
\codex{(<< "(A five element list)")}
is the same as
\codex{(<< ,(reverse '(list element five A))){\rm.}}
(Here we use the implicit backquoting feature to compute the list to
be printed.)
The redirection \ex{(= \var{fdes} \var{fdes/port})} causes \var{fdes/port}
to be dup'd into file descriptor \var{fdes}.
For example, the redirection
\codex{(= 2 1)}
causes stderr to be the same as stdout.
\var{fdes/port} can also be a port, for example:
\codex{(= 2 ,(current-output-port))}
causes stderr to be dup'd from the current output port.
In this case, it is an error if the port is not a file port
(\eg, a string port).
More complex redirections can be accomplished using the \ex{begin}
process form, discussed below, which gives the programmer full control
of I/O redirection from {\Scheme}.
\subsection{Port and file descriptor sync}
\begin{sloppypar}
It's important to remember that rebinding Scheme's current I/O ports
(\eg, using \ex{call-with-input-file} to rebind the value of
\ex{(current-input-port)})
does \emph{not} automatically ``rebind'' the file referenced by the
{\Unix} stdio file descriptors 0, 1, and 2.
This is impossible to do in general, since some {\Scheme} ports are
not representable as {\Unix} file descriptors.
For example, many {\Scheme} implementations provide ``string ports,''
that is, ports that collect characters sent to them into memory buffers.
The accumulated string can later be retrieved from the port as a string.
If a user were to bind \ex{(current-output-port)} to such a port, it would
be impossible to associate file descriptor 1 with this port, as it
cannot be represented in {\Unix}.
So, if the user subsequently forked off some other program as a subprocess,
that program would of course not see the {\Scheme} string port as its standard
output.
\end{sloppypar}
To keep stdio synced with the values of {\Scheme}'s current I/O ports,
use the special redirection \ex{stdports}.
This causes 0, 1, 2 to be redirected from the current {\Scheme} standard ports.
It is equivalent to the three redirections:
\begin{code}
(= 0 ,(current-input-port))
(= 1 ,(current-output-port))
(= 2 ,(error-output-port))\end{code}
%
The redirections are done in the indicated order. This will cause an error if
one of the current I/O ports isn't a {\Unix} port (\eg, if one is a string
port).
This {\Scheme}/{\Unix} I/O synchronisation can also be had in {\Scheme} code
(as opposed to a redirection spec) with the \ex{(stdports->stdio)}
procedure.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Process forms}
A \emph{process form} specifies a computation to perform as an independent
{\Unix} process. It can be one of the following:
%
\begin{leftinset}
\begin{codebox}
(begin . \var{scheme-code})
(| \vari{pf}{\!1} {\ldots} \vari{pf}{\!n})
(|+ \var{connect-list} \vari{pf}{\!1} {\ldots} \vari{pf}{\!n})
(epf . \var{epf})
(\var{prog} \vari{arg}{1} {\ldots} \vari{arg}{n})
\end{codebox}
\qquad
\begin{codebox}
; Run \var{scheme-code} in a fork.
; Simple pipeline
; Complex pipeline
; An extended process form.
; Default: exec the program.
\end{codebox}
\end{leftinset}
%
The default case \ex{(\var{prog} \vari{arg}1 {\ldots} \vari{arg}n)}
is also implicitly backquoted.
That is, it is equivalent to:
%
\codex{(begin (apply exec-path `(\var{prog} \vari{arg}1 {\ldots} \vari{arg}n)))}
%
\ex{Exec-path} is the version of the \ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=exec&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{exec()}} system call that
uses scsh's path list to search for an executable.
The program and the arguments must be either strings, symbols, or integers.
Symbols and integers are coerced to strings.
A symbol's print-name is used.
Integers are converted to strings in base 10.
Using symbols instead of strings is convenient, since it suppresses the
clutter of the surrounding \ex{"\ldots"} quotation marks.
To aid this purpose, scsh reads symbols in a case-sensitive manner,
so that you can say
\codex{(more Readme)}
and get the right file.
A \var{connect-list} is a specification of how two processes are to be wired
together by pipes.
It has the form \ex{((\vari{from}1 \vari{from}2 {\ldots} \var{to}) \ldots)}
and is implicitly backquoted.
For example,
%
\codex{(|+ ((1 2 0) (3 1)) \vari{pf}{\!1} \vari{pf}{\!2})}
%
runs \vari{pf}{\!1} and \vari{pf}{\!2}.
The first clause \ex{(1 2 0)} causes \vari{pf}{\!1}'s
stdout (1) and stderr (2) to be connected via pipe
to \vari{pf}{\!2}'s stdin (0).
The second clause \ex{(3 1)} causes \vari{pf}{\!1}'s file descriptor 3 to be
connected to \vari{pf}{\!2}'s file descriptor 1.
%---this is unusual, and not expected to occur very often.
The \ex{begin} process form does a \ex{stdio->stdports} synchronisation
in the child process before executing the body of the form.
This guarantees that the \ex{begin} form, like all other process forms,
``sees'' the effects of any associated I/O redirections.
Note that {\RnRS} does not specify whether or not \ex{|} and \ex{|+}
are readable symbols. Scsh does.
\section{Using extended process forms in \Scheme}
Process forms and extended process forms are \emph{not} {\Scheme}.
They are a different notation for expressing computation that, like {\Scheme},
is based upon s-expressions.
Extended process forms are used in {\Scheme} programs by embedding them inside
special {\Scheme} forms.
There are three basic {\Scheme} forms that use extended process forms:
\ex{exec-epf}, \cd{&}, and \ex{run}.
\dfn {exec-epf} {. \var{epf}} {\noreturn} {syntax}
\dfnx {\&} {. \var{epf}} {proc} {syntax}
\dfnx {run} {. \var{epf}} {status} {syntax}
\begin{desc}
\index{exec-epf} \index{\&} \index{run}
The \ex{(exec-epf . \var{epf})} form nukes the current process: it establishes
the I/O redirections and then overlays the current process with the requested
computation.
The \ex{(\& . \var{epf})} form is similar, except that the process is forked
off in background. The form returns the subprocess' process object.
The \ex{(run . \var{epf})} form runs the process in foreground:
after forking off the computation, it waits for the subprocess to exit,
and returns its exit status.
These special forms are macros that expand into the equivalent
series of system calls.
The definition of the \ex{exec-epf} macro is non-trivial,
as it produces the code to handle I/O redirections and set up pipelines.
However, the definitions of the \cd{&} and \ex{run} macros are very simple:
\begin{leftinset}
\begin{tabular}{@{}l@{\quad$\equiv$\quad}l@{}}
\cd{(& . \var{epf})} & \ex{(fork (\l{} (exec-epf . \var{epf})))} \\
\ex{(run . \var{epf})} & \cd{(wait (& . \var{epf}))}
\end{tabular}
\end{leftinset}
\end{desc}
\subsection{Procedures and special forms}
It is a general design principle in scsh that all functionality
made available through special syntax is also available in a
straightforward procedural form.
So there are procedural equivalents for all of the process notation.
In this way, the programmer is not restricted by the particular details of
the syntax.
Here are some of the syntax/procedure equivalents:
\begin{inset}
\begin{tabular}{@{}|ll|@{}}
\hline
Notation & Procedure \\ \hline \hline
\ex{|} & \ex{fork/pipe} \\
\ex{|+} & \ex{fork/pipe+} \\
\ex{exec-epf} & \ex{exec-path} \\
redirection & \ex{open}, \ex{dup} \\
\cd{&} & \ex{fork} \\
\ex{run} & $\ex{wait} + \ex{fork}$ \\
\hline
\end{tabular}
\end{inset}
%
Having a solid procedural foundation also allows for general notational
experimentation using {\Scheme}'s macros.
For example, the programmer can build his own pipeline notation on top of the
\ex{fork} and \ex{fork/pipe} procedures.
Chapter~\ref{chapt:syscalls} gives the full story on all the procedures
in the syscall library.
\subsection{Interfacing process output to {\Scheme}}
\label{sec:io-interface}
There is a family of procedures and special forms that can be used
to capture the output of processes as {\Scheme} data.
%
\dfn {run/port} {. \var{epf}} {port} {syntax}
\dfnx{run/file} {. \var{epf}} {\str} {syntax}
\dfnx{run/string} {. \var{epf}} {\str} {syntax}
\dfnx{run/strings} {. \var{epf}} {{\str} list} {syntax}
\dfnx{run/sexp} {. \var{epf}} {object} {syntax}
\dfnx{run/sexps} {. \var{epf}} {list} {syntax}
\begin{desc}
These forms all fork off subprocesses, collecting the process' output
to stdout in some form or another.
The subprocess runs with file descriptor 1 and the current output port
bound to a pipe.
\begin{desctable}{0.7\linewidth}
\ex{run/port} & Value is a port open on process's stdout.
Returns immediately after forking child. \\
\ex{run/file} & Value is name of a temp file containing process's output.
Returns when process exits. \\
\ex{run/string} & Value is a string containing process' output.
Returns when eof read. \\
\ex{run/strings}& Splits process' output into a list of
newline-delimited strings. Returns when eof read. \\
\ex{run/sexp} & Reads a single object from process' stdout with \ex{read}.
Returns as soon as the read completes. \\
\ex{run/sexps} & Repeatedly reads objects from process' stdout with \ex{read}.
Returns accumulated list upon eof.
\end{desctable}
The delimiting newlines are not included in the strings returned by
\ex{run/strings}.
These special forms just expand into calls to the following analogous
procedures.
\end{desc}
\defun {run/port*} {thunk} {port}
\defunx {run/file*} {thunk} {\str}
\defunx {run/string*} {thunk} {\str}
\defunx {run/strings*} {thunk} {{\str} list}
\defunx {run/sexp*} {thunk} {object}
\defunx {run/sexps*} {thunk} {object list}
\begin{desc}
For example, \ex{(run/port . \var{epf})} expands into
\codex{(run/port* (\l{} (exec-epf . \var{epf}))).}
\end{desc}
The following procedures are also of utility for generally parsing
input streams in scsh:
\defun {port->string} {port} {\str}
\defunx {port->sexp-list} {port} {list}
\defunx {port->string-list} {port} {{\str} list}
\defunx {port->list} {reader port} {list}
\begin{desc}
\ex{Port->string} reads the port until eof,
then returns the accumulated string.
\ex{Port->sexp-list} repeatedly reads data from the port until eof,
then returns the accumulated list of items.
\ex{Port->string-list} repeatedly reads newline-terminated strings from the
port until eof, then returns the accumulated list of strings.
The delimiting newlines are not part of the returned strings.
\ex{Port->list} generalises these two procedures.
It uses \var{reader} to repeatedly read objects from a port.
It accumulates these objects into a list, which is returned upon eof.
The \ex{port->string-list} and \ex{port->sexp-list} procedures
are trivial to define, being merely \ex{port->list} curried with
the appropriate parsers:
\begin{code}\cddollar
(port->string-list \var{port}) $\equiv$ (port->list read-line \var{port})
(port->sexp-list \var{port}) $\equiv$ (port->list read \var{port})\end{code}
%
The following compositions also hold:
\begin{code}\cddollar
run/string* $\equiv$ port->string $\circ$ run/port*
run/strings* $\equiv$ port->string-list $\circ$ run/port*
run/sexp* $\equiv$ read $\circ$ run/port*
run/sexps* $\equiv$ port->sexp-list $\circ$ run/port*\end{code}
\end{desc}
\defun{port-fold}{port reader op . seeds} {\object\star}
\begin{desc}
This procedure can be used to perform a variety of iterative operations
over an input stream.
It repeatedly uses \var{reader} to read an object from \var{port}.
If the first read returns eof, then the entire \ex{port-fold}
operation returns the seeds as multiple values.
If the first read operation returns some other value $v$, then
\var{op} is applied to $v$ and the seeds:
\ex{(\var{op} \var{v} . \var{seeds})}.
This should return a new set of seed values, and the reduction then loops,
reading a new value from the port, and so forth.
(If multiple seed values are used, then \var{op} must return multiple values.)
For example, \ex{(port->list \var{reader} \var{port})}
could be defined as
\codex{(reverse (port-fold \var{port} \var{reader} cons '()))}
An imperative way to look at \ex{port-fold} is to say that it
abstracts the idea of a loop over a stream of values read from
some port, where the seed values express the loop state.
\remark{This procedure was formerly named \texttt{\indx{reduce-port}}.
The old binding is still provided, but is deprecated and will
probably vanish in a future release.}
\end{desc}
\section{More complex process operations}
The procedures and special forms in the previous section provide for the
common case, where the programmer is only interested in the output of the
process.
These special forms and procedures provide more complicated facilities
for manipulating processes.
\subsection{Pids and ports together}
\dfn {run/port+proc} {. \var{epf}} {[port proc]} {syntax}
\defunx {run/port+proc*} {thunk} {[port proc]}
\begin{desc}
This special form and its analogous procedure can be used
if the programmer also wishes access to the process' pid, exit status,
or other information.
They both fork off a subprocess, returning two values:
a port open on the process' stdout (and current output port),
and the subprocess's process object.
A process object encapsulates the subprocess' process id and exit code;
it is the value passed to the \ex{wait} system call.
For example, to uncompress a tech report, reading the uncompressed
data into scsh, and also be able to track the exit status of
the decompression process, use the following:
\begin{code}
(receive (port child) (run/port+proc (zcat tr91-145.tex.Z))
(let* ((paper (port->string port))
(status (wait child)))
{\rm\ldots{}use \ex{paper}, \ex{status}, and \ex{child} here\ldots}))\end{code}
%
Note that you must \emph{first} do the \ex{port->string} and
\emph{then} do the wait---the other way around may lock up when the
zcat fills up its output pipe buffer.
\end{desc}
\subsection{Multiple stream capture}
Occasionally, the programmer may want to capture multiple distinct output
streams from a process. For instance, he may wish to read the stdout and
stderr streams into two distinct strings. This is accomplished with the
\ex{run/collecting} form and its analogous procedure, \ex{run/collecting*}.
%
\dfn {run/collecting} {fds . epf} {[status port\ldots]} {syntax}
\defunx {run/collecting*} {fds thunk} {[status port\ldots]}
\begin{desc}
\ex{Run/collecting} and \ex{run/collecting*} run processes that produce
multiple output streams and return ports open on these streams. To avoid
issues of deadlock, \ex{run/collecting} doesn't use pipes. Instead, it first
runs the process with output to temp files, then returns ports open on the
temp files. For example,
%
\codex{(run/collecting (1 2) (ls))}
%
runs \ex{ls} with stdout (fd 1) and stderr (fd 2) redirected to temporary
files.
When the \ex{ls} is done, \ex{run/collecting} returns three values: the
\ex{ls} process' exit status, and two ports open on the temporary files. The
files are deleted before \ex{run/collecting} returns, so when the ports are
closed, they vanish. The \ex{fds} list of file descriptors is implicitly
backquoted by the special-form version.
For example, if Kaiming has his mailbox protected, then
\begin{code}
(receive (status out err)
(run/collecting (1 2) (cat /usr/kmshea/mbox))
(list status (port->string out) (port->string err)))\end{code}
%
might produce the list
\codex{(256 "" "cat: /usr/kmshea/mbox: Permission denied")}
What is the deadlock hazard that causes \ex{run/collecting} to use temp files?
Processes with multiple output streams can lock up if they use pipes
to communicate with {\Scheme} I/O readers. For example, suppose
some {\Unix} program \ex{myprog} does the following:
\begin{enumerate}
\item First, outputs a single ``\ex{(}'' to stderr.
\item Then, outputs a megabyte of data to stdout.
\item Finally, outputs a single ``\ex{)}'' to stderr, and exits.
\end{enumerate}
Our scsh programmer decides to run \ex{myprog} with stdout and stderr redirected
\emph{via {\Unix} pipes} to the ports \ex{port1} and \ex{port2}, respectively.
He gets into trouble when he subsequently says \ex{(read port2)}.
The {\Scheme} \ex{read} routine reads the open paren, and then hangs in a
\ex{\urlh{http://www.FreeBSD.org/cgi/man.cgi?query=read&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html}{read()}} system call trying to read a matching close paren.
But before \ex{myprog} sends the close paren down the stderr
pipe, it first tries to write a megabyte of data to the stdout pipe.
However, {\Scheme} is not reading that pipe---it's stuck waiting for input on
stderr.
So the stdout pipe quickly fills up, and \ex{myprog} hangs, waiting for the
pipe to drain.
The \ex{myprog} child is stuck in a stdout/\ex{port1} write;
the {\Scheme} parent is stuck in a stderr/\ex{port2} read.
Deadlock.
Here's a concrete example that does exactly the above:
\begin{code}
(receive (status port1 port2)
(run/collecting (1 2)
(begin
;; Write an open paren to stderr.
(run (echo "(") (= 1 2))
;; Copy a lot of stuff to stdout.
(run (cat /usr/dict/words))
;; Write a close paren to stderr.
(run (echo ")") (= 1 2))))
;; OK. Here, I have a port PORT1 built over a pipe
;; connected to the BEGIN subproc's stdout, and
;; PORT2 built over a pipe connected to the BEGIN
;; subproc's stderr.
(read port2) ; Should return the empty list.
(port->string port1)) ; Should return a big string.\end{code}
%
In order to avoid this problem, \ex{run/collecting} and \ex{run/collecting*}
first run the child process to completion, buffering all the output
streams in temp files (using the \ex{temp-file-channel} procedure, see below).
When the child process exits, ports open on the buffered output are returned.
This approach has two disadvantages over using pipes:
\begin{itemize}
\item The total output from the child output is temporarily written
to the disk before returning from \ex{run/collecting}. If this output
is some large intermediate result, the disk could fill up.
\item The child producer and {\Scheme} consumer are serialised; there is
no concurrency overlap in their execution.
\end{itemize}
%
However, it remains a simple solution that avoids deadlock. More
sophisticated solutions can easily be programmed up as
needed---\ex{run/collecting*} itself is only 12 lines of simple code.
See \ex{temp-file-channel} for more information on creating temp files
as communication channels.
\end{desc}
\section{Conditional process sequencing forms}
These forms allow conditional execution of a sequence of processes.
\dfn{||} {\vari{pf}1 \ldots \vari{pf}n} {\boolean} {syntax}
\begin{desc}
Run each proc until one completes successfully (\ie, exit status zero).
Return true if some proc completes successfully; otherwise \sharpf.
\end{desc}
\dfn{\&\&} {\vari{pf}1 \ldots \vari{pf}n} {\boolean} {syntax}
\begin{desc}
Run each proc until one fails (\ie, exit status non-zero).
Return true if all procs complete successfully; otherwise \sharpf.
\end{desc}
\section{Process filters}
These procedures are useful for forking off processes to filter
text streams.
\begin{defundesc}{make-char-port-filter}{filter}{\proc}
The \var{filter} argument is a character$\rightarrow$character procedure.
Returns a procedure that when called, repeatedly reads a character
from the current input port, applies \var{filter} to the character,
and writes the result to the current output port.
The procedure returns upon reaching eof on the input port.
For example, to downcase a stream of text in a spell-checking pipeline,
instead of using the {\Unix} \ex{tr A-Z a-z} command, we can say:
\begin{code}
(run (| (delatex)
(begin ((char-filter char-downcase))) ; tr A-Z a-z
(spell)
(sort)
(uniq))
(< scsh.tex)
(> spell-errors.txt))\end{code}
\end{defundesc}
\begin{defundesc}{make-string-port-filter}{filter [buflen]}{\proc}
The \var{filter} argument is a string$\rightarrow$string procedure.
Returns a procedure that when called, repeatedly reads a string
from the current input port, applies \var{filter} to the string,
and writes the result to the current output port.
The procedure returns upon reaching eof on the input port.
The optional \var{buflen} argument controls the number of characters
each internal read operation requests; this means that \var{filter}
will never be applied to a string longer than \var{buflen} chars.
The default \var{buflen} value is 1024.
\end{defundesc}

153
doc/scsh-manual/rdelim.tex Normal file
View File

@ -0,0 +1,153 @@
%&latex -*- latex -*-
\chapter{Reading delimited strings}
\label{chapt:rdelim}
Scsh provides a set of procedures that read delimited strings from
input ports.
There are procedures to read a single line of text
(terminated by a newline character),
a single paragraph (terminated by a blank line),
and general delimited strings
(terminated by a character belonging to an arbitrary character set).
These procedures can be applied to any Scheme input port.
However, the scsh virtual machine has native-code support for performing
delimited reads on Unix ports, and these input operations should be
particularly fast---much faster than doing the equivalent character-at-a-time
operation from Scheme code.
All of the delimited input operations described below take a \ex{handle-delim}
parameter, which determines what the procedure does with the terminating
delimiter character.
There are four possible choices for a \ex{handle-delim} parameter:
\begin{inset}
\begin{tabular}{|l|l|} \hline
\ex{handle-delim} & Meaning \\ \hline\hline
\ex{'trim} & Ignore delimiter character. \\
\ex{'peek} & Leave delimiter character in input stream. \\
\ex{'concat} & Append delimiter character to returned value. \\
\ex{'split} & Return delimiter as second value. \\
\hline
\end{tabular}
\end{inset}
The first case, \ex{'trim}, is the standard default for all the routines
described in this section.
The last three cases allow the programmer to distinguish between strings
that are terminated by a delimiter character, and strings that are
terminated by an end-of-file.
\begin{defundesc} {read-line} {[port handle-newline]} {{\str} or eof-object}
Reads and returns one line of text; on eof, returns the eof object.
A line is terminated by newline or eof.
\var{handle-newline} determines what \ex{read-line} does with the
newline or EOF that terminates the line; it takes the general set
of values described for the general \ex{handle-delim} case above,
and defaults to \ex{'trim} (discard the newline).
Using this argument allows one to tell whether or not the last line of
input in a file is newline terminated.
\end{defundesc}
\defun{read-paragraph} {[port handle-delim]} {{\str} or eof}
\begin{desc}
This procedure skips blank lines,
then reads text from a port until a blank line or eof is found.
A ``blank line'' is a (possibly empty) line composed only of white space.
The \var{handle-delim} parameter determines how the terminating
blank line is handled.
It is described above, and defaults to \ex{'trim}.
The \ex{'peek} option is not available.
\end{desc}
The following procedures read in strings from ports delimited by characters
belonging to a specific set.
See section~\ref{sec:char-sets} for information on character set manipulation.
\defun{read-delimited}{char-set [port handle-delim]} {{\str} or eof}
\begin{desc}
Read until we encounter one of the chars in \var{char-set} or eof.
The \var{handle-delim} parameter determines how the terminating character
is handled. It is described above, and defaults to \ex{'trim}.
The \var{char-set} argument may be a charset, a string, or a
character; it is coerced to a charset.
\end{desc}
\dfni{read-delimited!} {char-set buf [port handle-delim start end]}
{nchars or eof or \#f}{procedure}
{read-delimited"!@\texttt{read-delimited"!}}
\begin{desc}
A side-effecting variant of \ex{read-delimited}.
The data is written into the string \var{buf} at the indices in the
half-open interval $[\var{start},\var{end})$; the default interval is the
whole string: $\var{start}=0$ and $\var{end}=\ex{(string-length
\var{buf})}$. The values of \var{start} and \var{end} must specify a
well-defined interval in \var{str}, \ie, $0 \le \var{start} \le \var{end}
\le \ex{(string-length \var{buf})}$.
It returns \var{nbytes}, the number of bytes read. If the buffer filled up
without a delimiter character being found, \ex{\#f} is returned. If
the port is at eof when the read starts, the eof object is returned.
If an integer is returned (\ie, the read is successfully terminated by
reading a delimiter character), then the \var{handle-delim} parameter
determines how the terminating character is handled.
It is described above, and defaults to \ex{'trim}.
\end{desc}
\dfni{\%read-delimited!} {char-set buf gobble? [port start end]}
{[char-or-eof-or-\#f \integer]}{procedure}
{\%read-delimited"!@\texttt{\%read-delimited"!}}
\begin{desc}
This low-level delimited reader uses an alternate interface.
It returns two values: \var{terminator} and \var{num-read}.
\begin{description}
\item [terminator]
A value describing why the read was terminated:
\begin{flushleft}
\begin{tabular}{l@{\qquad$\Rightarrow$\qquad}l}
Character or eof-object & Read terminated by this value. \\
\ex{\#f} & Filled buffer without finding a delimiter.
\end{tabular}
\end{flushleft}
\item [num-read]
Number of characters read into \var{buf}.
\end{description}
If the read is successfully terminated by reading a delimiter character,
then the \var{gobble?} parameter determines what to do with the terminating
character.
If true, the character is removed from the input stream;
if false, the character is left in the input stream where a subsequent
read operation will retrieve it.
In either case, the character is also the first value returned by
the procedure call.
\end{desc}
%Note:
%- Invariant: TERMINATOR = #f => NUM-READ = END - START.
%- Invariant: TERMINATOR = eof-object and NUM-READ = 0 => at EOF.
%- When determining the TERMINATOR return value, ties are broken
% favoring character or the eof-object over #f. That is, if the buffer
% fills up, %READ-DELIMITED! will peek at one more character from the
% input stream to determine if it terminates the input. If so, that
% is returned, not #f.
\begin{defundesc} {skip-char-set} {skip-chars [port]} {\integer}
Skip characters occurring in the set \var{skip-chars};
return the number of characters skipped.
The \var{skip-chars} argument may be a charset, a string, or a
character; it is coerced to a charset.
\end{defundesc}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "man"
%%% End:

1012
doc/scsh-manual/running.tex Normal file

File diff suppressed because it is too large Load Diff

1442
doc/scsh-manual/sre.tex Normal file

File diff suppressed because it is too large Load Diff

501
doc/scsh-manual/strings.tex Normal file
View File

@ -0,0 +1,501 @@
% -*- latex -*-
\chapter{Strings and characters}
Strings are the basic communication medium for {\Unix} processes, so a
Unix programming environment must have reasonable facilities for manipulating
them.
Scsh provides a powerful set of procedures for processing strings and
characters.
Besides the the facilities described in this chapter, scsh also provides
\begin{itemize}
\itum{Regular expressions (chapter~\ref{chapt:sre})}
A complete regular-expression system.
\itum{Field parsing, delimited record I/O and the awk loop
(chapter~\ref{chapt:fr-awk})}
These procedures let you read in chunks of text delimited by selected
characters, and
parse each record into fields based on regular expressions
(for example, splitting a string at every occurrence of colon or
white-space).
The \ex{awk} form allows you to loop over streams of these records
in a convenient way.
\itum{The SRFI-13 string libraries}
This pair of libraries contains procedures that create, fold, iterate over,
search, compare, assemble, cut, hash, case-map, and otherwise manipulate
strings.
They are provided by the \ex{string-lib} and \ex{string-lib-internals}
packages, and are also available in the default \ex{scsh} package.
More documentation on these procedures can be found at URLs
\begin{tightinset}
% The gratuitous mbox makes xdvi render the hyperlinks better.
\texonly
\mbox{\url{http://srfi.schemers.org/srfi-13/srfi-13.html}}\\
\url{http://srfi.schemers.org/srfi-13/srfi-13.txt}
\endtexonly
% Changed the \mbox into \urlh for tex2page to avoid problems runing tex2page
\htmlonly
\urlh{http://srfi.schemers.org/srfi-13/srfi-13.html}{http://srfi.schemers.org/srfi-13/srfi-13.html}\\
\urlh{http://srfi.schemers.org/srfi-13/srfi-13.txt}{http://srfi.schemers.org/srfi-13/srfi-13.txt}
\endhtmlonly
\end{tightinset}
\itum{The SRFI-14 character-set library}
This library provides a set-of-characters abstraction, which is frequently
useful when searching, parsing, filtering or otherwise operating on
strings and character data. The SRFI is provided by the \ex{char-set-lib}
package; it's bindings are also available in the default \ex{scsh} package.
More documentation on this library can be found at URLs
\begin{tightinset}
% The gratuitous mbox makes xdvi render the hyperlinks better.
\texonly
\mbox{\url{http://srfi.schemers.org/srfi-14/srfi-14.html}}\\
\url{http://srfi.schemers.org/srfi-14/srfi-14.txt}
\endtexonly
% Changed the \mbox into \urlh for tex2page to avoid problems runing tex2page
\htmlonly
\urlh{http://srfi.schemers.org/srfi-14/srfi-14.html}{http://srfi.schemers.org/srfi-14/srfi-14.html}\\
\urlh{http://srfi.schemers.org/srfi-14/srfi-14.txt}{http://srfi.schemers.org/srfi-14/srfi-14.txt}
\endhtmlonly
\end{tightinset}
\end{itemize}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Manipulating file names}
\label{sec:filenames}
These procedures do not access the file-system at all; they merely operate
on file-name strings. Much of this structure is patterned after the gnu emacs
design. Perhaps a more sophisticated system would be better, something
like the pathname abstractions of {\CommonLisp} or MIT Scheme. However,
being {\Unix}-specific, we can be a little less general.
\subsection{Terminology}
These procedures carefully adhere to the {\Posix} standard for file-name
resolution, which occasionally entails some slightly odd things.
This section will describe these rules, and give some basic terminology.
A \emph{file-name} is either the file-system root (``/''),
or a series of slash-terminated directory components, followed by
a a file component.
Root is the only file-name that may end in slash.
Some examples:
\begin{center}
\begin{tabular}{lll}
File name & Dir components & File component \\\hline
\ex{src/des/main.c} & \ex{("src" "des")} & \ex{"main.c"} \\
\ex{/src/des/main.c} & \ex{("" "src" "des")} & \ex{"main.c"} \\
\ex{main.c} & \ex{()} & \ex{"main.c"} \\
\end{tabular}
\end{center}
Note that the relative filename \ex{src/des/main.c} and the absolute filename
\ex{/src/des/main.c} are distinguished by the presence of the root component
\ex{""} in the absolute path.
Multiple embedded slashes within a path have the same meaning as
a single slash.
More than two leading slashes at the beginning of a path have the same
meaning as a single leading slash---they indicate that the file-name
is an absolute one, with the path leading from root.
However, {\Posix} permits the OS to give special meaning to
\emph{two} leading slashes.
For this reason, the routines in this section do not simplify two leading
slashes to a single slash.
A file-name in \emph{directory form} is either a file-name terminated by
a slash, \eg, ``\ex{/src/des/}'', or the empty string, ``''.
The empty string corresponds to the current working directory,
whose file-name is dot (``\ex{.}'').
Working backwards from the append-a-slash rule,
we extend the syntax of {\Posix} file-names to define the empty string
to be a file-name form of the root directory ``\ex{/}''.
(However, ``\ex{/}'' is also acceptable as a file-name form for root.)
So the empty string has two interpretations:
as a file-name form, it is the file-system root;
as a directory form, it is the current working directory.
Slash is also an ambiguous form: \ex{/} is both a directory-form and
a file-name form.
The directory form of a file-name is very rarely used.
Almost all of the procedures in scsh name directories by giving
their file-name form (without the trailing slash), not their directory form.
So, you say ``\ex{/usr/include}'', and ``\ex{.}'', not
``\ex{/usr/include/}'' and ``''.
The sole exceptions are
\ex{file-name-as-directory} and \ex{directory-as-file-name},
whose jobs are to convert back-and-forth between these forms,
and \ex{file-name-directory}, whose job it is to split out the
directory portion of a file-name.
However, most procedures that expect a directory argument will coerce
a file-name in directory form to file-name form if it does not have
a trailing slash.
Bear in mind that the ambiguous case, empty string, will be
interpreted in file-name form, \ie, as root.
\subsection{Procedures}
\defun {file-name-directory?} {fname} \boolean
\defunx {file-name-non-directory?} {fname} \boolean
\begin{desc}
These predicates return true if the string is in directory form, or
file-name form (see the above discussion of these two forms).
Note that they both return true on the ambiguous case of empty string,
which is both a directory (current working directory), and a file name
(the file-system root).
\begin{center}
\begin{tabular}{lll}
File name & \ex{\ldots-directory?} & \ex{\ldots-non-directory?} \\
\hline
\ex{"src/des"} & \ex{\sharpf} & \ex{\sharpt} \\
\ex{"src/des/"} & \ex{\sharpt} & \ex{\sharpf} \\
\ex{"/"} & \ex{\sharpt} & \ex{\sharpf} \\
\ex{"."} & \ex{\sharpf} & \ex{\sharpt} \\
\ex{""} & \ex{\sharpt} & \ex{\sharpt}
\end{tabular}
\end{center}
\end{desc}
\begin{defundesc} {file-name-as-directory} {fname} \str
Convert a file-name to directory form.
Basically, add a trailing slash if needed:
\begin{exampletable}
\ex{(file-name-as-directory "src/des")} & \ex{"src/des/"} \\
\ex{(file-name-as-directory "src/des/")} & \ex{"src/des/"} \\[2ex]
%
\header{\ex{.}, \ex{/}, and \ex{""} are special:}
\ex{(file-name-as-directory ".")} & \ex{""} \\
\ex{(file-name-as-directory "/")} & \ex{"/"} \\
\ex{(file-name-as-directory "")} & \ex{"/"}
\end{exampletable}
\end{defundesc}
\begin{defundesc} {directory-as-file-name} {fname} \str
Convert a directory to a simple file-name.
Basically, kill a trailing slash if one is present:
\begin{exampletable}
\ex{(directory-as-file-name "foo/bar/")} & \ex{"foo/bar"} \\[2ex]
%
\header{\ex{/} and \ex{""} are special:}
\ex{(directory-as-file-name "/")} & \ex{"/"} \\
\ex{(directory-as-file-name "")} & \ex{"."} (\ie, the cwd) \\
\end{exampletable}
\end{defundesc}
\begin{defundesc} {file-name-absolute?} {fname} \boolean
Does \var{fname} begin with a root or \ex{\~} component?
(Recognising \ex{\~} as a home-directory specification
is an extension of {\Posix} rules.)
%
\begin{exampletable}
\ex{(file-name-absolute? "/usr/shivers")} & {\sharpt} \\
\ex{(file-name-absolute? "src/des")} & {\sharpf} \\
\ex{(file-name-absolute? "\~/src/des")} & {\sharpt} \\[2ex]
%
\header{Non-obvious case:}
\ex{(file-name-absolute? "")} & {\sharpt} (\ie, root)
\end{exampletable}
\end{defundesc}
\begin{defundesc} {file-name-directory} {fname} {{\str} or false}
Return the directory component of \var{fname} in directory form.
If the file-name is already in directory form, return it as-is.
%
\begin{exampletable}
\ex{(file-name-directory "/usr/bdc")} & \ex{"/usr/"} \\
{\ex{(file-name-directory "/usr/bdc/")}} &
{\ex{"/usr/bdc/"}} \\
\ex{(file-name-directory "bdc/.login")} & \ex{"bdc/"} \\
\ex{(file-name-directory "main.c")} & \ex{""} \\[2ex]
%
\header{Root has no directory component:}
\ex{(file-name-directory "/")} & \ex{""} \\
\ex{(file-name-directory "")} & \ex{""}
\end{exampletable}
\end{defundesc}
\begin{defundesc} {file-name-nondirectory} {fname} \str
Return non-directory component of fname.
%
\begin{exampletable}
{\ex{(file-name-nondirectory "/usr/ian")}} &
{\ex{"ian"}} \\
\ex{(file-name-nondirectory "/usr/ian/")} & \ex{""} \\
{\ex{(file-name-nondirectory "ian/.login")}} &
{\ex{".login"}} \\
\ex{(file-name-nondirectory "main.c")} & \ex{"main.c"} \\
\ex{(file-name-nondirectory "")} & \ex{""} \\
\ex{(file-name-nondirectory "/")} & \ex{"/"}
\end{exampletable}
\end{defundesc}
\begin{defundesc} {split-file-name} {fname} {{\str} list}
Split a file-name into its components.
%
\begin{exampletable}
\splitline{\ex{(split-file-name "src/des/main.c")}}
{\ex{("src" "des" "main.c")}} \\[1.5ex]
%
\splitline{\ex{(split-file-name "/src/des/main.c")}}
{\ex{("" "src" "des" "main.c")}} \\[1.5ex]
%
\splitline{\ex{(split-file-name "main.c")}} {\ex{("main.c")}} \\[1.5ex]
%
\splitline{\ex{(split-file-name "/")}} {\ex{("")}}
\end{exampletable}
\end{defundesc}
\begin{defundesc} {path-list->file-name} {path-list [dir]} \str
Inverse of \ex{split-file-name}.
\begin{code}
(path-list->file-name '("src" "des" "main.c"))
{\evalto} "src/des/main.c"
(path-list->file-name '("" "src" "des" "main.c"))
{\evalto} "/src/des/main.c"
\cb
{\rm{}Optional \var{dir} arg anchors relative path-lists:}
(path-list->file-name '("src" "des" "main.c")
"/usr/shivers")
{\evalto} "/usr/shivers/src/des/main.c"\end{code}
%
The optional \var{dir} argument is usefully \ex{(cwd)}.
\end{defundesc}
\begin{defundesc} {file-name-extension} {fname} \str
Return the file-name's extension.
%
\begin{exampletable}
\ex{(file-name-extension "main.c")} & \ex{".c"} \\
\ex{(file-name-extension "main.c.old")} & \ex{".old"} \\
\ex{(file-name-extension "/usr/shivers")} & \ex{""}
\end{exampletable}
%
\begin{exampletable}
\header{Weird cases:}
\ex{(file-name-extension "foo.")} & \ex{"."} \\
\ex{(file-name-extension "foo..")} & \ex{"."}
\end{exampletable}
%
\begin{exampletable}
\header{Dot files are not extensions:}
\ex{(file-name-extension "/usr/shivers/.login")} & \ex{""}
\end{exampletable}
\end{defundesc}
\begin{defundesc} {file-name-sans-extension} {fname} \str
Return everything but the extension.
%
\begin{exampletable}
\ex{(file-name-sans-extension "main.c")} & \ex{"main"} \\
\ex{(file-name-sans-extension "main.c.old")} & \ex{"main.c""} \\
\splitline{\ex{(file-name-sans-extension "/usr/shivers")}}
{\ex{"/usr/shivers"}}
\end{exampletable}
%
\begin{exampletable}
\header{Weird cases:}
\ex{(file-name-sans-extension "foo.")} & \ex{"foo"} \\
\ex{(file-name-sans-extension "foo..")} & \ex{"foo."} \\[2ex]
%
\header{Dot files are not extensions:}
\splitline{\ex{(file-name-sans-extension "/usr/shivers/.login")}}
{\ex{"/usr/shivers/.login}}
\end{exampletable}
Note that appending the results of \ex{file-name-extension} and
{\ttt file\=name\=sans\=extension} in all cases produces the original file-name.
\end{defundesc}
\begin{defundesc} {parse-file-name} {fname} {[dir name extension]}
Let $f$ be \ex{(file-name-nondirectory \var{fname})}.
This function returns the three values:
\begin{itemize}
\item \ex{(file-name-directory \var{fname})}
\item \ex{(file-name-sans-extension \var{f}))}
\item \ex{(file-name-extension \var{f}\/)}
\end{itemize}
The inverse of \ex{parse-file-name}, in all cases, is \ex{string-append}.
The boundary case of \ex{/} was chosen to preserve this inverse.
\end{defundesc}
\begin{defundesc} {replace-extension} {fname ext} \str
This procedure replaces \var{fname}'s extension with \var{ext}.
It is exactly equivalent to
\codex{(string-append (file-name-sans-extension \var{fname}) \var{ext})}
\end{defundesc}
\defun{simplify-file-name}{fname}\str
\begin{desc}
Removes leading and internal occurrences of dot.
A trailing dot is left alone, as the parent could be a symlink.
Removes internal and trailing double-slashes.
A leading double-slash is left alone, in accordance with {\Posix}.
However, triple and more leading slashes are reduced to a single slash,
in accordance with {\Posix}.
Double-dots (parent directory) are left alone, in case they come after
symlinks or appear in a \ex{/../\var{machine}/\ldots} ``super-root'' form
(which {\Posix} permits).
\end{desc}
\defun{resolve-file-name}{fname [dir]}\str
\begin{desc}
\begin{itemize}
\item Do \ex{\~} expansion.
\item If \var{dir} is given,
convert a relative file-name to an absolute file-name,
relative to directory \var{dir}.
\end{itemize}
\end{desc}
\begin{defundesc} {expand-file-name} {fname [dir]} \str
Resolve and simplify the file-name.
\end{defundesc}
\begin{defundesc} {absolute-file-name} {fname [dir]} \str
Convert file-name \var{fname} into an absolute file name,
relative to directory \var{dir}, which defaults to the current
working directory. The file name is simplified before being
returned.
This procedure does not treat a leading tilde character specially.
\end{defundesc}
\begin{defundesc} {home-dir} {[user]} \str
\ex{home-dir} returns \var{user}'s home directory.
\var{User} defaults to the current user.
\begin{exampletable}
\ex{(home-dir)} & \ex{"/user1/lecturer/shivers"} \\
\ex{(home-dir "ctkwan")} & \ex{"/user0/research/ctkwan"}
\end{exampletable}
\end{defundesc}
\begin{defundesc} {home-file} {[user] fname} \str
Returns file-name \var{fname} relative to \var{user}'s home directory;
\var{user} defaults to the current user.
%
\begin{exampletable}
\ex{(home-file "man")} & \ex{"/usr/shivers/man"} \\
\ex{(home-file "fcmlau" "man")} & \ex{"/usr/fcmlau/man"}
\end{exampletable}
\end{defundesc}
The general \ex{substitute-env-vars} string procedure,
defined in the previous section,
is also frequently useful for expanding file-names.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Other string manipulation facilities}
\begin{defundesc} {substitute-env-vars} {fname} \str
Replace occurrences of environment variables with their values.
An environment variable is denoted by a dollar sign followed by
alphanumeric chars and underscores, or is surrounded by braces.
\begin{exampletable}
\splitline{\ex{(substitute-env-vars "\$USER/.login")}}
{\ex{"shivers/.login"}} \\
\cd{(substitute-env-vars "$\{USER\}_log")} & \cd{"shivers_log"}
\end{exampletable}
\end{defundesc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{ASCII encoding}
\defun {char->ascii}{\character} \integer
\defunx {ascii->char}{\integer} \character
\begin{desc}
These are identical to \ex{char->integer} and \ex{integer->char} except that
they use the {\Ascii} encoding.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Character predicates}
\defun {char-letter?}\character\boolean
\defunx{char-lower-case?}\character\boolean
\defunx{char-upper-case?}\character\boolean
\defunx{char-title-case?}\character\boolean
\defunx{char-digit?}\character\boolean
\defunx{char-letter+digit?}\character\boolean
\defunx{char-graphic?}\character\boolean
\defunx{char-printing?}\character\boolean
\defunx{char-whitespace?}\character\boolean
\defunx{char-blank?}\character\boolean
\defunx{char-iso-control?}\character\boolean
\defunx{char-punctuation?}\character\boolean
\defunx{char-hex-digit?}\character\boolean
\defunx{char-ascii?}\character\boolean
\begin{desc}
Each of these predicates tests for membership in one of the standard
character sets provided by the SRFI-14 character-set library.
Additionally, the following redundant bindings are provided for {\RnRS}
compatibility:
\begin{inset}
\begin{tabular}{ll}
{\RnRS} name & scsh definition \\ \hline
\ex{char-alphabetic?} & \ex{char-letter+digit?} \\
\ex{char-numeric?} & \ex{char-digit?} \\
\ex{char-alphanumeric?} & \ex{char-letter+digit?}
\end{tabular}
\end{inset}
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Deprecated character-set procedures}
\label{sec:char-sets}
The SRFI-13 character-set library grew out of an earlier library developed
for scsh.
However, the SRFI standardisation process introduced incompatibilities with
the original scsh bindings.
The current version of scsh provides the library
\ex{obsolete-char-set-lib}, which contains the old bindings found in
previous releases of scsh.
The following table lists the members of this library, along with
the equivalent SRFI-13 binding. This obsolete library is deprecated and
\emph{not} open by default in the standard \ex{scsh} environment;
new code should use the SRFI-13 bindings.
\begin{inset}
\begin{tabular}{ll}
Old \ex{obsolete-char-set-lib} & SRFI-13 \ex{char-set-lib} \\ \hline
\ex{char-set-members} & \ex{char-set->list} \\
\ex{chars->char-set} & \ex{list->char-set} \\
\ex{ascii-range->char-set} & \ex{ucs-range->char-set} (not exact) \\
\ex{predicate->char-set} & \ex{char-set-filter} (not exact) \\
\ex{char-set-every}? & \ex{char-set-every} \\
\ex{char-set-any}? & \ex{char-set-any} \\
\\
\ex{char-set-invert} & \ex{char-set-complement} \\
\ex{char-set-invert}! & \ex{char-set-complement!} \\
\\
\ex{char-set:alphabetic} & \ex{char-set:letter} \\
\ex{char-set:numeric} & \ex{char-set:digit} \\
\ex{char-set:alphanumeric} & \ex{char-set:letter+digit} \\
\ex{char-set:control} & \ex{char-set:iso-control}
\end{tabular}
\end{inset}
Note also that the \ex{->char-set} procedure no longer handles a predicate
argument.
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "man"
%%% End:

3357
doc/scsh-manual/syscalls.tex Normal file

File diff suppressed because it is too large Load Diff

33
doc/scsh-manual/test.tex Normal file
View File

@ -0,0 +1,33 @@
%&latex -*- latex -*-
\documentclass{report}
\usepackage{code,boxedminipage,draftfooters,palatino,ct,makeidx,
headings,mantitle,array,matter,mysize10}
\parskip = 3pt plus 3pt
\sloppy
\input{decls}
%%% End preamble
\begin{document}
\begin{tabular}{ll}
{\begin{codebox}[b]
define structure web server
open scsh
scheme
net-hax
file web\end{codebox}}
&
{\begin{codebox}[b]
(define-structure web-server
(open scheme
scsh
net-hax
\vdots)
(file web))\end{codebox}}\\
\end{tabular}
\end{document}

254
doc/scsh-manual/threads.tex Normal file
View File

@ -0,0 +1,254 @@
%latex -*- latex -*-
\chapter{Concurrent system programming}
The Scheme Shell provides the user with support for concurrent programming.
The interface consists of several parts:
\begin{itemize}
\item The thread system
\item Synchronization vehicles
\item Process state abstractions
\end{itemize}
Whereas the user deals with threads and synchronization explicitly,
the process state abstractions are built into the rest of the system,
almost transparent for the user. Section \ref{sec:ps_interac}
describes the interaction between process state and threads.
\section{Threads}
A thread can be thought of as a procedure that can run independently of
and concurrent to the rest of the system. The calling procedure fires
the thread up and forgets about it.
The current thread interface is completely taken from Scheme\ 48. This
documentation is an extension of the file \texttt{doc/threads.txt}.
The thread structure is named \texttt{threads}, it has to be opened explicitly.
\defun {spawn} {thunk [name]} \undefined
Create and schedule a new thread that will execute \var{thunk}, a
procedure with no arguments. Note that Scsh's \ex{spawn} does
\textbf{not} return a reference to a thread object. The optional
argument \var{name} is used when printing the thread.
The new thread will not inherit the values for the process state from
its parent, see the procedure \texttt{fork-thread} in Section
\ref{sec:ps_interac} for a way to create a thread with
semantics similar to process forking.
\defun {relinquish-timeslice} {} \undefined
Let other threads run for a while.
\defun {sleep} {time} \undefined
Puts the current thread into sleep for \var{time} milliseconds. The
time at which the thread is run again may be longer of course.
\defun {terminate-current-thread} {} {does-not-return}
Kill the current thread.
Mainly for debugging purposes, there is also an interface to the
internal representation of thread objects:
\defun {current-thread} {} {thread-object}
Return the object to which the current thread internally corresponds.
Note that this procedure is exported by the package
\texttt{threads-internal} only.
\defun {thread?} {thing} {\boolean}
Returns true iff \var{thing} is a thread object.
\defun {thread-name} {thread} {name}
\var{Name} corresponds to the second parameter that was given to
\ex{spawn} when \var{thread} was created.
\defun{thread-uid} {thread} {\integer}
Returns a unique identifier for the current thread.
\section{Locks}
Locks are a simple mean for mutual exclusion. They implement a concept
commonly known as \textit{semaphores}. Threads can obtain and release
locks. If a thread tries to obtain a lock which is held by another
thread, the first thread is blocked. To access the following
procedures, you must open the structure \texttt{locks}.
\defun{make-lock} {} {lock}
Creates a lock.
\defun{lock?} {thing} {\boolean}
Returns true iff \var{thing} is a lock.
\defun{obtain-lock} {lock} {\undefined}
Obtain \var{lock}. Causes the thread to block if the lock is held by
a thread.
\defun{maybe-obtain-lock} {lock} {\boolean}
Tries to obtain \var{lock}, but returns false if the lock cannot be
obtained.
\defun{release-lock} {lock} {\boolean}
Releases \var{lock}. Returns true if the lock immediately got a new
owner, false otherwise.
\defun{lock-owner-uid} {lock} {\integer}
Returns the uid of the thread that currently holds \var{lock} or false
if the lock is free.
\section{Placeholders}
Placeholers combine synchronization with value delivery. They can be
thought of as special variables. After creation the value of the
placeholder is undefined. If a thread tries to read the placeholders
value this thread is blocked. Multiple threads are allowed to block on
a single placeholder. They will continue running after another thread
sets the value of the placeholder. Now all reading threads receive the
value and continue executing. Setting a placeholder to two different
values causes an error. The structure \texttt{placeholders} features
the following procedures:
\defun {make-placeholder} {} {placeholder}
Creates a new placeholder.
\defun {placeholder?} {thing} {\boolean}
Returns true iff \var{thing} is a placeholder.
\defun {placeholder-set!} {placeholder value} {\undefined}
Sets the placeholders value to \var{value}. If the placeholder is
already set to a \textit{different} value an exception is risen.
\defun {placeholder-value} {placeholder} {value}
Returns the value of the placeholder. If the placeholder is yet unset,
the current thread is blocked until another thread sets the value by
means of \ex{placeholder-set!}.
\section{The event interface to interrupts}
\label{sec:event-interf-interr}
Scsh provides an synchronous interface to the asynchronous signals
delivered by the operation system\footnote{Olin's paper ``Automatic
management of operation-system resources'' describes this system in
detail.}. The key element in this system is an object called
\textit{sigevent} which corresponds to the single occurrence of a
signal. A sigevent has two fields: the Unix signal that occurred and a
pointer to the sigevent that happened or will happen. That is, events
are kept in a linked list in increasing-time order. Scsh's structure
\texttt{sigevents} provides various procedures to access this list:
\defun {most-recent-sigevent} {} {sigevent}
Returns the most recent sigevent --- the head of the sigevent
list.
\defun {sigevent?} {object} {\boolean}
The predicate for sigevents.
\defun {next-sigevent} {pre-event type} {event}
Returns the next sigevent of type \texttt{type} after sigevent
\texttt{pre-event}. If no such event exists, the procedure blocks.
\defun {next-sigevent-set} {pre-event set} {event}
Returns the next sigevent whose type is in \texttt{set} after
\texttt{pre-event}. If no such event exists, the procdure blocks.
\defun {next-sigevent/no-wait} {pre-event type} {event or \sharpf}
Same as \texttt{next-sigevent}, but returns \sharpf if no appropriate
event exists.
\defun {next-sigevent-set/no-wait} {set pre-event} {event or \sharpf}
Same as \texttt{next-sigevent-set}, but returns \sharpf if no appropriate
event exists.
As a small example, consider this piece of code that toggles the
variable \texttt{state} by USR1 and USR2:
\begin{code}
(define state #t)
(let lp ((sigevent (most-recent-sigevent)))
(let ((next (next-sigevent sigevent interrupt/usr1)))
(set! state #f)
(let ((next (next-sigevent next interrupt/usr2)))
(set! state #t)
(lp next))))
\end{code}
\textbf{Warning:} The current version of scsh also defines
asynchronous handlers for interrupts (See Section
\ref{sec:int_handlers}). The default action of some of these handlers
is to terminate the process in which case you will most likely not see
an effect of the synchronous event interface described here. It is
therefore recommended to disable the corresponding interrupt handler
using \texttt{(set-interrupt-handler interrupt \#f)}.
\section{Interaction between threads and process state}
\label{sec:ps_interac}
In Unix, a number of resources are global to the process: signal
handlers, working directory, umask, environment, user and group ids.
Modular programming is difficult in the context of this global state
and for concurrent programming things get even worse. Section
\ref{sec:event-interf-interr} presents how scsh turns
the global, asynchronous signals handlers into modular, synchronous
sigevents. Concurrent programming also benefit from sigevents as every
thread may chase down the sigevent chain separately.
Scsh treats the working directory, umask, environment, and the
effective user/group ID as thread-local resources. The initial value
of the resources is determined by the way a thread is started:
\texttt{spawn} assigns the initial values whereas \texttt{fork-thread}
adopts the values of its parent. Here is a detailed description of the
whole facility:
\begin{itemize}
\item The procedures to access and modify the resources remain as
described in the previous chapters (\texttt{cwd} and \texttt{chdir},
\texttt{umask} and \texttt{set-umask}, \texttt{getenv} and
\texttt{putenv}).
\item Every thread receives its own copy of each resource.
\item If \texttt{spawn} is used to start a new thread, the values of
the resources are the same as they where at the start of scsh.
\item The procedure
\defun {fork-thread} {thunk} \undefined
from the structure \texttt{thread-fluids} starts a thread which
inherits the values of all resources from its parent. This behaviour
is similar to what happens at process forking.
\item The actual process state is updated only when necessary, i.e. on
access or modification but not on context switch from one thread
to another.
\end{itemize}
\defun{spoon} {thunk} \undefined
This is just an alias for \ex{fork-thread} suggested by Alan Bawden.
For user and group identities arbitrary changing is not possible.
Therefore they remain global process state: If a thread changes one of
these values, all other threads see the new value. Consequently, scsh
does not provide \texttt{with-uid} and friends.
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "man"
%%% End:

747
doc/scsh-manual/tty.tex Normal file
View File

@ -0,0 +1,747 @@
%&latex -*- latex -*-
% Fix OXTABS footnote bug
% Figures should be dumped out earlier? Pack two to a page?
\section{Terminal device control}
\label{sect:tty}
\newcommand{\fr}[1]{\makebox[0pt][r]{#1}}
Scsh provides a complete set of routines for manipulating terminal
devices---putting them in ``raw'' mode, changing and querying their
special characters, modifying their I/O speeds, and so forth.
The scsh interface is designed both for generality and portability
across different Unix platforms, so you don't have to rewrite your
program each time you move to a new system.
We've also made an effort to use reasonable, Scheme-like names for
the multitudinous named constants involved, so when you are reading
code, you'll have less likelihood of getting lost in a bewildering
maze of obfuscatory constants named \ex{ICRNL}, \ex{INPCK}, \ex{IUCLC},
and \ex{ONOCR}.
This section can only lay out the basic functionality of the terminal
device interface.
For further details, see the termios(3) man page on your system,
or consult one of the standard {\Unix} texts.
\subsection{Portability across OS variants}
Terminal-control software is inescapably complex, ugly, and low-level.
Unix variants each provide their own way of controlling terminal
devices, making it difficult to provide interfaces that are
portable across different Unix systems.
Scsh's terminal support is based primarily upon the {\Posix} termios
interface.
Programs that can be written using only the {\Posix} interface are likely
to be widely portable.
The bulk of the documentation that follows consists of several pages worth
of tables defining different named constants that enable and disable different
features of the terminal driver.
Some of these flags are {\Posix}; others are taken from the two common
branches of Unix development, SVR4 and 4.3+ Berkeley.
Scsh guarantees that the non-{\Posix} constants will be bound identifiers.
\begin{itemize}
\item If your OS supports a particular non-{\Posix} flag,
its named constant will be bound to the flag's value.
\item If your OS doesn't support the flag, its named constant
will be present, but bound to \sharpf.
\end{itemize}
This means that if you want to use SVR4 or Berkeley features in a program,
your program can portably test the values of the flags before using
them---the flags can reliably be referenced without producing OS-dependent
``unbound variable'' errors.
Finally, note that although {\Posix}, SVR4, and Berkeley cover the lion's
share of the terminal-driver functionality,
each operating system inevitably has non-standard extensions.
While a particular scsh implementation may provide these extensions,
they are not portable, and so are not documented here.
\subsection{Miscellaneous procedures}
\defun{tty?}{fd/port}{\boolean}
\begin{desc}
Return true if the argument is a tty.
\end{desc}
\defun{tty-file-name}{fd/port}{\str}
\begin{desc}
The argument \var{fd/port} must be a file descriptor or port open on a tty.
Return the file-name of the tty.
\end{desc}
\subsection{The tty-info record type}
The primary data-structure that describes a terminal's mode is
a \ex{tty-info} record, defined as follows:
\index{tty-info record type}
\indextt{tty-info:control-chars}
\indextt{tty-info:input-flags}
\indextt{tty-info:output-flags}
\indextt{tty-info:control-flags}
\indextt{tty-info:local-flags}
\indextt{tty-info:input-speed}
\indextt{tty-info:output-speed}
\indextt{tty-info:min}
\indextt{tty-info:time}
\indextt{tty-info?}
\begin{code}
(define-record tty-info
control-chars ; String: Magic input chars
input-flags ; Int: Input processing
output-flags ; Int: Output processing
control-flags ; Int: Serial-line control
local-flags ; Int: Line-editting UI
input-speed ; Int: Code for input speed
output-speed ; Int: Code for output speed
min ; Int: Raw-mode input policy
time) ; Int: Raw-mode input policy\end{code}
\subsubsection{The control-characters string}
The \ex{control-chars} field is a character string;
its characters may be indexed by integer values taken from
table~\ref{table:ttychars}.
As discussed above,
only the {\Posix} entries in table~\ref{table:ttychars} are guaranteed
to be legal, integer indices.
A program can reliably test the OS to see if the non-{\Posix}
characters are supported by checking the index constants.
If the control-character function is supported by the terminal driver,
then the corresponding index will be bound to an integer;
if it is not supported, the index will be bound to \sharpf.
To disable a given control-character function, set its corresponding
entry in the \ex{tty-info:control-chars} string to the
special character \exi{disable-tty-char}
(and then use the \ex{(set-tty-info \var{fd/port} \var{info})} procedure
to update the terminal's state).
\subsubsection{The flag fields}
The \ex{tty-info} record's \ex{input-flags}, \ex{output-flags},
\ex{control-flags}, and \ex{local-flags} fields are all bit sets
represented as two's-complement integers.
Their values are composed by or'ing together values taken from
the named constants listed in tables~\ref{table:ttyin}
through \ref{table:ttylocal}.
As discussed above,
only the {\Posix} entries listed in these tables are guaranteed
to be legal, integer flag values.
A program can reliably test the OS to see if the non-{\Posix}
flags are supported by checking the named constants.
If the feature is supported by the terminal driver,
then the corresponding flag will be bound to an integer;
if it is not supported, the flag will be bound to \sharpf.
%%%%% I managed to squeeze this into the DEFINE-RECORD's comments.
% Here is a small table classifying the four flag fields by
% the kind of features they determine:
% \begin{center}
% \begin{tabular}{|ll|}\hline
% Field & Affects \\ \hline \hline
% \ex{input-flags} & Processing of input chars \\
% \ex{output-flags} & Processing of output chars \\
% \ex{control-flags} & Controlling of terminal's serial line \\
% \ex{local-flags} & Details of the line-editting user interface \\
% \hline
% \end{tabular}
% \end{center}
%%%
%%% The figures used to go here.
%%%
\subsubsection{The speed fields}
The \ex{input-speed} and \ex{output-speed} fields determine the
I/O rate of the terminal's line.
The value of these fields is an integer giving the speed
in bits-per-second.
The following speeds are supported by {\Posix}:
\begin{center}
\begin{tabular}{rrrr}
0 & 134 & 600 & 4800 \\
50 & 150 & 1200 & 9600 \\
75 & 200 & 1800 & 19200 \\
110 & 300 & 2400 & 38400 \\
\end{tabular}
\end{center}
Your OS may accept others; it may also allow the special symbols
\ex{'exta} and \ex{'extb}.
\subsubsection{The min and time fields}
The integer \ex{min} and \ex{time} fields determine input blocking
behaviour during non-canonical (raw) input; otherwise, they are ignored.
See the termios(3) man page for further details.
Be warned that {\Posix} allows the base system call's representation
of the \ex{tty-info} record to share storage for the \ex{min} field
and the \ex{ttychar/eof} element of the control-characters string,
and for the \ex{time} field and the \ex{ttychar/eol} element
of the control-characters string.
Many implementations in fact do this.
To stay out of trouble, set the \ex{min} and \ex{time} fields only
if you are putting the terminal into raw mode;
set the eof and eol control-characters only if you are putting
the terminal into canonical mode.
It's ugly, but it's {\Unix}.
\subsection{Using tty-info records}
\defun{make-tty-info}{if of cf lf ispeed ospeed min time}
{tty-info-record}
\defunx{copy-tty-info}{tty-info-record}{tty-info-record}
\begin{desc}
These procedures make it possible to create new \ex{tty-info} records.
The typical method for creating a new record is to copy one retrieved
by a call to the \ex{tty-info} procedure, then modify the copy as desired.
Note that the \ex{make-tty-info} procedure does not take a parameter
to define the new record's control characters.\footnote{
Why? Because the length of the string varies from Unix to Unix.
For example, the word-erase control character (typically control-w)
is provided by most Unixes, but not part of the {\Posix} spec.}
Instead, it simply returns a \ex{tty-info} record whose control-character
string has all elements initialised to {\Ascii} nul.
You may then install the special characters by assigning to the string.
Similarly, the control-character string in the record produced by
\ex{copy-tty-info} does not share structure with the string in the record
being copied, so you may mutate it freely.
\end{desc}
\defun{tty-info}{[fd/port/fname]}{tty-info-record}
\begin{desc}
The \var{fd/port/fname} parameter is an integer file descriptor or
Scheme I/O port opened on a terminal device,
or a file-name for a terminal device; it defaults to the current input port.
This procedure returns a \ex{tty-info} record describing the terminal's
current mode.
\end{desc}
\defun {set-tty-info/now} {fd/port/fname info}{no-value}
\defunx{set-tty-info/drain}{fd/port/fname info}{no-value}
\defunx{set-tty-info/flush}{fd/port/fname info}{no-value}
\begin{desc}
The \var{fd/port/fname} parameter is an integer file descriptor or
Scheme I/O port opened on a terminal device,
or a file-name for a terminal device.
The procedure chosen determines when and how the terminal's mode is altered:
\begin{center}
\begin{tabular}{|ll|} \hline
Procedure & Meaning \\ \hline \hline
\ex{set-tty-info/now} & Make change immediately. \\
\ex{set-tty-info/drain} & Drain output, then change. \\
\ex{set-tty-info/flush} & Drain output, flush input, then change. \\ \hline
\end{tabular}
\end{center}
\oops{If I had defined these with the parameters in the reverse order,
I could have made \var{fd/port/fname} optional. Too late now.}
\end{desc}
\subsection{Other terminal-device procedures}
\defun{send-tty-break}{[fd/port/fname duration]}{no-value}
\begin{desc}
The \var{fd/port/fname} parameter is an integer file descriptor or
Scheme I/O port opened on a terminal device,
or a file-name for a terminal device; it defaults to the current output port.
Send a break signal to the designated terminal.
A break signal is a sequence of continuous zeros on the terminal's transmission
line.
The \var{duration} argument determines the length of the break signal.
A zero value (the default) causes a break of between
0.25 and 0.5 seconds to be sent;
other values determine a period in a manner that will depend upon local
community standards.
\end{desc}
\defun{drain-tty}{[fd/port/fname]}{no-value}
\begin{desc}
The \var{fd/port/fname} parameter is an integer file descriptor or
Scheme I/O port opened on a terminal device,
or a file-name for a terminal device; it defaults to the current output port.
This procedure waits until all the output written to the
terminal device has been transmitted to the device.
If \var{fd/port/fname} is an output port with buffered I/O
enabled, then the port's buffered characters are flushed before
waiting for the device to drain.
\end{desc}
\defun {flush-tty/input} {[fd/port/fname]}{no-value}
\defunx{flush-tty/output}{[fd/port/fname]}{no-value}
\defunx{flush-tty/both} {[fd/port/fname]}{no-value}
\begin{desc}
The \var{fd/port/fname} parameter is an integer file descriptor or
Scheme I/O port opened on a terminal device,
or a file-name for a terminal device; it defaults to the current input
port (\ex{flush-tty/input} and \ex{flush-tty/both}),
or output port (\ex{flush-tty/output}).
These procedures discard the unread input chars or unwritten
output chars in the tty's kernel buffers.
\end{desc}
\defun {start-tty-output}{[fd/port/fname]} {no-value}
\defunx{stop-tty-output} {[fd/port/fname]} {no-value}
\defunx{start-tty-input} {[fd/port/fname]} {no-value}
\defunx{stop-tty-input} {[fd/port/fname]} {no-value}
\begin{desc}
These procedures can be used to control a terminal's input and output flow.
The \var{fd/port/fname} parameter is an integer file descriptor or
Scheme I/O port opened on a terminal device,
or a file-name for a terminal device; it defaults to the current input
or output port.
The \ex{stop-tty-output} and \ex{start-tty-output} procedures suspend
and resume output from a terminal device.
The \ex{stop-tty-input} and \ex{start-tty-input} procedures transmit
the special STOP and START characters to the terminal with the intention
of stopping and starting terminal input flow.
\end{desc}
% --- Obsolete ---
% \defun {encode-baud-rate}{speed}{code}
% \defunx{decode-baud-rate}{code}{speed}
% \begin{desc}
% These procedures can be used to map between the special codes
% that are legal values for the \ex{tty-info:input-speed} and
% \ex{tty-info:output-speed} fields, and actual integer bits-per-second speeds.
% The codes are the values bound to the
% \ex{baud/4800}, \ex{baud/9600}, and other named constants defined above.
% For example:
% \begin{code}
% (decode-baud-rate baud/9600) {\evalto} 9600
%
% ;;; These two expressions are identical:
% (set-tty-info:input-speed ti baud/14400)
% (set-tty-info:input-speed ti (encode-baud-rate 14400))\end{code}
% \end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Control terminals, sessions, and terminal process groups}
\defun{open-control-tty}{tty-name [flags]}{port}
\begin{desc}
This procedure opens terminal device \var{tty-name} as the process'
control terminal
(see the \ex{termios} man page for more information on control terminals).
The \var{tty-name} argument is a file-name such as \ex{/dev/ttya}.
The \var{flags} argument is a value suitable as the second argument
to the \ex{open-file} call; it defaults to \ex{open/read+write}, causing
the terminal to be opened for both input and output.
The port returned is an input port if the \var{flags} permit it,
otherwise an output port.
\RnRS/\scm/scsh do not have input/output ports,
so it's one or the other.
However, you can get both read and write ports open on a terminal
by opening it read/write, taking the result input port,
and duping it to an output port with \ex{dup->outport}.
This procedure guarantees to make the opened terminal the
process' control terminal only if the process does not have
an assigned control terminal at the time of the call.
If the scsh process already has a control terminal, the results are undefined.
To arrange for the process to have no control terminal prior to calling
this procedure, use the \ex{become-session-leader} procedure.
%\oops{The control terminal code was added just before release time
% for scsh release 0.4. Control terminals are one of the less-standardised
% elements of Unix. We can't guarantee that the terminal is definitely
% attached as a control terminal; we were only able to test this out
% on HP-UX. If you intend to use this feature on your OS, you should
% test it out first. If your OS requires the use of the \ex{TIOCSCTTY}
% \ex{ioctl}, uncomment the appropriate few lines of code in the
% file \ex{tty1.c} and send us email.}
\end{desc}
\defun{become-session-leader}{}{\integer}
\begin{desc}
This is the C \ex{setsid()} call.
{\Posix} job-control has a three-level hierarchy:
session/process-group/process.
Every session has an associated control terminal.
This procedure places the current process into a brand new session,
and disassociates the process from any previous control terminal.
You may subsequently use \ex{open-control-tty} to open a new control
terminal.
It is an error to call this procedure if the current process is already
a process-group leader.
One way to guarantee this is not the case is only to call this procedure
after forking.
\end{desc}
\defun {tty-process-group}{fd/port/fname}{\integer}
\defunx{set-tty-process-group}{fd/port/fname pgrp}{\undefined}
\begin{desc}
This pair of procedures gets and sets the process group of a given
terminal.
\end{desc}
\defun{control-tty-file-name}{}{\str}
\begin{desc}
Return the file-name of the process' control tty.
On every version of Unix of which we are aware, this is just the string
\ex{"/dev/tty"}.
However, this procedure uses the official Posix interface, so it is more
portable than simply using a constant string.
\end{desc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Pseudo-terminals}
Scsh implements an interface to Berkeley-style pseudo-terminals.
\defun{fork-pty-session}{thunk}{[process pty-in pty-out tty-name]}
\begin{desc}
This procedure gives a convenient high-level interface to pseudo-terminals.
It first allocates a pty/tty pair of devices, and then forks a child
to execute procedure \var{thunk}.
In the child process
\begin{itemize}
\item Stdio and the current I/O ports are bound to the terminal device.
\item The child is placed in its own, new session
(see \ex{become\=session\=leader}).
\item The terminal device becomes the new session's controlling terminal
(see \ex{open-control-tty}).
\item The \ex{(error-output-port)} is unbuffered.
\end{itemize}
The \ex{fork-pty-session} procedure returns four values:
the child's process object, two ports open on the controlling pty device,
and the name of the child's corresponding terminal device.
\end{desc}
\defun{open-pty}{}{pty-inport tty-name}
\begin{desc}
This procedure finds a free pty/tty pair, and opens the pty device
with read/write access.
It returns a port on the pty,
and the name of the corresponding terminal device.
The port returned is an input port---Scheme doesn't allow input/output
ports.
However, you can easily use \ex{(dup->outport \var{pty-inport})}
to produce a matching output port.
You may wish to turn off I/O buffering for this output port.
\end{desc}
\defun {pty-name->tty-name}{pty-name}{tty-name}
\defunx{tty-name->pty-name}{tty-name}{pty-name}
\begin{desc}
These two procedures map between corresponding terminal and pty controller
names.
For example,
\begin{code}
(pty-name->tty-name "/dev/ptyq3") {\evalto} "/dev/ttyq3"
(tty-name->pty-name "/dev/ttyrc") {\evalto} "/dev/ptyrc"\end{code}
\remark{This is rather Berkeley-specific. SVR4 ptys are rare enough that
I've no real idea if it generalises across the Unix gap. Experts
are invited to advise. Users feel free to not worry---the predominance
of current popular Unix systems use Berkeley ptys.}
\end{desc}
\defunx{make-pty-generator}{}{\proc}
\begin{desc}
This procedure returns a generator of candidate pty names.
Each time the returned procedure is called, it produces a
new candidate.
Software that wishes to search through the set of available ptys
can use a pty generator to iterate over them.
After producing all the possible ptys, a generator returns {\sharpf}
every time it is called.
Example:
\begin{code}
(define pg (make-pty-generator))
(pg) {\evalto} "/dev/ptyp0"
(pg) {\evalto} "/dev/ptyp1"
\vdots
(pg) {\evalto} "/dev/ptyqe"
(pg) {\evalto} "/dev/ptyqf" \textit{(Last one)}
(pg) {\evalto} {\sharpf}
(pg) {\evalto} {\sharpf}
\vdots\end{code}
\end{desc}
% Flag tables
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Control-chars indices
%%%%%%%%%%%%%%%%%%%%%%%
\begin{table}[p]
\begin{center}
\begin{tabular}{|lll|} \hline
Scsh & C & Typical char \\
\hline\hline
{\Posix} & & \\
\exi{ttychar/delete-char} & \ex{ERASE} & del \\
\exi{ttychar/delete-line} & \ex{KILL} & \verb|^U| \\
\exi{ttychar/eof} & \ex{EOF} & \verb|^D| \\
\exi{ttychar/eol} & \ex{EOL} & \\
\exi{ttychar/interrupt} & \ex{INTR} & \verb|^C| \\
\exi{ttychar/quit} & \ex{QUIT} & \verb|^\| \\
\exi{ttychar/suspend} & \ex{SUSP} & \verb|^Z| \\
\exi{ttychar/start} & \ex{START} & \verb|^Q| \\
\exi{ttychar/stop} & \ex{STOP} & \verb|^S| \\
\hline\hline
{SVR4 and 4.3+BSD} & & \\
\exi{ttychar/delayed-suspend} & \ex{DSUSP} & \verb|^Y| \\
\exi{ttychar/delete-word} & \ex{WERASE} & \verb|^W| \\
\exi{ttychar/discard} & \ex{DISCARD} & \verb|^O| \\
\exi{ttychar/eol2} & \ex{EOL2} & \\
\exi{ttychar/literal-next} & \ex{LNEXT} & \verb|^V| \\
\exi{ttychar/reprint} & \ex{REPRINT} & \verb|^R| \\
\hline\hline
{4.3+BSD} & & \\
\exi{ttychar/status} & \ex{STATUS} & \verb|^T| \\
\hline
\end{tabular}
\end{center}
\caption{Indices into the \protect\ex{tty-info} record's
\protect\var{control-chars} string,
and the character traditionally found at each index.
Only the indices for the {\Posix} entries are guaranteed to
be non-\sharpf.}
\label{table:ttychars}
\end{table}
% Input flags
%%%%%%%%%%%%%
\begin{table}[p]
\begin{center}\small
\begin{tabular}{|lll|} \hline
Scsh & C & Meaning \\
\hline\hline
\Posix & & \\
\exi{ttyin/check-parity}
& \ex{INPCK} & Check parity. \\
\exi{ttyin/ignore-bad-parity-chars}
& \ex{IGNPAR} & Ignore chars with parity errors. \\
\exi{ttyin/mark-parity-errors}
& \ex{PARMRK} & Insert chars to mark parity errors.\\
\exi{ttyin/ignore-break}
& \ex{IGNBRK} & Ignore breaks. \\
\exi{ttyin/interrupt-on-break}
& \ex{BRKINT} & Signal on breaks. \\
\exi{ttyin/7bits}
& \ex{ISTRIP} & Strip char to seven bits. \\
\exi{ttyin/cr->nl}
& \ex{ICRNL} & Map carriage-return to newline. \\
\exi{ttyin/ignore-cr}
& \ex{IGNCR} & Ignore carriage-returns. \\
\exi{ttyin/nl->cr}
& \ex{INLCR} & Map newline to carriage-return. \\
\exi{ttyin/input-flow-ctl}
& \ex{IXOFF} & Enable input flow control. \\
\exi{ttyin/output-flow-ctl}
& \ex{IXON} & Enable output flow control. \\
\hline\hline
{SVR4 and 4.3+BSD} & & \\
\exi{ttyin/xon-any} & \ex{IXANY} & Any char restarts after stop. \\
\exi{ttyin/beep-on-overflow} & \ex{IMAXBEL} & Ring bell when queue full. \\
\hline\hline
{SVR4} & & \\
\exi{ttyin/lowercase} & \ex{IUCLC} & Map upper case to lower case. \\
\hline
\end{tabular}
\end{center}
\caption{Input-flags. These are the named flags for the \protect\ex{tty-info}
record's \protect\var{input-flags} field.
These flags generally control the processing of input chars.
Only the {\Posix} entries are guaranteed to be non-\sharpf.
}
\label{table:ttyin}
\end{table}
% Output flags
%%%%%%%%%%%%%%
\begin{table}[p]
\begin{center}%\small
\begin{tabular}{|lll|} \hline
Scsh & C & Meaning \\ \hline\hline
\multicolumn{3}{|l|}{\Posix} \\
\exi{ttyout/enable} & \ex{OPOST} & Enable output processing. \\
\hline\hline
\multicolumn{3}{|l|}{SVR4 and 4.3+BSD} \\
\exi{ttyout/nl->crnl} & \ex{ONLCR} & Map nl to cr-nl. \\
\hline\hline
\multicolumn{3}{|l|}{4.3+BSD} \\
\exi{ttyout/discard-eot} & \ex{ONOEOT} & Discard EOT chars. \\
\exi{ttyout/expand-tabs} & \ex{OXTABS}\footnote{
Note this is distinct from the SVR4-equivalent
\ex{ttyout/tab-delayx} flag defined in
table~\ref{table:ttydelays}.}
& Expand tabs. \\
\hline\hline
\multicolumn{3}{|l|}{SVR4} \\
\exi{ttyout/cr->nl} & \ex{OCRNL} & Map cr to nl. \\
\exi{ttyout/nl-does-cr} & \ex{ONLRET}& Nl performs cr as well. \\
\exi{ttyout/no-col0-cr} & \ex{ONOCR} & No cr output in column 0. \\
\exi{ttyout/delay-w/fill-char} & \ex{OFILL} & Send fill char to delay. \\
\exi{ttyout/fill-w/del} & \ex{OFDEL} & Fill char is {\Ascii} DEL. \\
\exi{ttyout/uppercase} & \ex{OLCUC} & Map lower to upper case. \\
\hline
\end{tabular}
\end{center}
\caption{Output-flags. These are the named flags for the \protect\ex{tty-info}
record's \protect\var{output-flags} field.
These flags generally control the processing of output chars.
Only the {\Posix} entries are guaranteed to be non-\sharpf.}
\label{table:ttyout}
\end{table}
% Delay flags
%%%%%%%%%%%%%
\begin{table}[p]
\begin{tabular}{r|ll|} \cline{2-3}
& Value & Comment \\ \cline{2-3}
{Backspace delay} & \exi{ttyout/bs-delay} & Bit-field mask \\
& \exi{ttyout/bs-delay0} & \\
& \exi{ttyout/bs-delay1} & \\
\cline{2-3}
{Carriage-return delay} & \exi{ttyout/cr-delay} & Bit-field mask \\
& \exi{ttyout/cr-delay0} & \\
& \exi{ttyout/cr-delay1} & \\
& \exi{ttyout/cr-delay2} & \\
& \exi{ttyout/cr-delay3} & \\
\cline{2-3}
{Form-feed delay} & \exi{ttyout/ff-delay} & Bit-field mask \\
& \exi{ttyout/ff-delay0} & \\
& \exi{ttyout/ff-delay1} & \\
\cline{2-3}
{Horizontal-tab delay} & \exi{ttyout/tab-delay} & Bit-field mask \\
& \exi{ttyout/tab-delay0} & \\
& \exi{ttyout/tab-delay1} & \\
& \exi{ttyout/tab-delay2} & \\
& \exi{ttyout/tab-delayx} & Expand tabs \\
\cline{2-3}
{Newline delay} & \exi{ttyout/nl-delay} & Bit-field mask \\
& \exi{ttyout/nl-delay0} & \\
& \exi{ttyout/nl-delay1} & \\
\cline{2-3}
{Vertical tab delay} & \exi{ttyout/vtab-delay} & Bit-field mask \\
& \exi{ttyout/vtab-delay0} & \\
& \exi{ttyout/vtab-delay1} & \\
\cline{2-3}
{All} & \exi{ttyout/all-delay} & Total bit-field mask \\
\cline{2-3}
\end{tabular}
\caption{Delay constants. These are the named flags for the
\protect\ex{tty-info} record's \protect\var{output-flags} field.
These flags control the output delays associated with printing
special characters.
They are non-{\Posix}, and have non-{\sharpf} values
only on SVR4 systems.}
\label{table:ttydelays}
\end{table}
% Control flags
%%%%%%%%%%%%%%%
\begin{table}[p]
\begin{center}%\small
\begin{tabular}{|lll|} \hline
Scsh & C & Meaning \\
\hline\hline
\multicolumn{3}{|l|}{\Posix} \\
\exi{ttyc/char-size} & \ex{CSIZE} & Character size mask \\
\exi{ttyc/char-size5} & \ex{CS5} & 5 bits \\
\exi{ttyc/char-size6} & \ex{CS6} & 6 bits \\
\exi{ttyc/char-size7} & \ex{CS7} & 7 bits \\
\exi{ttyc/char-size8} & \ex{CS8} & 8 bits \\
\exi{ttyc/enable-parity}& \ex{PARENB} & Generate and detect parity. \\
\exi{ttyc/odd-parity} & \ex{PARODD} & Odd parity. \\
\exi{ttyc/enable-read} & \ex{CREAD} & Enable reception of chars. \\
\exi{ttyc/hup-on-close} & \ex{HUPCL} & Hang up on last close. \\
\exi{ttyc/no-modem-sync}& \ex{LOCAL} & Ignore modem lines. \\
\exi{ttyc/2-stop-bits} & \ex{CSTOPB} & Send two stop bits. \\
\hline\hline
\multicolumn{3}{|l|}{4.3+BSD} \\
\exi{ttyc/ignore-flags} & \ex{CIGNORE} & Ignore control flags. \\
\exi{ttyc/CTS-output-flow-ctl} & \verb|CCTS_OFLOW| & CTS flow control of output \\
\exi{ttyc/RTS-input-flow-ctl} & \verb|CRTS_IFLOW| & RTS flow control of input \\
\exi{ttyc/carrier-flow-ctl} & \ex{MDMBUF} & \\
\hline
\end{tabular}
\end{center}
\caption{Control-flags. These are the named flags for the \protect\ex{tty-info}
record's \protect\var{control-flags} field.
These flags generally control the details of the terminal's
serial line.
Only the {\Posix} entries are guaranteed to be non-\sharpf.}
\label{table:ttyctl}
\end{table}
% Local flags
%%%%%%%%%%%%%
\begin{table}[p]
\begin{center}\small
\begin{tabular}{|lll|} \hline
Scsh & C & Meaning \\
\hline\hline
\multicolumn{3}{|l|}{\Posix} \\
\exi{ttyl/canonical} & \ex{ICANON} & Canonical input processing. \\
\exi{ttyl/echo} & \ex{ECHO} & Enable echoing. \\
\exi{ttyl/echo-delete-line} & \ex{ECHOK} & Echo newline after line kill. \\
\exi{ttyl/echo-nl} & \ex{ECHONL} & Echo newline even if echo is off. \\
\exi{ttyl/visual-delete}& \ex{ECHOE} & Visually erase chars. \\
\exi{ttyl/enable-signals} & \ex{ISIG} & Enable \verb|^|C, \verb|^|Z signalling. \\
\exi{ttyl/extended} & \ex{IEXTEN} & Enable extensions. \\
\exi{ttyl/no-flush-on-interrupt}
& \ex{NOFLSH} & Don't flush after interrupt. \\
\exi{ttyl/ttou-signal} & \ex{ITOSTOP} & \ex{SIGTTOU} on background output. \\
\hline\hline
\multicolumn{3}{|l|}{SVR4 and 4.3+BSD} \\
\exi{ttyl/echo-ctl} & \ex{ECHOCTL}
& Echo control chars as ``\verb|^X|''. \\
\exi{ttyl/flush-output} & \ex{FLUSHO} & Output is being flushed. \\
\exi{ttyl/hardcopy-delete} & \ex{ECHOPRT} & Visual erase for hardcopy. \\
\exi{ttyl/reprint-unread-chars} & \ex{PENDIN} & Retype pending input. \\
\exi{ttyl/visual-delete-line} & \ex{ECHOKE} & Visually erase a line-kill. \\
\hline\hline
\multicolumn{3}{|l|}{4.3+BSD} \\
\exi{ttyl/alt-delete-word} & \ex{ALTWERASE} & Alternate word erase algorithm \\
\exi{ttyl/no-kernel-status} & \ex{NOKERNINFO} & No kernel status on \verb|^T|. \\
\hline\hline
\multicolumn{3}{|l|}{SVR4} \\
\exi{ttyl/case-map} & \ex{XCASE} & Canonical case presentation \\
\hline
\end{tabular}
\end{center}
\caption{Local-flags. These are the named flags for the \protect\ex{tty-info}
record's \protect\var{local-flags} field.
These flags generally control the details of the line-editting
user interface.
Only the {\Posix} entries are guaranteed to be non-\sharpf.}
\label{table:ttylocal}
\end{table}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

38
doc/scsh-manual/xman.tex Normal file
View File

@ -0,0 +1,38 @@
%&latex -*- latex -*-
% This is the reference manual for the Scheme Shell.
\documentclass[twoside]{report}
\usepackage{code,boxedminipage,draftfooters,makeidx,palatino,ct,
headings,mantitle,array,matter,a4,tex2page}
% Style issues
\parskip = 3pt plus 3pt
\sloppy
\input{decls}
\makeindex
%%% End preamble
\begin{document}
\frontmatter
\include{front}
\mainmatter
\include{intro}
\include{procnotation}
\include{syscalls}
\include{network}
\include{strings}
\include{rdelim}
\include{awk}
\include{miscprocs}
\include{running}
\include{changes}
\include{todo}
\backmatter
\printindex
\end{document}

View File

@ -0,0 +1 @@
html

33
doc/scsh-paper/Makefile Normal file
View File

@ -0,0 +1,33 @@
.SUFFIXES: .idx .ind .tex .dvi .ps .pdf $(.SUFFIXES)
TEX= headings.tex scsh-paper.tex
TEX2PAGE=tex2page
scsh-paper.dvi: $(TEX)
scsh-paper.pdf: $(TEX)
.dvi.ps:
dvips -j0 -o $@ $<
.tex.dvi:
latex $< && latex $<
rm $*.log
.tex.pdf:
pdflatex $< && thumbpdf $@ && pdflatex $<
rm $*.log
.idx.ind:
makeindex $<
clean:
-rm -f *.log *.png scsh-paper.out scsh-paper.dvi scsh-paper.ps scsh-paper.pdf thumb*.png
rm -rf html
INSTALL_DATA= install -c -m 644
html: $(TEX)
$(TEX2PAGE) scsh-paper && $(TEX2PAGE) scsh-paper

View File

@ -0,0 +1,45 @@
% boxedminipage.sty
%
% adds the boxedminipage environment---just like minipage, but has a
% box round it!
%
% The thickneess of the rules around the box is controlled by
% \fboxrule, and the distance between the rules and the edges of the
% inner box is governed by \fboxsep.
%
% This code is based on Lamport's minipage code.
\def\boxedminipage{\@ifnextchar [{\@iboxedminipage}{\@iboxedminipage[c]}}
\def\@iboxedminipage[#1]#2{\leavevmode \@pboxswfalse
\if #1b\vbox
\else \if #1t\vtop
\else \ifmmode \vcenter
\else \@pboxswtrue $\vcenter
\fi
\fi
\fi\bgroup % start of outermost vbox/vtop/vcenter
\hsize #2
\hrule\@height\fboxrule
\hbox\bgroup % inner hbox
\vrule\@width\fboxrule \hskip\fboxsep \vbox\bgroup % innermost vbox
\advance\hsize -2\fboxrule \advance\hsize-2\fboxsep
\textwidth\hsize \columnwidth\hsize
\@parboxrestore
\def\@mpfn{mpfootnote}\def\thempfn{\thempfootnote}\c@mpfootnote\z@
\let\@footnotetext\@mpfootnotetext
\let\@listdepth\@mplistdepth \@mplistdepth\z@
\@minipagerestore\@minipagetrue
\everypar{\global\@minipagefalse\everypar{}}}
\def\endboxedminipage{%
\par\vskip-\lastskip
\ifvoid\@mpfootins\else
\vskip\skip\@mpfootins\footnoterule\unvbox\@mpfootins\fi
\egroup % ends the innermost \vbox
\hskip\fboxsep \vrule\@width\fboxrule
\egroup % ends the \hbox
\hrule\@height\fboxrule
\egroup% ends the vbox/vtop/vcenter
\if@pboxsw $\fi}

296
doc/scsh-paper/code.sty Normal file
View File

@ -0,0 +1,296 @@
% code.sty: -*- latex -*-
% Latex macros for a "weak" verbatim mode.
% -- like verbatim, except \, {, and } have their usual meanings.
% Environments: code, tightcode, codeaux, codebox, centercode
% Commands: \dcd, \cddollar, \cdmath, \cd, \codeallowbreaks, \codeskip, \^
% Already defined in LaTeX, but of some relevance: \#, \$, \%, \&, \_, \{, \}
% Changelog at the end of the file.
% These commands give you an environment, code, that is like verbatim
% except that you can still insert commands in the middle of the environment:
% \begin{code}
% for(x=1; x<loop_bound; x++)
% y += x^3; /* {\em Add in {\tt x} cubed} */
% \end{code}
%
% All characters are ordinary except \{}. To get \{} in your text,
% you use the commands \\, \{, and \}.
% These macros mess with the definition of the special chars (e.g., ^_~%).
% The characters \{} are left alone, so you can still have embedded commands:
% \begin{code} f(a,b,\ldots,y,z) \end{code}
% However, if your embedded commands use the formerly-special chars, as in
% \begin{code} x := x+1 /* \mbox{\em This is $y^3$} */ \end{code}
% then you lose. The $ and ^ chars are scanned in as non-specials,
% so they don't work. If the chars are scanned *outside* the code env,
% then you have no problem:
% \def\ycube{$y^3$}
% \begin{code} x := x+1 /* {\em This is \ycube} */ \end{code}
% If you must put special chars inside the code env, you do it by
% prefixing them with the special \dcd ("decode") command, that
% reverts the chars to back to special status:
% \begin{code} x := x+1 /* {\dcd\em This is $y^3$} */ \end{code}
% \dcd's scope is bounded by its enclosing braces. It is only defined within
% the code env. You can also turn on just $ with the \cddollar command;
% you can turn on just $^_ with the \cdmath command. See below.
%
% Alternatively, just use \(...\) for $...$, \sp for ^, and \sb for _.
% WARNING:
% Like \verb, you cannot put a \cd{...} inside an argument to a macro
% or a command. If you try, for example,
% \mbox{\cd{$x^y$}}
% you will lose. That is because the text "\cd{$x^y$}" gets read in
% as \mbox's argument before the \cd executes. But the \cd has to
% have a chance to run before LaTeX ever reads the $x^y$ so it can
% turn off the specialness of $ and ^. So, \cd has to appear at
% top level, not inside an argument. Similarly, you can't have
% a \cd or a \code inside a macro (Although you could use \gdef to
% define a macro *inside* a \cd, which you could then use outside.
% Don't worry about this if you don't understand it.)
% BUG: In the codebox env, the effect of a \dcd, \cddollar, or \cdmath
% command is reset at the end of each line. This can be hacked by
% messing with the \halign's preamble, if you feel up to it.
% Useage note: the initial newline after the \begin{code} or
% \begin{codebox} is eaten, but the last newline is not.
% So,
% \begin{code}
% foo
% bar
% \end{code}
% leaves one more blank line after bar than does
% \begin{code}
% foo
% bar\end{code}
% Moral: get in the habit of terminating code envs without a newline
% (as in the second example).
%
% All this stuff tweaks the meaning of space, tab, and newline.
%===============================================================================
% \cd@obeyspaces
% Turns all spaces into non-breakable spaces.
% Note: this is like \@vobeyspaces except without spurious space in defn.
% @xobeysp is basically a space; it's defined in latex.tex.
%
{\catcode`\ =\active\gdef\cd@obeyspaces{\catcode`\ =\active\let =\@xobeysp}}
% \cd@obeytabs
% Turns all tabs into 8 non-breakable spaces (which is bogus).
%
{\catcode`\^^I=\active %
\gdef\cd@obeytabs{\catcode`\^^I=\active\let^^I=\cd@tab}}
\def\cd@tab{\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp\@xobeysp}
% \cd@obeylines
% Turns all cr's into linebreaks. Pagebreaks are not permitted between lines.
% This is copied from lplain.tex's \obeylines, with the cr def'n changed.
%
{\catcode`\^^M=\active % these lines must end with %
\gdef\cd@obeylines{\catcode`\^^M=\active\let^^M=\cd@cr}}
% What ^M turns into. This def'n keeps blank lines from being compressed out.
\def\cd@cr{\par\penalty10000\leavevmode} % TeX magicness
%\def\cd@cr{\par\penalty10000\mbox{}} % LaTeX
% \codeallowbreaks
% Same as \cd@obeylines, except pagebreaks are allowed.
% Put this command inside a code env to allow pagebreaks.
{\catcode`\^^M=\active % these lines must end with %
\gdef\codeallowbreaks{\catcode`\^^M\active\let^^M\cd@crbr}}
%\def\cd@crbr{\leavevmode\endgraf} % What ^M turns into.
\def\cd@crbr{\par\leavevmode} % What ^M turns into.
% \cd@obeycrsp
% Turns cr's into non-breakable spaces. Used by \cd.
{\catcode`\^^M=\active % these lines must end with %
\gdef\cd@obeycrsp{\catcode`\^^M=\active\let^^M=\@xobeysp}}
% =============================================================================
% Set up code environment, in which most of the common special characters
% appearing in code are treated verbatim, namely: $&#^_~%
% \ { } are still enabled so that macros can be called in this
% environment. Use \\, \{, and \} to use these characters verbatim
% in this environment.
%
% Inside a group, you can make
% all the hacked chars special with the \dcd command
% $ special with the \cddollar command
% $^_ special with the \cdmath command.
% If you have a bunch of math $..$'s in your code env, then a global \cddollar
% or \cdmath at the beginning of the env can save a lot of trouble.
% When chars are special (e.g., after a \dcd), you can still get #$%&_{} with
% \#, \$, \%, \&, \_, \{, and \} -- this is standard LaTeX.
% Additionally, \\ gives \ inside the code env, and when \cdmath
% makes ^ special, it also defines \^ to give ^.
%The hacked characters can be made special again
% within a group by using the \dcd command.
% Note: this environment allows no breaking of lines whatsoever; not
% at spaces or hypens. To arrange for a break use the standard \- command,
% or a \discretionary{}{}{} which breaks, but inserts nothing. This is useful,
% for example for allowing hypenated identifiers to be broken, e.g.
% \def\={\discretionary{}{}{}} %optional break
% FOO-\=BAR.
\def\setupcode{\parsep=0pt\parindent=0pt%
\normalfont\ttfamily\frenchspacing\catcode``=13\@noligs%
\def\\{\char`\\}%
\let\dcd=\cd@dcd\let\cddollar=\cd@dollarspecial\let\cdmath=\cd@mathspecial%
\@makeother\$\@makeother\&\@makeother\#%
\@makeother\^\@makeother\_\@makeother\~%
\@makeother\%\cd@obeytabs\cd@obeyspaces}
% other: $&#^_~%
% left special: \{}
% unnecessary: @`'"
%% codebox, centercode
%%=============================================================================
%% The codebox env makes a box exactly as wide as it needs to be
%% (i.e., as wide as the longest line of code is). This is useful
%% if you want to center a chunk of code, or flush it right, or
%% something like that. The optional argument to the environment,
%% [t], [c], or [b], specifies how to vertically align the codebox,
%% just as with arrays or other boxes. Default is [c].
%% Must be a newline immediately after "\begin{codebox}[t]"!
{\catcode`\^^M=\active % these lines must end with %
\gdef\cd@obeycr{\catcode`\^^M=\active\let^^M=\cr}}
% If there is a [<letter>] option, then the following newline will
% be read *after* ^M is bound to \cr, so we're cool. If there isn't
% an option given (i.e., default to [c]), then the @\ifnextchar will
% gobble up the newline as it gobbles whitespace. So we insert the
% \cr explicitly. Isn't TeX fun?
\def\codebox{\leavevmode\@ifnextchar[{\@codebox}{\@codebox[c]\cr}} %]
\def\@codebox[#1]%
{\hbox\bgroup$\if #1t\vtop \else \if#1b\vbox \else \vcenter \fi\fi\bgroup%
\tabskip\z@\setupcode\cd@obeycr% just before cd@obey
\halign\bgroup##\hfil\span}
\def\endcodebox{\crcr\egroup\egroup\m@th$\egroup}
% Center the box on the page:
\newenvironment{centercode}%
{\begin{center}\begin{codebox}[c]}%
{\end{codebox}\end{center}}
%% code, codeaux, tightcode
%%=============================================================================
%% Code environment as described above. Lines are kept on one page.
%% This actually works by setting a huge penalty for breaking
%% between lines of code. Code is indented same as other displayed paras.
%% Note: to increase left margin, use \begin{codeaux}{\leftmargin=1in}.
% To allow pagebreaks, say \codeallowbreaks immediately inside the env.
% You can allow breaks at specific lines with a \pagebreak form.
%% N.B.: The \global\@ignoretrue command must be performed just inside
%% the *last* \end{...} before the following text. If not, you will
%% get an extra space on the following line. Blech.
%% This environment takes two arguments.
%% The second, required argument is the \list parameters to override the
%% \@listi... defaults.
%% - Usefully set by clients: \topsep \leftmargin
%% - Possible, but less useful: \partopsep
%% The first, optional argument is the extra \parskip glue that you get around
%% \list environments. It defaults to the value of \parskip.
\def\codeaux{\@ifnextchar[{\@codeaux}{\@codeaux[\parskip]}} %]
\def\@codeaux[#1]#2{%
\bgroup\parskip#1%
\begin{list}{}%
{\parsep\z@\rightskip\z@\listparindent\z@\itemindent\z@#2}%
\item[]\setupcode\cd@obeylines}%
\def\endcodeaux{\end{list}\leavevmode\egroup\ignorespaces\global\@ignoretrue}
%% Code env is codeaux with the default margin and spacing \list params:
\def\code{\codeaux{}} \let\endcode=\endcodeaux
%% Like code, but with no extra vertical space above and below.
\def\tightcode{\codeaux[=0pt]{\topsep\z@}}%
\let\endtightcode\endcodeaux
% {\vspace{-1\parskip}\begin{codeaux}{\partopsep\z@\topsep\z@}}%
% {\end{codeaux}\vspace{-1\parskip}}
% Reasonable separation between lines of code
\newcommand{\codeskip}{\penalty0\vspace{2ex}}
% \cd is used to build a code environment in the middle of text.
% Note: only difference from display code is that cr's are taken
% as unbreakable spaces instead of linebreaks.
\def\cd{\leavevmode\begingroup\ifmmode\let\startcode=\startmcode\else%
\let\startcode\starttcode\fi%
\setupcode\cd@obeycrsp\startcode}
\def\starttcode#1{#1\endgroup}
\def\startmcode#1{\hbox{#1}\endgroup}
% Restore $&#^_~% to their normal catcodes
% Define \^ to give the ^ char.
% \dcd points to this guy inside a code env.
\def\cd@dcd{\catcode`\$=3\catcode`\&=4\catcode`\#=6\catcode`\^=7%
\catcode`\_=8\catcode`\~=13\catcode`\%=14\def\^{\char`\^}}
% Selectively enable $, and $^_ as special.
% \cd@mathspecial also defines \^ give the ^ char.
% \cddollar and \cdmath point to these guys inside a code env.
\def\cd@dollarspecial{\catcode`\$=3}
\def\cd@mathspecial{\catcode`\$=3\catcode`\^=7\catcode`\_=8%
\def\^{\char`\^}}
% Change log:
% Started off as some macros found in C. Rich's library.
% Olin 1/90:
% Removed \makeatletter, \makeatother's -- they shouldn't be there,
% because style option files are read with makeatletter. The terminal
% makeatother screwed things up for the following style options.
% Olin 3/91:
% Rewritten.
% - Changed things so blank lines don't get compressed out (the \leavevmove
% in \cd@cr and \cd@crwb).
% - Changed names to somewhat less horrible choices.
% - Added lots of doc, so casual hackers can more easily mess with all this.
% - Removed `'"@ from the set of hacked chars, since they are already
% non-special.
% - Removed the bigcode env, which effect can be had with the \codeallowbreaks
% command.
% - Removed the \@noligs command, since it's already defined in latex.tex.
% - Win big with the new \dcd, \cddollar, and \cdmath commands.
% - Now, *only* the chars \{} are special inside the code env. If you need
% more, use the \dcd command inside a group.
% - \cd now works inside math mode. (But if you use it in a superscript,
% it still comes out full size. You must explicitly put a \scriptsize\tt
% inside the \cd: $x^{\cd{\scriptsize\tt...}}$. A \leavevmode was added
% so that if you begin a paragraph with a \cd{...}, TeX realises you
% are starting a paragraph.
% - Added the codebox env. Tricky bit involving the first line hacked
% with help from David Long.
% Olin 8/94
% Changed the font commands for LaTeX2e.

114
doc/scsh-paper/css.t2p Normal file
View File

@ -0,0 +1,114 @@
% css.t2p
% Dorai Sitaram
% 19 Jan 2001
% A basic style for HTML documents generated
% with tex2page.
\ifx\shipout\UNDEFINED
\cssblock
body {
color: black;
/* background-color: #e5e5e5;*/
background-color: #ffffff;
/*background-color: beige;*/
margin-top: 2em;
margin-left: 8%;
margin-right: 8%;
}
h1,h2,h3,h4,h5,h6 {
margin-top: .5em;
}
.partheading {
font-size: 100%;
}
.chapterheading {
font-size: 100%;
}
pre {
margin-left: 2em;
}
ol {
list-style-type: decimal;
}
ol ol {
list-style-type: lower-alpha;
}
ol ol ol {
list-style-type: lower-roman;
}
ol ol ol ol {
list-style-type: upper-alpha;
}
.scheme {
color: brown;
}
.scheme .keyword {
color: #990000;
font-weight: bold;
}
.scheme .builtin {
color: #990000;
}
.scheme .variable {
color: navy;
}
.scheme .global {
color: purple;
}
.scheme .selfeval {
color: green;
}
.scheme .comment {
color: teal;
}
.schemeresponse {
color: green;
}
.navigation {
color: red;
text-align: right;
font-style: italic;
}
.disable {
/* color: #e5e5e5; */
color: gray;
}
.smallcaps {
font-size: 75%;
}
.smallprint {
color: gray;
font-size: 75%;
text-align: right;
}
.smallprint hr {
text-align: left;
width: 40%;
}
\endcssblock
\fi
% ex:ft=css

6
doc/scsh-paper/ct.sty Normal file
View File

@ -0,0 +1,6 @@
% Loads cmtt fonts in on \tt. -*- latex -*-
% I prefer these to the Courier fonts that latex gives you w/postscript styles.
% Courier is too spidery and too wide -- it's hard to get 80 chars on a line.
% -Olin
\renewcommand{\ttdefault}{cmtt}

Some files were not shown because too many files have changed in this diff Show More