diff options
author | Bryan Newbold <bnewbold@robocracy.org> | 2017-02-20 00:05:23 -0800 |
---|---|---|
committer | Bryan Newbold <bnewbold@robocracy.org> | 2017-02-20 00:05:23 -0800 |
commit | 5ca6e8e6a4e5c022a6fb5d28f30219c22c99eda8 (patch) | |
tree | 9b744b9dbf39e716e56daa620e2f3041968caf19 | |
download | scm-5ca6e8e6a4e5c022a6fb5d28f30219c22c99eda8.tar.gz scm-5ca6e8e6a4e5c022a6fb5d28f30219c22c99eda8.zip |
Import Upstream version 4e6upstream/4e6
-rw-r--r-- | ANNOUNCE | 218 | ||||
-rw-r--r-- | COPYING | 339 | ||||
-rw-r--r-- | ChangeLog | 3029 | ||||
-rw-r--r-- | Iedline.scm | 103 | ||||
-rw-r--r-- | Init.scm | 854 | ||||
-rw-r--r-- | Link.scm | 284 | ||||
-rw-r--r-- | Makefile | 384 | ||||
-rw-r--r-- | Makefile.in | 462 | ||||
-rw-r--r-- | QUICKREF | 201 | ||||
-rw-r--r-- | README | 384 | ||||
-rw-r--r-- | README.unix | 182 | ||||
-rw-r--r-- | Transcen.scm | 133 | ||||
-rw-r--r-- | acconfig-1.5.h | 22 | ||||
-rw-r--r-- | bench.scm | 55 | ||||
-rwxr-xr-x | build.bat | 1 | ||||
-rwxr-xr-x | build.scm | 1393 | ||||
-rwxr-xr-x | configure | 849 | ||||
-rw-r--r-- | configure.in | 33 | ||||
-rw-r--r-- | continue.c | 255 | ||||
-rw-r--r-- | continue.h | 178 | ||||
-rw-r--r-- | crs.c | 412 | ||||
-rw-r--r-- | dynl.c | 448 | ||||
-rw-r--r-- | ecrt0.c | 614 | ||||
-rw-r--r-- | edline.c | 94 | ||||
-rw-r--r-- | eval.c | 1494 | ||||
-rw-r--r-- | example.scm | 137 | ||||
-rw-r--r-- | findexec.c | 145 | ||||
-rw-r--r-- | gmalloc.c | 1638 | ||||
-rw-r--r-- | gsubr.c | 138 | ||||
-rw-r--r-- | install-sh | 238 | ||||
-rw-r--r-- | ioext.c | 703 | ||||
-rwxr-xr-x | mkinstalldirs | 35 | ||||
-rw-r--r-- | patchlvl.h | 8 | ||||
-rw-r--r-- | pi.c | 78 | ||||
-rw-r--r-- | pi.scm | 165 | ||||
-rw-r--r-- | posix.c | 408 | ||||
-rw-r--r-- | pre-crt0.c | 9 | ||||
-rw-r--r-- | r4rstest.scm | 1038 | ||||
-rw-r--r-- | ramap.c | 1677 | ||||
-rw-r--r-- | record.c | 349 | ||||
-rw-r--r-- | repl.c | 1649 | ||||
-rw-r--r-- | rgx.c | 661 | ||||
-rw-r--r-- | rope.c | 335 | ||||
-rw-r--r-- | sc2.c | 172 | ||||
-rw-r--r-- | scl.c | 2393 | ||||
-rw-r--r-- | scm.1 | 335 | ||||
-rw-r--r-- | scm.c | 940 | ||||
-rw-r--r-- | scm.doc | 330 | ||||
-rw-r--r-- | scm.h | 817 | ||||
-rw-r--r-- | scm.texi | 6911 | ||||
-rw-r--r-- | scm4e3.scmconfig.patch | 60 | ||||
-rw-r--r-- | scmconfig.h.in | 69 | ||||
-rw-r--r-- | scmfig.h | 671 | ||||
-rw-r--r-- | setjump.h | 122 | ||||
-rw-r--r-- | setjump.mar | 38 | ||||
-rw-r--r-- | setjump.s | 40 | ||||
-rw-r--r-- | socket.c | 635 | ||||
-rw-r--r-- | split.scm | 87 | ||||
-rw-r--r-- | subr.c | 2009 | ||||
-rw-r--r-- | sys.c | 1758 | ||||
-rw-r--r-- | time.c | 389 | ||||
-rw-r--r-- | unexec.c | 1238 | ||||
-rw-r--r-- | unexelf.c | 908 | ||||
-rw-r--r-- | unif.c | 2000 | ||||
-rw-r--r-- | unix.c | 151 |
65 files changed, 43905 insertions, 0 deletions
diff --git a/ANNOUNCE b/ANNOUNCE new file mode 100644 index 0000000..0edea3c --- /dev/null +++ b/ANNOUNCE @@ -0,0 +1,218 @@ +This message announces the availability of Scheme release scm4e6. + +New in scm4e6 are: + + * bench.scm (benchmark): added. computes and display statistics + on "pi.scm" benchmark. + * Makefile (benchlit bench): targets added. Append stats to file + "BenchLog". + * scm.texi (Socket): added examples of chat servers and clients. + (Internet Addresses and Socket Names): enlarged from "Internet + Addresses". + * socket.c (l_connect): BUF0 was missing from mode bits set in + returned port. + * build.scm (build-params): Added compiler-options and + linker-options; added --batch-dialect and --script-name as aliases + for -h and -w. + * scmfig.h (HAVE_SELECT): Now defined for linux. + * sys.c (igc): fixed off-by-1 error for sizeof save_regs_gc_mark. + (gc_mark): fixed off-by-1 error for sizeof(CONTINUATION). These + seem to fix a very obscure GC bug. + * Init.scm (exec-self): Added. + * repl.c (init_repl): DUMP sets RESTART to EXEC-SELF. + * repl.c (tryload): Made tail-recursive so that dump, quit, exit, + etc. will work as the last expression in a loading file. + (scm_execpath): Split out from scm_unexec. + * unexec.c: All Updated from emacs-19.34 -- no changes necessary. + * gmalloc.c: + * pre-crt0.c: + * ecrt0.c: + * unexelf.c: fixes Linux (ELF) dump bug. + * build.scm (platform): linux renamed linux-aout. linux-elf fixed + and renamed linux. + (C-libraries): X11R6 moved library files on RedHat Linux. Linux + graphics library now has entry (doesn't default). + (compile-dll-c-files linux): + (make-dll-archive linux): Now converts from ".o" objects to ELF + ".so" form and "links" the usual libraries. + * Link.scm (usr:lib x:lib): dynamic linking fixed for (linux ELF) + dlopen. Libraries other than ".so" object not needed; eliminated + by usr:lib and x:lib returning #f. + * dynl.c (l_dyn_unlink): prints result of dlerror() on errors. + * eval.c (nconc2last): If CAUTIOUS is defined, checks that + APPLY's arglist and last element of arglist are LIST?s. + * sys.c (igc): symhash GC can now be disabled with + #define NO_SYM_GC. + * Init.scm (boot-tail): Added FSF --help and --version options. + Added --no-init-file as a synonym for -no-init-file. + * scm.texi (File-System Habitat): improved wording and added + examples. + * scm.texi (Top): Renamed sections. + * sys.c (mark_syms mark_sym_values): Split up mark_symhash() to + immunize against accidental pointers. + * repl.c (gc_ports_collected): added to instrument symbol GC. + * scm.texi (Debugging Scheme Code): Added section. + * eval.c (definedp): Changed from a memoizing macro to a `syntax'. + + From maximum entropy <entropy@zippy.bernstein.com>: + + * ioext.c, scmfig.h: support for SGI (tested with SGI IRIX 5.2/gcc) + * ioext.c (file_set_position): If a port is bidirectional + (e.g. a socket) it may be necessary on some systems to perform a + file positioning operation when switching between reading and + writing. This is required by ANSI C (ISO/IEC 9899:1990 + 7.9.5.3). Therefore, a file-set-position on a bidirectional + port should not signal an error if fseek generates an + ESPIPE -- the fseek operation actually "succeeded" in that it + reset the I/O direction flag for the FILE. + * repl.c (input_waiting): R4RS requires that "char-ready?" + return "#t" at end-of-file. The semantics for "ioctl(..., + FIONREAD, ...)" are such that it gives 0 on a socket that is + closed (on the other side of the connection). If the + system has select(), use that instead to get the correct + behavior. + * socket.c (l_listen): Treat sockets that have been "listened" + as input-ports. This allows polling for new connections + (e.g. with "char-ready?") instead of blocking in + "socket:accept". + * socket.c (l_accept): Fix type checking to agree with + previous patch. + + From Radey Shouman <shouman@zianet.com> + + * eval.c (unmemocar): The code in unmemocar to deal with ILOCs was + never being executed. + * sys.c (intern): fixed (new) symhash GC bug. + * sys.c (igc): Added calls to mark_symhash() and sweep_symhash(). + These GC unused symbols with a top-level value of UNDEFINED. + (mark_symhash): added. + (sweep_symhash): added. + + From Eric Hanchrow <erich@MICROSOFT.com> + + * scm.c (l_sleep): Ported to Windows NT (_WIN32) + * ioext.c: Ported to Windows NT (_WIN32) + + -=-=- + +Scm conforms to Revised^4 Report on the Algorithmic Language Scheme +and the IEEE P1178 specification. Scm is written in C and runs under +Amiga, Atari-ST, MacOS, MS-DOS, OS/2, NOS/VE, Unicos, VMS, Unix and +similar systems. ASCII and EBCDIC are supported. + +Documentation is included explaining the many Scheme Language +extensions in scm, the internal representations, and how to extend or +include SCM in other programs. Documentation is online at: + + http://ftp-swiss.ai.mit.edu/~jaffer/SCM.html + +SCM can be obtained via FTP (detailed instructions follow) from: + ftp-swiss.ai.mit.edu:pub/scm/scm4e6.tar.gz + prep.ai.mit.edu:pub/gnu/jacal/scm4e6.tar.gz + ftp.maths.tcd.ie:pub/bosullvn/jacal/scm4e6.tar.gz + ftp.cs.indiana.edu:/pub/scheme-repository/imp/scm4e6.tar.gz + +SLIB is a portable Scheme library which SCM uses: + ftp-swiss.ai.mit.edu:pub/scm/slib2a6.tar.gz + prep.ai.mit.edu:pub/gnu/jacal/slib2a6.tar.gz + ftp.maths.tcd.ie:pub/bosullvn/jacal/slib2a6.tar.gz + ftp.cs.indiana.edu:/pub/scheme-repository/code/lib/slib2a6.tar.gz + +JACAL is a symbolic math system written in Scheme: + ftp-swiss.ai.mit.edu:pub/scm/jacal1a5.tar.gz + prep.ai.mit.edu:pub/gnu/jacal/jacal1a5.tar.gz + ftp.maths.tcd.ie:pub/bosullvn/jacal/jacal1a5.tar.gz + ftp.cs.indiana.edu:/pub/scheme-repository/code/num/jacal1a5.tar.gz + +HOBBIT is a compiler for SCM code: + ftp-swiss.ai.mit.edu:pub/scm/hobbit4d.tar.gz + ftp.maths.tcd.ie:pub/bosullvn/jacal/hobbit4d.tar.gz + ftp.cs.indiana.edu:/pub/scheme-repository/imp/hobbit4d.tar.gz + +SCMCONFIG contains additional files for the SCM distribution to build +SCM on Unix machines using GNU autoconf. + ftp-swiss.ai.mit.edu:pub/scm/scmconfig4e3.tar.gz + prep.ai.mit.edu:pub/gnu/jacal/scmconfig4e3.tar.gz + ftp.maths.tcd.ie:pub/bosullvn/jacal/scmconfig4e3.tar.gz + ftp.cs.indiana.edu:/pub/scheme-repository/imp/SCM-support/scmconfig4e3.tar.gz + +SLIB-PSD is a portable debugger for Scheme (requires emacs editor): + ftp-swiss.ai.mit.edu:pub/scm/slib-psd1-3.tar.gz + prep.ai.mit.edu:pub/gnu/jacal/slib-psd1-3.tar.gz + ftp.maths.tcd.ie:pub/bosullvn/jacal/slib-psd1-3.tar.gz + ftp.cs.indiana.edu:/pub/scheme-repository/utl/slib-psd1-3.tar.gz + +SLIB-SCHELOG is an embedding of Prolog in Scheme: + ftp-swiss.ai.mit.edu:pub/scm/slib-schelog.tar.gz + prep.ai.mit.edu:pub/gnu/jacal/slib-schelog.tar.gz + ftp.maths.tcd.ie:pub/bosullvn/jacal/slib-schelog.tar.gz + ftp.cs.indiana.edu:/pub/scheme-repository/utl/slib-schelog.tar.gz + +SMG-SCM is an SMG interface package which works with SCM on VMS. + ftp-swiss.ai.mit.edu:pub/scm/smg-scm2a1.zip + prep.ai.mit.edu:pub/gnu/jacal/smg-scm2a1.zip + ftp.cs.indiana.edu:/pub/scheme-repository/imp/SCM-support/smg-scm2a1.zip + ftp.maths.tcd.ie:pub/bosullvn/jacal/smg-scm2a1.zip +A VMS version of Unzip is available by anonymous FTP from + ftp.spc.edu:[ANONYMOUS.MACRO32]UNZIP.EXE. + +TURTLSCM is a turtle graphics package which works with SCM on MS-DOS +or X11 machines: + ftp-swiss.ai.mit.edu:pub/scm/turtlegr.tar.gz + prep.ai.mit.edu:pub/gnu/jacal/turtlegr.tar.gz + ftp.maths.tcd.ie:pub/bosullvn/jacal/turtlegr.tar.gz + ftp.cs.indiana.edu:/pub/scheme-repository/imp/SCM-support/turtlegr.tar.gz + +XSCM is a X windows interface package which works with SCM: + ftp-swiss.ai.mit.edu:pub/scm/xscm-2.01.tar.gz + prep.ai.mit.edu:pub/gnu/jacal/xscm-2.01.tar.gz + ftp.cs.indiana.edu:/pub/scheme-repository/imp/SCM-support/xscm-2.01.tar.gz + +MacSCM is a Macintosh applications building package which works with +SCM (similar to XSCM). + ftp-swiss.ai.mit.edu:pub/scm/macscm.tar.Z + ftp.maths.tcd.ie:pub/bosullvn/jacal/macscm.tar.Z + ftp.cs.indiana.edu:/pub/scheme-repository/imp/SCM-support/macscm.tar.gz + +WB is a disk based, sorted associative array (B-tree) library for SCM. +Using WB, large databases can be created and managed from SCM. + ftp-swiss.ai.mit.edu:pub/scm/wb1a2.tar.gz + ftp.maths.tcd.ie:pub/bosullvn/jacal/wb1a2.tar.gz + ftp.cs.indiana.edu:/pub/scheme-repository/imp/SCM-support/wb1a2.tar.gz + +DLD is a C library package allowing SCM to dynamically load object +files on Linux, VAX (Ultrix), Sun 3 (SunOS 3.4 and 4.0), SPARCstation +(SunOS 4.0), Sequent Symmetry (Dynix), and Atari ST. + + prep.ai.mit.edu:pub/gnu/dld-3.3.tar.gz + -=-=- + + ftp ftp-swiss.ai.mit.edu (anonymous) + bin + cd pub/scm + get scm4e6.tar.gz + get slib2a6.tar.gz +or + ftp prep.ai.mit.edu (anonymous) + bin + cd pub/gnu/jacal + get scm4e6.tar.gz + get slib2a6.tar.gz + + `scm4e6.tar.gz' is a gzipped tar file of the C code distribution. + `slib2a6.tar.gz' is a gzipped tar file of a Scheme Library. + +Files in these directories with the ".gz" suffix are compressed with +patent-free gzip (no relation to zip). The program to uncompress them +is available from + prep.ai.mit.edu:pub/gnu/gzip-1.2.4.tar + prep.ai.mit.edu:pub/gnu/gzip-1.2.4.shar + prep.ai.mit.edu:pub/gnu/gzip-1.2.4.msdos.exe + +Remember to use binary mode when transferring the files. +Be sure to get and read the GNU General Public License (COPYING). +It is included in scm4e6.tar.gz. + +I sell IBM PC floppy disk sets with the source files, documentation, +and MS-DOS and i386 MS-DOS executables for $99.00. To order, send +e-mail to jaffer@ai.mit.edu. @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e689bb5 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,3029 @@ +Mon Nov 18 22:56:11 1996 Aubrey Jaffer <jaffer@localhost.bertronics.com> + + * patchlvl.h (SCMVERSION): 4e6 released. + + * bench.scm (benchmark): added. computes and display statistics + on "pi.scm" benchmark. + + * Makefile (benchlit bench): targets added. Append stats to file + "BenchLog". + +Sun Nov 17 22:21:28 1996 Aubrey Jaffer <jaffer@localhost.bertronics.com> + + * scm.texi (Socket): added examples of chat servers and clients. + (Internet Addresses and Socket Names): enlarged from "Internet + Addresses". + + * socket.c (l_connect): BUF0 was missing from mode bits set in + returned port. + +Sat Nov 16 22:02:39 1996 Aubrey Jaffer <jaffer@localhost.bertronics.com> + + * build.scm (build-params): Added compiler-options and + linker-options; added --batch-dialect and --script-name as aliases + for -h and -w. + + * scmfig.h (HAVE_SELECT): Now defined for linux. + +Sat Nov 2 09:24:50 EST 1996 maximum entropy <entropy@zippy.bernstein.com> + + * ioext.c, scmfig.h: support for SGI (tested with SGI IRIX 5.2/gcc) + + * ioext.c (file_set_position): If a port is bidirectional + (e.g. a socket) it may be necessary on some systems to perform a + file positioning operation when switching between reading and + writing. This is required by ANSI C (ISO/IEC 9899:1990 + 7.9.5.3). Therefore, a file-set-position on a bidirectional + port should not signal an error if fseek generates an + ESPIPE -- the fseek operation actually "succeeded" in that it + reset the I/O direction flag for the FILE. + + * repl.c (input_waiting): R4RS requires that "char-ready?" + return "#t" at end-of-file. The semantics for "ioctl(..., + FIONREAD, ...)" are such that it gives 0 on a socket that is + closed (on the other side of the connection). If the + system has select(), use that instead to get the correct + behavior. + + * socket.c (l_listen): Treat sockets that have been "listened" + as input-ports. This allows polling for new connections + (e.g. with "char-ready?") instead of blocking in + "socket:accept". + + * socket.c (l_accept): Fix type checking to agree with + previous patch. + +Wed Nov 13 17:11:59 1996 Aubrey Jaffer <jaffer@localhost.bertronics.com> + + * sys.c (igc): fixed off-by-1 error for sizeof save_regs_gc_mark. + (gc_mark): fixed off-by-1 error for sizeof(CONTINUATION). These + seem to fix a very obscure GC bug. + +Tue Oct 29 10:47:41 1996 Aubrey Jaffer <jaffer@localhost.bertronics.com> + + * Init.scm (exec-self): Added. + + * repl.c (init_repl): DUMP sets RESTART to EXEC-SELF. + +Mon Oct 28 11:39:30 1996 Aubrey Jaffer <jaffer@localhost.bertronics.com> + + * repl.c (tryload): Made tail-recursive so that dump, quit, exit, + etc. will work as the last expression in a loading file. + (scm_execpath): Split out from scm_unexec. + +Sun Oct 27 22:12:32 1996 Aubrey Jaffer <jaffer@localhost.bertronics.com> + + * unexec.c: All Updated from emacs-19.34 -- no changes necessary. + * gmalloc.c: + * pre-crt0.c: + * ecrt0.c: + * unexelf.c: fixes Linux (ELF) dump bug. + +Mon Oct 21 21:49:20 1996 Aubrey Jaffer <jaffer@martigny.bertronics> + + * build.scm (platform): linux renamed linux-aout. linux-elf fixed + and renamed linux. + (C-libraries): X11R6 moved library files on RedHat Linux. Linux + graphics library now has entry (doesn't default). + (compile-dll-c-files linux): + (make-dll-archive linux): Now converts from ".o" objects to ELF + ".so" form and "links" the usual libraries. + + * Link.scm (usr:lib x:lib): dynamic linking fixed for (linux ELF) + dlopen. Libraries other than ".so" object not needed; eliminated + by usr:lib and x:lib returning #f. + + * dynl.c (l_dyn_unlink): prints result of dlerror() on errors. + +Thu Oct 10 14:05:14 1996 Aubrey Jaffer <jaffer@martigny.bertronics> + + * eval.c (nconc2last): If CAUTIOUS is defined, checks that + APPLY's arglist and last element of arglist are LIST?s. + +Sun Oct 6 16:40:54 1996 Radey Shouman <shouman@zianet.com> + + * eval.c (unmemocar): The code in unmemocar to deal with ILOCs was + never being executed. + +Fri Oct 4 13:57:35 1996 Aubrey Jaffer <jaffer@martigny.bertronics> + + * sys.c (igc): symhash GC can now be disabled with + #define NO_SYM_GC. + +Wed Oct 2 20:51:07 1996 Aubrey Jaffer <jaffer@martigny.bertronics> + + * Init.scm (boot-tail): Added FSF --help and --version options. + Added --no-init-file as a synonym for -no-init-file. + +Sun Sep 29 23:59:19 1996 Aubrey Jaffer <jaffer@martigny.bertronics> + + * scm.texi (File-System Habitat): improved wording and added + examples. + +Thu Sep 26 22:23:32 1996 Radey Shouman <shouman@zianet.com> + + * sys.c (intern): fixed (new) symhash GC bug. + +Tue Sep 24 13:55:11 1996 Aubrey Jaffer <jaffer@martigny.bertronics> + + * scm.texi (Top): Renamed sections. + + * sys.c (mark_syms mark_sym_values): Split up mark_symhash() to + immunize against accidental pointers. + +Sat Sep 14 22:53:46 1996 Aubrey Jaffer <jaffer@martigny.bertronics> + + * repl.c (gc_ports_collected): added to instrument symbol GC. + +Sat Sep 14 15:35:29 1996 Radey Shouman <shouman@zianet.com> + + * sys.c (igc): Added calls to mark_symhash() and sweep_symhash(). + These GC unused symbols with a top-level value of UNDEFINED. + (mark_symhash): added. + (sweep_symhash): added. + +Wed Sep 11 21:18:05 1996 Aubrey Jaffer <jaffer@martigny.bertronics> + + * scm.texi (Debugging Scheme Code): Added section. + +Sat Aug 31 14:05:24 1996 Eric Hanchrow <erich@MICROSOFT.com> + + * scm.c (l_sleep): Ported to Windows NT (_WIN32) + + * ioext.c: Ported to Windows NT (_WIN32) + +Sat Aug 31 13:18:34 1996 Aubrey Jaffer <jaffer@martigny.bertronics> + + * eval.c (definedp): Changed from a memoizing macro to a `syntax'. + +Sun Jul 21 01:06:44 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * Link.scm (link-named-scm): fixed to call "build.scm". + +Sat Jul 20 23:53:17 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * scm.texi (Memoized Expressions): section added. + (Errors): section added. + +Wed Jul 17 17:40:01 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * r4rstest.scm: renamed from "test.scm". Now carries copyright + notice suitable for single file distribution. + +Fri May 17 23:37:16 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * findexec.c (dld_find_executable): names changed to keep up with + DLD changes. + +Sun May 12 21:43:14 1996 Radey Shouman <shouman@zianet.com> + + * unif.c (array_rank): Was returning 0 for bit-vectors. + (uve_fill): Fixed error report. + (lcount): + (position): Made to work with 1-d shared bit-arrays. + (aind): Added check for second argument, must be either + an INUM, NULL, or a pair. Without this, e.g. + (uniform-vector-set! <vector> 'x 0) + starts cdr'ing down the symbol ... + (array_inbp): Cleaned up to work with enclosed and huge arrays. + + * gsubr.c (gsubr_apply): Fixed error report. + + * scl.c (equal): Prevent fallthrough on last case, could cause + wierdness if cases are added later. + + * ramap.c (ra_matchp): Fixed to allow any 1-d array of zero size + to match a uniform vector, and to require all non-zero length + dimensions of two arrays to match even after a zero length + dimension. Now promotes 0-d arrays as well as scalars to match + first array shape. + (sc2array): Reshapes 0-d arrays as well as scalars. + Added check to make sure 2nd argument is really an array, + vector or uve. + (ramapc): Changed to allocate fewer array headers when arguments + are 1-d arrays. (Still allocates more than strictly necessary.) + (array_copy): Added check for scalar destination argument, since + ra_matchp() will now promote scalars to arrays. + +Sun May 12 00:52:51 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * build.scm (build): fixed HP-UX compile-dll-c-files. + + * findexec.c (dld_find_executable): ifdefed out stat() for hpux. + + * scm.c: New const declarations rejected by hp-ux cc; ifdefed out. + +Thu May 9 10:28:14 1996 Tim Pierce <twpierce@midway.uchicago.edu> + + * time.c sys.c findexec.c: string[s].h configuration for Solaris + 2.3 system using gcc 2.7.2. + +Tue Apr 9 19:46:21 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * sys.c (igc): stackbase argument added. Passing 0 disables stack + marking (used by dump). + + * build.scm (build link-c-program djgpp): + (build compile-c-files djgpp): Uses new batch:apply-chop-to-fit to + deal with MS-DOS line length restrictions. + +Sun Apr 7 23:15:36 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * repl.c (repl_driver): now supports unexec conditionally by + CAN_DUMP. + (scm_unexec): moved from dump.c. Now throws to top level to avoid + saving continuations. + + * dump.c: removed. Contents moved to repl.c. + + * continue.c (dynthrow): One instruction interrupt vulnerability + removed for machines with long ints. Others define SHORT_INT. + + * repl.c (repl_driver): Throws to top level now encoded by COOKIE + flags for non- SHORT_INT platforms. + +Sat Apr 6 14:29:47 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * unexec.c (A_TEXT_OFFSET A_TEXT_SEEK ADJUST_EXEC_HEADER NO_REMAP + TEXT_START HAVE_GETPAGESIZE SEGMENT_MASK): definitions moved from + scmfig.h. + + * gmalloc.c (HAVE_GETPAGESIZE): copied definition here so that + scm.h and scmfig.h won't be included for just one definition. + + * dump.c (scm_dump): reworked to use execpath as default second + argument. Removed "#include DUMP_CODE" abomination; using + suppress parameters in build.scm + + * build.scm (build C-libraries): added dump (unexec) and nostart + libraries to support dump. + (build compile-commands): Added support for dump + (build features): dump + + * scm.c (execpath): now a global which init_dump() also sets. + + * repl.c (repl_driver): added scm_evstr("(boot-tail)") call + after scm_ldfile(initpath) so command-line arguments can be + processed after "Init.scm" is loaded. + + * build.scm (build platform): added record for MS-DOS so defaults + don't cause errors when -p not specified. + +Mon Jan 9 15:43:36 1995 Patrick LECOANET <lecoanet%sid1@cenaath.cena.dgac.fr> + + * dump.c (dump): created. + + * pre-crt0.c crt0.c gmalloc.c unexec.c unexelf.c: adapted from + emacs (circa 1994). + +Fri Apr 5 00:16:59 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * ramap.c (ramapc ra2contig array_imap): Added +0L to cast first + argument to make_uve() to long. + +Thu Apr 4 00:47:09 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * ramap.c: removed #ifdef ARRAYS (over whole file). + +Wed Apr 3 10:14:18 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * Link.scm (compile-file): Now calls build.scm for compiling C. + + * hobbit.scm ("auxiliary functions" butlast ...): removed and + renamed gratuitous (and incompatible) duplications of + slib/comlist.scm. + +Mon Apr 1 08:56:09 1996 Johann Friedrich Heinrichmeyer <Fritz.Heinrichmeyer@fernuni-hagen.de> + + * sys.c (stack_check): sizeof(STACKITEM) was multiplied on wrong + side of inequality. + +Fri Mar 29 23:52:03 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * patchlvl.h (SCMVERSION): 4e4 + + * build.scm (build): microsoft-c-nt support added. + + * scm.c (l_raise): Disabled for WINDOWS_NT. + (scm_find_impl_file): fixed for getenv("SCM_INIT_PATH") case. + +Sun Mar 24 00:18:10 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * build.scm (build): fixed -tdll to not make archive or compile + all 'linkable files. + +Sun Mar 10 17:23:39 1996 Radey Shouman <shouman@ccwf.cc.utexas.edu> + + * ramap.c (sc2array): Added, converts a scalar to a shared array. + (ramapc): Uses sc2array to convert scalar arguments to arrays + for ARRAY-MAP! &c. + (ura_read, ura_write, ura_fill): Added. + (array_map): Added check for number of arguments when procedure + arg is a subr. Added cclo case. + + * unif.c (dims2ura): Fixed, it wasn't properly filling its result + sometimes. Added range check for size of conventional arrays. + (aind): Added range check when called as subr3. + (array_inbp): Returns #t if called with a scalar and no + index args -- APLish boundary case. + (cvref): Now recycles enclosed array refs. + (aset): Uses num2dbl for setting inexact array elts, so + e.g. (array-set! <inexact-array> 0 ...) works. + (array_contents): For strict option, wasn't returning an array + whenever the base was non-zero, now less restrictive. + (ra2contig): moved to ramap.c, as it calls ramapc(). To allow + dynamic linking of ramap.c. + (rafill): moved from ramap.c, to allow filling of arrays on + creation without needing ramap.c. + (uve_fill): Added, for filling uves / 1-d arrays without needing + ramap.c. + (uve_read, uve_write): (Re)added + (ura_read, ura_write): Moved to ramap.c, now call uve_[read write]. + (ra2l): uses cvref instead of aref, maybe faster and works for + enclosed arrays. + (init_unif): Added feature 'string-case, to prevent require + from nuking STRING-UPCASE!, STRING-DOWNCASE! + (encl_array): Added range check for dimension args. + + * rope.c (num2dbl): Added, analogous to num2dbl. + + * scmfig.h Eliminated redundant #ifdef + + * scl.c (makdbl) Rearranged so that it tests for out of range + double argument before assigning to float variable, this + avoids causing SIGFPE on my Linux box. + (equal): Fixed so that it doesn't need extern array_equal, + allowing ramap.c to be dynamically linkable. + + * scm.c Added documented variable *scm-version* + +Thu Mar 21 00:14:29 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * Link.scm (scm:object-suffix): Changed to ".so" when + 'sun-dl is PROVIDED?. + + * scmfig.h (getcwd): addition for scmconfig. + * findexec.c: minor change for scmconfig. + +Wed Mar 20 00:12:43 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * README (Making SCM with Think C 4.0 or 4.1): Instructions added + back in. + +Sun Mar 17 00:17:21 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * findexec.c (dld_find_executable): Added support for ~ and ~/ in + PATH environment variable. + +Sat Mar 16 10:38:15 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * scm.c (scm_find_impl_file): Added generic_name argument to test + for cases where executable *doesn't* have its usual name. + (scm_sep_init_try): Added combined function to reduce length of + scm_find_impl_file. + (scm_try_path): Now tests for (and returns) 0. + + * build.scm (build): fixed assorted bugs. + +Tue Mar 12 12:48:28 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * 4e3: released. + * repl.c (read_token): ',' now delimits token. + +Mon Mar 4 23:19:50 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * scm.texi (SLIB and require.scm): SLIB installation and + "require.scm" trampoline configuration method explained. + + * Init.scm (load:pre load:post): added to share code between + scm:load and scm:load-source. "require" is now loaded using the + regular calls; trying to maintain SCM initializing without SLIB is + too hard. + +Sun Mar 3 10:59:23 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * build.bat: Added for MS-DOS. + +Fri Mar 1 23:47:57 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * scm.texi (Line Editing): html-linked readline and editline ftp + sites. + + * build.scm: Added support for edline. + +Wed Feb 28 23:39:55 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * build.scm (build:build): library field `supress-files' added. + Used for supressing "findexec.c" when DLD is present. + +Sun Feb 25 00:29:47 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * scm.c (scm_find_impl_file): Tries hard to find Init.scm in + implementation vicinity. + (scm_try_path scm_cat_path): used by scm_find_impl_file. + (main): Changed to use scm_find_impl_file() and free pathnames + before exit. + +Wed Feb 21 23:27:43 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * findexec.c (dld_find_executable): extracted from DLD for + general use. + +Tue Feb 20 00:08:29 1996 Jochen Schwarze <schwarze@isa.de> + + * Init.scm (*vicinity-suffix*): Now includes #\/ for MSDOS, + etc. (GCC support). + (library-vicinity): Now set from implementation-vicinity if + environment variable SCHEME_LIBRARY_PATH is not defined. + + * scm.c (SYSTNAME): not redefined with DJGPP (both MSDOS and + unix). + +Sun Feb 18 09:29:57 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * subr.c (divbigint): fixed sign bug for 0 return value. + +Sun Feb 18 00:29:43 1996 Per Bothner <bothner@cygnus.com> + + * gsubr.c (gsubr_apply): elided gratuitous make_vector call. + +Sat Feb 17 11:50:41 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * Init.scm (*features*): string-case added. + (string-upcase string-downcase string-capitalize): added. + + * unif.c (strcap): string-capitalize! + + * sys.c (sysintern): Now looks for (and uses) symbol already + created. This will eliminate order of linking and loading + dependencies. + +Tue Sep 26 20:37:25 1995 Aubrey Jaffer (jaffer@jacal) + + * scm.texi (Evaluation): Enlarged description to include type + folding. + (Cells): Split Node Cells into Header, Subr, Ptob, and Smob Cells. + +Fri Sep 22 22:31:13 1995 Aubrey Jaffer (jaffer@jacal) + + * scm.c scmfig.h (WINDOWS_NT): support added. But what flag does + Windows NT #define? + +Sun Sep 10 13:37:44 1995 Aubrey Jaffer (jaffer@jacal) + + * repl.c (scm_stack_trace): Added Scheme call "stack-trace" to + print stack from exception handlers. + (everr): Now processes all exceptions before longjmping to + rootcont #ifdef CAUTIOUS. + + * Init.scm (user-interrupt): If stack-trace available, prints + stack-trace and enters breakpoint. + (break): Autoloaded. + +Mon Aug 7 12:52:15 1995 Aubrey Jaffer (jaffer@jacal) + + * scm.h (stacktrace): now a sys_protect. + + * subr.c (ilength): differentiated negative return codes; + non-terminating returns -1, not a list -2. + +Sat Aug 5 18:50:11 1995 Aubrey Jaffer (jaffer@jacal) + + * repl.c (scm_print_stack): added. Called by def_err_response. + + * eval.c (ceval): SCM stacktrace variable maintained and saved + in CONT(cont)->other.stacktrace. Under CAUTIOUS flag, + checkargs1 label added to check special single argument calls. + +Wed Jul 26 23:26:21 1995 Aubrey Jaffer (jaffer@jacal) + + * repl.c (char_readyp): Now looks for BUF0 flag to determine if + input_waiting() possible. + + * scm.c (init_scm run_scm main): BUF0 flag now set on cur_inp + to indicate whether CHAR-READY? will work. + +Wed Jul 19 13:25:01 1995 Shigenobu Kimura <skimu@komachi.phys.s.u-tokyo.ac.jp> + * dynl.c (l_dyn_main_call): Arguments to main (in DLD section) + were reveresed! Added hpux l_dyn_main_call. + +Sat Jul 8 22:23:03 1995 Aubrey Jaffer (jaffer@jacal) + + * Init.scm (scm:load): Internal define dependency problem fixed. + Variable *interactive* set for invocation without options. + + * scm.texi: Guile WWW and citation added. + + * subr.c: logical (2's complement) operations rewritten to now + work with bignums. Logical procedure names changed to conform + with Guile convention. + +Fri Jun 9 13:47:58 1995 Aubrey Jaffer (jaffer@jacal) + + * continue.c (stack_size): + (make_root_continuation): + (make_continuation): + (free_continuation): + (throw_to_continuation): moved from sys.c to make possible library + module. + + * continue.h: created from setjump.h + + * scm.texi (Compiling And Linking): Documented l_dyn_main_call. + (Type Conversions): added rope.c documentation. + (Callbacks): split from "Calling Scheme From C". + (Continuations): Rewritten to describe new "continue.c" + +Fri May 19 01:32:12 1995 Aubrey Jaffer (jaffer@jacal) + + * *.c: converted applicable uses of makfromstr with strlen to + makfrom0str. + + * rope.c: new + (scm_addr): added. + (num2long num2ulong num2ushort num2uchar ulong2num long2num): + moved from scl.c and elsewhere. + (makfromstrs makfrom0str makfromstr): moved from sys.c and posix.c + (must_free_argv): new + (scm_ldprog scm_ldfile scm_ldstr scm_evstr): moved from repl.c + (makargvfrmstrs): chopped out of i_execv in ioext.c. + makargvfrmstrs isn't really done correctly; it is GC leaky. + It should return a SMOB which can be GCed, but this makes this + C interface harder to use. + + * dynl.c (l_dyn_main_call): added procedure to call + dynamically linked procedure with string arguments converted + to argv and argc. Written only for DLD. Needs to be repeated + for other dynamic linking regimes. + +Tue Apr 25 10:24:42 1995 Aubrey Jaffer (jaffer@jacal) + + * subr.c (make_string): Was silently failing for illegal 2nd args! + +Sat Apr 15 23:18:47 1995 Aubrey Jaffer (jaffer@jacal) + + * Link.scm (catalog:add-link): When feature is already in catalog, + will only add new feature association to catalog if file exists. + +Sun Apr 9 22:59:46 1995 Aubrey Jaffer (jaffer@jacal) + + * repl.c (repl_driver): Now closes load port when ABORTing. + +Sat Apr 8 21:35:43 1995 Aubrey Jaffer (jaffer@jacal) + + From: Tom Lord <lord@cygnus.com> + * scm.texi: + Tcl Facilities:: Mutual calling between Tcl and Scheme. + Tk Facilities:: Accessing Tk from Scheme. + Gwish:: A Wish-like application of Guile. + System Calls:: Psst. Wanna write a manual section? + Gscsh:: Shell and systems programming features. + + From: chen@adi.com (Franklin Chen) + * scm.c (l_raise): uses raise() ifdef STDC_HEADERS, otherwise + kill(). + + From: Radey Shouman <shouman@ccwf.cc.utexas.edu> + * scl.c (istr2int): Fixed complaints of overflow on octal numbers + >= 2^BITSPERDIGIT. Patch should make this work for all radix 2 <= + radix <= 16. + (num2ulong): Makes it work for negative bignum argments, and + adds an overflow check. + + * ramap.c unif.c: There are several places in ramap.c, and + raprin1() in unif.c, where I had assumed that an ivect or uvect + elt would be representable no larger than an INUM. This patch + should fix these, also adding overflow checking for array + arithmetic on uvects and ivects. + + Also, fixes aref, which assumed that if its argument was a smob + that it was an array. Changes cvref to return a real number when + the imaginary part of an elt is 0. + +Sat Mar 25 20:37:48 1995 Aubrey Jaffer (jaffer@jacal) + + From: Don Bennett <dpb@netcom.com> + * rgx.c: rewritten and extended. The compile function now takes a + string of optional flags. New operations specific to the GNU + regex library is conditionalized with _GNU_SOURCE. + + From: Radey Shouman <shouman@ccwf.cc.utexas.edu> + * Iedline.scm ((make-edited-line-port)): + * edline.c (lreadline): Added Gnu `readline' input editing + (get ftp.sys.toronto.edu:/pub/rc/editline.shar). + + * unif.c (ra2contig): Fix a nasty bug ra2contig() (used for + UNIFORM-ARRAY-WRITE / READ!) that produced arrays with undersized + contents vectors. + + * eval.c (apply): Fix so that (APPLY <cclo> '()) works properly. + + * gsubr.c (make_gsubr): Give the arg number ASSERTion the right + sense. + (gsubr_apply): Add an ASSERTion to check for too many arguments. + (gsubr_apply): Take the address of the temporary vector, so as to + prevent its being optimized away and allowing gc of the vector. + (This happened with Cray cc in the MAP and FOR-EACH code; I'm no + longer able to find out if it would happen there.) + +Thu Mar 23 23:22:59 1995 Aubrey Jaffer (jaffer@jacal) + + * scm.texi (I/O-Extensions): Finished. + + * Init.scm (scm:load): `loading' messages now indented. + +Sat Mar 4 20:58:51 1995 Aubrey Jaffer (jaffer@jacal) + + * scm.texi: documentation finished for "posix.c" and "unix.c". + + * posix.c (scm_getgroups): added. + + * posix.c (makfrom0str): According to glibc.info, some field in + structures like pwent may have NULL pointers. Changed makfrom0str + to return BOOL_F in this case. + +Thu Mar 2 12:52:25 1995 Aubrey Jaffer (jaffer@jacal) + + * time.c: CLKTCK set from CLOCKS_PER_SEC, if available. Metaware + HighC ported. + + * scm.h: USE_ANSI_PROTOTYPES now controls prototypes (was + __STDC__). This allows an overly fussy compiler to still have + __STDC__. + + From: dorai@ses.com (Dorai Sitaram) + * ioext.c (l_utime): include files fixed for __EMX__ + +Sun Feb 26 21:03:04 1995 Aubrey Jaffer (jaffer@jacal) + + * sys.c (gc_mark gc_sweep): tc7_ssymbol now gets GCed because it + gets used for non-GCed strings in scm_evalstr scm_loadstr. + (mkstrport cwos cwis): changed so caller's name is passed into + mkstrport(). + + * repl.c + (scm_eval_string scm_evalstr scm_load_string scm_loadstr): added + for easier C to scheme callbacks. + (loadport): variable added so lreadr() and flush_ws() + increment linum only when reading from the correct port. + (def_err_response): now handles ARGn for argument numbers > 5 and + unknown position arguments. + + * dynl.c: Dynamic Linking now sets and restores *load-pathname* + around the init_ call. + +Sat Feb 25 11:03:56 1995 Aubrey Jaffer (jaffer@jacal) + + * scm.c (lsystem getenv softtype ed vms_debug): moved from scl.c. + (add_feature): moved from repl.c. + (features): init table removed (caused multiple symbols). + +Fri Feb 24 23:48:03 1995 Aubrey Jaffer (jaffer@jacal) + + * scm.c (scm_init_extensions COMPILED_INITS): Added so that + statically linked, compiled code can be initialized *after* most + of Init.scm has loaded. + +Wed Feb 22 15:54:01 1995 Aubrey Jaffer (jaffer@jacal) + + * subr.c (append): Added check for bad arguments and fixed errobj. + +Sun Feb 19 01:31:59 1995 Aubrey Jaffer (jaffer@jacal) + + * ioext.c (exec execp): changed so that 2nd arguments is argv[0] + (like posix) and renamed to execl and execlp. + (execv execvp): added. + +Sat Feb 11 17:30:14 1995 Aubrey Jaffer (jaffer@jacal) + + * ioext.c (lexec): moved from repl.c and scm.c. + (lexecp i_exec l_putenv): added. + + * posix.c (open_pipe l_open_input_pipe l_open_output_pipe + prinpipe): moved from ioext.c. + (l_fork): added. + +Fri Feb 10 10:50:03 1995 Aubrey Jaffer (jaffer@jacal) + + * scl.c (num2long long2num): moved here from subr.c. + (num2ulong): fixed (< to >=) bug. + + * unif.c (aset array2list array_ref cvref): uniform integers and + unsigned integer arrays now handle full size integers (and + inexacts) using num2long, num2ulong, long2num, and ulong2num when + INUMS_ONLY is not defined. + + * scmfig.h (INUMS_ONLY): defined when INUMs are the only numbers. + +Sun Jan 29 23:22:40 1995 Aubrey Jaffer (jaffer@jacal) + + * scm.texi (Overview): scm.1 converted to texinfo format and + incorporated. + +Sun Jan 22 11:13:58 1995 Aubrey Jaffer (jaffer@jacal) + + * scm.texi (Internals): code.doc converted to texinfo format. + Much added and reorganized. code.doc removed. + +Thu Jan 19 00:40:11 1995 Aubrey Jaffer (jaffer@jacal) + + * subr.c (logbitp logtest): added. + +Wed Jan 11 14:45:17 1995 Aubrey Jaffer (jaffer@jacal) + + * scl.c (num2ulong): checks for bignum sign and magnitude added. + + * subr.c (logand logior logxor lognot): lognot restriction to + INUMs removed. Logand, logior, and logxor now will work for up to + 32 bit signed numbers. + +Tue Jan 10 13:19:52 1995 Aubrey Jaffer (jaffer@jacal) + + * repl.c (def_err_response): Circuitous call to quit() replaced + with exit(EXIT_FAILURE); + (everr): Now calls def_err_response() in interrupt frame if + errjmp_bad or there are dynwinds to do. This prevents silent + failure in batch mode. + +Mon Jan 9 00:12:14 1995 Aubrey Jaffer (jaffer@jacal) + + * scm.texi (Trouble Shooting): Section converted from README. + + * Init.scm (-d filename): option added which does: + (begin (require 'database-utilities) (open-database filename)) + + * repl.c (handle_it): Now discards possibly used top freelist cell + for GC safety. Also now just punts if errjmp_bad. + + * scm.texi: converted from MANUAL. GUILE documentation merged in. + +Tue Jan 3 15:09:36 1995 Aubrey Jaffer (jaffer@jacal) + + * scl.c (SYSTNAME): msdos changed to ms-dos. windows added. + archimedes changed to acorn. + + From: jon_seymour@vnet.ibm.com (jon seymour) + * scmfig.h: defined LACK_TIMES and STDC_HEADERS if __IBMC__ is + defined. + + * sys.c: #include <io.h> and #include <direct.h>. define ttyname() + macro. + + * scm.c: #include <io.h> and compile out execvp() call. + + * time.c: #include <sys/timeb.h> + + * makefile.os2: makefile for use with OS/2 toolkit nmake. + +Sun Jan 1 21:17:36 1995 Aubrey Jaffer (jaffer@jacal) + + * dynl.c Link.scm: names unified. Libraries for HP-UX fixed. + HP-UX dll suffix now ".sl". + + From: Shigenobu Kimura <skimu@komachi.phys.s.u-tokyo.ac.jp> * + dynl.c (fcall): Fixed dynamic linking on hp9000s700 (or 720) HP-UX + 9.01 or 9.03. + +Wed Dec 7 21:19:26 1994 Aubrey Jaffer (jaffer@jacal) + + * ioext.c (l_open_input_pipe, l_open_output_pipe): moved from + "Init.scm". + +Mon Dec 5 16:55:21 1994 Aubrey Jaffer (jaffer@jacal) + + * sys.c (i_setbuf0): added. + (open_file): `0' in mode string now controls the buffered-ness of + returned port. + + * Init.scm (slib:load-compiled): no longer silently fails if other + than the first argument does not link correctly. + + From: Robert Sanders <rsanders@hrothgar.mindspring.com> + * ioext.c (l_write_line): moved from "Init.scm". + +Sun Dec 4 21:47:08 1994 Aubrey Jaffer (jaffer@jacal) + + * sys.c (free_storage): lord@cygnus.com pointed out that candle + was being burnt from both ends. Loop fixed. Mallocs either + leaking or counted wrong. + +Sat Dec 3 22:32:59 1994 Aubrey Jaffer (jaffer@jacal) + + * code.doc: added description of compiled closures. + +Thu Nov 24 23:10:31 1994 Aubrey Jaffer (jaffer@jacal) + + * socket.c (l_socketpair): added. Both make-stream-socketpair and + make-stream-socket now take optional prototype argument. + +Tue Nov 22 00:16:05 1994 Aubrey Jaffer (jaffer@jacal) + + * ramap.c (ramapc and friends): moved from unif.c to get source + file sizes below 64k. + +Mon Nov 21 00:44:32 1994 Aubrey Jaffer (jaffer@jacal) + + * posix.c (l_pwinfo grinfo): made to work like network inquiry + procedures (no args steps through entries). + (l_setgr l_setpw l_uname): added. + + From: Radey Shouman <shouman@ccwf.cc.utexas.edu> + * gsubr.c (make_gsubr gubr_apply): allows arbitrary (< 11) + required, optional, and rest arguments to compiled functions. + +Sun Nov 20 11:59:18 1994 Aubrey Jaffer (jaffer@jacal) + + * socket.c MANUAL: most Scheme names for socket functions changed + for consistency. + * socket.c (socket:shutdown): added. I can't imagine what use + shutdown provides. SOCKETs can be closed like any other port. + Should socket:shutdown SOCKETs be closed? Does having shutdown + sockets cause file descriptors to be reused? Socket:shutdown will + be removed if no use is found for it. + (tc16_sknm): added to encapsulate information retrieved from + getpeername and getsockname. + (socket-name:family socket-name:port-number socket-name:address): + added to retrieve information from tc16_sknm. + (inet:string->address inet:address->string inet:network + inet:local-network-address inet:make-address): added. + (gethost sethostent getnet getnetent getproto setprotoent getserv + setservent): inquiry procedures added. + + * sys.c (makfromstrs(argc, argv)): added. converts C array of + strings to SCM list of strings. If argc < 0, a null terminated + array is assumed. + +Sat Nov 19 00:20:58 1994 Aubrey Jaffer (jaffer@jacal) + + * eval.c (l_proc_doc): added procedure-documentation. + +Fri Nov 18 23:34:35 1994 Aubrey Jaffer (jaffer@jacal) + + * build.scm (scm:build): Added. Replaces system specific + makefiles. + * ccnfigdb.scm: Database of system specific compile, link, and + archive procedures and library information. + +Thu Oct 27 12:57:02 1994 Jerry D. Hedden <hedden@esdsdf.dnet.ge.com> + + * ioext.c: conditional code for vms and version (3.6) of Aztec C. + * pi.scm ((e digits)): Modified 'bigpi' for slight speed + improvement. Added function to calculate digits of 'e'. + +Wed Oct 26 11:22:05 1994 Gary Houston <ghouston@actrix.gen.nz> + + * scl.c (round): Now rounds as described in R4RS. + + * test.scm (test-inexact): test cases for round. + +Tue Oct 25 00:02:27 1994 Aubrey Jaffer (jaffer@jacal) + + * sys.c (grow_throw lthrow dynthrow): now pass arrays, check + for adequate growth, and clear out register windows (on sparc). + +Mon Oct 24 01:05:34 1994 Aubrey Jaffer (jaffer@jacal) + + * ioext.c (ttyname fileno): added. + +Sat Oct 22 12:12:57 1994 Aubrey Jaffer (jaffer@jacal) + + * unix.c (symlink readlink lstat): added. + + * scmfig.h repl.c sys.c (IO_EXTENSIONS): flag removed. + + * ioext.c (read-line read-line! file-position, file-set-position + reopen-file open-pipe opendir readdir rewinddir closedir chdir + umask rename-file isatty? access chmod mkdir rmdir stat utime + raise): moved from "repl.c" and "sys.c". + +Fri Oct 21 21:19:13 1994 Radey Shouman <shouman@ccwf.cc.utexas.edu> + + * unif.c (ra2contig): now has a second parameter to indicate + whether copying is necessary or not. Eliminates gratuitous copy + by UNIFORM-ARRAY-READ! when called with a noncontiguous array. + + (array_map): more liberal check on when ARRAY-MAP! can use + array-ified asubrs. + +Thu Oct 20 18:00:35 1994 Aubrey Jaffer (jaffer@jacal) + + * sys.c (opendir readdir rewinddir closedir reopen-file): added + under IO_EXTENSIONS. + +Wed Oct 19 14:18:26 1994 Aubrey Jaffer (jaffer@jacal) + + * eval.c (badargsp): added under ifndef RECKLESS to check @apply + and apply() arg counts. + +Tue Oct 18 00:02:10 1994 Aubrey Jaffer (jaffer@jacal) + + * unix.c (mknod acct nice sync): added. + + * socket.c (socket bind! gethost connect! listen! accept): added. + + * time.c (utime): added under IO_EXTENSIONS. + +Mon Oct 17 23:49:06 1994 Aubrey Jaffer (jaffer@jacal) + + * sys.c (getcwd umask access chmod mkdir rmdir): added + under IO_EXTENSIONS. + + * scm.c (l_pause): added if SIGALRM defined. + (l_sleep): added if SIGALRM not defined. + + * scl.c (num2ulong): added. Used in "time.c" + +Sun Oct 16 22:41:04 1994 Aubrey Jaffer (jaffer@jacal) + + * sys.c (access chmod): Posix access added under IO_EXTENSIONS. + +Fri Oct 14 09:45:32 1994 Aubrey Jaffer (jaffer@jacal) + + * posix.c (chown link pipe waitpid, kill, getpw, getgr, get*id, + set*id): added. + + * time.c (l_raise l_getpid): added + * subr.c (ulong2big): + * scl.c (ulong2num): useful routines for system call data + conversion moved from "time.c". + +Thu Sep 22 14:48:16 1994 Aubrey Jaffer (jaffer@jacal) + + * subr.c (big2inum): (more accruately) renamed from big2long. + +Mon Aug 29 11:36:46 1994 Radey Shouman <rshouman@hpcf.cc.utexas.edu> + + * unif.c: This is a large patch, but also a bit larger than it + appears -- I moved a few function definitions around to eliminate + gratuitous forward references. + + * unif.c repl.c (raprin1): Combined print routine for arrays with + that for uves. + + * unif.c (UNIFORM-VECTOR-READ! and -WRITE): work with general + arrays, by copying when necessary, renamed them to + UNIFORM-ARRAY-READ! and -WRITE. + + * unif.c (ARRAY-CONTENTS): Generalized so that it returns a 1-d + array even when the stride in the last dimension is greater than + one, gave it an optional second argument STRICT, which makes it + behave as it did before, returning an array/vector only if the + contents are contiguous in memory. + + * unif.c (ARRAY-CONTIGUOUS?) Eliminated. Instead, use + (lambda (ra) (array? (array-contents ra #t))) + + * unif.c code.doc (ramapc): unrolls arrays mapping into one loop + if possible, to make this quick, changed the format of the array + CAR, now uses one bit to indicate that an array is contiguous -- + this still allows a ridiculous number of dimensions. + + * scm.h (DSUBRF): dsubrs are mapped directly, to allow this I + moved the typedef for dsubr and #define for DSUBRF to scm.h + + * unif.c (ARRAY-MAP!) taught something about subrs, now most subrs + may be mapped without going through apply(), saving time and + reducing consing. +, -, *, /, =, <, <=, >, and >= are mapped + directly as special cases -- for uniform arrays this is nearly as + fast as the equivalent C, and doesnt' cons. I've made sure that + +, -, *, and / vectorize on the CRAY, this may be wasted effort + but the effort is not great. + + * unif.c (ARRAY-COPY!) now copies many arrays of differing types + to each other without going through the aref/aset, e.g. float -> + double, double -> complex, integer -> float ... This should make + array type coercions for arithmetic faster. + + * unif.c (TRANSPOSE-ARRAY) Added, which returns a shared array + that is the transpose of its first argument. I think this does + what an APL:TRANSPOSE would. + + * unif.c (ENCLOSE-ARRAY) Added, this returns an array that looks + like an array of shared arrays, the difference being that the + shared arrays are not actually allocated until referenced. + Internally, the contents of an enclosed array is another array. + The main reason for this is to allow a reasonably efficient + implementation of APL:COMPRESS, EXPAND, and INDEXING. In order to + actually make an array of shared arrays, just use ARRAY-COPY!. + + * unif.c (cvref): Created internal version of aref(), cvref() that + doesn't do error checking; Thus speeding things up. Profiling of + SCM running array code revealed that aref() was taking a + surprising fraction of the CPU time + + TO DO: + + The mechanism for looking up the vectorized functions is a little + kludgy, I was tempted to steal some of the CAR of the subr type to + encode an offset into a table of vectorized functions, but this + would make it more likely that dynamically loaded subrs lose thier + names. + + It is almost possible to write APL:+ and friends now, it is just + necessary to figure out the appropriate type of the returned array + and allocate it, and to promote scalar arguments to arrays (with + increments 0). + + This doesn't include vectorized REAL-PART, IMAG-PART, + MAKE-RECTANGULAR ... + + I think some C support for APL:REDUCE and maybe INNER-PRODUCT will + be needed for a reasonably fast APL.scm + + unif.c is getting quite big, time to split it up? + + +Mon Sep 5 22:44:50 1994 Aubrey Jaffer (jaffer@jacal) + + * Init.scm repl.c (quit): code was not using return values + correctly. + +Sun Aug 21 01:02:48 1994 Aubrey Jaffer (jaffer@jacal) + + * record.c (init_record): remaining record functions moved into C + code. + * eval.c sys.c: compiled closures now conditional under CCLO. + +Sat Aug 20 23:03:36 1994 rshouman@chpc.utexas.edu (Radey Shouman) + + * eval.c (ceval apply): + * sys.c (makcclo): tc7_cclo, compiled closures, now supported. + * record.c (init_record): C implementation of slib "Record"s using + CCLO. + * scm.h subr.c (QUOTIENT MODULO REMAINDER): fixes a bug for + bignums with DIGSTOOBIG defined. Also, changed the return type of + longdigs() to void, since that value is no longer used anywhere. + +Mon Aug 1 11:16:56 1994 Aubrey Jaffer (jaffer@jacal) + + * time.c (curtime): replaces get-universal-time. Other time + functions removed (SLIB support more complete). + + * subr.c (divbigbig): fixed (modulo -2177452800 86400) => 86400 + bug. Also added to test.scm. + +Sun Jul 24 16:09:48 1994 Aubrey Jaffer (jaffer@jacal) + + * dynl.c (init_dynl): *feature* dld:dyncm added for dynamically + (ldso) linked libc.sa and libm.sa (under Linux). + +Fri Jul 15 12:53:48 1994 Aubrey Jaffer (jaffer@jacal) + + * unif.c (array-fill!): bug with increment in default clause fixed. + Fast string support added. + + From: rshouman@chpc.utexas.edu (Radey Shouman) + * unif.c (array-fill! array-for-each): bug fixes. + +Sun Jul 10 01:51:00 1994 Aubrey Jaffer (jaffer@jacal) + + * scm.c (run_scm init_scm): "-a" heap allocation argument supported. + + * Makefile (proto.h): removed. + + From: Drew Whitehouse, Drew.Whitehouse@anu.edu.au + * scm.h (P): Conditionalized ANSI'fied version of the scm.h. + +Sun Jun 26 12:41:59 1994 Aubrey Jaffer (jaffer@jacal) + + * Link.scm (usr:lib lib): Now checks for shared libraries + (lib*.sa) first. + +Thu Jun 23 19:45:53 1994 Aubrey Jaffer (jaffer@jacal) + + * scl.c scm.c: Support for compilation under Turbo C++ for Windows + (system and exec disabled) added under C flag "_Windows". + +Sat Jun 18 11:47:17 1994 Aubrey Jaffer (jaffer@jacal) + + * test.scm ((test-delay)): added. + ((test-bignum)): added and called automatically if bignums + suported. test-inexact called automatically if inexacts + supported. + +Mon Jun 6 09:26:35 1994 Aubrey Jaffer (jaffer@jacal) + + * Init.scm (trace untrace): moved to SLIB/trace.scm. + +Thu May 12 00:01:20 1994 Aubrey Jaffer (jaffer@jacal) + + * Link.scm: Autoload for hobbit now does (provide 'hobbit). This + allows hobbit to know if it is self compiling (although reloads of + hobbit will not be quite right). + ((compile file . args)): removed. + + * makefile.unix (proto.h): removed. + + * Transcen.scm: compile-allnumbers HOBBIT declaration added. + Init.scm will now load compiled Transcen.o. + + * scm.h: HOBBIT section removed. + + * README (SLIB): Now strongly recommends getting SLIB and lists + ftp sites. + + * eval.c (m_delay): fixed bug with multiple sets of (delay x). + +Thu Apr 28 22:41:41 1994 Aubrey Jaffer (jaffer@jacal) + + * unif.c (makflo): shortcut for single precision float arrays + added. + +Fri Apr 15 00:54:14 1994 rshouman@chpc.utexas.edu (Radey Shouman) + + * unif.c: no longer uses pointer comparisons in loops. Should + fix problems on 8086 processors. + * unif.c (make_sh_array): Fixes MAKE-SHARED-ARRAY so that shared + arrays with only 1 element in some direction may still be + ARRAY-CONTIGUOUS? + (uve_write uve_read): Fixes bug in UNIFORM-ARRAY-WRITE, + UNIFORM-ARRAY_READ!. Now they do the right thing for shared + bit-arrays not starting at the beginning of their contents vector. + (array_contents ARRAY-SIMPLE?): ARRAY-CONTENTS may now return a + shared, contiguous, 1-d array, instead of a vector, if the array + cannot access all of the contents vector. ARRAY-SIMPLE? removed. + (array-fill!): a replacement and generalization of + UNIFORM-VECTOR-FILL!. + (raequal): Combines with uve_equal(), providing also ARRAY-EQUAL? + ARRAY-EQUAL? is equivalent to EQUAL? if all its arguments are + uniform vectors or if all are arrays. It differs from EQUAL? in + that a shared, 1-d array may be ARRAY-EQUAL? to a uniform vector. + for example + (define sh (make-shared-array '#(0 1 2 3) list '(0 1))) ==> #1(0 1) + (equal? '#(0 1) sh) ==> #F + (array-equal? '#(0 1) sh) ==> #T + (list2ura): Combines list2uve() and list2ura(). + +Thu Apr 14 23:26:54 1994 Aubrey Jaffer (jaffer@jacal) + + * time.c (LACK_FTIME LACK_TIMES): defined for vms. + +Mon Apr 4 10:39:47 1994 Aubrey Jaffer (jaffer@jacal) + + * eval.c (copytree): now copies vectors as well. + + * repl.c (quit): now accepts #t and #f values. + +Sun Apr 3 23:30:14 1994 Aubrey Jaffer (jaffer@jacal) + + * repl.c (repl): call to my_time() moved to not include READ time. + + * time.c (mytime): now prefers to use times() over clock(). + Compilation constant CLOCKS_PER_SEC doesn't scale when a binary is + moved between machines. + +Thu Mar 31 16:22:53 1994 Aubrey Jaffer (jaffer@jacal) + + * Init.scm (*SCM-VERSION*): added. + + * Makefile (intro): Added message for those who just make. + Cleaned up and reorganized Makefile. + + * patchlvl.h (PATCHLEVEL): removed. Whole version now just in + SCMVERSION. + +Wed Mar 23 00:09:51 1994 rshouman@chpc.utexas.edu (Radey Shouman) + + * repl.c (iprin1): Characters higher than 127 print as + #\<octal-number>. + + * Init.scm ((read:array digit port)): added. Most # syntax + handled in read:sharp. + + * unif.c (clist2uve clist2array): removed. + +Fri Mar 11 15:10:53 1994 Radey Shouman (rshouman@chpc.utexas.edu) + + * sys.c (sfgetc): can now return EOF. + +Mon Mar 7 17:07:26 1994 Aubrey Jaffer (jaffer@jacal) + + * patchlvl.h (SCMVERSION): 4e0 + + * scmfig.h: was config.h (too generic). + + * scm.c (main run_scm) repl.c (repl_driver init_init): now take + initpath argument. IMPLINIT now used in scm.c + +Sun Feb 27 00:27:45 1994 Aubrey Jaffer (jaffer@jacal) + + * eval.c (ceval m_cont IM_CONT): @call-with-current-continuation + special form for tail recursive call-with-current-continuation + added. call_cc() routine removed. + +Fri Feb 25 01:55:06 1994 Aubrey Jaffer (jaffer@jacal) + + * eval.c (ceval m_apply IM_APPLY apply:nconc-to-last): @apply + special form for tail-recursive apply added. ISYMs reactivated. + +Mon Feb 21 14:42:12 1994 Aubrey Jaffer (jaffer@jacal) + + * crs.c (nodelay): added. In NODELAY mode WGETCH returns + eof-object when no input is ready. + + * Init.scm ((read:sharp c port)): defined to handle #', #+, and + #-. + + * repl.c (lreadr): Now calls out to Scheme function read:sharp + when encountering unknown #<char>. + +Tue Feb 15 01:08:10 1994 Shiro KAWAI <kawai@sail.t.u-tokyo.ac.jp> + + * eval.c (ceval apply): under flag CAUTIOUS, checks for applying + to non-lists added. + +Sat Feb 12 21:23:01 1994 Aubrey Jaffer (jaffer@jacal) + + * sys.c (sym2vcell intern sysintern): now use internal strhash(). + + * scl.c sys.c (hash hashv hashq strhash()): added. + +Sat Feb 5 01:24:35 1994 Aubrey Jaffer (jaffer@jacal) + + * scm.h (ARRAY_NDIM): #define ARRAY_NDIM NUMDIGS changed to + #define ARRAY_NDIM(x) NUMDIGS(x) to correct problem on Next. + +Fri Feb 4 23:15:21 1994 rshouman@chpc.utexas.edu (Radey Shouman) + + * unif.c: 0d arrays added. Serial array mapping functions and + ARRAY-SIMPLE? added. + +Thu Feb 3 12:42:18 1994 Aubrey Jaffer (jaffer@jacal) + + * scm.h (LENGTH): now does unsigned shift. + +Wed Feb 2 23:40:25 1994 Aubrey Jaffer (jaffer@jacal) + + * Link.scm (*catalog*): catalog entries for db (wb), + turtle-graphics, curses, regex, rev2-procedures, and + rev3-procedures added. + +Sun Jan 30 19:25:24 1994 rshouman@chpc.utexas.edu (Radey Shouman) + + * sys.c eval.c setjump.h setjump.s (longjump setjump): full + continuations now work on Cray YMP. + +Thu Jan 27 01:09:13 1994 Aubrey Jaffer (jaffer@jacal) + + * dynl.c MANUAL Init.scm (init_dynl): dynamic linking modified for + modern linux. + +Sat Jan 22 17:58:55 1994 Aubrey Jaffer (jaffer@jacal) + + From: ucs3028@aberdeen.ac.uk (Al Slater) + * makefile.acorn repl.c (set_erase): Port to acorn archimedes. + This uses Huw Rogers free unix function call library for the + archimedes - this is very very widely available and should pose no + problem to anyone trying to find it - its on every archimedes ftp + site. + + From: hugh@cosc.canterbury.ac.nz (Hugh Emberson) + * dynl.c Link.scm: Dynamic Linking with SunOS. + +Thu Jan 6 22:12:51 1994 (jaffer at jacal) + + * sys.c (gc_mark mark_locations): now externally callable. + +Sun Jan 2 19:32:59 1994 fred@sce.carleton.ca (Fred J Kaudel) + + * unif.c (ra_matchp ramapc): patch to unif.c avoids two problems + (K&R C does not allow initialization of "automatic" arrays or + structures). This was not use in 4d2 or previously, and the + following patch ensures that such initialization only occurs for + ANSI C compilers (Note that K&R C compilers need to explicitly + assign the values). + +Sat Dec 18 23:55:30 1993 (jaffer at jacal) + + * scm.1 scm.doc (FEATURES): improved and updated manual page. + + * repl.c (BRACKETS_AS_PARENS): controls whether [ and ] are read + as ( and ) in forms. + +Wed Dec 8 23:13:09 1993 rshouman@chpc.utexas.edu (Radey Shouman) + + * unif.c: More array fixes and functions. + +Tue Dec 7 00:44:23 1993 (jaffer at jacal) + + * dynl.c (dld_stub): removed since dld is working better on Linux. + +Wed Dec 1 15:27:44 1993 (jaffer at jacal) + + * scm.h (SNAME): explicit cast added to get rid of compiler + warnings. + + From: bh@anarres.CS.Berkeley.EDU (Brian Harvey) + * repl.c (repl) output newlines when more than one form on a line + for Borland C. + + From: rshouman@chpc.utexas.edu (Radey Shouman) + * unif.c: More array fixes and documentation. + +Mon Nov 29 01:06:21 1993 rshouman@chpc.utexas.edu (Radey Shouman) + + * unif.c: More array functions (need documentation). + +Sun Nov 28 01:34:22 1993 (jaffer at jacal) + + * scm.h (SNAME): returns a pointer to nullstr if offset is 0. + + * subr.c eval.c (make_synt make_subr): now check that offset from + heap_org hack works for each subr. If not, 0 is used. + + * Link.scm (compile-file): compiles SCM file to object suitable + for LOAD. + + * Link.scm: initialization file created with Scheme code for + compilation and linking. LOAD now automatically loads SCM object + files. + + * dynl.c Init.scm: dynamic linking now works under DLD on Linux. + Wb, crs, and sc2 can by dynamically loaded. + +Thu Nov 25 22:58:36 1993 (jaffer at jacal) + + * sys.c (ltmpnam): return value of mktemp call tested in accord + with HP-UX documentation (returns "" on error). + + * config.h (SYSCALLDEF): removed. Macro I/O calls (getc, putc) + replaced with function versions. Control-C interrupts should work + while pending input on all systems again. + +Tue Nov 23 01:18:35 1993 dorai@cs.rice.edu (Dorai Sitaram) + + * repl.c sys.c time.c config.h: MWC (Mark Williams C) support. + +Sun Nov 7 10:58:53 1993 "Greg Wilson" <Greg.Wilson@cs.anu.edu.au> + + * scm.c config.h (TICKS ticks tick-interrupt): if TICKS is + #defined, ticks and tick-interrupt work like alarm and + alarm-interrupt, but with units of evaluation rather than units of + time. + +Mon Nov 1 18:47:04 1993 (jaffer at jacal) + + * unif.c (uniform-vector-ref => array-ref): integrated arrays + with uniform-vectors. Strings, vectors, and uniform-vectors + now just special case of arrays (to the user). + +Fri Oct 29 01:26:53 1993 (jaffer at jacal) + + * unif.c (rasmob tc16_array): arrays are now a smob. + +Thu Oct 28 01:21:43 1993 (jaffer at jacal) + + * sys.c repl.c (igc gc_start): GC message gives reason for GC. + +Wed Oct 27 10:03:00 1993 (jaffer at jacal) + + * config.h (SICP): flag makes (eq? '() '#f) and changes other + things in order to make SCM more compatible with Abelson and + Sussman's book. + + * sys.c (gc_mark gc_sweep mark_locations): GC bug fixed. GC from + must_malloc would collect the tc_free_cell already allocated. + + * sys.c setjump.h (must_malloc must_realloc INIT_MALLOC_LIMIT): + modified to call igc when malloc usage exceeds mtrigger (idea from + hugh@ear.MIT.EDU, Hugh Secker-Walker). + + From: Jerry D. Hedden + * pi.scm (bigpi): bignum version of pi calculator. + +Tue Oct 26 18:41:33 1993 (jaffer at jacal) + + * repl.c (room): added procedure for printing storage statistics. + +Sun Oct 24 22:40:15 1993 (jaffer at jacal) + + * config.h eval.c scl.c (STACK_LIMIT CHECK_STACK): added. + * sys.c (stack_check): added. + +Sat Oct 23 00:08:30 1993 (jaffer at jacal) + + * sys.c (mallocated): added to keep track of non-heap usage. + + * sys.c (igc): fixed interrupt vulnerabilities around gc. + +Sun Oct 17 13:06:11 1993 (jaffer at jacal) + + * repl.c (exit_report): added. Prints cumulative times if + (verbose > 2). Called from free_storage(). + + * repl.c (repl): fixed CRDYP(stdin) BUG! Transcripts should work + again. Other annoying CR behaviour fixed. + + * time.c (init_time your_base my_base): now not reset when + restarting so timing numbers for restarting are correct. + + * scm.h (sys_protects): rearranged. + * sys.c (tmp_errp): now a statically allocated global variable, + used by init_storage and free_storage. + * scm.h sys.c (tc16_fport, tc16_pupe, tc16_strport, tc16_sfport): + now #defines (which must correspond to order of newptob calls). + +Sun Oct 3 20:38:09 1993 Bryan O'Sullivan (bos@scrg.cs.tcd.ie) + + * README.unix configure configure.in scmconfig.h.in + mkinstalldirs Makefile.in acconfig-1.5.h: SCM can now be built + using GNU autoconf. Put in scmconfig4c5.tar.gz + +Sun Oct 3 00:33:57 1993 (jaffer at jacal) + + * MANUAL (bit-count bit-position bit-set*! bit-count* + bit-invert!): (from unif.c) are now documented. + + * sys.c (fixconfig): added 3rd argument to distinguish between + setjump.h and config.h. + * setjump.h config.h: moved IN_SYS stuff from config.h to + setjump.h. + * config.h (HAVE_CONFIG_H): User config preferences now taken + from "scmconfig.h" if HAVE_CONFIG_H is defined. + * config.h (EXIT_SUCCESS EXIT_FAILURE): fixed for VMS. + +Sat Oct 2 00:34:38 1993 rshouman@hermes.chpc.utexas.edu (Radey Shouman) + + * unif.c repl.c: added read and write syntax for uniform vectors. + * unif.c (uniform-vector->list list->uniform-vector): created. + * time.c (time_in_msec): conditionalized for wide range of CLKTCK + values. + * config.h (BITSPERDIG POINTERS_MUNGED) + * scm.h (PTR2SCM SCM2PTR) + * scl.c (DIGSTOOBIG) + Ported SCM to Unicos, the Cray operating system. + + From: schwab@ls5.informatik.uni-dortmund.de (Andreas Schwab) + * scl.c (dblprec): set from DBL_DIG, if available. + +Fri Oct 1 21:43:58 1993 (jaffer at jacal) + + * unif.c (bit-position): now returns #f when item is not found. + Now returns #f when 3rd argument is length of 2nd argument + (instead of error). + +Fri Sep 24 14:30:47 1993 (jaffer at jacal) + + * sys.c (free_storage): fixed bug where growth_mon was being + called after the port cell had been freed. gc_end now also + called at end. + +Tue Sep 21 23:46:05 1993 (jaffer at jacal) + + * Init.scm scm.c: Restored old command line behaviour (loading all + command line arguments) for case when first command line argument + does not have leading `-'. + + * sys.c (mode_bits): abstracted from open_file and mksfpt. + + * scm.h (*FPORTP): series of predicates added for operations which + only work on some fports. + + * sys.c crs.c: ungetc removed from ptobfuns structure and + soft-ports. + +Mon Sep 20 23:53:25 1993 (jaffer at jacal) + + * sys.c (make-soft-port): Soft-ports added, allowing Scheme + i/o extensions. + +Sun Sep 19 22:55:28 1993 (jaffer at jacal) + + * 4c4: released. + * Init.scm scm.c scm.1: command line proccessing totally + rewritten. Thanks to Scott Schwartz + <schwartz@groucho.cs.psu.edu> for help with this. + +Mon Sep 13 21:45:52 1993 pegelow@moorea.uni-muenster.de (Ulrich Pegelow) + + * scl.c (add1): finally a way to fool optimizing gcc to not use + extra precision registers. + +Sun Sep 12 18:46:02 1993 (jaffer at jacal) + + * sys.c (pwrite): added to stubbify fwrite to fix bug on VMS. + * config.h: moved flags to top per suggestions from Bryan + O'Sullivan (bos@scrg.cs.tcd.ie). + +Fri Sep 10 11:42:27 1993 (jaffer at jacal) + + * repl.c config.h (EXIT_SUCCESS EXIT_ERROR): added. Values + returned by SCM program. + +Thu Sep 9 13:09:28 1993 Vincent Manis <manis@cs.ubc.ca> + + * sys.c (stwrite init_types add_final): fixed declarations. + +Mon Sep 6 16:10:50 1993 Bryan O'Sullivan (bos@scrg.cs.tcd.ie) + + * README: changed the build and installation instructions to bring + them up to date with reality. + +Sun Sep 5 23:08:54 1993 Bryan O'Sullivan (bos@scrg.cs.tcd.ie) + + * Wrote autoconf script to support GNU Autoconf configuration + to make scm easier to build. + + * Created Makefile.in; a radical overhaul of Makefile to remove + some of the brokenness and allow cross-compilation and use of + autoconf. + +Sat Sep 4 23:00:49 1993 (jaffer at jacal) + + * 4c3: released. + * sys.c (grow_throw): removed use of memset for SPARC machines. + +Sat Sep 4 18:09:59 1993 Bryan O'Sullivan (bos@scrg.cs.tcd.ie) + + * time.c: added SVR4 to the list of LACK_FTIME systems, because + most all SVR4 BSD-compatibility stuff is a total mess. + + * config.h: changed definition of STDC_HEADERS so it does the + Right Thing on systems which run GCC but don't have header files + with prototypes. + + * makefile.unix: added a note for SVR4 users. + +Tue Aug 31 18:30:53 1993 (jaffer at jacal) + + * eval.c (m_define): if verbose >= 5 warnings are issued for all + top-level redefinitions. + +Mon Aug 30 16:24:26 1993 (jaffer at jacal) + + * scm.c sys.c (finals num_finals add_final): Finalization calls + now dynamically, incrementally, defined. + +Thu Aug 26 12:38:27 1993 Aubrey Jaffer (jaffer at camelot) + + * 4c2: fixed declaration problems in PTOB with K&R C. + +Sun Aug 22 23:02:51 1993 (jaffer at jacal) + + * split.scm: code which directs input, output, and diagnostic + output to separate windows (using curses functions defined in + crs.c). + +Sat Aug 21 16:46:33 1993 (jaffer at jacal) + + * Init.scm (output-port-height): added if not already defined. + output-port-width also made conditional. + + * sys.c (tc16_strport): string ports created. + +Thu Aug 19 11:37:07 1993 (jaffer at jacal) + + * sys.c (init_types): freecell, floats, and bignums now have SMOB + entries. gc_sweep and gc_mark still inline codes for bignums and + floats. + + * sys.c repl.c code.doc: Ports now an extensible type. + Indirection suggested by Shen <sls@aero.org>. + +Mon Aug 16 01:20:26 1993 (jaffer at jacal) + + * crs.c: curses support created. + +Sun Aug 15 16:56:36 1993 (jaffer at jacal) + + * rgx.c sys.c (mark0 equal0): mark0 moved to sys.c. equal0 + created. + +Fri Jun 25 01:16:31 1993 (jaffer at jacal) + + * QUICKREF: added. + +Tue Jun 22 00:40:58 1993 Aubrey Jaffer (jaffer at camelot) + + * repl.c (ungetted): replaced with CRDYP(stdin) to fix recently + introduced transcript bug. + +Sun Jun 20 22:29:32 1993 Aubrey Jaffer (jaffer at camelot) + + * config.h (NOSETBUF): setbuf() now conditionalized on NOSETBUF. + + * Init.scm (defmacro): now copies the results of macro expansion + in order to avoid capture of memoized code by macros like: + (defmacro f (x) `(list '= ',x ,x)). + +Wed Jun 2 23:32:05 1993 Aubrey Jaffer (jaffer at caddr) + + * eval.c (map for-each): now check that arguments are lists. + +Mon May 31 23:05:19 1993 Aubrey Jaffer (jaffer at camelot) + + * Init.scm (trace untrace): now defmacros which handle (trace) and + (untrace) as in Common Lisp. + +Wed May 5 01:17:37 1993 Roland Orre <orre@sans.kth.se> + + * all: internal output functions now take SCM ports instead of + FILE* in preparation for string-ports. + +Tue May 4 17:49:49 1993 Aubrey Jaffer (jaffer at wbtree) + + * makefile.unix (escm.a): created scm "ar" file and used for + dbscm. + +Sun Apr 25 21:35:46 1993 Aubrey Jaffer (jaffer at camelot) + + * sys.c (free_storage): i++ moved out of CELL_* in response to: +From: john kozak <jkozak@cix.compulink.co.uk> +Minor bug report: around line 10 of routine "free_storage" you do calls +to CELL_UP and CELL_DOWN with arguments having side-effects: with the +PROT386switch defined in config.h these args are evaluated twice... + +Sun Apr 11 22:56:19 1993 Aubrey Jaffer (jaffer at camelot) + + * eval.c (IM_DEFINE): added. Internal defines are no longer + turned into LETRECS. + +Wed Apr 7 13:32:53 1993 Jerry D. Hedden <HEDDEN@ESDSDF.dnet.ge.com> + + * scl.c (idbl2str): fix for bug introduced by removing +'s. + +Tue Mar 23 15:37:12 1993 Aubrey Jaffer (jaffer at camelot) + + * scl.c (idbl2str): now prints positivie infinity as +#.# again + (instead of #.#). + +Mon Mar 22 01:38:02 1993 Aubrey Jaffer (jaffer at montreux) + + * subr.c (quotient): renamed to lquotient to avoid conflict with + HP-UX 9.01. + +Fri Mar 19 01:21:08 1993 Aubrey Jaffer (jaffer at camelot) + + * sys.c repl.c: #ifndef THINK_C #include <sys/ioctl.h> + * time.c (lstat): #ifndef THINK_C. ThinkC 5.0.1 lacked. + +Mon Mar 15 23:35:32 1993 jhowland@ariel.cs.trinity.edu (Dr. John E. Howland) + + * scl.c (idbl2str iflo2str big2str): leading + eliminated on + output and number->string. + +Wed Mar 10 00:58:32 1993 Aubrey Jaffer (jaffer at camelot) + + * repl.c scm.h (CRDYP CLRDY CGETUN CUNGET): cleaned up ungetc hack. + + * scm.c repl.c (exec): added. + +Sun Mar 7 22:44:23 1993 Aubrey Jaffer (jaffer at camelot) + + * repl.c (def_err_response): now will print errobjs if they are + immediates, symbols, ports, procedures, or numbers. + +Fri Mar 5 23:15:54 1993 Aubrey Jaffer (jaffer at camelot) + + * repl.c (repl): now gives repl_report() for initialization. + + * Init.scm (defvar): added. + + From: Roland Orre <orre@sans.kth.se> + * repl.c (lungetc): no longer calls ungetc. Fixed problem that + many systems had with ungetc on unbuffered ports (setbuf(0)). + +Thu Mar 4 13:51:12 1993 Stephen Schissler + + * makefile.wcc: Watcom support added. + +Wed Mar 3 23:11:08 1993 Aubrey Jaffer (jaffer at montreux) + + * sys.c scm.h (dynwinds): made a sys_protect. + +Mon Feb 15 11:30:50 1993 Aubrey Jaffer (jaffer at camelot) + + * Init.scm (defmacro macroexpand macroexpand1 macro? gensym): + added. + + * repl.c (stdin): setbuf not done for __TURBOC__==1. + + * makefile.bor: now has method to build turtegr.exe. + + * eval.c (ceval): Memoizing macros now can return any legal Scheme + expression. + +Sat Feb 13 18:01:13 1993 Aubrey Jaffer (jaffer at camelot) + + * subr.c (mkbig adjbig): now check for bignum size. + + * Init.scm: reorganized so site-specific information is at the + head. + + * repl.c (errno): changed from set-errno now returns value. + + * subr.c (intexpt): now handles bignum exponents. + + From: "David J. Fiander" <davidf@golem.waterloo.on.ca> + * time.c makefile.unix subr.c: SCO Unix and XENIX patches. + +Fri Feb 12 22:18:57 1993 Aubrey Jaffer (jaffer at camelot) + + * Init.scm (WITH-INPUT-FROM-PORT WITH-OUTPUT-TO-PORT + WITH-ERROR-TO-PORT): added. + + * subr.c (ash): fixed for case (ash 2 40) where INUM arguments + make a bignum result. + + * repl.c (lreadr): \ followed by a newline in a string is ignored. + + From: Scott Schwartz <schwartz@groucho.cs.psu.edu> + * repl.c (lreadr): Can now read \0\f\n\r\t\a\v in strings. + +Thu Feb 11 01:25:50 1993 Aubrey Jaffer (jaffer at camelot) + + * Init.scm (with-input-from-file with-output-to-file + with-error-to-file): now use dynamic-wind. + +Sun Feb 7 22:51:08 1993 Aubrey Jaffer (jaffer at camelot) + + * eval.c (ceval): fixed bug with non-memoizing macro returning an + IMP. + +Sat Feb 6 01:22:27 1993 Aubrey Jaffer (jaffer at camelot) + + * (current-error-port with-error-to-file): add. + +Fri Feb 5 00:51:23 1993 Aubrey Jaffer (jaffer at camelot) + + * time.c (stat): added. + + From: rnelson@wsuaix.csc.wsu.edu (roger nelson) + * dmakefile: support for DICE C on Amiga. + +Thu Feb 4 01:55:30 1993 Aubrey Jaffer (jaffer at camelot) + + * sys.c (open-file) makes unbuffered if isatty. + + * repl.c (char-ready?) added. + +Mon Feb 1 15:24:18 1993 Aubrey Jaffer (jaffer at camelot) + + * subr.c (logor): changed to LOGIOR to be compatible with common + Lisp. + + * eval.c (bodycheck): now checks for empty bodies. + +Sun Jan 31 01:01:11 1993 Aubrey Jaffer (jaffer at camelot) + + * time.c (get-universal-time decode-universal-time): now use + bignums. + +Tue Jan 26 00:17:06 1993 Aubrey Jaffer (jaffer at camelot) + + * sys.c (mark_locations): now length argument in terms of + STACKITEM. Does both alignments in one pass. + +Mon Jan 25 12:13:40 1993 soravi@Athena.MIT.EDU + + * makefile.emx: for OS/2 + +Sun Jan 24 18:46:32 1993 stevev@miser.uoregon.edu (Steve VanDevender) + + * scl.c (big2str): now faster because it divides by as many 10s as + fit in a BIGDIG. + +Sat Jan 23 00:23:53 1993 stevev@miser.uoregon.edu (Steve VanDevender): + + * config.h (INUM MAKINUM): shift optimization for TURBOC. + +Fri Jan 22 00:46:58 1993 hanche@ams.sunysb.edu (Harald Hanche-Olsen) + + * unif.c (uniform-vector?): added. + +Tue Jan 19 00:27:04 1993 stevev@miser.uoregon.edu (Steve VanDevender) + + * subr.c scl.c config.h: bignum bug fixes for MSDOS. + +Mon Jan 18 01:15:24 1993 Aubrey Jaffer (jaffer at camelot) + + * subr.c (ash lognot intlength logcount bitextract): now handle + bignums. + +Sun Jan 17 10:42:44 1993 Aubrey Jaffer (jaffer at camelot) + + * sys.c (close_port): can now close pipes as well. + + * subr.c (adjbig normbig divide quotient): fixed more divide bugs. + + * subr.c (even? odd?): fixed problem with bignums. + +Sat Jan 16 00:02:05 1993 Aubrey Jaffer (jaffer at camelot) + + * subr.c (divbigbig): Fixed last divide bug? + +Fri Jan 15 00:07:27 1993 Aubrey Jaffer (jaffer at camelot) + + * rgx.c (regmatch?): added. Debugged for both HP-UX and GNU + regex-0.11. Documentation added to MANUAL. + +Thu Jan 14 11:54:52 1993 Aubrey Jaffer (jaffer at camelot) + + * patchlvl.h (SCMVERSION): moved from config.h. + + * scl.c (product): fixed missing {} bug. + + From: HEDDEN@esdsdf.dnet.ge.com + * scl.c (lmin lmax) bignum versions. + +Wed Jan 13 01:40:51 1993 Aubrey Jaffer (jaffer at camelot) + + * released scm4b0. + + * subr.c: fixed bignum bugs found by jacal. + + * code cleanup. + + From: HEDDEN@esdsdf.dnet.ge.com + * subr.c (lgcd quotent modulo lremainder): Bignum versions. + * subr.c (divbigbig): new version. + +Sun Jan 3 00:29:35 1993 stevev@miser.uoregon.edu (Steve VanDevender) + + * Re-port to BorlandC v2.0 + + * sys.c (must_realloc): added + + * config.h subr.c (BIGRAD pseudolong): now insensitive to ratio of + sizeof(long)/sizeof(BIGDIG). + +Mon Dec 21 23:20:47 1992 Aubrey Jaffer (jaffer at camelot) + + From: Scott Schwartz <schwartz@groucho.cs.psu.edu> + * rgx.c: created SCM interface to regex and regexp routines. + + From: HEDDEN@esdsdf.dnet.ge.com + * subr.c scl.c: Now just one mulbigbig and addbigbig routine. + + from: soravi@Athena.MIT.EDU + * README: directions for compiling SCM under OS/2 2.0. + +Wed Dec 9 15:34:30 1992 Aubrey Jaffer (jaffer at camelot) + + * eval.c (tc7_subr_2x): eliminated. All comparison subrs now + rpsubrs. + + * scm.h: Changed SUBR numbers. This improves HP-UX interpretation + speed (why?). + + * eval.c (PURE_FUNCTIONAL): removed. Can now be done in + initialization code. + + * eval.c (tc7_rpsubr): added type for transitive comparison + operators. Suprisingly, this slows down (pi 100 5). + +Mon Dec 7 16:15:47 1992 Aubrey Jaffer (jaffer at camelot) + + * subr.c (logand logor logxor lognot ash logcount integer-length + bit-extract): added. + + From: HEDDEN@esdsdf.dnet.ge.com + * scl.c: lots more numeric improvements and code reductions. + +Mon Nov 30 12:25:54 1992 Aubrey Jaffer (jaffer at camelot) + + * scm.h (IDINC ICDR IDIST): enlarged depth count in ILOCs. + +Sun Nov 29 01:10:18 1992 Aubrey Jaffer (jaffer at camelot) + + * subr.c scl.c: most arithmetic operations will now return + bignums. + + * config.h (FIXABLE POSFIXABLE NEGFIXABLE): added. + + * sys.c (object-hash object-unhash): now use bignums. + + * scl.c (big2str istr2int): bignum i/o implemented. + + * unif.c: subr2s were incorrectly initialized as lsubr2s. + +Tue Nov 24 14:02:52 1992 Aubrey Jaffer (jaffer at camelot) + + * eval.c (ceval): added unmemocar calls to error handling when + possible. + + * scl.c (idbl2str): added back NAN and infinity support. + + * eval.c (syntax_mem): replaced with individual macros. + * eval.c (procedure->syntax procedure->macro + procedure->memoizing-macro): All syntactic keywords are now + tc7_symbol. User definable macros added. + * sys.c: ISYMs no longer in symhash. ISYMs cannot be read. + init_isyms merged into init_eval. + +Sat Nov 21 00:39:31 1992 Aubrey Jaffer (jaffer at camelot) + + * makefile.unix (check): now exits with error code. + + * sys.c (init_isyms): eliminated. ISYMS now inited in init_eval. + +Fri Nov 20 16:14:06 1992 Aubrey Jaffer (jaffer at camelot) + + * released scm4a13 + + * repl.c: longjmps now dowinds() first. + + * setjump.h: now has all setjmp related definitions. + + * Init.scm (trace untrace): use new macro system. + + * eval.c (defined? procedure->macro procedure->memoizing-macro + make_synt): macro system added. defined? uses it. + + From: HEDDEN@esdsdf.dnet.ge.com + * scl.c: fixes for several transcendental functions. + +Thu Nov 19 01:14:38 1992 Aubrey Jaffer (jaffer at camelot) + + * repl.c sys.c: errjmp replaced with JMPBUF(rootcont). + +Sun Nov 15 01:49:00 1992 HEDDEN@esdsdf.dnet.ge.com + + * scl.c (istr2int istr2flo istring2number string2number): new + versions. + +Thu Nov 12 23:00:04 1992 Aubrey Jaffer (jaffer at Ivan) + + * Init.scm (load): now prints out actual filename found in mesasge + ;done loading ... + +Wed Nov 11 01:01:59 1992 Aubrey Jaffer (jaffer at camelot) + + * repl.c (def_err_response): ARG1 error with errobj==UNDEFINED + becomes WNA error. + + From: HEDDEN@esdsdf.dnet.ge.com (Jerry D. Hedden) + * scl.c (difference divide): Now are asubrs. + + * Init.scm (*features*): fixed to correspond to SLIB conventions. + +Mon Nov 9 12:03:58 1992 Aubrey Jaffer (jaffer at camelot) + + * scl.h test.scm: (string->number "i") and "3I" and "3.3I" fixed + to return #f. Tests added to test.scm. + +Fri Nov 6 16:39:38 1992 Aubrey Jaffer (jaffer at camelot) + + * scm.h (rootcont): sysprotect added. + + From: Vincent Manis <manis@cs.ubc.ca> + * scm.h: __cplusplus prototype support. + +Thu Nov 5 00:39:50 1992 Aubrey Jaffer (jaffer at Ivan) + + * eval.c (lookupcar): now checks for UNDEFINED in local bindings + becuase LETREC inits to UNDEFINED. + + * sys.c (dynamic-wind): added. + + * config.h eval.c (ceval): CAUTIOUS mode added. + + From: hugh@ear.MIT.EDU (Hugh Secker-Walker) + * eval.c (ceval): internal defines now transformed to letrecs. + +Sun Oct 25 12:27:23 1992 Aubrey Jaffer (jaffer at Ivan) + + * repl.c (read-line read-line!): created. + +Sat Oct 24 18:36:23 1992 Aubrey Jaffer (jaffer at camelot) + + * repl.c (lreadparen): now tail-recursive. + + * eval.c (copy-tree eval): added. dummy_cell replaced with a + cons(obj,UNDEFINED). + +Thu Oct 22 21:26:53 1992 Aubrey Jaffer (jaffer at Ivan) + + * repl.c (set-errno!): changed to set-errno. + +Thu Oct 15 00:49:20 1992 Aubrey Jaffer (jaffer at camelot) + + * sys.c (must_free): must_free created. Pointers are set to 0. + It detects objects being freed twice. + +Wed Oct 14 23:57:43 1992 Aubrey Jaffer (jaffer at camelot) + + * scm.c (run_scm): Now has INITS and FINALS. + + * scm.c (init_signals ignore_signals unignore_signals + restore_signals): siginterrupt() for ultix. + +Fri Oct 9 14:25:06 1992 Aubrey Jaffer (jaffer at camelot) + + * all: put in explicit casts to (unsigned char *) and (long) to + satisfy lint. + + * sys.c (gc): all to gc_end was during deferred interrupts, + causing problems with verbose=3 and interrupts during GC. + + * config.h(SYSCALLDEF): fixed so that test on errno occurs before + ALLOW_INTS (and possible call to user code). + +Sun Oct 4 01:45:25 1992 Aubrey Jaffer (jaffer at camelot) + + * eval.c (syntax_mem): removed gratuitous cons. + + * eval.c repl.c scm.h: Reduced static string use. Added peephole + optimizations for AND and OR. + + From: hugh@ear.MIT.EDU (Hugh Secker-Walker) + * eval.c repl.c scm.h (syntax_mem): syntax forms are now memoized + so that syntax checks are done only once. Interpreter is now + smaller and faster and uses less stack space. Modifications to + code are now made under DEFER_INTS as they always should have + been. + +Wed Sep 30 22:06:24 1992 Aubrey Jaffer (jaffer at Ivan) + + * scl.c subr.c scm.h config.h: Started adding bignum code. + +Sun Sep 27 22:59:59 1992 Aubrey Jaffer (jaffer at Ivan) + + * repl.c (restart): added. + + * sys.c (freeall): finished. + + * scm.h (tc7_symbol): split into tc7_ssymbol and tc7_msymbol to + distinguish between non-GCable and GCable symbols. + +Wed Sep 23 00:36:23 1992 Aubrey Jaffer (jaffer at Ivan) + + * repl.c (peek_char lungetc): added workaround for TURBOC 1.0 + problem with ungetc inside SYSCALLDEF macro. + + * repl.c (iprin1): uses ttyname for #<stream ..> if available. + + * Init.scm: now sets verbose to 0 if stdin or stdout is not a tty. + + * repl.c (isatty?): added. + + * repl.c (verbose): levels bumped up by 1. verbose == 0 means no + prompt. + + * makefile.djg config.h (GNUDOS -> GO32): flags changed for djgpp108. + +Wed Aug 26 21:46:26 1992 Aubrey Jaffer (jaffer at Ivan) + + * test.scm: put in (test #f < 1 3 2) and (test #f >= 1 3 2). + + * scl.c (leqp greqp): put back in. (not (< 1 3 2)) does not imply + (>= 1 3 2). + + * makefile.unix: tar and shar files now created in subdirectory. + + * config.h time.c: Linux support added. + + * repl.c: Greatly improved VMS interrupt support. + + * eval.c (ceval): I_LET now changes to I_LETSTAR for single clause + unnamed lets.y + + * (tc7_lsubr_2n): removed. + +Fri Jul 31 00:24:50 1992 Aubrey Jaffer (jaffer at Ivan) + + * unif.c (bit-position): fixed; I am sure I had done these + changes before. Also corrected some error messages. + + From: campbell@redsox.bsw.com (Larry Campbell) + * scm.h subr.c sys.c (equalp): smobfuns now include equalp. + +Mon Jul 20 16:44:30 1992 Aubrey Jaffer (jaffer at Ivan) + + From: Stephen Adams <S.R.Adams@ecs.southampton.ac.uk> + * eval.c scm.h subr.c (BOOL_NOT) macro added to fix ^ bug in + BorlandC. This was fixed previously as well. + + From: campbell@redsox.bsw.com (Larry Campbell) + * unif.c (vector-set-length!): was always typing to tc7_vector. + +Sat Jul 18 01:07:33 1992 Aubrey Jaffer (jaffer at Ivan) + + * subr.c sys.c (make_vector init_storage resizuve): mallocs and + reallocs are now always > 0. + + * time.c (get_univ_time): bypassed mktime() for (__TURBOC__ == 1). + +Mon Jul 13 22:27:04 1992 Aubrey Jaffer (jaffer at Ivan) + + * repl.c (lreadr): now ignores first line of port if begins with "#!" + + * scl.c (lesseqp greqp): removed; changed to use tc7_lsubr_2n. + + * scm.h eval.c (tc7_lsubr_2n): type added. Other subr types + rearranged. + +Sat Jul 11 23:47:18 1992 Aubrey Jaffer (jaffer at Ivan) + + * scm.h sys.c repl.c eval.c code.doc (newsmob smobs smobfuns): now + support dynamically added smob types. Promises moved to eval.c. + Promises and arbiters are now newsmobs. + + * makefile.unix repl.c scl.c (floprint): moved from repl.c to + scl.c. The only files which care about -DFLOATS are now scl.c, + eval.c, scm.c, and unif.c. + + * sys.c scm.h (init_storage): now uses variable num_protects + instead of #define NUM_PROTECTS. + +Tue Jul 7 00:00:57 1992 Ulf_Moeller@hh2.maus.de (Ulf Moeller) + + * Init.scm config.h makefile.prj: support for the ATARI-ST with + Turbo C added. + +Tue Jun 30 23:45:50 1992 Aubrey Jaffer (jaffer at Ivan) + + * unif.c (make-uniform-vector uniform-vector-set! + uniform-vector-ref): added. + +Tue Jun 23 11:49:13 1992 Aubrey Jaffer (jaffer at Ivan) + + * scm.h sys.c code.doc: rearranged tc7 codes and added bvect, + ivect, uvect, fvect, dvect, cvect, and cclo. + + * scm.h sys.c eval.c repl.c code.doc: Changed symbols to be + tc7_symbol. + +Sat Jun 6 22:27:40 1992 campbell@redsox.bsw.com (Larry Campbell) + + * scl.c (divide): divide by 0 and Exact-only divides of non + multiples now cause exception in RECKLESS mode. + +Wed May 27 16:02:58 1992 Aubrey Jaffer (jaffer at Ivan) + + * config.h scl.c (NUMBUFLEN): split into INTBUFLEN and FLOBUFLEN + and made proportional to size of numeric types. + + From: fred@sce.carleton.ca (Fred J Kaudel) + * makefile.ast scm.c Init.scm: minor chages for ATARI ST support. + + * test.scm (test-inexact): created. + +Thu May 21 11:43:41 1992 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 5 + + From: hugh@ear.mit.edu (Hugh Secker-Walker) + * config.h: better wording for heap allocation strategy + explanation. + +Wed May 20 00:31:18 1992 S.R.Adams@ecs.southampton.ac.uk + + * subr.c (stci_leqp st_leqp): reversed order of ^ clauses to avoid + Borland 3.0 bug. + + * sys.c (gc_sweep): missing i-=2; added when splicing out segment. + + * MANUAL time.c (get-universal-time decode-universal-time): half + hearted attempt to add these. Needs bignums. + +Wed May 13 14:01:07 1992 Aubrey Jaffer (jaffer at Ivan) + + * sys.c (gc_mark): improved tail recursivness for CONSes. + + * repl.c (growth_mon): now prints out the hplims table if + verbose>3. + + * sys.c (init_heap_seg): Serious bug in growing hplims fixed. + num_heap_segs eliminated; hplims are realloced whenever grown. + +Tue May 12 15:36:17 1992 Aubrey Jaffer (jaffer at train) + + * config.h sys.c (alloc_some_heap expmem): expmem captures + whether the INIT_HEAP_SIZE allocation was successful. If so, + alloc_some_heap uses exponential heap allocation instead of + HEAP_SEG_SIZE. + +Mon May 11 15:29:04 1992 Aubrey Jaffer (jaffer at Ivan) + + * sys.c (gc_sweep init_heap_seg heap_org): Empty heap segments + are now freed. + + * sc2.c (STR_EXTENSIONS): renamed REV2_PROCEDURES and R2RS and + R3RS functions put into sc2.c. + +Sun May 10 01:34:11 1992 Aubrey Jaffer (jaffer at Ivan) + + * scm.c (ignore_interrupts unignore_interrupts): added for + system, edt$edit, and popen to use. + + * repl.c (lwrite display newline write_char): Close pipe if EPIPE. + + * repl.c (file_set_position): now errs on ESPIPE. + + * scm.c (SIGPIPE): now ignored (errs come back as EPIPE). + +Sat May 9 17:52:36 1992 Stephen Adams <S.R.Adams@ecs.southampton.ac.uk> + + * config.h (PROT386): PROT386 added. PTR_LT and CELL_UP modified. + +Fri May 8 17:57:22 1992 hugh@ear.mit.edu (Hugh Secker-Walker) + + * Init.scm (last-pair append!): last-pair is faster version. + Append! corrected for null first arg. (getenv "HOME") now gets + a "/" added if not present. + + * config.scm (MIN_GC_YIELD): now proportional to HEAP_SEG_SIZE. + + * README: setting environment variables corrected. + + * subr.c (length): error message now has arg if not a list. + + * sys.c (open-pipe): now turns off interrupts before forking. + + * scl.c (lsystem): now turns off interrupts before forking. + + * scm.c (ignore_signals): created. + +Sat May 2 01:02:16 1992 Aubrey Jaffer (jaffer at Ivan) + + * Init.c (WITH-INPUT-FROM-FILE WITH-OUTPUT-TO-FILE): defined in + terms of current-input-port and current-output-port. Bug in + open-input-pipe and open-output-pipe fixed. + + * sys.c repl.c (current-input-port current-output-port): moved + from sys.c to repl.c. set-current-input-port and + set-current-output-port added to repl.c. + +Mon Apr 13 22:51:32 1992 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h: (PATCHLEVEL): released scm4a1. + + * makefile.* VMSBUILD.COM VMSGCC.COM: compile time.h. + + * scm.c (alrm_signal int_signal): now save and restore errno so + SYSCALL will work correctly across interrupts. + +Sun Apr 12 01:44:10 1992 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h: (PATCHLEVEL): released scm4a0. + + * repl.c (lread): tok_buf now local to each invocation of read. + This makes READ interruptable and reentrant. + + * sys.c MANUAL (STRING-SET-LENGTH! STRING-VECTOR-LENGTH!): created. + + * sys.c repl.c (grow_tok_buf tok_buf tok_buf_len): moved to repl.c + + * repl.c (lfwrite): now emulated for VMS. + + * repl.c scl.c (num_buf): now local to all routines that use it. + + * time.h: created by moving time functions from repl.c. Read and + write functions were moved from sys.c to repl.c. + + * sys.c repl.c (DEFER_INTS ALLOW_INTS CHECK_INTS): totally + rewritten. SIGALRM and SIGINT now execute at interrupt level. + Interrupts deferred only for protected code sections, not for + reads and writes. + + * sys.c repl.c (SYSCALL): created to reexecute system calls + interrupted (EINTR) by SIGALRM and SIGINT. + + * sys.c scl.c (flo0): 0.0 is now always flo0. + + * repl.c sys.c (TRANSCRIPT-ON TRANSCRIPT-OFF): added. This + required shadowing putc, fputs, fwrite, and getc with lputc, + lputs, lfwrite, and lgetc. + +Sun Apr 5 00:27:33 1992 HEDDEN@esdsdf.dnet.ge.com (Jerry D. Hedden) + + * scl.c (eqp lessp greaterp lesseqp greatereqp): + Comparisons with inexact numbers was not being performed + correctly. For example, (< 1.0 2.0 1.5) would yield #t. What was + missing was a line x=y; in the inexact comparison sections of + lessp(), greaterp(), lesseqp() and greatereqp(). In addition, I + modified these routines and eqp() to allow for mixed arithmetic + types. + +Sat Apr 4 00:17:29 1992 Aubrey Jaffer (jaffer at Ivan) + + * scm.h code.doc: tc7_bignum => tc7_spare. Added tc16_bigpos and + tc16_bigneg. SMOBS reordered. tc16_record added. + + * scm.h repl.c sys.c (make-arbiter try-arbiter release-arbiter): + added. tc16_arbiter added. + +Fri Apr 3 01:25:35 1992 Aubrey Jaffer (jaffer at Ivan) + + * sys.c config.h (TEMPTEMPLATE): created in config.h. + + * scm.h: removed long aliases for C versions of Scheme functions. + + * sys.c eval.c scm.h: (delay force makprom): added. Also added + tc16_promise data type. + + * Init.scm (trace untrace): added autoloads and read macros. + + From: T. Kurt Bond, tkb@mtnet2.wvnet.edu + * sys.c (template): correct template for VMS. + +Tue Mar 31 01:50:12 1992 Aubrey Jaffer (jaffer at Ivan) + + * sys.c config.h Init.scm (open-file open-pipe): created and + expressed other open functions in terms of. Bracketed all i/o + system calls with DEFER and ALLOW _SIGINTS. + +Sat Mar 28 00:24:01 1992 Aubrey Jaffer (jaffer at Ivan) + + * sys.c MANUAL (#.): read macro syntax added. Balanced comments + also documented. + +Fri Mar 27 22:53:26 1992 Aubrey Jaffer (jaffer at Ivan) + + * sys.c (iprin1): changed printed representation for unreadable + objects from #[...] to #<...>. + + From: brh@aquila.ahse.cdc.com (brian r hanson x6009): + * scm.h config.h (NCELLP PTR_LT): fixes for 64 bit pointers on + nosve. + +Fri Mar 20 01:36:08 1992 Aubrey Jaffer (jaffer at Ivan) + + * Released scm3c13 + + * code.doc: corrected some minor inconsistencies and added a + section "To add a package of new procedures to scm". + +Sun Mar 15 19:44:45 1992 Aubrey Jaffer (jaffer at Ivan) + + * Init.scm: now loads <program-name>_INIT_PATH when <program-name> + is not "SCM". + + * config.h (PTR_LT): (x < y) => ((x) < (y)) + +Wed Mar 4 01:53:15 1992 Aubrey Jaffer (jaffer at Ivan) + + * Released scm3c12. + + * scm.h code.doc eval.c sys.c (IXSYM): Eliminated Immediate IXSYM + type. + +Tue Mar 3 00:58:18 1992 Aubrey Jaffer (jaffer at Ivan) + + * eval.c config.c (ceval DEFINED? SYNTAX_EXTENSIONS): added + DEFINED? to ceval conditional on SYNTAX_EXTENSIONS. + + From: Andrew Wilcox <andrew@astro.psu.edu> + * makefile.unix scm.c (main init_scm display_banner init_signals + restore_signals run_scm): RTL support. + +Mon Mar 2 19:05:29 1992 Aubrey Jaffer (jaffer at Ivan) + + * subr.c (make-string): now checks for ARG1 >= 0. + +Fri Feb 28 00:13:00 1992 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 12 + + * Init.scm: loads JCAL if scm is invoked with name JCAL, JACAL, + jcal or jacal. + + * Init.scm (ABS): set to MAGNITUDE if FLOATS are supported. + + * gc_mark gc: no longer assume sizeof(short) == 2. + + * config.h (CELL_UP CELL_DN): no longer assume sizeof(CELL) == 8. + + From: Brian Hanson, Control Data Corporation. brh@ahse.cdc.com + * scl.c config.h repl.c: partial port to Control Data NOS/VE. + + From: fred@sce.carleton.ca (Fred J Kaudel) + * repl.c Init.scm makefile.ast: Port to Atari-ST + + * sys.c scm.h eval.c (throw): renamed to lthrow to avoid conflict + with Gnu CC. + +Mon Feb 10 14:31:24 1992 Aubrey Jaffer (jaffer at Ivan) + + * sys.c (delete-file rename-file): added. + + * sys.c (chdir): now returns #f instead of error. + + * Init.scm: Calls to PROVIDED? inlined so no longer dependent on + SLIB being loaded. (set! ABS MAGNITUDE) if inexacts supported. + Support for slib1b3 added. + + * sys.c (alloc_some_heap): fixed bugs. One fix from + bowles@is.s.u-tokyo.ac.jp. + + * eval.c (ceval): fixed bug with internal (define foo bar) where + bar is a global. Put badfun2: back in for better error reporting. + + * patchlvl.h (PATCHLEVEL): 11 + +Mon Jan 20 16:19:04 1992 Aubrey Jaffer (jaffer at Ivan) + + * config.c (INITS): comments added. + + From: T. Kurt Bond, tkb@mtnet2.wvnet.edu + * VMSGCC.COM VMSMAKE.COM: now take arguments. + + From: "Fred Bayer" <bayerf@lan.informatik.tu-muenchen.de> + * makefile.aztec repl.c: Aztec C (makefile) port. + +Fri Jan 17 16:36:07 1992 Aubrey Jaffer (jaffer at Ivan) + + * sys.c (gc init_storage stack_size): stack_size now of type + sizet. init_storage no longer uses it. gc() now uses it instead + of pointer to local. This fixes bug with gcc -O. + + * sys.c (cons cons2 cons2r): &w;&x;&y; removed because of above + fix. + +Thu Jan 16 22:33:00 1992 Aubrey Jaffer (jaffer at Ivan) + + * scl.c (real-part): added. + +Wed Jan 15 13:06:39 1992 "Fred Bayer" <bayerf@lan.informatik.tu-muenchen.de> + + * scl.c repl.c scm.c config.c: Port for AMIGA + + * scm.h (REALP): fixed for SINGLES not defined. + +Sat Jan 11 20:20:40 1992 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 8 released. + + * README: added hints for EDITING SCHEME CODE. + + * repl.c (SIGRETTYPE): now int for __TURBOC__. + + * makefile.tur makefile.djg: created. + + * config.h: DJGPP (__GO32__) support added. + + * scm.h (memv): definition added. + +Sun Jan 5 00:33:44 1992 Aubrey Jaffer (jaffer at Ivan) + + * repl.c makefile.* (main): INITS added. + + * scl.c: fixed ASSERT statements with mismatched ARGn and + arguments. + +Thu Dec 19 19:16:50 1991 Aubrey Jaffer (jaffer at train) + + * sys.c (cons cons2 cons2r): added fix for gcc -O bug. + + * repl.c (LACK_FTIME LACK_TIMES): more messing with these. + + * sys.c config.o (HAVE_PIPE): created. + + * config.h (FLT_RADIX): now #ifdef FLT_RADIX rather than __STDC__. + Needed for DJGCC. + + * sys.c (DBLMANT_DIG DBL_FLOAT_DIG): now tested for directly + rather than STDC_INCLUDES. + + * makefile.unix (subr.o): explicit compilation line added. + + * scl.c (truncate -> ltrunc): Name conflict with DJGCC libraries. + +Sun Dec 8 23:31:04 1991 Aubrey Jaffer (jaffer at Ivan) + + * eval.c (apply): added check for number of args to closures. + +Sat Dec 7 01:30:46 1991 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 7 + + * sys.c (chdir): THINK_C doesn't support; + + * repl.c: SVR2 needs <time.h> instead of <sys/time.h> + + * repl.c: SVR2 needs LACK_FTIME + + * repl.c: #include <sys/timeb.h> now automatic ifndef LACK_FTIME. + +Mon Dec 2 15:42:11 1991 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 5 + + * sys.c (intern sysintern): made strings and hash unsigned. Fixed + bug with characters > 128 in symbols. + + From: boopsy!mike@maccs.dcss.mcmaster.ca (Michael A. Borza) + * scl.c (eqv? memv assv): created if FLOATS is #defined. + +Mon Dec 2 11:37:11 1991 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 4 + + * sys.c (gc_sweep): usaage of pclose() now conditional on unix. + + * MANUAL (chdir): documented. + + From: T. Kurt Bond, Adminisoft, Inc. <tkb@MTNET2.WVNET.EDU>: + + * repl.c sys.c (errno): VMS GNU C uses a special hack in <errno.h> + to get the link-time attributes for the errno variable to match + those the VMS C run-time library expects (it makes errno a + preprocessor define so that the variable that the compiler sees + has a special form that the assember then interprets), so if it is + VMS and __GNUC__ is defined <errno.h> needs included. + + * setjump.h (SETJUMP LONGJUMP): SETJUMP and LONGJUMP changed to + setjump and longjump. The VMS linker is case-indifferent. VMS GNU + C mangles variable names that have upper case letters in them to + preserve their uniqueness. + + * sys.c (iprint iprin1): Now inline putc loops instead of calls to + fwrite for VMS. The VMS `fwrite' has been enhanced to work with + VMS's Record Management Sevice, RMS. Part of this enhancement is + to treat each call to `fwrite' as producing a seperate record. + This works fine if you are writing to a stream_LF file or an + actual terminal screen, but if you are writing to a file that has + implied carriage control (such as a batch log file, or a mailbox + used for subprocess communication), which is a more common file + organization for RMS, each call to `fwrite' has a newline appended + to it. This causes much of the output to be incorrectly split + across lines. + + * vmsgcc.com: created. + +Sun Dec 1 00:33:42 1991 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 3 released. + + * Init.scm (rev2-procedures): all now supported. + + * Init.scm sys.c MANUAL (flush): flush changed to force-output to + be compatible with Common Lisp. + + * sys.c (chdir): added. + +Wed Nov 27 09:37:20 1991 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 2 + + * repl.c (set-errno! perror): added. + + * sys.c (gc): FLUSH_REGISTER_WINDOWS call added. + + * sys.c (open-input-pipe open-output-pipe close-pipe): added. + +Mon Nov 25 13:02:13 1991 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 1 + + * sys.c (flush): added. + + * repl.c (mytime): macro was missing (). CLKTCK now defaults to 60. + + From: Yasuaki Honda, honda@csl.SONY.co.jp, + * README Init.scm subr.c scm.c repl.c scl.c: support for + Macintosh running Think C. + +Sun Nov 24 15:30:51 1991 Aubrey Jaffer (jaffer at Ivan) + + * scl.c (str2flo): fixed parsing of -1-i. + + * subr.c (equal): Now correct for inexacts. Need to do eqv. + + * scm.h (REALPART): fixed pixel C compiler bug with doubles inside + `?' conditionals. + + * scl.c (zerop): now checks imaginary half of complex number. + + From: jjc@jclark.com + * repl.c (repl_driver): now checks that s_response is non-NULL + before INTERNing. + +Tue Nov 19 00:10:59 1991 Aubrey Jaffer (jaffer at Ivan) + + * version scm3c0 + + * documentation: changed revised^3.99 to revised^4. + + * example.scm: created from Scheme^4 spec. + + * makefile.msc: -Ox changed to -Oxp to fix over-enthusiastic float + optimizations. + + * Init.scm (ed): defined. + + * repl.c (def_err_response): UNDEFINED objects don't print out. + +Sun Nov 17 23:11:03 1991 Aubrey Jaffer (jaffer at Ivan) + + * scl.c (vms-debug): now returns UNSPECIFIED. + + * repl.c MANUAL (restart_repl): RESTART-REPL changed to ABORT. + + * repl.c (err_ctrl_c):now clears sig_pending. + +Wed Nov 13 23:51:36 1991 Aubrey Jaffer (jaffer at Ivan) + + * config.h: removed #ifdef sparc #define STDC_HEADERS + + * makefile.bor: added extra '\' to filepath. + + * repl.c (everr): fixed bug with ARGx. + + * repl.c (errmsgs def_err_response): cleaned up error messages. + +Sun Nov 10 23:10:24 1991 Aubrey Jaffer (jaffer at Ivan) + + * released scm3b7 + +Mon Nov 4 18:36:49 1991 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 6 + + * sys.c (idbl2str): tests for Not-a-Number and Infinity added. + + * repl.c scm.h: response system rewritten and integrated with + error system. + + * scl.c (/): now returns inexacts if integer arguments do not + divide evenly. + +Mon Oct 28 23:44:16 1991 Aubrey Jaffer (jaffer at Ivan) + + * makefile.unix: can now make float (scm) and integer-only (escm) + versions in same directory. + + * repl.c (*sigint-response* *arithmetic-response* restart-repl): + responses for signals added. + + * scl.c (lmin lmax sum difference product divide expt exp log): + now take mixed types. expt available in non-FLOATS compilation. + + * repl.c (get-decoded-time): added. Includes and time functions + reorganized. + + * sys.c (object-hash object-unhash): added. + +Tue Oct 15 00:45:35 1991 Aubrey Jaffer (jaffer at Ivan) + + * repl.c Init.scm (*features*): moved constant features into + Init.scm. Moved tests for numeric features to slib/require.scm. + + * release scm3b1. + + * config.h (ANSI_INCLUDES): redid include files. + + * subr.c scl.c: moved all FLOAT conditionals from subr.c to scl.c. + +Wed Oct 9 00:28:54 1991 Aubrey Jaffer (jaffer at Ivan) + + * release scm3a13. + + * patchlvl.h (PATCHLEVEL): 13 + + * Init.scm: "vicinity.scm" changed to "require.scm" + +Mon Oct 7 00:34:07 1991 Aubrey Jaffer (jaffer at Ivan) + + * test.scm: test of redefining built-in symbol and extra ')' + removed. + + * scm.doc makefile.unix: scm.doc created from scm.1 in + makefile.unix. + + * VMSBUILD.COM setjump.asm setjump.h (setjmp longjmp jmp_buf): put + in from comp.sources.reviewed in order to let VMS have full + continuations. VMSBUILD.COM is a compile script. + +Fri Oct 4 00:05:54 1991 Aubrey Jaffer (jaffer at Ivan) + + * scl.c(sleep): removed; not supported by MSC (although could be + written). + + * scm.h config.h (size_t): moved to config.h. + + * sys.c (f_getc): -> lgetc for vax, getc otherwise. + + * patchlvl.h (PATCHLEVEL): 12 + +Mon Sep 30 01:14:48 1991 Aubrey Jaffer (jaffer at Ivan) + + * scl.c(sleep): created. + + * repl.c(internal-time-units-per-second get=internal-run-time): + created + + * repl.c: created from scm.c (shuffled around lots of functions). + +Sat Sep 28 00:22:30 1991 Aubrey Jaffer (jaffer at Ivan) + + * scm.c config.h (char-code-limit most-positive-fixnum + most-negative-fixnum): created. + +Tue Sep 24 01:21:43 1991 Aubrey Jaffer (jaffer at Ivan) + + * scm.c (software-type); created. + + * scm.c config.h (terms, list-file, library-vicinity, + program-vicinity, user-vicinity, make-vicinity, sub-vicinity): + moved to Init.scm and library. + + * scm.c config.h Makefile (PROGPATH): changed to IMPLPATH. + + * Init.scm: created + +Fri Sep 20 13:22:08 1991 Aubrey Jaffer (jaffer at Ivan) + + * patchlvl.h (PATCHLEVEL): 5 + + * all: changed declarations to size_t where appropriate. scm.h + test preprocessor flag _SIZE_T to determine if already declared. + size_t should greatly enhance portability to Macintosh and other + machines. + +Tue Sep 17 01:15:31 1991 Aubrey Jaffer (jaffer at Ivan) + + * scm.c (tmpnam): support for mktemp added. + +Mon Sep 16 14:06:26 1991 Aubrey Jaffer (jaffer at train) + + * scm.c (implementation-vicinity): added. (program-vicinity) now + returns undefined if called not within a load. + + * sys.c (call-with-io-file): removed. + + * scm.c (tmpnam): added. + + * scm.c config.h (tmporary-vicinity): removed. + +Sun Sep 15 22:21:30 1991 bevan@cs.man.ac.uk + + * subr.c scm.h (remainder): renamed to lremainder to avoid + conflict with math.h on SunOS4.1. + +Sat Sep 7 22:27:49 1991 Aubrey Jaffer (jaffer at Ivan) + + * scm.c (program-arguments load): program-arguments created. + + * scm.c (getenv): added getenv and used for program-vicinity and + library-vicinity. + + * scm.c (program-vicinity): fixed if load_name is NULL. + + * scl.c config.h (substring-move-left! substring-move-right!): + added under STR_EXTENSIONS flag. + +Wed Aug 28 22:59:20 1991 Aubrey Jaffer (jaffer at Ivan) + + * Sending scm3a to comp.sources.reviewed + + * scm.c (main): prints out feature list at startup. + + * subr.c (eqp lessp greaterp lesseqp greatereqp): now work for + floats. + + * scl.c (sum difference divide product): moved to scl.c and + now work for floats. + + * all: all masks with low bits explicity cast to (int). + +Sat Aug 17 00:39:06 1991 Aubrey Jaffer (jaffer at Ivan) + + * sys.c subr.c scl.c (iint2str istr2int istring2number istr2flo + iflo2str idbl2str): number I/O and conversion to strings rewritten. + + * sys.c (gc_mark): continuations now marked SHORT_ALIGNed. (from + Craig Lawson). + + * added QuickC support from Craig Lawson. + +Tue Jul 30 01:08:52 1991 Aubrey Jaffer (jaffer at Ivan) + + * config.h: #ifdef pyr added. + + * scm.c MANUAL: vicinity functions added. + +Tue Jul 16 00:51:23 1991 Aubrey Jaffer (jaffer at Ivan) + + * scl.c sys.c: float functions added. + + * Documentation reorganized according to comp.sources.reviewed + guidelines. + + * sys.c config.h (open_input_file open_output_file open_rw_file): + file mode string moved to defines in config.h + +Thu Jul 11 23:30:03 1991 Aubrey Jaffer (jaffer at Ivan) + + * sys.c config.h (EBCDIC ASCII) moved to config.h + + * subr.c config.h (BADIVSGNS) moved to config.h + + * scm.h config.h (SRS) moved to config.h + +Sun Jul 7 23:49:26 1991 Aubrey Jaffer (jaffer at Ivan) + + * all: started adding comp.sources.reviewed corrections and + suggestions. + + * scm.c patchlvl.h (main): PATCHLEVEL now printed in banner. + + * subr.c sys.c: read_integer removed. istring2number created. + lread and string2number now both use istring2number. + +Fri Jun 7 13:43:40 1991 Aubrey Jaffer (jaffer at Ivan) + + * VERSION scm2e sent to comp.sources.reviewed + + * public.lic: renamed COPYING. + + * scm.c (gc_status): gc_status renamed prolixity. Now returns old + value of verbose. Can take 0 arguments. + + * sys.c (lreadr): added #| common lisp style |# balanced comments. + + * scm.h scm.c sys.c (I/O functions): combined **PORTP and OPENP to + become OP**PORTP. + + * scm.h sys.c (gc_sweep): moved OPENP to bit in upper half word of + port cells. + +Sat May 25 00:04:45 1991 Aubrey Jaffer (jaffer at Ivan) + + * scm.c (stack_start_ptr, repl_driver, main, err functions): + exits removed from all err functions. all escapes through + repl_driver. + + * scm.c README (verbose): Now has graded verbosity. + + * scm.c README (quit): Now takes optional argument which is return + value. + +Wed May 22 01:40:17 1991 Aubrey Jaffer (jaffer at Ivan) + + * code.doc scm.h eval.c (ceval): Rearanged immediate type codes to + create IXSYMs (immediate extension syms) to allow more than 15 + special forms. ILOCs now work with up to 32767 in one environment + frame. Dispatch is slightly faster for ILOCs in function position. + ICHRs can be up to 24 bits. + +Fri May 10 00:16:32 1991 Aubrey Jaffer (jaffer at Ivan) + + * scm.h sys.c (gc_mark, gc_sweep): GCMARK moved to bit 8 of CAR + for some datatypes. + +Wed May 1 14:11:05 1991 Aubrey Jaffer (jaffer at Ivan) + + * patch1 MESSAGE SENT. + + From: jclark@bugs.specialix.co.uk.jjc + * sys.c (lreadr): removed + order evaluation bug when growing tok_buf. + +Fri Apr 26 10:39:41 1991 Aubrey Jaffer (jaffer at Ivan) + + * scm2d RELEASED + + * sys.c (closure) no longer calls ilength (ECONS problem). Added + ASSERT before call to closure in eval. + +Thu Apr 25 09:53:40 1991 Aubrey Jaffer (jaffer at Ivan) + + * scm.c (error): created. + +Wed Apr 24 16:58:06 1991 Aubrey Jaffer (jaffer at Ivan) + + * utils.scm: created. + + * makefile (name8s): code from dmason works in makefile. + + * eval.c (evalcar): fixed errobj on (else 3 4) error. + Inlined function application in (cond ((foo => fun))). + + * sys.c (lprin1): change looped putcs to fwrite. + +Wed Apr 24 01:54:09 1991 Aubrey Jaffer (jaffer at Ivan) + + * sys.c (lreadr): fixed assert for "eof in string". + + * subr.c (lgcd): changed to work with borland C. + + * eval.c (eval): added checks to LAMBDA and LET. + + * eval.c (apply): now checks for null arg1 in lsubr. + +Fri Apr 12 00:09:03 1991 Aubrey Jaffer (jaffer at kleph) + + * config.h scm.h (SCMPTR): created to correct address arithmetic + on stack bounds under Borland C++. Borland C++ now runs scm2c. + +Wed Apr 10 21:38:09 1991 Aubrey Jaffer (jaffer at Ivan) + + * sys.c (open_io_file, cw_io_file, file_position, file_set_pos, + read_to_str) created (IO_EXTENSIONS) + + * config.h (IO_EXTENSIONS): defined + + * sys.c scm.c: lprin1f changed to iprin1 + +Wed Apr 10 12:58:59 1991 Aubrey Jaffer (jaffer at Ivan) + + * sys.c (intern): line 850: for(i = alen;0 <= --i;)changed to + for(i = alen;0 < --i;). + This fixed b_pos and v_pos mapping to the same symbol. + +Wed Apr 4 00:00:00 1991 Aubrey Jaffer (jaffer at kleph.ai.mit.edu) + + * released scm2b + +Wed Apr 3 22:51:39 1991 Aubrey Jaffer (jaffer at Ivan) + + * all files: eliminated types tc7_subr_2n and tc7_subr_2xn. + Replaced with tc7_subr_2o and tc7_subr_1o so that all subr calls + can be checked for number of arguments. + +Tue Apr 2 23:11:15 1991 Aubrey Jaffer (jaffer at Ivan) + + * code.doc: cleaned up. + +Mon Apr 1 14:27:22 1991 Aubrey Jaffer (jaffer at Ivan) + + * eval.c (ceval): fixed nasty tail recursion bug at carloop:. + + * scm.c (everr): still fixing error reporting. + + * eval.c subr.c: added flag PURE_FUNCTIONAL which removes side + effect special forms and functions. + + * subr.c (substring): now allows first index to be equal to length + of string + + * sys.c (lprin1f): dispatches on TYP16 of smobs. + + * scm.h: fixed typo in unused function defs. + +Mon Mar 28 00:00:00 1991 Aubrey Jaffer (jaffer at zohar.ai.mit.edu) + + * scm2a released: too many changes to record. See code.doc. + +Mon Feb 18 21:48:24 1991 Aubrey Jaffer (jaffer at foxkid) + + * scm.h: types reformatted (TYP6 -> TYP7). + + * eval.c (ceval): Now dispatch directly on ISYMs in ceval. + +Fri Feb 15 23:39:48 1991 Aubrey Jaffer (jaffer at foxkid) + + * sys.c: #include <malloc.h> not done for VMS + +Wed Feb 13 17:49:33 1991 Aubrey Jaffer (jaffer at foxkid) + + * scm.c scl.c: added unsigned declarations to some char * + definitions in order to fix characters having negative codes. + + * scm.h (MAKISYM, MAKFLAG, ICHR, MAKICHR, MAKINUM): Now cast to + long so that their calls don't have to. Changing MAKICHR fixed + problem in scl.c (string2list) on IBMPC. + + * subr.c (quotient): support for `/' reintroduced; required by + r3.99rs but not IEEE. + + * subr.c (char functions): added isascii tests for + char-alphabetic, char-numeric?, char-whitespace?, + char-upper-case?, and char-lower-case?. Added test against + char_code_limit to int2char. + + * subr.c (s_char_alphap): is subr_1 not lsubr. + + * test.scm: added tests for char-alphabetic, char-numeric?, + char-whitespace?, char-upper-case?, and char-lower-case?. + + * sys.c: most `return;'s eliminated to reduce warning messages. + Substituted breaks and reordered switch and if clauses. + +Sun Feb 3 23:12:34 1991 Aubrey Jaffer (jaffer at foxkid) + + * scm1-2: released. + + * sys.c (read-char peek-char) added code for EOF. + + * test.scm (leaf-eq?) added and file "cont.scm" removed. I/O + tests added. + + * sys.c (I/O functions) now check for input and output ports + rather than just ports. + + * sys.c (lprin1f): occurences of stdout changed to f. Newlines + after printing port removed. + +Thu Jan 31 22:52:39 1991 Aubrey Jaffer (jaffer at foxkid) + + * subr.c (quotient): support for `/' removed; not required. + + * scm.c (wta): message for OUTOFRANGE fixed. + +Mon Jan 28 12:45:55 1991 Aubrey Jaffer (jaffer at foxkid) + + * eval.c (apply): added checks for number of arguments. + + * scm.h (CHECK_SIGINT): checks for blocked SIGINT. + + * sys.c (lprin1): added blocking and testing for SIGINT so that + output won't hang on VMS. + + * scm.c (repl): added fflush call. + + * scm.c (err_head, wta): added fflush calls to error routines so + that error message come out in proper order. + diff --git a/Iedline.scm b/Iedline.scm new file mode 100644 index 0000000..cbeb265 --- /dev/null +++ b/Iedline.scm @@ -0,0 +1,103 @@ +;; Copyright (C) 1994, 1995 Free Software Foundation, Inc. +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this software; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;; As a special exception, the Free Software Foundation gives permission +;; for additional uses of the text contained in its release of GUILE. +;; +;; The exception is that, if you link the GUILE library with other files +;; to produce an executable, this does not by itself cause the +;; resulting executable to be covered by the GNU General Public License. +;; Your use of that executable is in no way restricted on account of +;; linking the GUILE library code into it. +;; +;; This exception does not however invalidate any other reasons why +;; the executable file might be covered by the GNU General Public License. +;; +;; This exception applies only to the code released by the +;; Free Software Foundation under the name GUILE. If you copy +;; code from other Free Software Foundation releases into a copy of +;; GUILE, as the General Public License permits, the exception does +;; not apply to the code that you add in this way. To avoid misleading +;; anyone as to the status of such modified files, you must delete +;; this exception notice from them. +;; +;; If you write modifications of your own for GUILE, it is your choice +;; whether to permit this exception to apply to your modifications. +;; If you do not wish that, delete this exception notice. + +;; "Iedline.scm" Scheme interface to readline library +;; Author: Radey Shouman + +;; Change both current-input-port and current-output-port to +;; allow line editing of input. +;; All output goes through a soft port in order to detect prompt +;; lines, i.e. lines unterminated by a newline. + +(define (make-edited-line-port) + (let ((prompt "") + (outp (default-output-port)) + (inp (default-input-port)) + (strp (call-with-input-string "" identity))) + (make-soft-port + (vector (lambda (c) + (write-char c outp)) + (lambda (s) + (display s outp) + (or (zero? (string-length s)) + (eq? #\newline (string-ref s (- (string-length s) 1))) + (begin + (set! prompt (string-append "\r" s)) + (force-output outp)))) + (lambda () + (force-output outp)) + (lambda () + (let tail ((c (read-char strp))) + (if (char? c) c + (let ((str (read-edited-line prompt))) + (if (string? str) + (let ((n (string-length str))) + (add-history str) + (vector-set-length! str (+ 1 n)) + (string-set! str n #\newline) + (set! strp (call-with-input-string + str identity)) + (tail (read-char strp))) + str))))) + #f) + OPEN_BOTH))) + +(define line-editing + (let ((edit-port #f) + (oiport #f) + (ooport #f)) + (lambda arg + (define past edit-port) + (cond ((null? arg)) + ((and (car arg) (not edit-port)) + (set! edit-port (make-edited-line-port)) + (set! oiport (set-current-input-port edit-port)) + (set! ooport (set-current-output-port edit-port))) + (edit-port + (set-current-input-port oiport) + (set-current-output-port ooport) + (set! edit-port #f))) + past))) + +(and + (if (provided? 'unix) (isatty? (current-input-port)) #t) + (eq? (current-input-port) (default-input-port)) + (not (getenv "EMACS")) + (line-editing #t)) diff --git a/Init.scm b/Init.scm new file mode 100644 index 0000000..758c407 --- /dev/null +++ b/Init.scm @@ -0,0 +1,854 @@ +;; Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this software; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;; As a special exception, the Free Software Foundation gives permission +;; for additional uses of the text contained in its release of GUILE. +;; +;; The exception is that, if you link the GUILE library with other files +;; to produce an executable, this does not by itself cause the +;; resulting executable to be covered by the GNU General Public License. +;; Your use of that executable is in no way restricted on account of +;; linking the GUILE library code into it. +;; +;; This exception does not however invalidate any other reasons why +;; the executable file might be covered by the GNU General Public License. +;; +;; This exception applies only to the code released by the +;; Free Software Foundation under the name GUILE. If you copy +;; code from other Free Software Foundation releases into a copy of +;; GUILE, as the General Public License permits, the exception does +;; not apply to the code that you add in this way. To avoid misleading +;; anyone as to the status of such modified files, you must delete +;; this exception notice from them. +;; +;; If you write modifications of your own for GUILE, it is your choice +;; whether to permit this exception to apply to your modifications. +;; If you do not wish that, delete this exception notice. + +;;;; "Init.scm", Scheme initialization code for SCM. +;;; Author: Aubrey Jaffer. + +(define (scheme-implementation-type) 'SCM) +(define (scheme-implementation-version) "4e6") + +;;; Temporary hack for compatability with older versions. +(define software-type + (cond ((eq? 'msdos (software-type)) + (lambda () 'ms-dos)) + (else software-type))) + +;;; This definition of PROGRAM-VICINITY is a copy of the definition in +;;; SLIB/require.scm. It is used here to bootstrap +;;; IMPLEMENTATION-VICINITY and possibly LIBRARY-VICINITY. + +(define program-vicinity + (let ((*vicinity-suffix* + (case (software-type) + ((AMIGA) '(#\: #\/)) + ((MS-DOS WINDOWS ATARIST OS/2) '(#\\ #\/)) + ((MACOS THINKC) '(#\:)) + ((NOSVE) '(#\: #\.)) + ((UNIX COHERENT) '(#\/)) + ((VMS) '(#\: #\]))))) + (lambda () + (let loop ((i (- (string-length *load-pathname*) 1))) + (cond ((negative? i) "") + ((memv (string-ref *load-pathname* i) *vicinity-suffix*) + (substring *load-pathname* 0 (+ i 1))) + (else (loop (- i 1)))))))) + +(define in-vicinity string-append) + +;;; This is the vicinity where this file resides. +(define implementation-vicinity + (let ((vic (program-vicinity))) + (lambda () vic))) + +;;; (library-vicinity) should be defined to be the pathname of the +;;; directory where files of Scheme library functions reside. + +;;; If the environment variable SCHEME_LIBRARY_PATH is undefined, use +;;; (implementation-vicinity) as (library-vicinity). "require.scm", +;;; the first file loaded from (library-vicinity), can redirect it. + +(define library-vicinity + (let ((library-path (getenv "SCHEME_LIBRARY_PATH"))) + (if library-path (lambda () library-path) + implementation-vicinity))) + +;;; Here for backward compatability +(define scheme-file-suffix + (case (software-type) + ((NOSVE) (lambda () "_scm")) + (else (lambda () ".scm")))) + +(set! *features* + (append '(getenv tmpnam abort transcript with-file + ieee-p1178 rev4-report rev4-optional-procedures + hash object-hash delay eval dynamic-wind + multiarg-apply multiarg/and- logical defmacro + string-port source current-time) + *features*)) + +(define slib:exit quit) +(define (exec-self) + (require 'i/o-extensions) + (execv (execpath) (program-arguments))) + +(define (terms) + (list-file (in-vicinity (implementation-vicinity) "COPYING"))) + +(define (list-file file) + (call-with-input-file file + (lambda (inport) + (do ((c (read-char inport) (read-char inport))) + ((eof-object? c)) + (write-char c))))) + +(define (read:eval-feature exp) + (cond ((symbol? exp) + (or (memq exp *features*) (eq? exp (software-type)))) + ((and (pair? exp) (list? exp)) + (case (car exp) + ((not) (not (read:eval-feature (cadr exp)))) + ((or) (if (null? (cdr exp)) #f + (or (read:eval-feature (cadr exp)) + (read:eval-feature (cons 'or (cddr exp)))))) + ((and) (if (null? (cdr exp)) #t + (and (read:eval-feature (cadr exp)) + (read:eval-feature (cons 'and (cddr exp)))))) + (else (error "read:sharp+ invalid expression " exp)))))) + +(define (read:array digit port) + (define chr0 (char->integer #\0)) + (let ((rank (let readnum ((val (- (char->integer digit) chr0))) + (if (char-numeric? (peek-char port)) + (readnum (+ (* 10 val) + (- (char->integer (read-char port)) chr0))) + val))) + (prot (if (eq? #\( (peek-char port)) + '() + (let ((c (read-char port))) + (case c ((#\b) #t) + ((#\a) #\a) + ((#\u) 1) + ((#\e) -1) + ((#\s) 1.0) + ((#\i) 1/3) + ((#\c) 0+i) + (else (error "read:array unknown option " c))))))) + (if (eq? (peek-char port) #\() + (list->uniform-array rank prot (read port)) + (error "read:array list not found")))) + +(define (read:uniform-vector proto port) + (if (eq? #\( (peek-char port)) + (list->uniform-array 1 proto (read port)) + (error "read:uniform-vector list not found"))) + +(define (read:sharp c port) + (define (barf) + (error "unknown # object" c)) + (case c ((#\') (read port)) + ((#\+) (if (read:eval-feature (read port)) + (read port) + (begin (read port) (if #f #f)))) + ((#\-) (if (not (read:eval-feature (read port))) + (read port) + (begin (read port) (if #f #f)))) + ((#\b) (read:uniform-vector #t port)) + ((#\a) (read:uniform-vector #\a port)) + ((#\u) (read:uniform-vector 1 port)) + ((#\e) (read:uniform-vector -1 port)) + ((#\s) (read:uniform-vector 1.0 port)) + ((#\i) (read:uniform-vector 1/3 port)) + ((#\c) (read:uniform-vector 0+i port)) + ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) + (read:array c port)) + ((#\!) (if (= 1 (line-number)) + (let skip () (if (eq? #\newline (peek-char port)) + (if #f #f) + (begin (read-char port) (skip)))) + (barf))) + (else (barf)))) + +(define type 'type) ;for /bin/sh hack. + +;;;; Here are some Revised^2 Scheme functions: +(define 1+ + (let ((+ +)) + (lambda (n) (+ n 1)))) +(define -1+ + (let ((+ +)) + (lambda (n) (+ n -1)))) +(define 1- -1+) +(define <? <) +(define <=? <=) +(define =? =) +(define >? >) +(define >=? >=) +(define t #t) +(define nil #f) +(define sequence begin) + +(set! apply + (let ((apply:nconc-to-last apply:nconc-to-last) + (@apply @apply)) + (lambda (fun . args) (@apply fun (apply:nconc-to-last args))))) +(define call-with-current-continuation + (let ((@call-with-current-continuation @call-with-current-continuation)) + (lambda (proc) (@call-with-current-continuation proc)))) + +;;; VMS does something strange when output is sent to both +;;; CURRENT-OUTPUT-PORT and CURRENT-ERROR-PORT. +(case (software-type) ((VMS) (set-current-error-port (current-output-port)))) + +;;; OPEN_READ, OPEN_WRITE, and OPEN_BOTH are used to request the proper +;;; mode to open files in. MS-DOS does carraige return - newline +;;; translation if not opened in `b' mode. + +(define OPEN_READ (case (software-type) + ((MS-DOS WINDOWS ATARIST) "rb") + (else "r"))) +(define OPEN_WRITE (case (software-type) + ((MS-DOS WINDOWS ATARIST) "wb") + (else "w"))) +(define OPEN_BOTH (case (software-type) + ((MS-DOS WINDOWS ATARIST) "r+b") + (else "r+"))) +(define (_IONBF mode) (string-append mode "0")) + +(define could-not-open #f) + +(define (open-input-file str) + (or (open-file str OPEN_READ) + (and (procedure? could-not-open) (could-not-open) #f) + (error "OPEN-INPUT-FILE couldn't open file " str))) +(define (open-output-file str) + (or (open-file str OPEN_WRITE) + (and (procedure? could-not-open) (could-not-open) #f) + (error "OPEN-OUTPUT-FILE couldn't open file " str))) +(define (open-io-file str) (open-file str OPEN_BOTH)) + +(define close-input-port close-port) +(define close-output-port close-port) +(define close-io-port close-port) + +(define (call-with-input-file str proc) + (let* ((file (open-input-file str)) + (ans (proc file))) + (close-input-port file) + ans)) + +(define (call-with-output-file str proc) + (let* ((file (open-output-file str)) + (ans (proc file))) + (close-output-port file) + ans)) + +(define (with-input-from-port port thunk) + (let* ((swaports (lambda () (set! port (set-current-input-port port))))) + (dynamic-wind swaports thunk swaports))) + +(define (with-output-to-port port thunk) + (let* ((swaports (lambda () (set! port (set-current-output-port port))))) + (dynamic-wind swaports thunk swaports))) + +(define (with-error-to-port port thunk) + (let* ((swaports (lambda () (set! port (set-current-error-port port))))) + (dynamic-wind swaports thunk swaports))) + +(define (with-input-from-file file thunk) + (let* ((nport (open-input-file file)) + (ans (with-input-from-port nport thunk))) + (close-port nport) + ans)) + +(define (with-output-to-file file thunk) + (let* ((nport (open-output-file file)) + (ans (with-output-to-port nport thunk))) + (close-port nport) + ans)) + +(define (with-error-to-file file thunk) + (let* ((nport (open-output-file file)) + (ans (with-error-to-port nport thunk))) + (close-port nport) + ans)) + +(if (not (defined? force-output)) + (define (force-output . a) #f)) + +(define (error . args) + (define cep (current-error-port)) + (perror "ERROR") + (errno 0) + (display "ERROR: " cep) + (if (not (null? args)) + (begin (display (car args) cep) + (for-each (lambda (x) (display #\ cep) (write x cep)) + (cdr args)))) + (newline cep) + (force-output cep) + (abort)) + +(define set-errno errno) +(define exit quit) + +(define (file-exists? str) + (let ((port (open-file str OPEN_READ))) + (if port (begin (close-port port) #t) + #f))) + +(define difftime -) +(define offset-time +) + +(if (not (memq 'ed *features*)) + (begin + (define (ed . args) + (system (apply string-append + (or (getenv "EDITOR") "ed") + (map (lambda (s) (string-append " " s)) args)))) + (set! *features* (cons 'ed *features*)))) + +(if (not (defined? output-port-width)) + (define (output-port-width . arg) 80)) + +(if (not (defined? output-port-height)) + (define (output-port-height . arg) 24)) + +(if (not (defined? last-pair)) + (define (last-pair l) (if (pair? (cdr l)) (last-pair (cdr l)) l))) + +(define (has-suffix? str suffix) + (let ((sufl (string-length suffix)) + (sl (string-length str))) + (and (> sl sufl) + (string=? (substring str (- sl sufl) sl) suffix)))) + +(define (identity x) x) +(define slib:error error) +(define slib:tab #\tab) +(define slib:form-feed #\page) +(define slib:eval eval) + +;;; Load. +(define load:indent 0) +(define (load:pre file) + (define cep (current-error-port)) + (cond ((> (verbose) 1) + (display + (string-append ";" (make-string load:indent #\ ) "loading " file) + cep) + (set! load:indent (modulo (+ 2 load:indent) 16)) + (newline cep))) + (force-output cep)) + +(define (load:post filesuf) + (define cep (current-error-port)) + (errno 0) + (cond ((> (verbose) 1) + (set! load:indent (modulo (+ -2 load:indent) 16)) + (display (string-append ";" (make-string load:indent #\ ) + "done loading " filesuf) + cep) + (newline cep) + (force-output cep)))) + +(define (scm:load file . libs) + (define filesuf file) + (define hss (has-suffix? file (scheme-file-suffix))) + (load:pre file) + (or (and (defined? link:link) (not hss) + (or (apply link:link file libs) + (and link:able-suffix + (let ((fs (string-append file link:able-suffix))) + (cond ((not (file-exists? fs)) #f) + ((apply link:link fs libs) (set! filesuf fs) #t) + (else #f)))))) + (and (null? libs) (try-load file)) + ;;HERE is where the suffix gets specified + (and (not hss) + (begin (errno 0) ; clean up error from TRY-LOAD above + (set! filesuf (string-append file (scheme-file-suffix))) + (try-load filesuf))) + (and (procedure? could-not-open) (could-not-open) #f) + (let () (set! load:indent 0) + (error "LOAD couldn't find file " file))) + (load:post filesuf)) +(define load scm:load) +(define slib:load load) + +(define (scm:load-source file) + (define sfs (scheme-file-suffix)) + (define filesuf file) + (load:pre file) + (or (and (or (try-load file) + ;;HERE is where the suffix gets specified + (and (not (has-suffix? file sfs)) + (begin (set! filesuf (string-append file sfs)) + (try-load filesuf))))) + (and (procedure? could-not-open) (could-not-open) #f) + (error "LOAD couldn't find file " file)) + (load:post filesuf)) +(define slib:load-source scm:load-source) + +(load (in-vicinity (library-vicinity) "require")) + +;;; DO NOT MOVE! This has to be done after "require.scm" is loaded. +(define slib:load-source scm:load-source) +(define slib:load scm:load) + +(cond ((or (defined? dyn:link) + (defined? vms:dynamic-link-call) + (file-exists? (in-vicinity (implementation-vicinity) "hobbit.tms"))) + (load (in-vicinity (implementation-vicinity) "Link")))) + +(cond ((defined? link:link) + (define (slib:load-compiled . args) + (or (apply link:link args) + (error "Couldn't link files " args))) + (provide 'compiled))) + +(define (string-upcase str) (string-upcase! (string-copy str))) +(define (string-downcase str) (string-downcase! (string-copy str))) +(define (string-capitalize str) (string-capitalize! (string-copy str))) + +(define logical:logand logand) +(define logical:logior logior) +(define logical:logxor logxor) +(define logical:lognot lognot) +(define logical:ash ash) +(define logical:logcount logcount) +(define logical:integer-length integer-length) +(define logical:bit-extract bit-extract) +(define logical:integer-expt integer-expt) + +(define (logical:ipow-by-squaring x k acc proc) + (cond ((zero? k) acc) + ((= 1 k) (proc acc x)) + (else (logical:ipow-by-squaring (proc x x) + (quotient k 2) + (if (even? k) acc (proc acc x)) + proc)))) + +;defmacro from dorai@cs.rice.edu (heavily hacked by jaffer): +(define *defmacros* '()) +(define (defmacro? m) (and (assq m *defmacros*) #t)) + +(define defmacro:transformer + (lambda (f) + (procedure->memoizing-macro + (lambda (exp env) + (copy-tree (apply f (cdr exp))))))) + +(define defmacro + (let ((defmacro-transformer + (lambda (name parms . body) + `(define ,name + (let ((transformer (lambda ,parms ,@body))) + (set! *defmacros* (acons ',name transformer *defmacros*)) + (defmacro:transformer transformer)))))) + (set! *defmacros* (acons 'defmacro defmacro-transformer *defmacros*)) + (defmacro:transformer defmacro-transformer))) + +(define (macroexpand-1 e) + (if (pair? e) (let ((a (car e))) + (cond ((symbol? a) (set! a (assq a *defmacros*)) + (if a (apply (cdr a) (cdr e)) e)) + (else e))) + e)) + +(define (macroexpand e) + (if (pair? e) (let ((a (car e))) + (cond ((symbol? a) + (set! a (assq a *defmacros*)) + (if a (macroexpand (apply (cdr a) (cdr e))) e)) + (else e))) + e)) + +(define gentemp + (let ((*gensym-counter* -1)) + (lambda () + (set! *gensym-counter* (+ *gensym-counter* 1)) + (string->symbol + (string-append "scm:G" (number->string *gensym-counter*)))))) + +(define defmacro:eval slib:eval) +(define defmacro:load load) + +(define (slib:eval-load <filename> evl) + (if (not (file-exists? <filename>)) + (set! <filename> (string-append <filename> (scheme-file-suffix)))) + (call-with-input-file <filename> + (lambda (port) + (let ((old-load-pathname *load-pathname*)) + (set! *load-pathname* <filename>) + (do ((o (read port) (read port))) + ((eof-object? o)) + (evl o)) + (set! *load-pathname* old-load-pathname))))) + +(define (print . args) + (define result #f) + (for-each (lambda (x) (set! result x) (write x) (display #\ )) args) + (newline) + result) + +;;; Autoloads for SLIB procedures. + +(define (tracef . args) (require 'trace) (apply tracef args)) +(define (trace:tracef . args) (require 'trace) (apply trace:tracef args)) +(define (trace-all . args) (require 'debug) (apply trace-all args)) +(define (pretty-print . args) (require 'pretty-print) + (apply pretty-print args)) + +;;; Macros. + +;;; Trace gets redefmacroed when tracef autoloads. +(defmacro trace x + (if (null? x) '() + `(begin ,@(map (lambda (x) `(set! ,x (trace:tracef ,x ',x))) x)))) +(defmacro break x + (if (null? x) '() + `(begin ,@(map (lambda (x) `(set! ,x (break:breakf ,x ',x))) x)))) + +(defmacro defvar (var val) + `(if (not (defined? ,var)) (define ,var ,val))) + +(cond + ((defined? stack-trace) + + #+breakpoint-error;; remove this line to enable breakpointing on errors + (define (error . args) + (define cep (current-error-port)) + (perror "ERROR") + (errno 0) + (display "ERROR: " cep) + (if (not (null? args)) + (begin (display (car args) cep) + (for-each (lambda (x) (display #\ cep) (write x cep)) + (cdr args)))) + (newline cep) + (cond ((stack-trace) (newline cep))) + (display " * Breakpoint established: (continue <val>) to return." cep) + (newline cep) (force-output cep) + (require 'debug) (apply breakpoint args)) + + (define (user-interrupt . args) + (define cep (current-error-port)) + (newline cep) (display "ERROR: user interrupt" cep) + (newline cep) + (cond ((stack-trace) (newline cep))) + (display " * Breakpoint established: (continue <val>) to return." cep) + (newline cep) (force-output cep) + (require 'debug) (apply breakpoint args)) + )) + +;;; ABS and MAGNITUDE can be the same. +(cond ((and (inexact? (string->number "0.0")) (not (defined? exp))) + (if (defined? usr:lib) + (if (usr:lib "m") + (load (in-vicinity (implementation-vicinity) "Transcen") + (usr:lib "m")) + (load (in-vicinity (implementation-vicinity) "Transcen"))) + (load (in-vicinity (implementation-vicinity) "Transcen" + (scheme-file-suffix)))) + (set! abs magnitude))) + +(if (defined? array?) + (begin + (define uniform-vector? array?) + (define make-uniform-vector dimensions->uniform-array) +; (define uniform-vector-ref array-ref) + (define (uniform-vector-set! u i o) + (uniform-vector-set1! u o i)) +; (define uniform-vector-fill! array-fill!) +; (define uniform-vector-read! uniform-array-read!) +; (define uniform-vector-write uniform-array-write) + + (define (make-array fill . args) + (dimensions->uniform-array args () fill)) + (define (make-uniform-array prot . args) + (dimensions->uniform-array args prot)) + (define (list->array ndim lst) + (list->uniform-array ndim '() lst)) + (define (list->uniform-vector prot lst) + (list->uniform-array 1 prot lst)) + (define (array-shape a) + (map (lambda (ind) (if (number? ind) (list 0 (+ -1 ind)) ind)) + (array-dimensions a))))) + +;;;; Initialize statically linked add-ons +(cond ((defined? scm_init_extensions) + (scm_init_extensions) + (set! scm_init_extensions #f))) + +;;; Use *argv* instead of (program-arguments), to allow option +;;; processing to be done on it. "ScmInit.scm" must +;;; (set! *argv* (program-arguments)) +;;; if it wants to alter the arguments which BOOT-TAIL processes. +(define *argv* #f) + +;;; This loads the user's initialization file, or files named in +;;; program arguments. + +(or + (eq? (software-type) 'THINKC) + (member "-no-init-file" (program-arguments)) + (member "--no-init-file" (program-arguments)) + (try-load + (in-vicinity + (let ((home (getenv "HOME"))) + (if home + (case (software-type) + ((UNIX COHERENT) + (if (char=? #\/ (string-ref home (+ -1 (string-length home)))) + home ;V7 unix has a / on HOME + (string-append home "/"))) + (else home)) + (user-vicinity))) + "ScmInit.scm")) + (errno 0)) + +(if (not (defined? *R4RS-macro*)) + (define *R4RS-macro* #f)) +(if (not (defined? *interactive*)) + (define *interactive* #f)) + +(define (boot-tail) + (cond ((not *argv*) (set! *argv* (program-arguments)) + (cond ((provided? 'getopt) (set! *optind* 1) + (set! *optarg* #f))))) + (cond + ((and (> (length *argv*) 1) (char=? #\- (string-ref (cadr *argv*) 0))) + (require 'getopt) +;;; (else +;;; (define *optind* 1) +;;; (define getopt:opt #f) +;;; (define (getopt argc argv optstring) #f)) + + (let* ((simple-opts "muqvbis") + (arg-opts '("a kbytes" "no-init-file" "-no-init-file" + "-version" "-help" "p number" + "r feature" "f filename" "l filename" + "d filename" "c string" "e string" + "o filename")) + (opts (apply string-append ":" simple-opts + (map (lambda (o) + (string-append (string (string-ref o 0)) ":")) + arg-opts))) + (argc (length *argv*)) + (didsomething #f) + (moreopts #t) + (exe-name (symbol->string (scheme-implementation-type))) + (up-name (apply string (map char-upcase (string->list exe-name))))) + + (define (do-thunk thunk) + (if *interactive* + (thunk) + (let ((complete #f)) + (dynamic-wind + (lambda () #f) + (lambda () + (thunk) + (set! complete #t)) + (lambda () (if (not complete) (quit #f))))))) + + (define (do-string-arg) + (require 'string-port) + (do-thunk + (lambda () + ((if *R4RS-macro* macro:eval eval) + (call-with-input-string + (string-append "(begin " *optarg* ")") + read)))) + (set! didsomething #t)) + + (define (do-load file) + (do-thunk + (lambda () + (cond (*R4RS-macro* (require 'macro) (macro:load file)) + (else (load file))))) + (set! didsomething #t)) + + (define (usage preopt opt postopt success?) + (define cep (if success? (current-output-port) (current-error-port))) + (define indent (make-string 6 #\ )) + (define i 3) + (cond ((char? opt) (set! opt (string opt))) + ;;((symbol? opt) (set! opt (symbol->string opt))) + ) + (display (string-append preopt opt postopt) cep) + (newline cep) + (display (string-append "Usage: " + exe-name + " [-a kbytes] [-" simple-opts "]") cep) + (for-each + (lambda (o) + (display (string-append " [-" o "]") cep) + (set! i (+ 1 i)) + (cond ((zero? (modulo i 4)) (newline cep) (display indent cep)))) + (cdr arg-opts)) + (display " [-- | -s | -] [file] [args...]" cep) (newline cep) + (if success? (display success? cep) (exit #f))) + + ;; -a int => ignore (handled by run_scm) + ;; -c str => (eval str) + ;; -e str => (eval str) + ;; -d str => (require 'database-utilities) (open-database str) + ;; -f str => (load str) + ;; -l str => (load str) + ;; -r str => (require str) + ;; -o str => (dump str) + ;; -p int => (verbose int) + ;; -m => (set! *R4RS-macro* #t) + ;; -u => (set! *R4RS-macro* #f) + ;; -v => (verbose 3) + ;; -q => (verbose 0) + ;; -i => (set! *interactive* #t) + ;; -b => (set! *interactive* #f) + ;; -s => set argv, don't execute first one + ;; -no-init-file => don't load init file + ;; --no-init-file => don't load init file + ;; --help => print and exit + ;; --version => print and exit + ;; -- => last option + + (let loop ((option (getopt-- argc *argv* opts))) + (case option + ((#\a) + (cond ((> *optind* 3) + (usage "scm: option `-" getopt:opt "' must be first" #f)) + ((or (not (exact? (string->number *optarg*))) + (not (<= 1 (string->number *optarg*) 10000))) + ;; This size limit should match scm.c ^^ + (usage "scm: option `-" getopt:opt + (string-append *optarg* "' unreasonable") #f)))) + ((#\e #\c) (do-string-arg)) ;sh-like + ((#\f #\l) (do-load *optarg*)) ;(set-car! *argv* *optarg*) + ((#\d) (require 'database-utilities) + (open-database *optarg*)) + ((#\o) (require 'dump) + (if (< *optind* (length *argv*)) + (dump *optarg* #t) + (dump *optarg*))) + ((#\r) (do-thunk (lambda () + (if (and (= 1 (string-length *optarg*)) + (char-numeric? (string-ref *optarg* 0))) + (case (string-ref *optarg* 0) + ((#\2) (require 'rev3-procedures) + (require 'rev2-procedures)) + ((#\3) (require 'rev3-procedures)) + ((#\4) (require 'rev4-optional-procedures)) + ((#\5) (require 'dynamic-wind) + (require 'values) + (require 'macro) + (set! *R4RS-macro* #t)) + (else (require (string->symbol *optarg*)))) + (require (string->symbol *optarg*)))))) + ((#\p) (verbose (string->number *optarg*))) + ((#\q) (verbose 0)) + ((#\v) (verbose 3)) + ((#\i) (set! *interactive* #t) ;sh-like + (verbose (max 2 (verbose)))) + ((#\b) (set! didsomething #t) + (set! *interactive* #f)) + ((#\s) (set! moreopts #f) ;sh-like + (set! didsomething #t) + (set! *interactive* #t)) + ((#\m) (set! *R4RS-macro* #t)) + ((#\u) (set! *R4RS-macro* #f)) + ((#\n) (if (not (string=? "o-init-file" *optarg*)) + (usage "scm: unrecognized option `-n" *optarg* "'" #f))) + ((#\:) (usage "scm: option `-" getopt:opt "' requires an argument" #f)) + ((#\?) (usage "scm: unrecognized option `-" getopt:opt "'" #f)) + ((#f) (set! moreopts #f) ;sh-like + (cond ((and (< *optind* (length *argv*)) + (string=? "-" (list-ref *argv* *optind*))) + (set! *optind* (+ 1 *optind*))))) + (else + (or (cond ((not (string? option)) #f) + ((string-ci=? "no-init-file" option)) + ((string-ci=? "version" option) + (display + (string-append exe-name " " + (scheme-implementation-version) + " +Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. +" + up-name + " may be distributed under the terms of" + " the GNU General Public Licence; +certain other uses are permitted as well." + " For details, see the file `COPYING', +which is included in the " + up-name " distribution. +There is no warranty, to the extent permitted by law. +" + )) + (cond ((execpath) + (display " This executable was loaded from ") + (display (execpath)) + (newline))) + (quit #t)) + ((string-ci=? "help" option) + (usage "This is " + up-name + ", a Scheme interpreter." + (string-append + "Latest info: " + "http://www-swiss.ai.mit.edu/~jaffer/" + up-name ".html +" + )) + (quit #t)) + (else #f)) + (usage "scm: unknown option `--" option "'" #f)))) + + (cond ((and moreopts (< *optind* (length *argv*))) + (loop (getopt-- argc *argv* opts))) + ((< *optind* (length *argv*)) ;No more opts + (set! *argv* (list-tail *argv* *optind*)) + (set! *optind* 1) + (cond ((not didsomething) (do-load (car *argv*)) + (set! *optind* (+ 1 *optind*)))) + (cond ((and (> (verbose) 2) + (not (= (+ -1 *optind*) (length *argv*)))) + (display "scm: extra command arguments unused:" + (current-error-port)) + (for-each (lambda (x) (display (string-append " " x) + (current-error-port))) + (list-tail *argv* (+ -1 *optind*))) + (newline (current-error-port))))) + ((and (not didsomething) (= *optind* (length *argv*))) + (set! *interactive* #t))))) + + (cond ((not *interactive*) (quit)) + (*R4RS-macro* + (require 'repl) + (require 'macro) + (let* ((oquit quit)) + (set! quit (lambda () (repl:quit))) + (set! exit quit) + (repl:top-level macro:eval) + (oquit)))) + ;;otherwise, fall into non-macro SCM repl. + ) + (else + (begin (errno 0) + (set! *interactive* #t) + (for-each load (cdr (program-arguments))))))) diff --git a/Link.scm b/Link.scm new file mode 100644 index 0000000..ad88e47 --- /dev/null +++ b/Link.scm @@ -0,0 +1,284 @@ +;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this software; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;; As a special exception, the Free Software Foundation gives permission +;; for additional uses of the text contained in its release of GUILE. +;; +;; The exception is that, if you link the GUILE library with other files +;; to produce an executable, this does not by itself cause the +;; resulting executable to be covered by the GNU General Public License. +;; Your use of that executable is in no way restricted on account of +;; linking the GUILE library code into it. +;; +;; This exception does not however invalidate any other reasons why +;; the executable file might be covered by the GNU General Public License. +;; +;; This exception applies only to the code released by the +;; Free Software Foundation under the name GUILE. If you copy +;; code from other Free Software Foundation releases into a copy of +;; GUILE, as the General Public License permits, the exception does +;; not apply to the code that you add in this way. To avoid misleading +;; anyone as to the status of such modified files, you must delete +;; this exception notice from them. +;; +;; If you write modifications of your own for GUILE, it is your choice +;; whether to permit this exception to apply to your modifications. +;; If you do not wish that, delete this exception notice. + +;;;; "Link.scm", Compiling and dynamic linking code for SCM. +;;; Author: Aubrey Jaffer. + +(define cc:command + (let ((default "cc -c")) ;-O removed for HP-UX self-compile + (case (software-type) + ((unix) (if (memq 'sun-dl *features*) + "gcc -g -O -fpic -c" ; If you have problems change -fpic to + ; -fPIC (see GCC info pages). + default)) + (else default)))) + +(define link:command + (case (software-type) + (else "cc"))) + +(define scm:object-suffix + (case (software-type) + ((MSDOS VMS) ".OBJ") + (else (if (provided? 'sun-dl) ".so" ".o")))) + +;;; This is an unusual autoload because it should load either the +;;; source or compiled version if present. +(if (not (defined? hobbit)) ;Autoload for hobbit + (define (hobbit . args) + (require (in-vicinity (implementation-vicinity) "hobbit")) + (provide 'hobbit) + (apply hobbit args))) + +(define (compile-file file . args) + (apply hobbit file args) + (require (in-vicinity (implementation-vicinity) "build")) + (build-from-whole-argv + (list "build" "-tdll" + (string-append "--compiler-options=-I" (implementation-vicinity)) + "-c" + (string-append (descmify file) ".c") + ;; or (replace-suffix file (scheme-file-suffix) ".c") + "-hsystem" + ))) + +(define (link-named-scm name . modules) + (require (in-vicinity (implementation-vicinity) "build")) + (let* ((iv (implementation-vicinity)) + (oss (string-append scm:object-suffix " ")) + (command + (list "build" "--type=exe" "-cscm.c" "-hsystem" + (string-append "--linker-options=-L" (implementation-vicinity)) + (apply string-append + "-i" + (map (lambda (n) + (string-append "init_" n)) + modules)) + (apply string-append + "-j" + (map (lambda (n) + (string-append n oss)) modules)) + "-o" name))) + (cond ((>= (verbose) 3) + (write command) (newline))) + (build-from-whole-argv command))) + +;;;; Dynamic linking/loading + +(cond + ((defined? dyn:link) + (define link:modules '()) + (define link:able-suffix + (cond ((provided? 'shl) ".sl") + ((provided? 'sun-dl) ".so") + (else ".o"))) + (define link:link + (lambda (file . libs) + (define oloadpath *load-pathname*) + (let* ((sl (string-length file)) + (lasl (string-length link:able-suffix)) + (*vicinity-suffix* + (case (software-type) + ((NOSVE) '(#\: #\.)) + ((AMIGA) '(#\: #\/)) + ((UNIX) '(#\/)) + ((VMS) '(#\: #\])) + ((MSDOS ATARIST OS/2) '(#\\)) + ((MACOS THINKC) '(#\:)))) + (fname (let loop ((i (- sl 1))) + (cond ((negative? i) file) + ((memv (string-ref file i) *vicinity-suffix*) + (substring file (+ i 1) sl)) + (else (loop (- i 1)))))) + (nsl (string-length fname)) + (name (cond ((< nsl lasl) fname) + ((string-ci=? (substring fname (- nsl lasl) nsl) + link:able-suffix) + (substring fname 0 (- nsl lasl))) + (else fname))) + (linkobj #f)) + (set! *load-pathname* file) + (set! linkobj (assoc name link:modules)) + (cond (linkobj (dyn:unlink (cdr linkobj)))) + (set! linkobj (dyn:link file)) + (for-each (lambda (lib) + (cond ((dyn:link lib)) + (else (slib:error "couldn't link: " lib)))) + libs) + (cond ((not linkobj) + (set! *load-pathname* oloadpath) #f) + ((dyn:call + (string-append + "init_" (list->string (map char-downcase (string->list name)))) + linkobj) + (set! link:modules (acons name linkobj link:modules)) + (set! *load-pathname* oloadpath) #t) + (else + (dyn:unlink linkobj) + (set! *load-pathname* oloadpath) #f))))))) + +(cond + ((defined? vms:dynamic-link-call) + (define link:able-suffix #f) + (define (link:link file) + (define dir "") + (define fil "") + (let loop ((i (- (string-length file) 1))) + (cond ((negative? i) (set! dir file)) + ((memv (string-ref file i) '(#\: #\])) + (set! dir (substring file 0 (+ i 1))) + (set! fil (substring file (+ i 1) (string-length file)))) + (else (loop (- i 1))))) + (vms:dynamic-link-call dir fil (string-append "init_" fil))))) + +(set! *catalog* + (acons 'scmhob (in-vicinity (implementation-vicinity) "scmhob") + *catalog*)) +(and (defined? *catalog*) (defined? link:link) + (cond ((provided? 'dld:dyncm) + (define (usr:lib lib) + (or (and (member lib '("c" "m")) + (let ((sa (string-append "/usr/lib/lib" lib ".sa"))) + (and (file-exists? sa) sa))) + (string-append "/usr/lib/lib" lib ".a"))) + (define (x:lib lib) (string-append "/usr/X11/lib/lib" lib ".sa"))) + ((provided? 'sun-dl) + ;; These libraries are (deferred) linked in conversion to ".so" + (define (usr:lib lib) #f) + (define (x:lib lib) #f)) + ((provided? 'shl) + (define (usr:lib lib) + (if (member lib '("c" "m")) + (string-append "/lib/lib" lib link:able-suffix) + (string-append "/usr/lib/lib" lib link:able-suffix))) + (define (x:lib lib) (string-append "/usr/X11R5/lib/lib" + lib link:able-suffix))) + (else + (define (usr:lib lib) (string-append "/usr/lib/lib" lib ".a")) + (define (x:lib lib) (string-append "/usr/X11/lib/lib" lib ".sa")))) + (begin + (define wb:vicinity (string-append (implementation-vicinity) "../wb/")) + (define (catalog:add-link feature ofile . libs) + (define fe (file-exists? ofile)) + (cond ((or (not (require:feature->path feature)) fe) + ;; remove #f from libs list + (set! libs (let rem ((l libs)) + (cond ((null? l) l) + ((car l) (cons (car l) (rem (cdr l)))) + (else (rem (cdr l)))))) + (set! *catalog* + (acons feature (cons 'compiled (cons ofile libs)) + *catalog*)) + fe) + (else #f))) + (set! *catalog* + (acons 'wb-table (in-vicinity wb:vicinity "wbtab") *catalog*)) + (catalog:add-link 'db + (in-vicinity wb:vicinity "db" link:able-suffix) + (in-vicinity wb:vicinity "handle" link:able-suffix) + (in-vicinity wb:vicinity "blink" link:able-suffix) + (in-vicinity wb:vicinity "prev" link:able-suffix) + (in-vicinity wb:vicinity "ent" link:able-suffix) + (in-vicinity wb:vicinity "sys" link:able-suffix) + (in-vicinity wb:vicinity "del" link:able-suffix) + (in-vicinity wb:vicinity "stats" link:able-suffix) + (in-vicinity wb:vicinity "blkio" link:able-suffix) + (in-vicinity wb:vicinity "scan" link:able-suffix) + (usr:lib "c")) + (set! *catalog* (cons '(wb . db) *catalog*)) + (catalog:add-link 'turtle-graphics + (in-vicinity (implementation-vicinity) "turtlegr" + link:able-suffix) + (x:lib "X11") + (usr:lib "m") + (usr:lib "c")) + (catalog:add-link 'curses + (in-vicinity (implementation-vicinity) "crs" + link:able-suffix) + (usr:lib "ncurses") + ;;(usr:lib "curses") + ;;(usr:lib "termcap") + (usr:lib "c")) + (catalog:add-link 'edit-line + (in-vicinity (implementation-vicinity) "edline" + link:able-suffix) + (usr:lib "edit") + (usr:lib "termcap") + (usr:lib "c")) + (catalog:add-link 'regex + (in-vicinity (implementation-vicinity) "rgx" + link:able-suffix) + (usr:lib "c")) + (catalog:add-link 'unix + (in-vicinity (implementation-vicinity) "unix" + link:able-suffix) + (in-vicinity (implementation-vicinity) "ioext" + link:able-suffix) + (usr:lib "c")) + (catalog:add-link 'posix + (in-vicinity (implementation-vicinity) "posix" + link:able-suffix) + (usr:lib "c")) + (catalog:add-link 'socket + (in-vicinity (implementation-vicinity) "socket" + link:able-suffix) + (usr:lib "c")) + (cond ((catalog:add-link 'i/o-extensions + (in-vicinity (implementation-vicinity) "ioext" + link:able-suffix) + (usr:lib "c")) + (set! *catalog* (append '((line-i/o . i/o-extensions) + (pipe . i/o-extensions)) + *catalog*)))) + (cond ((catalog:add-link 'rev2-procedures + (in-vicinity (implementation-vicinity) "sc2" + link:able-suffix)) + (set! *catalog* (cons '(rev3-procedures . rev2-procedures) + *catalog*)))) + (catalog:add-link 'record + (in-vicinity (implementation-vicinity) "record" + link:able-suffix)) + (catalog:add-link 'generalized-c-arguments + (in-vicinity (implementation-vicinity) "gsubr" + link:able-suffix)) + (catalog:add-link 'array-for-each + (in-vicinity (implementation-vicinity) "ramap" + link:able-suffix)) + )) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2bb47f6 --- /dev/null +++ b/Makefile @@ -0,0 +1,384 @@ +# Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# +# As a special exception, the Free Software Foundation gives permission +# for additional uses of the text contained in its release of GUILE. +# +# The exception is that, if you link the GUILE library with other files +# to produce an executable, this does not by itself cause the +# resulting executable to be covered by the GNU General Public License. +# Your use of that executable is in no way restricted on account of +# linking the GUILE library code into it. +# +# This exception does not however invalidate any other reasons why +# the executable file might be covered by the GNU General Public License. +# +# This exception applies only to the code released by the +# Free Software Foundation under the name GUILE. If you copy +# code from other Free Software Foundation releases into a copy of +# GUILE, as the General Public License permits, the exception does +# not apply to the code that you add in this way. To avoid misleading +# anyone as to the status of such modified files, you must delete +# this exception notice from them. +# +# If you write modifications of your own for GUILE, it is your choice +# whether to permit this exception to apply to your modifications. +# If you do not wish that, delete this exception notice. + +# "Makefile" for scm4e6 Scheme Interpreter +# Author: Aubrey Jaffer + +SHELL = /bin/sh +#CC = +CFLAGS = #-g +#LIBS = +LD = $(CC) #-g + +# directory where COPYING and Init.scm reside. +#IMPLPATH = /usr/local/src/scm/ +#this one is good for bootstrapping +IMPLPATH = `pwd`/ +# Pathname where Init.scm resides. +IMPLINIT = $(IMPLPATH)Init.scm +DFLAG = -DIMPLINIT=\"$(IMPLINIT)\" + +# If pathname where Init.scm resides is not known in advance then +# SCM_INIT_PATH is the environment variable whose value is the +# pathname where Init.scm resides. + +intro: + @echo + @echo "This is scm$(VERSION). Read \"scm.info\" (from \"scm.texi\")" + @echo "to learn how to build and install SCM." + @echo "Here is a quick guide:" + @echo + @echo " From: bos@scrg.cs.tcd.ie" + @echo " Build and install scripts using GNU autoconf are" + @echo " available as scmconfig.tar.gz in the SCM distribution" + @echo " directories. See README.unix in scmconfig.tar.gz for" + @echo " further instructions." + @echo + @echo " Alternatively:" + @echo " make scmlit" + @echo + @echo " If you are on a non-unix system, create an empty file" + @echo " \"scmflags.h\". Then compile time.c, repl.c, scl.c," + @echo " sys.c, eval.c, subr.c, unif.c, and rope.c. Then link" + @echo " them to create a \"scmlit\" executable." + @echo + @echo " Once you have built scmlit successfully, test it:" + @echo " make checklit" + @echo " If this reports no errors, use scmlit to build.scm" + @echo " fancier versions of scm, with optional features." + +ofiles = time.o repl.o scl.o sys.o eval.o subr.o unif.o rope.o \ + continue.o findexec.o +# ramap.o + +all: scmlit +scmlit: $(ofiles) scm.o + $(LD) -o scmlit $(ofiles) scm.o $(LIBS) +scm.o: scm.c scm.h scmfig.h patchlvl.h scmflags.h + $(CC) $(CFLAGS) -c $(DFLAG) scm.c +scmflags.h: scmflags +scmflags: + echo "#ifndef IMPLINIT" > scmflags.h + echo "#define IMPLINIT \"$(IMPLINIT)\"" >> scmflags.h + echo "#endif" >> scmflags.h + +.c.o: + $(CC) -c $(CFLAGS) $< -o $@ +scl.o: scl.c scm.h scmfig.h scmflags.h +eval.o: eval.c scm.h scmfig.h scmflags.h setjump.h +unif.o: unif.c scm.h scmfig.h scmflags.h +#ramap.o: ramap.c scm.h scmfig.h scmflags.h +repl.o: repl.c scm.h scmfig.h scmflags.h setjump.h +sys.o: sys.c scm.h scmfig.h scmflags.h setjump.h +time.o: time.c scm.h scmfig.h scmflags.h +subr.o: subr.c scm.h scmfig.h scmflags.h +rope.o: rope.c scm.h scmfig.h scmflags.h +continue.o: continue.c continue.h setjump.h + $(CC) $(CFLAGS) -c continue.c + +srcdir=$(HOME)/scm/ + +udscm: + $(srcdir)build.scm -hsystem -Fcautious bignums arrays inexact \ + engineering-notation dump dynamic-linking -o udscm + +myscm: udscm $(ifiles) + ./udscm -o scm +mylib: + $(srcdir)build.scm -hsystem -Fcautious bignums arrays inexact \ + engineering-notation dump dynamic-linking -tlib +pgscm: + $(srcdir)build.scm -hsystem -Fcautious bignums arrays inexact \ + engineering-notation dump dynamic-linking -o udscm \ + --compiler-options=-pg --linker-options=-pg + ./udscm -o pgscm +mydebug: + $(srcdir)build.scm -hsystem -Fcautious bignums arrays inexact \ + engineering-notation dump dynamic-linking debug -ogdbscm \ + --compiler-options=-Wall --linker-options=-Wall +mydlls: + $(srcdir)build.scm -h system -t dll -c sc2.c rgx.c crs.c edline.c \ + record.c gsubr.c ioext.c posix.c unix.c socket.c \ + ramap.c +myturtle: + $(srcdir)build.scm -h system -F turtlegr -t dll + +checklit: r4rstest.scm + ./scmlit -fr4rstest.scm -e'(test-sc4)(test-cont)(test-delay)(gc)' +check: r4rstest.scm + ./scm -fr4rstest.scm -e'(test-sc4)(test-cont)(test-delay)(gc)' +bench: + echo `whoami`@`hostname` testing scm >> BenchLog + echo on `date` >> BenchLog + ls -l scm >> BenchLog + size scm >> BenchLog + uname -a >> BenchLog + ./scm -lbench.scm + cat bench.log >> BenchLog + echo >> BenchLog + echo + tail -20 BenchLog +benchlit: + echo `whoami`@`hostname` testing scmlit >> BenchLog + echo on `date` >> BenchLog + ls -l scmlit >> BenchLog + size scmlit >> BenchLog + uname -a >> BenchLog + ./scmlit -lbench.scm + cat bench.log >> BenchLog + echo >> BenchLog + echo + tail -20 BenchLog + +dvidir=../dvi/ +dvi: $(dvidir)scm.dvi +$(dvidir)scm.dvi: $(srcdir)scm.texi $(dvidir)scm.fn Makefile +# cd $(dvidir);texi2dvi $(srcdir)scm.texi + -(cd $(dvidir);export set TEXINPUTS=$(srcdir):$$TEXINPUTS;texindex scm.??) + cd $(dvidir);export set TEXINPUTS=$(srcdir):$$TEXINPUTS;tex $(srcdir)scm.texi +$(dvidir)scm.fn: + cd $(dvidir);tex $(srcdir)scm.texi +xdvi: $(dvidir)scm.dvi + xdvi -s 3 $(dvidir)scm.dvi +htmldir=../public_html/ +html: $(htmldir)scm_toc.html +$(htmldir)scm_toc.html: $(srcdir)scm.texi + cd $(htmldir);make scm_toc.html + +################ INSTALL DEFINITIONS ################ + +prefix = /usr/local/ +exec_prefix = $(prefix)/ +# directory where `make install' will put executable. +bindir = $(exec_prefix)bin/ +libdir = $(exec_prefix)lib/ +# directory where `make install' will put manual page. +man1dir = $(prefix)man/man1/ +infodir = $(prefix)info/ +includedir = $(prefix)include/ + +info: $(infodir)/scm.info +$(infodir)/scm.info: scm.texi + makeinfo scm.texi -o $(infodir)/scm.info + +infoz: $(infodir)/scm.info.gz +$(infodir)/scm.info.gz: $(infodir)/scm.info + -rm $(infodir)/scm.info*.gz + gzip $(infodir)/scm.info* + +install: scm.1 + test -d $(bindir) || mkdir $(bindir) + test -d $(man1dir) || mkdir $(man1dir) + -cp scm $(bindir) + -strip $(bindir)scm + -cp scm.1 $(man1dir) + test -d $(IMPLPATH) || mkdir $(IMPLPATH) + -cp Init.scm $(IMPLPATH) + -cp Link.scm $(IMPLPATH) + -cp Transcen.scm $(IMPLPATH) + -cp COPYING $(IMPLPATH) + +installlib: + test -d $(includedir) || mkdir $(includedir) + cp scm.h $(includedir)scm.h + cp scmfig.h $(includedir)scmfig.h + test -d $(libdir) || mkdir $(libdir) + cp libscm.a $(libdir)libscm.a + +uninstall: + -rm $(bindir)scm + -rm $(man1dir)scm.1 + -rm $(includedir)scm.h + -rm $(includedir)scmfig.h + -rm $(libdir)libscm.a +# -rm $(IMPLPATH)Init.scm +# -cp $(IMPLPATH)Link.scm +# -rm $(IMPLPATH)Transcen.scm +# -rm $(IMPLPATH)COPYING + +scm.doc: scm.1 + nroff -man $< | ul -tunknown >$@ + +#### Stuff for maintaining SCM below #### + +VERSION = 4e6 +ver = $(VERSION) +RM_R = rm -rf +cfiles = scm.c time.c repl.c ioext.c scl.c sys.c eval.c subr.c sc2.c \ + unif.c rgx.c crs.c dynl.c record.c posix.c socket.c unix.c \ + rope.c ramap.c gsubr.c edline.c Iedline.scm continue.c \ + findexec.c +ufiles = pre-crt0.c ecrt0.c gmalloc.c unexec.c unexelf.c +confiles = scmconfig.h.in mkinstalldirs acconfig-1.5.h install-sh \ + configure configure.in Makefile.in COPYING README.unix + +hfiles = scm.h scmfig.h setjump.h patchlvl.h continue.h +ifiles = Init.scm Transcen.scm Link.scm +tfiles = r4rstest.scm example.scm pi.scm pi.c split.scm bench.scm +dfiles = ANNOUNCE README COPYING scm.1 scm.doc QUICKREF \ + scm.texi ChangeLog +mfiles = Makefile build.scm build.bat +vfiles = setjump.mar setjump.s +afiles = $(dfiles) $(cfiles) $(hfiles) $(ifiles) $(tfiles) $(mfiles) \ + $(vfiles) $(ufiles) + +makedev = make -f $(HOME)/makefile.dev +CHPAT=$(HOME)/bin/chpat +dest = $(HOME)/dist/ +temp/scm: $(afiles) + -$(RM_R) temp + mkdir temp + mkdir temp/scm + ln $(afiles) temp/scm + +dist: $(dest)scm$(VERSION).tar.gz +$(dest)scm$(VERSION).tar.gz: temp/scm + $(makedev) DEST=$(dest) PROD=scm ver=$(VERSION) tar.gz +shar: scm.shar +scm.shar: temp/scm + $(makedev) PROD=scm shar +dclshar: scm.com +com: scm.com +scm.com: temp/scm + $(makedev) PROD=scm com +zip: scm.zip +scm.zip: temp/scm + $(makedev) PROD=scm zip +distzip: scm$(VERSION).zip +scm$(VERSION).zip: temp/scm turtle turtlegr.c grtest.scm require.scm + $(makedev) DEST=$(dest) PROD=scm ver=$(VERSION) zip + cd ..; zip -9ur $(dest)scm$(VERSION).zip \ + scm/turtle scm/turtlegr.c scm/grtest.scm scm/require.scm + mv $(dest)scm$(VERSION).zip /c/scm/dist/ +pubzip: temp/scm + $(makedev) DEST=$(HOME)/pub/ PROD=scm zip + +diffs: pubdiffs +pubdiffs: temp/scm + $(makedev) DEST=$(HOME)/pub/ PROD=scm pubdiffs +distdiffs: temp/scm + $(makedev) DEST=$(dest) PROD=scm ver=$(ver) distdiffs + + +HOBBITVERSION = 4d +hobfiles = README.hob hobbit.doc hobbit.tms hobbit.scm scmhob.h + +hobtemp/scm: $(hobfiles) + -$(RM_R) hobtemp + mkdir hobtemp + mkdir hobtemp/scm + ln $(hobfiles) hobtemp/scm + +hobdist: $(dest)hobbit$(HOBBITVERSION).tar.gz +$(dest)hobbit$(HOBBITVERSION).tar.gz: hobtemp/scm + $(makedev) DEST=$(dest) PROD=scm ver=-hob$(HOBBITVERSION) \ + tar.gz TEMP=hobtemp/ + mv $(dest)scm-hob$(HOBBITVERSION).tar.gz \ + $(dest)hobbit$(HOBBITVERSION).tar.gz +hobbit$(HOBBITVERSION).zip: hobtemp/scm + $(makedev) TEMP=hobtemp/ name=hobbit$(HOBBITVERSION) PROD=scm zip + +new: + $(CHPAT) scm$(VERSION) scm$(ver) ANNOUNCE ../jacal/ANNOUNCE \ + ../wb/README ../wb/ANNOUNCE \ + ../public_html/README.html ../dist/README \ + ../public_html/SLIB.html ../public_html/JACAL.html \ + ../public_html/SCM.html ../public_html/Hobbit.html \ + /c/scm/dist/install.bat /c/scm/dist/makefile \ + /c/scm/dist/mkdisk.bat + $(CHPAT) $(VERSION) $(ver) README scm.texi patchlvl.h \ + Init.scm ../public_html/SCM.html Makefile + +configtemp/scm: $(confiles) + -$(RM_R) configtemp/scm + -mkdir configtemp + mkdir configtemp/scm + ln $(confiles) configtemp/scm +confdist: scmconfig.tar.gz +scmconfig.tar.gz: configtemp/scm + cd configtemp; tar cohf ../scmconfig.tar scm + chmod 664 scmconfig.tar + -rm -f scmconfig.tar.*z + gzip scmconfig.tar + chmod 664 scmconfig.tar.*z + +lint: lints +lints: $(cfiles) $(hfiles) + lint $(CPPFLAGS) $(ALL_CFLAGS) $(cfiles) | tee lints +# lint $(CPPFLAGS) $(ALL_CFLAGS) $(cfiles) | tee lintes + +#seds to help find names not unique in first 8 characters (name8s) +# for BSD nm format +SED_TO_STRIP_NM=sed -e '/.*\.o$$/d' -e 's/.* _//' -e 's/.* T //' +#old, bad for T [^_] on suns: SED_TO_STRIP_NM=sed -e '/.*\.o$$/d' -e 's/.* _//' +# For a System V nm where plain C identifiers have _ prepended: +#SED_TO_STRIP_NM=sed -e '/^_[A-Za-z][A-za-z0-9_]*[ |].*|extern|!d' -e 's/|/ /g' -e 's/^_//' +# For a System V nm where plain C identifiers have nothing prepended: +#SED_TO_STRIP_NM=sed -e '/^[A-Za-z][A-za-z0-9_]*[ |].*|extern|!d' -e 's/|/ /g' + +name8: name8s +name8s: scm + nm scm |\ + $(SED_TO_STRIP_NM) |\ + sort -u|\ + awk '{ if (substr(l,1,8)==substr($$1,1,8)) {\ + if (p) print l;\ + print $$1;p=0;stat=1\ + }else p=1;\ + l=$$1\ + }END{exit stat}' - +ctags: $(hfiles) $(cfiles) + etags $(hfiles) $(cfiles) +TAGS: +tags: $(hfiles) $(cfiles) $(ifiles) $(vfiles) $(ufiles)\ + hobbit.scm scm.texi README build.scm # $(mfiles) ChangeLog + etags $(hfiles) $(cfiles) $(ifiles) $(vfiles) $(ufiles)\ + hobbit.scm scm.texi README build.scm # $(mfiles) ChangeLog +mostlyclean: +clean: + -rm -f *~ *.bak *.orig *.rej core a.out ramap.o $(ofiles) scm.o \ + lints tmp* \#* *\# + -$(RM_R) *temp +distclean: clean + -rm -f $(EXECFILES) *.o a.out TAGS +realclean: distclean + -rm -f scm.doc +realempty: temp/scm + -rm -f $(afiles) diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..c2f69c5 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,462 @@ +# Copyright (C) 1990, 1991, 1992, 1993 Aubrey Jaffer. -*- Makefile -*- +# This file is part of SCM. +# +# SCM is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# SCM is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SCM; see the file COPYING. If not, write to the Free +# Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +# +# Makefile for SCM +# + +# Ultrix 2.2 make doesn't expand the value of VPATH. +srcdir = @srcdir@ + +CC = @CC@ + +CFLAGS = @CFLAGS@ -I. -I$(srcdir) +LDFLAGS = @LDFLAGS@ + +# Define these for your system as follows: +# -DRTL To create a run-time library only (no +# interactive front end). +# -DRECKLESS To turn most SCM error schecking off. +# -DCAUTIOUS To always check the number of arguments to +# interpreted closures. +# -DIO_EXTENSIONS To get primitives such as chdir, delete-file, +# file-opisition, and pipes. +# -DPROMPT=\"..\" To change the default prompt. +# -DFLOATS To turn on support for inexact numbers. +# -DSINGLES To use single-precision floats (if a float is +# the same size as a long). +# -DSINGLESONLY To make all inexact real numbers to be single +# precision. Only useful if SINGLES is also +# defined. +# -DGC_FREE_SEGMENTS +# To have all segments of unused heap be freed +# up after garbage collection. Do not define if +# you never want the heap to shrink. +# -DTICKS If you want the ticks and ticks-interrupt +# functions defined. +# -DBRACKETS_AS_PARENS +# To have square brackets read as parentheses +# in forms. +# -DMEMOIZE_LOCALS To speed up most local variable references. +# You will need to remove this and recompile +# eval.c if you use very large or deep +# environments (more than 4095 bound variables +# in one procedure). +# -DENGNOT To use engineering notation instead of +# scientific notation. +# -DSICP To make SCM more compatible with the Scheme used +# in Abelson & Sussman's book. +# -DSTACK_LIMIT To limit the maximum growth of the stack (you +# almost certainly don't want this). +# See also `scmconfig.h' and `scmfig.h'. +defines = @DEFS@ \ + -DCAUTIOUS -DARRAYS -DBIGNUMS -DCCLO \ + -DFLOATS -DIO_EXTENSIONS -DMEMOIZE_LOCALS -DGC_FREE_SEGMENTS + +# If you are using user extension files, change INITS and FINALS +# below. INITS makes up the initialization calls for user extension +# files. FINALS defines the finalization calls for user extension +# files. + +# File INITS FINALS functions defined +# +# sc2.c init_sc2\(\) substring-move-left!, +# substring-move-right!, +# substring-fill!, append!, last-pair +# rgx.c init_rgx\(\) regcomp, regexec (POSIX) +# crs.c init_curses\(\) lendwin\(\) ... lots ... + +INITS = -DINITS=init_sc2\(\)\; +FINALS = -DFINALS=\; + +# If you are using rgx.c, set the next line to point to the include +# directory where your POSIX regexp include files live (if you are using +# GNU regex). +# RGXFLAGS = -I/archive/regex-0.11/ + +# If your system needs extra libraries loaded in, define them here. +# -lm For floating point math (needed). +# -lcurses For crs.c extensions. +# -lncurses For curses on Linux (curses has bugs). +# -lterm{cap,lib} May be required for curses support. +# -lregex For POSIX regexp support (rgx.c). +LOADLIBES = @LIBS@ -lm + +# Any extra object files your system needs. +extras = @LIBOBJS@ + +# Common prefix for machine-independent installed files. +prefix = /usr/local +# Common prefix for machine-dependent installed files. +exec_prefix = $(prefix) + +# Name under which to install SCM. +instname = scm +# Directory to install `scm' in. +bindir = $(exec_prefix)/bin +# Directory in which to install Init.scm, COPYING, and Transcen.scm. +libdir = $(exec_prefix)/lib/scm +# Directory to search by default for included makefiles. +includedir = $(prefix)/include +# Directory to install the Info files in. +infodir = $(prefix)/info +# Directory to install the man page in. +mandir = $(prefix)/man/man$(manext) +# Number to put on the man page filename. +manext = 1 +# Directory to perform pre-install tests in. +testdir = $(srcdir) + +# Program to install `scm'. +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +# Program to install the man page. +INSTALL_DATA = @INSTALL_DATA@ +# Generic install program. +INSTALL = @INSTALL@ + +# Program to format Texinfo source into Info files. +MAKEINFO = makeinfo +# Program to format Texinfo source into DVI files. +TEXI2DVI = texi2dvi + +# Programs to make tags files. +ETAGS = etags +CTAGS = ctags -tw + +# You should not need to change below this line. + +SHELL = /bin/sh +DFLAG = -DIMPLINIT=\"$(libdir)/Init.scm\" +TDFLAG = -DIMPLINIT=\"$(testdir)/Init.scm\" +# nunix = nonunix +nunix = $(srcdir) +# examples = examples +examples = $(srcdir) +ffiles = continue.o time.o repl.o fscl.o sys.o feval.o subr.o sc2.o \ +funif.o rope.o ramap.o findexec.o #rgx.o +fifiles = continue.o time.o repl.o iscm.o fscl.o sys.o feval.o subr.o \ +sc2.o funif.o rope.o ramap.o findexec.o #rgx.o +efiles = time.o repl.o escl.o sys.o eeval.o subr.o sc2.o eunif.o #rgx.o +cfiles = $(srcdir)/scm.c $(srcdir)/time.c $(srcdir)/repl.c \ + $(srcdir)/scl.c $(srcdir)/sys.c $(srcdir)/eval.c \ + $(srcdir)/subr.c $(srcdir)/sc2.c $(srcdir)/unif.c \ + $(srcdir)/rgx.c $(srcdir)/crs.c $(srcdir)/dynl.c $(srcdir)/findexec.c +hfiles = $(srcdir)/scm.h $(srcdir)/scmfig.h scmconfig.h \ + $(srcdir)/setjump.h $(srcdir)/patchlvl.h +ifiles = Init.scm Transcen.scm +tfiles = $(examples)/test.scm $(examples)/example.scm \ + $(examples)/pi.scm $(examples)/pi.c $(examples)/split.scm +dfiles = $(srcdir)/README $(srcdir)/COPYING $(srcdir)/scm.1 \ + $(srcdir)/QUICKREF $(srcdir)/MANUAL $(srcdir)/ChangeLog \ + $(srcdir)/code.doc $(srcdir)/ANNOUNCE +mfiles = Makefile $(nunix)/makefile.msc $(nunix)/makefile.bor \ + $(nunix)/makefile.tur $(nunix)/makefile.djg \ + $(nunix)/makefile.emx $(nunix)/makefile.qc \ + $(nunix)/compile.amiga $(nunix)/link.amiga \ + $(nunix)/makefile.aztec $(nunix)/makefile.ast \ + $(nunix)/makefile.prj $(nunix)/dmakefile \ + $(nunix)/makefile.wcc +vfiles = $(nunix)/setjump.mar $(nunix)/VMSBUILD.COM $(nunix)/VMSGCC.COM +afiles = $(dfiles) $(cfiles) $(hfiles) $(ifiles) $(tfiles) $(mfiles) $(vfiles) + +.SUFFIXES: +.SUFFIXES: .o .c .h .ps .dvi .info .texinfo .scm + +.PHONY: all +all: scm + +# -DINITS= the initialization calls for user extension files. +# -DFINALS= the finalialization calls for user extension files. +dbscm: escm.a sc2.o $(srcdir)/../wb/db.a $(srcdir)/scm.c $(srcdir)/scm.h \ + $(srcdir)/scmfig.h $(srcdir)/patchlvl.h Makefile + $(CC) -o dbscm $(CFLAGS) $(INITS)init_db\(\)\;init_rgx\(\) \ + $(FINALS)final_db\(\) $(defines) $(srcdir)/scm.c \ + escm.a $(srcdir)/../wb/db.a $(LOADLIBES) $(extras) + rm escm.a +curscm: escm.a crs.o + $(CC) -o curscm $(CFLAGS) $(INITS)init_curses\(\)\;init_rgx\(\) \ + $(FINALS)lendwin\(\) $(srcdir)/scm.c crs.o escm.a -lcurses \ + $(LOADLIBES) $(extras) + rm escm.a +dscm: dscm.a main.o + $(CC) -o dscm $(CFLAGS) main.o -ldld +dscm.a: $(efiles) Makefile dynl.o $(srcdir)/scm.c + $(CC) $(CFLAGS) -DRTL $(INITS)init_dynl\(\) -c $(srcdir)/scm.c + ar crvs dscm.a scm.o dynl.o $(efiles) $(LOADLIBES) +dynl.o: $(srcdir)/dynl.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + Makefile + $(CC) $(CFLAGS) -DDLD -DRTL -c $(srcdir)/dynl.c + +instscm: $(fifiles) + $(CC) -o instscm $(fifiles) $(LOADLIBES) $(extras) + +scm: $(ffiles) fscm.o + $(CC) -o scm $(ffiles) fscm.o $(LOADLIBES) $(extras) +fscm.o: $(srcdir)/scm.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + scmconfig.h $(srcdir)/patchlvl.h + $(CC) $(CFLAGS) $(TDFLAG) $(defines) -c $(FFLAGS) $(INITS) \ + $(FINALS) $(srcdir)/scm.c + mv scm.o fscm.o + +iscm.o: $(srcdir)/scm.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + scmconfig.h $(srcdir)/patchlvl.h + $(CC) $(CFLAGS) $(DFLAG) $(defines) -c $(FFLAGS) $(INITS) \ + $(FINALS) $(srcdir)/scm.c + mv scm.o iscm.o + +fscl.o: $(srcdir)/scl.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(FFLAGS) $(srcdir)/scl.c + mv scl.o fscl.o +feval.o: $(srcdir)/eval.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(FFLAGS) $(srcdir)/eval.c + mv eval.o feval.o +funif.o: $(srcdir)/unif.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(FFLAGS) $(srcdir)/unif.c + mv unif.o funif.o + +escm: $(efiles) escm.o + $(CC) -o escm $(efiles) escm.o $(LOADLIBES) $(extras) +escm.o: $(srcdir)/scm.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + scmconfig.h $(srcdir)/patchlvl.h + $(CC) $(CFLAGS) $(defines) -c $(INITS) $(FINALS) $(srcdir)/scm.c + mv scm.o escm.o +escl.o: $(srcdir)/scl.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(srcdir)/scl.c + mv scl.o escl.o +eeval.o: $(srcdir)/eval.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(srcdir)/eval.c + mv eval.o eeval.o +eunif.o: $(srcdir)/unif.c $(srcdir)/scm.h scmconfig.h + $(CC) $(CFLAGS) $(defines) -c unif.c + mv unif.o eunif.o + +repl.o: $(srcdir)/repl.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + $(srcdir)/setjump.h scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(TDFLAG) $(srcdir)/repl.c +sys.o: $(srcdir)/sys.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + $(srcdir)/setjump.h scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(srcdir)/sys.c +continue.o: $(srcdir)/continue.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + $(srcdir)/setjump.h scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(srcdir)/continue.c +rope.o: $(srcdir)/rope.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + $(srcdir)/setjump.h scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(srcdir)/rope.c +ramap.o: $(srcdir)/ramap.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + $(srcdir)/setjump.h scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(srcdir)/ramap.c +time.o: $(srcdir)/time.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(srcdir)/time.c +subr.o: $(srcdir)/subr.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(srcdir)/subr.c +sc2.o: $(srcdir)/sc2.c $(srcdir)/scm.h scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(srcdir)/sc2.c +rgx.o: $(srcdir)/rgx.c $(srcdir)/scm.h Makefile scmconfig.h + $(CC) $(CFLAGS) $(defines) $(RGXFLAGS) -c rgx.c +crs.o: $(srcdir)/crs.c $(srcdir)/scm.h scmconfig.h + $(CC) $(CFLAGS) $(defines) -c crs.c +findexec.o: $(srcdir)/findexec.c + $(CC) $(CFLAGS) $(defines) -c $(srcdir)/findexec.c + +both: scm escm + +$(srcdir)/proto.h: $(cfiles) + rm -f $(srcdir)/proto.h + mkproto $(cfiles) > $(srcdir)/proto.h + +libscm.a: rtlscm.o $(ffiles) + rm -f libscm.a + ar rc libscm.a rtlscm.o $(ffiles) + $(RANLIB) libscm.a + +rtlscm.o: $(srcdir)/scm.c $(srcdir)/scm.h $(srcdir)/scmfig.h \ + $(srcdir)/patchlvl.h scmconfig.h + $(CC) $(CFLAGS) $(defines) -c $(FFLAGS) -DRTL $(INITS)init_user_scm\(\) \ + $(FINALS) $(srcdir)/scm.c + mv scm.o rtlscm.o + +.PHONY: install installdirs +install: installdirs \ + $(bindir)/$(instname) $(mandir)/$(instname).$(manext) \ + $(libdir)/Init.scm $(libdir)/Transcen.scm $(libdir)/COPYING + +installdirs: + $(SHELL) ${srcdir}/mkinstalldirs $(bindir) $(infodir) \ + $(mandir) $(libdir) + +$(bindir)/$(instname): instscm + $(INSTALL_PROGRAM) instscm $@.new +# Some systems can't deal with renaming onto a running binary. + -rm -f $@.old + -mv $@ $@.old + mv $@.new $@ + +$(mandir)/$(instname).$(manext): $(srcdir)/scm.1 + $(INSTALL_DATA) $(srcdir)/scm.1 $@ + +$(libdir)/Init.scm: $(srcdir)/Init.scm + $(INSTALL_DATA) $(srcdir)/Init.scm $@ + +$(libdir)/Transcen.scm: $(srcdir)/Transcen.scm + $(INSTALL_DATA) $(srcdir)/Transcen.scm $@ + +$(libdir)/COPYING: $(srcdir)/COPYING + $(INSTALL_DATA) $(srcdir)/COPYING $@ + +.PHONY: tar shar dclshar com zip pubzip +tar: scm.tar +shar: scm.shar +dclshar: scm.com +com: scm.com +zip: scm.zip +scm.tar: temp/scm + cd temp; tar chf ../scm.tar scm + chmod 664 scm.tar +scm.shar: temp/scm + cd temp; shar scm >../scm.shar + chmod 664 scm.shar +scm.com: temp/scm + cd temp; dclshar scm >../scm.com + chmod 664 scm.com +scm.zip: temp/scm + cd temp; zip -r ../scm.zip scm + chmod 664 scm.zip +pubzip: temp/scm + cd temp; zip -ru ../../pub/scm.zip scm + chmod 664 ../pub/scm.zip + +temp/scm: $(afiles) + -rm -rf temp + mkdir temp + mkdir temp/scm + ln $(afiles) temp/scm + +.PHONY: dist tar.Z tar.gz shar.Z +dist: tar.gz +tar.Z: scm.tar.Z +tar.gz: scm.tar.gz +shar.Z: scm.shar.Z +scm.tar.Z: scm.tar + -rm -f scm.tar.Z + compress scm.tar + chmod 664 scm.tar.Z +scm.tar.gz: scm.tar + -rm -f scm.tar.gz + gzip scm.tar + chmod 664 scm.tar.gz +scm.shar.Z: scm.shar + -rm -f scm.shar.Z + compress scm.shar + chmod 664 scm.shar.Z + +.PHONY: pubdiffs distdiffs +pubdiffs: temp/scm + mv temp/scm temp/nscm + cd temp;unzip ../../pub/scm.zip + -rm -f scm.diffs + -diff -c temp/scm temp/nscm > scm.diffs + -rm -rf temp + ls -l scm.diffs +distdiffs: temp/scm + mv temp/scm temp/nscm + cd temp;zcat ../../dist/scm*.tar.gz | tar xvf - + -rm -f scm.pat + -diff -c temp/scm temp/nscm > scm.pat + -rm -rf temp + ls -l scm.pat + +.PHONY: checks check echeck +checks: check echeck +check: ./scm test.scm + echo '(test-sc4)(test-cont)(test-inexact)(gc)(exit (length errs))' \ + | ./scm test.scm +echeck: ./escm test.scm + echo '(test-sc4)(test-cont)(gc)(exit (length errs))' \ + | ./escm test.scm + +.PHONY: lint +lint: lints +lints: $(cfiles) $(hfiles) + lint $(CFLAGS) $(cfiles) | tee lints +# lint $(CFLAGS) $(cfiles) | tee lintes + +# Seds to help find names not unique in first 8 characters (name8s). +# for BSD nm format +# SED_TO_STRIP_NM = sed -e '/.*\.o$$/d' -e 's/.* _//' -e 's/.* T //' +#old, bad for T [^_] on suns: SED_TO_STRIP_NM=sed -e '/.*\.o$$/d' -e 's/.* _//' +# For a System V nm where plain C identifiers have _ prepended: +#SED_TO_STRIP_NM = sed -e '/^_[A-Za-z][A-za-z0-9_]*[ |].*|extern|!d' -e 's/|/ /g' -e 's/^_//' +# For a System V nm where plain C identifiers have nothing prepended: +#SED_TO_STRIP_NM = sed -e '/^[A-Za-z][A-za-z0-9_]*[ |].*|extern|!d' -e 's/|/ /g' +SED_TO_STRIP_NM = : + +.PHONY: name8 +name8: name8s +name8s: scm + nm scm |\ + $(SED_TO_STRIP_NM) |\ + sort -u|\ + awk '{ if (substr(l,1,8)==substr($$1,1,8)) {\ + if (p) print l;\ + print $$1;p=0;stat=1\ + }else p=1;\ + l=$$1\ + }END{exit stat}' - |\ + tee name8s + +tagsrcs = $(hfiles) $(cfiles) $(ifiles) $(mfiles) $(vfiles) \ + MANUAL code.doc README +TAGS: $(tagsrcs) + $(ETAGS) $(tagsrcs) +tags: $(tagsrcs) + $(CTAGS) $(tagsrcs) + +.PHONY: clean cleanish realclean +clean: + -rm -f *~ \#* *.o *\# *.orig *.rej a.out core lints tmp* + -rm -rf temp hobtemp +cleanish: + -rm -f *~ \#* *\# *.orig *.rej a.out core lints tmp* + -rm -rf temp hobtemp +distclean: + -rm -f *~ \#* *.o *\# *.orig *.rej a.out core TAGS lints tmp* \ + scmconfig.h config.status + -rm -rf temp hobtemp + +Makefile: config.status $(srcdir)/Makefile.in + $(SHELL) config.status +scmconfig.h: stamp-config ; +stamp-config: config.status $(srcdir)/scmconfig.h.in + $(SHELL) config.status + touch stamp-config + +configure: configure.in + autoconf $(ACFLAGS) +scmconfig.h.in: configure.in + autoheader $(ACFLAGS) + +# This tells versions [3.59,3.63) of GNU make not to export all variables. +.NOEXPORT: + +# Automatically generated dependencies will be put at the end of the file. diff --git a/QUICKREF b/QUICKREF new file mode 100644 index 0000000..93ca5d4 --- /dev/null +++ b/QUICKREF @@ -0,0 +1,201 @@ +;; FILE "Scheme Sigs" +;; IMPLEMENTS R^4RS Function Signature Synopsis +;; AUTHOR Kenneth A Dickey +;; DATE 1992 October 2 +;; LAST UPDATED 1992 October 3 +;; NOTES: Extracted from Amiga Gambit QuickTour file + +=== FUNCTION SYNOPSIS === + +Notation: + <object> any Scheme data object. + <object>* zero or more objects + <object>+ one or more objects + [<object>] optional object + ( <whatever> )... Zero or more occurances of ( <whatever> ) + +; SYNTAX + + (LAMBDA <name> <exp>+ ) + (LAMBDA (<name>* ) <exp>+ ) + (AND <exp>*) + (OR <exp>*) + (IF <test-exp> <if-true> [<if-false>] ) + (COND (<test> <exp>* )... [(ELSE <exp>+)] ) + (CASE <key-exp> ((<datum>+ ) <exp>* )... [(ELSE <exp>+)] ) + (DEFINE ( <name> <name>* ) <exp>+ ) + (DEFINE <name> <exp> ) + (LET [<name>] ( (<vname> <value-exp>)... ) <exp>+ ) + (LET* ( (<vname> <value-exp>)... ) <exp>+ ) + (LETREC ( (<vname> <value-exp>)... ) <exp>+ ) + (BEGIN <expression>+ ) + (DO ( (<var> <init> <step>)... ) ( <test> <exp>* ) <exp>* ) + ;; Note also R^4RS syntax, below + + +; IEEE Scheme + + (NOT <object>) + (BOOLEAN? <object>) + + (EQ? <obj1> <obj2>) + (EQV? <obj1> <obj2>) + (EQUAL? <obj1> <obj2>) + + (PAIR? <object>) + (CONS <obj1> <obj2>) + (CAR <pair>) + (CDR <pair>) + (SET-CAR! <pair> <object>) + (SET-CDR! <pair> <object>) + (CAAR <list>) (CADR <list>) (CDAR <list>) (CDDR <list>) + (CAAAR <list>) (CAADR <list>) (CADAR <list>) (CADDR <list>) + (CDAAR <list>) (CDADR <list>) (CDDAR <list>) (CDDDR <list>) + (CAAAAR <list>) (CAAADR <list>) (CAADAR <list>) (CAADDR <list>) + (CADAAR <list>) (CADADR <list>) (CADDAR <list>) (CADDDR <list>) + (CDAAAR <list>) (CDAADR <list>) (CDADAR <list>) (CDADDR <list>) + (CDDAAR <list>) (CDDADR <list>) (CDDDAR <list>) (CDDDDR <list>) + (NULL? <object>) + (LIST? <object>) + (LIST <object>* ) + (LENGTH <list>) + (APPEND <list>+ ) + (REVERSE <list>) + (LIST-REF <list> <index>) + + (MEMQ <object> <list>) + (MEMV <object> <list>) + (MEMBER <object> <list>) + + (ASSQ <object> <alist>) + (ASSV <object> <alist>) + (ASSOC <object> <alist>) + + (SYMBOL? <object>) (SYMBOL->STRING <symbol>) (STRING->SYMBOL <string>) + + (NUMBER? <object>) + (COMPLEX? <object>) + (REAL? <object>) + (RATIONAL? <object>) + (INTEGER? <object>) + (EXACT? <number>) (INEXACT? <number>) + (= <number>+ ) + (< <number>+ ) (> <number>+ ) + (<= <number>+ ) (>= <number>+ ) + (ZERO? <number>) + (POSITIVE? <number>) (NEGATIVE? <number>) + (ODD? <number>) (EVEN? <number>) + (MAX <number>+ ) (MIN <number>+ ) + (+ <number>+ ) + (* <number>+ ) + (- <number>+ ) + (/ <number>+ ) + (ABS <number>) + (QUOTIENT <num1> <num2>) (REMAINDER <num1> <num2>) + (MODULO <num1> <num2>) + (GCD <number>* ) (LCM <number>* ) + (NUMERATOR <rational>) (DENOMINATOR <rational>) + (FLOOR <number>) (CEILING <number>) + (TRUNCATE <number>) (ROUND <number>) + (RATIONALIZE <num1> <num2>) + (EXP <number>) (LOG <number>) + (SIN <number>) (COS <number>) (TAN <number>) + (ASIN <number>) (ACOS <number>) (ATAN <number> [<number>]) + (SQRT <number>) + (EXPT <num1> <num2>) + (MAKE-RECTANGULAR <num1> <num2>) (MAKE-POLAR <num1> <num2>) + (REAL-PART <number>) (IMAG-PART <number>) + (MAGNITUDE <number>) (ANGLE <number>) + (EXACT->INEXACT <number>) (INEXACT->EXACT <number>) + (NUMBER->STRING <number>) (STRING->NUMBER <string>) + + (CHAR? <object>) + (CHAR=? <char1> <char2>) (CHAR-CI=? <char1> <char2>) + (CHAR<? <char1> <char2>) (CHAR-CI<? <char1> <char2>) + (CHAR>? <char1> <char2>) (CHAR-CI>? <char1> <char2>) + (CHAR<=? <char1> <char2>) (CHAR-CI<=? <char1> <char2>) + (CHAR>=? <char1> <char2>) (CHAR-CI>=? <char1> <char2>) + (CHAR-ALPHABETIC? <character>) + (CHAR-NUMERIC? <character>) + (CHAR-WHITESPACE? <character>) + (CHAR-UPPER-CASE? <character>) (CHAR-LOWER-CASE? <character>) + (CHAR->INTEGER <character>) (INTEGER->CHAR <integer>) + (CHAR-UPCASE <character>) (CHAR-DOWNCASE <character>) + + (STRING? <object>) + (MAKE-STRING <length> [<character>] ) + (STRING <character>+ ) + (STRING-LENGTH <string>) + (STRING-REF <string> <index>) + (STRING-SET! <string> <index> <character>) + (STRING=? <string1> <string2>) (STRING-CI=? <string1> <string2>) + (STRING<? <string1> <string2>) (STRING-CI<? <string1> <string2>) + (STRING>? <string1> <string2>) (STRING-CI>? <string1> <string2>) + (STRING<=? <string1> <string2>) (STRING-CI<=? <string1> <string2>) + (STRING>=? <string1> <string2>) (STRING-CI>=? <string1> <string2>) + (SUBSTRING <string> <start-index> <end-index>) + (STRING-APPEND <string>+ ) + + (VECTOR? <object>) + (MAKE-VECTOR <length> [<object>] ) + (VECTOR <object>* ) + (VECTOR-LENGTH <vector>) + (VECTOR-REF <vector> <index>) + (VECTOR-SET! <vector> <index> <object>) + + (PROCEDURE? <object>) + (APPLY <procedure> <arg>* <arg-list>) + (MAP <procedure> <list>+ ) + (FOR-EACH <procedure> <list>+ ) + (CALL-WITH-CURRENT-CONTINUATION <one-argument-procedure>) + + (CALL-WITH-INPUT-FILE <string> <procedure>) + (CALL-WITH-OUTPUT-FILE <string> <procedure>) + (INPUT-PORT? <object>) (OUTPUT-PORT? <object>) + (CURRENT-INPUT-PORT) (CURRENT-OUTPUT-PORT) + (OPEN-INPUT-FILE <string>) (OPEN-OUTPUT-FILE <string>) + (CLOSE-INPUT-PORT <input-port>) (CLOSE-OUTPUT-PORT <output-port>) + (EOF-OBJECT? <object>) + (READ [<input-port>] ) + (READ-CHAR [<input-port>] ) + (PEEK-CHAR [<input-port>] ) + (WRITE <object> [<output-port>] ) + (DISPLAY <object> [<output-port>] ) + (NEWLINE [<output-port>] ) + (WRITE-CHAR <character> [<output-port>] ) + + +; R4RS Scheme + + (LIST-TAIL <list> <index>) + (STRING->LIST <string>) + (LIST->STRING <list-of-characters>) + (STRING-COPY <string>) + (STRING-FILL! <string> <character>) + (VECTOR->LIST <vector>) + (LIST->VECTOR <list>) + (VECTOR-FILL! <vector> <object>) + (DELAY <expression>) + (FORCE <promise>) + (WITH-INPUT-FROM-FILE <string> <thunk>) + (WITH-OUTPUT-TO-FILE <string> <thunk>) + (CHAR-READY? [<input-port>] ) + (LOAD <string>) + (TRANSCRIPT-ON <string>) + (TRANSCRIPT-OFF) + + (DEFINE-SYNTAX <name> <transformer-spec>) -- High-Level macros (only) + (LET-SYNTAX ( <syntax-spec>* ) <exp>+ ) + (LETREC-SYNTAX ( <syntax-spec>* ) <exp>+ ) + + + +=== STANDARDS REFERENCES === + + +IEEE Standard 1178-1990. "IEEE Standard for the Scheme Programming +Language", IEEE, New York, 1991, ISBN 1-55937-125-0 [1-800-678-IEEE: +order # SH14209]. -- now also an ANSI standard. + +W. Clinger and J. Rees, eds., "Revised^4 Report on the Algorithmic +Language Scheme", ACM LISP Pointers IV, 3 (July-September 1991). @@ -0,0 +1,384 @@ +This directory contains the distribution of scm4e6. Scm conforms to +Revised^4 Report on the Algorithmic Language Scheme and the IEEE P1178 +specification. Scm runs under VMS, MS-DOS, OS2, MacOS, Amiga, +Atari-ST, NOS/VE, Unix and similar systems. + +This file consists mainly of excerpts from "scm.info", the result of +compiling (with makeinfo) "scm.texi" to `info' form. In case of +conflicts with "scm.info", consult "scm.info". + +The author can be reached at <jaffer@ai.mit.edu> + + MANIFEST + + `README' is this file. It contains a MANIFEST, INSTALLATION + INSTRUCTIONS, hints for EDITING SCHEME CODE, and a TROUBLE + SHOOTING GUIDE. + `COPYING' details the LACK OF WARRANTY for scm and the conditions + for distributing scm. + `scm.1' is the unix style man page in nroff format. + `scm.doc' is the text man page generated from scm.1. + `QUICKREF' is a Quick Reference card for IEEE and R4RS. + `scm.texi' details feature support and enhancements to Scheme and + contains a SCHEME BIBLIOGRAPHY. + `ChangeLog' documents changes to the scm. + + `r4rstest.scm' is Scheme code which tests conformance with Scheme + specifications. + `example.scm' is Scheme code from Revised^4 Report on the + Algorithmic Language Scheme which uses inexact numbers. + `pi.scm' is Scheme code for computing digits of pi [type (pi 100 5)] + which can be used to test the performance of scm against + compiled C code [cc -o pi pi.c;time pi 100 5]. + `pi.c' is C code for computing digits of pi. + `bench.scm' is Scheme code for computing and recording speed of + "pi.scm". + + `Makefile' is for building scmlit using the `make' program. + `build.scm' creates a database and program for compiling and linking + new SCM executables, libraries, and dlls. + `build.bat' invokes build.scm on MS-DOS platforms. + `setjump.mar' provides setjmp and longjmp which do not use $unwind + utility on VMS. + `setjump.s' provides setjmp and longjmp for the Cray YMP. + + `Init.scm' is Scheme initialization code. + `Transcen.scm' has Scheme code for inexact builtin procedures. + `Link.scm' has Scheme code for compiling and dynamic linking. + `scmfig.h' is a C include file containing system dependent definitions. + `patchlvl.h is the patchlevel of this release. + `continue.c' code for continuations. + `continue.h' data types and external functions for continuations. + `setjump.h' is an include file dealing with continuations, stacks, + and memory allocation. + `scm.h' has the data type and external definitions of scm. + + `scm.c' has the top level and interrupt code. + `findexec.c' has code to find the executable file. + `time.c' has functions dealing with time. + `repl.c' has error, read-eval-print loop, read, write and load code. + `scl.c' has the code for utility functions which are not part of the + IEEE Scheme spec or which are required for non-integer + arithmetic. + `eval.c' has the evaluator, apply, map, and foreach. + `sys.c' has the code for opening and closing files, storage + allocation and garbage collection. + `rope.c' has C interface functions. + `subr.c' has all the rest of functions. + `sc2.c' has code for procedures from R2RS and R3RS not in R4RS. + `dynl.c' has c code for dynamically loading object files. + `unif.c' has code for uniform vectors. + `rgx.c' has code for string regular expression match. + `crs.c' has code for interactive terminal control. + `split.scm' sets up CURSCM (SCM with crs.c) so that input, output, + and diagnostic output are each directed to separate windows. + `edline.c' Gnu readline input editing + (get ftp.sys.toronto.edu:/pub/rc/editline.shar). + `Iedline.scm' Gnu readline input editing. + `record.c' has code for proposed "Record" user definable datatypes. + `gsubr.c' has make_gsubr for arbitrary (< 11) arguments to C functions. + + `ioext.c' has code for system calls in common between PC compilers and unix. + `posix.c' has code for posix library interface. + `unix.c' has code for non-posix system calls on unix systems. + `socket.c' has code for socket interface. + + SLIB + +[SLIB] is a portable Scheme library meant to provide compatibility and +utility functions for all standard Scheme implementations. Although +SLIB is not *neccessary* to run SCM, I strongly suggest you obtain and +install it. Bug reports about running SCM without SLIB have very low +priority. SLIB is available from the same sites as SCM: + + * ftp-swiss.ai.mit.edu:pub/scm/slib2a6.tar.gz + * prep.ai.mit.edu:pub/gnu/jacal/slib2a6.tar.gz + * ftp.maths.tcd.ie:pub/bosullvn/jacal/slib2a6.tar.gz + * ftp.cs.indiana.edu:/pub/scheme-repository/imp/slib2a6.tar.gz + +Unpack SLIB (`tar xzf slib2a6.tar.gz' or `unzip -ao slib2a6.zip') in an +appropriate directory for your system; both `tar' and `unzip' will +create the directory `slib'. + +Then create a file `require.scm' in the SCM "implementation-vicinity" +(this is the same directory as where the file `Init.scm' is installed). +`require.scm' should have the contents: + + (define (library-vicinity) "/usr/local/lib/slib/") + (load (in-vicinity (library-vicinity) "require")) + +where the pathname string `/usr/local/lib/slib/' is to be replaced by +the pathname into which you installed SLIB. Absolute pathnames are +recommended here; if you use a relative pathname, SLIB can get confused +when the working directory is changed (*note chmod: I/O-Extensions.). +The way to specify a relative pathname is to append it to the +implementation-vicinity, which is absolute: + + (define library-vicinity + (let ((lv (string-append (implementation-vicinity) "../slib/"))) + (lambda () lv))) + (load (in-vicinity (library-vicinity) "require")) + +Alternatively, you can set the (shell) environment variable +`SCHEME_LIBRARY_PATH' to the pathname of the SLIB directory (*note +SCHEME_LIBRARY_PATH: SCM Variables.). If set, the environment variable +overrides `require.scm'. Again, absolute pathnames are recommended. + + MAKING SCM + + The SCM distribution has "Makefile" which contains rules for making +"scmlit", a "bare-bones" version of SCM sufficient for running +`build.scm'. `build.scm' is used to compile (or create scripts to +compile) full featured versions. + + Makefiles are not portable to the majority of platforms. If +`Makefile' works for you, good; If not, I don't want to hear about it. +If you need to compile SCM without build.scm, there are several ways to +proceed: + + * Use SCM on a different platform to run `build.scm' to create a + script to build SCM; + + * Use another implementation of Scheme to run `build.scm' to create a + script to build SCM; + + * Create your own script or `Makefile'. + + * Buy a SCM executable from jaffer@ai.mit.edu. See the end of + `ANNOUNCE' in the distribution for details. + + * Use scmconfig (From: bos@scrg.cs.tcd.ie): + + Build and install scripts using GNU "autoconf" are available from + `scmconfig4e6.tar.gz' in the distribution directories. See + `README.unix' in `scmconfig4e6.tar.gz' for further instructions. + + Making SCM with Think C 4.0 or 4.1 + +Note: These instructions need to be uptdated for scm4e6. If Think C +can be called using system(), then SCM can be built using build.scm. + + Edit Scmfig.H to set desired options and IMPLINIT. + from Yasuaki Honda // honda@csl.SONY.co.jp: + Make a project and add source files repl.c, time.c, scm.c, subr.c, + sys.c, eval.c, scl.c, sc2.c, and unif.c to it. + Add libraries MacTraps, unix, ANSI to the project. + The project should be segmented in the following way: + ---------- + repl.c + scm.c + subr.c + sys.c + sc2.c + unif.c + time.c + ---------- + MacTraps + unix + ---------- + ANSI + ---------- + eval.c + ---------- + scl.c + ---------- + Choose 'Set Project Type' from 'Project' menu. + Choose Application from radio buttons. + Set Partition size to 600K. (The default 384K is not enough). + + EDITING SCHEME CODE + +Gnu Emacs: + Editing of Scheme code is supported by emacs. Buffers holding + files ending in .scm are automatically put into scheme-mode. + + If your Emacs can run a process in a buffer you can use the Emacs + command `M-x run-scheme' with SCM. However, the run-scheme + (`xscheme.el') which comes included with Gnu Emacs 18 will work + only with MIT Cscheme. If you are using Emacs 18, get the emacs + packages: + + * ftp-swiss.ai.mit.edu:/pub/scheme-editor-packages/cmuscheme.el + + * ftp-swiss.ai.mit.edu:/pub/scheme-editor-packages/comint.el + + These files are already standard in Emacs 19. + + If your Emacs can not run a process in a buffer, see "under other + systems" below. + +Epsilon (MS-DOS): + There is lisp (and scheme) mode available by use of the package + `LISP.E'. It offers several different indentation formats. With + this package, buffers holding files ending in `.L', `.LSP', `.S', + and `.SCM' (my modification) are automatically put into lisp-mode. + + It is possible to run a process in a buffer under Epsilon. With + Epsilon 5.0 the command line options `-e512 -m0' are neccessary to + manage RAM properly. It has been reported that when compiling SCM + with Turbo C, you need to `#define NOSETBUF' for proper operation + in a process buffer with Epsilon 5.0. + + One can also call out to an editor from SCM if RAM is at a + premium; See "under other systems" below. + +other systems: + Define the environment variable `EDITOR' to be the name of the + editing program you use. The SCM procedure `(ed arg1 ...)' will + invoke your editor and return to SCM when you exit the editor. The + following definition is convenient: + + (define (e) (ed "work.scm") (load "work.scm")) + + Typing `(e)' will invoke the editor with the file of interest. + After editing, the modified file will be loaded. + + TROUBLE SHOOTING + +Reported problems and solutions are grouped under "Compiling", +"Linking", "Running", and "Testing". If you don't find your problem +listed here, you can send a bug report to <jaffer@ai.mit.edu>. The +bug report should include: + + * The version of SCM (printed when SCM is invoked with no arguments). + + * The type of computer you are using. + + * The name and version of your computer's operating system. + + * The values of the environment variables SCM_INIT_PATH and + SCHEME_LIBRARY_PATH. + + * The name and version of your C compiler. + + * If you are using an executable from a distribution, the name, + vendor, and date of that distribution. In this case, + corresponding with the vendor is recommended. + + + Compiling: + +FILE ERROR or WARNING HOW TO FIX + +*.c include file not found Correct status of + STDC_HEADERS + + fix #include statement + or add #define for + system type to scmfig.h + +scm.c assignment between incompatible types change SIGRETTYPE in scm.c + +time.c CLK_TCK redefined incompatablility + between <stdlib.h> and + <sys/types.h>. remove + STDC_HEADERS in scmfig.h + + edit <sys/types.h> to + remove incompatability. + +sys.c statement not reached ignore + constant in conditional expression ignore + +sys.c: `???' undeclared, outside of functions #undef STDC_HEADERS + in scmfig.h + +scl.c syntax error define system type in + scmfig.h and scl.c (softtype) + + Linking: + +ERROR or WARNING HOW TO FIX + +_sin etc. missing. uncomment LIBS in makefile + + Running: + +PROBLEM HOW TO FIX + +Opening message and then machine Change memory model option +crashes. to C compiler (or makefile). + + Make sure sizet definition is + correct in scmfig.h + + Reduce size of HEAP_SEG_SIZE + in setjump.h + +Input hangs #define NOSETBUF + +ERROR: heap: need larger initial Need to increase the initial + heap allocation using + -a<kbytes> or INIT_HEAP_SIZE. + +ERROR: Could not allocate ... Check sizet definition. + + Get more memory. + + Don't try to run as subproccess + +... in scmfig.h and recompile scm Do it and recompile files. + +ERROR: Init.scm not found Assign correct IMPLINIT in + makefile or scmfig.h or + define environment variable + SCM_INIT_PATH to be the full + pathname of Init.scm (see + INSTALLATION instructions). + +WARNING: require.scm not found define environment variable + SCHEME_LIBRARY_PATH to be the + full pathname of the scheme + library SLIB or change + library-vicinity in Init.scm + to point to library or remove. + See section SLIB above. + + Make sure library-vicinity has + a trailing file separator + (like / or \). + + Testing: (load "r4rstest.scm") or (load "pi.scm") (pi 100 5) + +Runs some and then machine crashes. See above under machine + crashes. + +Runs some and then ERROR: ... Remove optimization option +(after a GC has happened) to C compiler and recompile. + + #define SHORT_ALIGN in scmfig.h + +Some symbol names print incorrectly. Change memory model option + to C compiler (or makefile). + + Check that HEAP_SEG_SIZE fits + within sizet. + + Increase size of HEAP_SEG_SIZE + (or INIT_HEAP_SIZE if it is + smaller than HEAP_SEG_SIZE). + +ERROR: Rogue pointer in Heap. See above under machine + crashes. + +Newlines don't appear correctly in Check file mode (define OPEN_... +output files. in Init.scm + +Spaces or control characters appear Check character defines in +in symbol names scmfig.h + +Negative numbers turn positive. Check SRS in scmfig.h + +VMS: Couldn't unwind stack #define CHEAP_CONTIUATIONS +VAX: botched longjmp in scmfig.h + +Sparc(SUN-4) heap is growing out of control: + + You are experiencing a GC problem peculiar to the Sparc. The + problem is that SCM doesn't know how to clear register + windows. Every location which is not reused still gets marked + at GC time. This causes lots of stuff which should be + collected to not be. This will be a problem with any + "conservative" GC until we find what instruction will clear + the register windows. This problem is exacerbated by using + lots of call-with-current-continuations. diff --git a/README.unix b/README.unix new file mode 100644 index 0000000..0f9094d --- /dev/null +++ b/README.unix @@ -0,0 +1,182 @@ +This file contains the instructions for building scm4e under Unix +systems. Scm conforms to Revised^4 Report on the Algorithmic Language +Scheme and the IEEE P1178 specification. Scm runs under VMS, MS-DOS, +OS2, MacOS, Amiga, Atari-ST, NOS/VE, Unix and similar systems. + +The author of scm can be reached at <jaffer@ai.mit.edu> or +Aubrey Jaffer, 84 Pleasant St., Wakefield MA 01880. + +The Unix installation support included in this scmconfig distribution +has been written by myself, Bryan O'Sullivan <bosullvn@maths.tcd.ie>, +and is maintained by me. Please direct any problems you have with +either scm itself or this configuration software to <bug-scm@scrg.cs.tcd.ie>. + +NOTE: Before you get started, make sure that you have unpacked this + scmconfig distribution into the whatever directory you have + unpacked the same version of scm. + +Several chunks of this file have been lifted more or less verbatim +from the standard INSTALL file which comes with most GNU utilities +these days. + + MANIFEST + + `README.unix' is this file. It contains a MANIFEST, INSTALLATION + INSTRUCTIONS, TROUBLESHOOTING, and various other information. + `COPYING' details the LACK OF WARRANTY for scmconfig and scm and the + conditions for distributing scm and scmconfig. + `acconfig-1.5.h' is a temporary fix for a bug in version 1.5 of GNU + autoconf. This file should not concern you unless you are + familiar with autoconf (you don't need to be). + `configure' is an executable shell script which generates + `scmconfig.h' and `Makefile'. + `configure.in' is a template file used by with autoconf (autoconf is + not needed to build scm), which produces the `configure' + script. + `scmconfig.h.in' is an automatically-generated template file used by + configure, which produces `scmconfig.h'. + `Makefile.in' is a template file used by configure, which produces + `Makefile'. + + INSTALLATION INSTRUCTIONS + +To compile this package: + +1. In the directory that this file is in, 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. + + You may wish to edit the generated `Makefile' file in order to + customise scm to your own preferences. The comments in there + should be adequate to let you decide what you want to do. + `Makefile' has a reasonable set of defaults for most Unix systems, + so you may not have to edit it at all. + +[You can skip the rest of this section (down to point 2 below) the + first time around.] + + The `configure' shell script attempts to guess correct values for + various system-dependent variables used during compilation, and + creates the Makefile. + + 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'. + + 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 `configure'. `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. + + See the section titled `INSTALL' below on building scm with + different default search paths. By default, when you run `make', + scm looks in the source directory for `Init.scm'. The binary + which is built when you run `make install' looks in the correct + places for files. + + Another `configure' option is useful mainly in `Makefile' rules + for updating `config.status' and `Makefile'. The `--no-create' + option figures out the configuration for your system and records + it in `config.status', without actually configuring the package + (creating `Makefile's and perhaps a configuration header file). + Later, you can run `./config.status' to actually configure the + package. You can also give `config.status' the `--recheck' + option, which makes it re-run `configure' with the same arguments + you used before. This option is useful if you change `configure'. + + `configure' ignores any other arguments that you give it. + + If your system requires unusual options for compilation or linking + that `configure' doesn't know about, you can give `configure' + initial values for some variables by setting them in the + environment. In Bourne-compatible shells, you can do that on the + command line like this: + CC='gcc -traditional' DEFS=-D_POSIX_SOURCE ./configure + +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. Test scm. This is done in the following way (user input comes + after the `bash$' and `>' prompts): + bash$ scm + SCM version xxx, Copyright (C) 1990, 1991, 1992, 1993 Aubrey Jaffer. + SCM comes with ABSOLUTELY NO WARRANTY; for details type `(terms)'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `(terms)' for details. + ;loading ".../Transcen.scm" + ;done loading ".../Transcen.scm" + ;Evaluation took 230 mSec (0 in gc) 8661 cons work + > (load "test.scm") + ... + > (test-sc4) + ... + > (test-cont) + ... + > (test-inexact) + +4. 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'. + +[You can skip this next bit unless you are editing the `configure.in' + file, which you should not do unless you are familiar with autoconf.] + + If you are using versions of autoconf before or including 1.5, you + should rename `acconfig-1.5.h' to `acconfig.h' before running + autoheader, since these distributions do not handle + `TIME_WITH_SYS_TIME' correctly. + + INSTALL + +Type `make install' to install programs, data files, and +documentation. + +By default, `make install' will install the package's files in +/usr/local/bin, /usr/local/lib, /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 + +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 regular prefix. + + TROUBLESHOOTING + +If you encounter any problems while building scm, please send +electronic mail to <bug-scm@scrg.cs.tcd.ie> with a description of the +problem, and any solution to it you may have found. Some mention of +the version of Unix you are trying to build scm on, and the versions +of scm and scmconfig you are using, would be helpful in diagnosing the +problem. + +If you encounter any problems with system include files not being +found, or attempts being made to read the wrong files, please contact +<bug-scm@scrg.cs.tcd.ie> with a description of the include files that +are not being handled correctly; the problem probably lies in the +autoconf support, and can usually be quickly fixed by manually editing +`scmconfig.h'. + +If you find that scm does not link because it cannot find a +time-related function, please mail a description of the problem to +<bug-scm@scrg.cs.tcd.ie>, stating which function(s) can't be found. +In the mean time, editing the top of `time.c' should provide a fix for +the problem. diff --git a/Transcen.scm b/Transcen.scm new file mode 100644 index 0000000..896f77f --- /dev/null +++ b/Transcen.scm @@ -0,0 +1,133 @@ +;; Copyright (C) 1992, 1993, 1995 Free Software Foundation, Inc. +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this software; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;; As a special exception, the Free Software Foundation gives permission +;; for additional uses of the text contained in its release of GUILE. +;; +;; The exception is that, if you link the GUILE library with other files +;; to produce an executable, this does not by itself cause the +;; resulting executable to be covered by the GNU General Public License. +;; Your use of that executable is in no way restricted on account of +;; linking the GUILE library code into it. +;; +;; This exception does not however invalidate any other reasons why +;; the executable file might be covered by the GNU General Public License. +;; +;; This exception applies only to the code released by the +;; Free Software Foundation under the name GUILE. If you copy +;; code from other Free Software Foundation releases into a copy of +;; GUILE, as the General Public License permits, the exception does +;; not apply to the code that you add in this way. To avoid misleading +;; anyone as to the status of such modified files, you must delete +;; this exception notice from them. +;; +;; If you write modifications of your own for GUILE, it is your choice +;; whether to permit this exception to apply to your modifications. +;; If you do not wish that, delete this exception notice. + +;;;; "Transcen.scm", Complex trancendental functions for SCM. +;;; Author: Jerry D. Hedden. + +(define compile-allnumbers #t) ;for HOBBIT compiler + +(define (exp z) + (if (real? z) ($exp z) + (make-polar ($exp (real-part z)) (imag-part z)))) + +(define (log z) + (if (and (real? z) (>= z 0)) + ($log z) + (make-rectangular ($log (magnitude z)) (angle z)))) + +(define (sqrt z) + (if (real? z) + (if (negative? z) (make-rectangular 0 ($sqrt (- z))) + ($sqrt z)) + (make-polar ($sqrt (magnitude z)) (/ (angle z) 2)))) + +(define expt + (let ((integer-expt integer-expt)) + (lambda (z1 z2) + (cond ((exact? z2) + (integer-expt z1 z2)) + ((and (real? z2) (real? z1) (>= z1 0)) + ($expt z1 z2)) + (else + (exp (* z2 (log z1)))))))) + +(define (sinh z) + (if (real? z) ($sinh z) + (let ((x (real-part z)) (y (imag-part z))) + (make-rectangular (* ($sinh x) ($cos y)) + (* ($cosh x) ($sin y)))))) +(define (cosh z) + (if (real? z) ($cosh z) + (let ((x (real-part z)) (y (imag-part z))) + (make-rectangular (* ($cosh x) ($cos y)) + (* ($sinh x) ($sin y)))))) +(define (tanh z) + (if (real? z) ($tanh z) + (let* ((x (* 2 (real-part z))) + (y (* 2 (imag-part z))) + (w (+ ($cosh x) ($cos y)))) + (make-rectangular (/ ($sinh x) w) (/ ($sin y) w))))) + +(define (asinh z) + (if (real? z) ($asinh z) + (log (+ z (sqrt (+ (* z z) 1)))))) + +(define (acosh z) + (if (and (real? z) (>= z 1)) + ($acosh z) + (log (+ z (sqrt (- (* z z) 1)))))) + +(define (atanh z) + (if (and (real? z) (> z -1) (< z 1)) + ($atanh z) + (/ (log (/ (+ 1 z) (- 1 z))) 2))) + +(define (sin z) + (if (real? z) ($sin z) + (let ((x (real-part z)) (y (imag-part z))) + (make-rectangular (* ($sin x) ($cosh y)) + (* ($cos x) ($sinh y)))))) +(define (cos z) + (if (real? z) ($cos z) + (let ((x (real-part z)) (y (imag-part z))) + (make-rectangular (* ($cos x) ($cosh y)) + (- (* ($sin x) ($sinh y))))))) +(define (tan z) + (if (real? z) ($tan z) + (let* ((x (* 2 (real-part z))) + (y (* 2 (imag-part z))) + (w (+ ($cos x) ($cosh y)))) + (make-rectangular (/ ($sin x) w) (/ ($sinh y) w))))) + +(define (asin z) + (if (and (real? z) (>= z -1) (<= z 1)) + ($asin z) + (* -i (asinh (* +i z))))) + +(define (acos z) + (if (and (real? z) (>= z -1) (<= z 1)) + ($acos z) + (+ (/ (angle -1) 2) (* +i (asinh (* +i z)))))) + +(define (atan z . y) + (if (null? y) + (if (real? z) ($atan z) + (/ (log (/ (- +i z) (+ +i z))) +2i)) + ($atan2 z (car y)))) diff --git a/acconfig-1.5.h b/acconfig-1.5.h new file mode 100644 index 0000000..4f33b04 --- /dev/null +++ b/acconfig-1.5.h @@ -0,0 +1,22 @@ +/* acconfig.h + This file is in the public domain. + + Descriptive text for the C preprocessor macros that + the distributed Autoconf macros can define. + No software package will use all of them; autoheader copies the ones + your configure.in uses into your configuration header file templates. + + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). + + Leave the following blank line there!! Autoheader needs it. */ + + +/* Define if <sys/time.h> and <time.h> do not clash with each other. */ +#undef TIME_WITH_SYS_TIME + + +/* Leave that blank line there!! Autoheader needs it. + If you're adding to this file, keep in mind: + The entries are in sort -df order: alphabetical, case insensitive, + ignoring punctuation (such as underscores). */ diff --git a/bench.scm b/bench.scm new file mode 100644 index 0000000..acb4a2c --- /dev/null +++ b/bench.scm @@ -0,0 +1,55 @@ + +(require (in-vicinity (implementation-vicinity) "pi.scm")) +(require 'transcript) +(define isqrt + (cond ((provided? 'inexact) sqrt) + (else (require 'root) integer-sqrt))) +(define i/ + (cond ((provided? 'inexact) /) + (else quotient))) +(define around + (cond ((provided? 'inexact) + (lambda (x) + (cond ((>= 3000 (abs x) 3) (inexact->exact (round x))) + (else x)))) + (else identity))) + +(define (time-pi digits) + (let ((start-time (get-internal-run-time))) + (pi digits 4) + (i/ (* 1000 (- (get-internal-run-time) start-time)) + internal-time-units-per-second))) + +(define (benchmark . arg) + (define file + (cond ((null? arg) "bench.log") + (else (car arg)))) + (do ((digits 50 (+ digits digits)) + (t 0 (time-pi (+ digits digits)))) + ((> t 3000) + (do ((tl '() (cons (time-pi digits) tl)) + (j 12 (+ -1 j))) + ((zero? j) + (let* ((avg (i/ (apply + tl) (length tl))) + (dev (isqrt (i/ (apply + + (map (lambda (x) (* (- x avg) (- x avg))) + tl)) + (length tl))))) + (and file (transcript-on file)) + (for-each display + (list digits " digits took " (around avg) " mSec +/- " + (around dev) " mSec.")) + (newline) + (let ((scaled-avg (i/ (* (i/ (* avg 1000) digits) 1000) digits))) + (for-each display + (list " That is about " scaled-avg + " mSec/k-digit^2 +/- " + (around + (i/ (* 100 (i/ (* (i/ (* dev 1000) digits) + 1000) digits)) + scaled-avg)) + "%.")) + (newline) + (and file (transcript-off))) + )))))) +(benchmark) diff --git a/build.bat b/build.bat new file mode 100755 index 0000000..723e25e --- /dev/null +++ b/build.bat @@ -0,0 +1 @@ +scm -f %0 -e(bi) build %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/build.scm b/build.scm new file mode 100755 index 0000000..557a5ab --- /dev/null +++ b/build.scm @@ -0,0 +1,1393 @@ +#!/bin/sh +type;exec scmlit -f $0 -e"(bi)" build $* +;;; "build.scm" Build database and program -*-scheme-*- +;;; Copyright (C) 1994, 1995, 1996 Aubrey Jaffer. +;;; See the file `COPYING' for terms applying to this program. + +(require 'getopt) +(require 'parameters) +(require 'database-utilities) + +;;;(define build (create-database "buildscm.scm" 'alist-table)) +(define build (create-database #f 'alist-table)) + +(require 'batch) +(batch:initialize! build) + +(define-tables build + + '(file-formats + ((format symbol)) + () + ((plaintext) + (c-source) + (c-header) + (scheme) + (vax-asm) + (cray-asm) + (makefile) + (MS-DOS-batch) + (nroff) + (texinfo))) + + '(file-categories + ((category symbol)) + ((documentation string)) + ((documentation "Documentation file (or source for)") + (required "File required for building executable SCM") + (optional "File required for some feature") + (linkable "File whose object can be dynamically linked") + (test "File to test SCM") + (none "No files"))) + + '(build-whats + ((name symbol)) + ((class file-categories) + (c-proc symbol) + (o-proc symbol) + (spec expression) + (documentation string)) + ((exe required compile-c-files link-c-program #f + "executable program") + (lib required compile-c-files make-archive ((define "RTL")) + "library module") + (dlls linkable compile-dll-c-files make-dll-archive ((define "RTL")) + "archived dynamically linked library object files") + (dll none compile-dll-c-files make-nothing #f + "dynamically linked library object file"))) + + '(manifest + ((file string)) + ((format file-formats) + (category file-categories) + (documentation string)) + (("README" plaintext documentation "contains a MANIFEST, INSTALLATION INSTRUCTIONS, hints for EDITING SCHEME CODE, and a TROUBLE SHOOTING GUIDE.") + ("COPYING" plaintext documentation "details the LACK OF WARRANTY for SCM and the conditions for distributing SCM.") + ("scm.1" nroff documentation "unix style man page.") + ("scm.doc" plaintext documentation "man page generated from scm.1.") + ("QUICKREF" plaintext documentation "Quick Reference card for R4RS and IEEE Scheme.") + ("scm.texi" Texinfo documentation "SCM installation and use.") + ("ChangeLog" plaintext documentation "changes to SCM.") + ("r4rstest.scm" Scheme test "tests conformance with Scheme specifications.") + ("example.scm" Scheme test "example from R4RS which uses inexact numbers.") + ("pi.scm" Scheme test "computes digits of pi [type (pi 100 5)]. Test performance against pi.c.") + ("pi.c" c-source test "computes digits of pi [cc -o pi pi.c;time pi 100 5].") + ("bench.scm" Scheme test "computes and records performance statistics of pi.scm.") + ("Makefile" Makefile required "builds SCMLIT using the `make' program.") + ("build.scm" Scheme required "database for compiling and linking new SCM programs.") + ("build.bat" MS-DOS-batch optional "invokes build.scm for MS-DOS") + ("setjump.mar" Vax-asm optional "provides setjmp and longjmp which do not use $unwind utility on VMS.") + ("setjump.s" Cray-asm optional "provides setjmp and longjmp for the Cray YMP.") + ("Init.scm" Scheme required "Scheme initialization.") + ("Transcen.scm" Scheme required "inexact builtin procedures.") + ("Link.scm" Scheme required "compiles and dynamically links.") + ("scmfig.h" c-header required "contains system dependent definitions.") + ("patchlvl.h" c-header required "patchlevel of this release.") + ("setjump.h" c-header required "continuations, stacks, and memory allocation.") + ("continue.h" c-header required "continuations.") + ("continue.c" c-source required "continuations.") + ("scm.h" c-header required "data type and external definitions of SCM.") + ("scm.c" c-source required "top level, interrupts, and non-IEEE utility functions.") + ("findexec.c" c-source required "find the executable file function.") + ("time.c" c-source required "functions dealing with time.") + ("repl.c" c-source required "error, read-eval-print loop, read, write and load.") + ("scl.c" c-source required "inexact arithmetic") + ("eval.c" c-source required "evaluator, apply, map, and foreach.") + ("sys.c" c-source required "call-with-current-continuation, opening and closing files, storage allocation and garbage collection.") + ("subr.c" c-source required "the rest of IEEE functions.") + ("unif.c" c-source required "uniform vectors.") + ("rope.c" c-source required "C interface functions.") + ("ramap.c" c-source optional "array mapping") + ("dynl.c" c-source optional "dynamically load object files.") + ("sc2.c" c-source linkable "procedures from R2RS and R3RS not in R4RS.") + ("rgx.c" c-source linkable "string regular expression match.") + ("crs.c" c-source linkable "interactive terminal control.") + ("split.scm" Scheme test "example use of crs.c. Input, output, and diagnostic output directed to separate windows.") + ("edline.c" c-source linkable "Gnu readline input editing (get ftp.sys.toronto.edu:/pub/rc/editline.shar).") + ("Iedline.scm" Scheme optional "Gnu readline input editing.") + ("record.c" c-source linkable "proposed `Record' user definable datatypes.") + ("gsubr.c" c-source linkable "make_gsubr for arbitrary (< 11) arguments to C functions.") + ("ioext.c" c-source linkable "system calls in common between PC compilers and unix.") + ("posix.c" c-source linkable "posix library interface.") + ("unix.c" c-source linkable "non-posix system calls on unix systems.") + ("socket.c" c-source linkable "BSD socket interface.") + ("pre-crt0.c" c-source optional "loaded before crt0.o on machines which do not remap part of the data space into text space in unexec.") + ("ecrt0.c" c-source optional "standard Vax 4.2 Unix crt0.c cannot be used because it makes `envron' an initialized variable.") + ("gmalloc.c" c-source optional "Gnu malloc().") + ("unexec.c" c-source optional "Convert a running program into an a.out file.") + ("unexelf.c" c-source optional "Convert a running ELF program into an a.out file.") + ))) + +(for-each (build 'add-domain) + '((optstring #f (lambda (x) (or (not x) (string? x))) string #f) + (filename #f #f string #f) + (build-whats #f #f symbol #f))) + +(define-tables build + + '(processor-family + ((family atom)) + ((also-runs processor-family)) + ((*unknown* #f) + (8086 #f) + (acorn #f) + (cray #f) + (hp-risc #f) + (i386 8086) + (m68000 #f) + (m68030 m68000) + (mips #f) + (nos/ve #f) + (pdp-10 #f) + (pdp-11 #f) + (pdp-8 #f) + (powerpc #f) + (pyramid #f) + (sequent #f) + (sparc #f) + (tahoe #f) + (vax pdp-11) + )) + + '(platform + ((name symbol)) + ((processor processor-family) + (operating-system operating-system) + (compiler symbol)) + ((*unknown* *unknown* unix *unknown*) + (acorn-unixlib acorn *unknown* *unknown*) + (aix powerpc aix *unknown*) + (amiga-aztec m68000 amiga aztec) + (amiga-dice-c m68000 amiga dice-c) + (amiga-sas/c-5.10 m68000 amiga sas/c) + (atari-st-gcc m68000 atari.st gcc) + (atari-st-turbo-c m68000 atari.st turbo-c) + (borland-c-3.1 8086 ms-dos borland-c) + (djgpp i386 ms-dos gcc) + (gcc *unknown* unix gcc) + (highc.31 i386 ms-dos highc) + (hp-ux hp-risc hp-ux *unknown*) + (linux-aout i386 linux gcc) + (linux i386 linux gcc) + (microsoft-c 8086 ms-dos microsoft-c) + (microsoft-c-nt i386 ms-dos microsoft-c) + (microsoft-quick-c 8086 ms-dos microsoft-quick-c) + (ms-dos 8086 ms-dos *unknown*) + (os/2-cset i386 os/2 C-Set++) + (os/2-emx i386 os/2 gcc) + (sun sparc sun-os *unknown*) + (svr4 *unknown* unix *unknown*) + (turbo-c-2 8086 ms-dos turbo-c) + (unicos cray unicos *unknown*) + (unix *unknown* unix *unknown*) + (vms vax vms *unknown*) + (vms-gcc vax vms gcc) + (watcom-9.0 i386 ms-dos watcom) + )) + + '(C-libraries + ((library symbol) + (platform platform)) + ((compiler-flags string) + (link-lib-flag string) + (lib-path optstring) + (supress-files expression)) + + ((m *unknown* "" "-lm" "/usr/lib/libm.a" ()) + (c *unknown* "" "-lc" "/usr/lib/libc.a" ()) + (regex *unknown* "" "-lrgx" "/usr/lib/librgx.a" ()) + (curses *unknown* "" "-lcurses" "/usr/lib/libcurses.a" ()) + (graphics *unknown* "-I/usr/X11/include -DX11" "-lX11" + "/usr/X11/lib/libX11.sa" ()) + (editline *unknown* "" "-ledit" "/usr/lib/libedit.a" ()) + (termcap *unknown* "" "-ltermcap" "/usr/lib/libtermcap.a" ()) + (debug *unknown* "-g" "-g" #f ()) + + (m linux-aout "" "-lm" "/usr/lib/libm.sa" ()) + (c linux-aout "" "-lc" "/usr/lib/libc.sa" ()) + (dlll linux-aout "-DDLD -DDLD_DYNCM" "-ldld" #f ("findexec.c")) + (regex linux-aout "" "" "" ()) + (curses linux-aout "-I/usr/include/ncurses" "-lncurses" + "/usr/lib/libncurses.a" ()) + (nostart linux-aout "" "-nostartfiles" #f ("ecrt0.c")) + (dump linux-aout "" "/usr/lib/crt0.o" #f ("unexelf.c")) + + (m linux "" "-lm" "/lib/libm.so" ()) + (c linux "" "-lc" "/lib/libc.so" ()) + (dlll linux "-DSUN_DL" "-ldl" #f ()) + (graphics linux "-I/usr/include/X11 -DX11" "-L/usr/X11R6/lib -lX11" + "/usr/X11R6/lib/libX11.so" ()) + (curses linux "" "-lcurses" "/lib/libncurses.so" ()) + (nostart linux "" "" #f ("pre-crt0.c" "ecrt0.c")) + (dump linux "" "" #f ("unexec.c")) + + (m acorn-unixlib "" "" #f ()) + + (m amiga-dice-c "" "-lm" #f ()) + (m amiga-SAS/C-5.10 "" "lcmieee.lib" #f ()) + (c amiga-SAS/C-5.10 "" "lc.lib" #f ()) + + (m vms-gcc "" "" #f ()) + (m vms "" "" #f ()) + + (m atari-st-gcc "" "-lpml" #f ()) + (m atari-st-turbo-c "" "" #f ()) + + (m sun "" "-lm" #f ()) + (dlll sun "-DSUN_DL" "-ldl" #f ()) + (nostart sun "" "-e __start -nostartfiles -static" #f ("pre-crt0.c")) + (dump sun "" "" #f ("unexec.c")) + + (m hp-ux "" "-lm" #f ()) + (dlll hp-ux "-DHAVE_DYNL" "-Wl,-E -ldld" #f ()) + (graphics hp-ux "-DX11" "-lX" "/usr/lib/X11R5/libX11.sl" ()) + + (c djgpp "" "-lc" #f ("findexec.c")) + (curses djgpp "-I/djgpp/contrib/pdcurses/include/" + "-L/djgpp/contrib/pdcurses/lib/ -lcurses" + "\\djgpp\\contrib\\pdcurses\\lib\\libcurse.a" ()) + (nostart djgpp "" "-nostartfiles" #f ("ecrt0.c")) + (dump djgpp "" "c:/djgpp/lib/crt0.o" #f ("unexelf.c")) + + (c Microsoft-C "" "" #f ("findexec.c")) + (m Microsoft-C "" "" #f ()) + (c Microsoft-C-nt "" "" #f ("findexec.c")) + (m Microsoft-C-nt "" "" #f ()) + (c Microsoft-Quick-C "" "" #f ("findexec.c")) + (m Microsoft-Quick-C "" "" #f ()) + + (c Turbo-C-2 "" "" #f ("findexec.c")) + (m Turbo-C-2 "" "" #f ()) + (graphics Turbo-C-2 "" "graphics.lib" #f ()) + + (c Borland-C-3.1 "" "" #f ("findexec.c")) + (m Borland-C-3.1 "" "" #f ()) + (graphics Borland-C-3.1 "" "graphics.lib" #f ()) + (windows Borland-C-3.1 "-N -W" "-W" #f ()) + + (c highc.31 "" "" #f ("findexec.c")) + (m highc.31 "" "" #f ()) + (windows highc.31 "-Hwin" "-Hwin" #f ()) + )) + + '(compile-commands + ((name symbol) + (platform platform)) + ((procedure expression)) + + ((compile-c-files Borland-C-3.1 + (lambda (files parms) + (define rsp-name "temp.rsp") + (apply batch:lines->file parms rsp-name files) + (batch:system parms + "bcc" "-d" "-O" "-Z" "-G" "-w-pro" "-ml" "-c" + (if (member '(define "FLOATS" #t) + (c-defines parms)) + "" "-f-") + (c-includes parms) + (c-flags parms) + (string-append "@" rsp-name)) + (replace-suffix files ".c" ".obj"))) + (link-c-program Borland-C-3.1 + (lambda (oname objects libs parms) + (define lnk-name (string-append oname ".lnk")) + (apply batch:lines->file parms + lnk-name + (append libs objects)) + (batch:system parms "bcc" + (string-append "-e" oname) + "-ml" + (string-append "@" lnk-name)) + (string-append oname ".exe"))) + + (compile-c-files Turbo-C-2 + (lambda (files parms) + (batch:system parms + "tcc" "-c" "-d" "-O" "-Z" "-G" "-ml" "-c" + "-Ic:\\turboc\\include" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".obj"))) + (link-c-program Turbo-C-2 + (lambda (oname objects libs parms) + (let ((exe (replace-suffix (car objects) ".obj" ".exe")) + (oexe (string-append oname ".exe"))) + (if (not (string-ci=? exe oexe)) + (batch:delete-file parms oexe)) + (batch:system parms + "tcc" "-Lc:\\turboc\\lib" libs objects) + (if (not (string-ci=? exe oexe)) + (batch:rename-file parms exe oexe)) + oexe))) + + (compile-c-files Microsoft-C + (lambda (files parms) + (batch:system parms + "cl" "-c" "Oxp" "-AH" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".obj"))) + (link-c-program Microsoft-C + (lambda (oname objects libs parms) + (let ((exe (replace-suffix (car objects) ".obj" ".exe")) + (oexe (string-append oname ".exe"))) + (if (not (string-ci=? exe oexe)) + (batch:delete-file parms oexe)) + (batch:system parms + "link" "/noe" "/ST:40000" + (apply string-join "+" + (map (lambda (o) + (replace-suffix o ".obj" "")) + objects)) + libs) + (if (not (string-ci=? exe oexe)) + (batch:rename-file parms exe oexe)) + oexe))) + (compile-c-files Microsoft-C-nt + (lambda (files parms) + (batch:system parms + "cl" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".obj"))) + (link-c-program Microsoft-C-nt + (lambda (oname objects libs parms) + (let ((exe (replace-suffix (car objects) ".obj" ".exe")) + (oexe (string-append oname ".exe"))) + (if (not (string-ci=? exe oexe)) + (batch:delete-file parms oexe)) + (batch:system parms + "link" + (apply string-join " " + (map (lambda (o) + (replace-suffix o ".obj" "")) + objects)) + libs) + (if (not (string-ci=? exe oexe)) + (batch:rename-file parms exe oexe)) + oexe))) + + (compile-c-files Microsoft-Quick-C + (lambda (files parms) + (batch:system parms + "qcl" "/AH" "/W1" "/Ze" "/O" "/Ot" "/DNDEBUG" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".obj"))) + (link-c-program Microsoft-Quick-C + (lambda (oname objects libs parms) + (define crf-name (string-append oname ".crf")) + (apply batch:lines->file parms + crf-name + `(,@(map (lambda (f) (string-append f " +")) + objects) + "" + ,(string-append oname ".exe") + ,(apply string-join " " libs) + ";")) + (batch:system parms + "qlink" + "/CP:0xffff" "/NOI" "/SE:0x80" "/ST:0x9c40" + crf-name) + (string-append oname ".exe"))) + + (compile-c-files Watcom-9.0 + (lambda (files parms) + (batch:system parms + "wcc386p" "/mf" "/d2" "/ze" "/oxt" "/3s" + "/zq" "/w3" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".obj"))) + (link-c-program Watcom-9.0 + (lambda (oname objects libs parms) + (let ((exe (replace-suffix (car objects) + ".obj" ".exe")) + (oexe (string-append oname ".exe"))) + (if (not (string-ci=? exe oexe)) + (batch:delete-file parms oexe)) + (batch:system parms + "wlinkp" "option" "quiet" "option" + "stack=40000" "FILE" + (apply string-join "," + (map (lambda (o) + (replace-suffix o ".obj" "")) + objects)) + libs) + (if (not (string-ci=? exe oexe)) + (batch:rename-file parms exe oexe)) + oexe))) + (compile-c-files highc.31 + (lambda (files parms) + (define hcc-name "temp.hcc") + (apply batch:lines->file parms hcc-name files) + (batch:system parms + "\\hi_c\\hc386.31\\bin\\hc386" + (c-includes parms) + (c-flags parms) + "-c" (string-append "@" hcc-name)) + (replace-suffix files ".c" ".obj"))) + (link-c-program highc.31 + (lambda (oname objects libs parms) + (let ((oexe (string-append oname ".exe"))) + (define lnk-name (string-append oname ".lnk")) + (apply batch:lines->file parms + lnk-name (append libs objects)) + (batch:system parms + "\\hi_c\\hc386.31\\bin\\hc386" "-o" oname + (string-append "@" lnk-name)) + (batch:system parms + "bind386" "/hi_c/pharlap.51/run386b.exe" oname + "-exe" oexe) + oexe))) + + (compile-c-files djgpp + (lambda (files parms) + (batch:apply-chop-to-fit + batch:try-system parms + "gcc" "-Wall" "-O2" "-c" + (c-includes parms) (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (link-c-program djgpp + (lambda (oname objects libs parms) + (let ((exe (string-append oname ".exe"))) + (or + (batch:try-system parms + "gcc" "-o" oname + (must-be-first + '("-nostartfiles" + "pre-crt0.o" "ecrt0.o" + "c:/djgpp/lib/crt0.o") + (append objects libs))) + (let ((arname (string-append oname ".a"))) + (batch:delete-file parms arname) + (batch:apply-chop-to-fit + batch:try-system parms + "ar" "r" arname objects) + (batch:system + parms "gcc" "-o" oname + (must-be-first + '("-nostartfiles" + "pre-crt0.o" "ecrt0.o" + "c:/djgpp/lib/crt0.o") + (cons arname libs)))) + (slib:error 'build "couldn't build archive")) + (batch:system parms "strip" oname) + (batch:delete-file parms exe) + (batch:system parms + "coff2exe" "-s" + "c:\\djgpp\\bin\\go32.exe" + oname) + exe))) + + (compile-c-files os/2-emx + (lambda (files parms) + (batch:system parms + "gcc" "-O" "-m386" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (link-c-program os/2-emx + (lambda (oname objects libs parms) + (batch:system parms + "gcc" "-o" (string-append oname ".exe") + objects libs) + (string-append oname ".exe"))) + + (compile-c-files os/2-cset + (lambda (files parms) + (batch:system parms + "icc.exe" "/Gd-" "/Ge+" "/Gm+" "/Q" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".obj"))) + (link-c-program os/2-cset + (lambda (oname objects libs parms) + (batch:system parms + "link386.exe" objects libs + (string-append "," oname ".exe,,,;")) + (string-append oname ".exe"))) + + (compile-c-files HP-UX + (lambda (files parms) + (batch:system parms + "cc" "+O1" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (compile-dll-c-files HP-UX + (lambda (files parms) + (batch:system parms + "cc" "+O1" "-Wl,-E" "+z" "-c" + (c-includes parms) + (c-flags parms) + files) + (for-each + (lambda (fname) + (batch:rename-file parms + (string-append fname ".sl") + (string-append fname ".sl~")) + (batch:system parms + "ld" "-b" "-o" + (string-append fname ".sl") + (string-append fname ".o"))) + (replace-suffix files ".c" "")) + (replace-suffix files ".c" ".sl"))) +; (make-dll-archive HP-UX +; (lambda (oname objects libs parms) +; (batch:system parms +; "ld" "-b" "-o" (string-append oname ".sl") +; objects) +; (string-append oname ".sl"))) + + (make-dll-archive sun + (lambda (oname objects libs parms) + (batch:system parms + "ld" "-assert" "pure-text" "-o" + (string-append oname ".so.1.0") + objects) + (string-append oname ".so.1.0"))) + + (compile-c-files linux-aout + (lambda (files parms) + (batch:system parms + "gcc" "-Wall" "-O2" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (compile-dll-c-files linux-aout + (lambda (files parms) + (batch:system parms + "gcc" "-Wall" "-O2" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) +;;; (make-dll-archive linux-aout +;;; (lambda (oname objects libs parms) #t +;;; oname)) + + (compile-c-files linux + (lambda (files parms) + (batch:system parms + "gcc" "-O2" "-c" (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (compile-dll-c-files linux + (lambda (files parms) + (batch:system parms + "gcc" "-O2" "-fpic" "-c" (c-includes parms) + (c-flags parms) + files) + (let* ((platform (car (parameter-list-ref + parms 'platform))) + (ld-opts + (map (lambda (l) + (build:lib-ld-flag l platform)) + (parameter-list-ref parms 'c-lib)))) + (for-each + (lambda (fname) + (batch:system parms + "gcc" "-shared" "-o" + (string-append fname ".so") + (string-append fname ".o") + ld-opts)) + (replace-suffix files ".c" ""))) + (replace-suffix files ".c" ".so"))) + (make-dll-archive linux + (lambda (oname objects libs parms) + (let ((platform (car (parameter-list-ref + parms 'platform)))) + (batch:system + parms + "gcc" "-shared" "-o" + (string-append oname ".so") + objects + (map (lambda (l) (build:lib-ld-flag l platform)) + (parameter-list-ref parms 'c-lib)))) + (string-append oname ".so"))) + (link-c-program linux + (lambda (oname objects libs parms) + (batch:system parms + "gcc" "-rdynamic" "-o" oname + (must-be-first + '("pre-crt0.o" "ecrt0.o" "/usr/lib/crt0.o") + (append objects libs))) + oname)) + + (compile-c-files Unicos + (lambda (files parms) + (batch:system parms + "cc" "-hvector2" "-hscalar2" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (link-c-program Unicos + (lambda (oname objects libs parms) + (batch:system parms + "cc" "setjump.o" "-o" oname objects libs) + oname)) + + (compile-c-files gcc + (lambda (files parms) + (batch:system parms + "gcc" "-Wall" "-O2" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + + (link-c-program gcc + (lambda (oname objects libs parms) + (batch:rename-file parms + oname (string-append oname "~")) + (batch:system parms + "gcc" "-o" oname + (must-be-first + '("-nostartfiles" + "pre-crt0.o" "ecrt0.o" + "/usr/lib/crt0.o") + (append objects libs))) + oname)) + + (compile-c-files svr4 + (lambda (files parms) + (batch:system parms + "cc" "-O" "-DSVR4" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + + (compile-c-files aix + (lambda (files parms) + (batch:system parms + "cc" "-O" "-Dunix" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (link-c-program aix + (lambda (oname objects libs parms) + (batch:system parms + "cc" "-lansi" "-o" oname objects libs) + oname)) + + (compile-c-files amiga-aztec + (lambda (files parms) + (batch:system parms + "cc" "-dAMIGA" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (link-c-program amiga-aztec + (lambda (oname objects libs parms) + (batch:system parms + "cc" "-o" oname objects libs "-lma") + oname)) + + (compile-c-files amiga-SAS/C-5.10 + (lambda (files parms) + (batch:system parms + "lc" "-d3" "-M" "-fi" "-O" + (c-includes parms) + (c-flags parms) + files) + (batch:system parms "blink with link.amiga NODEBUG") + (replace-suffix files ".c" ".o"))) + (link-c-program amiga-SAS/C-5.10 + (lambda (oname objects libs parms) + (define lnk-name "link.amiga") + (apply batch:lines->file parms + lnk-name + (apply string-join "+" ">FROM LIB:c.o" + (map object->string objects)) + (string-append + "TO " (object->string (string-append "/" oname))) + (append + (cond + ((pair? libs) + (cons (string-append "LIB LIB:" (car libs)) + (map (lambda (s) + (string-append " LIB:" s)) + (cdr libs)))) + (else '())) + '("VERBOSE" "SC" "SD"))) + oname)) + + (compile-c-files amiga-dice-c + (lambda (files parms) + (batch:system parms + "dcc" "-r" "-gs" "-c" + (c-includes parms) + (c-flags parms) + files "-o" (replace-suffix files ".c" ".o")) + (replace-suffix files ".c" ".o"))) + (link-c-program amiga-dice-c + (lambda (oname objects libs parms) + (batch:system parms + "dcc" "-r" "-gs" "-o" oname objects libs) + oname)) + + (compile-c-files atari-st-gcc + (lambda (files parms) + (batch:system parms + "gcc" "-v" "-O" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (link-c-program atari-st-gcc + (lambda (oname objects libs parms) + (batch:system parms + "gcc" "-v" "-o" (string-append oname ".ttp") + objects libs) + (string-append oname ".ttp"))) + + (compile-c-files atari-st-turbo-c + (lambda (files parms) + (batch:system parms + "tcc" "-P" "-W-" "-Datarist" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (link-c-program atari-st-turbo-c + (lambda (oname objects libs parms) + (batch:system parms + "tlink" "-o" (string-append oname ".ttp") + objects libs "mintlib.lib" "osbind.lib" + "pcstdlib.lib" "pcfltlib.lib") + (string-append oname ".ttp"))) + + (compile-c-files acorn-unixlib + (lambda (files parms) + (batch:system parms + "cc" "-c" "-depend" "!Depend" "-IUnixLib:" + "-pcc" "-Dunix" "-DSVR3" "-DARM_ULIB" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (link-c-program acorn-unixlib + (lambda (oname objects libs parms) + (batch:system parms + "link" "-o" oname objects libs + ":5.$.dev.gcc.unixlib36d.clib.o.unixlib") + (batch:system parms + "squeeze" oname) + oname)) + + (compile-c-files vms + (lambda (files parms) + (batch:system parms + "cc" + (c-includes parms) + (c-flags parms) + (replace-suffix files ".c" "")) + (replace-suffix files ".c" ".obj"))) + (link-c-program vms + (lambda (oname objects libs parms) + (let ((exe (replace-suffix (car objects) + ".obj" ".exe")) + (oexe (string-append oname ".exe"))) + (batch:system parms + "macro" "setjump") + (batch:system parms + "link" + (apply string-join "," + (append (map (lambda (f) + (replace-suffix f ".obj" "")) + objects) + '("setjump" "sys$input/opt\n "))) + (apply string-join + "," (append (remove "" libs) + '("sys$share:vaxcrtl/share")))) + (if (not (string-ci=? exe oexe)) + (batch:rename-file parms exe oexe)) + oexe))) + + (compile-c-files vms-gcc + (lambda (files parms) + (batch:system parms + "gcc" + (c-includes parms) + (c-flags parms) + (replace-suffix files ".c" "")) + (replace-suffix files ".c" ".obj"))) + (link-c-program vms-gcc + (lambda (oname objects libs parms) + (let ((exe (replace-suffix (car objects) + ".obj" ".exe")) + (oexe (string-append oname ".exe"))) + (batch:system parms + "macro" "setjump") + (batch:system parms + "link" + (apply string-join "," + (append objects + '("setjump.obj" + "sys$input/opt\n "))) + (apply string-join + "," (append (remove "" libs) + '("gnu_cc:[000000]gcclib/lib" + "sys$share:vaxcrtl/share")))) + (if (not (string-ci=? exe oexe)) + (batch:rename-file parms exe oexe)) + oexe))) + + (compile-c-files *unknown* + (lambda (files parms) + (batch:system parms + "cc" "-O" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (link-c-program *unknown* + (lambda (oname objects libs parms) + (batch:rename-file parms + oname (string-append oname "~")) + (batch:system parms + "cc" "-o" oname + (must-be-first + '("-nostartfiles" + "pre-crt0.o" "ecrt0.o" + "/usr/lib/crt0.o") + (append objects libs))) + oname)) + (make-archive *unknown* + (lambda (oname objects libs parms) + (let ((aname (string-append oname ".a"))) + (batch:system parms + "ar rc" aname objects) + (batch:system parms + "ranlib" aname) + aname))) + (compile-dll-c-files *unknown* + (lambda (files parms) + (batch:system parms + "cc" "-O" "-c" + (c-includes parms) + (c-flags parms) + files) + (replace-suffix files ".c" ".o"))) + (make-dll-archive *unknown* + (lambda (oname objects libs parms) + (let ((aname (string-append oname ".a"))) + (batch:system parms + "ar rc" aname objects) + (batch:system parms + "ranlib" aname) + aname))) + (make-nothing *unknown* + (lambda (oname objects libs parms) + (if (= 1 (length objects)) (car objects) + objects))) + )) + + '(features + ((name symbol)) + ((spec expression) + (documentation string)) + ((lit () "Light - no features") + (none () "No features") + + (cautious ((define "CAUTIOUS")) + "\ +Normally, the number of arguments arguments to interpreted closures + (from LAMBDA) are checked if the function part of a form is not a +symbol or only the first time the form is executed if the function +part is a symbol. defining RECKLESS disables any checking. If you +want to have SCM always check the number of arguments to interpreted +closures #define CAUTIOUS.") + + (careful-interrupt-masking ((define "CAREFUL_INTS")) + "\ +Define CAREFUL_INTS for extra checking of interrupt masking. This is +for debugging C code in sys.c and repl.c.") + + (debug ((c-lib debug) + (features cautious careful-interrupt-masking stack-limit)) + "Debugging") + + (reckless ((define "RECKLESS")) + "\ +If your scheme code runs without any errors you can disable almost all +error checking by compiling all files with RECKLESS.") + + (stack-limit ((define ("STACK_LIMIT" "(HEAP_SEG_SIZE/2)"))) + "\ +Define STACK_LIMIT to enable checking for stack overflow. Define +value of STACK_LIMIT to be the size to which SCM should allow the +stack to grow. STACK_LIMIT should be less than the maximum size the +hardware can support, as not every routine checks the stack.") + + (bignums ((define "BIGNUMS")) + "\ +Large precision integers.") + + (arrays ((define "ARRAYS")) + "\ +Define ARRAYS if you want arrays, uniform-arrays and uniform-vectors.") + + (array-for-each ((c-file "ramap.c") (init "init_ramap")) + "\ +array-map! and array-for-each (ARRAYS must also be defined).") + + (inexact ((define "FLOATS") (c-lib m)) + "\ +Define FLOATS if you want floating point numbers.") + + (engineering-notation ((define "ENGNOT")) + "\ +Define ENGNOT if you want floats to display in engineering notation + (exponents always multiples of 3) instead of scientific notation.") + + (single-precision-only ((define "SINGLESONLY")) + "\ +Define SINGLESONLY if you want all inexact real numbers to be single +precision. This only has an effect if SINGLES is also defined (which +is the default). This does not affect complex numbers.") + + (sicp ((define "SICP")) + "\ +Define SICP if you want to run code from: + + H. Abelson, G. J. Sussman, and J. Sussman, + Structure and Interpretation of Computer Programs, + The MIT Press, Cambridge, Massachusetts, USA + + (eq? '() '#f) is the major difference.") + + (rev2-procedures ((c-file "sc2.c") (init "init_sc2")) + "\ +These procedures were specified in the `Revised^2 Report on Scheme' +but not in `R4RS'.") + + (record ((c-file "record.c") (init "init_record")) + "\ +The Record package provides a facility for user to define their own +record data types. See SLIB for documentation.") + + (compiled-closure ((define "CCLO")) + "\ +Define CCLO if you want to use compiled closures.") + + (generalized-c-arguments ((c-file "gsubr.c") (init "init_gsubr")) + "\ +make_gsubr for arbitrary (< 11) arguments to C functions.") + + (tick-interrupts ((define "TICKS")) + "\ +Define TICKS if you want the ticks and ticks-interrupt functions.") + + (i/o-extensions ((c-file "ioext.c") (init "init_ioext")) + "\ +Commonly available I/O extensions: `Exec', line I/O, file positioning, +file delete and rename, and directory functions.") + + (turtlegr + ((c-file "turtlegr.c") (c-lib graphics) (features inexact) + (init "init_turtlegr")) + "\ +`Turtle' graphics calls for both Borland-C and X11.") + + (curses ((c-file "crs.c") (c-lib curses) (init "init_crs")) + "\ +`Curses' screen management package.") + + (edit-line + ((c-file "edline.c") (c-lib termcap editline) (compiled-init "init_edline")) + "\ +interface to the editline or GNU readline library") + + (regex ((c-file "rgx.c") (c-lib regex) (init "init_rgx")) + "\ +String regular expression matching.") + + (socket ((c-file "socket.c") (init "init_socket")) + "\ +BSD socket interface.") + + (posix ((c-file "posix.c") (init "init_posix")) + "\ +Posix functions available on all `Unix-like' systems. fork and +process functions, user and group IDs, file permissions, and `link'.") + + (unix ((c-file "unix.c") (init "init_unix")) + "\ +Those unix features which have not made it into the Posix specs: nice, +acct, lstat, readlink, symlink, mknod and sync.") + + (windows ((c-lib windows)) ; (define "NON_PREEMPTIVE") + "\ +Microsoft Windows executable.") + + (dynamic-linking ((c-file "dynl.c") (c-lib dlll)) + "\ +Load compiled files while running.") + + (dump ((define "CAN_DUMP") + (c-lib dump) + (c-lib nostart) + (c-file "unexec.c") + (c-file "unexelf.c") + (c-file "gmalloc.c") + (c-file "ecrt0.c") + (c-file "pre-crt0.c")) + "\ +Convert a running scheme program into an executable file.") + +;;;; Descriptions of these parameters is in "setjump.h". +;;; (initial-heap-size ((define "INIT_HEAP_SIZE" (* 25000 sizeof-cell)))) +;;; (heap-segment-size ((define "HEAP_SEG_SIZE" (* 8100 sizeof-cell)))) +;;; (short-aligned-stack ((define "SHORT_ALIGN"))) +;;; (initial-malloc-limit ((define "INIT_MALLOC_LIMIT" 100000))) +;;; (number-of-hash-buckets ((define "NUM_HASH_BUCKETS" 137))) +;;; (minimum-gc-yield ((define "MIN_GC_YIELD" "(heap_size/4)"))) + + (heap-can-shrink ((define "DONT_GC_FREE_SEGMENTS")) + "\ +Define DONT_GC_FREE_SEGMENTS if you want segments of unused heap to +not be freed up after garbage collection. This may reduce time in GC +for *very* large working sets.") + + (cheap-continuations ((define "CHEAP_CONTINUATIONS")) + "\ +If you only need straight stack continuations CHEAP_CONTINUATIONS will +run faster and use less storage than not having it. Machines with +unusual stacks need this. Also, if you incorporate new C code into +scm which uses VMS system services or library routines (which need to +unwind the stack in an ordrly manner) you may need to define +CHEAP_CONTINUATIONS.") + + (memoize-local-bindings ((define "MEMOIZE_LOCALS")) + "\ +Saves the interpeter from having to look up local bindings for every +identifier reference") + )) + '(build-params + *parameter-columns* + *parameter-columns* + ((1 platform single platform + (lambda (pl) (list batch:platform)) + #f + "what to build it for") + (2 target-name single string (lambda (pl) '("scm")) #f + "base name of target") + (3 c-lib nary symbol (lambda (pl) '(c)) #f + "C library (and include files)") + (4 define nary string #f #f "#define FLAG") + (5 implinit single string + (lambda (pl) (list (object->string + (in-vicinity (implementation-vicinity) "Init.scm")))) + #f "implementation vicinity") + (6 c-file nary filename #f #f "C source files") + (7 o-file nary filename #f #f "other object files") + (8 init nary string #f #f "initialization calls") + (9 compiled-init nary string #f #f "later initialization calls") + (10 features nary symbol + (lambda (pl) '(arrays inexact bignums)) + (lambda (rdb) (((rdb 'open-table) 'features #f) 'get 'spec)) + "features to include") + (11 what single build-whats + (lambda (pl) '(exe)) + (lambda (rdb) + (define tab (((rdb 'open-table) 'build-whats #f) 'get 'class)) + (define manifest ((((rdb 'open-table) 'manifest #f) + 'row:retrieve*))) + (lambda (what) + (define catgry (tab what)) + `((c-file + ,@(map car + (remove-if-not + (lambda (row) (and (eq? 'c-source (cadr row)) + (eq? catgry (caddr row)))) + manifest))) + ,@(or ((((rdb 'open-table) 'build-whats #f) 'get 'spec) what) + '())))) + "what to build") + (12 batch-dialect single batch-dialect + guess-how + #f + "How to build") + (13 who single expression (lambda (pl) (list (current-output-port))) #f + "name of buildfile or port") + (14 compiler-options nary string #f #f "command-line compiler options") + (15 linker-options nary string #f #f "command-line linker options") + + (17 batch-port nary expression #f #f + "port batch file will be written to.") + (18 c-defines nary expression #f #f "#defines for C") + (19 c-includes nary expression #f #f "library induced defines for C") + )) + '(build-pnames + ((name string)) + ((parameter-index uint)) + ( + ("p" 1) ("platform" 1) + ("o" 2) ("outname" 2) + ("l" 3) ("libraries" 3) + ("D" 4) ("defines" 4) + ("s" 5) ("scheme initialization file" 5) + ("c" 6) ("c source files" 6) + ("j" 7) ("object files" 7) + ("i" 9) ("initialization calls" 9) + ("F" 10) ("features" 10) + ("t" 11) ("type" 11) + ("h" 12) ("batch dialect" 12) + ("w" 13) ("script name" 13) + ("compiler options" 14) + ("linker options" 15) + )) + + '(*commands* + ((name symbol)) ;or just desc:*commands* + ((parameters parameter-list) + (parameter-names parameter-name-translation) + (procedure expression) + (documentation string)) + ((build + build-params + build-pnames + build:build + "build program.") + (*initialize* + no-parameters + no-parameters + build:init + "SCM Build Database")))) + +;;;((build 'close-database)) +;;;(define build (open-database! "buildscm.scm" 'alist-table)) + +(define build:error slib:error) +(define build:c-libraries #f) +(define build:lib-cc-flag #f) +(define build:lib-ld-flag #f) +(define build:c-supress #f) +(define plan-command #f) + +;;; Look up command on a platform, but default to '*unknown* if not +;;; initially found. + +(define (make-defaulting-platform-lookup getter) + (lambda (thing plat) + (define (look platform) + (let ((ans (getter thing platform))) + (cond (ans ans) + ((eq? '*unknown* platform) + (build:error "Couldn't find: " thing)) + (else (look '*unknown*))))) + (look plat))) + +(define system:success? zero?) + +(require 'alist) +(require 'common-list-functions) +(require 'object->string) + +(define build:build + (lambda (rdb) + (lambda (parms) + (let ((expanders + (map (lambda (e) (and e (lambda (s) (e s)))) + (map (lambda (f) (if f ((slib:eval f) rdb) f)) + ((((rdb 'open-table) 'build-params #f) + 'get* 'expander)))))) + (parameter-list-expand expanders parms) + (set! parms + (fill-empty-parameters + (map slib:eval + ((((rdb 'open-table) 'build-params #f) + 'get* 'default))) + parms)) + (parameter-list-expand expanders parms)) + (let* ((platform (car (parameter-list-ref parms 'platform))) + (init= (apply string-append + (map (lambda (c) + (string-append c "();")) + (parameter-list-ref parms 'init)))) + (compiled-init= + (apply string-append + (map (lambda (c) + (string-append c "();")) + (parameter-list-ref parms 'compiled-init)))) + (c-defines + `((define "IMPLINIT" + ,(car (parameter-list-ref parms 'implinit))) + ,@(if (string=? "" init=) '() + `((define "INITS" ,init=))) + ,@(if (string=? "" compiled-init=) '() + `((define "COMPILED_INITS" ,compiled-init=))) + ,@(map (lambda (d) (if (pair? d) + `(define ,@d) + `(define ,d #t))) + (parameter-list-ref parms 'define)))) + (c-includes + (map (lambda (l) (build:lib-cc-flag l platform)) + (parameter-list-ref parms 'c-lib))) + (batch-dialect (car (parameter-list-ref parms 'batch-dialect))) + (what (car (parameter-list-ref parms 'what))) + (c-proc (plan-command ((((rdb 'open-table) 'build-whats #f) + 'get 'c-proc) + what) + platform))) + (adjoin-parameters! + parms + (cons 'c-defines c-defines) + (cons 'c-includes c-includes) + ) + + (let ((name (car (parameter-list-ref parms 'who)))) + (batch:call-with-output-script + parms + name + (lambda (batch-port) + (define o-files '()) + (adjoin-parameters! + parms + (list 'batch-port batch-port)) + + ;; ================ Write file with C defines + (apply batch:lines->file parms + "scmflags.h" + (defines->c-defines c-defines)) + + ;; ================ Compile C source files + (set! o-files + (let ((supressors + (apply append + (map (lambda (l) (build:c-supress l platform)) + (parameter-list-ref parms 'c-lib))))) + (c-proc (remove-if (lambda (file) (member file supressors)) + (parameter-list-ref parms 'c-file)) + parms))) + + ;; ================ Link C object files + ((plan-command + ((((rdb 'open-table) 'build-whats #f) 'get 'o-proc) what) + platform) + (car (parameter-list-ref parms 'target-name)) + (append o-files (parameter-list-ref parms 'o-file)) + (append + (parameter-list-ref parms 'linker-options) + (map (lambda (l) (build:lib-ld-flag l platform)) + (parameter-list-ref parms 'c-lib))) + parms)))))))) + +(define (c-defines parms) + (parameter-list-ref parms 'c-defines)) +(define (c-includes parms) + (parameter-list-ref parms 'c-includes)) +(define (c-flags parms) + (parameter-list-ref parms 'compiler-options)) + +(define (defines->c-defines defines) + (map + (lambda (d) + (case (caddr d) + ((#t) (string-join " " "#define" (cadr d))) + ((#f) (string-join " " "#undef" (cadr d))) + (else (apply string-join " " "#define" (cdr d))))) + defines)) + +(define (defines->flags defines) + (map + (lambda (d) + (case (caddr d) + ((#t) (string-append "-D" (cadr d))) + ((#f) (string-append "-U" (cadr d))) + (else (string-append "-D" (cadr d) "=" (object->string (caddr d)))))) + defines)) + +(define (guess-how pl) + (let* ((plat (parameter-list-ref pl 'platform)) + (platform (if (pair? plat) (car plat) batch:platform))) + (let ((os (or ((((build 'open-table) 'platform #f) + 'get 'operating-system) platform) batch:platform))) + (cond ((not os) (slib:error "OS corresponding to " platform " unknown")) + (else (list (os->batch-dialect os))))))) + +(define build:initializer + (lambda (rdb) + (set! build:c-libraries ((rdb 'open-table) 'c-libraries #f)) + (set! build:lib-cc-flag + (make-defaulting-platform-lookup + (build:c-libraries 'get 'compiler-flags))) + (set! build:lib-ld-flag + (make-defaulting-platform-lookup + (build:c-libraries 'get 'link-lib-flag))) + (set! build:c-supress + (make-defaulting-platform-lookup + (build:c-libraries 'get 'supress-files))) + (set! plan-command + (let ((lookup (make-defaulting-platform-lookup + (((rdb 'open-table) 'compile-commands #f) + 'get 'procedure)))) + (lambda (thing plat) + (slib:eval (lookup thing plat))))))) +(build:initializer build) + +(define (build-from-argv argv) + (cond ((string? argv) + (require 'read-command) + (set! argv (call-with-input-string argv read-command)))) + (let () + (define command (string->symbol (list-ref argv *optind*))) + (define argc (length argv)) + (cond + ((pair? argv) + (set! *optind* (+ 1 *optind*)) + ((make-command-server build '*commands*) + command + (lambda (comname comval options positions arities types + defaults checks aliases) + (let* ((params (getopt->parameter-list + argc argv options arities types aliases)) + (fparams (fill-empty-parameters defaults params))) + (cond ((not (list? params)) #f) + ((not (check-parameters checks fparams)) #f) + ((not (check-arities (map arity->arity-spec arities) fparams)) + (slib:error 'build-from-argv "arity error" fparams) #f) + (else (comval fparams)))))))))) + +(define (build-from-whole-argv argv) + (set! *optind* 0) + (set! *optarg* #f) + (build-from-argv argv)) + +(define b build-from-whole-argv) + +(define (b*) + (require 'read-command) + (do ((e (read-command) (read-command))) + ((eof-object? e)) + (cond ((null? e)) + (else + (cond ((not (string-ci=? (car e) "build")) + (set! e (cons "build" e)))) + (write (build-from-whole-argv e)) + (newline))) + (display "build> ") + (force-output))) + +(define (bi) (build-from-argv *argv*)) + +(cond (*interactive* + (display "type (b \"build <command-line>\") to build") (newline) + (display "type (b*) to enter build command loop") (newline))) diff --git a/configure b/configure new file mode 100755 index 0000000..53d869e --- /dev/null +++ b/configure @@ -0,0 +1,849 @@ +#!/bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf. +# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp] +# [--prefix=PREFIX] [--exec-prefix=PREFIX] [--with-PACKAGE[=VALUE]] +# Ignores all args except --srcdir, --prefix, --exec-prefix, and +# --with-PACKAGE[=VALUE] unless this script has special code to handle it. + +for arg +do + # Handle --exec-prefix with a space before the argument. + if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix= + # Handle --host with a space before the argument. + elif test x$next_host = xyes; then next_host= + # Handle --prefix with a space before the argument. + elif test x$next_prefix = xyes; then prefix=$arg; next_prefix= + # Handle --srcdir with a space before the argument. + elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir= + else + case $arg in + # For backward compatibility, recognize -exec-prefix and --exec_prefix. + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* | --exe=* | --ex=* | --e=*) + exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e) + next_exec_prefix=yes ;; + + -gas | --gas | --ga | --g) ;; + + -host=* | --host=* | --hos=* | --ho=* | --h=*) ;; + -host | --host | --hos | --ho | --h) + next_host=yes ;; + + -nfp | --nfp | --nf) ;; + + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + next_prefix=yes ;; + + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=* | --s=*) + srcdir=`echo $arg | sed 's/[-a-z_]*=//'` ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s) + next_srcdir=yes ;; + + -with-* | --with-*) + package=`echo $arg|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that aren't valid shell variable names. + if test -n "`echo $package| sed 's/[-a-zA-Z0-9_]//g'`"; then + echo "configure: $package: invalid package name" >&2; exit 1 + fi + package=`echo $package| sed 's/-/_/g'` + case "$arg" in + *=*) val="`echo $arg|sed 's/[^=]*=//'`" ;; + *) val=1 ;; + esac + eval "with_$package='$val'" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb | --ver | --ve | --v) + verbose=yes ;; + + *) ;; + esac + fi +done + +trap 'rm -fr conftest* confdefs* core; exit 1' 1 3 15 +trap 'rm -f confdefs*' 0 + +# NLS nuisances. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "${LC_ALL+set}" = 'set' ; then LC_ALL=C; export LC_ALL; fi +if test "${LANG+set}" = 'set' ; then LANG=C; export LANG; fi + +rm -f conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h +compile='${CC-cc} $CFLAGS conftest.c -o conftest $LIBS >/dev/null 2>&1' + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +unique_file=scl.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + srcdirdefaulted=yes + # Try the directory containing this script, then `..'. + prog=$0 + confdir=`echo $prog|sed 's%/[^/][^/]*$%%'` + test "X$confdir" = "X$prog" && confdir=. + srcdir=$confdir + if test ! -r $srcdir/$unique_file; then + srcdir=.. + fi +fi +if test ! -r $srcdir/$unique_file; then + if test x$srcdirdefaulted = xyes; then + echo "configure: Can not find sources in \`${confdir}' or \`..'." 1>&2 + else + echo "configure: Can not find sources in \`${srcdir}'." 1>&2 + fi + exit 1 +fi +# Preserve a srcdir of `.' to avoid automounter screwups with pwd. +# But we can't avoid them for `..', to make subdirectories work. +case $srcdir in + .|/*|~*) ;; + *) srcdir=`cd $srcdir; pwd` ;; # Make relative path absolute. +esac + + +# Save the original args to write them into config.status later. +configure_args="$*" + + + +test -z "$CFLAGS" && CFLAGS=-g +test -z "$LDFLAGS" && LDFLAGS=-g + +if test -z "$CC"; then + # Extract the first word of `gcc', so it can be a program name with args. + set dummy gcc; word=$2 + echo checking for $word + IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/$word; then + CC="gcc" + break + fi + done + IFS="$saveifs" +fi +test -z "$CC" && CC="cc" +test -n "$CC" && test -n "$verbose" && echo " setting CC to $CC" + +# Find out if we are using GNU C, under whatever name. +cat > conftest.c <<EOF +#ifdef __GNUC__ + yes +#endif +EOF +${CC-cc} -E conftest.c > conftest.out 2>&1 +if egrep yes conftest.out >/dev/null 2>&1; then + GCC=1 # For later tests. +fi +rm -f conftest* + +# Make sure to not get the incompatible SysV /etc/install and +# /usr/sbin/install, which might be in PATH before a BSD-like install, +# or the SunOS /usr/etc/install directory, or the AIX /bin/install, +# or the AFS install, which mishandles nonexistent args, or +# /usr/ucb/install on SVR4, which tries to use the nonexistent group +# `staff'. On most BSDish systems install is in /usr/bin, not /usr/ucb +# anyway. Sigh. +if test "z${INSTALL}" = "z" ; then + echo checking for install + IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + test -z "$dir" && dir=. + case $dir in + /etc|/usr/sbin|/usr/etc|/usr/afsws/bin|/usr/ucb) ;; + *) + if test -f $dir/installbsd; then + INSTALL="$dir/installbsd -c" # OSF1 + INSTALL_PROGRAM='$(INSTALL)' + INSTALL_DATA='$(INSTALL) -m 644' + break + fi + if test -f $dir/install; then + if grep dspmsg $dir/install >/dev/null 2>&1; then + : # AIX + else + INSTALL="$dir/install -c" + INSTALL_PROGRAM='$(INSTALL)' + INSTALL_DATA='$(INSTALL) -m 644' + break + fi + fi + ;; + esac + done + IFS="$saveifs" +fi +INSTALL=${INSTALL-cp} +test -n "$verbose" && echo " setting INSTALL to $INSTALL" +INSTALL_PROGRAM=${INSTALL_PROGRAM-'$(INSTALL)'} +test -n "$verbose" && echo " setting INSTALL_PROGRAM to $INSTALL_PROGRAM" +INSTALL_DATA=${INSTALL_DATA-'$(INSTALL)'} +test -n "$verbose" && echo " setting INSTALL_DATA to $INSTALL_DATA" + +echo checking how to run the C preprocessor +if test -z "$CPP"; then + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and ``${CC-cc}'' will simply confuse + # make. It must be expanded now. + CPP="${CC-cc} -E" + cat > conftest.c <<EOF +#include "confdefs.h" +#include <stdio.h> +Syntax Error +EOF +err=`eval "($CPP conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + : +else + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +test ".${verbose}" != "." && echo " setting CPP to $CPP" + +if test -z "$RANLIB"; then + # Extract the first word of `ranlib', so it can be a program name with args. + set dummy ranlib; word=$2 + echo checking for $word + IFS="${IFS= }"; saveifs="$IFS"; IFS="${IFS}:" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/$word; then + RANLIB="ranlib" + break + fi + done + IFS="$saveifs" +fi +test -z "$RANLIB" && RANLIB=":" +test -n "$RANLIB" && test -n "$verbose" && echo " setting RANLIB to $RANLIB" + +echo checking for AIX +cat > conftest.c <<EOF +#include "confdefs.h" +#ifdef _AIX + yes +#endif + +EOF +eval "$CPP conftest.c > conftest.out 2>&1" +if egrep "yes" conftest.out >/dev/null 2>&1; then + rm -rf conftest* + +{ +test -n "$verbose" && \ +echo " defining _ALL_SOURCE" +echo "#define" _ALL_SOURCE 1 >> confdefs.h +DEFS="$DEFS -D_ALL_SOURCE=1" +SEDDEFS="${SEDDEFS}\${SEDdA}_ALL_SOURCE\${SEDdB}_ALL_SOURCE\${SEDdC}1\${SEDdD} +\${SEDuA}_ALL_SOURCE\${SEDuB}_ALL_SOURCE\${SEDuC}1\${SEDuD} +\${SEDeA}_ALL_SOURCE\${SEDeB}_ALL_SOURCE\${SEDeC}1\${SEDeD} +" +} + + +fi +rm -f conftest* + + +echo checking for POSIXized ISC +if test -d /etc/conf/kconfig.d && + grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 +then + ISC=1 # If later tests want to check for ISC. + +{ +test -n "$verbose" && \ +echo " defining _POSIX_SOURCE" +echo "#define" _POSIX_SOURCE 1 >> confdefs.h +DEFS="$DEFS -D_POSIX_SOURCE=1" +SEDDEFS="${SEDDEFS}\${SEDdA}_POSIX_SOURCE\${SEDdB}_POSIX_SOURCE\${SEDdC}1\${SEDdD} +\${SEDuA}_POSIX_SOURCE\${SEDuB}_POSIX_SOURCE\${SEDuC}1\${SEDuD} +\${SEDeA}_POSIX_SOURCE\${SEDeB}_POSIX_SOURCE\${SEDeC}1\${SEDeD} +" +} + + if test -n "$GCC"; then + CC="$CC -posix" + else + CC="$CC -Xp" + fi +fi + +echo checking for minix/config.h +cat > conftest.c <<EOF +#include "confdefs.h" +#include <minix/config.h> +EOF +err=`eval "($CPP conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + rm -rf conftest* + MINIX=1 + +fi +rm -f conftest* + +# The Minix shell can't assign to the same variable on the same line! +if test -n "$MINIX"; then + +{ +test -n "$verbose" && \ +echo " defining _POSIX_SOURCE" +echo "#define" _POSIX_SOURCE 1 >> confdefs.h +DEFS="$DEFS -D_POSIX_SOURCE=1" +SEDDEFS="${SEDDEFS}\${SEDdA}_POSIX_SOURCE\${SEDdB}_POSIX_SOURCE\${SEDdC}1\${SEDdD} +\${SEDuA}_POSIX_SOURCE\${SEDuB}_POSIX_SOURCE\${SEDuC}1\${SEDuD} +\${SEDeA}_POSIX_SOURCE\${SEDeB}_POSIX_SOURCE\${SEDeC}1\${SEDeD} +" +} + + +{ +test -n "$verbose" && \ +echo " defining" _POSIX_1_SOURCE to be 2 +echo "#define" _POSIX_1_SOURCE 2 >> confdefs.h +DEFS="$DEFS -D_POSIX_1_SOURCE=2" +SEDDEFS="${SEDDEFS}\${SEDdA}_POSIX_1_SOURCE\${SEDdB}_POSIX_1_SOURCE\${SEDdC}2\${SEDdD} +\${SEDuA}_POSIX_1_SOURCE\${SEDuB}_POSIX_1_SOURCE\${SEDuC}2\${SEDuD} +\${SEDeA}_POSIX_1_SOURCE\${SEDeB}_POSIX_1_SOURCE\${SEDeC}2\${SEDeD} +" +} + + +{ +test -n "$verbose" && \ +echo " defining _MINIX" +echo "#define" _MINIX 1 >> confdefs.h +DEFS="$DEFS -D_MINIX=1" +SEDDEFS="${SEDDEFS}\${SEDdA}_MINIX\${SEDdB}_MINIX\${SEDdC}1\${SEDdD} +\${SEDuA}_MINIX\${SEDuB}_MINIX\${SEDuC}1\${SEDuD} +\${SEDeA}_MINIX\${SEDeB}_MINIX\${SEDeC}1\${SEDeD} +" +} + +fi + +echo checking for ANSI C header files +cat > conftest.c <<EOF +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +err=`eval "($CPP conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + rm -rf conftest* + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +echo '#include "confdefs.h" +#include <string.h>' > conftest.c +eval "$CPP conftest.c > conftest.out 2>&1" +if egrep "memchr" conftest.out >/dev/null 2>&1; then + rm -rf conftest* + # SGI's /bin/cc from Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +cat > conftest.c <<EOF +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e,f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +eval $compile +if test -s conftest && (./conftest; exit) 2>/dev/null; then + +{ +test -n "$verbose" && \ +echo " defining STDC_HEADERS" +echo "#define" STDC_HEADERS 1 >> confdefs.h +DEFS="$DEFS -DSTDC_HEADERS=1" +SEDDEFS="${SEDDEFS}\${SEDdA}STDC_HEADERS\${SEDdB}STDC_HEADERS\${SEDdC}1\${SEDdD} +\${SEDuA}STDC_HEADERS\${SEDuB}STDC_HEADERS\${SEDuC}1\${SEDuD} +\${SEDeA}STDC_HEADERS\${SEDeB}STDC_HEADERS\${SEDeC}1\${SEDeD} +" +} + + +fi +rm -fr conftest* + +fi +rm -f conftest* + + +fi +rm -f conftest* + +for hdr in unistd.h string.h memory.h limits.h time.h sys/types.h sys/time.h sys/timeb.h sys/times.h +do +trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'` +echo checking for ${hdr} +cat > conftest.c <<EOF +#include "confdefs.h" +#include <${hdr}> +EOF +err=`eval "($CPP conftest.c >/dev/null) 2>&1"` +if test -z "$err"; then + rm -rf conftest* + +{ +test -n "$verbose" && \ +echo " defining ${trhdr}" +echo "#define" ${trhdr} 1 >> confdefs.h +DEFS="$DEFS -D${trhdr}=1" +SEDDEFS="${SEDDEFS}\${SEDdA}${trhdr}\${SEDdB}${trhdr}\${SEDdC}1\${SEDdD} +\${SEDuA}${trhdr}\${SEDuB}${trhdr}\${SEDuC}1\${SEDuD} +\${SEDeA}${trhdr}\${SEDeB}${trhdr}\${SEDeC}1\${SEDeD} +" +} + + +fi +rm -f conftest* +done + +echo checking for whether time.h and sys/time.h may both be included +cat > conftest.c <<EOF +#include "confdefs.h" +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> +int main() { exit(0); } +int t() { struct tm *tp; } +EOF +if eval $compile; then + rm -rf conftest* + +{ +test -n "$verbose" && \ +echo " defining TIME_WITH_SYS_TIME" +echo "#define" TIME_WITH_SYS_TIME 1 >> confdefs.h +DEFS="$DEFS -DTIME_WITH_SYS_TIME=1" +SEDDEFS="${SEDDEFS}\${SEDdA}TIME_WITH_SYS_TIME\${SEDdB}TIME_WITH_SYS_TIME\${SEDdC}1\${SEDdD} +\${SEDuA}TIME_WITH_SYS_TIME\${SEDuB}TIME_WITH_SYS_TIME\${SEDuC}1\${SEDuD} +\${SEDeA}TIME_WITH_SYS_TIME\${SEDeB}TIME_WITH_SYS_TIME\${SEDeC}1\${SEDeD} +" +} + + +fi +rm -f conftest* + +for func in ftime times +do +trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` +echo checking for ${func} +cat > conftest.c <<EOF +#include "confdefs.h" +#include <ctype.h> +int main() { exit(0); } +int t() { +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_${func}) || defined (__stub___${func}) +choke me +#else +/* Override any gcc2 internal prototype to avoid an error. */ +extern char ${func}(); ${func}(); +#endif + } +EOF +if eval $compile; then + rm -rf conftest* + { +test -n "$verbose" && \ +echo " defining ${trfunc}" +echo "#define" ${trfunc} 1 >> confdefs.h +DEFS="$DEFS -D${trfunc}=1" +SEDDEFS="${SEDDEFS}\${SEDdA}${trfunc}\${SEDdB}${trfunc}\${SEDdC}1\${SEDdD} +\${SEDuA}${trfunc}\${SEDuB}${trfunc}\${SEDuC}1\${SEDuD} +\${SEDeA}${trfunc}\${SEDeB}${trfunc}\${SEDeC}1\${SEDeD} +" +} + + +fi +rm -f conftest* +done + +echo checking for return type of signal handlers +cat > conftest.c <<EOF +#include "confdefs.h" +#include <sys/types.h> +#include <signal.h> +#ifdef signal +#undef signal +#endif +extern void (*signal ()) (); +int main() { exit(0); } +int t() { int i; } +EOF +if eval $compile; then + rm -rf conftest* + +{ +test -n "$verbose" && \ +echo " defining" RETSIGTYPE to be void +echo "#define" RETSIGTYPE void >> confdefs.h +DEFS="$DEFS -DRETSIGTYPE=void" +SEDDEFS="${SEDDEFS}\${SEDdA}RETSIGTYPE\${SEDdB}RETSIGTYPE\${SEDdC}void\${SEDdD} +\${SEDuA}RETSIGTYPE\${SEDuB}RETSIGTYPE\${SEDuC}void\${SEDuD} +\${SEDeA}RETSIGTYPE\${SEDeB}RETSIGTYPE\${SEDeC}void\${SEDeD} +" +} + + +else + rm -rf conftest* + +{ +test -n "$verbose" && \ +echo " defining" RETSIGTYPE to be int +echo "#define" RETSIGTYPE int >> confdefs.h +DEFS="$DEFS -DRETSIGTYPE=int" +SEDDEFS="${SEDDEFS}\${SEDdA}RETSIGTYPE\${SEDdB}RETSIGTYPE\${SEDdC}int\${SEDdD} +\${SEDuA}RETSIGTYPE\${SEDuB}RETSIGTYPE\${SEDuC}int\${SEDuD} +\${SEDeA}RETSIGTYPE\${SEDeB}RETSIGTYPE\${SEDeC}int\${SEDeD} +" +} + +fi +rm -f conftest* + + +prog='/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25,17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +}' +echo checking for lack of working const +cat > conftest.c <<EOF +#include "confdefs.h" + +int main() { exit(0); } +int t() { $prog } +EOF +if eval $compile; then + : +else + rm -rf conftest* + +{ +test -n "$verbose" && \ +echo " defining" const to be empty +echo "#define" const >> confdefs.h +DEFS="$DEFS -Dconst=" +SEDDEFS="${SEDDEFS}\${SEDdA}const\${SEDdB}const\${SEDdC}\${SEDdD} +\${SEDuA}const\${SEDuB}const\${SEDuC}\${SEDuD} +\${SEDeA}const\${SEDeB}const\${SEDeC}\${SEDeD} +" +} + +fi +rm -f conftest* + +echo checking whether $CC and cc understand -c and -o together +echo 'foo(){}' > conftest.c +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +if ${CC-cc} -c conftest.c -o conftest.o >/dev/null 2>&1 \ + && test -f conftest.o && ${CC-cc} -c conftest.c -o conftest.o >/dev/null 2>&1 +then + # Test first that cc exists at all. + if cc -c conftest.c >/dev/null 2>&1 + then + if cc -c conftest.c -o conftest2.o >/dev/null 2>&1 && \ + test -f conftest2.o && cc -c conftest.c -o conftest2.o >/dev/null 2>&1 + then + : + else + +{ +test -n "$verbose" && \ +echo " defining NO_MINUS_C_MINUS_O" +echo "#define" NO_MINUS_C_MINUS_O 1 >> confdefs.h +DEFS="$DEFS -DNO_MINUS_C_MINUS_O=1" +SEDDEFS="${SEDDEFS}\${SEDdA}NO_MINUS_C_MINUS_O\${SEDdB}NO_MINUS_C_MINUS_O\${SEDdC}1\${SEDdD} +\${SEDuA}NO_MINUS_C_MINUS_O\${SEDuB}NO_MINUS_C_MINUS_O\${SEDuC}1\${SEDuD} +\${SEDeA}NO_MINUS_C_MINUS_O\${SEDeB}NO_MINUS_C_MINUS_O\${SEDeC}1\${SEDeD} +" +} + + fi + fi +else + +{ +test -n "$verbose" && \ +echo " defining NO_MINUS_C_MINUS_O" +echo "#define" NO_MINUS_C_MINUS_O 1 >> confdefs.h +DEFS="$DEFS -DNO_MINUS_C_MINUS_O=1" +SEDDEFS="${SEDDEFS}\${SEDdA}NO_MINUS_C_MINUS_O\${SEDdB}NO_MINUS_C_MINUS_O\${SEDdC}1\${SEDdD} +\${SEDuA}NO_MINUS_C_MINUS_O\${SEDuB}NO_MINUS_C_MINUS_O\${SEDuC}1\${SEDuD} +\${SEDeA}NO_MINUS_C_MINUS_O\${SEDeB}NO_MINUS_C_MINUS_O\${SEDeC}1\${SEDeD} +" +} + +fi +rm -f conftest* + + + + +# Set default prefixes. +if test -n "$prefix"; then + test -z "$exec_prefix" && exec_prefix='${prefix}' + prsub="s%^prefix\\([ ]*\\)=\\([ ]*\\).*$%prefix\\1=\\2$prefix%" +fi +if test -n "$exec_prefix"; then + prsub="$prsub +s%^exec_prefix\\([ ]*\\)=\\([ ]*\\).*$%exec_prefix\\1=\\2$exec_prefix%" +fi +# Quote sed substitution magic chars in DEFS. +cat >conftest.def <<EOF +$DEFS +EOF +escape_ampersand_and_backslash='s%[&\\]%\\&%g' +DEFS=`sed "$escape_ampersand_and_backslash" <conftest.def` +rm -f conftest.def +# Substitute for predefined variables. + +trap 'rm -f config.status; exit 1' 1 3 15 +echo creating config.status +rm -f config.status +cat > config.status <<EOF +#!/bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $configure_args + +for arg +do + case "\$arg" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo running \${CONFIG_SHELL-/bin/sh} $0 $configure_args + exec \${CONFIG_SHELL-/bin/sh} $0 $configure_args ;; + *) echo "Usage: config.status --recheck" 2>&1; exit 1 ;; + esac +done + +trap 'rm -fr Makefile scmconfig.h conftest*; exit 1' 1 3 15 +CFLAGS='$CFLAGS' +LDFLAGS='$LDFLAGS' +CC='$CC' +INSTALL='$INSTALL' +INSTALL_PROGRAM='$INSTALL_PROGRAM' +INSTALL_DATA='$INSTALL_DATA' +CPP='$CPP' +RANLIB='$RANLIB' +LIBOBJS='$LIBOBJS' +LIBS='$LIBS' +srcdir='$srcdir' +prefix='$prefix' +exec_prefix='$exec_prefix' +prsub='$prsub' +extrasub='$extrasub' +EOF +cat >> config.status <<\EOF + +top_srcdir=$srcdir + +CONFIG_FILES=${CONFIG_FILES-"Makefile"} +for file in .. ${CONFIG_FILES}; do if test "x$file" != x..; then + srcdir=$top_srcdir + # Remove last slash and all that follows it. Not all systems have dirname. + dir=`echo $file|sed 's%/[^/][^/]*$%%'` + if test "$dir" != "$file"; then + test "$top_srcdir" != . && srcdir=$top_srcdir/$dir + test ! -d $dir && mkdir $dir + fi + echo creating $file + rm -f $file + echo "# Generated automatically from `echo $file|sed 's|.*/||'`.in by configure." > $file + sed -e " +$prsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@CC@%$CC%g +s%@INSTALL@%$INSTALL%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@CPP@%$CPP%g +s%@RANLIB@%$RANLIB%g +s%@LIBOBJS@%$LIBOBJS%g +s%@LIBS@%$LIBS%g +s%@srcdir@%$srcdir%g +s%@DEFS@%-DHAVE_CONFIG_H%" $top_srcdir/${file}.in >> $file +fi; done + +CONFIG_HEADERS=${CONFIG_HEADERS-"scmconfig.h"} +for file in .. ${CONFIG_HEADERS}; do if test "x$file" != x..; then +echo creating $file + +# These sed commands are put into SEDDEFS when defining a macro. +# They are broken into pieces to make the sed script easier to manage. +# They are passed to sed as "A NAME B NAME C VALUE D", where NAME +# is the cpp macro being defined and VALUE is the value it is being given. +# Each defining turns into a single global substitution command. +# +# SEDd sets the value in "#define NAME VALUE" lines. +SEDdA='s@^\([ ]*\)#\([ ]*define[ ][ ]*\)' +SEDdB='\([ ][ ]*\)[^ ]*@\1#\2' +SEDdC='\3' +SEDdD='@g' +# SEDu turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +SEDuA='s@^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +SEDuB='\([ ]\)@\1#\2define\3' +SEDuC=' ' +SEDuD='\4@g' +# SEDe turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +SEDeA='s@^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +SEDeB='$@\1#\2define\3' +SEDeC=' ' +SEDeD='@g' +rm -f conftest.sed +EOF +# Turn off quoting long enough to insert the sed commands. +rm -f conftest.sh +cat > conftest.sh <<EOF +$SEDDEFS +EOF + +# Break up $SEDDEFS (now in conftest.sh) because some shells have a limit +# on the size of here documents. + +# Maximum number of lines to put in a single here document. +maxshlines=9 + +while : +do + # wc gives bogus results for an empty file on some systems. + lines=`grep -c . conftest.sh` + if test -z "$lines" || test "$lines" -eq 0; then break; fi + rm -f conftest.s1 conftest.s2 + sed ${maxshlines}q conftest.sh > conftest.s1 # Like head -20. + sed 1,${maxshlines}d conftest.sh > conftest.s2 # Like tail +21. + # Write a limited-size here document to append to conftest.sed. + echo 'cat >> conftest.sed <<CONFEOF' >> config.status + cat conftest.s1 >> config.status + echo 'CONFEOF' >> config.status + rm -f conftest.s1 conftest.sh + mv conftest.s2 conftest.sh +done +rm -f conftest.sh + +# Now back to your regularly scheduled config.status. +cat >> config.status <<\EOF +# This sed command replaces #undef's with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it in +# scmconfig.h. +cat >> conftest.sed <<\CONFEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +CONFEOF +rm -f conftest.h +# Break up the sed commands because old seds have small limits. +maxsedlines=20 +cp $top_srcdir/$file.in conftest.h1 +while : +do + lines=`grep -c . conftest.sed` + if test -z "$lines" || test "$lines" -eq 0; then break; fi + rm -f conftest.s1 conftest.s2 conftest.h2 + sed ${maxsedlines}q conftest.sed > conftest.s1 # Like head -20. + sed 1,${maxsedlines}d conftest.sed > conftest.s2 # Like tail +21. + sed -f conftest.s1 < conftest.h1 > conftest.h2 + rm -f conftest.s1 conftest.h1 conftest.sed + mv conftest.h2 conftest.h1 + mv conftest.s2 conftest.sed +done +rm -f conftest.sed conftest.h +echo "/* $file. Generated automatically by configure. */" > conftest.h +cat conftest.h1 >> conftest.h +rm -f conftest.h1 +if cmp -s $file conftest.h 2>/dev/null; then + # The file exists and we would not be changing it. + echo "$file is unchanged" + rm -f conftest.h +else + rm -f $file + mv conftest.h $file +fi +fi; done + + + +exit 0 +EOF +chmod +x config.status +${CONFIG_SHELL-/bin/sh} config.status + + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..76c60ad --- /dev/null +++ b/configure.in @@ -0,0 +1,33 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(scl.c) +AC_CONFIG_HEADER(scmconfig.h) + +test -z "$CFLAGS" && CFLAGS=-g AC_SUBST(CFLAGS) +test -z "$LDFLAGS" && LDFLAGS=-g AC_SUBST(LDFLAGS) + +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_CPP +AC_PROG_RANLIB +AC_AIX +AC_ISC_POSIX +AC_MINIX +AC_STDC_HEADERS +AC_HAVE_HEADERS(unistd.h string.h memory.h limits.h time.h sys/types.h sys/time.h sys/timeb.h sys/times.h) +AC_TIME_WITH_SYS_TIME +AC_HAVE_FUNCS(ftime times getcwd) +AC_RETSIGTYPE +AC_CONST +AC_MINUS_C_MINUS_O +dnl AC_PREFIX(scm) + +AC_SUBST(LIBOBJS) + +AC_OUTPUT(Makefile) + +dnl Local Variables: +dnl comment-start: "dnl " +dnl comment-end: "" +dnl comment-start-skip: "\\bdnl\\b\\s *" +dnl compile-command: "make configure scmconfig.h.in" +dnl End: diff --git a/continue.c b/continue.c new file mode 100644 index 0000000..b28fe6e --- /dev/null +++ b/continue.c @@ -0,0 +1,255 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "continue.c" Scheme Continuations for C. + Author: Aubrey Jaffer */ + +/* "setjump.h" contains definitions for the `other' field (type + CONTINUATION_OTHER) the struct Continuation. "setjump.h" must + #include "continue.h". CONTINUATION_OTHER defaults to `long' */ + +#define IN_CONTINUE_C +#ifdef USE_CONTINUE_H +# include "continue.h" +#else +# include "setjump.h" +#endif + +/* For platforms with short integers, we use thrown_value instead of + the value returned from setjmp so that any (long) value can be + returned. */ + +#ifdef SHORT_INT +long thrown_value; +#endif + +/* stack_size() returns the number of units of size STACKITEM which + fit between @var{start} and the current top of stack. No check is + done in this routine to ensure that @var{start} is actually in the + current stack segment. */ + +long stack_size(start) + STACKITEM *start; +{ + STACKITEM stack; +#ifdef STACK_GROWS_UP + return &stack - start; +#else + return start - &stack; +#endif /* def STACK_GROWS_UP */ +} + +/* make_root_continuation() allocates (malloc) storage for a + CONTINUATION near the current extent of stack. This newly + allocated CONTINUATION is returned if successful, 0 if not. After + make_root_continuation() returns, the calling routine still needs + to `setjmp(new_continuation->jmpbuf)' in order to complete the + capture of this continuation. */ + +CONTINUATION *make_root_continuation(stack_base) + STACKITEM *stack_base; +{ + CONTINUATION *cont; + cont = (CONTINUATION *)malloc(sizeof(CONTINUATION)); + if (!cont) return 0; + cont->length = 0; + cont->stkbse = stack_base; + cont->parent = cont; + return cont; +} + +/* make_continuation() allocates storage for the current continuation, + copying (or encapsulating) the stack state from parent_cont->stkbse + to the current top of stack. The newly allocated CONTINUATION is + returned if successful, 0 if not. After make_continuation() + returns, the calling routine still needs to + `setjmp(new_continuation->jmpbuf)' in order to complete the capture + of this continuation. */ + +/* Note: allocating local (stack) storage for the CONTINUATION would + not work; Think about it. */ + +CONTINUATION *make_continuation(parent_cont) + CONTINUATION *parent_cont; +{ + CONTINUATION *cont; +#ifdef CHEAP_CONTINUATIONS + cont = (CONTINUATION *)malloc(sizeof(CONTINUATION)); + if (!cont) return 0; + cont->length = 0; + cont->stkbse = parent_cont->stkbse; +#else + long j; + register STACKITEM *src, *dst; + FLUSH_REGISTER_WINDOWS; + j = stack_size(parent_cont->stkbse); + cont = (CONTINUATION *)malloc((sizeof(CONTINUATION) + j*sizeof(STACKITEM))); + if (!cont) return 0; + cont->length = j; + cont->stkbse = parent_cont->stkbse; + src = cont->stkbse; +# ifdef STACK_GROWS_UP + src += parent_cont->length; +# else + src -= parent_cont->length + cont->length; +# endif/* ndef STACK_GROWS_UP */ + dst = (STACKITEM *)(cont + 1); + for (j = cont->length; 0 <= --j; ) *dst++ = *src++; +#endif /* ndef CHEAP_CONTINUATIONS */ + cont->parent = parent_cont; + return cont; +} + +/* free_continuation() is trivial, but who knows what the future + holds. */ + +void free_continuation(cont) + CONTINUATION *cont; +{ + free(cont); +} + +/* Final routine involved in throw()ing to a continuation. After + ensuring that there is sufficient room on the stack for the saved + continuation, dynthrow() copies the continuation onto the stack and + longjmp()s into it. The routine does not return. */ + +/* If you use conservative GC and your Sparc(SUN-4) heap is growing + out of control: + + You are experiencing a GC problem peculiar to the Sparc. The + problem is that contin doesn't know how to clear register windows. + Every location which is not reused still gets marked at GC time. + This causes lots of stuff which should be collected to not be. + This will be a problem with any *conservative* GC until we find + what instruction will clear the register windows. This problem is + exacerbated by using lots of make-CONTINUATION. + + Possibly adding the following before the thrown_value = val; line + might help to clear out unused stack above the continuation (a + small part of the problem). + +#ifdef sparc + bzero((void *)&a, sizeof(STACKITEM) * + (((STACKITEM *)&a) - (dst - cont->length))) +#endif + + Let me know if you try it. */ + +void dynthrow(a) + long *a; +{ + register CONTINUATION *cont = (CONTINUATION *)(a[0]); + long val = a[1]; +#ifndef CHEAP_CONTINUATIONS + register long j; + register STACKITEM *src, *dst = cont->stkbse; +# ifdef STACK_GROWS_UP + if (a[2] && (a - ((long *)a[3]) < 100)) + puts("grow_throw: check if long growth[100]; being optimized out"); + /* if (a[2]) fprintf(stderr, " ct = %ld, dist = %ld\n", a[2], (((long *)a[3]) - a)); */ + if PTR_GE(dst + (cont->length), (STACKITEM *)&a) grow_throw(a); +# else + if (a[2] && (((long *)a[3]) - a < 100)) + puts("grow_throw: check if long growth[100]; being optimized out"); + /* if (a[2]) fprintf(stderr, " ct = %ld, dist = %ld\n", a[2], (((long *)a[3]) - a)); */ + dst -= cont->length; + if PTR_LE(dst, (STACKITEM *)&a) grow_throw(a); +# endif/* def STACK_GROWS_UP */ + FLUSH_REGISTER_WINDOWS; + src = (STACKITEM *)(cont + 1); + for (j = cont->length;0 <= --j;) *dst++ = *src++; +#endif /* ndef CHEAP_CONTINUATIONS */ +#ifdef SHORT_INT + thrown_value = val; + longjmp(cont->jmpbuf, 1); +#else + longjmp(cont->jmpbuf, val); +#endif +} + +/* grow_throw() grows the stack by 100 long words. If the "sizeof + growth" assignment is not sufficient to restrain your overly + optimistic compiler, the stack will grow by much less and + grow_throw() and dynthrow() will waste time calling each other. To + fix this you will have to compile grow_throw() in a separate file + so the compiler won't be able to guess that the growth array isn't + all used. */ + +#ifndef CHEAP_CONTINUATIONS +void grow_throw(a) /* Grow the stack so that there is room */ + long *a; /* to copy in the continuation. Then */ +{ /* retry the throw. */ + long growth[100]; + growth[0] = a[0]; + growth[1] = a[1]; + growth[2] = a[2] + 1; + growth[3] = (long) a; + growth[99] = sizeof growth; + dynthrow(growth); +} +#endif /* ndef CHEAP_CONTINUATIONS */ + +/* throw_to_continuation() restores the stack in effect when + @var{cont} was made and resumes @var{cont}'s processor state. If + the stack cannot be resotred because @var{cont} and @var{root_cont} + do not have the same stkbase, @code{throw_to_continuation() + returns. */ + +/* Note: If 2 or more @var{cont}s share a parent continuation and if + the values of stack allocated variables in that parent continuation + are changed, the results are unspecified. This is because the + parent continuation may or may not be reloaded, depending on what + other throws have intervened. */ + +void throw_to_continuation(cont, val, root_cont) + CONTINUATION *cont; + long val; + CONTINUATION *root_cont; +{ + long a[3]; + a[0] = (long)cont; + a[1] = val; + a[2] = 0; + if (cont->stkbse != root_cont->stkbse) + return; /* Stale continuation */ + dynthrow(a); +} diff --git a/continue.h b/continue.h new file mode 100644 index 0000000..3309172 --- /dev/null +++ b/continue.h @@ -0,0 +1,178 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "continue.h" Scheme Continuations for C. + Author: Aubrey Jaffer. */ + +#ifdef vms +# ifndef CHEAP_CONTINUATIONS + + typedef int jmp_buf[17]; + extern int setjump(jmp_buf env); + extern int longjump(jmp_buf env, int ret); + +# define setjmp setjump +# define longjmp longjump +# else +# include <setjmp.h> +# endif +#else /* ndef vms */ +# ifdef _CRAY1 + typedef int jmp_buf[112]; + extern int setjump(jmp_buf env); + extern int longjump(jmp_buf env, int ret); + +# define setjmp setjump +# define longjmp longjump +# else /* ndef _CRAY1 */ +# include <setjmp.h> +# endif /* ndef _CRAY1 */ +#endif /* ndef vms */ + +/* `other' is a CONTINUATION slot for miscellaneous data of type + CONTINUATION_OTHER. */ + +#ifndef CONTINUATION_OTHER +# define CONTINUATION_OTHER int +#endif + +/* If stack is not longword aligned then */ + +/* #define SHORT_ALIGN */ +#ifdef THINK_C +# define SHORT_ALIGN +#endif +#ifdef MSDOS +# define SHORT_ALIGN +#endif +#ifdef atarist +# define SHORT_ALIGN +#endif + +#ifdef SHORT_ALIGN +typedef short STACKITEM; +#else +typedef long STACKITEM; +#endif + +struct Continuation {jmp_buf jmpbuf; + long thrwval; + long length; + STACKITEM *stkbse; + CONTINUATION_OTHER other; + struct Continuation *parent; + }; +typedef struct Continuation CONTINUATION; + +#ifndef P +# ifdef USE_ANSI_PROTOTYPES +# define P(s) s +# else +# define P(s) () +# endif +#endif + +extern long thrown_value; +long stack_size P((STACKITEM *start)); +CONTINUATION *make_root_continuation P((STACKITEM *stack_base)); +CONTINUATION *make_continuation P((CONTINUATION *parent_cont)); +void free_continuation P((CONTINUATION *cont)); +void dynthrow P((long *a)); +void grow_throw P((long *a)); +void throw_to_continuation P((CONTINUATION *cont, long val, + CONTINUATION *root_cont)); + +/* how to get the local definition for malloc */ + +#ifndef STDC_HEADERS +# ifndef malloc + char *malloc P((sizet size)); +# endif + char *realloc P((char *ptr, sizet size)); +#endif + +/* PTR_LT defines how to compare two addresses (which may not be in + the same array). */ + +#if defined(__TURBOC__) && !defined(__TOS__) +# ifdef PROT386 +# define PTR_LT(x, y) (((long)(x)) < ((long)(y))) +# else +# define PTR_LT(x, y) ((x) < (y)) +# endif +#else /* not __TURBOC__ */ +# ifdef nosve +# define PTR_MASK 0xffffffffffff +# define PTR_LT(x, y) (((int)(x)&PTR_MASK) < ((int)(y)&PTR_MASK)) +# else +# define PTR_LT(x, y) ((x) < (y)) +# endif +#endif + +#define PTR_GT(x, y) PTR_LT(y, x) +#define PTR_LE(x, y) (!PTR_GT(x, y)) +#define PTR_GE(x, y) (!PTR_LT(x, y)) + +/* James Clark came up with this neat one instruction fix for + continuations on the SPARC. It flushes the register windows so + that all the state of the process is contained in the stack. */ + +#ifdef sparc +# define FLUSH_REGISTER_WINDOWS asm("ta 3") +#else +# define FLUSH_REGISTER_WINDOWS /* empty */ +#endif + +/* If stacks grow up then */ + +/* #define STACK_GROWS_UP */ +#ifdef hp9000s800 +# define STACK_GROWS_UP +#endif +#ifdef pyr +# define STACK_GROWS_UP +#endif +#ifdef nosve +# define STACK_GROWS_UP +#endif +#ifdef _UNICOS +# define STACK_GROWS_UP +#endif @@ -0,0 +1,412 @@ +/* Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "crs.c" interface to `curses' interactive terminal control library. + Author: Aubrey Jaffer */ + +#include "scm.h" +#include <curses.h> + +#ifdef MWC +# include <unctrl.h> +#endif + +#ifndef STDC_HEADERS + int wrefresh P((WINDOW *)); + int wgetch P((WINDOW *)); +#endif + +/* define WIN port type */ +#define WIN(obj) ((WINDOW*)CDR(obj)) +#define WINP(obj) (tc16_window==TYP16(obj)) +int freewindow(win) + WINDOW *win; +{ + if (win==stdscr) return 0; + delwin(win); + return 0; +} +int prinwindow(exp, port, writing) + SCM exp; SCM port; int writing; +{ + prinport(exp, port, "window"); + return !0; +} +int bwaddch(c, win) int c; WINDOW *win; {waddch(win, c);return c;} +int bwaddstr(str, win) char *str; WINDOW *win; {waddstr(win, str);return 0;} +sizet bwwrite(str, siz, num, win) + sizet siz, num; + char *str; WINDOW *win; +{ + sizet i = 0, prod = siz*num; + for (;i < prod;i++) waddch(win, str[i]); + return num; +} +int tc16_window; +static ptobfuns winptob = { + mark0, + freewindow, + prinwindow, + equal0, + bwaddch, + bwaddstr, + bwwrite, + wrefresh, + wgetch, + freewindow}; + +SCM mkwindow(win) + WINDOW *win; +{ + SCM z; + if (NULL==win) return BOOL_F; + NEWCELL(z); + DEFER_INTS; + SETCHARS(z, win); + CAR(z) = tc16_window | OPN | RDNG | WRTNG; + ALLOW_INTS; + return z; +} + +SCM *loc_stdscr = 0; +SCM linitscr() +{ + WINDOW *win; + if NIMP(*loc_stdscr) { + refresh(); + return *loc_stdscr; + } + win = initscr(); + return *loc_stdscr = mkwindow(win); +} +SCM lendwin() +{ + if IMP(*loc_stdscr) return BOOL_F; + return ERR==endwin() ? BOOL_F : BOOL_T; +} + +static char s_newwin[] = "newwin", s_subwin[] = "subwin", s_mvwin[] = "mvwin", + s_overlay[] = "overlay", s_overwrite[] = "overwrite"; +SCM lnewwin(lines, cols, args) + SCM lines, cols, args; +{ + SCM begin_y, begin_x; + WINDOW *win; + ASSERT(INUMP(lines), lines, ARG1, s_newwin); + ASSERT(INUMP(cols), cols, ARG2, s_newwin); + ASSERT(2==ilength(args), args, WNA, s_newwin); + begin_y = CAR(args); + begin_x = CAR(CDR(args)); + ASSERT(INUMP(begin_y), begin_y, ARG3, s_newwin); + ASSERT(INUMP(begin_x), begin_y, ARG4, s_newwin); + win = newwin(INUM(lines), INUM(cols), + INUM(begin_y), INUM(begin_x)); + return mkwindow(win); +} + +SCM lmvwin(win, y, x) + SCM win, y, x; +{ + ASSERT(NIMP(win) && WINP(win), win, ARG1, s_mvwin); + ASSERT(INUMP(x), x, ARG2, s_mvwin); + ASSERT(INUMP(y), y, ARG3, s_mvwin); + return ERR==mvwin(WIN(win), INUM(y), INUM(x)) ? BOOL_F : BOOL_T; +} + +SCM lsubwin(win, lines, args) + SCM win, lines, args; +{ + SCM cols, begin_y, begin_x; + WINDOW *nwin; + ASSERT(NIMP(win) && WINP(win), win, ARG1, s_subwin); + ASSERT(INUMP(lines), lines, ARG2, s_subwin); + ASSERT(3==ilength(args), args, WNA, s_subwin); + cols = CAR(args); + args = CDR(args); + begin_y = CAR(args); + begin_x = CAR(CDR(args)); + ASSERT(INUMP(cols), cols, ARG3, s_subwin); + ASSERT(INUMP(begin_y), begin_y, ARG3, s_subwin); + ASSERT(INUMP(begin_x), begin_y, ARG4, s_subwin); + nwin = subwin(WIN(win), INUM(lines), INUM(cols), + INUM(begin_y), INUM(begin_x)); + return mkwindow(nwin); +} + +SCM loverlay(srcwin, dstwin) + SCM srcwin, dstwin; +{ + ASSERT(NIMP(srcwin) && WINP(srcwin), srcwin, ARG1, s_overlay); + ASSERT(NIMP(dstwin) && WINP(dstwin), dstwin, ARG2, s_overlay); + return ERR==overlay(WIN(srcwin), WIN(dstwin)) ? BOOL_F : BOOL_T; +} + +SCM loverwrite(srcwin, dstwin) + SCM srcwin, dstwin; +{ + ASSERT(NIMP(srcwin) && WINP(srcwin), srcwin, ARG1, s_overwrite); + ASSERT(NIMP(dstwin) && WINP(dstwin), dstwin, ARG2, s_overwrite); + return ERR==overwrite(WIN(srcwin), WIN(dstwin)) ? BOOL_F : BOOL_T; +} + +static char s_wmove[] = "wmove", s_wadd[] = "wadd", s_winsert[] = "winsert", + s_box[] = "box"; +SCM lwmove(win, y, x) + SCM win, y, x; +{ + ASSERT(NIMP(win) && WINP(win), win, ARG1, s_wmove); + ASSERT(INUMP(x), x, ARG2, s_wmove); + ASSERT(INUMP(y), y, ARG3, s_wmove); + return ERR==wmove(WIN(win), INUM(y), INUM(x)) ? BOOL_F : BOOL_T; +} + +SCM lwadd(win, obj) + SCM win, obj; +{ + ASSERT(NIMP(win) && WINP(win), win, ARG1, s_wadd); + if ICHRP(obj) + return ERR==waddch(WIN(win), ICHR(obj)) ? BOOL_F : BOOL_T; + if INUMP(obj) + return ERR==waddch(WIN(win), INUM(obj)) ? BOOL_F : BOOL_T; + ASSERT(NIMP(obj) && STRINGP(obj), obj, ARG2, s_wadd); + return ERR==waddstr(WIN(win), CHARS(obj)) ? BOOL_F : BOOL_T; +} + +SCM lwinsert(win, obj) + SCM win, obj; +{ + ASSERT(NIMP(win) && WINP(win), win, ARG1, s_winsert); + if INUMP(obj) + return ERR==winsch(WIN(win), INUM(obj)) ? BOOL_F : BOOL_T; + ASSERT(ICHRP(obj), obj, ARG2, s_winsert); + return ERR==winsch(WIN(win), ICHR(obj)) ? BOOL_F : BOOL_T; +} + +SCM lbox(win, vertch, horch) + SCM win, vertch, horch; +{ + int v, h; + ASSERT(NIMP(win) && WINP(win), win, ARG1, s_box); + if INUMP(vertch) v = INUM(vertch); + else { + ASSERT(ICHRP(vertch), vertch, ARG2, s_box); + v = ICHR(vertch); + } + if INUMP(horch) h = INUM(horch); + else { + ASSERT(ICHRP(horch), horch, ARG3, s_box); + h = ICHR(horch); + } + return ERR==box(WIN(win), v, h) ? BOOL_F : BOOL_T; +} + +static char s_getyx[] = "getyx", s_winch[] = "winch", s_unctrl[] = "unctrl"; +SCM lgetyx(win) + SCM win; +{ + int y, x; + ASSERT(NIMP(win) && WINP(win), win, ARG1, s_getyx); + getyx(WIN(win), y, x); + return cons2(MAKINUM(y), MAKINUM(x), EOL); +} + +SCM lwinch(win) + SCM win; +{ + ASSERT(NIMP(win) && WINP(win), win, ARG1, s_winch); + return MAKICHR(winch(WIN(win))); +} + +SCM lunctrl(c) + SCM c; +{ + ASSERT(ICHRP(c), c, ARG1, s_unctrl); + { + char *str = unctrl(ICHR(c)); + return makfrom0str(str); + } +} +static char s_owidth[] = "output-port-width"; +static char s_oheight[] = "output-port-height"; +SCM owidth(arg) + SCM arg; +{ + if UNBNDP(arg) arg = cur_outp; + ASSERT(NIMP(arg) && OPOUTPORTP(arg), arg, ARG1, s_owidth); + if NIMP(*loc_stdscr) + if WINP(arg) return MAKINUM(WIN(arg)->_maxx+1); + else return MAKINUM(COLS); + return MAKINUM(80); +} +SCM oheight(arg) + SCM arg; +{ + if UNBNDP(arg) arg = cur_outp; + ASSERT(NIMP(arg) && OPOUTPORTP(arg), arg, ARG1, s_owidth); + if NIMP(*loc_stdscr) + if WINP(arg) return MAKINUM(WIN(arg)->_maxy+1); + else return MAKINUM(LINES); + return MAKINUM(24); +} +SCM lrefresh() +{ + return MAKINUM(wrefresh(curscr)); +} + +#define SUBR0(lname, name) SCM lname(){name();return UNSPECIFIED;} +SUBR0(lnl, nl) +SUBR0(lnonl, nonl) +SUBR0(lcbreak, cbreak) +SUBR0(lnocbreak, nocbreak) +SUBR0(lecho, echo) +SUBR0(lnoecho, noecho) +SUBR0(lraw, raw) +SUBR0(lnoraw, noraw) +SUBR0(lsavetty, savetty) +SUBR0(lresetty, resetty) + +static char s_nonl[] = "nonl", s_nocbreak[] = "nocbreak", + s_noecho[] = "noecho", s_noraw[] = "noraw"; + +static iproc subr0s[] = { + {"initscr", linitscr}, + {"endwin", lendwin}, + {&s_nonl[2], lnl}, + {s_nonl, lnonl}, + {&s_nocbreak[2], lcbreak}, + {s_nocbreak, lnocbreak}, + {&s_noecho[2], lecho}, + {s_noecho, lnoecho}, + {&s_noraw[2], lraw}, + {s_noraw, lnoraw}, + {"resetty", lresetty}, + {"savetty", lsavetty}, + {"refresh", lrefresh}, + {0, 0}}; + +#define SUBRW(ln, n, s_n, sn) static char s_n[]=sn;\ + SCM ln(w)SCM w;\ + {ASSERT(NIMP(w) && WINP(w), w, ARG1, sn);\ + return ERR==n(WIN(w))?BOOL_F:BOOL_T;} + +SUBRW(lwerase, werase, s_werase, "werase") +SUBRW(lwclear, wclear, s_wclear, "wclear") +SUBRW(lwclrtobot, wclrtobot, s_wclrtobot, "wclrtobot") +SUBRW(lwclrtoeol, wclrtoeol, s_wclrtoeol, "wclrtoeol") +SUBRW(lwdelch, wdelch, s_wdelch, "wdelch") +SUBRW(lwdeleteln, wdeleteln, s_wdeleteln, "wdeleteln") +SUBRW(lwinsertln, winsertln, s_winsertln, "winsertln") +SUBRW(lscroll, scroll, s_scroll, "scroll") +SUBRW(ltouchwin, touchwin, s_touchwin, "touchwin") +SUBRW(lwstandout, wstandout, s_wstandout, "wstandout") +SUBRW(lwstandend, wstandend, s_wstandend, "wstandend") + +static iproc subr1s[] = { + {s_werase, lwerase}, + {s_wclear, lwclear}, + {s_wclrtobot, lwclrtobot}, + {s_wclrtoeol, lwclrtoeol}, + {s_wdelch, lwdelch}, + {s_wdeleteln, lwdeleteln}, + {s_winsertln, lwinsertln}, + {s_scroll, lscroll}, + {s_touchwin, ltouchwin}, + {s_wstandout, lwstandout}, + {s_wstandend, lwstandend}, + {s_getyx, lgetyx}, + {s_winch, lwinch}, + {s_unctrl, lunctrl}, + {0, 0}}; + +#define SUBROPT(ln, n, s_n, sn) static char s_n[]=sn;\ + SCM ln(w, b)SCM w, b;\ + {ASSERT(NIMP(w) && WINP(w), w, ARG1, sn);\ + return ERR==n(WIN(w), BOOL_F != b)?BOOL_F:BOOL_T;} + +/* SUBROPT(lclearok, clearok, s_clearok, "clearok") */ +/* SUBROPT(lidlok, idlok, s_idlok, "idlok") */ +SUBROPT(lleaveok, leaveok, s_leaveok, "leaveok") +SUBROPT(lscrollok, scrollok, s_scrollok, "scrollok") +/* SUBROPT(lnodelay, nodelay, s_nodelay, "nodelay") */ + +static char s_clearok[] = "clearok"; +SCM lclearok(w, b) SCM w, b; +{ + if (BOOL_T==w) return ERR==clearok(curscr, BOOL_F != b)?BOOL_F:BOOL_T; + ASSERT(NIMP(w) && WINP(w), w, ARG1, s_clearok); + return ERR==clearok(WIN(w), BOOL_F != b)?BOOL_F:BOOL_T; +} + +static iproc subr2s[] = { + {s_overlay, loverlay}, + {s_overwrite, loverwrite}, + {s_wadd, lwadd}, + {s_winsert, lwinsert}, + {s_clearok, lclearok}, + /* {s_idlok, lidlok}, */ + {s_leaveok, lleaveok}, + {s_scrollok, lscrollok}, +/* {s_nodelay, lnodelay}, */ + {0, 0}}; + +void init_crs() +{ + /* savetty(); */ + /* "Stdscr" is a nearly inaccessible symbol used as a GC protect. */ + loc_stdscr = &CDR(sysintern("Stdscr", UNDEFINED)); + tc16_window = newptob(&winptob); + + init_iprocs(subr0s, tc7_subr_0); + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(subr2s, tc7_subr_2); + + make_subr(s_owidth, tc7_subr_1o, owidth); + make_subr(s_oheight, tc7_subr_1o, oheight); + + make_subr(s_newwin, tc7_lsubr_2, lnewwin); + make_subr(s_subwin, tc7_lsubr_2, lsubwin); + + make_subr(s_wmove, tc7_subr_3, lwmove); + make_subr(s_mvwin, tc7_subr_3, lmvwin); + make_subr(s_box, tc7_subr_3, lbox); + add_feature("curses"); + add_final(lendwin); +} @@ -0,0 +1,448 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "dynl.c" dynamically link&load object files. + Author: Aubrey Jaffer */ + +#include "scm.h" +#ifndef STDC_HEADERS + int free (); /* P((char *ptr)) */ +#endif + +/* linkpath holds the filename which just got linked. Scheme + *loadpath* will get set to linkpath and then restored around the + initialization call */ +/* static SCM linkpath; */ + +#ifdef DLD +# include "dld.h" + +void listundefs() +{ + int i; + char **undefs = dld_list_undefined_sym(); + puts(" undefs:"); + for(i = dld_undefined_sym_count;i--;) { + putc('"', stdout); + fputs(undefs[i], stdout); + puts("\""); + } + free(undefs); +} + +static char s_link[] = "dyn:link", s_call[] = "dyn:call"; +SCM l_dyn_link(fname) + SCM fname; +{ + int status; + ASSERT(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); + DEFER_INTS; + status = dld_link(CHARS(fname)); + ALLOW_INTS; + if (!status) {/* linkpath = fname; */ return fname;} + if (DLD_ENOFILE==status) return BOOL_F; + if (DLD_EBADOBJECT==status) return BOOL_F; + dld_perror("DLD"); + return BOOL_F; +} +SCM l_dyn_call(symb, shl) + SCM symb, shl; +{ + int i; + void (*func)() = 0; +/* SCM oloadpath = *loc_loadpath; */ + ASSERT(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); + DEFER_INTS; + if ((i = dld_function_executable_p(CHARS(symb)))) + func = (void (*) ()) dld_get_func(CHARS(symb)); + else dld_perror("DLDP"); + ALLOW_INTS; + if (!i) listundefs(); + if (!func) { + dld_perror("DLD"); + return BOOL_F; + } +/* *loc_loadpath = linkpath; */ + (*func) (); +/* *loc_loadpath = oloadpath; */ + return BOOL_T; +} +static char s_main_call[] = "dyn:main-call"; +SCM l_dyn_main_call(symb, shl, args) + SCM symb, shl, args; +{ + int i; + int (*func)(int argc, char **argv) = 0; + char **argv; +/* SCM oloadpath = *loc_loadpath; */ + ASSERT(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); + DEFER_INTS; + argv = makargvfrmstrs(args, s_main_call); + if ((i = dld_function_executable_p(CHARS(symb)))) + func = (int (*) (int argc, char **argv)) dld_get_func(CHARS(symb)); + else dld_perror("DLDP"); + if (!i) listundefs(); + if (!func) { + must_free_argv(argv); + ALLOW_INTS; + dld_perror("DLD"); + return BOOL_F; + } + ALLOW_INTS; +/* *loc_loadpath = linkpath; */ + i = (*func) ((int)ilength(args), argv); +/* *loc_loadpath = oloadpath; */ + DEFER_INTS; + must_free_argv(argv); + ALLOW_INTS; + return MAKINUM(0L+i); +} + +static char s_unlink[] = "dyn:unlink"; +SCM l_dyn_unlink(fname) + SCM fname; +{ + int status; + ASSERT(NIMP(fname) && STRINGP(fname), fname, ARG1, s_unlink); + DEFER_INTS; + status = dld_unlink_by_file(CHARS(fname), 1); + ALLOW_INTS; + if (!status) return BOOL_T; + dld_perror("DLD"); + return BOOL_F; +} +static iproc subr1s[] = { + {s_link, l_dyn_link}, + {s_unlink, l_dyn_unlink}, + {0, 0}}; +void init_dynl() +{ +# ifndef RTL + if (!execpath) execpath = dld_find_executable(CHARS(CAR(progargs))); + if (dld_init(execpath)) { + dld_perror("DLD:"); +/* wta(CAR(progargs), "couldn't init", "dld"); */ + return; + } +# endif + init_iprocs(subr1s, tc7_subr_1); + make_subr(s_call, tc7_subr_2, l_dyn_call); + make_subr(s_main_call, tc7_lsubr_2, l_dyn_main_call); + add_feature("dld"); +# ifdef DLD_DYNCM + add_feature("dld:dyncm"); +# endif +} +#else + +# ifdef hpux +# include "dl.h" + +# define SHL(obj) ((shl_t*)CDR(obj)) +int prinshl(exp, port, writing) + SCM exp; SCM port; int writing; +{ + lputs("#<shl ", port); + intprint(CDR(exp), 16, port); + lputc('>', port); + return 1; +} +int tc16_shl; +static smobfuns shlsmob = {mark0, free0, prinshl}; + +static char s_link[] = "dyn:link", s_call[] = "dyn:call"; +SCM l_dyn_link(fname) + SCM fname; +{ + SCM z; + shl_t shl; + ASSERT(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); + DEFER_INTS; + shl = shl_load(CHARS(fname), BIND_DEFERRED , 0L); + if (NULL==shl) { + ALLOW_INTS; + return BOOL_F; + } + NEWCELL(z); + SETCHARS(z, shl); + CAR(z) = tc16_shl; + ALLOW_INTS; +/* linkpath = fname; */ + return z; +} +SCM l_dyn_call(symb, shl) + SCM symb, shl; +{ + void (*func)() = 0; + int i; +/* SCM oloadpath = *loc_loadpath; */ + ASSERT(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); + ASSERT(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_call); + DEFER_INTS; + if ((i = shl_findsym(&SHL(shl), + CHARS(symb), + TYPE_PROCEDURE, &func)) != 0) { + puts(" undef:"); puts(CHARS(symb)); + } + ALLOW_INTS; + if (i != 0) return BOOL_F; +/* *loc_loadpath = linkpath; */ + (*func) (); +/* *loc_loadpath = oloadpath; */ + return BOOL_T; +} + +static char s_main_call[] = "dyn:main-call"; +SCM l_dyn_main_call(symb, shl, args) + SCM symb, shl, args; +{ + int i; + int (*func)P((int argc, char **argv)) = 0; + char **argv; +/* SCM oloadpath = *loc_loadpath; */ + ASSERT(NIMP(symb) && STRINGP(symb), symb, ARG1, s_main_call); + ASSERT(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_main_call); + DEFER_INTS; + if ((i = shl_findsym(&SHL(shl), + CHARS(symb), + TYPE_PROCEDURE, &func)) != 0) { + puts(" undef:"); puts(CHARS(symb)); + } + argv = makargvfrmstrs(args, s_main_call); + ALLOW_INTS; + if (i != 0) return BOOL_F; +/* *loc_loadpath = linkpath; */ + i = (*func) ((int)ilength(args), argv); +/* *loc_loadpath = oloadpath; */ + DEFER_INTS; + must_free_argv(argv); + ALLOW_INTS; + return MAKINUM(0L+i); +} + +static char s_unlink[] = "dyn:unlink"; +SCM l_dyn_unlink(shl) + SCM shl; +{ + int status; + ASSERT(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG1, s_unlink); + DEFER_INTS; + status = shl_unload(SHL(shl)); + ALLOW_INTS; + if (!status) return BOOL_T; + return BOOL_F; +} +static iproc subr1s[] = { + {s_link, l_dyn_link}, + {s_unlink, l_dyn_unlink}, + {0, 0}}; +void init_dynl() +{ + tc16_shl = newsmob(&shlsmob); + init_iprocs(subr1s, tc7_subr_1); + make_subr(s_call, tc7_subr_2, l_dyn_call); + make_subr(s_main_call, tc7_lsubr_2, l_dyn_main_call); + add_feature("shl"); +} +# endif +#endif + +#ifdef vms +/* This permits dynamic linking. For example, the procedure of 0 arguments + from a file could be the initialization procedure. + (vms:dynamic-link-call "MYDISK:[MYDIR].EXE" "foo" "INIT_FOO") + The first argument specifies the directory where the file specified + by the second argument resides. The current directory would be + "SYS$DISK:[].EXE". + The second argument cannot contain any punctuation. + The third argument probably needs to be uppercased to mimic the VMS linker. + */ + +# include <descrip.h> +# include <ssdef.h> +# include <rmsdef.h> + +struct dsc$descriptor *descriptorize(x, buff) + struct dsc$descriptor *x; + SCM buff; +{(*x).dsc$w_length = LENGTH(buff); + (*x).dsc$a_pointer = CHARS(buff); + (*x).dsc$b_class = DSC$K_CLASS_S; + (*x).dsc$b_dtype = DSC$K_DTYPE_T; + return(x);} + +static char s_dynl[] = "vms:dynamic-link-call"; +SCM dynl(dir, symbol, fname) + SCM dir, symbol, fname; +{ + struct dsc$descriptor fnamed, symbold, dird; + void (*fcn)(); + long retval; + ASSERT(IMP(dir) || STRINGP(dir), dir, ARG1, s_dynl); + ASSERT(NIMP(fname) && STRINGP(fname), fname, ARG2, s_dynl); + ASSERT(NIMP(symbol) && STRINGP(symbol), symbol, ARG3, s_dynl); + descriptorize(&fnamed, fname); + descriptorize(&symbold, symbol); + DEFER_INTS; + retval = lib$find_image_symbol(&fnamed, &symbold, &fcn, + IMP(dir) ? 0 : descriptorize(&dird, dir)); + if (SS$_NORMAL != retval) { + /* wta(MAKINUM(retval), "vms error", s_dynl); */ + ALLOW_INTS; + return BOOL_F; + } + ALLOW_INTS; +/* *loc_loadpath = dir; */ + (*fcn)(); +/* *loc_loadpath = oloadpath; */ + return BOOL_T; +} + +void init_dynl() +{ + make_subr(s_dynl, tc7_subr_3, dynl); +} +#endif + + +#ifdef SUN_DL +# include <dlfcn.h> + +# define SHL(obj) ((void*)CDR(obj)) + +# ifdef SVR4 /* Solaris 2. */ +# define DLOPEN_MODE RTLD_LAZY +# else +# define DLOPEN_MODE 1 /* Thats what it says in the man page. */ +# endif + +sizet frshl(ptr) + CELLPTR ptr; +{ +# if 0 + /* Should freeing a shl close and possibly unmap the object file it */ + /* refers to? */ + if(SHL(ptr)) + dlclose(SHL(ptr)); +# endif + return 0; +} + +int prinshl(exp, port, writing) + SCM exp; SCM port; int writing; +{ + lputs("#<shl ", port); + intprint(CDR(exp), 16, port); + lputc('>', port); + return 1; +} +int tc16_shl; +static smobfuns shlsmob = {mark0, frshl, prinshl}; + +static char s_link[] = "dyn:link", s_call[] = "dyn:call"; +SCM l_dyn_link(fname) + SCM fname; +{ + SCM z; + void *handle; + if FALSEP(fname) return fname; + ASSERT(NIMP(fname) && STRINGP(fname), fname, ARG1, s_link); + DEFER_INTS; + handle = dlopen(CHARS(fname), DLOPEN_MODE); + if (NULL==handle) { + ALLOW_INTS; + return BOOL_F; + } + NEWCELL(z); + SETCHARS(z, handle); + CAR(z) = tc16_shl; + ALLOW_INTS; +/* linkpath = fname; */ + return z; +} + +SCM l_dyn_call(symb, shl) + SCM symb, shl; +{ + void (*func)() = 0; +/* SCM oloadpath = *loc_loadpath; */ + ASSERT(NIMP(symb) && STRINGP(symb), symb, ARG1, s_call); + ASSERT(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG2, s_call); + DEFER_INTS; + func = dlsym(SHL(shl), CHARS(symb)); + if (!func) { + const char *dlr = dlerror(); + ALLOW_INTS; + if (dlr) puts(dlr); + return BOOL_F; + } + ALLOW_INTS; +/* *loc_loadpath = linkpath; */ + (*func) (); +/* *loc_loadpath = oloadpath; */ + return BOOL_T; +} +static char s_unlink[] = "dyn:unlink"; +SCM l_dyn_unlink(shl) + SCM shl; +{ + int status; + ASSERT(NIMP(shl) && CAR(shl)==tc16_shl, shl, ARG1, s_unlink); + DEFER_INTS; + status = dlclose(SHL(shl)); + SETCHARS(shl, NULL); + ALLOW_INTS; + if (!status) return BOOL_T; + return BOOL_F; +} +static iproc subr1s[] = { +{s_link, l_dyn_link}, +{s_unlink, l_dyn_unlink}, +{0, 0}}; + +void init_dynl() +{ + tc16_shl = newsmob(&shlsmob); + init_iprocs(subr1s, tc7_subr_1); + make_subr(s_call, tc7_subr_2, l_dyn_call); + add_feature("sun-dl"); +} +#endif /* SUN_DL */ @@ -0,0 +1,614 @@ +/* C code startup routine. + Copyright (C) 1985, 1986, 1992 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* The standard Vax 4.2 Unix crt0.c cannot be used for Emacs + because it makes `environ' an initialized variable. + It is easiest to have a special crt0.c on all machines + though I don't know whether other machines actually need it. */ + +/* On the vax and 68000, in BSD4.2 and USG5.2, + this is the data format on startup: + (vax) ap and fp are unpredictable as far as I know; don't use them. + sp -> word containing argc + word pointing to first arg string + [word pointing to next arg string]... 0 or more times + 0 +Optionally: + [word pointing to environment variable]... 1 or more times + ... + 0 +And always: + first arg string + [next arg string]... 0 or more times +*/ + +/* On the 16000, at least in the one 4.2 system I know about, + the initial data format is + sp -> word containing argc + word containing argp + word pointing to first arg string, and so on as above +*/ + +#ifdef emacs +#include <config.h> +#endif + +/* ******** WARNING ******** + Do not insert any data definitions before data_start! + Since this is the first file linked, the address of the following + variable should correspond to the start of initialized data space. + On some systems this is a constant that is independent of the text + size for shared executables. On others, it is a function of the + text size. In short, this seems to be the most portable way to + discover the start of initialized data space dynamically at runtime, + for either shared or unshared executables, on either swapping or + virtual systems. It only requires that the linker allocate objects + in the order encountered, a reasonable model for most Unix systems. + Similarly, note that the address of _start() should be the start + of text space. Fred Fish, UniSoft Systems Inc. */ + +int data_start = 0; + +#ifdef NEED_ERRNO +int errno; +#endif + +#ifndef DONT_NEED_ENVIRON +char **environ; +#endif + +#ifndef static +/* On systems where the static storage class is usable, this function + should be declared as static. Otherwise, the static keyword has + been defined to be something else, and code for those systems must + take care of this declaration appropriately. */ +static start1 (); +#endif + +#ifdef APOLLO +extern char *malloc(), *realloc(), *(*_libc_malloc) (), *(*_libc_realloc)(); +extern void free(), (*_libc_free) (); extern int main(); +std_$call void unix_$main(); + +_start() +{ + _libc_malloc = malloc; + _libc_realloc = realloc; + _libc_free = free; + unix_$main(main); /* no return */ +} +#endif /* APOLLO */ + +#if defined(orion) || defined(pyramid) || defined(celerity) || defined(ALLIANT) || defined(clipper) || defined(sps7) + +#if defined(sps7) && defined(V3x) + asm(" section 10"); + asm(" ds.b 0xb0"); +#endif + +#ifdef ALLIANT +/* _start must initialize _curbrk and _minbrk on the first startup; + when starting up after dumping, it must initialize them to what they were + before the dumping, since they are in the shared library and + are not dumped. See ADJUST_EXEC_HEADER in m-alliant.h. */ +extern unsigned char *_curbrk, *_minbrk; +extern unsigned char end; +unsigned char *_setbrk = &end; +#ifdef ALLIANT_2800 +unsigned char *_end = &end; +#endif +#endif + +#ifndef DUMMIES +#define DUMMIES +#endif + +_start (DUMMIES argc, argv, envp) + int argc; + char **argv, **envp; +{ +#ifdef ALLIANT +#ifdef ALLIANT_2800 + _curbrk = _end; + _minbrk = _end; +#else + _curbrk = _setbrk; + _minbrk = _setbrk; +#endif +#endif + + environ = envp; + + exit (main (argc, argv, envp)); +} + +#endif /* orion or pyramid or celerity or alliant or clipper */ + +#if defined (ns16000) && !defined (sequent) && !defined (UMAX) && !defined (CRT0_DUMMIES) + +_start () +{ +/* On 16000, _start pushes fp onto stack */ + start1 (); +} + +/* ignore takes care of skipping the fp value pushed in start. */ +static +start1 (ignore, argc, argv) + int ignore; + int argc; + register char **argv; +{ + environ = argv + argc + 1; + + if (environ == *argv) + environ--; + exit (main (argc, argv, environ)); +} +#endif /* ns16000, not sequent and not UMAX, and not the CRT0_DUMMIES method */ + +#ifdef UMAX +_start() +{ + asm(" exit [] # undo enter"); + asm(" .set exitsc,1"); + asm(" .set sigcatchall,0x400"); + + asm(" .globl _exit"); + asm(" .globl start"); + asm(" .globl __start"); + asm(" .globl _main"); + asm(" .globl _environ"); + asm(" .globl _sigvec"); + asm(" .globl sigentry"); + + asm("start:"); + asm(" br .xstart"); + asm(" .org 0x20"); + asm(" .double p_glbl,0,0xf00000,0"); + asm(" .org 0x30"); + asm(".xstart:"); + asm(" adjspb $8"); + asm(" movd 8(sp),0(sp) # argc"); + asm(" addr 12(sp),r0"); + asm(" movd r0,4(sp) # argv"); + asm("L1:"); + asm(" movd r0,r1"); + asm(" addqd $4,r0"); + asm(" cmpqd $0,0(r1) # null args term ?"); + asm(" bne L1"); + asm(" cmpd r0,0(4(sp)) # end of 'env' or 'argv' ?"); + asm(" blt L2"); + asm(" addqd $-4,r0 # envp's are in list"); + asm("L2:"); + asm(" movd r0,8(sp) # env"); + asm(" movd r0,@_environ # indir is 0 if no env ; not 0 if env"); + asm(" movqd $0,tos # setup intermediate signal handler"); + asm(" addr @sv,tos"); + asm(" movzwd $sigcatchall,tos"); + asm(" jsr @_sigvec"); + asm(" adjspb $-12"); + asm(" jsr @_main"); + asm(" adjspb $-12"); + asm(" movd r0,tos"); + asm(" jsr @_exit"); + asm(" adjspb $-4"); + asm(" addr @exitsc,r0"); + asm(" svc"); + asm(" .align 4 # sigvec arg"); + asm("sv:"); + asm(" .double sigentry"); + asm(" .double 0"); + asm(" .double 0"); + + asm(" .comm p_glbl,1"); +} +#endif /* UMAX */ + +#ifdef CRT0_DUMMIES + +/* Define symbol "start": here; some systems want that symbol. */ +#ifdef DOT_GLOBAL_START +asm(" .text "); +asm(" .globl start "); +asm(" start: "); +#endif /* DOT_GLOBAL_START */ + +#ifdef NODOT_GLOBAL_START +asm(" text "); +asm(" global start "); +asm(" start: "); +#endif /* NODOT_GLOBAL_START */ + +#ifdef m68000 + +/* GCC 2.1, when optimization is turned off, seems to want to push a + word of garbage on the stack, which screws up the CRT0_DUMMIES + hack. So we hand-code _start in assembly language. */ +asm(".text "); +asm(" .even "); +asm(".globl __start "); +asm("__start: "); +asm(" link a6,#0 "); +asm(" jbsr _start1 "); +asm(" unlk a6 "); +asm(" rts "); + +#else /* not m68000 */ + +_start () +{ +/* On vax, nothing is pushed here */ +/* On sequent, bogus fp is pushed here */ + start1 (); +} + +#endif /* possibly m68000 */ + +static +start1 (CRT0_DUMMIES argc, xargv) + int argc; + char *xargv; +{ + register char **argv = &xargv; + environ = argv + argc + 1; + + if ((char *)environ == xargv) + environ--; + exit (main (argc, argv, environ)); + + /* Refer to `start1' so GCC will not think it is never called + and optimize it out. */ + (void) &start1; +} +#else /* not CRT0_DUMMIES */ + +/* "m68k" and "m68000" both stand for m68000 processors, + but with different program-entry conventions. + This is a kludge. Now that the CRT0_DUMMIES mechanism above exists, + most of these machines could use the vax code above + with some suitable definition of CRT0_DUMMIES. + Then the symbol m68k could be flushed. + But I don't want to risk breaking these machines + in a version 17 patch release, so that change is being put off. */ + +#ifdef m68k /* Can't do it all from C */ + asm (" global _start"); + asm (" text"); + asm ("_start:"); +#ifndef NU +#ifdef STRIDE + asm (" comm havefpu%,2"); +#else /* m68k, not STRIDE */ + asm (" comm splimit%,4"); +#endif /* STRIDE */ + asm (" global exit"); + asm (" text"); +#ifdef STRIDE + asm (" trap &3"); + asm (" mov.w %d0,havefpu%"); +#else /* m68k, not STRIDE */ + asm (" mov.l %d0,splimit%"); +#endif /* STRIDE */ +#endif /* not NU */ + asm (" jsr start1"); + asm (" mov.l %d0,(%sp)"); + asm (" jsr exit"); + asm (" mov.l &1,%d0"); /* d0 = 1 => exit */ + asm (" trap &0"); +#else /* m68000, not m68k */ + +#ifdef m68000 + +#ifdef ISI68K +/* Added by ESM Sun May 24 12:44:02 1987 to get new ISI library to work */ +/* Edited by Ray Mon May 15 15:59:56 EST 1989 so we can compile with gcc */ +#if defined(BSD4_3) && !defined(__GNUC__) +static foo () { +#endif + asm (" .globl is68020"); + asm ("is68020:"); +#ifndef BSD4_3 + asm (" .long 0x00000000"); + asm (" .long 0xffffffff"); +/* End of stuff added by ESM */ +#endif + asm (" .text"); + asm (" .globl __start"); + asm ("__start:"); + asm (" .word 0"); + asm (" link a6,#0"); + asm (" jbsr _start1"); + asm (" unlk a6"); + asm (" rts"); +#if defined(BSD4_3) && !defined(__GNUC__) + } +#endif +#else /* not ISI68K */ + +_start () +{ +#ifdef sun +#ifdef LISP_FLOAT_TYPE + finitfp_(); +#endif +#endif +/* On 68000, _start pushes a6 onto stack */ + start1 (); +} +#endif /* not ISI68k */ +#endif /* m68000 */ +#endif /* m68k */ + +#if defined(m68k) || defined(m68000) +/* ignore takes care of skipping the a6 value pushed in start. */ +static +#if defined(m68k) +start1 (argc, xargv) +#else +start1 (ignore, argc, xargv) +#endif + int argc; + char *xargv; +{ + register char **argv = &xargv; + environ = argv + argc + 1; + + if ((char *)environ == xargv) + environ--; +#ifdef sun_68881 + asm(" jsr f68881_used"); +#endif +#ifdef sun_fpa + asm(" jsr ffpa_used"); +#endif +#ifdef sun_soft + asm(" jsr start_float"); +#endif + exit (main (argc, argv, environ)); +} + +#endif /* m68k or m68000 */ + +#endif /* not CRT0_DUMMIES */ + +#ifdef hp9000s300 +int argc_value; +char **argv_value; +#ifdef OLD_HP_ASSEMBLER + asm(" text"); + asm(" globl __start"); + asm(" globl _exit"); + asm(" globl _main"); + asm("__start"); + asm(" dc.l 0"); + asm(" subq.w #0x1,d0"); + asm(" move.w d0,float_soft"); + asm(" move.l 0x4(a7),d0"); + asm(" beq.s skip_1"); + asm(" move.l d0,a0"); + asm(" clr.l -0x4(a0)"); + asm("skip_1"); + asm(" move.l a7,a0"); + asm(" subq.l #0x8,a7"); + asm(" move.l (a0),(a7)"); + asm(" move.l (a0),_argc_value"); + asm(" addq.l #0x4,a0"); + asm(" move.l a0,0x4(a7)"); + asm(" move.l a0,_argv_value"); + asm("incr_loop"); + asm(" tst.l (a0)+"); + asm(" bne.s incr_loop"); + asm(" move.l 0x4(a7),a1"); + asm(" cmp.l (a1),a0"); + asm(" blt.s skip_2"); + asm(" subq.l #0x4,a0"); + asm("skip_2"); + asm(" move.l a0,0x8(a7)"); + asm(" move.l a0,_environ"); + asm(" jsr _main"); + asm(" addq.l #0x8,a7"); + asm(" move.l d0,-(a7)"); + asm(" jsr _exit"); + asm(" move.w #0x1,d0"); + asm(" trap #0x0"); + asm(" comm float_soft,4"); +/* float_soft is allocated in this way because C would + put an underscore character in its name otherwise. */ + +#else /* new hp assembler */ + + asm(" text"); + asm(" global float_loc"); + asm(" set float_loc,0xFFFFB000"); + asm(" global fpa_loc"); + asm(" set fpa_loc,0xfff08000"); + asm(" global __start"); + asm(" global _exit"); + asm(" global _main"); + asm("__start:"); + asm(" byte 0,0,0,0"); + asm(" subq.w &1,%d0"); + asm(" mov.w %d0,float_soft"); + asm(" mov.w %d1,flag_68881"); +#ifndef HPUX_68010 + asm(" beq.b skip_float"); + asm(" fmov.l &0x7400,%fpcr"); +/* asm(" fmov.l &0x7480,%fpcr"); */ +#endif /* HPUX_68010 */ + asm("skip_float:"); + asm(" mov.l %a0,%d0"); + asm(" add.l %d0,%d0"); + asm(" subx.w %d1,%d1"); + asm(" mov.w %d1,flag_68010"); + asm(" add.l %d0,%d0"); + asm(" subx.w %d1,%d1"); + asm(" mov.w %d1,flag_fpa"); + asm(" tst.l %d2"); + asm(" ble.b skip_3"); + asm(" lsl flag_68881"); + asm(" lsl flag_fpa"); + asm("skip_3:"); + asm(" mov.l 4(%a7),%d0"); + asm(" beq.b skip_1"); + asm(" mov.l %d0,%a0"); + asm(" clr.l -4(%a0)"); + asm("skip_1:"); + asm(" mov.l %a7,%a0"); + asm(" subq.l &8,%a7"); + asm(" mov.l (%a0),(%a7)"); + asm(" mov.l (%a0),_argc_value"); + asm(" addq.l &4,%a0"); + asm(" mov.l %a0,4(%a7)"); + asm(" mov.l %a0,_argv_value"); + asm("incr_loop:"); + asm(" tst.l (%a0)+"); + asm(" bne.b incr_loop"); + asm(" mov.l 4(%a7),%a1"); + asm(" cmp.l %a0,(%a1)"); + asm(" blt.b skip_2"); + asm(" subq.l &4,%a0"); + asm("skip_2:"); + asm(" mov.l %a0,8(%a7)"); + asm(" mov.l %a0,_environ"); + asm(" jsr _main"); + asm(" addq.l &8,%a7"); + asm(" mov.l %d0,-(%a7)"); + asm(" jsr _exit"); + asm(" mov.w &1,%d0"); + asm(" trap &0"); + asm(" comm float_soft, 4"); + asm(" comm flag_68881, 4"); + asm(" comm flag_68010, 4"); + asm(" comm flag_68040, 4"); + asm(" comm flag_fpa, 4"); + +#endif /* new hp assembler */ +#endif /* hp9000s300 */ + +#ifdef GOULD + +/* startup code has to be in near text rather + than fartext as allocated by the C compiler. */ + asm(" .text"); + asm(" .align 2"); + asm(" .globl __start"); + asm(" .text"); + asm("__start:"); +/* setup base register b1 (function base). */ + asm(" .using b1,."); + asm(" tpcbr b1"); +/* setup base registers b3 through b7 (data references). */ + asm(" file basevals,b3"); +/* setup base register b2 (stack pointer); it should be + aligned on a 8-word boundary; but because it is pointing + to argc, its value should be remembered (in r5). */ + asm(" movw b2,r4"); + asm(" movw b2,r5"); + asm(" andw #~0x1f,r4"); + asm(" movw r4,b2"); +/* allocate stack frame to do some work. */ + asm(" subea 16w,b2"); +/* initialize signal catching for UTX/32 1.2; this is + necessary to make restart from saved image work. */ + asm(" movea sigcatch,r1"); + asm(" movw r1,8w[b2]"); + asm(" svc #1,#150"); +/* setup address of argc for start1. */ + asm(" movw r5,8w[b2]"); + asm(" func #1,_start1"); + asm(" halt"); +/* space for ld to store base register initial values. */ + asm(" .align 5"); + asm("basevals:"); + asm(" .word __base3,__base4,__base5,__base6,__base7"); + +static +start1 (xargc) + int *xargc; +{ + register int argc; + register char **argv; + + argc = *xargc; + argv = (char **)(xargc) + 1; + environ = argv + argc + 1; + + if (environ == argv) + environ--; + exit (main (argc, argv, environ)); + +} + +#endif /* GOULD */ + +#ifdef elxsi +#include <elxsi/argvcache.h> + +extern char **environ; +extern int errno; +extern void _init_doscan(), _init_iob(); +extern char end[]; +char *_init_brk = end; + +_start() +{ + environ = exec_cache.ac_envp; + brk (_init_brk); + errno = 0; + _init_doscan (); + _init_iob (); + _exit (exit (main (exec_cache.ac_argc, + exec_cache.ac_argv, + exec_cache.ac_envp))); +} +#endif /* elxsi */ + + +#ifdef sparc +asm (".global __start"); +asm (".text"); +asm ("__start:"); +asm (" mov 0, %fp"); +asm (" ld [%sp + 64], %o0"); +asm (" add %sp, 68, %o1"); +asm (" sll %o0, 2, %o2"); +asm (" add %o2, 4, %o2"); +asm (" add %o1, %o2, %o2"); +asm (" sethi %hi(_environ), %o3"); +asm (" st %o2, [%o3+%lo(_environ)]"); +asm (" andn %sp, 7, %sp"); +asm (" call _main"); +asm (" sub %sp, 24, %sp"); +asm (" call __exit"); +asm (" nop"); + +#endif /* sparc */ + +#if __FreeBSD__ == 2 +char *__progname; +#endif +#ifdef __bsdi__ +#include <sys/param.h> /* for version number */ +#if defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199501) +char *__progname; +#endif +#endif /* __bsdi__ */ diff --git a/edline.c b/edline.c new file mode 100644 index 0000000..ab15578 --- /dev/null +++ b/edline.c @@ -0,0 +1,94 @@ +/* Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "readline.c" Scheme interface to readline library + Author: Radey Shouman */ + +#include "scm.h" + +char *readline P((const char *prompt)); +void add_history P((char *p)); + + /* Reads on stdin/stdout only */ +static char s_readline[] = "read-edited-line"; +SCM lreadline(prompt) + SCM prompt; +{ + SCM res; + char *s; + ASSERT(NIMP(prompt) && STRINGP(prompt), prompt, ARG1, s_readline); + s = readline(CHARS(prompt)); + if (NULL == s) return EOF_VAL; + NEWCELL(res); + DEFER_INTS; + SETCHARS(res,s); + SETLENGTH(res,(sizet)strlen(s),tc7_string); + ALLOW_INTS; + return res; +} +static char s_add_history[] = "add-history"; +SCM ladd_history(line) + SCM line; +{ + ASSERT(NIMP(line) && STRINGP(line), line, ARG1, s_add_history); + add_history(CHARS(line)); + return UNSPECIFIED; +} +static char s_def_inport[] = "default-input-port"; +SCM def_inport() +{ + return def_inp; +} +static char s_def_outport[] = "default-output-port"; +SCM def_outport() +{ + return def_outp; +} +static char s_Iedline[] = "Iedline.scm"; +void init_edline() +{ + make_subr(s_def_inport, tc7_subr_0, def_inport); + make_subr(s_def_outport, tc7_subr_0, def_outport); + make_subr(s_readline, tc7_subr_1, lreadline); + make_subr(s_add_history, tc7_subr_1, ladd_history); + if (scm_ldprog(s_Iedline)) + wta(*loc_errobj, "couldn't init", s_Iedline); +} @@ -0,0 +1,1494 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "eval.c" eval and apply. + Authors: Aubrey Jaffer & Hugh E. Secker-Walker. */ + +#include "scm.h" +#include "setjump.h" + +#define I_SYM(x) (CAR((x)-1L)) +#define I_VAL(x) (CDR((x)-1L)) +#define EVALCELLCAR(x, env) SYMBOLP(CAR(x))?*lookupcar(x, env):ceval(CAR(x), env) +#ifdef MEMOIZE_LOCALS +# define EVALIMP(x, env) (ILOCP(x)?*ilookup((x), env):x) +#else +# define EVALIMP(x, env) x +#endif +#define EVALCAR(x, env) (NCELLP(CAR(x))?(IMP(CAR(x))?EVALIMP(CAR(x), env):\ + I_VAL(CAR(x))):EVALCELLCAR(x, env)) +#define EXTEND_ENV acons + +#ifdef MEMOIZE_LOCALS +SCM *ilookup(iloc, env) + SCM iloc, env; +{ + register int ir = IFRAME(iloc); + register SCM er = env; + for(;0 != ir;--ir) er = CDR(er); + er = CAR(er); + for(ir = IDIST(iloc);0 != ir;--ir) er = CDR(er); + if ICDRP(iloc) return &CDR(er); + return &CAR(CDR(er)); +} +#endif +SCM *lookupcar(vloc, genv) + SCM vloc, genv; +{ + SCM env = genv; + register SCM *al, fl, var = CAR(vloc); +#ifdef MEMOIZE_LOCALS + register SCM iloc = ILOC00; +#endif + for(;NIMP(env);env = CDR(env)) { + al = &CAR(env); + for(fl = CAR(*al);NIMP(fl);fl = CDR(fl)) { + if NCONSP(fl) + if (fl==var) { +#ifdef MEMOIZE_LOCALS + CAR(vloc) = iloc + ICDR; +#endif + return &CDR(*al); + } + else break; + al = &CDR(*al); + if (CAR(fl)==var) { +#ifdef MEMOIZE_LOCALS +# ifndef RECKLESS /* letrec inits to UNDEFINED */ + if UNBNDP(CAR(*al)) {env = EOL; goto errout;} +# endif + CAR(vloc) = iloc; +#endif + return &CAR(*al); + } +#ifdef MEMOIZE_LOCALS + iloc += IDINC; +#endif + } +#ifdef MEMOIZE_LOCALS + iloc = (~IDSTMSK) & (iloc + IFRINC); +#endif + } + var = sym2vcell(var); +#ifndef RECKLESS + if (NNULLP(env) || UNBNDP(CDR(var))) { + var = CAR(var); + errout: + everr(vloc, genv, var, + NULLP(env)?"unbound variable: ":"damaged environment", ""); + } +#endif + CAR(vloc) = var + 1; + return &CDR(var); +} +static SCM unmemocar(form, env) + SCM form, env; +{ + register int ir; + if IMP(form) return form; + if (1==TYP3(form)) + CAR(form) = I_SYM(CAR(form)); +#ifdef MEMOIZE_LOCALS + else if ILOCP(CAR(form)) { + for(ir = IFRAME(CAR(form)); ir != 0; --ir) env = CDR(env); + env = CAR(CAR(env)); + for(ir = IDIST(CAR(form));ir != 0;--ir) env = CDR(env); + CAR(form) = ICDRP(CAR(form)) ? env : CAR(env); + } +#endif + return form; +} + +SCM eval_args(l, env) + SCM l, env; +{ + SCM res = EOL, *lloc = &res; + while NIMP(l) { + *lloc = cons(EVALCAR(l, env), EOL); + lloc = &CDR(*lloc); + l = CDR(l); + } + return res; +} + + /* the following rewrite expressions and + * some memoized forms have different syntax */ + +static char s_expression[] = "missing or extra expression"; +static char s_test[] = "bad test"; +static char s_body[] = "bad body"; +static char s_bindings[] = "bad bindings"; +static char s_variable[] = "bad variable"; +static char s_clauses[] = "bad or missing clauses"; +static char s_formals[] = "bad formals"; +#define ASSYNT(_cond, _arg, _pos, _subr) if(!(_cond))wta(_arg, (char *)_pos, _subr); + +SCM i_dot, i_quote, i_quasiquote, i_lambda, + i_let, i_arrow, i_else, i_unquote, i_uq_splicing, i_apply; +static char s_quasiquote[] = "quasiquote"; +static char s_delay[] = "delay"; + +#define ASRTSYNTAX(cond_, msg_) if(!(cond_))wta(xorig, (msg_), what); + +static void bodycheck(xorig, bodyloc, what) + SCM xorig, *bodyloc; + char *what; +{ + ASRTSYNTAX(ilength(*bodyloc) >= 1, s_expression); +} + +SCM m_quote(xorig, env) + SCM xorig, env; +{ + ASSYNT(ilength(CDR(xorig))==1, xorig, s_expression, s_quote); + return cons(IM_QUOTE, CDR(xorig)); +} + +SCM m_begin(xorig, env) + SCM xorig, env; +{ + ASSYNT(ilength(CDR(xorig)) >= 1, xorig, s_expression, s_begin); + return cons(IM_BEGIN, CDR(xorig)); +} + +SCM m_if(xorig, env) + SCM xorig, env; +{ + int len = ilength(CDR(xorig)); + ASSYNT(len >= 2 && len <= 3, xorig, s_expression, s_if); + return cons(IM_IF, CDR(xorig)); +} + +SCM m_set(xorig, env) + SCM xorig, env; +{ + SCM x = CDR(xorig); + ASSYNT(2==ilength(x), xorig, s_expression, s_set); + ASSYNT(NIMP(CAR(x)) && SYMBOLP(CAR(x)), + xorig, s_variable, s_set); + return cons(IM_SET, x); +} + +SCM m_and(xorig, env) + SCM xorig, env; +{ + int len = ilength(CDR(xorig)); + ASSYNT(len >= 0, xorig, s_test, s_and); + if (len >= 1) return cons(IM_AND, CDR(xorig)); + else return BOOL_T; +} + +SCM m_or(xorig, env) + SCM xorig, env; +{ + int len = ilength(CDR(xorig)); + ASSYNT(len >= 0, xorig, s_test, s_or); + if (len >= 1) return cons(IM_OR, CDR(xorig)); + else return BOOL_F; +} + +SCM m_case(xorig, env) + SCM xorig, env; +{ + SCM proc, x = CDR(xorig); + ASSYNT(ilength(x) >= 2, xorig, s_clauses, s_case); + while(NIMP(x = CDR(x))) { + proc = CAR(x); + ASSYNT(ilength(proc) >= 2, xorig, s_clauses, s_case); + ASSYNT(ilength(CAR(proc)) >= 0 || i_else==CAR(proc), + xorig, s_clauses, s_case); + } + return cons(IM_CASE, CDR(xorig)); +} + +SCM m_cond(xorig, env) + SCM xorig, env; +{ + SCM arg1, x = CDR(xorig); + int len = ilength(x); + ASSYNT(len >= 1, xorig, s_clauses, s_cond); + while(NIMP(x)) { + arg1 = CAR(x); + len = ilength(arg1); + ASSYNT(len >= 1, xorig, s_clauses, s_cond); + if (i_else==CAR(arg1)) { + ASSYNT(NULLP(CDR(x)) && len >= 2, xorig, "bad ELSE clause", s_cond); + CAR(arg1) = BOOL_T; + } + if (len >= 2 && i_arrow==CAR(CDR(arg1))) + ASSYNT(3==len && NIMP(CAR(CDR(CDR(arg1)))), + xorig, "bad recipient", s_cond); + x = CDR(x); + } + return cons(IM_COND, CDR(xorig)); +} + +SCM m_lambda(xorig, env) + SCM xorig, env; +{ + SCM proc, x = CDR(xorig); + if (ilength(x) < 2) goto badforms; + proc = CAR(x); + if NULLP(proc) goto memlambda; + if IMP(proc) goto badforms; + if SYMBOLP(proc) goto memlambda; + if NCONSP(proc) goto badforms; + while NIMP(proc) { + if NCONSP(proc) + if (!SYMBOLP(proc)) goto badforms; + else goto memlambda; + if (!(NIMP(CAR(proc)) && SYMBOLP(CAR(proc)))) goto badforms; + proc = CDR(proc); + } + if NNULLP(proc) + badforms: wta(xorig, s_formals, s_lambda); + memlambda: + bodycheck(xorig, &CDR(x), s_lambda); + return cons(IM_LAMBDA, CDR(xorig)); +} +SCM m_letstar(xorig, env) + SCM xorig, env; +{ + SCM x = CDR(xorig), arg1, proc, vars = EOL, *varloc = &vars; + int len = ilength(x); + ASSYNT(len >= 2, xorig, s_body, s_letstar); + proc = CAR(x); + ASSYNT(ilength(proc) >= 0, xorig, s_bindings, s_letstar); + while NIMP(proc) { + arg1 = CAR(proc); + ASSYNT(2==ilength(arg1), xorig, s_bindings, s_letstar); + ASSYNT(NIMP(CAR(arg1)) && SYMBOLP(CAR(arg1)), xorig, s_variable, s_letstar); + *varloc = cons2(CAR(arg1), CAR(CDR(arg1)), EOL); + varloc = &CDR(CDR(*varloc)); + proc = CDR(proc); + } + x = cons(vars, CDR(x)); + bodycheck(xorig, &CDR(x), s_letstar); + return cons(IM_LETSTAR, x); +} + +/* DO gets the most radically altered syntax + (do ((<var1> <init1> <step1>) + (<var2> <init2>) + ... ) + (<test> <return>) + <body>) + ;; becomes + (do_mem (varn ... var2 var1) + (<init1> <init2> ... <initn>) + (<test> <return>) + (<body>) + <step1> <step2> ... <stepn>) ;; missing steps replaced by var + */ +SCM m_do(xorig, env) + SCM xorig, env; +{ + SCM x = CDR(xorig), arg1, proc; + SCM vars = EOL, inits = EOL, steps = EOL; + SCM *initloc = &inits, *steploc = &steps; + int len = ilength(x); + ASSYNT(len >= 2, xorig, s_test, s_do); + proc = CAR(x); + ASSYNT(ilength(proc) >= 0, xorig, s_bindings, s_do); + while NIMP(proc) { + arg1 = CAR(proc); + len = ilength(arg1); + ASSYNT(2==len || 3==len, xorig, s_bindings, s_do); + ASSYNT(NIMP(CAR(arg1)) && SYMBOLP(CAR(arg1)), xorig, s_variable, s_do); + /* vars reversed here, inits and steps reversed at evaluation */ + vars = cons(CAR(arg1), vars); /* variable */ + arg1 = CDR(arg1); + *initloc = cons(CAR(arg1), EOL); /* init */ + initloc = &CDR(*initloc); + arg1 = CDR(arg1); + *steploc = cons(IMP(arg1)?CAR(vars):CAR(arg1), EOL); /* step */ + steploc = &CDR(*steploc); + proc = CDR(proc); + } + x = CDR(x); + ASSYNT(ilength(CAR(x)) >= 1, xorig, s_test, s_do); + x = cons2(CAR(x), CDR(x), steps); + x = cons2(vars, inits, x); + bodycheck(xorig, &CAR(CDR(CDR(x))), s_do); + return cons(IM_DO, x); +} + +/* evalcar is small version of inline EVALCAR when we don't care about speed */ +static SCM evalcar(x, env) + SCM x, env; +{ + return EVALCAR(x, env); +} + +static SCM iqq(form, env, depth) + SCM form, env; + int depth; +{ + SCM tmp; + int edepth = depth; + if IMP(form) return form; + if VECTORP(form) { + long i = LENGTH(form); + SCM *data = VELTS(form); + tmp = EOL; + for(;--i >= 0;) tmp = cons(data[i], tmp); + return vector(iqq(tmp, env, depth)); + } + if NCONSP(form) return form; + tmp = CAR(form); + if (i_quasiquote==tmp) { + depth++; + goto label; + } + if (i_unquote==tmp) { + --depth; + label: + form = CDR(form); + ASSERT(NIMP(form) && ECONSP(form) && NULLP(CDR(form)), + form, ARG1, s_quasiquote); + if (0==depth) return evalcar(form, env); + return cons2(tmp, iqq(CAR(form), env, depth), EOL); + } + if (NIMP(tmp) && (i_uq_splicing==CAR(tmp))) { + tmp = CDR(tmp); + if (0==--edepth) + return append(cons2(evalcar(tmp, env), iqq(CDR(form), env, depth), EOL)); + } + return cons(iqq(CAR(form), env, edepth), iqq(CDR(form), env, depth)); +} + +/* Here are acros which return values rather than code. */ + +SCM m_quasiquote(xorig, env) + SCM xorig, env; +{ + SCM x = CDR(xorig); + ASSYNT(ilength(x)==1, xorig, s_expression, s_quasiquote); + return iqq(CAR(x), env, 1); +} + +SCM m_delay(xorig, env) + SCM xorig, env; +{ + ASSYNT(ilength(xorig)==2, xorig, s_expression, s_delay); + xorig = CDR(xorig); + return makprom(closure(cons2(EOL, CAR(xorig), CDR(xorig)), env)); +} + +extern int verbose; +SCM m_define(x, env) + SCM x, env; +{ + SCM proc, arg1 = x; x = CDR(x); + /* ASSYNT(NULLP(env), x, "bad placement", s_define);*/ + ASSYNT(ilength(x) >= 2, arg1, s_expression, s_define); + proc = CAR(x); x = CDR(x); + while (NIMP(proc) && CONSP(proc)) { /* nested define syntax */ + x = cons(cons2(i_lambda, CDR(proc), x), EOL); + proc = CAR(proc); + } + ASSYNT(NIMP(proc) && SYMBOLP(proc), arg1, s_variable, s_define); + ASSYNT(1==ilength(x), arg1, s_expression, s_define); + if NULLP(env) { + x = evalcar(x, env); + arg1 = sym2vcell(proc); +#ifndef RECKLESS + if (NIMP(CDR(arg1)) && ((SCM) SNAME(CDR(arg1))==proc) + && (CDR(arg1) != x)) + warn("redefining built-in ", CHARS(proc)); + else +#endif + if (5 <= verbose && UNDEFINED != CDR(arg1)) + warn("redefining ", CHARS(proc)); + CDR(arg1) = x; +#ifdef SICP + return cons2(i_quote, CAR(arg1), EOL); +#else + return UNSPECIFIED; +#endif + } + return cons2(IM_DEFINE, proc, x); +} +/* end of acros */ + +SCM m_letrec(xorig, env) + SCM xorig, env; +{ + SCM cdrx = CDR(xorig); /* locally mutable version of form */ + char *what = CHARS(CAR(xorig)); + SCM x = cdrx, proc, arg1; /* structure traversers */ + SCM vars = EOL, inits = EOL, *initloc = &inits; + + ASRTSYNTAX(ilength(x) >= 2, s_body); + proc = CAR(x); + if NULLP(proc) return m_letstar(xorig, env); /* null binding, let* faster */ + ASRTSYNTAX(ilength(proc) >= 1, s_bindings); + do { + /* vars list reversed here, inits reversed at evaluation */ + arg1 = CAR(proc); + ASRTSYNTAX(2==ilength(arg1), s_bindings); + ASRTSYNTAX(NIMP(CAR(arg1)) && SYMBOLP(CAR(arg1)), s_variable); + vars = cons(CAR(arg1), vars); + *initloc = cons(CAR(CDR(arg1)), EOL); + initloc = &CDR(*initloc); + } while NIMP(proc = CDR(proc)); + cdrx = cons2(vars, inits, CDR(x)); + bodycheck(xorig, &CDR(CDR(cdrx)), what); + return cons(IM_LETREC, cdrx); +} + +SCM m_let(xorig, env) + SCM xorig, env; +{ + SCM cdrx = CDR(xorig); /* locally mutable version of form */ + SCM x = cdrx, proc, arg1, name; /* structure traversers */ + SCM vars = EOL, inits = EOL, *varloc = &vars, *initloc = &inits; + + ASSYNT(ilength(x) >= 2, xorig, s_body, s_let); + proc = CAR(x); + if (NULLP(proc) + || (NIMP(proc) && CONSP(proc) + && NIMP(CAR(proc)) && CONSP(CAR(proc)) && NULLP(CDR(proc)))) + return m_letstar(xorig, env); /* null or single binding, let* is faster */ + ASSYNT(NIMP(proc), xorig, s_bindings, s_let); + if CONSP(proc) /* plain let, proc is <bindings> */ + return cons(IM_LET, CDR(m_letrec(xorig, env))); + if (!SYMBOLP(proc)) wta(xorig, s_bindings, s_let); /* bad let */ + name = proc; /* named let, build equiv letrec */ + x = CDR(x); + ASSYNT(ilength(x) >= 2, xorig, s_body, s_let); + proc = CAR(x); /* bindings list */ + ASSYNT(ilength(proc) >= 0, xorig, s_bindings, s_let); + while NIMP(proc) { /* vars and inits both in order */ + arg1 = CAR(proc); + ASSYNT(2==ilength(arg1), xorig, s_bindings, s_let); + ASSYNT(NIMP(CAR(arg1)) && SYMBOLP(CAR(arg1)), xorig, s_variable, s_let); + *varloc = cons(CAR(arg1), EOL); + varloc = &CDR(*varloc); + *initloc = cons(CAR(CDR(arg1)), EOL); + initloc = &CDR(*initloc); + proc = CDR(proc); + } + return + m_letrec(cons2(i_let, + cons(cons2(name, cons2(i_lambda, vars, CDR(x)), EOL), EOL), + acons(name, inits, EOL)), /* body */ + env); +} + +#define s_atapply (ISYMCHARS(IM_APPLY)+1) + +SCM m_apply(xorig, env) + SCM xorig, env; +{ + ASSYNT(ilength(CDR(xorig))==2, xorig, s_expression, s_atapply); + return cons(IM_APPLY, CDR(xorig)); +} + +#define s_atcall_cc (ISYMCHARS(IM_CONT)+1) + +SCM m_cont(xorig, env) + SCM xorig, env; +{ + ASSYNT(ilength(CDR(xorig))==1, xorig, s_expression, s_atcall_cc); + return cons(IM_CONT, CDR(xorig)); +} + +#ifndef RECKLESS +int badargsp(formals, args) + SCM formals, args; +{ + while NIMP(formals) { + if NCONSP(formals) return 0; + if IMP(args) return 1; + formals = CDR(formals); + args = CDR(args); + } + return NNULLP(args) ? 1 : 0; +} +#endif + +char s_map[] = "map", s_for_each[] = "for-each", s_eval[] = "eval"; +SCM eqv P((SCM x, SCM y)); +long tc16_macro; /* Type code for macros */ +#ifdef CAUTIOUS +static char s_bottom[] = "stacktrace bottommed out"; +#endif + +SCM ceval(x, env) + SCM x, env; +{ + union {SCM *lloc; SCM arg1;} t; + SCM proc, arg2; + CHECK_STACK; + loop: POLL; + switch TYP7(x) { + case tcs_symbols: + /* only happens when called at top level */ + x = cons(x, UNDEFINED); + goto retval; + case (127 & IM_AND): + x = CDR(x); + t.arg1 = x; + while(NNULLP(t.arg1 = CDR(t.arg1))) + if FALSEP(EVALCAR(x, env)) return BOOL_F; + else x = t.arg1; + goto carloop; + cdrtcdrxbegin: +#ifdef CAUTIOUS + ASSERT(NIMP(stacktrace), EOL, s_bottom, s_eval); + stacktrace = CDR(stacktrace); +#endif + cdrxbegin: + case (127 & IM_BEGIN): + x = CDR(x); + begin: + t.arg1 = x; + while(NNULLP(t.arg1 = CDR(t.arg1))) { + SIDEVAL(CAR(x), env); + x = t.arg1; + } + carloop: /* eval car of last form in list */ + if NCELLP(CAR(x)) { + x = CAR(x); + return IMP(x)?EVALIMP(x, env):I_VAL(x); + } + if SYMBOLP(CAR(x)) { + retval: + return *lookupcar(x, env); + } + x = CAR(x); + goto loop; /* tail recurse */ + + case (127 & IM_CASE): + x = CDR(x); + t.arg1 = EVALCAR(x, env); + while(NIMP(x = CDR(x))) { + proc = CAR(x); + if (i_else==CAR(proc)) { + x = CDR(proc); + goto begin; + } + proc = CAR(proc); + while NIMP(proc) { + if (CAR(proc)==t.arg1 +#ifdef FLOATS + || NFALSEP(eqv(CAR(proc), t.arg1)) +#endif + ) { + x = CDR(CAR(x)); + goto begin; + } + proc = CDR(proc); + } + } + return UNSPECIFIED; + case (127 & IM_COND): + while(NIMP(x = CDR(x))) { + proc = CAR(x); + t.arg1 = EVALCAR(proc, env); + if NFALSEP(t.arg1) { + x = CDR(proc); + if NULLP(x) return t.arg1; + if (i_arrow != CAR(x)) goto begin; + proc = CDR(x); + proc = EVALCAR(proc, env); + ASRTGO(NIMP(proc), badfun); +#ifdef CAUTIOUS + if CLOSUREP(proc) goto checkargs1; +#endif + goto evap1; + } + } + return UNSPECIFIED; + case (127 & IM_DO): + x = CDR(x); + proc = CAR(CDR(x)); /* inits */ + t.arg1 = EOL; /* values */ + while NIMP(proc) { + t.arg1 = cons(EVALCAR(proc, env), t.arg1); + proc = CDR(proc); + } + env = EXTEND_ENV(CAR(x), t.arg1, env); + x = CDR(CDR(x)); + while (proc = CAR(x), FALSEP(EVALCAR(proc, env))) { + for(proc = CAR(CDR(x));NIMP(proc);proc = CDR(proc)) { + t.arg1 = CAR(proc); /* body */ + SIDEVAL(t.arg1, env); + } + for(t.arg1 = EOL, proc = CDR(CDR(x)); NIMP(proc); proc = CDR(proc)) + t.arg1 = cons(EVALCAR(proc, env), t.arg1); /* steps */ + env = EXTEND_ENV(CAR(CAR(env)), t.arg1, CDR(env)); + } + x = CDR(proc); + if NULLP(x) return UNSPECIFIED; + goto begin; + case (127 & IM_IF): + x = CDR(x); + if NFALSEP(EVALCAR(x, env)) x = CDR(x); + else if IMP(x = CDR(CDR(x))) return UNSPECIFIED; + goto carloop; + case (127 & IM_LET): + x = CDR(x); + proc = CAR(CDR(x)); + t.arg1 = EOL; + do { + t.arg1 = cons(EVALCAR(proc, env), t.arg1); + } while NIMP(proc = CDR(proc)); + env = EXTEND_ENV(CAR(x), t.arg1, env); + x = CDR(x); + goto cdrxbegin; + case (127 & IM_LETREC): + x = CDR(x); + env = EXTEND_ENV(CAR(x), undefineds, env); + x = CDR(x); + proc = CAR(x); + t.arg1 = EOL; + do { + t.arg1 = cons(EVALCAR(proc, env), t.arg1); + } while NIMP(proc = CDR(proc)); + CDR(CAR(env)) = t.arg1; + goto cdrxbegin; + case (127 & IM_LETSTAR): + x = CDR(x); + proc = CAR(x); + if IMP(proc) { + env = EXTEND_ENV(EOL, EOL, env); + goto cdrxbegin; + } + do { + t.arg1 = CAR(proc); + proc = CDR(proc); + env = EXTEND_ENV(t.arg1, EVALCAR(proc, env), env); + } while NIMP(proc = CDR(proc)); + goto cdrxbegin; + case (127 & IM_OR): + x = CDR(x); + t.arg1 = x; + while(NNULLP(t.arg1 = CDR(t.arg1))) { + x = EVALCAR(x, env); + if NFALSEP(x) return x; + x = t.arg1; + } + goto carloop; + case (127 & IM_LAMBDA): + return closure(CDR(x), env); + case (127 & IM_QUOTE): + return CAR(CDR(x)); + case (127 & IM_SET): + x = CDR(x); + proc = CAR(x); + switch (7 & (int)proc) { + case 0: + t.lloc = lookupcar(x, env); + break; + case 1: + t.lloc = &I_VAL(proc); + break; +#ifdef MEMOIZE_LOCALS + case 4: + t.lloc = ilookup(proc, env); + break; +#endif + } + x = CDR(x); + *t.lloc = EVALCAR(x, env); +#ifdef SICP + return *t.lloc; +#else + return UNSPECIFIED; +#endif + case (127 & IM_DEFINE): /* only for internal defines */ + x = CDR(x); + proc = CAR(x); + x = CDR(x); + x = evalcar(x, env); + env = CAR(env); + DEFER_INTS; + CAR(env) = cons(proc, CAR(env)); + CDR(env) = cons(x, CDR(env)); + ALLOW_INTS; + return UNSPECIFIED; + /* new syntactic forms go here. */ + case (127 & MAKISYM(0)): + proc = CAR(x); + ASRTGO(ISYMP(proc), badfun); + switch ISYMNUM(proc) { + case (ISYMNUM(IM_APPLY)): + proc = CDR(x); + proc = EVALCAR(proc, env); + ASRTGO(NIMP(proc), badfun); + if (CLOSUREP(proc)) { + t.arg1 = CDR(CDR(x)); + t.arg1 = EVALCAR(t.arg1, env); +#ifndef RECKLESS + if (badargsp(CAR(CODE(proc)), t.arg1)) goto wrongnumargs; +#endif + env = EXTEND_ENV(CAR(CODE(proc)), t.arg1, ENV(proc)); + x = CODE(proc); + goto cdrxbegin; + } + proc = i_apply; + goto evapply; + case (ISYMNUM(IM_CONT)): + t.arg1 = scm_make_cont(); + if (proc = setjmp(CONT(t.arg1)->jmpbuf)) +#ifdef SHORT_INT + return (SCM)thrown_value; +#else + return (SCM)proc; +#endif + proc = CDR(x); + proc = evalcar(proc, env); + ASRTGO(NIMP(proc), badfun); +#ifdef CAUTIOUS + if CLOSUREP(proc) { + checkargs1: + stacktrace = cons(x, stacktrace); + /* Check that argument list of proc can match 1 arg. */ + arg2 = CAR(CODE(proc)); + ASRTGO(NIMP(arg2), wrongnumargs); + if NCONSP(arg2) goto evap1; + arg2 = CDR(arg2); + ASRTGO(NULLP(arg2) || NCONSP(arg2), wrongnumargs); + } +#endif + goto evap1; + default: + goto badfun; + } + default: + proc = x; + badfun: + everr(x, env, proc, "Wrong type to apply: ", ""); + case tc7_vector: + case tc7_bvect: case tc7_ivect: case tc7_uvect: + case tc7_fvect: case tc7_dvect: case tc7_cvect: + case tc7_string: + case tc7_smob: + return x; +#ifdef MEMOIZE_LOCALS + case (127 & ILOC00): + proc = *ilookup(CAR(x), env); + ASRTGO(NIMP(proc), badfun); +# ifndef RECKLESS +# ifdef CAUTIOUS + goto checkargs; +# endif +# endif + break; +#endif /* ifdef MEMOIZE_LOCALS */ + case tcs_cons_gloc: + proc = I_VAL(CAR(x)); + ASRTGO(NIMP(proc), badfun); +#ifndef RECKLESS +# ifdef CAUTIOUS + goto checkargs; +# endif +#endif + break; + case tcs_cons_nimcar: + if SYMBOLP(CAR(x)) { + proc = *lookupcar(x, env); + if IMP(proc) {unmemocar(x, env); goto badfun;} + if (tc16_macro==TYP16(proc)) { + unmemocar(x, env); + t.arg1 = apply(CDR(proc), x, cons(env, listofnull)); + switch ((int)(CAR(proc)>>16)) { + case 2: + if (ilength(t.arg1) <= 0) + t.arg1 = cons2(IM_BEGIN, t.arg1, EOL); + DEFER_INTS; + CAR(x) = CAR(t.arg1); + CDR(x) = CDR(t.arg1); + ALLOW_INTS; + goto loop; + case 1: + if NIMP(x = t.arg1) goto loop; + case 0: + return t.arg1; + } + } + } + else proc = ceval(CAR(x), env); + ASRTGO(NIMP(proc), badfun); +#ifndef RECKLESS +# ifdef CAUTIOUS + checkargs: +# endif + /* At this point proc is the evaluated procedure from the function + position and x has the form which is being evaluated. */ + if CLOSUREP(proc) { +# ifdef CAUTIOUS + stacktrace = cons(x, stacktrace); +# endif + arg2 = CAR(CODE(proc)); + t.arg1 = CDR(x); + while NIMP(arg2) { + if NCONSP(arg2) { + goto evapply; + } + if IMP(t.arg1) goto umwrongnumargs; + arg2 = CDR(arg2); + t.arg1 = CDR(t.arg1); + } + if NNULLP(t.arg1) goto umwrongnumargs; + } +#endif + } + evapply: + if NULLP(CDR(x)) switch TYP7(proc) { /* no arguments given */ + case tc7_subr_0: + return SUBRF(proc)(); + case tc7_subr_1o: + return SUBRF(proc) (UNDEFINED); + case tc7_lsubr: + return SUBRF(proc)(EOL); + case tc7_rpsubr: + return BOOL_T; + case tc7_asubr: + return SUBRF(proc)(UNDEFINED, UNDEFINED); +#ifdef CCLO + case tc7_cclo: + t.arg1 = proc; + proc = CCLO_SUBR(proc); + goto evap1; +#endif + case tcs_closures: + x = CODE(proc); + env = EXTEND_ENV(CAR(x), EOL, ENV(proc)); + goto cdrtcdrxbegin; + case tc7_contin: + case tc7_subr_1: + case tc7_subr_2: + case tc7_subr_2o: + case tc7_cxr: + case tc7_subr_3: + case tc7_lsubr_2: + umwrongnumargs: + unmemocar(x, env); + wrongnumargs: + everr(x, env, proc, (char *)WNA, ""); + default: + goto badfun; + } + x = CDR(x); +#ifdef CAUTIOUS + if (IMP(x)) goto wrongnumargs; +#endif + t.arg1 = EVALCAR(x, env); + x = CDR(x); + if NULLP(x) +evap1: switch TYP7(proc) { /* have one argument in t.arg1 */ + case tc7_subr_2o: + return SUBRF(proc)(t.arg1, UNDEFINED); + case tc7_subr_1: + case tc7_subr_1o: + return SUBRF(proc)(t.arg1); + case tc7_cxr: +#ifdef FLOATS + if SUBRF(proc) { + if INUMP(t.arg1) + return makdbl(DSUBRF(proc)((double) INUM(t.arg1)), 0.0); + ASRTGO(NIMP(t.arg1), floerr); + if REALP(t.arg1) + return makdbl(DSUBRF(proc)(REALPART(t.arg1)), 0.0); +# ifdef BIGDIG + if BIGP(t.arg1) + return makdbl(DSUBRF(proc)(big2dbl(t.arg1)), 0.0); +# endif + floerr: + wta(t.arg1, (char *)ARG1, CHARS(SNAME(proc))); + } +#endif + proc = (SCM)SNAME(proc); + { + char *chrs = CHARS(proc)+LENGTH(proc)-1; + while('c' != *--chrs) { + ASSERT(NIMP(t.arg1) && CONSP(t.arg1), + t.arg1, ARG1, CHARS(proc)); + t.arg1 = ('a'==*chrs)?CAR(t.arg1):CDR(t.arg1); + } + return t.arg1; + } + case tc7_rpsubr: + return BOOL_T; + case tc7_asubr: + return SUBRF(proc)(t.arg1, UNDEFINED); + case tc7_lsubr: + return SUBRF(proc)(cons(t.arg1, EOL)); +#ifdef CCLO + case tc7_cclo: + arg2 = t.arg1; + t.arg1 = proc; + proc = CCLO_SUBR(proc); + goto evap2; +#endif + case tcs_closures: + x = CODE(proc); + env = EXTEND_ENV(CAR(x), cons(t.arg1, EOL), ENV(proc)); + goto cdrtcdrxbegin; + case tc7_contin: + scm_dynthrow(CONT(proc), t.arg1); + case tc7_subr_2: + case tc7_subr_0: + case tc7_subr_3: + case tc7_lsubr_2: + goto wrongnumargs; + default: + goto badfun; + } +#ifdef CAUTIOUS + if (IMP(x)) goto wrongnumargs; +#endif + { /* have two or more arguments */ + arg2 = EVALCAR(x, env); + x = CDR(x); + if NULLP(x) +#ifdef CCLO + evap2: +#endif + switch TYP7(proc) { /* have two arguments */ + case tc7_subr_2: + case tc7_subr_2o: + return SUBRF(proc)(t.arg1, arg2); + case tc7_lsubr: + return SUBRF(proc)(cons2(t.arg1, arg2, EOL)); + case tc7_lsubr_2: + return SUBRF(proc)(t.arg1, arg2, EOL); + case tc7_rpsubr: + case tc7_asubr: + return SUBRF(proc)(t.arg1, arg2); +#ifdef CCLO + cclon: case tc7_cclo: + return apply(CCLO_SUBR(proc), proc, + cons2(t.arg1, arg2, cons(eval_args(x, env), EOL))); +/* case tc7_cclo: + x = cons(arg2, eval_args(x, env)); + arg2 = t.arg1; + t.arg1 = proc; + proc = CCLO_SUBR(proc); + goto evap3; */ +#endif + case tc7_subr_0: + case tc7_cxr: + case tc7_subr_1o: + case tc7_subr_1: + case tc7_subr_3: + case tc7_contin: + goto wrongnumargs; + default: + goto badfun; + case tcs_closures: + env = EXTEND_ENV(CAR(CODE(proc)), cons2(t.arg1, arg2, EOL), ENV(proc)); + x = CODE(proc); + goto cdrtcdrxbegin; + } + switch TYP7(proc) { /* have 3 or more arguments */ + case tc7_subr_3: + ASRTGO(NULLP(CDR(x)), wrongnumargs); + return SUBRF(proc)(t.arg1, arg2, EVALCAR(x, env)); + case tc7_asubr: +/* t.arg1 = SUBRF(proc)(t.arg1, arg2); + while NIMP(x) { + t.arg1 = SUBRF(proc)(t.arg1, EVALCAR(x, env)); + x = CDR(x); + } + return t.arg1; */ + case tc7_rpsubr: + return apply(proc, t.arg1, acons(arg2, eval_args(x, env), EOL)); + case tc7_lsubr_2: + return SUBRF(proc)(t.arg1, arg2, eval_args(x, env)); + case tc7_lsubr: + return SUBRF(proc)(cons2(t.arg1, arg2, eval_args(x, env))); +#ifdef CCLO + case tc7_cclo: goto cclon; +#endif + case tcs_closures: + env = EXTEND_ENV(CAR(CODE(proc)), + cons2(t.arg1, arg2, eval_args(x, env)), + ENV(proc)); + x = CODE(proc); + goto cdrtcdrxbegin; + case tc7_subr_2: + case tc7_subr_1o: + case tc7_subr_2o: + case tc7_subr_0: + case tc7_cxr: + case tc7_subr_1: + case tc7_contin: + goto wrongnumargs; + default: + goto badfun; + } + } +} + +SCM procedurep(obj) + SCM obj; +{ + if NIMP(obj) switch TYP7(obj) { + case tcs_closures: + case tc7_contin: + case tcs_subrs: +#ifdef CCLO + case tc7_cclo: +#endif + return BOOL_T; + } + return BOOL_F; +} + +static char s_proc_doc[] = "procedure-documentation"; +SCM l_proc_doc(proc) + SCM proc; +{ + SCM code; + ASSERT(BOOL_T==procedurep(proc) && NIMP(proc) && TYP7(proc) != tc7_contin, + proc, ARG1, s_proc_doc); + switch TYP7(proc) { + case tcs_closures: + code = CDR(CODE(proc)); + if IMP(CDR(code)) return BOOL_F; + code = CAR(code); + if IMP(code) return BOOL_F; + if STRINGP(code) return code; + default: + return BOOL_F; +/* + case tcs_subrs: +#ifdef CCLO + case tc7_cclo: +#endif +*/ + } +} + +/* This code is for apply. it is destructive on multiple args. + This will only screw you if you do (apply apply '( ... )) */ +SCM nconc2last(lst) + SCM lst; +{ + SCM *lloc = &lst; +#ifdef CAUTIOUS + ASSERT(ilength(lst) >= 1, lst, WNA, s_apply); +#endif + while NNULLP(CDR(*lloc)) lloc = &CDR(*lloc); +#ifdef CAUTIOUS + ASSERT(ilength(CAR(*lloc)) >= 0, lst, ARGn, s_apply); +#endif + *lloc = CAR(*lloc); + return lst; +} + + +SCM apply(proc, arg1, args) + SCM proc, arg1, args; +{ + ASRTGO(NIMP(proc), badproc); + if NULLP(args) + if NULLP(arg1) arg1 = UNDEFINED; + else { + args = CDR(arg1); + arg1 = CAR(arg1); + } + else { + /* ASRTGO(NIMP(args) && CONSP(args), wrongnumargs); */ + args = nconc2last(args); + } +#ifdef CCLO + tail: +#endif + switch TYP7(proc) { + case tc7_subr_2o: + args = NULLP(args)?UNDEFINED:CAR(args); + return SUBRF(proc)(arg1, args); + case tc7_subr_2: + ASRTGO(NULLP(CDR(args)), wrongnumargs); + args = CAR(args); + return SUBRF(proc)(arg1, args); + case tc7_subr_0: + ASRTGO(UNBNDP(arg1), wrongnumargs); + return SUBRF(proc)(); + case tc7_subr_1: + case tc7_subr_1o: + ASRTGO(NULLP(args), wrongnumargs); + return SUBRF(proc)(arg1); + case tc7_cxr: + ASRTGO(NULLP(args), wrongnumargs); +#ifdef FLOATS + if SUBRF(proc) { + if INUMP(arg1) + return makdbl(DSUBRF(proc)((double) INUM(arg1)), 0.0); + ASRTGO(NIMP(arg1), floerr); + if REALP(arg1) + return makdbl(DSUBRF(proc)(REALPART(arg1)), 0.0); +# ifdef BIGDIG + if BIGP(arg1) + return makdbl(DSUBRF(proc)(big2dbl(arg1)), 0.0); +# endif + floerr: + wta(arg1, (char *)ARG1, CHARS(SNAME(proc))); + } +#endif + proc = (SCM)SNAME(proc); + { + char *chrs = CHARS(proc)+LENGTH(proc)-1; + while('c' != *--chrs) { + ASSERT(NIMP(arg1) && CONSP(arg1), + arg1, ARG1, CHARS(proc)); + arg1 = ('a'==*chrs)?CAR(arg1):CDR(arg1); + } + return arg1; + } + case tc7_subr_3: + return SUBRF(proc)(arg1, CAR(args), CAR(CDR(args))); + case tc7_lsubr: + return SUBRF(proc)(UNBNDP(arg1) ? EOL : cons(arg1, args)); + case tc7_lsubr_2: + ASRTGO(NIMP(args) && CONSP(args), wrongnumargs); + return SUBRF(proc)(arg1, CAR(args), CDR(args)); + case tc7_asubr: + if NULLP(args) return SUBRF(proc)(arg1, UNDEFINED); + while NIMP(args) { + ASSERT(CONSP(args), args, ARG2, s_apply); + arg1 = SUBRF(proc)(arg1, CAR(args)); + args = CDR(args); + } + return arg1; + case tc7_rpsubr: + if NULLP(args) return BOOL_T; + while NIMP(args) { + ASSERT(CONSP(args), args, ARG2, s_apply); + if FALSEP(SUBRF(proc)(arg1, CAR(args))) return BOOL_F; + arg1 = CAR(args); + args = CDR(args); + } + return BOOL_T; + case tcs_closures: + arg1 = (UNBNDP(arg1) ? EOL : cons(arg1, args)); +#ifndef RECKLESS + if (badargsp(CAR(CODE(proc)), arg1)) goto wrongnumargs; +#endif + args = EXTEND_ENV(CAR(CODE(proc)), arg1, ENV(proc)); + proc = CODE(proc); + while NNULLP(proc = CDR(proc)) arg1 = EVALCAR(proc, args); + return arg1; + case tc7_contin: + ASRTGO(NULLP(args), wrongnumargs); + scm_dynthrow(CONT(proc), arg1); +#ifdef CCLO + case tc7_cclo: + args = (UNBNDP(arg1) ? EOL : cons(arg1, args)); + arg1 = proc; + proc = CCLO_SUBR(proc); + goto tail; +#endif + wrongnumargs: + wta(proc, (char *)WNA, s_apply); + default: + badproc: + wta(proc, (char *)ARG1, s_apply); + return arg1; + } +} + +SCM map(proc, arg1, args) + SCM proc, arg1, args; +{ + long i; + SCM res = EOL, *pres = &res; + SCM *ve = &args; /* Keep args from being optimized away. */ + if NULLP(arg1) return res; + ASSERT(NIMP(arg1), arg1, ARG2, s_map); + if NULLP(args) { + while NIMP(arg1) { + ASSERT(CONSP(arg1), arg1, ARG2, s_map); + *pres = cons(apply(proc, CAR(arg1), listofnull), EOL); + pres = &CDR(*pres); + arg1 = CDR(arg1); + } + return res; + } + args = vector(cons(arg1, args)); + ve = VELTS(args); +#ifndef RECKLESS + for(i = LENGTH(args)-1; i >= 0; i--) + ASSERT(NIMP(ve[i]) && CONSP(ve[i]), args, ARG2, s_map); +#endif + while (1) { + arg1 = EOL; + for (i = LENGTH(args)-1;i >= 0;i--) { + if IMP(ve[i]) return res; + arg1 = cons(CAR(ve[i]), arg1); + ve[i] = CDR(ve[i]); + } + *pres = cons(apply(proc, arg1, EOL), EOL); + pres = &CDR(*pres); + } +} +SCM for_each(proc, arg1, args) + SCM proc, arg1, args; +{ + SCM *ve = &args; /* Keep args from being optimized away. */ + long i; + if NULLP(arg1) return UNSPECIFIED; + ASSERT(NIMP(arg1), arg1, ARG2, s_for_each); + if NULLP(args) { + while NIMP(arg1) { + ASSERT(CONSP(arg1), arg1, ARG2, s_for_each); + apply(proc, CAR(arg1), listofnull); + arg1 = CDR(arg1); + } + return UNSPECIFIED; + } + args = vector(cons(arg1, args)); + ve = VELTS(args); + while (1) { + arg1 = EOL; + for (i = LENGTH(args)-1;i >= 0;i--) { + if IMP(ve[i]) return UNSPECIFIED; + arg1 = cons(CAR(ve[i]), arg1); + ve[i] = CDR(ve[i]); + } + apply(proc, arg1, EOL); + } +} + +SCM closure(code, env) + SCM code, env; +{ + register SCM z; + NEWCELL(z); + SETCODE(z, code); + ENV(z) = env; + return z; +} + +long tc16_promise; +SCM makprom(code) + SCM code; +{ + register SCM z; + NEWCELL(z); + CDR(z) = code; + CAR(z) = tc16_promise; + return z; +} +static int prinprom(exp, port, writing) + SCM exp; + SCM port; + int writing; +{ + lputs("#<promise ", port); + iprin1(CDR(exp), port, writing); + lputc('>', port); + return !0; +} + +SCM makacro(code) + SCM code; +{ + register SCM z; + NEWCELL(z); + CDR(z) = code; + CAR(z) = tc16_macro; + return z; +} +SCM makmacro(code) + SCM code; +{ + register SCM z; + NEWCELL(z); + CDR(z) = code; + CAR(z) = tc16_macro | (1L<<16); + return z; +} +SCM makmmacro(code) + SCM code; +{ + register SCM z; + NEWCELL(z); + CDR(z) = code; + CAR(z) = tc16_macro | (2L<<16); + return z; +} +static int prinmacro(exp, port, writing) + SCM exp; + SCM port; + int writing; +{ + if (CAR(exp) & (3L<<16)) lputs("#<macro", port); + else lputs("#<syntax", port); + if (CAR(exp) & (2L<<16)) lputc('!', port); + lputc(' ', port); + iprin1(CDR(exp), port, writing); + lputc('>', port); + return !0; +} + +char s_force[] = "force"; +SCM force(x) + SCM x; +{ + ASSERT((TYP16(x)==tc16_promise), x, ARG1, s_force); + if (!((1L<<16) & CAR(x))) { + SCM ans = apply(CDR(x), EOL, EOL); + if (!((1L<<16) & CAR(x))) { + DEFER_INTS; + CDR(x) = ans; + CAR(x) |= (1L<<16); + ALLOW_INTS; + } + } + return CDR(x); +} + +SCM copytree(obj) + SCM obj; +{ + SCM ans, tl; + if IMP(obj) return obj; + if VECTORP(obj) { + sizet i = LENGTH(obj); + ans = make_vector(MAKINUM(i), UNSPECIFIED); + while(i--) VELTS(ans)[i] = copytree(VELTS(obj)[i]); + return ans; + } + if NCONSP(obj) return obj; +/* return cons(copytree(CAR(obj)), copytree(CDR(obj))); */ + ans = tl = cons(copytree(CAR(obj)), UNSPECIFIED); + while(NIMP(obj = CDR(obj)) && CONSP(obj)) + tl = (CDR(tl) = cons(copytree(CAR(obj)), UNSPECIFIED)); + CDR(tl) = obj; + return ans; +} +SCM eval(obj) + SCM obj; +{ + obj = copytree(obj); + return EVAL(obj, (SCM)EOL); +} + +SCM definedp(x, env) + SCM x, env; +{ + SCM proc = CAR(x = CDR(x)); + return (ISYMP(proc) + || (NIMP(proc) && SYMBOLP(proc) + && !UNBNDP(CDR(sym2vcell(proc)))))? + (SCM)BOOL_T : (SCM)BOOL_F; +} + +static iproc subr1s[] = { + {"copy-tree", copytree}, + {s_eval, eval}, + {s_force, force}, + {s_proc_doc, l_proc_doc}, + {"procedure->syntax", makacro}, + {"procedure->macro", makmacro}, + {"procedure->memoizing-macro", makmmacro}, + {"apply:nconc-to-last", nconc2last}, + {0, 0}}; + +static iproc lsubr2s[] = { +/* {s_apply, apply}, now explicity initted */ + {s_map, map}, + {s_for_each, for_each}, + {0, 0}}; + +static smobfuns promsmob = {markcdr, free0, prinprom}; +static smobfuns macrosmob = {markcdr, free0, prinmacro}; + +SCM make_synt(name, macroizer, fcn) + char *name; + SCM (*macroizer)(); + SCM (*fcn)(); +{ + SCM symcell = sysintern(name, UNDEFINED); + long tmp = ((((CELLPTR)(CAR(symcell)))-heap_org)<<8); + register SCM z; + if ((tmp>>8) != ((CELLPTR)(CAR(symcell))-heap_org)) + tmp = 0; + NEWCELL(z); + SUBRF(z) = fcn; + CAR(z) = tmp + tc7_subr_2; + CDR(symcell) = macroizer(z); + return CAR(symcell); +} + +void init_eval() +{ + tc16_promise = newsmob(&promsmob); + tc16_macro = newsmob(¯osmob); + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(lsubr2s, tc7_lsubr_2); + i_apply = make_subr(s_apply, tc7_lsubr_2, apply); + i_dot = CAR(sysintern(".", UNDEFINED)); + i_arrow = CAR(sysintern("=>", UNDEFINED)); + i_else = CAR(sysintern("else", UNDEFINED)); + i_unquote = CAR(sysintern("unquote", UNDEFINED)); + i_uq_splicing = CAR(sysintern("unquote-splicing", UNDEFINED)); + + /* acros */ + i_quasiquote = make_synt(s_quasiquote, makacro, m_quasiquote); + make_synt(s_define, makmmacro, m_define); + make_synt(s_delay, makacro, m_delay); + /* end of acros */ + + make_synt(s_and, makmmacro, m_and); + make_synt(s_begin, makmmacro, m_begin); + make_synt(s_case, makmmacro, m_case); + make_synt(s_cond, makmmacro, m_cond); + make_synt(s_do, makmmacro, m_do); + make_synt(s_if, makmmacro, m_if); + i_lambda = make_synt(s_lambda, makmmacro, m_lambda); + i_let = make_synt(s_let, makmmacro, m_let); + make_synt(s_letrec, makmmacro, m_letrec); + make_synt(s_letstar, makmmacro, m_letstar); + make_synt(s_or, makmmacro, m_or); + i_quote = make_synt(s_quote, makmmacro, m_quote); + make_synt(s_set, makmmacro, m_set); + make_synt(s_atapply, makmmacro, m_apply); + make_synt(s_atcall_cc, makmmacro, m_cont); + + make_synt("defined?", makacro, definedp); +} diff --git a/example.scm b/example.scm new file mode 100644 index 0000000..4a7b4a0 --- /dev/null +++ b/example.scm @@ -0,0 +1,137 @@ +;From Revised^4 Report on the Algorithmic Language Scheme +;William Clinger and Jonathon Rees (Editors) + +; EXAMPLE + +;INTEGRATE-SYSTEM integrates the system +; y_k' = f_k(y_1, y_2, ..., y_n), k = 1, ..., n +;of differential equations with the method of Runge-Kutta. + +;The parameter SYSTEM-DERIVATIVE is a function that takes a system +;state (a vector of values for the state variables y_1, ..., y_n) and +;produces a system derivative (the values y_1', ..., y_n'). The +;parameter INITIAL-STATE provides an initial system state, and H is an +;initial guess for the length of the integration step. + +;The value returned by INTEGRATE-SYSTEM is an infinite stream of +;system states. + +(define integrate-system + (lambda (system-derivative initial-state h) + (let ((next (runge-kutta-4 system-derivative h))) + (letrec ((states + (cons initial-state + (delay (map-streams next states))))) + states)))) + +;RUNGE-KUTTA-4 takes a function, F, that produces a +;system derivative from a system state. RUNGE-KUTTA-4 +;produces a function that takes a system state and +;produces a new system state. + +(define runge-kutta-4 + (lambda (f h) + (let ((*h (scale-vector h)) + (*2 (scale-vector 2)) + (*1/2 (scale-vector (/ 1 2))) + (*1/6 (scale-vector (/ 1 6)))) + (lambda (y) + ;; Y is a system state + (let* ((k0 (*h (f y))) + (k1 (*h (f (add-vectors y (*1/2 k0))))) + (k2 (*h (f (add-vectors y (*1/2 k1))))) + (k3 (*h (f (add-vectors y k2))))) + (add-vectors y + (*1/6 (add-vectors k0 + (*2 k1) + (*2 k2) + k3)))))))) + +(define elementwise + (lambda (f) + (lambda vectors + (generate-vector + (vector-length (car vectors)) + (lambda (i) + (apply f + (map (lambda (v) (vector-ref v i)) + vectors))))))) + +(define generate-vector + (lambda (size proc) + (let ((ans (make-vector size))) + (letrec ((loop + (lambda (i) + (cond ((= i size) ans) + (else + (vector-set! ans i (proc i)) + (loop (+ i 1))))))) + (loop 0))))) + +(define add-vectors (elementwise +)) + +(define scale-vector + (lambda (s) + (elementwise (lambda (x) (* x s))))) + +;MAP-STREAMS is analogous to MAP: it applies its first +;argument (a procedure) to all the elements of its second argument (a +;stream). + +(define map-streams + (lambda (f s) + (cons (f (head s)) + (delay (map-streams f (tail s)))))) + +;Infinite streams are implemented as pairs whose car holds the first +;element of the stream and whose cdr holds a promise to deliver the rest +;of the stream. + +(define head car) +(define tail + (lambda (stream) (force (cdr stream)))) + + +;The following illustrates the use of INTEGRATE-SYSTEM in +;integrating the system +; +; dvC vC +; C --- = -i - -- +; dt L R +; +; diL +; L --- = v +; dt C +; +;which models a damped oscillator. + +(define damped-oscillator + (lambda (R L C) + (lambda (state) + (let ((Vc (vector-ref state 0)) + (Il (vector-ref state 1))) + (vector (- 0 (+ (/ Vc (* R C)) (/ Il C))) + (/ Vc L)))))) + +(define the-states + (integrate-system + (damped-oscillator 10000 1000 .001) + '#(1 0) + .01)) + +(do ((i 10 (- i 1)) + (s the-states (tail s))) + ((zero? i) (newline)) + (newline) + (write (head s))) + +; #(1 0) +; #(0.99895054 9.994835e-6) +; #(0.99780226 1.9978681e-5) +; #(0.9965554 2.9950552e-5) +; #(0.9952102 3.990946e-5) +; #(0.99376684 4.985443e-5) +; #(0.99222565 5.9784474e-5) +; #(0.9905868 6.969862e-5) +; #(0.9888506 7.9595884e-5) +; #(0.9870173 8.94753e-5) diff --git a/findexec.c b/findexec.c new file mode 100644 index 0000000..bbeac76 --- /dev/null +++ b/findexec.c @@ -0,0 +1,145 @@ +/* This file was part of DLD, a dynamic link/unlink editor for C. + + Copyright (C) 1990 by W. Wilson Ho. + + The author can be reached electronically by how@cs.ucdavis.edu or + through physical mail at: + + W. Wilson Ho + Division of Computer Science + University of California at Davis + Davis, CA 95616 + +Fri Sep 14 22:16:14 1990 Edgar Roeder (edgar at megamaster) + + * added a separate DLDPATH environment variable in + dld_find_executable so that users may specify a special path + for object modules. + +Thu Feb 3 01:46:16 1994 Aubrey Jaffer (jaffer@jacal) + + * find_exec.c (dld_find_executable): added stat check for + linux so that it doesn't think directories with the same name + as the program are executable. + +Wed Feb 21 23:06:35 1996 Aubrey Jaffer <jaffer@jacal.bertronics> + + * find_exec.c: extracted for general use. Generalized to + MS-DOS. */ + +/* This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 1, or (at your option) any + later version. */ + +/* Given a filename, dld_find_executable searches the directories + listed in the environment variable PATH for a file with that + filename. A new copy of the complete path name of that file is + returned. This new string may be disposed by free() later on. */ + +#include <sys/file.h> +#include <sys/param.h> +#ifdef linux +# include <stdlib.h> +# include <sys/stat.h> +# include <unistd.h> /* for X_OK define */ +#endif +#ifdef __svr4__ +# include <string.h> +# include <stdlib.h> +# include <sys/stat.h> +# include <unistd.h> /* for X_OK define */ +#else +# ifdef __sgi__ +# include <string.h> +# include <stdlib.h> +# include <sys/stat.h> +# include <unistd.h> /* for X_OK define */ +# else +# include <strings.h> +# endif +#endif +#ifndef __STDC__ +# define const /**/ +#endif + +#ifndef DEFAULT_PATH +# define DEFAULT_PATH ".:~/bin::/usr/local/bin:/usr/new:/usr/ucb:/usr/bin:/bin:/usr/hosts" +#endif + +static char *copy_of(s) + register const char *s; +{ + register char *p = (char *) malloc(strlen(s)+1); + if (!p) return 0; + *p = 0; + strcpy(p, s); + return p; +} + +/* ABSOLUTE_FILENAME_P(fname): True if fname is an absolute filename */ +#ifdef atarist +# define ABSOLUTE_FILENAME_P(fname) ((fname[0] == '/') || \ + (fname[0] && (fname[1] == ':'))) +#else +# define ABSOLUTE_FILENAME_P(fname) (fname[0] == '/') +#endif /* atarist */ + +char *dld_find_executable(name) + const char *name; +{ + char *search; + register char *p; + char tbuf[MAXPATHLEN]; + + if (ABSOLUTE_FILENAME_P(name)) + return copy_of(name); + + if ((name[0] == '.') && (name[1] == '/')) { + getcwd(tbuf, MAXPATHLEN); + strcat(tbuf, name + 1); + return copy_of(tbuf); + } + + if (((search = (char *) getenv("DLDPATH")) == 0) && + ((search = (char *) getenv("PATH")) == 0)) + search = DEFAULT_PATH; + + p = search; + + while (*p) { + register char *next = tbuf; + + if (p[0]=='~' && p[1]=='/' && getenv("HOME")) { + strcpy(tbuf, (char *)getenv("HOME")); + next = tbuf + strlen(tbuf); + p++; + } + + /* Copy directory name into [tbuf] */ + while (*p && *p != ':') *next++ = *p++; + *next = 0; + if (*p) p++; + + if (tbuf[0] == '.' && tbuf[1] == 0) + getcwd(tbuf, MAXPATHLEN); /* was getwd(tbuf); */ + else if (tbuf[0]=='~' && tbuf[1]==0 && getenv("HOME")) + strcpy(tbuf, (char *)getenv("HOME")); + + strcat(tbuf, "/"); + strcat(tbuf, name); + + if (access(tbuf, X_OK) == 0) { +#ifndef hpux +# ifndef ultrix + struct stat stat_temp; + if (stat(tbuf,&stat_temp)) continue; + if (S_IFREG != (S_IFMT & stat_temp.st_mode)) continue; +# endif/* ultrix */ +#endif /* hpux */ + return copy_of(tbuf); + } + } + + return 0; +} diff --git a/gmalloc.c b/gmalloc.c new file mode 100644 index 0000000..59874ee --- /dev/null +++ b/gmalloc.c @@ -0,0 +1,1638 @@ +/* DO NOT EDIT THIS FILE -- it is automagically generated. -*- C -*- */ + +#define _MALLOC_INTERNAL + +/* The malloc headers and source files from the C library follow here. */ + +/* Declarations for `malloc' and friends. + Copyright 1990, 91, 92, 93, 95, 96 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_H + +#define _MALLOC_H 1 + +#ifdef _MALLOC_INTERNAL + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(args) args +#undef __ptr_t +#define __ptr_t void * +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(args) () +#undef const +#define const +#undef __ptr_t +#define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG) +#include <string.h> +#else +#ifndef memset +#define memset(s, zero, n) bzero ((s), (n)) +#endif +#ifndef memcpy +#define memcpy(d, s, n) bcopy ((s), (d), (n)) +#endif +#endif + +#if defined (__GNU_LIBRARY__) || (defined (__STDC__) && __STDC__) +#include <limits.h> +#else +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#endif /* _MALLOC_INTERNAL. */ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined (__STDC__) && __STDC__ +#include <stddef.h> +#define __malloc_size_t size_t +#define __malloc_ptrdiff_t ptrdiff_t +#else +#define __malloc_size_t unsigned int +#define __malloc_ptrdiff_t int +#endif + +#ifndef NULL +#define NULL 0 +#endif + + +/* Allocate SIZE bytes of memory. */ +extern __ptr_t malloc __P ((__malloc_size_t __size)); +/* Re-allocate the previously allocated block + in __ptr_t, making the new block SIZE bytes long. */ +extern __ptr_t realloc __P ((__ptr_t __ptr, __malloc_size_t __size)); +/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ +extern __ptr_t calloc __P ((__malloc_size_t __nmemb, __malloc_size_t __size)); +/* Free a block allocated by `malloc', `realloc' or `calloc'. */ +extern void free __P ((__ptr_t __ptr)); + +/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ +#if ! (defined (_MALLOC_INTERNAL) && __DJGPP__ - 0 == 1) /* Avoid conflict. */ +extern __ptr_t memalign __P ((__malloc_size_t __alignment, + __malloc_size_t __size)); +#endif + +/* Allocate SIZE bytes on a page boundary. */ +#if ! (defined (_MALLOC_INTERNAL) && defined (GMALLOC_INHIBIT_VALLOC)) +extern __ptr_t valloc __P ((__malloc_size_t __size)); +#endif + + +#ifdef _MALLOC_INTERNAL + +/* The allocator divides the heap into blocks of fixed size; large + requests receive one or more whole blocks, and small requests + receive a fragment of a block. Fragment sizes are powers of two, + and all fragments of a block are the same size. When all the + fragments in a block have been freed, the block itself is freed. */ +#define INT_BIT (CHAR_BIT * sizeof(int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* Determine the amount of memory spanned by the initial heap table + (not an absolute limit). */ +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of + memory before they will be returned to the system. */ +#define FINAL_FREE_BLOCKS 8 + +/* Data structure giving per-block information. */ +typedef union + { + /* Heap information for a busy block. */ + struct + { + /* Zero for a large (multiblock) object, or positive giving the + logarithm to the base two of the fragment size. */ + int type; + union + { + struct + { + __malloc_size_t nfree; /* Free frags in a fragmented block. */ + __malloc_size_t first; /* First free fragment of the block. */ + } frag; + /* For a large object, in its first block, this has the number + of blocks in the object. In the other blocks, this has a + negative number which says how far back the first block is. */ + __malloc_ptrdiff_t size; + } info; + } busy; + /* Heap information for a free block + (that may be the first of a free cluster). */ + struct + { + __malloc_size_t size; /* Size (in blocks) of a free cluster. */ + __malloc_size_t next; /* Index of next free cluster. */ + __malloc_size_t prev; /* Index of previous free cluster. */ + } free; + } malloc_info; + +/* Pointer to first block of the heap. */ +extern char *_heapbase; + +/* Table indexed by block number giving per-block information. */ +extern malloc_info *_heapinfo; + +/* Address to block number and vice versa. */ +#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) +#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Current search index for the heap table. */ +extern __malloc_size_t _heapindex; + +/* Limit of valid info table indices. */ +extern __malloc_size_t _heaplimit; + +/* Doubly linked lists of free fragments. */ +struct list + { + struct list *next; + struct list *prev; + }; + +/* Free list headers for each fragment size. */ +extern struct list _fraghead[]; + +/* List of blocks allocated with `memalign' (or `valloc'). */ +struct alignlist + { + struct alignlist *next; + __ptr_t aligned; /* The address that memaligned returned. */ + __ptr_t exact; /* The address that malloc returned. */ + }; +extern struct alignlist *_aligned_blocks; + +/* Instrumentation. */ +extern __malloc_size_t _chunks_used; +extern __malloc_size_t _bytes_used; +extern __malloc_size_t _chunks_free; +extern __malloc_size_t _bytes_free; + +/* Internal versions of `malloc', `realloc', and `free' + used when these functions need to call each other. + They are the same but don't call the hooks. */ +extern __ptr_t _malloc_internal __P ((__malloc_size_t __size)); +extern __ptr_t _realloc_internal __P ((__ptr_t __ptr, __malloc_size_t __size)); +extern void _free_internal __P ((__ptr_t __ptr)); + +#endif /* _MALLOC_INTERNAL. */ + +/* Given an address in the middle of a malloc'd object, + return the address of the beginning of the object. */ +extern __ptr_t malloc_find_object_address __P ((__ptr_t __ptr)); + +/* Underlying allocation function; successive calls should + return contiguous pieces of memory. */ +extern __ptr_t (*__morecore) __P ((__malloc_ptrdiff_t __size)); + +/* Default value of `__morecore'. */ +extern __ptr_t __default_morecore __P ((__malloc_ptrdiff_t __size)); + +/* If not NULL, this function is called after each time + `__morecore' is called to increase the data size. */ +extern void (*__after_morecore_hook) __P ((void)); + +/* Number of extra blocks to get each time we ask for more core. + This reduces the frequency of calling `(*__morecore)'. */ +extern __malloc_size_t __malloc_extra_blocks; + +/* Nonzero if `malloc' has been called and done its initialization. */ +extern int __malloc_initialized; +/* Function called to initialize malloc data structures. */ +extern int __malloc_initialize __P ((void)); + +/* Hooks for debugging versions. */ +extern void (*__malloc_initialize_hook) __P ((void)); +extern void (*__free_hook) __P ((__ptr_t __ptr)); +extern __ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); +extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); +extern __ptr_t (*__memalign_hook) __P ((__malloc_size_t __size, + __malloc_size_t __alignment)); + +/* Return values for `mprobe': these are the kinds of inconsistencies that + `mcheck' enables detection of. */ +enum mcheck_status + { + MCHECK_DISABLED = -1, /* Consistency checking is not turned on. */ + MCHECK_OK, /* Block is fine. */ + MCHECK_FREE, /* Block freed twice. */ + MCHECK_HEAD, /* Memory before the block was clobbered. */ + MCHECK_TAIL /* Memory after the block was clobbered. */ + }; + +/* Activate a standard collection of debugging hooks. This must be called + before `malloc' is ever called. ABORTFUNC is called with an error code + (see enum above) when an inconsistency is detected. If ABORTFUNC is + null, the standard function prints on stderr and then calls `abort'. */ +extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status)))); + +/* Check for aberrations in a particular malloc'd block. You must have + called `mcheck' already. These are the same checks that `mcheck' does + when you free or reallocate a block. */ +extern enum mcheck_status mprobe __P ((__ptr_t __ptr)); + +/* Activate a standard collection of tracing hooks. */ +extern void mtrace __P ((void)); +extern void muntrace __P ((void)); + +/* Statistics available to the user. */ +struct mstats + { + __malloc_size_t bytes_total; /* Total size of the heap. */ + __malloc_size_t chunks_used; /* Chunks allocated by the user. */ + __malloc_size_t bytes_used; /* Byte total of user-allocated chunks. */ + __malloc_size_t chunks_free; /* Chunks in the free list. */ + __malloc_size_t bytes_free; /* Byte total of chunks in the free list. */ + }; + +/* Pick up the current statistics. */ +extern struct mstats mstats __P ((void)); + +/* Call WARNFUN with a warning message when memory usage is high. */ +extern void memory_warnings __P ((__ptr_t __start, + void (*__warnfun) __P ((const char *)))); + + +/* Relocating allocator. */ + +/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ +extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); + +/* Free the storage allocated in HANDLEPTR. */ +extern void r_alloc_free __P ((__ptr_t *__handleptr)); + +/* Adjust the block at HANDLEPTR to be SIZE bytes long. */ +extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); + + +#ifdef __cplusplus +} +#endif + +#endif /* malloc.h */ +/* Memory allocator `malloc'. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif +#include <errno.h> + +/* How to really get more memory. */ +__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore; + +/* Debugging hook for `malloc'. */ +__ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); + +/* Pointer to the base of the first block. */ +char *_heapbase; + +/* Block information table. Allocated with align/__free (not malloc/free). */ +malloc_info *_heapinfo; + +/* Number of info entries. */ +static __malloc_size_t heapsize; + +/* Search index in the info table. */ +__malloc_size_t _heapindex; + +/* Limit of valid info table indices. */ +__malloc_size_t _heaplimit; + +/* Free lists for each fragment size. */ +struct list _fraghead[BLOCKLOG]; + +/* Instrumentation. */ +__malloc_size_t _chunks_used; +__malloc_size_t _bytes_used; +__malloc_size_t _chunks_free; +__malloc_size_t _bytes_free; + +/* Are you experienced? */ +int __malloc_initialized; + +__malloc_size_t __malloc_extra_blocks; + +void (*__malloc_initialize_hook) __P ((void)); +void (*__after_morecore_hook) __P ((void)); + + +/* Aligned allocation. */ +static __ptr_t align __P ((__malloc_size_t)); +static __ptr_t +align (size) + __malloc_size_t size; +{ + __ptr_t result; + unsigned long int adj; + + result = (*__morecore) (size); + adj = (unsigned long int) ((unsigned long int) ((char *) result - + (char *) NULL)) % BLOCKSIZE; + if (adj != 0) + { + __ptr_t new; + adj = BLOCKSIZE - adj; + new = (*__morecore) (adj); + result = (char *) result + adj; + } + + if (__after_morecore_hook) + (*__after_morecore_hook) (); + + return result; +} + +/* Get SIZE bytes, if we can get them starting at END. + Return the address of the space we got. + If we cannot get space at END, fail and return 0. */ +static __ptr_t get_contiguous_space __P ((__malloc_ptrdiff_t, __ptr_t)); +static __ptr_t +get_contiguous_space (size, position) + __malloc_ptrdiff_t size; + __ptr_t position; +{ + __ptr_t before; + __ptr_t after; + + before = (*__morecore) (0); + /* If we can tell in advance that the break is at the wrong place, + fail now. */ + if (before != position) + return 0; + + /* Allocate SIZE bytes and get the address of them. */ + after = (*__morecore) (size); + if (!after) + return 0; + + /* It was not contiguous--reject it. */ + if (after != position) + { + (*__morecore) (- size); + return 0; + } + + return after; +} + + +/* This is called when `_heapinfo' and `heapsize' have just + been set to describe a new info table. Set up the table + to describe itself and account for it in the statistics. */ +static void register_heapinfo __P ((void)); +#ifdef __GNUC__ +__inline__ +#endif +static void +register_heapinfo () +{ + __malloc_size_t block, blocks; + + block = BLOCK (_heapinfo); + blocks = BLOCKIFY (heapsize * sizeof (malloc_info)); + + /* Account for the _heapinfo block itself in the statistics. */ + _bytes_used += blocks * BLOCKSIZE; + ++_chunks_used; + + /* Describe the heapinfo block itself in the heapinfo. */ + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + /* Leave back-pointers for malloc_find_address. */ + while (--blocks > 0) + _heapinfo[block + blocks].busy.info.size = -blocks; +} + +/* Set everything up and remember that we have. */ +int +__malloc_initialize () +{ + if (__malloc_initialized) + return 0; + + if (__malloc_initialize_hook) + (*__malloc_initialize_hook) (); + + heapsize = HEAP / BLOCKSIZE; + _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info)); + if (_heapinfo == NULL) + return 0; + memset (_heapinfo, 0, heapsize * sizeof (malloc_info)); + _heapinfo[0].free.size = 0; + _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; + _heapindex = 0; + _heapbase = (char *) _heapinfo; + _heaplimit = BLOCK (_heapbase + heapsize * sizeof (malloc_info)); + + register_heapinfo (); + + __malloc_initialized = 1; + return 1; +} + +static int morecore_recursing; + +/* Get neatly aligned memory, initializing or + growing the heap info table as necessary. */ +static __ptr_t morecore __P ((__malloc_size_t)); +static __ptr_t +morecore (size) + __malloc_size_t size; +{ + __ptr_t result; + malloc_info *newinfo, *oldinfo; + __malloc_size_t newsize; + + if (morecore_recursing) + /* Avoid recursion. The caller will know how to handle a null return. */ + return NULL; + + result = align (size); + if (result == NULL) + return NULL; + + /* Check if we need to grow the info table. */ + if ((__malloc_size_t) BLOCK ((char *) result + size) > heapsize) + { + /* Calculate the new _heapinfo table size. We do not account for the + added blocks in the table itself, as we hope to place them in + existing free space, which is already covered by part of the + existing table. */ + newsize = heapsize; + do + newsize *= 2; + while ((__malloc_size_t) BLOCK ((char *) result + size) > newsize); + + /* We must not reuse existing core for the new info table when called + from realloc in the case of growing a large block, because the + block being grown is momentarily marked as free. In this case + _heaplimit is zero so we know not to reuse space for internal + allocation. */ + if (_heaplimit != 0) + { + /* First try to allocate the new info table in core we already + have, in the usual way using realloc. If realloc cannot + extend it in place or relocate it to existing sufficient core, + we will get called again, and the code above will notice the + `morecore_recursing' flag and return null. */ + int save = errno; /* Don't want to clobber errno with ENOMEM. */ + morecore_recursing = 1; + newinfo = (malloc_info *) _realloc_internal + (_heapinfo, newsize * sizeof (malloc_info)); + morecore_recursing = 0; + if (newinfo == NULL) + errno = save; + else + { + /* We found some space in core, and realloc has put the old + table's blocks on the free list. Now zero the new part + of the table and install the new table location. */ + memset (&newinfo[heapsize], 0, + (newsize - heapsize) * sizeof (malloc_info)); + _heapinfo = newinfo; + heapsize = newsize; + goto got_heap; + } + } + + /* Allocate new space for the malloc info table. */ + while (1) + { + newinfo = (malloc_info *) align (newsize * sizeof (malloc_info)); + + /* Did it fail? */ + if (newinfo == NULL) + { + (*__morecore) (-size); + return NULL; + } + + /* Is it big enough to record status for its own space? + If so, we win. */ + if ((__malloc_size_t) BLOCK ((char *) newinfo + + newsize * sizeof (malloc_info)) + < newsize) + break; + + /* Must try again. First give back most of what we just got. */ + (*__morecore) (- newsize * sizeof (malloc_info)); + newsize *= 2; + } + + /* Copy the old table to the beginning of the new, + and zero the rest of the new table. */ + memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info)); + memset (&newinfo[heapsize], 0, + (newsize - heapsize) * sizeof (malloc_info)); + oldinfo = _heapinfo; + _heapinfo = newinfo; + heapsize = newsize; + + register_heapinfo (); + + /* Reset _heaplimit so _free_internal never decides + it can relocate or resize the info table. */ + _heaplimit = 0; + _free_internal (oldinfo); + + /* The new heap limit includes the new table just allocated. */ + _heaplimit = BLOCK ((char *) newinfo + heapsize * sizeof (malloc_info)); + return result; + } + + got_heap: + _heaplimit = BLOCK ((char *) result + size); + return result; +} + +/* Allocate memory from the heap. */ +__ptr_t +_malloc_internal (size) + __malloc_size_t size; +{ + __ptr_t result; + __malloc_size_t block, blocks, lastblocks, start; + register __malloc_size_t i; + struct list *next; + + /* ANSI C allows `malloc (0)' to either return NULL, or to return a + valid address you can realloc and free (though not dereference). + + It turns out that some extant code (sunrpc, at least Ultrix's version) + expects `malloc (0)' to return non-NULL and breaks otherwise. + Be compatible. */ + +#if 0 + if (size == 0) + return NULL; +#endif + + if (size < sizeof (struct list)) + size = sizeof (struct list); + +#ifdef SUNOS_LOCALTIME_BUG + if (size < 16) + size = 16; +#endif + + /* Determine the allocation policy based on the request size. */ + if (size <= BLOCKSIZE / 2) + { + /* Small allocation to receive a fragment of a block. + Determine the logarithm to base two of the fragment size. */ + register __malloc_size_t log = 1; + --size; + while ((size /= 2) != 0) + ++log; + + /* Look in the fragment lists for a + free fragment of the desired size. */ + next = _fraghead[log].next; + if (next != NULL) + { + /* There are free fragments of this size. + Pop a fragment out of the fragment list and return it. + Update the block's nfree and first counters. */ + result = (__ptr_t) next; + next->prev->next = next->next; + if (next->next != NULL) + next->next->prev = next->prev; + block = BLOCK (result); + if (--_heapinfo[block].busy.info.frag.nfree != 0) + _heapinfo[block].busy.info.frag.first = (unsigned long int) + ((unsigned long int) ((char *) next->next - (char *) NULL) + % BLOCKSIZE) >> log; + + /* Update the statistics. */ + ++_chunks_used; + _bytes_used += 1 << log; + --_chunks_free; + _bytes_free -= 1 << log; + } + else + { + /* No free fragments of the desired size, so get a new block + and break it into fragments, returning the first. */ + result = malloc (BLOCKSIZE); + if (result == NULL) + return NULL; + + /* Link all fragments but the first into the free list. */ + next = (struct list *) ((char *) result + (1 << log)); + next->next = NULL; + next->prev = &_fraghead[log]; + _fraghead[log].next = next; + + for (i = 2; i < (__malloc_size_t) (BLOCKSIZE >> log); ++i) + { + next = (struct list *) ((char *) result + (i << log)); + next->next = _fraghead[log].next; + next->prev = &_fraghead[log]; + next->prev->next = next; + next->next->prev = next; + } + + /* Initialize the nfree and first counters for this block. */ + block = BLOCK (result); + _heapinfo[block].busy.type = log; + _heapinfo[block].busy.info.frag.nfree = i - 1; + _heapinfo[block].busy.info.frag.first = i - 1; + + _chunks_free += (BLOCKSIZE >> log) - 1; + _bytes_free += BLOCKSIZE - (1 << log); + _bytes_used -= BLOCKSIZE - (1 << log); + } + } + else + { + /* Large allocation to receive one or more blocks. + Search the free list in a circle starting at the last place visited. + If we loop completely around without finding a large enough + space we will have to get more memory from the system. */ + blocks = BLOCKIFY (size); + start = block = _heapindex; + while (_heapinfo[block].free.size < blocks) + { + block = _heapinfo[block].free.next; + if (block == start) + { + /* Need to get more from the system. Get a little extra. */ + __malloc_size_t wantblocks = blocks + __malloc_extra_blocks; + block = _heapinfo[0].free.prev; + lastblocks = _heapinfo[block].free.size; + /* Check to see if the new core will be contiguous with the + final free block; if so we don't need to get as much. */ + if (_heaplimit != 0 && block + lastblocks == _heaplimit && + /* We can't do this if we will have to make the heap info + table bigger to accomodate the new space. */ + block + wantblocks <= heapsize && + get_contiguous_space ((wantblocks - lastblocks) * BLOCKSIZE, + ADDRESS (block + lastblocks))) + { + /* We got it contiguously. Which block we are extending + (the `final free block' referred to above) might have + changed, if it got combined with a freed info table. */ + block = _heapinfo[0].free.prev; + _heapinfo[block].free.size += (wantblocks - lastblocks); + _bytes_free += (wantblocks - lastblocks) * BLOCKSIZE; + _heaplimit += wantblocks - lastblocks; + continue; + } + result = morecore (wantblocks * BLOCKSIZE); + if (result == NULL) + return NULL; + block = BLOCK (result); + /* Put the new block at the end of the free list. */ + _heapinfo[block].free.size = wantblocks; + _heapinfo[block].free.prev = _heapinfo[0].free.prev; + _heapinfo[block].free.next = 0; + _heapinfo[0].free.prev = block; + _heapinfo[_heapinfo[block].free.prev].free.next = block; + ++_chunks_free; + /* Now loop to use some of that block for this allocation. */ + } + } + + /* At this point we have found a suitable free list entry. + Figure out how to remove what we need from the list. */ + result = ADDRESS (block); + if (_heapinfo[block].free.size > blocks) + { + /* The block we found has a bit left over, + so relink the tail end back into the free list. */ + _heapinfo[block + blocks].free.size + = _heapinfo[block].free.size - blocks; + _heapinfo[block + blocks].free.next + = _heapinfo[block].free.next; + _heapinfo[block + blocks].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[_heapinfo[block].free.next].free.prev + = _heapindex = block + blocks; + } + else + { + /* The block exactly matches our requirements, + so just remove it from the list. */ + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapindex = _heapinfo[block].free.next; + --_chunks_free; + } + + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = blocks; + ++_chunks_used; + _bytes_used += blocks * BLOCKSIZE; + _bytes_free -= blocks * BLOCKSIZE; + + /* Mark all the blocks of the object just allocated except for the + first with a negative number so you can find the first block by + adding that adjustment. */ + while (--blocks > 0) + _heapinfo[block + blocks].busy.info.size = -blocks; + } + + return result; +} + +__ptr_t +malloc (size) + __malloc_size_t size; +{ + if (!__malloc_initialized && !__malloc_initialize ()) + return NULL; + + return (__malloc_hook != NULL ? *__malloc_hook : _malloc_internal) (size); +} + +#ifndef _LIBC + +/* On some ANSI C systems, some libc functions call _malloc, _free + and _realloc. Make them use the GNU functions. */ + +__ptr_t +_malloc (size) + __malloc_size_t size; +{ + return malloc (size); +} + +void +_free (ptr) + __ptr_t ptr; +{ + free (ptr); +} + +__ptr_t +_realloc (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + return realloc (ptr, size); +} + +#endif +/* Free a block of memory allocated by `malloc'. + Copyright 1990, 1991, 1992, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + + +/* Cope with systems lacking `memmove'. */ +#ifndef memmove +#if (defined (MEMMOVE_MISSING) || \ + !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) +#ifdef emacs +#undef __malloc_safe_bcopy +#define __malloc_safe_bcopy safe_bcopy +#endif +/* This function is defined in realloc.c. */ +extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); +#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) +#endif +#endif + + +/* Debugging hook for free. */ +void (*__free_hook) __P ((__ptr_t __ptr)); + +/* List of blocks allocated by memalign. */ +struct alignlist *_aligned_blocks = NULL; + +/* Return memory to the heap. + Like `free' but don't call a __free_hook if there is one. */ +void +_free_internal (ptr) + __ptr_t ptr; +{ + int type; + __malloc_size_t block, blocks; + register __malloc_size_t i; + struct list *prev, *next; + __ptr_t curbrk; + const __malloc_size_t lesscore_threshold + /* Threshold of free space at which we will return some to the system. */ + = FINAL_FREE_BLOCKS + 2 * __malloc_extra_blocks; + + register struct alignlist *l; + + if (ptr == NULL) + return; + + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == ptr) + { + l->aligned = NULL; /* Mark the slot in the list as free. */ + ptr = l->exact; + break; + } + + block = BLOCK (ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Get as many statistics as early as we can. */ + --_chunks_used; + _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; + _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; + + /* Find the free cluster previous to this one in the free list. + Start searching at the last block referenced; this may benefit + programs with locality of allocation. */ + i = _heapindex; + if (i > block) + while (i > block) + i = _heapinfo[i].free.prev; + else + { + do + i = _heapinfo[i].free.next; + while (i > 0 && i < block); + i = _heapinfo[i].free.prev; + } + + /* Determine how to link this block into the free list. */ + if (block == i + _heapinfo[i].free.size) + { + /* Coalesce this block with its predecessor. */ + _heapinfo[i].free.size += _heapinfo[block].busy.info.size; + block = i; + } + else + { + /* Really link this block back into the free list. */ + _heapinfo[block].free.size = _heapinfo[block].busy.info.size; + _heapinfo[block].free.next = _heapinfo[i].free.next; + _heapinfo[block].free.prev = i; + _heapinfo[i].free.next = block; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + ++_chunks_free; + } + + /* Now that the block is linked in, see if we can coalesce it + with its successor (by deleting its successor from the list + and adding in its size). */ + if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) + { + _heapinfo[block].free.size + += _heapinfo[_heapinfo[block].free.next].free.size; + _heapinfo[block].free.next + = _heapinfo[_heapinfo[block].free.next].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + --_chunks_free; + } + + /* How many trailing free blocks are there now? */ + blocks = _heapinfo[block].free.size; + + /* Where is the current end of accessible core? */ + curbrk = (*__morecore) (0); + + if (_heaplimit != 0 && curbrk == ADDRESS (_heaplimit)) + { + /* The end of the malloc heap is at the end of accessible core. + It's possible that moving _heapinfo will allow us to + return some space to the system. */ + + __malloc_size_t info_block = BLOCK (_heapinfo); + __malloc_size_t info_blocks = _heapinfo[info_block].busy.info.size; + __malloc_size_t prev_block = _heapinfo[block].free.prev; + __malloc_size_t prev_blocks = _heapinfo[prev_block].free.size; + __malloc_size_t next_block = _heapinfo[block].free.next; + __malloc_size_t next_blocks = _heapinfo[next_block].free.size; + + if (/* Win if this block being freed is last in core, the info table + is just before it, the previous free block is just before the + info table, and the two free blocks together form a useful + amount to return to the system. */ + (block + blocks == _heaplimit && + info_block + info_blocks == block && + prev_block != 0 && prev_block + prev_blocks == info_block && + blocks + prev_blocks >= lesscore_threshold) || + /* Nope, not the case. We can also win if this block being + freed is just before the info table, and the table extends + to the end of core or is followed only by a free block, + and the total free space is worth returning to the system. */ + (block + blocks == info_block && + ((info_block + info_blocks == _heaplimit && + blocks >= lesscore_threshold) || + (info_block + info_blocks == next_block && + next_block + next_blocks == _heaplimit && + blocks + next_blocks >= lesscore_threshold))) + ) + { + malloc_info *newinfo; + __malloc_size_t oldlimit = _heaplimit; + + /* Free the old info table, clearing _heaplimit to avoid + recursion into this code. We don't want to return the + table's blocks to the system before we have copied them to + the new location. */ + _heaplimit = 0; + _free_internal (_heapinfo); + _heaplimit = oldlimit; + + /* Tell malloc to search from the beginning of the heap for + free blocks, so it doesn't reuse the ones just freed. */ + _heapindex = 0; + + /* Allocate new space for the info table and move its data. */ + newinfo = (malloc_info *) _malloc_internal (info_blocks + * BLOCKSIZE); + memmove (newinfo, _heapinfo, info_blocks * BLOCKSIZE); + _heapinfo = newinfo; + + /* We should now have coalesced the free block with the + blocks freed from the old info table. Examine the entire + trailing free block to decide below whether to return some + to the system. */ + block = _heapinfo[0].free.prev; + blocks = _heapinfo[block].free.size; + } + + /* Now see if we can return stuff to the system. */ + if (block + blocks == _heaplimit && blocks >= lesscore_threshold) + { + register __malloc_size_t bytes = blocks * BLOCKSIZE; + _heaplimit -= blocks; + (*__morecore) (-bytes); + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[block].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + block = _heapinfo[block].free.prev; + --_chunks_free; + _bytes_free -= bytes; + } + } + + /* Set the next search to begin at this block. */ + _heapindex = block; + break; + + default: + /* Do some of the statistics. */ + --_chunks_used; + _bytes_used -= 1 << type; + ++_chunks_free; + _bytes_free += 1 << type; + + /* Get the address of the first free fragment in this block. */ + prev = (struct list *) ((char *) ADDRESS (block) + + (_heapinfo[block].busy.info.frag.first << type)); + + if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1) + { + /* If all fragments of this block are free, remove them + from the fragment list and free the whole block. */ + next = prev; + for (i = 1; i < (__malloc_size_t) (BLOCKSIZE >> type); ++i) + next = next->next; + prev->prev->next = next; + if (next != NULL) + next->prev = prev->prev; + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = 1; + + /* Keep the statistics accurate. */ + ++_chunks_used; + _bytes_used += BLOCKSIZE; + _chunks_free -= BLOCKSIZE >> type; + _bytes_free -= BLOCKSIZE; + + free (ADDRESS (block)); + } + else if (_heapinfo[block].busy.info.frag.nfree != 0) + { + /* If some fragments of this block are free, link this + fragment into the fragment list after the first free + fragment of this block. */ + next = (struct list *) ptr; + next->next = prev->next; + next->prev = prev; + prev->next = next; + if (next->next != NULL) + next->next->prev = next; + ++_heapinfo[block].busy.info.frag.nfree; + } + else + { + /* No fragments of this block are free, so link this + fragment into the fragment list and announce that + it is the first free fragment of this block. */ + prev = (struct list *) ptr; + _heapinfo[block].busy.info.frag.nfree = 1; + _heapinfo[block].busy.info.frag.first = (unsigned long int) + ((unsigned long int) ((char *) ptr - (char *) NULL) + % BLOCKSIZE >> type); + prev->next = _fraghead[type].next; + prev->prev = &_fraghead[type]; + prev->prev->next = prev; + if (prev->next != NULL) + prev->next->prev = prev; + } + break; + } +} + +/* Return memory to the heap. */ +void +free (ptr) + __ptr_t ptr; +{ + if (__free_hook != NULL) + (*__free_hook) (ptr); + else + _free_internal (ptr); +} + +/* Define the `cfree' alias for `free'. */ +#ifdef weak_alias +weak_alias (free, cfree) +#else +void +cfree (ptr) + __ptr_t ptr; +{ + free (ptr); +} +#endif +/* Change the size of a block allocated by `malloc'. + Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + + + +/* Cope with systems lacking `memmove'. */ +#if (defined (MEMMOVE_MISSING) || \ + !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) + +#ifdef emacs +#undef __malloc_safe_bcopy +#define __malloc_safe_bcopy safe_bcopy +#else + +/* Snarfed directly from Emacs src/dispnew.c: + XXX Should use system bcopy if it handles overlap. */ + +/* Like bcopy except never gets confused by overlap. */ + +void +__malloc_safe_bcopy (afrom, ato, size) + __ptr_t afrom; + __ptr_t ato; + __malloc_size_t size; +{ + char *from = afrom, *to = ato; + + if (size <= 0 || from == to) + return; + + /* If the source and destination don't overlap, then bcopy can + handle it. If they do overlap, but the destination is lower in + memory than the source, we'll assume bcopy can handle that. */ + if (to < from || from + size <= to) + bcopy (from, to, size); + + /* Otherwise, we'll copy from the end. */ + else + { + register char *endf = from + size; + register char *endt = to + size; + + /* If TO - FROM is large, then we should break the copy into + nonoverlapping chunks of TO - FROM bytes each. However, if + TO - FROM is small, then the bcopy function call overhead + makes this not worth it. The crossover point could be about + anywhere. Since I don't think the obvious copy loop is too + bad, I'm trying to err in its favor. */ + if (to - from < 64) + { + do + *--endt = *--endf; + while (endf != from); + } + else + { + for (;;) + { + endt -= (to - from); + endf -= (to - from); + + if (endt < to) + break; + + bcopy (endf, endt, to - from); + } + + /* If SIZE wasn't a multiple of TO - FROM, there will be a + little left over. The amount left over is + (endt + (to - from)) - to, which is endt - from. */ + bcopy (from, to, endt - from); + } + } +} +#endif /* emacs */ + +#ifndef memmove +extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); +#define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) +#endif + +#endif + + +#define min(A, B) ((A) < (B) ? (A) : (B)) + +/* Debugging hook for realloc. */ +__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); + +/* Resize the given region to the new size, returning a pointer + to the (possibly moved) region. This is optimized for speed; + some benchmarks seem to indicate that greater compactness is + achieved by unconditionally allocating and copying to a + new region. This module has incestuous knowledge of the + internals of both free and malloc. */ +__ptr_t +_realloc_internal (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + __ptr_t result; + int type; + __malloc_size_t block, blocks, oldlimit; + + if (size == 0) + { + _free_internal (ptr); + return _malloc_internal (0); + } + else if (ptr == NULL) + return _malloc_internal (size); + + block = BLOCK (ptr); + + type = _heapinfo[block].busy.type; + switch (type) + { + case 0: + /* Maybe reallocate a large block to a small fragment. */ + if (size <= BLOCKSIZE / 2) + { + result = _malloc_internal (size); + if (result != NULL) + { + memcpy (result, ptr, size); + _free_internal (ptr); + return result; + } + } + + /* The new size is a large allocation as well; + see if we can hold it in place. */ + blocks = BLOCKIFY (size); + if (blocks < _heapinfo[block].busy.info.size) + { + /* The new size is smaller; return + excess memory to the free list. */ + _heapinfo[block + blocks].busy.type = 0; + _heapinfo[block + blocks].busy.info.size + = _heapinfo[block].busy.info.size - blocks; + _heapinfo[block].busy.info.size = blocks; + /* We have just created a new chunk by splitting a chunk in two. + Now we will free this chunk; increment the statistics counter + so it doesn't become wrong when _free_internal decrements it. */ + ++_chunks_used; + _free_internal (ADDRESS (block + blocks)); + result = ptr; + } + else if (blocks == _heapinfo[block].busy.info.size) + /* No size change necessary. */ + result = ptr; + else + { + /* Won't fit, so allocate a new region that will. + Free the old region first in case there is sufficient + adjacent free space to grow without moving. */ + blocks = _heapinfo[block].busy.info.size; + /* Prevent free from actually returning memory to the system. */ + oldlimit = _heaplimit; + _heaplimit = 0; + _free_internal (ptr); + result = _malloc_internal (size); + if (_heaplimit == 0) + _heaplimit = oldlimit; + if (result == NULL) + { + /* Now we're really in trouble. We have to unfree + the thing we just freed. Unfortunately it might + have been coalesced with its neighbors. */ + if (_heapindex == block) + (void) _malloc_internal (blocks * BLOCKSIZE); + else + { + __ptr_t previous + = _malloc_internal ((block - _heapindex) * BLOCKSIZE); + (void) _malloc_internal (blocks * BLOCKSIZE); + _free_internal (previous); + } + return NULL; + } + if (ptr != result) + memmove (result, ptr, blocks * BLOCKSIZE); + } + break; + + default: + /* Old size is a fragment; type is logarithm + to base two of the fragment size. */ + if (size > (__malloc_size_t) (1 << (type - 1)) && + size <= (__malloc_size_t) (1 << type)) + /* The new size is the same kind of fragment. */ + result = ptr; + else + { + /* The new size is different; allocate a new space, + and copy the lesser of the new size and the old. */ + result = _malloc_internal (size); + if (result == NULL) + return NULL; + memcpy (result, ptr, min (size, (__malloc_size_t) 1 << type)); + _free_internal (ptr); + } + break; + } + + return result; +} + +__ptr_t +realloc (ptr, size) + __ptr_t ptr; + __malloc_size_t size; +{ + if (!__malloc_initialized && !__malloc_initialize ()) + return NULL; + + return (__realloc_hook != NULL ? *__realloc_hook : _realloc_internal) + (ptr, size); +} +/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +/* Allocate an array of NMEMB elements each SIZE bytes long. + The entire array is initialized to zeros. */ +__ptr_t +calloc (nmemb, size) + register __malloc_size_t nmemb; + register __malloc_size_t size; +{ + register __ptr_t result = malloc (nmemb * size); + + if (result != NULL) + (void) memset (result, 0, nmemb * size); + + return result; +} +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the GNU C Library; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +#ifndef __GNU_LIBRARY__ +#define __sbrk sbrk +#endif + +#ifdef __GNU_LIBRARY__ +/* It is best not to declare this and cast its result on foreign operating + systems with potentially hostile include files. */ + +#include <stddef.h> +extern __ptr_t __sbrk __P ((ptrdiff_t increment)); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* Allocate INCREMENT more bytes of data space, + and return the start of data space, or NULL on errors. + If INCREMENT is negative, shrink data space. */ +__ptr_t +__default_morecore (increment) + __malloc_ptrdiff_t increment; +{ + __ptr_t result = (__ptr_t) __sbrk (increment); + if (result == (__ptr_t) -1) + return NULL; + return result; +} +/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +#if __DJGPP__ - 0 == 1 + +/* There is some problem with memalign in DJGPP v1 and we are supposed + to omit it. Noone told me why, they just told me to do it. */ + +#else + +__ptr_t (*__memalign_hook) __P ((size_t __size, size_t __alignment)); + +__ptr_t +memalign (alignment, size) + __malloc_size_t alignment; + __malloc_size_t size; +{ + __ptr_t result; + unsigned long int adj, lastadj; + + if (__memalign_hook) + return (*__memalign_hook) (alignment, size); + + /* Allocate a block with enough extra space to pad the block with up to + (ALIGNMENT - 1) bytes if necessary. */ + result = malloc (size + alignment - 1); + if (result == NULL) + return NULL; + + /* Figure out how much we will need to pad this particular block + to achieve the required alignment. */ + adj = (unsigned long int) ((char *) result - (char *) NULL) % alignment; + + do + { + /* Reallocate the block with only as much excess as it needs. */ + free (result); + result = malloc (adj + size); + if (result == NULL) /* Impossible unless interrupted. */ + return NULL; + + lastadj = adj; + adj = (unsigned long int) ((char *) result - (char *) NULL) % alignment; + /* It's conceivable we might have been so unlucky as to get a + different block with weaker alignment. If so, this block is too + short to contain SIZE after alignment correction. So we must + try again and get another block, slightly larger. */ + } while (adj > lastadj); + + if (adj != 0) + { + /* Record this block in the list of aligned blocks, so that `free' + can identify the pointer it is passed, which will be in the middle + of an allocated block. */ + + struct alignlist *l; + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == NULL) + /* This slot is free. Use it. */ + break; + if (l == NULL) + { + l = (struct alignlist *) malloc (sizeof (struct alignlist)); + if (l == NULL) + { + free (result); + return NULL; + } + l->next = _aligned_blocks; + _aligned_blocks = l; + } + l->exact = result; + result = l->aligned = (char *) result + alignment - adj; + } + + return result; +} + +#endif /* Not DJGPP v1 */ +/* Allocate memory on a page boundary. + Copyright (C) 1991, 92, 93, 94, 96 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + +#if defined (_MALLOC_INTERNAL) && defined (GMALLOC_INHIBIT_VALLOC) + +/* Emacs defines GMALLOC_INHIBIT_VALLOC to avoid this definition + on MSDOS, where it conflicts with a system header file. */ + +#define ELIDE_VALLOC + +#endif + +#ifndef ELIDE_VALLOC + +#if defined (__GNU_LIBRARY__) || defined (_LIBC) +#include <stddef.h> +#include <sys/cdefs.h> +extern size_t __getpagesize __P ((void)); +#else +#include "getpagesize.h" +#define __getpagesize() getpagesize() +#endif + +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include <malloc.h> +#endif + +static __malloc_size_t pagesize; + +__ptr_t +valloc (size) + __malloc_size_t size; +{ + if (pagesize == 0) + pagesize = __getpagesize (); + + return memalign (pagesize, size); +} + +#endif /* Not ELIDE_VALLOC. */ @@ -0,0 +1,138 @@ +/* Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "gsubr.c" CCLOs taking general number of required, optional, and rest args. + Author: Radey Shouman */ + +#include "scm.h" + +#define GSUBR_MAKTYPE(req, opt, rst) ((req)|((opt)<<4)|((rst)<<8)) +#define GSUBR_REQ(x) ((int)(x)&0xf) +#define GSUBR_OPT(x) (((int)(x)&0xf0)>>4) +#define GSUBR_REST(x) ((int)(x)>>8) + +#define GSUBR_MAX 10 +#define GSUBR_TYPE(cclo) (VELTS(cclo)[1]) +#define GSUBR_PROC(cclo) (VELTS(cclo)[2]) + +static SCM f_gsubr_apply; +SCM make_gsubr(name, req, opt, rst, fcn) + char *name; + int req, opt, rst; + SCM (*fcn)(); +{ + switch GSUBR_MAKTYPE(req, opt, rst) { + case GSUBR_MAKTYPE(0, 0, 0): return make_subr(name, tc7_subr_0, fcn); + case GSUBR_MAKTYPE(1, 0, 0): return make_subr(name, tc7_subr_1, fcn); + case GSUBR_MAKTYPE(0, 1, 0): return make_subr(name, tc7_subr_1o, fcn); + case GSUBR_MAKTYPE(1, 1, 0): return make_subr(name, tc7_subr_2o, fcn); + case GSUBR_MAKTYPE(2, 0, 0): return make_subr(name, tc7_subr_2, fcn); + case GSUBR_MAKTYPE(3, 0, 0): return make_subr(name, tc7_subr_3, fcn); + case GSUBR_MAKTYPE(0, 0, 1): return make_subr(name, tc7_lsubr, fcn); + case GSUBR_MAKTYPE(2, 0, 1): return make_subr(name, tc7_lsubr_2, fcn); + default: + { + SCM symcell = sysintern(name, UNDEFINED); + SCM z, cclo = makcclo(f_gsubr_apply, 3L); + long tmp = ((((CELLPTR)(CAR(symcell)))-heap_org)<<8); + ASSERT(GSUBR_MAX >= req + opt + rst, MAKINUM(req + opt + rst), + OUTOFRANGE, "make_gsubr"); + if ((tmp>>8) != ((CELLPTR)(CAR(symcell))-heap_org)) + tmp = 0; + NEWCELL(z); + SUBRF(z) = fcn; + CAR(z) = tmp + tc7_subr_0; + GSUBR_PROC(cclo) = z; + GSUBR_TYPE(cclo) = MAKINUM(GSUBR_MAKTYPE(req, opt, rst)); + CDR(symcell) = cclo; + return cclo; + } + } +} + +char s_gsubr_apply[] = " gsubr-apply"; +SCM gsubr_apply(args) + SCM args; +{ + SCM self = CAR(args); + SCM (*fcn)() = SUBRF(GSUBR_PROC(self)); + int typ = INUM(GSUBR_TYPE(self)); + int i, n = GSUBR_REQ(typ) + GSUBR_OPT(typ) + GSUBR_REST(typ); + SCM v[10]; + if (n > 10) wta(self, "internal programming error", s_gsubr_apply); + args = CDR(args); + for (i = 0; i < GSUBR_REQ(typ); i++) { +#ifndef RECKLESS + if IMP(args) + wnargs: wta(UNDEFINED, (char *)WNA, CHARS(SNAME(GSUBR_PROC(self)))); +#endif + v[i] = CAR(args); + args = CDR(args); + } + for (; i < GSUBR_REQ(typ) + GSUBR_OPT(typ); i++) { + if NIMP(args) { + v[i] = CAR(args); + args = CDR(args); + } + else + v[i] = UNDEFINED; + } + if GSUBR_REST(typ) + v[i] = args; + else + ASRTGO(NULLP(args), wnargs); + switch (n) { + case 2: return (*fcn)(v[0], v[1]); + case 3: return (*fcn)(v[0], v[1], v[2]); + case 4: return (*fcn)(v[0], v[1], v[2], v[3]); + case 5: return (*fcn)(v[0], v[1], v[2], v[3], v[4]); + case 6: return (*fcn)(v[0], v[1], v[2], v[3], v[4], v[5]); + case 7: return (*fcn)(v[0], v[1], v[2], v[3], v[4], v[5], v[6]); + case 8: return (*fcn)(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); + case 9: return (*fcn)(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]); + case 10: return (*fcn)(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9]); + } +} + +void init_gsubr() +{ + f_gsubr_apply = make_subr(s_gsubr_apply, tc7_lsubr, gsubr_apply); +} diff --git a/install-sh b/install-sh new file mode 100644 index 0000000..89fc9b0 --- /dev/null +++ b/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 @@ -0,0 +1,703 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "ioext.c" code for system calls in common between PC compilers and unix. + Author: Aubrey Jaffer */ + +#include "scm.h" + +#ifdef __EMX__ +# include <sys/types.h> +#endif + +#ifndef THINK_C +# ifdef vms +# include <stat.h> +# else +# include <sys/stat.h> +# endif +# ifdef __TURBOC__ +# include <io.h> +# endif +SCM stat2scm P((struct stat *stat_temp)); +/* int mkdir P((const char *path, mode_t mode)); */ +#endif +#ifdef hpux +# include <unistd.h> +#endif +#ifdef __sgi__ +# include <unistd.h> +#endif + +#ifndef STDC_HEADERS + int chdir P((const char *path)); + int unlink P((const char *name)); + int link P((const char *from, const char *to)); + char *getcwd P((char *buf, sizet size)); + int access P((const char *name, int type)); + int dup P((int fd)); + int dup2 P((int fd, int fd2)); + int close P((int fd)); + int rmdir P((const char *path)); + int execv P((const char *, char *const *)); + int execvp P((const char *, char *const *)); + int putenv P((const char *)); +#else +# ifdef _WIN32 +# include <direct.h> +# include <io.h> +# include <process.h> +# endif +# ifdef __HIGHC__ +# include <direct.h> +# include <dirent.h> +# include <process.h> +# define mkdir(foo,bar) mkdir(foo) +# endif +#endif /* STDC_HEADERS */ + +#ifdef __EMX__ + int execv P((const char *, char *const *)); + int execvp P((const char *, char *const *)); + int putenv P((const char *)); +#endif + +static char s_read_line[] = "read-line"; +SCM read_line(port) + SCM port; +{ + register int c; + register int j = 0; + sizet len = 30; + SCM tok_buf = makstr((long) len); + register char *p = CHARS(tok_buf); + if UNBNDP(port) port = cur_inp; + else ASSERT(NIMP(port) && OPINPORTP(port), port, ARG1, s_read_line); + if (EOF==(c = lgetc(port))) return EOF_VAL; + while(1) { + switch (c) { + case LINE_INCREMENTORS: + case EOF: + if (len==j) return tok_buf; + return resizuve(tok_buf, (SCM)MAKINUM(j)); + default: + if (j >= len) { + p = grow_tok_buf(tok_buf); + len = LENGTH(tok_buf); + } + p[j++] = c; + c = lgetc(port); + } + } +} +static char s_read_line1[] = "read-line!"; +SCM read_line1(str, port) + SCM str, port; +{ + register int c; + register int j = 0; + register char *p; + sizet len; + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_read_line1); + p = CHARS(str); + len = LENGTH(str); + if UNBNDP(port) port = cur_inp; + else ASSERT(NIMP(port) && OPINPORTP(port), port, ARG2, s_read_line1); + c = lgetc(port); + if (EOF==c) return EOF_VAL; + while(1) { + switch (c) { + case LINE_INCREMENTORS: + case EOF: + return MAKINUM(j); + default: + if (j >= len) { + lungetc(c, port); + return BOOL_F; + } + p[j++] = c; + c = lgetc(port); + } + } +} +static char s_write_line[] = "write-line"; +SCM l_write_line(obj, port) + SCM obj, port; +{ + display(obj, port); + return newline(port); +} + +static char s_file_position[] = "file-position", + s_file_set_pos[] = "file-set-position"; +SCM file_position(port) + SCM port; +{ + long ans; + ASSERT(NIMP(port) && OPFPORTP(port), port, ARG1, s_file_position); + SYSCALL(ans = ftell(STREAM(port));); + if CRDYP(port) ans--; + return MAKINUM(ans); + } +SCM file_set_position(port, pos) + SCM port, pos; +{ + SCM ans; + ASSERT(NIMP(port) && OPFPORTP(port), port, ARG1, s_file_set_pos); + CLRDY(port); /* Clear ungetted char */ + SYSCALL(ans = (fseek(STREAM(port), INUM(pos), 0)) ? BOOL_F : BOOL_T;); +#ifdef HAVE_PIPE +# ifdef ESPIPE + if (!OPIOPORTP(port)) + ASSERT(ESPIPE != errno, port, ARG1, s_file_set_pos); +# endif +#endif + return ans; +} + +static char s_reopen_file[] = "reopen-file"; +SCM reopen_file(filename, modes, port) + SCM filename, modes, port; +{ + FILE *f; + ASSERT(NIMP(filename) && STRINGP(filename), filename, ARG1, s_reopen_file); + ASSERT(NIMP(modes) && STRINGP(modes), modes, ARG2, s_reopen_file); + DEFER_INTS; + ASSERT(NIMP(port) && FPORTP(port) && OPENP(port), port, ARG3, s_reopen_file); + SYSCALL(f = freopen(CHARS(filename), CHARS(modes), STREAM(port));); + if (!f) port = BOOL_F; + else { + SETSTREAM(port, f); + if (BUF0 & (CAR(port) = tc16_fport | mode_bits(CHARS(modes)))) + i_setbuf0(port); + } + ALLOW_INTS; + return port; +} + +#ifndef MCH_AMIGA + +static char s_dup[]="duplicate-port"; +SCM l_dup(oldpt, modes) + SCM oldpt, modes; +{ + int tfd; + FILE *f; + SCM newpt; + ASSERT(NIMP(oldpt) && OPPORTP(oldpt), oldpt, ARG1, s_dup); + ASSERT(NIMP(modes) && STRINGP(modes), modes, ARG2, s_dup); + NEWCELL(newpt); + DEFER_INTS; + SYSCALL(tfd = dup(fileno(STREAM(oldpt)));); + if (-1==tfd) {ALLOW_INTS;return BOOL_F;}; + SYSCALL(f = fdopen(tfd, CHARS(modes));); + if (!f) { + close(tfd); + wta(MAKINUM(tfd), (char *)NALLOC, s_port_type); + } + SETSTREAM(newpt, f); + if (BUF0 & (CAR(newpt) = tc16_fport | mode_bits(CHARS(modes)))) + i_setbuf0(newpt); + ALLOW_INTS; + return newpt; +} +static char s_dup2[]="redirect-port!"; +SCM l_dup2(into_pt, from_pt) + SCM into_pt, from_pt; +{ + int ans, oldfd, newfd; + DEFER_INTS; + ASSERT(NIMP(into_pt) && OPPORTP(into_pt), into_pt, ARG1, s_dup2); + ASSERT(NIMP(from_pt) && OPPORTP(from_pt), from_pt, ARG1, s_dup2); + oldfd = fileno(STREAM(into_pt)); + newfd = fileno(STREAM(from_pt)); + SYSCALL(ans = dup2(oldfd, newfd);); + if (-1==ans) {ALLOW_INTS;return BOOL_F;}; + ALLOW_INTS; + return into_pt; +} + +# ifndef vms +# ifndef _WIN32 +# include <dirent.h> +static char s_opendir[]="opendir"; +SCM l_opendir(dirname) + SCM dirname; +{ + DIR *ds; + SCM dir; + ASSERT(NIMP(dirname) && STRINGP(dirname), dirname, ARG1, s_opendir); + NEWCELL(dir); + DEFER_INTS; + SYSCALL(ds = opendir(CHARS(dirname));); + if (!ds) {ALLOW_INTS; return BOOL_F;} + CAR(dir) = tc16_dir | OPN; + SETCDR(dir, ds); + ALLOW_INTS; + return dir; +} +static char s_readdir[]="readdir"; +SCM l_readdir(port) + SCM port; +{ + struct dirent *rdent; + DEFER_INTS; + ASSERT(OPDIRP(port), port, ARG1, s_readdir); + SYSCALL(rdent = readdir((DIR *)CDR(port));); + if (!rdent) {ALLOW_INTS; return BOOL_F;} + ALLOW_INTS; + /* rdent could be overwritten by another readdir to the same handle */ + return makfrom0str(rdent->d_name); +} +static char s_rewinddir[]="rewinddir"; +SCM l_rewinddir(port) + SCM port; +{ + ASSERT(OPDIRP(port), port, ARG1, s_rewinddir); + rewinddir((DIR *)CDR(port)); + return UNSPECIFIED; +} +static char s_closedir[]="closedir"; +SCM l_closedir(port) + SCM port; +{ + int sts; + ASSERT(DIRP(port), port, ARG1, s_closedir); + DEFER_INTS; + if CLOSEDP(port) {ALLOW_INTS;return BOOL_F;} + SYSCALL(sts = closedir((DIR *)CDR(port));); + if (sts) {ALLOW_INTS; return BOOL_F;} + CAR(port) = tc16_dir; + ALLOW_INTS; + return BOOL_T; +} + +int dir_print(sexp, port, writing) + SCM sexp; SCM port; int writing; +{ + prinport(sexp, port, "directory"); + return !0; +} +sizet dir_free(p) + CELLPTR p; +{ + if OPENP((SCM)p) closedir((DIR *)CDR((SCM)p)); + return 0; +} + +long tc16_dir; +static smobfuns dir_smob = {mark0, dir_free, dir_print, 0}; +# endif /* _WIN32 */ +# endif /* vms */ + +static char s_mkdir[] = "mkdir"; +SCM l_mkdir(path, mode) + SCM path, mode; +{ + int val; + ASSERT(NIMP(path) && STRINGP(path), path, ARG1, s_mkdir); + ASSERT(INUMP(mode), mode, ARG2, s_mkdir); +# ifdef _WIN32 + SYSCALL(val = mkdir(CHARS(path));); +# else + SYSCALL(val = mkdir(CHARS(path), INUM(mode));); + /* (mode_t)INUM(mode) might be needed */ +# endif + return val ? BOOL_F : BOOL_T; +} +# ifdef vms +static char s_dot_dir[] = ".DIR"; +# endif +static char s_rmdir[] = "rmdir"; +SCM l_rmdir(path) + SCM path; +{ + int val; + ASSERT(NIMP(path) && STRINGP(path), path, ARG1, s_rmdir); +# ifdef vms + return del_fil(st_append(cons2(path, s_dot_dir, EOL))); +# else + SYSCALL(val = rmdir(CHARS(path));); + return val ? BOOL_F : BOOL_T; +# endif +} +#endif /* MCH_AMIGA */ + +#ifndef THINK_C +static char s_chdir[] = "chdir"; +SCM lchdir(str) + SCM str; +{ + int ans; + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_chdir); + SYSCALL(ans = chdir(CHARS(str));); + return ans ? BOOL_F : BOOL_T; +} +# ifndef MCH_AMIGA +# ifdef __TURBOC__ +# include <dir.h> +# endif +SCM l_getcwd() +{ + char *ans; +# ifndef vms + char wd[256]; + SYSCALL(ans = getcwd(wd, 256);); + return ans ? makfrom0str(wd) : BOOL_F; +# else + SYSCALL(ans = getenv("PATH");); + return ans ? makfrom0str(ans) : BOOL_F; +# endif +} + +static char s_chmod[] = "chmod"; +SCM l_chmod(pathname, mode) + SCM pathname, mode; +{ + int val; + ASSERT(NIMP(pathname) && STRINGP(pathname), pathname, ARG1, s_chmod); + ASSERT(INUMP(mode), mode, ARG2, s_chmod); + SYSCALL(val = chmod(CHARS(pathname), INUM(mode));); + return val ? BOOL_F : BOOL_T; +} + +# ifndef vms +# ifdef __EMX__ +# include <sys/utime.h> +# else +# ifdef _WIN32 +# include <sys/utime.h> +# else +# include <utime.h> +# endif +# endif +static char s_utime[] = "utime"; +SCM l_utime(pathname, acctime, modtime) + SCM pathname, acctime, modtime; +{ + int val; + struct utimbuf utm_tmp; + utm_tmp.actime = num2ulong(acctime, (char *)ARG2, s_utime); + utm_tmp.modtime = num2ulong(modtime, (char *)ARG3, s_utime); + ASSERT(NIMP(pathname) && STRINGP(pathname), pathname, ARG1, s_utime); + SYSCALL(val = utime(CHARS(pathname), &utm_tmp);); + return val ? BOOL_F : BOOL_T; +} +# endif /* vms */ + +static char s_umask[] = "umask"; +SCM l_umask(mode) + SCM mode; +{ + ASSERT(INUMP(mode), mode, ARG1, s_umask); + return MAKINUM(umask(INUM(mode))); +} +# endif /* MCH_AMIGA */ +#endif /* THINK_C */ + +static char s_ren_fil[] = "rename-file"; +SCM ren_fil(oldname, newname) + SCM oldname, newname; +{ + SCM ans; + ASSERT(NIMP(oldname) && STRINGP(oldname), oldname, ARG1, s_ren_fil); + ASSERT(NIMP(newname) && STRINGP(newname), newname, ARG2, s_ren_fil); +#ifdef STDC_HEADERS + SYSCALL(ans = (rename(CHARS(oldname), CHARS(newname))) ? BOOL_F: BOOL_T;); + return ans; +#else + DEFER_INTS; + SYSCALL(ans = link(CHARS(oldname), CHARS(newname)) ? BOOL_F : BOOL_T;); + if (!FALSEP(ans)) { + SYSCALL(ans = unlink(CHARS(oldname)) ? BOOL_F : BOOL_T;); + if FALSEP(ans) + SYSCALL(unlink(CHARS(newname));); /* unlink failed. remove new name */ + } + ALLOW_INTS; + return ans; +#endif +} +static char s_fileno[] = "fileno"; +SCM l_fileno(port) + SCM port; +{ + ASSERT(NIMP(port) && OPPORTP(port), port, ARG1, s_fileno); + if (tc16_fport != TYP16(port)) return BOOL_F; + return MAKINUM(fileno(STREAM(port))); +} +static char s_isatty[] = "isatty?"; +SCM l_isatty(port) + SCM port; +{ + ASSERT(NIMP(port) && OPPORTP(port), port, ARG1, s_isatty); + if (tc16_fport != TYP16(port)) return BOOL_F; + return isatty(fileno(STREAM(port)))?BOOL_T:BOOL_F; +} +#ifndef F_OK +# define F_OK 00 +# define X_OK 01 +# define W_OK 02 +# define R_OK 04 +#endif +static char s_access[] = "access"; +SCM l_access(pathname, mode) + SCM pathname, mode; +{ + int val; + int imodes; + ASSERT(NIMP(pathname) && STRINGP(pathname), pathname, ARG1, s_access); + if INUMP(mode) imodes = INUM(mode); + else { + ASSERT(NIMP(mode) && STRINGP(mode), mode, ARG2, s_access); + imodes = F_OK | (strchr(CHARS(mode), 'r') ? R_OK : 0) + | (strchr(CHARS(mode), 'w') ? W_OK : 0) + | (strchr(CHARS(mode), 'x') ? X_OK : 0); + } + SYSCALL(val = access(CHARS(pathname), imodes);); + return val ? BOOL_F : BOOL_T; +} + +#ifndef THINK_C + +char s_stat[] = "stat"; +SCM l_stat(str) + SCM str; +{ + int i; + struct stat stat_temp; + if IMP(str) + badarg1: wta(str, (char *)ARG1, s_stat); + if STRINGP(str) {SYSCALL(i = stat(CHARS(str), &stat_temp););} + else { +# ifndef MCH_AMIGA + if (!OPFPORTP(str)) goto badarg1; + SYSCALL(i = fstat(fileno(STREAM(str)), &stat_temp);); +# else + goto badarg1; +# endif + } + if (i) return BOOL_F; + return stat2scm(&stat_temp); +} +# ifdef MCH_AMIGA +SCM stat2scm(stat_temp) + struct stat *stat_temp; +{ + SCM ans = make_vector(MAKINUM(3), UNSPECIFIED); + SCM *ve = VELTS(ans); + ve[ 0] = ulong2num((unsigned long)stat_temp->st_attr); + ve[ 1] = ulong2num((unsigned long)stat_temp->st_mtime); + ve[ 2] = ulong2num((unsigned long)stat_temp->st_size); + return ans; +} +# else +SCM stat2scm(stat_temp) + struct stat *stat_temp; +{ + SCM ans = make_vector(MAKINUM(11), UNSPECIFIED); + SCM *ve = VELTS(ans); + ve[ 0] = ulong2num((unsigned long)stat_temp->st_dev); + ve[ 1] = ulong2num((unsigned long)stat_temp->st_ino); + ve[ 2] = ulong2num((unsigned long)stat_temp->st_mode); + ve[ 3] = ulong2num((unsigned long)stat_temp->st_nlink); + ve[ 4] = ulong2num((unsigned long)stat_temp->st_uid); + ve[ 5] = ulong2num((unsigned long)stat_temp->st_gid); + ve[ 6] = ulong2num((unsigned long)stat_temp->st_rdev); + ve[ 7] = ulong2num((unsigned long)stat_temp->st_size); + ve[ 8] = ulong2num((unsigned long)stat_temp->st_atime); + ve[ 9] = ulong2num((unsigned long)stat_temp->st_mtime); + ve[10] = ulong2num((unsigned long)stat_temp->st_ctime); + return ans; +} +# ifdef __TURBOC__ +# include <process.h> +# endif +SCM l_getpid() +{ + return MAKINUM((unsigned long)getpid()); +} +# endif /* MCH_AMIGA */ +#endif /* THINK_C */ + +#ifndef __IBMC__ +# ifndef THINK_C +# ifndef __WATCOMC__ +# ifndef GO32 +# ifndef _Windows +# ifdef __TURBOC__ +# include <process.h> +# endif +char s_execv[] = "execv"; +char s_execvp[] = "execvp"; +SCM i_execv(modes, path, args) + char * modes; + SCM path, args; +{ + char **execargv; + int i = ilength(args); + ASSERT(i>0, args, WNA, s_execv); + ASSERT(NIMP(path) && STRINGP(path), path, ARG1, s_execv); + /* dowinds(EOL, ilength(dynwinds)); */ + args = cons(path, args); + DEFER_INTS; + execargv = makargvfrmstrs(args, s_execv); + ALLOW_INTS; + (strchr(modes, 'p') ? execvp : execv)(execargv[0], &execargv[1]); + perror(execargv[0]); + return MAKINUM(errno); +} +SCM lexec(path, arg0, args) + SCM path, arg0, args; +{ + return i_execv("", path, cons(arg0, args)); +} +SCM lexecp(path, arg0, args) + SCM path, arg0, args; +{ + return i_execv("p", path, cons(arg0, args)); +} +SCM lexecv(path, args) + SCM path, args; +{ + return i_execv("", path, args); +} +SCM lexecvp(path, args) + SCM path, args; +{ + return i_execv("p", path, args); +} +static char s_putenv[] = "putenv"; +SCM l_putenv(str) + SCM str; +{ + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_putenv); + return putenv(CHARS(str)) ? BOOL_F : BOOL_T; +} +# endif +# endif +# endif +# endif +#endif + +static iproc subr1s[] = { + {s_file_position, file_position}, + {s_fileno, l_fileno}, + {s_isatty, l_isatty}, +#ifndef MCH_AMIGA +# ifndef vms +# ifndef _WIN32 + {s_opendir, l_opendir}, + {s_readdir, l_readdir}, + {s_rewinddir, l_rewinddir}, + {s_closedir, l_closedir}, +# endif +# endif + {s_rmdir, l_rmdir}, +#endif +#ifndef THINK_C +# ifndef MCH_AMIGA + {s_umask, l_umask}, +# endif + {s_chdir, lchdir}, + {s_stat, l_stat}, +#endif + {0, 0}}; + +static iproc subr1os[] = { + {s_read_line, read_line}, + {0, 0}}; + +static iproc subr2s[] = { + {s_ren_fil, ren_fil}, + {s_access, l_access}, +#ifndef MCH_AMIGA + {s_dup, l_dup}, + {s_dup2, l_dup2}, + {s_mkdir, l_mkdir}, +# ifndef THINK_C + {s_chmod, l_chmod}, +# endif +#endif + {0, 0}}; + +static iproc subr2os[] = { + {s_file_set_pos, file_set_position}, + {s_read_line1, read_line1}, + {s_write_line, l_write_line}, + {0, 0}}; + +void init_ioext() +{ + init_iprocs(subr1os, tc7_subr_1o); + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(subr2os, tc7_subr_2o); + init_iprocs(subr2s, tc7_subr_2); + make_subr(s_reopen_file, tc7_subr_3, reopen_file); +#ifndef THINK_C +# ifndef MCH_AMIGA + make_subr("getpid", tc7_subr_0, l_getpid); + make_subr("getcwd", tc7_subr_0, l_getcwd); +# ifndef vms +# ifndef _WIN32 + make_subr(s_utime, tc7_subr_3, l_utime); + tc16_dir = newsmob(&dir_smob); +# endif +# endif +# endif +#endif +#ifndef __IBMC__ +# ifndef THINK_C +# ifndef __WATCOMC__ +# ifndef GO32 +# ifndef _Windows + make_subr(s_execv, tc7_subr_2, lexecv); + make_subr(s_execvp, tc7_subr_2, lexecvp); + make_subr("execl", tc7_lsubr_2, lexec); + make_subr("execlp", tc7_lsubr_2, lexecp); + make_subr(s_putenv, tc7_subr_1, l_putenv); +# endif +# endif +# endif +# endif +#endif + add_feature("i/o-extensions"); + add_feature("line-i/o"); +} diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..0e29377 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,35 @@ +#!/bin/sh +# Make directory hierarchy. +# Written by Noah Friedman <friedman@prep.ai.mit.edu> +# Public domain. + +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +errstatus=0 + +for file in ${1+"$@"} ; do + oIFS="${IFS}" + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set - `echo ${file} | sed -e 's@/@%@g' -e 's@^%@/@'` + IFS="${oIFS}" + + pathcomp='' + + for d in ${1+"$@"} ; do + pathcomp="${pathcomp}${d}" + + if test ! -d "${pathcomp}"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "${pathcomp}" || errstatus=$? + fi + + pathcomp="${pathcomp}/" + done +done + +exit $errstatus + +# eof diff --git a/patchlvl.h b/patchlvl.h new file mode 100644 index 0000000..97543ec --- /dev/null +++ b/patchlvl.h @@ -0,0 +1,8 @@ +/* SCMVERSION is a string for the version specifier. The leading + number is the major version number, the letter is the revision ("a" + for alpha release, "b" for beta release, "c", and so on), and the + trailing number is the patchlevel. */ + +#ifndef SCMVERSION +# define SCMVERSION "4e6" +#endif @@ -0,0 +1,78 @@ +/* Copyright (C) 1991 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "pi.c", program for computing digits of numerical value of PI. + Author: Aubrey Jaffer + +pi <n> <d> prints out <n> digits of pi in groups of <d> digits. + +'Spigot' algorithm origionally due to Stanly Rabinowitz. +This algorithm takes time proportional to the square of <n>/<d>. +This fact can make comparisons of computational speed between systems +of vastly differring performances quicker and more accurate. + +Try: pi 100 5 +The digit size <d> will have to be reduced for larger <n> or an +error due to overflow will occur. */ + +short *calloc(); +main(c,v) +int c;char **v;{ + int n=200,j=0,m,b=2,k=0,t,r=1,d=5; + long q; + short *a; + if(c>1)n=atoi(v[1]); + if(c>2)d=atoi(v[2]); + while(k++<d)r=r*10; + n=n/d+1; + k=m=3.322*n*d; + a=calloc(1+m,2); + while(k)a[--k]=2; + for(a[m]=4;j<n;b=q%r){ + q=0; + for(k=m;k;){ + q+=a[k]*r; + t=(2*k+1); + a[k]=q%t; + q=q/t; + q*=k--;} + printf("%0*d%s",d,b+q/r,++j%10?" ":"\n");} + puts("");} @@ -0,0 +1,165 @@ +;; Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc. +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this software; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;; As a special exception, the Free Software Foundation gives permission +;; for additional uses of the text contained in its release of GUILE. +;; +;; The exception is that, if you link the GUILE library with other files +;; to produce an executable, this does not by itself cause the +;; resulting executable to be covered by the GNU General Public License. +;; Your use of that executable is in no way restricted on account of +;; linking the GUILE library code into it. +;; +;; This exception does not however invalidate any other reasons why +;; the executable file might be covered by the GNU General Public License. +;; +;; This exception applies only to the code released by the +;; Free Software Foundation under the name GUILE. If you copy +;; code from other Free Software Foundation releases into a copy of +;; GUILE, as the General Public License permits, the exception does +;; not apply to the code that you add in this way. To avoid misleading +;; anyone as to the status of such modified files, you must delete +;; this exception notice from them. +;; +;; If you write modifications of your own for GUILE, it is your choice +;; whether to permit this exception to apply to your modifications. +;; If you do not wish that, delete this exception notice. + +;;;; "pi.scm", program for computing digits of numerical value of PI. +;;;; "bigpi.scm", program for computing digits of numerical value of PI. +;;;; "e.scm", program for computing digits of numerical value of 'e'. +;;; Authors: Aubrey Jaffer & Jerry D. Hedden + +;;; (pi <n> <d>) prints out <n> digits of pi in groups of <d> digits. + +;;; 'Spigot' algorithm origionally due to Stanly Rabinowitz. +;;; This algorithm takes time proportional to the square of <n>/<d>. +;;; This fact can make comparisons of computational speed between systems +;;; of vastly differring performances quicker and more accurate. + +;;; Try (pi 100 5) +;;; The digit size <d> will have to be reduced for larger <n> or an +;;; overflow error will occur (on systems lacking bignums). + +;;; It your Scheme has bignums try (pi 1000). + +(define (pi n . args) + (if (null? args) (bigpi n) + (let* ((d (car args)) + (r (do ((s 1 (* 10 s)) + (i d (- i 1))) + ((zero? i) s))) + (n (+ (quotient n d) 1)) + (m (quotient (* n d 3322) 1000)) + (a (make-vector (+ 1 m) 2))) + (vector-set! a m 4) + (do ((j 1 (+ 1 j)) + (q 0 0) + (b 2 (remainder q r))) + ((> j n)) + (do ((k m (- k 1))) + ((zero? k)) + (set! q (+ q (* (vector-ref a k) r))) + (let ((t (+ 1 (* 2 k)))) + (vector-set! a k (remainder q t)) + (set! q (* k (quotient q t))))) + (let ((s (number->string (+ b (quotient q r))))) + (do ((l (string-length s) (+ 1 l))) + ((>= l d) (display s)) + (display #\0))) + (if (zero? (modulo j 10)) (newline) (display #\ ))) + (newline)))) + +;;; (pi <n>) prints out <n> digits of pi. + +;;; 'Spigot' algorithm originally due to Stanly Rabinowitz: +;;; +;;; PI = 2+(1/3)*(2+(2/5)*(2+(3/7)*(2+ ... *(2+(k/(2k+1))*(4)) ... ))) +;;; +;;; where 'k' is approximately equal to the desired precision of 'n' +;;; places times 'log2(10)'. +;;; +;;; This version takes advantage of "bignums" in SCM to compute all +;;; of the requested digits in one pass! Basically, it calculates +;;; the truncated portion of (PI * 10^n), and then displays it in a +;;; nice format. + +(define (bigpi digits) + (let* ((n (* 10 (quotient (+ digits 9) 10))) ; digits in multiples of 10 + (z (inexact->exact (truncate ; z = number of terms + (/ (* n (log 10)) (log 2))))) + (q (do ((x 2 (* 10000000000 x)) ; q = 2 * 10^n + (i (/ n 10) (- i 1))) + ((zero? i) x))) + (_pi (number->string ; _pi = PI * 10^n + ;; do the calculations in one pass!!! + (let pi_calc ((j z) (k (+ z z 1)) (p (+ q q))) + (if (zero? j) + p + (pi_calc (- j 1) (- k 2) (+ q (quotient (* p j) k)))))))) + ;; print out the result ("3." followed by 5 groups of 10 digits per line) + (display (substring _pi 0 1)) (display #\.) (newline) + (do ((i 0 (+ i 10))) + ((>= i n)) + (display (substring _pi (+ i 1) (+ i 11))) + (display (if (zero? (modulo (+ i 10) 50)) #\newline #\ ))) + (if (not (zero? (modulo n 50))) (newline)))) + +;;; (e <n>) prints out <n> digits of 'e'. + +;;; Uses the formula: +;;; +;;; 1 1 1 1 1 +;;; e = 1 + -- + -- + -- + -- + ... + -- +;;; 1! 2! 3! 4! k! +;;; +;;; where 'k' is determined using the desired precision 'n' in: +;;; +;;; n < ((k * (ln(k) - 1)) / ln(10)) +;;; +;;; which uses Stirling's formula for approximating ln(k!) +;;; +;;; This program takes advantage of "bignums" in SCM to compute all +;;; the requested digits at once! Basically, it calculates the +;;; fractional part of 'e' (i.e., e-2) as a fraction of two bignums +;;; 'e_n' and 'e_d', determines the integer part of (e_n * 10^n)/e_d, +;;; and then displays it in a nice format. + +(define (e digits) + (let* ((n (* 10 (quotient (+ digits 9) 10))) ; digits in multiples of 10 + (k (do ((i 15 (+ i 1))) ; k = number of terms + ((< n (/ (* i (- (log i) 1)) (log 10))) i))) + (q (do ((x 1 (* 10000000000 x)) ; q = 10^n + (i (/ n 10) (- i 1))) + ((zero? i) x))) + (_e (let ((ee + ; do calculations + (let e_calc ((i k) (e_d 1) (e_n 0)) + (if (= i 1) + (cons (* q e_n) e_d) + (e_calc (- i 1) (* e_d i) (+ e_n e_d)))))) + (number->string (+ (quotient (car ee) (cdr ee)) + ; rounding + (if (< (remainder (car ee) (cdr ee)) + (quotient (cdr ee) 2)) + 0 1)))))) + ;; print out the result ("2." followed by 5 groups of 10 digits per line) + (display "2.") (newline) + (do ((i 0 (+ i 10))) + ((>= i n)) + (display (substring _e i (+ i 10))) + (display (if (zero? (modulo (+ i 10) 50)) #\newline #\ ))) + (if (not (zero? (modulo n 50))) (newline)))) @@ -0,0 +1,408 @@ +/* Copyright (C) 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "posix.c" functions only in Posix (unix). + Author: Aubrey Jaffer */ + +#include "scm.h" + +#include <pwd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#ifndef STDC_HEADERS + char *ttyname P((int fd)); + FILE *popen P((const char* command, const char* type)); + int pclose P((FILE* stream)); +#endif + + /* Only the superuser can successfully execute this call */ +static char s_chown[] = "chown"; +SCM l_chown(path, owner, group) + SCM path, owner, group; +{ + int val; + ASSERT(NIMP(path) && STRINGP(path), path, ARG1, s_chown); + ASSERT(INUMP(owner), owner, ARG2, s_chown); + ASSERT(INUMP(group), group, ARG3, s_chown); + SYSCALL(val = chown(CHARS(path), INUM(owner), INUM(group));); + return val ? BOOL_F : BOOL_T; +} + +static char s_link[] = "link"; +SCM l_link(oldpath, newpath) + SCM oldpath, newpath; +{ + int val; + ASSERT(NIMP(oldpath) && STRINGP(oldpath), oldpath, ARG1, s_link); + ASSERT(NIMP(newpath) && STRINGP(newpath), newpath, ARG2, s_link); + SYSCALL(val = link(CHARS(oldpath), CHARS(newpath));); + return val ? BOOL_F : BOOL_T; +} + +SCM l_pipe() +{ + int fd[2], ret; + FILE *f_rd, *f_wt; + SCM p_rd, p_wt; + NEWCELL(p_rd); NEWCELL(p_wt); + SYSCALL(ret = pipe(fd);); + if (ret) {ALLOW_INTS; return BOOL_F;} + SYSCALL(f_rd = fdopen(fd[0], "r");); + if (!f_rd) { + close(fd[0]); + goto errout; + } + SYSCALL(f_wt = fdopen(fd[1], "w");); + if (!f_wt) { + fclose(f_rd); + errout: + close(fd[1]); + wta(UNDEFINED, (char *)NALLOC, s_port_type); + } + CAR(p_rd) = tc16_fport | mode_bits("r"); + CAR(p_wt) = tc16_fport | mode_bits("w"); + SETSTREAM(p_rd, f_rd); + SETSTREAM(p_wt, f_wt); + ALLOW_INTS; + return cons(p_rd, p_wt); +} + +char s_op_pipe[] = "open-pipe"; +SCM open_pipe(pipestr, modes) + SCM pipestr, modes; +{ + FILE *f; + register SCM z; + ASSERT(NIMP(pipestr) && STRINGP(pipestr), pipestr, ARG1, s_op_pipe); + ASSERT(NIMP(modes) && STRINGP(modes), modes, ARG2, s_op_pipe); + NEWCELL(z); + /* DEFER_INTS, SYSCALL, and ALLOW_INTS are probably paranoid here*/ + DEFER_INTS; + ignore_signals(); + SYSCALL(f = popen(CHARS(pipestr), CHARS(modes));); + unignore_signals(); + if (!f) z = BOOL_F; + else { + CAR(z) = tc16_pipe | OPN | (strchr(CHARS(modes), 'r') ? RDNG : WRTNG); + SETSTREAM(z, f); + } + ALLOW_INTS; + return z; +} +SCM l_open_input_pipe(pipestr) + SCM pipestr; +{ + return open_pipe(pipestr, makfromstr("r", (sizeof "r")-1)); +} +SCM l_open_output_pipe(pipestr) + SCM pipestr; +{ + return open_pipe(pipestr, makfromstr("w", (sizeof "w")-1)); +} +static int prinpipe(exp, port, writing) + SCM exp; SCM port; int writing; +{ + prinport(exp, port, s_pipe); + return !0; +} + +static char scm_s_getgroups[] = "getgroups"; +SCM scm_getgroups() +{ + SCM grps, ans; + int ngroups = getgroups(NULL, 0); + if (!ngroups) return BOOL_F; + NEWCELL(grps); + DEFER_INTS; + { + gid_t *groups = (gid_t *)must_malloc(ngroups * sizeof(gid_t), + scm_s_getgroups); + int val = getgroups(ngroups, groups); + if (val < 0) { + must_free(groups); + ALLOW_INTS; + return BOOL_F; + } + SETCHARS(grps, groups); /* set up grps as a GC protect */ + SETLENGTH(grps, 0L + ngroups * sizeof(gid_t), tc7_string); + ALLOW_INTS; + ans = make_vector(MAKINUM(ngroups), UNDEFINED); + while (--ngroups >= 0) VELTS(ans)[ngroups] = MAKINUM(groups[ngroups]); + SETCHARS(grps, groups); /* to make sure grps stays around. */ + return ans; + } +} + +/* These 2 routines are not protected against `entry' being reused + before access to that structure is completed */ + +static char s_pwinfo[] = "getpw"; +SCM l_pwinfo(user) + SCM user; +{ + SCM ans = make_vector(MAKINUM(7), UNSPECIFIED); + struct passwd *entry; + SCM *ve = VELTS(ans); + DEFER_INTS; + if UNBNDP(user) SYSCALL(entry = getpwent();); + else if INUMP(user) SYSCALL(entry = getpwuid(INUM(user));); + else { + ASSERT(NIMP(user) && STRINGP(user), user, ARG1, s_pwinfo); + SYSCALL(entry = getpwnam(CHARS(user));); + } + ALLOW_INTS; + if (!entry) return BOOL_F; + ve[ 0] = makfrom0str(entry->pw_name); + ve[ 1] = makfrom0str(entry->pw_passwd); + ve[ 2] = ulong2num((unsigned long)entry->pw_uid); + ve[ 3] = ulong2num((unsigned long)entry->pw_gid); + ve[ 4] = makfrom0str(entry->pw_gecos); + ve[ 5] = makfrom0str(entry->pw_dir); + ve[ 6] = makfrom0str(entry->pw_shell); + return ans; +} +#include <grp.h> +static char s_grinfo[] = "getgr"; +SCM l_grinfo(name) + SCM name; +{ + SCM ans = make_vector(MAKINUM(4), UNSPECIFIED); + struct group *entry; + SCM *ve = VELTS(ans); + DEFER_INTS; + if UNBNDP(name) SYSCALL(entry = getgrent();); + else if INUMP(name) SYSCALL(entry = getgrgid(INUM(name));); + else { + ASSERT(NIMP(name) && STRINGP(name), name, ARG1, s_grinfo); + SYSCALL(entry = getgrnam(CHARS(name));); + } + ALLOW_INTS; + if (!entry) return BOOL_F; + ve[ 0] = makfrom0str(entry->gr_name); + ve[ 1] = makfrom0str(entry->gr_passwd); + ve[ 2] = ulong2num((unsigned long)entry->gr_gid); + ve[ 3] = makfromstrs(-1, entry->gr_mem); + return ans; +} +SCM l_setgr(arg) + SCM arg; +{ + if (UNBNDP(arg) || FALSEP(arg)) endgrent(); + else setgrent(); + return UNSPECIFIED; +} +SCM l_setpw(arg) + SCM arg; +{ + if (UNBNDP(arg) || FALSEP(arg)) endpwent(); + else setpwent(); + return UNSPECIFIED; +} + +static char s_kill[] = "kill"; +SCM l_kill(pid, sig) + SCM pid, sig; +{ + int i; + ASSERT(INUMP(pid), pid, ARG1, s_kill); + ASSERT(INUMP(sig), sig, ARG2, s_kill); + SYSCALL(i = kill((int)INUM(pid), (int)INUM(sig));); + return MAKINUM(0L+i); +} +static char s_waitpid[] = "waitpid"; +SCM l_waitpid(pid, options) + SCM pid, options; +{ + int i, status; + ASSERT(INUMP(pid), pid, ARG1, s_waitpid); + ASSERT(INUMP(options), options, ARG2, s_waitpid); + SYSCALL(i = waitpid(INUM(pid), &status, INUM(options));); + return i < 0 ? BOOL_F : MAKINUM(0L+status); +} + +SCM l_getppid() +{ + return MAKINUM(0L+getppid()); +} + +SCM l_getuid() +{ + return MAKINUM(0L+getuid()); +} +SCM l_getgid() +{ + return MAKINUM(0L+getgid()); +} +#ifndef LACK_E_IDs +SCM l_geteuid() +{ + return MAKINUM(0L+geteuid()); +} +SCM l_getegid() +{ + return MAKINUM(0L+getegid()); +} +#endif + +static char s_setuid[] = "setuid"; +SCM l_setuid(id) + SCM id; +{ + ASSERT(INUMP(id), id, ARG1, s_setuid); + return setuid(INUM(id)) ? BOOL_F : BOOL_T; +} +static char s_setgid[] = "setgid"; +SCM l_setgid(id) + SCM id; +{ + ASSERT(INUMP(id), id, ARG1, s_setgid); + return setgid(INUM(id)) ? BOOL_F : BOOL_T; +} + +#ifndef LACK_E_IDs +static char s_seteuid[] = "seteuid"; +SCM l_seteuid(id) + SCM id; +{ + ASSERT(INUMP(id), id, ARG1, s_seteuid); + return seteuid(INUM(id)) ? BOOL_F : BOOL_T; +} +static char s_setegid[] = "setegid"; +SCM l_setegid(id) + SCM id; +{ + ASSERT(INUMP(id), id, ARG1, s_setegid); + return setegid(INUM(id)) ? BOOL_F : BOOL_T; +} +#endif + +static char s_ttyname[] = "ttyname"; +SCM l_ttyname(port) + SCM port; +{ + char *ans; + ASSERT(NIMP(port) && OPPORTP(port), port, ARG1, s_ttyname); + if (tc16_fport != TYP16(port)) return BOOL_F; + SYSCALL(ans = ttyname(fileno(STREAM(port)));); + /* ans could be overwritten by another call to ttyname */ + return ans ? makfrom0str(ans) : BOOL_F; +} + +SCM l_fork() +{ + long pid = 0L + fork(); + return -1L==pid ? BOOL_F : MAKINUM(pid); +} + +#include <sys/utsname.h> +SCM l_uname() +{ + struct utsname buf; + SCM ans = make_vector(MAKINUM(5), UNSPECIFIED); + SCM *ve = VELTS(ans); + if (uname(&buf)) return BOOL_F; + ve[ 0] = makfrom0str(buf.sysname); + ve[ 1] = makfrom0str(buf.nodename); + ve[ 2] = makfrom0str(buf.release); + ve[ 3] = makfrom0str(buf.version); + ve[ 4] = makfrom0str(buf.machine); + /* ve[ 5] = makfrom0str(buf.domainname); */ + return ans; +} + +static iproc subr0s[] = { + {"pipe", l_pipe}, + {scm_s_getgroups, scm_getgroups}, + {"getppid", l_getppid}, + {"getuid", l_getuid}, + {"getgid", l_getgid}, +#ifndef LACK_E_IDs + {"getegid", l_getegid}, + {"geteuid", l_geteuid}, +#endif + {"uname", l_uname}, + {"fork", l_fork}, + {0, 0}}; + +static iproc subr1os[] = { + {s_pwinfo, l_pwinfo}, + {s_grinfo, l_grinfo}, + {"setpwent", l_setpw}, + {"setgrent", l_setgr}, + {0, 0}}; + +static iproc subr1s[] = { + {"setuid", l_setuid}, + {"setgid", l_setgid}, +#ifndef LACK_E_IDs + {"setegid", l_setegid}, + {"seteuid", l_seteuid}, +#endif + {"open-input-pipe", l_open_input_pipe}, + {"open-output-pipe", l_open_output_pipe}, + {s_ttyname, l_ttyname}, + {0, 0}}; + +static iproc subr2s[] = { + {s_link, l_link}, + {s_kill, l_kill}, + {s_waitpid, l_waitpid}, + {s_op_pipe, open_pipe}, + {0, 0}}; + +static iproc subr3s[] = { + {s_chown, l_chown}, + {0, 0}}; + +void init_posix() +{ + init_iprocs(subr0s, tc7_subr_0); + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(subr1os, tc7_subr_1o); + init_iprocs(subr2s, tc7_subr_2); + init_iprocs(subr3s, tc7_subr_3); + add_feature("posix"); + ptobs[0x0ff & (tc16_pipe>>8)].fclose = pclose; + ptobs[0x0ff & (tc16_pipe>>8)].free = pclose; + ptobs[0x0ff & (tc16_pipe>>8)].print = prinpipe; + add_feature(s_pipe); +} diff --git a/pre-crt0.c b/pre-crt0.c new file mode 100644 index 0000000..67fd31c --- /dev/null +++ b/pre-crt0.c @@ -0,0 +1,9 @@ +/* This file is loaded before crt0.o on machines where we do not + remap part of the data space into text space in unexec. + On these machines, there is no problem with standard crt0.o's + that make environ an initialized variable. However, we do + need to make sure the label data_start exists anyway. */ + +/* Create a label to appear at the beginning of data space. */ + +int data_start = 0; diff --git a/r4rstest.scm b/r4rstest.scm new file mode 100644 index 0000000..6573e20 --- /dev/null +++ b/r4rstest.scm @@ -0,0 +1,1038 @@ +;; Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +;; +;; This program is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by the +;; Free Software Foundation; either version 2, or (at your option) any +;; later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; To receive a copy of the GNU General Public License, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA; or view +;; http://www-swiss.ai.mit.edu/~jaffer/GPL.html + +;;;; "r4rstest.scm" Test correctness of scheme implementations. +;;; Author: Aubrey Jaffer + +;;; This includes examples from +;;; William Clinger and Jonathan Rees, editors. +;;; Revised^4 Report on the Algorithmic Language Scheme +;;; and the IEEE specification. + +;;; The input tests read this file expecting it to be named "r4rstest.scm". +;;; Files `tmp1', `tmp2' and `tmp3' will be created in the course of running +;;; these tests. You may need to delete them in order to run +;;; "r4rstest.scm" more than once. + +;;; There are three optional tests: +;;; (TEST-CONT) tests multiple returns from call-with-current-continuation +;;; +;;; (TEST-SC4) tests procedures required by R4RS but not by IEEE +;;; +;;; (TEST-DELAY) tests DELAY and FORCE, which are not required by +;;; either standard. + +;;; If you are testing a R3RS version which does not have `list?' do: +;;; (define list? #f) + +;;; send corrections or additions to jaffer@ai.mit.edu + +(define cur-section '())(define errs '()) +(define SECTION (lambda args + (display "SECTION") (write args) (newline) + (set! cur-section args) #t)) +(define record-error (lambda (e) (set! errs (cons (list cur-section e) errs)))) + +(define test + (lambda (expect fun . args) + (write (cons fun args)) + (display " ==> ") + ((lambda (res) + (write res) + (newline) + (cond ((not (equal? expect res)) + (record-error (list res expect (cons fun args))) + (display " BUT EXPECTED ") + (write expect) + (newline) + #f) + (else #t))) + (if (procedure? fun) (apply fun args) (car args))))) +(define (report-errs) + (newline) + (if (null? errs) (display "Passed all tests") + (begin + (display "errors were:") + (newline) + (display "(SECTION (got expected (call)))") + (newline) + (for-each (lambda (l) (write l) (newline)) + errs))) + (newline)) + +(SECTION 2 1);; test that all symbol characters are supported. +'(+ - ... !.. $.+ %.- &.! *.: /:. :+. <-. =. >. ?. ~. _. ^.) + +(SECTION 3 4) +(define disjoint-type-functions + (list boolean? char? null? number? pair? procedure? string? symbol? vector?)) +(define type-examples + (list + #t #f #\a '() 9739 '(test) record-error "test" "" 'test '#() '#(a b c) )) +(define i 1) +(for-each (lambda (x) (display (make-string i #\ )) + (set! i (+ 3 i)) + (write x) + (newline)) + disjoint-type-functions) +(define type-matrix + (map (lambda (x) + (let ((t (map (lambda (f) (f x)) disjoint-type-functions))) + (write t) + (write x) + (newline) + t)) + type-examples)) +(set! i 0) +(define j 0) +(for-each (lambda (x y) + (set! j (+ 1 j)) + (set! i 0) + (for-each (lambda (f) + (set! i (+ 1 i)) + (cond ((and (= i j)) + (cond ((not (f x))) (test #t f x))) + ((f x) (test #f f x))) + (cond ((and (= i j)) + (cond ((not (f y))) (test #t f y))) + ((f y) (test #f f y)))) + disjoint-type-functions)) + (list #t #\a '() 9739 '(test) record-error "test" 'car '#(a b c)) + (list #f #\newline '() -3252 '(t . t) car "" 'nil '#())) +(SECTION 4 1 2) +(test '(quote a) 'quote (quote 'a)) +(test '(quote a) 'quote ''a) +(SECTION 4 1 3) +(test 12 (if #f + *) 3 4) +(SECTION 4 1 4) +(test 8 (lambda (x) (+ x x)) 4) +(define reverse-subtract + (lambda (x y) (- y x))) +(test 3 reverse-subtract 7 10) +(define add4 + (let ((x 4)) + (lambda (y) (+ x y)))) +(test 10 add4 6) +(test '(3 4 5 6) (lambda x x) 3 4 5 6) +(test '(5 6) (lambda (x y . z) z) 3 4 5 6) +(SECTION 4 1 5) +(test 'yes 'if (if (> 3 2) 'yes 'no)) +(test 'no 'if (if (> 2 3) 'yes 'no)) +(test '1 'if (if (> 3 2) (- 3 2) (+ 3 2))) +(SECTION 4 1 6) +(define x 2) +(test 3 'define (+ x 1)) +(set! x 4) +(test 5 'set! (+ x 1)) +(SECTION 4 2 1) +(test 'greater 'cond (cond ((> 3 2) 'greater) + ((< 3 2) 'less))) +(test 'equal 'cond (cond ((> 3 3) 'greater) + ((< 3 3) 'less) + (else 'equal))) +(test 2 'cond (cond ((assv 'b '((a 1) (b 2))) => cadr) + (else #f))) +(test 'composite 'case (case (* 2 3) + ((2 3 5 7) 'prime) + ((1 4 6 8 9) 'composite))) +(test 'consonant 'case (case (car '(c d)) + ((a e i o u) 'vowel) + ((w y) 'semivowel) + (else 'consonant))) +(test #t 'and (and (= 2 2) (> 2 1))) +(test #f 'and (and (= 2 2) (< 2 1))) +(test '(f g) 'and (and 1 2 'c '(f g))) +(test #t 'and (and)) +(test #t 'or (or (= 2 2) (> 2 1))) +(test #t 'or (or (= 2 2) (< 2 1))) +(test #f 'or (or #f #f #f)) +(test #f 'or (or)) +(test '(b c) 'or (or (memq 'b '(a b c)) (+ 3 0))) +(SECTION 4 2 2) +(test 6 'let (let ((x 2) (y 3)) (* x y))) +(test 35 'let (let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) (* z x)))) +(test 70 'let* (let ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x)))) +(test #t 'letrec (letrec ((even? + (lambda (n) (if (zero? n) #t (odd? (- n 1))))) + (odd? + (lambda (n) (if (zero? n) #f (even? (- n 1)))))) + (even? 88))) +(define x 34) +(test 5 'let (let ((x 3)) (define x 5) x)) +(test 34 'let x) +(test 6 'let (let () (define x 6) x)) +(test 34 'let x) +(test 7 'let* (let* ((x 3)) (define x 7) x)) +(test 34 'let* x) +(test 8 'let* (let* () (define x 8) x)) +(test 34 'let* x) +(test 9 'letrec (letrec () (define x 9) x)) +(test 34 'letrec x) +(test 10 'letrec (letrec ((x 3)) (define x 10) x)) +(test 34 'letrec x) +(SECTION 4 2 3) +(define x 0) +(test 6 'begin (begin (set! x 5) (+ x 1))) +(SECTION 4 2 4) +(test '#(0 1 2 3 4) 'do (do ((vec (make-vector 5)) + (i 0 (+ i 1))) + ((= i 5) vec) + (vector-set! vec i i))) +(test 25 'do (let ((x '(1 3 5 7 9))) + (do ((x x (cdr x)) + (sum 0 (+ sum (car x)))) + ((null? x) sum)))) +(test 1 'let (let foo () 1)) +(test '((6 1 3) (-5 -2)) 'let + (let loop ((numbers '(3 -2 1 6 -5)) + (nonneg '()) + (neg '())) + (cond ((null? numbers) (list nonneg neg)) + ((negative? (car numbers)) + (loop (cdr numbers) + nonneg + (cons (car numbers) neg))) + (else + (loop (cdr numbers) + (cons (car numbers) nonneg) + neg))))) +(SECTION 4 2 6) +(test '(list 3 4) 'quasiquote `(list ,(+ 1 2) 4)) +(test '(list a (quote a)) 'quasiquote (let ((name 'a)) `(list ,name ',name))) +(test '(a 3 4 5 6 b) 'quasiquote `(a ,(+ 1 2) ,@(map abs '(4 -5 6)) b)) +(test '((foo 7) . cons) + 'quasiquote + `((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons)))) + +;;; sqt is defined here because not all implementations are required to +;;; support it. +(define (sqt x) + (do ((i 0 (+ i 1))) + ((> (* i i) x) (- i 1)))) + +(test '#(10 5 2 4 3 8) 'quasiquote `#(10 5 ,(sqt 4) ,@(map sqt '(16 9)) 8)) +(test 5 'quasiquote `,(+ 2 3)) +(test '(a `(b ,(+ 1 2) ,(foo 4 d) e) f) + 'quasiquote `(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)) +(test '(a `(b ,x ,'y d) e) 'quasiquote + (let ((name1 'x) (name2 'y)) `(a `(b ,,name1 ,',name2 d) e))) +(test '(list 3 4) 'quasiquote (quasiquote (list (unquote (+ 1 2)) 4))) +(test '`(list ,(+ 1 2) 4) 'quasiquote '(quasiquote (list (unquote (+ 1 2)) 4))) +(SECTION 5 2 1) +(define add3 (lambda (x) (+ x 3))) +(test 6 'define (add3 3)) +(define first car) +(test 1 'define (first '(1 2))) +(define old-+ +) +(define + (lambda (x y) (list y x))) +(test '(3 6) add3 6) +(set! + old-+) +(test 9 add3 6) +(SECTION 5 2 2) +(test 45 'define + (let ((x 5)) + (define foo (lambda (y) (bar x y))) + (define bar (lambda (a b) (+ (* a b) a))) + (foo (+ x 3)))) +(define x 34) +(define (foo) (define x 5) x) +(test 5 foo) +(test 34 'define x) +(define foo (lambda () (define x 5) x)) +(test 5 foo) +(test 34 'define x) +(define (foo x) ((lambda () (define x 5) x)) x) +(test 88 foo 88) +(test 4 foo 4) +(test 34 'define x) +(SECTION 6 1) +(test #f not #t) +(test #f not 3) +(test #f not (list 3)) +(test #t not #f) +(test #f not '()) +(test #f not (list)) +(test #f not 'nil) + +;(test #t boolean? #f) +;(test #f boolean? 0) +;(test #f boolean? '()) +(SECTION 6 2) +(test #t eqv? 'a 'a) +(test #f eqv? 'a 'b) +(test #t eqv? 2 2) +(test #t eqv? '() '()) +(test #t eqv? '10000 '10000) +(test #f eqv? (cons 1 2)(cons 1 2)) +(test #f eqv? (lambda () 1) (lambda () 2)) +(test #f eqv? #f 'nil) +(let ((p (lambda (x) x))) + (test #t eqv? p p)) +(define gen-counter + (lambda () + (let ((n 0)) + (lambda () (set! n (+ n 1)) n)))) +(let ((g (gen-counter))) (test #t eqv? g g)) +(test #f eqv? (gen-counter) (gen-counter)) +(letrec ((f (lambda () (if (eqv? f g) 'f 'both))) + (g (lambda () (if (eqv? f g) 'g 'both)))) + (test #f eqv? f g)) + +(test #t eq? 'a 'a) +(test #f eq? (list 'a) (list 'a)) +(test #t eq? '() '()) +(test #t eq? car car) +(let ((x '(a))) (test #t eq? x x)) +(let ((x '#())) (test #t eq? x x)) +(let ((x (lambda (x) x))) (test #t eq? x x)) + +(test #t equal? 'a 'a) +(test #t equal? '(a) '(a)) +(test #t equal? '(a (b) c) '(a (b) c)) +(test #t equal? "abc" "abc") +(test #t equal? 2 2) +(test #t equal? (make-vector 5 'a) (make-vector 5 'a)) +(SECTION 6 3) +(test '(a b c d e) 'dot '(a . (b . (c . (d . (e . ())))))) +(define x (list 'a 'b 'c)) +(define y x) +(and list? (test #t list? y)) +(set-cdr! x 4) +(test '(a . 4) 'set-cdr! x) +(test #t eqv? x y) +(test '(a b c . d) 'dot '(a . (b . (c . d)))) +(and list? (test #f list? y)) +(and list? (let ((x (list 'a))) (set-cdr! x x) (test #f 'list? (list? x)))) + +;(test #t pair? '(a . b)) +;(test #t pair? '(a . 1)) +;(test #t pair? '(a b c)) +;(test #f pair? '()) +;(test #f pair? '#(a b)) + +(test '(a) cons 'a '()) +(test '((a) b c d) cons '(a) '(b c d)) +(test '("a" b c) cons "a" '(b c)) +(test '(a . 3) cons 'a 3) +(test '((a b) . c) cons '(a b) 'c) + +(test 'a car '(a b c)) +(test '(a) car '((a) b c d)) +(test 1 car '(1 . 2)) + +(test '(b c d) cdr '((a) b c d)) +(test 2 cdr '(1 . 2)) + +(test '(a 7 c) list 'a (+ 3 4) 'c) +(test '() list) + +(test 3 length '(a b c)) +(test 3 length '(a (b) (c d e))) +(test 0 length '()) + +(test '(x y) append '(x) '(y)) +(test '(a b c d) append '(a) '(b c d)) +(test '(a (b) (c)) append '(a (b)) '((c))) +(test '() append) +(test '(a b c . d) append '(a b) '(c . d)) +(test 'a append '() 'a) + +(test '(c b a) reverse '(a b c)) +(test '((e (f)) d (b c) a) reverse '(a (b c) d (e (f)))) + +(test 'c list-ref '(a b c d) 2) + +(test '(a b c) memq 'a '(a b c)) +(test '(b c) memq 'b '(a b c)) +(test '#f memq 'a '(b c d)) +(test '#f memq (list 'a) '(b (a) c)) +(test '((a) c) member (list 'a) '(b (a) c)) +(test '(101 102) memv 101 '(100 101 102)) + +(define e '((a 1) (b 2) (c 3))) +(test '(a 1) assq 'a e) +(test '(b 2) assq 'b e) +(test #f assq 'd e) +(test #f assq (list 'a) '(((a)) ((b)) ((c)))) +(test '((a)) assoc (list 'a) '(((a)) ((b)) ((c)))) +(test '(5 7) assv 5 '((2 3) (5 7) (11 13))) +(SECTION 6 4) +;(test #t symbol? 'foo) +(test #t symbol? (car '(a b))) +;(test #f symbol? "bar") +;(test #t symbol? 'nil) +;(test #f symbol? '()) +;(test #f symbol? #f) +;;; But first, what case are symbols in? Determine the standard case: +(define char-standard-case char-upcase) +(if (string=? (symbol->string 'A) "a") + (set! char-standard-case char-downcase)) +(test #t 'standard-case + (string=? (symbol->string 'a) (symbol->string 'A))) +(test #t 'standard-case + (or (string=? (symbol->string 'a) "A") + (string=? (symbol->string 'A) "a"))) +(define (str-copy s) + (let ((v (make-string (string-length s)))) + (do ((i (- (string-length v) 1) (- i 1))) + ((< i 0) v) + (string-set! v i (string-ref s i))))) +(define (string-standard-case s) + (set! s (str-copy s)) + (do ((i 0 (+ 1 i)) + (sl (string-length s))) + ((>= i sl) s) + (string-set! s i (char-standard-case (string-ref s i))))) +(test (string-standard-case "flying-fish") symbol->string 'flying-fish) +(test (string-standard-case "martin") symbol->string 'Martin) +(test "Malvina" symbol->string (string->symbol "Malvina")) +(test #t 'standard-case (eq? 'a 'A)) + +(define x (string #\a #\b)) +(define y (string->symbol x)) +(string-set! x 0 #\c) +(test "cb" 'string-set! x) +(test "ab" symbol->string y) +(test y string->symbol "ab") + +(test #t eq? 'mISSISSIppi 'mississippi) +(test #f 'string->symbol (eq? 'bitBlt (string->symbol "bitBlt"))) +(test 'JollyWog string->symbol (symbol->string 'JollyWog)) + +(SECTION 6 5 5) +(test #t number? 3) +(test #t complex? 3) +(test #t real? 3) +(test #t rational? 3) +(test #t integer? 3) + +(test #t exact? 3) +(test #f inexact? 3) + +(test #t = 22 22 22) +(test #t = 22 22) +(test #f = 34 34 35) +(test #f = 34 35) +(test #t > 3 -6246) +(test #f > 9 9 -2424) +(test #t >= 3 -4 -6246) +(test #t >= 9 9) +(test #f >= 8 9) +(test #t < -1 2 3 4 5 6 7 8) +(test #f < -1 2 3 4 4 5 6 7) +(test #t <= -1 2 3 4 5 6 7 8) +(test #t <= -1 2 3 4 4 5 6 7) +(test #f < 1 3 2) +(test #f >= 1 3 2) + +(test #t zero? 0) +(test #f zero? 1) +(test #f zero? -1) +(test #f zero? -100) +(test #t positive? 4) +(test #f positive? -4) +(test #f positive? 0) +(test #f negative? 4) +(test #t negative? -4) +(test #f negative? 0) +(test #t odd? 3) +(test #f odd? 2) +(test #f odd? -4) +(test #t odd? -1) +(test #f even? 3) +(test #t even? 2) +(test #t even? -4) +(test #f even? -1) + +(test 38 max 34 5 7 38 6) +(test -24 min 3 5 5 330 4 -24) + +(test 7 + 3 4) +(test '3 + 3) +(test 0 +) +(test 4 * 4) +(test 1 *) + +(test -1 - 3 4) +(test -3 - 3) +(test 7 abs -7) +(test 7 abs 7) +(test 0 abs 0) + +(test 5 quotient 35 7) +(test -5 quotient -35 7) +(test -5 quotient 35 -7) +(test 5 quotient -35 -7) +(test 1 modulo 13 4) +(test 1 remainder 13 4) +(test 3 modulo -13 4) +(test -1 remainder -13 4) +(test -3 modulo 13 -4) +(test 1 remainder 13 -4) +(test -1 modulo -13 -4) +(test -1 remainder -13 -4) +(define (divtest n1 n2) + (= n1 (+ (* n2 (quotient n1 n2)) + (remainder n1 n2)))) +(test #t divtest 238 9) +(test #t divtest -238 9) +(test #t divtest 238 -9) +(test #t divtest -238 -9) + +(test 4 gcd 0 4) +(test 4 gcd -4 0) +(test 4 gcd 32 -36) +(test 0 gcd) +(test 288 lcm 32 -36) +(test 1 lcm) + +;;;;From: fred@sce.carleton.ca (Fred J Kaudel) +;;; Modified by jaffer. +(define (test-inexact) + (define f3.9 (string->number "3.9")) + (define f4.0 (string->number "4.0")) + (define f-3.25 (string->number "-3.25")) + (define f.25 (string->number ".25")) + (define f4.5 (string->number "4.5")) + (define f3.5 (string->number "3.5")) + (define f0.0 (string->number "0.0")) + (define f0.8 (string->number "0.8")) + (define f1.0 (string->number "1.0")) + (define wto write-test-obj) + (define dto display-test-obj) + (define lto load-test-obj) + (newline) + (display ";testing inexact numbers; ") + (newline) + (SECTION 6 5 5) + (test #t inexact? f3.9) + (test #t 'inexact? (inexact? (max f3.9 4))) + (test f4.0 'max (max f3.9 4)) + (test f4.0 'exact->inexact (exact->inexact 4)) + (test (- f4.0) round (- f4.5)) + (test (- f4.0) round (- f3.5)) + (test (- f4.0) round (- f3.9)) + (test f0.0 round f0.0) + (test f0.0 round f.25) + (test f1.0 round f0.8) + (test f4.0 round f3.5) + (test f4.0 round f4.5) + (set! write-test-obj (list f.25 f-3.25));.25 inexact errors less likely. + (set! display-test-obj (list f.25 f-3.25));.3 often has such errors (~10^-13) + (set! load-test-obj (list 'define 'foo (list 'quote write-test-obj))) + (test #t call-with-output-file + "tmp3" + (lambda (test-file) + (write-char #\; test-file) + (display write-test-obj test-file) + (newline test-file) + (write load-test-obj test-file) + (output-port? test-file))) + (check-test-file "tmp3") + (set! write-test-obj wto) + (set! display-test-obj dto) + (set! load-test-obj lto) + (let ((x (string->number "4195835.0")) + (y (string->number "3145727.0"))) + (test #t 'pentium-fdiv-bug (> f1.0 (- x (* (/ x y) y))))) + (report-errs)) + +(define (test-bignum) + (define tb + (lambda (n1 n2) + (= n1 (+ (* n2 (quotient n1 n2)) + (remainder n1 n2))))) + (newline) + (display ";testing bignums; ") + (newline) + (SECTION 6 5 5) + (test 0 modulo 3333333333 3) + (test 0 modulo 3333333333 -3) + (test 0 remainder 3333333333 3) + (test 0 remainder 3333333333 -3) + (test 2 modulo 3333333332 3) + (test -1 modulo 3333333332 -3) + (test 2 remainder 3333333332 3) + (test 2 remainder 3333333332 -3) + (test 1 modulo -3333333332 3) + (test -2 modulo -3333333332 -3) + (test -2 remainder -3333333332 3) + (test -2 remainder -3333333332 -3) + + (test 3 modulo 3 3333333333) + (test 3333333330 modulo -3 3333333333) + (test 3 remainder 3 3333333333) + (test -3 remainder -3 3333333333) + (test -3333333330 modulo 3 -3333333333) + (test -3 modulo -3 -3333333333) + (test 3 remainder 3 -3333333333) + (test -3 remainder -3 -3333333333) + + (test 0 modulo -2177452800 86400) + (test 0 modulo 2177452800 -86400) + (test 0 modulo 2177452800 86400) + (test 0 modulo -2177452800 -86400) + (test #t 'remainder (tb 281474976710655 65535)) + (test #t 'remainder (tb 281474976710654 65535)) + (SECTION 6 5 6) + (test 281474976710655 string->number "281474976710655") + (test "281474976710655" number->string 281474976710655) + (report-errs)) + +(SECTION 6 5 6) +(test "0" number->string 0) +(test "100" number->string 100) +(test "100" number->string 256 16) +(test 100 string->number "100") +(test 256 string->number "100" 16) +(test #f string->number "") +(test #f string->number ".") +(test #f string->number "d") +(test #f string->number "D") +(test #f string->number "i") +(test #f string->number "I") +(test #f string->number "3i") +(test #f string->number "3I") +(test #f string->number "33i") +(test #f string->number "33I") +(test #f string->number "3.3i") +(test #f string->number "3.3I") +(test #f string->number "-") +(test #f string->number "+") + +(SECTION 6 6) +(test #t eqv? '#\ #\Space) +(test #t eqv? #\space '#\Space) +(test #t char? #\a) +(test #t char? #\() +(test #t char? #\ ) +(test #t char? '#\newline) + +(test #f char=? #\A #\B) +(test #f char=? #\a #\b) +(test #f char=? #\9 #\0) +(test #t char=? #\A #\A) + +(test #t char<? #\A #\B) +(test #t char<? #\a #\b) +(test #f char<? #\9 #\0) +(test #f char<? #\A #\A) + +(test #f char>? #\A #\B) +(test #f char>? #\a #\b) +(test #t char>? #\9 #\0) +(test #f char>? #\A #\A) + +(test #t char<=? #\A #\B) +(test #t char<=? #\a #\b) +(test #f char<=? #\9 #\0) +(test #t char<=? #\A #\A) + +(test #f char>=? #\A #\B) +(test #f char>=? #\a #\b) +(test #t char>=? #\9 #\0) +(test #t char>=? #\A #\A) + +(test #f char-ci=? #\A #\B) +(test #f char-ci=? #\a #\B) +(test #f char-ci=? #\A #\b) +(test #f char-ci=? #\a #\b) +(test #f char-ci=? #\9 #\0) +(test #t char-ci=? #\A #\A) +(test #t char-ci=? #\A #\a) + +(test #t char-ci<? #\A #\B) +(test #t char-ci<? #\a #\B) +(test #t char-ci<? #\A #\b) +(test #t char-ci<? #\a #\b) +(test #f char-ci<? #\9 #\0) +(test #f char-ci<? #\A #\A) +(test #f char-ci<? #\A #\a) + +(test #f char-ci>? #\A #\B) +(test #f char-ci>? #\a #\B) +(test #f char-ci>? #\A #\b) +(test #f char-ci>? #\a #\b) +(test #t char-ci>? #\9 #\0) +(test #f char-ci>? #\A #\A) +(test #f char-ci>? #\A #\a) + +(test #t char-ci<=? #\A #\B) +(test #t char-ci<=? #\a #\B) +(test #t char-ci<=? #\A #\b) +(test #t char-ci<=? #\a #\b) +(test #f char-ci<=? #\9 #\0) +(test #t char-ci<=? #\A #\A) +(test #t char-ci<=? #\A #\a) + +(test #f char-ci>=? #\A #\B) +(test #f char-ci>=? #\a #\B) +(test #f char-ci>=? #\A #\b) +(test #f char-ci>=? #\a #\b) +(test #t char-ci>=? #\9 #\0) +(test #t char-ci>=? #\A #\A) +(test #t char-ci>=? #\A #\a) + +(test #t char-alphabetic? #\a) +(test #t char-alphabetic? #\A) +(test #t char-alphabetic? #\z) +(test #t char-alphabetic? #\Z) +(test #f char-alphabetic? #\0) +(test #f char-alphabetic? #\9) +(test #f char-alphabetic? #\space) +(test #f char-alphabetic? #\;) + +(test #f char-numeric? #\a) +(test #f char-numeric? #\A) +(test #f char-numeric? #\z) +(test #f char-numeric? #\Z) +(test #t char-numeric? #\0) +(test #t char-numeric? #\9) +(test #f char-numeric? #\space) +(test #f char-numeric? #\;) + +(test #f char-whitespace? #\a) +(test #f char-whitespace? #\A) +(test #f char-whitespace? #\z) +(test #f char-whitespace? #\Z) +(test #f char-whitespace? #\0) +(test #f char-whitespace? #\9) +(test #t char-whitespace? #\space) +(test #f char-whitespace? #\;) + +(test #f char-upper-case? #\0) +(test #f char-upper-case? #\9) +(test #f char-upper-case? #\space) +(test #f char-upper-case? #\;) + +(test #f char-lower-case? #\0) +(test #f char-lower-case? #\9) +(test #f char-lower-case? #\space) +(test #f char-lower-case? #\;) + +(test #\. integer->char (char->integer #\.)) +(test #\A integer->char (char->integer #\A)) +(test #\a integer->char (char->integer #\a)) +(test #\A char-upcase #\A) +(test #\A char-upcase #\a) +(test #\a char-downcase #\A) +(test #\a char-downcase #\a) +(SECTION 6 7) +(test #t string? "The word \"recursion\\\" has many meanings.") +;(test #t string? "") +(define f (make-string 3 #\*)) +(test "?**" 'string-set! (begin (string-set! f 0 #\?) f)) +(test "abc" string #\a #\b #\c) +(test "" string) +(test 3 string-length "abc") +(test #\a string-ref "abc" 0) +(test #\c string-ref "abc" 2) +(test 0 string-length "") +(test "" substring "ab" 0 0) +(test "" substring "ab" 1 1) +(test "" substring "ab" 2 2) +(test "a" substring "ab" 0 1) +(test "b" substring "ab" 1 2) +(test "ab" substring "ab" 0 2) +(test "foobar" string-append "foo" "bar") +(test "foo" string-append "foo") +(test "foo" string-append "foo" "") +(test "foo" string-append "" "foo") +(test "" string-append) +(test "" make-string 0) +(test #t string=? "" "") +(test #f string<? "" "") +(test #f string>? "" "") +(test #t string<=? "" "") +(test #t string>=? "" "") +(test #t string-ci=? "" "") +(test #f string-ci<? "" "") +(test #f string-ci>? "" "") +(test #t string-ci<=? "" "") +(test #t string-ci>=? "" "") + +(test #f string=? "A" "B") +(test #f string=? "a" "b") +(test #f string=? "9" "0") +(test #t string=? "A" "A") + +(test #t string<? "A" "B") +(test #t string<? "a" "b") +(test #f string<? "9" "0") +(test #f string<? "A" "A") + +(test #f string>? "A" "B") +(test #f string>? "a" "b") +(test #t string>? "9" "0") +(test #f string>? "A" "A") + +(test #t string<=? "A" "B") +(test #t string<=? "a" "b") +(test #f string<=? "9" "0") +(test #t string<=? "A" "A") + +(test #f string>=? "A" "B") +(test #f string>=? "a" "b") +(test #t string>=? "9" "0") +(test #t string>=? "A" "A") + +(test #f string-ci=? "A" "B") +(test #f string-ci=? "a" "B") +(test #f string-ci=? "A" "b") +(test #f string-ci=? "a" "b") +(test #f string-ci=? "9" "0") +(test #t string-ci=? "A" "A") +(test #t string-ci=? "A" "a") + +(test #t string-ci<? "A" "B") +(test #t string-ci<? "a" "B") +(test #t string-ci<? "A" "b") +(test #t string-ci<? "a" "b") +(test #f string-ci<? "9" "0") +(test #f string-ci<? "A" "A") +(test #f string-ci<? "A" "a") + +(test #f string-ci>? "A" "B") +(test #f string-ci>? "a" "B") +(test #f string-ci>? "A" "b") +(test #f string-ci>? "a" "b") +(test #t string-ci>? "9" "0") +(test #f string-ci>? "A" "A") +(test #f string-ci>? "A" "a") + +(test #t string-ci<=? "A" "B") +(test #t string-ci<=? "a" "B") +(test #t string-ci<=? "A" "b") +(test #t string-ci<=? "a" "b") +(test #f string-ci<=? "9" "0") +(test #t string-ci<=? "A" "A") +(test #t string-ci<=? "A" "a") + +(test #f string-ci>=? "A" "B") +(test #f string-ci>=? "a" "B") +(test #f string-ci>=? "A" "b") +(test #f string-ci>=? "a" "b") +(test #t string-ci>=? "9" "0") +(test #t string-ci>=? "A" "A") +(test #t string-ci>=? "A" "a") +(SECTION 6 8) +(test #t vector? '#(0 (2 2 2 2) "Anna")) +;(test #t vector? '#()) +(test '#(a b c) vector 'a 'b 'c) +(test '#() vector) +(test 3 vector-length '#(0 (2 2 2 2) "Anna")) +(test 0 vector-length '#()) +(test 8 vector-ref '#(1 1 2 3 5 8 13 21) 5) +(test '#(0 ("Sue" "Sue") "Anna") 'vector-set + (let ((vec (vector 0 '(2 2 2 2) "Anna"))) + (vector-set! vec 1 '("Sue" "Sue")) + vec)) +(test '#(hi hi) make-vector 2 'hi) +(test '#() make-vector 0) +(test '#() make-vector 0 'a) +(SECTION 6 9) +(test #t procedure? car) +;(test #f procedure? 'car) +(test #t procedure? (lambda (x) (* x x))) +(test #f procedure? '(lambda (x) (* x x))) +(test #t call-with-current-continuation procedure?) +(test 7 apply + (list 3 4)) +(test 7 apply (lambda (a b) (+ a b)) (list 3 4)) +(test 17 apply + 10 (list 3 4)) +(test '() apply list '()) +(define compose (lambda (f g) (lambda args (f (apply g args))))) +(test 30 (compose sqt *) 12 75) + +(test '(b e h) map cadr '((a b) (d e) (g h))) +(test '(5 7 9) map + '(1 2 3) '(4 5 6)) +(test '#(0 1 4 9 16) 'for-each + (let ((v (make-vector 5))) + (for-each (lambda (i) (vector-set! v i (* i i))) + '(0 1 2 3 4)) + v)) +(test -3 call-with-current-continuation + (lambda (exit) + (for-each (lambda (x) (if (negative? x) (exit x))) + '(54 0 37 -3 245 19)) + #t)) +(define list-length + (lambda (obj) + (call-with-current-continuation + (lambda (return) + (letrec ((r (lambda (obj) (cond ((null? obj) 0) + ((pair? obj) (+ (r (cdr obj)) 1)) + (else (return #f)))))) + (r obj)))))) +(test 4 list-length '(1 2 3 4)) +(test #f list-length '(a b . c)) +(test '() map cadr '()) + +;;; This tests full conformance of call-with-current-continuation. It +;;; is a separate test because some schemes do not support call/cc +;;; other than escape procedures. I am indebted to +;;; raja@copper.ucs.indiana.edu (Raja Sooriamurthi) for fixing this +;;; code. The function leaf-eq? compares the leaves of 2 arbitrary +;;; trees constructed of conses. +(define (next-leaf-generator obj eot) + (letrec ((return #f) + (cont (lambda (x) + (recur obj) + (set! cont (lambda (x) (return eot))) + (cont #f))) + (recur (lambda (obj) + (if (pair? obj) + (for-each recur obj) + (call-with-current-continuation + (lambda (c) + (set! cont c) + (return obj))))))) + (lambda () (call-with-current-continuation + (lambda (ret) (set! return ret) (cont #f)))))) +(define (leaf-eq? x y) + (let* ((eot (list 'eot)) + (xf (next-leaf-generator x eot)) + (yf (next-leaf-generator y eot))) + (letrec ((loop (lambda (x y) + (cond ((not (eq? x y)) #f) + ((eq? eot x) #t) + (else (loop (xf) (yf))))))) + (loop (xf) (yf))))) +(define (test-cont) + (newline) + (display ";testing continuations; ") + (newline) + (SECTION 6 9) + (test #t leaf-eq? '(a (b (c))) '((a) b c)) + (test #f leaf-eq? '(a (b (c))) '((a) b c d)) + (report-errs)) + +;;; Test Optional R4RS DELAY syntax and FORCE procedure +(define (test-delay) + (newline) + (display ";testing DELAY and FORCE; ") + (newline) + (SECTION 6 9) + (test 3 'delay (force (delay (+ 1 2)))) + (test '(3 3) 'delay (let ((p (delay (+ 1 2)))) + (list (force p) (force p)))) + (test 2 'delay (letrec ((a-stream + (letrec ((next (lambda (n) + (cons n (delay (next (+ n 1))))))) + (next 0))) + (head car) + (tail (lambda (stream) (force (cdr stream))))) + (head (tail (tail a-stream))))) + (letrec ((count 0) + (p (delay (begin (set! count (+ count 1)) + (if (> count x) + count + (force p))))) + (x 5)) + (test 6 force p) + (set! x 10) + (test 6 force p)) + (test 3 'force + (letrec ((p (delay (if c 3 (begin (set! c #t) (+ (force p) 1))))) + (c #f)) + (force p))) + (report-errs)) + +(SECTION 6 10 1) +(test #t input-port? (current-input-port)) +(test #t output-port? (current-output-port)) +(test #t call-with-input-file "r4rstest.scm" input-port?) +(define this-file (open-input-file "r4rstest.scm")) +(test #t input-port? this-file) +(SECTION 6 10 2) +(test #\; peek-char this-file) +(test #\; read-char this-file) +(test '(define cur-section '()) read this-file) +(test #\( peek-char this-file) +(test '(define errs '()) read this-file) +(close-input-port this-file) +(close-input-port this-file) +(define (check-test-file name) + (define test-file (open-input-file name)) + (test #t 'input-port? + (call-with-input-file + name + (lambda (test-file) + (test load-test-obj read test-file) + (test #t eof-object? (peek-char test-file)) + (test #t eof-object? (read-char test-file)) + (input-port? test-file)))) + (test #\; read-char test-file) + (test display-test-obj read test-file) + (test load-test-obj read test-file) + (close-input-port test-file)) +(SECTION 6 10 3) +(define write-test-obj + '(#t #f #\a () 9739 -3 . #((test) "te \" \" st" "" test #() b c))) +(define display-test-obj + '(#t #f a () 9739 -3 . #((test) te " " st test #() b c))) +(define load-test-obj + (list 'define 'foo (list 'quote write-test-obj))) +(test #t call-with-output-file + "tmp1" + (lambda (test-file) + (write-char #\; test-file) + (display write-test-obj test-file) + (newline test-file) + (write load-test-obj test-file) + (output-port? test-file))) +(check-test-file "tmp1") + +(define test-file (open-output-file "tmp2")) +(write-char #\; test-file) +(display write-test-obj test-file) +(newline test-file) +(write load-test-obj test-file) +(test #t output-port? test-file) +(close-output-port test-file) +(check-test-file "tmp2") +(define (test-sc4) + (newline) + (display ";testing scheme 4 functions; ") + (newline) + (SECTION 6 7) + (test '(#\P #\space #\l) string->list "P l") + (test '() string->list "") + (test "1\\\"" list->string '(#\1 #\\ #\")) + (test "" list->string '()) + (SECTION 6 8) + (test '(dah dah didah) vector->list '#(dah dah didah)) + (test '() vector->list '#()) + (test '#(dididit dah) list->vector '(dididit dah)) + (test '#() list->vector '()) + (SECTION 6 10 4) + (load "tmp1") + (test write-test-obj 'load foo) + (report-errs)) + +(report-errs) +(if (and (string->number "0.0") (inexact? (string->number "0.0"))) + (test-inexact)) + +(let ((n (string->number "281474976710655"))) + (if (and n (exact? n)) + (test-bignum))) +(newline) +(display "To fully test continuations, Scheme 4, and DELAY/FORCE do:") +(newline) +(display "(test-cont) (test-sc4) (test-delay)") +(newline) +"last item in file" @@ -0,0 +1,1677 @@ +/* Copyright (C) 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "ramap.c" Array mapping functions for APL-Scheme. + Author: Radey Shouman */ + +#include "scm.h" + +typedef struct { + char *name; + SCM sproc; + int (* vproc)(); +} ra_iproc; + +# define BVE_REF(a, i) ((VELTS(a)[(i)/LONG_BIT] & (1L<<((i)%LONG_BIT))) ? 1 : 0) +# define BVE_SET(a, i) (VELTS(a)[(i)/LONG_BIT] |= (1L<<((i)%LONG_BIT))) +# define BVE_CLR(a, i) (VELTS(a)[(i)/LONG_BIT] &= ~(1L<<((i)%LONG_BIT))) +/* Fast, recycling vector ref */ +# define RVREF(ra, i, e) (e = cvref(ra, i, e)) +/* #define RVREF(ra, i, e) (cvref(ra, i, UNDEFINED)) to turn off */ + +/* IVDEP means "ignore vector dependencies", meaning we guarantee that + elements of vector operands are not aliased */ +# ifdef _UNICOS +# define IVDEP(test, line) if (test) {_Pragma("ivdep"); line} else {line} +# else +# define IVDEP(test, line) line +# endif + + /* inds must be a uvect or ivect, no check. */ +static sizet cind(ra, inds) + SCM ra, inds; +{ + sizet i; + int k; + long *ve = VELTS(inds); + if (!ARRAYP(ra)) + return *ve; + i = ARRAY_BASE(ra); + for (k = 0; k < ARRAY_NDIM(ra); k++) + i += (ve[k] - ARRAY_DIMS(ra)[k].lbnd)*ARRAY_DIMS(ra)[k].inc; + return i; +} + + /* Checker for array mapping functions: + return values: 4 --> shapes, increments, and bases are the same; + 3 --> shapes and increments are the same; + 2 --> shapes are the same; + 1 --> ras are at least as big as ra0; + 0 --> no match. + */ +int ra_matchp(ra0, ras) + SCM ra0, ras; +{ + SCM ra1; + array_dim dims; + array_dim *s0 = &dims; + array_dim *s1; + sizet bas0 = 0; + int i, ndim = 1; + int exact = 2 /* 4 */; /* Don't care about values >2 (yet?) */ + if IMP(ra0) return 0; + switch TYP7(ra0) { + default: return 0; + case tc7_vector: case tc7_string: case tc7_bvect: case tc7_uvect: + case tc7_ivect: case tc7_fvect: case tc7_dvect: case tc7_cvect: + s0->lbnd = 0; + s0->inc = 1; + s0->ubnd = (long)LENGTH(ra0) - 1; + break; + case tc7_smob: + if (!ARRAYP(ra0)) return 0; + ndim = ARRAY_NDIM(ra0); + s0 = ARRAY_DIMS(ra0); + bas0 = ARRAY_BASE(ra0); + break; + } + while NIMP(ras) { + ra1 = CAR(ras); + switch (IMP(ra1) ? 0 : TYP7(ra1)) { + default: scalar: + CAR(ras) = sc2array(ra1,ra0,EOL); break; + case tc7_vector: case tc7_string: case tc7_bvect: case tc7_uvect: + case tc7_ivect: case tc7_fvect: case tc7_dvect: case tc7_cvect: + if (1 != ndim) return 0; + switch (exact) { + case 4: if (0 != bas0) exact = 3; + case 3: if (1 != s0->inc) exact = 2; + case 2: if ((0==s0->lbnd) && (s0->ubnd==LENGTH(ra1) - 1)) break; + exact = 1; + case 1: if (s0->lbnd < 0 || s0->ubnd >= LENGTH(ra1)) + if (s0->lbnd <= s0->ubnd) return 0; + } + break; + case tc7_smob: + if (!ARRAYP(ra1)) goto scalar; + if (ndim != ARRAY_NDIM(ra1)) + if (0==ARRAY_NDIM(ra1)) + goto scalar; + else + return 0; + s1 = ARRAY_DIMS(ra1); + if (bas0 != ARRAY_BASE(ra1)) exact = 3; + for (i = 0; i < ndim; i++) + switch (exact) { + case 4: case 3: + if (s0[i].inc != s1[i].inc) + exact = 2; + case 2: + if (s0[i].lbnd==s1[i].lbnd && s0[i].ubnd==s1[i].ubnd) + break; + exact = 1; + default: + if (s0[i].lbnd < s1[i].lbnd || s0[i].ubnd > s1[i].ubnd) + if (s0[i].lbnd <= s0[i].ubnd) return 0; + } + break; + } + ras = CDR(ras); + } + return exact; +} + +static char s_ra_mismatch[] = "array shape mismatch"; +int ramapc(cproc, data, ra0, lra, what) + int (*cproc)(); + SCM data, ra0, lra; + char *what; +{ + SCM inds, z; + SCM vra0, ra1, vra1; + SCM lvra, *plvra; + long *vinds; + int k, kmax = (ARRAYP(ra0) ? ARRAY_NDIM(ra0) - 1 : 0); + switch (ra_matchp(ra0, lra)) { + default: + case 0: wta(ra0, s_ra_mismatch, what); + case 2: case 3: case 4: /* Try unrolling arrays */ + if (kmax < 0) goto gencase; + vra0 = (0==kmax ? ra0 : array_contents(ra0, UNDEFINED)); + if IMP(vra0) goto gencase; + if (!ARRAYP(vra0)) { + vra1 = make_ra(1); + ARRAY_BASE(vra1) = 0; + ARRAY_DIMS(vra1)->lbnd = 0; + ARRAY_DIMS(vra1)->ubnd = LENGTH(vra0) - 1; + ARRAY_DIMS(vra1)->inc = 1; + ARRAY_V(vra1) = vra0; + vra0 = vra1; + } + lvra = EOL; + plvra = &lvra; + for (z = lra; NIMP(z); z = CDR(z)) { + vra1 = ra1 = (0==kmax ? CAR(z) : array_contents(CAR(z), UNDEFINED)); + if FALSEP(ra1) goto gencase; + if (!ARRAYP(ra1)) { + vra1 = make_ra(1); + ARRAY_DIMS(vra1)->lbnd = ARRAY_DIMS(vra0)->lbnd; + ARRAY_DIMS(vra1)->ubnd = ARRAY_DIMS(vra0)->ubnd; + ARRAY_BASE(vra1) = 0; + ARRAY_DIMS(vra1)->inc = 1; + ARRAY_V(vra1) = ra1; + } + *plvra = cons(vra1, EOL); + plvra = &CDR(*plvra); + } + return (UNBNDP(data) ? cproc(vra0, lvra) : cproc(vra0, data, lvra)); + case 1: gencase: /* Have to loop over all dimensions. */ + vra0 = make_ra(1); + if ARRAYP(ra0) { + if (kmax < 0) { + ARRAY_DIMS(vra0)->lbnd = 0; + ARRAY_DIMS(vra0)->ubnd = 0; + ARRAY_DIMS(vra0)->inc = 1; + } + else { + ARRAY_DIMS(vra0)->lbnd = ARRAY_DIMS(ra0)[kmax].lbnd; + ARRAY_DIMS(vra0)->ubnd = ARRAY_DIMS(ra0)[kmax].ubnd; + ARRAY_DIMS(vra0)->inc = ARRAY_DIMS(ra0)[kmax].inc; + } + ARRAY_BASE(vra0) = ARRAY_BASE(ra0); + ARRAY_V(vra0) = ARRAY_V(ra0); + } + else { + ARRAY_DIMS(vra0)->lbnd = 0; + ARRAY_DIMS(vra0)->ubnd = LENGTH(ra0) - 1; + ARRAY_DIMS(vra0)->inc = 1; + ARRAY_BASE(vra0) = 0; + ARRAY_V(vra0) = ra0; + ra0 = vra0; + } + lvra = EOL; + plvra = &lvra; + for (z = lra; NIMP(z); z = CDR(z)) { + ra1 = CAR(z); + vra1 = make_ra(1); + ARRAY_DIMS(vra1)->lbnd = ARRAY_DIMS(vra0)->lbnd; + ARRAY_DIMS(vra1)->ubnd = ARRAY_DIMS(vra0)->ubnd; + if ARRAYP(ra1) { + if (kmax >= 0) + ARRAY_DIMS(vra1)->inc = ARRAY_DIMS(ra1)[kmax].inc; + ARRAY_V(vra1) = ARRAY_V(ra1); + } + else { + ARRAY_DIMS(vra1)->inc = 1; + ARRAY_V(vra1) = ra1; + } + *plvra = cons(vra1, EOL); + plvra = &CDR(*plvra); + } + inds = make_uve(ARRAY_NDIM(ra0)+0L, MAKINUM(-1L)); + vinds = (long *)VELTS(inds); + for (k = 0; k <= kmax; k++) + vinds[k] = ARRAY_DIMS(ra0)[k].lbnd; + k = kmax; + do { + if (k==kmax) { + SCM y = lra; + ARRAY_BASE(vra0) = cind(ra0, inds); + for (z = lvra; NIMP(z); z = CDR(z), y = CDR(y)) + ARRAY_BASE(CAR(z)) = cind(CAR(y), inds); + if (0==(UNBNDP(data) ? cproc(vra0, lvra) : cproc(vra0, data, lvra))) + return 0; + k--; + continue; + } + if (vinds[k] < ARRAY_DIMS(ra0)[k].ubnd) { + vinds[k]++; + k++; + continue; + } + vinds[k] = ARRAY_DIMS(ra0)[k].lbnd - 1; + k--; + } while (k >= 0); + return 1; + } +} + +static char s_array_fill[] = "array-fill!"; +SCM array_fill(ra, fill) + SCM ra, fill; +{ + ramapc(rafill, fill, ra, EOL, s_array_fill); + return UNSPECIFIED; +} + +static char s_sarray_copy[] = "serial-array-copy!"; +# define s_array_copy (s_sarray_copy + 7) +static int racp(src, dst) + SCM dst, src; +{ + long n = (ARRAY_DIMS(src)->ubnd - ARRAY_DIMS(src)->lbnd + 1); + long inc_d, inc_s = ARRAY_DIMS(src)->inc; + sizet i_d, i_s = ARRAY_BASE(src); + dst = CAR(dst); + inc_d = ARRAY_DIMS(dst)->inc; + i_d = ARRAY_BASE(dst); + src = ARRAY_V(src); + dst = ARRAY_V(dst); + switch TYP7(dst) { + default: gencase: case tc7_vector: + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + aset(dst, cvref(src, i_s, UNDEFINED), MAKINUM(i_d)); + break; + case tc7_string: if (tc7_string != TYP7(dst)) goto gencase; + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + CHARS(dst)[i_d] = CHARS(src)[i_s]; + break; + case tc7_bvect: if (tc7_bvect != TYP7(dst)) goto gencase; + if (1==inc_d && 1==inc_s && i_s%LONG_BIT==i_d%LONG_BIT && n>=LONG_BIT) { + long *sv = (long *)VELTS(src); + long *dv = (long *)VELTS(dst); + sv += i_s/LONG_BIT; + dv += i_d/LONG_BIT; + if (i_s % LONG_BIT) { /* leading partial word */ + *dv = (*dv & ~(~0L<<(i_s%LONG_BIT))) | (*sv & (~0L<<(i_s%LONG_BIT))); + dv++; + sv++; + n -= LONG_BIT - (i_s % LONG_BIT); + } + IVDEP(src != dst, + for (; n >= LONG_BIT; n -= LONG_BIT, sv++, dv++) + *dv = *sv;) + if (n) /* trailing partial word */ + *dv = (*dv & (~0L<<n)) | (*sv & ~(~0L<<n)); + } + else { + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + if (VELTS(src)[i_s/LONG_BIT] & (1L << (i_s%LONG_BIT))) + VELTS(dst)[i_d/LONG_BIT] |= (1L << (i_d%LONG_BIT)); + else + VELTS(dst)[i_d/LONG_BIT] &= ~(1L << (i_d%LONG_BIT)); + } + break; + case tc7_uvect: + case tc7_ivect: { + long *d = (long *)VELTS(dst), *s = (long *)VELTS(src); + if (TYP7(src)==TYP7(dst)) { + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + d[i_d] = s[i_s];) + } + else if (tc7_ivect==TYP7(dst)) + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + d[i_d] = num2long(cvref(src, i_s, UNDEFINED), + (char *)ARG2, s_array_copy); + else + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + d[i_d] = num2ulong(cvref(src, i_s, UNDEFINED), + (char *)ARG2, s_array_copy); + break; + } +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *d = (float *)VELTS(dst); + float *s = (float *)VELTS(src); + switch TYP7(src) { + default: goto gencase; + case tc7_ivect: case tc7_uvect: + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + d[i_d] = ((long *)s)[i_s]; ) + break; + case tc7_fvect: + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + d[i_d] = s[i_s]; ) + break; + case tc7_dvect: + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + d[i_d] = ((double *)s)[i_s]; ) + break; + } + break; + } +# endif /* SINGLES */ + case tc7_dvect: { + double *d = (double *)VELTS(dst); + double *s = (double *)VELTS(src); + switch TYP7(src) { + default: goto gencase; + case tc7_ivect: case tc7_uvect: + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + d[i_d] = ((long *)s)[i_s]; ) + break; + case tc7_fvect: + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + d[i_d] = ((float *)s)[i_s];) + break; + case tc7_dvect: + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) + d[i_d] = s[i_s];) + break; + } + break; + } + case tc7_cvect: { + double (*d)[2] = (double (*)[2])VELTS(dst); + double (*s)[2] = (double (*)[2])VELTS(src); + switch TYP7(src) { + default: goto gencase; + case tc7_ivect: case tc7_uvect: + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) { + d[i_d][0] = ((long *)s)[i_s]; + d[i_d][1] = 0.0; + }) + break; + case tc7_fvect: + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) { + d[i_d][0] = ((float *)s)[i_s]; + d[i_d][1] = 0.0; + }) + break; + case tc7_dvect: + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) { + d[i_d][0] = ((double *)s)[i_s]; + d[i_d][1] = 0.0; + }) + break; + case tc7_cvect: + IVDEP(src != dst, + for (; n-- > 0; i_s += inc_s, i_d += inc_d) { + d[i_d][0] = s[i_s][0]; + d[i_d][1] = s[i_s][1]; + }) + } + break; + } +# endif /* FLOATS */ + } + return 1; +} +SCM array_copy(src, dst) + SCM src; + SCM dst; +{ +#ifndef RECKLESS + if (INUM0==array_rank(dst)) + ASSERT(NIMP(dst) && ARRAYP(dst) && INUM0==array_rank(src), + dst, ARG2, s_array_copy); +#endif + ramapc(racp, UNDEFINED, src, cons(dst, EOL), s_array_copy); + return UNSPECIFIED; +} + +SCM ra2contig(ra, copy) + SCM ra; + int copy; +{ + SCM ret; + long inc = 1; + sizet k, len = 1; + for (k = ARRAY_NDIM(ra); k--;) + len *= ARRAY_DIMS(ra)[k].ubnd - ARRAY_DIMS(ra)[k].lbnd + 1; + k = ARRAY_NDIM(ra); + if (ARRAY_CONTP(ra) && ((0==k) || (1==ARRAY_DIMS(ra)[k-1].inc))) { + if (tc7_bvect != TYP7(ARRAY_V(ra))) + return ra; + if ((len==LENGTH(ARRAY_V(ra)) && + 0==ARRAY_BASE(ra) % LONG_BIT && + 0==len % LONG_BIT)) + return ra; + } + ret = make_ra(k); + ARRAY_BASE(ret) = 0; + while (k--) { + ARRAY_DIMS(ret)[k].lbnd = ARRAY_DIMS(ra)[k].lbnd; + ARRAY_DIMS(ret)[k].ubnd = ARRAY_DIMS(ra)[k].ubnd; + ARRAY_DIMS(ret)[k].inc = inc; + inc *= ARRAY_DIMS(ra)[k].ubnd - ARRAY_DIMS(ra)[k].lbnd + 1; + } + CAR(ret) |= ARRAY_CONTIGUOUS; + ARRAY_V(ret) = make_uve(inc+0L, array_prot(ra)); + if (copy) array_copy(ra, ret); + return ret; +} + +static char s_ura_rd[] = "uniform-array-read!"; +SCM ura_read(ra, port) + SCM ra, port; +{ + SCM ret, cra; + if (NIMP(ra) && ARRAYP(ra)) { + cra = ra2contig(ra, 0); + ret = uve_read(cra, port); + if (cra != ra) array_copy(cra, ra); + return ret; + } + else return uve_read(ra, port); +} + +static char s_ura_wr[] = "uniform-array-write"; +SCM ura_write(ra, port) + SCM ra, port; +{ + if (NIMP(ra) && ARRAYP(ra)) + return uve_write(ra2contig(ra,1), port); + else + return uve_write(ra, port); +} + +static char s_sc2array[] = "scalar->array"; +SCM sc2array(s, ra, prot) + SCM s, ra, prot; +{ + SCM res; + ASSERT(NIMP(ra), ra, ARG2, s_sc2array); + if ARRAYP(ra) { + int k = ARRAY_NDIM(ra); + res = make_ra(k); + while (k--) { + ARRAY_DIMS(res)[k].ubnd = ARRAY_DIMS(ra)[k].ubnd; + ARRAY_DIMS(res)[k].lbnd = ARRAY_DIMS(ra)[k].lbnd; + ARRAY_DIMS(res)[k].inc = 0; + } + ra = ARRAY_V(ra); + } + else { + ASSERT(BOOL_T==arrayp(ra, UNDEFINED), ra, ARG2, s_sc2array); + res = make_ra(1); + ARRAY_DIMS(res)->ubnd = LENGTH(ra) - 1; + ARRAY_DIMS(res)->lbnd = 0; + ARRAY_DIMS(res)->inc = 0; + } + if (NIMP(s) && ARRAYP(s) && 0==ARRAY_NDIM(s)) { + ARRAY_BASE(res) = ARRAY_BASE(s); + ARRAY_V(res) = ARRAY_V(s); + return res; + } + ARRAY_BASE(res) = 0; + ARRAY_V(res) = make_uve(1L, NULLP(prot) ? array_prot(ra) : CAR(prot)); + switch TYP7(ARRAY_V(res)) { + case tc7_vector: + break; + case tc7_string: + if ICHRP(s) break; + goto mismatch; + case tc7_uvect: + if (INUMP(s) && INUM(s)>=0) break; +#ifdef BIGDIG + if (NIMP(s) && tc16_bigpos==TYP16(s) && NUMDIGS(s)<=DIGSPERLONG) break; +#endif + goto mismatch; + case tc7_ivect: + if INUMP(s) break; +#ifdef BIGDIG + if (NIMP(s) && BIGP(s) && NUMDIGS(s)<=DIGSPERLONG) break; +#endif + goto mismatch; +#ifdef FLOATS +#ifdef SINGLES + case tc7_fvect: +#endif + case tc7_dvect: + if (NUMBERP(s) && !(NIMP(s) && CPLXP(s))) break; + goto mismatch; + case tc7_cvect: + if NUMBERP(s) break; + goto mismatch; +#endif + mismatch: ARRAY_V(res) = make_vector(MAKINUM(1), s); + return res; + } + aset(ARRAY_V(res), s, INUM0); + return res; +} + +/* Functions callable by ARRAY-MAP! */ +int ra_eqp(ra0, ras) + SCM ra0, ras; +{ + SCM ra1 = CAR(ras), ra2 = CAR(CDR(ras)); + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1), i2 = ARRAY_BASE(ra2); + long inc0 = ARRAY_DIMS(ra0)->inc; + long inc1 = ARRAY_DIMS(ra1)->inc; + long inc2 = ARRAY_DIMS(ra2)->inc; + ra0 = ARRAY_V(ra0); + ra1 = ARRAY_V(ra1); + ra2 = ARRAY_V(ra2); + switch (TYP7(ra1)==TYP7(ra2) ? TYP7(ra1) : 0) { + default: { + SCM e1 = UNDEFINED, e2 = UNDEFINED; + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + if BVE_REF(ra0, i0) + if FALSEP(eqp(RVREF(ra1, i1, e1), RVREF(ra2, i2, e2))) + BVE_CLR(ra0, i0); + break; + } + case tc7_uvect: + case tc7_ivect: + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + if BVE_REF(ra0, i0) + if (VELTS(ra1)[i1] != VELTS(ra2)[i2]) BVE_CLR(ra0, i0); + break; +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + if BVE_REF(ra0, i0) + if (((float *)VELTS(ra1))[i1] != ((float *)VELTS(ra2))[i2]) + BVE_CLR(ra0, i0); + break; +# endif /*SINGLES*/ + case tc7_dvect: + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + if BVE_REF(ra0, i0) + if (((double *)VELTS(ra1))[i1] != ((double *)VELTS(ra2))[i2]) + BVE_CLR(ra0, i0); + break; + case tc7_cvect: + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + if BVE_REF(ra0, i0) + if (((double *)VELTS(ra1))[2*i1] != ((double *)VELTS(ra2))[2*i2] || + ((double *)VELTS(ra1))[2*i1+1] != ((double *)VELTS(ra2))[2*i2+1]) + BVE_CLR(ra0, i0); + break; +# endif /*FLOATS*/ + } + return 1; +} +/* opt 0 means <, nonzero means >= */ +static int ra_compare(ra0, ra1, ra2, opt) + SCM ra0, ra1, ra2; + int opt; +{ + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1), i2 = ARRAY_BASE(ra2); + long inc0 = ARRAY_DIMS(ra0)->inc; + long inc1 = ARRAY_DIMS(ra1)->inc; + long inc2 = ARRAY_DIMS(ra2)->inc; + ra0 = ARRAY_V(ra0); + ra1 = ARRAY_V(ra1); + ra2 = ARRAY_V(ra2); + switch (TYP7(ra1)==TYP7(ra2) ? TYP7(ra1) : 0) { + default: { + SCM e1 = UNDEFINED, e2 = UNDEFINED; + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + if BVE_REF(ra0, i0) + if (opt ? + NFALSEP(lessp(RVREF(ra1, i1, e1), RVREF(ra2, i2, e2))) : + FALSEP(lessp(RVREF(ra1, i1, e1), RVREF(ra2, i2, e2))) ) + BVE_CLR(ra0, i0); + break; + } + case tc7_uvect: + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) { + if BVE_REF(ra0, i0) + if (opt ? + ((unsigned long*)VELTS(ra1))[i1] < ((unsigned long*)VELTS(ra2))[i2] : + ((unsigned long*)VELTS(ra1))[i1] >= ((unsigned long*)VELTS(ra2))[i2]) + BVE_CLR(ra0, i0); + } + break; + case tc7_ivect: + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) { + if BVE_REF(ra0, i0) + if (opt ? + VELTS(ra1)[i1] < VELTS(ra2)[i2] : + VELTS(ra1)[i1] >= VELTS(ra2)[i2]) + BVE_CLR(ra0, i0); + } + break; +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + if BVE_REF(ra0, i0) + if (opt ? + ((float *)VELTS(ra1))[i1] < ((float *)VELTS(ra2))[i2] : + ((float *)VELTS(ra1))[i1] >= ((float *)VELTS(ra2))[i2]) + BVE_CLR(ra0, i0); + break; +# endif /*SINGLES*/ + case tc7_dvect: + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + if BVE_REF(ra0, i0) + if (opt ? + ((double *)VELTS(ra1))[i1] < ((double *)VELTS(ra2))[i2] : + ((double *)VELTS(ra1))[i1] >= ((double *)VELTS(ra2))[i2]) + BVE_CLR(ra0, i0); + break; +# endif /*FLOATS*/ + } + return 1; +} +int ra_lessp(ra0, ras) + SCM ra0, ras; +{ + return ra_compare(ra0, CAR(ras), CAR(CDR(ras)), 0); +} +int ra_leqp(ra0, ras) + SCM ra0, ras; +{ + return ra_compare(ra0, CAR(CDR(ras)), CAR(ras), 1); +} +int ra_grp(ra0, ras) + SCM ra0, ras; +{ + return ra_compare(ra0, CAR(CDR(ras)), CAR(ras), 0); +} +int ra_greqp(ra0, ras) + SCM ra0, ras; +{ + return ra_compare(ra0, CAR(ras), CAR(CDR(ras)), 1); +} + +int ra_sum(ra0, ras) + SCM ra0, ras; +{ + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + sizet i0 = ARRAY_BASE(ra0); + long inc0 = ARRAY_DIMS(ra0)->inc; + ra0 = ARRAY_V(ra0); + if NNULLP(ras) { + SCM ra1 = CAR(ras); + sizet i1 = ARRAY_BASE(ra1); + long inc1 = ARRAY_DIMS(ra1)->inc; + ra1 = ARRAY_V(ra1); + switch (TYP7(ra0)==TYP7(ra1) ? TYP7(ra0) : 0) { + ovflow: wta(ra0, (char *)OVFLOW, "+"); + default: { + SCM e0 = UNDEFINED, e1 = UNDEFINED; + for (; n-- > 0; i0 += inc0, i1 += inc1) + aset(ra0, sum(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)), + MAKINUM(i0)); + break; + } + case tc7_uvect: { + unsigned long r; + unsigned long *v0 = (unsigned long *)VELTS(ra0); + unsigned long *v1 = (unsigned long *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) { + r = v0[i0] + v1[i1]; + ASRTGO(r >= v0[i0], ovflow); /* Will prevent vectorization */ + v0[i0] = r; + } ); + break; + } + case tc7_ivect: { + long r, *v0 = (long *)VELTS(ra0), *v1 = (long *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) { + r = v0[i0] + v1[i1]; + ASRTGO((v0[i0]>0 ? r>=0 || v1[i1]<0 : r<=0 || v1[i1]>0), ovflow); + v0[i0] = r; + } ); + break; + } +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *v0 = (float *)VELTS(ra0); + float *v1 = (float *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) + v0[i0] += v1[i1]); + break; + } +# endif /* SINGLES */ + case tc7_dvect: { + double *v0 = (double *)VELTS(ra0); + double *v1 = (double *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) + v0[i0] += v1[i1]); + break; + } + case tc7_cvect: { + double (*v0)[2] = (double (*)[2])VELTS(ra0); + double (*v1)[2] = (double (*)[2])VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) { + v0[i0][0] += v1[i1][0]; + v0[i0][1] += v1[i1][1]; + }); + break; + } +# endif /* FLOATS */ + } + } + return 1; +} + +int ra_difference(ra0, ras) + SCM ra0, ras; +{ + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + sizet i0 = ARRAY_BASE(ra0); + long inc0 = ARRAY_DIMS(ra0)->inc; + ra0 = ARRAY_V(ra0); + if NULLP(ras) { + switch TYP7(ra0) { + default: { + SCM e0 = UNDEFINED; + for (; n-- > 0; i0 += inc0) + aset(ra0, difference(RVREF(ra0, i0, e0), UNDEFINED), MAKINUM(i0)); + break; + } + case tc7_ivect: { + long *v0 = VELTS(ra0); + for (; n-- > 0; i0 += inc0) + v0[i0] = -v0[i0]; + break; + } +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *v0 = (float *)VELTS(ra0); + for (; n-- > 0; i0 += inc0) + v0[i0] = -v0[i0]; + break; + } +# endif /* SINGLES */ + case tc7_dvect: { + double *v0 = (double *)VELTS(ra0); + for (; n-- > 0; i0 += inc0) + v0[i0] = -v0[i0]; + break; + } + case tc7_cvect: { + double (*v0)[2] = (double (*)[2])VELTS(ra0); + for (; n-- > 0; i0 += inc0) { + v0[i0][0] = -v0[i0][0]; + v0[i0][1] = -v0[i0][1]; + } + break; + } +# endif /* FLOATS */ + } + } + else { + SCM ra1 = CAR(ras); + sizet i1 = ARRAY_BASE(ra1); + long inc1 = ARRAY_DIMS(ra1)->inc; + ra1 = ARRAY_V(ra1); + switch (TYP7(ra0)==TYP7(ra1) ? TYP7(ra0) : 0) { + ovflow: wta(ra0, (char *)OVFLOW, "-"); + default: { + SCM e0 = UNDEFINED, e1 = UNDEFINED; + for (; n-- > 0; i0 += inc0, i1 += inc1) + aset(ra0, difference(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)), MAKINUM(i0)); + break; + } + case tc7_uvect: { + unsigned long r; + unsigned long *v0 = (unsigned long *)VELTS(ra0); + unsigned long *v1 = (unsigned long*)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) { + r = v0[i0] - v1[i1]; + ASRTGO(r <= v0[i0], ovflow); + v0[i0] = r; + } ); + break; + } + case tc7_ivect: { + long r, *v0 = VELTS(ra0), *v1 = VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) { + r = v0[i0] - v1[i1]; + ASRTGO((v0[i0]>0 ? r>=0 || v1[i1]>0 : r<=0 || v1[i1]<0), ovflow); + v0[i0] = r; + } ); + break; + } +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *v0 = (float *)VELTS(ra0); + float *v1 = (float *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) + v0[i0] -= v1[i1]); + break; + } +# endif /* SINGLES */ + case tc7_dvect: { + double *v0 = (double *)VELTS(ra0); + double *v1 = (double *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) + v0[i0] -= v1[i1]); + break; + } + case tc7_cvect: { + double (*v0)[2] = (double (*)[2])VELTS(ra0); + double (*v1)[2] = (double (*)[2])VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) { + v0[i0][0] -= v1[i1][0]; + v0[i0][1] -= v1[i1][1]; + }) + break; + } +# endif /* FLOATS */ + } + } + return 1; +} + +int ra_product(ra0, ras) + SCM ra0, ras; +{ + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + sizet i0 = ARRAY_BASE(ra0); + long inc0 = ARRAY_DIMS(ra0)->inc; + ra0 = ARRAY_V(ra0); + if NNULLP(ras) { + SCM ra1 = CAR(ras); + sizet i1 = ARRAY_BASE(ra1); + long inc1 = ARRAY_DIMS(ra1)->inc; + ra1 = ARRAY_V(ra1); + switch (TYP7(ra0)==TYP7(ra1) ? TYP7(ra0) : 0) { + ovflow: wta(ra0, (char *)OVFLOW, "*"); + default: { + SCM e0 = UNDEFINED, e1 = UNDEFINED; + for (; n-- > 0; i0 += inc0, i1 += inc1) + aset(ra0, product(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)), + MAKINUM(i0)); + break; + } + case tc7_uvect: { + unsigned long r; + unsigned long *v0 = (unsigned long *)VELTS(ra0); + unsigned long *v1 = (unsigned long *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) { + r = v0[i0] * v1[i1]; + ASRTGO(0==v0[i0] || v1[i1]==r/v0[i0], ovflow); + v0[i0] = r; + } ); + break; + } + case tc7_ivect: { + long r, *v0 = VELTS(ra0), *v1 =VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) { + r = v0[i0] * v1[i1]; + ASRTGO(0==v0[i0] || v1[i1]==r/v0[i0], ovflow); + v0[i0] = r; + } ); + break; + } +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *v0 = (float *)VELTS(ra0); + float *v1 = (float *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) + v0[i0] *= v1[i1]); + break; + } +# endif /* SINGLES */ + case tc7_dvect: { + double *v0 = (double *)VELTS(ra0); + double *v1 = (double *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) + v0[i0] *= v1[i1]); + break; + } + case tc7_cvect: { + double (*v0)[2] = (double (*)[2])VELTS(ra0); + register double r; + double (*v1)[2] = (double (*)[2])VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) { + r = v0[i0][0]*v1[i1][0] - v0[i0][1]*v1[i1][1]; + v0[i0][1] = v0[i0][0]*v1[i1][1] + v0[i0][1]*v1[i1][0]; + v0[i0][0] = r; + }); + break; + } +# endif /* FLOATS */ + } + } + return 1; +} +int ra_divide(ra0, ras) + SCM ra0, ras; +{ + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + sizet i0 = ARRAY_BASE(ra0); + long inc0 = ARRAY_DIMS(ra0)->inc; + ra0 = ARRAY_V(ra0); + if NULLP(ras) { + switch TYP7(ra0) { + default: { + SCM e0 = UNDEFINED; + for (; n-- > 0; i0 += inc0) + aset(ra0, divide(RVREF(ra0, i0, e0), UNDEFINED), MAKINUM(i0)); + break; + } +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *v0 = (float *)VELTS(ra0); + for (; n-- > 0; i0 += inc0) + v0[i0] = 1.0/v0[i0]; + break; + } +# endif /* SINGLES */ + case tc7_dvect: { + double *v0 = (double *)VELTS(ra0); + for (; n-- > 0; i0 += inc0) + v0[i0] = 1.0/v0[i0]; + break; + } + case tc7_cvect: { + register double d; + double (*v0)[2] = (double (*)[2])VELTS(ra0); + for (; n-- > 0; i0 += inc0) { + d = v0[i0][0]*v0[i0][0] + v0[i0][1]*v0[i0][1]; + v0[i0][0] /= d; + v0[i0][1] /= -d; + } + break; + } +# endif /* FLOATS */ + } + } + else { + SCM ra1 = CAR(ras); + sizet i1 = ARRAY_BASE(ra1); + long inc1 = ARRAY_DIMS(ra1)->inc; + ra1 = ARRAY_V(ra1); + switch (TYP7(ra0)==TYP7(ra1) ? TYP7(ra0) : 0) { + default: { + SCM e0 = UNDEFINED, e1 = UNDEFINED; + for (; n-- > 0; i0 += inc0, i1 += inc1) + aset(ra0, divide(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)), MAKINUM(i0)); + break; + } +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *v0 = (float *)VELTS(ra0); + float *v1 = (float *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) + v0[i0] /= v1[i1]); + break; + } +# endif /* SINGLES */ + case tc7_dvect: { + double *v0 = (double *)VELTS(ra0); + double *v1 = (double *)VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) + v0[i0] /= v1[i1]); + break; + } + case tc7_cvect: { + register double d, r; + double (*v0)[2] = (double (*)[2])VELTS(ra0); + double (*v1)[2] = (double (*)[2])VELTS(ra1); + IVDEP(ra0 != ra1, + for (; n-- > 0; i0 += inc0, i1 += inc1) { + d = v1[i1][0]*v1[i1][0] + v1[i1][1]*v1[i1][1]; + r = (v0[i0][0]*v1[i1][0] + v0[i0][1]*v1[i1][1])/d; + v0[i0][1] = (v0[i0][1]*v1[i1][0] - v0[i0][0]*v1[i1][1])/d; + v0[i0][0] = r; + }) + break; + } +# endif /* FLOATS */ + } + } + return 1; +} +static int ra_identity(dst, src) + SCM src, dst; +{ + return racp(CAR(src), cons(dst, EOL)); +} + +static int ramap(ra0, proc, ras) + SCM ra0, proc, ras; +{ + long i = ARRAY_DIMS(ra0)->lbnd; + long inc = ARRAY_DIMS(ra0)->inc; + long n = ARRAY_DIMS(ra0)->ubnd; + long base = ARRAY_BASE(ra0) - i*inc; + ra0 = ARRAY_V(ra0); + if NULLP(ras) + for (; i <= n; i++) + aset(ra0, apply(proc, EOL, EOL), MAKINUM(i*inc + base)); + else { + SCM ra1 = CAR(ras); + SCM args, *ve = &ras; + sizet k, i1 = ARRAY_BASE(ra1); + long inc1 = ARRAY_DIMS(ra1)->inc; + ra1 = ARRAY_V(ra1); + ras = CDR(ras); + if NULLP(ras) + ras = nullvect; + else { + ras = vector(ras); + ve = VELTS(ras); + } + for (; i <= n; i++, i1 += inc1) { + args = EOL; + for (k = LENGTH(ras); k--;) + args = cons(aref(ve[k], MAKINUM(i)), args); + args = cons(cvref(ra1, i1, UNDEFINED), args); + aset(ra0, apply(proc, args, EOL), MAKINUM(i*inc + base)); + } + } + return 1; +} +static int ramap_cxr(ra0, proc, ras) + SCM ra0, proc, ras; +{ + SCM ra1 = CAR(ras); + SCM e1 = UNDEFINED; + sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1); + long inc0 = ARRAY_DIMS(ra0)->inc, inc1 = ARRAY_DIMS(ra1)->inc; + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra1)->lbnd + 1; + ra0 = ARRAY_V(ra0); + ra1 = ARRAY_V(ra1); + switch TYP7(ra0) { + default: gencase: + for (; n-- > 0; i0 += inc0, i1 += inc1) + aset(ra0, apply(proc, RVREF(ra1, i1, e1), listofnull), MAKINUM(i0)); + break; +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *dst = (float *)VELTS(ra0); + switch TYP7(ra1) { + default: goto gencase; + case tc7_fvect: + for (; n-- > 0; i0 += inc0, i1 += inc1) + dst[i0] = DSUBRF(proc)((double)((float *)VELTS(ra1))[i1]); + break; + case tc7_uvect: + case tc7_ivect: + for (; n-- > 0; i0 += inc0, i1 += inc1) + dst[i0] = DSUBRF(proc)((double)VELTS(ra1)[i1]); + break; + } + break; + } +# endif /* SINGLES */ + case tc7_dvect: { + double *dst = (double *)VELTS(ra0); + switch TYP7(ra1) { + default: goto gencase; + case tc7_dvect: + for (; n-- > 0; i0 += inc0, i1 += inc1) + dst[i0] = DSUBRF(proc)(((double *)VELTS(ra1))[i1]); + break; + case tc7_uvect: + case tc7_ivect: + for (; n-- > 0; i0 += inc0, i1 += inc1) + dst[i0] = DSUBRF(proc)((double)VELTS(ra1)[i1]); + break; + } + break; + } +# endif /* FLOATS */ + } + return 1; +} +static int ramap_rp(ra0, proc, ras) + SCM ra0, proc, ras; +{ + SCM ra1 = CAR(ras), ra2 = CAR(CDR(ras)); + SCM e1 = UNDEFINED, e2 = UNDEFINED; + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1), i2 = ARRAY_BASE(ra2); + long inc0 = ARRAY_DIMS(ra0)->inc; + long inc1 = ARRAY_DIMS(ra1)->inc; + long inc2 = ARRAY_DIMS(ra2)->inc; + ra0 = ARRAY_V(ra0); + ra1 = ARRAY_V(ra1); + ra2 = ARRAY_V(ra2); + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + if BVE_REF(ra0, i0) + if FALSEP(SUBRF(proc)(RVREF(ra1, i1, e1), RVREF(ra2, i2, e2))) + BVE_CLR(ra0, i0); + return 1; +} +static int ramap_1(ra0, proc, ras) + SCM ra0, proc, ras; +{ + SCM ra1 = CAR(ras); + SCM e1 = UNDEFINED; + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1); + long inc0 = ARRAY_DIMS(ra0)->inc, inc1 = ARRAY_DIMS(ra1)->inc; + ra0 = ARRAY_V(ra0); + ra1 = ARRAY_V(ra1); + if (tc7_vector==TYP7(ra0)) + for (; n-- > 0; i0 += inc0, i1 += inc1) + VELTS(ra0)[i0] = SUBRF(proc)(cvref(ra1, i1, UNDEFINED)); + else + for (; n-- > 0; i0 += inc0, i1 += inc1) + aset(ra0, SUBRF(proc)(RVREF(ra1, i1, e1)), MAKINUM(i0)); + return 1; +} +static int ramap_2o(ra0, proc, ras) + SCM ra0, proc, ras; +{ + SCM ra1 = CAR(ras); + SCM e1 = UNDEFINED; + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + sizet i0 = ARRAY_BASE(ra0), i1 = ARRAY_BASE(ra1); + long inc0 = ARRAY_DIMS(ra0)->inc, inc1 = ARRAY_DIMS(ra1)->inc; + ra0 = ARRAY_V(ra0); + ra1 = ARRAY_V(ra1); + ras = CDR(ras); + if NULLP(ras) { + if (tc7_vector==TYP7(ra0)) + for (; n-- > 0; i0 += inc0, i1 += inc1) + VELTS(ra0)[i0] = SUBRF(proc)(cvref(ra1, i1, UNDEFINED), UNDEFINED); + else + for (; n-- > 0; i0 += inc0, i1 += inc1) + aset(ra0, SUBRF(proc)(RVREF(ra1, i1, e1), UNDEFINED), + MAKINUM(i0)); + } + else { + SCM ra2 = CAR(ras); + SCM e2 = UNDEFINED; + sizet i2 = ARRAY_BASE(ra2); + long inc2 = ARRAY_DIMS(ra2)->inc; + ra2 = ARRAY_V(ra2); + if (tc7_vector==TYP7(ra0)) + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + VELTS(ra0)[i0] = + SUBRF(proc)(cvref(ra1, i1, UNDEFINED), cvref(ra2, i2, UNDEFINED)); + else + for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2) + aset(ra0, + SUBRF(proc)(RVREF(ra1, i1, e1), RVREF(ra2, i2, e2)), + MAKINUM(i0)); + } + return 1; +} +static int ramap_a(ra0, proc, ras) + SCM ra0, proc, ras; +{ + SCM e0 = UNDEFINED, e1 = UNDEFINED; + long n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + sizet i0 = ARRAY_BASE(ra0); + long inc0 = ARRAY_DIMS(ra0)->inc; + ra0 = ARRAY_V(ra0); + if NULLP(ras) + for (; n-- > 0; i0 += inc0) + aset(ra0, SUBRF(proc)(RVREF(ra0, i0, e0), UNDEFINED), MAKINUM(i0)); + else { + SCM ra1 = CAR(ras); + sizet i1 = ARRAY_BASE(ra1); + long inc1 = ARRAY_DIMS(ra1)->inc; + ra1 = ARRAY_V(ra1); + for (; n-- > 0; i0 += inc0, i1 += inc1) + aset(ra0, SUBRF(proc)(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1)), + MAKINUM(i0)); + } + return 1; +} + +/* These tables are a kluge that will not scale well when more + vectorized subrs are added. It is tempting to steal some bits from + the CAR of all subrs (like those selected by SMOBNUM) to hold an + offset into a table of vectorized subrs. */ + +static ra_iproc ra_rpsubrs[] = { + {"=", UNDEFINED, ra_eqp}, + {"<", UNDEFINED, ra_lessp}, + {"<=", UNDEFINED, ra_leqp}, + {">", UNDEFINED, ra_grp}, + {">=", UNDEFINED, ra_greqp}, + {0, 0, 0}}; +static ra_iproc ra_asubrs[] = { + {"+", UNDEFINED, ra_sum}, + {"-", UNDEFINED, ra_difference}, + {"*", UNDEFINED, ra_product}, + {"/", UNDEFINED, ra_divide}, + {0, 0, 0}}; + +static char s_sarray_map[] = "serial-array-map!"; +# define s_array_map (s_sarray_map + 7) +SCM array_map(ra0, proc, lra) + SCM ra0, proc, lra; +{ + int narg = ilength(lra); + ASSERT(BOOL_T==procedurep(proc), proc, ARG2, s_array_map); + tail: + switch TYP7(proc) { + wna: wta(UNDEFINED, (char *)WNA, s_array_map); + default: gencase: + ramapc(ramap, proc, ra0, lra, s_array_map); + return UNSPECIFIED; + case tc7_subr_1: ASRTGO(1==narg, wna); + ramapc(ramap_1, proc, ra0, lra, s_array_map); + return UNSPECIFIED; + case tc7_subr_2: ASRTGO(2==narg, wna); + case tc7_subr_2o: ASRTGO(2>=narg, wna); + ramapc(ramap_2o, proc, ra0, lra, s_array_map); + return UNSPECIFIED; + case tc7_cxr: if (! SUBRF(proc)) goto gencase; + ASRTGO(1==narg, wna); + ramapc(ramap_cxr, proc, ra0, lra, s_array_map); + return UNSPECIFIED; + case tc7_rpsubr: { + ra_iproc *p; + if (FALSEP(arrayp(ra0, BOOL_T))) goto gencase; + array_fill(ra0, BOOL_T); + for (p = ra_rpsubrs; p->name; p++) + if (proc==p->sproc) { + while (NNULLP(lra) && NNULLP(CDR(lra))) { + ramapc(p->vproc, UNDEFINED, ra0, lra, s_array_map); + lra = CDR(lra); + } + return UNSPECIFIED; + } + while (NNULLP(lra) && NNULLP(CDR(lra))) { + ramapc(ramap_rp, proc, ra0, lra, s_array_map); + lra = CDR(lra); + } + return UNSPECIFIED; + } + case tc7_asubr: + if NULLP(lra) { + SCM prot, fill = SUBRF(proc)(UNDEFINED, UNDEFINED); + if INUMP(fill) { + prot = array_prot(ra0); +# ifdef FLOATS + if (NIMP(prot) && INEXP(prot)) + fill = makdbl((double)INUM(fill), 0.0); +# endif + } + array_fill(ra0, fill); + } + else { + SCM tail, ra1 = CAR(lra); + SCM v0 = (NIMP(ra0) && ARRAYP(ra0) ? ARRAY_V(ra0) : ra0); + ra_iproc *p; + /* Check to see if order might matter. + This might be an argument for a separate + SERIAL-ARRAY-MAP! */ + if (v0==ra1 || (NIMP(ra1) && ARRAYP(ra1) && v0==ARRAY_V(ra1))) + if (ra0 != ra1 || (ARRAYP(ra0) && !ARRAY_CONTP(ra0))) + goto gencase; + for (tail = CDR(lra); NNULLP(tail); tail = CDR(tail)) { + ra1 = CAR(tail); + if (v0==ra1 || (NIMP(ra1) && ARRAYP(ra1) && v0==ARRAY_V(ra1))) + goto gencase; + } + for (p = ra_asubrs; p->name; p++) + if (proc==p->sproc) { + if (ra0 != CAR(lra)) + ramapc(ra_identity, UNDEFINED, ra0, cons(CAR(lra), EOL), s_array_map); + lra = CDR(lra); + while (1) { + ramapc(p->vproc, UNDEFINED, ra0, lra, s_array_map); + if (IMP(lra) || IMP(CDR(lra))) return UNSPECIFIED; + lra = CDR(lra); + } + } + ramapc(ramap_2o, proc, ra0, lra, s_array_map); + lra = CDR(lra); + if NIMP(lra) + for (lra = CDR(lra); NIMP(lra); lra = CDR(lra)) + ramapc(ramap_a, proc, ra0, lra, s_array_map); + } + return UNSPECIFIED; +#ifdef CCLO + case tc7_cclo: + lra = cons(sc2array(proc,ra0,EOL), lra); + proc = CCLO_SUBR(proc); + goto tail; +#endif + } +} + +static int rafe(ra0, proc, ras) + SCM ra0, proc, ras; +{ + long i = ARRAY_DIMS(ra0)->lbnd; + sizet i0 = ARRAY_BASE(ra0); + long inc0 = ARRAY_DIMS(ra0)->inc; + long n = ARRAY_DIMS(ra0)->ubnd; + ra0 = ARRAY_V(ra0); + if NULLP(ras) + for (; i <= n; i++, i0 += inc0) + apply(proc, cvref(ra0, i0, UNDEFINED), listofnull); + else { + SCM ra1 = CAR(ras); + SCM args, *ve = &ras; + sizet k, i1 = ARRAY_BASE(ra1); + long inc1 = ARRAY_DIMS(ra1)->inc; + ra1 = ARRAY_V(ra1); + ras = CDR(ras); + if NULLP(ras) + ras = nullvect; + else { + ras = vector(ras); + ve = VELTS(ras); + } + for (; i <= n; i++, i0 += inc0, i1 += inc1) { + args = EOL; + for (k = LENGTH(ras); k--;) + args = cons(aref(ve[k], MAKINUM(i)), args); + args = cons2(cvref(ra0, i0, UNDEFINED), cvref(ra1, i1, UNDEFINED), args); + apply(proc, args, EOL); + } + } + return 1; +} +static char s_array_for_each[] = "array-for-each"; +SCM array_for_each(proc, ra0, lra) + SCM proc, ra0, lra; +{ + ASSERT(BOOL_T==procedurep(proc), proc, ARG1, s_array_for_each); + tail: + switch TYP7(proc) { + default: + ramapc(rafe, proc, ra0, lra, s_array_for_each); + return UNSPECIFIED; +#ifdef CCLO + case tc7_cclo: + lra = cons(ra0, lra); + ra0 = sc2array(proc, ra0, EOL); + proc = CCLO_SUBR(proc); + goto tail; +#endif + } +} + +static char s_array_imap[] = "array-index-map!"; +SCM array_imap(ra, proc) + SCM ra, proc; +{ + sizet i; + ASSERT(NIMP(ra), ra, ARG1, s_array_imap); + ASSERT(BOOL_T==procedurep(proc), proc, ARG2, s_array_imap); + switch TYP7(ra) { + default: badarg: wta(ra, (char *)ARG1, s_array_imap); + case tc7_vector: + { + SCM *ve = VELTS(ra); + for (i = 0; i < LENGTH(ra); i++) + ve[i] = apply(proc, MAKINUM(i), listofnull); + return UNSPECIFIED; + } + case tc7_string: case tc7_bvect: case tc7_uvect: case tc7_ivect: + case tc7_fvect: case tc7_dvect: case tc7_cvect: + for (i = 0; i < LENGTH(ra); i++) + aset(ra, apply(proc, MAKINUM(i), listofnull), MAKINUM(i)); + return UNSPECIFIED; + case tc7_smob: ASRTGO(ARRAYP(ra), badarg); + { + SCM args = EOL; + SCM inds = make_uve(ARRAY_NDIM(ra)+0L, MAKINUM(-1L)); + long *vinds = VELTS(inds); + int j, k, kmax = ARRAY_NDIM(ra) - 1; + for (k = 0; k <= kmax; k++) + vinds[k] = ARRAY_DIMS(ra)[k].lbnd; + k = kmax; + do { + if (k==kmax) { + vinds[k] = ARRAY_DIMS(ra)[k].lbnd; + i = cind(ra, inds); + for (; vinds[k] <= ARRAY_DIMS(ra)[k].ubnd; vinds[k]++) { + for (j = kmax+1, args = EOL; j--;) + args = cons(MAKINUM(vinds[j]), args); + aset(ARRAY_V(ra), apply(proc, args, EOL), MAKINUM(i)); + i += ARRAY_DIMS(ra)[k].inc; + } + k--; + continue; + } + if (vinds[k] < ARRAY_DIMS(ra)[k].ubnd) { + vinds[k]++; + k++; + continue; + } + vinds[k] = ARRAY_DIMS(ra)[k].lbnd - 1; + k--; + } while (k >= 0); + return UNSPECIFIED; + } + } +} + +SCM array_equal P((SCM ra0, SCM ra1)); +static int raeql_1(ra0, as_equal, ra1) + SCM ra0, as_equal, ra1; +{ + SCM e0 = UNDEFINED, e1 = UNDEFINED; + sizet i0 = 0, i1 = 0; + long inc0 = 1, inc1 = 1; + sizet n = LENGTH(ra0); + ra1 = CAR(ra1); + if ARRAYP(ra0) { + n = ARRAY_DIMS(ra0)->ubnd - ARRAY_DIMS(ra0)->lbnd + 1; + i0 = ARRAY_BASE(ra0); + inc0 = ARRAY_DIMS(ra0)->inc; + ra0 = ARRAY_V(ra0); + } + if ARRAYP(ra1) { + i1 = ARRAY_BASE(ra1); + inc1 = ARRAY_DIMS(ra1)->inc; + ra1 = ARRAY_V(ra1); + } + switch TYP7(ra0) { + case tc7_vector: default: + for (; n--; i0+=inc0, i1+=inc1) { + if FALSEP(as_equal) { + if FALSEP(array_equal(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1))) + return 0; + } + else + if FALSEP(equal(RVREF(ra0, i0, e0), RVREF(ra1, i1, e1))) + return 0; + } + return 1; + case tc7_string: { + char *v0 = CHARS(ra0) + i0; + char *v1 = CHARS(ra1) + i1; + for (; n--; v0 += inc0, v1 += inc1) + if (*v0 != *v1) return 0; + return 1; + } + case tc7_bvect: + for (; n--; i0 += inc0, i1 += inc1) + if (BVE_REF(ra0, i0) != BVE_REF(ra1, i1)) return 0; + return 1; + case tc7_uvect: case tc7_ivect: { + long *v0 = (long *)VELTS(ra0) + i0; + long *v1 = (long *)VELTS(ra1) + i1; + for (; n--; v0 += inc0, v1 += inc1) + if (*v0 != *v1) return 0; + return 1; + } +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *v0 = (float *)VELTS(ra0) + i0; + float *v1 = (float *)VELTS(ra1) + i1; + for (; n--; v0 += inc0, v1 += inc1) + if (*v0 != *v1) return 0; + return 1; + } +# endif /* SINGLES */ + case tc7_dvect: { + double *v0 = (double *)VELTS(ra0) + i0; + double *v1 = (double *)VELTS(ra1) + i1; + for (; n--; v0 += inc0, v1 += inc1) + if (*v0 != *v1) return 0; + return 1; + } + case tc7_cvect: { + double (*v0)[2]= (double (*)[2])VELTS(ra0) + i0; + double (*v1)[2] = (double (*)[2])VELTS(ra1) + i1; + for (; n--; v0 += inc0, v1 += inc1) { + if ((*v0)[0] != (*v1)[0]) return 0; + if ((*v0)[1] != (*v1)[1]) return 0; + } + return 1; + } +# endif /* FLOATS */ + } +} +static int raeql(ra0, as_equal, ra1) + SCM ra0, as_equal, ra1; +{ + SCM v0 = ra0, v1 = ra1; + array_dim dim0, dim1; + array_dim *s0 = &dim0, *s1 = &dim1; + sizet bas0 = 0, bas1 = 0; + int k, unroll = 1, ndim = 1; + if ARRAYP(ra0) { + ndim = ARRAY_NDIM(ra0); + s0 = ARRAY_DIMS(ra0); + bas0 = ARRAY_BASE(ra0); + v0 = ARRAY_V(ra0); + } + else { + s0->inc = 1; s0->lbnd = 0; s0->ubnd = LENGTH(v0) - 1; + } + if ARRAYP(ra1) { + if (ndim != ARRAY_NDIM(ra1)) return 0; + s1 = ARRAY_DIMS(ra1); + bas1 = ARRAY_BASE(ra1); + v1 = ARRAY_V(ra1); + } + else { + if (1 != ndim) return BOOL_F; + s1->inc = 1; s1->lbnd = 0; s1->ubnd = LENGTH(v1) - 1; + } + if (TYP7(v0) != TYP7(v1)) return 0; + unroll = (bas0==bas1); + for (k = ndim; k--;) { + if (s0[k].lbnd != s1[k].lbnd || s0[k].ubnd != s1[k].ubnd) return 0; + if (unroll) unroll = (s0[k].inc==s1[k].inc); + } + if (unroll && v0==v1) return BOOL_T; + return ramapc(raeql_1, as_equal, ra0, cons(ra1, EOL), ""); +} + +SCM raequal(ra0, ra1) + SCM ra0, ra1; +{ + return (raeql(ra0, BOOL_T, ra1) ? BOOL_T : BOOL_F); +} +static char s_array_equalp[] = "array-equal?"; +SCM array_equal(ra0, ra1) + SCM ra0, ra1; +{ + if (IMP(ra0) || IMP(ra1)) + callequal: return equal(ra0, ra1); + switch TYP7(ra0) { + default: goto callequal; + case tc7_bvect: case tc7_string: case tc7_uvect: case tc7_ivect: + case tc7_fvect: case tc7_dvect: case tc7_cvect: case tc7_vector: + break; + case tc7_smob: if (!ARRAYP(ra0)) goto callequal; + } + switch TYP7(ra1) { + default: goto callequal; + case tc7_bvect: case tc7_string: case tc7_uvect: case tc7_ivect: + case tc7_fvect: case tc7_dvect: case tc7_cvect: case tc7_vector: + break; + case tc7_smob: if (!ARRAYP(ra1)) goto callequal; + } + return (raeql(ra0, BOOL_F, ra1) ? BOOL_T : BOOL_F); +} + +static iproc subr2os[] = { + {s_ura_rd, ura_read}, + {s_ura_wr, ura_write}, + {0, 0}}; + +static iproc subr2s[] = { + {s_array_fill, array_fill}, + {s_array_copy, array_copy}, + {s_sarray_copy, array_copy}, + {0, 0}}; + +static iproc lsubr2s[] = { + {s_sc2array, sc2array}, + {s_array_map, array_map}, + {s_sarray_map, array_map}, + {s_array_for_each, array_for_each}, + {s_array_imap, array_imap}, + {0, 0}}; + +static void init_raprocs(subra) + ra_iproc *subra; +{ + for(; subra->name; subra++) + subra->sproc = CDR(intern(subra->name, strlen(subra->name))); +} + +void init_ramap() +{ + init_raprocs(ra_rpsubrs); + init_raprocs(ra_asubrs); + init_iprocs(subr2os, tc7_subr_2o); + init_iprocs(subr2s, tc7_subr_2); + init_iprocs(lsubr2s, tc7_lsubr_2); + make_subr(s_array_equalp, tc7_rpsubr, array_equal); + smobs[0x0ff & (tc16_array>>8)].equalp = raequal; + add_feature(s_array_for_each); +} diff --git a/record.c b/record.c new file mode 100644 index 0000000..40b224c --- /dev/null +++ b/record.c @@ -0,0 +1,349 @@ +/* Copyright (C) 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "record.c" code for (R5RS) proposed "Record" user definable datatypes. + Author: Radey Shouman */ + +#include "scm.h" + +typedef struct { + SCM rtd; + SCM name; + SCM fields; +} rtd_type; + +typedef union { + struct { + SCM proc; + SCM rtd; + } pred; + struct { + SCM proc; + SCM rtd; + SCM index; + } acc; + struct { + SCM proc; + SCM rtd; + SCM recsize; + SCM indices; + } constr; +} rec_cclo; + +long tc16_record; + +/* Record-type-descriptor for record-type-descriptors */ +static SCM the_rtd_rtd; + +/* Record <= [rtd, ... elts ... ] */ +#define REC_RTD(x) (VELTS(x)[0]) +#define RECP(x) (tc16_record==TYP16(x)) +#define RTDP(x) (RECP(x) && the_rtd_rtd==REC_RTD(x)) +#define RTD_NAME(x) (((rtd_type *)CDR(x))->name) +#define RTD_FIELDS(x) (((rtd_type *)CDR(x))->fields) +#define RCLO_RTD(x) (((rec_cclo *)CDR(x))->pred.rtd) + +#ifdef ARRAYS +# define MAKE_REC_INDS(n) make_uve((long)n, MAKINUM(1)) +# define REC_IND_REF(x, i) VELTS(x)[(i)] +# define REC_IND_SET(x, i, val) VELTS(x)[(i)] = (val) +#else +# define MAKE_REC_INDS(n) make_vector(MAKINUM(n), INUM0) +# define REC_IND_REF(x, i) INUM(VELTS(x)[(i)]) +# define REC_IND_SET(x, i, val) VELTS(x)[(i)] = MAKINUM(val) +#endif + +static char s_record[] = "record"; +static char s_recordp[] = "record?"; +SCM recordp(obj) + SCM obj; +{ + return (NIMP(obj) && RECP(obj) ? BOOL_T : BOOL_F); +} +static char s_rec_pred1[] = " record-predicate-procedure"; +SCM rec_pred1(cclo, obj) + SCM cclo, obj; +{ + if (NIMP(obj) && RECP(obj) && (REC_RTD(obj)==RCLO_RTD(cclo))) + return BOOL_T; + return BOOL_F; +} +static SCM f_rec_pred1; +static char s_rec_pred[] = "record-predicate"; +SCM rec_pred(rtd) + SCM rtd; +{ + SCM cclo = makcclo(f_rec_pred1, 2L); + ASSERT(NIMP(rtd) && RTDP(rtd), rtd, ARG1, s_rec_pred); + RCLO_RTD(cclo) = rtd; + return cclo; +} + +static char s_rec_rtd[] = "record-type-descriptor"; +SCM rec_rtd(rec) + SCM rec; +{ + if (IMP(rec) || !RECP(rec)) return BOOL_F; + return REC_RTD(rec); +} + +static SCM f_rec_constr1; +static char s_rec_constr[] = "record-constructor"; +SCM rec_constr(rtd, flds) + SCM rtd, flds; +{ + SCM flst, fld; + SCM cclo = makcclo(f_rec_constr1, (long)sizeof(rec_cclo)/sizeof(SCM)); + rec_cclo *ptr = (rec_cclo *)CDR(cclo); + sizet i, j; + ASSERT(NIMP(rtd) && RTDP(rtd), rtd, ARG1, s_rec_constr); + ptr->constr.rtd = rtd; + i = ilength(RTD_FIELDS(rtd)); + ptr->constr.recsize = MAKINUM(i); + if UNBNDP(flds) { + ptr->constr.indices = MAKE_REC_INDS(i); + while (i--) + REC_IND_SET(ptr->constr.indices, i, i+1); + } + else { + ASSERT(NIMP(flds) && CONSP(flds), flds, ARG2, s_rec_constr); + ptr->constr.indices = MAKE_REC_INDS(ilength(flds)); + for(i = 0; NIMP(flds); i++, flds = CDR(flds)) { + fld = CAR(flds); + ASSERT(NIMP(fld) && SYMBOLP(fld), fld, ARG2, s_rec_constr); + flst = RTD_FIELDS(rtd); + for (j = 0; ; j++, flst = CDR(flst)) { + if (fld==CAR(flst)) { + REC_IND_SET(ptr->constr.indices, i, j+1); + break; + } + ASSERT(NNULLP(flst), fld, ARG2, s_rec_constr); + } + } + } + return cclo; +} +static char s_rec_constr1[] = " record-constructor-procedure"; +SCM rec_constr1(args) + SCM args; +{ + SCM cclo = CAR(args); + SCM rec, inds = (((rec_cclo *)CDR(cclo))->constr.indices); + sizet i = INUM(((rec_cclo *)CDR(cclo))->constr.recsize); + args = CDR(args); + NEWCELL(rec); + DEFER_INTS; + SETCHARS(rec, must_malloc((i+1L)*sizeof(SCM), s_record)); + SETNUMDIGS(rec, i+1L, tc16_record); + ALLOW_INTS; + while (i--) + VELTS(rec)[i+1] = UNSPECIFIED; + REC_RTD(rec) = RCLO_RTD(cclo); + for (i = 0; i < LENGTH(inds); i++, args = CDR(args)) { + ASSERT(NNULLP(args), UNDEFINED, WNA, s_rec_constr1); + VELTS(rec)[ REC_IND_REF(inds, i) ] = CAR(args); + } + ASSERT(NULLP(args), UNDEFINED, WNA, s_rec_constr1); + return rec; + +} + +/* Makes an accessor or modifier. + A cclo with 2 env elts -- rtd and field-number. */ +static SCM makrecclo(proc, rtd, field, what) + SCM proc, rtd, field; + char *what; +{ + SCM flst; + SCM cclo = makcclo(proc, 3L); + int i; + ASSERT(RTDP(rtd), rtd, ARG1, what); + ASSERT(NIMP(field) && SYMBOLP(field), field, ARG2, what); + RCLO_RTD(cclo) = rtd; + flst = RTD_FIELDS(rtd); + for (i = 1; ; i++) { + ASSERT(NNULLP(flst), field, ARG2, what); + if (CAR(flst)==field) break; + flst = CDR(flst); + } + (((rec_cclo *)CDR(cclo))->acc.index) = MAKINUM(i); + return cclo; +} +static char s_rec_accessor1[] = " record-accessor-procedure"; +SCM rec_accessor1(cclo, rec) + SCM cclo, rec; +{ + ASSERT(NIMP(rec) && RECP(rec), rec, ARG1, s_rec_accessor1); + ASSERT(RCLO_RTD(cclo)==REC_RTD(rec), rec, ARG1, s_rec_accessor1); + return VELTS(rec)[ INUM(((rec_cclo *)CDR(cclo))->acc.index) ]; +} +static char s_rec_modifier1[] = " record-modifier-procedure"; +SCM rec_modifier1(cclo, rec, val) + SCM cclo, rec, val; +{ + ASSERT(NIMP(rec) && RECP(rec), rec, ARG1, s_rec_modifier1); + ASSERT(RCLO_RTD(cclo)==REC_RTD(rec), rec, ARG1, s_rec_modifier1); + VELTS(rec)[ INUM(((rec_cclo *)CDR(cclo))->acc.index) ] = val; + return UNSPECIFIED; +} +static SCM f_rec_accessor1; +static char s_rec_accessor[] = "record-accessor"; +SCM rec_accessor(rtd, field) + SCM rtd, field; +{ + return makrecclo(f_rec_accessor1, rtd, field, s_rec_accessor); +} +static SCM f_rec_modifier1; +static char s_rec_modifier[] = "record-modifier"; +SCM rec_modifier(rtd, field) + SCM rtd, field; +{ + return makrecclo(f_rec_modifier1, rtd, field, s_rec_accessor); +} + +static char s_makrectyp[] = "make-record-type"; +SCM *loc_makrtd; +SCM makrectyp(name, fields) + SCM name, fields; +{ + SCM n; +#ifndef RECKLESS + if(ilength(fields) < 0) + errout: wta(fields, (char *)ARG2, s_makrectyp); + for (n=fields; NIMP(n); n = CDR(n)) + if (!SYMBOLP(CAR(n))) goto errout; +#endif + return apply(*loc_makrtd, name, cons(fields, listofnull)); +} + +static SCM markrec(ptr) + SCM ptr; +{ + sizet i; + if GC8MARKP(ptr) return BOOL_F; + SETGC8MARK(ptr); + for (i = NUMDIGS(ptr); --i;) + if NIMP(VELTS(ptr)[i]) gc_mark(VELTS(ptr)[i]); + return REC_RTD(ptr); +} +static sizet freerec(ptr) + CELLPTR ptr; +{ + must_free(CHARS(ptr)); + return sizeof(SCM)*NUMDIGS(ptr); +} +static int recprin1(exp, port, writing) + SCM exp, port; + int writing; +{ + SCM names = RTD_FIELDS(REC_RTD(exp)); + sizet i; + lputs("#s(", port); + iprin1(RTD_NAME(REC_RTD(exp)), port, 0); + for (i = 1; i < NUMDIGS(exp); i++) { + lputc(' ', port); + iprin1(CAR(names), port, 0); + names = CDR(names); + lputc(' ', port); + iprin1(VELTS(exp)[i], port, writing); + } + lputc(')', port); +/* + lputs("#<record <", port); + iprin1(RTD_NAME(REC_RTD(exp)), port, 0); + lputc('>', port); + for(i = 1; i < NUMDIGS(exp); i++) { + lputc(' ', port); + iprin1(VELTS(exp)[i], port, writing); + } + lputc('>', port); +*/ + return 1; +} +SCM recequal(rec0, rec1) + SCM rec0, rec1; +{ + sizet i = NUMDIGS(rec0); + if (i != NUMDIGS(rec1)) return BOOL_F; + if (REC_RTD(rec0) != REC_RTD(rec1)) return BOOL_F; + while(--i) + if FALSEP(equal(VELTS(rec0)[i], VELTS(rec1)[i])) + return BOOL_F; + return BOOL_T; +} +static smobfuns recsmob = {markrec, freerec, recprin1, recequal}; +static iproc subr1s[] = { + {s_recordp, recordp}, + {s_rec_pred, rec_pred}, + {s_rec_rtd, rec_rtd}, + {0, 0}}; +static iproc subr2s[] = { + {s_rec_accessor, rec_accessor}, + {s_rec_modifier, rec_modifier}, + {s_makrectyp, makrectyp}, + {0, 0}}; +static char s_name[] = "name"; +static char s_fields[] = "fields"; +void init_record() +{ + SCM i_name = CAR(intern(s_name, (sizeof s_name)-1)); + SCM i_fields = CAR(intern(s_fields, (sizeof s_fields)-1)); + tc16_record = newsmob(&recsmob); + NEWCELL(the_rtd_rtd); + SETCHARS(the_rtd_rtd, must_malloc((long)sizeof(rtd_type), s_record)); + SETNUMDIGS(the_rtd_rtd, (long)sizeof(rtd_type)/sizeof(SCM), tc16_record); + REC_RTD(the_rtd_rtd) = the_rtd_rtd; + RTD_NAME(the_rtd_rtd) = makfromstr(s_record, (sizeof s_record)-1); + RTD_FIELDS(the_rtd_rtd) = cons2(i_name, i_fields, EOL); + sysintern("record:rtd", the_rtd_rtd); + f_rec_pred1 = make_subr(s_rec_pred1, tc7_subr_2, rec_pred1); + f_rec_constr1 = make_subr(s_rec_constr1, tc7_lsubr, rec_constr1); + f_rec_accessor1 = make_subr(s_rec_accessor1, tc7_subr_2, rec_accessor1); + f_rec_modifier1 = make_subr(s_rec_modifier1, tc7_subr_3, rec_modifier1); + make_subr(s_rec_constr, tc7_subr_2o, rec_constr); + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(subr2s, tc7_subr_2); + sysintern("record-type-descriptor?", rec_pred(the_rtd_rtd)); + sysintern("record-type-name", rec_accessor(the_rtd_rtd, i_name)); + sysintern("record-type-field-names", rec_accessor(the_rtd_rtd, i_fields)); + loc_makrtd = &CDR(sysintern("RTD:make", rec_constr(the_rtd_rtd, UNDEFINED))); + add_feature(s_record); +} @@ -0,0 +1,1649 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "repl.c" error, read-eval-print loop, read, write and load code. + Author: Aubrey Jaffer */ + +#include "scm.h" +#include "setjump.h" +void igc P((char *what, STACKITEM *stackbase)); + +#ifdef ARM_ULIB +# include <termio.h> +int set_erase() +{ + struct termio tin; + + ioctl(0, TCGETA, &tin); + tin.c_cc[VERASE] = '\010'; + + ioctl(0, TCSETA,&tin); + return(0); +} +#endif + +unsigned char upcase[CHAR_CODE_LIMIT]; +unsigned char downcase[CHAR_CODE_LIMIT]; +unsigned char lowers[] = "abcdefghijklmnopqrstuvwxyz"; +unsigned char uppers[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +extern int verbose; +void init_tables() +{ + int i; + for(i = 0;i<CHAR_CODE_LIMIT;i++) upcase[i] = downcase[i] = i; + for(i = 0;i<sizeof lowers/sizeof(char);i++) { + upcase[lowers[i]] = uppers[i]; + downcase[uppers[i]] = lowers[i]; + } + verbose = 1; /* Here so that monitor info won't be */ + /* printed while in init_storage. (BOOM) */ +} + +#ifdef EBCDIC +char *charnames[] = { + "nul","soh","stx","etx", "pf", "ht", "lc","del", + 0 , 0 ,"smm", "vt", "ff", "cr", "so", "si", + "dle","dc1","dc2","dc3","res", "nl", "bs", "il", + "can", "em", "cc", 0 ,"ifs","igs","irs","ius", + "ds","sos", "fs", 0 ,"byp", "lf","eob","pre", + 0 , 0 , "sm", 0 , 0 ,"enq","ack","bel", + 0 , 0 ,"syn", 0 , "pn", "rs", "uc","eot", + 0 , 0 , 0 , 0 ,"dc4","nak", 0 ,"sub", + "space", s_newline, "tab", "backspace", "return", "page", "null"}; +char charnums[] = +"\000\001\002\003\004\005\006\007\ +\010\011\012\013\014\015\016\017\ +\020\021\022\023\024\025\026\027\ +\030\031\032\033\034\035\036\037\ +\040\041\042\043\044\045\046\047\ +\050\051\052\053\054\055\056\057\ +\060\061\062\063\064\065\066\067\ +\070\071\072\073\074\075\076\077\ + \n\t\b\r\f\0"; +#endif /* def EBCDIC */ +#ifdef ASCII +char *charnames[] = { + "nul","soh","stx","etx","eot","enq","ack","bel", + "bs", "ht", "nl", "vt", "np", "cr", "so", "si", + "dle","dc1","dc2","dc3","dc4","nak","syn","etb", + "can", "em","sub","esc", "fs", "gs", "rs", "us", + "space", s_newline, "tab", "backspace", "return", "page", "null", "del"}; +char charnums[] = +"\000\001\002\003\004\005\006\007\ +\010\011\012\013\014\015\016\017\ +\020\021\022\023\024\025\026\027\ +\030\031\032\033\034\035\036\037\ + \n\t\b\r\f\0\177"; +#endif /* def ASCII */ +char *isymnames[] = { + /* Special Forms */ + /* NUM_ISPCSYMS ISPCSYMS here */ + "#@and", "#@begin", "#@case", "#@cond", "#@do", "#@if", "#@lambda", + "#@let", "#@let*", "#@letrec", "#@or", "#@quote", "#@set!", + "#@define", "#@apply", "#@call-with-current-continuation", + /* user visible ISYMS */ + /* other keywords */ + /* Flags */ + "#f", "#t", "#<undefined>", "#<eof>", "()", "#<unspecified>" + }; + +static char s_read_char[] = "read-char", s_peek_char[] = "peek-char"; +char s_read[] = "read", s_write[] = "write", s_newline[] = "newline"; +static char s_display[] = "display", s_write_char[] = "write-char"; + +static char s_eofin[] = "end of file in "; +static char s_unknown_sharp[] = "unknown # object"; + +static SCM lreadr P((SCM tok_buf, SCM port)); +static SCM lreadparen P((SCM tok_buf, SCM port, char *name)); +static sizet read_token P((int ic, SCM tok_buf, SCM port)); + +void intprint(n, radix, port) + long n; + int radix; + SCM port; +{ + char num_buf[INTBUFLEN]; + lfwrite(num_buf, (sizet)sizeof(char), iint2str(n, radix, num_buf), port); +} + +void ipruk(hdr, ptr, port) + char *hdr; + SCM ptr; + SCM port; +{ + lputs("#<unknown-", port); + lputs(hdr, port); + if CELLP(ptr) { + lputs(" (0x", port); + intprint(CAR(ptr), 16, port); + lputs(" . 0x", port); + intprint(CDR(ptr), 16, port); + lputs(") @", port); + } + lputs(" 0x", port); + intprint(ptr, 16, port); + lputc('>', port); +} + +void iprlist(hdr, exp, tlr, port, writing) + char *hdr, tlr; + SCM exp; + SCM port; + int writing; +{ + lputs(hdr, port); + /* CHECK_INTS; */ + iprin1(CAR(exp), port, writing); + exp = CDR(exp); + for(;NIMP(exp);exp = CDR(exp)) { + if NECONSP(exp) break; + lputc(' ', port); + /* CHECK_INTS; */ + iprin1(CAR(exp), port, writing); + } + if NNULLP(exp) { + lputs(" . ", port); + iprin1(exp, port, writing); + } + lputc(tlr, port); +} +void iprin1(exp, port, writing) + SCM exp; + SCM port; +int writing; +{ + register long i; +taloop: + switch (7 & (int)exp) { + case 2: + case 6: + intprint(INUM(exp), 10, port); + break; + case 4: + if ICHRP(exp) { + i = ICHR(exp); + if (writing) lputs("#\\", port); + if (!writing) lputc((int)i, port); + else if ((i <= ' ') && charnames[i]) lputs(charnames[i], port); +#ifndef EBCDIC + else if (i=='\177') + lputs(charnames[(sizeof charnames/sizeof(char *))-1], port); +#endif /* ndef EBCDIC */ + else if (i > '\177') + intprint(i, 8, port); + else lputc((int)i, port); + } + else if (IFLAGP(exp) && (ISYMNUM(exp)<(sizeof isymnames/sizeof(char *)))) + lputs(ISYMCHARS(exp), port); + else if ILOCP(exp) { + lputs("#@", port); + intprint((long)IFRAME(exp), 10, port); + lputc(ICDRP(exp)?'-':'+', port); + intprint((long)IDIST(exp), 10, port); + } + else goto idef; + break; + case 1: /* gloc */ + lputs("#@", port); + exp = CAR(exp-1); + goto taloop; + default: + idef: + ipruk("immediate", exp, port); + break; + case 0: + switch TYP7(exp) { + case tcs_cons_gloc: + case tcs_cons_imcar: + case tcs_cons_nimcar: + iprlist("(", exp, ')', port, writing); + break; + case tcs_closures: + exp = CODE(exp); + iprlist("#<CLOSURE ", exp, '>', port, writing); + break; + case tc7_string: + if (writing) { + lputc('\"', port); + for(i = 0;i<LENGTH(exp);++i) switch (CHARS(exp)[i]) { + case '"': + case '\\': + lputc('\\', port); + default: + lputc(CHARS(exp)[i], port); + } + lputc('\"', port); + break; + } + case tcs_symbols: + lfwrite(CHARS(exp), (sizet)sizeof(char), (sizet)LENGTH(exp), port); + break; + case tc7_vector: + lputs("#(", port); + for(i = 0;i+1<LENGTH(exp);++i) { + /* CHECK_INTS; */ + iprin1(VELTS(exp)[i], port, writing); + lputc(' ', port); + } + if (i<LENGTH(exp)) { + /* CHECK_INTS; */ + iprin1(VELTS(exp)[i], port, writing); + } + lputc(')', port); + break; + case tc7_bvect: + case tc7_ivect: + case tc7_uvect: + case tc7_fvect: + case tc7_dvect: + case tc7_cvect: + raprin1(exp, port, writing); + break; + case tcs_subrs: + lputs("#<primitive-procedure ", port); + lputs(CHARS(SNAME(exp)), port); + lputc('>', port); + break; +#ifdef CCLO + case tc7_cclo: + lputs("#<compiled-closure ", port); + iprin1(CCLO_SUBR(exp), port, writing); + lputc('>', port); + break; +#endif + case tc7_contin: + lputs("#<continuation ", port); + intprint(LENGTH(exp), 10, port); + lputs(" @ ", port); + intprint((long)CHARS(exp), 16, port); + lputc('>', port); + break; + case tc7_port: + i = PTOBNUM(exp); + if (i<numptob && ptobs[i].print && (ptobs[i].print)(exp, port, writing)) + break; + goto punk; + case tc7_smob: + i = SMOBNUM(exp); + if (i<numsmob && smobs[i].print && (smobs[i].print)(exp, port, writing)) + break; + goto punk; + default: punk: ipruk("type", exp, port); + } + } +} + +#ifdef __IBMC__ +# define MSDOS +#endif +#ifdef MSDOS +# ifndef GO32 +# include <io.h> +# include <conio.h> +static int input_waiting(f) + FILE *f; +{ + if (feof(f)) return 1; + if (fileno(f)==fileno(stdin) && (isatty(fileno(stdin)))) return kbhit(); + return -1; +} +# endif +#else +# ifdef _DCC +# include <ioctl.h> +# else +# ifndef AMIGA +# ifndef vms +# ifdef MWC +# include <sys/io.h> +# else +# ifndef THINK_C +# ifndef ARM_ULIB +# include <sys/ioctl.h> +# endif +# endif +# endif +# endif +# endif +# endif + +# ifdef HAVE_SELECT +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# endif +# endif + +static int input_waiting(f) + FILE *f; +{ +# ifdef HAVE_SELECT + fd_set ifds; + struct timeval tv; + + FD_ZERO(&ifds); + FD_SET(fileno(f), &ifds); + tv.tv_sec = 0; + tv.tv_usec = 0; + select((fileno(f) + 1), &ifds, (fd_set *) NULL, (fd_set *) NULL, &tv); + return FD_ISSET(fileno(f), &ifds); +# else +# ifdef FIONREAD + long remir; + if (feof(f)) return 1; + ioctl(fileno(f), FIONREAD, &remir); + return remir; +# else + return -1; +# endif +# endif +} +#endif +/* perhaps should undefine MSDOS from __IBMC__ here */ +#ifndef GO32 +static char s_char_readyp[]="char-ready?"; +SCM char_readyp(port) + SCM port; +{ + if UNBNDP(port) port = cur_inp; + else ASSERT(NIMP(port) && OPINPORTP(port), port, ARG1, s_char_readyp); + if (CRDYP(port) || !(BUF0 & CAR(port))) return BOOL_T; + return input_waiting(STREAM(port)) ? BOOL_T : BOOL_F; +} +#endif + +SCM eof_objectp(x) + SCM x; +{ + return (EOF_VAL==x) ? BOOL_T : BOOL_F; +} + +void lfflush(port) /* internal SCM call */ + SCM port; +{ + sizet i = PTOBNUM(port); + (ptobs[i].fflush)(STREAM(port)); +} +static char s_flush[] = "force-output"; +SCM lflush(port) /* user accessible as force-output */ + SCM port; +{ + if UNBNDP(port) port = cur_outp; + else ASSERT(NIMP(port) && OPOUTPORTP(port), port, ARG1, s_flush); + { + sizet i = PTOBNUM(port); + SYSCALL((ptobs[i].fflush)(STREAM(port));); + return UNSPECIFIED; + } +} + +SCM lwrite(obj, port) + SCM obj, port; +{ + if UNBNDP(port) port = cur_outp; + else ASSERT(NIMP(port) && OPOUTPORTP(port), port, ARG2, s_write); + iprin1(obj, port, 1); +#ifdef HAVE_PIPE +# ifdef EPIPE + if (EPIPE==errno) close_port(port); +# endif +#endif + return UNSPECIFIED; +} +SCM display(obj, port) + SCM obj, port; +{ + if UNBNDP(port) port = cur_outp; + else ASSERT(NIMP(port) && OPOUTPORTP(port), port, ARG2, s_display); + iprin1(obj, port, 0); +#ifdef HAVE_PIPE +# ifdef EPIPE + if (EPIPE==errno) close_port(port); +# endif +#endif + return UNSPECIFIED; +} +SCM newline(port) + SCM port; +{ + if UNBNDP(port) port = cur_outp; + else ASSERT(NIMP(port) && OPOUTPORTP(port), port, ARG1, s_newline); + lputc('\n', port); +#ifdef HAVE_PIPE +# ifdef EPIPE + if (EPIPE==errno) close_port(port); + else +# endif +#endif + if (port==cur_outp) lfflush(port); + return UNSPECIFIED; +} +SCM write_char(chr, port) + SCM chr, port; +{ + if UNBNDP(port) port = cur_outp; + else ASSERT(NIMP(port) && OPOUTPORTP(port), port, ARG2, s_write_char); + ASSERT(ICHRP(chr), chr, ARG1, s_write_char); + lputc((int)ICHR(chr), port); +#ifdef HAVE_PIPE +# ifdef EPIPE + if (EPIPE==errno) close_port(port); +# endif +#endif + return UNSPECIFIED; +} + +FILE *trans = 0; +SCM trans_on(fil) + SCM fil; +{ + transcript = open_file(fil, makfromstr("w", (sizet)sizeof(char))); + if FALSEP(transcript) trans = 0; + else trans = STREAM(transcript); + return UNSPECIFIED; +} +SCM trans_off() +{ + if (!FALSEP(transcript)) close_port(transcript); + transcript = BOOL_F; + trans = 0; + return UNSPECIFIED; +} + +void lputc(c, port) + int c; + SCM port; +{ + sizet i = PTOBNUM(port); + SYSCALL((ptobs[i].fputc)(c, STREAM(port));); + if (trans && (port==def_outp || port==cur_errp)) + SYSCALL(fputc(c, trans);); +} +void lputs(s, port) + char *s; + SCM port; +{ + sizet i = PTOBNUM(port); + SYSCALL((ptobs[i].fputs)(s, STREAM(port));); + if (trans && (port==def_outp || port==cur_errp)) + SYSCALL(fputs(s, trans);); +} +int lfwrite(ptr, size, nitems, port) + char *ptr; + sizet size; + sizet nitems; + SCM port; +{ + int ret; + sizet i = PTOBNUM(port); + SYSCALL(ret = (ptobs[i].fwrite) + (ptr, size, nitems, STREAM(port));); + if (trans && (port==def_outp || port==cur_errp)) + SYSCALL(fwrite(ptr, size, nitems, trans);); + return ret; +} + +int lgetc(port) + SCM port; +{ + FILE *f; + int c; + sizet i; + /* One char may be stored in the high bits of (car port) orre@nada.kth.se. */ + if CRDYP(port) + { + c = CGETUN(port); + CLRDY(port); /* Clear ungetted char */ + return c; + } + f=STREAM(port); + i = PTOBNUM(port); +#ifdef linux + c = (ptobs[i].fgetc)(f); +#else + SYSCALL(c = (ptobs[i].fgetc)(f);); +#endif + if (trans && (f==stdin)) SYSCALL(fputc(c, trans);); + return c; +} +void lungetc(c, port) + int c; + SCM port; +{ +/* ASSERT(!CRDYP(port), port, ARG2, "too many lungetc");*/ + CUNGET(c, port); +} + +SCM scm_read_char(port) + SCM port; +{ + int c; + if UNBNDP(port) port = cur_inp; + else ASSERT(NIMP(port) && OPINPORTP(port), port, ARG1, s_read_char); + c = lgetc(port); + if (EOF==c) return EOF_VAL; + return MAKICHR(c); +} +SCM peek_char(port) + SCM port; +{ + int c; + if UNBNDP(port) port = cur_inp; + else ASSERT(NIMP(port) && OPINPORTP(port), port, ARG1, s_peek_char); + c = lgetc(port); + if (EOF==c) return EOF_VAL; + lungetc(c, port); + return MAKICHR(c); +} + +char *grow_tok_buf(tok_buf) + SCM tok_buf; +{ + sizet len = LENGTH(tok_buf); + len += len / 2; + resizuve(tok_buf, (SCM)MAKINUM(len)); + return CHARS(tok_buf); +} + +static int flush_ws(port, eoferr) + SCM port; +char *eoferr; +{ + register int c; + while(1) switch (c = lgetc(port)) { + case EOF: +goteof: + if (eoferr) wta(UNDEFINED, s_eofin, eoferr); + return c; + case ';': +lp: + switch (c = lgetc(port)) { + case EOF: + goto goteof; + default: + goto lp; + case LINE_INCREMENTORS: + break; + } + case LINE_INCREMENTORS: + if (port==loadport) linum++; + case WHITE_SPACES: + break; + default: + return c; + } +} +SCM lread(port) + SCM port; +{ + int c; + SCM tok_buf; + if UNBNDP(port) port = cur_inp; + else ASSERT(NIMP(port) && OPINPORTP(port), port, ARG1, s_read); + do { + c = flush_ws(port, (char *)NULL); + if (EOF==c) return EOF_VAL; + lungetc(c, port); + tok_buf = makstr(30L); + } while (EOF_VAL==(tok_buf = lreadr(tok_buf, port))); + return tok_buf; +} +static SCM lreadr(tok_buf, port) + SCM tok_buf; +SCM port; +{ + int c; + sizet j; + SCM p; +tryagain: + c = flush_ws(port, s_read); + switch (c) { +/* case EOF: return EOF_VAL;*/ +#ifdef BRACKETS_AS_PARENS + case '[': +#endif + case '(': return lreadparen(tok_buf, port, s_list); +#ifdef BRACKETS_AS_PARENS + case ']': +#endif + case ')': warn("unexpected \")\"", ""); + goto tryagain; + case '\'': return cons2(i_quote, lreadr(tok_buf, port), EOL); + case '`': return cons2(i_quasiquote, lreadr(tok_buf, port), EOL); + case ',': + c = lgetc(port); + if ('@'==c) p = i_uq_splicing; + else { + lungetc(c, port); + p = i_unquote; + } + return cons2(p, lreadr(tok_buf, port), EOL); + case '#': + c = lgetc(port); + switch (c) { +#ifdef BRACKETS_AS_PARENS + case '[': +#endif + case '(': + p = lreadparen(tok_buf, port, s_vector); + return NULLP(p) ? nullvect : vector(p); + case 't': case 'T': return BOOL_T; + case 'f': case 'F': return BOOL_F; + case 'b': case 'B': case 'o': case 'O': + case 'd': case 'D': case 'x': case 'X': + case 'i': case 'I': case 'e': case 'E': + lungetc(c, port); + c = '#'; + goto num; + case '*': + j = read_token(c, tok_buf, port); + p = istr2bve(CHARS(tok_buf)+1, (long)(j-1)); + if (NFALSEP(p)) return p; + else goto unkshrp; + case '\\': + c = lgetc(port); + j = read_token(c, tok_buf, port); + if (j==1) return MAKICHR(c); + if (c >= '0' && c < '8') { + p = istr2int(CHARS(tok_buf), (long)j, 8); + if (NFALSEP(p)) return MAKICHR(INUM(p)); + } + for (c = 0;c<sizeof charnames/sizeof(char *);c++) + if (charnames[c] + && (0==strcmp(charnames[c], CHARS(tok_buf)))) + return MAKICHR(charnums[c]); + wta(UNDEFINED, "unknown # object: #\\", CHARS(tok_buf)); + case '|': + j = 1; /* here j is the comment nesting depth */ +lp: c = lgetc(port); +lpc: switch (c) { + case EOF: + wta(UNDEFINED, s_eofin, "balanced comment"); + case LINE_INCREMENTORS: + if (port==loadport) linum++; + default: + goto lp; + case '|': + if ('#' != (c = lgetc(port))) goto lpc; + if (--j) goto lp; + break; + case '#': + if ('|' != (c = lgetc(port))) goto lpc; + ++j; goto lp; + } + goto tryagain; + case '.': + p = lreadr(tok_buf, port); + return EVAL(p, (SCM)EOL); + default: callshrp: + p = CDR(intern("read:sharp", (sizeof "read:sharp")-1)); + if NIMP(p) { + p = apply(p, MAKICHR(c), acons(port, EOL, EOL)); + if (UNSPECIFIED==p) goto tryagain; + return p; + } + unkshrp: wta((SCM)MAKICHR(c), s_unknown_sharp, ""); + } + case '\"': + j = 0; + while ('\"' != (c = lgetc(port))) { + ASSERT(EOF != c, UNDEFINED, s_eofin, s_string); + if (j+1 >= LENGTH(tok_buf)) grow_tok_buf(tok_buf); + if (c=='\\') switch (c = lgetc(port)) { + case '\n': continue; + case '0': c = '\0'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'a': c = '\007'; break; + case 'v': c = '\v'; break; + } + CHARS(tok_buf)[j] = c; + ++j; + } + if (j==0) return nullstr; + CHARS(tok_buf)[j] = 0; + return makfromstr(CHARS(tok_buf), j); + case DIGITS: + case '.': case '-': case '+': +num: + j = read_token(c, tok_buf, port); + p = istring2number(CHARS(tok_buf), (long)j, 10L); + if NFALSEP(p) return p; + if (c=='#') { + if ((j==2) && (lgetc(port)=='(')) { + lungetc('(', port); + c = CHARS(tok_buf)[1]; + goto callshrp; + } + wta(UNDEFINED, s_unknown_sharp, CHARS(tok_buf)); + } + goto tok; + default: + j = read_token(c, tok_buf, port); +tok: + p = intern(CHARS(tok_buf), j); + return CAR(p); + } +} + +#ifdef _UNICOS +_Pragma("noopt"); /* # pragma _CRI noopt */ +#endif +static sizet read_token(ic, tok_buf, port) + int ic; + SCM tok_buf; + SCM port; +{ + register sizet j = 1; + register int c = ic; + register char *p = CHARS(tok_buf); + p[0] = downcase[c]; + while(1) { + if (j+1 >= LENGTH(tok_buf)) p = grow_tok_buf(tok_buf); + switch (c = lgetc(port)) { +#ifdef BRACKETS_AS_PARENS + case '[': case ']': +#endif + case '(': case ')': case '\"': case ';': + case ',': case '`': case '#': + case WHITE_SPACES: + case LINE_INCREMENTORS: + lungetc(c, port); + case EOF: + p[j] = 0; + return j; + default: + p[j++] = downcase[c]; + } + } +} +#ifdef _UNICOS +_Pragma("opt"); /* # pragma _CRI opt */ +#endif + +static SCM lreadparen(tok_buf, port, name) + SCM tok_buf; + SCM port; + char *name; +{ + SCM tmp, tl, ans; + int c = flush_ws(port, name); + if (')'==c +#ifdef BRACKETS_AS_PARENS + || ']'==c +#endif + ) return EOL; + lungetc(c, port); + if (i_dot==(tmp = lreadr(tok_buf, port))) { + ans = lreadr(tok_buf, port); + closeit: + if (')' != (c = flush_ws(port, name)) +#ifdef BRACKETS_AS_PARENS + && ']' != c +#endif + ) + wta(UNDEFINED, "missing close paren", ""); + return ans; + } + ans = tl = cons(tmp, EOL); + while (')' != (c = flush_ws(port, name)) +#ifdef BRACKETS_AS_PARENS + && ']' != c +#endif + ) { + lungetc(c, port); + if (i_dot==(tmp = lreadr(tok_buf, port))) { + CDR(tl) = lreadr(tok_buf, port); + goto closeit; + } + tl = (CDR(tl) = cons(tmp, EOL)); + } + return ans; +} + +/* These procedures implement synchronization primitives. Processors + with an atomic test-and-set instruction can use it here (and not + DEFER_INTS). */ +char s_tryarb[] = "try-arbiter"; +char s_relarb[] = "release-arbiter"; +long tc16_arbiter; +SCM tryarb(arb) + SCM arb; +{ + ASSERT((TYP16(arb)==tc16_arbiter), arb, ARG1, s_tryarb); + DEFER_INTS; + if (CAR(arb) & (1L<<16)) + arb = BOOL_F; + else { + CAR(arb) = tc16_arbiter | (1L<<16); + arb = BOOL_T; + } + ALLOW_INTS; + return arb; +} +SCM relarb(arb) + SCM arb; +{ + ASSERT((TYP16(arb)==tc16_arbiter), arb, ARG1, s_relarb); + if (!(CAR(arb) & (1L<<16))) return BOOL_F; + CAR(arb) = tc16_arbiter; + return BOOL_T; +} +SCM makarb(name) + SCM name; +{ + register SCM z; + NEWCELL(z); + CDR(z) = name; + CAR(z) = tc16_arbiter; + return z; +} +static int prinarb(exp, port, writing) + SCM exp; SCM port; int writing; +{ + lputs("#<arbiter ", port); + if (CAR(exp) & (1L<<16)) lputs("locked ", port); + iprin1(CDR(exp), port, writing); + lputc('>', port); + return !0; +} + +static char s_tryload[] = "try-load"; +#define s_load (&s_tryload[4]) + +struct errdesc {char *msg;char *s_response;short parent_err;}; +struct errdesc errmsgs[] = { + {"Wrong number of args", 0, 0}, + {"numerical overflow", 0, FPE_SIGNAL}, + {"Argument out of range", 0, FPE_SIGNAL}, + {"Could not allocate", "out-of-storage", 0}, + {"EXIT", "end-of-program", -1}, + {"hang up", "hang-up", EXIT}, + {"user interrupt", "user-interrupt", 0}, + {"arithmetic error", "arithmetic-error", 0}, + {"bus error", 0, 0}, + {"segment violation", 0, 0}, + {"alarm", "alarm-interrupt", 0} +}; + +int errjmp_bad = 1, ints_disabled = 1, sig_deferred = 0, alrm_deferred; +SCM err_exp, err_env; +char *err_pos, *err_s_subr; +cell tmp_errobj = {(SCM)UNDEFINED, (SCM)EOL}; +cell tmp_loadpath = {(SCM)BOOL_F, (SCM)EOL}; +SCM *loc_errobj = (SCM *)&tmp_errobj; +SCM *loc_loadpath = (SCM *)&tmp_loadpath; +SCM loadport = UNDEFINED; +long linum = 1; +int verbose = 1; +long cells_allocated = 0, lcells_allocated = 0, + mallocated = 0, lmallocated = 0, + rt = 0, gc_rt, gc_time_taken; +long gc_cells_collected, gc_malloc_collected, gc_ports_collected; +long gc_syms_collected; +static void def_err_response P((void)); + +int handle_it(i) + int i; +{ + char *name = errmsgs[i-WNA].s_response; + SCM proc; + if (errjmp_bad) return -1; /* sends it to def_err_response */ + if (name) { + NEWCELL(proc); /* discard possibly-used cell */ + proc = CDR(intern(name, (sizet)strlen(name))); + if NIMP(proc) { + apply(proc, EOL, EOL); + return i; + } + } + return errmsgs[i-WNA].parent_err; +} +static char s_eval_string[] = "eval-string"; +static char s_load_string[] = "load-string"; +SCM scm_eval_string(str) + SCM str; +{ + str = mkstrport(INUM0, str, OPN | RDNG, s_eval_string); + str = lread(str); + return EVAL(str, (SCM)EOL); +} +SCM scm_load_string(str) + SCM str; +{ + ASSERT(NIMP(str) && (STRINGP(str) || SYMBOLP(str)), str, ARG1, + s_load_string); + str = mkstrport(INUM0, str, OPN | RDNG, s_load_string); + while(1) { + SCM form = lread(str); + if (EOF_VAL==form) break; + SIDEVAL(form, EOL); + } + return BOOL_T; +} + +SCM exitval; /* INUM with return value */ +extern char s_unexec[]; +SCM repl_driver(initpath) + char *initpath; +{ +#ifdef _UNICOS + int i; +#else + long i; +#endif + CONT(rootcont)->stkbse = (STACKITEM *)&i; + i = setjmp(CONT(rootcont)->jmpbuf); +#ifndef SHORT_INT + if (i) i = UNCOOK(i); +#endif + /* printf("repl_driver got %d\n", i); */ + drloop: + switch ((int)i) { + default: { + char *name = errmsgs[i-WNA].s_response; + if (name) { + SCM proc = CDR(intern(name, (sizet)strlen(name))); + if NIMP(proc) apply(proc, EOL, EOL); + } + if ((i = errmsgs[i-WNA].parent_err)) goto drloop; + def_err_response(); + goto reset_toplvl; + } + case 0: + exitval = MAKINUM(EXIT_SUCCESS); + errjmp_bad = 0; + errno = 0; + alrm_deferred = 0; + sig_deferred = 0; + ints_disabled = 0; + if (dumped) { + lcells_allocated = cells_allocated; + lmallocated = mallocated; + rt = INUM(my_time()); + gc_time_taken = 0; + } + else if (scm_ldfile(initpath)) /* load Scheme init files */ + wta(*loc_errobj, "Could not open file", s_load); + scm_evstr("(boot-tail)"); /* initialization tail-call */ + case -2: /* abrt */ + reset_toplvl: + errjmp_bad = 0; + alrm_deferred = 0; + sig_deferred = 0; + ints_disabled = 0; + + /* Closing the loading file turned out to be a bad idea. */ + /* But I will leave the code here in case someone wants it. */ +#ifdef CLOSE_LOADING_PORTS_ON_ABORT + if (NIMP(loadport) && OPINPORTP(loadport)) { + if (verbose > 1) { + lputs("; Aborting load (closing): ", cur_errp); + display(*loc_loadpath, cur_errp); + newline(cur_errp); + } + close_port(loadport); /* close loading file. */ + } +#endif + *loc_loadpath = BOOL_F; + loadport = UNDEFINED; + repl(); + err_pos = (char *)EXIT; + i = EXIT; + goto drloop; /* encountered EOF on stdin */ + case -1: /* quit */ + return exitval; + case -3: /* restart. */ + return 0; +#ifdef CAN_DUMP + case -4: /* dump */ + igc(s_unexec, (STACKITEM *)0); + dumped = 1; + unexec(CHARS(*loc_errobj), execpath, 0, 0, 0); + goto reset_toplvl; +#endif + } +} + +SCM line_num() +{ + return MAKINUM(linum); +} +SCM prog_args() +{ + return progargs; +} + +extern char s_heap[]; +extern sizet hplim_ind; +extern CELLPTR *hplims; +void growth_mon(obj, size, units) + char *obj; + long size; + char *units; +{ + if (verbose>2) + { + lputs("; grew ", cur_errp); + lputs(obj, cur_errp); + lputs(" to ", cur_errp); + intprint(size, 10, cur_errp); + lputc(' ', cur_errp); + lputs(units, cur_errp); + if ((verbose>4) && (obj==s_heap)) heap_report(); + lputs("\n", cur_errp); + } +} + +void gc_start(what) + char *what; +{ + if (verbose>3 && FPORTP(cur_errp)) { + ALLOW_INTS; + lputs(";GC(", cur_errp); + lputs(what, cur_errp); + lputs(")", cur_errp); + lfflush(cur_errp); + DEFER_INTS; + } + gc_rt = INUM(my_time()); + gc_cells_collected = 0; + gc_malloc_collected = 0; + gc_ports_collected = 0; + gc_syms_collected = 0; +} +void gc_end() +{ + gc_rt = INUM(my_time()) - gc_rt; + gc_time_taken = gc_time_taken + gc_rt; + if (verbose>3) { + ALLOW_INTS; + if (!FPORTP(cur_errp)) lputs(";GC ", cur_errp); + intprint(time_in_msec(gc_rt), 10, cur_errp); + lputs(" cpu mSec, ", cur_errp); + intprint(gc_cells_collected, 10, cur_errp); + lputs(" cells, ", cur_errp); + intprint(gc_malloc_collected, 10, cur_errp); + lputs(" malloc, ", cur_errp); + intprint(gc_syms_collected, 10, cur_errp); + lputs(" syms, ", cur_errp); + intprint(gc_ports_collected, 10, cur_errp); + lputs(" ports collected\n", cur_errp); + lfflush(cur_errp); + DEFER_INTS; + } +} +void repl_report() +{ + if (verbose>1) { + lfflush(cur_outp); + lputs(";Evaluation took ", cur_errp); + intprint(time_in_msec(INUM(my_time())-rt), 10, cur_errp); + lputs(" mSec (", cur_errp); + intprint(time_in_msec(gc_time_taken), 10, cur_errp); + lputs(" in gc) ", cur_errp); + intprint(cells_allocated - lcells_allocated, 10, cur_errp); + lputs(" cells work, ", cur_errp); + intprint(mallocated - lmallocated, 10, cur_errp); + lputs(" bytes other\n", cur_errp); + lfflush(cur_errp); + } +} +SCM lroom(args) + SCM args; +{ + intprint(cells_allocated, 10, cur_errp); + lputs(" out of ", cur_errp); + intprint(heap_size, 10, cur_errp); + lputs(" cells in use, ", cur_errp); + intprint(mallocated, 10, cur_errp); + lputs(" bytes allocated (of ", cur_errp); + intprint(mtrigger, 10, cur_errp); + lputs(")\n", cur_errp); + if NIMP(args) { + heap_report(); + lputs("\n", cur_errp); + stack_report(); + } + return UNSPECIFIED; +} +void heap_report() +{ + sizet i = 0; + lputs("; heap segments:", cur_errp); + while(i<hplim_ind) { + lputs("\n; 0x", cur_errp); + intprint((long)hplims[i++], 16, cur_errp); + lputs(" - 0x", cur_errp); + intprint((long)hplims[i++], 16, cur_errp); + } +} +void exit_report() +{ + if (verbose>2) { + lputs(";Totals: ", cur_errp); + intprint(time_in_msec(INUM(my_time())), 10, cur_errp); + lputs(" mSec my time, ", cur_errp); + intprint(time_in_msec(INUM(your_time())), 10, cur_errp); + lputs(" mSec your time\n", cur_errp); + } +} + +SCM prolixity(arg) + SCM arg; +{ + int old = verbose; + if (!UNBNDP(arg)) { + if FALSEP(arg) verbose = 1; + else verbose = INUM(arg); + } + return MAKINUM(old); +} + +void repl() +{ + SCM x; + repl_report(); + while(1) { + if OPOUTPORTP(cur_inp) { /* This case for curses window */ + lfflush(cur_outp); + if (verbose) lputs(PROMPT, cur_inp); + lfflush(cur_inp); + } + else { + if (verbose) lputs(PROMPT, cur_outp); + lfflush(cur_outp); + } + lcells_allocated = cells_allocated; + lmallocated = mallocated; + x = lread(cur_inp); + rt = INUM(my_time()); + gc_time_taken = 0; + if (EOF_VAL==x) break; + if (!CRDYP(cur_inp)) /* assure newline read (and transcripted) */ + lungetc(lgetc(cur_inp), cur_inp); +#ifdef __TURBOC__ + if ('\n' != CGETUN(cur_inp)) + if OPOUTPORTP(cur_inp) /* This case for curses window */ + {lfflush(cur_outp); newline(cur_inp);} + else newline(cur_outp); +#endif + x = EVAL(x, (SCM)EOL); + repl_report(); + iprin1(x, cur_outp, 1); + lputc('\n', cur_outp); + } +} +SCM quit(n) + SCM n; +{ + if (UNBNDP(n) || BOOL_T==n) n = MAKINUM(EXIT_SUCCESS); + else if INUMP(n) exitval = n; + else exitval = MAKINUM(EXIT_FAILURE); + if (errjmp_bad) exit(INUM(exitval)); + dowinds(EOL, ilength(dynwinds)); + longjmp(CONT(rootcont)->jmpbuf, COOKIE(-1)); +} +SCM abrt() +{ + if (errjmp_bad) exit(INUM(exitval)); + dowinds(EOL, ilength(dynwinds)); +#ifdef CAUTIOUS + stacktrace = EOL; +#endif + longjmp(CONT(rootcont)->jmpbuf, COOKIE(-2)); +} +char s_restart[] = "restart"; +SCM restart() +{ + /* ASSERT(!dumped, UNDEFINED, "dumped can't", s_restart); */ + dowinds(EOL, ilength(dynwinds)); +#ifdef CAUTIOUS + stacktrace = EOL; +#endif + longjmp(CONT(rootcont)->jmpbuf, COOKIE(-3)); +} + +#ifdef CAN_DUMP +char s_unexec[] = "unexec"; +SCM scm_unexec(newpath) + SCM newpath; +{ + ASSERT(NIMP(newpath) && STRINGP(newpath), newpath, ARG1, s_unexec); + *loc_errobj = newpath; +# ifdef CAUTIOUS + stacktrace = EOL; +# endif + longjmp(CONT(rootcont)->jmpbuf, COOKIE(-4)); +} +#endif + +char s_execpath[] = "execpath"; +SCM scm_execpath(newpath) + SCM newpath; +{ + SCM retval = execpath ? makfrom0str(execpath) : BOOL_F; + if (UNBNDP(newpath)) + return retval; + if (FALSEP(newpath)) { + if (execpath) free(execpath); + execpath = 0; + return retval; + } + ASSERT(NIMP(newpath) && STRINGP(newpath), newpath, ARG1, s_execpath); + if (execpath) free(execpath); + execpath = scm_cat_path(0L, CHARS(newpath), 0L); + return retval; +} + +void han_sig() +{ + sig_deferred = 0; + if (INT_SIGNAL != handle_it(INT_SIGNAL)) + wta(UNDEFINED, (char *)INT_SIGNAL, ""); +} +void han_alrm() +{ + alrm_deferred = 0; + if (ALRM_SIGNAL != handle_it(ALRM_SIGNAL)) + wta(UNDEFINED, (char *)ALRM_SIGNAL, ""); +} + +SCM tryload(filename) + SCM filename; +{ + ASSERT(NIMP(filename) && STRINGP(filename), filename, ARG1, s_load); + { + SCM oloadpath = *loc_loadpath; + SCM oloadport = loadport; + long olninum = linum; + SCM port, newform = BOOL_F; + port = open_file(filename, makfromstr("r", (sizet)sizeof(char))); + if FALSEP(port) return port; + *loc_loadpath = filename; + loadport = port; + linum = 1; + while(1) { + SCM form = newform; + newform = lread(port); + if (EOF_VAL==newform) { + close_port(port); + linum = olninum; + loadport = oloadport; + *loc_loadpath = oloadpath; + SIDEVAL(form, EOL); + return BOOL_T; + } + SIDEVAL(form, EOL); + } + } + return BOOL_T; +} +#ifdef CAUTIOUS +void scm_print_stack(stk) + SCM stk; +{ + switch (ilength(stk)) { + case -1: + lputs("\n; circular stacktrace!", cur_errp); + return; + case -2: + lputs("\n; stacktrace not a list?", cur_errp); + iprin1(stk, cur_errp, 1); + return; + default: + while NNULLP(stk) { + SCM ste = CAR(stk); + lputc('\n', cur_errp); + iprin1(ste, cur_errp, 1); + stk = CDR(stk); + } + } +} +SCM scm_stack_trace() +{ + if (0==ilength(stacktrace)) return BOOL_F; + scm_print_stack(stacktrace); + return BOOL_T; +} +#endif + +static void err_head(str) + char *str; +{ + int oerrno = errno; + exitval = MAKINUM(EXIT_FAILURE); + if NIMP(cur_outp) lfflush(cur_outp); + lputc('\n', cur_errp); + if(BOOL_F != *loc_loadpath) { + iprin1(*loc_loadpath, cur_errp, 1); + lputs(", line ", cur_errp); + intprint((long)linum, 10, cur_errp); + lputs(": ", cur_errp); + } + lfflush(cur_errp); + errno = oerrno; + if (cur_errp==def_errp) { + if (errno>0) perror(str); + fflush(stderr); + return; + } +} +void warn(str1, str2) + char *str1, *str2; +{ + err_head("WARNING"); + lputs("WARNING: ", cur_errp); + lputs(str1, cur_errp); + lputs(str2, cur_errp); + lputc('\n', cur_errp); + lfflush(cur_errp); +} + +SCM lerrno(arg) + SCM arg; +{ + int old = errno; + if (!UNBNDP(arg)) { + if FALSEP(arg) errno = 0; + else errno = INUM(arg); + } + return MAKINUM(old); +} +static char s_perror[] = "perror"; +SCM lperror(arg) + SCM arg; +{ + ASSERT(NIMP(arg) && STRINGP(arg), arg, ARG1, s_perror); + err_head(CHARS(arg)); + return UNSPECIFIED; +} +static void def_err_response() +{ + SCM obj = *loc_errobj; +#ifdef CAUTIOUS + SCM stk = stacktrace; +#endif + DEFER_INTS; + err_head("ERROR"); + lputs("ERROR: ", cur_errp); + if (err_s_subr && *err_s_subr) { + lputs(err_s_subr, cur_errp); + lputs(": ", cur_errp); + } + if (err_pos==(char *)ARG1 && UNBNDP(*loc_errobj)) err_pos = (char *)WNA; +#ifdef nosve + if ((~0x1fL) & (short)err_pos) lputs(err_pos, cur_errp); + else if (WNA>(short)err_pos) { + lputs("Wrong type in arg", cur_errp); + lputc(err_pos ? '0'+(short)err_pos : ' ', cur_errp); + } +#else + if ((~0x1fL) & (long)err_pos) lputs(err_pos, cur_errp); + else if (WNA>(long)err_pos) { + lputs("Wrong type in arg", cur_errp); + lputc(err_pos ? '0'+(int)err_pos : ' ', cur_errp); + } +#endif + else { + lputs(errmsgs[((int)err_pos)-WNA].msg, cur_errp); + goto outobj; + } + if (IMP(obj) || SYMBOLP(obj) || (TYP16(obj)==tc7_port) + || (NFALSEP(procedurep(obj))) || (NFALSEP(numberp(obj)))) { +outobj: + if (!UNBNDP(obj)) { + lputs(((long)err_pos==WNA)?" given ":" ", cur_errp); + iprin1(obj, cur_errp, 1); + } + } + else lputs(" (see errobj)", cur_errp); +#ifdef CAUTIOUS + if NNULLP(stk) scm_print_stack(stk); +#endif + if UNBNDP(err_exp) goto getout; + if NIMP(err_exp) { + lputs("\n; in expression: ", cur_errp); + if NCONSP(err_exp) iprin1(err_exp, cur_errp, 1); + else if (UNDEFINED==CDR(err_exp)) + iprin1(CAR(err_exp), cur_errp, 1); + else iprlist("(... ", err_exp, ')', cur_errp, 1); + } + if NULLP(err_env) lputs("\n; in top level environment.", cur_errp); + else { + SCM env = err_env; + lputs("\n; in scope:", cur_errp); + while NNULLP(env) { + lputc('\n', cur_errp); + lputs("; ", cur_errp); + iprin1(CAR(CAR(env)), cur_errp, 1); + env = CDR(env); + } + } + getout: + lputc('\n', cur_errp); + lfflush(cur_errp); + err_exp = err_env = UNDEFINED; + if (errjmp_bad) { + iprin1(obj, cur_errp, 1); + lputs("\nFATAL ERROR DURING CRITICAL CODE SECTION\n", cur_errp); +#ifdef vms + exit(EXIT_FAILURE); +#else + exit(errno? (long)errno : EXIT_FAILURE); +#endif + } + errno = 0; + ALLOW_INTS; +} +void everr(exp, env, arg, pos, s_subr) + SCM exp, env, arg; + char *pos, *s_subr; +{ + err_exp = exp; + err_env = env; + *loc_errobj = arg; + err_pos = pos; + err_s_subr = s_subr; +#ifndef CAUTIOUS + if (((~0x1fL) & (long)pos) || (WNA>(long)pos) + || NIMP(dynwinds) || errjmp_bad) +#endif + { + def_err_response(); + dowinds(EOL, ilength(dynwinds)); + abrt(); + } +#ifndef CAUTIOUS + /* We don't have to clear stacktrace because CAUTIOUS never gets here */ + /* We don't have to dowinds() because dynwinds is EOL */ + longjmp(CONT(rootcont)->jmpbuf, COOKIE((int)pos)); + /* will do error processing at stack base */ +#endif +} +void wta(arg, pos, s_subr) + SCM arg; +char *pos, *s_subr; +{ + everr(UNDEFINED, EOL, arg, pos, s_subr); +} +SCM cur_input_port() +{ + return cur_inp; +} +SCM cur_output_port() +{ + return cur_outp; +} +SCM cur_error_port() +{ + return cur_errp; +} +char s_cur_inp[] = "set-current-input-port"; +char s_cur_outp[] = "set-current-output-port"; +char s_cur_errp[] = "set-current-error-port"; +SCM set_inp(port) + SCM port; +{ + SCM oinp = cur_inp; + ASSERT(NIMP(port) && OPINPORTP(port), port, ARG1, s_cur_inp); + cur_inp = port; + return oinp; +} +SCM set_outp(port) + SCM port; +{ + SCM ooutp = cur_outp; + ASSERT(NIMP(port) && OPOUTPORTP(port), port, ARG1, s_cur_outp); + cur_outp = port; + return ooutp; +} +SCM set_errp(port) + SCM port; +{ + SCM oerrp = cur_errp; + ASSERT(NIMP(port) && OPOUTPORTP(port), port, ARG1, s_cur_errp); + cur_errp = port; + return oerrp; +} + +static iproc subr0s[] = { + {&s_cur_inp[4], cur_input_port}, + {&s_cur_outp[4], cur_output_port}, + {&s_cur_errp[4], cur_error_port}, + {"transcript-off", trans_off}, + {"program-arguments", prog_args}, + {"line-number", line_num}, + {"abort", abrt}, + {s_restart, restart}, +#ifdef CAUTIOUS + {"stack-trace", scm_stack_trace}, +#endif + {0, 0}}; + +static iproc subr1s[] = { + {s_cur_inp, set_inp}, + {s_cur_outp, set_outp}, + {s_cur_errp, set_errp}, + {"transcript-on", trans_on}, + {s_tryload, tryload}, + {s_load_string, scm_load_string}, + {s_eval_string, scm_eval_string}, + {s_perror, lperror}, + {"make-arbiter", makarb}, + {s_tryarb, tryarb}, + {s_relarb, relarb}, + {0, 0}}; + +static iproc subr1os[] = { + {s_read, lread}, + {s_read_char, scm_read_char}, + {s_peek_char, peek_char}, + {s_newline, newline}, + {s_flush, lflush}, +#ifndef GO32 + {s_char_readyp, char_readyp}, +#endif + {"quit", quit}, + {"verbose", prolixity}, + {"errno", lerrno}, + {s_execpath, scm_execpath}, + {0, 0}}; + +static iproc subr2os[] = { + {s_write, lwrite}, + {s_display, display}, + {s_write_char, write_char}, +#ifdef CAN_DUMP + {s_unexec, scm_unexec}, +#endif + {0, 0}}; + +static smobfuns arbsmob = {markcdr, free0, prinarb}; +char s_ccl[] = "char-code-limit"; + +void init_repl( iverbose ) + int iverbose; +{ + sysintern(s_ccl, MAKINUM(CHAR_CODE_LIMIT)); + loc_errobj = &CDR(sysintern("errobj", UNDEFINED)); + loc_loadpath = &CDR(sysintern("*load-pathname*", BOOL_F)); + transcript = BOOL_F; + trans = 0; + linum = 1; + verbose = iverbose; + init_iprocs(subr0s, tc7_subr_0); + init_iprocs(subr1os, tc7_subr_1o); + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(subr2os, tc7_subr_2o); + make_subr("room", tc7_lsubr, lroom); +#ifndef GO32 + add_feature(s_char_readyp); +#endif +#ifdef CAN_DUMP + if (!execpath) execpath = dld_find_executable(CHARS(CAR(progargs))); + add_feature("dump"); + scm_ldstr("\ +(define (dump file . thunk)\n\ + (cond ((null? thunk) (set! *interactive* #f) (set! *argv* #f))\n\ + ((not (car thunk)) (set! *argv* #f))\n\ + ((boolean? (car thunk)))\n\ + (else (set! boot-tail (car thunk))))\n\ + (set! restart exec-self)\n\ + (unexec file))\n\ +"); +#endif +#ifdef ARM_ULIB + set_erase(); +#endif + tc16_arbiter = newsmob(&arbsmob); +} +void final_repl() +{ + loc_errobj = (SCM *)&tmp_errobj; + loc_loadpath = (SCM *)&tmp_loadpath; + loadport = UNDEFINED; + transcript = BOOL_F; + trans = 0; + linum = 1; +} @@ -0,0 +1,661 @@ +#include "scm.h" +#include "regex.h" +#include <stdio.h> + +static char rcsid[] = + "$Id: rgx.c, v 1.20 1995/02/15 04:39:45 dpb Exp $"; + +#ifdef HAVE_ALLOCA +# include <alloca.h> +# define ALLOCA_PROTECT typedef int foobazzz +# define ALLOCA alloca +#else +# define ALLOCA_PROTECT SCM alloca_protect=EOL +# define ALLOCA(size) \ + (alloca_protect=cons(makstr((long)(size)), alloca_protect), \ + (void *)CDR(CAR(alloca_protect))) + +#endif + +#ifdef _GNU_SOURCE +/* following two lines stolen from GNU regex.c */ +# define CHAR_SET_SIZE 256 +# define ISUPPER(c) (isascii (c) && isupper (c)) +#endif + +/* forward function defs */ + +SCM lregsearch(); +SCM lregsearchv(); + +/* Posix regexp bindings. */ + +static char s_regex[] = "regex"; +static char s_regcomp[] = "regcomp", s_regerror[] = "regerror"; +static char s_regexec[] = "regexec", s_regmatp[] = "regmatch?"; +static char s_regsearch[] = "regsearch", s_regmatch[] = "regmatch"; +static char s_regsearchv[] = "regsearchv", s_regmatchv[] = "regmatchv"; +static char s_stringsplit[] = "string-split"; +static char s_stringsplitv[] = "string-splitv"; +static char s_stringedit[] = "string-edit"; + +#define s_error &s_regerror[3] + +#define RGX_INFO(obj) ((regex_info*)CDR(obj)) +#define RGX_PATTERN(obj) (((regex_info*)CDR(obj))->pattern) +#define RGX(obj) (&((regex_info*)CDR(obj))->rgx) +#ifndef _GNU_SOURCE +# define RGX2(obj) (&((regex_info*)CDR(obj))->rgx_anchored) +#endif + +#define FIXUP_REGEXP(prog) \ +{ \ + if (STRINGP(prog)) \ + prog = lregcomp(prog, UNDEFINED); \ + if (NIMP(prog) && CONSP(prog) && STRINGP(CAR(prog)) && \ + NIMP(CDR(prog)) && CONSP(CDR(prog)) && STRINGP(CAR(CDR(prog)))) \ + prog = lregcomp(CAR(prog), CAR(CDR(prog))); \ +} + +typedef struct regex_info { + SCM pattern; /* string we compiled to create our reg exp */ + regex_t rgx; +#ifndef _GNU_SOURCE + int options; /* for anchored pattern when matching */ + regex_t rgx_anchored; +#endif +} regex_info; + +sizet fregex(ptr) + CELLPTR ptr; +{ + regfree(RGX(ptr)); +#ifndef _GNU_SOURCE + /* options are null => we compiled the anchored pattern */ + if (RGX_INFO(ptr)->options==NULL) + regfree(RGX2(ptr)); +#endif + free(CHARS(ptr)); + return sizeof(regex_t); +} + +int prinregex(exp, port, writing) + SCM exp; SCM port; int writing; +{ + lputs("#<regex ", port); + intprint(CDR(exp), 16, port); + lputc(' ', port); + iprin1(RGX_PATTERN(exp), port, writing); + lputc('>', port); + return 1; +} + +SCM markregex(ptr) + SCM ptr; +{ + SETGC8MARK(ptr); + SETGC8MARK(RGX_PATTERN(ptr)); + return BOOL_F; +} + +int tc16_rgx; +static smobfuns rgxsmob = {markregex, fregex, prinregex}; + +SCM lregerror(scode) + SCM scode; +{ + int code, len; + SCM str; + ASSERT(INUMP(scode), scode, ARG1, s_regerror); + code = INUM(scode); + if (code < 0) + return makfromstr("Invalid code", sizeof("Invalid code")-1); + /* XXX - is regerror posix or not? */ +#ifdef __REGEXP_LIBRARY_H__ + /* XXX - gnu regexp doesn't use the re parameter, so we will + ignore it in a very untidy way. */ + len = regerror(code, 0, 0, 0); + str = makstr(len-1); + regerror(code, 0, CHARS(str), len); +#else + str = makfromstr(s_error, (sizet)5); +#endif + return str; +} + +SCM lregcomp(pattern, flags) + SCM pattern, flags; +{ + SCM z; + int i, options; + regex_t *prog; + regex_info *info; + char *flagchars; +#ifdef _GNU_SOURCE + int fastmap = 0; + int ignore_case = 0; + char *err_msg; +#endif + + ASSERT(NIMP(pattern) && STRINGP(pattern), pattern, ARG1, s_regcomp); + ASSERT(UNBNDP(flags) || (NIMP(flags) && STRINGP(flags)), + flags, ARG2, s_regcomp); + NEWCELL(z); + DEFER_INTS; + SETCHARS(z, info=(regex_info*)must_malloc((long)sizeof(regex_info), s_regex)); + prog = &(info->rgx); + CAR(z) = tc16_rgx; +#ifdef __REGEXP_LIBRARY_H__ + for(i=sizeof(regex_t);i--;((char *)prog)[i] = 0); +# ifndef _GNU_SOURCE + { + regex_t *prog2; + prog2 = &(info->rgx_anchored); + for(i=sizeof(regex_t);i--;((char *)prog2)[i] = 0); + } +# endif +#endif + + ALLOW_INTS; + info->pattern = pattern; + +#ifdef _GNU_SOURCE + options = RE_SYNTAX_POSIX_EXTENDED; +#else + options = REG_EXTENDED; +#endif + + if (!UNBNDP(flags)) { + flagchars = CHARS(flags); + for (i=0; i<LENGTH(flags); i++) + switch (flagchars[i]) { +#ifdef _GNU_SOURCE + case 'n': + options |= RE_HAT_LISTS_NOT_NEWLINE; + options &= (~RE_DOT_NEWLINE); + break; + case 'i': + ignore_case = 1; + break; + case '0': + options &= (~RE_DOT_NOT_NULL); + break; + case 'f': + fastmap = 1; + break; +#else + case 'n': + options |= REG_NEWLINE; + break; + case 'i': + options |= REG_ICASE; + break; +#endif + } + } + +#ifdef _GNU_SOURCE + DEFER_INTS; + if (fastmap) + prog->fastmap = must_malloc(CHAR_SET_SIZE, s_regex); + + if (ignore_case) { + prog->translate = must_malloc(CHAR_SET_SIZE, s_regex); + for (i = 0; i < CHAR_SET_SIZE; i++) + prog->translate[i] = ISUPPER (i) ? tolower (i) : i; + } + + re_set_syntax(options); + err_msg = (char *)re_compile_pattern(CHARS(pattern), LENGTH(pattern), prog); + ALLOW_INTS; + prog->regs_allocated = REGS_FIXED; + + /* if error, compile using regcomp to get the error number */ + if (err_msg) { + int i; + char *tmppat; + SCM protect; + + /* Fixup in case pattern has null characters */ + tmppat = CHARS(protect=makstr(LENGTH(pattern))); + bcopy(CHARS(pattern), tmppat, LENGTH(pattern)); + for (i=0; i<LENGTH(pattern); i++) + if (tmppat[i] == 0) + tmppat[i] = ' '; + + i = regcomp(prog, tmppat, options); + z = MAKINUM(i); + } +#else + info->options = options; + i = regcomp(prog, CHARS(pattern), options); + if (i) z = MAKINUM(i); +#endif + return z; +} + +SCM lregexec(prog, str) + SCM prog, str; +{ + ALLOCA_PROTECT; + + FIXUP_REGEXP(prog); + ASSERT(NIMP(prog) && tc16_rgx==CAR(prog), prog, ARG1, s_regexec); + ASSERT(NIMP(str) && STRINGP(str), str, ARG2, s_regexec); + +#ifdef _GNU_SOURCE + return lregsearchv(prog, str, EOL); +#else /* not _GNU_SOURCE */ + { + size_t nsub; + SCM ans; + regmatch_t *pm; + int flags = 0; /* XXX - optional arg? */ + + nsub = RGX(prog)->re_nsub + 1; /* XXX - is this posix? */ + pm = ALLOCA(nsub * sizeof(regmatch_t)); + if (regexec(RGX(prog), CHARS(str), nsub, pm, flags) != 0) + ans = BOOL_F; + else { + ans = make_vector(MAKINUM(2L * nsub), MAKINUM(-1L)); + while (nsub--) { + VELTS(ans)[2*nsub+0] = MAKINUM(pm[nsub].rm_so); + VELTS(ans)[2*nsub+1] = MAKINUM(pm[nsub].rm_eo); + } + } + return ans; + } +#endif /* _GNU_SOURCE */ +} + +SCM lregmatp(prog, str) + SCM prog, str; +{ + FIXUP_REGEXP(prog); + ASSERT(NIMP(prog) && tc16_rgx==CAR(prog), prog, ARG1, s_regmatp); + ASSERT(NIMP(str) && STRINGP(str), str, ARG2, s_regmatp); + +#ifdef _GNU_SOURCE + return (lregsearch(prog, str, EOL)==BOOL_F)?BOOL_F:BOOL_T; +#else /* not _GNU_SOURCE */ + { + int flags = 0; /* XXX - optional arg? */ + + flags = regexec(RGX(prog), CHARS(str), 0, NULL, flags); + if (!flags) return BOOL_T; + if (REG_NOMATCH!=flags) wta(MAKINUM(flags), s_error, s_regmatp); + return BOOL_F; + } +#endif +} + +#define SCALAR 0 +#define VECTOR 1 + +#define MATCH 0 +#define SEARCH 1 + +SCM lregsearchmatch(prog, str, args, search, vector) + SCM prog, str, args; + int vector, search; +{ + int len = ilength(args); + int start, size, nsub; + SCM matches; + ALLOCA_PROTECT; + + FIXUP_REGEXP(prog); + ASSERT(NIMP(prog) && tc16_rgx==CAR(prog), prog, ARG1, s_regsearch); + ASSERT(NIMP(str) && STRINGP(str), str, ARG2, s_regsearch); + ASSERT(len<=2, args, WNA, s_regsearch); + ASSERT((len<1)||(INUMP(CAR(args))), CAR(args), ARG3, s_regsearch); + ASSERT((len<2)||(INUMP(CAR(CDR(args)))), CAR(CDR(args)), ARG4, s_regsearch); + + start = (len>=1)?(INUM(CAR(args))):0; + size = (len>=2)?(INUM(CAR(CDR(args)))):LENGTH(str); + +#ifdef _GNU_SOURCE + { + int ret, dir=1; + struct re_registers regs, *pregs=NULL; + + if (search && start<0) + start *= -1, dir = -1; + + if (vector) { + pregs = ®s; + nsub = RGX(prog)->re_nsub + 1; + regs.num_regs = nsub; + + regs.start = ALLOCA(nsub * sizeof(regoff_t)); + regs.end = ALLOCA(nsub * sizeof(regoff_t)); + } + + if (search) + ret = re_search(RGX(prog), CHARS(str), size, start, dir*size, pregs); + else + ret = re_match(RGX(prog), CHARS(str), size, start, pregs); + + if (ret < 0) + return BOOL_F; + + if (!vector) + return MAKINUM(ret); + + matches = make_vector(MAKINUM(2L * nsub), MAKINUM(-1L)); + while (nsub--) { + VELTS(matches)[2*nsub+0] = MAKINUM(regs.start[nsub]); + VELTS(matches)[2*nsub+1] = MAKINUM(regs.end[nsub]); + } + return matches; + } +#else /* not _GNU_SOURCE */ + { + regex_t *regexp; + regmatch_t *pm; + char *search_string; + if (size > LENGTH(str)) + size = LENGTH(str); + + if (start<0 || start >= size) + return BOOL_F; + + if (size < LENGTH(str)) { + search_string = ALLOCA(size-start+1); + bcopy(CHARS(str)+start, search_string, size-start); + search_string[size-start] = 0; + } else + search_string = CHARS(str)+start; + + nsub = RGX(prog)->re_nsub + 1; + pm = ALLOCA(nsub * sizeof(regmatch_t)); + if (search) + regexp = RGX(prog); + else { + /* doing a match */ + if (RGX_INFO(prog)->options) { + /* strlen & strcpy OK, posix patterns are null terminated */ + char *pattern; + + pattern = ALLOCA(strlen(CHARS(RGX_PATTERN(prog)))+2); + pattern[0] = '^'; + strcpy(pattern+1, CHARS(RGX_PATTERN(prog))); + regcomp(RGX2(prog), pattern, RGX_INFO(prog)->options); + RGX_INFO(prog)->options = 0; + } + regexp = RGX2(prog); + } + + if (regexec(regexp, search_string, nsub, pm, 0) != 0) + return BOOL_F; + + if (vector) { + matches = make_vector(MAKINUM(2L * nsub), MAKINUM(-1L)); + while (nsub--) { + VELTS(matches)[2*nsub+0] = MAKINUM(pm[nsub].rm_so + start); + VELTS(matches)[2*nsub+1] = MAKINUM(pm[nsub].rm_eo + start); + } + return matches; + } + + if (search) + return MAKINUM(pm[0].rm_so + start); + else + return MAKINUM(pm[0].rm_eo - pm[0].rm_so); + } + +#endif /* _GNU_SOURCE */ +} + +SCM lregsearch(prog, str, args) + SCM prog, str, args; +{ + return lregsearchmatch(prog, str, args, SEARCH, SCALAR); +} + +SCM lregsearchv(prog, str, args) + SCM prog, str, args; +{ + return lregsearchmatch(prog, str, args, SEARCH, VECTOR); +} + +SCM lregmatch(prog, str, args) + SCM prog, str, args; +{ + return lregsearchmatch(prog, str, args, MATCH, SCALAR); +} + +SCM lregmatchv(prog, str, args) + SCM prog, str, args; +{ + return lregsearchmatch(prog, str, args, MATCH, VECTOR); +} + +SCM stringsplitutil(prog, str, vector) + SCM prog, str; + int vector; +{ + int anchor, match_start, match_end, num_substrings, num_elements; + int search_base; + SCM next_break, substrings, ret; + SCM st_start, st_end; + + FIXUP_REGEXP(prog); + ASSERT(NIMP(prog) && tc16_rgx==CAR(prog), prog, ARG1, s_stringsplit); + ASSERT(NIMP(str) && STRINGP(str), str, ARG2, s_stringsplit); + + substrings = EOL; + anchor = 0; + search_base = 0; + num_substrings = 0; + next_break = lregsearchv(prog, str, cons(MAKINUM(search_base), EOL)); + + while (next_break != BOOL_F) { + match_start = INUM(VELTS(next_break)[0]); + match_end = INUM(VELTS(next_break)[1]); + + if (match_start < match_end) { + substrings=cons2(MAKINUM(anchor), MAKINUM(match_start), substrings); + anchor = match_end; + num_substrings++; + } + + search_base = ((match_end>search_base)?match_end:(search_base+1)); + next_break = lregsearchv(prog, str, cons(MAKINUM(search_base), EOL)); + } + + /* get that tail bit */ + if (anchor < LENGTH(str)) { + substrings = cons2(MAKINUM(anchor), MAKINUM(LENGTH(str)), substrings); + num_substrings++; + } + + num_elements = vector?(2*num_substrings):num_substrings; + ret = make_vector(MAKINUM(num_elements), EOL); + + while (num_substrings--) { + st_start = CAR(substrings); + st_end = CAR(CDR(substrings)); + + if (vector) { + VELTS(ret)[num_substrings*2+0] = st_start; + VELTS(ret)[num_substrings*2+1] = st_end; + } else + VELTS(ret)[num_substrings] = substring(str, st_start, st_end); + + substrings = CDR(CDR(substrings)); + } + + return ret; +} + +SCM lstringsplit(prog, str) + SCM prog, str; +{ + return stringsplitutil(prog, str, SCALAR); +} + +SCM lstringsplitv(prog, str) + SCM prog, str; +{ + return stringsplitutil(prog, str, VECTOR); +} + +typedef struct _item { + struct _item *next; + char *string; + int start; + int end; +} *editItem; + +#define PUSH(list, string_parm, start_parm, end_parm) \ + { \ + editItem item; \ + \ + item = ALLOCA(sizeof(*item)); \ + item->next = list; \ + list = item; \ + item->string = string_parm; \ + item->start = start_parm; \ + item->end = end_parm; \ + } + +/* (string-edit <re> <edit-spec> <string> [<count>]) */ +SCM lstringedit(prog, editspec, args) + SCM prog, editspec, args; +{ + int match_start, match_end, search_base, editcount; + int total_len; + int i, args_len, anchor, maxsubnum; + int backslash; + char *ptr; + editItem editlist, substrings, edit; + SCM str, count, next_edit; + SCM result; + ALLOCA_PROTECT; + + args_len = ilength(args); + + FIXUP_REGEXP(prog); + ASSERT(NIMP(prog) && tc16_rgx==CAR(prog), prog, ARG1, s_stringedit); + ASSERT(NIMP(editspec) && STRINGP(editspec), editspec, ARG2, s_stringedit); + ASSERT((args_len==1)||(args_len==2), args, WNA, s_stringedit); + + str = CAR(args); + ASSERT(NIMP(str)&&STRINGP(str), str, ARG3, s_stringedit); + + if (args_len==2) { + count = CAR(CDR(args)); + ASSERT(INUMP(count)||(count==BOOL_T), count, ARG4, s_stringedit); + } else + count = MAKINUM(1); + + /* process the editspec - break it into a list of dotted pairs + * of integers for substrings to be inserted and + * integers representing matched subexpressions that + * should be inserted. + */ + + maxsubnum = RGX(prog)->re_nsub; + anchor = 0; + backslash = 0; + editlist = NULL; + ptr = CHARS(editspec); + + for (i=0; i<LENGTH(editspec); i++) { + if (backslash && (ptr[i]>='0') && (ptr[i] <='9') && + ((ptr[i]-'0')<=maxsubnum)) + { + if ((i-1)>anchor) + PUSH(editlist, CHARS(editspec), anchor, i-1); + + PUSH(editlist, CHARS(editspec), ptr[i]-'0', -1); + anchor = i+1; + } + backslash = (ptr[i] == '\\')?1:0; + } + + if (anchor < LENGTH(editspec)) + PUSH(editlist, CHARS(editspec), anchor, LENGTH(editspec)); + + /* now, reverse the list of edit items */ + { + editItem prev, cur, next; + + for (prev=NULL, cur=editlist; cur; prev=cur, cur=next) { + next = cur->next; + cur->next = prev; + } + editlist = prev; + } + + anchor = 0; + search_base = 0; + editcount = 0; + substrings = NULL; + + next_edit = lregsearchv(prog, str, cons(MAKINUM(search_base), EOL)); + + while (next_edit != BOOL_F) { + if (INUMP(count) && (editcount==INUM(count))) + break; + + match_start = INUM(VELTS(next_edit)[0]); + match_end = INUM(VELTS(next_edit)[1]); + + if (match_start < match_end) { + PUSH(substrings, CHARS(str), anchor, match_start); + anchor = match_end; + } + + for (edit=editlist; edit; edit=edit->next) { + if (edit->end == -1) { + /* A backslash number in the original editspec */ + PUSH(substrings, CHARS(str), + INUM(VELTS(next_edit)[edit->start*2+0]), + INUM(VELTS(next_edit)[edit->start*2+1])); + } else + /* normal string in the editspec */ + PUSH(substrings, edit->string, edit->start, edit->end); + } + + editcount++; + search_base = ((match_end>search_base)?match_end:(search_base+1)); + next_edit = lregsearchv(prog, str, cons(MAKINUM(search_base), EOL)); + } + + /* get that tail bit */ + if (anchor < LENGTH(str)) + PUSH(substrings, CHARS(str), anchor, LENGTH(str)); + + /* assemble the result string */ + for (edit=substrings, total_len=0; edit; edit=edit->next) + total_len += (edit->end - edit->start); + + result = makstr(total_len); + ptr = CHARS(result) + total_len; /* point at the null at the end */ + + for (edit=substrings; edit; edit=edit->next) { + ptr -= (edit->end - edit->start); + bcopy(edit->string + edit->start, ptr, edit->end - edit->start); + } + return result; +} +#undef PUSH + +void init_rgx() +{ + tc16_rgx = newsmob(&rgxsmob); + make_subr(s_regcomp, tc7_subr_2o, lregcomp); + make_subr(s_regexec, tc7_subr_2, lregexec); + make_subr(s_regmatp, tc7_subr_2, lregmatp); + make_subr(s_regerror, tc7_subr_1, lregerror); + make_subr(s_regsearch, tc7_lsubr_2, lregsearch); + make_subr(s_regsearchv, tc7_lsubr_2, lregsearchv); + make_subr(s_regmatch, tc7_lsubr_2, lregmatch); + make_subr(s_regmatchv, tc7_lsubr_2, lregmatchv); + make_subr(s_stringsplit, tc7_subr_2, lstringsplit); + make_subr(s_stringsplitv, tc7_subr_2, lstringsplitv); + make_subr(s_stringedit, tc7_lsubr_2, lstringedit); + add_feature(s_regex); +} @@ -0,0 +1,335 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "rope.c" interface between C and SCM. + Author: Aubrey Jaffer */ + +#include "scm.h" + + /* Numeric conversions */ + /* Convert longs to SCM */ +SCM long2num(sl) + long sl; +{ + if (!FIXABLE(sl)) { +# ifdef BIGDIG + return long2big(sl); +# else +# ifdef FLOATS + return makdbl((double) sl, 0.0); +# else + return BOOL_F; +# endif +# endif + } + return MAKINUM(sl); +} +SCM ulong2num(sl) + unsigned long sl; +{ + if (!POSFIXABLE(sl)) { +#ifdef BIGDIG + return ulong2big(sl); +#else +# ifdef FLOATS + return makdbl((double) sl, 0.0); +# else + return BOOL_F; +# endif +#endif + } + return MAKINUM(sl); +} + + /* Convert SCM to numbers */ +unsigned char num2uchar(num, pos, s_caller) + SCM num; + char *pos, *s_caller; +{ + unsigned long res = INUM(num); + ASSERT(INUMP(num) && (255L >= res),num,pos,s_caller); + return (unsigned char) res; +} +unsigned short num2ushort(num, pos, s_caller) + SCM num; + char *pos, *s_caller; +{ + unsigned long res = INUM(num); + ASSERT(INUMP(num) && (65535L >= res),num,pos,s_caller); + return (unsigned short) res; +} +unsigned long num2ulong(num, pos, s_caller) + SCM num; + char *pos, *s_caller; +{ + unsigned long res; + if INUMP(num) { + ASRTGO(0 < num, errout); + res = INUM((unsigned long)num); + return res; + } + ASRTGO(NIMP(num), errout); +#ifdef FLOATS + if REALP(num) { + double u = REALPART(num); + if ((0 <= u) && (u <= (unsigned long)~0L)) { + res = u; + return res; + } + } +#endif +#ifdef BIGDIG + if (TYP16(num)==tc16_bigpos) { + sizet l = NUMDIGS(num); + ASRTGO(DIGSPERLONG >= l, errout); + res = 0; + for(;l--;) res = BIGUP(res) + BDIGITS(num)[l]; + return res; + } +#endif + errout: wta(num, pos, s_caller); +} +long num2long(num, pos, s_caller) + SCM num; + char *pos, *s_caller; +{ + long res; + if INUMP(num) { + res = INUM((long)num); + return res; + } + ASRTGO(NIMP(num), errout); +# ifdef FLOATS + if REALP(num) { + double u = REALPART(num); + if (((MOST_NEGATIVE_FIXNUM * 4) <= u) + && (u <= (MOST_POSITIVE_FIXNUM * 4 + 3))) { + res = u; + return res; + } + } +# endif +# ifdef BIGDIG + if BIGP(num) { + sizet l = NUMDIGS(num); + ASRTGO(DIGSPERLONG >= l, errout); + res = 0; + for(;l--;) res = BIGUP(res) + BDIGITS(num)[l]; + ASRTGO(0<res, errout); + return (tc16_bigpos==TYP16(num) ? res : -res); + } +# endif + errout: wta(num, pos, s_caller); +} +#ifdef FLOATS +double num2dbl(num, pos, s_caller) + SCM num; + char *pos, *s_caller; +{ + if INUMP(num) return (double)INUM(num); + ASRTGO(NIMP(num), errout); + if REALP(num) return REALPART(num); +#ifdef BIGDIG + if BIGP(num) return big2dbl(num); +#endif + errout: wta(num, pos, s_caller); +} +#endif + + + /* Convert (arrays of) strings to SCM */ +SCM makfromstr(src, len) + char *src; + sizet len; +{ + SCM s; + register char *dst; + s = makstr((long)len); + dst = CHARS(s); + while (len--) *dst++ = *src++; + return s; +} +SCM makfrom0str(src) + char *src; +{ + if (!src) return BOOL_F; + return makfromstr(src, (sizet) strlen(src)); +} +/* converts C array of strings to SCM list of strings. */ +/* If argc < 0, a null terminated array is assumed. */ +SCM makfromstrs(argc, argv) + int argc; + char **argv; +{ + int i = argc; + SCM lst = EOL; + if (0 > i) for(i = 0; argv[i]; i++); + while (i--) lst = cons(makfrom0str(argv[i]), lst); + return lst; +} +/* Converts SCM list of strings to NULL terminated array of strings. */ +/* INTS must be DEFERed around this call and the use of the returned array. */ +char **makargvfrmstrs(args, s_name) + SCM args; + char *s_name; +{ + char **argv; + int argc = ilength(args); + argv = (char **)must_malloc((1L+argc)*sizeof(char *), s_vector); + for(argc = 0; NNULLP(args); args=CDR(args), ++argc) { + ASSERT(NIMP(CAR(args)) && STRINGP(CAR(args)), CAR(args), ARG2, s_name); + { + sizet len = 1 + LENGTH(CAR(args)); + char *dst = (char *)must_malloc((long)len, s_string); + char *src = CHARS(CAR(args)); + while (len--) dst[len] = src[len]; + argv[argc] = dst; + } + } + argv[argc] = 0; + return argv; +} +void must_free_argv(argv) + char **argv; +{ + char **av = argv; + while(!(*av)) free(*(av++)); + free(argv); +} + + /* Hooks to call SCM from C */ +SCM scm_evstr(str) + char *str; +{ + SCM lsym; + NEWCELL(lsym); + SETLENGTH(lsym, strlen(str)+0L, tc7_ssymbol); + SETCHARS(lsym, str); + return scm_eval_string(lsym); +} +void scm_ldstr(str) + char *str; +{ + SCM lsym; + NEWCELL(lsym); + SETLENGTH(lsym, strlen(str)+0L, tc7_ssymbol); + SETCHARS(lsym, str); + scm_load_string(lsym); +} +int scm_ldfile(path) + char *path; +{ + SCM name = makfrom0str(path); + *loc_errobj = name; + return BOOL_F==tryload(name); +} +int scm_ldprog(path) + char *path; +{ + SCM name = makfrom0str(path); + *loc_errobj = name; + return + BOOL_F==scm_evstr("(try-load (in-vicinity (program-vicinity) errobj))"); +} + + /* Get byte address of SCM array */ +#ifdef ARRAYS +long aind P((SCM ra, SCM args, char *what)); +unsigned long scm_addr(args, s_name) + SCM args; + char *s_name; +{ + long pos; + unsigned long ptr = 0; /* gratuitous assignment squelches cc warn. */ + SCM v; + ASRTGO(NIMP(args), wna); + v = CAR(args); + args = CDR(args); + if IMP(v) {goto badarg;} + else if ARRAYP(v) { + pos = aind(v, args, s_name); + v = ARRAY_V(v); + } + else { + if NIMP(args) { + ASSERT(CONSP(args) && INUMP(CAR(args)), args, ARG2, s_name); + pos = INUM(CAR(args)); + ASRTGO(NULLP(CDR(args)), wna); + } + else if NULLP(args) pos = 0; + else { + ASSERT(INUMP(args), args, ARG2, s_name); + pos = INUM(args); + } + ASRTGO(pos >= 0 && pos < LENGTH(v), outrng); + } + switch TYP7(v) { + case tc7_string: + ptr = (unsigned long)&(CHARS(v)[pos]); + break; +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: + ptr = (unsigned long)&(((float *)CDR(v))[pos]); + break; +# endif + case tc7_cvect: pos = 2 * pos; + case tc7_dvect: ptr = (unsigned long)&(((double *)CDR(v))[pos]); + break; +# endif + case tc7_bvect: ASRTGO(0==(pos%LONG_BIT), outrng); + pos = pos/LONG_BIT; + case tc7_uvect: + case tc7_ivect: + case tc7_vector: ptr = (unsigned long)&(VELTS(v)[pos]); + break; + outrng: wta(MAKINUM(pos), (char *)OUTOFRANGE, s_name); + default: + badarg: wta(v, (char *)ARG1, s_name); + wna: wta(UNDEFINED, (char *)WNA, s_name); + } + return ptr; +} +#endif /* ARRAYS */ + +void init_rope() +{ +} @@ -0,0 +1,172 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "sc2.c" R2RS and R3RS procedures not in R4RS. + Author: Aubrey Jaffer */ + +#include "scm.h" + +static char s_last_pair[] = "last-pair"; +SCM last_pair(sx) + SCM sx; +{ + register SCM res = sx; + register SCM x; + ASSERT(NIMP(res) && CONSP(res), res, ARG1, s_last_pair); + while (!0) { + x = CDR(res); + if (IMP(x) || NCONSP(x)) return res; + res = x; + x = CDR(res); + if (IMP(x) || NCONSP(x)) return res; + res = x; + sx = CDR(sx); + ASSERT(x != sx, sx, ARG1, s_last_pair); + } +} + +static char s_subml[] = "substring-move-left!"; +SCM subml(str1, start1, args) + SCM str1, start1, args; +{ + SCM end1, str2, start2; + long i, j, e; + ASSERT(3==ilength(args), args, WNA, s_subml); + end1 = CAR(args); args = CDR(args); + str2 = CAR(args); args = CDR(args); + start2 = CAR(args); + ASSERT(NIMP(str1) && STRINGP(str1), str1, ARG1, s_subml); + ASSERT(INUMP(start1), start1, ARG2, s_subml); + ASSERT(INUMP(end1), end1, ARG3, s_subml); + ASSERT(NIMP(str2) && STRINGP(str2), str2, ARG4, s_subml); + ASSERT(INUMP(start2), start2, ARG5, s_subml); + i = INUM(start1), j = INUM(start2), e = INUM(end1); + ASSERT(i <= LENGTH(str1) && i >= 0, start1, OUTOFRANGE, s_subml); + ASSERT(j <= LENGTH(str2) && j >= 0, start2, OUTOFRANGE, s_subml); + ASSERT(e <= LENGTH(str1) && e >= 0, end1, OUTOFRANGE, s_subml); + ASSERT(e-i+j <= LENGTH(str2), start2, OUTOFRANGE, s_subml); + while(i<e) CHARS(str2)[j++] = CHARS(str1)[i++]; + return UNSPECIFIED; +} +static char s_submr[] = "substring-move-right!"; +SCM submr(str1, start1, args) + SCM str1, start1, args; +{ + SCM end1, str2, start2; + long i, j, e; + ASSERT(3==ilength(args), args, WNA, s_submr); + end1 = CAR(args); args = CDR(args); + str2 = CAR(args); args = CDR(args); + start2 = CAR(args); + ASSERT(NIMP(str1) && STRINGP(str1), str1, ARG1, s_submr); + ASSERT(INUMP(start1), start1, ARG2, s_submr); + ASSERT(INUMP(end1), end1, ARG3, s_submr); + ASSERT(NIMP(str2) && STRINGP(str2), str2, ARG4, s_submr); + ASSERT(INUMP(start2), start2, ARG5, s_submr); + i = INUM(start1), j = INUM(start2), e = INUM(end1); + ASSERT(i <= LENGTH(str1) && i >= 0, start1, OUTOFRANGE, s_submr); + ASSERT(j <= LENGTH(str2) && j >= 0, start2, OUTOFRANGE, s_submr); + ASSERT(e <= LENGTH(str1) && e >= 0, end1, OUTOFRANGE, s_submr); + ASSERT((j = e-i+j) <= LENGTH(str2), start2, OUTOFRANGE, s_submr); + while(i<e) CHARS(str2)[--j] = CHARS(str1)[--e]; + return UNSPECIFIED; +} +static char s_subfl[] = "substring-fill!"; +SCM subfl(str, start, args) + SCM str, start, args; +{ + SCM end, fill; + long i, e; + char c; + ASSERT(2==ilength(args), args, WNA, s_subfl); + end = CAR(args); args = CDR(args); + fill = CAR(args); + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_subfl); + ASSERT(INUMP(start), start, ARG2, s_subfl); + ASSERT(INUMP(end), end, ARG3, s_subfl); + ASSERT(ICHRP(fill), fill, ARG4, s_subfl); + i = INUM(start), e = INUM(end);c = ICHR(fill); + ASSERT(i <= LENGTH(str) && i >= 0, start, OUTOFRANGE, s_subfl); + ASSERT(e <= LENGTH(str) && e >= 0, end, OUTOFRANGE, s_subfl); + while(i<e) CHARS(str)[i++] = c; + return UNSPECIFIED; +} + +static char s_strnullp[] = "string-null?"; +SCM strnullp(str) + SCM str; +{ + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_strnullp); + if LENGTH(str) return BOOL_F; + else return BOOL_T; +} + +static char s_appendb[] = "append!"; +SCM appendb(args) + SCM args; +{ + SCM arg; + tail: + if NULLP(args) return EOL; + arg = CAR(args); + ASSERT(NULLP(arg) || (NIMP(arg) && CONSP(arg)), arg, ARG1, s_appendb); + args = CDR(args); + if NULLP(args) return arg; + if NULLP(arg) goto tail; + CDR(last_pair(arg)) = appendb(args); + return arg; +} + +static iproc lsubr2s[] = { + {s_subml, subml}, + {s_submr, submr}, + {s_subfl, subfl}, + {0, 0}}; + +void init_sc2() +{ + make_subr(s_last_pair, tc7_subr_1, last_pair); + make_subr(s_strnullp, tc7_subr_1, strnullp); + make_subr(s_appendb, tc7_lsubr, appendb); + init_iprocs(lsubr2s, tc7_lsubr_2); + add_feature("rev2-procedures"); + add_feature("rev3-procedures"); +} @@ -0,0 +1,2393 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "scl.c" non-IEEE utility functions and non-integer arithmetic. + Authors: Jerry D. Hedden and Aubrey Jaffer */ + +#include "scm.h" + +#ifdef FLOATS +# include <math.h> + +static char s_makrect[] = "make-rectangular", s_makpolar[] = "make-polar", + s_magnitude[] = "magnitude", s_angle[] = "angle", + s_real_part[] = "real-part", s_imag_part[] = "imag-part", + s_in2ex[] = "inexact->exact"; +static char s_expt[] = "$expt", s_atan2[] = "$atan2"; +static char s_memv[] = "memv", s_assv[] = "assv"; +#endif + +SCM sys_protects[NUM_PROTECTS]; +sizet num_protects = NUM_PROTECTS; + +char s_inexactp[] = "inexact?"; +static char s_zerop[] = "zero?", + s_positivep[] = "positive?", s_negativep[] = "negative?"; +static char s_eqp[] = "=", s_lessp[] = "<", s_grp[] = ">"; +static char s_leqp[] = "<=", s_greqp[] = ">="; +static char s_max[] = "max", s_min[] = "min"; +char s_sum[] = "+", s_difference[] = "-", s_product[] = "*", + s_divide[] = "/"; +static char s_number2string[] = "number->string", + s_str2number[] = "string->number"; + +static char s_list_tail[] = "list-tail"; +static char s_str2list[] = "string->list"; +static char s_st_copy[] = "string-copy", s_st_fill[] = "string-fill!"; +static char s_vect2list[] = "vector->list", s_ve_fill[] = "vector-fill!"; + +/*** NUMBERS -> STRINGS ***/ +#ifdef FLOATS +int dblprec; +static double fx[] = {0.0, 5e-1, 5e-2, 5e-3, 5e-4, 5e-5, + 5e-6, 5e-7, 5e-8, 5e-9, 5e-10, + 5e-11,5e-12,5e-13,5e-14,5e-15, + 5e-16,5e-17,5e-18,5e-19,5e-20}; + +static sizet idbl2str(f, a) + double f; +char *a; +{ + int efmt, dpt, d, i, wp = dblprec; + sizet ch = 0; + int exp = 0; + + if (f==0.0) goto zero; /*{a[0]='0'; a[1]='.'; a[2]='0'; return 3;}*/ + if (f < 0.0) {f = -f;a[ch++]='-';} + else if (f > 0.0) ; + else goto funny; + if IS_INF(f) { + if (ch==0) a[ch++]='+'; + funny: a[ch++]='#'; a[ch++]='.'; a[ch++]='#'; return ch; + } +# ifdef DBL_MIN_10_EXP /* Prevent unnormalized values, as from + make-uniform-vector, from causing infinite loops. */ + while (f < 1.0) {f *= 10.0; if (exp-- < DBL_MIN_10_EXP) goto funny;} + while (f > 10.0) {f *= 0.10; if (exp++ > DBL_MAX_10_EXP) goto funny;} +# else + while (f < 1.0) {f *= 10.0; exp--;} + while (f > 10.0) {f /= 10.0; exp++;} +# endif + if (f+fx[wp] >= 10.0) {f = 1.0; exp++;} + zero: +# ifdef ENGNOT + dpt = (exp+9999)%3; + exp -= dpt++; + efmt = 1; +# else + efmt = (exp < -3) || (exp > wp+2); + if (!efmt) + if (exp < 0) { + a[ch++] = '0'; + a[ch++] = '.'; + dpt = exp; + while (++dpt) a[ch++] = '0'; + } else + dpt = exp+1; + else + dpt = 1; +# endif + + do { + d = f; + f -= d; + a[ch++] = d+'0'; + if (f < fx[wp]) break; + if (f+fx[wp] >= 1.0) { + a[ch-1]++; + break; + } + f *= 10.0; + if (!(--dpt)) a[ch++] = '.'; + } while (wp--); + + if (dpt > 0) +# ifndef ENGNOT + if ((dpt > 4) && (exp > 6)) { + d = (a[0]=='-'?2:1); + for (i = ch++; i > d; i--) + a[i] = a[i-1]; + a[d] = '.'; + efmt = 1; + } else +# endif + { + while (--dpt) a[ch++] = '0'; + a[ch++] = '.'; + } + if (a[ch-1]=='.') a[ch++]='0'; /* trailing zero */ + if (efmt && exp) { + a[ch++] = 'e'; + if (exp < 0) { + exp = -exp; + a[ch++] = '-'; + } + for (i = 10; i <= exp; i *= 10); + for (i /= 10; i; i /= 10) { + a[ch++] = exp/i + '0'; + exp %= i; + } + } + return ch; +} + +static sizet iflo2str(flt, str) + SCM flt; + char *str; +{ + sizet i; +# ifdef SINGLES + if SINGP(flt) i = idbl2str(FLO(flt), str); + else +# endif + i = idbl2str(REAL(flt), str); + if CPLXP(flt) { + if(0 <= IMAG(flt)) /* jeh */ + str[i++] = '+'; /* jeh */ + i += idbl2str(IMAG(flt), &str[i]); + str[i++] = 'i'; + } + return i; +} +#endif /* FLOATS */ + +sizet iint2str(num, rad, p) + long num; + int rad; + char *p; +{ + sizet j; + register int i = 1, d; + register long n = num; + if (n < 0) {n = -n; i++;} + for (n /= rad;n > 0;n /= rad) i++; + j = i; + n = num; + if (n < 0) {n = -n; *p++ = '-'; i--;} + while (i--) { + d = n % rad; + n /= rad; + p[i] = d + ((d < 10) ? '0' : 'a' - 10); + } + return j; +} +#ifdef BIGDIG +static SCM big2str(b, radix) + SCM b; + register unsigned int radix; +{ + SCM t = copybig(b, 0); /* sign of temp doesn't matter */ + register BIGDIG *ds = BDIGITS(t); + sizet i = NUMDIGS(t); + sizet j = radix==16 ? (BITSPERDIG*i)/4+2 + : radix >= 10 ? (BITSPERDIG*i*241L)/800+2 + : (BITSPERDIG*i)+2; + sizet k = 0; + sizet radct = 0; + sizet ch; /* jeh */ + BIGDIG radpow = 1, radmod = 0; + SCM ss = makstr((long)j); + char *s = CHARS(ss), c; + while ((long) radpow * radix < BIGRAD) { + radpow *= radix; + radct++; + } + s[0] = tc16_bigneg==TYP16(b) ? '-' : '+'; + while ((i || radmod) && j) { + if (k==0) { + radmod = (BIGDIG)divbigdig(ds, i, radpow); + k = radct; + if (!ds[i-1]) i--; + } + c = radmod % radix; radmod /= radix; k--; + s[--j] = c < 10 ? c + '0' : c + 'a' - 10; + } + ch = s[0]=='-' ? 1 : 0; /* jeh */ + if (ch < j) { /* jeh */ + for(i = j;j < LENGTH(ss);j++) s[ch+j-i] = s[j]; /* jeh */ + resizuve(ss, (SCM)MAKINUM(ch+LENGTH(ss)-i)); /* jeh */ + } + return ss; +} +#endif +SCM number2string(x, radix) + SCM x, radix; +{ + if UNBNDP(radix) radix=MAKINUM(10L); + else ASSERT(INUMP(radix), radix, ARG2, s_number2string); +#ifdef FLOATS + if NINUMP(x) { + char num_buf[FLOBUFLEN]; +# ifdef BIGDIG + ASRTGO(NIMP(x), badx); + if BIGP(x) return big2str(x, (unsigned int)INUM(radix)); +# ifndef RECKLESS + if (!(INEXP(x))) + badx: wta(x, (char *)ARG1, s_number2string); +# endif +# else + ASSERT(NIMP(x) && INEXP(x), x, ARG1, s_number2string); +# endif + return makfromstr(num_buf, iflo2str(x, num_buf)); + } +#else +# ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_number2string); + return big2str(x, (unsigned int)INUM(radix)); + } +# else + ASSERT(INUMP(x), x, ARG1, s_number2string); +# endif +#endif + { + char num_buf[INTBUFLEN]; + return makfromstr(num_buf, iint2str(INUM(x), (int)INUM(radix), num_buf)); + } +} +/* These print routines are stubbed here so that repl.c doesn't need + FLOATS or BIGDIGs conditionals */ +int floprint(sexp, port, writing) + SCM sexp; + SCM port; + int writing; +{ +#ifdef FLOATS + char num_buf[FLOBUFLEN]; + lfwrite(num_buf, (sizet)sizeof(char), iflo2str(sexp, num_buf), port); +#else + ipruk("float", sexp, port); +#endif + return !0; +} +int bigprint(exp, port, writing) + SCM exp; + SCM port; + int writing; +{ +#ifdef BIGDIG + exp = big2str(exp, (unsigned int)10); + lfwrite(CHARS(exp), (sizet)sizeof(char), (sizet)LENGTH(exp), port); +#else + ipruk("bignum", exp, port); +#endif + return !0; +} +/*** END nums->strs ***/ + +/*** STRINGS -> NUMBERS ***/ +#ifdef BIGDIG +SCM istr2int(str, len, radix) + char *str; + long len; + register long radix; +{ + sizet j; + register sizet k, blen = 1; + sizet i = 0; + int c; + SCM res; + register BIGDIG *ds; + register unsigned long t2; + + if (0 >= len) return BOOL_F; /* zero length */ + if (10==radix) j = 1+(84*len)/(BITSPERDIG*25); + else j = (8 < radix) ? 1+(4*len)/BITSPERDIG : 1+(3*len)/BITSPERDIG; + switch (str[0]) { /* leading sign */ + case '-': + case '+': if (++i==len) return BOOL_F; /* bad if lone `+' or `-' */ + } + res = mkbig(j, '-'==str[0]); + ds = BDIGITS(res); + for (k = j;k--;) ds[k] = 0; + do { + switch (c = str[i++]) { + case DIGITS: + c = c - '0'; + goto accumulate; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + c = c-'A'+10; + goto accumulate; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + c = c-'a'+10; + accumulate: + if (c >= radix) return BOOL_F; /* bad digit for radix */ + k = 0; + t2 = c; + moretodo: + while(k < blen) { +/* printf("k = %d, blen = %d, t2 = %ld, ds[k] = %d\n", k, blen, t2, ds[k]);*/ + t2 += ds[k]*radix; + ds[k++] = BIGLO(t2); + t2 = BIGDN(t2); + } + ASSERT(blen <= j, (SCM)MAKINUM(blen), OVFLOW, "bignum"); + if (t2) {blen++; goto moretodo;} + break; + default: + return BOOL_F; /* not a digit */ + } + } while (i < len); + if (blen * BITSPERDIG/CHAR_BIT <= sizeof(SCM)) + if INUMP(res = big2inum(res, blen)) return res; + if (j==blen) return res; + return adjbig(res, blen); +} +#else +SCM istr2int(str, len, radix) + register char *str; + long len; + register long radix; +{ + register long n = 0, ln; + register int c; + register int i = 0; + int lead_neg = 0; + if (0 >= len) return BOOL_F; /* zero length */ + switch (*str) { /* leading sign */ + case '-': lead_neg = 1; + case '+': if (++i==len) return BOOL_F; /* bad if lone `+' or `-' */ + } + + do { + switch (c = str[i++]) { + case DIGITS: + c = c - '0'; + goto accumulate; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + c = c-'A'+10; + goto accumulate; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + c = c-'a'+10; + accumulate: + if (c >= radix) return BOOL_F; /* bad digit for radix */ + ln = n; + n = n * radix - c; + /* Negation is a workaround for HP700 cc bug */ + if (n > ln || (-n > -MOST_NEGATIVE_FIXNUM)) goto ovfl; + break; + default: + return BOOL_F; /* not a digit */ + } + } while (i < len); + if (!lead_neg) if ((n = -n) > MOST_POSITIVE_FIXNUM) goto ovfl; + return MAKINUM(n); + ovfl: /* overflow scheme integer */ + return BOOL_F; +} +#endif + +#ifdef FLOATS +SCM istr2flo(str, len, radix) + register char *str; + register long len; + register long radix; +{ + register int c, i = 0; + double lead_sgn; + double res = 0.0, tmp = 0.0; + int flg = 0; + int point = 0; + SCM second; + + if (i >= len) return BOOL_F; /* zero length */ + + switch (*str) { /* leading sign */ + case '-': lead_sgn = -1.0; i++; break; + case '+': lead_sgn = 1.0; i++; break; + default : lead_sgn = 0.0; + } + if (i==len) return BOOL_F; /* bad if lone `+' or `-' */ + + if (str[i]=='i' || str[i]=='I') { /* handle `+i' and `-i' */ + if (lead_sgn==0.0) return BOOL_F; /* must have leading sign */ + if (++i < len) return BOOL_F; /* `i' not last character */ + return makdbl(0.0, lead_sgn); + } + do { /* check initial digits */ + switch (c = str[i]) { + case DIGITS: + c = c - '0'; + goto accum1; + case 'D': case 'E': case 'F': + if (radix==10) goto out1; /* must be exponent */ + case 'A': case 'B': case 'C': + c = c-'A'+10; + goto accum1; + case 'd': case 'e': case 'f': + if (radix==10) goto out1; + case 'a': case 'b': case 'c': + c = c-'a'+10; + accum1: + if (c >= radix) return BOOL_F; /* bad digit for radix */ + res = res * radix + c; + flg = 1; /* res is valid */ + break; + default: + goto out1; + } + } while (++i < len); + out1: + + /* if true, then we did see a digit above, and res is valid */ + if (i==len) goto done; + + /* By here, must have seen a digit, + or must have next char be a `.' with radix==10 */ + if (!flg) + if (!(str[i]=='.' && radix==10)) + return BOOL_F; + + while (str[i]=='#') { /* optional sharps */ + res *= radix; + if (++i==len) goto done; + } + + if (str[i]=='/') { + while (++i < len) { + switch (c = str[i]) { + case DIGITS: + c = c - '0'; + goto accum2; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + c = c-'A'+10; + goto accum2; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + c = c-'a'+10; + accum2: + if (c >= radix) return BOOL_F; + tmp = tmp * radix + c; + break; + default: + goto out2; + } + } + out2: + if (tmp==0.0) return BOOL_F; /* `slash zero' not allowed */ + if (i < len) + while (str[i]=='#') { /* optional sharps */ + tmp *= radix; + if (++i==len) break; + } + res /= tmp; + goto done; + } + + if (str[i]=='.') { /* decimal point notation */ + if (radix != 10) return BOOL_F; /* must be radix 10 */ + while (++i < len) { + switch (c = str[i]) { + case DIGITS: + point--; + res = res*10.0 + c-'0'; + flg = 1; + break; + default: + goto out3; + } + } + out3: + if (!flg) return BOOL_F; /* no digits before or after decimal point */ + if (i==len) goto adjust; + while (str[i]=='#') { /* ignore remaining sharps */ + if (++i==len) goto adjust; + } + } + + switch (str[i]) { /* exponent */ + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + case 'l': case 'L': + case 's': case 'S': { + int expsgn = 1, expon = 0; + if (radix != 10) return BOOL_F; /* only in radix 10 */ + if (++i==len) return BOOL_F; /* bad exponent */ + switch (str[i]) { + case '-': expsgn=(-1); + case '+': if (++i==len) return BOOL_F; /* bad exponent */ + } + if (str[i] < '0' || str[i] > '9') return BOOL_F; /* bad exponent */ + do { + switch (c = str[i]) { + case DIGITS: + expon = expon*10 + c-'0'; + if (expon > MAXEXP) return BOOL_F; /* exponent too large */ + break; + default: + goto out4; + } + } while (++i < len); + out4: + point += expsgn*expon; + } + } + + adjust: + if (point >= 0) + while (point--) res *= 10.0; + else +# ifdef _UNICOS + while (point++) res *= 0.1; +# else + while (point++) res /= 10.0; +# endif + + done: + /* at this point, we have a legitimate floating point result */ + if (lead_sgn==-1.0) res = -res; + if (i==len) return makdbl(res, 0.0); + + if (str[i]=='i' || str[i]=='I') { /* pure imaginary number */ + if (lead_sgn==0.0) return BOOL_F; /* must have leading sign */ + if (++i < len) return BOOL_F; /* `i' not last character */ + return makdbl(0.0, res); + } + + switch (str[i++]) { + case '-': lead_sgn = -1.0; break; + case '+': lead_sgn = 1.0; break; + case '@': { /* polar input for complex number */ + /* get a `real' for angle */ + second = istr2flo(&str[i], (long)(len-i), radix); + if (!(INEXP(second))) return BOOL_F; /* not `real' */ + if (CPLXP(second)) return BOOL_F; /* not `real' */ + tmp = REALPART(second); + return makdbl(res*cos(tmp), res*sin(tmp)); + } + default: return BOOL_F; + } + + /* at this point, last char must be `i' */ + if (str[len-1] != 'i' && str[len-1] != 'I') return BOOL_F; + /* handles `x+i' and `x-i' */ + if (i==(len-1)) return makdbl(res, lead_sgn); + /* get a `ureal' for complex part */ + second = istr2flo(&str[i], (long)((len-i)-1), radix); + if (!(INEXP(second))) return BOOL_F; /* not `ureal' */ + if (CPLXP(second)) return BOOL_F; /* not `ureal' */ + tmp = REALPART(second); + if (tmp < 0.0) return BOOL_F; /* not `ureal' */ + return makdbl(res, (lead_sgn*tmp)); +} +#endif /* FLOATS */ + + +SCM istring2number(str, len, radix) + char *str; + long len; + long radix; +{ + int i = 0; + char ex = 0; + char ex_p = 0, rx_p = 0; /* Only allow 1 exactness and 1 radix prefix */ + SCM res; + if (len==1) + if (*str=='+' || *str=='-') /* Catches lone `+' and `-' for speed */ + return BOOL_F; + + while ((len-i) >= 2 && str[i]=='#' && ++i) + switch (str[i++]) { + case 'b': case 'B': if (rx_p++) return BOOL_F; radix = 2; break; + case 'o': case 'O': if (rx_p++) return BOOL_F; radix = 8; break; + case 'd': case 'D': if (rx_p++) return BOOL_F; radix = 10; break; + case 'x': case 'X': if (rx_p++) return BOOL_F; radix = 16; break; + case 'i': case 'I': if (ex_p++) return BOOL_F; ex = 2; break; + case 'e': case 'E': if (ex_p++) return BOOL_F; ex = 1; break; + default: return BOOL_F; + } + + switch (ex) { + case 1: + return istr2int(&str[i], len-i, radix); + case 0: + res = istr2int(&str[i], len-i, radix); + if NFALSEP(res) return res; +#ifdef FLOATS + case 2: return istr2flo(&str[i], len-i, radix); +#endif + } + return BOOL_F; +} + + +SCM string2number(str, radix) + SCM str, radix; +{ + if UNBNDP(radix) radix=MAKINUM(10L); + else ASSERT(INUMP(radix), radix, ARG2, s_str2number); + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_str2number); + return istring2number(CHARS(str), LENGTH(str), INUM(radix)); +} +/*** END strs->nums ***/ + +#ifdef FLOATS +SCM makdbl (x, y) + double x, y; +{ + SCM z; + if ((y==0.0) && (x==0.0)) return flo0; + NEWCELL(z); + DEFER_INTS; + if (y==0.0) { +# ifdef SINGLES + float fx; +# ifndef SINGLESONLY + if ((-FLTMAX < x) && (x < FLTMAX) && ((fx=x)==x)) +# endif + { + CAR(z) = tc_flo; + FLO(z) = x; + ALLOW_INTS; + return z; + } +# endif /* def SINGLES */ + CDR(z) = (SCM)must_malloc(1L*sizeof(double), "real"); + CAR(z) = tc_dblr; + } + else { + CDR(z) = (SCM)must_malloc(2L*sizeof(double), "complex"); + CAR(z) = tc_dblc; + IMAG(z) = y; + } + REAL(z) = x; + ALLOW_INTS; + return z; +} + +SCM eqv(x, y) + SCM x, y; +{ + if (x==y) return BOOL_T; + if IMP(x) return BOOL_F; + if IMP(y) return BOOL_F; + /* this ensures that types and length are the same. */ + if (CAR(x) != CAR(y)) return BOOL_F; + if NUMP(x) { +# ifdef BIGDIG + if BIGP(x) return (0==bigcomp(x, y)) ? BOOL_T : BOOL_F; +# endif + if (REALPART(x) != REALPART(y)) return BOOL_F; + if (CPLXP(x) && (IMAG(x) != IMAG(y))) return BOOL_F; + return BOOL_T; + } + return BOOL_F; +} +SCM memv(x, lst) /* m.borza 12.2.91 */ +SCM x, lst; +{ + for(;NIMP(lst);lst = CDR(lst)) { + ASRTGO(CONSP(lst), badlst); + if NFALSEP(eqv(CAR(lst), x)) return lst; + } +# ifndef RECKLESS + if (!(NULLP(lst))) + badlst: wta(lst, (char *)ARG2, s_memv); +# endif + return BOOL_F; +} +SCM assv(x, alist) /* m.borza 12.2.91 */ +SCM x, alist; +{ + SCM tmp; + for(;NIMP(alist);alist = CDR(alist)) { + ASRTGO(CONSP(alist), badlst); + tmp = CAR(alist); + ASRTGO(NIMP(tmp) && CONSP(tmp), badlst); + if NFALSEP(eqv(CAR(tmp), x)) return tmp; + } +# ifndef RECKLESS + if (!(NULLP(alist))) + badlst: wta(alist, (char *)ARG2, s_assv); +# endif + return BOOL_F; +} +#endif /* FLOATS */ + +SCM list_tail(lst, k) + SCM lst, k; +{ + register long i; + ASSERT(INUMP(k), k, ARG2, s_list_tail); + i = INUM(k); + while (i-- > 0) { + ASSERT(NIMP(lst) && CONSP(lst), lst, ARG1, s_list_tail); + lst = CDR(lst); + } + return lst; +} + +SCM string2list(str) + SCM str; +{ + long i; + SCM res = EOL; + unsigned char *src; + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_str2list); + src = UCHARS(str); + for(i = LENGTH(str)-1;i >= 0;i--) res = cons((SCM)MAKICHR(src[i]), res); + return res; +} +SCM string_copy(str) + SCM str; +{ + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_st_copy); + return makfromstr(CHARS(str), (sizet)LENGTH(str)); +} +SCM string_fill(str, chr) + SCM str, chr; +{ + register char *dst, c; + register long k; + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_st_fill); + ASSERT(ICHRP(chr), chr, ARG2, s_st_fill); + c = ICHR(chr); + dst = CHARS(str); + for(k = LENGTH(str)-1;k >= 0;k--) dst[k] = c; + return UNSPECIFIED; +} +SCM vector2list(v) + SCM v; +{ + SCM res = EOL; + long i; + SCM *data; + ASSERT(NIMP(v) && VECTORP(v), v, ARG1, s_vect2list); + data = VELTS(v); + for(i = LENGTH(v)-1;i >= 0;i--) res = cons(data[i], res); + return res; +} +SCM vector_fill(v, fill) + SCM v, fill; +{ + register long i; + register SCM *data; + ASSERT(NIMP(v) && VECTORP(v), v, ARG1, s_ve_fill); + data = VELTS(v); + for(i = LENGTH(v)-1;i >= 0;i--) data[i] = fill; + return UNSPECIFIED; +} +static SCM vector_equal(x, y) + SCM x, y; +{ + long i; + for(i = LENGTH(x)-1;i >= 0;i--) + if FALSEP(equal(VELTS(x)[i], VELTS(y)[i])) return BOOL_F; + return BOOL_T; +} +SCM bigequal(x, y) + SCM x, y; +{ +#ifdef BIGDIG + if (0==bigcomp(x, y)) return BOOL_T; +#endif + return BOOL_F; +} +SCM floequal(x, y) + SCM x, y; +{ +#ifdef FLOATS + if (REALPART(x) != REALPART(y)) return BOOL_F; + if (!(CPLXP(x) && (IMAG(x) != IMAG(y)))) return BOOL_T; +#endif + return BOOL_F; +} +SCM equal(x, y) + SCM x, y; +{ + CHECK_STACK; + tailrecurse: POLL; + if (x==y) return BOOL_T; + if IMP(x) return BOOL_F; + if IMP(y) return BOOL_F; + if (CONSP(x) && CONSP(y)) { + if FALSEP(equal(CAR(x), CAR(y))) return BOOL_F; + x = CDR(x); + y = CDR(y); + goto tailrecurse; + } + /* this ensures that types and length are the same. */ + if (CAR(x) != CAR(y)) return BOOL_F; + switch (TYP7(x)) { + default: return BOOL_F; + case tc7_string: return st_equal(x, y); + case tc7_vector: return vector_equal(x, y); + case tc7_smob: { + int i = SMOBNUM(x); + if (!(i < numsmob)) return BOOL_F; + if (smobs[i].equalp) return (smobs[i].equalp)(x, y); + else return BOOL_F; + } + case tc7_bvect: case tc7_uvect: case tc7_ivect: + case tc7_fvect: case tc7_cvect: case tc7_dvect: { + SCM (*pred)() = smobs[0x0ff & (tc16_array>>8)].equalp; + if (pred) return (*pred)(x, y); + else return BOOL_F; + } + } + return BOOL_F; +} + +SCM numberp(x) + SCM x; +{ + if INUMP(x) return BOOL_T; +#ifdef FLOATS + if (NIMP(x) && NUMP(x)) return BOOL_T; +#else +# ifdef BIGDIG + if (NIMP(x) && NUMP(x)) return BOOL_T; +# endif +#endif + return BOOL_F; +} +#ifdef FLOATS +SCM realp(x) + SCM x; +{ + if INUMP(x) return BOOL_T; + if IMP(x) return BOOL_F; + if REALP(x) return BOOL_T; +# ifdef BIGDIG + if BIGP(x) return BOOL_T; +# endif + return BOOL_F; +} +SCM intp(x) + SCM x; +{ + double r; + if INUMP(x) return BOOL_T; + if IMP(x) return BOOL_F; +# ifdef BIGDIG + if BIGP(x) return BOOL_T; +# endif + if (!INEXP(x)) return BOOL_F; + if CPLXP(x) return BOOL_F; + r = REALPART(x); + if (r==floor(r)) return BOOL_T; + return BOOL_F; +} +#endif /* FLOATS */ + +SCM inexactp(x) + SCM x; +{ +#ifdef FLOATS + if (NIMP(x) && INEXP(x)) return BOOL_T; +#endif + return BOOL_F; +} +SCM eqp(x, y) + SCM x, y; +{ +#ifdef FLOATS + SCM t; + if NINUMP(x) { +# ifdef BIGDIG +# ifndef RECKLESS + if (!(NIMP(x))) + badx: wta(x, (char *)ARG1, s_eqp); +# endif + if BIGP(x) { + if INUMP(y) return BOOL_F; + ASRTGO(NIMP(y), bady); + if BIGP(y) return (0==bigcomp(x, y)) ? BOOL_T : BOOL_F; + ASRTGO(INEXP(y), bady); + bigreal: + return (REALP(y) && (big2dbl(x)==REALPART(y))) ? BOOL_T : BOOL_F; + } + ASRTGO(INEXP(x), badx); +# else + ASSERT(NIMP(x) && INEXP(x), x, ARG1, s_eqp); +# endif + if INUMP(y) {t = x; x = y; y = t; goto realint;} +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) {t = x; x = y; y = t; goto bigreal;} + ASRTGO(INEXP(y), bady); +# else + ASRTGO(NIMP(y) && INEXP(y), bady); +# endif + if (REALPART(x) != REALPART(y)) return BOOL_F; + if CPLXP(x) + return (CPLXP(y) && (IMAG(x)==IMAG(y))) ? BOOL_T : BOOL_F; + return CPLXP(y) ? BOOL_F : BOOL_T; + } + if NINUMP(y) { +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) return BOOL_F; +# ifndef RECKLESS + if (!(INEXP(y))) + bady: wta(y, (char *)ARG2, s_eqp); +# endif +# else +# ifndef RECKLESS + if (!(NIMP(y) && INEXP(y))) + bady: wta(y, (char *)ARG2, s_eqp); +# endif +# endif + realint: + return (REALP(y) && (((double)INUM(x))==REALPART(y))) ? BOOL_T : BOOL_F; + } +#else +# ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_eqp); + if INUMP(y) return BOOL_F; + ASRTGO(NIMP(y) && BIGP(y), bady); + return (0==bigcomp(x, y)) ? BOOL_T : BOOL_F; + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_eqp); +# endif + return BOOL_F; + } +# else + ASSERT(INUMP(x), x, ARG1, s_eqp); + ASSERT(INUMP(y), y, ARG2, s_eqp); +# endif +#endif + return ((long)x==(long)y) ? BOOL_T : BOOL_F; +} +SCM lessp(x, y) + SCM x, y; +{ +#ifdef FLOATS + if NINUMP(x) { +# ifdef BIGDIG +# ifndef RECKLESS + if (!(NIMP(x))) + badx: wta(x, (char *)ARG1, s_lessp); +# endif + if BIGP(x) { + if INUMP(y) return BIGSIGN(x) ? BOOL_T : BOOL_F; + ASRTGO(NIMP(y), bady); + if BIGP(y) return (1==bigcomp(x, y)) ? BOOL_T : BOOL_F; + ASRTGO(REALP(y), bady); + return (big2dbl(x) < REALPART(y)) ? BOOL_T : BOOL_F; + } + ASRTGO(REALP(x), badx); +# else + ASSERT(NIMP(x) && REALP(x), x, ARG1, s_lessp); +# endif + if INUMP(y) return (REALPART(x) < ((double)INUM(y))) ? BOOL_T : BOOL_F; +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) return (REALPART(x) < big2dbl(y)) ? BOOL_T : BOOL_F; + ASRTGO(REALP(y), bady); +# else + ASRTGO(NIMP(y) && REALP(y), bady); +# endif + return (REALPART(x) < REALPART(y)) ? BOOL_T : BOOL_F; + } + if NINUMP(y) { +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) return BIGSIGN(y) ? BOOL_F : BOOL_T; +# ifndef RECKLESS + if (!(REALP(y))) + bady: wta(y, (char *)ARG2, s_lessp); +# endif +# else +# ifndef RECKLESS + if (!(NIMP(y) && REALP(y))) + bady: wta(y, (char *)ARG2, s_lessp); +# endif +# endif + return (((double)INUM(x)) < REALPART(y)) ? BOOL_T : BOOL_F; + } +#else +# ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_lessp); + if INUMP(y) return BIGSIGN(x) ? BOOL_T : BOOL_F; + ASRTGO(NIMP(y) && BIGP(y), bady); + return (1==bigcomp(x, y)) ? BOOL_T : BOOL_F; + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_lessp); +# endif + return BIGSIGN(y) ? BOOL_F : BOOL_T; + } +# else + ASSERT(INUMP(x), x, ARG1, s_lessp); + ASSERT(INUMP(y), y, ARG2, s_lessp); +# endif +#endif + return ((long)x < (long)y) ? BOOL_T : BOOL_F; +} +SCM greaterp(x, y) + SCM x, y; +{ + return lessp(y, x); +} +SCM leqp(x, y) + SCM x, y; +{ + return BOOL_NOT(lessp(y, x)); +} +SCM greqp(x, y) + SCM x, y; +{ + return BOOL_NOT(lessp(x, y)); +} +SCM zerop(z) + SCM z; +{ +#ifdef FLOATS + if NINUMP(z) { +# ifdef BIGDIG + ASRTGO(NIMP(z), badz); + if BIGP(z) return BOOL_F; +# ifndef RECKLESS + if (!(INEXP(z))) + badz: wta(z, (char *)ARG1, s_zerop); +# endif +# else + ASSERT(NIMP(z) && INEXP(z), z, ARG1, s_zerop); +# endif + return (z==flo0) ? BOOL_T : BOOL_F; + } +#else +# ifdef BIGDIG + if NINUMP(z) { + ASSERT(NIMP(z) && BIGP(z), z, ARG1, s_zerop); + return BOOL_F; + } +# else + ASSERT(INUMP(z), z, ARG1, s_zerop); +# endif +#endif + return (z==INUM0) ? BOOL_T: BOOL_F; +} +SCM positivep(x) + SCM x; +{ +#ifdef FLOATS + if NINUMP(x) { +# ifdef BIGDIG + ASRTGO(NIMP(x), badx); + if BIGP(x) return TYP16(x)==tc16_bigpos ? BOOL_T : BOOL_F; +# ifndef RECKLESS + if (!(REALP(x))) + badx: wta(x, (char *)ARG1, s_positivep); +# endif +# else + ASSERT(NIMP(x) && REALP(x), x, ARG1, s_positivep); +# endif + return (REALPART(x) > 0.0) ? BOOL_T : BOOL_F; + } +#else +# ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_positivep); + return TYP16(x)==tc16_bigpos ? BOOL_T : BOOL_F; + } +# else + ASSERT(INUMP(x), x, ARG1, s_positivep); +# endif +#endif + return (x > INUM0) ? BOOL_T : BOOL_F; +} +SCM negativep(x) + SCM x; +{ +#ifdef FLOATS + if NINUMP(x) { +# ifdef BIGDIG + ASRTGO(NIMP(x), badx); + if BIGP(x) return TYP16(x)==tc16_bigpos ? BOOL_F : BOOL_T; +# ifndef RECKLESS + if (!(REALP(x))) + badx: wta(x, (char *)ARG1, s_negativep); +# endif +# else + ASSERT(NIMP(x) && REALP(x), x, ARG1, s_negativep); +# endif + return (REALPART(x) < 0.0) ? BOOL_T : BOOL_F; + } +#else +# ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_negativep); + return (TYP16(x)==tc16_bigneg) ? BOOL_T : BOOL_F; + } +# else + ASSERT(INUMP(x), x, ARG1, s_negativep); +# endif +#endif + return (x < INUM0) ? BOOL_T : BOOL_F; +} + +SCM lmax(x, y) + SCM x, y; +{ +#ifdef FLOATS + double z; +#endif + if UNBNDP(y) { +#ifndef RECKLESS + if (!(NUMBERP(x))) + badx: wta(x, (char *)ARG1, s_max); +#endif + return x; + } +#ifdef FLOATS + if NINUMP(x) { +# ifdef BIGDIG + ASRTGO(NIMP(x), badx); + if BIGP(x) { + if INUMP(y) return BIGSIGN(x) ? y : x; + ASRTGO(NIMP(y), bady); + if BIGP(y) return (1==bigcomp(x, y)) ? y : x; + ASRTGO(REALP(y), bady); + z = big2dbl(x); + return (z < REALPART(y)) ? y : makdbl(z, 0.0); + } + ASRTGO(REALP(x), badx); +# else + ASSERT(NIMP(x) && REALP(x), x, ARG1, s_max); +# endif + if INUMP(y) return (REALPART(x) < (z = INUM(y))) ? makdbl(z, 0.0) : x; +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) return (REALPART(x) < (z = big2dbl(y))) ? makdbl(z, 0.0) : x; + ASRTGO(REALP(y), bady); +# else + ASRTGO(NIMP(y) && REALP(y), bady); +# endif + return (REALPART(x) < REALPART(y)) ? y : x; + } + if NINUMP(y) { +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) return BIGSIGN(y) ? x : y; +# ifndef RECKLESS + if (!(REALP(y))) + bady: wta(y, (char *)ARG2, s_max); +# endif +# else +# ifndef RECKLESS + if (!(NIMP(y) && REALP(y))) + bady: wta(y, (char *)ARG2, s_max); +# endif +# endif + return ((z = INUM(x)) < REALPART(y)) ? y : makdbl(z, 0.0); + } +#else +# ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_max); + if INUMP(y) return BIGSIGN(x) ? y : x; + ASRTGO(NIMP(y) && BIGP(y), bady); + return (1==bigcomp(x, y)) ? y : x; + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_max); +# endif + return BIGSIGN(y) ? x : y; + } +# else + ASSERT(INUMP(x), x, ARG1, s_max); + ASSERT(INUMP(y), y, ARG2, s_max); +# endif +#endif + return ((long)x < (long)y) ? y : x; +} + +SCM lmin(x, y) + SCM x, y; +{ +#ifdef FLOATS + double z; +#endif + if UNBNDP(y) { +#ifndef RECKLESS + if (!(NUMBERP(x))) + badx: wta(x, (char *)ARG1, s_min); +#endif + return x; + } +#ifdef FLOATS + if NINUMP(x) { +# ifdef BIGDIG + ASRTGO(NIMP(x), badx); + if BIGP(x) { + if INUMP(y) return BIGSIGN(x) ? x : y; + ASRTGO(NIMP(y), bady); + if BIGP(y) return (-1==bigcomp(x, y)) ? y : x; + ASRTGO(REALP(y), bady); + z = big2dbl(x); + return (z > REALPART(y)) ? y : makdbl(z, 0.0); + } + ASRTGO(REALP(x), badx); +# else + ASSERT(NIMP(x) && REALP(x), x, ARG1, s_min); +# endif + if INUMP(y) return (REALPART(x) > (z = INUM(y))) ? makdbl(z, 0.0) : x; +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) return (REALPART(x) > (z = big2dbl(y))) ? makdbl(z, 0.0) : x; + ASRTGO(REALP(y), bady); +# else + ASRTGO(NIMP(y) && REALP(y), bady); +# endif + return (REALPART(x) > REALPART(y)) ? y : x; + } + if NINUMP(y) { +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) return BIGSIGN(y) ? y : x; +# ifndef RECKLESS + if (!(REALP(y))) + bady: wta(y, (char *)ARG2, s_min); +# endif +# else +# ifndef RECKLESS + if (!(NIMP(y) && REALP(y))) + bady: wta(y, (char *)ARG2, s_min); +# endif +# endif + return ((z = INUM(x)) > REALPART(y)) ? y : makdbl(z, 0.0); + } +#else +# ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_min); + if INUMP(y) return BIGSIGN(x) ? x : y; + ASRTGO(NIMP(y) && BIGP(y), bady); + return (-1==bigcomp(x, y)) ? y : x; + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_min); +# endif + return BIGSIGN(y) ? y : x; + } +# else + ASSERT(INUMP(x), x, ARG1, s_min); + ASSERT(INUMP(y), y, ARG2, s_min); +# endif +#endif + return ((long)x > (long)y) ? y : x; +} + +SCM sum(x, y) + SCM x, y; +{ + if UNBNDP(y) { + if UNBNDP(x) return INUM0; +#ifndef RECKLESS + if (!(NUMBERP(x))) + badx: wta(x, (char *)ARG1, s_sum); +#endif + return x; + } +#ifdef FLOATS + if NINUMP(x) { + SCM t; +# ifdef BIGDIG + ASRTGO(NIMP(x), badx); + if BIGP(x) { + if INUMP(y) {t = x; x = y; y = t; goto intbig;} + ASRTGO(NIMP(y), bady); + if BIGP(y) { + if (NUMDIGS(x) > NUMDIGS(y)) {t = x; x = y; y = t;} + return addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0); + } + ASRTGO(INEXP(y), bady); + bigreal: return makdbl(big2dbl(x)+REALPART(y), CPLXP(y)?IMAG(y):0.0); + } + ASRTGO(INEXP(x), badx); +# else + ASRTGO(NIMP(x) && INEXP(x), badx); +# endif + if INUMP(y) {t = x; x = y; y = t; goto intreal;} +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) {t = x; x = y; y = t; goto bigreal;} +# ifndef RECKLESS + else if (!(INEXP(y))) + bady: wta(y, (char *)ARG2, s_sum); +# endif +# else +# ifndef RECKLESS + if (!(NIMP(y) && INEXP(y))) + bady: wta(y, (char *)ARG2, s_sum); +# endif +# endif + { double i = 0.0; + if CPLXP(x) i = IMAG(x); + if CPLXP(y) i += IMAG(y); + return makdbl(REALPART(x)+REALPART(y), i); } + } + if NINUMP(y) { +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) + intbig: { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(x)); + return addbig((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0); +# endif + } + ASRTGO(INEXP(y), bady); +# else + ASRTGO(NIMP(y) && INEXP(y), bady); +# endif + intreal: return makdbl(INUM(x)+REALPART(y), CPLXP(y)?IMAG(y):0.0); + } +#else +# ifdef BIGDIG + if NINUMP(x) { + SCM t; + ASRTGO(NIMP(x) && BIGP(x), badx); + if INUMP(y) {t = x; x = y; y = t; goto intbig;} + ASRTGO(NIMP(y) && BIGP(y), bady); + if (NUMDIGS(x) > NUMDIGS(y)) {t = x; x = y; y = t;} + return addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0); + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_sum); +# endif + intbig: { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(x)); + return addbig(&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0); +# endif + } + } +# else + ASRTGO(INUMP(x), badx); + ASSERT(INUMP(y), y, ARG2, s_sum); +# endif +#endif + x = INUM(x)+INUM(y); + if FIXABLE(x) return MAKINUM(x); +#ifdef BIGDIG + return long2big(x); +#else +# ifdef FLOATS + return makdbl((double)x, 0.0); +# else + wta(y, (char *)OVFLOW, s_sum); +# endif +#endif +} + +SCM difference(x, y) + SCM x, y; +{ +#ifdef FLOATS + if NINUMP(x) { +# ifndef RECKLESS + if (!(NIMP(x))) + badx: wta(x, (char *)ARG1, s_difference); +# endif + if UNBNDP(y) { +# ifdef BIGDIG + if BIGP(x) { + x = copybig(x, !BIGSIGN(x)); + return NUMDIGS(x) * BITSPERDIG/CHAR_BIT <= sizeof(SCM) ? + big2inum(x, NUMDIGS(x)) : x; + } +# endif + ASRTGO(INEXP(x), badx); + return makdbl(-REALPART(x), CPLXP(x)?-IMAG(x):0.0); + } + if INUMP(y) return sum(x, MAKINUM(-INUM(y))); +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(x) { + if BIGP(y) return (NUMDIGS(x) < NUMDIGS(y)) ? + addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0x0100) : + addbig(BDIGITS(y), NUMDIGS(y), BIGSIGN(y) ^ 0x0100, x, 0); + ASRTGO(INEXP(y), bady); + return makdbl(big2dbl(x)-REALPART(y), CPLXP(y)?-IMAG(y):0.0); + } + ASRTGO(INEXP(x), badx); + if BIGP(y) return makdbl(REALPART(x)-big2dbl(y), CPLXP(x)?IMAG(x):0.0); + ASRTGO(INEXP(y), bady); +# else + ASRTGO(INEXP(x), badx); + ASRTGO(NIMP(y) && INEXP(y), bady); +# endif + if CPLXP(x) + if CPLXP(y) + return makdbl(REAL(x)-REAL(y), IMAG(x)-IMAG(y)); + else + return makdbl(REAL(x)-REALPART(y), IMAG(x)); + return makdbl(REALPART(x)-REALPART(y), CPLXP(y)?-IMAG(y):0.0); + } + if UNBNDP(y) {x = -INUM(x); goto checkx;} + if NINUMP(y) { +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(x)); + return addbig((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100); +# endif + } +# ifndef RECKLESS + if (!(INEXP(y))) + bady: wta(y, (char *)ARG2, s_difference); +# endif +# else +# ifndef RECKLESS + if (!(NIMP(y) && INEXP(y))) + bady: wta(y, (char *)ARG2, s_difference); +# endif +# endif + return makdbl(INUM(x)-REALPART(y), CPLXP(y)?-IMAG(y):0.0); + } +#else +# ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_difference); + if UNBNDP(y) { + x = copybig(x, !BIGSIGN(x)); + return NUMDIGS(x) * BITSPERDIG/CHAR_BIT <= sizeof(SCM) ? + big2inum(x, NUMDIGS(x)) : x; + } + if INUMP(y) { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(y)); + return addbig(&z, DIGSPERLONG, (y < 0) ? 0 : 0x0100, x, 0); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + return addbig(zdigs, DIGSPERLONG, (y < 0) ? 0 : 0x0100, x, 0); +# endif + } + ASRTGO(NIMP(y) && BIGP(y), bady); + return (NUMDIGS(x) < NUMDIGS(y)) ? + addbig(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0x0100) : + addbig(BDIGITS(y), NUMDIGS(y), BIGSIGN(y) ^ 0x0100, x, 0); + } + if UNBNDP(y) {x = -INUM(x); goto checkx;} + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_difference); +# endif + { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(x)); + return addbig(&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + return addbig(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100); +# endif + } + } +# else + ASSERT(INUMP(x), x, ARG1, s_difference); + if UNBNDP(y) {x = -INUM(x); goto checkx;} + ASSERT(INUMP(y), y, ARG2, s_difference); +# endif +#endif + x = INUM(x)-INUM(y); + checkx: + if FIXABLE(x) return MAKINUM(x); +#ifdef BIGDIG + return long2big(x); +#else +# ifdef FLOATS + return makdbl((double)x, 0.0); +# else + wta(y, (char *)OVFLOW, s_difference); +# endif +#endif +} + +SCM product(x, y) + SCM x, y; +{ + if UNBNDP(y) { + if UNBNDP(x) return MAKINUM(1L); +#ifndef RECKLESS + if (!(NUMBERP(x))) + badx: wta(x, (char *)ARG1, s_product); +#endif + return x; + } +#ifdef FLOATS + if NINUMP(x) { + SCM t; +# ifdef BIGDIG + ASRTGO(NIMP(x), badx); + if BIGP(x) { + if INUMP(y) {t = x; x = y; y = t; goto intbig;} + ASRTGO(NIMP(y), bady); + if BIGP(y) return mulbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), + BIGSIGN(x) ^ BIGSIGN(y)); + ASRTGO(INEXP(y), bady); + bigreal: { + double bg = big2dbl(x); + return makdbl(bg*REALPART(y), CPLXP(y)?bg*IMAG(y):0.0); } + } + ASRTGO(INEXP(x), badx); +# else + ASRTGO(NIMP(x) && INEXP(x), badx); +# endif + if INUMP(y) {t = x; x = y; y = t; goto intreal;} +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) {t = x; x = y; y = t; goto bigreal;} +# ifndef RECKLESS + else if (!(INEXP(y))) + bady: wta(y, (char *)ARG2, s_product); +# endif +# else +# ifndef RECKLESS + if (!(NIMP(y) && INEXP(y))) + bady: wta(y, (char *)ARG2, s_product); +# endif +# endif + if CPLXP(x) + if CPLXP(y) + return makdbl(REAL(x)*REAL(y)-IMAG(x)*IMAG(y), + REAL(x)*IMAG(y)+IMAG(x)*REAL(y)); + else + return makdbl(REAL(x)*REALPART(y), IMAG(x)*REALPART(y)); + return makdbl(REALPART(x)*REALPART(y), + CPLXP(y)?REALPART(x)*IMAG(y):0.0); + } + if NINUMP(y) { +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) { + intbig: if (INUM0==x) return x; if (MAKINUM(1L)==x) return y; + { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(x)); + return mulbig((BIGDIG *)&z, DIGSPERLONG, BDIGITS(y), NUMDIGS(y), + BIGSIGN(y) ? (x>0) : (x<0)); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + return mulbig(zdigs, DIGSPERLONG, BDIGITS(y), NUMDIGS(y), + BIGSIGN(y) ? (x>0) : (x<0)); +# endif + } + } + ASRTGO(INEXP(y), bady); +# else + ASRTGO(NIMP(y) && INEXP(y), bady); +# endif + intreal: return makdbl(INUM(x)*REALPART(y), CPLXP(y)?INUM(x)*IMAG(y):0.0); + } +#else +# ifdef BIGDIG + if NINUMP(x) { + ASRTGO(NIMP(x) && BIGP(x), badx); + if INUMP(y) {SCM t = x; x = y; y = t; goto intbig;} + ASRTGO(NIMP(y) && BIGP(y), bady); + return mulbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), + BIGSIGN(x) ^ BIGSIGN(y)); + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_product); +# endif + intbig: if (INUM0==x) return x; if (MAKINUM(1L)==x) return y; + { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(x)); + return mulbig(&z, DIGSPERLONG, BDIGITS(y), NUMDIGS(y), + BIGSIGN(y) ? (x>0) : (x<0)); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + return mulbig(zdigs, DIGSPERLONG, BDIGITS(y), NUMDIGS(y), + BIGSIGN(y) ? (x>0) : (x<0)); +# endif + } + } +# else + ASRTGO(INUMP(x), badx); + ASSERT(INUMP(y), y, ARG2, s_product); +# endif +#endif + { + long i, j, k; + i = INUM(x); + if (0==i) return x; + j = INUM(y); + k = i * j; + y = MAKINUM(k); + if (k != INUM(y) || k/i != j) +#ifdef BIGDIG + { int sgn = (i < 0) ^ (j < 0); +# ifndef DIGSTOOBIG + i = pseudolong(i); + j = pseudolong(j); + return mulbig((BIGDIG *)&i, DIGSPERLONG, + (BIGDIG *)&j, DIGSPERLONG, sgn); +# else /* DIGSTOOBIG */ + BIGDIG idigs[DIGSPERLONG]; + BIGDIG jdigs[DIGSPERLONG]; + longdigs(i, idigs); + longdigs(j, jdigs); + return mulbig(idigs, DIGSPERLONG, jdigs, DIGSPERLONG, sgn); +# endif + } +#else +# ifdef FLOATS + return makdbl(((double)i)*((double)j), 0.0); +# else + wta(y, (char *)OVFLOW, s_product); +# endif +#endif + return y; + } +} + +SCM divide(x, y) + SCM x, y; +{ +#ifdef FLOATS + double d, r, i, a; + if NINUMP(x) { +# ifndef RECKLESS + if (!(NIMP(x))) + badx: wta(x, (char *)ARG1, s_divide); +# endif + if UNBNDP(y) { +# ifdef BIGDIG + if BIGP(x) return makdbl(1.0/big2dbl(x), 0.0); +# endif + ASRTGO(INEXP(x), badx); + if REALP(x) return makdbl(1.0/REALPART(x), 0.0); + r = REAL(x); i = IMAG(x); d = r*r+i*i; + return makdbl(r/d, -i/d); + } +# ifdef BIGDIG + if BIGP(x) { + SCM z; + if INUMP(y) { + z = INUM(y); + ASSERT(z, y, OVFLOW, s_divide); + if (1==z) return x; + if (z < 0) z = -z; + if (z < BIGRAD) { + SCM w = copybig(x, BIGSIGN(x) ? (y>0) : (y<0)); + return divbigdig(BDIGITS(w), NUMDIGS(w), (BIGDIG)z) ? + makdbl(big2dbl(x)/INUM(y), 0.0) : normbig(w); + } +# ifndef DIGSTOOBIG + z = pseudolong(z); + z = divbigbig(BDIGITS(x), NUMDIGS(x), (BIGDIG *)&z, DIGSPERLONG, + BIGSIGN(x) ? (y>0) : (y<0), 3); +# else + { BIGDIG zdigs[DIGSPERLONG]; + longdigs(z, zdigs); + z = divbigbig(BDIGITS(x), NUMDIGS(x), zdigs, DIGSPERLONG, + BIGSIGN(x) ? (y>0) : (y<0), 3);} +# endif + return z ? z : makdbl(big2dbl(x)/INUM(y), 0.0); + } + ASRTGO(NIMP(y), bady); + if BIGP(y) { + z = divbigbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), + BIGSIGN(x) ^ BIGSIGN(y), 3); + return z ? z : makdbl(big2dbl(x)/big2dbl(y), 0.0); + } + ASRTGO(INEXP(y), bady); + if REALP(y) return makdbl(big2dbl(x)/REALPART(y), 0.0); + a = big2dbl(x); + goto complex_div; + } +# endif + ASRTGO(INEXP(x), badx); + if INUMP(y) {d = INUM(y); goto basic_div;} +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) {d = big2dbl(y); goto basic_div;} + ASRTGO(INEXP(y), bady); +# else + ASRTGO(NIMP(y) && INEXP(y), bady); +# endif + if REALP(y) { + d = REALPART(y); + basic_div: return makdbl(REALPART(x)/d, CPLXP(x)?IMAG(x)/d:0.0); + } + a = REALPART(x); + if REALP(x) goto complex_div; + r = REAL(y); i = IMAG(y); d = r*r+i*i; + return makdbl((a*r+IMAG(x)*i)/d, (IMAG(x)*r-a*i)/d); + } + if UNBNDP(y) { + if ((MAKINUM(1L)==x) || (MAKINUM(-1L)==x)) return x; + return makdbl(1.0/((double)INUM(x)), 0.0); + } + if NINUMP(y) { +# ifdef BIGDIG + ASRTGO(NIMP(y), bady); + if BIGP(y) return makdbl(INUM(x)/big2dbl(y), 0.0); +# ifndef RECKLESS + if (!(INEXP(y))) + bady: wta(y, (char *)ARG2, s_divide); +# endif +# else +# ifndef RECKLESS + if (!(NIMP(y) && INEXP(y))) + bady: wta(y, (char *)ARG2, s_divide); +# endif +# endif + if REALP(y) return makdbl(INUM(x)/REALPART(y), 0.0); + a = INUM(x); + complex_div: + r = REAL(y); i = IMAG(y); d = r*r+i*i; + return makdbl((a*r)/d, (-a*i)/d); + } +#else +# ifdef BIGDIG + if NINUMP(x) { + SCM z; + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_divide); + if UNBNDP(y) goto ov; + if INUMP(y) { + z = INUM(y); + if (!z) goto ov; + if (1==z) return x; + if (z < 0) z = -z; + if (z < BIGRAD) { + SCM w = copybig(x, BIGSIGN(x) ? (y>0) : (y<0)); + if (divbigdig(BDIGITS(w), NUMDIGS(w), (BIGDIG)z)) goto ov; + return w; + } +# ifndef DIGSTOOBIG + z = pseudolong(z); + z = divbigbig(BDIGITS(x), NUMDIGS(x), &z, DIGSPERLONG, + BIGSIGN(x) ? (y>0) : (y<0), 3); +# else + { BIGDIG zdigs[DIGSPERLONG]; + longdigs(z, zdigs); + z = divbigbig(BDIGITS(x), NUMDIGS(x), zdigs, DIGSPERLONG, + BIGSIGN(x) ? (y>0) : (y<0), 3);} +# endif + } else { + ASRTGO(NIMP(y) && BIGP(y), bady); + z = divbigbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), + BIGSIGN(x) ^ BIGSIGN(y), 3); + } + if (!z) goto ov; + return z; + } + if UNBNDP(y) { + if ((MAKINUM(1L)==x) || (MAKINUM(-1L)==x)) return x; + goto ov; + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_divide); +# endif + goto ov; + } +# else + ASSERT(INUMP(x), x, ARG1, s_divide); + if UNBNDP(y) { + if ((MAKINUM(1L)==x) || (MAKINUM(-1L)==x)) return x; + goto ov; + } + ASSERT(INUMP(y), y, ARG2, s_divide); +# endif +#endif + { + long z = INUM(y); + if ((0==z) || INUM(x)%z) goto ov; + z = INUM(x)/z; + if FIXABLE(z) return MAKINUM(z); +#ifdef BIGDIG + return long2big(z); +#endif +#ifdef FLOATS + ov: return makdbl(((double)INUM(x))/((double)INUM(y)), 0.0); +#else + ov: wta(x, (char *)OVFLOW, s_divide); +#endif + } +} + +#ifdef FLOATS +double lasinh(x) + double x; +{ + return log(x+sqrt(x*x+1)); +} + +double lacosh(x) + double x; +{ + return log(x+sqrt(x*x-1)); +} + +double latanh(x) + double x; +{ + return 0.5*log((1+x)/(1-x)); +} + +double ltrunc(x) + double x; +{ + if (x < 0.0) return -floor(-x); + return floor(x); +} +double round(x) + double x; +{ + double plus_half = x + 0.5; + double result = floor(plus_half); + /* Adjust so that the round is towards even. */ + return (plus_half==result && plus_half / 2 != floor(plus_half / 2)) + ? result - 1 : result; +} + +struct dpair {double x, y;}; + +void two_doubles(z1, z2, sstring, xy) + SCM z1, z2; + char *sstring; + struct dpair *xy; +{ + if INUMP(z1) xy->x = INUM(z1); + else { +# ifdef BIGDIG + ASRTGO(NIMP(z1), badz1); + if BIGP(z1) xy->x = big2dbl(z1); + else { +# ifndef RECKLESS + if (!(REALP(z1))) + badz1: wta(z1, (char *)ARG1, sstring); +# endif + xy->x = REALPART(z1);} +# else + {ASSERT(NIMP(z1) && REALP(z1), z1, ARG1, sstring); + xy->x = REALPART(z1);} +# endif + } + if INUMP(z2) xy->y = INUM(z2); + else { +# ifdef BIGDIG + ASRTGO(NIMP(z2), badz2); + if BIGP(z2) xy->y = big2dbl(z2); + else { +# ifndef RECKLESS + if (!(REALP(z2))) + badz2: wta(z2, (char *)ARG2, sstring); +# endif + xy->y = REALPART(z2);} +# else + {ASSERT(NIMP(z2) && REALP(z2), z2, ARG2, sstring); + xy->y = REALPART(z2);} +# endif + } +} + +SCM expt(z1, z2) + SCM z1, z2; +{ + struct dpair xy; + two_doubles(z1, z2, s_expt, &xy); + return makdbl(pow(xy.x, xy.y), 0.0); +} +SCM latan2(z1, z2) + SCM z1, z2; +{ + struct dpair xy; + two_doubles(z1, z2, s_atan2, &xy); + return makdbl(atan2(xy.x, xy.y), 0.0); +} +SCM makrect(z1, z2) + SCM z1, z2; +{ + struct dpair xy; + two_doubles(z1, z2, s_makrect, &xy); + return makdbl(xy.x, xy.y); +} +SCM makpolar(z1, z2) + SCM z1, z2; +{ + struct dpair xy; + two_doubles(z1, z2, s_makpolar, &xy); + return makdbl(xy.x*cos(xy.y), xy.x*sin(xy.y)); +} + +SCM real_part(z) + SCM z; +{ + if NINUMP(z) { +# ifdef BIGDIG + ASRTGO(NIMP(z), badz); + if BIGP(z) return z; +# ifndef RECKLESS + if (!(INEXP(z))) + badz: wta(z, (char *)ARG1, s_real_part); +# endif +# else + ASSERT(NIMP(z) && INEXP(z), z, ARG1, s_real_part); +# endif + if CPLXP(z) return makdbl(REAL(z), 0.0); + } + return z; +} +SCM imag_part(z) + SCM z; +{ + if INUMP(z) return INUM0; +# ifdef BIGDIG + ASRTGO(NIMP(z), badz); + if BIGP(z) return INUM0; +# ifndef RECKLESS + if (!(INEXP(z))) + badz: wta(z, (char *)ARG1, s_imag_part); +# endif +# else + ASSERT(NIMP(z) && INEXP(z), z, ARG1, s_imag_part); +# endif + if CPLXP(z) return makdbl(IMAG(z), 0.0); + return flo0; +} +SCM magnitude(z) + SCM z; +{ + if INUMP(z) return absval(z); +# ifdef BIGDIG + ASRTGO(NIMP(z), badz); + if BIGP(z) return absval(z); +# ifndef RECKLESS + if (!(INEXP(z))) + badz: wta(z, (char *)ARG1, s_magnitude); +# endif +# else + ASSERT(NIMP(z) && INEXP(z), z, ARG1, s_magnitude); +# endif + if CPLXP(z) + { + double i = IMAG(z), r = REAL(z); + return makdbl(sqrt(i*i+r*r), 0.0); + } + return makdbl(fabs(REALPART(z)), 0.0); +} + +SCM angle(z) + SCM z; +{ + double x, y = 0.0; + if INUMP(z) {x = (z>=INUM0) ? 1.0 : -1.0; goto do_angle;} +# ifdef BIGDIG + ASRTGO(NIMP(z), badz); + if BIGP(z) {x = (TYP16(z)==tc16_bigpos) ? 1.0 : -1.0; goto do_angle;} +# ifndef RECKLESS + if (!(INEXP(z))) { + badz: wta(z, (char *)ARG1, s_angle);} +# endif +# else + ASSERT(NIMP(z) && INEXP(z), z, ARG1, s_angle); +# endif + if REALP(z) {x = REALPART(z); goto do_angle;} + x = REAL(z); y = IMAG(z); +do_angle: + return makdbl(atan2(y, x), 0.0); +} + +double floident(z) + double z; +{ + return z; +} +SCM in2ex(z) + SCM z; +{ + if INUMP(z) return z; +# ifdef BIGDIG + ASRTGO(NIMP(z), badz); + if BIGP(z) return z; +# ifndef RECKLESS + if (!(REALP(z))) + badz: wta(z, (char *)ARG1, s_in2ex); +# endif +# else + ASSERT(NIMP(z) && REALP(z), z, ARG1, s_in2ex); +# endif +# ifdef BIGDIG + { + double u = floor(REALPART(z)+0.5); + if ((u <= MOST_POSITIVE_FIXNUM) && (-u <= -MOST_NEGATIVE_FIXNUM)) { + /* Negation is a workaround for HP700 cc bug */ + SCM ans = MAKINUM((long)u); + if (INUM(ans)==(long)u) return ans; + } + ASRTGO(!IS_INF(u), badz); /* problem? */ + return dbl2big(u); + } +# else + return MAKINUM((long)floor(REALPART(z)+0.5)); +# endif +} +#else /* ~FLOATS */ +static char s_trunc[] = "truncate"; +SCM numident(x) + SCM x; +{ + ASSERT(INUMP(x), x, ARG1, s_trunc); + return x; +} +#endif /* FLOATS */ + +#ifdef BIGDIG +# ifdef FLOATS +SCM dbl2big(d) + double d; /* must be integer */ +{ + sizet i = 0; + long c; + BIGDIG *digits; + SCM ans; + double u = (d < 0)?-d:d; + while (0 != floor(u)) {u /= BIGRAD;i++;} + ans = mkbig(i, d < 0); + digits = BDIGITS(ans); + while (i--) { + u *= BIGRAD; + c = floor(u); + u -= c; + digits[i] = c; + } + ASSERT(0==u, INUM0, OVFLOW, "dbl2big"); + return ans; +} +double big2dbl(b) + SCM b; +{ + double ans = 0.0; + sizet i = NUMDIGS(b); + BIGDIG *digits = BDIGITS(b); + while (i--) ans = digits[i] + BIGRAD*ans; + if (tc16_bigneg==TYP16(b)) return -ans; + return ans; +} +# endif +#endif + +unsigned long hasher(obj, n, d) + SCM obj; + unsigned long n; + sizet d; +{ + switch (7 & (int) obj) { + case 2: case 6: /* INUMP(obj) */ + return INUM(obj) % n; + case 4: + if ICHRP(obj) + return (unsigned)(downcase[ICHR(obj)]) % n; + switch ((int) obj) { +#ifndef SICP + case (int) EOL: d = 256; break; +#endif + case (int) BOOL_T: d = 257; break; + case (int) BOOL_F: d = 258; break; + case (int) EOF_VAL: d = 259; break; + default: d = 263; /* perhaps should be error */ + } + return d % n; + default: return 263 % n; /* perhaps should be error */ + case 0: + switch TYP7(obj) { + default: return 263 % n; + case tc7_smob: + switch TYP16(obj) { + case tcs_bignums: + bighash: return INUM(modulo(obj, MAKINUM(n))); + default: return 263 % n; +#ifdef FLOATS + case tc16_flo: + if REALP(obj) { + double r = REALPART(obj); + if (floor(r)==r) { + obj = in2ex(obj); + if IMP(obj) return INUM(obj) % n; + goto bighash; + } + } + obj = number2string(obj, MAKINUM(10)); +#endif + } + case tcs_symbols: case tc7_string: + return strhash(UCHARS(obj), (sizet) LENGTH(obj), n); + case tc7_vector: { + sizet len = LENGTH(obj); + SCM *data = VELTS(obj); + if (len>5) { + sizet i = d/2; + unsigned long h = 1; + while (i--) h = ((h<<8) + (hasher(data[h % len], n, 2))) % n; + return h; + } + else { + sizet i = len; + unsigned long h = (n)-1; + while (i--) h = ((h<<8) + (hasher(data[i], n, d/len))) % n; + return h; + } + } + case tcs_cons_imcar: case tcs_cons_nimcar: + if (d) return (hasher(CAR(obj), n, d/2)+hasher(CDR(obj), n, d/2)) % n; + else return 1; + case tc7_port: + return ((RDNG & CAR(obj)) ? 260 : 261) % n; + case tcs_closures: case tc7_contin: case tcs_subrs: + return 262 % n; + } + } +} + +static char s_hashv[] = "hashv", s_hashq[] = "hashq"; +extern char s_obunhash[]; +#define s_hash (&s_obunhash[9]) + +SCM hash(obj, n) + SCM obj; + SCM n; +{ + ASSERT(INUMP(n) && 0 <= n, n, ARG2, s_hash); + return MAKINUM(hasher(obj, INUM(n), 10)); +} + +SCM hashv(obj, n) + SCM obj; + SCM n; +{ + ASSERT(INUMP(n) && 0 <= n, n, ARG2, s_hashv); + if ICHRP(obj) return MAKINUM((unsigned)(downcase[ICHR(obj)]) % INUM(n)); + if (NIMP(obj) && NUMP(obj)) return MAKINUM(hasher(obj, INUM(n), 10)); + else return MAKINUM(obj % INUM(n)); +} + +SCM hashq(obj, n) + SCM obj; + SCM n; +{ + ASSERT(INUMP(n) && 0 <= n, n, ARG2, s_hashq); + return MAKINUM((((unsigned) obj) >> 1) % INUM(n)); +} + +static iproc subr1s[] = { + {"number?", numberp}, + {"complex?", numberp}, + {s_inexactp, inexactp}, +#ifdef FLOATS + {"real?", realp}, + {"rational?", realp}, + {"integer?", intp}, + {s_real_part, real_part}, + {s_imag_part, imag_part}, + {s_magnitude, magnitude}, + {s_angle, angle}, + {s_in2ex, in2ex}, +#else + {"real?", numberp}, + {"rational?", numberp}, + {"integer?", exactp}, + {"floor", numident}, + {"ceiling", numident}, + {s_trunc, numident}, + {"round", numident}, +#endif + {s_zerop, zerop}, + {s_positivep, positivep}, + {s_negativep, negativep}, + {s_str2list, string2list}, + {"list->string", string}, + {s_st_copy, string_copy}, + {"list->vector", vector}, + {s_vect2list, vector2list}, + {0, 0}}; + +static iproc asubrs[] = { + {s_difference, difference}, + {s_divide, divide}, + {s_max, lmax}, + {s_min, lmin}, + {s_sum, sum}, + {s_product, product}, + {0, 0}}; + +static iproc subr2s[] = { +#ifdef FLOATS + {s_makrect, makrect}, + {s_makpolar, makpolar}, + {s_memv, memv}, + {s_assv, assv}, + {s_atan2, latan2}, + {s_expt, expt}, +#else + {"memv", memq}, + {"assv", assq}, +#endif + {s_list_tail, list_tail}, + {s_ve_fill, vector_fill}, + {s_st_fill, string_fill}, + {s_hash, hash}, + {s_hashv, hashv}, + {s_hashq, hashq}, + {0, 0}}; + +static iproc subr2os[] = { + {s_str2number, string2number}, + {s_number2string, number2string}, + {0, 0}}; + +static iproc rpsubrs[] = { +#ifdef FLOATS + {"eqv?", eqv}, +#else + {"eqv?", eq}, +#endif + {s_eqp, eqp}, + {s_lessp, lessp}, + {s_grp, greaterp}, + {s_leqp, leqp}, + {s_greqp, greqp}, + {0, 0}}; + +#ifdef FLOATS +static dblproc cxrs[] = { + {"floor", floor}, + {"ceiling", ceil}, + {"truncate", ltrunc}, + {"round", round}, + {"$sqrt", sqrt}, + {"$abs", fabs}, + {"$exp", exp}, + {"$log", log}, + {"$sin", sin}, + {"$cos", cos}, + {"$tan", tan}, + {"$asin", asin}, + {"$acos", acos}, + {"$atan", atan}, + {"$sinh", sinh}, + {"$cosh", cosh}, + {"$tanh", tanh}, + {"$asinh", lasinh}, + {"$acosh", lacosh}, + {"$atanh", latanh}, + {"exact->inexact", floident}, + {0, 0}}; +#endif + +#ifdef FLOATS +# ifndef DBL_DIG +static void add1(f, fsum) + double f, *fsum; +{ + *fsum = f + 1.0; +} +# endif +#endif + +void init_scl() +{ + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(subr2os, tc7_subr_2o); + init_iprocs(subr2s, tc7_subr_2); + init_iprocs(asubrs, tc7_asubr); + init_iprocs(rpsubrs, tc7_rpsubr); +#ifdef SICP + add_feature("sicp"); +#endif +#ifdef FLOATS + init_iprocs((iproc *)cxrs, tc7_cxr); + NEWCELL(flo0); +# ifdef SINGLES + CAR(flo0) = tc_flo; + FLO(flo0) = 0.0; +# else + CDR(flo0) = (SCM)must_malloc(1L*sizeof(double), "real"); + REAL(flo0) = 0.0; + CAR(flo0) = tc_dblr; +# endif +# ifdef DBL_DIG + dblprec = (DBL_DIG > 20) ? 20 : DBL_DIG; +# else + { /* determine floating point precision */ + double f = 0.1; + double fsum = 1.0+f; + while (fsum != 1.0) { + f /= 10.0; + if (++dblprec > 20) break; + add1(f, &fsum); + } + dblprec = dblprec-1; + } +# endif /* DBL_DIG */ +#endif +} @@ -0,0 +1,335 @@ +.\" dummy line +.TH SCM "Jan 9 1995" +.UC 4 +.SH NAME +scm \- a Scheme Language Interpreter +.SH SYNOPSIS +.B scm +[-a +.I kbytes +] +[-ibvqmu] +[-p +.I number +] +[-c +.I expression +] +[-e +.I expression +] +[-f +.I filename +] +[-l +.I filename +] +[-d +.I filename +] +[-r +.I feature +] +[-- | - | -s] +[filename] [arguments ...] +.br +.sp 0.3 +.SH DESCRIPTION +.I Scm +is a Scheme interpreter. +.PP +Upon startup +.I scm +loads the file specified by by the environment variable SCM_INIT_PATH +or by the parameter IMPLINIT in the makefile (or scmfig.h) if +SCM_INIT_PATH is not defined. The makefiles attempt to set IMPLINIT +to "Init.scm" in the source directory. + +Unless the option +.I -no-init-file +occurs in the command line, "Init.scm" checks to see if there is file +"ScmInit.scm" in the path specified by the environment variable HOME +(or in the current directory if HOME is undefined). If it finds such +a file it is loaded. + +"Init.scm" then looks for command input from one of three sources: +From an option on the command line, from a file named on the command +line, or from standard input. + +.SH OPTIONS +The options are processed in the order specified on the command line. +.TP 5 +.BI -a kbytes +specifies that +.I scm +should allocate an initial heapsize of +.I kbytes. +This option, if present, must be the first on the command line. +.TP +.BI -no-init-file +Inhibits the loading of "ScmInit.scm" as described above. +.TP +.BI -e expression +.TP +.BI -c expression +specifies that the scheme expression +.I expression +is to be evaluated. These options are inspired by +.I perl +and +.I sh +respectively. +On Amiga systems the entire option and argument need to be enclosed in +qoutes. For instance "-e(newline)". +.TP +.BI -r feature +requires +.I feature. +This will load a file from SLIB if that +.I feature +is not already supported. If +.I feature +is 2, 3, 4, or 5 +.I scm +will require the features neccessary to support R2RS, R3RS, R4RS, or +proposed R5RS, respectively. +.TP +.BI -l filename +.TP +.BI -f filename +loads +.I filename. +.I Scm +will load the first (unoptioned) file named on the command line if no +-c, -e, -f, -l, or -s option preceeds it. +.TP +.BI -d filename +opens (read-only) the extended relational database +.I filename. +If +.I filename +contains initialization code, it will be run when the database is +opened. +.TP +.BI -p level +sets the prolixity (verboseness) to +.I level. +This is the same as the +.I scm +command (verobse +.I level +). +.TP +.B -v +(verbose mode) specifies that +.I scm +will print prompts, evaluation times, notice of loading files, and +garbage collection statistics. This is the same as +.I -p3. +.TP +.B -q +(quiet mode) specifies that +.I scm +will print no extra information. This is the same as +.I -p0. +.TP +.B -m +specifies that subsequent loads, evaluations, and user interactions +will be with R4RS macro capability. To use a specific R4RS macro +implementation from SLIB (instead of SLIB's default) put +.I -r macropackage +before +.I -m +on the command line. +.TP +.B -u +specifies that subsequent loads, evaluations, and user interactions +will be without R4RS macro capability. R4RS macro capability can be +restored by a subsequent +.I -m +on the command line or from Scheme code. +.TP +.B -i +specifies that +.I scm +should run interactively. That means that +.I scm +will not terminate until the +.I (quit) +or +.I (exit) +command is given, even if there are errors. It also sets the +prolixity level to 2 if it is less than 2. This will print +prompts, evaluation times, and notice of loading files. The prolixity +level can be set by subsequent options. If +.I scm +is started from a tty, it will assume that it should be interactive +unless given a subsequent +.I -b +option. +.TP +.B -b +specifies that +.I scm +should run non-interactively. That means that +.I scm +will terminate after processing the command line or if there are +errors. +.TP +.B -s +specifies, by analogy with +.I sh, +that further options are to be treated as program aguments. +.TP +.BI - +.BI -- +specifies that there are no more options on the command line. +.SH ENVIRONMENT VARIABLES +.TP 5 +.B SCM_INIT_PATH +is the pathname where +.I scm +will look for its initialization code. The default is the file +"Init.scm" in the source directory. +.TP +.B SCHEME_LIBRARY_PATH +is the SLIB Scheme library directory. +.TP +.B HOME +is the directory where "Init.scm" will look for the user +initialization file "ScmInit.scm". +.SH SCHEME VARIABLES +.TP 5 +.B *argv* +contains the list of arguments to the program. +.I *argv* +can change during argument processing. This list is +suitable for use as an argument to SLIB +.I getopt. +.TP +.B *R4RS-macro* +controls whether loading and interaction support R4RS macros. Define +this in "ScmInit.scm" or files specified on the command line. This +can be overridden by subsequent -m and -u options. +.TP +.B *interactive* +controls interactivity as explained for the -i and -b options. Define +this in "ScmInit.scm" or files specified on the command line. This +can be overridden by subsequent -i and -b options. +.SH EXAMPLES +.ne 5 +.TP 5 +% scm foo.scm arg1 arg2 arg3 +.br +Load and execute the contents of foo.scm. Parameters +arg1 arg2 and arg3 are stored in the global list *argv*. +.TP +% scm -f foo.scm arg1 arg2 arg3 +.br +The same. +.TP +% scm -s foo.scm arg1 arg2 +.br +Set *argv* to ("foo.scm" "arg1" "arg2") and enter interactive session. +.TP +% scm -e '(display (list-ref *argv* *optind*))' bar +.br +Print ``bar'' +.TP +% scm -rpretty-print -r format -i +.br +Load pretty-print and format and enter interactive mode. +.TP +% scm -r5 +.br +Load dynamic-wind, values, and R4RS macros and enter interactive (with +macros) mode. +.TP +% scm -r5 -r4 +.br +Like above but rev4-optional-procedures are also loaded. +.SH FEATURES +.PP +Runs under Amiga, Atari-ST, MacOS, MS-DOS, OS/2, NOS/VE, Unicos, VMS, +Unix and similar systems. Support for ASCII and EBCDIC character +sets. +.PP +Conforms to Revised^4 Report on the Algorithmic Language Scheme +and the IEEE P1178 specification. +.PP +Support for SICP, R2RS, R3RS, and (proposed) R5RS scheme code. +.PP +Many Common Lisp functions: +logand, logor, logxor, lognot, ash, logcount, integer-length, +bit-extract, defmacro, macroexpand, macroexpand1, gentemp, +defvar, force-output, software-type, get-decoded-time, +get-internal-run-time, get-internal-real-time, delete-file, +rename-file, copy-tree, acons, and eval. +.PP +Char-code-limit, most-positive-fixnum, most-negative-fixnum, +and internal-time-units-per-second constants. *Features* and +*load-pathname* variables. +.PP +Arrays and bit-vectors. String ports and software emulation ports. +I/O extensions providing most of ANSI C and POSIX.1 facilities. +.PP +User definable responses to interrupts and errors, +Process-syncronization primitives, String regular expression matching, +and the CURSES screen management package. +.PP +Available add-on packages including an interactive debugger, database, +X-window graphics, BGI graphics, Motif, and Open-Windows packages. +.PP +A compiler (HOBBIT, available separately) and dynamic linking of +compiled modules. +.PP +Setable levels of monitoring and timing information printed +interactively (the `verbose' function). Restart, quit, and exec. +.SH FILES +.TP +code.doc +.br +Documentation on the internal representation and how to extend or +include scm in other programs. +.TP +scm.texi +.br +Documentation of SCM in Texinfo format. +.SH AUTHOR +Aubrey Jaffer +.br +(jaffer@ai.mit.edu) +.SH BUGS +.SH SEE ALSO +The Scheme specifications for details on specific procedures +(ftp-swiss.ai.mit.edu:archive/scheme-reports/) or +.PP +IEEE Std 1178-1990, +.br +IEEE Standard for the Scheme Programming Language, +.br +Institute of Electrical and Electronic Engineers, Inc., +.br +New York, NY, 1991 +.PP +Brian Harvey and Matthew Wright +.br +Simply Scheme: Introducing Computer Science_ +.br +MIT Press, 1994 +ISBN 0-262-08226-8 +.PP +R. Kent Dybvig, The Scheme Programming Language, +.br +Prentice-Hall Inc, Englewood Cliffs, New Jersey 07632, USA +.PP +H. Abelson, G. J. Sussman, and J. Sussman, +.br +Structure and Interpretation of Computer Programs, +.br +The MIT Press, Cambridge, Massachusetts, USA +.PP +Enhancements in +.I scm +not in the standards are detailed in MANUAL in the source directory. + @@ -0,0 +1,940 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "scm.c" top level and interrupt code. + Author: Aubrey Jaffer */ + +#include <signal.h> +#include "scm.h" +#include "patchlvl.h" + +#ifdef __IBMC__ +# include <io.h> +#endif + +#ifndef STDC_HEADERS + int alarm P((unsigned int)); + int pause P((void)); + unsigned int sleep P((unsigned int seconds)); + char *getenv P((const char *name)); + int system P((const char *)); +#endif +#ifdef hpux +# define const /**/ +#endif + +void final_repl P((void)); +void init_dynl P((void)); +void init_eval P((void)); +void init_features P((void)); +void init_io P((void)); +void init_ioext P((void)); +void init_repl P((int iverbose)); +void init_sc2 P((void)); +void init_scl P((void)); +void init_signals P((void)); +void init_subrs P((void)); +void init_tables P((void)); +void init_time P((void)); +void init_types P((void)); +void init_unif P((void)); +void init_ramap P((void)); + +void init_banner() +{ + fputs("SCM version ", stderr); + fputs(SCMVERSION, stderr); + fputs(", Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996 \ +Free Software Foundation.\n\ +SCM comes with ABSOLUTELY NO WARRANTY; for details type `(terms)'.\n\ +This is free software, and you are welcome to redistribute it\n\ +under certain conditions; type `(terms)' for details.\n", stderr); +} + +SCM scm_init_extensions() +{ +#ifdef COMPILED_INITS + COMPILED_INITS; /* initialize statically linked add-ons */ +#endif + return UNSPECIFIED; +} + +#if (__TURBOC__==1) +# define signal ssignal /* Needed for TURBOC V1.0 */ +#endif + +/* SIGRETTYPE is the type that signal handlers return. See <signal.h>*/ + +#ifdef RETSIGTYPE +# define SIGRETTYPE RETSIGTYPE +#else +# ifdef STDC_HEADERS +# if (__TURBOC__==1) +# define SIGRETTYPE int +# else +# define SIGRETTYPE void +# endif +# else +# ifdef linux +# define SIGRETTYPE void +# else +# define SIGRETTYPE int +# endif +# endif +#endif + +#ifdef vms +# ifdef __GNUC__ +# define SIGRETTYPE int +# endif +#endif + +#ifdef SIGHUP +static SIGRETTYPE hup_signal(sig) + int sig; +{ + signal(SIGHUP, hup_signal); + wta(UNDEFINED, (char *)HUP_SIGNAL, ""); +} +#endif +static SIGRETTYPE int_signal(sig) + int sig; +{ + sig = errno; + signal(SIGINT, int_signal); + if (ints_disabled) sig_deferred = 1; + else han_sig(); + errno = sig; +} + +/* If doesn't have SIGFPE, disable FLOATS for the rest of this file. */ + +#ifndef SIGFPE +# undef FLOATS +#endif + +#ifdef FLOATS +static SIGRETTYPE fpe_signal(sig) + int sig; +{ + signal(SIGFPE, fpe_signal); + wta(UNDEFINED, (char *)FPE_SIGNAL, ""); +} +#endif +#ifdef SIGBUS +static SIGRETTYPE bus_signal(sig) + int sig; +{ + signal(SIGBUS, bus_signal); + wta(UNDEFINED, (char *)BUS_SIGNAL, ""); +} +#endif +#ifdef SIGSEGV /* AMIGA lacks! */ +static SIGRETTYPE segv_signal(sig) + int sig; +{ + signal(SIGSEGV, segv_signal); + wta(UNDEFINED, (char *)SEGV_SIGNAL, ""); +} +#endif +#ifdef atarist +# undef SIGALRM /* only available via MiNT libs */ +#endif +#ifdef GO32 +# undef SIGALRM +#endif +#ifdef __HIGHC__ +# undef SIGALRM +#endif +#ifdef SIGALRM +static SIGRETTYPE alrm_signal(sig) + int sig; +{ + sig = errno; + signal(SIGALRM, alrm_signal); + if (ints_disabled) alrm_deferred = 1; + else han_alrm(); + errno = sig; +} +static char s_alarm[] = "alarm"; +SCM lalarm(i) + SCM i; +{ + unsigned int j; + ASSERT(INUMP(i) && (INUM(i) >= 0), i, ARG1, s_alarm); + SYSCALL(j = alarm(INUM(i));); + return MAKINUM(j); +} +# ifndef AMIGA +SCM l_pause() +{ + pause(); + return UNSPECIFIED; +} +# endif +#endif /* SIGALRM */ + +#ifdef _WIN32 +# include <windows.h> +#endif +#ifndef AMIGA +# ifndef _Windows +static char s_sleep[] = "sleep"; +SCM l_sleep(i) + SCM i; +{ + unsigned int j = 0; + ASSERT(INUMP(i) && (INUM(i) >= 0), i, ARG1, s_sleep); +# ifdef __HIGHC__ + SYSCALL(sleep(INUM(i));); +# else +# ifdef _WIN32 + Sleep(INUM(i)); +# else + SYSCALL(j = sleep(INUM(i));); +# endif + return MAKINUM(j); +} +# endif +# endif +#endif + +#ifndef _WIN32 +# ifndef GO32 +# ifndef sun +/* int raise P((int sig)); */ +static char s_raise[] = "raise"; +SCM l_raise(sig) + SCM sig; +{ + ASSERT(INUMP(sig), sig, ARG1, s_raise); +# ifdef vms + return MAKINUM(gsignal((int)INUM(sig))); +# else +# ifndef __TURBOC__ +# ifdef STDC_HEADERS + return kill(getpid (), (int)INUM(sig)) ? BOOL_F : BOOL_T; +# else + return raise((int)INUM(sig)) ? BOOL_F : BOOL_T; +# endif +# else + return raise((int)INUM(sig)) ? BOOL_F : BOOL_T; +# endif +# endif +} +# endif +# endif +#endif +#ifdef TICKS +unsigned int tick_count = 0, ticken = 0; +SCM *loc_tick_signal; +void tick_signal() +{ + if (ticken && NIMP(*loc_tick_signal)) { + ticken = 0; + apply(*loc_tick_signal, EOL, EOL); + } +} +static char s_ticks[] = "ticks"; +SCM lticks(i) + SCM i; +{ + SCM j = ticken ? tick_count : 0; + if (!UNBNDP(i)) ticken = tick_count = INUM(i); + return MAKINUM(j); +} +#endif + +#ifdef SIGHUP +static SIGRETTYPE (*oldhup)(); +#endif +static SIGRETTYPE (*oldint)(); +#ifdef FLOATS +static SIGRETTYPE (*oldfpe)(); +#endif +#ifdef SIGBUS +static SIGRETTYPE (*oldbus)(); +#endif +#ifdef SIGSEGV /* AMIGA lacks! */ +static SIGRETTYPE (*oldsegv)(); +#endif +#ifdef SIGALRM +static SIGRETTYPE (*oldalrm) (); +#endif +#ifdef SIGPIPE +static SIGRETTYPE (*oldpipe) (); +#endif + +int dumped = 0; /* Is this an invocation of unexec exe? */ + +#ifdef SHORT_ALIGN +typedef short STACKITEM; +#else +typedef long STACKITEM; +#endif +/* See scm.h for definition of P */ +void init_storage P((STACKITEM *stack_start_ptr, long init_heap_size)); + +void init_scm( iverbose, buf0stdin, init_heap_size ) + int iverbose; + int buf0stdin; + long init_heap_size; +{ + STACKITEM i; + if (2 <= iverbose) init_banner(); + if (!dumped) { + init_types(); + init_tables(); + init_storage(&i, init_heap_size); /* CONT(rootcont)->stkbse gets set here */ + if (buf0stdin) CAR(def_inp) |= BUF0; + init_features(); + init_subrs(); + init_io(); + init_scl(); + init_eval(); + init_time(); + init_repl( iverbose ); + init_unif(); + }} + +void init_signals() +{ + oldint = signal(SIGINT, int_signal); +#ifdef SIGHUP + oldhup = signal(SIGHUP, hup_signal); +#endif +#ifdef FLOATS + oldfpe = signal(SIGFPE, fpe_signal); +#endif +#ifdef SIGBUS + oldbus = signal(SIGBUS, bus_signal); +#endif +#ifdef SIGSEGV /* AMIGA lacks! */ + oldsegv = signal(SIGSEGV, segv_signal); +#endif +#ifdef SIGALRM + alarm(0); /* kill any pending ALRM interrupts */ + oldalrm = signal(SIGALRM, alrm_signal); +#endif +#ifdef SIGPIPE + oldpipe = signal(SIGPIPE, SIG_IGN); +#endif +#ifdef ultrix + siginterrupt(SIGINT, 1); + siginterrupt(SIGALRM, 1); + siginterrupt(SIGHUP, 1); + siginterrupt(SIGPIPE, 1); +#endif /* ultrix */ +} + +/* This is used in preparation for a possible fork(). Ignore all + signals before the fork so that child will catch only if it + establishes a handler */ +void ignore_signals() +{ +#ifdef ultrix + siginterrupt(SIGINT, 0); + siginterrupt(SIGALRM, 0); + siginterrupt(SIGHUP, 0); + siginterrupt(SIGPIPE, 0); +#endif /* ultrix */ + signal(SIGINT, SIG_IGN); +#ifdef SIGHUP + signal(SIGHUP, SIG_DFL); +#endif +#ifdef FLOATS + signal(SIGFPE, SIG_DFL); +#endif +#ifdef SIGBUS + signal(SIGBUS, SIG_DFL); +#endif +#ifdef SIGSEGV /* AMIGA lacks! */ + signal(SIGSEGV, SIG_DFL); +#endif + /* Some documentation claims that ALRMs are cleared accross forks. + If this is not always true then the value returned by alarm(0) + will have to be saved and unignore_signals() will have to + reinstate it. */ + /* This code should be neccessary only if the forked process calls + alarm() without establishing a handler: +#ifdef SIGALRM + oldalrm = signal(SIGALRM, SIG_DFL); +#endif */ + /* These flushes are per warning in man page on fork(). */ + fflush(stdout); + fflush(stderr); +} + +void unignore_signals() +{ + signal(SIGINT, int_signal); +#ifdef SIGHUP + signal(SIGHUP, hup_signal); +#endif +#ifdef FLOATS + signal(SIGFPE, fpe_signal); +#endif +#ifdef SIGBUS + signal(SIGBUS, bus_signal); +#endif +#ifdef SIGSEGV /* AMIGA lacks! */ + signal(SIGSEGV, segv_signal); +#endif +#ifdef SIGALRM + signal(SIGALRM, alrm_signal); +#endif +#ifdef ultrix + siginterrupt(SIGINT, 1); + siginterrupt(SIGALRM, 1); + siginterrupt(SIGHUP, 1); + siginterrupt(SIGPIPE, 1); +#endif /* ultrix */ +} + +void restore_signals() +{ +#ifdef ultrix + siginterrupt(SIGINT, 0); + siginterrupt(SIGALRM, 0); + siginterrupt(SIGHUP, 0); + siginterrupt(SIGPIPE, 0); +#endif /* ultrix */ + signal(SIGINT, oldint); +#ifdef SIGHUP + signal(SIGHUP, oldhup); +#endif +#ifdef FLOATS + signal(SIGFPE, oldfpe); +#endif +#ifdef SIGBUS + signal(SIGBUS, oldbus); +#endif +#ifdef SIGSEGV /* AMIGA lacks! */ + signal(SIGSEGV, oldsegv); +#endif +#ifdef SIGPIPE + signal(SIGPIPE, oldpipe); +#endif +#ifdef SIGALRM + alarm(0); /* kill any pending ALRM interrupts */ + signal(SIGALRM, oldalrm); +#endif +} + +int run_scm(argc, argv, iverbose, buf0stdin, initpath) + int argc; + char **argv; + int iverbose; + int buf0stdin; + char *initpath; +{ + SCM i; + do { + i = 0L; + if ((2 <= argc) && argv[1] && (0==strncmp("-a", argv[1], 2))) { + char *str = (0==argv[1][2] && 3 <= argc && argv[2]) ?argv[2]:&argv[1][2]; + do { + switch (*str) { + case DIGITS: + i = i * 10 + (*str - '0'); + if (i <= 10000L) continue; /* the size limit should match Init.scm */ + default: + i = 0L; + } + break; + } while (* ++str); + } + init_scm(iverbose, buf0stdin, (0 >= i) ? 0L : 1024L * i); /* size in Kb */ + progargs = EOL; + progargs = makfromstrs(argc, argv); + + if (!dumped) { +#ifdef HAVE_DYNL + init_dynl(); +#endif +#ifdef INITS + INITS; /* call initialization of extension files */ +#endif + } + init_signals(); + i = repl_driver(initpath); + restore_signals(); +#ifdef TICKS + ticken = 0; +#endif +#ifdef FINALS + FINALS; /* call shutdown of extensions files */ +#endif /* for compatability with older modules */ + /* call finalization of user extensions */ + while (num_finals--) (finals[num_finals])(); + final_repl(); + free_storage(); /* free all allocated memory */ + if (i) break; + dumped = 0; + if (2 <= iverbose) fputs(";RESTART\n", stderr); + } while (!0); + if (2 <= iverbose) fputs(";EXIT\n", stderr); + fflush(stderr); + return (int)INUM(i); +} + +#ifdef vms +# define SYSTNAME "vms" +#endif +#ifdef unix +# define DIRSEP "/" +# ifndef MSDOS /* DJGPP defines both */ +# define SYSTNAME "unix" +# endif +#endif +#ifdef MWC +# define SYSTNAME "coherent" +# define DIRSEP "/" +#endif +#ifdef _Windows +# define SYSTNAME "windows" +# define DIRSEP "\\" +#else +# ifdef MSDOS +# define SYSTNAME "ms-dos" +# ifndef unix +# define DIRSEP "\\" +# endif +# endif +#endif +#ifdef __EMX__ +# define SYSTNAME "os/2" +# define DIRSEP "\\" +#endif +#ifdef __IBMC__ +# define SYSTNAME "os/2" +# define DIRSEP "\\" +#endif +#ifdef THINK_C +# define SYSTNAME "thinkc" +# define DIRSEP ":" +#endif +#ifdef AMIGA +# define SYSTNAME "amiga" +# define DIRSEP "/" +#endif +#ifdef atarist +# define SYSTNAME "atarist" +# define DIRSEP "\\" +#endif +#ifdef mach +# define SYSTNAME "mach" +# define DIRSEP "/" +#endif +#ifdef ARM_ULIB +# define SYSTNAME "acorn" +#endif +#ifdef nosve +# define INIT_FILE_NAME "Init_scm"; +# define DIRSEP "." +#endif + +SCM softtype() +{ +#ifdef nosve + return CAR(intern("nosve", 5)); +#else + return CAR(intern(SYSTNAME, sizeof SYSTNAME/sizeof(char) -1)); +#endif +} + +/* Concatentate str2 onto str1 at position n and return concatenated + string if file exists; 0 otherwise. */ + +char *scm_cat_path(str1, str2, n) + char *str1; + const char *str2; + long n; +{ + if (!n) n = strlen(str2); + if (str1) + { + long len = strlen(str1); + str1 = (char *)realloc(str1, (sizet)(len + n + 1)); + if (!str1) return 0; + strncat(str1 + len, str2, n); + return str1; + } + str1 = (char *)malloc((sizet)(n + 1)); + if (!str1) return 0; + str1[0] = 0; + strncat(str1, str2, n); + return str1; +} + +char *scm_try_path(path) + char *path; +{ + FILE *f; + /* fprintf(stderr, "Trying %s\n", path);fflush(stderr); */ + if (!path) return 0; + SYSCALL(f = fopen(path, "r");); + if (f) { + fclose(f); + return path; + } + free(path); + return 0; +} + +char *scm_sep_init_try(path, sep, initname) + char *path; + const char *sep, *initname; +{ + if (path) path = scm_cat_path(path, sep, 0L); + if (path) path = scm_cat_path(path, initname, 0L); + return scm_try_path(path); +} + +#ifdef MSDOS +char *dld_find_executable(file) + const char *file; +{ + return scm_cat_path(0L, file, 0L); +} +#endif + +#ifndef INIT_FILE_NAME +# define INIT_FILE_NAME "Init.scm" +#endif +#ifndef DIRSEP +# define DIRSEP "/" +#endif +#ifndef GENERIC_NAME +# define GENERIC_NAME "scm" +#endif + +/* Given dld_find_executable()'s best guess for the pathname of this + executable, find (and verify the existence of) initname in the + implementation-vicinity of this program. Returns a newly allocated + string if successful, 0 if not */ + +char *scm_find_impl_file(exec_path, generic_name, initname, sep) + char *exec_path; + const char *generic_name, *initname, *sep; +{ + char *sepptr = strrchr(exec_path, sep[0]); + char *extptr = exec_path + strlen(exec_path); + char *path = 0; + if (sepptr) { + long sepind = sepptr - exec_path + 1L; + + /* In case exec_path is in the source directory, look first in + exec_path's directory. */ + path = scm_cat_path(0L, exec_path, sepind - 1L); + path = scm_sep_init_try(path, sep, initname); + if (path) return path; + +#ifdef MSDOS + if (!strcmp(extptr - 4, ".exe") || !strcmp(extptr - 4, ".com") || + !strcmp(extptr - 4, ".EXE") || !strcmp(extptr - 4, ".COM")) + extptr = extptr - 4; +#endif + + if (generic_name && + !strncmp(exec_path + sepind, generic_name, extptr - exec_path)) + generic_name = 0; + + /* If exec_path is in directory "exe" or "bin": */ + path = scm_cat_path(0L, exec_path, sepind - 1L); + sepptr = path + sepind - 4; + if (!strcmp(sepptr, "exe") || !strcmp(sepptr, "bin") || + !strcmp(sepptr, "EXE") || !strcmp(sepptr, "BIN")) { + char *peer; + + /* Look for initname in peer directory "lib". */ + if (path) { + strncpy(sepptr, "lib", 3); + path = scm_sep_init_try(path, sep, initname); + if (path) return path; + } + + /* Look for initname in peer directories "lib" and "src" in + subdirectory with the name of the executable (sans any type + extension like .EXE). */ + for(peer="lib";!0;peer="src") { + path = scm_cat_path(0L, exec_path, extptr - exec_path + 0L); + if (path) { + strncpy(path + sepind - 4, peer, 3); + path[extptr - exec_path] = 0; + path = scm_sep_init_try(path, sep, initname); + if (path) return path; + } + if (!strcmp(peer,"src")) break; + } + + if (generic_name) { + + /* Look for initname in peer directories "lib" and "src" in + subdirectory with the generic name. */ + for(peer="lib";!0;peer="src") { + path = scm_cat_path(0L, exec_path, sepind); + if (path) { + strncpy(path + sepind - 4, "lib", 3); + path = scm_cat_path(path, generic_name, 0L); + path = scm_sep_init_try(path, sep, initname); + if (path) return path; + } + if (!strcmp(peer,"src")) break; + }}} + +#ifdef MSDOS + if (strlen(extptr)) { + /* If exec_path has type extension, look in a subdirectory with + the name of the executable sans the executable file's type + extension. */ + path = scm_cat_path(0L, exec_path, extptr - exec_path + 0L); + path = scm_sep_init_try(path, sep, initname); + if (path) return path; + + if (generic_name) { + + /* Also look in generic_name subdirectory. */ + path = scm_cat_path(0L, exec_path, sepind); + if (path) path = scm_cat_path(path, generic_name, 0L); + path = scm_sep_init_try(path, sep, initname); + if (path) return path; + }} +#endif + } + else { + + /* We don't have a parse-able exec_path. The only path to try is + just initname. */ + path = scm_cat_path(0L, initname, 0L); + if (path) path = scm_try_path(path); + if (path) return path; + } + return 0; +} + +#ifndef RTL +char *execpath = 0; +int main( argc, argv ) + int argc; + char **argv; +{ + int retval, buf0stdin = 0; + char *getenvpath, *implpath = 0; + +# ifndef nosve + getenvpath = getenv("SCM_INIT_PATH"); + if (getenvpath) implpath = scm_cat_path(0L, getenvpath, 0L); + if (implpath) { + + /* The value of the environment variable supersedes other + locations, as long as the file exists. */ + implpath = scm_try_path(implpath); + if (!implpath) { + fputs("Value of SCM_INIT_PATH (=\"", stderr); + fputs(getenvpath, stderr); + fputs("\") not found; Trying elsewhere\n", stderr); + } + } +# endif + + if (!implpath) { + execpath = dld_find_executable(argv[0]); + if (execpath) { + /* fprintf(stderr, "dld found exe \"%s\"\n", execpath); fflush(stderr); */ + implpath = scm_find_impl_file(execpath, + GENERIC_NAME, INIT_FILE_NAME, DIRSEP); + /* fprintf(stderr, "scm_find_impl_file returned \"%s\"\n", implpath); fflush(stderr); */ + } +# ifdef IMPLINIT + if (!implpath) implpath = scm_cat_path(0L, IMPLINIT, 0L); +# endif + } +# ifndef GO32 + if (isatty(fileno(stdin))) { + buf0stdin = !0; /* stdin gets marked BUF0 in init_scm() */ +# ifndef NOSETBUF +# ifndef _DCC +# ifndef ultrix +# ifndef __WATCOMC__ +# ifndef THINK_C +# if (__TURBOC__ != 1) +# ifndef _Windows + setbuf(stdin, 0); /* Often setbuf isn't actually required */ +# endif +# endif +# endif +# endif +# endif +# endif + } +# endif +# endif + retval = run_scm(argc, argv, + (isatty(fileno(stdin)) && isatty(fileno(stdout))) + ? (argc <= 1) ? 2 : 1 : 0, + buf0stdin, + implpath ? implpath : ""); + if (implpath) free(implpath); + if (execpath) free(execpath); + return retval; +} +#endif + +#ifndef _Windows +char s_system[] = "system"; +SCM lsystem(cmd) + SCM cmd; +{ + ASSERT(NIMP(cmd) && STRINGP(cmd), cmd, ARG1, s_system); + ignore_signals(); +# ifdef AZTEC_C + cmd = MAKINUM(Execute(CHARS(cmd), 0, 0)); +# else + cmd = MAKINUM(0L+system(CHARS(cmd))); +# endif + unignore_signals(); + return cmd; +} +#endif + +char s_getenv[] = "getenv"; +char *getenv(); +SCM lgetenv(nam) + SCM nam; +{ + char *val; + ASSERT(NIMP(nam) && STRINGP(nam), nam, ARG1, s_getenv); + val = getenv(CHARS(nam)); + if (!val) return BOOL_F; + return makfrom0str(val); +} + +#ifdef vms +# include <descrip.h> +# include <ssdef.h> +char s_ed[] = "ed"; +SCM ed(fname) + SCM fname; +{ + struct dsc$descriptor_s d; + ASSERT(NIMP(fname) && STRINGP(fname), fname, ARG1, s_ed); + d.dsc$b_dtype = DSC$K_DTYPE_T; + d.dsc$b_class = DSC$K_CLASS_S; + d.dsc$w_length = LENGTH(fname); + d.dsc$a_pointer = CHARS(fname); + /* I don't know what VMS does with signal handlers across the + edt$edit call. */ + ignore_signals(); + edt$edit(&d); + unignore_signals(); + return fname; +} +SCM vms_debug() +{ + lib$signal(SS$_DEBUG); + return UNSPECIFIED; +} +#endif + +static iproc subr0s[] = { + {"software-type", softtype}, + {"scm_init_extensions", scm_init_extensions}, +#ifdef vms + {"vms-debug", vms_debug}, +#endif +#ifdef SIGALRM +# ifndef AMIGA + {"pause", l_pause}, +# endif +#endif + {0, 0}}; +static iproc subr1s[] = { + {s_getenv, lgetenv}, +#ifndef _Windows + {s_system, lsystem}, +#endif +#ifdef vms + {s_ed, ed}, +#endif +#ifdef SIGALRM + {s_alarm, lalarm}, +#endif +#ifndef AMIGA +# ifndef _Windows + {s_sleep, l_sleep}, +# endif +#endif +#ifndef GO32 +# ifndef sun +# ifndef _WIN32 + {s_raise, l_raise}, +# endif +# endif +#endif + {0, 0}}; + +SCM *loc_features; +void add_feature(str) + char* str; +{ + *loc_features = cons(CAR(intern(str, strlen(str))), *loc_features); +} +void init_features() +{ + loc_features = &CDR(sysintern("*features*", EOL)); + init_iprocs(subr0s, tc7_subr_0); + init_iprocs(subr1s, tc7_subr_1); +#ifdef TICKS + loc_tick_signal = &CDR(sysintern("ticks-interrupt", UNDEFINED)); + make_subr(s_ticks, tc7_subr_1o, lticks); +#endif +#ifdef RECKLESS + add_feature("reckless"); +#endif +#ifndef _Windows + add_feature(s_system); +#endif +#ifdef vms + add_feature(s_ed); +#endif + sysintern("*scm-version*", makfrom0str(SCMVERSION)); +} @@ -0,0 +1,330 @@ + + + +SCM(Jan 9 1995) SCM(Jan 9 1995) + + +NAME + scm - a Scheme Language Interpreter + +SYNOPSIS + scm [-a kbytes ] [-ibvqmu] [-p number ] [-c expression ] + [-e expression ] [-f filename ] [-l filename ] [-d file- + name ] [-r feature ] [-- | - | -s] [filename] [arguments + ...] + +DESCRIPTION + Scm is a Scheme interpreter. + + Upon startup scm loads the file specified by by the envi- + ronment variable SCM_INIT_PATH or by the parameter + IMPLINIT in the makefile (or scmfig.h) if SCM_INIT_PATH is + not defined. The makefiles attempt to set IMPLINIT to + "Init.scm" in the source directory. + + Unless the option -no-init-file occurs in the command + line, "Init.scm" checks to see if there is file + "ScmInit.scm" in the path specified by the environment + variable HOME (or in the current directory if HOME is + undefined). If it finds such a file it is loaded. + + "Init.scm" then looks for command input from one of three + sources: From an option on the command line, from a file + named on the command line, or from standard input. + + +OPTIONS + The options are processed in the order specified on the + command line. + + -akbytes + specifies that scm should allocate an initial heap- + size of kbytes. This option, if present, must be the + first on the command line. + + -no-init-file + Inhibits the loading of "ScmInit.scm" as described + above. + + -eexpression + + -cexpression + specifies that the scheme expression expression is to + be evaluated. These options are inspired by perl and + sh respectively. On Amiga systems the entire option + and argument need to be enclosed in qoutes. For + instance "-e(newline)". + + -rfeature + requires feature. This will load a file from SLIB if + that feature is not already supported. If feature is + + + + 1 + + + + + +SCM(Jan 9 1995) SCM(Jan 9 1995) + + + 2, 3, 4, or 5 scm will require the features necces- + sary to support R2RS, R3RS, R4RS, or proposed R5RS, + respectively. + + -lfilename + + -ffilename + loads filename. Scm will load the first (unoptioned) + file named on the command line if no -c, -e, -f, -l, + or -s option preceeds it. + + -dfilename + opens (read-only) the extended relational database + filename. If filename contains initialization code, + it will be run when the database is opened. + + -plevel + sets the prolixity (verboseness) to level. This is + the same as the scm command (verobse level ). + + -v (verbose mode) specifies that scm will print prompts, + evaluation times, notice of loading files, and + garbage collection statistics. This is the same as + -p3. + + -q (quiet mode) specifies that scm will print no extra + information. This is the same as -p0. + + -m specifies that subsequent loads, evaluations, and + user interactions will be with R4RS macro capability. + To use a specific R4RS macro implementation from SLIB + (instead of SLIB's default) put -r macropackage + before -m on the command line. + + -u specifies that subsequent loads, evaluations, and + user interactions will be without R4RS macro capabil- + ity. R4RS macro capability can be restored by a sub- + sequent -m on the command line or from Scheme code. + + -i specifies that scm should run interactively. That + means that scm will not terminate until the (quit) or + (exit) command is given, even if there are errors. + It also sets the prolixity level to 2 if it is less + than 2. This will print prompts, evaluation times, + and notice of loading files. The prolixity level can + be set by subsequent options. If scm is started from + a tty, it will assume that it should be interactive + unless given a subsequent -b option. + + -b specifies that scm should run non-interactively. + That means that scm will terminate after processing + the command line or if there are errors. + + -s specifies, by analogy with sh, that further options + + + + 2 + + + + + +SCM(Jan 9 1995) SCM(Jan 9 1995) + + + are to be treated as program aguments. + + - -- specifies that there are no more options on the + command line. + +ENVIRONMENT VARIABLES + SCM_INIT_PATH + is the pathname where scm will look for its initial- + ization code. The default is the file "Init.scm" in + the source directory. + + SCHEME_LIBRARY_PATH + is the SLIB Scheme library directory. + + HOME is the directory where "Init.scm" will look for the + user initialization file "ScmInit.scm". + +SCHEME VARIABLES + *argv* + contains the list of arguments to the program. + *argv* can change during argument processing. This + list is suitable for use as an argument to SLIB + getopt. + + *R4RS-macro* + controls whether loading and interaction support R4RS + macros. Define this in "ScmInit.scm" or files speci- + fied on the command line. This can be overridden by + subsequent -m and -u options. + + *interactive* + controls interactivity as explained for the -i and -b + options. Define this in "ScmInit.scm" or files spec- + ified on the command line. This can be overridden by + subsequent -i and -b options. + +EXAMPLES + % scm foo.scm arg1 arg2 arg3 + Load and execute the contents of foo.scm. Parameters + arg1 arg2 and arg3 are stored in the global list + *argv*. + + % scm -f foo.scm arg1 arg2 arg3 + The same. + + % scm -s foo.scm arg1 arg2 + Set *argv* to ("foo.scm" "arg1" "arg2") and enter + interactive session. + + % scm -e '(display (list-ref *argv* *optind*))' bar + Print ``bar'' + + % scm -rpretty-print -r format -i + Load pretty-print and format and enter interactive + + + + 3 + + + + + +SCM(Jan 9 1995) SCM(Jan 9 1995) + + + mode. + + % scm -r5 + Load dynamic-wind, values, and R4RS macros and enter + interactive (with macros) mode. + + % scm -r5 -r4 + Like above but rev4-optional-procedures are also + loaded. + +FEATURES + Runs under Amiga, Atari-ST, MacOS, MS-DOS, OS/2, NOS/VE, + Unicos, VMS, Unix and similar systems. Support for ASCII + and EBCDIC character sets. + + Conforms to Revised^4 Report on the Algorithmic Language + Scheme and the IEEE P1178 specification. + + Support for SICP, R2RS, R3RS, and (proposed) R5RS scheme + code. + + Many Common Lisp functions: logand, logor, logxor, lognot, + ash, logcount, integer-length, bit-extract, defmacro, + macroexpand, macroexpand1, gentemp, defvar, force-output, + software-type, get-decoded-time, get-internal-run-time, + get-internal-real-time, delete-file, rename-file, copy- + tree, acons, and eval. + + Char-code-limit, most-positive-fixnum, most-negative- + fixnum, and internal-time-units-per-second constants. + *Features* and *load-pathname* variables. + + Arrays and bit-vectors. String ports and software emula- + tion ports. I/O extensions providing most of ANSI C and + POSIX.1 facilities. + + User definable responses to interrupts and errors, Pro- + cess-syncronization primitives, String regular expression + matching, and the CURSES screen management package. + + Available add-on packages including an interactive debug- + ger, database, X-window graphics, BGI graphics, Motif, and + Open-Windows packages. + + A compiler (HOBBIT, available separately) and dynamic + linking of compiled modules. + + Setable levels of monitoring and timing information + printed interactively (the `verbose' function). Restart, + quit, and exec. + +FILES + code.doc + Documentation on the internal representation and + + + + 4 + + + + + +SCM(Jan 9 1995) SCM(Jan 9 1995) + + + how to extend or include scm in other programs. + + scm.texi + Documentation of SCM in Texinfo format. + +AUTHOR + Aubrey Jaffer + (jaffer@ai.mit.edu) + +BUGS +SEE ALSO + The Scheme specifications for details on specific proce- + dures (ftp-swiss.ai.mit.edu:archive/scheme-reports/) or + + IEEE Std 1178-1990, + IEEE Standard for the Scheme Programming Language, + Institute of Electrical and Electronic Engineers, Inc., + New York, NY, 1991 + + Brian Harvey and Matthew Wright + Simply Scheme: Introducing Computer Science_ + MIT Press, 1994 ISBN 0-262-08226-8 + + R. Kent Dybvig, The Scheme Programming Language, + Prentice-Hall Inc, Englewood Cliffs, New Jersey 07632, USA + + H. Abelson, G. J. Sussman, and J. Sussman, + Structure and Interpretation of Computer Programs, + The MIT Press, Cambridge, Massachusetts, USA + + Enhancements in scm not in the standards are detailed in + MANUAL in the source directory. + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + + @@ -0,0 +1,817 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "scm.h" SCM data types and external functions. */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long SCM; +typedef struct {SCM car, cdr;} cell; +typedef struct {long sname;SCM (*cproc)();} subr; +typedef struct {char *string;SCM (*cproc)();} iproc; +typedef struct {long sname;double (*dproc)();} dsubr; + +#include <stdio.h> +#include "scmfig.h" + +#ifdef USE_ANSI_PROTOTYPES +# define P(s) s +#else +# define P(s) () +#endif + +#ifndef STDC_HEADERS + int isatty P((int)); +#endif + +typedef struct { + SCM (*mark)P((SCM)); + sizet (*free)P((CELLPTR)); + int (*print)P((SCM exp, SCM port, int writing)); + SCM (*equalp)P((SCM, SCM)); +} smobfuns; + +typedef struct { + SCM (*mark)P((SCM ptr)); + int (*free)P((FILE *p)); + int (*print)P((SCM exp, SCM port, int writing)); + SCM (*equalp)P((SCM, SCM)); + int (*fputc)P((int c, FILE *p)); + int (*fputs)P((char *s, FILE *p)); + sizet (*fwrite)P((char *s, sizet siz, sizet num, FILE *p)); + int (*fflush)P((FILE *stream)); + int (*fgetc)P((FILE *p)); + int (*fclose)P((FILE *p)); +} ptobfuns; + +typedef struct { + SCM v; + sizet base; +} array; +typedef struct { + long lbnd; + long ubnd; + long inc; +} array_dim; + +#ifdef FLOATS +typedef struct {char *string;double (*cproc)P((double));} dblproc; +# ifdef SINGLES +# ifdef CDR_DOUBLES +typedef struct {SCM type;double num;} flo; +# else +typedef struct {SCM type;float num;} flo; +# endif +# endif +typedef struct {SCM type;double *real;} dbl; +#endif + +#define IMP(x) (6 & (int)(x)) +#define NIMP(x) (!IMP(x)) + +#define INUMP(x) (2 & (int)(x)) +#define NINUMP(x) (!INUMP(x)) +#define INUM0 ((SCM) 2) +#define ICHRP(x) ((0xff & (int)(x))==0xf4) +#define ICHR(x) ((unsigned char)((x)>>8)) +#define MAKICHR(x) (((x)<<8)+0xf4L) + +#define ILOCP(n) ((0xff & (int)(n))==0xfc) +#define ILOC00 (0x000000fcL) +#define IDINC (0x00100000L) +#define ICDR (0x00080000L) +#define IFRINC (0x00000100L) +#define IDSTMSK (-IDINC) +#define IFRAME(n) ((int)((ICDR-IFRINC)>>8) & ((int)(n)>>8)) +#define IDIST(n) (((unsigned long)(n))>>20) +#define ICDRP(n) (ICDR & (n)) + +/* ISYMP tests for ISPCSYM and ISYM */ +#define ISYMP(n) ((0x187 & (int)(n))==4) +/* IFLAGP tests for ISPCSYM, ISYM and IFLAG */ +#define IFLAGP(n) ((0x87 & (int)(n))==4) +#define ISYMNUM(n) ((int)((n)>>9)) +#define ISYMCHARS(n) (isymnames[ISYMNUM(n)]) +#define MAKSPCSYM(n) (((n)<<9)+((n)<<3)+4L) +#define MAKISYM(n) (((n)<<9)+0x74L) +#define MAKIFLAG(n) (((n)<<9)+0x174L) + +extern char *isymnames[]; +#define NUM_ISPCSYM 14 +#define IM_AND MAKSPCSYM(0) +#define IM_BEGIN MAKSPCSYM(1) +#define IM_CASE MAKSPCSYM(2) +#define IM_COND MAKSPCSYM(3) +#define IM_DO MAKSPCSYM(4) +#define IM_IF MAKSPCSYM(5) +#define IM_LAMBDA MAKSPCSYM(6) +#define IM_LET MAKSPCSYM(7) +#define IM_LETSTAR MAKSPCSYM(8) +#define IM_LETREC MAKSPCSYM(9) +#define IM_OR MAKSPCSYM(10) +#define IM_QUOTE MAKSPCSYM(11) +#define IM_SET MAKSPCSYM(12) +#define IM_DEFINE MAKSPCSYM(13) + +#define s_and (ISYMCHARS(IM_AND)+2) +#define s_begin (ISYMCHARS(IM_BEGIN)+2) +#define s_case (ISYMCHARS(IM_CASE)+2) +#define s_cond (ISYMCHARS(IM_COND)+2) +#define s_do (ISYMCHARS(IM_DO)+2) +#define s_if (ISYMCHARS(IM_IF)+2) +#define s_lambda (ISYMCHARS(IM_LAMBDA)+2) +#define s_let (ISYMCHARS(IM_LET)+2) +#define s_letstar (ISYMCHARS(IM_LETSTAR)+2) +#define s_letrec (ISYMCHARS(IM_LETREC)+2) +#define s_or (ISYMCHARS(IM_OR)+2) +#define s_quote (ISYMCHARS(IM_QUOTE)+2) +#define s_set (ISYMCHARS(IM_SET)+2) +#define s_define (ISYMCHARS(IM_DEFINE)+2) + +extern SCM i_dot, i_quote, i_quasiquote, i_unquote, i_uq_splicing; +#define s_apply (ISYMCHARS(IM_APPLY)+2) + +/* each symbol defined here must have a unique number which */ + /* corresponds to it's position in isymnames[] in sys.c */ +#define IM_APPLY MAKISYM(14) +#define IM_CONT MAKISYM(15) + +#define NUM_ISYMS 16 + +#define BOOL_F MAKIFLAG(NUM_ISYMS+0) +#define BOOL_T MAKIFLAG(NUM_ISYMS+1) +#define UNDEFINED MAKIFLAG(NUM_ISYMS+2) +#define EOF_VAL MAKIFLAG(NUM_ISYMS+3) +#ifdef SICP +# define EOL BOOL_F +#else +# define EOL MAKIFLAG(NUM_ISYMS+4) +#endif +#define UNSPECIFIED MAKIFLAG(NUM_ISYMS+5) + +/* Now some unnamed flags used as magic cookies by repl_driver. */ +/* Argument n can range from -4 to 16 */ +#ifdef SHORT_INT +#define COOKIE(n) (n) +#define UNCOOK(f) (f) +#else +#define COOKIE(n) MAKIFLAG(NUM_ISYMS+6+4+n) +#define UNCOOK(f) (ISYMNUM(f)-(NUM_ISYMS+6+4)) +#endif + +#define FALSEP(x) (BOOL_F==(x)) +#define NFALSEP(x) (BOOL_F != (x)) +/* BOOL_NOT returns the other boolean. The order of ^s here is + important for Borland C++. */ +#define BOOL_NOT(x) ((x) ^ (BOOL_T ^ BOOL_F)) +#define NULLP(x) (EOL==(x)) +#define NNULLP(x) (EOL != (x)) +#define UNBNDP(x) (UNDEFINED==(x)) +#define CELLP(x) (!NCELLP(x)) +#define NCELLP(x) ((sizeof(cell)-1) & (int)(x)) + +#define GCMARKP(x) (1 & (int)CDR(x)) +#define GC8MARKP(x) (0x80 & (int)CAR(x)) +#define SETGCMARK(x) CDR(x) |= 1; +#define CLRGCMARK(x) CDR(x) &= ~1L; +#define SETGC8MARK(x) CAR(x) |= 0x80; +#define CLRGC8MARK(x) CAR(x) &= ~0x80L; +#define TYP3(x) (7 & (int)CAR(x)) +#define TYP7(x) (0x7f & (int)CAR(x)) +#define TYP7S(x) (0x7d & (int)CAR(x)) +#define TYP16(x) (0xffff & (int)CAR(x)) +#define TYP16S(x) (0xfeff & (int)CAR(x)) +#define GCTYP16(x) (0xff7f & (int)CAR(x)) + +#define NCONSP(x) (1 & (int)CAR(x)) +#define CONSP(x) (!NCONSP(x)) +#define ECONSP(x) (CONSP(x) || (1==TYP3(x))) +#define NECONSP(x) (NCONSP(x) && (1 != TYP3(x))) + +#define CAR(x) (((cell *)(SCM2PTR(x)))->car) +#define CDR(x) (((cell *)(SCM2PTR(x)))->cdr) +#define GCCDR(x) (~1L & CDR(x)) +#define SETCDR(x, v) CDR(x) = (SCM)(v) + +#define CLOSUREP(x) (TYP3(x)==tc3_closure) +#define CODE(x) (CAR(x)-tc3_closure) +#define SETCODE(x, e) CAR(x) = (e)+tc3_closure +#define ENV(x) CDR(x) + +#define PORTP(x) (TYP7(x)==tc7_port) +#define OPPORTP(x) (((0x7f | OPN) & CAR(x))==(tc7_port | OPN)) +#define OPINPORTP(x) (((0x7f | OPN | RDNG) & CAR(x))==(tc7_port | OPN | RDNG)) +#define OPOUTPORTP(x) (((0x7f | OPN | WRTNG) & CAR(x))==(tc7_port | OPN | WRTNG)) +#define OPIOPORTP(x) (((0x7f | OPN | RDNG | WRTNG) & CAR(x))==(tc7_port | OPN | RDNG | WRTNG)) +#define FPORTP(x) (TYP16S(x)==tc7_port) +#define OPFPORTP(x) (((0xfeff | OPN) & CAR(x))==(tc7_port | OPN)) +#define OPINFPORTP(x) (((0xfeff | OPN | RDNG) & CAR(x))==(tc7_port | OPN | RDNG)) +#define OPOUTFPORTP(x) (((0xfeff | OPN | WRTNG) & CAR(x))==(tc7_port | OPN | WRTNG)) + +#define INPORTP(x) (((0x7f | RDNG) & CAR(x))==(tc7_port | RDNG)) +#define OUTPORTP(x) (((0x7f | WRTNG) & CAR(x))==(tc7_port | WRTNG)) +#define OPENP(x) (OPN & CAR(x)) +#define CLOSEDP(x) (!OPENP(x)) +#define STREAM(x) ((FILE *)(CDR(x))) +#define SETSTREAM SETCDR +#define CRDYP(port) (CAR(port) & CRDY) +#define CLRDY(port) {CAR(port) &= CUC;} +#define CGETUN(port) ((int)SRS(CAR(port), 22)) +#define CUNGET(c, port) {CAR(port) += ((long)c<<22) + CRDY;} + +#define tc_socket (tc7_port | OPN) +#define SOCKP(x) (((0x7f | OPN | RDNG | WRTNG) & CAR(x))==(tc_socket)) +#define SOCKTYP(x) (CAR(x)>>24) + +#define DIRP(x) (NIMP(x) && (TYP16(x)==(tc16_dir))) +#define OPDIRP(x) (NIMP(x) && (CAR(x)==(tc16_dir | OPN))) + +#ifdef FLOATS +# define INEXP(x) (TYP16(x)==tc16_flo) +# define CPLXP(x) (CAR(x)==tc_dblc) +# define REAL(x) (*(((dbl *) (SCM2PTR(x)))->real)) +# define IMAG(x) (*((double *)(CHARS(x)+sizeof(double)))) +/* ((&REAL(x))[1]) */ +# ifdef SINGLES +# define REALP(x) ((~REAL_PART & CAR(x))==tc_flo) +# define SINGP(x) (CAR(x)==tc_flo) +# define FLO(x) (((flo *)(SCM2PTR(x)))->num) +# define REALPART(x) (SINGP(x)?0.0+FLO(x):REAL(x)) +# else /* SINGLES */ +# define REALP(x) (CAR(x)==tc_dblr) +# define REALPART REAL +# endif /* SINGLES */ +#endif + +#ifdef FLOATS +# define NUMBERP(x) (INUMP(x) || (NIMP(x) && NUMP(x))) +#else +# ifdef BIGDIG +# define NUMBERP(x) (INUMP(x) || (NIMP(x) && NUMP(x))) +# else +# define NUMBERP INUMP +# endif +#endif +#define NUMP(x) ((0xfcff & (int)CAR(x))==tc7_smob) +#define BIGP(x) (TYP16S(x)==tc16_bigpos) +#define BIGSIGN(x) (0x0100 & (int)CAR(x)) +#define BDIGITS(x) ((BIGDIG *)(CDR(x))) +#define NUMDIGS(x) ((sizet)(CAR(x)>>16)) +#define SETNUMDIGS(x, v, t) CAR(x) = (((v)+0L)<<16)+(t) + +#define SNAME(x) ((CAR(x)>>8)?(SCM)(heap_org+(CAR(x)>>8)):nullstr) +#define SUBRF(x) (((subr *)(SCM2PTR(x)))->cproc) +#define DSUBRF(x) (((dsubr *)(SCM2PTR(x)))->dproc) +#define CCLO_SUBR(x) (VELTS(x)[0]) + +#define SYMBOLP(x) (TYP7S(x)==tc7_ssymbol) +#define STRINGP(x) (TYP7(x)==tc7_string) +#define NSTRINGP(x) (!STRINGP(x)) +#define VECTORP(x) (TYP7(x)==tc7_vector) +#define NVECTORP(x) (!VECTORP(x)) +#define LENGTH(x) (((unsigned long)CAR(x))>>8) +#define LENGTH_MAX (0xffffffL) +#define SETLENGTH(x, v, t) CAR(x) = ((v)<<8)+(t) +#define CHARS(x) ((char *)(CDR(x))) +#define UCHARS(x) ((unsigned char *)(CDR(x))) +#define VELTS(x) ((SCM *)CDR(x)) +#define SETCHARS SETCDR +#define SETVELTS SETCDR + +extern long tc16_array; +#define ARRAYP(a) (tc16_array==TYP16(a)) +#define ARRAY_V(a) (((array *)CDR(a))->v) +/*#define ARRAY_NDIM(x) NUMDIGS(x)*/ +#define ARRAY_NDIM(x) ((sizet)(CAR(x)>>17)) +#define ARRAY_CONTIGUOUS 0x10000 +#define ARRAY_CONTP(x) (ARRAY_CONTIGUOUS & (int)CAR(x)) +#define ARRAY_BASE(a) (((array *)CDR(a))->base) +#define ARRAY_DIMS(a) ((array_dim *)(CHARS(a)+sizeof(array))) + +#define FREEP(x) (CAR(x)==tc_free_cell) +#define NFREEP(x) (!FREEP(x)) + +#define SMOBNUM(x) (0x0ff & (CAR(x)>>8)); +#define PTOBNUM(x) (0x0ff & (CAR(x)>>8)); + +#define DIGITS '0':case '1':case '2':case '3':case '4':\ + case '5':case '6':case '7':case '8':case '9' + +/* Aggregated types for dispatch in switch statements. */ + +#define tcs_cons_imcar 2:case 4:case 6:case 10:\ + case 12:case 14:case 18:case 20:\ + case 22:case 26:case 28:case 30:\ + case 34:case 36:case 38:case 42:\ + case 44:case 46:case 50:case 52:\ + case 54:case 58:case 60:case 62:\ + case 66:case 68:case 70:case 74:\ + case 76:case 78:case 82:case 84:\ + case 86:case 90:case 92:case 94:\ + case 98:case 100:case 102:case 106:\ + case 108:case 110:case 114:case 116:\ + case 118:case 122:case 124:case 126 +#define tcs_cons_nimcar 0:case 8:case 16:case 24:\ + case 32:case 40:case 48:case 56:\ + case 64:case 72:case 80:case 88:\ + case 96:case 104:case 112:case 120 +#define tcs_cons_gloc 1:case 9:case 17:case 25:\ + case 33:case 41:case 49:case 57:\ + case 65:case 73:case 81:case 89:\ + case 97:case 105:case 113:case 121 + +#define tcs_closures 3:case 11:case 19:case 27:\ + case 35:case 43:case 51:case 59:\ + case 67:case 75:case 83:case 91:\ + case 99:case 107:case 115:case 123 +#define tcs_subrs tc7_asubr:case tc7_subr_0:case tc7_subr_1:case tc7_cxr:\ + case tc7_subr_3:case tc7_subr_2:case tc7_rpsubr:case tc7_subr_1o:\ + case tc7_subr_2o:case tc7_lsubr_2:case tc7_lsubr +#define tcs_symbols tc7_ssymbol:case tc7_msymbol +#define tcs_bignums tc16_bigpos:case tc16_bigneg + +#define tc3_cons 0 +#define tc3_cons_gloc 1 +#define tc3_closure 3 + +#define tc7_ssymbol 5 +#define tc7_msymbol 7 +#define tc7_string 13 +#define tc7_vector 15 +#define tc7_bvect 21 +/* spare 23 */ +#define tc7_ivect 29 +#define tc7_uvect 31 +/* spare 37 39 */ +#define tc7_fvect 45 +#define tc7_dvect 47 +#define tc7_cvect 53 +#define tc7_port 55 +#define tc7_contin 61 +#define tc7_cclo 63 + +/* spare 69 71 77 79 */ +#define tc7_subr_0 85 +#define tc7_subr_1 87 +#define tc7_cxr 93 +#define tc7_subr_3 95 +#define tc7_subr_2 101 +#define tc7_asubr 103 +#define tc7_subr_1o 109 +#define tc7_subr_2o 111 +#define tc7_lsubr_2 117 +#define tc7_lsubr 119 +#define tc7_rpsubr 125 + +#define tc7_smob 127 +#define tc_free_cell 127 + +#define tc16_flo 0x017f +#define tc_flo 0x017fL + +#define REAL_PART (1L<<16) +#define IMAG_PART (2L<<16) +#define tc_dblr (tc16_flo|REAL_PART) +#define tc_dblc (tc16_flo|REAL_PART|IMAG_PART) + +#define tc16_bigpos 0x027f +#define tc16_bigneg 0x037f + +#define OPN (1L<<16) +#define RDNG (2L<<16) +#define WRTNG (4L<<16) +#define BUF0 (8L<<16) +#define CRDY (32L<<16) +#define CUC 0x001fffffL + +extern sizet numsmob, numptob; +extern smobfuns *smobs; +extern ptobfuns *ptobs; +extern ptobfuns pipob; +#define tc16_fport (tc7_port + 0*256L) +#define tc16_pipe (tc7_port + 1*256L) +#define tc16_strport (tc7_port + 2*256L) +#define tc16_sfport (tc7_port + 3*256L) +extern long tc16_dir; + +extern SCM sys_protects[]; +#define cur_inp sys_protects[0] +#define cur_outp sys_protects[1] +#define cur_errp sys_protects[2] +#define def_inp sys_protects[3] +#define def_outp sys_protects[4] +#define def_errp sys_protects[5] +#define listofnull sys_protects[6] +#define undefineds sys_protects[7] +#define nullvect sys_protects[8] +#define nullstr sys_protects[9] +#define progargs sys_protects[10] +#define transcript sys_protects[11] +#define rootcont sys_protects[12] +#define dynwinds sys_protects[13] +#define stacktrace sys_protects[14] +#ifdef FLOATS +# define flo0 sys_protects[15] +# define NUM_PROTECTS 16 +#else +# define NUM_PROTECTS 15 +#endif + +/* now for connects between source files */ + +extern sizet num_finals; +extern void (**finals)P((void)); +extern unsigned char upcase[], downcase[]; +extern SCM symhash; +extern int symhash_dim; +extern long heap_size; +extern CELLPTR heap_org; +extern SCM freelist; +extern long gc_cells_collected, gc_malloc_collected, gc_ports_collected; +extern long gc_syms_collected; +extern long cells_allocated, lcells_allocated, mallocated, lmallocated; +extern long mtrigger; +extern SCM *loc_loadpath; +extern SCM *loc_errobj; +extern SCM loadport; +extern long linum; +extern int errjmp_bad, ints_disabled, sig_deferred, alrm_deferred; +extern SCM exitval; +extern int cursinit; +extern unsigned int poll_count, tick_count; +extern int dumped; +extern char *execpath; + +/* strings used in several source files */ + +extern char s_read[], s_write[], s_newline[], s_system[]; +extern char s_make_string[], s_make_vector[], s_list[], s_op_pipe[]; +#define s_string (s_make_string+5) +#define s_vector (s_make_vector+5) +#define s_pipe (s_op_pipe+5) +extern char s_make_sh_array[]; +#define s_array (s_make_sh_array+12) +extern char s_ccl[]; +#define s_limit (s_ccl+10) +extern char s_close_port[]; +#define s_port_type (s_close_port+6) + +/* function prototypes */ + +void gc_mark P((SCM p)); +void han_sig P((void)); +void han_alrm P((void)); +char *must_malloc P((long len, char *what)); +char *must_realloc P((char *where, long olen, long len, char *what)); +void must_free P((char *obj)); +long ilength P((SCM sx)); +SCM hash P((SCM obj, SCM n)); +SCM hashv P((SCM obj, SCM n)); +SCM hashq P((SCM obj, SCM n)); +SCM obhash P((SCM obj)); +SCM obunhash P((SCM obj)); +unsigned long strhash P((unsigned char *str, sizet len, unsigned long n)); +unsigned long hasher P((SCM obj, unsigned long n, sizet d)); +SCM repl_driver P((char *initpath)); +SCM lroom P((SCM args)); +long newsmob P((smobfuns *smob)); +long newptob P((ptobfuns *ptob)); +void prinport P((SCM exp, SCM port, char *type)); +void repl P((void)); +void growth_mon P((char *obj, long size, char *units)); +void gc_start P((char *what)); +void gc_end P((void)); +void heap_report P((void)); +void exit_report P((void)); +void stack_report P((void)); +void iprin1 P((SCM exp, SCM port, int writing)); +void intprint P((long n, int radix, SCM port)); +void iprlist P((char *hdr, SCM exp, int tlr, SCM port, int writing)); +void lputc P((int c, SCM port)); +void lputs P((char *s, SCM port)); +int lfwrite P((char *ptr, sizet size, sizet nitems, SCM port)); +int lgetc P((SCM port)); +void lungetc P((int c, SCM port)); +char *grow_tok_buf P((SCM tok_buf)); +long mode_bits P((char *modes)); +long time_in_msec P((long x)); +SCM my_time P((void)); +SCM your_time P((void)); +void init_iprocs P((iproc *subra, int type)); +void init_scm P((int iverbose, int buf0stdin, long init_heap_size)); +SCM scm_init_extensions P((void)); +void ignore_signals P((void)); +void unignore_signals P((void)); +void free_storage P((void)); +void add_feature P((char *str)); +int raprin1 P((SCM exp, SCM port, int writing)); +SCM markcdr P((SCM ptr)); +SCM mark0 P((SCM ptr)); +SCM equal0 P((SCM ptr1, SCM ptr2)); +sizet free0 P((CELLPTR ptr)); +void warn P((char *str1, char *str2)); +void everr P((SCM exp, SCM env, SCM arg, char *pos, char *s_subr)); +void wta P((SCM arg, char *pos, char *s_subr)); +SCM intern P((char *name, sizet len)); +SCM sysintern P((char *name, SCM val)); +SCM sym2vcell P((SCM sym)); +SCM makstr P((long len)); +SCM make_subr P((char *name, int type, SCM (*fcn)())); +SCM closure P((SCM code, SCM env)); +SCM makprom P((SCM code)); +SCM force P((SCM x)); +SCM makarb P((SCM name)); +SCM tryarb P((SCM arb)); +SCM relarb P((SCM arb)); +SCM ceval P((SCM x, SCM env)); +SCM prolixity P((SCM arg)); +SCM gc_for_newcell P((void)); +SCM gc P((void)); +SCM tryload P((SCM filename)); +SCM acons P((SCM w, SCM x, SCM y)); +SCM cons2 P((SCM w, SCM x, SCM y)); +SCM resizuve P((SCM vect, SCM len)); +SCM lnot P((SCM x)); +SCM booleanp P((SCM obj)); +SCM eq P((SCM x, SCM y)); +SCM equal P((SCM x, SCM y)); +SCM consp P((SCM x)); +SCM cons P((SCM x, SCM y)); +SCM nullp P((SCM x)); +SCM setcar P((SCM pair, SCM value)); +SCM setcdr P((SCM pair, SCM value)); +SCM listp P((SCM x)); +SCM list P((SCM objs)); +SCM length P((SCM x)); +SCM append P((SCM args)); +SCM reverse P((SCM lst)); +SCM list_ref P((SCM lst, SCM k)); +SCM memq P((SCM x, SCM lst)); +SCM member P((SCM x, SCM lst)); +SCM memv P((SCM x, SCM lst)); +SCM assq P((SCM x, SCM alist)); +SCM assoc P((SCM x, SCM alist)); +SCM symbolp P((SCM x)); +SCM symbol2string P((SCM s)); +SCM string2symbol P((SCM s)); +SCM numberp P((SCM x)); +SCM exactp P((SCM x)); +SCM inexactp P((SCM x)); +SCM eqp P((SCM x, SCM y)); +SCM lessp P((SCM x, SCM y)); +SCM zerop P((SCM z)); +SCM positivep P((SCM x)); +SCM negativep P((SCM x)); +SCM oddp P((SCM n)); +SCM evenp P((SCM n)); +SCM lmax P((SCM x, SCM y)); +SCM lmin P((SCM x, SCM y)); +SCM sum P((SCM x, SCM y)); +SCM difference P((SCM x, SCM y)); +SCM product P((SCM x, SCM y)); +SCM divide P((SCM x, SCM y)); +SCM lquotient P((SCM x, SCM y)); +SCM absval P((SCM x)); +SCM lremainder P((SCM x, SCM y)); +SCM modulo P((SCM x, SCM y)); +SCM lgcd P((SCM x, SCM y)); +SCM llcm P((SCM n1, SCM n2)); +SCM number2string P((SCM x, SCM radix)); +SCM istring2number P((char *str, long len, long radix)); +SCM string2number P((SCM str, SCM radix)); +SCM istr2flo P((char *str, long len, long radix)); +SCM mkbig P((sizet nlen, int sign)); +SCM mkstrport P((SCM pos, SCM str, long modes, char *caller)); +SCM long2big P((long n)); +SCM ulong2big P((unsigned long n)); +SCM big2inum P((SCM b, sizet l)); +sizet iint2str P((long num, int rad, char *p)); +SCM floequal P((SCM x, SCM y)); +SCM uve_equal P((SCM u, SCM v)); +SCM raequal P((SCM ra0, SCM ra1)); +SCM array_equal P((SCM u, SCM v)); +int rafill P((SCM ra, SCM fill, SCM ignore)); +SCM uve_fill P((SCM uve, SCM fill)); +SCM array_fill P((SCM ra, SCM fill)); +SCM array_prot P((SCM ra)); +int bigprint P((SCM exp, SCM port, int writing)); +int floprint P((SCM sexp, SCM port, int writing)); +SCM istr2int P((char *str, long len, long radix)); +SCM istr2bve P((char *str, long len)); +void ipruk P((char *hdr, SCM ptr, SCM port)); +SCM charp P((SCM x)); +SCM char_lessp P((SCM x, SCM y)); +SCM chci_eq P((SCM x, SCM y)); +SCM chci_lessp P((SCM x, SCM y)); +SCM char_alphap P((SCM chr)); +SCM char_nump P((SCM chr)); +SCM char_whitep P((SCM chr)); +SCM char_upperp P((SCM chr)); +SCM char_lowerp P((SCM chr)); +SCM char2int P((SCM chr)); +SCM int2char P((SCM n)); +SCM char_upcase P((SCM chr)); +SCM char_downcase P((SCM chr)); +SCM stringp P((SCM x)); +SCM string P((SCM chrs)); +SCM make_string P((SCM k, SCM chr)); +SCM string2list P((SCM str)); +SCM st_length P((SCM str)); +SCM st_ref P((SCM str, SCM k)); +SCM st_set P((SCM str, SCM k, SCM chr)); +SCM st_equal P((SCM s1, SCM s2)); +SCM stci_equal P((SCM s1, SCM s2)); +SCM st_lessp P((SCM s1, SCM s2)); +SCM stci_lessp P((SCM s1, SCM s2)); +SCM substring P((SCM str, SCM start, SCM end)); +SCM st_append P((SCM args)); +SCM vectorp P((SCM x)); +SCM vector_length P((SCM v)); +SCM vector P((SCM l)); +SCM vector_ref P((SCM v, SCM k)); +SCM vector_set P((SCM v, SCM k, SCM obj)); +SCM make_vector P((SCM k, SCM fill)); +SCM vector2list P((SCM v)); +SCM for_each P((SCM proc, SCM arg1, SCM args)); +SCM procedurep P((SCM obj)); +SCM apply P((SCM proc, SCM arg1, SCM args)); +SCM map P((SCM proc, SCM arg1, SCM args)); +SCM scm_make_cont P((void)); +SCM copytree P((SCM obj)); +SCM eval P((SCM obj)); +SCM input_portp P((SCM x)); +SCM output_portp P((SCM x)); +SCM cur_input_port P((void)); +SCM cur_output_port P((void)); +SCM i_setbuf0 P((SCM port)); +SCM open_file P((SCM filename, SCM modes)); +SCM open_pipe P((SCM pipestr, SCM modes)); +SCM close_port P((SCM port)); +SCM lread P((SCM port)); +SCM scm_read_char P((SCM port)); +SCM peek_char P((SCM port)); +SCM eof_objectp P((SCM x)); +SCM lwrite P((SCM obj, SCM port)); +SCM display P((SCM obj, SCM port)); +SCM newline P((SCM port)); +SCM write_char P((SCM chr, SCM port)); +SCM file_position P((SCM port)); +SCM file_set_position P((SCM port, SCM pos)); +SCM lgetenv P((SCM nam)); +SCM prog_args P((void)); +SCM makacro P((SCM code)); +SCM makmacro P((SCM code)); +SCM makmmacro P((SCM code)); +void poll_routine P((void)); +void tick_signal P((void)); +void stack_check P((void)); +SCM list2ura P((SCM ndim, SCM prot, SCM lst)); +SCM make_ra P((int ndim)); +SCM makflo P((float x)); +SCM arrayp P((SCM v, SCM prot)); +SCM array_contents P((SCM ra, SCM strict)); +SCM uve_read P((SCM v, SCM port)); +SCM uve_write P((SCM v, SCM port)); +SCM ura_read P((SCM v, SCM port)); +SCM ura_write P((SCM v, SCM port)); +SCM aset P((SCM v, SCM obj, SCM args)); +SCM aref P((SCM v, SCM args)); +SCM cvref P((SCM v, sizet pos, SCM last)); +SCM quit P((SCM n)); +void add_final P((void (*final)(void))); +SCM makcclo P((SCM proc, long len)); +SCM make_uve P((long k, SCM prot)); +SCM ra2contig P((SCM ra, int copy)); +SCM sc2array P((SCM s, SCM ra, SCM prot)); +SCM array_copy P((SCM src, SCM dst)); +long aind P((SCM ra, SCM args, char *what)); +SCM scm_eval_string P((SCM str)); +SCM scm_load_string P((SCM str)); +void scm_print_stack P((SCM stk)); +char * dld_find_executable P((const char* command)); +SCM scm_unexec P((const SCM pathname)); +char * scm_cat_path P((char *str1, const char *str2, long n)); + + /* Defined in "rope.c" */ +SCM long2num P((long n)); +SCM ulong2num P((unsigned long n)); +unsigned char num2uchar P((SCM num, char *pos, char *s_caller)); +unsigned short num2ushort P((SCM num, char *pos, char *s_caller)); +unsigned long num2ulong P((SCM num, char *pos, char *s_caller)); + long num2long P((SCM num, char *pos, char *s_caller)); + double num2dbl P((SCM num, char *pos, char *s_caller)); +SCM makfromstr P((char *src, sizet len)); +SCM makfromstrs P((int argc, char **argv)); +SCM makfrom0str P((char *scr)); +char **makargvfrmstrs P((SCM args, char *s_v)); +void must_free_argv P((char **argv)); +SCM scm_evstr P((char *str)); +void scm_ldstr P((char *str)); +int scm_ldfile P((char *path)); +int scm_ldprog P((char *path)); +unsigned long scm_addr P((SCM args, char *name)); + +#ifdef FLOATS +SCM makdbl P((double x, double y)); +SCM dbl2big P((double d)); +double big2dbl P((SCM b)); +double lasinh P((double x)); +double lacosh P((double x)); +double latanh P((double x)); +double ltrunc P((double x)); +double round P((double x)); +double floident P((double x)); +#endif + +#ifdef BIGDIG +void longdigs P((long x, BIGDIG digs [DIGSPERLONG ])); +SCM adjbig P((SCM b, sizet nlen)); +SCM normbig P((SCM b)); +SCM copybig P((SCM b, int sign)); +SCM addbig P((BIGDIG *x, sizet nx, int xsgn, SCM bigy, int sgny)); +SCM mulbig P((BIGDIG *x, sizet nx, BIGDIG *y, sizet ny, int sgn)); +unsigned int divbigdig P((BIGDIG *ds, sizet h, BIGDIG div)); +SCM divbigint P((SCM x, long z, int sgn, int mode)); +SCM divbigbig P((BIGDIG *x, sizet nx, BIGDIG *y, sizet ny, int sgn, + int modes)); +long pseudolong P((long x)); +#endif +int bigcomp P((SCM x, SCM y)); +SCM bigequal P((SCM x, SCM y)); + +#ifdef RECKLESS +# define ASSERT(_cond, _arg, _pos, _subr) ; +# define ASRTGO(_cond, _label) ; +#else +# define ASSERT(_cond, _arg, _pos, _subr) if(!(_cond))wta(_arg, (char *)(_pos), _subr); +# define ASRTGO(_cond, _label) if(!(_cond)) goto _label; +#endif + +#define ARGn 0 +#define ARG1 1 +#define ARG2 2 +#define ARG3 3 +#define ARG4 4 +#define ARG5 5 + /* following must match entry indexes in errmsgs[] */ +#define WNA 6 +#define OVFLOW 7 +#define OUTOFRANGE 8 +#define NALLOC 9 +#define EXIT 10 +#define HUP_SIGNAL 11 +#define INT_SIGNAL 12 +#define FPE_SIGNAL 13 +#define BUS_SIGNAL 14 +#define SEGV_SIGNAL 15 +#define ALRM_SIGNAL 16 + +#define EVAL(x, env) (IMP(x)?(x):ceval((x), (env))) +#define SIDEVAL(x, env) if NIMP(x) ceval((x), (env)) + +#define NEWCELL(_into) {if IMP(freelist) _into = gc_for_newcell();\ + else {_into = freelist;freelist = CDR(freelist);++cells_allocated;}} + +#ifdef __cplusplus +} +#endif diff --git a/scm.texi b/scm.texi new file mode 100644 index 0000000..d7270f6 --- /dev/null +++ b/scm.texi @@ -0,0 +1,6911 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename scm.info +@settitle SCM +@setchapternewpage on +@c Choices for setchapternewpage are {on,off,odd}. +@paragraphindent 2 +@c %**end of header + +@iftex +@finalout +@c DL: lose the egregious vertical whitespace, esp. around examples +@c but paras in @defun-like things don't have parindent +@parskip 4pt plus 1pt +@end iftex + +@titlepage +@title SCM +@subtitle Scheme Implementation +@subtitle Version 4e6 +@subtitle March 1996 +@author by Aubrey Jaffer + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the author. +@end titlepage + +@node Top, Copying, (dir), (dir) + + +@ifinfo +This manual documents the SCM Scheme implementation. The most recent +information about SCM can be found on SCM's @dfn{WWW} home page: +@center http://www-swiss.ai.mit.edu/~jaffer/SCM.html + + +Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the author. +@end ifinfo + +@menu +* Copying:: Conditions for copying and changing SCM. +* Overview:: Whats here and how to start using it. +* Installing SCM:: Where it goes and how to get it there. +* The Language:: Reference. +* Packages:: Optional Capabilities. +* The Implementation:: How it works. +* Procedure and Macro Index:: +* Variable Index:: +* Type Index:: +@end menu + +@node Copying, Overview, Top, Top +@chapter Copying + +@center COPYRIGHT (c) 1989 BY +@center PARADIGM ASSOCIATES INCORPORATED, CAMBRIDGE, MASSACHUSETTS. +@center ALL RIGHTS RESERVED + +@noindent +Permission to use, copy, modify, distribute and sell this software +and its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all copies +and that both that copyright notice and this permission notice appear +in supporting documentation, and that the name of Paradigm Associates +Inc not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +@noindent +PARADIGM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +PARADIGM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +@noindent +gjc@@paradigm.com +@flushright +Phone: 617-492-6079 +@end flushright +@flushleft +Paradigm Associates Inc +29 Putnam Ave, Suite 6 +Cambridge, MA 02138 +@end flushleft + +@sp 2 + +@center Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 +@center Free Software Foundation, Inc. +@center 675 Mass Ave, Cambridge, MA 02139, USA + +@noindent +Permission to use, copy, modify, distribute, and sell this software and +its documentation for any purpose is hereby granted without fee, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. + +@center NO WARRANTY + +@noindent +BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH +YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +@noindent +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR +DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM +(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF +THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR +OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +@node Overview, Installing SCM, Copying, Top +@chapter Overview + +@noindent +Scm is a portable Scheme implementation written in C. Scm provides a +machine independent platform for [JACAL], a symbolic algebra system. + +@iftex +@noindent +The most recent information about SCM can be found on SCM's @dfn{WWW} +home page: +@ifset html +<A HREF="http://www-swiss.ai.mit.edu/~jaffer/SCM.html"> +@end ifset + +@center http://www-swiss.ai.mit.edu/~jaffer/SCM.html + +@ifset html +</A> +@end ifset +@end iftex + +@menu +* SCM Features:: +* SCM Authors:: +* Bibliography:: +* Invoking SCM:: +* SCM Options:: +* SCM Variables:: +* SCM Examples:: +* SCM Session:: +* Editing Scheme Code:: +* Debugging Scheme Code:: +@end menu + +@node SCM Features, SCM Authors, Overview, Overview +@section Features + +@itemize @bullet +@item +Conforms to Revised^4 Report on the Algorithmic Language Scheme [R4RS] +and the [IEEE] P1178 specification. +@item +Support for [SICP], [R2RS], [R3RS], and (proposed) [R5RS] scheme code. +@item +Runs under Amiga, Atari-ST, MacOS, MS-DOS, OS/2, NOS/VE, Unicos, VMS, +Unix and similar systems. Supports ASCII and EBCDIC character sets. +@item +Is fully documented in @TeX{}info form, allowing documentation to be +generated in info, @TeX{}, html, nroff, and troff formats. +@item +Supports inexact real and complex numbers, 30 bit immediate integers and +large precision integers. +@item +Many Common Lisp functions: @code{logand}, @code{logor}, @code{logxor}, +@code{lognot}, @code{ash}, @code{logcount}, @code{integer-length}, +@code{bit-extract}, @code{defmacro}, @code{macroexpand}, +@code{macroexpand1}, @code{gentemp}, @code{defvar}, @code{force-output}, +@code{software-type}, @code{get-decoded-time}, +@code{get-internal-run-time}, @code{get-internal-real-time}, +@code{delete-file}, @code{rename-file}, @code{copy-tree}, @code{acons}, +and @code{eval}. +@item +@code{Char-code-limit}, @code{most-positive-fixnum}, +@code{most-negative-fixnum}, @code{and internal-time-units-per-second} +constants. @code{*Features*} and @code{*load-pathname*} variables. +@item +Arrays and bit-vectors. String ports and software emulation ports. +I/O extensions providing ANSI C and POSIX.1 facilities. +@item +Interfaces to standard libraries including REGEX string regular +expression matching and the CURSES screen management package. +@item +Available add-on packages including an interactive debugger, database, +X-window graphics, BGI graphics, Motif, and Open-Windows packages. +@item +A compiler (HOBBIT, available separately) and dynamic linking of +compiled modules. +@item +User definable responses to interrupts and errors, +Process-syncronization primitives. Setable levels of monitoring and +timing information printed interactively (the @code{verbose} function). +@code{Restart}, @code{quit}, and @code{exec}. +@end itemize + +@node SCM Authors, Bibliography, SCM Features, Overview +@section Authors + +@table @b +@item Aubrey Jaffer (jaffer@@ai.mit.edu) +Most of SCM. +@item Radey Shouman +Arrays. @code{gsubr}s, compiled closures, and records. +@item Jerry D. Hedden +Real and Complex functions. Fast mixed type arithmetics. +@item Hugh Secker-Walker +Syntax checking and memoization of special forms by evaluator. Storage +allocation strategy and parameters. +@item George Carrette +@dfn{Siod}, written by George Carrette, was the starting point for SCM. +The major innovations taken from Siod are the evaluator's use of the +C-stack and being able to garbage collect off the C-stack +(@pxref{Garbage Collection}). +@end table + +@noindent +There are many other contributors to SCM. They are acknowledged in the +file @file{ChangeLog}, a log of changes that have been made to scm. + +@node Bibliography, Invoking SCM, SCM Authors, Overview +@section Bibliography + +@table @asis +@item [IEEE] +@pindex IEEE +@cite{IEEE Standard 1178-1990. IEEE Standard for the Scheme +Programming Language.} IEEE, New York, 1991. + +@item [Simply] +@pindex Simply +Brian Harvey and Matthew Wright. +@ifset html +<A HREF="http://HTTP.CS.Berkeley.EDU/~bh/simply-toc.html"> +@end ifset +@cite{Simply Scheme: Introducing Computer Science} +@ifset html +</A> +@end ifset +MIT Press, 1994 ISBN 0-262-08226-8 + +@item [SICP] +@pindex SICP +Harold Abelson and Gerald Jay Sussman with Julie Sussman. +@cite{Structure and Interpretation of Computer Programs.} +MIT Press, Cambridge, 1985. + +@item [R4RS] +@pindex R4RS +William Clinger and Jonathan Rees, Editors. +@ifset html +<A HREF="r4rs_toc.html"> +@end ifset +Revised(4) Report on the Algorithmic Language Scheme. +@ifset html +</A> +@end ifset +@cite{ACM Lisp Pointers} Volume IV, Number 3 (July-September 1991), +pp. 1-55. +@ifinfo + +@ref{Top, , , r4rs, Revised(4) Report on the Algorithmic Language +Scheme}. +@end ifinfo + +@item [GUILE] +@pindex GUILE +Tom Lord. +@ifset html +<A HREF="http://www.cygnus.com/library/ctr/guile.html"> +@end ifset +The Guile Architecture for Ubiquitous Computing. +@ifset html +</A> +@end ifset +@cite{Usenix Symposium on Tcl/Tk}, 1995. + +@item [SLIB] +@pindex SLIB +Todd R. Eigenschink, Dave Love, and Aubrey Jaffer. +@ifset html +<A HREF="slib_toc.html"> +@end ifset +SLIB, The Portable Scheme Library. +@ifset html +</A> +@end ifset +Version 2a3, June 1995. +@ifinfo + +@ref{Top, , , slib, SLIB}. +@end ifinfo + +@item [JACAL] +@pindex JACAL +Aubrey Jaffer. +@ifset html +<A HREF="jacal_toc.html"> +@end ifset +JACAL Symbolic Mathematics System. +@ifset html +</A> +@end ifset +Version 1a5, April 1994. +@ifinfo + +@ref{Top, , , jacal, JACAL}. +@end ifinfo +@end table + +@table @file +@item scm.texi +@itemx scm.info +Documentation of @code{scm} extensions (beyond Scheme standards). +Documentation on the internal representation and how to extend or +include @code{scm} in other programs. +@end table + +@node Invoking SCM, SCM Options, Bibliography, Overview +@section Invoking SCM + +@quotation +@exdent @b{ scm } [-a @i{kbytes}] [-ibvqmu] [-p @i{number}] +@w{[-c @i{expression}]} @w{[-e @i{expression}]} @w{[-f @i{filename}]} +@w{[-l @i{filename}]} @w{[-r @i{feature}]} @w{[-- | - | -s]} +@w{[@i{filename}]} @w{[@i{arguments} @dots{}]} +@end quotation + +@noindent +Upon startup @code{scm} loads the file specified by by the environment +variable @var{SCM_INIT_PATH}. + +@noindent +If @var{SCM_INIT_PATH} is not defined or if the file it names is not +present, @code{scm} tries to find the directory containing the +executable file. If it is able to locate the executable, @code{scm} +looks for the initialization file (usually @file{Init.scm}) in +platform-dependent directories relative to this directory. +@xref{File-System Habitat} for a blow-by-blow description. + +@noindent +As a last resort (if initialization file cannot be located), the C +compile parameter @var{IMPLINIT} (defined in the makefile or +@file{scmfig.h}) is tried. + +@noindent +Unless the option @code{-no-init-file} or @code{--no-init-file} occurs +in the command line, @file{Init.scm} checks to see if there is file +@file{ScmInit.scm} in the path specified by the environment variable +@var{HOME} (or in the current directory if @var{HOME} is undefined). If +it finds such a file it is loaded. + +@noindent +@file{Init.scm} then looks for command input from one of three sources: +From an option on the command line, from a file named on the command +line, or from standard input. + +@noindent +This explanation applies to SCMLIT or other builds of SCM. + +@noindent +Scheme-code files can also invoke SCM and its variants. @xref{Syntax +Extensions, #!}. + +@node SCM Options, SCM Variables, Invoking SCM, Overview +@section Options + +@noindent +The options are processed in the order specified on the command line. + +@deffn {Command Option} -a kb +specifies that @code{scm} should allocate an initial heapsize of +@var{kb} kilobytes. This option, if present, must be the first on +the command line. If not specified, the default is +@code{INIT_HEAP_SIZE} in source file @file{setjump.h} which the +distribution sets at @code{25000*sizeof(cell)}. +@end deffn + +@deffn {Command Option} -no-init-file +@deffnx {Command Option} --no-init-file +Inhibits the loading of @file{ScmInit.scm} as described above. +@end deffn + +@deffn {Command Option} -e expression +@deffnx {Command Option} -c expression +specifies that the scheme expression @var{expression} is to be +evaluated. These options are inspired by @code{perl} and @code{sh} +respectively. On Amiga systems the entire option and argument need to be +enclosed in quotes. For instance @samp{"-e(newline)"}. +@end deffn + +@deffn {Command Option} -r feature +requires @var{feature}. This will load a file from [SLIB] if that +@var{feature} is not already supported. If @var{feature} is 2, 3, 4, or +5 @code{scm} will require the features neccessary to support [R2RS], +[R3RS], [R4RS], or proposed [R5RS], respectively. +@end deffn + +@deffn {Command Option} -l filename +@deffnx {Command Option} -f filename +loads @var{filename}. @code{Scm} will load the first (unoptioned) file +named on the command line if no @code{-c}, @code{-e}, @code{-f}, +@code{-l}, or @code{-s} option preceeds +it. +@end deffn + +@deffn {Command Option} -p level +sets the prolixity (verboseness) to @var{level}. This is the same as +the @code{scm} command (verobse @var{level}). +@end deffn + +@deffn {Command Option} -v +(verbose mode) specifies that @code{scm} will print prompts, evaluation +times, notice of loading files, and garbage collection statistics. This +is the same as @code{-p3}. +@end deffn + +@deffn {Command Option} -q +(quiet mode) specifies that @code{scm} will print no extra +information. This is the same as @code{-p0}. +@end deffn + +@deffn {Command Option} -m +specifies that subsequent loads, evaluations, and user interactions will +be with [R4RS] macro capability. To use a specific [R4RS] macro +implementation from [SLIB] (instead of [SLIB]'s default) put @code{-r} +@var{macropackage} before @code{-m} on the command line. +@end deffn + +@deffn {Command Option} -u +specifies that subsequent loads, evaluations, and user interactions will +be without [R4RS] macro capability. [R4RS] macro capability can +be restored by a subsequent @code{-m} on the command line or from Scheme +code. +@end deffn + +@deffn {Command Option} -i +specifies that @code{scm} should run interactively. That means that +@code{scm} will not terminate until the @code{(quit)} or @code{(exit)} +command is given, even if there are errors. It also sets the prolixity +level to 2 if it is less than 2. This will print prompts, evaluation +times, and notice of loading files. The prolixity level can be set by +subsequent options. If @code{scm} is started from a tty, it will assume +that it should be interactive unless given a subsequent @code{-b} +option. +@end deffn + +@deffn {Command Option} -b +specifies that @code{scm} should run non-interactively. That means that +@code{scm} will terminate after processing the command line or if there +are errors. +@end deffn + +@deffn {Command Option} -s +specifies, by analogy with @code{sh}, that further options are to be +treated as program aguments. +@end deffn + +@deffn {Command Option} - +@deffnx {Command Option} -- +specifies that there are no more options on the command line. +@end deffn + +@deffn {Command Option} -d filename +loads SLIB database-utilities and opens @var{filename} as a database. +@end deffn + +@deffn {Command Option} -o filename +saves the current SCM session as the executable program @file{filename}. +This option works only in SCM builds supporting @code{dump} +(@pxref{Dump}). + +If options appear on the command line after @samp{-o @var{filename}}, +then the saved session will continue with processing those options when +it is invoked. Otherwise the (new) command line is processed as usual +when the saved image is invoked. +@end deffn + +@deffn {Command Option} --help +prints usage information and URL; then exit. +@end deffn + +@deffn {Command Option} --version +prints version information and exit. +@end deffn + +@node SCM Variables, SCM Examples, SCM Options, Overview +@section Environment Variables + +@defvr {Environment Variable} SCM_INIT_PATH +is the pathname where @code{scm} will look for its initialization +code. The default is the file @file{Init.scm} in the source directory. +@end defvr + +@defvr {Environment Variable} SCHEME_LIBRARY_PATH +is the [SLIB] Scheme library directory. +@end defvr + +@defvr {Environment Variable} HOME +is the directory where @file{Init.scm} will look for the user +initialization file @file{ScmInit.scm}. +@end defvr + +@section Scheme Variables + +@defvar *argv* +contains the list of arguments to the program. @code{*argv*} can change +during argument processing. This list is suitable for use as an argument +to [SLIB] @code{getopt}. +@end defvar + +@defvar *R4RS-macro* +controls whether loading and interaction support [R4RS] macros. Define +this in @file{ScmInit.scm} or files specified on the command line. This +can be overridden by subsequent @code{-m} and @code{-u} options. +@end defvar + +@defvar *interactive* +controls interactivity as explained for the @code{-i} and @code{-b} +options. Define this in @file{ScmInit.scm} or files specified on the +command line. This can be overridden by subsequent @code{-i} and +@code{-b} options. +@end defvar + +@node SCM Examples, SCM Session, SCM Variables, Overview +@section Examples + +@table @code +@item % scm foo.scm +Loads and executes the contents of @file{foo.scm} and then enters +interactive session. + +@item % scm -f foo.scm arg1 arg2 arg3 +Parameters @code{arg1}, @code{arg2}, and @code{arg3} are stored in the +global list @code{*argv*}; Loads and executes the contents of +@file{foo.scm} and exits. + +@item % scm -s foo.scm arg1 arg2 +Sets *argv* to @code{("foo.scm" "arg1" "arg2")} and enters interactive +session. + +@item % scm -e `(write (list-ref *argv* *optind*))' bar +Prints @samp{"bar"}. + +@item % scm -rpretty-print -r format -i +Loads @code{pretty-print} and @code{format} and enters interactive +session. + +@item % scm -r5 +Loads @code{dynamic-wind}, @code{values}, and [R4RS] macros and enters +interactive (with macros) session. + +@item % scm -r5 -r4 +Like above but @code{rev4-optional-procedures} are also loaded. +@end table + +@node SCM Session, Editing Scheme Code, SCM Examples, Overview +@section SCM Session + +@itemize @bullet +@item +Options, file loading and features can be specified from the command +line. @xref{System interface, , , scm, SCM}. @xref{Require, , , slib, +SLIB}. +@item +Typing the end-of-file character at the top level session (while SCM is +not waiting for parenthesis closure) causes SCM to exit. +@item +Typing the interrupt character aborts evaluation of the current form +and resumes the top level read-eval-print loop. +@end itemize + +@node Editing Scheme Code, Debugging Scheme Code, SCM Session, Overview +@section Editing Scheme Code + +@table @asis +@item Gnu Emacs: +Editing of Scheme code is supported by emacs. Buffers holding files +ending in .scm are automatically put into scheme-mode. + +If your Emacs can run a process in a buffer you can use the Emacs +command @samp{M-x run-scheme} with SCM. However, the run-scheme +(@file{xscheme.el}) which comes included with Gnu Emacs 18 will work +only with MIT Cscheme. If you are using Emacs 18, get the emacs +packages: + +@ifclear html +@itemize @bullet +@item +ftp-swiss.ai.mit.edu:/pub/scheme-editor-packages/cmuscheme.el +@item +ftp-swiss.ai.mit.edu:/pub/scheme-editor-packages/comint.el +@end itemize +@end ifclear + +@ifset html +<A HREF="file://ftp-swiss.ai.mit.edu/pub/scheme-editor-packages/cmuscheme.el"> +ftp-swiss.ai.mit.edu:/pub/scheme-editor-packages/cmuscheme.el +</A> +<A HREF="file://ftp-swiss.ai.mit.edu/pub/scheme-editor-packages/comint.el"> +ftp-swiss.ai.mit.edu:/pub/scheme-editor-packages/comint.el +</A> +@end ifset + +These files are already standard in Emacs 19. + +If your Emacs can not run a process in a buffer, see ``under other +systems'' below. + +@item Epsilon (MS-DOS): +There is lisp (and scheme) mode available by use of the package +@samp{LISP.E}. It offers several different indentation formats. With +this package, buffers holding files ending in @samp{.L}, @samp{.LSP}, +@samp{.S}, and @samp{.SCM} (my modification) are automatically put into +lisp-mode. + +It is possible to run a process in a buffer under Epsilon. With Epsilon +5.0 the command line options @samp{-e512 -m0} are neccessary to manage +RAM properly. It has been reported that when compiling SCM with Turbo +C, you need to @samp{#define NOSETBUF} for proper operation in a process +buffer with Epsilon 5.0. + +One can also call out to an editor from SCM if RAM is at a premium; See +``under other systems'' below. + +@item other systems: +Define the environment variable @samp{EDITOR} to be the name of the +editing program you use. The SCM procedure @code{(ed arg1 @dots{})} +will invoke your editor and return to SCM when you exit the editor. The +following definition is convenient: + +@example +(define (e) (ed "work.scm") (load "work.scm")) +@end example + +Typing @samp{(e)} will invoke the editor with the file of interest. +After editing, the modified file will be loaded. +@end table + +@node Debugging Scheme Code, , Editing Scheme Code, Overview +@section Debugging Scheme Code + +@noindent +The @code{cautious} and @code{stack-limit} options of @code{build} +(@pxref{Build Options}) support debugging in Scheme. + +@table @dfn +@item CAUTIOUS +If SCM is built with the @samp{CAUTIOUS} flag, then when an error +occurs, a @dfn{stack trace} of certain pending calls are printed as part +of the default error response. A (memoized) expression and newline are +printed for each partially evaluated combination whose procedure is not +builtin. @xref{Memoized Expressions} for how to read memoized +expressions. + +Also as the result of the @samp{CAUTIOUS} flag, both @code{error} and +@code{user-interrupt} (invoked by @key{C-c}) to print stack traces and +conclude by calling @code{breakpoint} (@pxref{Breakpoints, , , slib, +SLIB}) instead of aborting to top level. Under either condition, +program execution can be resumed by @code{(continue)}. + +In this configuration one can interrupt a running Scheme program with +@key{C-c}, inspect or modify top-level values, trace or untrace +procedures, and continue execution with @code{(continue)}. + +@item STACK_LIMIT +If SCM is built with the @samp{STACK_LIMIT} flag, the interpreter will +check stack size periodically. If the size of stack exceeds a certain +amount (default is @code{HEAP_SEG_SIZE/2}), SCM generates a +@code{segment violation} interrupt. + +The usefulness of @samp{STACK_LIMIT} depends on the user. I don't use +it; but the user I added this feature for got primarily this type of +error. +@end table + +@noindent +There are several SLIB macros which so useful that SCM automatically +loads the appropriate module from SLIB if they are invoked. + +@defmac trace proc1 @dots{} +Traces the top-level named procedures given as arguments. +@defmacx trace +With no arguments, makes sure that all the currently traced identifiers +are traced (even if those identifiers have been redefined) and returns a +list of the traced identifiers. +@end defmac + +@defmac untrace proc1 @dots{} +Turns tracing off for its arguments. +@defmacx untrace +With no arguments, untraces all currently traced identifiers and returns +a list of these formerly traced identifiers. +@end defmac + +The routine I use most for debugging is: + +@deffn Procedure print arg1 ... +@code{Print} writes all its arguments, separated by spaces. +@code{Print} outputs a @code{newline} at the end and returns the value +of the last argument. + +One can just insert @samp{(print '<proc-name>} and @samp{)} around an +expression in order to see its value as a program operates. +@end deffn + +@noindent +Sometimes more elaborate measures are needed to print values in a useful +manner. When the values to be printed may have very large (or infinite) +external representations, @ref{Quick Print, , , slib, SLIB}, can be +used. + +When @code{trace} is not sufficient to find program flow problems, +@ifset html +<A HREF="http://www.cs.tut.fi/staff/pk/scheme/psd/article/article.html"> +@end ifset +SLIB-PSD, the Portable Scheme Debugger +@ifset html +</A> +@end ifset +offers source code debugging from +GNU Emacs. PSD runs slowly, so start by instrumenting only a few +functions at a time. +@lisp +ftp-swiss.ai.mit.edu:pub/scm/slib-psd1-3.tar.gz +prep.ai.mit.edu:pub/gnu/jacal/slib-psd1-3.tar.gz +ftp.maths.tcd.ie:pub/bosullvn/jacal/slib-psd1-3.tar.gz +ftp.cs.indiana.edu:/pub/scheme-repository/utl/slib-psd1-3.tar.gz +@end lisp + + +@node Installing SCM, The Language, Overview, Top +@chapter Installing SCM + +@menu +* File-System Habitat:: All the usual suspects. +* Executable Pathname:: Where did I come from? +* Making SCM:: +* Building SCM:: +* SLIB:: REQUIREd reading. +* Installing Dynamic Linking:: +* Saving Images:: Make Fast-Booting Executables +* Automatic C Preprocessor Definitions:: +* Problems Compiling:: +* Problems Linking:: +* Problems Running:: +* Testing:: +* Reporting Problems:: +@end menu + +@node File-System Habitat, Executable Pathname, Installing SCM, Installing SCM +@section File-System Habitat + +@noindent +Where should software reside? Although individually a minor annoyance, +cumulatively this question represents many thousands of frustrated user +hours spent trying to find support files or guessing where packages need +to be installed. Even simple programs require proper habitat; games +need to find their score files. + +@noindent +Aren't there standards for this? Some Operating Systems have devised +regimes of software habitats -- only to have them violated by large +software packages and imports from other OS varieties. + +@noindent +In some programs, the expected locations of support files are fixed at +time of compilation. This means that the program may not run on +configurations unanticipated by the authors. Compiling locations into a +program also can make it immovable -- necessitating recompilation to +install it. + +@quotation +Programs of the world unite! You have nothing to lose but loss itself. +@end quotation + +@noindent +The function @code{scm_find_impl_file} in @file{scm.c} is an attempt to +create a utility (for inclusion in programs) which will hide the details +of platform-dependent file habitat conventions. It takes as input the +pathname of the executable file which is running. If there are systems +for which this information is either not available or unrelated to the +locations of support files, then a higher level interface will be +needed. + +@deftypefun char *scm_find_impl_file(char *@var{exec_path}, char +*@var{generic_name}, char *@var{initname}, char *@var{sep}) Given the +pathname of this executable (@var{exec_path}), test for the existence of +@var{initname} in the implementation-vicinity of this program. Return a +newly allocated string of the path if successful, 0 if not. The +@var{sep} argument is a @emph{mull-terminated string} of the character +used to separate directory components. +@end deftypefun + +@itemize @bullet +@item +One convention is to install the support files for an executable program +in the same directory as the program. This possibility is tried first, +which satisfies not only programs using this convention, but also +uninstalled builds when testing new releases, etc. + +@item +Another convention is to install the executables in a directory named +@file{bin}, @file{BIN}, @file{exe}, or @file{EXE} and support files in a +directroy named @file{lib}, which is a peer the executable directory. +This arrangement allows multiple executables can be stored in a single +directory. For example, the executable might be in +@samp{/usr/local/bin/} and initialization file in +@samp{/usr/local/lib/}. + +If the executable directory name matches, the peer directroy @file{lib} +is tested for @var{initname}. + +@item +Sometimes @file{lib} directories become too crowded. So we look in any +subdirectories of @file{lib} or @file{src} having the name (sans type +suffix such as @samp{.EXE}) of the program we are running. For example, +the executable might be @samp{/usr/local/bin/foo} and initialization +file in @samp{/usr/local/lib/foo/}. + +@item +But the executable name may not be the usual program name; So also look +in any @var{generic_name} subdirectories of @file{lib} or @file{src} +peers. + +@item +Finally, if the name of the executable file being run has a (system +dependent) suffix which is not needed to invoke the program, then look +in a subdirectory (of the one containing the executable file) named for +the executable (without the suffix); And look in a @var{generic_name} +subdirectory. For example, the executable might be +@samp{C:\foo\bar.exe} and the initialization file in @samp{C:\foo\bar\}. +@end itemize + + +@node Executable Pathname, Making SCM, File-System Habitat, Installing SCM +@section Executable Pathname + +@noindent +When a program is executed by MS-DOS, the full pathname of that +executable is available in @code{argv[0]}. This value can be passed to +@code{dld_find_executable} (@pxref{File-System Habitat}). + +In order to find the habitat for a unix program, we first need to know +the full pathname for the associated executable file. + +@deftypefun char *dld_find_executable (const char *@var{command}) +@code{dld_find_executable} returns the absolute path name of the file +that would be executed if @var{command} were given as a command. It +looks up the environment variable @var{PATH}, searches in each of the +directory listed for @var{command}, and returns the absolute path name +for the first occurrence. Thus, it is advisable to invoke +@code{dld_init} as: + +@example +main (int argc, char **argv) +@{ + @dots{} + if (dld_init (dld_find_executable (argv[0]))) @{ + @dots{} + @} + @dots{} +@} +@end example + +@quotation +@strong{Note:} If the current process is executed using the +@code{execve} call without passing the correct path name as argument 0, +@code{dld_find_executable (argv[0]) } will also fail to locate the +executable file. +@end quotation + +@code{dld_find_executable} returns zero if @code{command} is not found +in any of the directories listed in @code{PATH}. +@end deftypefun + +@node Making SCM, Building SCM, Executable Pathname, Installing SCM +@section Making SCM + +The SCM distribution has @dfn{Makefile} which contains rules for making +@dfn{scmlit}, a ``bare-bones'' version of SCM sufficient for running +@file{build.scm}. @file{build.scm} is used to compile (or create +scripts to compile) full featured versions. + +Makefiles are not portable to the majority of platforms. If +@file{Makefile} works for you, good; If not, I don't want to hear about +it. If you need to compile SCM without build.scm, there are several +ways to proceed: + +@itemize @bullet +@item +Use SCM on a different platform to run @file{build.scm} to create a +script to build SCM; + +@item +Use another implementation of Scheme to run @file{build.scm} to create a +script to build SCM; + +@item +Create your own script or @file{Makefile}. + +@item +Buy a SCM executable from jaffer@@ai.mit.edu. See the end of the +@file{ANNOUNCE} file in the distribution for details. + +@item +Use scmconfig (From: bos@@scrg.cs.tcd.ie): + +Build and install scripts using GNU @dfn{autoconf} are available from +@file{scmconfig4e6.tar.gz} in the distribution directories. See +@file{README.unix} in @file{scmconfig4e6.tar.gz} for further +instructions. +@end itemize + + +@node Building SCM, SLIB, Making SCM, Installing SCM +@section Building SCM + +The file @dfn{build.scm} builds and runs a relational database of how to +compile and link SCM executables. It has information for most platforms +which SCM has been ported to (of which I have been notified). Some of +this information is old, incorrect, or incomplete. Send corrections and +additions to jaffer@@ai.mit.edu. + +@menu +* Invoking Build:: +* Build Options:: +@end menu + +@node Invoking Build, Build Options, Building SCM, Building SCM +@subsection Invoking Build + +The @emph{all} method will also work for MS-DOS and unix. Use +the @emph{all} method if you encounter problems with @file{build.scm}. + +@table @asis +@item MS-DOS +From the SCM source directory, type @samp{build} followed by up to 9 +command line arguments. + +@item unix +From the SCM source directory, type @samp{build.scm} followed by command +line arguments. + +@item @emph{all} +From the SCM source directory, start @samp{scm} or @samp{scmlit} and +type @code{(load "build.scm")}. Alternatively, start @samp{scm} or +@samp{scmlit} with the command line argument @samp{-ilbuild}. + +@end table + +@node Build Options, , Invoking Build, Building SCM +@subsection Build Options + +@noindent +The options to @dfn{build} specify what, where, and how to build a SCM +program or dynamically linked module. These options are unrelated to +the SCM command line options. + +@deffn {Build Option} -p @var{platform-name} +@deffnx {Build Option} ---platform=@var{platform-name} +specifies that the compilation should be for a computer/operating-system +combination called @var{platform-name}. @emph{Note:} The case of +@var{platform-name} is distinguised. The current @var{platform-name}s +are all lower-case. + +The platforms defined by table @dfn{platform} in @file{build.scm} are: +@end deffn +@example +name processor operating-system compiler +symbol processor-family operating-system symbol +symbol atom symbol symbol +================= ================= ================= ================= +*unknown* *unknown* unix *unknown* +acorn-unixlib acorn *unknown* *unknown* +aix powerpc aix *unknown* +amiga-aztec m68000 amiga aztec +amiga-dice-c m68000 amiga dice-c +amiga-sas/c-5.10 m68000 amiga sas/c +atari-st-gcc m68000 atari.st gcc +atari-st-turbo-c m68000 atari.st turbo-c +borland-c-3.1 8086 ms-dos borland-c +djgpp i386 ms-dos gcc +gcc *unknown* unix gcc +highc.31 i386 ms-dos highc +hp-ux hp-risc hp-ux *unknown* +linux i386 linux gcc +linux-elf i386 linux gcc +microsoft-c 8086 ms-dos microsoft-c +microsoft-c-nt i386 ms-dos microsoft-c +microsoft-quick-c 8086 ms-dos microsoft-quick-c +ms-dos 8086 ms-dos *unknown* +os/2-cset i386 os/2 c-set++ +os/2-emx i386 os/2 gcc +sun sparc sun-os *unknown* +svr4 *unknown* unix *unknown* +turbo-c-2 8086 ms-dos turbo-c +unicos cray unicos *unknown* +unix *unknown* unix *unknown* +vms vax vms *unknown* +vms-gcc vax vms gcc +watcom-9.0 i386 ms-dos watcom +@end example + +@deffn {Build Option} -o @var{filename} +@deffnx {Build Option} ---outname=@var{filename} +specifies that the compilation should produce an executable or object +name of @var{filename}. The default is @samp{scm}. Executable suffixes +will be added if neccessary, e.g. @samp{scm} @result{} @samp{scm.exe}. +@end deffn + +@deffn {Build Option} -l @var{libname} @dots{} +@deffnx {Build Option} ---libraries=@var{libname} +specifies that the @var{libname} should be linked with the executable +produced. If compile flags or include directories (@samp{-I}) are +needed, they are automatically supplied for compilations. The @samp{c} +library is always included. SCM @dfn{features} specify any libraries +they need; so you shouldn't need this option often. +@end deffn + +@deffn {Build Option} -D @var{definition} @dots{} +@deffnx {Build Option} ---defines=@var{definition} +specifies that the @var{definition} should be made in any C source +compilations. If compile flags or include directories (@samp{-I}) are +needed, they are automatically supplied for compilations. SCM +@dfn{features} specify any flags they need; so you shouldn't need this +option often. +@end deffn + +@deffn {Build Option} ---compiler-options=@var{flag} +specifies that that @var{flag} will be put on compiler command-lines. +@end deffn + +@deffn {Build Option} ---linker-options=@var{flag} +specifies that that @var{flag} will be put on linker command-lines. +@end deffn + +@deffn {Build Option} -s @var{pathname} +@deffnx {Build Option} ---scheme-initial=@var{pathname} +specifies that @var{pathname} should be the default location of the SCM +initialization file @file{Init.scm}. SCM tries several likely locations +before resorting to @var{pathname} (@pxref{File-System Habitat}). +If not specified, the current directory (where build is building) is +used. +@end deffn + +@deffn {Build Option} -c @var{pathname} @dots{} +@deffnx {Build Option} ---c-source-files=@var{pathname} +specifies that the C source files @var{pathname} @dots{} are to be +compiled. +@end deffn + +@deffn {Build Option} -j @var{pathname} @dots{} +@deffnx {Build Option} ---object-files=@var{pathname} +specifies that the object files @var{pathname} @dots{} are to be linked. +@end deffn + +@deffn {Build Option} -i @var{call} @dots{} +@deffnx {Build Option} ---initialization=@var{call} +specifies that the C functions @var{call} @dots{} are to be +invoked during initialization. +@end deffn + +@deffn {Build Option} -t @var{build-what} +@deffnx {Build Option} ---type=@var{build-what} +specifies in general terms what sort of thing to build. The choices +are: +@table @samp +@item exe +executable program. +@item lib +library module. +@item dlls +archived dynamically linked library object files. +@item dll +dynamically linked library object file. +@end table + +The default is to build an executable. +@end deffn + +@deffn {Build Option} -h @var{batch-syntax} +@deffnx {Build Option} --batch-dialect=@var{batch-syntax} +specifies how to build. The default is to create a batch file for the +host system. The SLIB file @file{batch.scm} knows how to create batch +files for: +@itemize @bullet +@item +unix +@item +dos +@item +vms +@item +system + +This option executes the compilation and linking commands through the +use of the @code{system} procedure. +@item +*unknown* + +This option outputs Scheme code. +@end itemize +@end deffn + +@deffn {Build Option} -w @var{batch-filename} +@deffnx {Build Option} --script-name=@var{batch-filename} +specifies where to write the build script. The default is to display it +on @code{(current-output-port)}. +@end deffn + +@deffn {Build Option} -F @var{feature} @dots{} +@deffnx {Build Option} ---features=@var{feature} +specifies to build the given features into the executable. The defined +features are: + +@table @dfn +@item lit +@itemx none +Lightweight -- no features + +@item cautious +Normally, the number of arguments arguments to interpreted closures + (from LAMBDA) are checked if the function part of a form is not a +symbol or only the first time the form is executed if the function part +is a symbol. defining @samp{reckless} disables any checking. If you +want to have SCM always check the number of arguments to interpreted +closures define feature @samp{cautious}. + +@item careful-interrupt-masking +Define this for extra checking of interrupt masking. This is for +debugging C code in @file{sys.c} and @file{repl.c}. + +@item debug +Turns on features @samp{cautious} @samp{careful-interrupt-masking} +@samp{stack-limit} and uses @code{-g} flags for debugging SCM source +code. + +@item reckless +If your scheme code runs without any errors you can disable almost all +error checking by compiling all files with @samp{reckless}. + +@item stack-limit +Use to enable checking for stack overflow. Define value of the C +preprocessor variable @var{STACK_LIMIT} to be the size to which SCM +should allow the stack to grow. STACK_LIMIT should be less than the +maximum size the hardware can support, as not every routine checks the +stack. + +@item bignums +Large precision integers. + +@item arrays +Use if you want arrays, uniform-arrays and uniform-vectors. + +@item array-for-each +array-map! and array-for-each (arrays must also be defined). + +@item inexact +Use if you want floating point numbers. + +@item engineering-notation +Use if you want floats to display in engineering notation (exponents +always multiples of 3) instead of scientific notation. + +@item single-precision-only +Use if you want all inexact real numbers to be single precision. This +only has an effect if SINGLES is also defined (which is the default). +This does not affect complex numbers. + +@item sicp +Use if you want to run code from: + +H. Abelson, G. J. Sussman, and J. Sussman, +Structure and Interpretation of Computer Programs, +The MIT Press, Cambridge, Massachusetts, USA + +@code{(eq? '() '#f)} is the major difference. + +@item rev2-procedures +These procedures were specified in the @cite{Revised^2 Report on Scheme} +but not in @cite{R4RS}. + +@item record +The Record package provides a facility for user to define their own +record data types. See SLIB for documentation. + +@item compiled-closure +Use if you want to use compiled closures. + +@item generalized-c-arguments +@code{make_gsubr} for arbitrary (< 11) arguments to C functions. + +@item tick-interrupts +Use if you want the ticks and ticks-interrupt functions. + +@item i/o-extensions +Commonly available I/O extensions: @dfn{exec}, line I/O, file +positioning, file delete and rename, and directory functions. + +@item turtlegr +@dfn{Turtle} graphics calls for both Borland-C and X11 from +sjm@@ee.tut.fi. + +@item curses +For the @dfn{curses} screen management package. + +@item edit-line +interface to the editline or GNU readline library. + +@item regex +String regular expression matching. + +@item socket +BSD @dfn{socket} interface. + +@item posix +Posix functions available on all @dfn{Unix-like} systems. fork and +process functions, user and group IDs, file permissions, and @dfn{link}. + +@item unix +Those unix features which have not made it into the Posix specs: nice, +acct, lstat, readlink, symlink, mknod and sync. + +@item windows +Microsoft Windows executable. + +@item dynamic-linking +Be able to load compiled files while running. + +@item dump +Convert a running scheme program into an executable file. + +@item heap-can-shrink +Use if you want segments of unused heap to not be freed up after garbage +collection. This may reduce time in GC for *very* large working sets. + +@item cheap-continuations +If you only need straight stack continuations, executables compile with +this feature will run faster and use less storage than not having it. +Machines with unusual stacks @emph{need} this. Also, if you incorporate +new C code into scm which uses VMS system services or library routines +(which need to unwind the stack in an ordrly manner) you may need to +use this feature. + +@item memoize-local-bindings +Saves the interpeter from having to look up local bindings for every +identifier reference + +@end table +@end deffn + +@node SLIB, Installing Dynamic Linking, Building SCM, Installing SCM +@section SLIB + +@noindent +[SLIB] is a portable Scheme library meant to provide compatibility and +utility functions for all standard Scheme implementations. Although +SLIB is not @emph{neccessary} to run SCM, I strongly suggest you obtain +and install it. Bug reports about running SCM without SLIB have very +low priority. SLIB is available from the same sites as SCM: + +@ifclear html +@itemize @bullet +@item +ftp-swiss.ai.mit.edu:/pub/scm/slib2a6.tar.gz +@item +prep.ai.mit.edu:/pub/gnu/jacal/slib2a6.tar.gz +@item +ftp.maths.tcd.ie:pub/bosullvn/jacal/slib2a6.tar.gz +@item +ftp.cs.indiana.edu:/pub/scheme-repository/imp/slib2a6.tar.gz +@end itemize +@end ifclear + +@ifset html +<A HREF="file://ftp-swiss.ai.mit.edu/pub/scm/slib2a6.tar.gz"> +ftp-swiss.ai.mit.edu:/pub/scm/slib2a6.tar.gz +</A> +<A HREF="file://prep.ai.mit.edu/pub/gnu/jacal/slib2a6.tar.gz"> +prep.ai.mit.edu:/pub/gnu/jacal/slib2a6.tar.gz +</A> +<A HREF="file://ftp.maths.tcd.ie/pub/bosullvn/jacal/slib2a6.tar.gz"> +ftp.maths.tcd.ie:pub/bosullvn/jacal/slib2a6.tar.gz +</A> +<A HREF="file://ftp.cs.indiana.edu/pub/scheme-repository/code/lib/slib2a6.tar.gz"> +ftp.cs.indiana.edu:/pub/scheme-repository/code/lib/slib2a6.tar.gz +</A> +@end ifset + +@noindent +Unpack SLIB (@samp{tar xzf slib2a6.tar.gz} or @samp{unzip -ao +slib2a6.zip}) in an appropriate directory for your system; both +@code{tar} and @code{unzip} will create the directory @file{slib}. + +@noindent +Then create a file @file{require.scm} in the SCM +@dfn{implementation-vicinity} (this is the same directory as where the +file @file{Init.scm} is installed). @file{require.scm} should have the +contents: + +@example +(define (library-vicinity) "/usr/local/lib/slib/") +(load (in-vicinity (library-vicinity) "require")) +@end example + +@noindent +where the pathname string @file{/usr/local/lib/slib/} is to be replaced +by the pathname into which you installed SLIB. Absolute pathnames are +recommended here; if you use a relative pathname, SLIB can get confused +when the working directory is changed (@pxref{I/O-Extensions, chmod}). +The way to specify a relative pathname is to append it to the +implementation-vicinity, which is absolute: + +@example +(define library-vicinity + (let ((lv (string-append (implementation-vicinity) "../slib/"))) + (lambda () lv))) +(load (in-vicinity (library-vicinity) "require")) +@end example + +@noindent +Alternatively, you can set the (shell) environment variable +@code{SCHEME_LIBRARY_PATH} to the pathname of the SLIB directory +(@pxref{SCM Variables, SCHEME_LIBRARY_PATH, Environment Variables}). If +set, the environment variable overrides @file{require.scm}. Again, +absolute pathnames are recommended. + + +@node Installing Dynamic Linking, Saving Images, SLIB, Installing SCM +@section Installing Dynamic Linking + +@noindent +Dynamic linking has not been ported to all platforms. Operating systems +in the BSD family (a.out binary format) can usually be ported to +@dfn{DLD}. The @dfn{dl} library (@code{#define SUN_DL} for SCM) was a +proposed POSIX standard and may be available on other machines with +@dfn{COFF} binary format. For notes about porting to MS-Windows and +finishing the port to VMS @ref{Finishing Dynamic Linking}. + +@noindent +@dfn{DLD} is a library package of C functions that performs @dfn{dynamic +link editing} on Linux, VAX (Ultrix), Sun 3 (SunOS 3.4 and 4.0), +SPARCstation (SunOS 4.0), Sequent Symmetry (Dynix), and Atari ST. It is +available from: + +@ifclear html +@itemize @bullet +@item +prep.ai.mit.edu:pub/gnu/dld-3.3.tar.gz +@end itemize +@end ifclear + +@ifset html +<A HREF="ftp://prep.ai.mit.edu/pub/gnu/dld-3.3.tar.gz"> +prep.ai.mit.edu:pub/gnu/dld-3.3.tar.gz +</A> +@end ifset + +@noindent +These notes about using libdl on SunOS are from @file{gcc.info}: + +@quotation +On a Sun, linking using GNU CC fails to find a shared library and +reports that the library doesn't exist at all. + +This happens if you are using the GNU linker, because it does only +static linking and looks only for unshared libraries. If you have +a shared library with no unshared counterpart, the GNU linker +won't find anything. + +We hope to make a linker which supports Sun shared libraries, but +please don't ask when it will be finished--we don't know. + +Sun forgot to include a static version of @file{libdl.a} with some +versions of SunOS (mainly 4.1). This results in undefined symbols when +linking static binaries (that is, if you use @samp{-static}). If you +see undefined symbols @samp{_dlclose}, @samp{_dlsym} or @samp{_dlopen} +when linking, compile and link against the file +@file{mit/util/misc/dlsym.c} from the MIT version of X windows. +@end quotation + + +@node Saving Images, Automatic C Preprocessor Definitions, Installing Dynamic Linking, Installing SCM +@section Saving Images + +@noindent +In SCM, the ability to save running program images is called @dfn{dump} +(@pxref{Dump}). In order to make @code{dump} available to SCM, build +with feature @samp{dump}. @code{dump}ed executables are compatible with +dynamic linking. + +@noindent +Most of the code for @dfn{dump} is taken from +@file{emacs-19.34/src/unex*.c}. No modifications to the emacs source +code were required to use @file{unexelf.c}. Dump has not been ported to +all platforms. If @file{unexec.c} or @file{unexelf.c} don't work for +you, try using the appropriate @file{unex*.c} file from emacs. + + + +@node Automatic C Preprocessor Definitions, Problems Compiling, Saving Images, Installing SCM +@section Automatic C Preprocessor Definitions + +These @samp{#defines} are automatically provided by preprocessors of +various C compilers. SCM uses the presence or absence of these +definitions to configure @dfn{include file} locations and aliases for +library functions. If the definition(s) corresponding to your system +type is missing as your system is configured, add @code{-D@var{flag}} to +the compilation command lines or add a @code{#define @var{flag}} line to +@file{scmfig.h} or the beginning of @file{scmfig.h}. + +@example +#define Platforms: +------- ---------- +ARM_ULIB Huw Rogers free unix library for acorn archimedes +AZTEC_C Aztec_C 5.2a +_DCC Dice C on AMIGA +__GNUC__ Gnu CC (and DJGPP) +__EMX__ Gnu C port (gcc/emx 0.8e) to OS/2 2.0 +__HIGHC__ MetaWare High C +__IBMC__ C-Set++ on OS/2 2.1 +_MSC_VER MS VisualC++ 4.2 +MWC Mark Williams C on COHERENT +_QC Microsoft QuickC +__STDC__ ANSI C compliant +__TURBOC__ Turbo C and Borland C +__WATCOMC__ Watcom C on MS-DOS +__ZTC__ Zortech C + +_AIX AIX operating system +AMIGA SAS/C 5.10 or Dice C on AMIGA +atarist ATARI-ST under Gnu CC +GNUDOS DJGPP (obsolete in version 1.08) +__GO32__ DJGPP (future?) +hpux HP-UX +linux Linux +MCH_AMIGA Aztec_c 5.2a on AMIGA +MSDOS Microsoft C 5.10 and 6.00A +__MSDOS__ Turbo C, Borland C, and DJGPP +nosve Control Data NOS/VE +SVR2 System V Revision 2. +THINK_C developement environment for the Macintosh +ultrix VAX with ULTRIX operating system. +unix most Unix and similar systems and DJGPP (!?) +__unix__ Gnu CC and DJGPP +_UNICOS Cray operating system +_Windows Borland C 3.1 compiling for Windows +_WIN32 MS VisualC++ 4.2 under Windows-NT +vms (and VMS) VAX-11 C under VMS. + +hp9000s800 HP RISC processor +__i386__ DJGPP +i386 DJGPP +MULTIMAX Encore computer +pyr Pyramid 9810 processor +sparc SPARC processor +sequent Sequent computer +tahoe CCI Tahoe processor +@end example + +@node Problems Compiling, Problems Linking, Automatic C Preprocessor Definitions, Installing SCM +@section Problems Compiling + +@table @asis +@item FILE: PROBLEM +HOW TO FIX +@item *.c: include file not found +Correct the status of STDC_HEADERS in @file{scmfig.h} + +fix #include statement or add #define for system type to +@file{scmfig.h}. +@item *.c: Function should return a value in @dots{} +@itemx *.c: Parameter '@dots{}' is never used in @dots{} +@itemx *.c: Condition is always false in @dots{} +@itemx *.c: Unreachable code in function @dots{} +Ignore. +@item scm.c: assignment between incompatible types +change SIGRETTYPE in @file{scm.c}. +@item time.c: CLK_TCK redefined +incompatablility between <stdlib.h> and <sys/types.h>. remove +STDC_HEADERS in @file{scmfig.h}. + +edit <sys/types.h> to remove incompatability. +@item subr.c: Possibly incorrect assignment in function lgcd +Ignore. +@item sys.c: statement not reached +@itemx sys.c: constant in conditional expression +ignore +@item sys.c: `???' undeclared, outside of functions +#undef STDC_HEADERS in @file{scmfig.h}. +@item scl.c: syntax error +#define SYSTNAME to your system type in @file{scl.c} (softtype) +@end table + +@node Problems Linking, Problems Running, Problems Compiling, Installing SCM +@section Problems Linking + +@table @asis +@item PROBLEM +HOW TO FIX +@item _sin etc. missing. +uncomment LIBS in makefile +@end table + +@node Problems Running, Testing, Problems Linking, Installing SCM +@section Problems Running + +@table @asis +@item PROBLEM +HOW TO FIX +@item Opening message and then machine crashes. +Change memory model option to C compiler (or makefile). + +Make sure @code{sizet} definition is correct in @file{scmfig.h}. + +Reduce size of HEAP_SEG_SIZE in @file{setjump.h}. +@item Input hangs +#define NOSETBUF +@item ERROR: heap: need larger initial +Need to increase the initial heap allocation using -a<kb> or +INIT_HEAP_SIZE. +@item ERROR: Could not allocate @dots{} +Check @code{sizet} definition. + +Use 32 bit compiler mode. + +Don't try to run as subproccess +@item remove @dots{} in scmfig.h and recompile scm +@itemx add @dots{} in scmfig.h and recompile scm +Do it and recompile files. +@item ERROR: @file{Init.scm} not found +Assign correct IMPLINIT in makefile or @file{scmfig.h} or define +environment variable @code{SCM_INIT_PATH} to be the full pathname of +@file{Init.scm} (@pxref{Installing SCM}). +@item WARNING: require.scm not found +define environment variable @code{SCHEME_LIBRARY_PATH} to be the full +pathname of the scheme library [SLIB] or change @code{library-vicinity} in +@file{Init.scm} to point to library or remove. @xref{Installation, , , slib, +SLIB}. + +Make sure the value of @code{(library-vicinity)} has a trailing file +separator (like @key{/} or @key{\}). +@end table + +@node Testing, Reporting Problems, Problems Running, Installing SCM +@section Testing + +@noindent +Loading @file{r4rstest.scm} in the distribution will run an [R4RS] +conformance test on @code{scm}. + +@example +> (load "r4rstest.scm") +@print{} +;loading "r4rstest.scm" +SECTION(2 1) +SECTION(3 4) + #<primitive-procedure boolean?> + #<primitive-procedure char?> + #<primitive-procedure null?> + #<primitive-procedure number?> +@dots{} +@end example + +@noindent +Loading @file{pi.scm} in the distribution will enable you to compute +digits of pi. + +@example +> (load "pi") +;loading "pi" +;done loading "pi.scm" +;Evaluation took 20 mSec (0 in gc) 767 cells work, 233 bytes other +#<unspecified> +> (pi 100 5) +00003 14159 26535 89793 23846 26433 83279 50288 41971 69399 +37510 58209 74944 59230 78164 06286 20899 86280 34825 34211 +70679 +;Evaluation took 550 mSec (60 in gc) 36976 cells work, 1548 bytes other +#<unspecified> +@end example + +@noindent +Loading @file{bench.scm} will compute and display performance statistics +of SCM running @file{pi.scm}. @samp{make bench} or @samp{make benchlit} +appends the performance report to the file @file{BenchLog}, facilitating +tracking effects of changes to SCM on performance. + +@table @asis +@item PROBLEM +HOW TO FIX +@item Runs some and then machine crashes. +See above under machine crashes. +@item Runs some and then ERROR: @dots{} (after a GC has happened) +Remove optimization option to C compiler and recompile. + +@code{#define SHORT_ALIGN} in @file{scmfig.h}. +@item Some symbol names print incorrectly. +Change memory model option to C compiler (or makefile). + +Check that @code{HEAP_SEG_SIZE} fits within @code{sizet}. + +Increase size of @code{HEAP_SEG_SIZE} (or @code{INIT_HEAP_SIZE} if it is +smaller than @code{HEAP_SEG_SIZE}). +@item ERROR: Rogue pointer in Heap. +See above under machine crashes. +@item Newlines don't appear correctly in output files. +Check file mode (define OPEN_@dots{} in @file{Init.scm} +@item Spaces or control characters appear in symbol names +Check character defines in @file{scmfig.h}. +@item Negative numbers turn positive. +Check SRS in @file{scmfig.h}. +@item VMS: Couldn't unwind stack +@itemx VAX: botched longjmp +@code{#define CHEAP_CONTIUATIONS} in @file{scmfig.h}. +@item Sparc(SUN-4) heap is growing out of control +You are experiencing a GC problem peculiar to the Sparc. The problem is +that SCM doesn't know how to clear register windows. Every location +which is not reused still gets marked at GC time. This causes lots of +stuff which should be collected to not be. This will be a problem with +any @emph{conservative} GC until we find what instruction will clear the +register windows. This problem is exacerbated by using lots of +call-with-current-continuations. +@end table + +@node Reporting Problems, , Testing, Installing SCM +@section Reporting Problems + +@noindent +Reported problems and solutions are grouped under Compiling, Linking, +Running, and Testing. If you don't find your problem listed there, you +can send a bug report to @code{jaffer@@ai.mit.edu}. The bug report +should include: + +@enumerate +@item +The version of SCM (printed when SCM is invoked with no arguments). +@item +The type of computer you are using. +@item +The name and version of your computer's operating system. +@item +The values of the environment variables @code{SCM_INIT_PATH} and +@code{SCHEME_LIBRARY_PATH}. +@item +The name and version of your C compiler. +@item +If you are using an executable from a distribution, the name, vendor, +and date of that distribution. In this case, corresponding with the +vendor is recommended. +@end enumerate + +@node The Language, Packages, Installing SCM, Top +@chapter The Language + +This section describes features which are either present in all builds +of SCM or which must be enabled when SCM is compiled. + +@menu +* Standards Compliance:: Links to sections in [R4RS] and [SLIB] +* System Interface:: Like how to exit +* Errors:: +* Memoized Expressions:: What #@@0+1 and #@@? mean +* Internal State:: GC, errors, and diagnostics +* Miscellaneous Procedures:: +* Time:: Both real time and processor time +* Interrupts:: and exceptions +* Process Synchronization:: Because interrupts are preemptive +* Files and Ports:: +* Soft Ports:: Emulate I/O devices +* Syntax Extensions:: and how to Define New Syntax +* Low Level Syntactic Hooks:: +@end menu + +@node Standards Compliance, System Interface, The Language, The Language +@section Standards Compliance + +@noindent +Scm conforms to the +@ifset html +[IEEE], +@end ifset +@cite{IEEE Standard 1178-1990. IEEE Standard for the Scheme Programming +Language.} +@ifclear html +(@pxref{Bibliography}), +@end ifclear +and +@ifset html +[R4RS], <A HREF="r4rs_toc.html"> +@end ifset +@cite{Revised(4) Report on the Algorithmic Language Scheme}. +@ifset html +</A> +@end ifset +@ifinfo +@ref{Top, , , r4rs, Revised(4) Report on the Algorithmic Language +Scheme}. +@end ifinfo +All the required features of these specifications are supported. +Many of the optional features are supported as well. + +@subheading Optionals of [R4RS] Supported by SCM + +@table @asis +@item two clause @code{if}: @code{(if <test> <consequent>)} +@xref{Conditionals, , , r4rs, Revised(4) Scheme}. +@item @code{let*} +@itemx named @code{let} +@xref{Binding constructs, , , r4rs, Revised(4) Scheme}. +@item @code{do} +@xref{Iteration, , , r4rs, Revised(4) Scheme}. +@item All varieties of @code{define} +@xref{Definitions, , , r4rs, Revised(4) Scheme}. +@item @code{list-tail} +@xref{Pairs and lists, , , r4rs, Revised(4) Scheme}. +@item @code{string-copy} +@itemx @code{string-fill!} +@xref{Strings, , , r4rs, Revised(4) Scheme}. +@item @code{make-vector} of two arguments +@itemx @code{vector-fill!} +@xref{Vectors, , , r4rs, Revised(4) Scheme}. +@item @code{apply} of more than 2 arguments +@xref{Control features, , , r4rs, Revised(4) Scheme}. +@item @code{-} and @code{/} of more than 2 arguments +@itemx @code{exp} +@itemx @code{log} +@itemx @code{sin} +@itemx @code{cos} +@itemx @code{tan} +@itemx @code{asin} +@itemx @code{acos} +@itemx @code{atan} +@itemx @code{sqrt} +@itemx @code{expt} +@itemx @code{make-rectangular} +@itemx @code{make-polar} +@itemx @code{real-part} +@itemx @code{imag-part} +@itemx @code{magnitude} +@itemx @code{angle} +@itemx @code{exact->inexact} +@itemx @code{inexact->exact} +@xref{Numerical operations, , , r4rs, Revised(4) Scheme}. +@item @code{delay} +@itemx @code{force} +@xref{Control features, , , r4rs, Revised(4) Scheme}. +@itemx @code{with-input-from-file} +@itemx @code{with-output-to-file} +@xref{Ports, , , r4rs, Revised(4) Scheme}. +@itemx @code{char-ready?} +@xref{Input, , , r4rs, Revised(4) Scheme}. +@itemx @code{transcript-on} +@itemx @code{transcript-off} +@xref{System interface, , , r4rs, Revised(4) Scheme}. +@end table + +@subheading Optionals of [R4RS] not Supported by SCM + +@table @asis +@item @code{numerator} +@itemx @code{denominator} +@itemx @code{rationalize} +@xref{Numerical operations, , , r4rs, Revised(4) Scheme}. +@item [R4RS] appendix Macros +@xref{Macros, , , r4rs, Revised(4) Scheme}. +@end table + +@subheading [SLIB] Features of SCM and SCMLIT + +@table @code +@item delay +@itemx full-continuation +@itemx ieee-p1178 +@itemx object-hash +@itemx rev4-report +@itemx source +See SLIB file @file{Template.scm}. +@item current-time +@xref{Time, , , slib, SLIB}. +@item defmacro +@xref{Defmacro, , , slib, SLIB}. +@item dynamic-wind +@xref{Dynamic-Wind, , , slib, SLIB}. +@item eval +@xref{System, , , slib, SLIB}. +@item getenv +@itemx system +@xref{System Interface, , , slib, SLIB}. +@item hash +@xref{Hashing, , , slib, SLIB}. +@item logical +@xref{Bit-Twiddling, , , slib, SLIB}. +@item multiarg-apply +@xref{Multi-argument Apply, , , slib, SLIB}. +@item multiarg/and- +@xref{Multi-argument / and -, , , slib, SLIB}. +@item rev4-optional-procedures +@xref{Rev4 Optional Procedures, , , slib, SLIB}. +@item string-port +@xref{String Ports, , , slib, SLIB}. +@item tmpnam +@xref{Input/Output, , , slib, SLIB}. +@item transcript +@xref{Transcripts, , , slib, SLIB}. +@item vicinity +@xref{Vicinity, , , slib, SLIB}. +@item with-file +@xref{With-File, , , slib, SLIB}. +@end table + +@subheading [SLIB] Features of SCM + +@table @code +@item array +@xref{Arrays, , , slib, SLIB}. +@item array-for-each +@xref{Array Mapping, , , slib, SLIB}. +@item bignum +@itemx complex +@itemx inexact +@itemx rational +@itemx real +@xref{Require, , , slib, SLIB}. +@end table + +@node System Interface, Errors, Standards Compliance, The Language +@section System Interface + +@noindent +For documentation of the procedures @code{getenv} and @code{system} +@xref{System Interface, , , slib, SLIB}. + +@defun quit +@defunx quit n +@defunx exit +@defunx exit n +Aliases for @code{exit} (@pxref{System, exit, , slib, SLIB}). On many +systems, SCM can also tail-call another program. @xref{I/O-Extensions, +execp}. +@end defun + +@defun vms-debug +If SCM is compiled under VMS these commands will invoke the editor or +debugger respectively. +@end defun + +@defun ed filename +If SCM is compiled under VMS @code{ed} will invoke the editor with a +single the single argument @var{filename}. + +@defunx ed arg1 @dots{} +Otherwise, the value of the environment variable @code{EDITOR} (or just +@code{ed} if it isn't defined) is invoked as a command with arguments +@var{arg1} @dots{}. +@end defun + +@defun program-arguments +Returns a list of strings of the arguments scm was called with. +@end defun + +@defun errno +@defunx errno n +With no argument returns the current value of the system variable +@code{errno}. When given an argument, @code{errno} sets the system +variable @code{errno} to @var{n} and returns the previous value of +@code{errno}. @code{(errno 0)} will clear outstanding errors. This is +recommended after @code{try-load} returns @code{#f} since this occurs +when the file could not be opened. +@end defun + +@defun perror string +Prints on standard error output the argument @var{string}, a colon, +followed by a space, the error message corresponding to the current +value of @code{errno} and a newline. The value returned is unspecified. +@end defun + +@node Errors, Memoized Expressions, System Interface, The Language +@section Errors + +@noindent +A computer-language implementation designer faces choices of how +reflexive to make the implementation in handling exceptions and errors; +that is, how much of the error and exception routines should be written +in the language itself. The design of a portable implementation is +further constrained by the need to have (almost) all errors print +meaningful messages, even when the implementation itself is not +functioning correctly. Therefore, SCM implements much of its error +response code in C. + +@noindent +The following common error and conditions are handled by C code. Those +with callback names after them can also be handled by Scheme code +(@pxref{Interrupts}). If the callback identifier is not defined at top +level, the default error handler (C code) is invoked. There are many +other error messages which are not treated specially. + +@enumerate 0 +@item +Wrong type in arg 0 +@item +Wrong type in arg 1 +@item +Wrong type in arg 2 +@item +Wrong type in arg 3 +@item +Wrong type in arg 4 +@item +Wrong type in arg 5 +@item +Wrong number of args +@item +numerical overflow +@item +Argument out of range +@item +Could not allocate @code{(out-of-storage)} +@item +EXIT @code{(end-of-program)} +@item +hang up @code{(hang-up)} +@item +user interrupt @code{(user-interrupt)} +@item +arithmetic error @code{(arithmetic-error)} +@item +bus error +@item +segment violation +@item +alarm @code{(alarm-interrupt)} +@end enumerate + +@defvar errobj +If SCM encounters a non-fatal error it aborts evaluation of the current +form, prints a message explaining the error, and resumes the top level +read-eval-print loop. The value of @var{errobj} is the offending object +if appropriate. The builtin procedure @code{error} does @emph{not} set +@var{errobj}. +@end defvar + +@defun error arg1 arg2 arg3 @dots{} +Alias for @ref{System, error, , slib, SLIB}. Outputs an error message +containing the arguments, aborts evaluation of the current form and +resumes the top level read-eval-print loop. Error is defined in +@file{Init.scm}; Feel free to redefine it to suit your purposes. +@end defun + +@subsection CAUTIOUS enhancements + +@noindent +If SCM is built with the @samp{CAUTIOUS} flag, then when an error +occurs, a @dfn{stack trace} of certain pending calls are printed as part +of the default error response. A (memoized) expression and newline are +printed for each partially evaluated combination whose procedure is not +builtin. @xref{Memoized Expressions} for how to read memoized +expressions. + +@noindent +Also as the result of the @samp{CAUTIOUS} flag, both @code{error} and +@code{user-interrupt} (invoked by @key{C-c}) are defined to print stack +traces and conclude by calling @code{breakpoint} (@pxref{Breakpoints, , +, slib, SLIB}). This allows the user to interract with SCM as with Lisp +systems. + +@defun stack-trace +Prints information describing the stack of partially evaluated +expressions. @code{stack-trace} returns @code{#t} if any lines were +printed and @code{#f} otherwise. See @file{Init.scm} for an example of +the use of @code{stack-trace}. +@end defun + +@node Memoized Expressions, Internal State, Errors, The Language +@section Memoized Expressions + +@noindent +SCM memoizes the address of each occurence of an identifier's value when +first encountering it in a source expression. Subsequent executions of +that memoized expression is faster because the memoized reference +encodes where in the top-level or local environment its value is. + +@noindent +When procedures are displayed, the memoized locations appear in a format +different from references which have not yet been executed. I find this +a convenient aid to locating bugs and untested expressions. + +@itemize @bullet +@item +The names of memoized lexically bound identifiers are replaced with +@r{#@@}@i{<m>}@r{-}@i{<n>}, where @i{<m>} is the number of binding +contours back and @i{<n>} is the index of the value in that +binding countour. +@item +The names of identifiers which are not lexiallly bound but defined at +top-level have @r{#@@} prepended. +@end itemize + +@noindent +For instance, @code{open-input-file} is defined as follows in +@file{Init.scm}: + +@example +(define (open-input-file str) + (or (open-file str OPEN_READ) + (and (procedure? could-not-open) (could-not-open) #f) + (error "OPEN-INPUT-FILE couldn't open file " str))) +@end example + +@noindent +If @code{open-input-file} has not yet been used, the displayed procedure +is similar to the original definition (lines wrapped for readability): + +@example +open-input-file @result{} +#<CLOSURE (str) (or (open-file str open_read) + (and (procedure? could-not-open) (could-not-open) #f) + (error "OPEN-INPUT-FILE couldn't open file " str))> +@end example + +@noindent +If we open a file using @code{open-input-file}, the sections of code +used become memoized: + +@example +(open-input-file "r4rstest.scm") @result{} #<input-port 3> +open-input-file @result{} +#<CLOSURE (str) (#@@or (#@@open-file #@@0+0 #@@open_read) + (and (procedure? could-not-open) (could-not-open) #f) + (error "OPEN-INPUT-FILE couldn't open file " str))> +@end example + +@noindent +If we cause @code{open-input-file} to execute other sections of code, +they too become memoized: + +@example +(open-input-file "foo.scm") @result{} + +ERROR: No such file or directory +ERROR: OPEN-INPUT-FILE couldn't open file "foo.scm" + +open-input-file @result{} +#<CLOSURE (str) (#@@or (#@@open-file #@@0+0 #@@open_read) + (#@@and (#@@procedure? #@@could-not-open) (could-not-open) #f) + (#@@error "OPEN-INPUT-FILE couldn't open file " #@@0+0))> +@end example + + +@node Internal State, Miscellaneous Procedures, Memoized Expressions, The Language +@section Internal State + +@defvar *interactive* +The variable @var{*interactive*} determines whether the SCM session is +interactive, or should quit after the command line is processed. +@var{*interactive*} is controlled directly by the command-line options +@samp{-b}, @samp{-i}, and @samp{-s} (@pxref{Invoking SCM}). If none of +these options are specified, the rules to determine interactivity are +more complicated; see @file{Init.scm} for details. +@end defvar + +@defun abort +Resumes the top level Read-Eval-Print loop. +@end defun + +@defun restart +Restarts the SCM program with the same arguments as it was originally +invoked. All @samp{-l} loaded files are loaded again; If those files +have changed, those changes will be reflected in the new session. + +@emph{Note:} When running a saved executable (@pxref{Dump}), +@code{restart} is redefined to be @code{exec-self}. +@end defun + +@defun exec-self +Exits and immediately re-invokes the same executable with the same +arguments. If the executable file has been changed or replaced since +the beginning of the current session, the @emph{new} executable will be +invoked. This differentiates @code{exec-self} from @code{restart}. +@end defun + +@defun verbose n +Controls how much monitoring information is printed. +If @var{n} is: + +@table @asis +@item 0 +no prompt or information is printed. +@item >= 1 +a prompt is printed. +@item >= 2 +the CPU time is printed after each top level form evaluated. +@item >= 3 +messages about heap growth are printed. +@item >= 4 +garbage collection (@pxref{Garbage Collection}) messages are printed. +@item >= 5 +a warning will be printed for each top-level symbol which is defined +more than one time. +@end table +@end defun + +@defun gc +Scans all of SCM objects and reclaims for further use those that are +no longer accessible. +@end defun + +@defun room +@defunx room #t +Prints out statistics about SCM's current use of storage. @code{(room #t)} +also gives the hexadecimal heap segment and stack bounds. +@end defun + +@defvr Constant *scm-version* +Contains the version string (e.g. @file{4e6}) of SCM. +@end defvr + +@noindent +For other configuration constants and procedures @xref{Configuration, , +, slib, SLIB}. + +@node Miscellaneous Procedures, Time, Internal State, The Language +@section Miscellaneous Procedures + +@defun try-load filename +If the string @var{filename} names an existing file, the try-load +procedure reads Scheme source code expressions and definitions from the +file and evaluates them sequentially and returns @code{#t}. If not, +try-load returns @code{#f}. The try-load procedure does not affect the +values returned by @code{current-input-port} and +@code{current-output-port}. +@end defun + +@defvar *load-pathname* +Is set to the pathname given as argument to @code{load}, +@code{try-load}, and @code{dyn:link} (@pxref{Compiling And Linking}). +@code{*load-pathname*} is used to compute the value of @ref{Vicinity, +program-vicinity, , slib, SLIB}. +@end defvar + +@defun line-number +Returns the current line number of the file currently being loaded. +@end defun + +@defun eval obj +Alias for @ref{System, eval, , slib, SLIB}. +@end defun + +@defun eval-string str +Returns the result of reading an expression from @var{str} and +evaluating it. @code{eval-string} does not change +@code{*load-pathname*} or @code{line-number}. +@end defun + +@defun load-string str +Reads and evaluates all the expressions from @var{str}. As with +@code{load}, the value returned is unspecified. @code{eval-string} does +not change @code{*load-pathname*} or @code{line-number}. +@end defun + +@defun vector-set-length! object length +Change the length of string, vector, bit-vector, or uniform-array +@var{object} to @var{length}. If this shortens @var{object} then the +remaining contents are lost. If it enlarges @var{object} then the +contents of the extended part are undefined but the original part is +unchanged. It is an error to change the length of literal datums. The +new object is returned. +@end defun + +@defun copy-tree obj +@xref{Tree Operations, copy-tree, , slib, SLIB}. This extends the SLIB +version by also copying vectors. +@end defun + +@defun acons obj1 obj2 obj3 +Returns (cons (cons obj1 obj2) obj3). The expression (set! a-list +(acons key datum a-list)) adds a new association to a-list. +@end defun + +@defun terms +This command displays the GNU General Public License. +@end defun + +@defun list-file filename +Displays the text contents of @var{filename}. +@end defun + +@deffn Procedure print arg1 ... +@code{Print} writes all its arguments, separated by spaces. +@code{Print} outputs a @code{newline} at the end and returns the value +of the last argument. +@end deffn + +@node Time, Interrupts, Miscellaneous Procedures, The Language +@section Time + +@defvr Constant internal-time-units-per-second + +Is the integer number of internal time units in a second. +@end defvr + +@defun get-internal-run-time +Returns the integer run time in internal time units from an unspecified +starting time. The difference of two calls to +@code{get-internal-run-time} divided by +@code{internal-time-units-per-second} will give elapsed run time in +seconds. +@end defun + +@defun get-internal-real-time +Returns the integer time in internal time units from an unspecified +starting time. The difference of two calls to +@code{get-internal-real-time} divided by +@code{interal-time-units-per-second} will give elapsed real time in +seconds. +@end defun + +@defun current-time +Returns the time since 00:00:00 GMT, January 1, 1970, measured in +seconds. @xref{Time, current-time, , slib, SLIB}. @code{current-time} is +used in @ref{Time, , , slib, SLIB}. +@end defun + +@node Interrupts, Process Synchronization, Time, The Language +@section Interrupts + +@defun ticks n +Returns the number of ticks remaining till the next tick interrupt. +Ticks are an arbitrary unit of evaluation. Ticks can vary greatly in +the amount of time they represent. + +If @var{n} is 0, any ticks request is canceled. Otherwise a +@code{ticks-interrupt} will be signaled @var{n} from the current time. +@code{ticks} is supported if SCM is compiled with the @code{ticks} flag +defined. +@end defun + +@deffn {Callback procedure} ticks-interrupt @dots{} +Establishes a response for tick interrupts. Another tick interrupt will +not occur unless @code{ticks} is called again. Program execution will +resume if the handler returns. This procedure should (abort) or some +other action which does not return if it does not want processing to +continue. +@end deffn + +@defun alarm secs +Returns the number of seconds remaining till the next alarm interrupt. +If @var{secs} is 0, any alarm request is canceled. Otherwise an +@code{alarm-interrupt} will be signaled @var{secs} from the current +time. ALARM is not supported on all systems. +@end defun + +@deffn {Callback procedure} user-interrupt @dots{} +@deffnx {Callback procedure} alarm-interrupt @dots{} +Establishes a response for @code{SIGINT} (control-C interrupt) and +@code{SIGALRM} interrupts. Program execution will resume if the handler +returns. This procedure should @code{(abort)} or some other action +which does not return if it does not want processing to continue after +it returns. + +Interrupt handlers are disabled during execution @code{system} and +@code{ed} procedures. + +To unestablish a response for an interrupt set the handler symbol to +@code{#f}. For instance, @code{(set! user-interrupt #f)}. +@end deffn + +@deffn {Callback procedure} out-of-storage @dots{} +@deffnx {Callback procedure} could-not-open @dots{} +@deffnx {Callback procedure} end-of-program @dots{} +@deffnx {Callback procedure} hang-up @dots{} +@deffnx {Callback procedure} arithmetic-error @dots{} +Establishes a response for storage allocation error, file opening +error, end of program, SIGHUP (hang up interrupt) and arithmetic +errors respectively. This procedure should (abort) or some other +action which does not return if it does not want the default error +message to also be displayed. If no procedure is defined for @var{hang-up} +then @var{end-of-program} (if defined) will be called. + +To unestablish a response for an error set the handler symbol to +@code{#f}. For instance, @code{(set! could-not-open #f)}. +@end deffn + +@node Process Synchronization, Files and Ports, Interrupts, The Language +@section Process Synchronization + +@defun make-arbiter name + +Returns an object of type arbiter and name @var{name}. Its state is +initially unlocked. +@end defun + +@defun try-arbiter arbiter + +Returns @code{#t} and locks @var{arbiter} if @var{arbiter} was unlocked. +Otherwise, returns @code{#f}. +@end defun + +@defun release-arbiter arbiter + +Returns @code{#t} and unlocks @var{arbiter} if @var{arbiter} was locked. +Otherwise, returns @code{#f}. +@end defun + +@node Files and Ports, Soft Ports, Process Synchronization, The Language +@section Files and Ports + +@noindent +These procedures generalize and extend the standard capabilities in +@ref{Ports, , ,r4rs, Revised(4) Scheme}. + +@defun open-file string modes +Returns a port capable of receiving or delivering characters as +specified by the @var{modes} string. If a file cannot be opened +@code{#f} is returned. +@end defun + +@defvr Constant open_read +@defvrx Constant open_write +@defvrx Constant open_both +Contain modes strings specifying that a file is to be opened for +reading, writing, and both reading and writing respectively. +@end defvr + +@defun _ionbf modestr +Returns a version of modestr which when open-file is called with it as +the second argument will return an unbuffered port. A non-file +input-port must be unbuffered in order for char-ready? to work correctly +on it. The initial value of (current-input-port) is unbuffered if the +platform supports it. +@end defun + +@defun close-port port +Closes @var{port}. The same as close-input-port and close-output-port. +@end defun + +@defun open-io-file filename +@defunx close-io-port port +These functions are analogous to the standard scheme file functions. +The ports are open to @var{filename} in read/write mode. Both input and +output functions can be used with io-ports. An end of file must be read +or a file-set-position done on the port between a read operation and a +write operation or vice-versa. +@end defun + +@defun current-error-port +Returns the current port to which diagnostic output is directed. +@end defun + +@defun with-error-to-file string thunk +@var{thunk} must be a procedure of no arguments, and string must be a +string naming a file. The file is opened for output, an output port +connected to it is made the default value returned by +current-error-port, and the @var{thunk} is called with no arguments. When +the thunk returns, the port is closed and the previous default is +restored. With-error-to-file returns the value yielded by @var{thunk}. +@end defun + +@defun with-input-from-port port thunk +@defunx with-output-to-port port thunk +@defunx with-error-to-port port thunk +These routines differ from with-input-from-file, with-output-to-file, +and with-error-to-file in that the first argument is a port, rather +than a string naming a file. +@end defun + +@deffn {procedure} char-ready? +@deffnx {procedure} char-ready? port + +Returns @code{#t} if a character is ready on the input @var{port} and +returns @code{#f} otherwise. If @code{char-ready?} returns @code{#t} +then +@findex char-ready +the next @code{read-char} operation on the given @var{port} is +guaranteed +@findex read-char +not to hang. If the @var{port} is at end of file then +@code{char-ready?} returns @code{#t}. +@findex char-ready? +@var{Port} may be omitted, in which case it defaults to +the value returned by @code{current-input-port}. +@findex current-input-port + +@emph{Rationale:} @code{Char-ready?} exists to make it possible for a program to +@findex char-ready? +accept characters from interactive ports without getting stuck waiting +for input. Any input editors associated with such ports must ensure +that characters whose existence has been asserted by @code{char-ready?} +@findex char-ready? +cannot be rubbed out. If @code{char-ready?} were to return @code{#f} at +end of file, a port at end of file would be indistinguishable from an +interactive port that has no ready characters. +@c end rationale +@end deffn + + +@node Soft Ports, Syntax Extensions, Files and Ports, The Language +@section Soft Ports + +@noindent +A @dfn{soft-port} is a port based on a vector of procedures capable of +accepting or delivering characters. It allows emulation of I/O ports. + +@defun make-soft-port vector modes +Returns a port capable of receiving or delivering characters as +specified by the @var{modes} string (@pxref{Files and Ports, +open-file}). @var{vector} must be a vector of length 6. Its components +are as follows: + +@enumerate 0 +@item +procedure accepting one character for output +@item +procedure accepting a string for output +@item +thunk for flushing output +@item +thunk for getting one character +@item +thunk for closing port (not by garbage collection) +@end enumerate + +For an output-only port only elements 0, 1, 2, and 4 need be +procedures. For an input-only port only elements 3 and 4 need be +procedures. Thunks 2 and 4 can instead be @code{#f} if there is no useful +operation for them to perform. + +If thunk 3 returns @code{#f} or an @code{eof-object} (@pxref{Input, +eof-object?, ,r4rs, Revised(4) Scheme}) it indicates that the port has +reached end-of-file. For example: + +@example +(define stdout (current-output-port)) +(define p (make-soft-port + (vector + (lambda (c) (write c stdout)) + (lambda (s) (display s stdout)) + (lambda () (display "." stdout)) + (lambda () (char-upcase (read-char))) + (lambda () (display "@@" stdout))) + "rw")) + +(write p p) @result{} #<input-output-soft#\space45d10#\> +@end example +@end defun + +@node Syntax Extensions, Low Level Syntactic Hooks, Soft Ports, The Language +@section Syntax Extensions + +@deffn {Read syntax} #. expression +Is read as the object resulting from the evaluation of @var{expression}. +This substitution occurs even inside quoted structure. + +In order to allow compiled code to work with @code{#.} it is good +practice to define those symbols used inside of @var{expression} with +@code{#.(define @dots{})}. For example: + +@example +#.(define foo 9) @result{} #<unspecified> +'(#.foo #.(+ foo foo)) @result{} (9 18) +@end example +@end deffn + +@deffn {Read syntax} #+ feature form +If feature is @code{provided?} (by @code{*features*}) then @var{form} is +read as a scheme expression. If not, then @var{form} is treated as +whitespace. + +Feature is a boolean expression composed of symbols and @code{and}, +@code{or}, and @code{not} of boolean expressions. + +For more information on @code{provided?} and @code{*features*}, +@xref{Require, , , slib, SLIB}. +@end deffn + +@deffn {Read syntax} #- feature form +is equivalent to @code{#+(not feature) expression}. +@end deffn + +@deffn {Read syntax} #' form +is equivalent to @var{form} (for compatibility with common-lisp). +@end deffn + +@deffn {Read syntax} #| any thing |# +Is a balanced comment. Everything up to the matching @code{|#} is +ignored by the @code{read}. Nested @code{#|@dots{}|#} can occur inside +@var{any thing}. +@end deffn + +@deffn {Read syntax} #! any thing +On the first line of a file will be ignored when loaded by SCM. This +makes SCM files usable as POSIX shell scripts if the first line is: + +@example +#!/usr/local/bin/scm +@end example + +When such a file is invoked it executes /usr/local/bin/scm with the +name of this file as the first argument. The following shell script +will print factorial of its argument: +@example +#!/usr/local/bin/scm +;;; -*-scheme-*- tells emacs this is a scheme file. +(define (fact n) (if (< n 2) 1 (* n (fact (+ -1 n))))) +(display (fact (string->number (caddr (program-arguments))))) +(newline) +(quit) +@end example + +This technique has some drawbacks: +@itemize @bullet +@item +Some Unixes limit the length of the @samp{#!} interpreter line to the +size of an object file header, which can be as small as 32 bytes. +@item +A full, explicit pathname must be specified, perhaps requiring more than +32 bytes and making scripts vulnerable to programs being moved. +@end itemize + +The following approach solves both problems -- at the expense of +slightly slower startup. @code{type;} should appear on every line to be +executed by the shell. These lines do not have the length restriction +mentioned above. Also, @code{/bin/sh} searches the directories listed +in the `PATH' environment variable for @samp{scm}, eliminating the need +to know absolute locations in order to invoke a program. +@example +#!/bin/sh +type;exec scm $0 $* +;;; -*-scheme-*- tells emacs this is a scheme file. +(define (fact n) (if (< n 2) 1 (* n (fact (+ -1 n))))) +(display (fact (string->number (caddr (program-arguments))))) +(newline) +(quit) +@end example +@end deffn + +@defspec defined? symbol +Equivalent to @code{#t} if @var{symbol} is a syntactic keyword (such as +@code{if}) or a symbol with a value in the top level environment +(@pxref{Variables and regions, , ,r4rs, Revised(4) Scheme}). Otherwise +equivalent to @code{#f}. +@end defspec + +@defspec defvar identifier initial-value +If @var{identifier} is unbound in the top level environment, then +@var{identifier} is @code{define}d to the result of evaluating the form +@var{initial-value} as if the @code{defvar} form were instead the form +@code{(define identifier initial-value)} . If @var{identifier} already +has a value, then @var{initial-value} is @emph{not} evaluated and +@var{identifier}'s value is not changed. +@end defspec + +@noindent +SCM also supports the following constructs from Common Lisp: +@code{defmacro}, @code{macroexpand}, @code{macroexpand-1}, and +@code{gentemp}. @xref{Defmacro, , , slib, SLIB}. + + +@node Low Level Syntactic Hooks, , Syntax Extensions, The Language +@section Low Level Syntactic Hooks + +@deffn {Callback procedure} read:sharp c port +If a @key{#} followed by a character (for a non-standard syntax) is +encountered by @code{read}, @code{read} will call the value of the +symbol @code{read:sharp} with arguments the character and the port being +read from. The value returned by this function will be the value of +@code{read} for this expression unless the function returns +@code{#<unspecified>} in which case the expression will be treated as +whitespace. @code{#<unspecified>} is the value returned by the +expression @code{(if #f #f)}. + +@emph{Note:} When adding new @key{#} syntaxes, have your code save the +previous value of @code{read:sharp} when defining it. Call this saved +value if an invocation's syntax is not recognized. This will allow +@code{#+}, @code{#-}, @code{#!}, and @ref{Uniform Array}s to still be +supported (as they use @code{read:sharp}). +@end deffn + +@defun procedure->syntax proc +Returns a @dfn{macro} which, when a symbol defined to this value appears +as the first symbol in an expression, returns the result of applying +@var{proc} to the expression and the environment. +@end defun + +@defun procedure->macro proc +@defunx procedure->memoizing-macro proc +Returns a @dfn{macro} which, when a symbol defined to this value appears +as the first symbol in an expression, evaluates the result of applying +@var{proc} to the expression and the environment. The value returned +from @var{proc} which has been passed to +@code{PROCEDURE->MEMOIZING-MACRO} replaces the form passed to +@var{proc}. For example: + +@example +(define trace + (procedure->macro + (lambda (x env) `(set! ,(cadr x) (tracef ,(cadr x) ',(cadr x)))))) + +(trace @i{foo}) @equiv{} (set! @i{foo} (tracef @i{foo} '@i{foo})). +@end example + +An @dfn{environment} is a list of @dfn{environment frames}. There are 2 +types of environment frames: + +@table @code +@item ((lambda (variable1 @dots{}) @dots{}) value1 @dots{}) +@itemx (let ((variable1 value1) (variable2 value2) @dots{}) @dots{}) +@itemx (letrec ((variable1 value1) @dots{}) @dots{}) +result in a single enviroment frame: +@example +((variable1 @dots{}) value1 @dots{}) +@end example + +@item (let ((variable1 value1)) @dots{}) +@itemx (let* ((variable1 value1) @dots{}) @dots{}) +result in an environment frame for each variable: +@example +(variable1 . value1) (variable2 . value2) @dots{} +@end example +@end table +@end defun + +@defspec @@apply procedure argument-list +Returns the result of applying procedure to argument-list. (apply +procedure argument-list) will produce the same result. +@end defspec + +@defspec @@call-with-current-continuation procedure) +Returns the result of applying @var{procedure} to the current +continuation. A @dfn{continuation} is a SCM object of type +@code{contin} (@pxref{Continuations}). The procedure +@code{(call-with-current-continuation @var{procedure})} is defined to +have the same effect as @code{(@@call-with-current-continuation +procedure)}. +@end defspec + + +@node Packages, The Implementation, The Language, Top +@chapter Packages + +@menu +* Executable path:: +* Compiling And Linking:: Hobbit and Dynamic Linking +* Dynamic Linking:: +* Dump:: Create Fast-Booting Executables +* Numeric:: Numeric Language Extensions +* Arrays:: As in APL +* I/O-Extensions:: 'i/o-extensions +* Posix Extensions:: 'posix +* Regular Expression Pattern Matching:: 'regex +* Line Editing:: 'edit-line +* Curses:: Screen Control +* Sockets:: Cruise the Net +@end menu + +@node Executable path, Compiling And Linking, Packages, Packages +@section Executable path + +In order to dump a saved executable or to dynamically-link using DLD, +SCM must know where its executable file is. Sometimes SCM +(@pxref{Executable Pathname}) guesses incorrectly the location of the +currently running executable. In that case, the correct path can be set +by calling @code{execpath} with the pathname. + +@defun execpath +Returns the path (string) which SCM uses to find the executable file +whose invocation the currently running session is, or #f if the path is +not set. +@defunx execpath #f +@defunx execpath newpath +Sets the path to @code{#f} or @var{newpath}, respectively. The old path +is returned. +@end defun + +@node Compiling And Linking, Dynamic Linking, Executable path, Packages +@section Compiling And Linking + +@defun compile-file name1 name2 @dots{} +If the HOBBIT compiler is installed in the +@code{(implementation-vicinity)}, compiles the files @var{name1} +@var{name2} @dots{} to an object file name @var{name1}<object-suffix>, +where <object-suffix> is the object file suffix for your computer (for +instance, @file{.o}). @var{name1} must be in the current directory; +@var{name2} @dots{} can be in other directories. +@end defun + +@defun link-named-scm name module1 @dots{} +Creates a new SCM executable with name @var{name}. @var{name} will +include the object modules @var{module1} @dots{} which can be produced +with @code{compile-file}. + +@example +cd ~/scm/ +scm -e'(link-named-scm"cute""cube")' +(delete-file "scmflags.h") +(call-with-output-file + "scmflags.h" + (lambda (fp) + (for-each + (lambda (string) (write-line string fp)) + '("#define IMPLINIT \"/home/jaffer/scm/Init.scm\"" + "#define COMPILED_INITS init_cube();" + "#define BIGNUMS" + "#define FLOATS" + "#define ARRAYS")))) +(system "gcc -Wall -O2 -c continue.c findexec.c time.c + repl.c scl.c eval.c sys.c subr.c unif.c rope.c scm.c") +@dots{} +scm.c: In function `scm_init_extensions': +scm.c:95: warning: implicit declaration of function `init_cube' +scm.c: In function `scm_cat_path': +scm.c:589: warning: implicit declaration of function `realloc' +scm.c:594: warning: implicit declaration of function `malloc' +scm.c: In function `scm_try_path': +scm.c:612: warning: implicit declaration of function `free' +(system "cc -o cute continue.o findexec.o time.o repl.o scl.o + eval.o sys.o subr.o unif.o rope.o scm.o cube.o -lm -lc") + +Compilation finished at Sun Jul 21 00:59:17 +@end example +@end defun + +@node Dynamic Linking, Dump, Compiling And Linking, Packages +@section Dynamic Linking + +@noindent +If SCM has been compiled with @file{dynl.c} then the additional +properties of load and require (from [SLIB]) specified here are +supported. The @code{require} forms are preferred. The variable +@code{*catalog*} can be extended to define other @code{require}-able +packages. See @file{Link.scm} for details. + +@defun load filename lib1 @dots{} +In addition to the [R4RS] requirement of loading Scheme expressions if +@var{filename} is a Scheme source file, @code{load} will also +dynamically load/link object files (produced by @code{compile-file}, for +instance). The object-suffix need not be given to load. For example, + +@example +(load (in-vicinity (implementation-vicinity) "sc2")) +or (load (in-vicinity (implementation-vicinity) "sc2.o")) +or (require 'rev2-procedures) +or (require 'rev3-procedures) +@end example + +will load/link @file{sc2.o} if it exists. + +The @var{lib1} @dots{} pathnames are for additional libraries which may be +needed for object files not produced by the Hobbit compiler. For +instance, crs is linked on Linux by + +@example +(load (in-vicinity (implementation-vicinity) "crs.o") + (usr:lib "ncurses") (usr:lib "c")) +or (require 'curses) +@end example + +Turtlegr graphics library is linked by: + +@example +(load (in-vicinity (implementation-vicinity) "turtlegr") + (usr:lib "X11") (usr:lib "c") (usr:lib "m")) +or (require 'turtle-graphics) +@end example + +And the string regular expression (@pxref{Regular Expression Pattern +Matching}) package is linked by: + +@example +(load (in-vicinity (implementation-vicinity) "rgx") (usr:lib "c")) +@end example +or +@example +(require 'regex) +@end example +@end defun + +@defun require 'db +@defunx require 'wb +Either form will dynamically load the WB database system from the +wb:vicinity (@file{../wb/}) specified in @file{Link.scm}. See +@file{scm/ANNOUNCE} for ftp sites where WB is available. +@end defun + +@noindent +The following functions comprise the low-level Scheme interface to +dynamic linking. See the file @file{Link.scm} in the SCM distribution +for an example of their use. + +@defun dyn:link filename +@var{filename} should be a string naming an @dfn{object} or +@dfn{archive} file, the result of C-compiling. The @code{dyn:link} +procedure links and loads @var{filename} into the current SCM session. +If successfull, @code{dyn:link} returns a @dfn{link-token} suitable for +passing as the second argument to @code{dyn:call}. If not successful, +@code{#f} is returned. +@end defun + +@defun dyn:call name link-token +@var{link-token} should be the value returned by a call to +@code{dyn:link}. @var{name} should be the name of C function of no +arguments defined in the file named @var{filename} which was succesfully +@code{dyn:link}ed in the current SCM session. The @code{dyn:call} +procedure calls the C function corresponding to @var{name}. If +successful, @code{dyn:call} returns @code{#t}; If not successful, +@code{#f} is returned. + +@code{dyn:call} is used to call the @dfn{init_@dots{}} function after +loading SCM object files. The init_@dots{} function then makes the +identifiers defined in the file accessible as Scheme procedures. +@end defun + +@defun dyn:main-call name link-token arg1 @dots{} +@var{link-token} should be the value returned by a call to +@code{dyn:link}. @var{name} should be the name of C function of 2 +arguments, @code{(int argc, char **argv)}, defined in the file named +@var{filename} which was succesfully @code{dyn:link}ed in the current +SCM session. The @code{dyn:main-call} procedure calls the C function +corresponding to @var{name} with @code{argv} style arguments, such as +are given to C @code{main} functions. If successful, +@code{dyn:main-call} returns the integer returned from the call to +@var{name}. + +@code{dyn:main-call} can be used to call a @code{main} procedure from +SCM. For example, I link in and @code{dyn:main-call} a large C program, +the low level routines of which callback (@pxref{Callbacks}) into SCM +(which emulates PCI hardware). +@end defun + +@defun dyn:unlink link-token +@var{link-token} should be the value returned by a call to +@code{dyn:link}. The @code{dyn:unlink} procedure removes the previously +loaded file from the current SCM session. If successful, +@code{dyn:unlink} returns @code{#t}; If not successful, @code{#f} is +returned. +@end defun + +@defun usr:lib lib +Returns the pathname of the C library named lib. For example: +@code{(usr:lib "m")} could return @code{"/usr/lib/libm.a"}, the path of +the C math library. +@end defun + +@node Dump, Numeric, Dynamic Linking, Packages +@section Dump + +@dfn{Dump}, (also known as @dfn{unexec}), saves the continuation of an +entire SCM session to an executable file, which can then be invoked as a +program. Dumped executables start very quickly, since no Scheme code +has to be loaded. + +@noindent +There are constraints on which sessions are savable using @code{dump} + +@itemize @bullet +@item +Saved continuations are invalid in subsequent invocations; they cause +segmentation faults and other unpleasant side effects. +@item +Although DLD (@pxref{Dynamic Linking}) can be used to load compiled +modules both before and after dumping, @samp{SUN_DL} ELF systems can +load compiled modules only after dumping. This can be worked around by +compiling in those features you wish to @code{dump}. +@item +Ports (other than @code{current-input-port}, @code{current-output-port}, +@code{current-error-port}), X windows, etc. are invalid in subsequent +invocations. + +This restriction could be removed; @xref{Improvements To Make}. +@item +@code{Dump} should only be called from a loading file when the call to +dump is the last expression in that file. +@item +@code{Dump} can be called from the command line. +@end itemize + +@defun dump newpath +@defunx dump newpath #f +@defunx dump newpath #t +@defunx dump newpath thunk +@itemize @bullet +@item +Calls @code{gc}. +@item +Creates an executable program named @var{newpath} which continues the +state of the current SCM session when invoked. The optional argument +@var{thunk}, if provided, should be a procedure of no arguments. This +procedure will be called in the restored executable. + +If the optional argument is missing or a boolean, SCM's standard command +line processing will be called in the restored executable. + +If the second argument to @code{dump} is @code{#t}, argument processing +will continue from the command line passed to the dumping session. If +the second argument is missing or @code{#f} then the command line +arguments of the restoring invocation will be processed. +@item +Resumes the top level Read-Eval-Print loop. This is done instead of +continuing normally to avoid creating a saved continuation in the dumped +executable. +@end itemize + +@code{dump} may set the values of @code{boot-tail}, @code{*argv*}, +@code{restart}, and @var{*interactive*}. @code{dump} returns an +unspecified value. +@end defun + +When a dumped executable is invoked, the variable @var{*interactive*} +(@pxref{System Interface}) has the value it possessed when @code{dump} +created it. Calling @code{dump} with a single argument sets +@var{*interactive*} to @code{#f}, which is the state it has at the +beginning of command line processing. + +The procedure @code{program-arguments} returns the command line +arguments for the curent invocation. More specifically, +@code{program-arguments} for the restored session are @emph{not} saved +from the dumping session. Command line processing is done on +the value of the identifier @code{*argv*}. + +The thunk @code{boot-tail} is called by SCM to process command line +arguments. @code{dump} sets @code{boot-tail} to the @var{thunk} it is +called with. + +The following example shows how to create @samp{rscm}, which is like +regular scm, but which loads faster and has the @samp{random} package +alreadly provided. + +@example +bash$ scm -rrandom +> (dump "rscm") +#<unspecified> +> (quit) +bash$ ./rscm -lpi.scm -e"(pi (random 200) 5)" +00003 14159 26535 89793 23846 26433 83279 50288 41971 69399 +37510 58209 74944 59230 78164 06286 20899 86280 34825 34211 +70679 82148 08651 32823 06647 09384 46095 50582 23172 53594 +08128 48111 74502 84102 70193 85211 05559 64462 29489 +bash$ +@end example + +This task can also be accomplished using the @samp{-o} command line +option (@pxref{SCM Options}). + +@example +bash$ scm -rrandom -o rscm +> (quit) +bash$ ./rscm -lpi.scm -e"(pi (random 200) 5)" +00003 14159 26535 89793 23846 26433 83279 50288 41971 69399 +37510 58209 74944 59230 78164 06286 20899 86280 34825 34211 +70679 82148 08651 32823 06647 09384 46095 50582 23172 53594 +08128 48111 74502 84102 70193 85211 05559 64462 29489 +bash$ +@end example + +@node Numeric, Arrays, Dump, Packages +@section Numeric + +@defvr Constant most-positive-fixnum +The immediate integer closest to positive infinity. +@xref{Configuration, , , slib, SLIB}. +@end defvr + +@defvr Constant most-negative-fixnum +The immediate integer closest to negative infinity. +@end defvr + +@noindent +These procedures augment the standard capabilities in @ref{Numerical +operations, , ,r4rs, Revised(4) Scheme}. + +@defun sinh z +@defunx cosh z +@defunx tanh z +Return the hyperbolic sine, cosine, and tangent of @var{z} +@end defun + +@defun asinh z +@defunx acosh z +@defunx atanh z +Return the inverse hyperbolic sine, cosine, and tangent of @var{z} +@end defun + +@defun $sqrt x +@defunx $abs x +@defunx $exp x +@defunx $log x +@defunx $sin x +@defunx $cos x +@defunx $tan x +@defunx $asin x +@defunx $acos x +@defunx $atan x + +@defunx $sinh x +@defunx $cosh x +@defunx $tanh x +@defunx $asinh x +@defunx $acosh x +@defunx $atanh x +Real-only versions of these popular functions. The argument @var{x} +must be a real number. It is an error if the value which should be +returned by a call to these procedures is @emph{not} real. +@end defun + +@defun $atan2 y x +Computes @code{(angle (make-rectangular x y))} for real numbers @var{y} +and @var{x}. +@end defun + +@defun $expt x1 x2 +Returns real number @var{x1} raised to the real power @var{x2}. It is +an error if the value which should be returned by a call to @code{$expt} +is not real. +@end defun + +@node Arrays, I/O-Extensions, Numeric, Packages +@section Arrays + +@menu +* Conventional Arrays:: +* Array Mapping:: +* Uniform Array:: +* Bit Vectors:: +@end menu + +@node Conventional Arrays, Array Mapping, Arrays, Arrays +@subsection Conventional Arrays + +@dfn{Arrays} read and write as a @code{#} followed by the @dfn{rank} +(number of dimensions) followed by what appear as lists (of lists) of +elements. The lists must be nested to the depth of the rank. For each +depth, all lists must be the same length. +@example +(make-array 'ho 3 3) @result{} +#2((ho ho ho) (ho ho ho) (ho ho ho)) +@end example + +Unshared conventional (not uniform) 0-based arrays of rank 1 (dimension) +are equivalent to (and can't be distinguished from) vectors. +@example +(make-array 'ho 3) @result{} (ho ho ho) +@end example + +When constructing an array, @var{bound} is either an inclusive range of +indices expressed as a two element list, or an upper bound expressed +as a single integer. So +@example +(make-array 'foo 3 3) @equiv{} (make-array 'foo '(0 2) '(0 2)) +@end example + +@defun array? obj +Returns @code{#t} if the @var{obj} is an array, and @code{#f} if not. +@end defun + +@defun make-array initial-value bound1 bound2 @dots{} +Creates and returns an array that has as many dimensions as there are +@var{bound}s and fills it with @var{initial-value}. +@end defun + +@defun array-ref array index1 index2 @dots{} +Returns the @var{index1}, @var{index2}, @dots{}'th element of +@var{array}. +@end defun + +@defun array-in-bounds? array index1 index2 @dots{} +Returns @code{#t} if its arguments would be acceptable to @var{array-ref}. +@end defun + +@defun array-set! array new-value index1 index2 @dots{} +Sets the @var{index1}, @var{index2}, @dots{}'th element of @var{array} +to @var{new-value}. The value returned by @code{array-set!} is +unspecified. +@end defun + +@defun make-shared-array array mapper bound1 bound2 @dots{} +@code{make-shared-array} can be used to create shared subarrays of other +arrays. The @var{mapper} is a function that translates coordinates in +the new array into coordinates in the old array. A @var{mapper} must be +linear, and its range must stay within the bounds of the old array, but +it can be otherwise arbitrary. A simple example: +@example +(define fred (make-array #f 8 8)) +(define freds-diagonal + (make-shared-array fred (lambda (i) (list i i)) 8)) +(array-set! freds-diagonal 'foo 3) +(array-ref fred 3 3) @result{} foo +(define freds-center + (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2)) +(array-ref freds-center 0 0) @result{} foo +@end example +@end defun + +@defun transpose-array array dim0 dim1 @dots{} +Returns an array sharing contents with @var{array}, but with dimensions +arranged in a different order. There must be one @var{dim} argument for +each dimension of @var{array}. @var{dim0}, @var{dim1}, @dots{} should +be integers between 0 and the rank of the array to be returned. Each +integer in that range must appear at least once in the argument list. + +The values of @var{dim0}, @var{dim1}, @dots{} correspond to dimensions +in the array to be returned, their positions in the argument list to +dimensions of @var{array}. Several @var{dim}s may have the same value, +in which case the returned array will have smaller rank than +@var{array}. + +examples: +@example +(transpose-array '#2((a b) (c d)) 1 0) @result{} #2((a c) (b d)) +(transpose-array '#2((a b) (c d)) 0 0) @result{} #1(a d) +(transpose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 1 0) @result{} + #2((a 4) (b 5) (c 6)) +@end example +@end defun + +@defun enclose-array array dim0 dim1 @dots{} +@var{dim0}, @var{dim1} @dots{} should be nonnegative integers less than +the rank of @var{array}. @var{enclose-array} returns an array +resembling an array of shared arrays. The dimensions of each shared +array are the same as the @var{dim}th dimensions of the original array, +the dimensions of the outer array are the same as those of the original +array that did not match a @var{dim}. + +An enclosed array is not a general Scheme array. Its elements may not +be set using @code{array-set!}. Two references to the same element of +an enclosed array will be @code{equal?} but will not in general be +@code{eq?}. The value returned by @var{array-prototype} when given an +enclosed array is unspecified. + +examples: +@example +(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1) @result{} + #<enclosed-array (#1(a d) #1(b e) #1(c f)) (#1(1 4) #1(2 5) #1(3 6))> + +(enclose-array '#3(((a b c) (d e f)) ((1 2 3) (4 5 6))) 1 0) @result{} + #<enclosed-array #2((a 1) (d 4)) #2((b 2) (e 5)) #2((c 3) (f 6))> +@end example +@end defun + +@defun array-shape array +Returns a list of inclusive bounds of integers. +@example +(array-shape (make-array 'foo '(-1 3) 5)) @result{} ((-1 3) (0 4)) +@end example +@end defun + +@defun array-dimensions array +@code{Array-dimensions} is similar to @code{array-shape} but replaces +elements with a @code{0} minimum with one greater than the maximum. So: +@example +(array-dimensions (make-array 'foo '(-1 3) 5)) @result{} ((-1 3) 5) +@end example +@end defun + +@defun array-rank obj +Returns the number of dimensions of @var{obj}. If @var{obj} is not an +array, @code{0} is returned. +@end defun + +@defun array->list array +Returns a list consisting of all the elements, in order, of @var{array}. +@end defun + +@defun array-copy! source destination +Copies every element from vector or array @var{source} to the +corresponding element of @var{destination}. @var{destination} must have +the same rank as @var{source}, and be at least as large in each +dimension. The order of copying is unspecified. +@end defun + +@defun serial-array-copy! source destination +Same as @code{array-copy!} but guaranteed to copy in row-major order. +@end defun + +@defun array-fill! array fill +Stores @var{fill} in every element of @var{array}. The value returned +is unspecified. +@end defun + +@defun array-equal? array0 array1 @dots{} +Returns @code{#t} iff all arguments are arrays with the same shape, the +same type, and have corresponding elements which are either +@code{equal?} or @code{array-equal?}. This function differs from +@code{equal?} in that a one dimensional shared array may be +@var{array-equal?} but not @var{equal?} to a vector or uniform vector. +@end defun + +@defun array-contents array +@defunx array-contents array strict +If @var{array} may be @dfn{unrolled} into a one dimensional shared array +without changing their order (last subscript changing fastest), then +@code{array-contents} returns that shared array, otherwise it returns +@code{#f}. All arrays made by @var{make-array} and +@var{make-uniform-array} may be unrolled, some arrays made by +@var{make-shared-array} may not be. + +If the optional argument @var{strict} is provided, a shared array will +be returned only if its elements are stored internally contiguous in +memory. +@end defun + +@node Array Mapping, Uniform Array, Conventional Arrays, Arrays +@subsection Array Mapping + +@defun array-map! array0 proc array1 @dots{} + +If @var{array1}, @dots{} are arrays, they must have the same number of +dimensions as @var{array0} and have a range for each index which +includes the range for the corresponding index in @var{array0}. +If they are scalars, that is, not arrays, vectors, or strings, then +they will be converted internally to arrays of the appropriate shape. +@var{proc} is applied to each tuple of elements of @var{array1} @dots{} +and the result is stored as the corresponding element in @var{array0}. +The value returned is unspecified. The order of application is +unspecified. + +@end defun + +@defun serial-array-map! array0 proc array1 @dots{} +Same as @var{array-map!}, but guaranteed to apply @var{proc} in +row-major order. +@end defun + +@defun array-for-each proc array0 @dots{} +@var{proc} is applied to each tuple of elements of @var{array0} @dots{} +in row-major order. The value returned is unspecified. +@end defun + +@defun array-index-map! array proc +applies @var{proc} to the indices of each element of @var{array} in +turn, storing the result in the corresponding element. The value +returned and the order of application are unspecified. + +One can implement @var{array-indexes} as +@example +(define (array-indexes array) + (let ((ra (apply make-array #f (array-shape array)))) + (array-index-map! ra (lambda x x)) + ra)) +@end example +Another example: +@example +(define (apl:index-generator n) + (let ((v (make-uniform-vector n 1))) + (array-index-map! v (lambda (i) i)) + v)) +@end example +@end defun + +@defun scalar->array scalar array prototype +Returns a uniform array of the same shape as @var{array}, having only +one shared element, which is @code{eqv?} to @var{scalar}. +If the optional argument @var{prototype} is supplied it will be used +as the prototype for the returned array. Otherwise the returned array +will be of the same type as @code{array} if that is possible, and +a conventional array if it is not. This function is used internally +by @code{array-map!} and friends to handle scalar arguments. +@end defun + +@node Uniform Array, Bit Vectors, Array Mapping, Arrays +@subsection Uniform Array + +@noindent +@dfn{Uniform Arrays} and vectors are arrays whose elements are all of +the same type. Uniform vectors occupy less storage than conventional +vectors. Uniform Array procedures also work on vectors, +uniform-vectors, bit-vectors, and strings. + +@noindent +@var{prototype} arguments in the following procedures are interpreted +according to the table: + +@example +prototype type display prefix + +#t boolean (bit-vector) #b +#\a char (string) #a +integer >0 unsigned integer #u +integer <0 signed integer #e +1.0 float (single precision) #s +1/3 double (double precision float) #i ++i complex (double precision) #c +() conventional vector # +@end example + +@noindent +Unshared uniform character 0-based arrays of rank 1 (dimension) +are equivalent to (and can't be distinguished from) strings. +@example +(make-uniform-array #\a 3) @result{} "$q2" +@end example + +@noindent +Unshared uniform boolean 0-based arrays of rank 1 (dimension) are +equivalent to (and can't be distinguished from) @ref{Bit Vectors, +bit-vectors}. +@example +(make-uniform-array #t 3) @result{} #*000 +@equiv{} +#b(#f #f #f) @result{} #*000 +@equiv{} +#1b(#f #f #f) @result{} #*000 +@end example + +@noindent +Other uniform vectors are written in a form similar to that of vectors, +except that a single character from the above table is put between +@code{#} and @code{(}. For example, @code{'#e(3 5 9)} returns a uniform +vector of signed integers. + +@defun uniform-vector-ref uve index +Returns the element at the @var{index} element in @var{uve}. +@end defun + +@defun uniform-vector-set! uve index new-value +Sets the element at the @var{index} element in @var{uve} to +@var{new-value}. The value returned by @code{uniform-vector-set!} is +unspecified. +@end defun + +@defun array? obj prototype +Returns @code{#t} if the @var{obj} is an array of type corresponding to +@var{prototype}, and @code{#f} if not. +@end defun + +@defun make-uniform-array prototype bound1 bound2 @dots{} +Creates and returns a uniform array of type corresponding to +@var{prototype} that has as many dimensions as there are @var{bound}s +and fills it with @var{prototype}. +@end defun + +@defun array-prototype array +Returns an object that would produce an array of the same type as +@var{array}, if used as the @var{prototype} for +@code{make-uniform-array}. +@end defun + +@defun list->uniform-array rank prot lst +@defunx list->uniform-vector prot lst +Returns a uniform array of the type indicated by prototype @var{prot} +with elements the same as those of @var{lst}. Elements must be of the +appropriate type, no coercions are done. +@end defun + +@defun uniform-vector-fill! uve fill +Stores @var{fill} in every element of @var{uve}. The value returned is +unspecified. +@end defun + +@defun uniform-vector-length uve +Returns the number of elements in @var{uve}. +@end defun + +@defun dimensions->uniform-array dims prototype fill +@defunx dimensions->uniform-array dims prototype +@defunx make-uniform-vector length prototype fill +@defunx make-uniform-vector length prototype +Creates and returns a uniform array or vector of type corresponding to +@var{prototype} with dimensions @var{dims} or length @var{length}. If +the @var{fill} argument is supplied, the returned array is filled with +this value. +@end defun + +@defun uniform-array-read! ura +@defunx uniform-array-read! ura port +@defunx uniform-vector-read! uve +@defunx uniform-vector-read! uve port +Attempts to read all elements of @var{ura}, in lexicographic order, as +binary objects from @var{port}. If an end of file is encountered during +uniform-array-read! the objects up to that point only are put into @var{ura} +(starting at the beginning) and the remainder of the array is +unchanged. + +@code{uniform-array-read!} returns the number of objects read. +@var{port} may be omitted, in which case it defaults to the value +returned by @code{(current-input-port)}. +@end defun + +@defun uniform-array-write ura +@defunx uniform-array-write ura port +@defunx uniform-vector-write uve +@defunx uniform-vector-write uve port +Writes all elements of @var{ura} as binary objects to @var{port}. The +number of of objects actually written is returned. @var{port} may be +omitted, in which case it defaults to the value returned by +@code{(current-output-port)}. +@end defun + +@node Bit Vectors, , Uniform Array, Arrays +@subsection Bit Vectors + +@noindent +Bit vectors can be written and read as a sequence of @code{0}s and +@code{1}s prefixed by @code{#*}. + +@example +#b(#f #f #f #t #f #t #f) @result{} #*0001010 +@end example + +@noindent +Some of these operations will eventually be generalized to other +uniform-arrays. + +@defun bit-count bool bv +Returns the number occurrences of @var{bool} in @var{bv}. +@end defun + +@defun bit-position bool bv k +Returns the minimum index of an occurrence of @var{bool} in @var{bv} +which is at least @var{k}. If no @var{bool} occurs within the specified +range @code{#f} is returned. +@end defun + +@defun bit-invert! bv +Modifies @var{bv} by replacing each element with its negation. +@end defun + +@defun bit-set*! bv uve bool +If uve is a bit-vector @var{bv} and uve must be of the same length. If +@var{bool} is @code{#t}, uve is OR'ed into @var{bv}; If @var{bool} is @code{#f}, the +inversion of uve is AND'ed into @var{bv}. + +If uve is a unsigned integer vector all the elements of uve must be +between 0 and the @code{LENGTH} of @var{bv}. The bits of @var{bv} +corresponding to the indexes in uve are set to @var{bool}. + +The return value is unspecified. +@end defun + +@defun bit-count* bv uve bool +Returns +@example +(bit-count (bit-set*! (if bool bv (bit-invert! bv)) uve #t) #t). +@end example +@var{bv} is not modified. +@end defun + + +@node I/O-Extensions, Posix Extensions, Arrays, Packages +@section I/O-Extensions + +@noindent +If @code{'i/o-extensions} is provided (by linking in @file{ioext.o}), +@ref{Line I/O, , , slib, SLIB}, and the following functions are defined: + +@defun isatty? port +Returns @code{#t} if @var{port} is input or output to a serial non-file device. +@end defun + +@defun stat <port-or-string> +Returns a vector of integers describing the argument. The argument +can be either a string or an open input port. If the argument is an +open port then the returned vector describes the file to which the +port is opened; If the argument is a string then the returned vector +describes the file named by that string. If there exists no file with +the name string, or if the file cannot be accessed @code{#f} is returned. +The elements of the returned vector are as follows: + + +@table @r +@item 0 st_dev +ID of device containing a directory entry for this file +@item 1 st_ino +Inode number +@item 2 st_mode +File type, attributes, and access control summary +@item 3 st_nlink +Number of links +@item 4 st_uid +User ID of file owner +@item 5 st_gid +Group ID of file group +@item 6 st_rdev +Device ID; this entry defined only for char or blk spec files +@item 7 st_size +File size (bytes) +@item 8 st_atime +Time of last access +@item 9 st_mtime +Last modification time +@item 10 st_ctime +Last file status change time +@end table +@end defun + +@defun getpid +Returns the process ID of the current process. +@end defun + +@defun file-position port +Returns the current position of the character in @var{port} which will +next be read or written. If @var{port} is not open to a file the result +is unspecified. +@end defun + +@defun file-set-position port integer +Sets the current position in @var{port} which will next be read or +written. If @var{port} is not open to a file the action of +@code{file-set-position} is unspecified. The result of +@code{file-set-position} is unspecified. +@end defun + +@defun reopen-file filename modes port +Closes port @var{port} and reopens it with @var{filename} and +@var{modes}. @code{reopen-file} returns @code{#t} if successful, +@code{#f} if not. +@end defun + +@defun duplicate-port port modes +Creates and returns a @dfn{duplicate} port from @var{port}. Duplicate +@emph{unbuffered} ports share one file position. @var{modes} are as for +@ref{Files and Ports, open-file}. +@end defun + +@defun redirect-port! from-port to-port +Closes @var{to-port} and makes @var{to-port} be a duplicate of +@var{from-port}. @code{redirect-port!} returns @var{to-port} if +successful, @code{#f} if not. If unsuccessful, @var{to-port} is not +closed. +@end defun + +@defun opendir dirname +Returns a @dfn{directory} object corresponding to the file system +directory named @var{dirname}. If unsuccessful, returns @code{#f}. +@end defun + +@defun readdir dir +Returns the string name of the next entry from the directory @var{dir}. +If there are no more entries in the directory, @code{readdir} returns a +@code{#f}. +@end defun + +@defun rewinddir dir +Reinitializes @var{dir} so that the next call to @code{readdir} with +@var{dir} will return the first entry in the directory again. +@end defun + +@defun closedir dir +Closes @var{dir} and returns @code{#t}. If @var{dir} is already +closed,, @code{closedir} returns a @code{#f}. +@end defun + +@defun mkdir path mode +The @code{mkdir} function creates a new, empty directory whose name is +@var{path}. The integer argument @var{mode} specifies the file +permissions for the new directory. @xref{The Mode Bits for Access +Permission, , , libc, Gnu C Library}, for more information about this. + +@code{mkdir} returns if successful, @code{#f} if not. +@end defun + +@defun rmdir path +The @code{rmdir} function deletes the directory @var{path}. The +directory must be empty before it can be removed. @code{rmdir} returns +if successful, @code{#f} if not. +@end defun + +@defun chdir filename +Changes the current directory to @var{filename}. If @var{filename} does not +exist or is not a directory, @code{#f} is returned. Otherwise, @code{#t} is +returned. +@end defun + +@defun getcwd +The function @code{getcwd} returns a string containing the absolute file +name representing the current working directory. If this string cannot +be obtained, @code{#f} is returned. +@end defun + +@defun rename-file oldfilename newfilename +Renames the file specified by @var{oldfilename} to @var{newfilename}. +If the renaming is successful, @code{#t} is returned. Otherwise, +@code{#f} is returned. +@end defun + +@defun chmod file mode +The function @code{chmod} sets the access permission bits for the file +named by @var{file} to @var{mode}. The @var{file} argument may be a +string containing the filename or a port open to the file. + +@code{chmod} returns if successful, @code{#f} if not. +@end defun + +@defun utime pathname acctime modtime +Sets the file times associated with the file named @var{pathname} to +have access time @var{acctime} and modification time @var{modtime}. +@code{utime} returns if successful, @code{#f} if not. +@end defun + +@defun umask mode +The function @code{umask} sets the file creation mask of the current +process to @var{mask}, and returns the previous value of the file +creation mask. +@end defun + +@defun fileno port +Returns the integer file descriptor associated with the port @var{port}. +If an error is detected, @code{#f} is returned. +@end defun + +@defun access pathname how +Returns @code{#t} if the file named by @var{pathname} can be accessed in +the way specified by the @var{how} argument. The @var{how} argument can +be the @code{logior} of the flags: + +@enumerate 0 +@item +File-exists? +@item +File-is-executable? +@item +File-is-writable? +@end enumerate +@enumerate 4 +@item +File-is-readable? +@end enumerate + +Or the @var{how} argument can be a string of 0 to 3 of the following +characters in any order. The test performed is the @code{and} of the +associated tests and @code{file-exists?}. + +@table @key +@item x +File-is-executable? +@item w +File-is-writable? +@item r +File-is-readable? +@end table +@end defun + +@defun execl command arg0 @dots{} +@defunx execlp command arg0 @dots{} +Transfers control to program @var{command} called with arguments +@var{arg0} @dots{}. For @code{execl}, @var{command} must be an exact +pathname of an executable file. @code{execlp} searches for +@var{command} in the list of directories specified by the environment +variable @var{PATH}. The convention is that @var{arg0} is the same name +as @var{command}. + +If successful, this procedure does not return. Otherwise an error +message is printed and the integer @code{errno} is returned. + +@defunx execv command arglist +@defunx execvp command arglist +Like @code{execl} and @code{execlp} except that the set of arguments to +@var{command} is @var{arglist}. +@end defun + +@defun putenv string +adds or removes definitions from the @dfn{environment}. If the +@var{string} is of the form @samp{NAME=VALUE}, the definition is added +to the environment. Otherwise, the @var{string} is interpreted as the +name of an environment variable, and any definition for this variable in +the environment is removed. + +Names of environment variables are case-sensitive and must not contain +the character @code{=}. System-defined environment variables are +invariably uppercase. + +@code{Putenv} is used to set up the environment before calls to +@code{execl}, @code{execlp}, @code{execv}, @code{execvp}, @code{system}, +or @code{open-pipe} (@pxref{I/O-Extensions, open-pipe}). + +To access environment variables, use @code{getenv} (@pxref{System +Interface, getenv, , slib, SLIB}). +@end defun + +@node Posix Extensions, Regular Expression Pattern Matching, I/O-Extensions, Packages +@section Posix Extensions + +@noindent +If @code{'posix} is provided (by linking in @file{posix.o}), the +following functions are defined: + +@defun open-pipe string modes +If the string @var{modes} contains an @key{r}, returns an input port +capable of delivering characters from the standard output of the system +command @var{string}. Otherwise, returns an output port capable of +receiving characters which become the standard input of the system +command @var{string}. If a pipe cannot be created @code{#f} is +returned. +@end defun + +@defun open-input-pipe string +Returns an input port capable of delivering characters from the +standard output of the system command @var{string}. If a pipe cannot be +created @code{#f} is returned. +@end defun + +@defun open-output-pipe string +Returns an output port capable of receiving characters which become +the standard input of the system command @var{string}. If a pipe cannot +be created @code{#f} is returned. +@end defun + +@defun close-port pipe +Closes the @var{pipe}, rendering it incapable of delivering or accepting +characters. This routine has no effect if the pipe has already been +closed. The value returned is unspecified. +@end defun + +@defun pipe +Returns @code{(cons @var{rd} @var{wd})} where @var{rd} and @var{wd} are +the read and write (port) ends of a @dfn{pipe} respectively. +@end defun + +@defun fork +Creates a copy of the process calling @code{fork}. Both processes +return from @code{fork}, but the calling (@dfn{parent}) process's +@code{fork} returns the @dfn{child} process's ID whereas the child +process's @code{fork} returns 0. +@end defun + +@noindent +For a discussion of @dfn{ID}s @xref{Process Persona, , , GNU C Library, +libc}. + +@defun getppid +Returns the process ID of the parent of the current process. +For a process's own ID @xref{I/O-Extensions, getpid}. +@end defun + +@defun getuid +Returns the real user ID of this process. +@end defun + +@defun getgid +Returns the real group ID of this process. +@end defun + +@defun getegid +Returns the effective group ID of this process. +@end defun + +@defun geteuid +Returns the effective user ID of this process. +@end defun + +@defun setuid id +Sets the real user ID of this process to @var{id}. +Returns @code{#t} if successful, @code{#f} if not. +@end defun + +@defun setgid id +Sets the real group ID of this process to @var{id}. +Returns @code{#t} if successful, @code{#f} if not. +@end defun + +@defun setegid id +Sets the effective group ID of this process to @var{id}. +Returns @code{#t} if successful, @code{#f} if not. +@end defun + +@defun seteuid id +Sets the effective user ID of this process to @var{id}. +Returns @code{#t} if successful, @code{#f} if not. +@end defun + +@defun kill pid sig +The @code{kill} function sends the signal @var{signum} to the process or +process group specified by @var{pid}. Besides the signals listed in +@ref{Standard Signals, , ,libc , GNU C Library}, @var{signum} can also +have a value of zero to check the validity of the @var{pid}. + +The @var{pid} specifies the process or process group to receive the +signal: + +@table @asis +@item > 0 +The process whose identifier is @var{pid}. + +@item 0 +All processes in the same process group as the sender. The +sender itself does not receive the signal. + +@item -1 +If the process is privileged, send the signal to all +processes except for some special system processes. +Otherwise, send the signal to all processes with the same +effective user ID. + +@item < -1 +The process group whose identifier is @code{(abs @var{pid})}. +@end table + +A process can send a signal to itself with @code{(kill (getpid) +@var{signum})}. If @code{kill} is used by a process to send a signal to +itself, and the signal is not blocked, then @code{kill} delivers at +least one signal (which might be some other pending unblocked signal +instead of the signal @var{signum}) to that process before it returns. + +The return value from @code{kill} is zero if the signal can be sent +successfully. Otherwise, no signal is sent, and a value of @code{-1} is +returned. If @var{pid} specifies sending a signal to several processes, +@code{kill} succeeds if it can send the signal to at least one of them. +There's no way you can tell which of the processes got the signal or +whether all of them did. +@end defun + +@defun waitpid pid options + +The @code{waitpid} function suspends execution of the current process +until a child as specified by the @var{pid} argument has exited, or until a +signal is deliverd whose action is to terminate the current process or +to call a signal handling function. If a child as requested by @var{pid} has +already exited by the time of the call (a so-called @dfn{zombie} +process), the function returns immediately. Any system resources used +by the child are freed. + +The value of @var{pid} can be one of: + +@table @asis +@item < -1 +which means to wait for any child process whose process group ID is +equal to the absolute value of + +@item -1 +which means to wait for any child process whose process group ID is +equal to the @code{(abs @var{pid})}. + +@item -1 +which means to wait for any child process; this is the same behaviour +which wait exhibits. + +@item 0 +which means to wait for any child process whose process group ID is +equal to that of the calling process. + +@item > 0 +which means to wait for the child whose process ID is equal to the value +of @var{pid}. +@end table + +The value of @var{options} is one of the following: + +@enumerate 0 +@item +Nothing special. + +@item +(@code{WNOHANG}) which means to return immediately if no child is there +to be waited for. + +@item +(@code{WUNTRACED}) which means to also return for children which are +stopped, and whose status has not been reported. + +@item +Which means both of the above. +@end enumerate + +The return value is normally the process ID of the child process whose +status is reported. If the @code{WNOHANG} option was specified and no +child process is waiting to be noticed, the value is zero. A value of +@code{#f} is returned in case of error and @code{errno} is set. For +information about the @code{errno} codes @xref{Process Completion, , , +GNU C Library, libc}. +@end defun + +@defun uname +You can use the @code{uname} procedure to find out some information +about the type of computer your program is running on. + +Returns a vector of strings. These strings are: + +@enumerate 0 +@item +The name of the operating system in use. +@item +The network name of this particular computer. +@item +The current release level of the operating system implementation. +@item +The current version level within the release of the operating system. +@item +Description of the type of hardware that is in use. + +Some examples are @samp{"i386-ANYTHING"}, @samp{"m68k-hp"}, +@samp{"sparc-sun"}, @samp{"m68k-sun"}, @samp{"m68k-sony"} and @samp{"mips-dec"}. +@end enumerate +@end defun + +@defun getpw name +@defunx getpw uid +@defunx getpw +Returns a vector of information for the entry for @code{NAME}, +@code{UID}, or the next entry if no argument is given. The +information is: + +@enumerate 0 +@item +The user's login name. +@item +The encrypted password string. +@item +The user ID number. +@item +The user's default group ID number. +@item +A string typically containing the user's real name, and +possibly other information such as a phone number. +@item +The user's home directory, initial working directory, or @code{#f}, in +which case the interpretation is system-dependent. +@item +The user's default shell, the initial program run when the user logs in, +or @code{#f}, indicating that the system default should be used. +@end enumerate +@end defun + +@defun setpwent #t +Rewinds the pw entry table back to the begining. + +@defunx setpwent #f +@defunx setpwent +Closes the pw table. +@end defun + + +@defun getgr name +@defunx getgr uid +@defunx getgr +Returns a vector of information for the entry for @code{NAME}, +@code{UID}, or the next entry if no argument is given. The +information is: + +@enumerate 0 +@item +The name of the group. +@item +The encrypted password string. +@item +The group ID number. +@item +A list of (string) names of users in the group. +@end enumerate +@end defun + +@defun setgrent #t +Rewinds the group entry table back to the begining. + +@defunx setgrent #f +@defunx setgrent +Closes the group table. +@end defun + +@defun getgroups +Returns a vector of all the supplementary group IDs of the process. +@end defun + + +@defun link oldname newname +The @code{link} function makes a new link to the existing file named by +@var{oldname}, under the new name @var{newname}. + +@code{link} returns a value of @code{#t} if it is successful and +@code{#f} on failure. +@end defun + +@defun chown filename owner group +The @code{chown} function changes the owner of the file @var{filename} +to @var{owner}, and its group owner to @var{group}. + +@code{chown} returns a value of @code{#t} if it is successful and +@code{#f} on failure. +@end defun + +@defun ttyname port +If port @var{port} is associated with a terminal device, returns a +string containing the file name of termainal device; otherwise +@code{#f}. +@end defun + +@section Unix Extensions + +@noindent +If @code{'unix} is provided (by linking in @file{unix.o}), the following +functions are defined: + +@noindent +These @dfn{priveledged} and symbolic link functions are not in Posix: + +@defun symlink oldname newname +The @code{symlink} function makes a symbolic link to @var{oldname} named +@var{newname}. + +@code{symlink} returns a value of @code{#t} if it is successful and +@code{#f} on failure. +@end defun + +@defun readlink filename +Returns the value of the symbolic link @var{filename} or @code{#f} for +failure. +@end defun + +@defun lstat filename +The @code{lstat} function is like @code{stat}, except that it does not +follow symbolic links. If @var{filename} is the name of a symbolic +link, @code{lstat} returns information about the link itself; otherwise, +@code{lstat} works like @code{stat}. @xref{I/O-Extensions}. +@end defun + +@defun nice increment +Increment the priority of the current process by @var{increment}. +@code{chown} returns a value of @code{#t} if it is successful and +@code{#f} on failure. +@end defun + +@defun acct filename +When called with the name of an exisitng file as argument, accounting is +turned on, records for each terminating pro-cess are appended to +@var{filename} as it terminates. An argument of @code{#f} causes +accounting to be turned off. + +@code{acct} returns a value of @code{#t} if it is successful and +@code{#f} on failure. +@end defun + +@defun mknod filename mode dev +The @code{mknod} function makes a special file with name @var{filename} +and modes @var{mode} for device number @var{dev}. + +@code{mknod} returns a value of @code{#t} if it is successful and +@code{#f} on failure. +@end defun + +@defun sync +@code{sync} first commits inodes to buffers, and then buffers to disk. +sync() only schedules the writes, so it may return before the actual +writing is done. The value returned is unspecified. +@end defun + +@node Regular Expression Pattern Matching, Line Editing, Posix Extensions, Packages +@section Regular Expression Pattern Matching + +These functions are defined in @file{rgx.c} using a POSIX or GNU +@dfn{regex} library. If your computer does not support regex, a package +is available via ftp from +@file{prep.ai.mit.edu:/pub/gnu/regex-0.12.tar.gz}. For a description of +regular expressions, @xref{syntax, , , regex, "regex" regular expression +matching library}. + +@defun regcomp @var{pattern} [@var{flags}] +Compile a @dfn{regular expression}. Return a compiled regular +expression, or an integer error code suitable as an argument to +@code{regerror}. + +@var{flags} in @code{regcomp} is a string of option letters used to +control the compilation of the regular expression. The letters may +consist of: + +@table @samp +@item n +newlines won't be matched by @code{.} or hat lists; ( @code{[^...]} ) +@item i +ignore case. +@exdent only when compiled with @var{_GNU_SOURCE}: +@item 0 +allows dot to match a null character. +@item f +enable GNU fastmaps. +@end table +@end defun + +@defun regerror @var{errno} +Returns a string describing the integer @var{errno} returned when +@code{regcomp} fails. +@end defun + +@defun regexec @var{re} @var{string} +Returns @code{#f} or a vector of integers. These integers are in +doublets. The first of each doublet is the index of @var{string} of +the start of the matching expression or sub-expression (delimited by +parentheses in the pattern). The last of each doublet is index of +@var{string} of the end of that expression. @code{#f} is returned if +the string does not match. +@end defun + +@defun regmatch? @var{re} @var{string} +Returns @code{#t} if the @var{pattern} such that @var{regexp} = (regcomp +@var{pattern}) matches @var{string} as a POSIX extended regular +expressions. Returns @code{#f} otherwise. +@end defun + +@defun regsearch @var{re} @var{string} [@var{start} [@var{len}]] +@defunx regsearchv @var{re} @var{string} [@var{start} [@var{len}]] +@defunx regmatch @var{re} @var{string} [@var{start} [@var{len}]] +@defunx regmatchv @var{re} @var{string} [@var{start} [@var{len}]] +@code{Regsearch} searches for the pattern within the string. + +@code{Regmatch} anchors the pattern and begins matching it against +string. + +@code{Regsearch} returns the character position where @var{re} starts, +or @code{#f} if not found. + +@code{Regmatch} returns the number of characters matched, @code{#f} if +not matched. + +@code{Regsearchv} and @code{regmatchv} return the match vector is +returned if @var{re} is found, @code{#f} otherwise. + +@table @var +@item re +may be either: +@enumerate +@item +a compiled regular expression returned by @code{regcomp}; +@item +a string representing a regular expression; +@item +a list of a string and a set of option letters. +@end enumerate +@item string +The string to be operated upon. +@item start +The character position at which to begin the search or match. If absent, +the default is zero. + +@exdent @emph{Compiled _GNU_SOURCE and using GNU libregex only:} + +When searching, if @var{start} is negative, the absolute value of +@var{start} will be used as the start location and reverse searching +will be performed. + +@item len +The search is allowed to examine only the first @var{len} characters of +@var{string}. If absent, the entire string may be examined. +@end table +@end defun + +@defun string-split @var{re} @var{string} +@defunx string-splitv @var{re} @var{string} +@code{String-split} splits a string into substrings that are separated +by @var{re}, returning a vector of substrings. + +@code{String-splitv} returns a vector of string positions that indicate +where the substrings are located. +@end defun + +@defun string-edit @var{re} @var{edit-spec} @var{string} [@var{count}] +Returns the edited string. + +@table @var +@item edit-spec +Is a string used to replace occurances of @var{re}. Backquoted integers +in the range of 1-9 may be used to insert subexpressions in @var{re}, as +in @code{sed}. +@item count +The number of substitutions for @code{string-edit} to perform. If +@code{#t}, all occurances of @var{re} will be replaced. The default is +to perform one substitution. +@end table +@end defun + +@node Line Editing, Curses, Regular Expression Pattern Matching, Packages +@section Line Editing + +@noindent +These procedures provide input line editing and recall. + +@noindent +These functions are defined in @file{edline.c} and @file{Iedline.scm} +using the @dfn{editline} or GNU @dfn{readline} (@pxref{Top, , Overview +,readline ,GNU Readline Library}) libraries available from: + +@itemize @bullet +@item +@ifset html +<A HREF="ftp://ftp.sys.toronto.edu/pub/rc/editline.shar"> +@end ifset +@code{ftp.sys.toronto.edu:/pub/rc/editline.shar} +@ifset html +</A> +@end ifset +@item +@ifset html +<A HREF="ftp://prep.ai.mit.edu/pub/gnu/readline-2.0.tar.gz"> +@end ifset +@code{prep.ai.mit.edu:/pub/gnu/readline-2.0.tar.gz} +@ifset html +</A> +@end ifset +@end itemize + +@noindent +When @file{Iedline.scm} is loaded, if the current input port is the +default input port and the environment variable @var{EMACS} is not +defined, line-editing mode will be entered. + +@defun default-input-port +Returns the initial @code{current-input-port} SCM was invoked with +(stdin). +@end defun + +@defun default-output-port +Returns the initial @code{current-output-port} SCM was invoked with +(stdout). +@end defun + +@defun make-edited-line-port +Returns an input/output port that allows command line editing and +retrieval of history. +@end defun + +@defun line-editing +Returns the current edited line port or @code{#f}. + +@defunx line-editing bool +If @var{bool} is false, exits line-editing mode and returns the previous +value of @code{(line-editing)}. If @var{bool} is true, sets the current +input and output ports to an edited line port and returns the previous +value of @code{(line-editing)}. +@end defun + +@node Curses, Sockets, Line Editing, Packages +@section Curses + +@noindent +These functions are defined in @file{crs.c} using the @dfn{curses} +library. Unless otherwise noted these routines return @code{#t} for +successful completion and @code{#f} for failure. + +@defun initscr +Returns a port for a full screen window. This routine must be called to +initialize curses. +@end defun + +@defun endwin +A program should call @code{endwin} before exiting or escaping from +curses mode temporarily, to do a system call, for example. This routine +will restore termio modes, move the cursor to the lower left corner of +the screen and reset the terminal into the proper non-visual mode. To +resume after a temporary escape, call @ref{Window Manipulation, +refresh}. +@end defun + +@menu +* Output Options Setting:: +* Terminal Mode Setting:: +* Window Manipulation:: +* Output:: +* Input:: +* Curses Miscellany:: +@end menu + +@node Output Options Setting, Terminal Mode Setting, Curses, Curses +@subsection Output Options Setting + +@noindent +These routines set options within curses that deal with output. All +options are initially @code{#f}, unless otherwise stated. It is not +necessary to turn these options off before calling @code{endwin}. + +@defun clearok win bf +If enabled (@var{bf} is @code{#t}), the next call to @code{force-output} +or @code{refresh} with @var{win} will clear the screen completely and +redraw the entire screen from scratch. This is useful when the contents +of the screen are uncertain, or in some cases for a more pleasing visual +effect. +@end defun + +@defun idlok win bf +If enabled (@var{bf} is @code{#t}), curses will consider using the +hardware ``insert/delete-line'' feature of terminals so equipped. If +disabled (@var{bf} is @code{#f}), curses will very seldom use this +feature. The ``insert/delete-character'' feature is always considered. +This option should be enabled only if your application needs +``insert/delete-line'', for example, for a screen editor. It is +disabled by default because + +``insert/delete-line'' tends to be visually annoying when used in +applications where it is not really needed. If ``insert/delete-line'' +cannot be used, curses will redraw the changed portions of all lines. +@end defun + +@defun leaveok win bf +Normally, the hardware cursor is left at the location of the window +cursor being refreshed. This option allows the cursor to be left +wherever the update happens to leave it. It is useful for +applications where the cursor is not used, since it reduces the need +for cursor motions. If possible, the cursor is made invisible when +this option is enabled. +@end defun + +@defun scrollok win bf +This option controls what happens when the cursor of window @var{win} is +moved off the edge of the window or scrolling region, either from a +newline on the bottom line, or typing the last character of the last +line. If disabled (@var{bf} is @code{#f}), the cursor is left on the +bottom line at the location where the offending character was entered. +If enabled (@var{bf} is @code{#t}), @code{force-output} is called on the +window @var{win}, and then the physical terminal and window @var{win} +are scrolled up one line. + +@emph{Note:} in order to get the physical scrolling effect on the +terminal, it is also necessary to call @code{idlok}. +@end defun + +@defun nodelay win bf +This option causes wgetch to be a non-blocking call. If no input is +ready, wgetch will return an eof-object. If disabled, wgetch will hang +until a key is pressed. +@end defun + +@node Terminal Mode Setting, Window Manipulation, Output Options Setting, Curses +@subsection Terminal Mode Setting + +@noindent +These routines set options within curses that deal with input. The +options involve using ioctl(2) and therefore interact with curses +routines. It is not necessary to turn these options off before +calling @code{endwin}. The routines in this section all return an +unspecified value. + +@defun cbreak +@defunx nocbreak +These two routines put the terminal into and out of @code{CBREAK} mode, +respectively. In @code{CBREAK} mode, characters typed by the user are +immediately available to the program and erase/kill character +processing is not performed. When in @code{NOCBREAK} mode, the tty driver +will buffer characters typed until a @key{LFD} or @key{RET} is typed. +Interrupt and flowcontrol characters are unaffected by this mode. +Initially the terminal may or may not be in @code{CBREAK} mode, as it is +inherited, therefore, a program should call @code{cbreak} or @code{nocbreak} +explicitly. Most interactive programs using curses will set @code{CBREAK} +mode. + +@emph{Note:} @code{cbreak} overrides @code{raw}. For a discussion of +how these routines interact with @code{echo} and @code{noecho} +@xref{Input, read-char}. +@end defun + +@defun raw +@defunx noraw +The terminal is placed into or out of @code{RAW} mode. @code{RAW} mode +is similar to @code{CBREAK} mode, in that characters typed are +immediately passed through to the user program. The differences are +that in @code{RAW} mode, the interrupt, quit, suspend, and flow control +characters are passed through uninterpreted, instead of generating a +signal. @code{RAW} mode also causes 8-bit input and output. The +behavior of the @code{BREAK} key depends on other bits in the terminal +driver that are not set by curses. +@end defun + +@defun echo +@defunx noecho +These routines control whether characters typed by the user are echoed +by @code{read-char} as they are typed. Echoing by the tty driver is +always disabled, but initially @code{read-char} is in @code{ECHO} mode, +so characters typed are echoed. Authors of most interactive programs +prefer to do their own echoing in a controlled area of the screen, or +not to echo at all, so they disable echoing by calling @code{noecho}. +For a discussion of how these routines interact with @code{echo} and +@code{noecho} @xref{Input, read-char}. +@end defun + +@defun nl +@defunx nonl +These routines control whether @key{LFD} is translated into @key{RET} +and @code{LFD} on output, and whether @key{RET} is translated into +@key{LFD} on input. Initially, the translations do occur. By disabling +these translations using @code{nonl}, curses is able to make better use +of the linefeed capability, resulting in faster cursor motion. +@end defun + +@defun resetty +@defunx savetty +These routines save and restore the state of the terminal modes. +@code{savetty} saves the current state of the terminal in a buffer and +@code{resetty} restores the state to what it was at the last call to +@code{savetty}. +@end defun + +@node Window Manipulation, Output, Terminal Mode Setting, Curses +@subsection Window Manipulation + +@defun newwin nlines ncols begy begx +Create and return a new window with the given number of lines (or rows), +@var{nlines}, and columns, @var{ncols}. The upper left corner of the +window is at line @var{begy}, column @var{begx}. If either @var{nlines} +or @var{ncols} is 0, they will be set to the value of +@code{LINES}-@var{begy} and @code{COLS}-@var{begx}. A new full-screen +window is created by calling @code{newwin(0,0,0,0)}. +@end defun + +@defun subwin orig nlines ncols begy begx +Create and return a pointer to a new window with the given number of +lines (or rows), @var{nlines}, and columns, @var{ncols}. The window is +at position (@var{begy}, @var{begx}) on the screen. This position is +relative to the screen, and not to the window @var{orig}. The window is +made in the middle of the window @var{orig}, so that changes made to one +window will affect both windows. When using this routine, often it will +be necessary to call @code{touchwin} or @code{touchline} on @var{orig} +before calling @code{force-output}. +@end defun + +@defun close-port win +Deletes the window @var{win}, freeing up all memory associated with it. +In the case of sub-windows, they should be deleted before the main +window @var{win}. +@end defun + +@defun refresh +@defunx force-output win +These routines are called to write output to the terminal, as most other +routines merely manipulate data structures. @code{force-output} copies +the window @var{win} to the physical terminal screen, taking into +account what is already there in order to minimize the amount of +information that's sent to the terminal (called optimization). Unless +@code{leaveok} has been enabled, the physical cursor of the terminal is +left at the location of window @var{win}'s cursor. With @code{refresh}, +the number of characters output to the terminal is returned. +@end defun + +@defun mvwin win y x +Move the window @var{win} so that the upper left corner will be at position +(@var{y}, @var{x}). If the move would cause the window @var{win} to be off the +screen, it is an error and the window @var{win} is not moved. +@end defun + +@defun overlay srcwin dstwin +@defunx overwrite srcwin dstwin + +These routines overlay @var{srcwin} on top of @var{dstwin}; that is, all +text in @var{srcwin} is copied into @var{dstwin}. @var{srcwin} and +@var{dstwin} need not be the same size; only text where the two windows +overlap is copied. The difference is that @code{overlay} is +non-destructive (blanks are not copied), while @code{overwrite} is +destructive. +@end defun + +@defun touchwin win +@defunx touchline win start count +Throw away all optimization information about which parts of the window +@var{win} have been touched, by pretending that the entire window +@var{win} has been drawn on. This is sometimes necessary when using +overlapping windows, since a change to one window will affect the other +window, but the records of which lines have been changed in the other +window will not reflect the change. @code{touchline} only pretends that +@var{count} lines have been changed, beginning with line @var{start}. +@end defun + +@defun wmove win y x +The cursor associated with the window @var{win} is moved to line (row) @var{y}, +column @var{x}. This does not move the physical cursor of the terminal +until @code{refresh} (or @code{force-output}) is called. The position +specified is relative to the upper left corner of the window @var{win}, +which is (0, 0). +@end defun + +@node Output, Input, Window Manipulation, Curses +@subsection Output + +@noindent +These routines are used to @dfn{draw} text on windows + +@defun display ch win +@defunx display str win +@defunx wadd win ch +@defunx wadd win str +The character @var{ch} or characters in @var{str} are put into the +window @var{win} at the current cursor position of the window and the +position of @var{win}'s cursor is advanced. At the right margin, an +automatic newline is performed. At the bottom of the scrolling region, +if scrollok is enabled, the scrolling region will be scrolled up one +line. + +If @var{ch} is a @key{TAB}, @key{LFD}, or backspace, the cursor will be +moved appropriately within the window @var{win}. A @key{LFD} also does a +@code{wclrtoeol} before moving. @key{TAB} characters are considered to +be at every eighth column. If @var{ch} is another control character, it +will be drawn in the @kbd{C-x} notation. (Calling @code{winch} after +adding a control character will not return the control character, but +instead will return the representation of the control character.) + +Video attributes can be combined with a character by or-ing them into +the parameter. This will result in these attributes also being set. +The intent here is that text, including attributes, can be copied from +one place to another using inch and display. See @code{standout}, +below. + +@emph{Note:} For @code{wadd} @var{ch} can be an integer and will insert +the character of the corresponding value. +@end defun + +@defun werase win +This routine copies blanks to every position in the window @var{win}. +@end defun + +@defun wclear win +This routine is like @code{werase}, but it also calls @ref{Output +Options Setting, clearok}, arranging that the screen will be cleared +completely on the next call to @code{refresh} or @code{force-output} for +window @var{win}, and repainted from scratch. +@end defun + +@defun wclrtobot win +All lines below the cursor in window @var{win} are erased. Also, the +current line to the right of the cursor, inclusive, is erased. +@end defun + +@defun wclrtoeol win +The current line to the right of the cursor, inclusive, is erased. +@end defun + +@defun wdelch win +The character under the cursor in the window @var{win} is deleted. All +characters to the right on the same line are moved to the left one +position and the last character on the line is filled with a blank. The +cursor position does not change. This does not imply use of the +hardware ``delete-character'' feature. +@end defun + +@defun wdeleteln win +The line under the cursor in the window @var{win} is deleted. All lines +below the current line are moved up one line. The bottom line @var{win} +is cleared. The cursor position does not change. This does not imply +use of the hardware ``deleteline'' feature. +@end defun + +@defun winsch win ch +The character @var{ch} is inserted before the character under the +cursor. All characters to the right are moved one @key{SPC} to the +right, possibly losing the rightmost character of the line. The cursor +position does not change . This does not imply use of the hardware +``insertcharacter'' feature. +@end defun + +@defun winsertln win +A blank line is inserted above the current line and the bottom line is +lost. This does not imply use of the hardware ``insert-line'' feature. +@end defun + +@defun scroll win +The window @var{win} is scrolled up one line. This involves moving the +lines in @var{win}'s data structure. As an optimization, if @var{win} +is stdscr and the scrolling region is the entire window, the physical +screen will be scrolled at the same time. +@end defun + +@node Input, Curses Miscellany, Output, Curses +@subsection Input + +@defun read-char win +A character is read from the terminal associated with the window +@var{win}. Depending on the setting of @code{cbreak}, this will be +after one character (@code{CBREAK} mode), or after the first newline +(@code{NOCBREAK} mode). Unless @code{noecho} has been set, the +character will also be echoed into @var{win}. + +When using @code{read-char}, do not set both @code{NOCBREAK} mode +(@code{nocbreak}) and @code{ECHO} mode (@code{echo}) at the same time. +Depending on the state of the terminal driver when each character is +typed, the program may produce undesirable results. +@end defun + +@defun winch win +The character, of type chtype, at the current position in window +@var{win} is returned. If any attributes are set for that position, +their values will be OR'ed into the value returned. +@end defun + +@defun getyx win +A list of the y and x coordinates of the cursor position of the window +@var{win} is returned +@end defun + +@node Curses Miscellany, , Input, Curses +@subsection Curses Miscellany + +@defun wstandout win +@defunx wstandend win + +These functions set the current attributes of the window @var{win}. The +current attributes of @var{win} are applied to all characters that are +written into it. Attributes are a property of the character, and move +with the character through any scrolling and insert/delete +line/character operations. To the extent possible on the particular +terminal, they will be displayed as the graphic rendition of characters +put on the screen. + +@code{wstandout} sets the current attributes of the window @var{win} to +be visibly different from other text. @code{wstandend} turns off the +attributes. +@end defun + +@defun box win vertch horch +A box is drawn around the edge of the window @var{win}. @var{vertch} +and @var{horch} are the characters the box is to be drawn with. If +@var{vertch} and @var{horch} are 0, then appropriate default characters, +@code{ACS_VLINE} and @code{ACS_HLINE}, will be used. + +@emph{Note:} @var{vertch} and @var{horch} can be an integers and will +insert the character (with attributes) of the corresponding values. +@end defun + +@defun unctrl c +This macro expands to a character string which is a printable +representation of the character @var{c}. Control characters are +displayed in the @kbd{C-x} notation. Printing characters are displayed +as is. +@end defun + +@node Sockets, , Curses, Packages +@section Sockets + +@noindent +These procedures (defined in @file{socket.c}) provide a Scheme interface +to most of the C @dfn{socket} library. For more information on sockets, +@xref{Sockets, , , libc, The GNU C Library Reference Manual}. + +@menu +* Host Data:: +* Internet Addresses and Socket Names:: +* Socket:: +@end menu + +@node Host Data, Internet Addresses and Socket Names, Sockets, Sockets +@subsection Host Data, Network, Protocol, and Service Inquiries + +@defvr Constant af_inet +@defvrx Constant af_unix +Integer family codes for Internet and Unix sockets, respectively. +@end defvr + +@defun gethost host-spec +@defunx gethost +Returns a vector of information for the entry for @code{HOST-SPEC} or the +next entry if @code{HOST-SPEC} isn't given. The information is: + +@enumerate 0 +@item +host name string +@item +list of host aliases strings +@item +integer address type (@code{AF_INET}) +@item +integer size of address entries (in bytes) +@item +list of integer addresses +@end enumerate +@end defun + +@defun sethostent stay-open +@defunx sethostent +Rewinds the host entry table back to the begining if given an argument. +If the argument @var{stay-open} is @code{#f} queries will be be done +using @code{UDP} datagrams. Otherwise, a connected @code{TCP} socket +will be used. When called without an argument, the host table is +closed. +@end defun + +@defun getnet name-or-number +@defunx getnet +Returns a vector of information for the entry for @var{name-or-number} or +the next entry if an argument isn't given. The information is: + +@enumerate 0 +@item +official network name string +@item +list of network aliases strings +@item +integer network address type (@code{AF_INET}) +@item +integer network number +@end enumerate +@end defun + +@defun setnetent stay-open +@defunx setnetent +Rewinds the network entry table back to the begining if given an +argument. If the argument @var{stay-open} is @code{#f} the table will be closed +between calls to getnet. Otherwise, the table stays open. When +called without an argument, the network table is closed. +@end defun + +@defun getproto name-or-number +@defunx getproto +Returns a vector of information for the entry for @var{name-or-number} or +the next entry if an argument isn't given. The information is: + +@enumerate +@item +official protocol name string +@item +list of protocol aliases strings +@item +integer protocol number +@end enumerate +@end defun + +@defun setprotoent stay-open +@defunx setprotoent +Rewinds the protocol entry table back to the begining if given an +argument. If the argument @var{stay-open} is @code{#f} the table will be closed +between calls to getproto. Otherwise, the table stays open. When +called without an argument, the protocol table is closed. +@end defun + +@defun getserv name-or-port-number protocol +@defunx getserv +Returns a vector of information for the entry for @var{name-or-port-number} +and @var{protocol} or the next entry if arguments aren't given. The +information is: + +@enumerate 0 +@item +official service name string +@item +list of service aliases strings +@item +integer port number +@item +protocol +@end enumerate +@end defun + +@defun setservent stay-open +@defunx setservent +Rewinds the service entry table back to the begining if given an +argument. If the argument @var{stay-open} is @code{#f} the table will be closed +between calls to getserv. Otherwise, the table stays open. When +called without an argument, the service table is closed. +@end defun + +@node Internet Addresses and Socket Names, Socket, Host Data, Sockets +@subsection Internet Addresses and Socket Names + +@defun inet:string->address string +Returns the host address number (integer) for host @var{string} or +@code{#f} if not found. +@end defun + +@defun inet:address->string address +Converts an internet (integer) address to a string in numbers and dots +notation. This is an inverse function to inet:address. +@end defun + +@defun inet:network address +Returns the network number (integer) specified from @var{address} or +@code{#f} if not found. +@end defun + +@defun inet:local-network-address address +Returns the integer for the address of @var{address} within its local +network or @code{#f} if not found. +@end defun + +@defun inet:make-address network local-address +Returns the Internet address of @var{local-address} in @var{network}. +@end defun + +@noindent +The type @dfn{socket-name} is used for inquiries about open sockets in +the following procedures: + +@defun getsockname socket +Returns the socket-name of @var{socket}. Returns @code{#f} if +unsuccessful or @var{socket} is closed. +@end defun + +@defun getpeername socket +Returns the socket-name of the socket connected to @var{socket}. +Returns @code{#f} if unsuccessful or @var{socket} is closed. +@end defun + +@defun socket-name:family socket-name +Returns the integer code for the family of @var{socket-name}. +@end defun + +@defun socket-name:port-number socket-name +Returns the integer port number of @var{socket-name}. +@end defun + +@defun socket-name:address socket-name +Returns the integer Internet address for @var{socket-name}. +@end defun + + +@node Socket, , Internet Addresses and Socket Names, Sockets +@subsection Socket + +@noindent +When a port is returned from one of these calls it is unbuffered. +This allows both reading and writing to the same port to work. If you +want buffered ports you can (assuming sock-port is a socket i/o port): +@example +(require 'i/o-extensions) +(define i-port (duplicate-port sock-port "r")) +(define o-port (duplicate-port sock-port "w")) +@end example + +@defun make-stream-socket family +@defunx make-stream-socket family protocol + +Returns a @code{SOCK_STREAM} socket of type @var{family} using +@var{protocol}. If @var{family} has the value @code{AF_INET}, +@code{SO_REUSEADDR} will be set. The integer argument @var{protocol} +corresponds to the integer protocol numbers returned (as vector +elements) from @code{(getproto)}. If the @var{protocol} argument is not +supplied, the default (0) for the specified @var{family} is used. SCM +sockets look like ports opened for neither reading nor writing. +@end defun + +@defun make-stream-socketpair family +@defunx make-stream-socketpair family protocol + +Returns a pair (cons) of connected @code{SOCK_STREAM} (socket) ports of +type @var{family} using @var{protocol}. Many systems support only +socketpairs of the @code{af-unix} @var{family}. The integer argument +@var{protocol} corresponds to the integer protocol numbers returned (as +vector elements) from (getproto). If the @var{protocol} argument is +not supplied, the default (0) for the specified @var{family} is used. +@end defun + +@defun socket:shutdown socket how +Makes @var{socket} no longer respond to some or all operations depending on +the integer argument @var{how}: + +@enumerate 0 +@item +Further input is disallowed. +@item +Further output is disallowed. +@item +Further input or output is disallowed. +@end enumerate + +@code{Socket:shutdown} returns @var{socket} if successful, @code{#f} if +not. +@end defun + +@defun socket:connect inet-socket host-number port-number +@defunx socket:connect unix-socket pathname +Returns @var{socket} (changed to a read/write port) connected to the +Internet socket on host @var{host-number}, port @var{port-number} or +the Unix socket specified by @var{pathname}. Returns @code{#f} if not +successful. +@end defun + +@defun socket:bind inet-socket port-number +@defunx socket:bind unix-socket pathname +Returns @var{inet-socket} bound to the integer @var{port-number} or the +@var{unix-socket} bound to new socket in the file system at location +@var{pathname}. Returns @code{#f} if not successful. Binding a +@var{unix-socket} creates a socket in the file system that must be +deleted by the caller when it is no longer needed (using +@code{delete-file}). +@end defun + +@defun socket:listen socket backlog +The bound (@pxref{Socket, bind}) @var{socket} is readied to +accept connections. The positive integer @var{backlog} specifies how +many pending connections will be allowed before further connection +requests are refused. Returns @var{socket} (changed to a read-only +port) if successful, @code{#f} if not. +@end defun + +@defun char-ready? listen-socket +The input port returned by a successful call to @code{socket:listen} can +be polled for connections by @code{char-ready?} (@pxref{Files and Ports, +char-ready?}). This avoids blocking on connections by +@code{socket:accept}. +@end defun + +@defun socket:accept socket +Accepts a connection on a bound, listening @var{socket}. Returns an +input/output port for the connection. +@end defun + +@noindent +The following example is not too complicated, yet shows the use of +sockets for multiple connections without input blocking. + +@example +;;;; Scheme chat server + +;;; This program implements a simple `chat' server which accepts +;;; connections from multiple clients, and sends to all clients any +;;; characters received from any client. + +;;; To connect to chat `telnet localhost 8001' + +(require 'socket) +(require 'i/o-extensions) + +(let ((listener-socket (socket:bind (make-stream-socket af_inet) 8001)) + (connections '())) + (socket:listen listener-socket 5) + (do () (#f) + (cond ((char-ready? listener-socket) + (let ((con (socket:accept listener-socket))) + (display "accepting connection from ") + (display (getpeername con)) + (newline) + (set! connections (cons con connections)) + (display "connected" con) + (newline con)))) + (set! connections + (let next ((con-list connections)) + (cond ((null? con-list) '()) + (else + (let ((con (car con-list))) + (cond ((char-ready? con) + (let ((c (read-char con))) + (cond ((eof-object? c) + (display "closing connection from ") + (display (getpeername con)) + (newline) + (close-port con) + (next (cdr con-list))) + (else + (for-each (lambda (con) + (file-set-position con 0) + (write-char c con) + (file-set-position con 0)) + connections) + (cons con (next (cdr con-list))))))) + (else (cons con (next (cdr con-list)))))))))))) +@end example + +@noindent +You can use @samp{telnet localhost 8001} to connect to the chat server, +or you can use a client written in scheme: + +@example +;;;; Scheme chat client + +;;; this program connects to socket 8001. It then sends all +;;; characters from current-input-port to the socket and sends all +;;; characters from the socket to current-output-port. + +(require 'socket) +(require 'i/o-extensions) + +(define con (make-stream-socket af_inet)) +(set! con (socket:connect con (inet:string->address "localhost") 8001)) + +(do ((cs #f (and (char-ready? con) (read-char con))) + (ct #f (and (char-ready?) (read-char)))) + ((or (eof-object? cs) (eof-object? ct)) + (close-port con)) + (cond (cs (display cs))) + (cond (ct (file-set-position con 0) + (display ct con) + (file-set-position con 0)))) +@end example + + +@node The Implementation, Procedure and Macro Index, Packages, Top +@chapter The Implementation + +@menu +* Data Types:: +* Operations:: +* Improvements To Make:: +* Finishing Dynamic Linking:: +@end menu + +@node Data Types, Operations, The Implementation, The Implementation +@section Data Types + +@noindent +In the descriptions below it is assumed that @code{long int}s are 32 +bits in length. Acutally, SCM is written to work with any @code{long +int} size larger than 31 bits. With some modification, SCM could work +with word sizes as small as 24 bits. + +@noindent +All SCM objects are represented by type @dfn{SCM}. Type @code{SCM} come +in 2 basic flavors, Immediates and Cells: + +@menu +* Immediates:: +* Cells:: Non-Immediate types +* Header Cells:: Malloc objects +* Subr Cells:: Built-in and Compiled Procedures +* Ptob Cells:: I/O ports +* Smob Cells:: Miscellaneous datatypes +* Data Type Representations:: How they all fit together +@end menu + +@node Immediates, Cells, Data Types, Data Types +@subsection Immediates + +@noindent +An @dfn{immediate} is a data type contained in type @code{SCM} +(@code{long int}). The type codes distinguishing immediate types from +each other vary in length, but reside in the low order bits. + +@defmac IMP x +@defmacx NIMP x +Return non-zero if the @code{SCM} object @var{x} is an immediate or +non-immediate type, respectively. +@end defmac + +@deftp Immediate inum +immediate 30 bit signed integer. An INUM is flagged by a @code{1} in +the second to low order bit position. The high order 30 bits are used +for the integer's value. + +@defmac INUMP x +@defmacx NINUMP x +Return non-zero if the @code{SCM} @var{x} is an immediate integer or not +an immediate integer, respectively. +@end defmac + +@defmac INUM x +Returns the C @code{long integer} corresponding to @code{SCM} @var{x}. +@end defmac + +@defmac MAKINUM x +Returns the @code{SCM} inum corresponding to C @code{long integer} x. +@end defmac + +@defvr {Immediate Constant} INUM0 +is equivalent to @code{MAKINUM(0)}. +@end defvr + +Computations on INUMs are performed by converting the arguments to C +integers (by a shift), operating on the integers, and converting the +result to an inum. The result is checked for overflow by converting +back to integer and checking the reverse operation. + +The shifts used for conversion need to be signed shifts. If the C +implementation does not support signed right shift this fact is detected +in a #if statement in @file{scmfig.h} and a signed right shift, +@code{SRS}, is constructed in terms of unsigned right shift. +@end deftp + +@deftp Immediate ichr +characters. + +@defmac ICHRP x +Return non-zero if the @code{SCM} object @var{x} is a character. +@end defmac + +@defmac ICHR x +Returns corresponding @code{unsigned char}. +@end defmac + +@defmac MAKICHR x +Given @code{char} @var{x}, returns @code{SCM} character. +@end defmac + +@end deftp + +@deftp Immediate iflags +These are frequently used immediate constants. +@deftypevr {Immediate Constant} SCM BOOL_T +@code{#t} +@end deftypevr +@deftypevr {Immediate Constant} SCM BOOL_F +@code{#f} +@end deftypevr +@deftypevr {Immediate Constant} SCM EOL +@code{()}. If @code{SICP} is @code{#define}d, @code{EOL} is +@code{#define}d to be identical with @code{BOOL_F}. In this case, both +print as @code{#f}. +@end deftypevr +@deftypevr {Immediate Constant} SCM EOF_VAL +end of file token, @code{#<eof>}. +@end deftypevr +@deftypevr {Immediate Constant} SCM UNDEFINED +@code{#<undefined>} used for variables which have not been defined and +absent optional arguments. +@end deftypevr +@deftypevr {Immediate Constant} SCM UNSPECIFIED +@code{#<unspecified>} is returned for those procedures whose return +values are not specified. +@end deftypevr + +@end deftp + +@defmac IFLAGP n +Returns non-zero if @var{n} is an ispcsym, isym or iflag. +@end defmac + +@defmac ISYMP n +Returns non-zero if @var{n} is an ispcsym or isym. +@end defmac + +@defmac ISYMNUM n +Given ispcsym, isym, or iflag @var{n}, returns its index in the C array +@code{isymnames[]}. +@end defmac + +@defmac ISYMCHARS n +Given ispcsym, isym, or iflag @var{n}, returns its @code{char *} +representation (from @code{isymnames[]}). +@end defmac + +@defmac MAKSPCSYM n +Returns @code{SCM} ispcsym @var{n}. +@end defmac + +@defmac MAKISYM n +Returns @code{SCM} iisym @var{n}. +@end defmac + +@defmac MAKIFLAG n +Returns @code{SCM} iflag @var{n}. +@end defmac + +@defvar isymnames +An array of strings containing the external representations of all the +ispcsym, isym, and iflag immediates. Defined in @file{repl.c}. +@end defvar + +@defvr Constant NUM_ISPCSYM +@defvrx Constant NUM_ISYMS +The number of ispcsyms and ispcsyms+isyms, respectively. Defined in +@file{scm.h}. +@end defvr + +@deftp Immediate isym +@code{and}, @code{begin}, @code{case}, @code{cond}, @code{define}, +@code{do}, @code{if}, @code{lambda}, @code{let}, @code{let*}, +@code{letrec}, @code{or}, @code{quote}, @code{set!}, @code{#f}, +@code{#t}, @code{#<undefined>}, @code{#<eof>}, @code{()}, and +@code{#<unspecified>}. + +@deftpx {CAR Immediate} ispcsym +special symbols: syntax-checked versions of first 14 isyms +@end deftp + +@deftp {CAR Immediate} iloc +indexes to a variable's location in environment +@end deftp + +@deftp {CAR Immediate} gloc +pointer to a symbol's value cell +@end deftp + +@deftp Immediate CELLPTR +pointer to a cell (not really an immediate type, but here for +completeness). Since cells are always 8 byte aligned, a pointer to a +cell has the low order 3 bits @code{0}. + +There is one exception to this rule, @emph{CAR Immediate}s, described +next. +@end deftp + +@noindent +A @dfn{CAR Immediate} is an Immediate point which can only occur in the +@code{CAR}s of evaluated code (as a result of @code{ceval}'s memoization +process). + +@node Cells, Header Cells, Immediates, Data Types +@subsection Cells + +@noindent +@dfn{Cell}s represent all SCM objects other than immediates. A cell has +a @code{CAR} and a @code{CDR}. Low-order bits in @code{CAR} identify +the type of object. The rest of @code{CAR} and @code{CDR} hold object +data. The number after @code{tc} specifies how many bits are in the +type code. For instance, @code{tc7} indicates that the type code is 7 +bits. + +@defmac NEWCELL x +Allocates a new cell and stores a pointer to it in @code{SCM} local +variable @var{x}. + +Care needs to be taken that stores into the new cell pointed to by +@var{x} do not create an inconsistent object. @xref{Signals}. +@end defmac + +@noindent +All of the C macros decribed in this section assume that their argument +is of type @code{SCM} and points to a cell (@code{CELLPTR}). + +@defmac CAR x +@defmacx CDR x +Returns the @code{car} and @code{cdr} of cell @var{x}, respectively. +@end defmac + +@defmac TYP3 x +@defmacx TYP7 x +@defmacx TYP16 x +Returns the 3, 7, and 16 bit type code of a cell. +@end defmac + +@deftp Cell tc3_cons +scheme cons-cell returned by (cons arg1 arg2). + +@defmac CONSP x +@defmacx NCONSP x +Returns non-zero if @var{x} is a @code{tc3_cons} or isn't, respectively. +@end defmac +@end deftp + +@deftp Cell tc3_closure +applicable object returned by (lambda (args) @dots{}). +@code{tc3_closure}s have a pointer to other the body of the procedure in +the @code{CAR} and a pointer to the environment in the @code{CDR}. + +@defmac CLOSUREP x +Returns non-zero if @var{x} is a @code{tc3_closure}. +@end defmac + +@defmac CODE x +@defmacx ENV x +Returns the code body or environment of closure @var{x}, respectively. +@end defmac + +@end deftp + +@node Header Cells, Subr Cells, Cells, Data Types +@subsection Header Cells + +@noindent +@dfn{Header}s are Cells whose @code{CDR}s point elsewhere in memory, +such as to memory allocated by @code{malloc}. + +@deftp Header spare +spare @code{tc7} type code +@end deftp + +@deftp Header tc7_vector +scheme vector. + +@defmac VECTORP x +@defmacx NVECTORP x +Returns non-zero if @var{x} is a @code{tc7_vector} or if not, respectively. +@end defmac + +@defmac VELTS x +@defmacx LENGTH x +Returns the C array of @code{SCM}s holding the elements of vector +@var{x} or its length, respectively. +@end defmac +@end deftp + +@deftp Header tc7_ssymbol +static scheme symbol (part of initial system) + +@deftpx Header tc7_msymbol +@code{malloc}ed scheme symbol (can be GCed) + +@defmac SYMBOLP x +Returns non-zero if @var{x} is a @code{tc7_ssymbol} or +@code{tc7_msymbol}. +@end defmac + +@defmac CHARS x +@defmacx UCHARS x +@defmacx LENGTH x +Returns the C array of @code{char}s or as @code{unsigned char}s holding +the elements of symbol @var{x} or its length, respectively. +@end defmac +@end deftp + +@deftp Header tc7_string +scheme string + +@defmac STRINGP x +@defmacx NSTRINGP x +Returns non-zero if @var{x} is a @code{tc7_string} or isn't, +respectively. +@end defmac + +@defmac CHARS x +@defmacx UCHARS x +@defmacx LENGTH x +Returns the C array of @code{char}s or as @code{unsigned char}s holding +the elements of string @var{x} or its length, respectively. +@end defmac +@end deftp + +@deftp Header tc7_bvect +uniform vector of booleans (bit-vector) +@end deftp + +@deftp Header tc7_ivect +uniform vector of integers +@end deftp + +@deftp Header tc7_uvect +uniform vector of non-negative integers +@end deftp + +@deftp Header tc7_fvect +uniform vector of short inexact real numbers +@end deftp + +@deftp Header tc7_dvect +uniform vector of double precision inexact real numbers +@end deftp + +@deftp Header tc7_cvect +uniform vector of double precision inexact complex numbers +@end deftp + +@deftp Header tc7_contin +applicable object produced by call-with-current-continuation +@end deftp + +@deftp Header tc7_cclo +Subr and environment for compiled closure + +A cclo is similar to a vector (and is GCed like one), but can be applied +as a function: + +@enumerate +@item +the cclo itself is consed onto the head of the argument list +@item +the first element of the cclo is applied to that list. Cclo invocation +is currently not tail recursive when given 2 or more arguments. +@end enumerate + +@defun makcclo proc len +makes a closure from the @emph{subr} @var{proc} with @var{len}-1 extra +locations for @code{SCM} data. Elements of a @var{cclo} are referenced +using @code{VELTS(cclo)[n]} just as for vectors. +@end defun +@end deftp + +@node Subr Cells, Ptob Cells, Header Cells, Data Types +@subsection Subr Cells + +@noindent +A @dfn{Subr} is a header whose @code{CDR} points to a C code procedure. +Scheme primitive procedures are subrs. Except for the arithmetic +@code{tc7_cxr}s, the C code procedures will be passed arguments (and +return results) of type @code{SCM}. + +@deftp Subr tc7_asubr +associative C function of 2 arguments. Examples are @code{+}, @code{-}, +@code{*}, @code{/}, @code{max}, and @code{min}. +@end deftp + +@deftp Subr tc7_subr_0 +C function of no arguments. +@end deftp + +@deftp Subr tc7_subr_1 +C function of one argument. +@end deftp + +@deftp Subr tc7_cxr +These subrs are handled specially. If inexact numbers are enabled, the +@code{CDR} should be a function which takes and returns type +@code{double}. Conversions are handled in the interpreter. + +@code{floor}, @code{ceiling}, @code{truncate}, @code{round}, +@code{$sqrt}, @code{$abs}, @code{$exp}, @code{$log}, @code{$sin}, +@code{$cos}, @code{$tan}, @code{$asin}, @code{$acos}, @code{$atan}, +@code{$sinh}, @code{$cosh}, @code{$tanh}, @code{$asinh}, @code{$acosh}, +@code{$atanh}, and @code{exact->inexact} are defined this way. + +If the @code{CDR} is @code{0} (@code{NULL}), the name string of the +procedure is used to control traversal of its list structure argument. + +@code{car}, @code{cdr}, @code{caar}, @code{cadr}, @code{cdar}, +@code{cddr}, @code{caaar}, @code{caadr}, @code{cadar}, @code{caddr}, +@code{cdaar}, @code{cdadr}, @code{cddar}, @code{cdddr}, @code{caaaar}, +@code{caaadr}, @code{caadar}, @code{caaddr}, @code{cadaar}, +@code{cadadr}, @code{caddar}, @code{cadddr}, @code{cdaaar}, +@code{cdaadr}, @code{cdadar}, @code{cdaddr}, @code{cddaar}, +@code{cddadr}, @code{cdddar}, and @code{cddddr} are defined this way. +@end deftp + +@deftp Subr tc7_subr_3 +C function of 3 arguments. +@end deftp + +@deftp Subr tc7_subr_2 +C function of 2 arguments. +@end deftp + +@deftp Subr tc7_rpsubr +transitive relational predicate C function of 2 arguments. The C +function should return either @code{BOOL_T} or @code{BOOL_F}. +@end deftp + +@deftp Subr tc7_subr_1o +C function of one optional argument. If the optional argument is not +present, @code{UNDEFINED} is passed in its place. +@end deftp + +@deftp Subr tc7_subr_2o +C function of 1 required and 1 optional argument. If the optional +argument is not present, @code{UNDEFINED} is passed in its place. +@end deftp + +@deftp Subr tc7_lsubr_2 +C function of 2 arguments and a list of (rest of) @code{SCM} arguments. +@end deftp + +@deftp Subr tc7_lsubr +C function of list of @code{SCM} arguments. +@end deftp + +@node Ptob Cells, Smob Cells, Subr Cells, Data Types +@subsection Ptob Cells + +@noindent +A @dfn{ptob} is a port object, capable of delivering or accepting +characters. @xref{Ports, , , r4rs, Revised(4) Report on the Algorithmic +Language Scheme}. Unlike the types described so far, new varieties of +ptobs can be defined dynamically (@pxref{Defining Ptobs}). These are +the initial ptobs: + +@deftp ptob tc16_inport +input port. +@end deftp + +@deftp ptob tc16_outport +output port. +@end deftp + +@deftp ptob tc16_ioport +input-output port. +@end deftp + +@deftp ptob tc16_inpipe +input pipe created by @code{popen()}. +@end deftp + +@deftp ptob tc16_outpipe +output pipe created by @code{popen()}. +@end deftp + +@deftp ptob tc16_strport +String port created by @code{cwos()} or @code{cwis()}. +@end deftp + +@deftp ptob tc16_sfport +Software (virtual) port created by @code{mksfpt()} (@pxref{Soft Ports}). +@end deftp + +@defmac PORTP x +@defmacx OPPORTP x +@defmacx OPINPORTP x +@defmacx OPOUTPORTP x +@defmacx INPORTP x +@defmacx OUTPORTP x +Returns non-zero if @var{x} is a port, open port, open input-port, open +output-port, input-port, or output-port, respectively. +@end defmac + +@defmac OPENP x +@defmacx CLOSEDP x +Returns non-zero if port @var{x} is open or closed, respectively. +@end defmac + +@defmac STREAM x +Returns the @code{FILE *} stream for port @var{x}. +@end defmac + +@noindent +Ports which are particularly well behaved are called @dfn{fport}s. +Advanced operations like @code{file-position} and @code{reopen-file} +only work for fports. + +@defmac FPORTP x +@defmacx OPFPORTP x +@defmacx OPINFPORTP x +@defmacx OPOUTFPORTP x +Returns non-zero if @var{x} is a port, open port, open input-port, or +open output-port, respectively. +@end defmac + +@node Smob Cells, Data Type Representations, Ptob Cells, Data Types +@subsection Smob Cells + +@noindent +A @dfn{smob} is a miscellaneous datatype. The type code and GCMARK bit +occupy the lower order 16 bits of the @code{CAR} half of the cell. The +rest of the @code{CAR} can be used for sub-type or other information. +The @code{CDR} contains data of size long and is often a pointer to +allocated memory. + +@noindent +Like ptobs, new varieties of smobs can be defined dynamically +(@pxref{Defining Smobs}). These are the initial smobs: + +@deftp smob tc_free_cell +unused cell on the freelist. +@end deftp + +@deftp smob tc16_flo +single-precision float. + +Inexact number data types are subtypes of type @code{tc16_flo}. If the +sub-type is: + +@enumerate 0 +@item +a single precision float is contained in the @code{CDR}. +@item +@code{CDR} is a pointer to a @code{malloc}ed double. +@end enumerate +@enumerate 3 +@item +@code{CDR} is a pointer to a @code{malloc}ed pair of doubles. +@end enumerate + +@deftp smob tc_dblr +double-precision float. +@end deftp + +@deftp smob tc_dblc +double-precision complex. +@end deftp +@end deftp + +@deftp smob tc16_bigpos +@deftpx smob tc16_bigneg +positive and negative bignums, respectively. + +Scm has large precision integers called bignums. They are stored in +sign-magnitude form with the sign occuring in the type code of the SMOBs +bigpos and bigneg. The magnitude is stored as a @code{malloc}ed array +of type @code{BIGDIG} which must be an unsigned integral type with size +smaller than @code{long}. @code{BIGRAD} is the radix associated with +@code{BIGDIG}. +@end deftp + +@deftp smob tc16_promise +made by DELAY. @xref{Control features, , , r4rs, Revised(4) Scheme}. +@end deftp + +@deftp smob tc16_arbiter +synchronization object. @xref{Process Synchronization}. +@end deftp + +@deftp smob tc16_macro +macro expanding function. @xref{Low Level Syntactic Hooks}. +@end deftp + +@deftp smob tc16_array +multi-dimensional array. @xref{Arrays}. + +This type implements both conventional arrays (those with arbitrary data +as elements @pxref{Conventional Arrays}) and uniform arrays (those with +elements of a uniform type @pxref{Uniform Array}). + +Conventional Arrays have a pointer to a vector for their @code{CDR}. +Uniform Arrays have a pointer to a Uniform Vector type (string, bvect, +ivect, uvect, fvect, dvect, or cvect) in their @code{CDR}. +@end deftp + + +@node Data Type Representations, , Smob Cells, Data Types +@subsection Data Type Representations + +@format +@r{IMMEDIATE: B,D,E,F=data bit, C=flag code, P=pointer address bit} +@t{ ................................ +inum BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB10 +ichr BBBBBBBBBBBBBBBBBBBBBBBB11110100 +iflag CCCCCCC101110100 +isym CCCCCCC001110100} +@r{ IMCAR: only in car of evaluated code, cdr has cell's GC bit} +@t{ispcsym 000CCCC00CCCC100 +iloc 0DDDDDDDDDDDDDDDEFFFFFFF11111100 +pointer PPPPPPPPPPPPPPPPPPPPPPPPPPPPP000 +gloc PPPPPPPPPPPPPPPPPPPPPPPPPPPPP001} + +@r{ HEAP CELL: G=gc_mark; 1 during mark, 0 other times. + 1s and 0s here indicate type. G missing means sys (not GC'd) + SIMPLE:} +@t{cons ..........SCM car..............0 ...........SCM cdr.............G +closure ..........SCM code...........011 ...........SCM env.............G + HEADERs: +ssymbol .........long length....G0000101 ..........char *chars........... +msymbol .........long length....G0000111 ..........char *chars........... +string .........long length....G0001101 ..........char *chars........... +vector .........long length....G0001111 ...........SCM **elts........... +bvect .........long length....G0010101 ..........long *words........... + spare G0010111 +ivect .........long length....G0011101 ..........long *words........... +uvect .........long length....G0011111 ......unsigned long *words...... + spare G0100101 + spare G0100111 +fvect .........long length....G0101101 .........float *words........... +dvect .........long length....G0101111 ........double *words........... +cvect .........long length....G0110101 ........double *words........... + +contin .........long length....G0111101 .............*regs.............. +cclo .........long length....G0111111 ...........SCM **elts...........} +@r{ SUBRs:} +@t{ spare 010001x1 + spare 010011x1 +subr_0 ..........int hpoff.....01010101 ...........SCM (*f)()........... +subr_1 ..........int hpoff.....01010111 ...........SCM (*f)()........... +cxr ..........int hpoff.....01011101 .........double (*f)().......... +subr_3 ..........int hpoff.....01011111 ...........SCM (*f)()........... +subr_2 ..........int hpoff.....01100101 ...........SCM (*f)()........... +asubr ..........int hpoff.....01100111 ...........SCM (*f)()........... +subr_1o ..........int hpoff.....01101101 ...........SCM (*f)()........... +subr_2o ..........int hpoff.....01101111 ...........SCM (*f)()........... +lsubr_2 ..........int hpoff.....01110101 ...........SCM (*f)()........... +lsubr_2n..........int hpoff.....01110111 ...........SCM (*f)()........... +rpsubr ..........int hpoff.....01111101 ...........SCM (*f)()...........} +@r{ PTOBs:} +@t{ port 0bwroxxxxxxxxG1110111 ..........FILE *stream.......... + socket ttttttt 00001xxxxxxxxG1110111 ..........FILE *stream.......... + inport uuuuuuuuuuU00011xxxxxxxxG1110111 ..........FILE *stream.......... +outport 0000000000000101xxxxxxxxG1110111 ..........FILE *stream.......... + ioport uuuuuuuuuuU00111xxxxxxxxG1110111 ..........FILE *stream.......... +fport 00 00000000G1110111 ..........FILE *stream.......... +pipe 00 00000001G1110111 ..........FILE *stream.......... +strport 00 00000010G1110111 ..........FILE *stream.......... +sfport 00 00000011G1110111 ..........FILE *stream..........} +@r{ SMOBs:} +@t{free_cell + 000000000000000000000000G1111111 ...........*free_cell........000 +flo 000000000000000000000001G1111111 ...........float num............ +dblr 000000000000000100000001G1111111 ..........double *real.......... +dblc 000000000000001100000001G1111111 .........complex *cmpx.......... +bignum ...int length...0000001 G1111111 .........short *digits.......... +bigpos ...int length...00000010G1111111 .........short *digits.......... +bigneg ...int length...00000011G1111111 .........short *digits.......... + xxxxxxxx = code assigned by newsmob(); +promise 000000000000000fxxxxxxxxG1111111 ...........SCM val.............. +arbiter 000000000000000lxxxxxxxxG1111111 ...........SCM name............. +macro 000000000000000mxxxxxxxxG1111111 ...........SCM name............. +array ...short rank..cxxxxxxxxG1111111 ............*array..............} +@end format + +@node Operations, Improvements To Make, Data Types, The Implementation +@section Operations + +@menu +* Garbage Collection:: Automatically reclaims unused storage +* Signals:: +* C Macros:: +* Changing Scm:: +* Defining Subrs:: +* Defining Smobs:: +* Defining Ptobs:: +* Calling Scheme From C:: +* Callbacks:: +* Type Conversions:: For use with C code. +* Continuations:: For C and SCM +* Evaluation:: Why SCM is fast +@end menu + +@node Garbage Collection, Signals, Operations, Operations +@subsection Garbage Collection + +The garbage collector is in the latter half of @file{sys.c}. The +primary goal of @dfn{garbage collection} (or @dfn{GC}) is to recycle +those cells no longer in use. Immediates always appear as parts of +other objects, so they are not subject to explicit garbage collection. + +All cells reside in the @dfn{heap} (composed of @dfn{heap segments}). +Note that this is different from what Computer Science usually defines +as a heap. + +@menu +* Marking Cells:: +* Sweeping the Heap:: +@end menu + +@node Marking Cells, Sweeping the Heap, Garbage Collection, Garbage Collection +@subsubsection Marking Cells + +The first step in garbage collection is to @dfn{mark} all heap objects +in use. Each heap cell has a bit reserved for this purpose. For pairs +(cons cells) the lowest order bit (0) of the CDR is used. For other +types, bit 8 of the CAR is used. The GC bits are never set except +during garbage collection. Special C macros are defined in @file{scm.h} +to allow easy manipulation when GC bits are possibly set. @code{CAR}, +@code{TYP3}, and @code{TYP7} can be used on GC marked cells as they are. + +@defmac GCCDR x +Returns the CDR of a cons cell, even if that cell has been GC marked. +@end defmac +@defmac GCTYP16 x +Returns the 16 bit type code of a cell. +@end defmac + +We need to (recursively) mark only a few objects in order to assure that +all accessible objects are marked. Those objects are +@code{sys_protects[]} (for example, @code{dynwinds}), the current +C-stack and the hash table for symbols, @dfn{symhash}. + +@deftypefun void gc_mark (SCM @var{obj}) +The function @code{gc_mark()} is used for marking SCM cells. If +@var{obj} is marked, @code{gc_mark()} returns. If @var{obj} is +unmarked, gc_mark sets the mark bit in @var{obj}, then calls +@code{gc_mark()} on any SCM components of @var{obj}. The last call to +@code{gc_mark()} is tail-called (looped). +@end deftypefun + +@deftypefun void mark_locations (STACKITEM @var{x[]}, sizet @var{len})) +The function @code{mark_locations} is used for marking segments of +C-stack or saved segments of C-stack (marked continuations). The +argument @var{len} is the size of the stack in units of size +@code{(STACKITEM)}. + +Each longword in the stack is tried to see if it is a valid cell pointer +into the heap. If it is, the object itself and any objects it points to +are marked using @code{gc_mark}. If the stack is word rather than +longword aligned @code{(#define WORD_ALIGN)}, both alignments are tried. +This arrangement will occasionally mark an object which is no longer +used. This has not been a problem in practice and the advantage of +using the c-stack far outweighs it. +@end deftypefun + +@node Sweeping the Heap, , Marking Cells, Garbage Collection +@subsubsection Sweeping the Heap + +After all found objects have been marked, the heap is swept. + +The storage for strings, vectors, continuations, doubles, complexes, and +bignums is managed by malloc. There is only one pointer to each malloc +object from its type-header cell in the heap. This allows malloc +objects to be freed when the associated heap object is garbage +collected. + +@deftypefun static void gc_sweep () +The function @code{gc_sweep} scans through all heap segments. The mark +bit is cleared from marked cells. Unmarked cells are spliced into +@var{freelist}, where they can again be returned by invocations of +@code{NEWCELL}. + +If a type-header cell pointing to malloc space is unmarked, the malloc +object is freed. If the type header of smob is collected, the smob's +@code{free} procedure is called to free its storage. +@end deftypefun + +@node Signals, C Macros, Garbage Collection, Operations +@subsection Signals + +@defun init_signals +(in @file{scm.c}) initializes handlers for @code{SIGINT} and +@code{SIGALRM} if they are supported by the C implementation. All of +the signal handlers immediately reestablish themselves by a call to +@code{signal()}. +@end defun + +@defun int_signal sig +@defunx alrm_signal sig +The low level handlers for @code{SIGINT} and @code{SIGALRM}. +@end defun + +If an interrupt handler is defined when the interrupt is received, the +code is interpreted. If the code returns, execution resumes from where +the interrupt happened. @code{Call-with-current-continuation} allows +the stack to be saved and restored. + +SCM does not use any signal masking system calls. These are not a +portable feature. However, code can run uninterrupted by use of the C +macros @code{DEFER_INTS} and @code{ALLOW_INTS}. + +@defmac DEFER_INTS +sets the global variable @code{ints_disabled} to 1. If an interrupt +occurs during a time when @code{ints_disabled} is 1 one of the global +variables @code{sig_deferred} or @code{alrm_deferred} is set to 1 and +the handler returns. + +@defmacx ALLOW_INTS +Checks the deferred variables and if set the appropriate handler is +called. + +Calls to @code{DEFER_INTS} can not be nested. An @code{ALLOW_INTS} must +happen before another @code{DEFER_INTS} can be done. In order to check +that this constraint is satisfied @code{#define CAREFUL_INTS} in +@file{scmfig.h}. +@end defmac + +@node C Macros, Changing Scm, Signals, Operations +@subsection C Macros + + +@defmac ASSERT cond arg pos subr +signals an error if the expression (@var{cond}) is 0. @var{arg} is the +offending object, @var{subr} is the string naming the subr, and +@var{pos} indicates the position or type of error. @var{pos} can be one +of + +@itemize @bullet +@item @code{ARGn} @i{(> 5 or unknown ARG number)} +@item @code{ARG1} +@item @code{ARG2} +@item @code{ARG3} +@item @code{ARG4} +@item @code{ARG5} +@item @code{WNA} @i{(wrong number of args)} +@item @code{OVFLOW} +@item @code{OUTOFRANGE} +@item @code{NALLOC} +@item @code{EXIT} +@item @code{HUP_SIGNAL} +@item @code{INT_SIGNAL} +@item @code{FPE_SIGNAL} +@item @code{BUS_SIGNAL} +@item @code{SEGV_SIGNAL} +@item @code{ALRM_SIGNAL} +@item a C string @code{(char *)} +@end itemize + +Error checking is not done by @code{ASSERT} if the flag @code{RECKLESS} +is defined. An error condition can still be signaled in this case with +a call to @code{wta(arg, pos, subr)}. +@end defmac + +@defmac ASRTGO cond label +@code{goto} @var{label} if the expression (@var{cond}) is 0. Like +@code{ASSERT}, @code{ASRTGO} does is not active if the flag +@code{RECKLESS} is defined. +@end defmac + + +@node Changing Scm, Defining Subrs, C Macros, Operations +@subsection Changing Scm + +@noindent +When writing C-code for SCM, a precaution is recommended. If your +routine allocates a non-cons cell which will @emph{not} be incorporated +into a @code{SCM} object which is returned, you need to make sure that a +@code{SCM} variable in your routine points to that cell as long as part +of it might be referenced by your code. + +@noindent +In order to make sure this @code{SCM} variable does not get optimized +out you can put this assignment after its last possible use: + +@example +SCM_dummy1 = @i{foo}; +@end example + +@noindent +or put this assignment somewhere in your routine: + +@example +SCM_dummy1 = (SCM) &@i{foo}; +@end example + +@noindent +@code{SCM_dummy} variables are not currently defined. Passing the +address of the local @code{SCM} variable to @emph{any} procedure also +protects it. + +@noindent +Also, if you maintain a static pointer to some (non-immediate) +@code{SCM} object, you must either make your pointer be the value cell +of a symbol (see @code{errobj} for an example) or make your pointer be +one of the @code{sys_protects} (see @code{dynwinds} for an example). +The former method is prefered since it does not require any changes to +the SCM distribution. + +@noindent +To add a C routine to scm: + +@enumerate +@item +choose the appropriate subr type from the type list. +@item +write the code and put into @file{scm.c}. +@item +add a @code{make_subr} or @code{make_gsubr} call to @code{init_scm}. Or +put an entry into the appropriate @code{iproc} structure. +@end enumerate + +To add a package of new procedures to scm (see @file{crs.c} for +example): + +@enumerate +@item +create a new C file (@file{@i{foo}.c}). +@item +at the front of @file{@i{foo}.c} put declarations for strings for your +procedure names. + +@example +static char s_twiddle_bits[]="twiddle-bits!"; +static char s_bitsp[]="bits?"; +@end example + +@item +choose the appropriate subr types from the type list in @file{code.doc}. +@item +write the code for the procedures and put into @file{@i{foo}.c} +@item +create one @code{iproc} structure for each subr type used in @file{@i{foo}.c} + +@example +static iproc subr3s[]= @{ + @{s_twiddle-bits,twiddle-bits@}, + @{s_bitsp,bitsp@}, + @{0,0@} @}; +@end example + +@item +create an @code{init_@i{<name of file>}} routine at the end of the file +which calls @code{init_iprocs} with the correct type for each of the +@code{iproc}s created in step 5. + +@example +void init_@i{foo}() +@{ + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(subr3s, tc7_subr_3); +@} +@end example + +If your package needs to have a @dfn{finalization} routine called to +free up storage, close files, etc, then also have a line in +@code{init_@i{foo}} like: + +@example +add_final(final_@i{foo}); +@end example + +@code{final_@i{foo}} should be a (void) procedure of no arguments. The +finals will be called in opposite order from their definition. + +The line: + +@example +add_feature("@i{foo}"); +@end example + +will append a symbol @code{'@i{foo}} to the (list) value of +@code{*features*}. +@item +put any scheme code which needs to be run as part of your package into +@file{I@i{foo}.scm}. +@item +put an @code{if} into @file{Init.scm} which loads @file{I@i{foo}.scm} if +your package is included: + +@example +(if (defined? twiddle-bits!) + (load (in-vicinity (implementation-vicinity) + "I@i{foo}" + (scheme-file-suffix)))) +@end example + +or use @code{(provided? '@i{foo})} instead of @code{(defined? +twiddle-bits!)} if you have added the feature. +@item +put documentation of the new procedures into @file{@i{foo}.doc} +@item +add lines to your @file{Makefile} to compile and link SCM with your +object file. Add a @code{init_@i{foo}\(\)\;} to the @code{INITS=@dots{}} +line at the beginning of the makefile. +@end enumerate + +@noindent +These steps should allow your package to be linked into SCM with a +minimum of difficulty. Your package should also work with dynamic +linking if your SCM has this capability. + +Special forms (new syntax) can be added to scm. + +@enumerate +@item +define a new @code{MAKISYM} in @file{scm.h} and increment +@code{NUM_ISYMS}. +@item +add a string with the new name in the corresponding place in +@code{isymnames} in @file{repl.c}. +@item +add @code{case:} clause to @code{ceval()} near @code{i_quasiquote} (in +@file{eval.c}). +@end enumerate + +@noindent +New syntax can now be added without recompiling SCM by the use of the +@code{procedure->syntax}, @code{procedure->macro}, +@code{procedure->memoizing-macro}, and @code{defmacro}. For details, +@xref{Syntax Extensions}. + +@node Defining Subrs, Defining Smobs, Changing Scm, Operations +@subsection Defining Subrs + +@noindent +If @dfn{CCLO} is @code{#define}d when compiling, the compiled closure +feature will be enabled. It is automatically enabled if dynamic linking +is enabled. + +@noindent +The SCM interpreter directly recognizes subrs taking small numbers of +arguments. In order to create subrs taking larger numbers of arguments +use: + +@defun make_gsubr name req opt rest fcn +returns a cclo (compiled closure) object of name @code{char *} +@var{name} which takes @code{int} @var{req} required arguments, +@code{int} @var{opt} optional arguments, and a list of rest arguments if +@code{int} @var{rest} is 1 (0 for not). + +@code{SCM (*fcn)()} is a pointer to a C function to do the work. + +The C function will always be called with @var{req} + @var{opt} + +@var{rest} arguments, optional arguments not supplied will be passed +@code{UNDEFINED}. An error will be signaled if the subr is called with +too many or too few arguments. Currently a total of 10 arguments may be +specified, but increasing this limit should not be difficult. + +@example +/* A silly example, taking 2 required args, + 1 optional, and a list of rest args */ + +#include <scm.h> + +SCM gsubr_21l(req1,req2,opt,rst) + SCM req1,req2,opt,rst; +@{ + lputs("gsubr-2-1-l:\n req1: ", cur_outp); + display(req1,cur_outp); + lputs("\n req2: ", cur_outp); + display(req2,cur_outp); + lputs("\n opt: ", cur_outp); + display(opt,cur_outp); + lputs("\n rest: ", cur_outp); + display(rst,cur_outp); + newline(cur_outp); + return UNSPECIFIED; +@} + +void init_gsubr211() +@{ + make_gsubr("gsubr-2-1-l", 2, 1, 1, gsubr_21l); +@} +@end example +@end defun + +@node Defining Smobs, Defining Ptobs, Defining Subrs, Operations +@subsection Defining Smobs + +@noindent +Here is an example of how to add a new type named @code{@i{foo}} to SCM. +The following lines need to be added to your code: + +@table @code +@item long tc16_@i{foo}; +The type code which will be used to identify the new type. +@item static smobfuns @i{foo}smob = @{mark@i{foo},free@i{foo},print@i{foo},equalp@i{foo}@}; +smobfuns is a structure composed of 4 functions: + +@example +typedef struct @{ + SCM (*mark)P((SCM)); + sizet (*free)P((CELLPTR)); + int (*print)P((SCM exp, SCM port, int writing)); + SCM (*equalp)P((SCM, SCM)); +@} smobfuns; +@end example + +@table @code +@item smob.mark +is a function of one argument of type @code{SCM} (the cell to mark) and +returns type @code{SCM} which will then be marked. If no further +objects need to be marked then return an immediate object such as +@code{BOOL_F}. 2 functions are provided: + +@table @code +@item markcdr(ptr) +which marks the current cell and returns @code{CDR(ptr)}. +@item mark0(ptr) +which marks the current cell and returns @code{BOOL_F}. +@end table + +@item smob.free +is a function of one argument of type @code{CELLPTR} (the cell to +collected) and returns type @code{sizet} which is the number of +@code{malloc}ed bytes which were freed. @code{Smob.free} should free +any @code{malloc}ed storage associated with this object. The function +free0(ptr) is provided which does not free any storage and returns 0. +@item smob.print +is 0 or a function of 3 arguments. The first, of type @code{SCM}, is +the smob object. The second, of type @code{SCM}, is the stream on which +to write the result. The third, of type int, is 1 if the object should +be @code{write}n, 0 if it should be @code{display}ed. This function +should return non-zero if it printed, and zero otherwise (in which case +a hexadecimal number will be printed). +@item smob.equalp +is 0 or a function of 2 @code{SCM} arguments. Both of these arguments +will be of type @code{tc16@i{foo}}. This function should return +@code{BOOL_T} if the smobs are equal, @code{BOOL_F} if they are not. If +@code{smob.equalp} is 0, @code{equal?} will return @code{BOOL_F} if they +are not @code{eq?}. +@end table + +@item tc16_@i{foo} = newsmob(&@i{foo}smob); +Allocates the new type with the functions from @code{@i{foo}smob}. This +line goes in an @code{init_} routine. +@end table + +@noindent +Promises and macros in @file{eval.c} and arbiters in @file{repl.c} +provide examples of SMOBs. There are a maximum of 256 SMOBs. + +@node Defining Ptobs, Calling Scheme From C, Defining Smobs, Operations +@subsection Defining Ptobs + +@noindent +@dfn{ptob}s are similar to smobs but define new types of port to which +SCM procedures can read or write. The following functions are defined +in the @code{ptobfuns}: + +@example +typedef struct @{ + SCM (*mark)P((SCM ptr)); + int (*free)P((FILE *p)); + int (*print)P((SCM exp, SCM port, int writing)); + SCM (*equalp)P((SCM, SCM)); + int (*fputc)P((int c, FILE *p)); + int (*fputs)P((char *s, FILE *p)); + sizet (*fwrite)P((char *s, sizet siz, sizet num, FILE *p)); + int (*fflush)P((FILE *stream)); + int (*fgetc)P((FILE *p)); + int (*fclose)P((FILE *p)); +@} ptobfuns; +@end example + +@noindent +The @code{.free} component to the structure takes a @code{FILE *} or +other C construct as its argument, unlike @code{.free} in a smob, which +takes the whole smob cell. Often, @code{.free} and @code{.fclose} can be +the same function. See @code{fptob} and @code{pipob} in @file{sys.c} +for examples of how to define ptobs. + +@node Calling Scheme From C, Callbacks, Defining Ptobs, Operations +@subsection Calling Scheme From C + +@noindent +To use SCM as a whole from another program call @code{init_scm} or +@code{run_scm} as is done in @code{main()} in @file{scm.c}. + +@noindent +In order to call indivdual Scheme procedures from C code more is +required; SCM's storage system needs to be initialized. The simplest +way to do this for a statically linked single-thread program is to: + +@enumerate +@item +make a SCM procedure which calls your code's startup routine. +@item +use the @code{#define RTL} flag when compiling @file{scm.c} to elide +SCM's @code{main()}. +@item +In your @code{main()}, call @code{run_scm} with arguments (@code{argc} +and @code{argv}) to invoke your code's startup routine. +@item +link your code with SCM at compile time. +@end enumerate + +@noindent +For a dynamically linked single-thread program: + +@enumerate +@item +make an @code{init_} procedure for your code which will set up any Scheme +definitions you need and then call your startup routine +(@pxref{Changing Scm}). +@item +Start SCM with command line arguments to dynamically link your code. +After your module is linked, the @code{init_} procedure will be called, and +hence your startup routine. +@end enumerate + +@noindent +Now use @code{apply} (and perhaps @code{intern}) to call Scheme +procedures from your C code. For example: + +@example +/* If this apply fails, SCM will catch the error */ +apply(CDR(intern("srv:startup",sizeof("srv:startup")-1)), + mksproc(srvproc), + listofnull); + +func = CDR(intern(rpcname,strlen(rpcname))); +retval = apply(func, cons(mksproc(srvproc), args), EOL); +@end example + +@node Callbacks, Type Conversions, Calling Scheme From C, Operations +@subsection Callbacks + +@noindent +SCM now has routines to make calling back to Scheme procedures easier. +The source code for these routines are found in @file{rope.c}. + +@deftypefun int scm_ldfile (char *@var{file}) +Loads the Scheme source file @var{file}. Returns 0 if successful, non-0 +if not. This function is used to load SCM's initialization file +@file{Init.scm}. +@end deftypefun + +@deftypefun int scm_ldprog (char *@var{file}) +Loads the Scheme source file @code{(in-vicinity (program-vicinity) +@var{file})}. Returns 0 if successful, non-0 if not. + +This function is useful for compiled code init_ functions to load +non-compiled Scheme (source) files. @code{program-vicinity} is the +directory from which the calling code was loaded (@pxref{Vicinity, , , +slib, SLIB}). +@end deftypefun + +@deftypefun SCM scm_evstr (char *@var{str}) +Returns the result of reading an expression from @var{str} and +evaluating it. +@end deftypefun + +@deftypefun void scm_ldstr (char *@var{str}) +Reads and evaluates all the expressions from @var{str}. +@end deftypefun + +@noindent +If you wish to catch errors during execution of Scheme code, then you +can use a wrapper like this for your Scheme procedures: + +@example +(define (srv:protect proc) + (lambda args + (define result #f) ; put default value here + (call-with-current-continuation + (lambda (cont) + (dynamic-wind (lambda () #t) + (lambda () + (set! result (apply proc args)) + (set! cont #f)) + (lambda () + (if cont (cont #f)))))) + result)) +@end example + +@noindent +Calls to procedures so wrapped will return even if an error occurs. + +@node Type Conversions, Continuations, Callbacks, Operations +@subsection Type Conversions + +These type conversion functions are very useful for connecting SCM and C +code. Most are defined in @file{rope.c}. + +@deftypefun SCM long2num (long @var{n}) +@deftypefunx SCM ulong2num (unsigned long @var{n}) +Return an object of type @code{SCM} corresponding to the @code{long} or +@code{unsigned long} argument @var{n}. If @var{n} cannot be converted, +@code{BOOL_F} is returned. Which numbers can be converted depends on +whether SCM was compiled with the @code{BIGDIG} or @code{FLOATS} flags. + +To convert integer numbers of smaller types (@code{short} or +@code{char}), use the macro @code{MAKINUM(n)}. +@end deftypefun + +@deftypefun long num2long (SCM @var{num}, char *@var{pos}, char *@var{s_caller}) +@deftypefunx unsigned long num2ulong (SCM @var{num}, char *@var{pos}, char *@var{s_caller}) +@deftypefunx unsigned short num2ushort (SCM @var{num}, char *@var{pos}, char *@var{s_caller}) +@deftypefunx unsigned char num2uchar (SCM @var{num}, char *@var{pos}, char *@var{s_caller}) +These functions are used to check and convert @code{SCM} arguments to +the named C type. The first argument @var{num} is checked to see it it +is within the range of the destination type. If so, the converted +number is returned. If not, the @code{ASSERT} macro calls @code{wta} +with @var{num} and strings @var{pos} and @var{s_caller}. For a listing +of useful predefined @var{pos} macros, @xref{C Macros}. + +@emph{Note:} Inexact numbers are accepted only by @code{num2long} and +@code{num2ulong} (for when @code{SCM} is compiled without bignums). To +convert inexact numbers to exact numbers, @xref{Numerical operations, +inexact->exact, , r4rs, Revised(4) Scheme}. +@end deftypefun + +@deftypefun unsigned long scm_addr (SCM @var{args}, char *@var{s_name}) +Returns a pointer (cast to an @code{unsigned long}) to the storage +corresponding to the location accessed by +@code{aref(CAR(args),CDR(args))}. The string @var{s_name} is used in +any messages from error calls by @code{scm_addr}. + +@code{scm_addr} is useful for performing C operations on strings or +other uniform arrays (@pxref{Uniform Array}). + +@emph{Note:} While you use a pointer returned from @code{scm_addr} you +must keep a pointer to the associated @code{SCM} object in a stack +allocated variable or GC-protected location in order to assure that SCM +does not reuse that storage before you are done with it. +@end deftypefun + +@deftypefun SCM makfrom0str (char *@var{src}) +@deftypefunx SCM makfromstr (char *@var{src}, sizet @var{len}) +Return a newly allocated string @code{SCM} object copy of the +null-terminated string @var{src} or the string @var{src} of length +@var{len}, respectively. +@end deftypefun + +@deftypefun SCM makfromstrs (int @var{argc}, char **@var{argv}) +Returns a newly allocated @code{SCM} list of strings corresponding to +the @var{argc} length array of null-terminated strings @var{argv}. If +@var{argv} is less than @code{0}, @var{argv} is assumed to be +@code{NULL} terminated. @code{makfromstrs} is used by @code{run_scm} to +convert the arguments SCM was called with to a @code{SCM} list which is +the value of SCM procedure calls to @code{program-arguments} +(@pxref{System Interface, program-arguments}). +@end deftypefun + +@deftypefun char **makargvfrmstrs (SCM @var{args}, char *@var{s_name}) +Returns a @code{NULL} terminated list of null-terminated strings copied +from the @code{SCM} list of strings @var{args}. The string @var{s_name} +is used in messages from error calls by @code{makargvfrmstrs}. + +@code{makargvfrmstrs} is useful for constructing argument lists suitable +for passing to @code{main} functions. +@end deftypefun + +@deftypefun void must_free_argv (char **@var{argv}) +Frees the storage allocated to create @var{argv} by a call to +@code{makargvfrmstrs}. +@end deftypefun + +@node Continuations, Evaluation, Type Conversions, Operations +@subsection Continuations + +@noindent +The source files @file{continue.h} and @file{continue.c} are designed to +function as an independent resource for programs wishing to use +continuations, but without all the rest of the SCM machinery. The +concept of continuations is explained in @ref{Control features, +call-with-current-continuation, , r4rs, Revised(4) Scheme}. + +@deftp {Data type} CONTINUATION jmpbuf length stkbse other parent +is a @code{typedef}ed structure holding all the information needed to +represent a continuation. The @var{other} slot can be used to hold any +data the user wishes to put there by defining the macro +@code{CONTINUATION_OTHER}. +@end deftp + +@defmac SHORT_ALIGN +If @code{SHORT_ALIGN} is @code{#define}d (in @file{scmfig.h}), then the +it is assumed that pointers in the stack can be aligned on @code{short +int} boundaries. +@end defmac + +@deftp {Data type} STACKITEM +is a pointer to objects of the size specified by @code{SHORT_ALIGN} +being @code{#define}d or not. +@end deftp + +@defmac CHEAP_CONTINUATIONS +If @code{CHEAP_CONTINUATIONS} is @code{#define}d (in @file{scmfig.h}) +each @code{CONTINUATION} has size @code{sizeof CONTINUATION}. +Otherwise, all but @dfn{root} @code{CONTINUATION}s have additional +storage (immediately following) to contain a copy of part of the stack. + +@emph{Note:} On systems with nonlinear stack disciplines (multiple +stacks or non-contiguous stack frames) copying the stack will not work +properly. These systems need to #define @code{CHEAP_CONTINUATIONS} in +@file{scmfig.h}. +@end defmac + +@defmac STACK_GROWS_UP +Expresses which way the stack grows by its being @code{#define}d or not. +@end defmac + +@deftypevar long thrown_value +Gets set to the @var{value} passed to @code{throw_to_continuation}. +@end deftypevar + +@deftypefun long stack_size (STACKITEM *@var{start}) +Returns the number of units of size @code{STACKITEM} which fit between +@var{start} and the current top of stack. No check is done in this +routine to ensure that @var{start} is actually in the current stack +segment. +@end deftypefun + +@deftypefun CONTINUATION *make_root_continuation (STACKITEM *@var{stack_base}) +Allocates (@code{malloc}) storage for a @code{CONTINUATION} of the +current extent of stack. This newly allocated @code{CONTINUATION} is +returned if successful, @code{0} if not. After +@code{make_root_continuation} returns, the calling routine still needs +to @code{setjmp(@var{new_continuation}->jmpbuf)} in order to complete +the capture of this continuation. +@end deftypefun + +@deftypefun CONTINUATION *make_continuation (CONTINUATION *@var{parent_cont}) +Allocates storage for the current @code{CONTINUATION}, copying (or +encapsulating) the stack state from @code{@var{parent_cont}->stkbse} to +the current top of stack. The newly allocated @code{CONTINUATION} is +returned if successful, @code{0}q if not. After +@code{make_continuation} returns, the calling routine still needs to +@code{setjmp(@var{new_continuation}->jmpbuf)} in order to complete the +capture of this continuation. +@end deftypefun + +@deftypefun void free_continuation (CONTINUATION *@var{cont}) +Frees the storage pointed to by @var{cont}. Remember to free storage +pointed to by @code{@var{cont}->other}. +@end deftypefun + +@deftypefun void throw_to_continuation (CONTINUATION *@var{cont}, long @var{value}, CONTINUATION *@var{root_cont}) +Sets @code{thrown_value} to @var{value} and returns from the +continuation @var{cont}. + +If @code{CHEAP_CONTINUATIONS} is @code{#define}d, then +@code{throw_to_continuation} does @code{longjmp(@var{cont}->jmpbuf, val)}. + +If @code{CHEAP_CONTINUATIONS} is not @code{#define}d, the CONTINUATION +@var{cont} contains a copy of a portion of the C stack (whose bound must +be @code{CONT(@var{root_cont})->stkbse}). Then: + +@itemize @bullet +@item +the stack is grown larger than the saved stack, if neccessary. +@item +the saved stack is copied back into it's original position. +@item +@code{longjmp(@var{cont}->jmpbuf, val)}; +@end itemize +@end deftypefun + +@node Evaluation, , Continuations, Operations +@subsection Evaluation + +SCM uses its type representations to speed evaluation. All of the +@code{subr} types (@pxref{Subr Cells}) are @code{tc7} types. Since the +@code{tc7} field is in the low order bit position of the @code{CAR} it +can be retrieved and dispatched on quickly by dereferencing the SCM +pointer pointing to it and masking the result. + +All the SCM @dfn{Special Forms} get translated to immediate symbols +(@code{isym}) the first time they are encountered by the interpreter +(@code{ceval}). The representation of these immediate symbols is +engineered to occupy the same bits as @code{tc7}. All the @code{isym}s +occur only in the @code{CAR} of lists. + +If the @code{CAR} of a expression to evaluate is not immediate, then it +may be a symbol. If so, the first time it is encountered it will be +converted to an immediate type @code{ILOC} or @code{GLOC} +(@pxref{Immediates}). The codes for @code{ILOC} and @code{GLOC} lower 7 +bits distinguish them from all the other types we have discussed. + +Once it has determined that the expression to evaluate is not immediate, +@code{ceval} need only retrieve and dispatch on the low order 7 bits of +the @code{CAR} of that cell, regardless of whether that cell is a +closure, header, or subr, or a cons containing @code{ILOC} or +@code{GLOC}. + +In order to be able to convert a SCM symbol pointer to an immediate @code{ILOC} +or @code{GLOC}, the evaluator must be holding the pointer to the list in which +that symbol pointer occurs. Turning this requirement to an advantage, +@code{ceval} does not recursively call itself to evaluate symbols in +lists; It instead calls the macro @dfn{EVALCAR}. @code{EVALCAR} does +symbol lookup and memoization for symbols, retrieval of values for @code{ILOC}s +and @code{GLOC}s, returns other immediates, and otherwise recursively calls +itself with the @code{CAR} of the list. + +@code{ceval} inlines evaluation (using @code{EVALCAR}) of almost all +procedure call arguments. When @code{ceval} needs to evaluate a list of +more than length 3, the procedure @code{eval_args} is called. So +@code{ceval} can be said to have one level lookahead. The avoidance of +recursive invocations of @code{ceval} for the most common cases (special +forms and procedure calls) results in faster execution. The speed of +the interpreter is currently limited on most machines by interpreter +size, probably having to do with its cache footprint. In order to keep +the size down, certain @code{EVALCAR} calls which don't need to be fast +(because they rarely occur or because they are part of expensive +operations) are instead calls to the C function @code{evalcar}. + +There was some discussion a year ago about a "Forth" style Scheme +interpreter. This is the only improvement I know of which would beat +SCM in speed. + +@quotation +Provided there is still type code space available in SCM, if we devote +some of the IMCAR codes to "inlined" operations, we should get a +significant performance boost. What is eliminated is the having to look +up a @code{GLOC} or @code{ILOC} and then dispatch on the subr type. The +IMCAR operation would be dispatched to directly. Another way to view +this is that we make available special form versions of @code{CAR}, +@code{CDR}, etc. Since the actual operation code is localized in the +interpreter, it is much easier than uncompilation and then recompilation +to handle @code{(trace car)}; For instance a switch gets set which tells +the interpreter to instead always look up the values of the associated +symbols. +@end quotation + +@defvar symhash +Top level symbol values are stored in the @code{symhash} table. +@code{symhash} is an array of lists of @code{ISYM}s and pairs of symbols +and values. +@end defvar + +@deftp Immediate ILOC +Whenever a symbol's value is found in the local environment the pointer +to the symbol in the code is replaced with an immediate object +(@code{ILOC}) which specifies how many environment frames down and how +far in to go for the value. When this immediate object is subsequently +encountered, the value can be retrieved quickly. +@end deftp + +@deftp Immediate GLOC +Pointers to symbols not defined in local environments are changed to one +plus the value cell address in symhash. This incremented pointer is +called a @code{GLOC}. The low order bit is normally reserved for +GCmark; But, since references to variables in the code always occur in +the @code{CAR} position and the GCmark is in the @code{CDR}, there is no +conflict. +@end deftp + +If the compile FLAG @code{CAUTIOUS} is #defined then the number of +arguments is always checked for application of closures. If the compile +FLAG @code{RECKLESS} is #defined then they are not checked. Otherwise, +number of argument checks for closures are made only when the function +position (whose value is the closure) of a combination is not an +@code{ILOC} or @code{GLOC}. When the function position of a combination +is a symbol it will be checked only the first time it is evaluated +because it will then be replaced with an @code{ILOC} or @code{GLOC}. + +@defmac EVAL expression env +@defmacx SIDEVAL expression env +@code{EVAL} Returns the result of evaluating @var{expression} in +@var{env}. @code{SIDEVAL} evaluates @var{expression} in @var{env} when +the value of the expression is not used. + +Both of these macros alter the list structure of @var{expression} as it +is memoized and hence should be used only when it is known that +@var{expression} will not be referenced again. The C function +@code{eval} is safe from this problem. +@end defmac + +@deftypefun SCM eval (SCM @var{expression}) +Returns the result of evaluating @var{expression} in the top-level +environment. @code{eval} copies @code{expression} so that memoization +does not modify @code{expression}. +@end deftypefun + +@node Improvements To Make, Finishing Dynamic Linking, Operations, The Implementation +@section Improvements To Make + +@itemize @bullet +@item +Prefix and make more uniform all C function, variable, and constant +names. Provide a file full of #define's to provide backward +compatability. +@item +@code{lgcd()} @emph{needs} to generate at most one bignum, but currently +generates more. +@item +@code{divide()} could use shifts instead of multiply and divide when +scaling. +@item +If an open fails because there are no unused file handles, GC should +be done so that file handles which are no longer used can be +collected. +@item +Currently, @code{dump}ing an executable does not preserve ports. When +loading a @code{dump}ed executable, disk files could be reopened to the +same file and position as they had when the executable was dumped. +@item +Compaction could be done to @code{malloc}ed objects by freeing and +reallocing all the malloc objects encountered in a scan of the heap. +Whether compactions would actually occur is system depenedent. +@item +Copying all of the stack is wasteful of storage. Any time a +call-with-current-continuation is called the stack could be re-rooted +with a frame which calls the contin just created. This in combination +with checking stack depth could also be used to allow stacks deeper +than 64K on the IBM PC. +@item +lookupcar in @file{eval.c} should @emph{not} memoize (to @code{ILOC}s) +when it retrieves environments deeper or longer than 4095. The values +can still be retrieved (albeit slowly), but an @code{ILOC} should not be +made. The @code{MEMOIZE_LOCALS} flag could then be flushed. +@item +The @code{must-} or @code{make-} routines need some sort of C macros or +conditionalization so that they check: + +@itemize @bullet +@item +that the @code{LENGTH} field fits into a @code{size_t} (as is checked +now) for platforms with @code{(sizeof(size_t) < sizeof(SCM))}. +@item +that the @code{LENGTH} field fits into 24 (or 56) bits on machines where +@code{size_t} is 32 bits or more. +@end itemize + +This is trickier than it first looks because the must_malloc() routine +is also used for allocating heap segments, which do not have the +@code{LENGTH} field restriction. Putting the 24 bit test into +@code{must_malloc()} should be tested for speed impact. +@end itemize + +@node Finishing Dynamic Linking, , Improvements To Make, The Implementation +@section Finishing Dynamic Linking + +@noindent +Scott Schwartz <schwartz@@galapagos.cse.psu.edu> suggests: One way to +tidy up the dynamic loading stuff would be to grab the code from perl5. + +@subsubheading VMS + +@noindent +George Carrette (gjc@@mitech.com) outlines how to dynamically link on +VMS. There is already some code in @file{dynl.c} to do this, but +someone with a VMS system needs to finish and debug it. + +@enumerate +@item +Say you have this @file{main.c} program: + +@format +@t{main() +@{init_lisp(); + lisp_repl();@}} +@end format + +@item +and you have your lisp in files @file{repl.c}, @file{gc.c}, +@code{eval.c} and there are some toplevel non-static variables in use +called @code{the_heap}, @code{the_environment}, and some read-only +toplevel structures, such as @code{the_subr_table}. + +@format +@t{$ LINK/SHARE=LISPRTL.EXE/DEBUG REPL.OBJ,GC.OBJ,EVAL.OBJ,LISPRTL.OPT/OPT} +@end format + +@item +where @file{LISPRTL.OPT} must contain at least this: + +@format +@t{SYS$LIBRARY:VAXCRTL/SHARE +UNIVERSAL=init_lisp +UNIVERSAL=lisp_repl +PSECT_ATTR=the_subr_table,SHR,NOWRT,LCL +PSECT_ATTR=the_heap,NOSHR,LCL +PSECT_ATTR=the_environment,NOSHR,LCL} +@end format + +@emph{Notice:} The @dfn{psect} (Program Section) attributes. +@table @code +@item LCL +means to keep the name local to the shared library. You almost always +want to do that for a good clean library. +@item SHR,NOWRT +means shared-read-only. Which is the default for code, and is also good +for efficiency of some data structures. +@item NOSHR,LCL +is what you want for everything else. +@end table + +Note: If you do not have a handy list of all these toplevel variables, +do not dispair. Just do your link with the /MAP=LISPRTL.MAP/FULL +and then search the map file, + +@format +@t{$SEARCH/OUT=LISPRTL.LOSERS LISPRTL.MAP ", SHR,NOEXE, RD, WRT"} +@end format + +And use an emacs keyboard macro to muck the result into the proper form. +Of course only the programmer can tell if things can be made read-only. +I have a DCL command procedure to do this if you want it. + +@item +@noindent +Now MAIN.EXE would be linked thusly: + +@format +@t{$ DEFINE LISPRTL USER$DISK:[JAFFER]LISPRTL.EXE + +$LINK MAIN.OBJ,SYS$INPUT:/OPT + SYS$LIBRARY:VAXCRTL/SHARE + LISPRTL/SHARE} +@end format + +Note the definition of the @code{LISPRTL} logical name. Without such a +definition you will need to copy @file{LISPRTL.EXE} over to +@file{SYS$SHARE:} (aka @file{SYS$LIBRARY:}) in order to invoke the main +program once it is linked. + +@item +Now say you have a file of optional subrs, @file{MYSUBRS.C}. And there +is a routine @code{INIT_MYSUBRS} that must be called before using it. + +@format +@t{$ CC MYSUBRS.C +$ LINK/SHARE=MYSUBRS.EXE MYSUBRS.OBJ,SYS$INPUT:/OPT + SYS$LIBRARY:VAXCRTL/SHARE + LISPRTL/SHARE + UNIVERSAL=INIT_MYSUBRS} +@end format + +Ok. Another hint is that you can avoid having to add the @code{PSECT} +declaration of @code{NOSHR,LCL} by declaring variables @code{status} in +the C language source. That works great for most things. + +@item +Then the dynamic loader would have to do this: + +@format +@t{@{void (*init_fcn)(); + long retval; + retval = lib$find_image_symbol("MYSUBRS","INIT_MYSUBRS",&init_fcn, + "SYS$DISK:[].EXE"); + if (retval != SS$_NORMAL) error(@dots{}); + (*init_fcn)();@}} +@end format + +But of course all string arguments must be @code{(struct dsc$descriptor +*)} and the last argument is optional if @code{MYSUBRS} is defined as a +logical name or if @file{MYSUBRS.EXE} has been copied over to +@file{SYS$SHARE}. The other consideration is that you will want to turn +off @key{C-c} or other interrupt handling while you are inside most +@code{lib$} calls. + +As far as the generation of all the @code{UNIVERSAL=@dots{}} +declarations. Well, you could do well to have that automatically +generated from the public @file{LISPRTL.H} file, of course. + +VMS has a good manual called the @cite{Guide to Writing Modular +Procedures} or something like that, which covers this whole area rather +well, and also talks about advanced techniques, such as a way to declare +a program section with a pointer to a procedure that will be +automatically invoked whenever any shared image is dynamically +activated. Also, how to set up a handler for normal or abnormal program +exit so that you can clean up side effects (such as opening a database). +But for use with @code{LISPRTL} you probably don't need that hair. + +One fancier option that is useful under VMS for @file{LISPLIB.EXE} is to +define all your exported procedures through an @dfn{call vector} instead +of having them just be pointers into random places in the image, which +is what you get by using @code{UNIVERSAL}. + +If you set up the call vector thing correctly it will allow you to +modify and relink @file{LISPLIB.EXE} without having to relink programs +that have been linked against it. +@end enumerate + +@subsubheading Windows NT +@noindent +George Carrette (gjc@@mitech.com) outlines how to dynamically link on +Windows NT: + +@itemize @bullet +@item +The Software Developers Kit has a sample called SIMPLDLL. +Here is the gist of it, following along the lines of the VMS description +above (contents of a makefile for the SDK NMAKE) + +@format +@t{LISPLIB.exp: +LISPLIB.lib: LISPLIB.def + $(implib) -machine:$(CPU) -def:LISPLIB.def -out:LISPLIB.lib + +LISPLIB.DLL : $(LISPLIB_OBJS) LISPLIB.EXP + $(link) $(linkdebug) \ + -dll \ + -out:LISPLIB.DLL \ + LISPLIB.EXP $(LISPLIB_OBJS) $(conlibsdll)} +@end format + +@item +The @file{LISPDEF.DEF} file has this: + +@format +@t{LIBRARY lisplib +EXPORT + init_lisp + init_repl} +@end format + +@item +And @file{MAIN.EXE} using: + +@format +@t{CLINK = $(link) $(ldebug) $(conflags) -out:$*.exe $** $(conlibsdll) + +MAIN.EXE : MAIN.OBJ LISPLIB.LIB + $(CLINK)} +@end format + +@item +And @file{MYSUBRS.DLL} is produced using: + +@format +@t{mysubrs.exp: +mysubrs.lib: mysubrs.def + $(implib) -machine:$(CPU) -def:MYSUBRS.def -out:MYSUBRS.lib + +mysubrs.dll : mysubrs.obj mysubrs.exp mysubrs.lib + $(link) $(linkdebug) \ + -dll \ + -out:mysubrs.dll \ + MYSUBRS.OBJ MYSUBRS.EXP LISPLIB.LIB $(conlibsdll)} +@end format + +@item +Where @file{MYSUBRS.DEF} has + +@format +@t{LIBRARY mysubrs +EXPORT + INIT_MYSUBRS} +@end format + +@item +And the dynamic loader looks something like this, calling the two +procedures @code{LoadLibrary} and @code{GetProcAddress}. + +@format +@t{LISP share_image_load(LISP fname) +@{long iflag; + LISP retval,(*fcn)(void); + HANDLE hLib; + DWORD err; + char *libname,fcnname[64]; + iflag = nointerrupt(1); + libname = c_string(fname); + _snprintf(fcnname,sizeof(fcnname),"INIT_%s",libname); + if (!(hLib = LoadLibrary(libname))) + @{err = GetLastError(); + retval = list2(fname,LSPNUM(err)); + serror1("library failed to load",retval);@} + if (!(fcn = (LISP (*)(void)) GetProcAddress(hLib,fcnname))) + @{err = GetLastError(); + retval = list2(fname,LSPNUM(err)); + serror1("could not find library init procedure",retval);@} + retval = (*fcn)(); + nointerrupt(iflag); + return(retval);@}} +@end format + +@item +@emph{Note:} in VMS the linker and dynamic loader is case sensitive, but +all the language compilers, including C, will by default upper-case +external symbols for use by the linker, although the debugger gets its +own symbols and case sensitivity is language mode dependant. In Windows +NT things are case sensitive generally except for file and device names, +which are case canonicalizing like in the Symbolics filesystem. + +@item +@emph{Also:} All this WINDOWS NT stuff will work in MS-DOS MS-Windows +3.1 too, by a method of compiling and linking under Windows NT, and then +copying various files over to MS-DOS/WINDOWS. +@end itemize + + +@node Procedure and Macro Index, Variable Index, The Implementation, Top +@unnumbered Procedure and Macro Index + +This is an alphabetical list of all the procedures and macros in SCM. + +@printindex fn + +@node Variable Index, Type Index, Procedure and Macro Index, Top +@unnumbered Variable Index + +This is an alphabetical list of all the global variables in SCM. + +@printindex vr + +@node Type Index, , Variable Index, Top +@unnumbered Type Index + +This is an alphabetical list of all the data types in SCM. + +@printindex tp + +@contents +@bye diff --git a/scm4e3.scmconfig.patch b/scm4e3.scmconfig.patch new file mode 100644 index 0000000..ff7dc48 --- /dev/null +++ b/scm4e3.scmconfig.patch @@ -0,0 +1,60 @@ +diff -c temp/scm/findexec.c temp/nscm/findexec.c +*** temp/scm/findexec.c Sun Mar 17 23:16:26 1996 +--- temp/nscm/findexec.c Thu Mar 21 08:51:27 1996 +*************** +*** 37,46 **** + filename. A new copy of the complete path name of that file is + returned. This new string may be disposed by free() later on. */ + + #include <sys/file.h> + #include <sys/param.h> +! #include <strings.h> +! #ifdef linux + # include <stdlib.h> + # include <sys/stat.h> + # include <unistd.h> /* for X_OK define */ +--- 37,47 ---- + filename. A new copy of the complete path name of that file is + returned. This new string may be disposed by free() later on. */ + ++ #include "scm.h" ++ + #include <sys/file.h> + #include <sys/param.h> +! #if defined(linux) || defined(__svr4__) + # include <stdlib.h> + # include <sys/stat.h> + # include <unistd.h> /* for X_OK define */ +*************** +*** 116,122 **** + if (*p) p++; + + if (name[0] == '.' && name[1] == 0) +! getwd(name); + + else if (name[0]=='~' && name[1]==0 && getenv("HOME")) + strcpy(name, getenv("HOME")); +--- 117,123 ---- + if (*p) p++; + + if (name[0] == '.' && name[1] == 0) +! getcwd(name, MAXPATHLEN); + + else if (name[0]=='~' && name[1]==0 && getenv("HOME")) + strcpy(name, getenv("HOME")); +diff -c temp/scm/scmfig.h temp/nscm/scmfig.h +*** temp/scm/scmfig.h Fri Sep 22 22:29:00 1995 +--- temp/nscm/scmfig.h Wed Mar 20 23:47:15 1996 +*************** +*** 50,55 **** +--- 50,59 ---- + # include <strings.h> + # endif + ++ # ifndef HAVE_GETCWD ++ # define getcwd(S,L) getwd(S) ++ # endif ++ + #else /* HAVE_CONFIG_H */ + + # ifdef sequent diff --git a/scmconfig.h.in b/scmconfig.h.in new file mode 100644 index 0000000..5fb6d27 --- /dev/null +++ b/scmconfig.h.in @@ -0,0 +1,69 @@ +/* scmconfig.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +#undef _ALL_SOURCE +#endif + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* 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 + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both <sys/time.h> and <time.h>. */ +#undef TIME_WITH_SYS_TIME + +/* Define if you have ftime. */ +#undef HAVE_FTIME + +/* Define if you have getcwd. */ +#undef HAVE_GETCWD + +/* Define if you have times. */ +#undef HAVE_TIMES + +/* Define if you have the <limits.h> header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the <sys/timeb.h> header file. */ +#undef HAVE_SYS_TIMEB_H + +/* Define if you have the <sys/times.h> header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have the <time.h> header file. */ +#undef HAVE_TIME_H + +/* Define if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H diff --git a/scmfig.h b/scmfig.h new file mode 100644 index 0000000..ba95450 --- /dev/null +++ b/scmfig.h @@ -0,0 +1,671 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "scmfig.h" system-dependent configuration. + Author: Aubrey Jaffer */ + +#ifdef HAVE_CONFIG_H +# include "scmconfig.h" +# ifdef HAVE_STRING_H +# include <string.h> +# else +# include <strings.h> +# endif + +# ifndef HAVE_GETCWD +# define getcwd(S,L) getwd(S) +# endif + +#else /* HAVE_CONFIG_H */ + +# ifdef sequent +# include <strings.h> +# define strchr index +# define strrchr rindex +# else +# include <string.h> +# endif + +# include "scmflags.h" /* user specified, system independent flags */ + +/* IMPLINIT is the full pathname (surrounded by double quotes) of + Init.scm, the Scheme initialization code. This is best defined in + the makefile, if possible. If available, scm uses the value of + environment variable SCM_INIT_PATH instead of IMPLINIT. */ + +/* #define IMPLINIT "/usr/jaffer/scm/Init.scm" */ + +/* INITS is calls to initialization routines for any compiled + libraries being linked into scm. This is best done in the makefile. +File: INITS line: functions defined: + +sc2.c init_sc2(); substring-move-left!, substring-move-right!, + substring-fill!, append!, and last-pair +rgx.c init_rgx(); regcomp and regexec. */ + +/* #define INITS init_sc2(); */ + +/* #define SICP */ + +/* setbuf(0) needs to be done for tty ports in order for CHAR-READY? + to work. This can cause problems under MSDOS and other systems. */ + +/* #define NOSETBUF */ + +/* #define RECKLESS */ + +/* #define CAUTIOUS */ + +/* #define STACK_LIMIT (HEAP_SEG_SIZE/2) */ + +/* #define BIGNUMS */ + +/* #define ARRAYS */ + +/* #define FLOATS */ + +/* Define SINGLES if you want single precision floats and + (sizeof(float)==sizeof(long)) */ + +# ifdef FLOATS +# define SINGLES +# endif + +/* #define SINGLESONLY */ + +/* Define CDR_DOUBLES if (sizeof(double)==sizeof(long)), i.e. + a `single' is really a double. */ +# ifdef FLOATS +# ifdef __alpha +# define CDR_DOUBLES +# endif + +# ifdef _UNICOS /* doubles are no better than singles on Cray. */ +# define SINGLESONLY +# endif + +# ifdef CDR_DOUBLES +# define SINGLES +# define SINGLESONLY +# endif +# endif + +/* #define ENGNOT */ + +/* Define SUN_DL to configure code in "dynl.c" so that dynamic linking + is done using the SUN dynamic linking library "dl". */ + +/* #define SUN_DL */ + +/* Define DLD to configure code in "dynl.c" so that dynamic linking is + done using the "dld" library. DLD is ported to Linux, VAX + (Ultrix), Sun 3 (SunOS 3.4 and 4.0), SPARCstation (SunOS 4.0), + Sequent Symmetry (Dynix), and Atari ST. See scm/README or + scm/ANNOUNCE for ftp sites offering dld. */ + +/* #define DLD */ + +/* Define HAVE_DYNL if dynamic linking is available */ + +# ifdef DLD +# define HAVE_DYNL +# endif +# ifdef SUN_DL +# define HAVE_DYNL +# endif +# ifdef HP_SHL +# define HAVE_DYNL +# endif + +# ifdef HAVE_DYNL +# define CCLO +# endif + +/* Define GC_FREE_SEGMENTS if you want segments of unused heap to + be freed up after garbage collection. Don't define it if you + never want the heap to shrink. */ + +# ifndef DONT_GC_FREE_SEGMENTS +# define GC_FREE_SEGMENTS +# endif + +/* MEMOIZE_LOCALS will speed up most local variable references. You + will need to remove this and recompile eval.c if you use very large or + deep environments (more than 4095 bound variables in one procedure)*/ + +# define MEMOIZE_LOCALS + +/* #define CHEAP_CONTINUATIONS */ + +/* #define TICKS */ + +/* PROT386 should be defined on the compilation command line if the + program is to be run on an intel 386 in protected mode. `Huge' + pointers common on MSDOS compilers do not work in protected mode. + PROT386 is required if scm is to run as part of a Microsoft Windows + application. Added by Stephen Adams 8 May 92 */ + +/* #define PROT386 */ + +/* #define NON_PREEMPTIVE and RTL if you are using an non-preemptive + operating system in which periodic polling for interrupts is + necessary. Provide your own main procedure (e.g., WinMain, in + Windows). Define and initialize unsigned int poll_count, and + provide a procedure named poll_routine(), which POLL calls each + time poll_count reaches zero. poll_routine() must reinitialize + poll_count. It may also check for external actions, such as + Windows messages. The value assigned to poll_count can be quite + large, e.g., 1000, while still maintaining good response time. */ + +/* #define CAREFUL_INTS */ + +/* STDC_HEADERS indicates that the include file names are the same as + ANSI C. For most modern systems this is the case. */ + +/* added by Yasuaki Honda */ +# ifdef THINK_C +# define __STDC__ +# endif + +# ifdef __STDC__ +# ifndef __HIGHC__ /* overly fussy compiler */ +# define USE_ANSI_PROTOTYPES +# endif +# ifndef __GNUC__ +# define STDC_HEADERS +# else +# ifdef sparc +# ifdef SVR4 +# define STDC_HEADERS +# endif +# else +# ifndef tahoe +# ifndef sun +# define STDC_HEADERS +# endif +# endif +# endif +# endif +# endif +# ifdef MSDOS /* Microsoft C 5.10 and 6.00A */ +# ifndef GO32 +# define SHORT_INT +# endif +# endif +# ifdef _QC +# define SHORT_INT +# endif +# ifdef __TURBOC__ +# define SHORT_INT +# ifndef __TOS__ +# define MSDOS +# endif +# endif +# ifdef _WIN32 +# define MSDOS +# define LACK_TIMES +# endif +# ifdef _MSDOS +# define MSDOS +# endif +# ifdef MSDOS +# define STDC_HEADERS +# endif +# ifdef vms +# define STDC_HEADERS +# endif +# ifdef nosve +# define STDC_HEADERS +# endif + +# ifdef linux +# define HAVE_SELECT +# define HAVE_SYS_TIME_H +# undef STDC_HEADERS +# endif + +# ifdef _UNICOS +# define STDC_HEADERS +# endif + +# ifdef _AIX +# define _POSIX_SOURCE +# define LACK_FTIME +# endif + +# ifdef __sgi__ +# define LACK_FTIME +# define STDC_HEADERS +# define USE_ANSI_PROTOTYPES +# define HAVE_SELECT +# define HAVE_SYS_TIME_H +# define __svr4__ +# endif + +# ifdef hpux +# define LACK_E_IDs +# endif + +/* C-Set++ for OS/2 */ +# ifdef __IBMC__ +# define STDC_HEADERS +# define LACK_TIMES +# endif + +#endif /* HAVE_CONFIG_H */ + +/* PROMPT is the prompt string printed at top level */ + +#ifndef PROMPT +# ifdef SICP +# define PROMPT "==> " +# else +# define PROMPT "> " +# endif +#endif + +/* #define BRACKETS_AS_PARENS to have [ and ] be read as ( and ) in forms. */ + +/* #define BRACKETS_AS_PARENS */ + +/* LINE_INCREMENTORS are the characters which cause the line count to + be incremented for the purposes of error reporting. This feature + is only used for scheme code loaded from files. + + WHITE_SPACES are other characters which should be treated like spaces + in programs. in both cases sparate characters with ":case " */ + +#define LINE_INCREMENTORS '\n' +#ifdef MSDOS +# define WHITE_SPACES ' ':case '\t':case '\r':case '\f':case 26 +#else +# define WHITE_SPACES ' ':case '\t':case '\r':case '\f' +#endif + +/* NUM_HASH_BUCKETS is the number of symbol hash table buckets. */ + +#define NUM_HASH_BUCKETS 137 + +/* If fewer than MIN_GC_YIELD cells are recovered during a garbage + collection (GC) more space is allocated for the heap. */ + +#define MIN_GC_YIELD (heap_size/4) + +/* Define BIGDIG to an integer type whose size is smaller than long if + you want bignums. BIGRAD is one greater than the biggest BIGDIG. */ +/* Define DIGSTOOBIG if the digits equivalent to a long won't fit in a long. */ +#ifdef BIGNUMS +# ifdef _UNICOS +# define DIGSTOOBIG +# if (1L << 31) <= USHRT_MAX +# define BIGDIG unsigned short +# else +# define BIGDIG unsigned int +# endif +# define BITSPERDIG 32 +# else +# define BIGDIG unsigned short +# define BITSPERDIG (sizeof(BIGDIG)*CHAR_BIT) +# endif +# define BIGRAD (1L << BITSPERDIG) +# define DIGSPERLONG ((sizet)((sizeof(long)*CHAR_BIT+BITSPERDIG-1)/BITSPERDIG)) +# define BIGUP(x) ((unsigned long)(x) << BITSPERDIG) +# define BIGDN(x) ((x) >> BITSPERDIG) +# define BIGLO(x) ((x) & (BIGRAD-1)) +#endif + +#ifndef BIGDIG +# ifndef FLOATS +# define INUMS_ONLY +# endif +#endif + +#ifdef NON_PREEMPTIVE +# define DEFER_INTS /**/ +# ifdef TICKS +# define POLL {if (0==poll_count--) poll_routine(); \ + if (0==tick_count--) tick_signal();} +# else +# define POLL {if (0==poll_count--) poll_routine();} +# endif +# define CHECK_INTS POLL +# define ALLOW_INTS POLL +#else +# ifdef CAREFUL_INTS +# define DEFER_INTS {if (ints_disabled) \ + fputs("ints already disabled\n", stderr); \ + ints_disabled = 1;} +# define ALLOW_INTS {if (!ints_disabled) \ + fputs("ints already enabled\n", stderr); \ + ints_disabled = 0;CHECK_INTS} +# else +# define DEFER_INTS {ints_disabled = 1;} +# define ALLOW_INTS {ints_disabled = 0;CHECK_INTS} +# endif +# ifdef TICKS +# define CHECK_INTS {if (sig_deferred) han_sig();if (alrm_deferred) han_alrm();\ + POLL;} +# define POLL {if (0==tick_count--) tick_signal();} +# else +# define CHECK_INTS {if (sig_deferred) han_sig();if (alrm_deferred) han_alrm();} +# define POLL /**/ +# endif +#endif + +#ifdef STACK_LIMIT +# define CHECK_STACK {stack_check();} +#else +# define CHECK_STACK /**/ +#endif + +/* Cray machines have pointers that are incremented once for each word, + rather than each byte, the 3 most significant bits encode the byte + within the word. The following macros deal with this by storing the + native Cray pointers like the ones that looks like scm expects. This + is done for any pointers that might appear in the car of a cell, pointers + to vector elts, functions, &c are not munged. */ +#ifdef _UNICOS +# define SCM2PTR(x) ((int)(x) >> 3) +# define PTR2SCM(x) (((SCM)(x)) << 3) +# define POINTERS_MUNGED +#else +# define SCM2PTR(x) (x) +# define PTR2SCM(x) ((SCM)(x)) +#endif + +/* FIXABLE is non-null if its long argument can be encoded in an INUM. */ + +#define POSFIXABLE(n) ((n) <= MOST_POSITIVE_FIXNUM) +#define NEGFIXABLE(n) ((n) >= MOST_NEGATIVE_FIXNUM) +#define UNEGFIXABLE(n) ((n) <= -MOST_NEGATIVE_FIXNUM) +#define FIXABLE(n) (POSFIXABLE(n) && NEGFIXABLE(n)) + +/* The following 8 definitions are defined automatically by the C + pre-processor. You will need to override these if you are + cross-compiling or if the C pre-processor has different properties + than the compiler. */ + +#if (((-1)%2==-1) && ((-1)%(-2)==-1) && (1%2==1) && (1%(-2)==1)) +#else +# define BADIVSGNS +#endif + +/* SRS is signed right shift */ +/*--- Turbo C++ v1.0 has a bug with right shifts of signed longs! + It is believed to be fixed in Turbo C++ v1.01 ---*/ +#if (-1==(((-1)<<2)+2)>>2) && (__TURBOC__ != 0x295) +# define SRS(x, y) ((x)>>y) +# ifdef __TURBOC__ +# define INUM(x) (((x)>>1)>>1) +# else +# define INUM(x) SRS(x, 2) +# endif +#else +# define SRS(x, y) (((x)<0) ? ~((~(x))>>y) : (x)>>y) +# define INUM(x) SRS(x, 2) +#endif + +#ifdef __TURBOC__ +/* shifts of more than one are done by a library call, single shifts are + performed in registers */ +# define MAKINUM(x) ((((x)<<1)<<1)+2L) +#else +# define MAKINUM(x) (((x)<<2)+2L) +#endif + +#ifdef _DCC +# define ASCII +#else +# if (('\n'=='\025') && (' '=='\100') && ('a'=='\201') && ('A'=='\301')) +# define EBCDIC +# endif +# if (('\n'=='\012') && (' '=='\040') && ('a'=='\141') && ('A'=='\101')) +# define ASCII +# endif +#endif + +/* CHAR_CODE_LIMIT is the number of distinct characters represented by + the unsigned char datatype. */ +/* MOST_POSITIVE_FIXNUM is the INUM closest to positive infinity. */ +/* MOST_NEGATIVE_FIXNUM is the INUM closest to negative infinity. */ + +#ifdef __STDC__ +# define HAVE_LIMITSH +#endif +#ifdef MWC +# define HAVE_LIMITSH +#endif + +#ifdef HAVE_LIMITSH +# include <limits.h> +# ifdef UCHAR_MAX +# define CHAR_CODE_LIMIT (UCHAR_MAX+1L) +# else +# define CHAR_CODE_LIMIT 256L +# endif +# define MOST_POSITIVE_FIXNUM (LONG_MAX>>2) +# ifdef _UNICOS /* Stupid cray bug */ +# define MOST_NEGATIVE_FIXNUM ((long)LONG_MIN/4) +# else +# define MOST_NEGATIVE_FIXNUM SRS((long)LONG_MIN, 2) +# endif /* UNICOS */ +#else +# define CHAR_CODE_LIMIT 256L +# define MOST_POSITIVE_FIXNUM ((long)((unsigned long)~0L>>3)) +# if (0 != ~0) +# define MOST_NEGATIVE_FIXNUM (-MOST_POSITIVE_FIXNUM-1) +# else +# define MOST_NEGATIVE_FIXNUM (-MOST_POSITIVE_FIXNUM) +# endif +#endif + +/* INTBUFLEN is the maximum number of characters neccessary for the + printed or string representation of an exact number. */ + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif +#ifndef LONG_BIT +# define LONG_BIT (CHAR_BIT*sizeof(long)/sizeof(char)) +#endif +#define INTBUFLEN (5+LONG_BIT) + +/* FLOBUFLEN is the maximum number of characters neccessary for the + printed or string representation of an inexact number. */ + +#ifdef FLOATS +# define FLOBUFLEN (10+2*(sizeof(double)/sizeof(char)*CHAR_BIT*3+9)/10) +#endif /* FLOATS */ + +/* MAXEXP is the maximum double precision expontent */ +/* FLTMAX is less than or equal the largest single precision float */ + +#ifdef FLOATS +# ifdef STDC_HEADERS +# ifndef GO32 +# include <float.h> +# endif +# endif +# ifdef DBL_MAX_10_EXP +# define MAXEXP DBL_MAX_10_EXP +# else +# define MAXEXP 308 /* IEEE doubles */ +# endif +# ifdef FLT_MAX +# define FLTMAX FLT_MAX +# else +# define FLTMAX 1e+23 +# endif +#endif + +/* Only some machines have pipes */ +#ifdef _IBMR2 +# define unix +# define STDC_HEADERS +#endif +#ifdef unix + /* DJGPP (gcc for i386) defines unix! */ +# ifndef GO32 +# define HAVE_PIPE +# endif +#endif + +/* IS_INF tests its floating point number for infiniteness */ + +#ifndef IS_INF +# define IS_INF(x) ((x)==(x)/2) +#endif + +#ifndef THINK_C +# ifdef __WINDOWS__ /* there should be a better flag for this. */ +# define PROT386 +# endif +#endif + +/* PTR_LT defines how to compare two CELLPTRs (which may not be in the + same array). CELLPTR is a pointer to a cons cell which may be + compared or differenced. SCMPTR is used for stack bounds. */ + +#if defined(__TURBOC__) && !defined(__TOS__) +# ifdef PROT386 +typedef cell *CELLPTR; +typedef SCM *SCMPTR; +# define PTR_LT(x, y) (((long)(x)) < ((long)(y))) +# else +typedef cell huge *CELLPTR; +typedef SCM huge *SCMPTR; +# define PTR_LT(x, y) ((x) < (y)) +# endif +#else /* not __TURBOC__ */ +typedef cell *CELLPTR; +typedef SCM *SCMPTR; +# ifdef nosve +# define PTR_MASK 0xffffffffffff +# define PTR_LT(x, y) (((int)(x)&PTR_MASK) < ((int)(y)&PTR_MASK)) +# else +# define PTR_LT(x, y) ((x) < (y)) +# endif +#endif + +#ifdef STDC_HEADERS +# include <stdlib.h> +# ifdef AMIGA +# include <stddef.h> +# endif +# define sizet size_t +#else +# ifdef _SIZE_T +# define sizet size_t +# else +# define sizet unsigned int +# endif +#endif + +/* On VMS, GNU C's errno.h contains a special hack to get link attributes + for errno correct for linking to the C RTL. */ + +#include <errno.h> + +/* SYSCALL retries system calls that have been interrupted (EINTR) */ +#ifdef vms +# ifndef __GNUC__ +# include <ssdef.h> +# define SYSCALL(line) do{errno = 0;line} \ + while(EVMSERR==errno && (vaxc$errno>>3)==(SS$_CONTROLC>>3)) +# endif +#endif + +#ifndef SYSCALL +# ifdef EINTR +# if (EINTR > 0) +# define SYSCALL(line) do{errno = 0;line}while(EINTR==errno) +# endif +# endif +#endif + +#ifndef SYSCALL +# define SYSCALL(line) {line} +#endif + +#ifndef MSDOS +# ifdef ARM_ULIB + extern volatile int errno; +# else + extern int errno; +# endif +#endif +#ifdef __TURBOC__ +# if (__TURBOC__==1) + /* Needed for TURBOC V1.0 */ + extern int errno; +# endif +#endif + +/* EXIT_SUCCESS is the default code to return from SCM if no errors + were encountered. EXIT_FAILURE is the default code to return from + SCM if errors were encountered. The return code can be explicitly + specified in a SCM program with (quit <n>). */ + +#ifndef EXIT_SUCCESS +# ifdef vms +# define EXIT_SUCCESS 1 +# else +# define EXIT_SUCCESS 0 +# endif +#endif +#ifndef EXIT_FAILURE +# ifdef vms +# define EXIT_FAILURE 2 +# else +# define EXIT_FAILURE 1 +# endif +#endif + +/* Yasuaki Honda */ +/* Think C lacks isascii macro */ +#ifdef THINK_C +# define isascii(c) ((unsigned)(c) <= 0x7f) +#endif +#ifdef _DCC +# define isascii(c) ((unsigned)(c) <= 0x7f) +#endif + +/* end of automatic C pre-processor definitions */ diff --git a/setjump.h b/setjump.h new file mode 100644 index 0000000..eb7e90b --- /dev/null +++ b/setjump.h @@ -0,0 +1,122 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "setjump.h" memory and stack parameters. + Author: Aubrey Jaffer */ + +/* CELL_UP and CELL_DN are used by init_heap_seg to find cell aligned inner + bounds for allocated storage */ + +#ifdef PROT386 +/*in 386 protected mode we must only adjust the offset */ +#define CELL_UP(p) MK_FP(FP_SEG(p), ~7&(FP_OFF(p)+7)) +#define CELL_DN(p) MK_FP(FP_SEG(p), ~7&FP_OFF(p)) +#else +#ifdef _UNICOS +#define CELL_UP(p) (CELLPTR)(~1L & ((long)(p)+1L)) +#define CELL_DN(p) (CELLPTR)(~1L & (long)(p)) +#else +#define CELL_UP(p) (CELLPTR)(~(sizeof(cell)-1L) & ((long)(p)+sizeof(cell)-1L)) +#define CELL_DN(p) (CELLPTR)(~(sizeof(cell)-1L) & (long)(p)) +#endif /* UNICOS */ +#endif /* PROT386 */ + +/* These are parameters for controlling memory allocation. The heap + is the area out of which cons and object headers is allocated. + Each heap object is 8 bytes on a 32 bit machine and 16 bytes on a + 64 bit machine. The units of the _SIZE parameters are bytes. + + INIT_HEAP_SIZE is the initial size of heap. If this much heap is + allocated initially the heap will grow by half its current size + each subsequent time more heap is needed. + + If INIT_HEAP_SIZE heap cannot be allocated initially, HEAP_SEG_SIZE + will be used, and the heap will grow by HEAP_SEG_SIZE when more + heap is needed. HEAP_SEG_SIZE must fit into type sizet. This code + is in init_storage() and alloc_some_heap() in sys.c + + If INIT_HEAP_SIZE can be allocated initially, the heap will grow by + EXPHEAP(heap_size) when more heap is needed. + + MIN_HEAP_SEG_SIZE is minimum size of heap to accept when more heap + is needed. + + INIT_MALLOC_LIMIT is the initial amount of malloc usage which will + trigger a GC. */ + +#define INIT_HEAP_SIZE (25000L*sizeof(cell)) +#define MIN_HEAP_SEG_SIZE (2000L*sizeof(cell)) +#ifdef _QC +#define HEAP_SEG_SIZE 32400L +#else +#ifdef sequent +#define HEAP_SEG_SIZE (7000L*sizeof(cell)) +#else +#define HEAP_SEG_SIZE (8100L*sizeof(cell)) +#endif +#endif +#define EXPHEAP(heap_size) (heap_size*2) +#define INIT_MALLOC_LIMIT 100000 + +#ifdef IN_CONTINUE_C +# include "scm.h" +# define malloc(size) must_malloc((long)(size), s_cont) +# define free(obj) must_free((char *)(obj)) +#endif + +/* other.dynenv and other.parent get GCed just by being there. */ +struct scm_other {SCM dynenv; + SCM parent; +#ifdef CAUTIOUS + SCM stack_trace; +#endif + }; +#define CONTINUATION_OTHER struct scm_other +#define CONT(x) ((CONTINUATION *)CDR(x)) +#define SETCONT SETCDR +void dowinds P((SCM to, long delta)); + +#include "continue.h" + +/* See scm.h for definition of P */ +void mark_locations P((STACKITEM x [], sizet n )); +void scm_dynthrow P((CONTINUATION *cont, SCM val)); +#define s_cont (ISYMCHARS(IM_CONT)+20) diff --git a/setjump.mar b/setjump.mar new file mode 100644 index 0000000..2b49243 --- /dev/null +++ b/setjump.mar @@ -0,0 +1,38 @@ + .title setjump and longjump +; The VAX C runtime library uses the $unwind utility for implementing +; longjmp. That fails if your program do not follow normal +; stack decipline. This is a dirty implementation of setjmp +; and longjmp that does not have that problem. +; the names longjmp and setjmp are avoided so that the code can be linked +; with the vax c runtime library without name clashes. + +; This code was contributed by an anonymous reviewer from +; comp.sources.reviewed. + + .entry setjump,^M<IV> + movl 4(ap),r0 + movq r2,(r0)+ + movq r4,(r0)+ + movq r6,(r0)+ + movq r8,(r0)+ + movq r10,(r0)+ + movl fp,(r0)+ + movo 4(fp),(r0)+ + movq 20(fp),(r0) + clrl r0 + ret + + .entry longjump,^M<IV> + movl 4(ap),r0 + movq (r0)+,r2 + movq (r0)+,r4 + movq (r0)+,r6 + movq (r0)+,r8 + movq (r0)+,r10 + movl (r0)+,r1 + movo (r0)+,4(r1) + movq (r0),20(r1) + movl 8(ap),r0 + movl r1,fp + ret + .end diff --git a/setjump.s b/setjump.s new file mode 100644 index 0000000..b96fb05 --- /dev/null +++ b/setjump.s @@ -0,0 +1,40 @@ +* setjmp on the Cray YMP does not save all registers. Although this +* conforms to the ANSI standard, it is not sufficient for SCM garbage +* collection and continuations. +* +* This is a version of setjump for the Cray YMP that does save all non- +* temporary registers. It might work for the XMP. It definitely will +* not work on the Cray 2. I do not know if the setjmp on the Cray 2 will +* work with SCM or not. +* +* This has been tested under Unicos 6.1. +* +* --Radey Shouman <rshouman@chpc.utexas.edu> +* + IDENT SETJUMP + ENTRY setjump +setjump = * + A1 1,A6 + A2 56 + A0 A1 + ,A0 T00,A2 + A0 A1+A2 + ,A0 B00,A2 + S1 0 + J B00 +* + ENTRY longjump +longjump = * + A1 1,A6 + A0 A1 + A2 56 + T00,A2 ,A0 + A0 A1+A2 + B00,A2 ,A0 + S1 2,A6 + J B00 + END +** Local Variables: +** tab-stop-list: (12 28 45) +** indent-tabs-mode: nil +** End: diff --git a/socket.c b/socket.c new file mode 100644 index 0000000..4446253 --- /dev/null +++ b/socket.c @@ -0,0 +1,635 @@ +/* Copyright (C) 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "socket.c" internet stream socket support for client/server in SCM + Author: Aubrey Jaffer. + Thanks to Hallvard.Tretteberg@si.sintef.no + who credits NCSA httpd software by Rob McCool 3/21/93 +*/ + +#include "scm.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> + +#ifndef STDC_HEADERS + int close P((int fd)); +#endif /* STDC_HEADERS */ + +static char s_inetaddr[] = "inet:string->address"; +SCM l_inetaddr (host) + SCM host; +{ + struct in_addr soka; + ASSERT(NIMP(host) && STRINGP(host), host, ARG1, s_inetaddr); + soka.s_addr = inet_addr(CHARS(host)); + if (-1==soka.s_addr) { + struct hostent *entry; + DEFER_INTS; + SYSCALL(entry = gethostbyname(CHARS(host));); + ALLOW_INTS; + if (!entry) return BOOL_F; + return ulong2num(ntohl(((struct in_addr *)entry->h_addr)->s_addr)); + } + return ulong2num(ntohl(soka.s_addr)); +} + +static char s_inetstr[] = "inet:address->string"; +SCM l_inetstr (inetid) + SCM inetid; +{ + struct in_addr addr; + char *ans; + addr.s_addr = htonl(num2ulong(inetid, (char *)ARG1, s_inetstr)); + SYSCALL(ans = inet_ntoa(addr);); + return makfrom0str(ans); +} + +static char s_network[] = "inet:network"; +SCM l_network (host) + SCM host; +{ + struct in_addr addr; + addr.s_addr = htonl(num2ulong(host, (char *)ARG1, s_network)); + return ulong2num(0L+inet_netof(addr)); +} + +static char s_lna[] = "inet:local-network-address"; +SCM l_lna (host) + SCM host; +{ + struct in_addr addr; + addr.s_addr = htonl(num2ulong(host, (char *)ARG1, s_lna)); + return ulong2num(0L+inet_lnaof(addr)); +} + +static char s_makaddr[] = "inet:make-address"; +SCM l_makaddr (net, lna) + SCM net, lna; +{ + struct in_addr addr; + unsigned long netnum = num2ulong(net, (char *)ARG1, s_makaddr); + unsigned long lnanum = num2ulong(lna, (char *)ARG2, s_makaddr); + addr = inet_makeaddr(netnum, lnanum); + return ulong2num(ntohl(addr.s_addr)); +} + +static char s_hostinfo[] = "gethost"; +SCM l_hostinfo(name) + SCM name; +{ + SCM ans = make_vector(MAKINUM(5), UNSPECIFIED); + SCM *ve = VELTS(ans); + SCM lst = EOL; + struct hostent *entry; + struct in_addr inad; + char **argv; + int i = 0; +#ifndef linux + if UNBNDP(name) { + DEFER_INTS; + SYSCALL(entry = gethostent();); + } + else +#endif + if (NIMP(name) && STRINGP(name)) { + DEFER_INTS; + SYSCALL(entry = gethostbyname(CHARS(name));); + } + else { + inad.s_addr = htonl(num2ulong(name, (char *)ARG1, s_hostinfo)); + DEFER_INTS; + SYSCALL(entry = gethostbyaddr((char *)&inad , sizeof(inad), AF_INET);); + } + ALLOW_INTS; + if (!entry) return BOOL_F; + ve[ 0] = makfrom0str(entry->h_name); + ve[ 1] = makfromstrs(-1, entry->h_aliases); + ve[ 2] = MAKINUM(entry->h_addrtype + 0L); + ve[ 3] = MAKINUM(entry->h_length + 0L); + if (sizeof(struct in_addr) != entry->h_length) + {ve[ 4] = BOOL_F; return ans;} + for(argv = entry->h_addr_list; argv[i]; i++); + while (i--) { + inad = *(struct in_addr *)argv[i]; + lst = cons(ulong2num(ntohl(inad.s_addr)), lst); + } + ve[ 4] = lst; + return ans; +} +static char s_netinfo[] = "getnet"; +SCM l_netinfo(name) + SCM name; +{ + SCM ans = make_vector(MAKINUM(4), UNSPECIFIED); + SCM *ve = VELTS(ans); + struct netent *entry; + if UNBNDP(name) { + DEFER_INTS; + SYSCALL(entry = getnetent();); + } + else if (NIMP(name) && STRINGP(name)) { + DEFER_INTS; + SYSCALL(entry = getnetbyname(CHARS(name));); + } + else { + unsigned long netnum; + netnum = num2ulong(name, (char *)ARG1, s_netinfo); + DEFER_INTS; + SYSCALL(entry = getnetbyaddr(netnum, AF_INET);); + } + ALLOW_INTS; + if (!entry) return BOOL_F; + ve[ 0] = makfrom0str(entry->n_name); + ve[ 1] = makfromstrs(-1, entry->n_aliases); + ve[ 2] = MAKINUM(entry->n_addrtype + 0L); + ve[ 3] = ulong2num(entry->n_net + 0L); + return ans; +} +static char s_protoinfo[] = "getproto"; +SCM l_protoinfo(name) + SCM name; +{ + SCM ans = make_vector(MAKINUM(3), UNSPECIFIED); + SCM *ve = VELTS(ans); + struct protoent *entry; + if UNBNDP(name) { + DEFER_INTS; + SYSCALL(entry = getprotoent();); + } + else if (NIMP(name) && STRINGP(name)) { + DEFER_INTS; + SYSCALL(entry = getprotobyname(CHARS(name));); + } + else { + unsigned long protonum; + protonum = num2ulong(name, (char *)ARG1, s_protoinfo); + DEFER_INTS; + SYSCALL(entry = getprotobynumber(protonum);); + } + ALLOW_INTS; + if (!entry) return BOOL_F; + ve[ 0] = makfrom0str(entry->p_name); + ve[ 1] = makfromstrs(-1, entry->p_aliases); + ve[ 2] = MAKINUM(entry->p_proto + 0L); + return ans; +} +static char s_servinfo[] = "getserv"; +SCM l_servinfo(args) + SCM args; +{ + SCM ans = make_vector(MAKINUM(4), UNSPECIFIED); + SCM *ve = VELTS(ans); + SCM name, proto; + struct servent *entry; + if NULLP(args) { + DEFER_INTS; + SYSCALL(entry = getservent();); + goto comlab; + } + name = CAR(args); + proto = CDR(args); + ASSERT(NIMP(proto) && CONSP(proto), args, WNA, s_servinfo); + proto = CAR(proto); + ASSERT(NIMP(proto) && STRINGP(proto), args, ARG2, s_servinfo); + DEFER_INTS; + if (NIMP(name) && STRINGP(name)) + SYSCALL(entry = getservbyname(CHARS(name), CHARS(proto));); + else { + ASSERT(INUMP(proto), proto, ARG1, s_servinfo); + SYSCALL(entry = getservbyport(INUM(proto), CHARS(proto));); + } + comlab: ALLOW_INTS; + if (!entry) return BOOL_F; + ve[ 0] = makfrom0str(entry->s_name); + ve[ 1] = makfromstrs(-1, entry->s_aliases); + ve[ 2] = MAKINUM(ntohs(entry->s_port) + 0L); + ve[ 3] = makfrom0str(entry->s_proto); + return ans; +} + +SCM l_sethost(arg) + SCM arg; +{ + if UNBNDP(arg) endhostent(); + else sethostent(NFALSEP(arg)); + return UNSPECIFIED; +} +SCM l_setnet(arg) + SCM arg; +{ + if UNBNDP(arg) endnetent(); + else setnetent(NFALSEP(arg)); + return UNSPECIFIED; +} +SCM l_setproto(arg) + SCM arg; +{ + if UNBNDP(arg) endprotoent(); + else setprotoent(NFALSEP(arg)); + return UNSPECIFIED; +} +SCM l_setserv(arg) + SCM arg; +{ + if UNBNDP(arg) endservent(); + else setservent(NFALSEP(arg)); + return UNSPECIFIED; +} + +static char s_socket[] = "make-stream-socket"; +SCM l_socket(fam, proto) + SCM fam, proto; +{ + int sd, j, tp = INUM(fam); + FILE* f; + SCM port; + ASSERT(INUMP(fam), fam, ARG1, s_socket); + if UNBNDP(proto) proto = INUM0; + else ASSERT(INUMP(proto), proto, ARG2, s_socket); + NEWCELL(port); + DEFER_INTS; + SYSCALL(sd = socket(tp, SOCK_STREAM, INUM(proto));); + if (-1==sd) wta(UNDEFINED, (char *)NALLOC, s_socket); + SYSCALL(f = fdopen(sd, "r+");); + if (!f) { + close(sd); + wta(MAKINUM(sd), (char *)NALLOC, s_port_type); + } + CAR(port) = tc_socket | (tp<<24) | BUF0; + SETSTREAM(port, f); + i_setbuf0(port); + ALLOW_INTS; + if (AF_INET==tp) { + sd = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j)); + ASSERT(!sd, port, "could not set socket option", s_socket); + } + return port; +} +static char s_socketpair[] = "make-stream-socketpair"; +SCM l_socketpair(fam, proto) + SCM fam, proto; +{ + int sts, tp = INUM(fam); + int sv[2]; + FILE* f[2]; + SCM port[2]; + ASSERT(INUMP(fam), fam, ARG1, s_socketpair); + if UNBNDP(proto) proto = INUM0; + else ASSERT(INUMP(proto), proto, ARG2, s_socketpair); + NEWCELL(port[0]); NEWCELL(port[1]); + DEFER_INTS; + SYSCALL(sts = socketpair(tp, SOCK_STREAM, INUM(proto), sv);); + if (-1==sts) wta(UNDEFINED, (char *)NALLOC, s_socketpair); + SYSCALL(f[0] = fdopen(sv[0], "r+");); + if (!f[0]) { + close(sv[0]); + wta(MAKINUM(sv[0]), (char *)NALLOC, s_port_type); + } + SYSCALL(f[1] = fdopen(sv[1], "r+");); + if (!f[1]) { + fclose(f[0]); + close(sv[1]); + wta(MAKINUM(sv[1]), (char *)NALLOC, s_port_type); + } + CAR(port[0]) = CAR(port[1]) = tc16_fport | mode_bits("r+0"); + SETSTREAM(port[0], f[0]); SETSTREAM(port[1], f[1]); + i_setbuf0(port[0]); i_setbuf0(port[1]); + ALLOW_INTS; + return cons(port[0], port[1]); +} + +static char s_shutdown[] = "socket:shutdown"; +SCM l_shutdown(port, how) + SCM port, how; +{ + int sts; + ASSERT(NIMP(port) && OPPORTP(port), port, ARG1, s_shutdown); + ASSERT(INUMP(how) && 0 <= INUM(how) && 2 >= INUM(how), + how, ARG2, s_shutdown); + SYSCALL(sts = shutdown(fileno(STREAM(port)), INUM(how));); + if (sts) return BOOL_F; + switch (INUM(how)) { + case 0: CAR(port) &= ~RDNG; + break; + case 1: CAR(port) &= ~WRTNG; + break; + case 2: CAR(port) &= ~(RDNG | WRTNG); + } + if SOCKP(port) close_port(port); /* can't read or write */ + return port; +} +static char s_unkfam[] = "unknown-family"; +static char s_connect[] = "socket:connect"; +SCM l_connect (sockpt, address, arg) + SCM sockpt, address, arg; +{ + int sts; + ASSERT(NIMP(sockpt) && SOCKP(sockpt), sockpt, ARG1, s_connect); + switch SOCKTYP(sockpt) { + default: + ASSERT(0, sockpt, s_unkfam, s_connect); + case AF_INET: + ASSERT(NIMP(arg) && CONSP(arg) && NULLP(CDR(arg)), arg, WNA, s_connect); + arg = CAR(arg); + ASSERT(INUMP(arg), arg, ARG3, s_connect); + { + struct sockaddr_in soka; + soka.sin_addr.s_addr = + htonl(num2ulong(address, (char *)ARG2, s_connect)); + soka.sin_family = AF_INET; + soka.sin_port = htons(INUM(arg)); + SYSCALL(sts = connect(fileno(STREAM(sockpt)), + (struct sockaddr*)&soka, sizeof(soka));); + } + break; + case AF_UNIX: + ASSERT(NULLP(arg), arg, WNA, s_connect); + ASSERT(NIMP(address) && STRINGP(address), address, ARG2, s_connect); + { + struct sockaddr_un soka; + soka.sun_family = AF_UNIX; + memcpy(&soka.sun_path, CHARS(address), 1+LENGTH(address)); + SYSCALL(sts = connect(fileno(STREAM(sockpt)), + (struct sockaddr*)&soka, sizeof(soka));); + } + break; + } + if (sts) return BOOL_F; + CAR(sockpt) = tc16_fport | mode_bits("r+0"); + return sockpt; +} + +static char s_bind[] = "socket:bind"; +SCM l_bind(sockpt, address) + SCM sockpt, address; +{ + int sts; + ASSERT(NIMP(sockpt) && SOCKP(sockpt), sockpt, ARG1, s_bind); + switch SOCKTYP(sockpt) { + default: + ASSERT(0, sockpt, s_unkfam, s_bind); + case AF_UNIX: + ASSERT(NIMP(address) && STRINGP(address), address, ARG2, s_bind); + { + struct sockaddr_un sa_server; + bzero((char *) &sa_server, sizeof(sa_server)); + sa_server.sun_family = AF_UNIX; + memcpy(&sa_server.sun_path, CHARS(address), 1+LENGTH(address)); + SYSCALL(sts = bind(fileno(STREAM(sockpt)), + (struct sockaddr *)&sa_server, sizeof(sa_server));); + } + break; + case AF_INET: + ASSERT(INUMP(address), address, ARG2, s_bind); + { + struct sockaddr_in sa_server; + bzero((char *) &sa_server, sizeof(sa_server)); + sa_server.sin_family = AF_INET; + sa_server.sin_addr.s_addr = htonl(INADDR_ANY); + sa_server.sin_port = htons(INUM(address)); + SYSCALL(sts = bind(fileno(STREAM(sockpt)), + (struct sockaddr *)&sa_server, sizeof(sa_server));); + } + break; + } + return sts ? BOOL_F : sockpt; +} + +static char s_listen[] = "socket:listen"; +SCM l_listen(port, backlog) + SCM port, backlog; +{ + int sts; + ASSERT(NIMP(port) && SOCKP(port), port, ARG1, s_listen); + ASSERT(INUMP(backlog), backlog, ARG2, s_listen); + SYSCALL(sts = listen(fileno(STREAM(port)), INUM(backlog));); + if (sts) return BOOL_F; + CAR(port) = tc16_fport | mode_bits("r0"); + return port; +} + +static char s_accept[] = "socket:accept"; +SCM l_accept(sockpt) + SCM sockpt; +{ + int newsd, sadlen; + struct sockaddr sad; + FILE *newfd; + SCM newpt; + NEWCELL(newpt); + ASSERT(NIMP(sockpt) && OPINPORTP(sockpt), sockpt, ARG1, s_accept); + sadlen=sizeof(sad); + DEFER_INTS; + SYSCALL(newsd = accept(fileno(STREAM(sockpt)), &sad, &sadlen);); + if (-1==newsd) + if (EWOULDBLOCK != errno) return BOOL_F; + else wta(sockpt, "couldn't", s_accept); + SYSCALL(newfd = fdopen(newsd, "r+");); + if (!newfd) { + close(newsd); + wta(MAKINUM(newsd), (char *)NALLOC, s_port_type); + } + CAR(newpt) = tc16_fport | mode_bits("r+0"); + SETSTREAM(newpt, newfd); + i_setbuf0(newpt); + ALLOW_INTS; + return newpt; +} + +int sknm_print(exp, port, writing) + SCM exp; SCM port; int writing; +{ + lputs("#<", port); + switch (((struct sockaddr *)CDR(exp))->sa_family) { + case AF_UNIX: + lputs("unix-addr ", port); + lputs(((struct sockaddr_un *)CDR(exp))->sun_path, port); + break; + case AF_INET: + lputs("inet-addr ", port); + lputs(inet_ntoa(((struct sockaddr_in *)CDR(exp))->sin_addr), port); + lputc(':', port); + intprint(0L + ntohs(((struct sockaddr_in *)CDR(exp))->sin_port), 10, port); + break; + default: lputs(s_unkfam, port); + lputc(' ', port); + intprint(0L+((struct sockaddr *)CDR(exp))->sa_family, 10, port); + } + lputc('>', port); + return !0; +} +sizet sknm_free(p) + CELLPTR p; +{ + must_free(CHARS((SCM)p)); + return sizeof(struct sockaddr); +} +long tc16_sknm; +static smobfuns sknm_smob = {mark0, sknm_free, sknm_print, 0}; + +char s_sknm_family[] = "socket-name:family"; +SCM l_sknm_family(snm) + SCM snm; +{ + ASSERT(NIMP(snm) && TYP16(snm)==tc16_sknm, snm, ARG1, s_sknm_family); + return MAKINUM(((struct sockaddr *)CDR(snm))->sa_family + 0L); +} +char s_sknm_port_num[] = "socket-name:port-number"; +SCM l_sknm_port_num(snm) + SCM snm; +{ + ASRTGO(NIMP(snm) && TYP16(snm)==tc16_sknm, err1); + switch (((struct sockaddr *)CDR(snm))->sa_family) { + default: + err1: + wta(snm, (char *)ARG1, s_sknm_port_num); + case AF_INET: + return MAKINUM(ntohs(((struct sockaddr_in *)CDR(snm))->sin_port) + 0L); + } +} +char s_sknm_addr[] = "socket-name:address"; +SCM l_sknm_addr(snm) + SCM snm; +{ + ASRTGO(NIMP(snm) && TYP16(snm)==tc16_sknm, err1); + switch (((struct sockaddr *)CDR(snm))->sa_family) { + default: + err1: + wta(snm, (char *)ARG1, s_sknm_addr); + case AF_INET: + return ulong2num(ntohl(((struct sockaddr_in *)CDR(snm))->sin_addr.s_addr)); + case AF_UNIX: /* the manual says this won't work anyway */ + return makfrom0str(((struct sockaddr_un *)CDR(snm))->sun_path); + } +} + +SCM maksknm(sad) + struct sockaddr *sad; +{ + SCM sknm; + struct sockaddr *msknm; + NEWCELL(sknm); + DEFER_INTS; + msknm = (struct sockaddr *)must_malloc(0L+sizeof(struct sockaddr), "sknm"); + *msknm = *sad; + CAR(sknm) = tc16_sknm; + SETCDR(sknm, msknm); + ALLOW_INTS; + return sknm; +} + +static char s_getpeername[] = "getpeername"; +SCM l_getpeername(sockpt) + SCM sockpt; +{ + struct sockaddr_in sad; + int sts, sadlen = sizeof(sad); + bzero((char *) &sad, sizeof(sad)); + ASSERT(NIMP(sockpt) && OPPORTP(sockpt), sockpt, ARG1, s_getpeername); + SYSCALL(sts = getpeername(fileno(STREAM(sockpt)), + (struct sockaddr*)&sad, &sadlen);); + if (sts || sizeof(sad) != sadlen) return BOOL_F; +/* ASSERT(sad.sin_family==AF_INET, sockpt, "non-internet", s_getpeername); */ + return maksknm(&sad); +} +static char s_getsockname[] = "getsockname"; +SCM l_getsockname(sockpt) + SCM sockpt; +{ + struct sockaddr_in sad; + int sts, sadlen = sizeof(sad); + bzero((char *) &sad, sizeof(sad)); + ASSERT(NIMP(sockpt) && OPPORTP(sockpt), sockpt, ARG1, s_getsockname); + SYSCALL(sts = getsockname(fileno(STREAM(sockpt)), + (struct sockaddr*)&sad, &sadlen);); + if (sts || sizeof(sad) != sadlen) return BOOL_F; + return maksknm(&sad); +} +static iproc subr1s[] = { + {s_inetaddr, l_inetaddr}, + {s_inetstr, l_inetstr}, + {s_network, l_network}, + {s_lna, l_lna}, + {s_makaddr, l_makaddr}, + + {s_accept, l_accept}, + {s_sknm_family, l_sknm_family}, + {s_sknm_port_num, l_sknm_port_num}, + {s_sknm_addr, l_sknm_addr}, + {s_getpeername, l_getpeername}, + {s_getsockname, l_getsockname}, + {0, 0}}; + +static iproc subr1os[] = { + {s_hostinfo, l_hostinfo}, + {s_netinfo, l_netinfo}, + {s_protoinfo, l_protoinfo}, + {"sethostent", l_sethost}, + {"setnetent", l_setnet}, + {"setprotoent", l_setproto}, + {"setservent", l_setserv}, + {0, 0}}; + +static iproc subr2s[] = { + {s_shutdown, l_shutdown}, + {s_bind, l_bind}, + {s_listen, l_listen}, + {s_makaddr, l_makaddr}, + {0, 0}}; + +void init_socket() +{ + sysintern("af_unix", MAKINUM(AF_UNIX)); + sysintern("af_inet", MAKINUM(AF_INET)); + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(subr1os, tc7_subr_1o); + init_iprocs(subr2s, tc7_subr_2); + make_subr(s_servinfo, tc7_lsubr, l_servinfo); + make_subr(s_socket, tc7_subr_2o, l_socket); + make_subr(s_socketpair, tc7_subr_2o, l_socketpair); + make_subr(s_connect, tc7_lsubr_2, l_connect); + tc16_sknm = newsmob(&sknm_smob); + add_feature("socket"); +} diff --git a/split.scm b/split.scm new file mode 100644 index 0000000..1230946 --- /dev/null +++ b/split.scm @@ -0,0 +1,87 @@ +;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this software; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;; As a special exception, the Free Software Foundation gives permission +;; for additional uses of the text contained in its release of GUILE. +;; +;; The exception is that, if you link the GUILE library with other files +;; to produce an executable, this does not by itself cause the +;; resulting executable to be covered by the GNU General Public License. +;; Your use of that executable is in no way restricted on account of +;; linking the GUILE library code into it. +;; +;; This exception does not however invalidate any other reasons why +;; the executable file might be covered by the GNU General Public License. +;; +;; This exception applies only to the code released by the +;; Free Software Foundation under the name GUILE. If you copy +;; code from other Free Software Foundation releases into a copy of +;; GUILE, as the General Public License permits, the exception does +;; not apply to the code that you add in this way. To avoid misleading +;; anyone as to the status of such modified files, you must delete +;; this exception notice from them. +;; +;; If you write modifications of your own for GUILE, it is your choice +;; whether to permit this exception to apply to your modifications. +;; If you do not wish that, delete this exception notice. + +;;;; "split.scm", split input, output, and error streams into windows. +;;; Author: Aubrey Jaffer. + +(require 'curses) +(define *stdscr* (initscr)) +(nocbreak) +(echo) +(nl) +(define subwindow-height (max 2 (quotient (output-port-height) 5))) +(define *output-window* + (newwin (- (output-port-height) (* 2 subwindow-height) 2) + (output-port-width) + 0 + 0)) +(define *input-window* + (newwin subwindow-height + (output-port-width) + (- (output-port-height) (* 2 subwindow-height) 1) + 0)) +(define *error-window* + (newwin subwindow-height + (output-port-width) + (- (output-port-height) subwindow-height) + 0)) +(wmove *stdscr* (- (output-port-height) subwindow-height 1) 0) +(wstandout *stdscr*) +(display (make-string (output-port-width) #\-) *stdscr*) +(wmove *stdscr* (- (output-port-height) (* 2 subwindow-height) 2) 0) +(display (make-string (output-port-width) #\-) *stdscr*) +(wstandend *stdscr*) +(touchwin *stdscr*) +(force-output *stdscr*) +(scrollok *output-window* #t) +(scrollok *input-window* #t) +(scrollok *error-window* #t) +(define *default-output-port* (set-current-output-port *output-window*)) +(define *default-input-port* (set-current-input-port *input-window*)) +(define *default-error-port* (set-current-error-port *error-window*)) +(leaveok *output-window* #t) +(leaveok *input-window* #f) +(leaveok *error-window* #t) + +(define (unsplit) + (cond ((endwin) + (set-current-output-port *default-output-port*) + (set-current-input-port *default-input-port*) + (set-current-error-port *default-error-port*)))) @@ -0,0 +1,2009 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "subr.c" integer and other Scheme procedures + Author: Aubrey Jaffer */ + +#include <ctype.h> +#include "scm.h" + +#define s_length (s_st_length+7) +#define s_append (s_st_append+7) + +char s_make_string[] = "make-string"; +char s_list[] = "list"; + +static char s_setcar[] = "set-car!", s_setcdr[] = "set-cdr!", + s_reverse[] = "reverse", s_list_ref[] = "list-ref"; +static char s_memq[] = "memq", s_member[] = "member", + s_assq[] = "assq", s_assoc[] = "assoc"; +static char s_symbol2string[] = "symbol->string", + s_str2symbol[] = "string->symbol"; +extern char s_inexactp[]; +#define s_exactp (s_inexactp+2) +static char s_oddp[] = "odd?", s_evenp[] = "even?"; +static char s_abs[] = "abs", s_quotient[] = "quotient", + s_remainder[] = "remainder", s_modulo[] = "modulo"; +static char s_gcd[] = "gcd"; + +static char s_ci_eq[] = "char-ci=?", + s_ch_lessp[] = "char<?", s_ch_leqp[] = "char<=?", + s_ci_lessp[] = "char-ci<?", s_ci_leqp[] = "char-ci<=?", + s_ch_grp[] = "char>?", s_ch_geqp[] = "char>=?", + s_ci_grp[] = "char-ci>?", s_ci_geqp[] = "char-ci>=?"; +static char s_ch_alphap[] = "char-alphabetic?", + s_ch_nump[] = "char-numeric?", + s_ch_whitep[] = "char-whitespace?", + s_ch_upperp[] = "char-upper-case?", + s_ch_lowerp[] = "char-lower-case?"; +static char s_char2int[] = "char->integer", s_int2char[] = "integer->char", + s_ch_upcase[] = "char-upcase", s_ch_downcase[] = "char-downcase"; + +static char s_st_length[] = "string-length", + s_st_ref[] = "string-ref", s_st_set[] = "string-set!"; +static char s_st_equal[] = "string=?", s_stci_equal[] = "string-ci=?", + s_st_lessp[] = "string<?", s_stci_lessp[] = "string-ci<?"; +static char s_substring[] = "substring", s_st_append[] = "string-append"; + +static char s_ve_length[] = "vector-length", + s_ve_ref[] = "vector-ref", s_ve_set[] = "vector-set!"; + +SCM lnot(x) + SCM x; +{ + return FALSEP(x) ? BOOL_T : BOOL_F; +} +SCM booleanp(obj) + SCM obj; +{ + if (BOOL_F==obj) return BOOL_T; + if (BOOL_T==obj) return BOOL_T; + return BOOL_F; +} +SCM eq(x, y) + SCM x, y; +{ + if (x==y) return BOOL_T; + else return BOOL_F; +} + +SCM consp(x) + SCM x; +{ + if IMP(x) return BOOL_F; + return CONSP(x) ? BOOL_T : BOOL_F; +} +SCM setcar(pair, value) + SCM pair, value; +{ + ASSERT(NIMP(pair) && CONSP(pair), pair, ARG1, s_setcar); + CAR(pair) = value; + return UNSPECIFIED; +} +SCM setcdr(pair, value) + SCM pair, value; +{ + ASSERT(NIMP(pair) && CONSP(pair), pair, ARG1, s_setcdr); + CDR(pair) = value; + return UNSPECIFIED; +} +SCM nullp(x) + SCM x; +{ + return NULLP(x) ? BOOL_T : BOOL_F; +} +long ilength(sx) + SCM sx; +{ + register long i = 0; + register SCM x = sx; + do { + if IMP(x) return NULLP(x) ? i : -1; + if NCONSP(x) return -2; + x = CDR(x); + i++; + if IMP(x) return NULLP(x) ? i : -1; + if NCONSP(x) return -2; + x = CDR(x); + i++; + sx = CDR(sx); + } + while (x != sx); + return -1; +} +SCM listp(x) + SCM x; +{ + if (ilength(x)<0) return BOOL_F; + else return BOOL_T; +} +SCM list(objs) + SCM objs; +{ + return objs; +} +SCM length(x) + SCM x; +{ + SCM i = MAKINUM(ilength(x)); + ASSERT(i >= INUM0, x, ARG1, s_length); + return i; +} +SCM append(args) + SCM args; +{ + SCM res = EOL; + SCM *lloc = &res, arg; + if IMP(args) { + ASSERT(NULLP(args), args, ARGn, s_append); + return res; + } + ASSERT(CONSP(args), args, ARGn, s_append); + while (1) { + arg = CAR(args); + args = CDR(args); + if IMP(args) { + *lloc = arg; + ASSERT(NULLP(args), args, ARGn, s_append); + return res; + } + ASSERT(CONSP(args), args, ARGn, s_append); + for(;NIMP(arg);arg = CDR(arg)) { + ASSERT(CONSP(arg), arg, ARGn, s_append); + *lloc = cons(CAR(arg), EOL); + lloc = &CDR(*lloc); + } + ASSERT(NULLP(arg), arg, ARGn, s_append); + } +} +SCM reverse(lst) + SCM lst; +{ + SCM res = EOL; + SCM p = lst; + for(;NIMP(p);p = CDR(p)) { + ASSERT(CONSP(p), lst, ARG1, s_reverse); + res = cons(CAR(p), res); + } + ASSERT(NULLP(p), lst, ARG1, s_reverse); + return res; +} +SCM list_ref(lst, k) + SCM lst, k; +{ + register long i; + ASSERT(INUMP(k), k, ARG2, s_list_ref); + i = INUM(k); + ASSERT(i >= 0, k, ARG2, s_list_ref); + while (i-- > 0) { + ASRTGO(NIMP(lst) && CONSP(lst), erout); + lst = CDR(lst); + } +erout: ASSERT(NIMP(lst) && CONSP(lst), + NULLP(lst)?k:lst, NULLP(lst)?OUTOFRANGE:ARG1, s_list_ref); + return CAR(lst); +} +SCM memq(x, lst) + SCM x, lst; +{ + for(;NIMP(lst);lst = CDR(lst)) { + ASSERT(CONSP(lst), lst, ARG2, s_memq); + if (CAR(lst)==x) return lst; + } + ASSERT(NULLP(lst), lst, ARG2, s_memq); + return BOOL_F; +} +SCM member(x, lst) + SCM x, lst; +{ + for(;NIMP(lst);lst = CDR(lst)) { + ASSERT(CONSP(lst), lst, ARG2, s_member); + if NFALSEP(equal(CAR(lst), x)) return lst; + } + ASSERT(NULLP(lst), lst, ARG2, s_member); + return BOOL_F; +} +SCM assq(x, alist) + SCM x, alist; +{ + SCM tmp; + for(;NIMP(alist);alist = CDR(alist)) { + ASSERT(CONSP(alist), alist, ARG2, s_assq); + tmp = CAR(alist); + ASSERT(NIMP(tmp) && CONSP(tmp), alist, ARG2, s_assq); + if (CAR(tmp)==x) return tmp; + } + ASSERT(NULLP(alist), alist, ARG2, s_assq); + return BOOL_F; +} +SCM assoc(x, alist) + SCM x, alist; +{ + SCM tmp; + for(;NIMP(alist);alist = CDR(alist)) { + ASSERT(CONSP(alist), alist, ARG2, s_assoc); + tmp = CAR(alist); + ASSERT(NIMP(tmp) && CONSP(tmp), alist, ARG2, s_assoc); + if NFALSEP(equal(CAR(tmp), x)) return tmp; + } + ASSERT(NULLP(alist), alist, ARG2, s_assoc); + return BOOL_F; +} + +SCM symbolp(x) + SCM x; +{ + if IMP(x) return BOOL_F; + return SYMBOLP(x) ? BOOL_T : BOOL_F; +} +SCM symbol2string(s) + SCM s; +{ + ASSERT(NIMP(s) && SYMBOLP(s), s, ARG1, s_symbol2string); + return makfromstr(CHARS(s), (sizet)LENGTH(s)); +} +SCM string2symbol(s) + SCM s; +{ + ASSERT(NIMP(s) && STRINGP(s), s, ARG1, s_str2symbol); + s = intern(CHARS(s), (sizet)LENGTH(s)); + return CAR(s); +} + +SCM exactp(x) + SCM x; +{ + if INUMP(x) return BOOL_T; +#ifdef BIGDIG + if (NIMP(x) && BIGP(x)) return BOOL_T; +#endif + return BOOL_F; +} +SCM oddp(n) + SCM n; +{ +#ifdef BIGDIG + if NINUMP(n) { + ASSERT(NIMP(n) && BIGP(n), n, ARG1, s_oddp); + return (1 & BDIGITS(n)[0]) ? BOOL_T : BOOL_F; + } +#else + ASSERT(INUMP(n), n, ARG1, s_oddp); +#endif + return (4 & (int)n) ? BOOL_T : BOOL_F; +} +SCM evenp(n) + SCM n; +{ +#ifdef BIGDIG + if NINUMP(n) { + ASSERT(NIMP(n) && BIGP(n), n, ARG1, s_evenp); + return (1 & BDIGITS(n)[0]) ? BOOL_F : BOOL_T; + } +#else + ASSERT(INUMP(n), n, ARG1, s_evenp); +#endif + return (4 & (int)n) ? BOOL_F : BOOL_T; +} +SCM absval(x) + SCM x; +{ +#ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_abs); + if (TYP16(x)==tc16_bigpos) return x; + return copybig(x, 0); + } +#else + ASSERT(INUMP(x), x, ARG1, s_abs); +#endif + if (INUM(x) >= 0) return x; + x = -INUM(x); + if (!POSFIXABLE(x)) +#ifdef BIGDIG + return long2big(x); +#else + wta(MAKINUM(-x), (char *)OVFLOW, s_abs); +#endif + return MAKINUM(x); +} +SCM lquotient(x, y) + SCM x, y; +{ + register long z; +#ifdef BIGDIG + if NINUMP(x) { + long w; + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_quotient); + if NINUMP(y) { + ASRTGO(NIMP(y) && BIGP(y), bady); + return divbigbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), + BIGSIGN(x) ^ BIGSIGN(y), 2); + } + z = INUM(y); + ASRTGO(z, ov); + if (1==z) return x; + if (z < 0) z = -z; + if (z < BIGRAD) { + w = copybig(x, BIGSIGN(x) ? (y>0) : (y<0)); + divbigdig(BDIGITS(w), NUMDIGS(w), (BIGDIG)z); + return normbig(w); + } +# ifndef DIGSTOOBIG + w = pseudolong(z); + return divbigbig(BDIGITS(x), NUMDIGS(x), (BIGDIG *)&w, DIGSPERLONG, + BIGSIGN(x) ? (y>0) : (y<0), 2); +# else + { BIGDIG zdigs[DIGSPERLONG]; + longdigs(z, zdigs); + return divbigbig(BDIGITS(x), NUMDIGS(x), zdigs, DIGSPERLONG, + BIGSIGN(x) ? (y>0) : (y<0), 2); + } +# endif + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_quotient); +# endif + return INUM0; + } +#else + ASSERT(INUMP(x), x, ARG1, s_quotient); + ASSERT(INUMP(y), y, ARG2, s_quotient); +#endif + if ((z = INUM(y))==0) + ov: wta(y, (char *)OVFLOW, s_quotient); + z = INUM(x)/z; +#ifdef BADIVSGNS + { +# if (__TURBOC__==1) + long t = ((y<0) ? -INUM(x) : INUM(x))%INUM(y); +# else + long t = INUM(x)%INUM(y); +# endif + if (t==0) ; + else if (t < 0) + if (x < 0) ; + else z--; + else if (x < 0) z++; + } +#endif + if (!FIXABLE(z)) +#ifdef BIGDIG + return long2big(z); +#else + wta(x, (char *)OVFLOW, s_quotient); +#endif + return MAKINUM(z); +} +SCM lremainder(x, y) + SCM x, y; +{ + register long z; +#ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_remainder); + if NINUMP(y) { + ASRTGO(NIMP(y) && BIGP(y), bady); + return divbigbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), + BIGSIGN(x), 0); + } + if (!(z = INUM(y))) goto ov; + return divbigint(x, z, BIGSIGN(x), 0); + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_remainder); +# endif + return x; + } +#else + ASSERT(INUMP(x), x, ARG1, s_remainder); + ASSERT(INUMP(y), y, ARG2, s_remainder); +#endif + if (!(z = INUM(y))) + ov: wta(y, (char *)OVFLOW, s_remainder); +#if (__TURBOC__==1) + if (z < 0) z = -z; +#endif + z = INUM(x)%z; +#ifdef BADIVSGNS + if (!z) ; + else if (z < 0) + if (x < 0) ; + else z += INUM(y); + else if (x < 0) z -= INUM(y); +#endif + return MAKINUM(z); +} +SCM modulo(x, y) + SCM x, y; +{ + register long yy, z; +#ifdef BIGDIG + if NINUMP(x) { + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_modulo); + if NINUMP(y) { + ASRTGO(NIMP(y) && BIGP(y), bady); + return divbigbig(BDIGITS(x), NUMDIGS(x), BDIGITS(y), NUMDIGS(y), + BIGSIGN(y), (BIGSIGN(x) ^ BIGSIGN(y)) ? 1 : 0); + } + if (!(z = INUM(y))) goto ov; + return divbigint(x, z, y < 0, (BIGSIGN(x) ? (y > 0) : (y < 0)) ? 1 : 0); + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_modulo); +# endif + return (BIGSIGN(y) ? (x>0) : (x<0)) ? sum(x, y) : x; + } +#else + ASSERT(INUMP(x), x, ARG1, s_modulo); + ASSERT(INUMP(y), y, ARG2, s_modulo); +#endif + if (!(yy = INUM(y))) + ov: wta(y, (char *)OVFLOW, s_modulo); +#if (__TURBOC__==1) + z = INUM(x); + z = ((yy<0) ? -z : z)%yy; +#else + z = INUM(x)%yy; +#endif + return MAKINUM(((yy<0) ? (z>0) : (z<0)) ? z+yy : z); +} + +SCM lgcd(x, y) + SCM x, y; +{ + register long u, v, k, t; + tailrec: + if UNBNDP(y) return UNBNDP(x) ? INUM0 : x; +#ifdef BIGDIG + if NINUMP(x) { + big_gcd: + ASSERT(NIMP(x) && BIGP(x), x, ARG1, s_gcd); + if BIGSIGN(x) x = copybig(x, 0); + newy: + if NINUMP(y) { + ASSERT(NIMP(y) && BIGP(y), y, ARG2, s_gcd); + if BIGSIGN(y) y = copybig(y, 0); + switch (bigcomp(x, y)) { + case -1: + swaprec: t = lremainder(x, y); x = y; y = t; goto tailrec; + case 0: return x; + case 1: y = lremainder(y, x); goto newy; + } + /* instead of the switch, we could just return lgcd(y, modulo(x, y)); */ + } + if (INUM0==y) return x; goto swaprec; + } + if NINUMP(y) { t=x; x=y; y=t; goto big_gcd;} +#else + ASSERT(INUMP(x), x, ARG1, s_gcd); + ASSERT(INUMP(y), y, ARG2, s_gcd); +#endif + u = INUM(x); + if (u<0) u = -u; + v = INUM(y); + if (v<0) v = -v; + else if (0==v) goto getout; + if (0==u) {u = v; goto getout;} + for (k = 1;!(1 & ((int)u|(int)v));k <<= 1, u >>= 1, v >>= 1); + if (1 & (int)u) t = -v; + else { + t = u; +b3: + t = SRS(t, 1); + } + if (!(1 & (int)t)) goto b3; + if (t>0) u = t; + else v = -t; + if ((t = u-v)) goto b3; + u = u*k; +getout: + if (!POSFIXABLE(u)) +#ifdef BIGDIG + return long2big(u); +#else + wta(x, (char *)OVFLOW, s_gcd); +#endif + return MAKINUM(u); +} +SCM llcm(n1, n2) + SCM n1, n2; +{ + SCM d; + if UNBNDP(n2) { + n2 = MAKINUM(1L); + if UNBNDP(n1) return n2; + } + d = lgcd(n1, n2); + if (INUM0==d) return d; + return absval(product(n1, lquotient(n2, d))); +} + +/* Emulating 2's complement bignums with sign magnitude arithmetic: + + Logand: + X Y Result Method: + (len) + + + + x (map digit:logand X Y) + + - + x (map digit:logand X (lognot (+ -1 Y))) + - + + y (map digit:logand (lognot (+ -1 X)) Y) + - - - (+ 1 (map digit:logior (+ -1 X) (+ -1 Y))) + + Logior: + X Y Result Method: + + + + + (map digit:logior X Y) + + - - y (+ 1 (map digit:logand (lognot X) (+ -1 Y))) + - + - x (+ 1 (map digit:logand (+ -1 X) (lognot Y))) + - - - x (+ 1 (map digit:logand (+ -1 X) (+ -1 Y))) + + Logxor: + X Y Result Method: + + + + + (map digit:logxor X Y) + + - - (+ 1 (map digit:logxor X (+ -1 Y))) + - + - (+ 1 (map digit:logxor (+ -1 X) Y)) + - - + (map digit:logxor (+ -1 X) (+ -1 Y)) + + Logtest: + X Y Result + + + + (any digit:logand X Y) + + - (any digit:logand X (lognot (+ -1 Y))) + - + (any digit:logand (lognot (+ -1 X)) Y) + - - #t + +*/ + +#ifdef BIGDIG + +SCM scm_big_ior P((BIGDIG *x, sizet nx, int xsgn, SCM bigy)); +SCM scm_big_and P((BIGDIG *x, sizet nx, int xsgn, SCM bigy, int zsgn)); +SCM scm_big_xor P((BIGDIG *x, sizet nx, int xsgn, SCM bigy)); +SCM scm_big_test P((BIGDIG *x, sizet nx, int xsgn, SCM bigy)); + +SCM scm_copy_big_dec(b, sign) + SCM b; + int sign; +{ + long num = -1; + sizet nx = NUMDIGS(b); + sizet i = 0; + SCM ans = mkbig(nx, sign); + BIGDIG *src = BDIGITS(b), *dst = BDIGITS(ans); + if BIGSIGN(b) do { + num += src[i]; + if (num < 0) {dst[i] = num + BIGRAD; num = -1;} + else {dst[i] = BIGLO(num); num = 0;} + } while (++i < nx); + else + while (nx--) dst[nx] = src[nx]; + return ans; +} + +SCM scm_copy_smaller(x, nx, zsgn) + BIGDIG *x; + sizet nx; + int zsgn; +{ + long num = -1; + sizet i = 0; + SCM z = mkbig(nx, zsgn); + BIGDIG *zds = BDIGITS(z); + if (zsgn) do { + num += x[i]; + if (num < 0) {zds[i] = num + BIGRAD; num = -1;} + else {zds[i] = BIGLO(num); num = 0;} + } while (++i < nx); + else do zds[i] = x[i]; while (++i < nx); + return z; +} + +SCM scm_big_ior(x, nx, xsgn, bigy) + BIGDIG *x; + SCM bigy; + sizet nx; /* Assumes nx <= NUMDIGS(bigy) */ + int xsgn; /* Assumes xsgn equals either 0 or 0x0100 */ +{ + long num = -1; + sizet i = 0, ny = NUMDIGS(bigy); + SCM z = scm_copy_big_dec(bigy, xsgn & BIGSIGN(bigy)); + BIGDIG *zds = BDIGITS(z); + if (xsgn) { + do { + num += x[i]; + if (num < 0) {zds[i] |= num + BIGRAD; num = -1;} + else {zds[i] |= BIGLO(num); num = 0;} + } while (++i < nx); + /* ========= Need to increment zds now =========== */ + i = 0; num = 1; + while (i < ny) { + num += zds[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + if (!num) return z; + } + adjbig(z, 1 + ny); /* OOPS, overflowed into next digit. */ + BDIGITS(z)[ny] = 1; + return z; + } + else do zds[i] = zds[i] | x[i]; while (++i < nx); + return z; +} + +SCM scm_big_xor(x, nx, xsgn, bigy) + BIGDIG *x; + SCM bigy; + sizet nx; /* Assumes nx <= NUMDIGS(bigy) */ + int xsgn; /* Assumes xsgn equals either 0 or 0x0100 */ +{ + long num = -1; + sizet i = 0, ny = NUMDIGS(bigy); + SCM z = scm_copy_big_dec(bigy, xsgn ^ BIGSIGN(bigy)); + BIGDIG *zds = BDIGITS(z); + if (xsgn) do { + num += x[i]; + if (num < 0) {zds[i] ^= num + BIGRAD; num = -1;} + else {zds[i] ^= BIGLO(num); num = 0;} + } while (++i < nx); + else do { + zds[i] = zds[i] ^ x[i]; + } while (++i < nx); + + if (xsgn ^ BIGSIGN(bigy)) { + /* ========= Need to increment zds now =========== */ + i = 0; num = 1; + while (i < ny) { + num += zds[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + if (!num) return normbig(z); + } + } + return normbig(z); +} + +SCM scm_big_and(x, nx, xsgn, bigy, zsgn) + BIGDIG *x; + SCM bigy; + sizet nx; /* Assumes nx <= NUMDIGS(bigy) */ + int xsgn; /* Assumes xsgn equals either 0 or 0x0100 */ + int zsgn; /* return sign equals either 0 or 0x0100 */ +{ + long num = -1; + sizet i = 0; + SCM z; + BIGDIG *zds; + if (xsgn==zsgn) { + z = scm_copy_smaller(x, nx, zsgn); + x = BDIGITS(bigy); + xsgn = BIGSIGN(bigy); + } + else z = scm_copy_big_dec(bigy, zsgn); + zds = BDIGITS(z); + + if (zsgn) { + if (xsgn) do { + num += x[i]; + if (num < 0) {zds[i] &= num + BIGRAD; num = -1;} + else {zds[i] &= BIGLO(num); num = 0;} + } while (++i < nx); + else do zds[i] = zds[i] & ~x[i]; while (++i < nx); + /* ========= need to increment zds now =========== */ + i = 0; num = 1; + while (i < nx) { + num += zds[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + if (!num) return normbig(z); + } + } + else if (xsgn) do { + num += x[i]; + if (num < 0) {zds[i] &= num + BIGRAD; num = -1;} + else {zds[i] &= ~BIGLO(num); num = 0;} + } while (++i < nx); + else do zds[i] = zds[i] & x[i]; while (++i < nx); + return normbig(z); +} + +SCM scm_big_test(x, nx, xsgn, bigy) + BIGDIG *x; + SCM bigy; + sizet nx; /* Assumes nx <= NUMDIGS(bigy) */ + int xsgn; /* Assumes xsgn equals either 0 or 0x0100 */ +{ + BIGDIG *y; + sizet i = 0; + long num = -1; + if (BIGSIGN(bigy) & xsgn) return BOOL_T; + if (NUMDIGS(bigy) != nx && xsgn) return BOOL_T; + y = BDIGITS(bigy); + if (xsgn) + do { + num += x[i]; + if (num < 0) { + if (y[i] & ~(num + BIGRAD)) return BOOL_T; + num = -1; + } + else { + if (y[i] & ~BIGLO(num)) return BOOL_T; + num = 0; + } + } while (++i < nx); + else if BIGSIGN(bigy) + do { + num += y[i]; + if (num < 0) { + if (x[i] & ~(num + BIGRAD)) return BOOL_T; + num = -1; + } + else { + if (x[i] & ~BIGLO(num)) return BOOL_T; + num = 0; + } + } while (++i < nx); + else + do if (x[i] & y[i]) return BOOL_T; + while (++i < nx); + return BOOL_F; +} + +#endif + +static char s_logand[] = "logand", s_lognot[] = "lognot", + s_logior[] = "logior", s_logxor[] = "logxor", + s_logtest[] = "logtest", s_logbitp[] = "logbit?", + s_ash[] = "ash", s_logcount[] = "logcount", + s_intlength[] = "integer-length", + s_intexpt[] = "integer-expt", + s_bitextract[] = "bit-extract"; + +SCM scm_logior(x, y) + SCM x, y; +{ + if UNBNDP(y) { + if UNBNDP(x) return INUM0; +#ifndef RECKLESS + if (!(NUMBERP(x))) + badx: wta(x, (char *)ARG1, s_logior); +#endif + return x; + } +#ifdef BIGDIG + if NINUMP(x) { + SCM t; + ASRTGO(NIMP(x) && BIGP(x), badx); + if INUMP(y) {t = x; x = y; y = t; goto intbig;} + ASRTGO(NIMP(y) && BIGP(y), bady); + if (NUMDIGS(x) > NUMDIGS(y)) {t = x; x = y; y = t;} + if ((!BIGSIGN(x)) && !BIGSIGN(y)) + return scm_big_ior(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y); + return scm_big_and(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0x0100); + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_logior); +# endif + intbig: { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(x)); + if ((!(x < 0)) && !BIGSIGN(y)) + return scm_big_ior((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y); + return scm_big_and((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, + 0x0100); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + if ((!(x < 0)) && !BIGSIGN(y)) + return scm_big_ior(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y); + return scm_big_and(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0x0100); +# endif + }} +#else + ASRTGO(INUMP(x), badx); + ASSERT(INUMP(y), y, ARG2, s_logior); +#endif + return MAKINUM(INUM(x) | INUM(y)); +} + +SCM scm_logand(x, y) + SCM x, y; +{ + if UNBNDP(y) { + if UNBNDP(x) return MAKINUM(-1); +#ifndef RECKLESS + if (!(NUMBERP(x))) + badx: wta(x, (char *)ARG1, s_logand); +#endif + return x; + } +#ifdef BIGDIG + if NINUMP(x) { + SCM t; + ASRTGO(NIMP(x) && BIGP(x), badx); + if INUMP(y) {t = x; x = y; y = t; goto intbig;} + ASRTGO(NIMP(y) && BIGP(y), bady); + if (NUMDIGS(x) > NUMDIGS(y)) {t = x; x = y; y = t;} + if ((BIGSIGN(x)) && BIGSIGN(y)) + return scm_big_ior(BDIGITS(x), NUMDIGS(x), 0x0100, y); + return scm_big_and(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y, 0); + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_logand); +# endif + intbig: { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(x)); + if ((x < 0) && BIGSIGN(y)) + return scm_big_ior((BIGDIG *)&z, DIGSPERLONG, 0x0100, y); + return scm_big_and((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, + 0); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + if ((x < 0) && BIGSIGN(y)) + return scm_big_ior(zdigs, DIGSPERLONG, 0x0100, y); + return scm_big_and(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y, 0); +# endif + }} +#else + ASRTGO(INUMP(x), badx); + ASSERT(INUMP(y), y, ARG2, s_logand); +#endif + return MAKINUM(INUM(x) & INUM(y)); +} + +SCM scm_logxor(x, y) + SCM x, y; +{ + if UNBNDP(y) { + if UNBNDP(x) return INUM0; +#ifndef RECKLESS + if (!(NUMBERP(x))) + badx: wta(x, (char *)ARG1, s_logxor); +#endif + return x; + } +#ifdef BIGDIG + if NINUMP(x) { + SCM t; + ASRTGO(NIMP(x) && BIGP(x), badx); + if INUMP(y) {t = x; x = y; y = t; goto intbig;} + ASRTGO(NIMP(y) && BIGP(y), bady); + if (NUMDIGS(x) > NUMDIGS(y)) {t = x; x = y; y = t;} + return scm_big_xor(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y); + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_logxor); +# endif + intbig: { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(x)); + return scm_big_xor((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + return scm_big_xor(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y); +# endif + }} +#else + ASRTGO(INUMP(x), badx); + ASSERT(INUMP(y), y, ARG2, s_logxor); +#endif + return (x ^ y) + INUM0; +} + +SCM scm_logtest(x, y) + SCM x, y; +{ +#ifndef RECKLESS + if (!(NUMBERP(x))) + badx: wta(x, (char *)ARG1, s_logtest); +#endif +#ifdef BIGDIG + if NINUMP(x) { + SCM t; + ASRTGO(NIMP(x) && BIGP(x), badx); + if INUMP(y) {t = x; x = y; y = t; goto intbig;} + ASRTGO(NIMP(y) && BIGP(y), bady); + if (NUMDIGS(x) > NUMDIGS(y)) {t = x; x = y; y = t;} + return scm_big_test(BDIGITS(x), NUMDIGS(x), BIGSIGN(x), y); + } + if NINUMP(y) { +# ifndef RECKLESS + if (!(NIMP(y) && BIGP(y))) + bady: wta(y, (char *)ARG2, s_logtest); +# endif + intbig: { +# ifndef DIGSTOOBIG + long z = pseudolong(INUM(x)); + return scm_big_test((BIGDIG *)&z, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y); +# else + BIGDIG zdigs[DIGSPERLONG]; + longdigs(INUM(x), zdigs); + return scm_big_test(zdigs, DIGSPERLONG, (x < 0) ? 0x0100 : 0, y); +# endif + }} +#else + ASRTGO(INUMP(x), badx); + ASSERT(INUMP(y), y, ARG2, s_logtest); +#endif + return (INUM(x) & INUM(y)) ? BOOL_T : BOOL_F; +} + +SCM scm_logbitp(index, j1) + SCM index, j1; +{ + ASSERT(INUMP(index) && INUM(index) >= 0, index, ARG1, s_logbitp); +#ifdef BIGDIG + if NINUMP(j1) { + ASSERT(NIMP(j1) && BIGP(j1), j1, (char *)ARG2, s_logbitp); + if (NUMDIGS(j1) * BITSPERDIG < INUM(index)) return BOOL_F; + else if BIGSIGN(j1) { + long num = -1; + sizet i = 0; + BIGDIG *x = BDIGITS(j1); + sizet nx = INUM(index)/BITSPERDIG; + while (!0) { + num += x[i]; + if (nx==i++) + return ((1L << (INUM(index)%BITSPERDIG)) & num) ? BOOL_F : BOOL_T; + if (num < 0) num = -1; + else num = 0; + } + } + else return (BDIGITS(j1)[INUM(index)/BITSPERDIG] & + (1L << (INUM(index)%BITSPERDIG))) ? BOOL_T : BOOL_F; + } +#else + ASSERT(INUMP(j1), j1, (char *)ARG2, s_logbitp); +#endif + return ((1L << INUM(index)) & INUM(j1)) ? BOOL_T : BOOL_F; +} + +SCM scm_lognot(n) + SCM n; +{ + return difference(MAKINUM(-1L), n); +} + +SCM scm_intexpt(z1, z2) + SCM z1, z2; +{ + SCM acc = MAKINUM(1L); +#ifdef BIGDIG + if (INUM0==z1 || acc==z1) return z1; + else if (MAKINUM(-1L)==z1) return BOOL_F==evenp(z2)?z1:acc; +#endif + ASSERT(INUMP(z2), z2, ARG2, s_intexpt); + z2 = INUM(z2); + if (z2 < 0) { + z2 = -z2; + z1 = divide(z1, UNDEFINED); + } + while(1) { + if (0==z2) return acc; + if (1==z2) return product(acc, z1); + if (z2 & 1) acc = product(acc, z1); + z1 = product(z1, z1); + z2 >>= 1; + } +} +SCM scm_ash(n, cnt) + SCM n, cnt; +{ + SCM res = INUM(n); + ASSERT(INUMP(cnt), cnt, ARG2, s_ash); +#ifdef BIGDIG + if(cnt < 0) { + res = scm_intexpt(MAKINUM(2), MAKINUM(-INUM(cnt))); + if NFALSEP(negativep(n)) + return sum(MAKINUM(-1L), lquotient(sum(MAKINUM(1L), n), res)); + else return lquotient(n, res); + } + else return product(n, scm_intexpt(MAKINUM(2), cnt)); +#else + ASSERT(INUMP(n), n, ARG1, s_ash); + cnt = INUM(cnt); + if (cnt < 0) return MAKINUM(SRS(res, -cnt)); + res = MAKINUM(res<<cnt); + if (INUM(res)>>cnt != INUM(n)) wta(n, (char *)OVFLOW, s_ash); + return res; +#endif +} + +SCM scm_bitextract(n, start, end) + SCM n, start, end; +{ + ASSERT(INUMP(start), start, ARG2, s_bitextract); + ASSERT(INUMP(end), end, ARG3, s_bitextract); + start = INUM(start); end = INUM(end); + ASSERT(end >= start, MAKINUM(end), OUTOFRANGE, s_bitextract); +#ifdef BIGDIG + if NINUMP(n) + return + scm_logand(difference(scm_intexpt(MAKINUM(2), MAKINUM(end - start)), + MAKINUM(1L)), + scm_ash(n, MAKINUM(-start))); +#else + ASSERT(INUMP(n), n, ARG1, s_bitextract); +#endif + return MAKINUM((INUM(n)>>start) & ((1L<<(end-start))-1)); +} + +char logtab[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; +SCM scm_logcount(n) + SCM n; +{ + register unsigned long c = 0; + register long nn; +#ifdef BIGDIG + if NINUMP(n) { + sizet i; BIGDIG *ds, d; + ASSERT(NIMP(n) && BIGP(n), n, ARG1, s_logcount); + if BIGSIGN(n) return scm_logcount(difference(MAKINUM(-1L), n)); + ds = BDIGITS(n); + for(i = NUMDIGS(n); i--; ) + for(d = ds[i]; d; d >>= 4) c += logtab[15 & d]; + return MAKINUM(c); + } +#else + ASSERT(INUMP(n), n, ARG1, s_logcount); +#endif + if ((nn = INUM(n)) < 0) nn = -1 - nn; + for(; nn; nn >>= 4) c += logtab[15 & nn]; + return MAKINUM(c); +} + +char ilentab[] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4}; +SCM scm_intlength(n) + SCM n; +{ + register unsigned long c = 0; + register long nn; + unsigned int l = 4; +#ifdef BIGDIG + if NINUMP(n) { + BIGDIG *ds, d; + ASSERT(NIMP(n) && BIGP(n), n, ARG1, s_intlength); + if BIGSIGN(n) return scm_intlength(difference(MAKINUM(-1L), n)); + ds = BDIGITS(n); + d = ds[c = NUMDIGS(n)-1]; + for(c *= BITSPERDIG; d; d >>= 4) {c += 4; l = ilentab[15 & d];} + return MAKINUM(c - 4 + l); + } +#else + ASSERT(INUMP(n), n, ARG1, s_intlength); +#endif + if ((nn = INUM(n)) < 0) nn = -1 - nn; + for(;nn; nn >>= 4) {c += 4; l = ilentab[15 & nn];} + return MAKINUM(c - 4 + l); +} + +SCM charp(x) + SCM x; +{ + return ICHRP(x) ? BOOL_T : BOOL_F; +} +SCM char_lessp(x, y) + SCM x, y; +{ + ASSERT(ICHRP(x), x, ARG1, s_ch_lessp); + ASSERT(ICHRP(y), y, ARG2, s_ch_lessp); + return (ICHR(x) < ICHR(y)) ? BOOL_T : BOOL_F; +} +SCM char_leqp(x, y) + SCM x, y; +{ + ASSERT(ICHRP(x), x, ARG1, s_ch_leqp); + ASSERT(ICHRP(y), y, ARG2, s_ch_leqp); + return (ICHR(x) <= ICHR(y)) ? BOOL_T : BOOL_F; +} +SCM char_grp(x, y) + SCM x, y; +{ + ASSERT(ICHRP(x), x, ARG1, s_ch_grp); + ASSERT(ICHRP(y), y, ARG2, s_ch_grp); + return (ICHR(x) > ICHR(y)) ? BOOL_T : BOOL_F; +} +SCM char_geqp(x, y) + SCM x, y; +{ + ASSERT(ICHRP(x), x, ARG1, s_ch_geqp); + ASSERT(ICHRP(y), y, ARG2, s_ch_geqp); + return (ICHR(x) >= ICHR(y)) ? BOOL_T : BOOL_F; +} +SCM chci_eq(x, y) + SCM x, y; +{ + ASSERT(ICHRP(x), x, ARG1, s_ci_eq); + ASSERT(ICHRP(y), y, ARG2, s_ci_eq); + return (upcase[ICHR(x)]==upcase[ICHR(y)]) ? BOOL_T : BOOL_F; +} +SCM chci_lessp(x, y) + SCM x, y; +{ + ASSERT(ICHRP(x), x, ARG1, s_ci_lessp); + ASSERT(ICHRP(y), y, ARG2, s_ci_lessp); + return (upcase[ICHR(x)] < upcase[ICHR(y)]) ? BOOL_T : BOOL_F; +} +SCM chci_leqp(x, y) + SCM x, y; +{ + ASSERT(ICHRP(x), x, ARG1, s_ci_leqp); + ASSERT(ICHRP(y), y, ARG2, s_ci_leqp); + return (upcase[ICHR(x)] <= upcase[ICHR(y)]) ? BOOL_T : BOOL_F; +} +SCM chci_grp(x, y) + SCM x, y; +{ + ASSERT(ICHRP(x), x, ARG1, s_ci_grp); + ASSERT(ICHRP(y), y, ARG2, s_ci_grp); + return (upcase[ICHR(x)] > upcase[ICHR(y)]) ? BOOL_T : BOOL_F; +} +SCM chci_geqp(x, y) + SCM x, y; +{ + ASSERT(ICHRP(x), x, ARG1, s_ci_geqp); + ASSERT(ICHRP(y), y, ARG2, s_ci_geqp); + return (upcase[ICHR(x)] >= upcase[ICHR(y)]) ? BOOL_T : BOOL_F; +} +SCM char_alphap(chr) + SCM chr; +{ + ASSERT(ICHRP(chr), chr, ARG1, s_ch_alphap); + return (isascii(ICHR(chr)) && isalpha(ICHR(chr))) ? BOOL_T : BOOL_F; +} +SCM char_nump(chr) + SCM chr; +{ + ASSERT(ICHRP(chr), chr, ARG1, s_ch_nump); + return (isascii(ICHR(chr)) && isdigit(ICHR(chr))) ? BOOL_T : BOOL_F; +} +SCM char_whitep(chr) + SCM chr; +{ + ASSERT(ICHRP(chr), chr, ARG1, s_ch_whitep); + return (isascii(ICHR(chr)) && isspace(ICHR(chr))) ? BOOL_T : BOOL_F; +} +SCM char_upperp(chr) + SCM chr; +{ + ASSERT(ICHRP(chr), chr, ARG1, s_ch_upperp); + return (isascii(ICHR(chr)) && isupper(ICHR(chr))) ? BOOL_T : BOOL_F; +} +SCM char_lowerp(chr) + SCM chr; +{ + ASSERT(ICHRP(chr), chr, ARG1, s_ch_lowerp); + return (isascii(ICHR(chr)) && islower(ICHR(chr))) ? BOOL_T : BOOL_F; +} +SCM char2int(chr) + SCM chr; +{ + ASSERT(ICHRP(chr), chr, ARG1, s_char2int); + return MAKINUM(ICHR(chr)); +} +SCM int2char(n) + SCM n; +{ + ASSERT(INUMP(n), n, ARG1, s_int2char); + ASSERT((n >= INUM0) && (n < MAKINUM(CHAR_CODE_LIMIT)), + n, OUTOFRANGE, s_int2char); + return MAKICHR(INUM(n)); +} +SCM char_upcase(chr) + SCM chr; +{ + ASSERT(ICHRP(chr), chr, ARG1, s_ch_upcase); + return MAKICHR(upcase[ICHR(chr)]); +} +SCM char_downcase(chr) + SCM chr; +{ + ASSERT(ICHRP(chr), chr, ARG1, s_ch_downcase); + return MAKICHR(downcase[ICHR(chr)]); +} + +SCM stringp(x) + SCM x; +{ + if IMP(x) return BOOL_F; + return STRINGP(x) ? BOOL_T : BOOL_F; +} +SCM string(chrs) + SCM chrs; +{ + SCM res; + register char *data; + long i = ilength(chrs); + ASSERT(i >= 0, chrs, ARG1, s_string); + res = makstr(i); + data = CHARS(res); + for(;NNULLP(chrs);chrs = CDR(chrs)) { + ASSERT(ICHRP(CAR(chrs)), chrs, ARG1, s_string); + *data++ = ICHR(CAR(chrs)); + } + return res; +} +SCM make_string(k, chr) + SCM k, chr; +{ + SCM res; + register char *dst; + register long i; + ASSERT(INUMP(k) && (k >= 0), k, ARG1, s_make_string); + i = INUM(k); + res = makstr(i); + dst = CHARS(res); + if (!UNBNDP(chr)) { + ASSERT(ICHRP(chr), chr, ARG2, s_make_string); + for(i--;i >= 0;i--) dst[i] = ICHR(chr); + } + return res; +} +SCM st_length(str) + SCM str; +{ + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_st_length); + return MAKINUM(LENGTH(str)); +} +SCM st_ref(str, k) + SCM str, k; +{ + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_st_ref); + ASSERT(INUMP(k), k, ARG2, s_st_ref); + ASSERT(INUM(k) < LENGTH(str) && INUM(k) >= 0, k, OUTOFRANGE, s_st_ref); + return MAKICHR(CHARS(str)[INUM(k)]); +} +SCM st_set(str, k, chr) + SCM str, k, chr; +{ + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_st_set); + ASSERT(INUMP(k), k, ARG2, s_st_set); + ASSERT(ICHRP(chr), chr, ARG3, s_st_set); + ASSERT(INUM(k) < LENGTH(str) && INUM(k) >= 0, k, OUTOFRANGE, s_st_set); + CHARS(str)[INUM(k)] = ICHR(chr); + return UNSPECIFIED; +} +SCM st_equal(s1, s2) + SCM s1, s2; +{ + register sizet i; + register char *c1, *c2; + ASSERT(NIMP(s1) && STRINGP(s1), s1, ARG1, s_st_equal); + ASSERT(NIMP(s2) && STRINGP(s2), s2, ARG2, s_st_equal); + i = LENGTH(s2); + if (LENGTH(s1) != i) return BOOL_F; + c1 = CHARS(s1); + c2 = CHARS(s2); + while(0 != i--) if(*c1++ != *c2++) return BOOL_F; + return BOOL_T; +} +SCM stci_equal(s1, s2) + SCM s1, s2; +{ + register sizet i; + register unsigned char *c1, *c2; + ASSERT(NIMP(s1) && STRINGP(s1), s1, ARG1, s_stci_equal); + ASSERT(NIMP(s2) && STRINGP(s2), s2, ARG2, s_stci_equal); + i = LENGTH(s2); + if (LENGTH(s1) != i) return BOOL_F; + c1 = UCHARS(s1); + c2 = UCHARS(s2); + while(0 != i--) if(upcase[*c1++] != upcase[*c2++]) return BOOL_F; + return BOOL_T; +} +SCM st_lessp(s1, s2) + SCM s1, s2; +{ + register sizet i, len; + register unsigned char *c1, *c2; + register int c; + ASSERT(NIMP(s1) && STRINGP(s1), s1, ARG1, s_st_lessp); + ASSERT(NIMP(s2) && STRINGP(s2), s2, ARG2, s_st_lessp); + len = LENGTH(s1); + i = LENGTH(s2); + if (len>i) i = len; + c1 = UCHARS(s1); + c2 = UCHARS(s2); + for(i = 0;i<len;i++) { + c = (*c1++ - *c2++); + if (c>0) return BOOL_F; + if (c<0) return BOOL_T; + } + return (LENGTH(s2) != len) ? BOOL_T : BOOL_F; +} +SCM st_leqp(s1, s2) + SCM s1, s2; +{ + return BOOL_NOT(st_lessp(s2, s1)); +} +SCM st_grp(s1, s2) + SCM s1, s2; +{ + return st_lessp(s2, s1); +} +SCM st_geqp(s1, s2) + SCM s1, s2; +{ + return BOOL_NOT(st_lessp(s1, s2)); +} +SCM stci_lessp(s1, s2) + SCM s1, s2; +{ + register sizet i, len; + register unsigned char *c1, *c2; + register int c; + ASSERT(NIMP(s1) && STRINGP(s1), s1, ARG1, s_stci_lessp); + ASSERT(NIMP(s2) && STRINGP(s2), s2, ARG2, s_stci_lessp); + len = LENGTH(s1); + i = LENGTH(s2); + if (len>i) i=len; + c1 = UCHARS(s1); + c2 = UCHARS(s2); + for(i = 0;i<len;i++) { + c = (upcase[*c1++] - upcase[*c2++]); + if (c>0) return BOOL_F; + if (c<0) return BOOL_T; + } + return (LENGTH(s2) != len) ? BOOL_T : BOOL_F; +} +SCM stci_leqp(s1, s2) + SCM s1, s2; +{ + return BOOL_NOT(stci_lessp(s2, s1)); +} +SCM stci_grp(s1, s2) + SCM s1, s2; +{ + return stci_lessp(s2, s1); +} +SCM stci_geqp(s1, s2) + SCM s1, s2; +{ + return BOOL_NOT(stci_lessp(s1, s2)); +} +SCM substring(str, start, end) + SCM str, start, end; +{ + long l; + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_substring); + ASSERT(INUMP(start), start, ARG2, s_substring); + ASSERT(INUMP(end), end, ARG3, s_substring); + ASSERT(INUM(start) <= LENGTH(str), start, OUTOFRANGE, s_substring); + ASSERT(INUM(end) <= LENGTH(str), end, OUTOFRANGE, s_substring); + l = INUM(end)-INUM(start); + ASSERT(l >= 0, MAKINUM(l), OUTOFRANGE, s_substring); + return makfromstr(&CHARS(str)[INUM(start)], (sizet)l); +} +SCM st_append(args) + SCM args; +{ + SCM res; + register long i = 0; + register SCM l, s; + register char *data; + for(l = args;NIMP(l);) { + ASSERT(CONSP(l), l, ARGn, s_st_append); + s = CAR(l); + ASSERT(NIMP(s) && STRINGP(s), s, ARGn, s_st_append); + i += LENGTH(s); + l = CDR(l); + } + ASSERT(NULLP(l), args, ARGn, s_st_append); + res = makstr(i); + data = CHARS(res); + for(l = args;NIMP(l);l = CDR(l)) { + s = CAR(l); + for(i = 0;i<LENGTH(s);i++) *data++ = CHARS(s)[i]; + } + return res; +} + +SCM vectorp(x) + SCM x; +{ + if IMP(x) return BOOL_F; + return VECTORP(x) ? BOOL_T : BOOL_F; +} +SCM vector_length(v) + SCM v; +{ + ASSERT(NIMP(v) && VECTORP(v), v, ARG1, s_ve_length); + return MAKINUM(LENGTH(v)); +} +SCM vector(l) + SCM l; +{ + SCM res; + register SCM *data; + long i = ilength(l); + ASSERT(i >= 0, l, ARG1, s_vector); + res = make_vector(MAKINUM(i), UNSPECIFIED); + data = VELTS(res); + for(;NIMP(l);l = CDR(l)) *data++ = CAR(l); + return res; +} +SCM vector_ref(v, k) + SCM v, k; +{ + ASSERT(NIMP(v) && VECTORP(v), v, ARG1, s_ve_ref); + ASSERT(INUMP(k), k, ARG2, s_ve_ref); + ASSERT((INUM(k) < LENGTH(v)) && (INUM(k) >= 0), k, OUTOFRANGE, s_ve_ref); + return VELTS(v)[((long) INUM(k))]; +} +SCM vector_set(v, k, obj) + SCM v, k, obj; +{ + ASSERT(NIMP(v) && VECTORP(v), v, ARG1, s_ve_set); + ASSERT(INUMP(k), k, ARG2, s_ve_set); + ASSERT((INUM(k) < LENGTH(v)) && (INUM(k) >= 0), k, OUTOFRANGE, s_ve_set); + VELTS(v)[((long) INUM(k))] = obj; + return UNSPECIFIED; +} +char s_make_vector[] = "make-vector"; +SCM make_vector(k, fill) + SCM k, fill; +{ + SCM v; + register long i; + register SCM *velts; + ASSERT(INUMP(k), k, ARG1, s_make_vector); + if UNBNDP(fill) fill = UNSPECIFIED; + i = INUM(k); + NEWCELL(v); + DEFER_INTS; + SETCHARS(v, must_malloc(i?(long)(i*sizeof(SCM)):1L, s_vector)); + SETLENGTH(v, i, tc7_vector); + velts = VELTS(v); + while(--i >= 0) (velts)[i] = fill; + ALLOW_INTS; + return v; +} +#ifdef BIGDIG +char s_bignum[] = "bignum"; +SCM mkbig(nlen, sign) + sizet nlen; + int sign; +{ + SCM v = nlen; + if (((v << 16) >> 16) != nlen) + wta(MAKINUM(v), (char *)NALLOC, s_bignum); + NEWCELL(v); + DEFER_INTS; + SETCHARS(v, must_malloc((long)(nlen*sizeof(BIGDIG)), s_bignum)); + SETNUMDIGS(v, nlen, sign?tc16_bigneg:tc16_bigpos); + ALLOW_INTS; + return v; +} +SCM big2inum(b, l) + SCM b; + sizet l; +{ + unsigned long num = 0; + BIGDIG *tmp = BDIGITS(b); + while (l--) num = BIGUP(num) + tmp[l]; + if (TYP16(b)==tc16_bigpos) { + if POSFIXABLE(num) return MAKINUM(num); + } + else if UNEGFIXABLE(num) return MAKINUM(-num); + return b; +} +char s_adjbig[] = "adjbig"; +SCM adjbig(b, nlen) + SCM b; + sizet nlen; +{ + long nsiz = nlen; + if (((nsiz << 16) >> 16) != nlen) wta(MAKINUM(nsiz), (char *)NALLOC, s_adjbig); + DEFER_INTS; + SETCHARS(b, (BIGDIG *)must_realloc((char *)CHARS(b), + (long)(NUMDIGS(b)*sizeof(BIGDIG)), + (long)(nsiz*sizeof(BIGDIG)), s_adjbig)); + SETNUMDIGS(b, nsiz, TYP16(b)); + ALLOW_INTS; + return b; +} +SCM normbig(b) + SCM b; +{ +# ifndef _UNICOS + sizet nlen = NUMDIGS(b); +# else + int nlen = NUMDIGS(b); /* unsigned nlen breaks on Cray when nlen => 0 */ +# endif + BIGDIG *zds = BDIGITS(b); + while (nlen-- && !zds[nlen]); nlen++; + if (nlen * BITSPERDIG/CHAR_BIT <= sizeof(SCM)) + if INUMP(b = big2inum(b, (sizet)nlen)) return b; + if (NUMDIGS(b)==nlen) return b; + return adjbig(b, (sizet)nlen); +} +SCM copybig(b, sign) + SCM b; + int sign; +{ + sizet i = NUMDIGS(b); + SCM ans = mkbig(i, sign); + BIGDIG *src = BDIGITS(b), *dst = BDIGITS(ans); + while (i--) dst[i] = src[i]; + return ans; +} +SCM long2big(n) + long n; +{ + sizet i = 0; + BIGDIG *digits; + SCM ans = mkbig(DIGSPERLONG, n<0); + digits = BDIGITS(ans); + if (n < 0) n = -n; + while (i < DIGSPERLONG) { + digits[i++] = BIGLO(n); + n = BIGDN((unsigned long)n); + } + return ans; +} +SCM ulong2big(n) + unsigned long n; +{ + sizet i = 0; + BIGDIG *digits; + SCM ans = mkbig(DIGSPERLONG, 0); + digits = BDIGITS(ans); + while (i < DIGSPERLONG) { + digits[i++] = BIGLO(n); + n = BIGDN(n); + } + return ans; +} + +int bigcomp(x, y) + SCM x, y; +{ + int xsign = BIGSIGN(x); + int ysign = BIGSIGN(y); + sizet xlen, ylen; + if (ysign < xsign) return 1; + if (ysign > xsign) return -1; + if ((ylen = NUMDIGS(y)) > (xlen = NUMDIGS(x))) return (xsign) ? -1 : 1; + if (ylen < xlen) return (xsign) ? 1 : -1; + while(xlen-- && (BDIGITS(y)[xlen]==BDIGITS(x)[xlen])); + if (-1==xlen) return 0; + return (BDIGITS(y)[xlen] > BDIGITS(x)[xlen]) ? + (xsign ? -1 : 1) : (xsign ? 1 : -1); +} + +# ifndef DIGSTOOBIG +long pseudolong(x) + long x; +{ + union { + long l; + BIGDIG bd[DIGSPERLONG]; + } p; + sizet i = 0; + if (x < 0) x = -x; + while (i < DIGSPERLONG) {p.bd[i++] = BIGLO(x); x = BIGDN(x);} +/* p.bd[0] = BIGLO(x); p.bd[1] = BIGDN(x); */ + return p.l; +} +# else +void longdigs(x, digs) + long x; + BIGDIG digs[DIGSPERLONG]; +{ + sizet i = 0; + if (x < 0) x = -x; + while (i < DIGSPERLONG) {digs[i++] = BIGLO(x); x = BIGDN(x);} +} +# endif + +SCM addbig(x, nx, xsgn, bigy, sgny) + BIGDIG *x; + SCM bigy; + sizet nx; /* Assumes nx <= NUMDIGS(bigy) */ + int xsgn, sgny; /* Assumes xsgn and sgny equal either 0 or 0x0100 */ +{ + long num = 0; + sizet i = 0, ny = NUMDIGS(bigy); + SCM z = copybig(bigy, BIGSIGN(bigy) ^ sgny); + BIGDIG *zds = BDIGITS(z); + if (xsgn ^ BIGSIGN(z)) { + do { + num += (long) zds[i] - x[i]; + if (num < 0) {zds[i] = num + BIGRAD; num = -1;} + else {zds[i] = BIGLO(num); num = 0;} + } while (++i < nx); + if (num && nx==ny) { + num = 1; i = 0; + CAR(z) ^= 0x0100; + do { + num += (BIGRAD-1) - zds[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + } while (i < ny); + } + else while (i < ny) { + num += zds[i]; + if (num < 0) {zds[i++] = num + BIGRAD; num = -1;} + else {zds[i++] = BIGLO(num); num = 0;} + } + } else { + do { + num += (long) zds[i] + x[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + } while (i < nx); + if (!num) return z; + while (i < ny) { + num += zds[i]; + zds[i++] = BIGLO(num); + num = BIGDN(num); + if (!num) return z; + } + if (num) {z = adjbig(z, ny+1); BDIGITS(z)[ny] = num; return z;} + } + return normbig(z); +} + +SCM mulbig(x, nx, y, ny, sgn) + BIGDIG *x, *y; + sizet nx, ny; + int sgn; +{ + sizet i = 0, j = nx + ny; + unsigned long n = 0; + SCM z = mkbig(j, sgn); + BIGDIG *zds = BDIGITS(z); + while (j--) zds[j] = 0; + do { + j = 0; + if (x[i]) { + do { + n += zds[i + j] + ((unsigned long) x[i] * y[j]); + zds[i + j++] = BIGLO(n); + n = BIGDN(n); + } while (j < ny); + if (n) {zds[i + j] = n; n = 0;} + } + } while (++i < nx); + return normbig(z); +} +unsigned int divbigdig(ds, h, div) + BIGDIG *ds; + sizet h; + BIGDIG div; +{ + register unsigned long t2 = 0; + while(h--) { + t2 = BIGUP(t2) + ds[h]; + ds[h] = t2 / div; + t2 %= div; + } + return t2; +} +SCM divbigint(x, z, sgn, mode) + SCM x; + long z; + int sgn, mode; +{ + if (z < 0) z = -z; + if (z < BIGRAD) { + register unsigned long t2 = 0; + register BIGDIG *ds = BDIGITS(x); + sizet nd = NUMDIGS(x); + while(nd--) t2 = (BIGUP(t2) + ds[nd]) % z; + if (mode && t2) t2 = z - t2; + return MAKINUM(sgn ? -t2 : t2); + } + { +# ifndef DIGSTOOBIG + unsigned long t2 = pseudolong(z); + return divbigbig(BDIGITS(x), NUMDIGS(x), (BIGDIG *)&t2, + DIGSPERLONG, sgn, mode); +# else + BIGDIG t2[DIGSPERLONG]; + longdigs(z, t2); + return divbigbig(BDIGITS(x), NUMDIGS(x), t2, DIGSPERLONG, sgn, mode); +# endif + } +} +SCM divbigbig(x, nx, y, ny, sgn, modes) + BIGDIG *x, *y; + sizet nx, ny; + int sgn, modes; + /* modes description + 0 remainder + 1 modulo + 2 quotient + 3 quotient but returns 0 if division is not exact. */ +{ + sizet i = 0, j = 0; + long num = 0; + unsigned long t2 = 0; + SCM z, newy; + BIGDIG d = 0, qhat, *zds, *yds; + /* algorithm requires nx >= ny */ + if (nx < ny) + switch (modes) { + case 0: /* remainder -- just return x */ + z = mkbig(nx, sgn); zds = BDIGITS(z); + do {zds[i] = x[i];} while (++i < nx); + return z; + case 1: /* modulo -- return y-x */ + z = mkbig(ny, sgn); zds = BDIGITS(z); + do { + num += (long) y[i] - x[i]; + if (num < 0) {zds[i] = num + BIGRAD; num = -1;} + else {zds[i] = num; num = 0;} + } while (++i < nx); + while (i < ny) { + num += y[i]; + if (num < 0) {zds[i++] = num + BIGRAD; num = -1;} + else {zds[i++] = num; num = 0;} + } + goto doadj; + case 2: return INUM0; /* quotient is zero */ + case 3: return 0; /* the division is not exact */ + } + + z = mkbig(nx==ny ? nx+2 : nx+1, sgn); zds = BDIGITS(z); + if (nx==ny) zds[nx+1] = 0; + while(!y[ny-1]) ny--; /* in case y came in as a psuedolong */ + if (y[ny-1] < (BIGRAD>>1)) { /* normalize operands */ + d = BIGRAD/(y[ny-1]+1); + newy = mkbig(ny, 0); yds = BDIGITS(newy); + while(j < ny) + {t2 += (unsigned long) y[j]*d; yds[j++] = BIGLO(t2); t2 = BIGDN(t2);} + y = yds; j = 0; t2 = 0; + while(j < nx) + {t2 += (unsigned long) x[j]*d; zds[j++] = BIGLO(t2); t2 = BIGDN(t2);} + zds[j] = t2; + } + else {zds[j = nx] = 0; while (j--) zds[j] = x[j];} + j = nx==ny ? nx+1 : nx; /* dividend needs more digits than divisor */ + do { /* loop over digits of quotient */ + if (zds[j]==y[ny-1]) qhat = BIGRAD-1; + else qhat = (BIGUP(zds[j]) + zds[j-1])/y[ny-1]; + if (!qhat) continue; + i = 0; num = 0; t2 = 0; + do { /* multiply and subtract */ + t2 += (unsigned long) y[i] * qhat; + num += zds[j - ny + i] - BIGLO(t2); + if (num < 0) {zds[j - ny + i] = num + BIGRAD; num = -1;} + else {zds[j - ny + i] = num; num = 0;} + t2 = BIGDN(t2); + } while (++i < ny); + num += zds[j - ny + i] - t2; /* borrow from high digit; don't update */ + while (num) { /* "add back" required */ + i = 0; num = 0; qhat--; + do { + num += (long) zds[j - ny + i] + y[i]; + zds[j - ny + i] = BIGLO(num); + num = BIGDN(num); + } while (++i < ny); + num--; + } + if (modes & 2) zds[j] = qhat; + } while (--j >= ny); + switch (modes) { + case 3: /* check that remainder==0 */ + for(j = ny;j && !zds[j-1];--j) ; if (j) return 0; + case 2: /* move quotient down in z */ + j = (nx==ny ? nx+2 : nx+1) - ny; + for (i = 0;i < j;i++) zds[i] = zds[i+ny]; + ny = i; + break; + case 1: /* subtract for modulo */ + i = 0; num = 0; j = 0; + do {num += y[i] - zds[i]; + j = j | zds[i]; + if (num < 0) {zds[i] = num + BIGRAD; num = -1;} + else {zds[i] = num; num = 0;} + } while (++i < ny); + if (!j) return INUM0; + case 0: /* just normalize remainder */ + if (d) divbigdig(zds, ny, d); + } + doadj: + for(j = ny;j && !zds[j-1];--j) ; + if (j * BITSPERDIG <= sizeof(SCM)*CHAR_BIT) + if INUMP(z = big2inum(z, j)) return z; + return adjbig(z, j); +} +#endif + +static iproc cxrs[] = { + {"car", 0}, {"cdr", 0}, + {"caar", 0}, {"cadr", 0}, {"cdar", 0}, {"cddr", 0}, + {"caaar", 0}, {"caadr", 0}, {"cadar", 0}, {"caddr", 0}, + {"cdaar", 0}, {"cdadr", 0}, {"cddar", 0}, {"cdddr", 0}, + {"caaaar", 0}, {"caaadr", 0}, {"caadar", 0}, {"caaddr", 0}, + {"cadaar", 0}, {"cadadr", 0}, {"caddar", 0}, {"cadddr", 0}, + {"cdaaar", 0}, {"cdaadr", 0}, {"cdadar", 0}, {"cdaddr", 0}, + {"cddaar", 0}, {"cddadr", 0}, {"cdddar", 0}, {"cddddr", 0}, + {0, 0}}; + +static iproc subr1s[] = { + {"not", lnot}, + {"boolean?", booleanp}, + {"pair?", consp}, + {"null?", nullp}, + {"list?", listp}, + {s_length, length}, + {s_reverse, reverse}, + {"symbol?", symbolp}, + {s_symbol2string, symbol2string}, + {s_str2symbol, string2symbol}, + {s_exactp, exactp}, + {s_oddp, oddp}, + {s_evenp, evenp}, + {s_abs, absval}, + {s_lognot, scm_lognot}, + {s_logcount, scm_logcount}, + {s_intlength, scm_intlength}, + {"char?", charp}, + {s_ch_alphap, char_alphap}, + {s_ch_nump, char_nump}, + {s_ch_whitep, char_whitep}, + {s_ch_upperp, char_upperp}, + {s_ch_lowerp, char_lowerp}, + {s_char2int, char2int}, + {s_int2char, int2char}, + {s_ch_upcase, char_upcase}, + {s_ch_downcase, char_downcase}, + {"string?", stringp}, + {s_st_length, st_length}, + {"vector?", vectorp}, + {s_ve_length, vector_length}, + {"procedure?", procedurep}, + {0, 0}}; + +static char s_acons[] = "acons"; +static iproc subr2s[] = { + {&s_acons[1], cons}, + {s_setcar, setcar}, + {s_setcdr, setcdr}, + {s_list_ref, list_ref}, + {s_memq, memq}, + {s_member, member}, + {s_assq, assq}, + {s_assoc, assoc}, + {s_quotient, lquotient}, + {s_remainder, lremainder}, + {s_modulo, modulo}, + {s_logtest, scm_logtest}, + {s_logbitp, scm_logbitp}, + {s_ash, scm_ash}, + {s_intexpt, scm_intexpt}, + {s_st_ref, st_ref}, + {"string<=?", st_leqp}, + {"string-ci<=?", stci_leqp}, + {s_ve_ref, vector_ref}, + {0, 0}}; + +static iproc lsubrs[] = { + {s_list, list}, + {s_append, append}, + {s_string, string}, + {s_st_append, st_append}, + {s_vector, vector}, + {0, 0}}; + +static iproc subr2os[] = { + {s_make_string, make_string}, + {s_make_vector, make_vector}, + {0, 0}}; + +static iproc asubrs[] = { + {s_gcd, lgcd}, + {"lcm", llcm}, + {s_logand, scm_logand}, + {s_logior, scm_logior}, + {s_logxor, scm_logxor}, + {0, 0}}; + +static iproc rpsubrs[] = { + {"eq?", eq}, + {"equal?", equal}, + {"char=?", eq}, + {s_ch_lessp, char_lessp}, + {s_ci_eq, chci_eq}, + {s_ci_lessp, chci_lessp}, + {s_ch_leqp, char_leqp}, + {s_ci_leqp, chci_leqp}, + {s_ch_grp, char_grp}, + {s_ci_grp, chci_grp}, + {s_ch_geqp, char_geqp}, + {s_ci_geqp, chci_geqp}, + + {s_st_equal, st_equal}, + {s_stci_equal, stci_equal}, + {s_st_lessp, st_lessp}, + {s_stci_lessp, stci_lessp}, + {"string>?", st_grp}, + {"string-ci>?", stci_grp}, + {"string>=?", st_geqp}, + {"string-ci>=?", stci_geqp}, + {0, 0}}; + +static iproc subr3s[] = { + {s_bitextract, scm_bitextract}, + {s_substring, substring}, + {s_acons, acons}, + {s_st_set, st_set}, + {s_ve_set, vector_set}, + {0, 0}}; + +void init_iprocs(subra, type) + iproc *subra; + int type; +{ + for(;subra->string; subra++) + make_subr(subra->string, + type, + subra->cproc); +} + +void init_subrs() +{ + init_iprocs(cxrs, tc7_cxr); + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(subr2s, tc7_subr_2); + init_iprocs(subr2os, tc7_subr_2o); + init_iprocs(rpsubrs, tc7_rpsubr); + init_iprocs(lsubrs, tc7_lsubr); + init_iprocs(asubrs, tc7_asubr); + init_iprocs(subr3s, tc7_subr_3); +} @@ -0,0 +1,1758 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "sys.c" opening and closing files, storage, and GC. */ + +#include <ctype.h> + +#include "scm.h" +#include "setjump.h" +void igc P((char *what, STACKITEM *stackbase)); + +/* ttyname() etc. should be defined in <unistd.h>. But unistd.h is + missing on many systems. */ + +#ifndef STDC_HEADERS + char *ttyname P((int fd)); + char *tmpnam P((char *s)); + sizet fwrite (); +# ifdef sun +# ifndef __svr4__ + int fputs P((char *s, FILE* stream)); + int fputc P((char c, FILE* stream)); + int fflush P((FILE* stream)); +# endif +# endif + int fgetc P((FILE* stream)); + int fclose P((FILE* stream)); + int pclose P((FILE* stream)); + int unlink P((const char *pathname)); + char *mktemp P((char *template)); +#endif + +static void gc_sweep P((void)); + +char s_nogrow[] = "could not grow", s_heap[] = "heap", + s_hplims[] = "hplims"; +static char s_input_portp[] = "input-port?", + s_output_portp[] = "output-port?"; +static char s_open_file[] = "open-file"; +char s_close_port[] = "close-port"; + +#ifdef __IBMC__ +# include <io.h> +# include <direct.h> +# define ttyname(x) "CON:" +#else +# ifndef MSDOS +# ifndef ultrix +# ifndef vms +# ifdef _DCC +# include <ioctl.h> +# define setbuf(stream, buf) setvbuf(stream, buf, _IONBF, 0) +# else +# ifdef MWC +# include <sys/io.h> +# else +# ifndef THINK_C +# ifndef ARM_ULIB +# include <sys/ioctl.h> +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif /* __IBMC__ */ +SCM i_setbuf0(port) /* should be called with DEFER_INTS active */ + SCM port; +{ +#ifndef NOSETBUF +# ifndef MSDOS +# ifdef FIONREAD +# ifndef ultrix + SYSCALL(setbuf(STREAM(port), 0);); +# endif +# endif +# endif +#endif + return UNSPECIFIED; +} + +long mode_bits(modes) + char *modes; +{ + return OPN | (strchr(modes, 'r') || strchr(modes, '+') ? RDNG : 0) + | (strchr(modes, 'w') || strchr(modes, 'a') || strchr(modes, '+') ? WRTNG : 0) + | (strchr(modes, '0') ? BUF0 : 0); +} + +SCM open_file(filename, modes) + SCM filename, modes; +{ + register SCM port; + FILE *f; + ASSERT(NIMP(filename) && STRINGP(filename), filename, ARG1, s_open_file); + ASSERT(NIMP(modes) && STRINGP(modes), modes, ARG2, s_open_file); + NEWCELL(port); + DEFER_INTS; + SYSCALL(f = fopen(CHARS(filename), CHARS(modes));); + if (!f) port = BOOL_F; + else { + SETSTREAM(port, f); + if (BUF0 & (CAR(port) = tc16_fport | mode_bits(CHARS(modes)))) + i_setbuf0(port); + ALLOW_INTS; + } + return port; +} + +SCM close_port(port) + SCM port; +{ + sizet i; + ASSERT(NIMP(port) && PORTP(port), port, ARG1, s_close_port); + if CLOSEDP(port) return UNSPECIFIED; + i = PTOBNUM(port); + DEFER_INTS; + if (ptobs[i].fclose) { + SYSCALL((ptobs[i].fclose)(STREAM(port));); + } + CAR(port) &= ~OPN; + ALLOW_INTS; + return UNSPECIFIED; +} +SCM input_portp(x) + SCM x; +{ + if IMP(x) return BOOL_F; + return INPORTP(x) ? BOOL_T : BOOL_F; +} +SCM output_portp(x) + SCM x; +{ + if IMP(x) return BOOL_F; + return OUTPORTP(x) ? BOOL_T : BOOL_F; +} + +#if (__TURBOC__==1) +# undef L_tmpnam /* Not supported in TURBOC V1.0 */ +#endif +#ifdef GO32 +# undef L_tmpnam +#endif +#ifdef MWC +# undef L_tmpnam +#endif + +#ifdef L_tmpnam +SCM ltmpnam() +{ + char name[L_tmpnam]; + SYSCALL(tmpnam(name);); + return makfrom0str(name); +} +#else +/* TEMPTEMPLATE is used only if mktemp() is being used instead of + tmpnam(). */ + +# ifdef AMIGA +# define TEMPTEMPLATE "T:SchemeaaaXXXXXX"; +# else +# ifdef vms +# define TEMPTEMPLATE "sys$scratch:aaaXXXXXX"; +# else /* vms */ +# ifdef __MSDOS__ +# ifdef GO32 +# define TEMPTEMPLATE "\\tmp\\TMPaaaXXXXXX"; +# else +# define TEMPTEMPLATE "TMPaaaXXXXXX"; +# endif +# else /* __MSDOS__ */ +# define TEMPTEMPLATE "/tmp/aaaXXXXXX"; +# endif /* __MSDOS__ */ +# endif /* vms */ +# endif /* AMIGA */ + +char template[] = TEMPTEMPLATE; +# define TEMPLEN (sizeof template/sizeof(char) - 1) +SCM ltmpnam() +{ + SCM name; + int temppos = TEMPLEN-9; + name = makfromstr(template, (sizet)TEMPLEN); + DEFER_INTS; +inclp: + template[temppos]++; + if (!isalpha(template[temppos])) { + template[temppos++] = 'a'; + goto inclp; + } +# ifndef AMIGA +# ifndef __MSDOS__ + SYSCALL(temppos = !*mktemp(CHARS(name));); + if (temppos) name = BOOL_F; +# endif +# endif + ALLOW_INTS; + return name; +} +#endif /* L_tmpnam */ + +#ifdef M_SYSV +# define remove unlink +#endif +static char s_del_fil[] = "delete-file"; +SCM del_fil(str) + SCM str; +{ + int ans; + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_del_fil); +#ifdef STDC_HEADERS + SYSCALL(ans = remove(CHARS(str));); +#else + SYSCALL(ans = unlink(CHARS(str));); +#endif + return ans ? BOOL_F : BOOL_T; +} + +void prinport(exp, port, type) + SCM exp; SCM port; char *type; +{ + lputs("#<", port); + if CLOSEDP(exp) lputs("closed-", port); + else { + if (RDNG & CAR(exp)) lputs("input-", port); + if (WRTNG & CAR(exp)) lputs("output-", port); + } + lputs(type, port); + lputc(' ', port); +#ifndef MSDOS +# ifndef __EMX__ +# ifndef _DCC +# ifndef AMIGA +# ifndef THINK_C + if (OPENP(exp) && tc16_fport==TYP16(exp) && isatty(fileno(STREAM(exp)))) + lputs(ttyname(fileno(STREAM(exp))), port); + else +# endif +# endif +# endif +# endif +#endif + if OPFPORTP(exp) intprint((long)fileno(STREAM(exp)), 10, port); + else intprint(CDR(exp), 16, port); + lputc('>', port); +} +static int prinfport(exp, port, writing) + SCM exp; SCM port; int writing; +{ + prinport(exp, port, s_port_type); + return !0; +} +static int prinstpt(exp, port, writing) + SCM exp; SCM port; int writing; +{ + prinport(exp, port, s_string); + return !0; +} +static int prinsfpt(exp, port, writing) + SCM exp; SCM port; int writing; +{ + prinport(exp, port, "soft"); + return !0; +} + +static int stputc(c, p) + int c; SCM p; +{ + sizet ind = INUM(CAR(p)); + if (ind >= LENGTH(CDR(p))) resizuve(CDR(p), MAKINUM(ind + (ind>>1))); + CHARS(CDR(p))[ind] = c; + CAR(p) = MAKINUM(ind + 1); + return c; +} +sizet stwrite(str, siz, num, p) + sizet siz, num; + char *str; SCM p; +{ + sizet ind = INUM(CAR(p)); + sizet len = siz * num; + char *dst; + if (ind + len >= LENGTH(CDR(p))) + resizuve(CDR(p), MAKINUM(ind + len + ((ind + len)>>1))); + dst = &(CHARS(CDR(p))[ind]); + while (len--) dst[len] = str[len]; + CAR(p) = MAKINUM(ind + siz*num); + return num; +} +static int stputs(s, p) + char *s; SCM p; +{ + stwrite(s, 1, strlen(s), p); + return 0; +} +static int stgetc(p) + SCM p; +{ + sizet ind = INUM(CAR(p)); + if (ind >= LENGTH(CDR(p))) return EOF; + CAR(p) = MAKINUM(ind + 1); + return CHARS(CDR(p))[ind]; +} +int noop0(stream) + FILE *stream; +{ + return 0; +} +SCM mkstrport(pos, str, modes, caller) + SCM pos; + SCM str; + long modes; + char *caller; +{ + SCM z; + ASSERT(INUMP(pos) && INUM(pos) >= 0, pos, ARG1, caller); + ASSERT(NIMP(str) && (STRINGP(str) || SYMBOLP(str)), str, ARG1, caller); + str = cons(pos, str); + NEWCELL(z); + DEFER_INTS; + SETCHARS(z, str); + CAR(z) = tc16_strport | modes; + ALLOW_INTS; + return z; +} +static char s_cwos[] = "call-with-output-string"; +static char s_cwis[] = "call-with-input-string"; +SCM cwos(proc) + SCM proc; +{ + SCM p = mkstrport(INUM0, make_string(MAKINUM(30), UNDEFINED), + OPN | WRTNG, + s_cwos); + apply(proc, p, listofnull); + return resizuve(CDR(CDR(p)), CAR(CDR(p))); +} +SCM cwis(str, proc) + SCM str, proc; +{ + SCM p = mkstrport(INUM0, str, OPN | RDNG, s_cwis); + return apply(proc, p, listofnull); +} +#ifdef vms +sizet pwrite(ptr, size, nitems, port) + char *ptr; + sizet size, nitems; + FILE* port; +{ + sizet len = size * nitems; + sizet i = 0; + for(;i < len;i++) putc(ptr[i], port); + return len; +} +# define ffwrite pwrite +#else +# define ffwrite fwrite +#endif + +static ptobfuns fptob = { + mark0, + fclose, + prinfport, + 0, + fputc, + fputs, + ffwrite, + fflush, + fgetc, + fclose}; +ptobfuns pipob = { + mark0, + 0, /* replaced by pclose in init_ioext() */ + 0, /* replaced by prinpipe in init_ioext() */ + 0, + fputc, + fputs, + ffwrite, + fflush, + fgetc, + 0}; /* replaced by pclose in init_ioext() */ +static ptobfuns stptob = { + markcdr, + noop0, + prinstpt, + 0, + stputc, + stputs, + stwrite, + noop0, + stgetc, + 0}; + + /* Soft ports */ + +/* fputc, fwrite, fputs, and fclose are called within a + SYSCALL. So we need to set errno to 0 before returning. fflush + may be called within a SYSCALL. So we need to set errno to 0 + before returning. */ + +static int sfputc(c, p) + int c; SCM p; +{ + apply(VELTS(p)[0], MAKICHR(c), listofnull); + errno = 0; + return c; +} +sizet sfwrite(str, siz, num, p) + sizet siz, num; + char *str; SCM p; +{ + SCM sstr; + sstr = makfromstr(str, siz * num); + apply(VELTS(p)[1], sstr, listofnull); + errno = 0; + return num; +} +static int sfputs(s, p) + char *s; SCM p; +{ + sfwrite(s, 1, strlen(s), p); + return 0; +} +int sfflush(stream) + SCM stream; +{ + SCM f = VELTS(stream)[2]; + if (BOOL_F==f) return 0; + f = apply(f, EOL, EOL); + errno = 0; + return BOOL_F==f ? EOF : 0; +} +static int sfgetc(p) + SCM p; +{ + SCM ans; + ans = apply(VELTS(p)[3], EOL, EOL); + errno = 0; + if (FALSEP(ans) || EOF_VAL==ans) return EOF; + ASSERT(ICHRP(ans), ans, ARG1, "getc"); + return ICHR(ans); +} +static int sfclose(p) + SCM p; +{ + SCM f = VELTS(p)[4]; + if (BOOL_F==f) return 0; + f = apply(f, EOL, EOL); + errno = 0; + return BOOL_F==f ? EOF : 0; +} +static char s_mksfpt[] = "make-soft-port"; +SCM mksfpt(pv, modes) + SCM pv, modes; +{ + SCM z; + ASSERT(NIMP(pv) && VECTORP(pv) && 5==LENGTH(pv), pv, ARG1, s_mksfpt); + ASSERT(NIMP(modes) && STRINGP(modes), modes, ARG2, s_mksfpt); + NEWCELL(z); + DEFER_INTS; + CAR(z) = tc16_sfport | mode_bits(CHARS(modes)); + SETSTREAM(z, pv); + ALLOW_INTS; + return z; +} + +static ptobfuns sfptob = { + markcdr, + noop0, + prinsfpt, + 0, + sfputc, + sfputs, + sfwrite, + sfflush, + sfgetc, + sfclose}; + +static smobfuns freecell = { + mark0, + free0, + 0, + 0}; +static smobfuns flob = { + mark0, + /*flofree*/0, + floprint, + floequal}; +static smobfuns bigob = { + mark0, + /*bigfree*/0, + bigprint, + bigequal}; +void (**finals)() = 0; +sizet num_finals = 0; +static char s_final[] = "final"; + +void init_types() +{ + numptob = 0; + ptobs = (ptobfuns *)malloc(4*sizeof(ptobfuns)); + /* These newptob calls must be done in this order */ + /* tc16_fport = */ newptob(&fptob); + /* tc16_pipe = */ newptob(&pipob); + /* tc16_strport = */ newptob(&stptob); + /* tc16_sfport = */ newptob(&sfptob); + numsmob = 0; + smobs = (smobfuns *)malloc(7*sizeof(smobfuns)); + /* These newsmob calls must be done in this order */ + newsmob(&freecell); + newsmob(&flob); + newsmob(&bigob); + newsmob(&bigob); + finals = (void(**)())malloc(2 * sizeof(finals[0])); + num_finals = 0; +} + +void add_final(final) + void (* final)(); +{ + DEFER_INTS; + finals = (void (**)()) must_realloc((char *)finals, + 1L*(num_finals)*sizeof(finals[0]), + (1L+num_finals)*sizeof(finals[0]), + s_final); + finals[num_finals++] = final; + ALLOW_INTS; + return; +} + +char s_obunhash[] = "object-unhash"; +static iproc subr0s[] = { + {"gc", gc}, + {"tmpnam", ltmpnam}, + {0, 0}}; + +static iproc subr1s[] = { + {s_input_portp, input_portp}, + {s_output_portp, output_portp}, + {s_close_port, close_port}, + {"eof-object?", eof_objectp}, + {s_cwos, cwos}, + {"object-hash", obhash}, + {s_obunhash, obunhash}, + {s_del_fil, del_fil}, + {0, 0}}; + +static iproc subr2s[] = { + {s_open_file, open_file}, + {s_cwis, cwis}, + {s_mksfpt, mksfpt}, + {0, 0}}; + +SCM dynwind P((SCM thunk1, SCM thunk2, SCM thunk3)); +void init_io(){ + make_subr("dynamic-wind", tc7_subr_3, dynwind); + init_iprocs(subr0s, tc7_subr_0); + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(subr2s, tc7_subr_2); +#ifndef CHEAP_CONTINUATIONS + add_feature("full-continuation"); +#endif +} + +void grew_lim(nm) + long nm; +{ + ALLOW_INTS; + growth_mon(s_limit, nm, "bytes"); + DEFER_INTS; +} +int expmem = 0; +sizet hplim_ind = 0; +long heap_size = 0; +CELLPTR *hplims, heap_org; +SCM freelist = EOL; +long mtrigger; +char *must_malloc(len, what) + long len; + char *what; +{ + char *ptr; + sizet size = len; + long nm = mallocated+size; + if (len != size) +malerr: + wta(MAKINUM(len), (char *)NALLOC, what); + if ((nm <= mtrigger)) { + SYSCALL(ptr = (char *)malloc(size);); + if (NULL != ptr) {mallocated = nm; return ptr;} + } + igc(what, CONT(rootcont)->stkbse); + nm = mallocated+size; + if (nm > mtrigger) grew_lim(nm+nm/2); /* must do before malloc */ + SYSCALL(ptr = (char *)malloc(size);); + if (NULL != ptr) { + mallocated = nm; + if (nm > mtrigger) mtrigger = nm + nm/2; + return ptr;} + goto malerr; +} +char *must_realloc(where, olen, len, what) + char *where; + long olen, len; + char *what; +{ + char *ptr; + sizet size = len; + long nm = mallocated+size-olen; + if (len != size) +ralerr: + wta(MAKINUM(len), (char *)NALLOC, what); + if ((nm <= mtrigger)) { + SYSCALL(ptr = (char *)realloc(where, size);); + if (NULL != ptr) {mallocated = nm; return ptr;} + } + igc(what, CONT(rootcont)->stkbse); + nm = mallocated+size-olen; + if (nm > mtrigger) grew_lim(nm+nm/2); /* must do before realloc */ + SYSCALL(ptr = (char *)realloc(where, size);); + if (NULL != ptr) { + mallocated = nm; + if (nm > mtrigger) mtrigger = nm + nm/2; + return ptr;} + goto ralerr; +} +void must_free(obj) + char *obj; +{ + if (obj) free(obj); + else wta(INUM0, "already free", ""); +} + +SCM symhash; /* This used to be a sys_protect, but + Radey Shouman <shouman@zianet.com> + added GC for unuesd, UNDEFINED + symbols.*/ +int symhash_dim = NUM_HASH_BUCKETS; +/* sym2vcell looks up the symbol in the symhash table. */ +SCM sym2vcell(sym) + SCM sym; +{ + SCM lsym, z; + sizet hash = strhash(UCHARS(sym), (sizet)LENGTH(sym), + (unsigned long)symhash_dim); + for(lsym = VELTS(symhash)[hash];NIMP(lsym);lsym = CDR(lsym)) { + z = CAR(lsym); + if (CAR(z)==sym) return z; + } + wta(sym, "uninterned symbol? ", ""); +} +/* intern() and sysintern() return a pair; + CAR is the symbol, CDR is the value. */ +SCM intern(name, len) + char *name; + sizet len; +{ + SCM lsym, z; + register sizet i = len; + register unsigned char *tmp = (unsigned char *)name; + sizet hash = strhash(tmp, i, (unsigned long)symhash_dim); + for(lsym = VELTS(symhash)[hash];NIMP(lsym);lsym = CDR(lsym)) { + z = CAR(lsym); + z = CAR(z); + tmp = UCHARS(z); + if (LENGTH(z) != len) goto trynext; + for(i = len;i--;) if (((unsigned char *)name)[i] != tmp[i]) goto trynext; + return CAR(lsym); + trynext: ; + } + lsym = makfromstr(name, len); + DEFER_INTS; + SETLENGTH(lsym, (long)len, tc7_msymbol); + ALLOW_INTS; + z = acons(lsym, UNDEFINED, UNDEFINED); + DEFER_INTS; /* Operations on symhash must be atomic. */ + CDR(z) = VELTS(symhash)[hash]; + VELTS(symhash)[hash] = z; + z = CAR(z); + ALLOW_INTS; + return z; +} +SCM sysintern(name, val) + char *name; + SCM val; +{ + SCM lsym, z; + sizet len = strlen(name); + register sizet i = len; + register unsigned char *tmp = (unsigned char *)name; + sizet hash = strhash(tmp, i, (unsigned long)symhash_dim); + for(lsym = VELTS(symhash)[hash];NIMP(lsym);lsym = CDR(lsym)) { + z = CAR(lsym); + z = CAR(z); + tmp = UCHARS(z); + if (LENGTH(z) != len) goto trynext; + for(i = len;i--;) if (((unsigned char *)name)[i] != tmp[i]) goto trynext; + lsym = CAR(lsym); + CDR(lsym) = val; + return lsym; + trynext: ; + } + NEWCELL(lsym); + SETLENGTH(lsym, (long)len, tc7_ssymbol); + SETCHARS(lsym, name); + lsym = cons(lsym, val); + z = cons(lsym, UNDEFINED); + CDR(z) = VELTS(symhash)[hash]; + VELTS(symhash)[hash] = z; + return lsym; +} +SCM cons(x, y) + SCM x, y; +{ + register SCM z; + NEWCELL(z); + CAR(z) = x; + CDR(z) = y; + return z; +} +SCM cons2(w, x, y) + SCM w, x, y; +{ + register SCM z; + NEWCELL(z); + CAR(z) = x; + CDR(z) = y; + x = z; + NEWCELL(z); + CAR(z) = w; + CDR(z) = x; + return z; +} +SCM acons(w, x, y) + SCM w, x, y; +{ + register SCM z; + NEWCELL(z); + CAR(z) = w; + CDR(z) = x; + x = z; + NEWCELL(z); + CAR(z) = x; + CDR(z) = y; + return z; +} + +SCM makstr(len) + long len; +{ + SCM s; + NEWCELL(s); + DEFER_INTS; + SETCHARS(s, must_malloc(len+1, s_string)); + SETLENGTH(s, len, tc7_string); + ALLOW_INTS; + CHARS(s)[len] = 0; + return s; +} + +SCM make_subr(name, type, fcn) + char *name; + int type; + SCM (*fcn)(); +{ + SCM symcell = sysintern(name, UNDEFINED); + long tmp = ((((CELLPTR)(CAR(symcell)))-heap_org)<<8); + register SCM z; + if ((tmp>>8) != ((CELLPTR)(CAR(symcell))-heap_org)) + tmp = 0; + NEWCELL(z); + SUBRF(z) = fcn; + CAR(z) = tmp + type; + CDR(symcell) = z; + return z; +} + +#ifdef CCLO +SCM makcclo(proc, len) + SCM proc; + long len; +{ + SCM s; + NEWCELL(s); + DEFER_INTS; + SETCHARS(s, must_malloc(len*sizeof(SCM), "compiled-closure")); + SETLENGTH(s, len, tc7_cclo); + while (--len) VELTS(s)[len] = UNSPECIFIED; + CCLO_SUBR(s) = proc; + ALLOW_INTS; + return s; +} +#endif + +#ifdef STACK_LIMIT +void stack_check() +{ + STACKITEM *start = CONT(rootcont)->stkbse; + STACKITEM stack; +# ifdef STACK_GROWS_UP + if (&stack - start > STACK_LIMIT/sizeof(STACKITEM)) +# else + if (start - &stack > STACK_LIMIT/sizeof(STACKITEM)) +# endif /* def STACK_GROWS_UP */ + wta(UNDEFINED, (char *)SEGV_SIGNAL, "stack"); +} +#endif +void stack_report() +{ + STACKITEM stack; + intprint(stack_size(CONT(rootcont)->stkbse)*sizeof(STACKITEM), 16, cur_errp); + lputs(" of stack: 0x", cur_errp); + intprint((long)CONT(rootcont)->stkbse, 16, cur_errp); + lputs(" - 0x", cur_errp); + intprint((long)&stack, 16, cur_errp); + lputs("\n", cur_errp); +} + +SCM dynwind(thunk1, thunk2, thunk3) + SCM thunk1, thunk2, thunk3; +{ + SCM ans; + apply(thunk1, EOL, EOL); + dynwinds = acons(thunk1, thunk3, dynwinds); + ans = apply(thunk2, EOL, EOL); + dynwinds = CDR(dynwinds); + apply(thunk3, EOL, EOL); + return ans; +} +void dowinds(to, delta) + SCM to; + long delta; +{ + tail: + if (dynwinds==to); + else if (0 > delta) { + dowinds(CDR(to), 1+delta); + apply(CAR(CAR(to)), EOL, EOL); + dynwinds = to; + } + else { + SCM from = CDR(CAR(dynwinds)); + dynwinds = CDR(dynwinds); + apply(from, EOL, EOL); + delta--; goto tail; /* dowinds(to, delta-1); */ + } +} + +/* Remember that setjmp needs to be called after scm_make_cont */ + +SCM scm_make_cont() +{ + SCM cont; + CONTINUATION *ncont; + NEWCELL(cont); + DEFER_INTS; + ncont = make_continuation(CONT(rootcont)); + if (!ncont) wta(MAKINUM(-1), (char *)NALLOC, s_cont); + ncont->other.parent = rootcont; + SETCONT(cont, ncont); + SETLENGTH(cont, ncont->length, tc7_contin); + ncont->other.dynenv = dynwinds; +#ifdef CAUTIOUS + CONT(cont)->other.stack_trace = stacktrace; +#endif + ALLOW_INTS; + return cont; +} +static char s_sstale[] = "strangely stale"; +void scm_dynthrow(cont, val) + CONTINUATION *cont; + SCM val; +{ + if (cont->stkbse != CONT(rootcont)->stkbse) + wta(cont->other.dynenv, &s_sstale[10], s_cont); + dowinds(cont->other.dynenv, + ilength(dynwinds)-ilength(cont->other.dynenv)); +#ifdef CAUTIOUS + stacktrace = cont->other.stack_trace; +#endif + throw_to_continuation(cont, val, CONT(rootcont)); + wta(cont->other.dynenv, s_sstale, s_cont); +} + +SCM obhash(obj) + SCM obj; +{ + +#ifdef BIGDIG + long n = SRS(obj, 1); + if (!FIXABLE(n)) return long2big(n); +#endif + return (obj<<1)+2L; +} + +SCM obunhash(obj) + SCM obj; +{ +#ifdef BIGDIG + if (NIMP(obj) && BIGP(obj)) { + sizet i = NUMDIGS(obj); + BIGDIG *ds = BDIGITS(obj); + if (TYP16(obj)==tc16_bigpos) { + obj = 0; + while (i--) obj = BIGUP(obj) + ds[i]; + } + else { + obj = 0; + while (i--) obj = BIGUP(obj) - ds[i]; + } + obj <<= 1; + goto comm; + } +#endif + ASSERT(INUMP(obj), obj, ARG1, s_obunhash); + obj = SRS(obj, 1) & ~1L; + comm: + if IMP(obj) return obj; + if NCELLP(obj) return BOOL_F; + { /* code is adapted from mark_locations */ + register CELLPTR ptr = (CELLPTR)SCM2PTR(obj); + register sizet i = 0, j = hplim_ind; + do { + if PTR_GT(hplims[i++], ptr) break; + if PTR_LE(hplims[--j], ptr) break; + if ((i != j) + && PTR_LE(hplims[i++], ptr) + && PTR_GT(hplims[--j], ptr)) continue; + if NFREEP(obj) return obj; + break; + } while(i<j); + } + return BOOL_F; +} + +unsigned long strhash(str, len, n) + unsigned char *str; + sizet len; + unsigned long n; +{ + if (len>5) + { + sizet i = 5; + unsigned long h = 264 % n; + while (i--) h = ((h<<8) + ((unsigned)(downcase[str[h % len]]))) % n; + return h; + } + else { + sizet i = len; + unsigned long h = 0; + while (i) h = ((h<<8) + ((unsigned)(downcase[str[--i]]))) % n; + return h; + } +} + +static void fixconfig(s1, s2, s) + char *s1, *s2; + int s; +{ + fputs(s1, stderr); + fputs(s2, stderr); + fputs("\nin ", stderr); + fputs(s ? "setjump" : "scmfig", stderr); + fputs(".h and recompile scm\n", stderr); + quit(MAKINUM(1L)); +} + +sizet init_heap_seg(seg_org, size) + CELLPTR seg_org; + sizet size; +{ + register CELLPTR ptr = seg_org; +#ifdef POINTERS_MUNGED + register SCM scmptr; +#else +# define scmptr ptr +#endif + CELLPTR seg_end = CELL_DN((char *)ptr + size); + sizet i = hplim_ind, ni = 0; + if (ptr==NULL) return 0; + while((ni < hplim_ind) && PTR_LE(hplims[ni], seg_org)) ni++; + while(i-- > ni) hplims[i+2] = hplims[i]; + hplim_ind += 2; + hplims[ni++] = ptr; /* same as seg_org here */ + hplims[ni++] = seg_end; + ptr = CELL_UP(ptr); + ni = seg_end - ptr; + for (i = ni;i--;ptr++) { +#ifdef POINTERS_MUNGED + scmptr = PTR2SCM(ptr); +#endif + CAR(scmptr) = (SCM)tc_free_cell; + CDR(scmptr) = PTR2SCM(ptr+1); + } +/* CDR(scmptr) = freelist; */ + CDR(PTR2SCM(--ptr)) = freelist; + freelist = PTR2SCM(CELL_UP(seg_org)); + heap_size += ni; + return size; +#ifdef scmptr +# undef scmptr +#endif +} +static void alloc_some_heap() +{ + CELLPTR ptr, *tmplims; + sizet len = (2+hplim_ind)*sizeof(CELLPTR); + ASRTGO(len==(2+hplim_ind)*sizeof(CELLPTR), badhplims); + if (errjmp_bad) wta(UNDEFINED, "need larger initial", s_heap); + SYSCALL(tmplims = (CELLPTR *)realloc((char *)hplims, len);); + if (!tmplims) +badhplims: + wta(UNDEFINED, s_nogrow, s_hplims); + else hplims = tmplims; + /* hplim_ind gets incremented in init_heap_seg() */ + if (expmem) { + len = (sizet)(EXPHEAP(heap_size)*sizeof(cell)); + if ((sizet)(EXPHEAP(heap_size)*sizeof(cell)) != len) len = 0; + } + else len = HEAP_SEG_SIZE; + while (len >= MIN_HEAP_SEG_SIZE) { + SYSCALL(ptr = (CELLPTR) malloc(len);); + if (ptr) { + init_heap_seg(ptr, len); + return; + } + len /= 2; + } + wta(UNDEFINED, s_nogrow, s_heap); +} + +smobfuns *smobs; +sizet numsmob; +long newsmob(smob) + smobfuns *smob; +{ + char *tmp; + if (255 <= numsmob) goto smoberr; + DEFER_INTS; + SYSCALL(tmp = (char *)realloc((char *)smobs, (1+numsmob)*sizeof(smobfuns));); + if (tmp) { + smobs = (smobfuns *)tmp; + smobs[numsmob].mark = smob->mark; + smobs[numsmob].free = smob->free; + smobs[numsmob].print = smob->print; + smobs[numsmob].equalp = smob->equalp; + numsmob++; + } + ALLOW_INTS; + if (!tmp) smoberr: wta(MAKINUM((long)numsmob), (char *)NALLOC, "newsmob"); + return tc7_smob + (numsmob-1)*256; +} +ptobfuns *ptobs; +sizet numptob; +long newptob(ptob) + ptobfuns *ptob; +{ + char *tmp; + if (255 <= numptob) goto ptoberr; + DEFER_INTS; + SYSCALL(tmp = (char *)realloc((char *)ptobs, (1+numptob)*sizeof(ptobfuns));); + if (tmp) { + ptobs = (ptobfuns *)tmp; + ptobs[numptob].mark = ptob->mark; + ptobs[numptob].free = ptob->free; + ptobs[numptob].print = ptob->print; + ptobs[numptob].equalp = ptob->equalp; + ptobs[numptob].fputc = ptob->fputc; + ptobs[numptob].fputs = ptob->fputs; + ptobs[numptob].fwrite = ptob->fwrite; + ptobs[numptob].fflush = ptob->fflush; + ptobs[numptob].fgetc = ptob->fgetc; + ptobs[numptob].fclose = ptob->fclose; + numptob++; + } + ALLOW_INTS; + if (!tmp) ptoberr: wta(MAKINUM((long)numptob), (char *)NALLOC, "newptob"); + return tc7_port + (numptob-1)*256; +} +SCM markcdr(ptr) + SCM ptr; +{ + if GC8MARKP(ptr) return BOOL_F; + SETGC8MARK(ptr); + return CDR(ptr); +} +SCM mark0(ptr) + SCM ptr; +{ + SETGC8MARK(ptr); + return BOOL_F; +} +sizet free0(ptr) + CELLPTR ptr; +{ + return 0; +} +SCM equal0(ptr1, ptr2) + SCM ptr1, ptr2; +{ + return (CDR(ptr1)==CDR(ptr2)) ? BOOL_T : BOOL_F; +} + +/* statically allocated port for diagnostic messages */ +cell tmp_errp = {(SCM)((0L<<8)|tc16_fport|OPN|WRTNG), 0}; + +static char remsg[] = "remove\n#define ", addmsg[] = "add\n#define "; +extern sizet num_protects; /* sys_protects now in scl.c */ +void init_storage(stack_start_ptr, init_heap_size) + STACKITEM *stack_start_ptr; + long init_heap_size; +{ + sizet j = num_protects; + /* Because not all protects may get initialized */ + while(j) sys_protects[--j] = BOOL_F; + tmp_errp.cdr = (SCM)stderr; + cur_errp = PTR2SCM(&tmp_errp); + freelist = EOL; + expmem = 0; + +#ifdef SHORT_INT + if (sizeof(int) >= sizeof(long)) + fixconfig(remsg, "SHORT_INT", 1); +#else + if (sizeof(int) < sizeof(long)) + fixconfig(addmsg, "SHORT_INT", 1); +#endif +#ifdef CDR_DOUBLES + if (sizeof(double) != sizeof(long)) + fixconfig(remsg, "CDR_DOUBLES", 0); +#else +# ifdef SINGLES + if (sizeof(float) != sizeof(long)) + if (sizeof(double) == sizeof(long)) + fixconfig(addmsg, "CDR_DOUBLES", 0); + else + fixconfig(remsg, "SINGLES", 0); +# endif +#endif +#ifdef BIGDIG + if (2*BITSPERDIG/CHAR_BIT > sizeof(long)) + fixconfig(remsg, "BIGDIG", 0); +# ifndef DIGSTOOBIG + if (DIGSPERLONG*sizeof(BIGDIG) > sizeof(long)) + fixconfig(addmsg, "DIGSTOOBIG", 0); +# endif +#endif +#ifdef STACK_GROWS_UP + if (((STACKITEM *)&j - stack_start_ptr) < 0) + fixconfig(remsg, "STACK_GROWS_UP", 1); +#else + if ((stack_start_ptr - (STACKITEM *)&j) < 0) + fixconfig(addmsg, "STACK_GROWS_UP", 1); +#endif + j = HEAP_SEG_SIZE; + if (HEAP_SEG_SIZE != j) + fixconfig("reduce", "size of HEAP_SEG_SIZE", 0); + + mtrigger = INIT_MALLOC_LIMIT; + hplims = (CELLPTR *) must_malloc(2L*sizeof(CELLPTR), s_hplims); + if (0L==init_heap_size) init_heap_size = INIT_HEAP_SIZE; + j = init_heap_size; + if ((init_heap_size != j) || !init_heap_seg((CELLPTR) malloc(j), j)) { + j = HEAP_SEG_SIZE; + if (!init_heap_seg((CELLPTR) malloc(j), j)) + wta(MAKINUM(j), (char *)NALLOC, s_heap); + } + else expmem = 1; + heap_org = CELL_UP(hplims[0]); + /* hplims[0] can change. do not remove heap_org */ + + NEWCELL(def_inp); + CAR(def_inp) = (tc16_fport|OPN|RDNG); + SETSTREAM(def_inp, stdin); + NEWCELL(def_outp); + CAR(def_outp) = (tc16_fport|OPN|WRTNG); + SETSTREAM(def_outp, stdout); + NEWCELL(def_errp); + CAR(def_errp) = (tc16_fport|OPN|WRTNG); + SETSTREAM(def_errp, stderr); + cur_inp = def_inp; + cur_outp = def_outp; + cur_errp = def_errp; + dynwinds = EOL; + NEWCELL(rootcont); + SETCONT(rootcont, make_root_continuation(stack_start_ptr)); + CAR(rootcont) = tc7_contin; + CONT(rootcont)->other.dynenv = EOL; + CONT(rootcont)->other.parent = BOOL_F; + stacktrace = EOL; +#ifdef CAUTIOUS + CONT(rootcont)->other.stack_trace = EOL; +#endif + listofnull = cons(EOL, EOL); + undefineds = cons(UNDEFINED, EOL); + CDR(undefineds) = undefineds; + nullstr = makstr(0L); + nullvect = make_vector(INUM0, UNDEFINED); + /* NEWCELL(nullvect); + CAR(nullvect) = tc7_vector; + SETCHARS(nullvect, NULL); */ + symhash = make_vector((SCM)MAKINUM(symhash_dim), EOL); + sysintern("most-positive-fixnum", (SCM)MAKINUM(MOST_POSITIVE_FIXNUM)); + sysintern("most-negative-fixnum", (SCM)MAKINUM(MOST_NEGATIVE_FIXNUM)); +#ifdef BIGDIG + sysintern("bignum-radix", MAKINUM(BIGRAD)); +#endif + /* flo0 is now setup in scl.c */ +} + +/* The way of garbage collecting which allows use of the cstack is due to */ +/* Scheme In One Defun, but in C this time. + + * COPYRIGHT (c) 1989 BY * + * PARADIGM ASSOCIATES INCORPORATED, CAMBRIDGE, MASSACHUSETTS. * + * ALL RIGHTS RESERVED * + +Permission to use, copy, modify, distribute and sell this software +and its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all copies +and that both that copyright notice and this permission notice appear +in supporting documentation, and that the name of Paradigm Associates +Inc not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +PARADIGM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +PARADIGM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +gjc@paradigm.com + +Paradigm Associates Inc Phone: 617-492-6079 +29 Putnam Ave, Suite 6 +Cambridge, MA 02138 +*/ +char s_cells[] = "cells"; +SCM gc_for_newcell() +{ + SCM fl; + DEFER_INTS; + igc(s_cells, CONT(rootcont)->stkbse); + ALLOW_INTS; + if ((gc_cells_collected < MIN_GC_YIELD) || IMP(freelist)) { + DEFER_INTS; + alloc_some_heap(); + ALLOW_INTS; + growth_mon("number of heaps", (long)(hplim_ind/2), "segments"); + growth_mon(s_heap, heap_size, s_cells); + } + ++cells_allocated; + fl = freelist; + freelist = CDR(fl); + return fl; +} + +static char s_bad_type[] = "unknown type in "; +jmp_buf save_regs_gc_mark; +void mark_locations P((STACKITEM x[], sizet n)); +static void mark_syms P((SCM v)); +static void mark_sym_values P((SCM v)); +static void sweep_symhash P((SCM v)); + +SCM gc() +{ + DEFER_INTS; + igc("call", CONT(rootcont)->stkbse); + ALLOW_INTS; + return UNSPECIFIED; +} +void igc(what, stackbase) + char *what; + STACKITEM *stackbase; +{ + int j = num_protects; + long oheap_size = heap_size; + gc_start(what); + ++errjmp_bad; + /* By marking symhash first, we provide the best immunity from + accidental references. In order to accidentally protect a + symbol, a pointer will have to point directly at the symbol (as + opposed to the vector or bucket lists). */ + mark_syms(symhash); + /* mark_sym_values() can be called anytime after mark_syms. */ +#ifdef NO_SYM_GC + gc_mark(symhash); +#else + mark_sym_values(symhash); +#endif + if (stackbase) { + FLUSH_REGISTER_WINDOWS; + /* This assumes that all registers are saved into the jmp_buf */ + setjmp(save_regs_gc_mark); + mark_locations((STACKITEM *) save_regs_gc_mark, + (sizet) (sizeof(STACKITEM) - 1 + sizeof save_regs_gc_mark) / + sizeof(STACKITEM)); + { + /* stack_len is long rather than sizet in order to guarantee that + &stack_len is long aligned */ +#ifdef STACK_GROWS_UP +# ifdef nosve + long stack_len = (STACKITEM *)(&stack_len) - stackbase; +# else + long stack_len = stack_size(stackbase); +# endif + mark_locations(stackbase, (sizet)stack_len); +#else +# ifdef nosve + long stack_len = stackbase - (STACKITEM *)(&stack_len); +# else + long stack_len = stack_size(stackbase); +# endif + mark_locations((stackbase - stack_len), (sizet)stack_len); +#endif + } + } + while(j--) gc_mark(sys_protects[j]); + sweep_symhash(symhash); + gc_sweep(); + --errjmp_bad; + gc_end(); + if (oheap_size != heap_size) { + ALLOW_INTS; + growth_mon(s_heap, heap_size, s_cells); + DEFER_INTS; + } +} + +static char s_not_free[] = "not freed"; +void free_storage() +{ + DEFER_INTS; + gc_start("free"); + ++errjmp_bad; + cur_inp = BOOL_F; cur_outp = BOOL_F; cur_errp = PTR2SCM(&tmp_errp); + gc_mark(def_inp); /* don't want to close stdin */ + gc_mark(def_outp); /* don't want to close stdout */ + gc_mark(def_errp); /* don't want to close stderr */ + gc_sweep(); + rootcont = BOOL_F; + while (hplim_ind) { /* free heap segments */ + hplim_ind -= 2; + { + CELLPTR ptr = CELL_UP(hplims[hplim_ind]); + sizet seg_size = CELL_DN(hplims[hplim_ind+1]) - ptr; + heap_size -= seg_size; + must_free((char *)hplims[hplim_ind]); + hplims[hplim_ind] = 0; + growth_mon(s_heap, heap_size, s_cells); + }} + if (heap_size) wta(MAKINUM(heap_size), s_not_free, s_heap); + if (hplim_ind) wta((SCM)MAKINUM(hplim_ind), s_not_free, s_hplims); + /* Not all cells get freed (see gc_mark() calls above). */ + /* if (cells_allocated) wta(MAKINUM(cells_allocated), s_not_free, "cells"); */ + /* either there is a small memory leak or I am counting wrong. */ + /* if (mallocated) wta(MAKINUM(mallocated), s_not_free, "malloc"); */ + must_free((char *)hplims); + hplims = 0; + must_free((char *)smobs); + smobs = 0; + gc_end(); + ALLOW_INTS; /* A really bad idea, but printing does it anyway. */ + exit_report(); + must_free((char *)ptobs); + ptobs = 0; + lmallocated = mallocated = 0; + /* Can't do gc_end() here because it uses ptobs which have been freed */ +} + +void gc_mark(p) + SCM p; +{ + register long i; + register SCM ptr = p; + gc_mark_loop: + if IMP(ptr) return; + gc_mark_nimp: + if (NCELLP(ptr) + /* #ifndef RECKLESS + || PTR_GT(hplims[0], (CELLPTR)ptr) + || PTR_GE((CELLPTR)ptr, hplims[hplim_ind-1]) +#endif */ + ) wta(ptr, "rogue pointer in ", s_heap); + switch TYP7(ptr) { + case tcs_cons_nimcar: + if GCMARKP(ptr) break; + SETGCMARK(ptr); + if IMP(CDR(ptr)) { /* IMP works even with a GC mark */ + ptr = CAR(ptr); + goto gc_mark_nimp; + } + gc_mark(CAR(ptr)); + ptr = GCCDR(ptr); + goto gc_mark_nimp; + case tcs_cons_imcar: + case tcs_cons_gloc: + if GCMARKP(ptr) break; + SETGCMARK(ptr); + ptr = GCCDR(ptr); + goto gc_mark_loop; + case tcs_closures: + if GCMARKP(ptr) break; + SETGCMARK(ptr); + if IMP(CDR(ptr)) { + ptr = CODE(ptr); + goto gc_mark_nimp; + } + gc_mark(CODE(ptr)); + ptr = GCCDR(ptr); + goto gc_mark_nimp; + case tc7_vector: +#ifdef CCLO + case tc7_cclo: +#endif + if GC8MARKP(ptr) break; + SETGC8MARK(ptr); + i = LENGTH(ptr); + if (i==0) break; + while(--i>0) if NIMP(VELTS(ptr)[i]) gc_mark(VELTS(ptr)[i]); + ptr = VELTS(ptr)[0]; + goto gc_mark_loop; + case tc7_contin: + if GC8MARKP(ptr) break; + SETGC8MARK(ptr); + mark_locations((STACKITEM *)VELTS(ptr), + (sizet)(LENGTH(ptr) + + (sizeof(STACKITEM) - 1 + sizeof(CONTINUATION)) / + sizeof(STACKITEM))); + break; + case tc7_bvect: + case tc7_ivect: + case tc7_uvect: + case tc7_fvect: + case tc7_dvect: + case tc7_cvect: + case tc7_string: + case tc7_msymbol: + case tc7_ssymbol: + SETGC8MARK(ptr); + case tcs_subrs: + break; + case tc7_port: + i = PTOBNUM(ptr); + if (!(i < numptob)) goto def; + ptr = (ptobs[i].mark)(ptr); + goto gc_mark_loop; + case tc7_smob: + if GC8MARKP(ptr) break; + switch TYP16(ptr) { /* should be faster than going through smobs */ + case tc_free_cell: + /* printf("found free_cell %X ", ptr); fflush(stdout); */ + SETGC8MARK(ptr); + CDR(ptr) = EOL; + break; + case tcs_bignums: + case tc16_flo: + SETGC8MARK(ptr); + break; + default: + i = SMOBNUM(ptr); + if (!(i < numsmob)) goto def; + ptr = (smobs[i].mark)(ptr); + goto gc_mark_loop; + } + break; + default: def: wta(ptr, s_bad_type, "gc_mark"); + } +} + +void mark_locations(x, n) + STACKITEM x[]; + sizet n; +{ + register long m = n; + register int i, j; + register CELLPTR ptr; + while(0 <= --m) if CELLP(*(SCM **)&x[m]) { + ptr = (CELLPTR)SCM2PTR((*(SCM **)&x[m])); + i = 0; + j = hplim_ind; + do { + if PTR_GT(hplims[i++], ptr) break; + if PTR_LE(hplims[--j], ptr) break; + if ((i != j) + && PTR_LE(hplims[i++], ptr) + && PTR_GT(hplims[--j], ptr)) continue; + /* if NFREEP(*(SCM **)&x[m]) */ gc_mark(*(SCM *)&x[m]); + break; + } while(i<j); + } +} + +#define HUGE_LENGTH(x) (LENGTH_MAX==LENGTH(x) ? *((long *)VELTS(x)) : LENGTH(x)) + +static void gc_sweep() +{ + register CELLPTR ptr; +#ifdef POINTERS_MUNGED + register SCM scmptr; +#else +#define scmptr (SCM)ptr +#endif + register SCM nfreelist = EOL; + register long n = 0, m = 0; + register sizet j; + sizet i = 0; + sizet seg_size; + while (i<hplim_ind) { + ptr = CELL_UP(hplims[i++]); + seg_size = CELL_DN(hplims[i++]) - ptr; + for(j = seg_size;j--;++ptr) { +#ifdef POINTERS_MUNGED + scmptr = PTR2SCM(ptr); +#endif + switch TYP7(scmptr) { + case tcs_cons_imcar: + case tcs_cons_nimcar: + case tcs_cons_gloc: + case tcs_closures: + if GCMARKP(scmptr) goto cmrkcontinue; + break; + case tc7_vector: +#ifdef CCLO + case tc7_cclo: +#endif + if GC8MARKP(scmptr) goto c8mrkcontinue; + m += (LENGTH(scmptr)*sizeof(SCM)); + freechars: + must_free(CHARS(scmptr)); +/* SETCHARS(scmptr, 0);*/ + break; + case tc7_bvect: + if GC8MARKP(scmptr) goto c8mrkcontinue; + m += sizeof(long)*((HUGE_LENGTH(scmptr)+LONG_BIT-1)/LONG_BIT); + goto freechars; + case tc7_ivect: + case tc7_uvect: + if GC8MARKP(scmptr) goto c8mrkcontinue; + m += HUGE_LENGTH(scmptr)*sizeof(long); + goto freechars; + case tc7_fvect: + if GC8MARKP(scmptr) goto c8mrkcontinue; + m += HUGE_LENGTH(scmptr)*sizeof(float); + goto freechars; + case tc7_dvect: + if GC8MARKP(scmptr) goto c8mrkcontinue; + m += HUGE_LENGTH(scmptr)*sizeof(double); + goto freechars; + case tc7_cvect: + if GC8MARKP(scmptr) goto c8mrkcontinue; + m += HUGE_LENGTH(scmptr)*2*sizeof(double); + goto freechars; + case tc7_string: + if GC8MARKP(scmptr) goto c8mrkcontinue; + m += HUGE_LENGTH(scmptr)+1; + goto freechars; + case tc7_msymbol: + if GC8MARKP(scmptr) goto c8mrkcontinue; + m += LENGTH(scmptr)+1; + goto freechars; + case tc7_contin: + if GC8MARKP(scmptr) goto c8mrkcontinue; + m += LENGTH(scmptr)*sizeof(STACKITEM) + sizeof(CONTINUATION); +/* free_continuation(CONT(scmptr)); */ + goto freechars; + case tc7_ssymbol: + if GC8MARKP(scmptr) goto c8mrkcontinue; + /* Do not free storage because tc7_ssymbol means scmptr's + storage was not created by a call to malloc(). */ + break; + case tcs_subrs: + continue; + case tc7_port: + if GC8MARKP(scmptr) goto c8mrkcontinue; + if OPENP(scmptr) { + int k = PTOBNUM(scmptr); + if (!(k < numptob)) goto sweeperr; + /* Yes, I really do mean ptobs[k].free */ + /* rather than ftobs[k].close. .close */ + /* is for explicit CLOSE-PORT by user */ + (ptobs[k].free)(STREAM(scmptr)); + gc_ports_collected++; + SETSTREAM(scmptr, 0); + CAR(scmptr) &= ~OPN; + } + break; + case tc7_smob: + switch GCTYP16(scmptr) { + case tc_free_cell: + if GC8MARKP(scmptr) goto c8mrkcontinue; + break; +#ifdef BIGDIG + case tcs_bignums: + if GC8MARKP(scmptr) goto c8mrkcontinue; + m += (NUMDIGS(scmptr)*BITSPERDIG/CHAR_BIT); + goto freechars; +#endif /* def BIGDIG */ + case tc16_flo: + if GC8MARKP(scmptr) goto c8mrkcontinue; + switch ((int)(CAR(scmptr)>>16)) { + case (IMAG_PART | REAL_PART)>>16: + m += sizeof(double); + case REAL_PART>>16: + case IMAG_PART>>16: + m += sizeof(double); + goto freechars; + case 0: + break; + default: + goto sweeperr; + } + break; + default: + if GC8MARKP(scmptr) goto c8mrkcontinue; + { + int k = SMOBNUM(scmptr); + if (!(k < numsmob)) goto sweeperr; + m += (smobs[k].free)((CELLPTR)scmptr); + } + } + break; + default: sweeperr: wta(scmptr, s_bad_type, "gc_sweep"); + } + ++n; + CAR(scmptr) = (SCM)tc_free_cell; + CDR(scmptr) = nfreelist; + nfreelist = scmptr; + continue; + c8mrkcontinue: + CLRGC8MARK(scmptr); + continue; + cmrkcontinue: + CLRGCMARK(scmptr); + } +#ifdef GC_FREE_SEGMENTS + if (n==seg_size) { + heap_size -= seg_size; + must_free((char *)hplims[i-2]); + hplims[i-2] = 0; + for(j = i;j < hplim_ind;j++) hplims[j-2] = hplims[j]; + hplim_ind -= 2; + i -= 2; /* need to scan segment just moved. */ + nfreelist = freelist; + } + else +#endif /* ifdef GC_FREE_SEGMENTS */ + freelist = nfreelist; + gc_cells_collected += n; + n = 0; + } + lcells_allocated += (heap_size - gc_cells_collected - cells_allocated); + cells_allocated = (heap_size - gc_cells_collected); + lmallocated -= m; + mallocated -= m; + gc_malloc_collected = m; +} + +/* mark_syms marks those symbols of hash table V which have + non-UNDEFINED values. */ +static char s_gc_sym[] = "mark_syms"; +static void mark_syms(v) + SCM v; +{ + SCM x, al; + int k = LENGTH(v); + while (k--) + for (al = VELTS(v)[k]; NIMP(al); al = GCCDR(al)) { + /* If this bucket has already been marked, then something is wrong. */ + ASSERT(!GCMARKP(al), al, s_bad_type, s_gc_sym); + x = CAR(al); + SETGCMARK(al); + ASSERT(!GCMARKP(x), x, s_bad_type, s_gc_sym); + if (UNDEFINED==CDR(x) && tc7_msymbol==TYP7(CAR(x))) + goto used; /* Don't mark symbol. */ + SETGC8MARK(CAR(x)); + used: + SETGCMARK(x); /* Do mark value cell. */ + } + SETGC8MARK(v); /* Mark bucket list. */ +} + +/* mark_symhash marks the values of hash table V. */ +static void mark_sym_values(v) + SCM v; +{ + SCM x, al; + int k = LENGTH(v); + SETGC8MARK(v); + while (k--) + for (al = VELTS(v)[k]; NIMP(al); al = GCCDR(al)) { + x = GCCDR(CAR(al)); + if IMP(x) continue; + gc_mark(x); + } +} + +/* Splice any unused valueless symbols out of the hash buckets. */ +static void sweep_symhash(v) + SCM v; +{ + SCM al, x, *lloc; + int k = LENGTH(v); + while (k--) { + lloc = &(VELTS(v)[k]); + while NIMP(al = (*lloc & ~1L)) { + x = CAR(al); + if GC8MARKP(CAR(x)) + lloc = &(CDR(al)); + else { + *lloc = CDR(al); + CLRGCMARK(al); /* bucket pair to be collected by gc_sweep */ + CLRGCMARK(x); /* value cell to be collected by gc_sweep */ + gc_syms_collected++; + } + } + VELTS(v)[k] &= ~1L; /* We may have deleted the first cell */ + } +} @@ -0,0 +1,389 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "time.c" functions dealing with time. + Author: Aubrey Jaffer */ + +#include "scm.h" + +#ifdef HAVE_CONFIG_H + +# ifndef HAVE_FTIME +# define LACK_FTIME +# endif +# ifndef HAVE_TIMES +# define LACK_TIMES +# endif +# ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +# endif +# ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +# else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# ifdef HAVE_TIME_H +# include <time.h> +# endif +# endif +# endif +# ifdef HAVE_SYS_TIMES_H +# include <sys/times.h> +# else +# ifdef HAVE_SYS_TIMEB_H +# include <sys/timeb.h> +# endif +# endif +# ifdef HAVE_FTIME +# ifdef unix +# ifndef GO32 +# include <sys/timeb.h> +# endif +# endif +# endif + +#else + +# ifdef STDC_HEADERS +# include <time.h> +# ifdef M_SYSV +# include <sys/types.h> +# include <sys/times.h> +# endif +# ifdef sun +# include <sys/types.h> +# include <sys/times.h> +# endif +# ifdef ultrix +# include <sys/types.h> +# include <sys/times.h> +# endif +# ifdef nosve +# include <sys/types.h> +# include <sys/times.h> +# endif +# ifdef _UNICOS +# include <sys/types.h> +# include <sys/times.h> +# endif +# ifdef __IBMC__ +# include <sys/timeb.h> +# endif +# else +# ifdef SVR2 +# include <time.h> +# else +# ifndef ARM_ULIB +# include <sys/time.h> +# else +# include <time.h> +# endif +# endif +# include <sys/types.h> + +# ifndef ARM_ULIB +# include <sys/times.h> +# else +# include <time.h> +# endif + +# endif + +/* Define this if your system lacks ftime(). */ +/* #define LACK_FTIME */ +/* Define this if your system lacks times(). */ +/* #define LACK_TIMES */ + +# ifdef __TURBOC__ +# define LACK_TIMES +# endif +# if (__TURBOC__==1) /* Needed for TURBOC V1.0 */ +# define LACK_FTIME +# undef MSDOS +# endif +# ifdef __HIGHC__ +# define LACK_TIMES +# endif +# ifdef THINK_C +# define LACK_FTIME +# define LACK_TIMES +# define CLK_TCK 60 +# endif +# ifdef SVR2 +# define LACK_FTIME +# endif +# ifdef SVR4 +# define LACK_FTIME +# endif +# ifdef __svr4__ +# define LACK_FTIME +# endif +# ifdef nosve +# define LACK_FTIME +# endif +# ifdef GO32 +# define LACK_FTIME +# define LACK_TIMES +# endif +# ifdef atarist +# define LACK_FTIME +# define LACK_TIMES +# endif +# ifdef ARM_ULIB +# define LACK_FTIME +# define LACK_TIMES +# endif +# ifdef _DCC +# define LACK_FTIME +# endif +# ifdef MSDOS +# ifndef GO32 +# include <sys/types.h> +# include <sys/timeb.h> +# endif +# endif +# ifdef _UNICOS +# define LACK_FTIME +# endif + +# ifndef LACK_FTIME +# ifdef unix +# ifndef GO32 +# include <sys/timeb.h> +# endif +# endif +# endif + +# ifdef __EMX__ +# define LACK_TIMES +# include <sys/types.h> +# include <sys/timeb.h> +# endif + +# ifdef MWC +# include <time.h> +# include <sys/timeb.h> +# endif + +# ifdef ARM_ULIB +# include <sys/types.h> +# include <time.h> +# endif + +#endif /* HAVE_CONFIG_H */ + +#ifdef vms +# define LACK_TIMES +# define LACK_FTIME +#endif + +#ifdef CLK_TCK +# define CLKTCK CLK_TCK +# ifdef CLOCKS_PER_SEC +# ifdef unix +# ifndef ARM_ULIB +# include <sys/times.h> +# endif +# define LACK_CLOCK + /* This is because clock() might be POSIX rather than ANSI. + This occurs on HP-UX machines */ +# endif +# endif +#else +# ifdef CLOCKS_PER_SEC +# define CLKTCK CLOCKS_PER_SEC +# else +# define LACK_CLOCK +# ifdef AMIGA +# include <stddef.h> +# define LACK_TIMES +# define LACK_FTIME +# define CLKTCK 1000 +# else +# define CLKTCK 60 +# endif +# endif +#endif + +#ifdef __STDC__ +# define timet time_t +#else +# define timet long +#endif + +#ifdef LACK_TIMES +# ifdef LACK_CLOCK +# ifdef AMIGA +/* From: "Fred Bayer" <bayerf@lan.informatik.tu-muenchen.de> */ +# ifdef AZTEC_C /* AZTEC_C */ +# include <devices/timer.h> +static long mytime() +{ + long sec, mic, mili = 0; + struct timerequest *timermsg; + struct MsgPort *timerport; + if(!(timerport = (struct MsgPort *)CreatePort(0, 0))){ + lputs("No mem for port.\n", cur_errp); + return mili; + } + if(!(timermsg = (struct timerequest *) + CreateExtIO(timerport, sizeof(struct timerequest)))){ + lputs("No mem for timerequest.\n", cur_errp); + DeletePort(timermsg->tr_node.io_Message.mn_ReplyPort); + return mili; + } + if(!(OpenDevice(TIMERNAME, UNIT_MICROHZ, timermsg, 0))){ + timermsg->tr_node.io_Command = TR_GETSYSTIME; + timermsg->tr_node.io_Flags = 0; + DoIO(timermsg); + sec = timermsg->tr_time.tv_secs; + mic = timermsg->tr_time.tv_micro; + mili = sec*1000+mic/1000; + CloseDevice(timermsg); + } + else lputs("No Timer available.\n", cur_errp); + DeletePort(timermsg->tr_node.io_Message.mn_ReplyPort); + DeleteExtIO(timermsg); + return mili ; +} +# else /* this is for SAS/C */ +static long mytime() +{ + unsigned int cl[2]; + timer(cl); + return(cl[0]*1000+cl[1]/1000); +} +# endif /* AZTEC_C */ +# else /* AMIGA */ +# define mytime() ((time((timet*)0) - your_base) * CLKTCK) +# endif /* AMIGA */ +# else /* LACK_CLOCK */ +# define mytime clock +# endif /* LACK_CLOCK */ +#else /* LACK_TIMES */ +static long mytime() +{ + struct tms time_buffer; + times(&time_buffer); + return time_buffer.tms_utime + time_buffer.tms_stime; +} +#endif /* LACK_TIMES */ + +#ifdef LACK_FTIME +# ifdef AMIGA +SCM your_time() +{ + return MAKINUM(mytime()); +} +# else +timet your_base = 0; +SCM your_time() +{ + return MAKINUM((time((timet*)0) - your_base) * (int)CLKTCK); +} +# endif /* AMIGA */ +#else /* LACK_FTIME */ +struct timeb your_base = {0}; +SCM your_time() +{ + struct timeb time_buffer; + long tmp; + ftime(&time_buffer); + time_buffer.time -= your_base.time; + tmp = time_buffer.millitm - your_base.millitm; + tmp = time_buffer.time*1000L + tmp; + tmp *= CLKTCK; + tmp /= 1000; + return MAKINUM(tmp); +} +#endif /* LACK_FTIME */ + +long my_base = 0; +SCM my_time() +{ + return MAKINUM(mytime()-my_base); +} + +SCM curtime() +{ + timet timv = time((timet*)0); + SCM ans; +#ifndef _DCC +# ifdef STDC_HEADERS +# if (__TURBOC__ > 0x201) + timv = mktime(gmtime(&timv)); +# endif +# endif +#endif + ans = ulong2num(timv); + return BOOL_F==ans ? MAKINUM(timv) : ans; +} + +long time_in_msec(x) + long x; +{ + if (CLKTCK==60) return (x*50)/3; + else + return (CLKTCK < 1000 ? x*(1000L/(long)CLKTCK) : (x*1000L)/(long)CLKTCK); +} + +static iproc subr0s[] = { + {"get-internal-run-time", my_time}, + {"get-internal-real-time", your_time}, + {"current-time", curtime}, + {0, 0}}; + +void init_time() +{ + sysintern("internal-time-units-per-second", + MAKINUM((long)CLKTCK)); +#ifdef LACK_FTIME +# ifndef AMIGA + if (!your_base) time(&your_base); +# endif +#else + if (!your_base.time) ftime(&your_base); +#endif + if (!my_base) my_base = mytime(); + init_iprocs(subr0s, tc7_subr_0); +} diff --git a/unexec.c b/unexec.c new file mode 100644 index 0000000..f7ff9ca --- /dev/null +++ b/unexec.c @@ -0,0 +1,1238 @@ +/* Copyright (C) 1985,86,87,88,92,93,94 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* + * unexec.c - Convert a running program into an a.out file. + * + * Author: Spencer W. Thomas + * Computer Science Dept. + * University of Utah + * Date: Tue Mar 2 1982 + * Modified heavily since then. + * + * Synopsis: + * unexec (new_name, a_name, data_start, bss_start, entry_address) + * char *new_name, *a_name; + * unsigned data_start, bss_start, entry_address; + * + * Takes a snapshot of the program and makes an a.out format file in the + * file named by the string argument new_name. + * If a_name is non-NULL, the symbol table will be taken from the given file. + * On some machines, an existing a_name file is required. + * + * The boundaries within the a.out file may be adjusted with the data_start + * and bss_start arguments. Either or both may be given as 0 for defaults. + * + * Data_start gives the boundary between the text segment and the data + * segment of the program. The text segment can contain shared, read-only + * program code and literal data, while the data segment is always unshared + * and unprotected. Data_start gives the lowest unprotected address. + * The value you specify may be rounded down to a suitable boundary + * as required by the machine you are using. + * + * Specifying zero for data_start means the boundary between text and data + * should not be the same as when the program was loaded. + * If NO_REMAP is defined, the argument data_start is ignored and the + * segment boundaries are never changed. + * + * Bss_start indicates how much of the data segment is to be saved in the + * a.out file and restored when the program is executed. It gives the lowest + * unsaved address, and is rounded up to a page boundary. The default when 0 + * is given assumes that the entire data segment is to be stored, including + * the previous data and bss as well as any additional storage allocated with + * break (2). + * + * The new file is set up to start at entry_address. + * + * If you make improvements I'd like to get them too. + * harpo!utah-cs!thomas, thomas@Utah-20 + * + */ + +/* Modified to support SysVr3 shared libraries by James Van Artsdalen + * of Dell Computer Corporation. james@bigtex.cactus.org. + */ + +/* There are several compilation parameters affecting unexec: + +* COFF + +Define this if your system uses COFF for executables. + +* COFF_ENCAPSULATE + +Define this if you are using the GNU coff encapsulated a.out format. +This is closer to a.out than COFF. You should *not* define COFF if +you define COFF_ENCAPSULATE + +Otherwise we assume you use Berkeley format. + +* NO_REMAP + +Define this if you do not want to try to save Emacs's pure data areas +as part of the text segment. + +Saving them as text is good because it allows users to share more. + +However, on machines that locate the text area far from the data area, +the boundary cannot feasibly be moved. Such machines require +NO_REMAP. + +Also, remapping can cause trouble with the built-in startup routine +/lib/crt0.o, which defines `environ' as an initialized variable. +Dumping `environ' as pure does not work! So, to use remapping, +you must write a startup routine for your machine in Emacs's crt0.c. +If NO_REMAP is defined, Emacs uses the system's crt0.o. + +* SECTION_ALIGNMENT + +Some machines that use COFF executables require that each section +start on a certain boundary *in the COFF file*. Such machines should +define SECTION_ALIGNMENT to a mask of the low-order bits that must be +zero on such a boundary. This mask is used to control padding between +segments in the COFF file. + +If SECTION_ALIGNMENT is not defined, the segments are written +consecutively with no attempt at alignment. This is right for +unmodified system V. + +* SEGMENT_MASK + +Some machines require that the beginnings and ends of segments +*in core* be on certain boundaries. For most machines, a page +boundary is sufficient. That is the default. When a larger +boundary is needed, define SEGMENT_MASK to a mask of +the bits that must be zero on such a boundary. + +* A_TEXT_OFFSET(HDR) + +Some machines count the a.out header as part of the size of the text +segment (a_text); they may actually load the header into core as the +first data in the text segment. Some have additional padding between +the header and the real text of the program that is counted in a_text. + +For these machines, define A_TEXT_OFFSET(HDR) to examine the header +structure HDR and return the number of bytes to add to `a_text' +before writing it (above and beyond the number of bytes of actual +program text). HDR's standard fields are already correct, except that +this adjustment to the `a_text' field has not yet been made; +thus, the amount of offset can depend on the data in the file. + +* A_TEXT_SEEK(HDR) + +If defined, this macro specifies the number of bytes to seek into the +a.out file before starting to write the text segment. + +* EXEC_MAGIC + +For machines using COFF, this macro, if defined, is a value stored +into the magic number field of the output file. + +* ADJUST_EXEC_HEADER + +This macro can be used to generate statements to adjust or +initialize nonstandard fields in the file header + +* ADDR_CORRECT(ADDR) + +Macro to correct an int which is the bit pattern of a pointer to a byte +into an int which is the number of a byte. + +This macro has a default definition which is usually right. +This default definition is a no-op on most machines (where a +pointer looks like an int) but not on all machines. + +*/ + +#ifndef emacs +#define PERROR(arg) perror (arg); return -1 +#else +#define IN_UNEXEC +#include <config.h> +#define PERROR(file) report_error (file, new) +#endif + +#ifndef CANNOT_DUMP /* all rest of file! */ + +#ifdef COFF_ENCAPSULATE +int need_coff_header = 1; +#include <coff-encap/a.out.encap.h> /* The location might be a poor assumption */ +#else +#ifdef MSDOS +#if __DJGPP__ > 1 +#include <fcntl.h> /* for O_RDONLY, O_RDWR */ +#include <crt0.h> /* for _crt0_startup_flags and its bits */ +static int save_djgpp_startup_flags; +#endif +#include <coff.h> +#define filehdr external_filehdr +#define scnhdr external_scnhdr +#define syment external_syment +#define auxent external_auxent +#define n_numaux e_numaux +#define n_type e_type +struct aouthdr +{ + unsigned short magic; /* type of file */ + unsigned short vstamp; /* version stamp */ + unsigned long tsize; /* text size in bytes, padded to FW bdry*/ + unsigned long dsize; /* initialized data " " */ + unsigned long bsize; /* uninitialized data " " */ + unsigned long entry; /* entry pt. */ + unsigned long text_start;/* base of text used for this file */ + unsigned long data_start;/* base of data used for this file */ +}; + + +#else /* not MSDOS */ +#include <a.out.h> +#endif /* not MSDOS */ +#endif + +/* Define getpagesize if the system does not. + Note that this may depend on symbols defined in a.out.h. */ +#include "getpagesize.h" + +#ifndef makedev /* Try to detect types.h already loaded */ +#include <sys/types.h> +#endif /* makedev */ +#include <stdio.h> +#include <sys/stat.h> +#include <errno.h> + +#include <sys/file.h> /* Must be after sys/types.h for USG and BSD4_1*/ + +#ifdef USG5 +#include <fcntl.h> +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif +#ifndef O_RDWR +#define O_RDWR 2 +#endif + + +extern char *start_of_text (); /* Start of text */ +extern char *start_of_data (); /* Start of initialized data */ + +#ifdef COFF +static long block_copy_start; /* Old executable start point */ +static struct filehdr f_hdr; /* File header */ +static struct aouthdr f_ohdr; /* Optional file header (a.out) */ +long bias; /* Bias to add for growth */ +long lnnoptr; /* Pointer to line-number info within file */ +#define SYMS_START block_copy_start + +static long text_scnptr; +static long data_scnptr; + +#else /* not COFF */ + +#ifdef HPUX +extern void *sbrk (); +#else +#if 0 +/* Some systems with __STDC__ compilers still declare this `char *' in some + header file, and our declaration conflicts. The return value is always + cast, so it should be harmless to leave it undefined. Hopefully + machines with different size pointers and ints declare sbrk in a header + file. */ +#ifdef __STDC__ +extern void *sbrk (); +#else +extern char *sbrk (); +#endif /* __STDC__ */ +#endif +#endif /* HPUX */ + +#define SYMS_START ((long) N_SYMOFF (ohdr)) + +/* Some machines override the structure name for an a.out header. */ +#ifndef EXEC_HDR_TYPE +#define EXEC_HDR_TYPE struct exec +#endif + +#ifdef HPUX +#ifdef HP9000S200_ID +#define MY_ID HP9000S200_ID +#else +#include <model.h> +#define MY_ID MYSYS +#endif /* no HP9000S200_ID */ +static MAGIC OLDMAGIC = {MY_ID, SHARE_MAGIC}; +static MAGIC NEWMAGIC = {MY_ID, DEMAND_MAGIC}; +#define N_TXTOFF(x) TEXT_OFFSET(x) +#define N_SYMOFF(x) LESYM_OFFSET(x) +static EXEC_HDR_TYPE hdr, ohdr; + +#else /* not HPUX */ + +#if defined (USG) && !defined (IBMAIX) && !defined (IRIS) && !defined (COFF_ENCAPSULATE) && !defined (LINUX) +static struct bhdr hdr, ohdr; +#define a_magic fmagic +#define a_text tsize +#define a_data dsize +#define a_bss bsize +#define a_syms ssize +#define a_trsize rtsize +#define a_drsize rdsize +#define a_entry entry +#define N_BADMAG(x) \ + (((x).fmagic)!=OMAGIC && ((x).fmagic)!=NMAGIC &&\ + ((x).fmagic)!=FMAGIC && ((x).fmagic)!=IMAGIC) +#define NEWMAGIC FMAGIC +#else /* IRIS or IBMAIX or not USG */ +static EXEC_HDR_TYPE hdr, ohdr; +#define NEWMAGIC ZMAGIC +#endif /* IRIS or IBMAIX not USG */ +#endif /* not HPUX */ + +static int unexec_text_start; +static int unexec_data_start; + +#ifdef COFF_ENCAPSULATE +/* coffheader is defined in the GNU a.out.encap.h file. */ +struct coffheader coffheader; +#endif + +#endif /* not COFF */ + +static int pagemask; + +/* Correct an int which is the bit pattern of a pointer to a byte + into an int which is the number of a byte. + This is a no-op on ordinary machines, but not on all. */ + +#ifndef ADDR_CORRECT /* Let m-*.h files override this definition */ +#define ADDR_CORRECT(x) ((char *)(x) - (char*)0) +#endif + +#ifdef emacs + +#include "lisp.h" + +static +report_error (file, fd) + char *file; + int fd; +{ + if (fd) + close (fd); + report_file_error ("Cannot unexec", Fcons (build_string (file), Qnil)); +} +#endif /* emacs */ + +#define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1 +#define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1 +#define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1 + +static +report_error_1 (fd, msg, a1, a2) + int fd; + char *msg; + int a1, a2; +{ + close (fd); +#ifdef emacs + error (msg, a1, a2); +#else + fprintf (stderr, msg, a1, a2); + fprintf (stderr, "\n"); +#endif +} + +static int make_hdr (); +static int copy_text_and_data (); +static int copy_sym (); +static void mark_x (); + +/* **************************************************************** + * unexec + * + * driving logic. + */ +unexec (new_name, a_name, data_start, bss_start, entry_address) + char *new_name, *a_name; + unsigned data_start, bss_start, entry_address; +{ + int new, a_out = -1; + + if (a_name && (a_out = open (a_name, O_RDONLY)) < 0) + { + PERROR (a_name); + } + if ((new = creat (new_name, 0666)) < 0) + { + PERROR (new_name); + } + + if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0 + || copy_text_and_data (new, a_out) < 0 + || copy_sym (new, a_out, a_name, new_name) < 0 +#ifdef COFF +#ifndef COFF_BSD_SYMBOLS + || adjust_lnnoptrs (new, a_out, new_name) < 0 +#endif +#endif + ) + { + close (new); + /* unlink (new_name); /* Failed, unlink new a.out */ + return -1; + } + + close (new); + if (a_out >= 0) + close (a_out); + mark_x (new_name); + return 0; +} + +/* **************************************************************** + * make_hdr + * + * Make the header in the new a.out from the header in core. + * Modify the text and data sizes. + */ +static int +make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) + int new, a_out; + unsigned data_start, bss_start, entry_address; + char *a_name; + char *new_name; +{ + int tem; +#ifdef COFF + auto struct scnhdr f_thdr; /* Text section header */ + auto struct scnhdr f_dhdr; /* Data section header */ + auto struct scnhdr f_bhdr; /* Bss section header */ + auto struct scnhdr scntemp; /* Temporary section header */ + register int scns; +#endif /* COFF */ +#ifdef USG_SHARED_LIBRARIES + extern unsigned int bss_end; +#else + unsigned int bss_end; +#endif + + pagemask = getpagesize () - 1; + + /* Adjust text/data boundary. */ +#ifdef NO_REMAP + data_start = (int) start_of_data (); +#else /* not NO_REMAP */ + if (!data_start) + data_start = (int) start_of_data (); +#endif /* not NO_REMAP */ + data_start = ADDR_CORRECT (data_start); + +#ifdef SEGMENT_MASK + data_start = data_start & ~SEGMENT_MASK; /* (Down) to segment boundary. */ +#else + data_start = data_start & ~pagemask; /* (Down) to page boundary. */ +#endif + + bss_end = ADDR_CORRECT (sbrk (0)) + pagemask; + bss_end &= ~ pagemask; + + /* Adjust data/bss boundary. */ + if (bss_start != 0) + { + bss_start = (ADDR_CORRECT (bss_start) + pagemask); + /* (Up) to page bdry. */ + bss_start &= ~ pagemask; + if (bss_start > bss_end) + { + ERROR1 ("unexec: Specified bss_start (%u) is past end of program", + bss_start); + } + } + else + bss_start = bss_end; + + if (data_start > bss_start) /* Can't have negative data size. */ + { + ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)", + data_start, bss_start); + } + +#ifdef COFF + /* Salvage as much info from the existing file as possible */ + if (a_out >= 0) + { + if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) + { + PERROR (a_name); + } + block_copy_start += sizeof (f_hdr); + if (f_hdr.f_opthdr > 0) + { + if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) + { + PERROR (a_name); + } + block_copy_start += sizeof (f_ohdr); + } + /* Loop through section headers, copying them in */ + lseek (a_out, sizeof (f_hdr) + f_hdr.f_opthdr, 0); + for (scns = f_hdr.f_nscns; scns > 0; scns--) { + if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) + { + PERROR (a_name); + } + if (scntemp.s_scnptr > 0L) + { + if (block_copy_start < scntemp.s_scnptr + scntemp.s_size) + block_copy_start = scntemp.s_scnptr + scntemp.s_size; + } + if (strcmp (scntemp.s_name, ".text") == 0) + { + f_thdr = scntemp; + } + else if (strcmp (scntemp.s_name, ".data") == 0) + { + f_dhdr = scntemp; + } + else if (strcmp (scntemp.s_name, ".bss") == 0) + { + f_bhdr = scntemp; + } + } + } + else + { + ERROR0 ("can't build a COFF file from scratch yet"); + } + + /* Now we alter the contents of all the f_*hdr variables + to correspond to what we want to dump. */ + +#ifdef USG_SHARED_LIBRARIES + + /* The amount of data we're adding to the file is distance from the + * end of the original .data space to the current end of the .data + * space. + */ + + bias = bss_start - (f_ohdr.data_start + f_dhdr.s_size); + +#endif + + f_hdr.f_flags |= (F_RELFLG | F_EXEC); +#ifdef TPIX + f_hdr.f_nscns = 3; +#endif +#ifdef EXEC_MAGIC + f_ohdr.magic = EXEC_MAGIC; +#endif +#ifndef NO_REMAP + f_ohdr.text_start = (long) start_of_text (); + f_ohdr.tsize = data_start - f_ohdr.text_start; + f_ohdr.data_start = data_start; +#endif /* NO_REMAP */ + f_ohdr.dsize = bss_start - f_ohdr.data_start; + f_ohdr.bsize = bss_end - bss_start; +#ifndef KEEP_OLD_TEXT_SCNPTR + /* On some machines, the old values are right. + ??? Maybe on all machines with NO_REMAP. */ + f_thdr.s_size = f_ohdr.tsize; + f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr); + f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr)); +#endif /* KEEP_OLD_TEXT_SCNPTR */ +#ifdef ADJUST_TEXT_SCNHDR_SIZE + /* On some machines, `text size' includes all headers. */ + f_thdr.s_size -= f_thdr.s_scnptr; +#endif /* ADJUST_TEST_SCNHDR_SIZE */ + lnnoptr = f_thdr.s_lnnoptr; +#ifdef SECTION_ALIGNMENT + /* Some systems require special alignment + of the sections in the file itself. */ + f_thdr.s_scnptr + = (f_thdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT; +#endif /* SECTION_ALIGNMENT */ +#ifdef TPIX + f_thdr.s_scnptr = 0xd0; +#endif + text_scnptr = f_thdr.s_scnptr; +#ifdef ADJUST_TEXTBASE + text_scnptr = sizeof (f_hdr) + sizeof (f_ohdr) + (f_hdr.f_nscns) * (sizeof (f_thdr)); +#endif +#ifndef KEEP_OLD_PADDR + f_dhdr.s_paddr = f_ohdr.data_start; +#endif /* KEEP_OLD_PADDR */ + f_dhdr.s_vaddr = f_ohdr.data_start; + f_dhdr.s_size = f_ohdr.dsize; + f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size; +#ifdef SECTION_ALIGNMENT + /* Some systems require special alignment + of the sections in the file itself. */ + f_dhdr.s_scnptr + = (f_dhdr.s_scnptr + SECTION_ALIGNMENT) & ~SECTION_ALIGNMENT; +#endif /* SECTION_ALIGNMENT */ +#ifdef DATA_SECTION_ALIGNMENT + /* Some systems require special alignment + of the data section only. */ + f_dhdr.s_scnptr + = (f_dhdr.s_scnptr + DATA_SECTION_ALIGNMENT) & ~DATA_SECTION_ALIGNMENT; +#endif /* DATA_SECTION_ALIGNMENT */ + data_scnptr = f_dhdr.s_scnptr; +#ifndef KEEP_OLD_PADDR + f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize; +#endif /* KEEP_OLD_PADDR */ + f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize; + f_bhdr.s_size = f_ohdr.bsize; + f_bhdr.s_scnptr = 0L; +#ifndef USG_SHARED_LIBRARIES + bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start; +#endif + + if (f_hdr.f_symptr > 0L) + { + f_hdr.f_symptr += bias; + } + + if (f_thdr.s_lnnoptr > 0L) + { + f_thdr.s_lnnoptr += bias; + } + +#ifdef ADJUST_EXEC_HEADER + ADJUST_EXEC_HEADER; +#endif /* ADJUST_EXEC_HEADER */ + + if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) + { + PERROR (new_name); + } + + if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) + { + PERROR (new_name); + } + +#ifndef USG_SHARED_LIBRARIES + + if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr)) + { + PERROR (new_name); + } + + if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr)) + { + PERROR (new_name); + } + + if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr)) + { + PERROR (new_name); + } + +#else /* USG_SHARED_LIBRARIES */ + + /* The purpose of this code is to write out the new file's section + * header table. + * + * Scan through the original file's sections. If the encountered + * section is one we know (.text, .data or .bss), write out the + * correct header. If it is a section we do not know (such as + * .lib), adjust the address of where the section data is in the + * file, and write out the header. + * + * If any section precedes .text or .data in the file, this code + * will not adjust the file pointer for that section correctly. + */ + + /* This used to use sizeof (f_ohdr) instead of .f_opthdr. + .f_opthdr is said to be right when there is no optional header. */ + lseek (a_out, sizeof (f_hdr) + f_hdr.f_opthdr, 0); + + for (scns = f_hdr.f_nscns; scns > 0; scns--) + { + if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) + PERROR (a_name); + + if (!strcmp (scntemp.s_name, f_thdr.s_name)) /* .text */ + { + if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr)) + PERROR (new_name); + } + else if (!strcmp (scntemp.s_name, f_dhdr.s_name)) /* .data */ + { + if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr)) + PERROR (new_name); + } + else if (!strcmp (scntemp.s_name, f_bhdr.s_name)) /* .bss */ + { + if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr)) + PERROR (new_name); + } + else + { + if (scntemp.s_scnptr) + scntemp.s_scnptr += bias; + if (write (new, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) + PERROR (new_name); + } + } +#endif /* USG_SHARED_LIBRARIES */ + + return (0); + +#else /* if not COFF */ + + /* Get symbol table info from header of a.out file if given one. */ + if (a_out >= 0) + { +#ifdef COFF_ENCAPSULATE + if (read (a_out, &coffheader, sizeof coffheader) != sizeof coffheader) + { + PERROR(a_name); + } + if (coffheader.f_magic != COFF_MAGIC) + { + ERROR1("%s doesn't have legal coff magic number\n", a_name); + } +#endif + if (read (a_out, &ohdr, sizeof hdr) != sizeof hdr) + { + PERROR (a_name); + } + + if (N_BADMAG (ohdr)) + { + ERROR1 ("invalid magic number in %s", a_name); + } + hdr = ohdr; + } + else + { +#ifdef COFF_ENCAPSULATE + /* We probably could without too much trouble. The code is in gld + * but I don't have that much time or incentive. + */ + ERROR0 ("can't build a COFF file from scratch yet"); +#else +#ifdef MSDOS /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */ + bzero ((void *)&hdr, sizeof hdr); +#else + bzero (&hdr, sizeof hdr); +#endif +#endif + } + + unexec_text_start = (long) start_of_text (); + unexec_data_start = data_start; + + /* Machine-dependent fixup for header, or maybe for unexec_text_start */ +#ifdef ADJUST_EXEC_HEADER + ADJUST_EXEC_HEADER; +#endif /* ADJUST_EXEC_HEADER */ + + hdr.a_trsize = 0; + hdr.a_drsize = 0; + if (entry_address != 0) + hdr.a_entry = entry_address; + + hdr.a_bss = bss_end - bss_start; + hdr.a_data = bss_start - data_start; +#ifdef NO_REMAP + hdr.a_text = ohdr.a_text; +#else /* not NO_REMAP */ + hdr.a_text = data_start - unexec_text_start; + +#ifdef A_TEXT_OFFSET + hdr.a_text += A_TEXT_OFFSET (ohdr); +#endif + +#endif /* not NO_REMAP */ + +#ifdef COFF_ENCAPSULATE + /* We are encapsulating BSD format within COFF format. */ + { + struct coffscn *tp, *dp, *bp; + tp = &coffheader.scns[0]; + dp = &coffheader.scns[1]; + bp = &coffheader.scns[2]; + tp->s_size = hdr.a_text + sizeof(struct exec); + dp->s_paddr = data_start; + dp->s_vaddr = data_start; + dp->s_size = hdr.a_data; + bp->s_paddr = dp->s_vaddr + dp->s_size; + bp->s_vaddr = bp->s_paddr; + bp->s_size = hdr.a_bss; + coffheader.tsize = tp->s_size; + coffheader.dsize = dp->s_size; + coffheader.bsize = bp->s_size; + coffheader.text_start = tp->s_vaddr; + coffheader.data_start = dp->s_vaddr; + } + if (write (new, &coffheader, sizeof coffheader) != sizeof coffheader) + { + PERROR(new_name); + } +#endif /* COFF_ENCAPSULATE */ + + if (write (new, &hdr, sizeof hdr) != sizeof hdr) + { + PERROR (new_name); + } + +#if 0 /* This #ifndef caused a bug on Linux when using QMAGIC. */ + /* This adjustment was done above only #ifndef NO_REMAP, + so only undo it now #ifndef NO_REMAP. */ + /* #ifndef NO_REMAP */ +#endif +#ifdef A_TEXT_OFFSET + hdr.a_text -= A_TEXT_OFFSET (ohdr); +#endif + + return 0; + +#endif /* not COFF */ +} + +/* **************************************************************** + * copy_text_and_data + * + * Copy the text and data segments from memory to the new a.out + */ +static int +copy_text_and_data (new, a_out) + int new, a_out; +{ + register char *end; + register char *ptr; + +#ifdef COFF + +#ifdef USG_SHARED_LIBRARIES + + int scns; + struct scnhdr scntemp; /* Temporary section header */ + + /* The purpose of this code is to write out the new file's section + * contents. + * + * Step through the section table. If we know the section (.text, + * .data) do the appropriate thing. Otherwise, if the section has + * no allocated space in the file (.bss), do nothing. Otherwise, + * the section has space allocated in the file, and is not a section + * we know. So just copy it. + */ + + lseek (a_out, sizeof (struct filehdr) + sizeof (struct aouthdr), 0); + + for (scns = f_hdr.f_nscns; scns > 0; scns--) + { + if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) + PERROR ("temacs"); + + if (!strcmp (scntemp.s_name, ".text")) + { + lseek (new, (long) text_scnptr, 0); + ptr = (char *) f_ohdr.text_start; + end = ptr + f_ohdr.tsize; + write_segment (new, ptr, end); + } + else if (!strcmp (scntemp.s_name, ".data")) + { + lseek (new, (long) data_scnptr, 0); + ptr = (char *) f_ohdr.data_start; + end = ptr + f_ohdr.dsize; + write_segment (new, ptr, end); + } + else if (!scntemp.s_scnptr) + ; /* do nothing - no data for this section */ + else + { + char page[BUFSIZ]; + int size, n; + long old_a_out_ptr = lseek (a_out, 0, 1); + + lseek (a_out, scntemp.s_scnptr, 0); + for (size = scntemp.s_size; size > 0; size -= sizeof (page)) + { + n = size > sizeof (page) ? sizeof (page) : size; + if (read (a_out, page, n) != n || write (new, page, n) != n) + PERROR ("emacs"); + } + lseek (a_out, old_a_out_ptr, 0); + } + } + +#else /* COFF, but not USG_SHARED_LIBRARIES */ + +#ifdef MSDOS +#if __DJGPP__ >= 2 + /* Dump the original table of exception handlers, not the one + where our exception hooks are registered. */ + __djgpp_exception_toggle (); + + /* Switch off startup flags that might have been set at runtime + and which might change the way that dumped Emacs works. */ + save_djgpp_startup_flags = _crt0_startup_flags; + _crt0_startup_flags &= ~(_CRT0_FLAG_NO_LFN | _CRT0_FLAG_NEARPTR); +#endif +#endif + + lseek (new, (long) text_scnptr, 0); + ptr = (char *) f_ohdr.text_start; +#ifdef HEADER_INCL_IN_TEXT + /* For Gould UTX/32, text starts after headers */ + ptr = (char *) (ptr + text_scnptr); +#endif /* HEADER_INCL_IN_TEXT */ + end = ptr + f_ohdr.tsize; + write_segment (new, ptr, end); + + lseek (new, (long) data_scnptr, 0); + ptr = (char *) f_ohdr.data_start; + end = ptr + f_ohdr.dsize; + write_segment (new, ptr, end); + +#ifdef MSDOS +#if __DJGPP__ >= 2 + /* Restore our exception hooks. */ + __djgpp_exception_toggle (); + + /* Restore the startup flags. */ + _crt0_startup_flags = save_djgpp_startup_flags; +#endif +#endif + +#endif /* USG_SHARED_LIBRARIES */ + +#else /* if not COFF */ + +/* Some machines count the header as part of the text segment. + That is to say, the header appears in core + just before the address that start_of_text returns. + For them, N_TXTOFF is the place where the header goes. + We must adjust the seek to the place after the header. + Note that at this point hdr.a_text does *not* count + the extra A_TEXT_OFFSET bytes, only the actual bytes of code. */ + +#ifdef A_TEXT_SEEK + lseek (new, (long) A_TEXT_SEEK (hdr), 0); +#else + lseek (new, (long) N_TXTOFF (hdr), 0); +#endif /* no A_TEXT_SEEK */ + +#ifdef RISCiX + + /* Acorn's RISC-iX has a wacky way of initialising the position of the heap. + * There is a little table in crt0.o that is filled at link time with + * the min and current brk positions, among other things. When start + * runs, it copies the table to where these parameters live during + * execution. This data is in text space, so it cannot be modified here + * before saving the executable, so the data is written manually. In + * addition, the table does not have a label, and the nearest accessible + * label (mcount) is not prefixed with a '_', thus making it inaccessible + * from within C programs. To overcome this, emacs's executable is passed + * through the command 'nm %s | fgrep mcount' into a pipe, and the + * resultant output is then used to find the address of 'mcount'. As far as + * is possible to determine, in RISC-iX releases prior to 1.2, the negative + * offset of the table from mcount is 0x2c, whereas from 1.2 onwards it is + * 0x30. bss_end has been rounded up to page boundary. This solution is + * based on suggestions made by Kevin Welton and Steve Hunt of Acorn, and + * avoids the need for a custom version of crt0.o for emacs which has its + * table in data space. + */ + + { + char command[1024]; + char errbuf[1024]; + char address_text[32]; + int proforma[4]; + FILE *pfile; + char *temp_ptr; + char c; + int mcount_address, mcount_offset, count; + extern char *_execname; + + + /* The use of _execname is incompatible with RISCiX 1.1 */ + sprintf (command, "nm %s | fgrep mcount", _execname); + + if ( (pfile = popen(command, "r")) == NULL) + { + sprintf (errbuf, "Could not open pipe"); + PERROR (errbuf); + } + + count=0; + while ( ((c=getc(pfile)) != EOF) && (c != ' ') && (count < 31)) + address_text[count++]=c; + address_text[count]=0; + + if ((count == 0) || pclose(pfile) != NULL) + { + sprintf (errbuf, "Failed to execute the command '%s'\n", command); + PERROR (errbuf); + } + + sscanf(address_text, "%x", &mcount_address); + ptr = (char *) unexec_text_start; + mcount_offset = (char *)mcount_address - ptr; + +#ifdef RISCiX_1_1 +#define EDATA_OFFSET 0x2c +#else +#define EDATA_OFFSET 0x30 +#endif + + end = ptr + mcount_offset - EDATA_OFFSET; + + write_segment (new, ptr, end); + + proforma[0] = bss_end; /* becomes _edata */ + proforma[1] = bss_end; /* becomes _end */ + proforma[2] = bss_end; /* becomes _minbrk */ + proforma[3] = bss_end; /* becomes _curbrk */ + + write (new, proforma, 16); + + temp_ptr = ptr; + ptr = end + 16; + end = temp_ptr + hdr.a_text; + + write_segment (new, ptr, end); + } + +#else /* !RISCiX */ + ptr = (char *) unexec_text_start; + end = ptr + hdr.a_text; + write_segment (new, ptr, end); +#endif /* RISCiX */ + + ptr = (char *) unexec_data_start; + end = ptr + hdr.a_data; +/* This lseek is certainly incorrect when A_TEXT_OFFSET + and I believe it is a no-op otherwise. + Let's see if its absence ever fails. */ +/* lseek (new, (long) N_TXTOFF (hdr) + hdr.a_text, 0); */ + write_segment (new, ptr, end); + +#endif /* not COFF */ + + return 0; +} + +write_segment (new, ptr, end) + int new; + register char *ptr, *end; +{ + register int i, nwrite, ret; + char buf[80]; + extern int errno; + /* This is the normal amount to write at once. + It is the size of block that NFS uses. */ + int writesize = 1 << 13; + int pagesize = getpagesize (); + char zeros[1 << 13]; + + bzero (zeros, sizeof (zeros)); + + for (i = 0; ptr < end;) + { + /* Distance to next multiple of writesize. */ + nwrite = (((int) ptr + writesize) & -writesize) - (int) ptr; + /* But not beyond specified end. */ + if (nwrite > end - ptr) nwrite = end - ptr; + ret = write (new, ptr, nwrite); + /* If write gets a page fault, it means we reached + a gap between the old text segment and the old data segment. + This gap has probably been remapped into part of the text segment. + So write zeros for it. */ + if (ret == -1 +#ifdef EFAULT + && errno == EFAULT +#endif + ) + { + /* Write only a page of zeros at once, + so that we we don't overshoot the start + of the valid memory in the old data segment. */ + if (nwrite > pagesize) + nwrite = pagesize; + write (new, zeros, nwrite); + } +#if 0 /* Now that we have can ask `write' to write more than a page, + it is legit for write do less than the whole amount specified. */ + else if (nwrite != ret) + { + sprintf (buf, + "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d", + ptr, new, nwrite, ret, errno); + PERROR (buf); + } +#endif + i += nwrite; + ptr += nwrite; + } +} + +/* **************************************************************** + * copy_sym + * + * Copy the relocation information and symbol table from the a.out to the new + */ +static int +copy_sym (new, a_out, a_name, new_name) + int new, a_out; + char *a_name, *new_name; +{ + char page[1024]; + int n; + + if (a_out < 0) + return 0; + +#ifdef COFF + if (SYMS_START == 0L) + return 0; +#endif /* COFF */ + +#ifdef COFF + if (lnnoptr) /* if there is line number info */ + lseek (a_out, lnnoptr, 0); /* start copying from there */ + else +#endif /* COFF */ + lseek (a_out, SYMS_START, 0); /* Position a.out to symtab. */ + + while ((n = read (a_out, page, sizeof page)) > 0) + { + if (write (new, page, n) != n) + { + PERROR (new_name); + } + } + if (n < 0) + { + PERROR (a_name); + } + return 0; +} + +/* **************************************************************** + * mark_x + * + * After successfully building the new a.out, mark it executable + */ +static void +mark_x (name) + char *name; +{ + struct stat sbuf; + int um; + int new = 0; /* for PERROR */ + + um = umask (777); + umask (um); + if (stat (name, &sbuf) == -1) + { + PERROR (name); + } + sbuf.st_mode |= 0111 & ~um; + if (chmod (name, sbuf.st_mode) == -1) + PERROR (name); +} + +#ifdef COFF +#ifndef COFF_BSD_SYMBOLS + +/* + * If the COFF file contains a symbol table and a line number section, + * then any auxiliary entries that have values for x_lnnoptr must + * be adjusted by the amount that the line number section has moved + * in the file (bias computed in make_hdr). The #@$%&* designers of + * the auxiliary entry structures used the absolute file offsets for + * the line number entry rather than an offset from the start of the + * line number section! + * + * When I figure out how to scan through the symbol table and pick out + * the auxiliary entries that need adjustment, this routine will + * be fixed. As it is now, all such entries are wrong and sdb + * will complain. Fred Fish, UniSoft Systems Inc. + */ + +/* This function is probably very slow. Instead of reopening the new + file for input and output it should copy from the old to the new + using the two descriptors already open (WRITEDESC and READDESC). + Instead of reading one small structure at a time it should use + a reasonable size buffer. But I don't have time to work on such + things, so I am installing it as submitted to me. -- RMS. */ + +adjust_lnnoptrs (writedesc, readdesc, new_name) + int writedesc; + int readdesc; + char *new_name; +{ + register int nsyms; + register int new; +#if defined (amdahl_uts) || defined (pfa) + SYMENT symentry; + AUXENT auxentry; +#else + struct syment symentry; + union auxent auxentry; +#endif + + if (!lnnoptr || !f_hdr.f_symptr) + return 0; + +#ifdef MSDOS + if ((new = writedesc) < 0) +#else + if ((new = open (new_name, O_RDWR)) < 0) +#endif + { + PERROR (new_name); + return -1; + } + + lseek (new, f_hdr.f_symptr, 0); + for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++) + { + read (new, &symentry, SYMESZ); + if (symentry.n_numaux) + { + read (new, &auxentry, AUXESZ); + nsyms++; + if (ISFCN (symentry.n_type) || symentry.n_type == 0x2400) + { + auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias; + lseek (new, -AUXESZ, 1); + write (new, &auxentry, AUXESZ); + } + } + } +#ifndef MSDOS + close (new); +#endif + return 0; +} + +#endif /* COFF_BSD_SYMBOLS */ + +#endif /* COFF */ + +#endif /* not CANNOT_DUMP */ diff --git a/unexelf.c b/unexelf.c new file mode 100644 index 0000000..60e82cc --- /dev/null +++ b/unexelf.c @@ -0,0 +1,908 @@ +/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992 + Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + + +/* + * unexec.c - Convert a running program into an a.out file. + * + * Author: Spencer W. Thomas + * Computer Science Dept. + * University of Utah + * Date: Tue Mar 2 1982 + * Modified heavily since then. + * + * Synopsis: + * unexec (new_name, a_name, data_start, bss_start, entry_address) + * char *new_name, *a_name; + * unsigned data_start, bss_start, entry_address; + * + * Takes a snapshot of the program and makes an a.out format file in the + * file named by the string argument new_name. + * If a_name is non-NULL, the symbol table will be taken from the given file. + * On some machines, an existing a_name file is required. + * + * The boundaries within the a.out file may be adjusted with the data_start + * and bss_start arguments. Either or both may be given as 0 for defaults. + * + * Data_start gives the boundary between the text segment and the data + * segment of the program. The text segment can contain shared, read-only + * program code and literal data, while the data segment is always unshared + * and unprotected. Data_start gives the lowest unprotected address. + * The value you specify may be rounded down to a suitable boundary + * as required by the machine you are using. + * + * Specifying zero for data_start means the boundary between text and data + * should not be the same as when the program was loaded. + * If NO_REMAP is defined, the argument data_start is ignored and the + * segment boundaries are never changed. + * + * Bss_start indicates how much of the data segment is to be saved in the + * a.out file and restored when the program is executed. It gives the lowest + * unsaved address, and is rounded up to a page boundary. The default when 0 + * is given assumes that the entire data segment is to be stored, including + * the previous data and bss as well as any additional storage allocated with + * break (2). + * + * The new file is set up to start at entry_address. + * + * If you make improvements I'd like to get them too. + * harpo!utah-cs!thomas, thomas@Utah-20 + * + */ + +/* Even more heavily modified by james@bigtex.cactus.org of Dell Computer Co. + * ELF support added. + * + * Basic theory: the data space of the running process needs to be + * dumped to the output file. Normally we would just enlarge the size + * of .data, scooting everything down. But we can't do that in ELF, + * because there is often something between the .data space and the + * .bss space. + * + * In the temacs dump below, notice that the Global Offset Table + * (.got) and the Dynamic link data (.dynamic) come between .data1 and + * .bss. It does not work to overlap .data with these fields. + * + * The solution is to create a new .data segment. This segment is + * filled with data from the current process. Since the contents of + * various sections refer to sections by index, the new .data segment + * is made the last in the table to avoid changing any existing index. + + * This is an example of how the section headers are changed. "Addr" + * is a process virtual address. "Offset" is a file offset. + +raid:/nfs/raid/src/dist-18.56/src> dump -h temacs + +temacs: + + **** SECTION HEADER TABLE **** +[No] Type Flags Addr Offset Size Name + Link Info Adralgn Entsize + +[1] 1 2 0x80480d4 0xd4 0x13 .interp + 0 0 0x1 0 + +[2] 5 2 0x80480e8 0xe8 0x388 .hash + 3 0 0x4 0x4 + +[3] 11 2 0x8048470 0x470 0x7f0 .dynsym + 4 1 0x4 0x10 + +[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr + 0 0 0x1 0 + +[5] 9 2 0x8049010 0x1010 0x338 .rel.plt + 3 7 0x4 0x8 + +[6] 1 6 0x8049348 0x1348 0x3 .init + 0 0 0x4 0 + +[7] 1 6 0x804934c 0x134c 0x680 .plt + 0 0 0x4 0x4 + +[8] 1 6 0x80499cc 0x19cc 0x3c56f .text + 0 0 0x4 0 + +[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini + 0 0 0x4 0 + +[10] 1 2 0x8085f40 0x3df40 0x69c .rodata + 0 0 0x4 0 + +[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1 + 0 0 0x4 0 + +[12] 1 3 0x8088330 0x3f330 0x20afc .data + 0 0 0x4 0 + +[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1 + 0 0 0x4 0 + +[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got + 0 0 0x4 0x4 + +[15] 6 3 0x80a9874 0x60874 0x80 .dynamic + 4 0 0x4 0x8 + +[16] 8 3 0x80a98f4 0x608f4 0x449c .bss + 0 0 0x4 0 + +[17] 2 0 0 0x608f4 0x9b90 .symtab + 18 371 0x4 0x10 + +[18] 3 0 0 0x6a484 0x8526 .strtab + 0 0 0x1 0 + +[19] 3 0 0 0x729aa 0x93 .shstrtab + 0 0 0x1 0 + +[20] 1 0 0 0x72a3d 0x68b7 .comment + 0 0 0x1 0 + +raid:/nfs/raid/src/dist-18.56/src> dump -h xemacs + +xemacs: + + **** SECTION HEADER TABLE **** +[No] Type Flags Addr Offset Size Name + Link Info Adralgn Entsize + +[1] 1 2 0x80480d4 0xd4 0x13 .interp + 0 0 0x1 0 + +[2] 5 2 0x80480e8 0xe8 0x388 .hash + 3 0 0x4 0x4 + +[3] 11 2 0x8048470 0x470 0x7f0 .dynsym + 4 1 0x4 0x10 + +[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr + 0 0 0x1 0 + +[5] 9 2 0x8049010 0x1010 0x338 .rel.plt + 3 7 0x4 0x8 + +[6] 1 6 0x8049348 0x1348 0x3 .init + 0 0 0x4 0 + +[7] 1 6 0x804934c 0x134c 0x680 .plt + 0 0 0x4 0x4 + +[8] 1 6 0x80499cc 0x19cc 0x3c56f .text + 0 0 0x4 0 + +[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini + 0 0 0x4 0 + +[10] 1 2 0x8085f40 0x3df40 0x69c .rodata + 0 0 0x4 0 + +[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1 + 0 0 0x4 0 + +[12] 1 3 0x8088330 0x3f330 0x20afc .data + 0 0 0x4 0 + +[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1 + 0 0 0x4 0 + +[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got + 0 0 0x4 0x4 + +[15] 6 3 0x80a9874 0x60874 0x80 .dynamic + 4 0 0x4 0x8 + +[16] 8 3 0x80c6800 0x7d800 0 .bss + 0 0 0x4 0 + +[17] 2 0 0 0x7d800 0x9b90 .symtab + 18 371 0x4 0x10 + +[18] 3 0 0 0x87390 0x8526 .strtab + 0 0 0x1 0 + +[19] 3 0 0 0x8f8b6 0x93 .shstrtab + 0 0 0x1 0 + +[20] 1 0 0 0x8f949 0x68b7 .comment + 0 0 0x1 0 + +[21] 1 3 0x80a98f4 0x608f4 0x1cf0c .data + 0 0 0x4 0 + + * This is an example of how the file header is changed. "Shoff" is + * the section header offset within the file. Since that table is + * after the new .data section, it is moved. "Shnum" is the number of + * sections, which we increment. + * + * "Phoff" is the file offset to the program header. "Phentsize" and + * "Shentsz" are the program and section header entries sizes respectively. + * These can be larger than the apparent struct sizes. + +raid:/nfs/raid/src/dist-18.56/src> dump -f temacs + +temacs: + + **** ELF HEADER **** +Class Data Type Machine Version +Entry Phoff Shoff Flags Ehsize +Phentsize Phnum Shentsz Shnum Shstrndx + +1 1 2 3 1 +0x80499cc 0x34 0x792f4 0 0x34 +0x20 5 0x28 21 19 + +raid:/nfs/raid/src/dist-18.56/src> dump -f xemacs + +xemacs: + + **** ELF HEADER **** +Class Data Type Machine Version +Entry Phoff Shoff Flags Ehsize +Phentsize Phnum Shentsz Shnum Shstrndx + +1 1 2 3 1 +0x80499cc 0x34 0x96200 0 0x34 +0x20 5 0x28 22 19 + + * These are the program headers. "Offset" is the file offset to the + * segment. "Vaddr" is the memory load address. "Filesz" is the + * segment size as it appears in the file, and "Memsz" is the size in + * memory. Below, the third segment is the code and the fourth is the + * data: the difference between Filesz and Memsz is .bss + +raid:/nfs/raid/src/dist-18.56/src> dump -o temacs + +temacs: + ***** PROGRAM EXECUTION HEADER ***** +Type Offset Vaddr Paddr +Filesz Memsz Flags Align + +6 0x34 0x8048034 0 +0xa0 0xa0 5 0 + +3 0xd4 0 0 +0x13 0 4 0 + +1 0x34 0x8048034 0 +0x3f2f9 0x3f2f9 5 0x1000 + +1 0x3f330 0x8088330 0 +0x215c4 0x25a60 7 0x1000 + +2 0x60874 0x80a9874 0 +0x80 0 7 0 + +raid:/nfs/raid/src/dist-18.56/src> dump -o xemacs + +xemacs: + ***** PROGRAM EXECUTION HEADER ***** +Type Offset Vaddr Paddr +Filesz Memsz Flags Align + +6 0x34 0x8048034 0 +0xa0 0xa0 5 0 + +3 0xd4 0 0 +0x13 0 4 0 + +1 0x34 0x8048034 0 +0x3f2f9 0x3f2f9 5 0x1000 + +1 0x3f330 0x8088330 0 +0x3e4d0 0x3e4d0 7 0x1000 + +2 0x60874 0x80a9874 0 +0x80 0 7 0 + + + */ + +/* Modified by wtien@urbana.mcd.mot.com of Motorola Inc. + * + * The above mechanism does not work if the unexeced ELF file is being + * re-layout by other applications (such as `strip'). All the applications + * that re-layout the internal of ELF will layout all sections in ascending + * order of their file offsets. After the re-layout, the data2 section will + * still be the LAST section in the section header vector, but its file offset + * is now being pushed far away down, and causes part of it not to be mapped + * in (ie. not covered by the load segment entry in PHDR vector), therefore + * causes the new binary to fail. + * + * The solution is to modify the unexec algorithm to insert the new data2 + * section header right before the new bss section header, so their file + * offsets will be in the ascending order. Since some of the section's (all + * sections AFTER the bss section) indexes are now changed, we also need to + * modify some fields to make them point to the right sections. This is done + * by macro PATCH_INDEX. All the fields that need to be patched are: + * + * 1. ELF header e_shstrndx field. + * 2. section header sh_link and sh_info field. + * 3. symbol table entry st_shndx field. + * + * The above example now should look like: + + **** SECTION HEADER TABLE **** +[No] Type Flags Addr Offset Size Name + Link Info Adralgn Entsize + +[1] 1 2 0x80480d4 0xd4 0x13 .interp + 0 0 0x1 0 + +[2] 5 2 0x80480e8 0xe8 0x388 .hash + 3 0 0x4 0x4 + +[3] 11 2 0x8048470 0x470 0x7f0 .dynsym + 4 1 0x4 0x10 + +[4] 3 2 0x8048c60 0xc60 0x3ad .dynstr + 0 0 0x1 0 + +[5] 9 2 0x8049010 0x1010 0x338 .rel.plt + 3 7 0x4 0x8 + +[6] 1 6 0x8049348 0x1348 0x3 .init + 0 0 0x4 0 + +[7] 1 6 0x804934c 0x134c 0x680 .plt + 0 0 0x4 0x4 + +[8] 1 6 0x80499cc 0x19cc 0x3c56f .text + 0 0 0x4 0 + +[9] 1 6 0x8085f3c 0x3df3c 0x3 .fini + 0 0 0x4 0 + +[10] 1 2 0x8085f40 0x3df40 0x69c .rodata + 0 0 0x4 0 + +[11] 1 2 0x80865dc 0x3e5dc 0xd51 .rodata1 + 0 0 0x4 0 + +[12] 1 3 0x8088330 0x3f330 0x20afc .data + 0 0 0x4 0 + +[13] 1 3 0x80a8e2c 0x5fe2c 0x89d .data1 + 0 0 0x4 0 + +[14] 1 3 0x80a96cc 0x606cc 0x1a8 .got + 0 0 0x4 0x4 + +[15] 6 3 0x80a9874 0x60874 0x80 .dynamic + 4 0 0x4 0x8 + +[16] 1 3 0x80a98f4 0x608f4 0x1cf0c .data + 0 0 0x4 0 + +[17] 8 3 0x80c6800 0x7d800 0 .bss + 0 0 0x4 0 + +[18] 2 0 0 0x7d800 0x9b90 .symtab + 19 371 0x4 0x10 + +[19] 3 0 0 0x87390 0x8526 .strtab + 0 0 0x1 0 + +[20] 3 0 0 0x8f8b6 0x93 .shstrtab + 0 0 0x1 0 + +[21] 1 0 0 0x8f949 0x68b7 .comment + 0 0 0x1 0 + + */ + +#include <sys/types.h> +#include <stdio.h> +#include <sys/stat.h> +#include <memory.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <elf.h> +#include <sys/mman.h> + +#ifndef emacs +#define fatal(a, b, c) fprintf (stderr, a, b, c), exit (1) +#else +#include <config.h> +extern void fatal (char *, ...); +#endif + +#ifndef ELF_BSS_SECTION_NAME +#define ELF_BSS_SECTION_NAME ".bss" +#endif + +/* Get the address of a particular section or program header entry, + * accounting for the size of the entries. + */ +/* + On PPC Reference Platform running Solaris 2.5.1 + the plt section is also of type NOBI like the bss section. + (not really stored) and therefore sections after the bss + section start at the plt offset. The plt section is always + the one just before the bss section. + Thus, we modify the test from + if (NEW_SECTION_H (nn).sh_offset >= new_data2_offset) + to + if (NEW_SECTION_H (nn).sh_offset >= + OLD_SECTION_H (old_bss_index-1).sh_offset) + This is just a hack. We should put the new data section + before the .plt section. + And we should not have this routine at all but use + the libelf library to read the old file and create the new + file. + The changed code is minimal and depends on prep set in m/prep.h + Erik Deumens + Quantum Theory Project + University of Florida + deumens@qtp.ufl.edu + Apr 23, 1996 + */ + +#define OLD_SECTION_H(n) \ + (*(Elf32_Shdr *) ((byte *) old_section_h + old_file_h->e_shentsize * (n))) +#define NEW_SECTION_H(n) \ + (*(Elf32_Shdr *) ((byte *) new_section_h + new_file_h->e_shentsize * (n))) +#define OLD_PROGRAM_H(n) \ + (*(Elf32_Phdr *) ((byte *) old_program_h + old_file_h->e_phentsize * (n))) +#define NEW_PROGRAM_H(n) \ + (*(Elf32_Phdr *) ((byte *) new_program_h + new_file_h->e_phentsize * (n))) + +#define PATCH_INDEX(n) \ + do { \ + if ((int) (n) >= old_bss_index) \ + (n)++; } while (0) +typedef unsigned char byte; + +/* Round X up to a multiple of Y. */ + +int +round_up (x, y) + int x, y; +{ + int rem = x % y; + if (rem == 0) + return x; + return x - rem + y; +} + +/* **************************************************************** + * unexec + * + * driving logic. + * + * In ELF, this works by replacing the old .bss section with a new + * .data section, and inserting an empty .bss immediately afterwards. + * + */ +void +unexec (new_name, old_name, data_start, bss_start, entry_address) + char *new_name, *old_name; + unsigned data_start, bss_start, entry_address; +{ + int new_file, old_file, new_file_size; + + /* Pointers to the base of the image of the two files. */ + caddr_t old_base, new_base; + + /* Pointers to the file, program and section headers for the old and new + * files. + */ + Elf32_Ehdr *old_file_h, *new_file_h; + Elf32_Phdr *old_program_h, *new_program_h; + Elf32_Shdr *old_section_h, *new_section_h; + + /* Point to the section name table in the old file */ + char *old_section_names; + + Elf32_Addr old_bss_addr, new_bss_addr; + Elf32_Word old_bss_size, new_data2_size; + Elf32_Off new_data2_offset; + Elf32_Addr new_data2_addr; + + int n, nn, old_bss_index, old_data_index, new_data2_index; + struct stat stat_buf; + + /* Open the old file & map it into the address space. */ + + old_file = open (old_name, O_RDONLY); + + if (old_file < 0) + fatal ("Can't open %s for reading: errno %d\n", old_name, errno); + + if (fstat (old_file, &stat_buf) == -1) + fatal ("Can't fstat (%s): errno %d\n", old_name, errno); + + old_base = mmap (0, stat_buf.st_size, PROT_READ, MAP_SHARED, old_file, 0); + + if (old_base == (caddr_t) -1) + fatal ("Can't mmap (%s): errno %d\n", old_name, errno); + +#ifdef DEBUG + fprintf (stderr, "mmap (%s, %x) -> %x\n", old_name, stat_buf.st_size, + old_base); +#endif + + /* Get pointers to headers & section names */ + + old_file_h = (Elf32_Ehdr *) old_base; + old_program_h = (Elf32_Phdr *) ((byte *) old_base + old_file_h->e_phoff); + old_section_h = (Elf32_Shdr *) ((byte *) old_base + old_file_h->e_shoff); + old_section_names = (char *) old_base + + OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset; + + /* Find the old .bss section. Figure out parameters of the new + * data2 and bss sections. + */ + + for (old_bss_index = 1; old_bss_index < (int) old_file_h->e_shnum; + old_bss_index++) + { +#ifdef DEBUG + fprintf (stderr, "Looking for .bss - found %s\n", + old_section_names + OLD_SECTION_H (old_bss_index).sh_name); +#endif + if (!strcmp (old_section_names + OLD_SECTION_H (old_bss_index).sh_name, + ELF_BSS_SECTION_NAME)) + break; + } + if (old_bss_index == old_file_h->e_shnum) + fatal ("Can't find .bss in %s.\n", old_name, 0); + + old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr; + old_bss_size = OLD_SECTION_H (old_bss_index).sh_size; +#if defined(emacs) || !defined(DEBUG) + new_bss_addr = (Elf32_Addr) sbrk (0); +#else + new_bss_addr = old_bss_addr + old_bss_size + 0x1234; +#endif + new_data2_addr = old_bss_addr; + new_data2_size = new_bss_addr - old_bss_addr; + new_data2_offset = OLD_SECTION_H (old_bss_index).sh_offset; + +#ifdef DEBUG + fprintf (stderr, "old_bss_index %d\n", old_bss_index); + fprintf (stderr, "old_bss_addr %x\n", old_bss_addr); + fprintf (stderr, "old_bss_size %x\n", old_bss_size); + fprintf (stderr, "new_bss_addr %x\n", new_bss_addr); + fprintf (stderr, "new_data2_addr %x\n", new_data2_addr); + fprintf (stderr, "new_data2_size %x\n", new_data2_size); + fprintf (stderr, "new_data2_offset %x\n", new_data2_offset); +#endif + + if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size) + fatal (".bss shrank when undumping???\n", 0, 0); + + /* Set the output file to the right size and mmap it. Set + * pointers to various interesting objects. stat_buf still has + * old_file data. + */ + + new_file = open (new_name, O_RDWR | O_CREAT, 0666); + if (new_file < 0) + fatal ("Can't creat (%s): errno %d\n", new_name, errno); + + new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_data2_size; + + if (ftruncate (new_file, new_file_size)) + fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno); + +#ifdef UNEXEC_USE_MAP_PRIVATE + new_base = mmap (0, new_file_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, + new_file, 0); +#else + new_base = mmap (0, new_file_size, PROT_READ | PROT_WRITE, MAP_SHARED, + new_file, 0); +#endif + + if (new_base == (caddr_t) -1) + fatal ("Can't mmap (%s): errno %d\n", new_name, errno); + + new_file_h = (Elf32_Ehdr *) new_base; + new_program_h = (Elf32_Phdr *) ((byte *) new_base + old_file_h->e_phoff); + new_section_h = (Elf32_Shdr *) + ((byte *) new_base + old_file_h->e_shoff + new_data2_size); + + /* Make our new file, program and section headers as copies of the + * originals. + */ + + memcpy (new_file_h, old_file_h, old_file_h->e_ehsize); + memcpy (new_program_h, old_program_h, + old_file_h->e_phnum * old_file_h->e_phentsize); + + /* Modify the e_shstrndx if necessary. */ + PATCH_INDEX (new_file_h->e_shstrndx); + + /* Fix up file header. We'll add one section. Section header is + * further away now. + */ + + new_file_h->e_shoff += new_data2_size; + new_file_h->e_shnum += 1; + +#ifdef DEBUG + fprintf (stderr, "Old section offset %x\n", old_file_h->e_shoff); + fprintf (stderr, "Old section count %d\n", old_file_h->e_shnum); + fprintf (stderr, "New section offset %x\n", new_file_h->e_shoff); + fprintf (stderr, "New section count %d\n", new_file_h->e_shnum); +#endif + + /* Fix up a new program header. Extend the writable data segment so + * that the bss area is covered too. Find that segment by looking + * for a segment that ends just before the .bss area. Make sure + * that no segments are above the new .data2. Put a loop at the end + * to adjust the offset and address of any segment that is above + * data2, just in case we decide to allow this later. + */ + + for (n = new_file_h->e_phnum - 1; n >= 0; n--) + { + /* Compute maximum of all requirements for alignment of section. */ + int alignment = (NEW_PROGRAM_H (n)).p_align; + if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment) + alignment = OLD_SECTION_H (old_bss_index).sh_addralign; + + if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz > old_bss_addr) + fatal ("Program segment above .bss in %s\n", old_name, 0); + + if (NEW_PROGRAM_H (n).p_type == PT_LOAD + && (round_up ((NEW_PROGRAM_H (n)).p_vaddr + + (NEW_PROGRAM_H (n)).p_filesz, + alignment) + == round_up (old_bss_addr, alignment))) + break; + } + if (n < 0) + fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0); + + NEW_PROGRAM_H (n).p_filesz += new_data2_size; + NEW_PROGRAM_H (n).p_memsz = NEW_PROGRAM_H (n).p_filesz; + +#if 0 /* Maybe allow section after data2 - does this ever happen? */ + for (n = new_file_h->e_phnum - 1; n >= 0; n--) + { + if (NEW_PROGRAM_H (n).p_vaddr + && NEW_PROGRAM_H (n).p_vaddr >= new_data2_addr) + NEW_PROGRAM_H (n).p_vaddr += new_data2_size - old_bss_size; + + if (NEW_PROGRAM_H (n).p_offset >= new_data2_offset) + NEW_PROGRAM_H (n).p_offset += new_data2_size; + } +#endif + + /* Fix up section headers based on new .data2 section. Any section + * whose offset or virtual address is after the new .data2 section + * gets its value adjusted. .bss size becomes zero and new address + * is set. data2 section header gets added by copying the existing + * .data header and modifying the offset, address and size. + */ + for (old_data_index = 1; old_data_index < (int) old_file_h->e_shnum; + old_data_index++) + if (!strcmp (old_section_names + OLD_SECTION_H (old_data_index).sh_name, + ".data")) + break; + if (old_data_index == old_file_h->e_shnum) + fatal ("Can't find .data in %s.\n", old_name, 0); + + /* Walk through all section headers, insert the new data2 section right + before the new bss section. */ + for (n = 1, nn = 1; n < (int) old_file_h->e_shnum; n++, nn++) + { + caddr_t src; + /* If it is bss section, insert the new data2 section before it. */ + if (n == old_bss_index) + { + /* Steal the data section header for this data2 section. */ + memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (old_data_index), + new_file_h->e_shentsize); + + NEW_SECTION_H (nn).sh_addr = new_data2_addr; + NEW_SECTION_H (nn).sh_offset = new_data2_offset; + NEW_SECTION_H (nn).sh_size = new_data2_size; + /* Use the bss section's alignment. This will assure that the + new data2 section always be placed in the same spot as the old + bss section by any other application. */ + NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (n).sh_addralign; + + /* Now copy over what we have in the memory now. */ + memcpy (NEW_SECTION_H (nn).sh_offset + new_base, + (caddr_t) OLD_SECTION_H (n).sh_addr, + new_data2_size); + nn++; + } + + memcpy (&NEW_SECTION_H (nn), &OLD_SECTION_H (n), + old_file_h->e_shentsize); + + /* The new bss section's size is zero, and its file offset and virtual + address should be off by NEW_DATA2_SIZE. */ + if (n == old_bss_index) + { + /* NN should be `old_bss_index + 1' at this point. */ + NEW_SECTION_H (nn).sh_offset += new_data2_size; + NEW_SECTION_H (nn).sh_addr += new_data2_size; + /* Let the new bss section address alignment be the same as the + section address alignment followed the old bss section, so + this section will be placed in exactly the same place. */ + NEW_SECTION_H (nn).sh_addralign = OLD_SECTION_H (nn).sh_addralign; + NEW_SECTION_H (nn).sh_size = 0; + } + else + { + /* Any section that was original placed AFTER the bss + section should now be off by NEW_DATA2_SIZE. */ +#ifdef SOLARIS_POWERPC + /* On PPC Reference Platform running Solaris 2.5.1 + the plt section is also of type NOBI like the bss section. + (not really stored) and therefore sections after the bss + section start at the plt offset. The plt section is always + the one just before the bss section. + It would be better to put the new data section before + the .plt section, or use libelf instead. + Erik Deumens, deumens@qtp.ufl.edu. */ + if (NEW_SECTION_H (nn).sh_offset + >= OLD_SECTION_H (old_bss_index-1).sh_offset) + NEW_SECTION_H (nn).sh_offset += new_data2_size; +#else + if (round_up (NEW_SECTION_H (nn).sh_offset, + OLD_SECTION_H (old_bss_index).sh_addralign) + >= new_data2_offset) + NEW_SECTION_H (nn).sh_offset += new_data2_size; +#endif + /* Any section that was originally placed after the section + header table should now be off by the size of one section + header table entry. */ + if (NEW_SECTION_H (nn).sh_offset > new_file_h->e_shoff) + NEW_SECTION_H (nn).sh_offset += new_file_h->e_shentsize; + } + + /* If any section hdr refers to the section after the new .data + section, make it refer to next one because we have inserted + a new section in between. */ + + PATCH_INDEX (NEW_SECTION_H (nn).sh_link); + /* For symbol tables, info is a symbol table index, + so don't change it. */ + if (NEW_SECTION_H (nn).sh_type != SHT_SYMTAB + && NEW_SECTION_H (nn).sh_type != SHT_DYNSYM) + PATCH_INDEX (NEW_SECTION_H (nn).sh_info); + + /* Now, start to copy the content of sections. */ + if (NEW_SECTION_H (nn).sh_type == SHT_NULL + || NEW_SECTION_H (nn).sh_type == SHT_NOBITS) + continue; + + /* Write out the sections. .data and .data1 (and data2, called + ".data" in the strings table) get copied from the current process + instead of the old file. */ + if (!strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data") + || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name), + ".data1")) + src = (caddr_t) OLD_SECTION_H (n).sh_addr; + else + src = old_base + OLD_SECTION_H (n).sh_offset; + + memcpy (NEW_SECTION_H (nn).sh_offset + new_base, src, + NEW_SECTION_H (nn).sh_size); + + /* If it is the symbol table, its st_shndx field needs to be patched. */ + if (NEW_SECTION_H (nn).sh_type == SHT_SYMTAB + || NEW_SECTION_H (nn).sh_type == SHT_DYNSYM) + { + Elf32_Shdr *spt = &NEW_SECTION_H (nn); + unsigned int num = spt->sh_size / spt->sh_entsize; + Elf32_Sym * sym = (Elf32_Sym *) (NEW_SECTION_H (nn).sh_offset + + new_base); + for (; num--; sym++) + { + if ((sym->st_shndx == SHN_UNDEF) + || (sym->st_shndx == SHN_ABS) + || (sym->st_shndx == SHN_COMMON)) + continue; + + PATCH_INDEX (sym->st_shndx); + } + } + } + + /* Update the symbol values of _edata and _end. */ + for (n = new_file_h->e_shnum - 1; n; n--) + { + byte *symnames; + Elf32_Sym *symp, *symendp; + + if (NEW_SECTION_H (n).sh_type != SHT_DYNSYM + && NEW_SECTION_H (n).sh_type != SHT_SYMTAB) + continue; + + symnames = ((byte *) new_base + + NEW_SECTION_H (NEW_SECTION_H (n).sh_link).sh_offset); + symp = (Elf32_Sym *) (NEW_SECTION_H (n).sh_offset + new_base); + symendp = (Elf32_Sym *) ((byte *)symp + NEW_SECTION_H (n).sh_size); + + for (; symp < symendp; symp ++) + if (strcmp ((char *) (symnames + symp->st_name), "_end") == 0 + || strcmp ((char *) (symnames + symp->st_name), "_edata") == 0) + memcpy (&symp->st_value, &new_bss_addr, sizeof (new_bss_addr)); + } + + /* This loop seeks out relocation sections for the data section, so + that it can undo relocations performed by the runtime linker. */ + for (n = new_file_h->e_shnum - 1; n; n--) + { + Elf32_Shdr section = NEW_SECTION_H (n); + switch (section.sh_type) { + default: + break; + case SHT_REL: + case SHT_RELA: + /* This code handles two different size structs, but there should + be no harm in that provided that r_offset is always the first + member. */ + nn = section.sh_info; + if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".data") + || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name), + ".data1")) + { + Elf32_Addr offset = NEW_SECTION_H (nn).sh_addr - + NEW_SECTION_H (nn).sh_offset; + caddr_t reloc = old_base + section.sh_offset, end; + for (end = reloc + section.sh_size; reloc < end; + reloc += section.sh_entsize) + { + Elf32_Addr addr = ((Elf32_Rel *) reloc)->r_offset - offset; + memcpy (new_base + addr, old_base + addr, 4); + } + } + break; + } + } + +#ifdef UNEXEC_USE_MAP_PRIVATE + if (lseek (new_file, 0, SEEK_SET) == -1) + fatal ("Can't rewind (%s): errno %d\n", new_name, errno); + + if (write (new_file, new_base, new_file_size) != new_file_size) + fatal ("Can't write (%s): errno %d\n", new_name, errno); +#endif + + /* Close the files and make the new file executable. */ + + if (close (old_file)) + fatal ("Can't close (%s): errno %d\n", old_name, errno); + + if (close (new_file)) + fatal ("Can't close (%s): errno %d\n", new_name, errno); + + if (stat (new_name, &stat_buf) == -1) + fatal ("Can't stat (%s): errno %d\n", new_name, errno); + + n = umask (777); + umask (n); + stat_buf.st_mode |= 0111 & ~n; + if (chmod (new_name, stat_buf.st_mode) == -1) + fatal ("Can't chmod (%s): errno %d\n", new_name, errno); +} @@ -0,0 +1,2000 @@ +/* Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "unif.c" Uniform vectors and arrays + Authors: Aubrey Jaffer & Radey Shouman. + +The set of uniform vector types is: + Vector of: Called: +char string +boolean bvect +signed int ivect +unsigned int uvect +float fvect +double dvect +complex double cvect +*/ + +#include "scm.h" + +#ifndef STDC_HEADERS + int ungetc P((int c, FILE *stream)); + sizet fwrite (); +#endif + +long tc16_array = 0; + +char s_resizuve[] = "vector-set-length!"; +SCM resizuve(vect, len) + SCM vect, len; +{ + long l = INUM(len); + sizet siz, sz; + ASRTGO(NIMP(vect), badarg1); + switch TYP7(vect) { + default: badarg1: wta(vect, (char *)ARG1, s_resizuve); + case tc7_string: + ASRTGO(vect != nullstr, badarg1); + sz = sizeof(char); + l++; + break; + case tc7_vector: + ASRTGO(vect != nullvect, badarg1); + sz = sizeof(SCM); + break; +#ifdef ARRAYS + case tc7_bvect: + l = (l+LONG_BIT-1)/LONG_BIT; + case tc7_uvect: + case tc7_ivect: + sz = sizeof(long); + break; +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: + sz = sizeof(float); + break; +# endif + case tc7_dvect: + sz = sizeof(double); + break; + case tc7_cvect: + sz = 2*sizeof(double); + break; +# endif +#endif + } + ASSERT(INUMP(len), len, ARG2, s_resizuve); + if (!l) l = 1L; + siz = l * sz; + if (siz != l * sz) wta(MAKINUM(l * sz), (char *) NALLOC, s_resizuve); + DEFER_INTS; + SETCHARS(vect, (char *)must_realloc((char *)CHARS(vect), + (long)LENGTH(vect)*sz, + (long)siz, s_resizuve)); + if VECTORP(vect) { + sz = LENGTH(vect); + while(l > sz) VELTS(vect)[--l] = UNSPECIFIED; + } + else if STRINGP(vect) CHARS(vect)[l-1] = 0; + SETLENGTH(vect, INUM(len), TYP7(vect)); + ALLOW_INTS; + return vect; +} + +#ifdef ARRAYS + +# ifdef FLOATS +# ifdef SINGLES +SCM makflo (x) + float x; +{ + SCM z; + if (x==0.0) return flo0; + NEWCELL(z); + DEFER_INTS; + CAR(z) = tc_flo; + FLO(z) = x; + ALLOW_INTS; + return z; +} +# endif +# endif + +SCM make_uve(k, prot) + long k; + SCM prot; +{ + SCM v; + long i, type; + if (BOOL_T==prot) { + i = sizeof(long)*((k+LONG_BIT-1)/LONG_BIT); + type = tc7_bvect; + } + else if ICHRP(prot) { + i = sizeof(char)*k; + type = tc7_string; + } + else if INUMP(prot) { + i = sizeof(long)*k; + if (INUM(prot)>0) type = tc7_uvect; + else type = tc7_ivect; + } + else +# ifdef FLOATS + if (IMP(prot) || !INEXP(prot)) +# endif + /* Huge non-unif vectors are NOT supported. */ + return make_vector(MAKINUM(k), UNDEFINED); /* no special vector */ +# ifdef FLOATS +# ifdef SINGLES + else if SINGP(prot) { +# ifdef CDR_DOUBLES + double x = FLO(prot); + float fx = x; + if (x != fx) { + i = sizeof(double)*k; + type = tc7_dvect; + } + else +# endif + { + i = sizeof(float)*k; + type = tc7_fvect; + } + } +# endif + else if (CPLXP(prot)) { + i = 2*sizeof(double)*k; + type = tc7_cvect; + } + else { + i = sizeof(double)*k; + type = tc7_dvect; + } +# endif + + NEWCELL(v); + DEFER_INTS; + SETCHARS(v, must_malloc((i ? i : 1L), s_vector)); + SETLENGTH(v, (k<LENGTH_MAX ? k : LENGTH_MAX), type); + ALLOW_INTS; + return v; +} + +static char s_uve_len[] = "uniform-vector-length"; +SCM uve_len(v) + SCM v; +{ + ASRTGO(NIMP(v), badarg1); + switch TYP7(v) { + default: badarg1: wta(v, (char *)ARG1, s_uve_len); + case tc7_bvect: + case tc7_string: + case tc7_uvect: + case tc7_ivect: + case tc7_fvect: + case tc7_dvect: + case tc7_cvect: + case tc7_vector: + return MAKINUM(LENGTH(v)); + } +} + +SCM arrayp(v, prot) + SCM v, prot; +{ + int nprot = UNBNDP(prot), enclosed = 0; + if IMP(v) return BOOL_F; + loop: + switch TYP7(v) { + case tc7_smob: if (!ARRAYP(v)) return BOOL_F; + if (nprot) return BOOL_T; + if (enclosed++) return BOOL_F; + v = ARRAY_V(v); + goto loop; + case tc7_bvect: return nprot || BOOL_T==prot ? BOOL_T : BOOL_F; + case tc7_string: return nprot || ICHRP(prot) ? BOOL_T : BOOL_F; + case tc7_uvect: + return nprot || (INUMP(prot) && INUM(prot)>0) ? BOOL_T : BOOL_F; + case tc7_ivect: + return nprot || (INUMP(prot) && INUM(prot)<=0) ? BOOL_T : BOOL_F; +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: return nprot || (NIMP(prot) && SINGP(prot)) ? BOOL_T : BOOL_F; +# endif + case tc7_dvect: return nprot || (NIMP(prot) && REALP(prot)) ? BOOL_T : BOOL_F; + case tc7_cvect: return nprot || (NIMP(prot) && CPLXP(prot)) ? BOOL_T : BOOL_F; +# endif + case tc7_vector: return nprot || NULLP(prot) ? BOOL_T : BOOL_F; + default:; + } + return BOOL_F; +} +SCM array_rank(ra) + SCM ra; +{ + if IMP(ra) return INUM0; + switch (TYP7(ra)) { + default: return INUM0; + case tc7_string: case tc7_vector: case tc7_bvect: + case tc7_uvect: case tc7_ivect: case tc7_fvect: + case tc7_cvect: case tc7_dvect: + return MAKINUM(1L); + case tc7_smob: + if ARRAYP(ra) return MAKINUM(ARRAY_NDIM(ra)); + return INUM0; + } +} +static char s_array_dims[] = "array-dimensions"; +SCM array_dims(ra) + SCM ra; +{ + SCM res=EOL; + sizet k; + array_dim *s; + if IMP(ra) return BOOL_F; + switch (TYP7(ra)) { + default: return BOOL_F; + case tc7_string: case tc7_vector: case tc7_bvect: + case tc7_uvect: case tc7_ivect: case tc7_fvect: + case tc7_cvect: case tc7_dvect: + return cons(MAKINUM(LENGTH(ra)), EOL); + case tc7_smob: + if (!ARRAYP(ra)) return BOOL_F; + k = ARRAY_NDIM(ra); + s = ARRAY_DIMS(ra); + while (k--) + res = cons(s[k].lbnd ? cons2(MAKINUM(s[k].lbnd), MAKINUM(s[k].ubnd), EOL) : + MAKINUM(1+(s[k].ubnd)) + , res); + return res; + } +} +static char s_bad_ind[] = "Bad array index"; +long aind(ra, args, what) + SCM ra, args; + char *what; +{ + SCM ind; + register long j; + register sizet pos = ARRAY_BASE(ra); + register sizet k = ARRAY_NDIM(ra); + array_dim *s = ARRAY_DIMS(ra); + if INUMP(args) { + ASSERT(1==k, UNDEFINED, WNA, what); + j = INUM(args); + ASSERT(j >= (s->lbnd) && j <= (s->ubnd), args, OUTOFRANGE, what); + return pos + (j - s->lbnd)*(s->inc); + } + ASSERT((IMP(args) ? NULLP(args) : CONSP(args)), args, s_bad_ind, what); + while (k && NIMP(args)) { + ind = CAR(args); + args = CDR(args); + ASSERT(INUMP(ind), ind, s_bad_ind, what); + j = INUM(ind); + ASSERT(j >= (s->lbnd) && j <= (s->ubnd), ind, OUTOFRANGE, what); + pos += (j - s->lbnd)*(s->inc); + k--; + s++; + } + ASSERT(0==k && NULLP(args), UNDEFINED, WNA, what); + return pos; +} + +SCM make_ra(ndim) + int ndim; +{ + SCM ra; + NEWCELL(ra); + DEFER_INTS; + SETCDR(ra, must_malloc((long)(sizeof(array)+ndim*sizeof(array_dim)), + "array")); + CAR(ra) = ((long)ndim << 17) + tc16_array; + ARRAY_V(ra) = nullvect; + ALLOW_INTS; + return ra; +} + +static char s_bad_spec[] = "Bad array dimension"; +/* Increments will still need to be set. */ +SCM shap2ra(args, what) + SCM args; + char *what; +{ + array_dim *s; + SCM ra, spec, sp; + int ndim = ilength(args); + ASSERT(0 <= ndim, args, s_bad_spec, what); + ra = make_ra(ndim); + ARRAY_BASE(ra) = 0; + s = ARRAY_DIMS(ra); + for (; NIMP(args); s++, args = CDR(args)) { + spec = CAR(args); + if IMP(spec) { + ASSERT(INUMP(spec)&&INUM(spec)>=0, spec, s_bad_spec, what); + s->lbnd = 0; + s->ubnd = INUM(spec) - 1; + s->inc = 1; + } + else { + ASSERT(CONSP(spec) && INUMP(CAR(spec)), spec, s_bad_spec, what); + s->lbnd = INUM(CAR(spec)); + sp = CDR(spec); + ASSERT(INUMP(CAR(sp)) && NULLP(CDR(sp)), + spec, s_bad_spec, what); + s->ubnd = INUM(CAR(sp)); + s->inc = 1; + } + } + return ra; +} + +static char s_uve_fill[] = "uniform-vector-fill!"; +int rafill(ra, fill, ignore) + SCM ra, fill, ignore; +{ + sizet i, n; + long inc = 1; + sizet base = 0; + if ARRAYP(ra) { + n = ARRAY_DIMS(ra)->ubnd - ARRAY_DIMS(ra)->lbnd + 1; + inc = ARRAY_DIMS(ra)->inc; + base = ARRAY_BASE(ra); + ra = ARRAY_V(ra); + } + else + n = LENGTH(ra); + switch TYP7(ra) { + badarg2: wta(fill, (char *)ARG2, s_uve_fill); + default: ASSERT(NFALSEP(arrayp(ra, UNDEFINED)), ra, ARG1, s_uve_fill); + for (i = base; n--; i += inc) + aset(ra, fill, MAKINUM(i)); + break; + case tc7_vector: { + SCM *ve = VELTS(ra); + for (i = base; n--; i += inc) + ve[i] = fill; + break; + } + case tc7_string: { + char *ve = CHARS(ra); + SCM f = ICHR(fill); + ASRTGO(ICHRP(fill), badarg2); + for (i = base; n--; i += inc) + ve[i] = f; + break; + } + case tc7_bvect: { + long *ve = (long *)VELTS(ra); + if (1==inc && (n >= LONG_BIT || n==LENGTH(ra))) { + i = base/LONG_BIT; + if (BOOL_F==fill) { + if (base % LONG_BIT) /* leading partial word */ + ve[i++] &= ~(~0L << (base % LONG_BIT)); + for (; i < (base + n)/LONG_BIT; i++) + ve[i] = 0L; + if ((base + n) % LONG_BIT) /* trailing partial word */ + ve[i] &= (~0L << ((base + n) % LONG_BIT)); + } + else if (BOOL_T==fill) { + if (base % LONG_BIT) + ve[i++] |= ~0L << (base % LONG_BIT); + for (; i < (base + n)/LONG_BIT; i++) + ve[i] = ~0L; + if ((base + n) % LONG_BIT) + ve[i] |= ~(~0L << ((base + n) % LONG_BIT)); + } + else goto badarg2; + } + else { + if (BOOL_F==fill) + for (i = base; n--; i += inc) + ve[i/LONG_BIT] &= ~(1L<<(i%LONG_BIT)); + else if (BOOL_T==fill) + for (i = base; n--; i += inc) + ve[i/LONG_BIT] |= (1L<<(i%LONG_BIT)); + else goto badarg2; + } + break; + } + case tc7_uvect: + case tc7_ivect: + { + long *ve = VELTS(ra); + long f = (tc7_uvect==TYP7(ra) ? + num2ulong(fill, (char *)ARG2, s_uve_fill) : + num2long(fill, (char *)ARG2, s_uve_fill)); + for (i = base; n--; i += inc) + ve[i] = f; + break; + } +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *ve = (float *)VELTS(ra); + float f = num2dbl(fill, (char *)ARG2, s_uve_fill); + for (i = base; n--; i += inc) + ve[i] = f; + break; + } +# endif /* SINGLES */ + case tc7_dvect: { + double *ve = (double *)VELTS(ra); + double f = num2dbl(fill, (char *)ARG2, s_uve_fill); + for (i = base; n--; i += inc) + ve[i] = f; + break; + } + case tc7_cvect: { + double fr, fi=0.0; + double (*ve)[2] = (double (*)[2])VELTS(ra); + if (NIMP(fill) && CPLXP(fill)) { + fr = REAL(fill); + fi = IMAG(fill); + } + else + fr = num2dbl(fill, (char *)ARG2, s_uve_fill); + for (i = base; n--; i += inc) { + ve[i][0] = fr; + ve[i][1] = fi; + } + break; + } +# endif /* FLOATS */ + } + return 1; +} +SCM uve_fill(uve, fill) + SCM uve, fill; +{ + + ASSERT(NIMP(uve) && (!ARRAYP(uve) || 1==ARRAY_NDIM(uve)), + uve, ARG1, s_uve_fill); + rafill(uve, fill, EOL); + return UNSPECIFIED; +} + +static char s_dims2ura[] = "dimensions->uniform-array"; +SCM dims2ura(dims, prot, fill) + SCM dims, prot, fill; +{ + sizet k, vlen = 1; + long rlen = 1; + array_dim *s; + SCM ra; + if INUMP(dims) + if (INUM(dims) < LENGTH_MAX) { + ra = make_uve(INUM(dims), prot); + if NNULLP(fill) + rafill(ra, CAR(fill), EOL); + return ra; + } + else + dims = cons(dims, EOL); + ASSERT(NULLP(dims) || (NIMP(dims) && CONSP(dims)), dims, ARG1, s_dims2ura); + ra = shap2ra(dims, s_dims2ura); + CAR(ra) |= ARRAY_CONTIGUOUS; + s = ARRAY_DIMS(ra); + k = ARRAY_NDIM(ra); + while (k--) { + s[k].inc = (rlen > 0 ? rlen : 0); + rlen = (s[k].ubnd - s[k].lbnd + 1)*s[k].inc; + vlen *= (s[k].ubnd - s[k].lbnd + 1); + } + if (rlen < LENGTH_MAX) + ARRAY_V(ra) = make_uve((rlen > 0 ? rlen : 0L), prot); + else { + sizet bit; + switch TYP7(make_uve(0L, prot)) { + default: bit = LONG_BIT; break; + case tc7_vector: wta(dims, (char *)OUTOFRANGE, s_dims2ura); + case tc7_bvect: bit = 1; break; + case tc7_string: bit = CHAR_BIT; break; + case tc7_fvect: bit = sizeof(float)*CHAR_BIT/sizeof(char); break; + case tc7_dvect: bit = sizeof(double)*CHAR_BIT/sizeof(char); break; + case tc7_cvect: bit = 2*sizeof(double)*CHAR_BIT/sizeof(char); break; + } + ARRAY_BASE(ra) = (LONG_BIT + bit - 1)/bit; + rlen += ARRAY_BASE(ra); + ARRAY_V(ra) = make_uve(rlen, prot); + *((long *)VELTS(ARRAY_V(ra))) = rlen; + } + if NNULLP(fill) { + ASSERT(1==ilength(fill), UNDEFINED, WNA, s_dims2ura); + rafill(ARRAY_V(ra), CAR(fill), EOL); + } + if (1==ARRAY_NDIM(ra) && 0==ARRAY_BASE(ra)) + if (s->ubnd < s->lbnd || (0==s->lbnd && 1==s->inc)) return ARRAY_V(ra); + return ra; +} + +void ra_set_contp(ra) + SCM ra; +{ + sizet k = ARRAY_NDIM(ra); + long inc; + if (k) inc = ARRAY_DIMS(ra)[k-1].inc; + while (k--) { + if (inc != ARRAY_DIMS(ra)[k].inc) { + CAR(ra) &= ~ARRAY_CONTIGUOUS; + return; + } + inc *= (ARRAY_DIMS(ra)[k].ubnd - ARRAY_DIMS(ra)[k].lbnd + 1); + } + CAR(ra) |= ARRAY_CONTIGUOUS; +} +char s_make_sh_array[] = "make-shared-array"; +SCM make_sh_array(oldra, mapfunc, dims) + SCM oldra; + SCM mapfunc; + SCM dims; +{ + SCM ra; + SCM inds, indptr; + SCM imap; + sizet i, k; + long old_min, new_min, old_max, new_max; + array_dim *s; + ASSERT(BOOL_T==procedurep(mapfunc), mapfunc, ARG2, s_make_sh_array); + ASSERT(NIMP(oldra) && arrayp(oldra, UNDEFINED), oldra, ARG1, s_make_sh_array); + ra = shap2ra(dims, s_make_sh_array); + if (ARRAYP(oldra)) { + ARRAY_V(ra) = ARRAY_V(oldra); + old_min = old_max = ARRAY_BASE(oldra); + s=ARRAY_DIMS(oldra); + k = ARRAY_NDIM(oldra); + while (k--) { + if (s[k].inc > 0) + old_max += (s[k].ubnd - s[k].lbnd)*s[k].inc; + else + old_min += (s[k].ubnd - s[k].lbnd)*s[k].inc; + } + } + else { + ARRAY_V(ra) = oldra; + old_min = 0; + old_max = (long)LENGTH(oldra) - 1; + } + inds = EOL; + s = ARRAY_DIMS(ra); + for (k = 0; k < ARRAY_NDIM(ra); k++) { + inds = cons(MAKINUM(s[k].lbnd), inds); + if (s[k].ubnd < s[k].lbnd) { + if (1==ARRAY_NDIM(ra)) + ra = make_uve(0L, array_prot(ra)); + else + ARRAY_V(ra) = make_uve(0L, array_prot(ra)); + return ra; + } + } + imap = apply(mapfunc, reverse(inds), EOL); + if ARRAYP(oldra) + i = (sizet)aind(oldra, imap, s_make_sh_array); + else { + if NINUMP(imap) { + ASSERT(1==ilength(imap) && INUMP(CAR(imap)), + imap, s_bad_ind, s_make_sh_array); + imap = CAR(imap); + } + i = INUM(imap); + } + ARRAY_BASE(ra) = new_min = new_max = i; + indptr = inds; + k = ARRAY_NDIM(ra); + while (k--) { + if (s[k].ubnd > s[k].lbnd) { + CAR(indptr) = MAKINUM(INUM(CAR(indptr))+1); + imap = apply(mapfunc, reverse(inds), EOL); + if ARRAYP(oldra) + s[k].inc = aind(oldra, imap, s_make_sh_array) - i; + else { + if NINUMP(imap) { + ASSERT(1==ilength(imap) && INUMP(CAR(imap)), + imap, s_bad_ind, s_make_sh_array); + imap = CAR(imap); + } + s[k].inc = (long)INUM(imap) - i; + } + i += s[k].inc; + if (s[k].inc > 0) + new_max += (s[k].ubnd - s[k].lbnd)*s[k].inc; + else + new_min += (s[k].ubnd - s[k].lbnd)*s[k].inc; + } + else + s[k].inc = new_max - new_min + 1; /* contiguous by default */ + indptr = CDR(indptr); + } + ASSERT(old_min <= new_min && old_max >= new_max, UNDEFINED, + "mapping out of range", s_make_sh_array); + if (1==ARRAY_NDIM(ra) && 0==ARRAY_BASE(ra)) { + if (1==s->inc && 0==s->lbnd + && LENGTH(ARRAY_V(ra))==1+s->ubnd) return ARRAY_V(ra); + if (s->ubnd < s->lbnd) return make_uve(0L, array_prot(ra)); + } + ra_set_contp(ra); + return ra; +} + +/* args are RA . DIMS */ +static char s_trans_array[] = "transpose-array"; +SCM trans_array(args) + SCM args; +{ + SCM ra, res, vargs, *ve = &vargs; + array_dim *s, *r; + int ndim, i, k; + ASSERT(NIMP(args), UNDEFINED, WNA, s_trans_array); + ra = CAR(args); + args = CDR(args); + switch TYP7(ra) { + default: badarg: wta(ra, (char *)ARG1, s_trans_array); + case tc7_bvect: case tc7_string: case tc7_uvect: case tc7_ivect: + case tc7_fvect: case tc7_dvect: case tc7_cvect: case tc7_vector: + ASSERT(NIMP(args) && NULLP(CDR(args)), UNDEFINED, WNA, s_trans_array); + ASSERT(INUM0==CAR(args), CAR(args), ARG1, s_trans_array); + return ra; + case tc7_smob: ASRTGO(ARRAYP(ra), badarg); + vargs = vector(args); + ASSERT(LENGTH(vargs)==ARRAY_NDIM(ra), UNDEFINED, WNA, s_trans_array); + ve = VELTS(vargs); + ndim = 0; + for (k = 0; k < ARRAY_NDIM(ra); k++) { + i = INUM(ve[k]); + ASSERT(INUMP(ve[k]) && i >=0 && i < ARRAY_NDIM(ra), + ve[k], ARG2, s_trans_array); + if (ndim < i) ndim = i; + } + ndim++; + res = make_ra(ndim); + ARRAY_V(res) = ARRAY_V(ra); + ARRAY_BASE(res) = ARRAY_BASE(ra); + for (k = ndim; k--;) { + ARRAY_DIMS(res)[k].lbnd = 0; + ARRAY_DIMS(res)[k].ubnd = -1; + } + for (k = ARRAY_NDIM(ra); k--;) { + i = INUM(ve[k]); + s = &(ARRAY_DIMS(ra)[k]); + r = &(ARRAY_DIMS(res)[i]); + if (r->ubnd < r->lbnd) { + r->lbnd = s->lbnd; + r->ubnd = s->ubnd; + r->inc = s->inc; + ndim--; + } + else { + if (r->ubnd > s->ubnd) + r->ubnd = s->ubnd; + if (r->lbnd < s->lbnd) { + ARRAY_BASE(res) += (s->lbnd - r->lbnd)*r->inc; + r->lbnd = s->lbnd; + } + r->inc += s->inc; + } + } + ASSERT(ndim <= 0, args, "bad argument list", s_trans_array); + ra_set_contp(res); + return res; + } +} + +/* args are RA . AXES */ +static char s_encl_array[] = "enclose-array"; +SCM encl_array(axes) + SCM axes; +{ + SCM axv, ra, res, ra_inr; + array_dim vdim, *s = &vdim; + int ndim, j, k, ninr, noutr; + ASSERT(NIMP(axes), UNDEFINED, WNA, s_encl_array); + ra = CAR(axes); + axes = CDR(axes); + if NULLP(axes) + axes = cons((ARRAYP(ra) ? MAKINUM(ARRAY_NDIM(ra) - 1) : INUM0), EOL); + ninr = ilength(axes); + ra_inr = make_ra(ninr); + ASRTGO(NIMP(ra), badarg1); + switch TYP7(ra) { + default: badarg1: wta(ra, (char *)ARG1, s_encl_array); + case tc7_string: case tc7_bvect: case tc7_uvect: case tc7_ivect: + case tc7_fvect: case tc7_dvect: case tc7_cvect: case tc7_vector: + s->lbnd = 0; + s->ubnd = LENGTH(ra) - 1; + s->inc = 1; + ARRAY_V(ra_inr) = ra; + ARRAY_BASE(ra_inr) = 0; + ndim = 1; + break; + case tc7_smob: ASRTGO(ARRAYP(ra), badarg1); + s = ARRAY_DIMS(ra); + ARRAY_V(ra_inr) = ARRAY_V(ra); + ARRAY_BASE(ra_inr) = ARRAY_BASE(ra); + ndim = ARRAY_NDIM(ra); + break; + } + noutr = ndim - ninr; + axv = make_string(MAKINUM(ndim), MAKICHR(0)); + ASSERT(0 <= noutr && 0 <= ninr, UNDEFINED, WNA, s_encl_array); + res = make_ra(noutr); + ARRAY_BASE(res) = ARRAY_BASE(ra_inr); + ARRAY_V(res) = ra_inr; + for (k = 0; k < ninr; k++, axes = CDR(axes)) { + j = INUM(CAR(axes)); + ASSERT(INUMP(CAR(axes)) && j<ndim, CAR(axes), "bad axis", s_encl_array); + ARRAY_DIMS(ra_inr)[k].lbnd = s[j].lbnd; + ARRAY_DIMS(ra_inr)[k].ubnd = s[j].ubnd; + ARRAY_DIMS(ra_inr)[k].inc = s[j].inc; + CHARS(axv)[j] = 1; + } + for (j = 0, k = 0; k < noutr; k++, j++) { + while (CHARS(axv)[j]) j++; + ARRAY_DIMS(res)[k].lbnd = s[j].lbnd; + ARRAY_DIMS(res)[k].ubnd = s[j].ubnd; + ARRAY_DIMS(res)[k].inc = s[j].inc; + } + ra_set_contp(ra_inr); + ra_set_contp(res); + return res; +} + +static char s_array_inbp[] = "array-in-bounds?"; +SCM array_inbp(args) + SCM args; +{ + SCM v, ind = EOL; + register long j; + ASRTGO(NIMP(args), wna); + v = CAR(args); + args = CDR(args); + if IMP(v) goto scalar; + switch TYP7(v) { + default: + scalar: if NULLP(args) return BOOL_T; + badarg1: wta(v, (char *)ARG1, s_array_inbp); + wna: wta(UNDEFINED, (char *)WNA, s_array_inbp); + case tc7_smob: + if (ARRAYP(v)) { + SCM ret = BOOL_T; + register sizet k = ARRAY_NDIM(v); + array_dim *s = ARRAY_DIMS(v); + while (k && NIMP(args)) { + ind = CAR(args); + args = CDR(args); + ASSERT(INUMP(ind), ind, s_bad_ind, s_array_inbp); + j = INUM(ind); + if (j < (s->lbnd) || j > (s->ubnd)) ret = BOOL_F; + k--; + s++; + } + ASRTGO(0==k && NULLP(args), wna); + return ret; + } + else goto scalar; + case tc7_bvect: case tc7_string: case tc7_uvect: case tc7_ivect: + case tc7_fvect: case tc7_dvect: case tc7_cvect: case tc7_vector: + ASRTGO(NIMP(args) && NULLP(CDR(args)), wna); + ind = CAR(args); + ASSERT(INUMP(ind), ind, s_bad_ind, s_array_inbp); + j = INUM(ind); + return j >= 0 && j < LENGTH(v) ? BOOL_T : BOOL_F; + } +} +static char s_aref[] = "array-ref"; +SCM aref(v, args) + SCM v, args; +{ + long pos; + if IMP(v) { + ASRTGO(NULLP(args), badarg); + return v; + } + else if ARRAYP(v) { + pos = aind(v, args, s_aref); + v = ARRAY_V(v); + } + else { + if NIMP(args) { + ASSERT(CONSP(args) && INUMP(CAR(args)), args, ARG2, s_aref); + pos = INUM(CAR(args)); + ASRTGO(NULLP(CDR(args)), wna); + } + else { + ASSERT(INUMP(args), args, ARG2, s_aref); + pos = INUM(args); + } + ASRTGO(pos >= 0 && pos < LENGTH(v), outrng); + } + switch TYP7(v) { + default: if NULLP(args) return v; + badarg: wta(v, (char *)ARG1, s_aref); + outrng: wta(MAKINUM(pos), (char *)OUTOFRANGE, s_aref); + wna: wta(UNDEFINED, (char *)WNA, s_aref); + case tc7_smob: { /* enclosed */ + int k = ARRAY_NDIM(v); + SCM res = make_ra(k); + if (!ARRAYP(v)) { + ASRTGO(NULLP(args),badarg); + return v; + } + ARRAY_V(res) = ARRAY_V(v); + ARRAY_BASE(res) = pos; + while (k--) { + ARRAY_DIMS(res)[k].lbnd = ARRAY_DIMS(v)[k].lbnd; + ARRAY_DIMS(res)[k].ubnd = ARRAY_DIMS(v)[k].ubnd; + ARRAY_DIMS(res)[k].inc = ARRAY_DIMS(v)[k].inc; + } + return res; + } + case tc7_bvect: + if (VELTS(v)[pos/LONG_BIT]&(1L<<(pos%LONG_BIT))) + return BOOL_T; + else return BOOL_F; + case tc7_string: + return MAKICHR(CHARS(v)[pos]); +# ifdef INUMS_ONLY + case tc7_uvect: + case tc7_ivect: + return MAKINUM(VELTS(v)[pos]); +# else + case tc7_uvect: + return ulong2num(VELTS(v)[pos]); + case tc7_ivect: + return long2num(VELTS(v)[pos]); +# endif +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: + return makflo(((float *)CDR(v))[pos]); +# endif + case tc7_dvect: + return makdbl(((double *)CDR(v))[pos], 0.0); + case tc7_cvect: + return makdbl(((double *)CDR(v))[2*pos], + ((double *)CDR(v))[2*pos+1]); +# endif + case tc7_vector: + return VELTS(v)[pos]; + } +} +SCM scm_array_ref(args) + SCM args; +{ + ASSERT(NIMP(args), UNDEFINED, WNA, s_aref); + return aref(CAR(args), CDR(args)); +} + +/* Internal version of aref for uves that does no error checking and + tries to recycle conses. (Make *sure* you want them recycled.) */ +SCM cvref(v, pos, last) + SCM v; + sizet pos; + SCM last; +{ + switch TYP7(v) { + default: wta(v, (char *)ARG1, "PROGRAMMING ERROR: cvref"); + case tc7_bvect: + if (VELTS(v)[pos/LONG_BIT]&(1L<<(pos%LONG_BIT))) + return BOOL_T; + else return BOOL_F; + case tc7_string: + return MAKICHR(CHARS(v)[pos]); +# ifdef INUMS_ONLY + case tc7_uvect: + case tc7_ivect: + return MAKINUM(VELTS(v)[pos]); +# else + case tc7_uvect: + return ulong2num(VELTS(v)[pos]); + case tc7_ivect: + return long2num(VELTS(v)[pos]); +# endif +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: + if (NIMP(last) && (last != flo0) && (tc_flo==CAR(last))) { + FLO(last) = ((float *)CDR(v))[pos]; + return last; + } + return makflo(((float *)CDR(v))[pos]); +# endif + case tc7_cvect: + if (0.0!=((double *)CDR(v))[2*pos+1]) { + if (NIMP(last) && tc_dblc==CAR(last)) { + REAL(last) = ((double *)CDR(v))[2*pos]; + IMAG(last) = ((double *)CDR(v))[2*pos+1]; + return last; + } + return makdbl(((double *)CDR(v))[2*pos], + ((double *)CDR(v))[2*pos+1]); + } + else pos *= 2; + /* Fall through */ + case tc7_dvect: +# ifdef CDR_DOUBLES + if (NIMP(last) && (last != flo0) && (tc_flo==CAR(last))) { + FLO(last) = ((double *)CDR(v))[pos]; + return last; + } +# else +# ifdef SINGLES + if (NIMP(last) && tc_dblr==CAR(last)) +# else + if (NIMP(last) && (last != flo0) && (tc_dblr==CAR(last))) +# endif + { + REAL(last) = ((double *)CDR(v))[pos]; + return last; + } +# endif /* ndef CDR_DOUBLES */ + return makdbl(((double *)CDR(v))[pos], 0.0); +# endif /* def FLOATS */ + case tc7_vector: + return VELTS(v)[pos]; + case tc7_smob: { /* enclosed array */ + int k = ARRAY_NDIM(v); + if (IMP(last) || (!ARRAYP(last))) { + last = make_ra(k); + ARRAY_V(last) = ARRAY_V(v); + while (k--) { + ARRAY_DIMS(last)[k].ubnd = ARRAY_DIMS(v)[k].ubnd; + ARRAY_DIMS(last)[k].lbnd = ARRAY_DIMS(v)[k].lbnd; + ARRAY_DIMS(last)[k].inc = ARRAY_DIMS(v)[k].inc; + } + } + ARRAY_BASE(last) = pos; + return last; + } + } +} + +static char s_aset[] = "array-set!"; +SCM aset(v, obj, args) + SCM v, obj, args; +{ + long pos; + ASRTGO(NIMP(v), badarg1); + if ARRAYP(v) { + pos = aind(v, args, s_aset); + v = ARRAY_V(v); + } + else { + if NIMP(args) { + ASSERT(CONSP(args) && INUMP(CAR(args)), args, ARG2, s_aset); + pos = INUM(CAR(args)); + ASRTGO(NULLP(CDR(args)), wna); + } + else { + ASSERT(INUMP(args), args, ARG2, s_aset); + pos = INUM(args); + } + ASRTGO(pos >= 0 && pos < LENGTH(v), outrng); + } + switch TYP7(v) { + default: badarg1: wta(v, (char *)ARG1, s_aset); + outrng: wta(MAKINUM(pos), (char *)OUTOFRANGE, s_aset); + wna: wta(UNDEFINED, (char *)WNA, s_aset); + case tc7_smob: /* enclosed */ + goto badarg1; + case tc7_bvect: + if (BOOL_F==obj) + VELTS(v)[pos/LONG_BIT] &= ~(1L<<(pos%LONG_BIT)); + else if (BOOL_T==obj) + VELTS(v)[pos/LONG_BIT] |= (1L<<(pos%LONG_BIT)); + else badarg2: wta(obj, (char *)ARG2, s_aset); + break; + case tc7_string: + ASRTGO(ICHRP(obj), badarg2); + CHARS(v)[pos] = ICHR(obj); break; +# ifdef INUMS_ONLY + case tc7_uvect: + ASRTGO(INUM(obj) >= 0, badarg2); + case tc7_ivect: + ASRTGO(INUMP(obj), badarg2); VELTS(v)[pos] = INUM(obj); break; +# else + case tc7_uvect: + VELTS(v)[pos] = num2ulong(obj, (char *)ARG2, s_aset); break; + case tc7_ivect: + VELTS(v)[pos] = num2long(obj, (char *)ARG2, s_aset); break; +# endif +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: + ((float*)VELTS(v))[pos] = (float)num2dbl(obj, (char *)ARG2, s_aset); break; +# endif + case tc7_dvect: + ((double*)VELTS(v))[pos] = num2dbl(obj, (char *)ARG2, s_aset); break; + case tc7_cvect: + if (NIMP(obj) && CPLXP(obj)) { + ((double *)CDR(v))[2*pos] = REALPART(obj); + ((double *)CDR(v))[2*pos+1] = IMAG(obj); + } + else { + ((double *)CDR(v))[2*pos] = num2dbl(obj, (char *)ARG2, s_aset); + ((double *)CDR(v))[2*pos+1] = 0.0; + } + break; +# endif + case tc7_vector: + VELTS(v)[pos] = obj; break; + } + return UNSPECIFIED; +} + +static char s_array_contents[] = "array-contents"; +SCM array_contents(ra, strict) + SCM ra, strict; +{ + SCM sra; + if IMP(ra) return BOOL_F; + switch TYP7(ra) { + default: + return BOOL_F; + case tc7_vector: case tc7_string: case tc7_bvect: case tc7_uvect: + case tc7_ivect: case tc7_fvect: case tc7_dvect: case tc7_cvect: + return ra; + case tc7_smob: { + sizet k, ndim = ARRAY_NDIM(ra), len = 1; + if (!ARRAYP(ra) || !ARRAY_CONTP(ra)) return BOOL_F; + for (k = 0; k < ndim; k++) + len *= ARRAY_DIMS(ra)[k].ubnd - ARRAY_DIMS(ra)[k].lbnd + 1; + if (!UNBNDP(strict)) { + if (ndim && (1 != ARRAY_DIMS(ra)[ndim-1].inc)) return BOOL_F; + if (tc7_bvect==TYP7(ARRAY_V(ra))) { + if (ARRAY_BASE(ra)%LONG_BIT) return BOOL_F; + if (len != LENGTH(ARRAY_V(ra)) && len%LONG_BIT) return BOOL_F; + } + } + if ((len==LENGTH(ARRAY_V(ra))) && 0==ARRAY_BASE(ra) && ARRAY_DIMS(ra)->inc) + return ARRAY_V(ra); + sra = make_ra(1); + ARRAY_DIMS(sra)->lbnd = 0; + ARRAY_DIMS(sra)->ubnd = len - 1; + ARRAY_V(sra) = ARRAY_V(ra); + ARRAY_BASE(sra) = ARRAY_BASE(ra); + ARRAY_DIMS(sra)->inc = (ndim ? ARRAY_DIMS(ra)[ndim - 1].inc : 1); + return sra; + } + } +} + +static char s_uve_rd[] = "uniform-vector-read!"; +SCM uve_read(v, port) + SCM v, port; +{ + long sz, len, ans; + long start=0; + if UNBNDP(port) port = cur_inp; + else ASSERT(NIMP(port) && OPINFPORTP(port), port, ARG2, s_uve_rd); + ASRTGO(NIMP(v), badarg1); + len = LENGTH(v); + loop: + switch TYP7(v) { + default: badarg1: wta(v, (char *)ARG1, s_uve_rd); + case tc7_smob: + v = array_contents(v, BOOL_T); + ASRTGO(NIMP(v), badarg1); + if ARRAYP(v) { + array_dim *d = ARRAY_DIMS(v); + start = ARRAY_BASE(v); + len = d->inc * (d->ubnd - d->lbnd + 1); + v = ARRAY_V(v); + } + else + len = LENGTH(v); + goto loop; + case tc7_string: + sz = sizeof(char); + break; + case tc7_bvect: + len = (len+LONG_BIT-1)/LONG_BIT; + start /= LONG_BIT; + case tc7_uvect: + case tc7_ivect: + sz = sizeof(long); + break; +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: + sz = sizeof(float); + break; +# endif + case tc7_dvect: + sz = sizeof(double); + break; + case tc7_cvect: + sz = 2*sizeof(double); + break; +# endif + } + /* An ungetc before an fread will not work on some systems if setbuf(0). + do #define NOSETBUF in scmfig.h to fix this. */ + if CRDYP(port) { /* UGGH!!! */ + ungetc(CGETUN(port), STREAM(port)); + CLRDY(port); /* Clear ungetted char */ + } + SYSCALL(ans = fread(CHARS(v)+start*sz, (sizet)sz, (sizet)len, STREAM(port));); + if (TYP7(v)==tc7_bvect) ans *= LONG_BIT; + return MAKINUM(ans); +} + +static char s_uve_wr[] = "uniform-vector-write"; +SCM uve_write(v, port) + SCM v, port; +{ + long sz, len, ans; + long start=0; + if UNBNDP(port) port = cur_outp; + else ASSERT(NIMP(port) && OPOUTFPORTP(port), port, ARG2, s_uve_wr); + ASRTGO(NIMP(v), badarg1); + len = LENGTH(v); + loop: + switch TYP7(v) { + default: badarg1: wta(v, (char *)ARG1, s_uve_wr); + case tc7_smob: + v = array_contents(v, BOOL_T); + ASRTGO(NIMP(v), badarg1); + if ARRAYP(v) { + array_dim *d = ARRAY_DIMS(v); + start = ARRAY_BASE(v); + len = d->inc * (d->ubnd - d->lbnd + 1); + v = ARRAY_V(v); + } + else + len = LENGTH(v); + goto loop; + case tc7_string: + sz = sizeof(char); + break; + case tc7_bvect: + len = (len+LONG_BIT-1)/LONG_BIT; + start /= LONG_BIT; + case tc7_uvect: + case tc7_ivect: + sz = sizeof(long); + break; +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: + sz = sizeof(float); + break; +# endif + case tc7_dvect: + sz = sizeof(double); + break; + case tc7_cvect: + sz = 2*sizeof(double); + break; +# endif + } + SYSCALL(ans = fwrite(CHARS(v)+start*sz, (sizet)sz, (sizet)len, STREAM(port));); + if (TYP7(v)==tc7_bvect) ans *= LONG_BIT; + return MAKINUM(ans); +} + +static char cnt_tab[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; +static char s_count[] = "bit-count"; +SCM lcount(item, seq) + SCM item, seq; +{ + long i, imin, ubnd, lbnd = 0; + int enclosed = 0; + register unsigned long cnt = 0, w; + ASSERT(NIMP(seq), seq, ARG2, s_count); + ubnd = LENGTH(seq) - 1; + tail: + switch TYP7(seq) { + default: badarg2: wta(seq, (char *)ARG2, s_count); + case tc7_bvect: + if (lbnd>ubnd) return INUM0; + i = ubnd/LONG_BIT; + imin = lbnd/LONG_BIT; + w = VELTS(seq)[i]; + if FALSEP(item) w = ~w; + w <<= LONG_BIT-1-(ubnd%LONG_BIT); + w >>= LONG_BIT-1-(ubnd%LONG_BIT); /* There may be only a partial word. */ + while (imin < i--) { + for(;w;w >>= 4) cnt += cnt_tab[w & 0x0f]; + w = VELTS(seq)[i]; + if FALSEP(item) w = ~w; + } + w >>= (lbnd%LONG_BIT); + for(;w;w >>= 4) cnt += cnt_tab[w & 0x0f]; + return MAKINUM(cnt); + case tc7_smob: + ASRTGO(ARRAYP(seq) && 1==ARRAY_NDIM(seq) && 0==enclosed++, badarg2); + { + long n, inc = ARRAY_DIMS(seq)->inc; + switch (inc) { + default: + i = ARRAY_BASE(seq); + n = ARRAY_DIMS(seq)->ubnd - ARRAY_DIMS(seq)->lbnd + 1; + if (n<=0) return INUM0; + seq = ARRAY_V(seq); + if FALSEP(item) + for (;n--; i+=inc) + if (!((VELTS(seq)[i/LONG_BIT]) & (1L<<(i%LONG_BIT)))) cnt++; + else + for (;n--; i+=inc) + if ((VELTS(seq)[i/LONG_BIT]) & (1L<<(i%LONG_BIT))) cnt++; + return MAKINUM(cnt); + case 1: + lbnd = ARRAY_BASE(seq); + ubnd = lbnd + (ARRAY_DIMS(seq)->ubnd - ARRAY_DIMS(seq)->lbnd)*inc; + seq = ARRAY_V(seq); + goto tail; + case -1: + ubnd = ARRAY_BASE(seq); + lbnd = ubnd + (ARRAY_DIMS(seq)->ubnd - ARRAY_DIMS(seq)->lbnd)*inc; + seq = ARRAY_V(seq); + goto tail; + } + } + } +} +static char s_uve_pos[] = "bit-position"; +SCM position(item, v, k) + SCM item, v, k; +{ + long i, len, lenw, xbits, pos = INUM(k), offset = 0; + int enclosed = 0; + register unsigned long w; + ASSERT(NIMP(v), v, ARG2, s_uve_pos); + ASSERT(INUMP(k), k, ARG3, s_uve_pos); + len = LENGTH(v); + tail: + switch TYP7(v) { + default: badarg2: wta(v, (char *)ARG2, s_uve_pos); + case tc7_bvect: + ASSERT((pos <= len) && (pos >= 0), k, OUTOFRANGE, s_uve_pos); + if (pos==len) return BOOL_F; + if (0==len) return MAKINUM(-1L); + lenw = (len-1)/LONG_BIT; /* watch for part words */ + i = pos/LONG_BIT; + w = VELTS(v)[i]; + if FALSEP(item) w = ~w; + xbits = (pos%LONG_BIT); + pos -= xbits; + w = ((w >> xbits) << xbits); + xbits = LONG_BIT-1-(len-1)%LONG_BIT; + while (!0) { + if (w && (i==lenw)) + w = ((w << xbits) >> xbits); + if (w) while (w) switch (w & 0x0f) + { + default: return MAKINUM(pos-offset); + case 2: case 6: case 10: case 14: return MAKINUM(pos+1-offset); + case 4: case 12: return MAKINUM(pos+2-offset); + case 8: return MAKINUM(pos+3-offset); + case 0: pos += 4; w >>= 4; + } + if (++i > lenw) break; + pos += LONG_BIT; + w = VELTS(v)[i]; + if FALSEP(item) w = ~w; + } + return BOOL_F; + case tc7_smob: ASRTGO(ARRAYP(v) && 1==ARRAY_NDIM(v) && !enclosed++, badarg2); + ASSERT(pos >= ARRAY_DIMS(v)->lbnd, k, OUTOFRANGE, s_uve_pos); + if (1==ARRAY_DIMS(v)->inc) { + len = ARRAY_DIMS(v)->ubnd - ARRAY_DIMS(v)->lbnd + ARRAY_BASE(v) + 1; + offset = ARRAY_BASE(v) - ARRAY_DIMS(v)->lbnd; + pos += offset; + v = ARRAY_V(v); + goto tail; + } + else { + long inc = ARRAY_DIMS(v)->inc; + long ubnd = ARRAY_DIMS(v)->ubnd; + if (ubnd < ARRAY_DIMS(v)->lbnd) + return MAKINUM(ARRAY_DIMS(v)->lbnd - 1); + i = ARRAY_BASE(v) + (pos - ARRAY_DIMS(v)->lbnd)*inc; + v = ARRAY_V(v); + for (; pos <= ubnd; pos++) { + if (item == + ((VELTS(v)[i/LONG_BIT])&(1L<<(i%LONG_BIT)) ? BOOL_T : BOOL_F)) + return MAKINUM(pos); + i += inc; + } + return BOOL_F; + } + } +} + +static char s_bit_set[] = "bit-set*!"; +SCM bit_set(v, kv, obj) + SCM v, kv, obj; +{ + register long i, k, vlen; + ASRTGO(NIMP(v), badarg1); + ASRTGO(NIMP(kv), badarg2); + switch TYP7(kv) { + default: badarg2: wta(kv, (char *)ARG2, s_bit_set); + case tc7_uvect: + switch TYP7(v) { + default: badarg1: wta(v, (char *)ARG1, s_bit_set); + case tc7_bvect: + vlen = LENGTH(v); + if (BOOL_F==obj) for (i = LENGTH(kv);i;) { + k = VELTS(kv)[--i]; + ASSERT((k < vlen), MAKINUM(k), OUTOFRANGE, s_bit_set); + VELTS(v)[k/LONG_BIT] &= ~(1L<<(k%LONG_BIT)); + } + else if (BOOL_T==obj) for (i = LENGTH(kv); i;) { + k = VELTS(kv)[--i]; + ASSERT((k < vlen), MAKINUM(k), OUTOFRANGE, s_bit_set); + VELTS(v)[k/LONG_BIT] |= (1L<<(k%LONG_BIT)); + } + else + badarg3: wta(obj, (char *)ARG3, s_bit_set); + } + break; + case tc7_bvect: + ASRTGO(TYP7(v)==tc7_bvect && LENGTH(v)==LENGTH(kv), badarg1); + if (BOOL_F==obj) + for (k = (LENGTH(v)+LONG_BIT-1)/LONG_BIT;k--;) + VELTS(v)[k] &= ~(VELTS(kv)[k]); + else if (BOOL_T==obj) + for (k = (LENGTH(v)+LONG_BIT-1)/LONG_BIT;k--;) + VELTS(v)[k] |= VELTS(kv)[k]; + else goto badarg3; + break; + } + return UNSPECIFIED; +} + +static char s_bit_count[] = "bit-count*"; +SCM bit_count(v, kv, obj) + SCM v, kv, obj; +{ + register long i, vlen, count = 0; + register unsigned long k; + ASRTGO(NIMP(v), badarg1); + ASRTGO(NIMP(kv), badarg2); + switch TYP7(kv) { + default: badarg2: wta(kv, (char *)ARG2, s_bit_count); + case tc7_uvect: + switch TYP7(v) { + default: badarg1: wta(v, (char *)ARG1, s_bit_count); + case tc7_bvect: + vlen = LENGTH(v); + if (BOOL_F==obj) for (i = LENGTH(kv);i;) { + k = VELTS(kv)[--i]; + ASSERT((k < vlen), MAKINUM(k), OUTOFRANGE, s_bit_count); + if (!(VELTS(v)[k/LONG_BIT] & (1L<<(k%LONG_BIT)))) count++; + } + else if (BOOL_T==obj) for (i = LENGTH(kv); i;) { + k = VELTS(kv)[--i]; + ASSERT((k < vlen), MAKINUM(k), OUTOFRANGE, s_bit_count); + if (VELTS(v)[k/LONG_BIT] & (1L<<(k%LONG_BIT))) count++; + } + else + badarg3: wta(obj, (char *)ARG3, s_bit_count); + } + break; + case tc7_bvect: + ASRTGO(TYP7(v)==tc7_bvect && LENGTH(v)==LENGTH(kv), badarg1); + if (0==LENGTH(v)) return INUM0; + ASRTGO(BOOL_T==obj || BOOL_F==obj, badarg3); + obj = (BOOL_T==obj); + i = (LENGTH(v)-1)/LONG_BIT; + k = VELTS(kv)[i] & (obj ? VELTS(v)[i] : ~VELTS(v)[i]); + k <<= LONG_BIT-1-((LENGTH(v)-1)%LONG_BIT); + while (!0) { + for(;k;k >>= 4) count += cnt_tab[k & 0x0f]; + if (0==i--) return MAKINUM(count); + k = VELTS(kv)[i] & (obj ? VELTS(v)[i] : ~VELTS(v)[i]); + } + } + return MAKINUM(count); +} + +static char s_bit_inv[] = "bit-invert!"; +SCM bit_inv(v) + SCM v; +{ + register long k; + ASRTGO(NIMP(v), badarg1); + k = LENGTH(v); + switch TYP7(v) { + case tc7_bvect: + for (k = (k+LONG_BIT-1)/LONG_BIT;k--;) + VELTS(v)[k] = ~VELTS(v)[k]; + break; + default: badarg1: wta(v, (char *)ARG1, s_bit_inv); + } + return UNSPECIFIED; +} + +static char s_strup[] = "string-upcase!"; +SCM strup(v) + SCM v; +{ + register long k; + register unsigned char *cs; + ASRTGO(NIMP(v), badarg1); + k = LENGTH(v); + switch TYP7(v) { + case tc7_string: + cs = UCHARS(v); + while (k--) cs[k] = upcase[cs[k]]; + break; + default: badarg1: wta(v, (char *)ARG1, s_strup); + } + return v; +} + +static char s_strdown[] = "string-downcase!"; +SCM strdown(v) + SCM v; +{ + register long k; + register unsigned char *cs; + ASRTGO(NIMP(v), badarg1); + k = LENGTH(v); + switch TYP7(v) { + case tc7_string: + cs = UCHARS(v); + while (k--) cs[k] = downcase[cs[k]]; + break; + default: badarg1: wta(v, (char *)ARG1, s_strdown); + } + return v; +} + +# include <ctype.h> +static char s_strcap[] = "string-capitalize!"; +SCM strcap(v) + SCM v; +{ + long i = 0, len; + register unsigned char *str; + register int non_first_alpha = 0; + ASRTGO(NIMP(v), badarg1); + len = LENGTH(v); + switch TYP7(v) { + case tc7_string: + for (str = UCHARS(v);i < len; i++) { + int c = str[i]; + if (isascii(c) && isalpha(c)) + if (non_first_alpha) str[i] = downcase[c]; + else { + non_first_alpha = !0; + str[i] = upcase[c]; + } + else non_first_alpha = 0; + } + break; + default: badarg1: wta(v, (char *)ARG1, s_strcap); + } + return v; +} + +SCM istr2bve(str, len) + char *str; + long len; +{ + SCM v = make_uve(len, BOOL_T); + long *data = (long *)VELTS(v); + register unsigned long mask; + register long k; + register long j; + for (k = 0; k < (len+LONG_BIT-1)/LONG_BIT; k++) { + data[k] = 0L; + j = len - k*LONG_BIT; + if (j > LONG_BIT) j = LONG_BIT; + for (mask = 1L; j--; mask <<= 1) + switch (*str++) { + case '0': break; + case '1': data[k] |= mask; break; + default: return BOOL_F; + } + } + return v; +} + +static SCM ra2l(ra, base, k) + SCM ra; + sizet base; + sizet k; +{ + register SCM res = EOL; + register long inc = ARRAY_DIMS(ra)[k].inc; + register sizet i; + if (ARRAY_DIMS(ra)[k].ubnd < ARRAY_DIMS(ra)[k].lbnd) return EOL; + i = base + (1 + ARRAY_DIMS(ra)[k].ubnd - ARRAY_DIMS(ra)[k].lbnd)*inc; + if (k < ARRAY_NDIM(ra) - 1) { + do { + i -= inc; + res = cons(ra2l(ra, i, k+1), res); + } while (i != base); + } + else + do { + i -= inc; + res = cons(cvref(ARRAY_V(ra), i, UNDEFINED), res); + } while (i != base); + return res; +} + +static char s_array2list[] = "array->list"; +SCM array2list(v) + SCM v; +{ + SCM res = EOL; + register long k; + ASRTGO(NIMP(v), badarg1); + switch TYP7(v) { + default: badarg1: wta(v, (char *)ARG1, s_array2list); + case tc7_smob: ASRTGO(ARRAYP(v), badarg1); + return ra2l(v, ARRAY_BASE(v), 0); + case tc7_vector: return vector2list(v); + case tc7_string: return string2list(v); + case tc7_bvect: { + long *data = (long *)VELTS(v); + register unsigned long mask; + for (k = (LENGTH(v)-1)/LONG_BIT; k > 0; k--) + for (mask = 1L<<(LONG_BIT-1); mask; mask >>=1) + res = cons(((long *)data)[k] & mask ? BOOL_T : BOOL_F, res); + for (mask = 1L<<((LENGTH(v)%LONG_BIT)-1); mask; mask >>=1) + res = cons(((long *)data)[k] & mask ? BOOL_T : BOOL_F, res); + return res; + } +# ifdef INUMS_ONLY + case tc7_uvect: + case tc7_ivect: { + long *data = (long *)VELTS(v); + for (k = LENGTH(v) - 1; k >= 0; k--) + res = cons(MAKINUM(data[k]), res); + return res; + } +# else + case tc7_uvect: { + long *data = (long *)VELTS(v); + for (k = LENGTH(v) - 1; k >= 0; k--) + res = cons(ulong2num(data[k]), res); + return res; + } + case tc7_ivect: { + long *data = (long *)VELTS(v); + for (k = LENGTH(v) - 1; k >= 0; k--) + res = cons(long2num(data[k]), res); + return res; + } +# endif +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: { + float *data = (float *)VELTS(v); + for (k = LENGTH(v) - 1; k >= 0; k--) + res = cons(makflo(data[k]), res); + return res; + } +# endif /*SINGLES*/ + case tc7_dvect: { + double *data = (double *)VELTS(v); + for (k = LENGTH(v) - 1; k >= 0; k--) + res = cons(makdbl(data[k], 0.0), res); + return res; + } + case tc7_cvect: { + double (*data)[2] = (double (*)[2])VELTS(v); + for (k = LENGTH(v) - 1; k >= 0; k--) + res = cons(makdbl(data[k][0], data[k][1]), res); + return res; + } +# endif /*FLOATS*/ + } +} + +static int l2ra P((SCM lst, SCM ra, sizet base, sizet k)); +static char s_bad_ralst[] = "Bad array contents list"; +static char s_list2ura[] = "list->uniform-array"; +SCM list2ura(ndim, prot, lst) + SCM ndim; + SCM prot; + SCM lst; +{ + SCM shp=EOL; + SCM row=lst; + SCM ra; + sizet k; + long n; + ASSERT(INUMP(ndim), ndim, ARG1, s_list2ura); + k = INUM(ndim); + for (; k--; NIMP(row) && (row = CAR(row))) { + n = ilength(row); + ASSERT(n>=0, lst, ARG2, s_list2ura); + shp = cons(MAKINUM(n), shp); + } + ra = dims2ura(reverse(shp), prot, EOL); + if NULLP(shp) { + ASRTGO(1==ilength(lst), badlst); + aset(ra, CAR(lst), EOL); + return ra; + } + if (!ARRAYP(ra)) { + for (k = 0; k < LENGTH(ra); k++, lst = CDR(lst)) + aset(ra, CAR(lst), MAKINUM(k)); + return ra; + } + if (l2ra(lst, ra, ARRAY_BASE(ra), 0)) + return ra; + else + badlst: wta(lst, s_bad_ralst, s_list2ura); + return BOOL_F; +} + +static int l2ra(lst, ra, base, k) + SCM lst; + SCM ra; + sizet base; + sizet k; +{ + register long inc = ARRAY_DIMS(ra)[k].inc; + register long n = (1 + ARRAY_DIMS(ra)[k].ubnd - ARRAY_DIMS(ra)[k].lbnd); + int ok = 1; + if (n <= 0) return (EOL==lst); + if (k < ARRAY_NDIM(ra) - 1) { + while (n--) { + if (IMP(lst) || NCONSP(lst)) return 0; + ok = ok && l2ra(CAR(lst), ra, base, k+1); + base += inc; + lst = CDR(lst); + } + if NNULLP(lst) return 0; + } + else { + while (n--) { + if (IMP(lst) || NCONSP(lst)) return 0; + ok = ok && aset(ARRAY_V(ra), CAR(lst), MAKINUM(base)); + base += inc; + lst = CDR(lst); + } + if NNULLP(lst) return 0; + } + return ok; +} + +static void rapr1(ra, j, k, port, writing) + SCM ra; + sizet j; + sizet k; + SCM port; + int writing; +{ + long inc = 1; + long n = LENGTH(ra); + int enclosed = 0; + tail: + switch TYP7(ra) { + case tc7_smob: + if (enclosed++) { + ARRAY_BASE(ra) = j; + if (n-- > 0) iprin1(ra, port, writing); + for (j += inc; n-- > 0; j += inc) { + lputc(' ', port); + ARRAY_BASE(ra) = j; + iprin1(ra, port, writing); + } + break; + } + if (k+1 < ARRAY_NDIM(ra)) { + long i; + inc = ARRAY_DIMS(ra)[k].inc; + for (i = ARRAY_DIMS(ra)[k].lbnd; i < ARRAY_DIMS(ra)[k].ubnd; i++) { + lputc('(', port); + rapr1(ra, j, k+1, port, writing); + lputs(") ", port); + j += inc; + } + if (i==ARRAY_DIMS(ra)[k].ubnd) { /* could be zero size. */ + lputc('(', port); + rapr1(ra, j, k+1, port, writing); + lputc(')', port); + } + break; + } + if ARRAY_NDIM(ra) { /* Could be zero-dimensional */ + inc = ARRAY_DIMS(ra)[k].inc; + n = (ARRAY_DIMS(ra)[k].ubnd - ARRAY_DIMS(ra)[k].lbnd + 1); + } + else + n = 1; + ra = ARRAY_V(ra); + goto tail; + default: + if (n-- > 0) iprin1(cvref(ra, j, UNDEFINED), port, writing); + for (j += inc; n-- > 0; j += inc) { + lputc(' ', port); + iprin1(cvref(ra, j, UNDEFINED), port, writing); + } + break; + case tc7_string: + if (n-- > 0) iprin1(MAKICHR(CHARS(ra)[j]), port, writing); + if (writing) + for (j += inc; n-- > 0; j += inc) { + lputc(' ', port); + iprin1(MAKICHR(CHARS(ra)[j]), port, writing); + } + else + for (j += inc; n-- > 0; j += inc) + lputc(CHARS(ra)[j], port); + break; + case tc7_uvect: + if (n-- > 0) iprin1(ulong2num(VELTS(ra)[j]), port, writing); + for (j += inc; n-- > 0; j += inc) { + lputc(' ', port); + iprin1(ulong2num(VELTS(ra)[j]), port, writing); + } + break; + case tc7_ivect: + if (n-- > 0) intprint(VELTS(ra)[j], 10, port); + for (j += inc; n-- > 0; j += inc) { + lputc(' ', port); + intprint(VELTS(ra)[j], 10, port); + } + break; +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: +# endif /*SINGLES*/ + case tc7_dvect: + case tc7_cvect: + if (n-- > 0) { + SCM z = cvref(ra, j, UNDEFINED); + floprint(z, port, writing); + for (j += inc; n-- > 0; j += inc) { + lputc(' ', port); + z = cvref(ra, j, z); + floprint(z, port, writing); + } + } + break; +# endif /*FLOATS*/ + } +} +int raprin1(exp, port, writing) + SCM exp; + SCM port; + int writing; +{ + SCM v = exp; + sizet base = 0; + lputc('#', port); + tail: + switch TYP7(v) { + case tc7_smob: { + long ndim = ARRAY_NDIM(v); + base = ARRAY_BASE(v); + v = ARRAY_V(v); + if ARRAYP(v) { + lputs("<enclosed-array ", port); + rapr1(exp, base, 0, port, writing); + lputc('>', port); + return 1; + } + else { + intprint(ndim, 10, port); + goto tail; + } + } + case tc7_bvect: + if (exp==v) { /* a uve, not an array */ + register long i, j, w; + lputc('*', port); + for(i = 0;i<(LENGTH(exp))/LONG_BIT;i++) { + w = VELTS(exp)[i]; + for(j = LONG_BIT;j;j--) { + lputc(w&1?'1':'0', port); + w >>= 1; + } + } + j = LENGTH(exp)%LONG_BIT; + if (j) { + w = VELTS(exp)[LENGTH(exp)/LONG_BIT]; + for(;j;j--) { + lputc(w&1?'1':'0', port); + w >>= 1; + } + } + return 1; + } + else + lputc('b', port); break; + case tc7_string: + lputc('a', port); break; + case tc7_uvect: + lputc('u', port); break; + case tc7_ivect: + lputc('e', port); break; +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: + lputc('s', port); break; +# endif /*SINGLES*/ + case tc7_dvect: + lputc('i', port); break; + case tc7_cvect: + lputc('c', port); break; +# endif /*FLOATS*/ + } + lputc('(', port); + rapr1(exp, base, 0, port, writing); + lputc(')', port); + return 1; +} + +static char s_array_prot[] = "array-prototype"; +SCM array_prot(ra) + SCM ra; +{ + int enclosed = 0; + ASRTGO(NIMP(ra), badarg); + loop: + switch TYP7(ra) { + default: badarg: wta(ra, (char *)ARG1, s_array_prot); + case tc7_smob: ASRTGO(ARRAYP(ra), badarg); + if (enclosed++) return UNSPECIFIED; + ra = ARRAY_V(ra); + goto loop; + case tc7_vector: return EOL; + case tc7_bvect: return BOOL_T; + case tc7_string: return MAKICHR('a'); + case tc7_uvect: return MAKINUM(1L); + case tc7_ivect: return MAKINUM(-1L); +# ifdef FLOATS +# ifdef SINGLES + case tc7_fvect: return makflo(1.0); +# endif + case tc7_dvect: return makdbl(1.0/3.0, 0.0); + case tc7_cvect: return makdbl(0.0, 1.0); +# endif + } +} + +static iproc subr3s[] = { + {"uniform-vector-set1!", aset}, + {s_uve_pos, position}, + {s_bit_set, bit_set}, + {s_bit_count, bit_count}, + {s_list2ura, list2ura}, + {0, 0}}; + +static iproc subr2s[] = { + {"uniform-vector-ref", aref}, + {s_resizuve, resizuve}, + {s_count, lcount}, + {s_uve_fill, uve_fill}, + {0, 0}}; + +static iproc subr1s[] = { + {"array-rank", array_rank}, + {s_array_dims, array_dims}, + {s_array2list, array2list}, + {s_uve_len, uve_len}, + {s_bit_inv, bit_inv}, + {s_strdown, strdown}, + {s_strcap, strcap}, + {s_strup, strup}, + {s_array_prot, array_prot}, + {0, 0}}; + +static iproc lsubrs[] = { + {s_aref, scm_array_ref}, + {s_trans_array, trans_array}, + {s_encl_array, encl_array}, + {s_array_inbp, array_inbp}, + {0, 0}}; + +static iproc lsubr2s[] = { + {s_make_sh_array, make_sh_array}, + {s_dims2ura, dims2ura}, + {s_aset, aset}, + {0, 0}}; + +static iproc subr2os[] = { + {"array?", arrayp}, + {s_array_contents, array_contents}, + {s_uve_rd, uve_read}, + {s_uve_wr, uve_write}, + {0, 0}}; + +static SCM markra(ptr) + SCM ptr; +{ + if GC8MARKP(ptr) return BOOL_F; + SETGC8MARK(ptr); + return ARRAY_V(ptr); +} +static sizet freera(ptr) + CELLPTR ptr; +{ + must_free(CHARS(ptr)); + return sizeof(array) + ARRAY_NDIM(ptr)*sizeof(array_dim); +} +static smobfuns rasmob = {markra, freera, raprin1, 0}; + /* 0 replaced by raequal in init_ramap() */ + +/* This must be done after init_scl() */ +void init_unif() +{ + init_iprocs(subr3s, tc7_subr_3); + init_iprocs(subr2s, tc7_subr_2); + init_iprocs(subr1s, tc7_subr_1); + init_iprocs(lsubrs, tc7_lsubr); + init_iprocs(lsubr2s, tc7_lsubr_2); + init_iprocs(subr2os, tc7_subr_2o); + tc16_array = newsmob(&rasmob); + add_feature(s_array); + add_feature("string-case"); +} + +#else /* ARRAYS */ + +int raprin1(exp, port, writing) + SCM exp; + SCM port; + int writing; +{ + return 0; +} + +SCM istr2bve(str, len) + char *str; + long len; +{ + return BOOL_F; +} + +SCM array_equal(ra0, ra1) + SCM ra0, ra1; +{ + return BOOL_F; +} + +void init_unif() +{ + make_subr(s_resizuve, tc7_subr_2, resizuve); +} + +#endif /* ARRAYS */ @@ -0,0 +1,151 @@ +/* Copyright (C) 1994, 1995 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * As a special exception, the Free Software Foundation gives permission + * for additional uses of the text contained in its release of GUILE. + * + * The exception is that, if you link the GUILE library with other files + * to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the GUILE library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the + * Free Software Foundation under the name GUILE. If you copy + * code from other Free Software Foundation releases into a copy of + * GUILE, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for GUILE, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + */ + +/* "unix.c" functions only in Unix (unix). + Author: Aubrey Jaffer */ + +#include "scm.h" + +#include <pwd.h> +#include <sys/types.h> +/* #include <sys/wait.h> */ +#include <sys/stat.h> + +SCM stat2scm P((struct stat *stat_temp)); + +#ifndef STDC_HEADERS + void sync P((void)); + int symlink P((const char *oldpath, const char *newpath)); + int readlink P((const char *path, char *buf, sizet bufsiz)); + int acct P((const char *filename)); + int nice P((int inc)); +#endif /* STDC_HEADERS */ + + /* Only the superuser can successfully execute mknod and acct */ +/* int mknod P((const char *path, mode_t mode, dev_t dev)); + should be in stat.h */ +static char s_mknod[] = "mknod"; +SCM l_mknod(path, mode, dev) + SCM path, mode, dev; +{ + int val; + ASSERT(NIMP(path) && STRINGP(path), path, ARG1, s_mknod); + ASSERT(INUMP(mode), mode, ARG2, s_mknod); + ASSERT(INUMP(dev), dev, ARG3, s_mknod); + SYSCALL(val = mknod(CHARS(path), INUM(mode), INUM(dev));); + return val ? BOOL_F : BOOL_T; +} +static char s_acct[] = "acct"; +SCM l_acct(path) + SCM path; +{ + int val; + if FALSEP(path) { + SYSCALL(val = acct(0);); + return val ? BOOL_F : BOOL_T; + } + ASSERT(NIMP(path) && STRINGP(path), path, ARG1, s_acct); + SYSCALL(val = acct(CHARS(path));); + return val ? BOOL_F : BOOL_T; +} + +static char s_nice[] = "nice"; +SCM l_nice(incr) + SCM incr; +{ + ASSERT(INUMP(incr), incr, ARG1, s_nice); + return nice(INUM(incr)) ? BOOL_F : BOOL_T; +} + +SCM l_sync() +{ + sync(); + return UNSPECIFIED; +} + +static char s_symlink[] = "symlink"; +SCM l_symlink(oldpath, newpath) + SCM oldpath, newpath; +{ + int val; + ASSERT(NIMP(oldpath) && STRINGP(oldpath), oldpath, ARG1, s_symlink); + ASSERT(NIMP(newpath) && STRINGP(newpath), newpath, ARG2, s_symlink); + SYSCALL(val = symlink(CHARS(oldpath), CHARS(newpath));); + return val ? BOOL_F : BOOL_T; +} +static char s_readlink[] = "readlink"; +SCM l_readlink(path) + SCM path; +{ + int i; + char buf[1024]; + ASSERT(NIMP(path) && STRINGP(path), path, ARG1, s_readlink); + SYSCALL(i = readlink(CHARS(path), buf, (sizet)sizeof(buf));); + if (-1==i) return BOOL_F; + return makfromstr(buf, (sizet)i); +} +static char s_lstat[] = "lstat"; +SCM l_lstat(str) + SCM str; +{ + int i; + struct stat stat_temp; + ASSERT(NIMP(str) && STRINGP(str), str, ARG1, s_lstat); + SYSCALL(i = lstat(CHARS(str), &stat_temp);); + if (i) return BOOL_F; + return stat2scm(&stat_temp); +} + +static iproc subr1s[] = { + {s_nice, l_nice}, + {s_acct, l_acct}, + {s_lstat, l_lstat}, + {s_readlink, l_readlink}, + {0, 0}}; + +void init_unix() +{ + make_subr("sync", tc7_subr_0, l_sync); + init_iprocs(subr1s, tc7_subr_1); + make_subr(s_symlink, tc7_subr_2, l_symlink); + make_subr(s_mknod, tc7_subr_3, l_mknod); + add_feature("unix"); +} |