summaryrefslogtreecommitdiff
path: root/debian
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2015-01-17 03:18:28 +0100
committerJustus Winter <4winter@informatik.uni-hamburg.de>2015-01-17 03:18:28 +0100
commita92f9a2ee857314e6916355b8de103572eb07bf8 (patch)
tree123eb5d70bddf35b9086fd40197473764220ddf2 /debian
parent79e05f8565531f8284a33978aaf0d48173236ebd (diff)
drop old patch series
Diffstat (limited to 'debian')
-rw-r--r--debian/patches/0001-libports-silence-pointless-error-message.patch30
-rw-r--r--debian/patches/0002-startup-give-the-tasks-we-create-a-name.patch33
-rw-r--r--debian/patches/0003-auth-simplify-expression.patch35
-rw-r--r--debian/patches/0004-auth-remove-implicit-assumption-about-the-bootstrap-.patch61
-rw-r--r--debian/patches/0005-proc-call-startup_essential_task-earlier.patch183
-rw-r--r--debian/patches/0006-libshouldbeinlibc-provide-mach_print-XXX.patch80
-rw-r--r--debian/patches/0007-libdiskfs-fixes-XXX.patch66
-rw-r--r--debian/patches/0008-trans-add-startup-standalone-XXX.patch486
-rw-r--r--debian/patches/0009-XXX-bootshell.patch10323
-rw-r--r--debian/patches/0010-potfu_bootshell_fixbuild.patch75
-rw-r--r--debian/patches/0011-bootshell-improve-error-message.patch27
-rw-r--r--debian/patches/series11
12 files changed, 0 insertions, 11410 deletions
diff --git a/debian/patches/0001-libports-silence-pointless-error-message.patch b/debian/patches/0001-libports-silence-pointless-error-message.patch
deleted file mode 100644
index 8e0fa7c8..00000000
--- a/debian/patches/0001-libports-silence-pointless-error-message.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From ba9d293d8fe40f6e634cf800c42ece97727ccd0f Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Sat, 3 Jan 2015 16:21:24 +0100
-Subject: [PATCH hurd 01/11] libports: silence pointless error message
-
-* libports/manage-multithread.c (adjust_priority): Silence pointless
-error message.
----
- libports/manage-multithread.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/libports/manage-multithread.c b/libports/manage-multithread.c
-index 2067cba..ad22991 100644
---- a/libports/manage-multithread.c
-+++ b/libports/manage-multithread.c
-@@ -50,6 +50,11 @@ adjust_priority (unsigned int totalthreads)
- thread_switch (MACH_PORT_NULL, SWITCH_OPTION_DEPRESS, t);
-
- err = get_privileged_ports (&host_priv, NULL);
-+ if (err == MACH_SEND_INVALID_DEST)
-+ /* This is returned if we neither have the privileged host control
-+ port cached nor have a proc server to talk to. Give up. */
-+ return;
-+
- if (err)
- goto error_host_priv;
-
---
-2.1.4
-
diff --git a/debian/patches/0002-startup-give-the-tasks-we-create-a-name.patch b/debian/patches/0002-startup-give-the-tasks-we-create-a-name.patch
deleted file mode 100644
index 6fa71755..00000000
--- a/debian/patches/0002-startup-give-the-tasks-we-create-a-name.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 522370cfcd2dde29dac73e1479d64a6af614cc25 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Fri, 9 Jan 2015 11:06:52 +0100
-Subject: [PATCH hurd 02/11] startup: give the tasks we create a name
-
-* startup/startup.c (run): Name the tasks we start.
----
- startup/startup.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/startup/startup.c b/startup/startup.c
-index 601c894..c9fe215 100644
---- a/startup/startup.c
-+++ b/startup/startup.c
-@@ -33,6 +33,7 @@
- #include <sys/file.h>
- #include <unistd.h>
- #include <string.h>
-+#include <mach/gnumach.h>
- #include <mach/notify.h>
- #include <stdlib.h>
- #include <hurd/msg.h>
-@@ -376,6 +377,7 @@ run (const char *server, mach_port_t *ports, task_t *task)
- printf ("Pausing for %s\n", prog);
- getchar ();
- }
-+ task_set_name (*task, (char *) prog);
- err = file_exec (file, *task, 0,
- (char *)prog, strlen (prog) + 1, /* Args. */
- startup_envz, startup_envz_len,
---
-2.1.4
-
diff --git a/debian/patches/0003-auth-simplify-expression.patch b/debian/patches/0003-auth-simplify-expression.patch
deleted file mode 100644
index 91ce3272..00000000
--- a/debian/patches/0003-auth-simplify-expression.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From f37373b80de3bf74ca8792d5d64498366b088fab Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Fri, 2 Jan 2015 21:53:08 +0100
-Subject: [PATCH hurd 03/11] auth: simplify expression
-
-* auth/auth.c (S_auth_{user,server}_authenticate): Simplify expression.
----
- auth/auth.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/auth/auth.c b/auth/auth.c
-index c36bcb2..a7a188a 100644
---- a/auth/auth.c
-+++ b/auth/auth.c
-@@ -299,7 +299,7 @@ S_auth_user_authenticate (struct authhandle *userauth,
- if (! userauth)
- return EOPNOTSUPP;
-
-- if (rendezvous == MACH_PORT_NULL || rendezvous == MACH_PORT_DEAD)
-+ if (! MACH_PORT_VALID (rendezvous))
- return EINVAL;
-
- u.user = userauth;
-@@ -380,7 +380,7 @@ S_auth_server_authenticate (struct authhandle *serverauth,
- if (! serverauth)
- return EOPNOTSUPP;
-
-- if (rendezvous == MACH_PORT_NULL || rendezvous == MACH_PORT_DEAD)
-+ if (! MACH_PORT_VALID (rendezvous))
- return EINVAL;
-
- pthread_mutex_lock (&pending_lock);
---
-2.1.4
-
diff --git a/debian/patches/0004-auth-remove-implicit-assumption-about-the-bootstrap-.patch b/debian/patches/0004-auth-remove-implicit-assumption-about-the-bootstrap-.patch
deleted file mode 100644
index 02c2c804..00000000
--- a/debian/patches/0004-auth-remove-implicit-assumption-about-the-bootstrap-.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From 267fb2b2fcffe5ed09c18ee879193ad698223d65 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Wed, 7 Jan 2015 16:00:06 +0100
-Subject: [PATCH hurd 04/11] auth: remove implicit assumption about the
- bootstrap process
-
-The current code assumes that it can speak the startup protocol over
-its bootstrap port.
-
-* auth/auth.c (main): Generalize by trying to use `/servers/startup'
-before falling back to the bootstrap port.
----
- auth/auth.c | 15 ++++++++++++++-
- 1 file changed, 14 insertions(+), 1 deletion(-)
-
-diff --git a/auth/auth.c b/auth/auth.c
-index a7a188a..d5ef587 100644
---- a/auth/auth.c
-+++ b/auth/auth.c
-@@ -25,6 +25,7 @@
- #include <pthread.h>
- #include <hurd.h>
- #include <hurd/startup.h>
-+#include <hurd/paths.h>
- #include <hurd/ports.h>
- #include <hurd/ihash.h>
- #include <idvec.h>
-@@ -482,6 +483,7 @@ main (int argc, char **argv)
- {
- error_t err;
- mach_port_t boot;
-+ mach_port_t startup;
- process_t proc;
- mach_port_t hostpriv, masterdev;
- struct authhandle *firstauth;
-@@ -518,10 +520,21 @@ main (int argc, char **argv)
- _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], proc);
- _hurd_proc_init (argv, NULL, 0);
-
-+ startup = file_name_lookup (_SERVERS_STARTUP, 0, 0);
-+ if (! MACH_PORT_VALID (startup))
-+ {
-+ error (0, errno, "%s", _SERVERS_STARTUP);
-+ /* Fall back to using the bootstrap port as before. */
-+ startup = boot;
-+ }
-+
- /* Init knows intimately that we will be ready for messages
- as soon as this returns. */
-- startup_essential_task (boot, mach_task_self (), MACH_PORT_NULL, "auth",
-+ startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL, "auth",
- hostpriv);
-+
-+ if (startup != boot)
-+ mach_port_deallocate (mach_task_self (), startup);
- mach_port_deallocate (mach_task_self (), boot);
- mach_port_deallocate (mach_task_self (), hostpriv);
-
---
-2.1.4
-
diff --git a/debian/patches/0005-proc-call-startup_essential_task-earlier.patch b/debian/patches/0005-proc-call-startup_essential_task-earlier.patch
deleted file mode 100644
index cd7f469d..00000000
--- a/debian/patches/0005-proc-call-startup_essential_task-earlier.patch
+++ /dev/null
@@ -1,183 +0,0 @@
-From 04f4b23c72c04136b2003dd121009de754fc7fa8 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Wed, 7 Jan 2015 16:05:48 +0100
-Subject: [PATCH hurd 05/11] proc: call `startup_essential_task' earlier
-
-Previously, the proc server did not call `startup_essential_task'
-until it got the message port of the startup server using
-`proc_setmsgport'.
-
-Now that we have `/servers/startup', we can do this in main, before we
-start our message service loop.
-
-A complication arises because the traditional startup server is
-single-threaded. Handle this by tweaking startup not to bind itself
-to `/servers/startup' before it is ready.
-
-* proc/main.c (main): Try to lookup `/servers/startup' and send the
-message here, or...
-* proc/msg.c (S_proc_setmsgport): ... fall back to the old way here.
-* proc/proc.h (startup_fallback): New variable.
-* startup/startup.c (main): Move code installing ourself on `/servers/startup'
-(install_as_translator): ... here.
-(launch_core_servers): And use it here, just before we reply to `/hurd/auth'.
----
- proc/main.c | 23 +++++++++++++++++++++++
- proc/msg.c | 2 +-
- proc/proc.h | 2 ++
- startup/startup.c | 44 ++++++++++++++++++++++++++++++++------------
- 4 files changed, 58 insertions(+), 13 deletions(-)
-
-diff --git a/proc/main.c b/proc/main.c
-index b4288fb..6df4141 100644
---- a/proc/main.c
-+++ b/proc/main.c
-@@ -22,6 +22,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
- #include <mach.h>
- #include <hurd/hurd_types.h>
- #include <hurd.h>
-+#include <hurd/paths.h>
- #include <hurd/startup.h>
- #include <device/device.h>
- #include <assert.h>
-@@ -62,6 +63,7 @@ message_demuxer (mach_msg_header_t *inp,
- }
-
- pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;
-+int startup_fallback;
-
- error_t
- increase_priority (void)
-@@ -99,6 +101,7 @@ main (int argc, char **argv, char **envp)
- error_t err;
- void *genport;
- process_t startup_port;
-+ mach_port_t startup;
- struct argp argp = { 0, 0, 0, "Hurd process server" };
-
- argp_parse (&argp, argc, argv, 0, 0, 0);
-@@ -173,6 +176,26 @@ main (int argc, char **argv, char **envp)
- mach_port_deallocate (mach_task_self (), cons);
- }
-
-+ startup = file_name_lookup (_SERVERS_STARTUP, 0, 0);
-+ if (MACH_PORT_VALID (startup))
-+ {
-+ err = startup_essential_task (startup, mach_task_self (),
-+ MACH_PORT_NULL, "proc", _hurd_host_priv);
-+ if (err)
-+ /* Due to the single-threaded nature of /hurd/startup, it can
-+ only handle requests once the core server bootstrap has
-+ completed. Therefore, it does not bind itself to
-+ /servers/startup until it is ready. */
-+ /* Fall back to abusing the message port lookup. */
-+ startup_fallback = 1;
-+
-+ err = mach_port_deallocate (mach_task_self (), startup);
-+ assert_perror (err);
-+ }
-+ else
-+ /* Fall back to abusing the message port lookup. */
-+ startup_fallback = 1;
-+
- while (1)
- ports_manage_port_operations_multithread (proc_bucket,
- message_demuxer,
-diff --git a/proc/msg.c b/proc/msg.c
-index 796cae3..c7bab99 100644
---- a/proc/msg.c
-+++ b/proc/msg.c
-@@ -63,7 +63,7 @@ S_proc_setmsgport (struct proc *p,
- prociterate (check_message_return, p);
- p->p_checkmsghangs = 0;
-
-- if (p == startup_proc)
-+ if (p == startup_proc && startup_fallback)
- {
- /* Init is single threaded, so we can't delay our reply for
- the essential task RPC; spawn a thread to do it. */
-diff --git a/proc/proc.h b/proc/proc.h
-index a056d18..4be1de4 100644
---- a/proc/proc.h
-+++ b/proc/proc.h
-@@ -151,6 +151,8 @@ mach_port_t generic_port; /* messages not related to a specific proc */
-
- pthread_mutex_t global_lock;
-
-+extern int startup_fallback; /* (ab)use /hurd/startup's message port */
-+
- /* Forward declarations */
- void complete_wait (struct proc *, int);
- int check_uid (struct proc *, uid_t);
-diff --git a/startup/startup.c b/startup/startup.c
-index c9fe215..e01d2a8 100644
---- a/startup/startup.c
-+++ b/startup/startup.c
-@@ -514,6 +514,32 @@ demuxer (mach_msg_header_t *inp,
- startup_server (inp, outp));
- }
-
-+error_t
-+install_as_translator (void)
-+{
-+ error_t err;
-+ file_t node;
-+
-+ node = file_name_lookup (_SERVERS_STARTUP, O_NOTRANS, 0);
-+ if (! MACH_PORT_VALID (node))
-+ {
-+ if (errno == ENOENT)
-+ {
-+ /* Degrade gracefully if the node does not exist. */
-+ error (0, errno, "%s", _SERVERS_STARTUP);
-+ return 0;
-+ }
-+ return errno;
-+ }
-+
-+ err = file_set_translator (node,
-+ 0, FS_TRANS_SET, 0,
-+ NULL, 0,
-+ startup, MACH_MSG_TYPE_COPY_SEND);
-+ mach_port_deallocate (mach_task_self (), node);
-+ return err;
-+}
-+
- static int
- parse_opt (int key, char *arg, struct argp_state *state)
- {
-@@ -587,18 +613,6 @@ main (int argc, char **argv, char **envp)
- /* Crash if the boot filesystem task dies. */
- request_dead_name (fstask);
-
-- file_t node = file_name_lookup (_SERVERS_STARTUP, O_NOTRANS, 0);
-- if (node == MACH_PORT_NULL)
-- error (0, errno, "%s", _SERVERS_STARTUP);
-- else
-- {
-- file_set_translator (node,
-- 0, FS_TRANS_SET, 0,
-- NULL, 0,
-- startup, MACH_MSG_TYPE_COPY_SEND);
-- mach_port_deallocate (mach_task_self (), node);
-- }
--
- /* Set up the set of ports we will pass to the programs we exec. */
- for (i = 0; i < INIT_PORT_MAX; i++)
- switch (i)
-@@ -672,6 +686,12 @@ launch_core_servers (void)
- proc_task2proc (procserver, authtask, &authproc);
- proc_mark_important (authproc);
- proc_mark_exec (authproc);
-+
-+ err = install_as_translator ();
-+ if (err)
-+ /* Good luck. Who knows, maybe it's an old installation. */
-+ error (0, err, "Failed to bind to " _SERVERS_STARTUP);
-+
- startup_authinit_reply (authreply, authreplytype, 0, authproc,
- MACH_MSG_TYPE_COPY_SEND);
- mach_port_deallocate (mach_task_self (), authproc);
---
-2.1.4
-
diff --git a/debian/patches/0006-libshouldbeinlibc-provide-mach_print-XXX.patch b/debian/patches/0006-libshouldbeinlibc-provide-mach_print-XXX.patch
deleted file mode 100644
index fdf3969a..00000000
--- a/debian/patches/0006-libshouldbeinlibc-provide-mach_print-XXX.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-From 383f73297a9b1658c4c1fb2112a1d47e3e8e3c14 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Tue, 13 Jan 2015 17:18:17 +0100
-Subject: [PATCH hurd 06/11] libshouldbeinlibc: provide `mach_print' XXX
-
-* libshouldbeinlibc/mach-print.c: New file.
-* libshouldbeinlibc/mach-print.h: Likewise.
-* libshouldbeinlibc/Makefile: Add `mach-print.{c,h}'.
----
- libshouldbeinlibc/Makefile | 2 ++
- libshouldbeinlibc/mach-print.c | 30 ++++++++++++++++++++++++++++++
- libshouldbeinlibc/mach-print.h | 2 ++
- 3 files changed, 34 insertions(+)
- create mode 100644 libshouldbeinlibc/mach-print.c
- create mode 100644 libshouldbeinlibc/mach-print.h
-
-diff --git a/libshouldbeinlibc/Makefile b/libshouldbeinlibc/Makefile
-index 633d60e..7a17d0e 100644
---- a/libshouldbeinlibc/Makefile
-+++ b/libshouldbeinlibc/Makefile
-@@ -29,10 +29,12 @@ SRCS = termsize.c timefmt.c exec-reauth.c maptime-funcs.c \
- ugids-auth.c ugids-xinl.c ugids-merge.c ugids-imply.c ugids-posix.c \
- ugids-verify-auth.c nullauth.c \
- refcount.c \
-+ mach-print.c \
-
- installhdrs = idvec.h timefmt.h maptime.h \
- wire.h portinfo.h portxlate.h cacheq.h ugids.h nullauth.h \
- refcount.h \
-+ mach-print.h \
-
- installhdrsubdir = .
-
-diff --git a/libshouldbeinlibc/mach-print.c b/libshouldbeinlibc/mach-print.c
-new file mode 100644
-index 0000000..2b31dca
---- /dev/null
-+++ b/libshouldbeinlibc/mach-print.c
-@@ -0,0 +1,30 @@
-+#include <stdio.h>
-+#include <stdarg.h>
-+
-+#define BUFFER_SIZE 1024
-+
-+void
-+mach_print(const char *msg)
-+{
-+ // XXX check architecture
-+ asm (" pop %%eax;"
-+ " push %0;"
-+ " push %%eax;"
-+ " mov $0xffffffe2, %%eax;"
-+ " lcall $0x7, $0x0;"
-+ : /* No outputs. */
-+ : "r" (msg)
-+ : "eax");
-+}
-+
-+void
-+mach_printf (const char *format, ...)
-+{
-+ va_list ap;
-+ char buf[BUFFER_SIZE];
-+
-+ va_start(ap, format);
-+ vsnprintf(buf, sizeof(buf), format, ap);
-+ mach_print(buf);
-+ va_end(ap);
-+}
-diff --git a/libshouldbeinlibc/mach-print.h b/libshouldbeinlibc/mach-print.h
-new file mode 100644
-index 0000000..a733939
---- /dev/null
-+++ b/libshouldbeinlibc/mach-print.h
-@@ -0,0 +1,2 @@
-+void mach_print(const char *);
-+void mach_printf(const char *format, ...); // XXX attribute printf
---
-2.1.4
-
diff --git a/debian/patches/0007-libdiskfs-fixes-XXX.patch b/debian/patches/0007-libdiskfs-fixes-XXX.patch
deleted file mode 100644
index 5b377a56..00000000
--- a/debian/patches/0007-libdiskfs-fixes-XXX.patch
+++ /dev/null
@@ -1,66 +0,0 @@
-From cdda9ead492454f3810f5473b7eefd8eab6e29ad Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Tue, 13 Jan 2015 18:59:29 +0100
-Subject: [PATCH hurd 07/11] libdiskfs: fixes XXX
-
----
- libdiskfs/boot-start.c | 3 ++-
- libdiskfs/init-init.c | 10 +++++-----
- libdiskfs/init-startup.c | 3 ++-
- 3 files changed, 9 insertions(+), 7 deletions(-)
-
-diff --git a/libdiskfs/boot-start.c b/libdiskfs/boot-start.c
-index cfe2303..5233cae 100644
---- a/libdiskfs/boot-start.c
-+++ b/libdiskfs/boot-start.c
-@@ -464,7 +464,8 @@ diskfs_S_fsys_init (struct diskfs_control *pt,
- struct peropen *rootpo;
-
- if (!pt
-- || pt->pi.class != diskfs_initboot_class)
-+ || (pt->pi.class != diskfs_initboot_class
-+ && pt->pi.class != diskfs_control_class)) // XXX
- return EOPNOTSUPP;
-
- if (initdone)
-diff --git a/libdiskfs/init-init.c b/libdiskfs/init-init.c
-index 7a7f248..bc25bbe 100644
---- a/libdiskfs/init-init.c
-+++ b/libdiskfs/init-init.c
-@@ -71,14 +71,14 @@ diskfs_init_diskfs (void)
- diskfs_default_pager = MACH_PORT_NULL;
- err = vm_set_default_memory_manager (host, &diskfs_default_pager);
- mach_port_deallocate (mach_task_self (), host);
--
-- if (!err)
-- err = maptime_map (1, 0, &diskfs_mtime);
- }
-+ if (err)
-+ return err;
- }
-- else
-- err = maptime_map (0, 0, &diskfs_mtime);
-
-+ err = maptime_map (0, 0, &diskfs_mtime);
-+ if (err)
-+ err = maptime_map (1, 0, &diskfs_mtime);
- if (err)
- return err;
-
-diff --git a/libdiskfs/init-startup.c b/libdiskfs/init-startup.c
-index 3a588e1..a3a0d2d 100644
---- a/libdiskfs/init-startup.c
-+++ b/libdiskfs/init-startup.c
-@@ -106,7 +106,8 @@ diskfs_startup_diskfs (mach_port_t bootstrap, int flags)
- mach_port_deallocate (mach_task_self (), bootstrap);
- _diskfs_ncontrol_ports++;
-
-- _diskfs_init_completed ();
-+ if (MACH_PORT_VALID (getproc ())) //XXX
-+ _diskfs_init_completed ();
- }
- else
- {
---
-2.1.4
-
diff --git a/debian/patches/0008-trans-add-startup-standalone-XXX.patch b/debian/patches/0008-trans-add-startup-standalone-XXX.patch
deleted file mode 100644
index b4259768..00000000
--- a/debian/patches/0008-trans-add-startup-standalone-XXX.patch
+++ /dev/null
@@ -1,486 +0,0 @@
-From 6686c9fef8c7298e4bf33bb75705ca690add7b37 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Tue, 13 Jan 2015 19:01:50 +0100
-Subject: [PATCH hurd 08/11] trans: add `startup-standalone' XXX
-
-Provide a stripped-down version of the startup translator that
-supervises core servers and handles system shutdown.
-
-* trans/startup-standalone.c: New file.
-* trans/Makefile: Add `startup-standalone'.
----
- trans/Makefile | 9 +-
- trans/startup-standalone.c | 428 +++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 433 insertions(+), 4 deletions(-)
- create mode 100644 trans/startup-standalone.c
-
-diff --git a/trans/Makefile b/trans/Makefile
-index ce1eae7..5153361 100644
---- a/trans/Makefile
-+++ b/trans/Makefile
-@@ -21,14 +21,14 @@ makemode := servers
-
- targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
- password hello hello-mt streamio fakeroot proxy-defpager remap \
-- mtab
-+ mtab startup-standalone
- SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \
- crash.c firmlink.c password.c hello.c hello-mt.c streamio.c \
-- fakeroot.c proxy-defpager.c remap.c mtab.c
-+ fakeroot.c proxy-defpager.c remap.c mtab.c startup-standalone.c
- OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
- crashServer.o crash_replyUser.o msgServer.o \
- default_pagerServer.o default_pagerUser.o \
-- device_replyServer.o elfcore.o
-+ device_replyServer.o elfcore.o startupServer.o
- HURDLIBS = ports netfs trivfs iohelp fshelp pipe ihash shouldbeinlibc
- LDLIBS += -lpthread
- password-LDLIBS = -lcrypt
-@@ -61,8 +61,9 @@ crash: crashServer.o crash_replyUser.o msgServer.o elfcore.o
- password: passwordServer.o
- streamio: device_replyServer.o
- proxy-defpager: default_pagerServer.o default_pagerUser.o
-+startup-standalone: startupServer.o startup_notifyUser.o
-
--proxy-defpager crash password streamio: ../libports/libports.a ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a
-+proxy-defpager crash password streamio startup-standalone: ../libports/libports.a ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a
- fifo new-fifo: ../libpipe/libpipe.a
- fwd: ../libfshelp/libfshelp.a ../libports/libports.a
- hello-mt magic null ifsock fifo new-fifo firmlink: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a
-diff --git a/trans/startup-standalone.c b/trans/startup-standalone.c
-new file mode 100644
-index 0000000..dcb2cb4
---- /dev/null
-+++ b/trans/startup-standalone.c
-@@ -0,0 +1,428 @@
-+/* Start and maintain hurd core servers and system run state
-+
-+ Copyright (C) 1993-2015 Free Software Foundation, Inc.
-+ This file is part of the GNU Hurd.
-+
-+ The GNU Hurd 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 Hurd 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 Hurd; see the file COPYING. If not, write to
-+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-+
-+/* Written by Michael I. Bushnell and Roland McGrath. */
-+
-+/* This is probably more include files than I've ever seen before for
-+ one file. */
-+
-+#include <argp.h>
-+#include <argz.h>
-+#include <error.h>
-+#include <fcntl.h>
-+#include <hurd/ports.h>
-+#include <hurd/trivfs.h>
-+#include <stdlib.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <sys/mman.h>
-+#include <sys/reboot.h>
-+#include <unistd.h>
-+#include <version.h>
-+
-+#include "startup_notify_U.h"
-+#include "startup_reply_U.h"
-+#include "startup_S.h"
-+#include "notify_S.h"
-+
-+/* The privileged host control port. Used for authentication. */
-+mach_port_t host_priv;
-+
-+/* We receive dead-name notifications here. */
-+struct port_info *notification;
-+
-+/* host_reboot flags for when we crash. */
-+static int crash_flags = RB_AUTOBOOT;
-+
-+#define BOOT(flags) ((flags & RB_HALT) ? "halt" : "reboot")
-+
-+const char *argp_program_version = STANDARD_HURD_VERSION (startup-standalone);
-+
-+/* Trivfs hooks. */
-+int trivfs_fstype = FSTYPE_MISC;
-+int trivfs_fsid = 0;
-+
-+int trivfs_allow_open = 0;
-+int trivfs_support_read = 0;
-+int trivfs_support_write = 0;
-+int trivfs_support_exec = 0;
-+
-+void
-+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
-+{
-+ /* Mark the node as a read-only plain file. */
-+ st->st_mode &= ~(S_IFMT | ALLPERMS);
-+ st->st_mode |= (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH);
-+ st->st_size = 0;
-+}
-+
-+error_t
-+trivfs_goaway (struct trivfs_control *cntl, int flags)
-+{
-+ exit (0);
-+}
-+
-+/* Options processing. We accept the same options on the command line
-+ and from fsys_set_options. */
-+
-+static const struct argp_option options[] =
-+{
-+ {0}
-+};
-+
-+static error_t
-+parse_opt (int opt, char *arg, struct argp_state *state)
-+{
-+ switch (opt)
-+ {
-+ default:
-+ return ARGP_ERR_UNKNOWN;
-+ case ARGP_KEY_INIT:
-+ case ARGP_KEY_SUCCESS:
-+ case ARGP_KEY_ERROR:
-+ break;
-+ }
-+ return 0;
-+}
-+
-+/* This will be called from libtrivfs to help construct the answer
-+ to an fsys_get_options RPC. */
-+error_t
-+trivfs_append_args (struct trivfs_control *fsys,
-+ char **argz, size_t *argz_len)
-+{
-+ return 0;
-+}
-+
-+static const char doc[] =
-+ "Supervise Hurd core servers and manage system shutdown";
-+
-+static struct argp hello_argp =
-+{ options, parse_opt, 0, doc };
-+
-+/* Setting this variable makes libtrivfs use our argp to
-+ parse options passed in an fsys_set_options RPC. */
-+struct argp *trivfs_runtime_argp = &hello_argp;
-+
-+static int
-+demuxer (mach_msg_header_t *inp,
-+ mach_msg_header_t *outp)
-+{
-+ // XXX nicer demuxer
-+ extern int startup_server (mach_msg_header_t *, mach_msg_header_t *);
-+
-+ return startup_server (inp, outp) || trivfs_demuxer (inp, outp);
-+}
-+
-+int
-+main (int argc, char **argv)
-+{
-+ error_t err;
-+ mach_port_t bootstrap;
-+ struct trivfs_control *fsys;
-+ struct port_class *notification_class;
-+
-+ // XXX
-+ fprintf (stdout, "stdout\n");
-+ fflush (stdout);
-+ fprintf (stderr, "stderr\n");
-+
-+ /* We use the same argp for options available at startup
-+ as for options we'll accept in an fsys_set_options RPC. */
-+ argp_parse (&hello_argp, argc, argv, 0, 0, 0);
-+
-+ err = get_privileged_ports (&host_priv, NULL);
-+ if (err)
-+ error (1, err, "Must be started as root");
-+
-+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
-+ if (bootstrap == MACH_PORT_NULL)
-+ error (1, 0, "Must be started as a translator");
-+
-+ /* Reply to our parent */
-+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
-+ if (err)
-+ error (3, err, "trivfs_startup");
-+
-+ err = mach_port_deallocate (mach_task_self (), bootstrap);
-+ assert_perror (err);
-+
-+ notification_class = ports_create_class (NULL, NULL);
-+ if (! notification_class)
-+ error (1, errno, "ports_create_class");
-+
-+ err = ports_create_port (notification_class, fsys->pi.bucket, 0,
-+ &notification);
-+ if (err)
-+ error (1, err, "ports_create_port");
-+
-+ /* Launch. */
-+ ports_manage_port_operations_one_thread (fsys->pi.bucket, demuxer, 0);
-+
-+ return 0;
-+}
-+
-+/* This structure keeps track of each notified task. */
-+struct ntfy_task
-+ {
-+ mach_port_t notify_port;
-+ struct ntfy_task *next;
-+ char *name;
-+ };
-+
-+/* This structure keeps track of each registered essential task. */
-+struct ess_task
-+ {
-+ struct ess_task *next;
-+ task_t task_port;
-+ char *name;
-+ };
-+
-+/* These are linked lists of all of the registered items. */
-+static struct ess_task *ess_tasks;
-+static struct ntfy_task *ntfy_tasks;
-+
-+/** System shutdown **/
-+
-+/* Reboot the microkernel. */
-+void
-+reboot_mach (int flags)
-+{
-+ error_t err;
-+ printf ("%s: %sing Mach (flags %#x)...\n",
-+ program_invocation_short_name, BOOT (flags), flags);
-+ fflush (stdout);
-+ sleep (5);
-+ while ((err = host_reboot (host_priv, flags)))
-+ error (0, err, "reboot");
-+ for (;;);
-+}
-+
-+/* Reboot the microkernel, specifying that this is a crash. */
-+void
-+crash_mach (void)
-+{
-+ reboot_mach (crash_flags);
-+}
-+
-+/* Notify all tasks that have requested shutdown notifications */
-+void
-+notify_shutdown (const char *msg)
-+{
-+ struct ntfy_task *n;
-+
-+ for (n = ntfy_tasks; n != NULL; n = n->next)
-+ {
-+ error_t err;
-+ printf ("%s: notifying %s of %s...",
-+ program_invocation_short_name, n->name, msg);
-+ fflush (stdout);
-+ err = startup_dosync (n->notify_port, 60000); /* 1 minute to reply */
-+ if (err == MACH_SEND_INVALID_DEST)
-+ puts ("(no longer present)");
-+ else if (err)
-+ puts (strerror (err));
-+ else
-+ puts ("done");
-+ fflush (stdout);
-+ }
-+}
-+
-+/* Reboot the Hurd. */
-+void
-+reboot_system (int flags)
-+{
-+ notify_shutdown (BOOT (flags));
-+ reboot_mach (flags);
-+}
-+
-+/* Reboot the Hurd, specifying that this is a crash. */
-+void
-+crash_system (void)
-+{
-+ reboot_system (crash_flags);
-+}
-+
-+/* Request a dead-name notification sent to our port. */
-+static error_t
-+request_dead_name (mach_port_t name)
-+{
-+ error_t err;
-+ mach_port_t prev;
-+ err = mach_port_request_notification (mach_task_self (), name,
-+ MACH_NOTIFY_DEAD_NAME, 1,
-+ notification->port_right,
-+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
-+ if (prev != MACH_PORT_NULL)
-+ mach_port_deallocate (mach_task_self (), prev);
-+ return err;
-+}
-+
-+/* Record an essential task in the list. */
-+static error_t
-+record_essential_task (const char *name, task_t task)
-+{
-+ error_t err;
-+ struct ess_task *et;
-+ /* Record this task as essential. */
-+ et = malloc (sizeof (struct ess_task));
-+ if (et == NULL)
-+ return ENOMEM;
-+ et->task_port = task;
-+ et->name = strdup (name);
-+ if (et->name == NULL)
-+ {
-+ free (et);
-+ return ENOMEM;
-+ }
-+ et->next = ess_tasks;
-+ ess_tasks = et;
-+
-+ /* Dead-name notification on the task port will tell us when it dies. */
-+ err = request_dead_name (task);
-+ if (err)
-+ return err;
-+
-+ return 0;
-+}
-+
-+kern_return_t
-+S_startup_essential_task (mach_port_t server,
-+ mach_port_t reply,
-+ mach_msg_type_name_t replytype,
-+ task_t task,
-+ mach_port_t excpt,
-+ char *name,
-+ mach_port_t credential)
-+{
-+ error_t err;
-+ if (credential != host_priv)
-+ return EPERM;
-+
-+ err = mach_port_deallocate (mach_task_self (), credential);
-+ assert_perror (err);
-+
-+ err = record_essential_task (name, task);
-+ if (err)
-+ return err;
-+
-+ return 0;
-+}
-+
-+kern_return_t
-+S_startup_request_notification (mach_port_t server,
-+ mach_port_t notify,
-+ char *name)
-+{
-+ struct ntfy_task *nt;
-+ request_dead_name (notify);
-+
-+ /* Note that the ntfy_tasks list is kept in inverse order of the
-+ calls; this is important. We need later notification requests
-+ to get executed first. */
-+ nt = malloc (sizeof (struct ntfy_task));
-+ nt->notify_port = notify;
-+ nt->next = ntfy_tasks;
-+ nt->name = strdup (name);
-+ ntfy_tasks = nt;
-+ return 0;
-+}
-+
-+kern_return_t
-+S_startup_procinit (startup_t bootstrap,
-+ mach_port_t reply,
-+ mach_msg_type_name_t replyPoly,
-+ process_t procserver,
-+ mach_port_t *startuptask,
-+ auth_t *auth,
-+ mach_port_t *hostpriv,
-+ mach_msg_type_name_t *hostprivPoly,
-+ mach_port_t *devmaster,
-+ mach_msg_type_name_t *devmasterPoly)
-+{
-+ return EOPNOTSUPP;
-+}
-+
-+kern_return_t
-+S_startup_authinit (startup_t bootstrap,
-+ mach_port_t reply,
-+ mach_msg_type_name_t replyPoly,
-+ mach_port_t auth,
-+ mach_port_t *proc,
-+ mach_msg_type_name_t *procPoly)
-+{
-+ return EOPNOTSUPP;
-+}
-+
-+error_t
-+ports_do_mach_notify_dead_name (struct port_info *pi,
-+ mach_port_t dead_name)
-+{
-+ error_t err;
-+ struct ntfy_task *nt, *pnt;
-+ struct ess_task *et;
-+
-+ if (!pi)
-+ return EOPNOTSUPP;
-+
-+ ports_dead_name (pi, dead_name);
-+
-+ /* Drop gratuitous extra reference that the notification creates. */
-+ err = mach_port_deallocate (mach_task_self (), dead_name);
-+ assert_perror (err);
-+
-+ if (pi != notification)
-+ return 0;
-+
-+ for (et = ess_tasks; et != NULL; et = et->next)
-+ if (et->task_port == dead_name)
-+ /* An essential task has died. */
-+ {
-+ error (0, 0, "Crashing system; essential task %s died", et->name);
-+ crash_system ();
-+ }
-+
-+ for (nt = ntfy_tasks, pnt = NULL; nt != NULL; pnt = nt, nt = nt->next)
-+ if (nt->notify_port == dead_name)
-+ {
-+ /* Someone who wanted to be notified is gone. */
-+ mach_port_deallocate (mach_task_self (), dead_name);
-+ if (pnt != NULL)
-+ pnt->next = nt->next;
-+ else
-+ ntfy_tasks = nt->next;
-+ free (nt);
-+
-+ return 0;
-+ }
-+
-+ return 0;
-+}
-+
-+kern_return_t
-+S_startup_reboot (mach_port_t server,
-+ mach_port_t refpt,
-+ int code)
-+{
-+ if (refpt != host_priv)
-+ return EPERM;
-+
-+ reboot_system (code);
-+ for (;;);
-+}
---
-2.1.4
-
diff --git a/debian/patches/0009-XXX-bootshell.patch b/debian/patches/0009-XXX-bootshell.patch
deleted file mode 100644
index 8864809c..00000000
--- a/debian/patches/0009-XXX-bootshell.patch
+++ /dev/null
@@ -1,10323 +0,0 @@
-From e41e16d77b66887d6630e3b4a05ae8a57bfe340d Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Tue, 23 Dec 2014 15:03:44 +0100
-Subject: [PATCH hurd 09/11] XXX bootshell
-
-XXX hack in toplevel Makefile.
----
- Makefile | 1 +
- bootshell/COPYING.tinyscheme | 31 +
- bootshell/Makefile | 63 +
- bootshell/Manual.txt | 452 ++++
- bootshell/MiniSCHEMETribute.txt | 88 +
- bootshell/boot.scm | 249 ++
- bootshell/bootshell.h | 32 +
- bootshell/exceptions.c | 72 +
- bootshell/exec-startup.c | 162 ++
- bootshell/ffi.c | 819 +++++++
- bootshell/ffi.h | 130 +
- bootshell/fs.c | 91 +
- bootshell/fsys.c | 74 +
- bootshell/hack.txt | 244 ++
- bootshell/init.scm | 716 ++++++
- bootshell/main.c | 296 +++
- bootshell/mig-decls.h | 3 +
- bootshell/mig-mutate.h | 27 +
- bootshell/opdefines.h | 195 ++
- bootshell/runsystem.scm | 175 ++
- bootshell/scheme-config.h | 11 +
- bootshell/scheme-private.h | 210 ++
- bootshell/scheme.c | 5075 +++++++++++++++++++++++++++++++++++++++
- bootshell/scheme.h | 255 ++
- bootshell/startup.c | 487 ++++
- bootshell/startup.h | 12 +
- bootshell/utils.c | 121 +
- 27 files changed, 10091 insertions(+)
- create mode 100644 bootshell/COPYING.tinyscheme
- create mode 100644 bootshell/Makefile
- create mode 100644 bootshell/Manual.txt
- create mode 100644 bootshell/MiniSCHEMETribute.txt
- create mode 100644 bootshell/boot.scm
- create mode 100644 bootshell/bootshell.h
- create mode 100644 bootshell/exceptions.c
- create mode 100644 bootshell/exec-startup.c
- create mode 100644 bootshell/ffi.c
- create mode 100644 bootshell/ffi.h
- create mode 100644 bootshell/fs.c
- create mode 100644 bootshell/fsys.c
- create mode 100644 bootshell/hack.txt
- create mode 100644 bootshell/init.scm
- create mode 100644 bootshell/main.c
- create mode 100644 bootshell/mig-decls.h
- create mode 100644 bootshell/mig-mutate.h
- create mode 100644 bootshell/opdefines.h
- create mode 100644 bootshell/runsystem.scm
- create mode 100644 bootshell/scheme-config.h
- create mode 100644 bootshell/scheme-private.h
- create mode 100644 bootshell/scheme.c
- create mode 100644 bootshell/scheme.h
- create mode 100644 bootshell/startup.c
- create mode 100644 bootshell/startup.h
- create mode 100644 bootshell/utils.c
-
-diff --git a/Makefile b/Makefile
-index 3178740..3a2c2ed 100644
---- a/Makefile
-+++ b/Makefile
-@@ -32,6 +32,7 @@ lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \
-
- # Hurd programs
- prog-subdirs = auth proc exec term \
-+ bootshell \
- ext2fs isofs tmpfs fatfs \
- storeio pflocal pfinet defpager mach-defpager \
- login daemons boot console \
-diff --git a/bootshell/COPYING.tinyscheme b/bootshell/COPYING.tinyscheme
-new file mode 100644
-index 0000000..a6c49a2
---- /dev/null
-+++ b/bootshell/COPYING.tinyscheme
-@@ -0,0 +1,31 @@
-+ LICENSE TERMS
-+
-+Copyright (c) 2000, Dimitrios Souflis
-+All rights reserved.
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are
-+met:
-+
-+Redistributions of source code must retain the above copyright notice,
-+this list of conditions and the following disclaimer.
-+
-+Redistributions in binary form must reproduce the above copyright
-+notice, this list of conditions and the following disclaimer in the
-+documentation and/or other materials provided with the distribution.
-+
-+Neither the name of Dimitrios Souflis nor the names of the
-+contributors may be used to endorse or promote products derived from
-+this software without specific prior written permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
-+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-diff --git a/bootshell/Makefile b/bootshell/Makefile
-new file mode 100644
-index 0000000..97e30f7
---- /dev/null
-+++ b/bootshell/Makefile
-@@ -0,0 +1,63 @@
-+# Makefile for bootshell subdirectory of hurd sources
-+#
-+# Copyright (C) 1999, 2000, 2002, 2007, 2010, 2012 Free Software Foundation,
-+# Inc.
-+#
-+# This file is part of the GNU Hurd.
-+#
-+# The GNU Hurd 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 Hurd 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.
-+
-+dir := bootshell
-+makemode:= server
-+target := bootshell
-+
-+SCRIPTS := init.scm boot.scm runsystem.scm
-+SRCS := \
-+ scheme.c \
-+ main.c \
-+ exceptions.c \
-+ fs.c \
-+ fsys.c \
-+ exec-startup.c \
-+ startup.c \
-+ utils.c \
-+ ffi.c \
-+
-+SPROTOCOLS := exc exec_startup fs fsys startup
-+UPROTOCOLS := startup startup_reply
-+
-+MIGSTUBS:= \
-+ $(foreach p,$(SPROTOCOLS),$(p)Server.o) \
-+ $(foreach p,$(UPROTOCOLS),$(p)User.o)
-+OBJS := $(SRCS:.c=.o) $(SCRIPTS:.scm=.o) $(MIGSTUBS)
-+
-+HURDLIBS:= shouldbeinlibc
-+#OTHERLIBS:= -lpthread -lreadline -lhistory \
-+# $(shell pkg-config --libs --static ncurses)
-+OTHERLIBS:= -lpthread
-+CFLAGS += -imacros scheme-config.h
-+LDFLAGS += -static
-+MIGSFLAGS := -imacros mig-mutate.h
-+
-+%.o: %.scm
-+ $(LD) -r --format=binary $< -o $@
-+
-+NOWARN := conversion sign-conversion switch unused-function
-+CFLAGS := $(filter-out $(foreach flag,$NOWARN,-W$(flag)),$(CFLAGS))
-+
-+CFLAGS += -Wno-sign-conversion
-+CFLAGS += -O0 -fno-omit-frame-pointer
-+
-+include ../Makeconf
-diff --git a/bootshell/Manual.txt b/bootshell/Manual.txt
-new file mode 100644
-index 0000000..bf0e8ea
---- /dev/null
-+++ b/bootshell/Manual.txt
-@@ -0,0 +1,452 @@
-+
-+
-+ TinySCHEME Version 1.41
-+
-+ "Safe if used as prescribed"
-+ -- Philip K. Dick, "Ubik"
-+
-+This software is open source, covered by a BSD-style license.
-+Please read accompanying file COPYING.
-+-------------------------------------------------------------------------------
-+
-+ This Scheme interpreter is based on MiniSCHEME version 0.85k4
-+ (see miniscm.tar.gz in the Scheme Repository)
-+ Original credits in file MiniSCHEMETribute.txt.
-+
-+ D. Souflis (dsouflis@acm.org)
-+
-+-------------------------------------------------------------------------------
-+ What is TinyScheme?
-+ -------------------
-+
-+ TinyScheme is a lightweight Scheme interpreter that implements as large
-+ a subset of R5RS as was possible without getting very large and
-+ complicated. It is meant to be used as an embedded scripting interpreter
-+ for other programs. As such, it does not offer IDEs or extensive toolkits
-+ although it does sport a small top-level loop, included conditionally.
-+ A lot of functionality in TinyScheme is included conditionally, to allow
-+ developers freedom in balancing features and footprint.
-+
-+ As an embedded interpreter, it allows multiple interpreter states to
-+ coexist in the same program, without any interference between them.
-+ Programmatically, foreign functions in C can be added and values
-+ can be defined in the Scheme environment. Being a quite small program,
-+ it is easy to comprehend, get to grips with, and use.
-+
-+ Known bugs
-+ ----------
-+
-+ TinyScheme is known to misbehave when memory is exhausted.
-+
-+
-+ Things that keep missing, or that need fixing
-+ ---------------------------------------------
-+
-+ There are no hygienic macros. No rational or
-+ complex numbers. No unwind-protect and call-with-values.
-+
-+ Maybe (a subset of) SLIB will work with TinySCHEME...
-+
-+ Decent debugging facilities are missing. Only tracing is supported
-+ natively.
-+
-+
-+ Scheme Reference
-+ ----------------
-+
-+ If something seems to be missing, please refer to the code and
-+ "init.scm", since some are library functions. Refer to the MiniSCHEME
-+ readme as a last resort.
-+
-+ Environments
-+ (interaction-environment)
-+ See R5RS. In TinySCHEME, immutable list of association lists.
-+
-+ (current-environment)
-+ The environment in effect at the time of the call. An example of its
-+ use and its utility can be found in the sample code that implements
-+ packages in "init.scm":
-+
-+ (macro (package form)
-+ `(apply (lambda ()
-+ ,@(cdr form)
-+ (current-environment))))
-+
-+ The environment containing the (local) definitions inside the closure
-+ is returned as an immutable value.
-+
-+ (defined? <symbol>) (defined? <symbol> <environment>)
-+ Checks whether the given symbol is defined in the current (or given)
-+ environment.
-+
-+ Symbols
-+ (gensym)
-+ Returns a new interned symbol each time. Will probably move to the
-+ library when string->symbol is implemented.
-+
-+ Directives
-+ (gc)
-+ Performs garbage collection immediatelly.
-+
-+ (gcverbose) (gcverbose <bool>)
-+ The argument (defaulting to #t) controls whether GC produces
-+ visible outcome.
-+
-+ (quit) (quit <num>)
-+ Stops the interpreter and sets the 'retcode' internal field (defaults
-+ to 0). When standalone, 'retcode' is returned as exit code to the OS.
-+
-+ (tracing <num>)
-+ 1, turns on tracing. 0 turns it off. (Only when USE_TRACING is 1).
-+
-+ Mathematical functions
-+ Since rationals and complexes are absent, the respective functions
-+ are also missing.
-+ Supported: exp, log, sin, cos, tan, asin, acos, atan, floor, ceiling,
-+ trunc, round and also sqrt and expt when USE_MATH=1.
-+ Number-theoretical quotient, remainder and modulo, gcd, lcm.
-+ Library: exact?, inexact?, odd?, even?, zero?, positive?, negative?,
-+ exact->inexact. inexact->exact is a core function.
-+
-+ Type predicates
-+ boolean?,eof-object?,symbol?,number?,string?,integer?,real?,list?,null?,
-+ char?,port?,input-port?,output-port?,procedure?,pair?,environment?',
-+ vector?. Also closure?, macro?.
-+
-+ Types
-+ Types supported:
-+
-+ Numbers (integers and reals)
-+ Symbols
-+ Pairs
-+ Strings
-+ Characters
-+ Ports
-+ Eof object
-+ Environments
-+ Vectors
-+
-+ Literals
-+ String literals can contain escaped quotes \" as usual, but also
-+ \n, \r, \t, \xDD (hex representations) and \DDD (octal representations).
-+ Note also that it is possible to include literal newlines in string
-+ literals, e.g.
-+
-+ (define s "String with newline here
-+ and here
-+ that can function like a HERE-string")
-+
-+ Character literals contain #\space and #\newline and are supplemented
-+ with #\return and #\tab, with obvious meanings. Hex character
-+ representations are allowed (e.g. #\x20 is #\space).
-+ When USE_ASCII_NAMES is defined, various control characters can be
-+ referred to by their ASCII name.
-+ 0 #\nul 17 #\dc1
-+ 1 #\soh 18 #\dc2
-+ 2 #\stx 19 #\dc3
-+ 3 #\etx 20 #\dc4
-+ 4 #\eot 21 #\nak
-+ 5 #\enq 22 #\syn
-+ 6 #\ack 23 #\etv
-+ 7 #\bel 24 #\can
-+ 8 #\bs 25 #\em
-+ 9 #\ht 26 #\sub
-+ 10 #\lf 27 #\esc
-+ 11 #\vt 28 #\fs
-+ 12 #\ff 29 #\gs
-+ 13 #\cr 30 #\rs
-+ 14 #\so 31 #\us
-+ 15 #\si
-+ 16 #\dle 127 #\del
-+
-+ Numeric literals support #x #o #b and #d. Flonums are currently read only
-+ in decimal notation. Full grammar will be supported soon.
-+
-+ Quote, quasiquote etc.
-+ As usual.
-+
-+ Immutable values
-+ Immutable pairs cannot be modified by set-car! and set-cdr!.
-+ Immutable strings cannot be modified via string-set!
-+
-+ I/O
-+ As per R5RS, plus String Ports (see below).
-+ current-input-port, current-output-port,
-+ close-input-port, close-output-port, input-port?, output-port?,
-+ open-input-file, open-output-file.
-+ read, write, display, newline, write-char, read-char, peek-char.
-+ char-ready? returns #t only for string ports, because there is no
-+ portable way in stdio to determine if a character is available.
-+ Also open-input-output-file, set-input-port, set-output-port (not R5RS)
-+ Library: call-with-input-file, call-with-output-file,
-+ with-input-from-file, with-output-from-file and
-+ with-input-output-from-to-files, close-port and input-output-port?
-+ (not R5RS).
-+ String Ports: open-input-string, open-output-string, get-output-string,
-+ open-input-output-string. Strings can be used with I/O routines.
-+
-+ Vectors
-+ make-vector, vector, vector-length, vector-ref, vector-set!, list->vector,
-+ vector-fill!, vector->list, vector-equal? (auxiliary function, not R5RS)
-+
-+ Strings
-+ string, make-string, list->string, string-length, string-ref, string-set!,
-+ substring, string->list, string-fill!, string-append, string-copy.
-+ string=?, string<?, string>?, string>?, string<=?, string>=?.
-+ (No string-ci*? yet). string->number, number->string. Also atom->string,
-+ string->atom (not R5RS).
-+
-+ Symbols
-+ symbol->string, string->symbol
-+
-+ Characters
-+ integer->char, char->integer.
-+ char=?, char<?, char>?, char<=?, char>=?.
-+ (No char-ci*?)
-+
-+ Pairs & Lists
-+ cons, car, cdr, list, length, map, for-each, foldr, list-tail,
-+ list-ref, last-pair, reverse, append.
-+ Also member, memq, memv, based on generic-member, assoc, assq, assv
-+ based on generic-assoc.
-+
-+ Streams
-+ head, tail, cons-stream
-+
-+ Control features
-+ Apart from procedure?, also macro? and closure?
-+ map, for-each, force, delay, call-with-current-continuation (or call/cc),
-+ eval, apply. 'Forcing' a value that is not a promise produces the value.
-+ There is no call-with-values, values, nor dynamic-wind. Dynamic-wind in
-+ the presence of continuations would require support from the abstract
-+ machine itself.
-+
-+ Property lists
-+ TinyScheme inherited from MiniScheme property lists for symbols.
-+ put, get.
-+
-+ Dynamically-loaded extensions
-+ (load-extension <filename without extension>)
-+ Loads a DLL declaring foreign procedures. On Unix/Linux, one can make use
-+ of the ld.so.conf file or the LD_RUN_PATH system variable in order to place
-+ the library in a directory other than the current one. Please refer to the
-+ appropriate 'man' page.
-+
-+ Esoteric procedures
-+ (oblist)
-+ Returns the oblist, an immutable list of all the symbols.
-+
-+ (macro-expand <form>)
-+ Returns the expanded form of the macro call denoted by the argument
-+
-+ (define-with-return (<procname> <args>...) <body>)
-+ Like plain 'define', but makes the continuation available as 'return'
-+ inside the procedure. Handy for imperative programs.
-+
-+ (new-segment <num>)
-+ Allocates more memory segments.
-+
-+ defined?
-+ See "Environments"
-+
-+ (get-closure-code <closure>)
-+ Gets the code as scheme data.
-+
-+ (make-closure <code> <environment>)
-+ Makes a new closure in the given environment.
-+
-+ Obsolete procedures
-+ (print-width <object>)
-+
-+ Programmer's Reference
-+ ----------------------
-+
-+ The interpreter state is initialized with "scheme_init".
-+ Custom memory allocation routines can be installed with an alternate
-+ initialization function: "scheme_init_custom_alloc".
-+ Files can be loaded with "scheme_load_file". Strings containing Scheme
-+ code can be loaded with "scheme_load_string". It is a good idea to
-+ "scheme_load" init.scm before anything else.
-+
-+ External data for keeping external state (of use to foreign functions)
-+ can be installed with "scheme_set_external_data".
-+ Foreign functions are installed with "assign_foreign". Additional
-+ definitions can be added to the interpreter state, with "scheme_define"
-+ (this is the way HTTP header data and HTML form data are passed to the
-+ Scheme script in the Altera SQL Server). If you wish to define the
-+ foreign function in a specific environment (to enhance modularity),
-+ use "assign_foreign_env".
-+
-+ The procedure "scheme_apply0" has been added with persistent scripts in
-+ mind. Persistent scripts are loaded once, and every time they are needed
-+ to produce HTTP output, appropriate data are passed through global
-+ definitions and function "main" is called to do the job. One could
-+ add easily "scheme_apply1" etc.
-+
-+ The interpreter state should be deinitialized with "scheme_deinit".
-+
-+ DLLs containing foreign functions should define a function named
-+ init_<base-name>. E.g. foo.dll should define init_foo, and bar.so
-+ should define init_bar. This function should assign_foreign any foreign
-+ function contained in the DLL.
-+
-+ The first dynamically loaded extension available for TinyScheme is
-+ a regular expression library. Although it's by no means an
-+ established standard, this library is supposed to be installed in
-+ a directory mirroring its name under the TinyScheme location.
-+
-+
-+ Foreign Functions
-+ -----------------
-+
-+ The user can add foreign functions in C. For example, a function
-+ that squares its argument:
-+
-+ pointer square(scheme *sc, pointer args) {
-+ if(args!=sc->NIL) {
-+ if(sc->isnumber(sc->pair_car(args))) {
-+ double v=sc->rvalue(sc->pair_car(args));
-+ return sc->mk_real(sc,v*v);
-+ }
-+ }
-+ return sc->NIL;
-+ }
-+
-+ Foreign functions are now defined as closures:
-+
-+ sc->interface->scheme_define(
-+ sc,
-+ sc->global_env,
-+ sc->interface->mk_symbol(sc,"square"),
-+ sc->interface->mk_foreign_func(sc, square));
-+
-+
-+ Foreign functions can use the external data in the "scheme" struct
-+ to implement any kind of external state.
-+
-+ External data are set with the following function:
-+ void scheme_set_external_data(scheme *sc, void *p);
-+
-+ As of v.1.17, the canonical way for a foreign function in a DLL to
-+ manipulate Scheme data is using the function pointers in sc->interface.
-+
-+ Standalone
-+ ----------
-+
-+ Usage: tinyscheme -?
-+ or: tinyscheme [<file1> <file2> ...]
-+ followed by
-+ -1 <file> [<arg1> <arg2> ...]
-+ -c <Scheme commands> [<arg1> <arg2> ...]
-+ assuming that the executable is named tinyscheme.
-+
-+ Use - in the place of a filename to denote stdin.
-+ The -1 flag is meant for #! usage in shell scripts. If you specify
-+ #! /somewhere/tinyscheme -1
-+ then tinyscheme will be called to process the file. For example, the
-+ following script echoes the Scheme list of its arguments.
-+
-+ #! /somewhere/tinyscheme -1
-+ (display *args*)
-+
-+ The -c flag permits execution of arbitrary Scheme code.
-+
-+
-+ Error Handling
-+ --------------
-+
-+ Errors are recovered from without damage. The user can install his
-+ own handler for system errors, by defining *error-hook*. Defining
-+ to '() gives the default behavior, which is equivalent to "error".
-+ USE_ERROR_HOOK must be defined.
-+
-+ A simple exception handling mechanism can be found in "init.scm".
-+ A new syntactic form is introduced:
-+
-+ (catch <expr returned exceptionally>
-+ <expr1> <expr2> ... <exprN>)
-+
-+ "Catch" establishes a scope spanning multiple call-frames
-+ until another "catch" is encountered.
-+
-+ Exceptions are thrown with:
-+
-+ (throw "message")
-+
-+ If used outside a (catch ...), reverts to (error "message").
-+
-+ Example of use:
-+
-+ (define (foo x) (write x) (newline) (/ x 0))
-+
-+ (catch (begin (display "Error!\n") 0)
-+ (write "Before foo ... ")
-+ (foo 5)
-+ (write "After foo"))
-+
-+ The exception mechanism can be used even by system errors, by
-+
-+ (define *error-hook* throw)
-+
-+ which makes use of the error hook described above.
-+
-+ If necessary, the user can devise his own exception mechanism with
-+ tagged exceptions etc.
-+
-+
-+ Reader extensions
-+ -----------------
-+
-+ When encountering an unknown character after '#', the user-specified
-+ procedure *sharp-hook* (if any), is called to read the expression.
-+ This can be used to extend the reader to handle user-defined constants
-+ or whatever. It should be a procedure without arguments, reading from
-+ the current input port (which will be the load-port).
-+
-+
-+ Colon Qualifiers - Packages
-+ ---------------------------
-+
-+ When USE_COLON_HOOK=1:
-+ The lexer now recognizes the construction <qualifier>::<symbol> and
-+ transforms it in the following manner (T is the transformation function):
-+
-+ T(<qualifier>::<symbol>) = (*colon-hook* 'T(<symbol>) <qualifier>)
-+
-+ where <qualifier> is a symbol not containing any double-colons.
-+
-+ As the definition is recursive, qualifiers can be nested.
-+ The user can define his own *colon-hook*, to handle qualified names.
-+ By default, "init.scm" defines *colon-hook* as EVAL. Consequently,
-+ the qualifier must denote a Scheme environment, such as one returned
-+ by (interaction-environment). "Init.scm" defines a new syntantic form,
-+ PACKAGE, as a simple example. It is used like this:
-+
-+ (define toto
-+ (package
-+ (define foo 1)
-+ (define bar +)))
-+
-+ foo ==> Error, "foo" undefined
-+ (eval 'foo) ==> Error, "foo" undefined
-+ (eval 'foo toto) ==> 1
-+ toto::foo ==> 1
-+ ((eval 'bar toto) 2 (eval 'foo toto)) ==> 3
-+ (toto::bar 2 toto::foo) ==> 3
-+ (eval (bar 2 foo) toto) ==> 3
-+
-+ If the user installs another package infrastructure, he must define
-+ a new 'package' procedure or macro to retain compatibility with supplied
-+ code.
-+
-+ Note: Older versions used ':' as a qualifier. Unfortunately, the use
-+ of ':' as a pseudo-qualifier in existing code (i.e. SLIB) essentially
-+ precludes its use as a real qualifier.
-+
-+
-+
-+
-+
-+
-+
-+
-diff --git a/bootshell/MiniSCHEMETribute.txt b/bootshell/MiniSCHEMETribute.txt
-new file mode 100644
-index 0000000..02ebd26
---- /dev/null
-+++ b/bootshell/MiniSCHEMETribute.txt
-@@ -0,0 +1,88 @@
-+ TinyScheme would not exist if it wasn't for MiniScheme. I had just
-+ written the HTTP server for Ovrimos SQL Server, and I was lamenting the
-+ lack of a scripting language. Server-side Javascript would have been the
-+ preferred solution, had there been a Javascript interpreter I could
-+ lay my hands on. But there weren't. Perl would have been another solution,
-+ but it was probably ten times bigger that the program it was supposed to
-+ be embedded in. There would also be thorny licencing issues.
-+
-+ So, the obvious thing to do was find a trully small interpreter. Forth
-+ was a language I had once quasi-implemented, but the difficulty of
-+ handling dynamic data and the weirdness of the language put me off. I then
-+ looked around for a LISP interpreter, the next thing I knew was easy to
-+ implement. Alas, the LeLisp I knew from my days in UPMC (Universite Pierre
-+ et Marie Curie) had given way to Common Lisp, a megalith of a language!
-+ Then my search lead me to Scheme, a language I knew was very orthogonal
-+ and clean. When I found Mini-Scheme, a single C file of some 2400 loc, I
-+ fell in love with it! What if it lacked floating-point numbers and
-+ strings! The rest, as they say, is history.
-+
-+ Below are the original credits. Don't email Akira KIDA, the address has
-+ changed.
-+
-+ ---------- Mini-Scheme Interpreter Version 0.85 ----------
-+
-+ coded by Atsushi Moriwaki (11/5/1989)
-+
-+ E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
-+
-+ THIS SOFTWARE IS IN THE PUBLIC DOMAIN
-+ ------------------------------------
-+ This software is completely free to copy, modify and/or re-distribute.
-+ But I would appreciate it if you left my name on the code as the author.
-+
-+ This version has been modified by R.C. Secrist.
-+
-+ Mini-Scheme is now maintained by Akira KIDA.
-+
-+ This is a revised and modified version by Akira KIDA.
-+ current version is 0.85k4 (15 May 1994)
-+
-+ Please send suggestions, bug reports and/or requests to:
-+ <SDI00379@niftyserve.or.jp>
-+
-+
-+ Features compared to MiniSCHEME
-+ -------------------------------
-+
-+ All code is now reentrant. Interpreter state is held in a 'scheme'
-+ struct, and many interpreters can coexist in the same program, possibly
-+ in different threads. The user can specify user-defined memory allocation
-+ primitives. (see "Programmer's Reference")
-+
-+ The reader is more consistent.
-+
-+ Strings, characters and flonums are supported. (see "Types")
-+
-+ Files being loaded can be nested up to some depth.
-+
-+ R5RS I/O is there, plus String Ports. (see "Scheme Reference","I/O")
-+
-+ Vectors exist.
-+
-+ As a standalone application, it supports command-line arguments.
-+ (see "Standalone")
-+
-+ Running out of memory is now handled.
-+
-+ The user can add foreign functions in C. (see "Foreign Functions")
-+
-+ The code has been changed slightly, core functions have been moved
-+ to the library, behavior has been aligned with R5RS etc.
-+
-+ Support has been added for user-defined error recovery.
-+ (see "Error Handling")
-+
-+ Support has been added for modular programming.
-+ (see "Colon Qualifiers - Packages")
-+
-+ To enable this, EVAL has changed internally, and can
-+ now take two arguments, as per R5RS. Environments are supported.
-+ (see "Colon Qualifiers - Packages")
-+
-+ Promises are now evaluated once only.
-+
-+ (macro (foo form) ...) is now equivalent to (macro foo (lambda(form) ...))
-+
-+ The reader can be extended using new #-expressions
-+ (see "Reader extensions")
-diff --git a/bootshell/boot.scm b/bootshell/boot.scm
-new file mode 100644
-index 0000000..f6b4d25
---- /dev/null
-+++ b/bootshell/boot.scm
-@@ -0,0 +1,249 @@
-+;; Missing library functions.
-+(define (filter pred lst)
-+ (cond ((null? lst) '())
-+ ((pred (car lst))
-+ (cons (car lst) (filter pred (cdr lst))))
-+ (else (filter pred (cdr lst)))))
-+
-+(define (any p l)
-+ (cond ((null? l) #f)
-+ ((p (car l)) #t)
-+ (else (any p (cdr l)))))
-+
-+;; Is s1 a prefix of s2 ?
-+(define (string-prefix? s1 s2)
-+ (and (>= (string-length s2) (string-length s1))
-+ (string=? s1 (substring s2 0 (string-length s1)))))
-+
-+;; Given a list of prefixes, does s start with any of them ?
-+(define (string-prefix-any? lp s)
-+ (any (lambda (p) (string-prefix? p s)) lp))
-+
-+;; The `catch' from init.scm doesn't give the thrown value to the
-+;; handler. XXX: Crappy workaround.
-+(define last-exception '())
-+(define (throw . x)
-+ (set! last-exception x)
-+ (if (more-handlers?)
-+ (apply (pop-handler))
-+ (apply error x)))
-+(define *error-hook* throw)
-+
-+;; Foreign function interface.
-+
-+(define (ffi-apply name f args)
-+ (let ((result (apply f args)))
-+ (cond
-+ ((null? result) (throw "Got NULL."))
-+ ((not (= (car result) 0)) (throw (string-append
-+ name ": " (strerror (car result)))))
-+ ((and (= (car result) 0) (pair? (cdr result))) (cadr result))
-+ ((= (car result) 0) '())
-+ (else
-+ (throw "Weird.")))))
-+
-+;; Convenience functions.
-+(define (echo . msg)
-+ (map display msg)
-+ (newline))
-+
-+(define (trace-show x)
-+ (write x)
-+ x)
-+
-+; Semi-crappy repl using `prompt' function.
-+(define (shell p)
-+ (let ((prefix ""))
-+ (do () (#f)
-+ (let ((line (prompt (p prefix))))
-+ (set! prefix (string-append prefix line))
-+
-+ (if (> (string-length prefix) 0)
-+ (let ((c (read (open-input-string prefix))))
-+ (cond
-+ ((eof-object? c) ())
-+ (else (catch (echo "Error: " last-exception)
-+ (echo " ===> " (eval c)))
-+ (set! prefix "")))))))))
-+
-+; unfortunately, this doesn't work
-+;(define (shell p)
-+; (display (p))
-+; (eval (read))
-+; (shell p))
-+
-+(define version "bootshell/TinySCHEME 1.41")
-+
-+(define (prompt-append-prefix prompt prefix)
-+ (string-append prompt (if (> (string-length prefix) 0)
-+ (string-append prefix " ... ")
-+ "> ")))
-+
-+(define (interactive-repl)
-+ (shell (lambda (p) (prompt-append-prefix "(bootshell) " p))))
-+
-+(define (emergency-shell)
-+ (shell (lambda (p) (prompt-append-prefix "(emergency-shell) " p))))
-+
-+(define (panic . msg)
-+ (display "\n\npanic: ")
-+ (map display msg)
-+ (newline)
-+ (emergency-shell))
-+
-+;; port management
-+(define (mach-port-valid? p) (not (or (= p MACH_PORT_NULL)
-+ (= p MACH_PORT_DEAD))))
-+
-+(define (make-send-right receive-right)
-+ (mach-port-insert-right mach-task-self receive-right receive-right
-+ MACH_MSG_TYPE_MAKE_SEND))
-+(define (copy-send-right send-right)
-+ (mach-port-insert-right mach-task-self send-right send-right
-+ MACH_MSG_TYPE_COPY_SEND))
-+
-+;; Binds a send right to an identifier, much like `let'. Deallocates
-+;; the send right once it goes out of scope.
-+(macro (letport form)
-+ (let ((result-sym (gensym)))
-+ `((lambda ((,@(caaadr form)))
-+ (let ((,result-sym
-+ ,(if (= 1 (length (cadr form)))
-+ `(begin ,@(cddr form))
-+ `(letport ,(cdadr form) ,@(cddr form)))))
-+ (if (mach-port-valid? ,(caaadr form))
-+ (mach-port-deallocate mach-task-self ,(caaadr form)))
-+ ,result-sym)) ,@(cdaadr form))))
-+
-+;; TinySCHEME doesn't have define-syntax :(
-+;;
-+;; (define-syntax letport
-+;; (syntax-rules ()
-+;; ((letport ((var expr) ...) body ...)
-+;; ((lambda expressions
-+;; (let ((result (apply (lambda (var ...) body ...) expressions)))
-+;; (map (lambda (p) (mach-port-deallocate mach-task-self p))
-+;; expressions)
-+;; result)) expr ...))))
-+
-+;; task management
-+
-+(define (task-get-kernel-port t)
-+ (task-get-special-port t TASK_KERNEL_PORT))
-+(define (task-get-exception-port t)
-+ (task-get-special-port t TASK_EXCEPTION_PORT))
-+(define (task-get-bootstrap-port t)
-+ (task-get-special-port t TASK_BOOTSTRAP_PORT))
-+
-+(define (task-set-kernel-port t p)
-+ (task-set-special-port t TASK_KERNEL_PORT p))
-+(define (task-set-exception-port t p)
-+ (task-set-special-port t TASK_EXCEPTION_PORT p))
-+(define (task-set-bootstrap-port t p)
-+ (task-set-special-port t TASK_BOOTSTRAP_PORT p))
-+
-+;; Hurd server bootstrap.
-+
-+(define ESUCCESS 0) ;
-+
-+;; translator linkage
-+
-+(define (set-active-translator path active-control)
-+ (letport ((node (file-name-lookup path O_NOTRANS 438))) ;;=^= 0666
-+ (file-set-translator node 0 FS_TRANS_SET 0 0 0
-+ active-control MACH_MSG_TYPE_COPY_SEND)))
-+
-+;; Wait for the predicate CONDITION to return #t, or throw 'timeout
-+;; after T microseconds.
-+(define (wait-for condition t)
-+ (if (<= t 0)
-+ (throw 'timeout)
-+ (if (not (condition))
-+ (begin (usleep 10000)
-+ (wait-for condition (- t 10000))))))
-+
-+;; Read a word from port P.
-+(define (read-word p)
-+ (list->string
-+ (let f ()
-+ (let ((c (peek-char p)))
-+ (cond
-+ ((eof-object? c) '())
-+ ((char-alphabetic? c)
-+ (read-char p)
-+ (cons c (f)))
-+ (else '()))))))
-+
-+;; Read everything from port P.
-+(define (read-all p)
-+ (list->string
-+ (let f ()
-+ (let ((c (peek-char p)))
-+ (cond
-+ ((eof-object? c) '())
-+ (else (read-char p)
-+ (cons c (f))))))))
-+
-+;; Shell-like functions.
-+
-+(define cd chdir)
-+(define (pwd) (echo (getcwd)))
-+(define (cat path)
-+ (display (call-with-input-file path read-all)))
-+(define (hostname)
-+ ((lambda (x) (if (string? x) x "unnamed"))
-+ (call-with-input-file "/etc/hostname" read-word)))
-+
-+(define (print-banner)
-+ (echo "
-+Welcome to bootshell, a scheme shell. Type `(help)' for help.
-+"))
-+
-+(define (reboot-hurd)
-+ (letport ((startup (file-name-lookup "/servers/startup" 0 0)))
-+ (startup-reboot startup host-priv RB_AUTOBOOT)))
-+
-+(define (halt-hurd)
-+ (letport ((startup (file-name-lookup "/servers/startup" 0 0)))
-+ (startup-reboot startup host-priv RB_HALT)))
-+
-+(define (reboot-mach) (host-reboot host-priv RB_AUTOBOOT))
-+(define (halt-mach) (host-reboot host-priv RB_HALT))
-+(define (kdb-mach) (host-reboot host-priv RB_DEBUGGER))
-+
-+(define (reboot)
-+ (catch (reboot-mach)
-+ (reboot-hurd)))
-+(define (halt)
-+ (catch (halt-mach)
-+ (halt-hurd)))
-+
-+;; Online documentation.
-+
-+(define (help)
-+ (echo "Welcome to the Hurd boot shell. XXX this is not up to date :(
-+
-+Functions
-+ General shell-like functions
-+ cat cd echo halt help hostname kdb mach-print panic prompt pwd
-+ reboot shell sleep {reboot,halt}-{mach,hurd}
-+" "
-+ Mach related
-+ mach-port-valid? {copy,make}-send-right task-{create,resume,terminate}
-+ task-{g,s}et-{special,kernel,exception,bootstrap}-port host-reboot
-+" "
-+ Hurd related
-+ file_name_lookup chdir getcwd startup-reboot
-+ XXX write them
-+ {s,g}etauth {s,g}etproc file_name_lookup_under file_name_path_lookup
-+" "
-+Environment:
-+ mach-task-self exception-port bootstrap-port host-priv device-master
-+ rootfs-task hello-task rootfs-control"))
-+
-+;; XXX
-+
-+(define log display)
-+
-+;; We're ready.
-+(echo version ".")
-diff --git a/bootshell/bootshell.h b/bootshell/bootshell.h
-new file mode 100644
-index 0000000..2112f83
---- /dev/null
-+++ b/bootshell/bootshell.h
-@@ -0,0 +1,32 @@
-+#ifndef _HURD_BOOTSHELL_H
-+#define _HURD_BOOTSHELL_H
-+
-+#include <mach.h>
-+
-+extern mach_port_t portarray_template[];
-+
-+/* We catch exceptions using this port. */
-+extern mach_port_t exception_port;
-+
-+extern mach_port_t console;
-+extern mach_port_t rootnode;
-+
-+error_t init_exception_handling (void);
-+error_t init_fs_server (void);
-+
-+void mach_print(const char *);
-+void mach_printf(const char *format, ...);
-+
-+mach_msg_return_t
-+mach_msg_server_timeout_once (boolean_t (*demux) (mach_msg_header_t *request,
-+ mach_msg_header_t *reply),
-+ mach_msg_size_t max_size,
-+ mach_port_t rcv_name,
-+ mach_msg_option_t option,
-+ mach_msg_timeout_t timeout,
-+ mach_msg_id_t *msgh_id);
-+
-+#define TRACE error (0, 0, "%s:%d", __FUNCTION__, __LINE__);
-+#define TR mach_printf ("%s:%d\n", __FUNCTION__, __LINE__);
-+
-+#endif
-diff --git a/bootshell/exceptions.c b/bootshell/exceptions.c
-new file mode 100644
-index 0000000..0ad6ada
---- /dev/null
-+++ b/bootshell/exceptions.c
-@@ -0,0 +1,72 @@
-+#include <mach.h>
-+/* Mach exception handling. */
-+#include <pthread.h>
-+// eek #include "exc_S.h"
-+
-+#include "bootshell.h"
-+
-+error_t
-+catch_exception_raise (mach_port_t e,
-+ thread_t thread,
-+ task_t task,
-+ int exception, int code, int subcode)
-+{
-+ if (e != exception_port)
-+ return EOPNOTSUPP;
-+
-+ mach_printf ("catch_exception_raise (%d, %d, %d, %d, %d): ",
-+ thread, task, exception, code, subcode);
-+
-+ if (task == mach_task_self ())
-+ mach_print ("terminating bootshell. bye.\n");
-+ else
-+ mach_printf ("terminating task %d.\n", task);
-+
-+ task_terminate (task);
-+ return 0;
-+}
-+
-+static void *
-+service_exception_requests (void *arg)
-+{
-+ extern boolean_t exc_server (mach_msg_header_t *, mach_msg_header_t *);
-+
-+ while (1)
-+ mach_msg_server (exc_server, 0, exception_port);
-+
-+ /* Not reached. */
-+ return NULL;
-+}
-+
-+error_t
-+init_exception_handling (void)
-+{
-+ error_t err;
-+ pthread_t t;
-+
-+ err = mach_port_allocate (mach_task_self (),
-+ MACH_PORT_RIGHT_RECEIVE,
-+ &exception_port);
-+ if (err)
-+ return err;
-+
-+ /* Make a thread to service exception requests. */
-+ err = pthread_create (&t, NULL, service_exception_requests, NULL);
-+ if (err)
-+ return err;
-+ pthread_detach (t);
-+
-+ err = mach_port_insert_right (mach_task_self (),
-+ exception_port,
-+ exception_port,
-+ MACH_MSG_TYPE_MAKE_SEND);
-+ if (err)
-+ return err;
-+
-+ err = task_set_exception_port (mach_task_self (), exception_port);
-+ if (err)
-+ return err;
-+
-+ return err;
-+}
-+
-diff --git a/bootshell/exec-startup.c b/bootshell/exec-startup.c
-new file mode 100644
-index 0000000..b036a4b
---- /dev/null
-+++ b/bootshell/exec-startup.c
-@@ -0,0 +1,162 @@
-+#include <assert.h>
-+#include <hurd.h>
-+#include <hurd/paths.h>
-+#include <mach.h>
-+#include <mach/message.h>
-+#include <stdio.h>
-+#include <sys/mman.h>
-+
-+// eek #include "fsys_S.h"
-+
-+#include "bootshell.h"
-+#include "ffi.h"
-+
-+/* XXX would be nice not to use a global variable, maybe with
-+ payloads. */
-+static struct
-+{
-+ /* Filled by caller. */
-+ mach_port_t bootstrap_port;
-+ char *argz;
-+ size_t argz_len;
-+
-+ /* Filled by the server function. */
-+} exec_startup_get_info_args;
-+
-+/* We look like an execserver to the execserver itself; it makes this
-+ call (as does any task) to get its state. We can't give it all of
-+ its ports (we'll provide those with a later call to exec_init). */
-+kern_return_t
-+S_exec_startup_get_info (mach_port_t bootstrap_port,
-+ vm_address_t *user_entry,
-+ vm_address_t *phdr_data,
-+ vm_size_t *phdr_size,
-+ vm_address_t *base_addr,
-+ vm_size_t *stack_size,
-+ int *flags,
-+ char **argz,
-+ mach_msg_type_number_t *argz_len,
-+ char **envz,
-+ mach_msg_type_number_t *envz_len,
-+ mach_port_t **dtableP,
-+ mach_msg_type_name_t *dtablepoly,
-+ mach_msg_type_number_t *dtablelen,
-+ mach_port_t **portarrayP,
-+ mach_msg_type_name_t *portarraypoly,
-+ mach_msg_type_number_t *portarraylen,
-+ int **intarrayP,
-+ mach_msg_type_number_t *intarraylen)
-+{
-+ error_t err;
-+ mach_port_t *portarray, *dtable;
-+ mach_port_t rootport;
-+
-+ if (bootstrap_port != exec_startup_get_info_args.bootstrap_port)
-+ return EOPNOTSUPP;
-+
-+ *user_entry = 0;
-+ *phdr_data = *base_addr = 0;
-+ *phdr_size = *stack_size = 0;
-+
-+ *flags = 0;
-+
-+ /* Arguments. */
-+ *argz_len = exec_startup_get_info_args.argz_len;
-+ if (*argz_len == 0)
-+ /* We have no args for it. Tell it to look on its stack
-+ for the args placed there by the boot loader. */
-+ *flags |= EXEC_STACK_ARGS;
-+ else
-+ {
-+ err = vm_allocate (mach_task_self (), argz, *argz_len, TRUE);
-+ if (err)
-+ return err;
-+ memcpy (*argz, exec_startup_get_info_args.argz, *argz_len);
-+ }
-+
-+ /* Environment. */
-+ *envz = NULL;
-+ *envz_len = 0;
-+
-+ /* File descriptors. */
-+ if (*dtablelen < 3)
-+ *dtableP = mmap (0, 3 * sizeof (mach_port_t), PROT_READ|PROT_WRITE,
-+ MAP_ANON, 0, 0);
-+ dtable = *dtableP;
-+ *dtablepoly = MACH_MSG_TYPE_COPY_SEND;
-+ *dtablelen = 3;
-+ dtable[0] = dtable[1] = dtable[2] = console;
-+
-+ /* Initial ports. */
-+ if (*portarraylen < INIT_PORT_MAX)
-+ *portarrayP = mmap (0, INIT_PORT_MAX * sizeof (mach_port_t),
-+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
-+ portarray = *portarrayP;
-+ *portarraylen = INIT_PORT_MAX;
-+ memcpy (portarray, portarray_template, INIT_PORT_MAX * sizeof *portarray);
-+ portarray[INIT_PORT_BOOTSTRAP] = bootstrap_port; /* use the same port */
-+ *portarraypoly = MACH_MSG_TYPE_COPY_SEND;
-+
-+ /* Initial ints. */
-+ *intarrayP = NULL;
-+ *intarraylen = 0;
-+
-+ return 0;
-+}
-+
-+boolean_t
-+exec_startup_get_info_demuxer (mach_msg_header_t *request,
-+ mach_msg_header_t *reply)
-+{
-+ extern boolean_t exec_startup_server (mach_msg_header_t *,
-+ mach_msg_header_t *);
-+ if (request->msgh_id != 30500) /* XXX hardcoded msgh_id */
-+ {
-+ /* Return MIG_BAD_ID. */
-+ mig_reply_setup (request, reply);
-+ return FALSE;
-+ }
-+ return exec_startup_server (request, reply);
-+}
-+
-+error_t
-+service_exec_startup_request (mach_port_t bootstrap,
-+ char *argz,
-+ size_t argz_len,
-+ mach_msg_timeout_t timeout)
-+{
-+ error_t err;
-+ mach_msg_id_t msgh_id;
-+
-+ if (! MACH_PORT_VALID (bootstrap))
-+ return EINVAL;
-+
-+ exec_startup_get_info_args.bootstrap_port = bootstrap;
-+ exec_startup_get_info_args.argz = argz;
-+ exec_startup_get_info_args.argz_len = argz_len;
-+
-+ err = mach_msg_server_timeout_once (exec_startup_get_info_demuxer,
-+ 0, bootstrap,
-+ MACH_RCV_TIMEOUT|MACH_SEND_TIMEOUT,
-+ timeout, &msgh_id);
-+ if (err != MACH_MSG_SUCCESS)
-+ return err;
-+
-+ return 0;
-+}
-+
-+pointer
-+do__handle_exec_startup (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("handle-exec-startup");
-+ SC_ARG (sc, mach_port_t, bootstrap, number, args);
-+ SC_ARG (sc, pointer, arguments, list, args);
-+ SC_ARG (sc, mach_msg_timeout_t, timeout, number, args);
-+ SC_ARGS_DONE (sc);
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+ ffi_list2argz (sc, &argz, &argz_len, arguments);
-+ err = service_exec_startup_request (bootstrap, argz, argz_len, timeout);
-+ free (argz);
-+ SC_RETURN (sc);
-+}
-diff --git a/bootshell/ffi.c b/bootshell/ffi.c
-new file mode 100644
-index 0000000..8cee903
---- /dev/null
-+++ b/bootshell/ffi.c
-@@ -0,0 +1,819 @@
-+#include <argz.h>
-+#include <assert.h>
-+#include <ctype.h>
-+#include <device/device.h>
-+#include <errno.h>
-+#include <error.h>
-+#include <fcntl.h>
-+#include <hurd.h>
-+#include <hurd/fsys.h>
-+#include <mach.h>
-+#include <mach/gnumach.h>
-+#include <sys/reboot.h>
-+#include <sys/mman.h>
-+#include <string.h>
-+#include <unistd.h>
-+
-+#include "bootshell.h"
-+#include "ffi.h"
-+
-+#include "startup.h"
-+
-+#define is_false(p) ((p) == sc->F)
-+
-+pointer
-+do_mach_print (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("mach_print");
-+ int dirty = 0;
-+ while (args && is_string (pair_car (args)))
-+ {
-+ const char *v = string_value (pair_car (args));
-+ if (dirty)
-+ mach_print (" ");
-+ mach_print (v);
-+ dirty = 1;
-+ args = pair_cdr (args);
-+ }
-+ SC_RETURN (sc);
-+}
-+
-+char *rl_gets (const char *prompt);
-+
-+pointer
-+do__prompt (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("prompt");
-+ SC_ARG (sc, char *, prompt, string, args);
-+ SC_ARGS_DONE (sc);
-+ const char *line = rl_gets (prompt);
-+ ffi_update (sc);
-+ SC_RETURN_STRING (sc, line);
-+}
-+
-+pointer
-+do_trace (scheme *sc, pointer args)
-+{
-+ sc->tracing = args != sc->NIL && ! is_false (pair_car (args));
-+ return sc->NIL;
-+}
-+
-+pointer
-+do__host_reboot (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("host-reboot");
-+ SC_ARG (sc, mach_port_t, host_priv, number, args);
-+ SC_ARG (sc, int, flags, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = host_reboot (host_priv, flags);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__task_create (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-create");
-+ SC_ARG (sc, task_t, parent, number, args);
-+ SC_ARG (sc, boolean_t, inherit_memory, number, args);
-+ SC_ARGS_DONE (sc);
-+ task_t task;
-+ err = task_create (parent, inherit_memory, &task);
-+ SC_RETURN_INT (sc, task);
-+}
-+
-+pointer
-+do__task_resume (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-resume");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = task_resume (task);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__task_terminate (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-terminate");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = task_terminate (task);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_sleep (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("sleep");
-+ SC_ARG (sc, unsigned int, seconds, number, args);
-+ SC_ARGS_DONE (sc);
-+ sleep (seconds);
-+ ffi_update (sc);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do_usleep (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("usleep");
-+ SC_ARG (sc, useconds_t, microseconds, number, args);
-+ SC_ARGS_DONE (sc);
-+ usleep (microseconds);
-+ ffi_update (sc);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__file_name_lookup (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("file-name-lookup");
-+ SC_ARG (sc, char *, name, string, args);
-+ SC_ARG (sc, int, flags, number, args);
-+ SC_ARG (sc, mode_t, mode, number, args);
-+ SC_ARGS_DONE (sc);
-+ file_t file = file_name_lookup (name, flags, mode);
-+ if (! MACH_PORT_VALID (file))
-+ SC_RETURN_ERR (sc, errno);
-+ SC_RETURN_INT (sc, file);
-+}
-+
-+pointer
-+do__chdir (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("chdir");
-+ SC_ARG (sc, char *, name, string, args);
-+ SC_ARGS_DONE (sc);
-+ if (chdir (name))
-+ SC_RETURN_ERR (sc, errno);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__strerror (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("strerror");
-+ SC_ARG (sc, int, error, number, args);
-+ SC_ARGS_DONE (sc);
-+ char *s, buf[128];
-+ s = strerror_r (error, buf, sizeof buf);
-+ SC_RETURN_STRING (sc, s);
-+}
-+
-+pointer
-+do__getproc (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("getproc");
-+ SC_ARGS_DONE (sc);
-+ SC_RETURN_INT (sc, getproc ());
-+}
-+
-+pointer
-+do__getcwd (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("getcwd");
-+ SC_ARGS_DONE (sc);
-+ SC_RETURN_STRING (sc, get_current_dir_name ());
-+}
-+
-+pointer
-+do__mach_port_allocate (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("mach-port-allocate");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, mach_port_t, right, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t name;
-+ err = mach_port_allocate (task, right, &name);
-+ SC_RETURN_INT (sc, name);
-+}
-+
-+pointer
-+do__mach_port_deallocate (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("mach-port-deallocate");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, mach_port_t, right, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = mach_port_deallocate (task, right);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__mach_port_destroy (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("mach-port-destroy");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, mach_port_t, right, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = mach_port_destroy (task, right);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__mach_port_insert_right (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("mach-port-insert-right");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, mach_port_t, name, number, args);
-+ SC_ARG (sc, mach_port_t, right, number, args);
-+ SC_ARG (sc, mach_msg_type_name_t, right_type, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = mach_port_insert_right (task, name, right, right_type);
-+ SC_RETURN_INT (sc, right);
-+}
-+
-+pointer
-+do__task_get_special_port (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-get-special-port");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, int, which, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t special_port;
-+ err = task_get_special_port (task, which, &special_port);
-+ SC_RETURN_INT (sc, special_port);
-+}
-+
-+pointer
-+do__task_set_special_port (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("task-set-special-port");
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, int, which, number, args);
-+ SC_ARG (sc, mach_port_t, special_port, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = task_set_special_port (task, which, special_port);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__device_open (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("device-open");
-+ SC_ARG (sc, mach_port_t, master, number, args);
-+ SC_ARG (sc, int, flags, number, args);
-+ SC_ARG (sc, char *, name, string, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t device;
-+ err = device_open (master, flags, name, &device);
-+ SC_RETURN_INT (sc, device);
-+}
-+
-+/* Hurd functions. */
-+pointer
-+do__handle_fsys_startup (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("handle-fsys-startup");
-+ SC_ARG (sc, mach_port_t, bootstrap, number, args);
-+ SC_ARG (sc, mach_port_t, realnode, number, args);
-+ SC_ARG (sc, mach_msg_type_name_t, realnodePoly, number, args);
-+ SC_ARG (sc, mach_msg_timeout_t, timeout, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t control;
-+ err = service_fsys_request (bootstrap,
-+ realnode,
-+ realnodePoly,
-+ timeout,
-+ &control);
-+ SC_RETURN_INT (sc, control);
-+}
-+
-+pointer
-+do__bind_root (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("_bind-root");
-+ SC_ARG (sc, mach_port_t, control, number, args);
-+ SC_ARG (sc, file_t, dotdot_node, number, args);
-+ SC_ARGS_DONE (sc);
-+ if (! MACH_PORT_VALID (control)
-+ || ! MACH_PORT_VALID (dotdot_node))
-+ SC_RETURN_ERR (sc, EINVAL);
-+
-+ if (_hurd_ports)
-+ SC_RETURN_ERR (sc, EPERM); /* XXX */
-+
-+ uid_t uids[1] = { 0 };
-+ size_t uids_len = 1;
-+ gid_t gids[1] = { 0 };
-+ size_t gids_len = 1;
-+
-+ retry_type retry;
-+ char retryname[1024]; /* XXX */
-+ file_t root;
-+ err = fsys_getroot (control,
-+ dotdot_node,
-+ MACH_MSG_TYPE_MAKE_SEND,
-+ uids, uids_len,
-+ gids, gids_len,
-+ (O_READ|O_EXEC),
-+ &retry,
-+ retryname,
-+ &root);
-+ if (err)
-+ SC_RETURN (sc);
-+
-+ // XXX check root
-+ portarray_template[INIT_PORT_CRDIR] = root;
-+ portarray_template[INIT_PORT_CWDIR] = root;
-+
-+ err = mach_port_mod_refs (mach_task_self (),
-+ root, MACH_PORT_RIGHT_SEND, +2);
-+ assert_perror (err);
-+
-+ /* We have no portarray or intarray because there was no
-+ exec_startup data; _hurd_init was never called. We now have the
-+ crucial ports, so create a portarray and call _hurd_init. */
-+ mach_port_t *portarray;
-+ portarray = mmap (0, INIT_PORT_MAX * sizeof *portarray,
-+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
-+ memcpy (portarray, portarray_template, INIT_PORT_MAX * sizeof *portarray);
-+ _hurd_init (0, NULL, portarray, INIT_PORT_MAX, NULL, 0);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__bind_proc (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("bind-proc");
-+ SC_ARG (sc, mach_port_t, procserver, number, args);
-+ SC_ARGS_DONE (sc);
-+ /* Give the library our proc server port. */
-+ _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], procserver);
-+ err = mach_port_mod_refs (mach_task_self (),
-+ procserver, MACH_PORT_RIGHT_SEND, +1);
-+ assert_perror (err);
-+ // dealloc ?
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__bind_auth (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("bind-auth");
-+ SC_ARG (sc, mach_port_t, authserver, number, args);
-+ SC_ARGS_DONE (sc);
-+ /* Give the library our auth and proc server ports. */
-+ _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver);
-+ portarray_template[INIT_PORT_AUTH] = authserver;
-+ // dealloc ?
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__fsys_init (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("fsys-init!");
-+ SC_ARG (sc, mach_port_t, fsys, number, args);
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARG (sc, mach_port_t, auth, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = fsys_init (fsys, proc, MACH_MSG_TYPE_COPY_SEND, auth);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__proc_task2proc (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc-task2proc");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t result;
-+ err = proc_task2proc (proc, task, &result);
-+ SC_RETURN_INT (sc, result);
-+}
-+
-+pointer
-+do__proc_mark_exec (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc-mark-exec!");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = proc_mark_exec (proc);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__proc_mark_important (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc->mark-important!");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = proc_mark_important (proc);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__proc_child (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc->proc->child!");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARG (sc, mach_port_t, child, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = proc_child (proc, child);
-+ if (err) error (0, err, "proc_child");
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__proc_set_init_task (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("proc->task->set-init-task!");
-+ SC_ARG (sc, mach_port_t, proc, number, args);
-+ SC_ARG (sc, mach_port_t, task, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = proc_set_init_task (proc, task);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__file_set_translator (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("file-set-translator");
-+ SC_ARG (sc, file_t, node, number, args);
-+ SC_ARG (sc, int, passive_flags, number, args);
-+ SC_ARG (sc, int, active_flags, number, args);
-+ SC_ARG (sc, int, goaway_flags, number, args);
-+ SC_ARG (sc, int, argz, number, args); //XXX
-+ SC_ARG (sc, int, argz_len, number, args); //XXX
-+ argz = argz_len = 0;
-+
-+ SC_ARG (sc, mach_port_t, active_control, number, args);
-+ SC_ARG (sc, mach_msg_type_name_t, active_controlPoly, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = file_set_translator (node,
-+ passive_flags, active_flags, goaway_flags,
-+ argz, argz_len,
-+ active_control, active_controlPoly);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+ffi_argz2list (scheme *sc, const char *argz, size_t argz_len, const char *entry)
-+{
-+ entry = argz_next (argz, argz_len, entry);
-+ if (argz == NULL || argz_len == 0 || entry == NULL)
-+ return sc->NIL;
-+ return _cons (sc,
-+ mk_string (sc, entry),
-+ ffi_argz2list (sc, argz, argz_len, entry),
-+ 1);
-+}
-+
-+void
-+ffi_list2argz (scheme *sc, char **argz, size_t *argz_len, pointer list)
-+{
-+ while (sc->vptr->is_pair (list))
-+ {
-+ argz_add (argz, argz_len, string_value (sc->vptr->pair_car (list)));
-+ list = sc->vptr->pair_cdr (list);
-+ }
-+}
-+
-+// XXX
-+pointer
-+do___exec (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("_exec");
-+ process_t proc, child_proc = MACH_PORT_NULL;
-+ mach_port_t dtable[STDERR_FILENO+1];
-+ mach_port_t portarray[INIT_PORT_MAX];
-+ int default_ints[INIT_INT_MAX];
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+ int i;
-+
-+ SC_ARG (sc, file_t, file, number, args);
-+ SC_ARG (sc, task_t, task, number, args);
-+ SC_ARG (sc, pointer, arguments, list, args);
-+ ffi_list2argz (sc, &argz, &argz_len, arguments);
-+ SC_ARG (sc, mach_port_t, bootstrap, number, args);
-+ SC_ARGS_DONE (sc);
-+
-+ proc = getproc ();
-+ if (MACH_PORT_VALID (proc))
-+ {
-+ err = proc_task2proc (proc, task, &child_proc);
-+ if (err)
-+ SC_RETURN (sc);
-+ }
-+
-+ dtable[STDIN_FILENO] = getdport (STDIN_FILENO);
-+ dtable[STDOUT_FILENO] = getdport (STDOUT_FILENO);
-+ dtable[STDERR_FILENO] = getdport (STDERR_FILENO);
-+
-+ memcpy (portarray, portarray_template, INIT_PORT_MAX * sizeof *portarray);
-+ portarray[INIT_PORT_CWDIR] = getcwdir ();
-+ portarray[INIT_PORT_CRDIR] = getcrdir ();
-+ portarray[INIT_PORT_PROC] = child_proc;
-+ portarray[INIT_PORT_BOOTSTRAP] = bootstrap;
-+
-+ memset (default_ints, 0, INIT_INT_MAX * sizeof *default_ints);
-+ /* All programs we start should ignore job control stop signals.
-+ That way Posix.1 B.2.2.2 is satisfied where it says that programs
-+ not run under job control shells are protected. */
-+ default_ints[INIT_SIGIGN] = (sigmask (SIGTSTP)
-+ | sigmask (SIGTTIN)
-+ | sigmask (SIGTTOU));
-+
-+ err = task_set_name (task, argz);
-+ if (err)
-+ {
-+ error (0, err, "task_set_name");
-+ goto lose;
-+ }
-+
-+ err = file_exec (file, task, 0,
-+ argz, argz_len,
-+ NULL, 0, /* env, env_len */
-+ dtable, MACH_MSG_TYPE_COPY_SEND, 3,
-+ portarray, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
-+ default_ints, INIT_INT_MAX,
-+ NULL, 0, NULL, 0);
-+ SC_RETURN_INT (sc, task);
-+
-+ lose:
-+ for (i = 0; i < STDERR_FILENO+1; i++)
-+ if (MACH_PORT_VALID (dtable[i]))
-+ {
-+ error_t err = mach_port_deallocate (mach_task_self (), dtable[i]);
-+ assert_perror (err);
-+ }
-+ for (i = 0; i < INIT_PORT_MAX; i++)
-+ if (MACH_PORT_VALID (portarray[i]))
-+ {
-+ error_t err = mach_port_deallocate (mach_task_self (), portarray[i]);
-+ assert_perror (err);
-+ }
-+
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__file_get_fs_options (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("file-get-fs-options");
-+ SC_ARG (sc, file_t, node, number, args);
-+ SC_ARGS_DONE (sc);
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+ pointer result;
-+ err = file_get_fs_options (node, &argz, &argz_len);
-+ if (err)
-+ SC_RETURN (sc);
-+ result = ffi_argz2list (sc, argz, argz_len, NULL);
-+ vm_deallocate (mach_task_self (), (vm_address_t) argz, argz_len);
-+ SC_RETURN_POINTER (sc, result);
-+}
-+
-+const char *
-+schemify_name (const char *s, int macro)
-+{
-+ char *n = strdup (s), *p;
-+ if (n == NULL)
-+ return s;
-+ for (p = n; *p; p++)
-+ {
-+ *p = (char) tolower (*p);
-+ /* We convert _ to - in identifiers. We allow, however, for
-+ function names to start with a leading _. The functions in
-+ this namespace are not yet finalized and might change or
-+ vanish without warning. Use them with care. */
-+ if (! macro
-+ && p != n
-+ && *p == '_')
-+ *p = '-';
-+ }
-+ return n;
-+}
-+
-+void
-+ffi_update (scheme *sc)
-+{
-+ // XXX nothng
-+}
-+
-+void
-+ffi_init (scheme *sc)
-+{
-+ define_constant (sc, MACH_PORT_NULL);
-+ define_constant (sc, MACH_PORT_DEAD); // XXX signedness
-+
-+ define_constant (sc, MACH_MSG_TYPE_UNSTRUCTURED);
-+ define_constant (sc, MACH_MSG_TYPE_BIT);
-+ define_constant (sc, MACH_MSG_TYPE_BOOLEAN);
-+ define_constant (sc, MACH_MSG_TYPE_INTEGER_16);
-+ define_constant (sc, MACH_MSG_TYPE_INTEGER_32);
-+ define_constant (sc, MACH_MSG_TYPE_CHAR);
-+ define_constant (sc, MACH_MSG_TYPE_BYTE);
-+ define_constant (sc, MACH_MSG_TYPE_INTEGER_8);
-+ define_constant (sc, MACH_MSG_TYPE_REAL);
-+ define_constant (sc, MACH_MSG_TYPE_INTEGER_64);
-+ define_constant (sc, MACH_MSG_TYPE_STRING);
-+ define_constant (sc, MACH_MSG_TYPE_STRING_C);
-+ define_constant (sc, MACH_MSG_TYPE_MOVE_RECEIVE);
-+ define_constant (sc, MACH_MSG_TYPE_MOVE_SEND);
-+ define_constant (sc, MACH_MSG_TYPE_MOVE_SEND_ONCE);
-+ define_constant (sc, MACH_MSG_TYPE_COPY_SEND);
-+ define_constant (sc, MACH_MSG_TYPE_MAKE_SEND);
-+ define_constant (sc, MACH_MSG_TYPE_MAKE_SEND_ONCE);
-+ define_constant (sc, MACH_MSG_TYPE_PORT_NAME);
-+ define_constant (sc, MACH_MSG_TYPE_PORT_RECEIVE);
-+ define_constant (sc, MACH_MSG_TYPE_PORT_SEND);
-+ define_constant (sc, MACH_MSG_TYPE_PORT_SEND_ONCE);
-+ define_constant (sc, MACH_MSG_TYPE_PROTECTED_PAYLOAD);
-+ define_constant (sc, MACH_MSG_TYPE_LAST);
-+ define_constant (sc, MACH_MSG_TYPE_POLYMORPHIC);
-+
-+ define_constant (sc, MACH_PORT_RIGHT_SEND);
-+ define_constant (sc, MACH_PORT_RIGHT_RECEIVE);
-+ define_constant (sc, MACH_PORT_RIGHT_SEND_ONCE);
-+ define_constant (sc, MACH_PORT_RIGHT_PORT_SET);
-+ define_constant (sc, MACH_PORT_RIGHT_DEAD_NAME);
-+ define_constant (sc, MACH_PORT_RIGHT_NUMBER);
-+
-+ define_constant (sc, KERN_SUCCESS);
-+ define_constant (sc, KERN_INVALID_ADDRESS);
-+ define_constant (sc, KERN_PROTECTION_FAILURE);
-+ define_constant (sc, KERN_NO_SPACE);
-+ define_constant (sc, KERN_INVALID_ARGUMENT);
-+ define_constant (sc, KERN_FAILURE);
-+ define_constant (sc, KERN_RESOURCE_SHORTAGE);
-+ define_constant (sc, KERN_NOT_RECEIVER);
-+ define_constant (sc, KERN_NO_ACCESS);
-+ define_constant (sc, KERN_MEMORY_FAILURE);
-+ define_constant (sc, KERN_MEMORY_ERROR);
-+ define_constant (sc, KERN_NOT_IN_SET);
-+ define_constant (sc, KERN_NAME_EXISTS);
-+ define_constant (sc, KERN_ABORTED);
-+ define_constant (sc, KERN_INVALID_NAME);
-+ define_constant (sc, KERN_INVALID_TASK);
-+ define_constant (sc, KERN_INVALID_RIGHT);
-+ define_constant (sc, KERN_INVALID_VALUE);
-+ define_constant (sc, KERN_UREFS_OVERFLOW);
-+ define_constant (sc, KERN_INVALID_CAPABILITY);
-+ define_constant (sc, KERN_RIGHT_EXISTS);
-+ define_constant (sc, KERN_INVALID_HOST);
-+ define_constant (sc, KERN_MEMORY_PRESENT);
-+ define_constant (sc, KERN_WRITE_PROTECTION_FAILURE);
-+ define_constant (sc, KERN_TERMINATED);
-+ define_constant (sc, MACH_MSG_SUCCESS);
-+ define_constant (sc, MACH_MSG_MASK);
-+ define_constant (sc, MACH_MSG_IPC_SPACE);
-+ define_constant (sc, MACH_MSG_VM_SPACE);
-+ define_constant (sc, MACH_MSG_IPC_KERNEL);
-+ define_constant (sc, MACH_MSG_VM_KERNEL);
-+ define_constant (sc, MACH_SEND_IN_PROGRESS);
-+ define_constant (sc, MACH_SEND_INVALID_DATA);
-+ define_constant (sc, MACH_SEND_INVALID_DEST);
-+ define_constant (sc, MACH_SEND_TIMED_OUT);
-+ define_constant (sc, MACH_SEND_WILL_NOTIFY);
-+ define_constant (sc, MACH_SEND_NOTIFY_IN_PROGRESS);
-+ define_constant (sc, MACH_SEND_INTERRUPTED);
-+ define_constant (sc, MACH_SEND_MSG_TOO_SMALL);
-+ define_constant (sc, MACH_SEND_INVALID_REPLY);
-+ define_constant (sc, MACH_SEND_INVALID_RIGHT);
-+ define_constant (sc, MACH_SEND_INVALID_NOTIFY);
-+ define_constant (sc, MACH_SEND_INVALID_MEMORY);
-+ define_constant (sc, MACH_SEND_NO_BUFFER);
-+ define_constant (sc, MACH_SEND_NO_NOTIFY);
-+ define_constant (sc, MACH_SEND_INVALID_TYPE);
-+ define_constant (sc, MACH_SEND_INVALID_HEADER);
-+ define_constant (sc, MACH_RCV_IN_PROGRESS);
-+ define_constant (sc, MACH_RCV_INVALID_NAME);
-+ define_constant (sc, MACH_RCV_TIMED_OUT);
-+ define_constant (sc, MACH_RCV_TOO_LARGE);
-+ define_constant (sc, MACH_RCV_INTERRUPTED);
-+ define_constant (sc, MACH_RCV_PORT_CHANGED);
-+ define_constant (sc, MACH_RCV_INVALID_NOTIFY);
-+ define_constant (sc, MACH_RCV_INVALID_DATA);
-+ define_constant (sc, MACH_RCV_PORT_DIED);
-+ define_constant (sc, MACH_RCV_IN_SET);
-+ define_constant (sc, MACH_RCV_HEADER_ERROR);
-+ define_constant (sc, MACH_RCV_BODY_ERROR);
-+
-+ define_constant (sc, TASK_KERNEL_PORT);
-+ define_constant (sc, TASK_EXCEPTION_PORT);
-+ define_constant (sc, TASK_BOOTSTRAP_PORT);
-+
-+ define_constant (sc, RB_DEBUGGER);
-+ define_constant (sc, RB_HALT);
-+ define_constant (sc, RB_AUTOBOOT);
-+
-+ define_ (sc, "mach-task-self", mk_integer (sc, mach_task_self ()));
-+
-+ define_ffi_function (sc, "mach-port-allocate", _mach_port_allocate);
-+ define_ffi_function (sc, "mach-port-deallocate", _mach_port_deallocate);
-+ define_ffi_function (sc, "mach-port-destroy", _mach_port_destroy);
-+ //define_function (sc, mach_port_get_refs);
-+ //define_function (sc, mach_port_mod_refs);
-+ define_ffi_function (sc, "mach-port-insert-right", _mach_port_insert_right);
-+ //define_function (sc, mach_port_extract_right);
-+
-+ define_function (sc, mach_print);
-+ define_ffi_function (sc, "task-create", _task_create);
-+ define_ffi_function (sc, "task-resume", _task_resume);
-+ define_ffi_function (sc, "task-terminate", _task_terminate);
-+ define_ffi_function (sc, "task-get-special-port", _task_get_special_port);
-+ define_ffi_function (sc, "task-set-special-port", _task_set_special_port);
-+ define_ffi_function (sc, "host-reboot", _host_reboot);
-+
-+ /* Device protocol. */
-+ define_constant (sc, D_READ);
-+ define_constant (sc, D_WRITE);
-+ define_ffi_function (sc, "device-open", _device_open);
-+
-+ /* Hurd stuff. */
-+ define_constant (sc, EXEC_NEWTASK);
-+ define_constant (sc, EXEC_SECURE);
-+ define_constant (sc, EXEC_DEFAULTS);
-+ define_constant (sc, EXEC_SIGTRAP);
-+ define_constant (sc, EXEC_STACK_ARGS);
-+ define_constant (sc, FS_TRANS_FORCE);
-+ define_constant (sc, FS_TRANS_EXCL);
-+ define_constant (sc, FS_TRANS_SET);
-+ define_constant (sc, FS_TRANS_ORPHAN);
-+ define_constant (sc, FS_RETRY_NORMAL);
-+ define_constant (sc, FS_RETRY_REAUTH);
-+ define_constant (sc, FS_RETRY_MAGICAL);
-+ define_constant (sc, FSYS_GOAWAY_NOWAIT);
-+ define_constant (sc, FSYS_GOAWAY_NOSYNC);
-+ define_constant (sc, FSYS_GOAWAY_FORCE);
-+ define_constant (sc, FSYS_GOAWAY_UNLINK);
-+ define_constant (sc, FSYS_GOAWAY_RECURSE);
-+ define_constant (sc, INIT_PORT_CWDIR);
-+ define_constant (sc, INIT_PORT_CRDIR);
-+ define_constant (sc, INIT_PORT_AUTH);
-+ define_constant (sc, INIT_PORT_PROC);
-+ define_constant (sc, INIT_PORT_CTTYID);
-+ define_constant (sc, INIT_PORT_BOOTSTRAP);
-+ define_constant (sc, INIT_PORT_MAX);
-+ define_constant (sc, INIT_UMASK);
-+ define_constant (sc, INIT_SIGMASK);
-+ define_constant (sc, INIT_SIGIGN);
-+ define_constant (sc, INIT_SIGPENDING);
-+ define_constant (sc, INIT_TRACEMASK);
-+ define_constant (sc, INIT_INT_MAX);
-+
-+ define_constant (sc, O_RDONLY);
-+ define_constant (sc, O_WRONLY);
-+ define_constant (sc, O_RDWR);
-+ define_constant (sc, O_EXEC);
-+ define_constant (sc, O_CREAT);
-+ define_constant (sc, O_NOTRANS);
-+
-+ define_variable (sc, exception_port);
-+ define_variable (sc, rootnode);
-+
-+ define_function (sc, trace);
-+ define_ffi_function (sc, "prompt", _prompt);
-+
-+ /* glibc. */
-+ define_function (sc, sleep);
-+ define_function (sc, usleep);
-+ define_ffi_function (sc, "getcwd", _getcwd);
-+ define_ffi_function (sc, "chdir", _chdir);
-+ define_ffi_function (sc, "strerror", _strerror);
-+ define_ffi_function (sc, "getproc", _getproc);
-+
-+ /* Boot process */
-+ define_ffi_function (sc, "bind-root", _bind_root);
-+ define_ffi_function (sc, "bind-proc", _bind_proc);
-+ define_ffi_function (sc, "bind-auth", _bind_auth);
-+ define_ffi_function (sc, "fsys-init", _fsys_init);
-+
-+ /* Early bootstrap protocols. */
-+ define_ffi_function (sc, "handle-startup-procinit", _handle_startup_procinit);
-+ define_ffi_function (sc, "handle-startup-authinit", _handle_startup_authinit);
-+ define_ffi_function (sc, "startup-procinit-reply", _startup_procinit_reply);
-+ define_ffi_function (sc, "startup-authinit-reply", _startup_authinit_reply);
-+
-+ define_ffi_function (sc, "startup-essential-task", _startup_essential_task);
-+ define_ffi_function (sc, "startup-request-notification",
-+ _startup_request_notification);
-+ define_ffi_function (sc, "startup-reboot", _startup_reboot);
-+
-+ /* Process and translator startup. */
-+ define_ffi_function (sc, "handle-exec-startup", _handle_exec_startup);
-+ define_ffi_function (sc, "handle-fsys-startup", _handle_fsys_startup);
-+
-+ /* Hurd fs API */
-+ define_ffi_function (sc, "file-name-lookup", _file_name_lookup);
-+ define_ffi_function (sc, "file-set-translator", _file_set_translator);
-+ define_ffi_function (sc, "file-get-fs-options", _file_get_fs_options);
-+
-+ /* Hurd process API */
-+ define_ffi_function (sc, "proc->task->proc", _proc_task2proc);
-+ define_ffi_function (sc, "proc->mark-important!", _proc_mark_important);
-+ define_ffi_function (sc, "proc->mark-exec!", _proc_mark_exec);
-+ define_ffi_function (sc, "proc->task->child!", _proc_child);
-+ define_ffi_function (sc, "proc->task->set-init-task!", _proc_set_init_task);
-+
-+ /* Hurd hacks. */
-+ define_ffi_function (sc, "_exec", __exec);
-+ define_ffi_function (sc, "start-handling-early-startup",
-+ _start_handling_early_startup);
-+ define_ffi_function (sc, "get-essential-tasks", _get_essential_tasks);
-+ define_ffi_function (sc, "get-registered-tasks", _get_registered_tasks);
-+ ffi_update (sc);
-+}
-diff --git a/bootshell/ffi.h b/bootshell/ffi.h
-new file mode 100644
-index 0000000..b1b3f97
---- /dev/null
-+++ b/bootshell/ffi.h
-@@ -0,0 +1,130 @@
-+#ifndef _HURD_BOOTSHELL_FFI_H
-+#define _HURD_BOOTSHELL_FFI_H
-+
-+#include <mach.h>
-+#include <mach/message.h>
-+
-+#include "scheme.h"
-+#include "scheme-private.h"
-+
-+#define SC_FFI_PROLOG(NAME) \
-+ const char *__ffi_name __attribute__ ((unused)) = NAME; \
-+ unsigned int __ffi_arg_index __attribute__ ((unused)) = 1; \
-+ error_t err = 0; \
-+
-+#define CONVERSION_number ivalue
-+#define CONVERSION_string string_value
-+#define CONVERSION_list
-+#define IS_A_number(SC, X) (SC)->vptr->is_number (X)
-+#define IS_A_string(SC, X) (SC)->vptr->is_string (X)
-+#define IS_A_list(SC, X) (SC)->vptr->is_list (SC, X)
-+
-+#define SC_ARG(SC, CTYPE, TARGET, WANT, ARGS) \
-+ if ((ARGS) == (SC)->NIL) { \
-+ fprintf (stderr, "Error: %s: too few arguments: " \
-+ "want " #TARGET "("#WANT"/"#CTYPE")\n", __ffi_name); \
-+ return (SC)->NIL; \
-+ } \
-+ if (! IS_A_##WANT ((SC), pair_car (ARGS))) { \
-+ fprintf (stderr, "Error: %s: argument %d must be: " \
-+ #WANT "\n", __ffi_name, __ffi_arg_index++); \
-+ return (SC)->NIL; \
-+ } \
-+ CTYPE TARGET = CONVERSION_##WANT (pair_car (ARGS)); \
-+ ARGS = pair_cdr (ARGS); \
-+
-+#define SC_ARGS_DONE(SC) \
-+ /* XXX */
-+
-+#define SC_RETURN_ERR(SC, ERR) \
-+ return _cons ((SC), mk_integer ((SC), (ERR)), (SC)->NIL, 1)
-+
-+#define SC_RETURN(SC) SC_RETURN_ERR (SC, err)
-+
-+#define SC_RETURN_POINTER(SC, X) \
-+ return _cons ((SC), mk_integer ((SC), err), \
-+ _cons ((SC), (X), (SC)->NIL, 1), 1)
-+#define SC_RETURN_INT(SC, X) \
-+ SC_RETURN_POINTER ((SC), mk_integer ((SC), (X)))
-+#define SC_RETURN_STRING(SC, X) \
-+ SC_RETURN_POINTER ((SC), mk_string ((SC), (X)))
-+
-+#define define_function(S, F) \
-+ scheme_define ((S), \
-+ (S)->global_env, \
-+ mk_symbol ((S), schemify_name (#F, 0)), \
-+ mk_foreign_func ((S), (do_##F)))
-+
-+#define define_ffi_function(S, P, F) \
-+ ({ \
-+ char _sc_buf[256]; \
-+ define_function (S, F); \
-+ snprintf (_sc_buf, sizeof _sc_buf, \
-+ "(define (%1$s . a) (ffi-apply \"%1$s\" %2$s a))", \
-+ P, schemify_name (#F, 0)); \
-+ scheme_load_string (S, _sc_buf); \
-+ })
-+
-+#define define_constant(S, C) \
-+ scheme_define ((S), \
-+ (S)->global_env, \
-+ mk_symbol ((S), schemify_name (#C, 1)), \
-+ mk_integer ((S), (C)))
-+
-+#define define_(S, SYM, EXP) \
-+ scheme_define ((S), (S)->global_env, mk_symbol ((S), (SYM)), EXP)
-+
-+#define define_variable(S, C) \
-+ scheme_define ((S), \
-+ (S)->global_env, \
-+ mk_symbol ((S), schemify_name (#C, 0)), \
-+ mk_integer ((S), (C)))
-+
-+#define define_variable_pointer(S, C, P) \
-+ scheme_define ((S), \
-+ (S)->global_env, \
-+ mk_symbol ((S), schemify_name (#C, 0)), \
-+ (P))
-+
-+#define define_variable_string(S, C) \
-+ define_variable_pointer (S, C, (S)->vptr->mk_string (S, C ?: ""))
-+
-+/* A variant of scheme_load_string that does not require the string to
-+ be zero-terminated. */
-+void scheme_load_mem (scheme *, const char *, const char *);
-+
-+#define declare_embedded_script(X) \
-+ extern char X##_start[] asm("_binary_"#X"_start"); \
-+ extern char X##_end[] asm("_binary_"#X"_end")
-+
-+#define load_embedded_script(S, X) \
-+ ({ \
-+ scheme_load_mem ((S), X##_start, X##_end); \
-+ if ((S)->retcode != 0) \
-+ fprintf (stderr, "Errors encountered evaluating %s\n", #X); \
-+ })
-+
-+declare_embedded_script (init_scm);
-+declare_embedded_script (boot_scm);
-+declare_embedded_script (runsystem_scm);
-+
-+void ffi_update (scheme *sc);
-+void ffi_init (scheme *sc);
-+
-+pointer ffi_argz2list (scheme *sc,
-+ const char *argz, size_t argz_len, const char *entry);
-+void ffi_list2argz (scheme *sc, char **argz, size_t *argz_len, pointer list);
-+
-+// XXX
-+error_t service_fsys_request (mach_port_t bootstrap,
-+ mach_port_t realnode,
-+ mach_msg_type_name_t realnodePoly,
-+ mach_msg_timeout_t timeout,
-+ mach_port_t *control);
-+
-+/* Forward declarations. */
-+
-+/* exec-startup.c */
-+pointer do__handle_exec_startup (scheme *sc, pointer args);
-+
-+#endif /* _HURD_BOOTSHELL_FFI_H */
-diff --git a/bootshell/fs.c b/bootshell/fs.c
-new file mode 100644
-index 0000000..3c8deb3
---- /dev/null
-+++ b/bootshell/fs.c
-@@ -0,0 +1,91 @@
-+#include <assert.h>
-+#include <hurd.h>
-+#include <mach.h>
-+#include <mach/message.h>
-+#include <pthread.h>
-+#include <stdio.h>
-+
-+// eek #include "fs_S.h"
-+
-+#include "bootshell.h"
-+
-+mach_port_t rootnode;
-+
-+/* A top-level function for the paging thread that just services paging
-+ requests. */
-+static void *
-+service_fs_requests (void *arg)
-+{
-+ extern boolean_t fs_server ();
-+
-+ int trace_demuxer (mach_msg_header_t *inp,
-+ mach_msg_header_t *outp)
-+ {
-+ error (0, 0, "(fs-server: %d)", inp->msgh_id);
-+ int i = fs_server (inp, outp);
-+ return i;
-+ }
-+
-+ while (1)
-+ mach_msg_server (0? trace_demuxer: fs_server, 0, rootnode);
-+
-+ /* Not reached. */
-+ return NULL;
-+}
-+
-+error_t
-+init_fs_server (void)
-+{
-+ error_t err;
-+ pthread_t t;
-+
-+ err = mach_port_allocate (mach_task_self (),
-+ MACH_PORT_RIGHT_RECEIVE,
-+ &rootnode);
-+ if (err)
-+ return err;
-+
-+ /* Make a thread to service the fs protocol. */
-+ err = pthread_create (&t, NULL, service_fs_requests, NULL);
-+ if (err)
-+ return err;
-+ pthread_detach (t);
-+
-+ err = mach_port_insert_right (mach_task_self (),
-+ rootnode,
-+ rootnode,
-+ MACH_MSG_TYPE_MAKE_SEND);
-+ if (err)
-+ return err;
-+
-+ setcrdir (rootnode); // XXX do we want this? not sure what for tbh.
-+ setcwdir (rootnode);
-+ portarray_template[INIT_PORT_CRDIR] = rootnode;
-+ portarray_template[INIT_PORT_CWDIR] = rootnode;
-+
-+ return err;
-+}
-+
-+error_t
-+S_dir_lookup (file_t file,
-+ char *path,
-+ int flags,
-+ mode_t mode,
-+ enum retry_type *retry,
-+ char *retryname,
-+ file_t *returned_port,
-+ mach_msg_type_name_t *returned_port_poly)
-+{
-+ if (file != rootnode)
-+ return EOPNOTSUPP;
-+
-+ if (portarray_template[INIT_PORT_CRDIR] == rootnode)
-+ /* Still no root filesystem. */
-+ return EOPNOTSUPP;
-+
-+ *retry = FS_RETRY_NORMAL;
-+ strncpy (retryname, path, sizeof (string_t));
-+ *returned_port = portarray_template[INIT_PORT_CRDIR];
-+ *returned_port_poly = MACH_MSG_TYPE_COPY_SEND;
-+ return 0;
-+}
-diff --git a/bootshell/fsys.c b/bootshell/fsys.c
-new file mode 100644
-index 0000000..3c5afa2
---- /dev/null
-+++ b/bootshell/fsys.c
-@@ -0,0 +1,74 @@
-+#include <assert.h>
-+#include <hurd.h>
-+#include <mach.h>
-+#include <mach/message.h>
-+#include <stdio.h>
-+
-+// eek #include "fsys_S.h"
-+
-+#include "bootshell.h"
-+
-+/* XXX would be nice not to use a global variable, maybe with
-+ payloads. */
-+static struct
-+{
-+ /* Filled by caller. */
-+ mach_port_t bootstrap_port;
-+ mach_port_t realnode;
-+ mach_msg_type_name_t realnodePoly;
-+
-+ /* Filled by the server function. */
-+ mach_port_t control_port;
-+} fsys_startup_args;
-+
-+error_t
-+S_fsys_startup (mach_port_t bootstrap,
-+ int openflags,
-+ mach_port_t control_port,
-+ mach_port_t *realnode,
-+ mach_msg_type_name_t *realnodePoly)
-+{
-+ assert (MACH_PORT_VALID (fsys_startup_args.bootstrap_port));
-+ if (bootstrap != fsys_startup_args.bootstrap_port)
-+ return EOPNOTSUPP;
-+
-+ fsys_startup_args.control_port = control_port;
-+ *realnode = fsys_startup_args.realnode;
-+ *realnodePoly = fsys_startup_args.realnodePoly;
-+ return 0;
-+}
-+
-+error_t
-+service_fsys_request (mach_port_t bootstrap,
-+ mach_port_t realnode,
-+ mach_msg_type_name_t realnodePoly,
-+ mach_msg_timeout_t timeout,
-+ mach_port_t *control)
-+{
-+ error_t err;
-+ extern boolean_t fsys_server ();
-+ mach_msg_id_t msgh_id;
-+
-+ if (! MACH_PORT_VALID (bootstrap))
-+ return EINVAL;
-+
-+ fsys_startup_args.bootstrap_port = bootstrap;
-+ fsys_startup_args.realnode = realnode;
-+ fsys_startup_args.realnodePoly = realnodePoly;
-+ fsys_startup_args.control_port = MACH_PORT_NULL;
-+
-+ err = mach_msg_server_timeout_once (fsys_server, 0, bootstrap,
-+ MACH_RCV_TIMEOUT|MACH_SEND_TIMEOUT,
-+ timeout, &msgh_id);
-+ if (err != MACH_MSG_SUCCESS)
-+ return err;
-+
-+ if (msgh_id != 22000)
-+ {
-+ fprintf (stderr, " (XXy:%d)", msgh_id); //XXX
-+ return EINVAL;
-+ }
-+
-+ *control = fsys_startup_args.control_port;
-+ return 0;
-+}
-diff --git a/bootshell/hack.txt b/bootshell/hack.txt
-new file mode 100644
-index 0000000..f3ee648
---- /dev/null
-+++ b/bootshell/hack.txt
-@@ -0,0 +1,244 @@
-+
-+ How to hack TinyScheme
-+ ----------------------
-+
-+ TinyScheme is easy to learn and modify. It is structured like a
-+ meta-interpreter, only it is written in C. All data are Scheme
-+ objects, which facilitates both understanding/modifying the
-+ code and reifying the interpreter workings.
-+
-+ In place of a dry description, we will pace through the addition
-+ of a useful new datatype: garbage-collected memory blocks.
-+ The interface will be:
-+
-+ (make-block <n> [<fill>]) makes a new block of the specified size
-+ optionally filling it with a specified byte
-+ (block? <obj>)
-+ (block-length <block>)
-+ (block-ref <block> <index>) retrieves byte at location
-+ (block-set! <block> <index> <byte>) modifies byte at location
-+
-+ In the sequel, lines that begin with '>' denote lines to add to the
-+ code. Lines that begin with '|' are just citations of existing code.
-+ Lines that begin with X denote lines to be removed from the code.
-+
-+ First of all, we need to assign a typeid to our new type. Typeids
-+ in TinyScheme are small integers declared in the scheme_types enum
-+ located near the top of the scheme.c file; it begins with T_STRING.
-+ Add a new entry at the end, say T_MEMBLOCK. Remember to adjust the
-+ value of T_LAST_SYTEM_TYPE when adding new entries. There can be at
-+ most 31 types, but you don't have to worry about that limit yet.
-+
-+| T_ENVIRONMENT=14,
-+X T_LAST_SYSTEM_TYPE=14
-+> T_MEMBLOCK=15,
-+> T_LAST_SYSTEM_TYPE=15
-+| };
-+
-+
-+ Then, some helper macros would be useful. Go to where is_string()
-+ and the rest are defined and add:
-+
-+> INTERFACE INLINE int is_memblock(pointer p) { return (type(p)==T_MEMBLOCK); }
-+
-+ This actually is a function, because it is meant to be exported by
-+ scheme.h. If no foreign function will ever manipulate a memory block,
-+ you can instead define it as a macro:
-+
-+> #define is_memblock(p) (type(p)==T_MEMBLOCK)
-+
-+ Then we make space for the new type in the main data structure:
-+ struct cell. As it happens, the _string part of the union _object
-+ (that is used to hold character strings) has two fields that suit us:
-+
-+| struct {
-+| char *_svalue;
-+| int _keynum;
-+| } _string;
-+
-+ We can use _svalue to hold the actual pointer and _keynum to hold its
-+ length. If we couln't reuse existing fields, we could always add other
-+ alternatives in union _object.
-+
-+ We then proceed to write the function that actually makes a new block.
-+ For conformance reasons, we name it mk_memblock
-+
-+> static pointer mk_memblock(scheme *sc, int len, char fill) {
-+> pointer x;
-+> char *p=(char*)sc->malloc(len);
-+>
-+> if(p==0) {
-+> return sc->NIL;
-+> }
-+> x = get_cell(sc, sc->NIL, sc->NIL);
-+>
-+> typeflag(x) = T_MEMBLOCK|T_ATOM;
-+> strvalue(x)=p;
-+> keynum(x)=len;
-+> memset(p,fill,len);
-+> return (x);
-+> }
-+
-+ The memory used by the MEMBLOCK will have to be freed when the cell
-+ is reclaimed during garbage collection. There is a placeholder for
-+ that staff, function finalize_cell(), currently handling strings only.
-+
-+| static void finalize_cell(scheme *sc, pointer a) {
-+| if(is_string(a)) {
-+| sc->free(strvalue(a));
-+> } else if(is_memblock(a)) {
-+> sc->free(strvalue(a));
-+| } else if(is_port(a)) {
-+
-+ There are no MEMBLOCK literals, so we don't concern ourselves with
-+ the READER part (yet!). We must cater to the PRINTER, though. We
-+ add one case more in atom2str().
-+
-+| } else if (iscontinuation(l)) {
-+| p = "#<CONTINUATION>";
-+> } else if (is_memblock(l)) {
-+> p = "#<MEMORY BLOCK>";
-+| } else {
-+
-+ Whenever a MEMBLOCK is displayed, it will look like that.
-+ Now, we must add the interface functions: constructor, predicate,
-+ accessor, modifier. We must in fact create new op-codes for the virtual
-+ machine underlying TinyScheme. Since version 1.30, TinyScheme uses
-+ macros and a single source text to keep the enums and the dispatch table
-+ in sync. The op-codes are defined in the opdefines.h file with one line
-+ for each op-code. The lines in the file have six columns between the
-+ starting _OPDEF( and ending ): A, B, C, D, E, and OP.
-+ Note that this file uses unusually long lines to accomodate all the
-+ information; adjust your editor to handle this.
-+
-+ The purpose of the columns is:
-+ - Column A is the name of the subroutine that handles the op-code.
-+ - Column B is the name of the op-code function.
-+ - Columns C and D are the minimum and maximum number of arguments
-+ that are accepted by the op-code.
-+ - Column E is a set of flags that tells the interpreter the type of
-+ each of the arguments expected by the op-code.
-+ - Column OP is used in the scheme_opcodes enum located in the
-+ scheme-private.h file.
-+
-+ Op-codes are really just tags for a huge C switch, only this switch
-+ is broken up in to a number of different opexe_X functions. The
-+ correspondence is made in table "dispatch_table". There, we assign
-+ the new op-codes to opexe_2, where the equivalent ones for vectors
-+ are situated. We also assign a name for them, and specify the minimum
-+ and maximum arity (number of expected arguments). INF_ARG as a maximum
-+ arity means "unlimited".
-+
-+ For reasons of consistency, we add the new op-codes right after those
-+ for vectors:
-+
-+| _OP_DEF(opexe_2, "vector-set!", 3, 3, TST_VECTOR TST_NATURAL TST_ANY, OP_VECSET )
-+> _OP_DEF(opexe_2, "make-block", 1, 2, TST_NATURAL TST_CHAR, OP_MKBLOCK )
-+> _OP_DEF(opexe_2, "block-length", 1, 1, T_MEMBLOCK, OP_BLOCKLEN )
-+> _OP_DEF(opexe_2, "block-ref", 2, 2, T_MEMBLOCK TST_NATURAL, OP_BLOCKREF )
-+> _OP_DEF(opexe_2, "block-set!", 1, 1, T_MEMBLOCK TST_NATURAL TST_CHAR, OP_BLOCKSET )
-+| _OP_DEF(opexe_3, "not", 1, 1, TST_NONE, OP_NOT )
-+
-+ We add the predicate along with the other predicates in opexe_3:
-+
-+| _OP_DEF(opexe_3, "vector?", 1, 1, TST_ANY, OP_VECTORP )
-+> _OP_DEF(opexe_3, "block?", 1, 1, TST_ANY, OP_BLOCKP )
-+| _OP_DEF(opexe_3, "eq?", 2, 2, TST_ANY, OP_EQ )
-+
-+ All that remains is to write the actual code to do the processing and
-+ add it to the switch statement in opexe_2, after the OP_VECSET case.
-+
-+> case OP_MKBLOCK: { /* make-block */
-+> int fill=0;
-+> int len;
-+>
-+> if(!isnumber(car(sc->args))) {
-+> Error_1(sc,"make-block: not a number:",car(sc->args));
-+> }
-+> len=ivalue(car(sc->args));
-+> if(len<=0) {
-+> Error_1(sc,"make-block: not positive:",car(sc->args));
-+> }
-+>
-+> if(cdr(sc->args)!=sc->NIL) {
-+> if(!isnumber(cadr(sc->args)) || ivalue(cadr(sc->args))<0) {
-+> Error_1(sc,"make-block: not a positive number:",cadr(sc->args));
-+> }
-+> fill=charvalue(cadr(sc->args))%255;
-+> }
-+> s_return(sc,mk_memblock(sc,len,(char)fill));
-+> }
-+>
-+> case OP_BLOCKLEN: /* block-length */
-+> if(!ismemblock(car(sc->args))) {
-+> Error_1(sc,"block-length: not a memory block:",car(sc->args));
-+> }
-+> s_return(sc,mk_integer(sc,keynum(car(sc->args))));
-+>
-+> case OP_BLOCKREF: { /* block-ref */
-+> char *str;
-+> int index;
-+>
-+> if(!ismemblock(car(sc->args))) {
-+> Error_1(sc,"block-ref: not a memory block:",car(sc->args));
-+> }
-+> str=strvalue(car(sc->args));
-+>
-+> if(cdr(sc->args)==sc->NIL) {
-+> Error_0(sc,"block-ref: needs two arguments");
-+> }
-+> if(!isnumber(cadr(sc->args))) {
-+> Error_1(sc,"block-ref: not a number:",cadr(sc->args));
-+> }
-+> index=ivalue(cadr(sc->args));
-+>
-+> if(index<0 || index>=keynum(car(sc->args))) {
-+> Error_1(sc,"block-ref: out of bounds:",cadr(sc->args));
-+> }
-+>
-+> s_return(sc,mk_integer(sc,str[index]));
-+> }
-+>
-+> case OP_BLOCKSET: { /* block-set! */
-+> char *str;
-+> int index;
-+> int c;
-+>
-+> if(!ismemblock(car(sc->args))) {
-+> Error_1(sc,"block-set!: not a memory block:",car(sc->args));
-+> }
-+> if(isimmutable(car(sc->args))) {
-+> Error_1(sc,"block-set!: unable to alter immutable memory block:",car(sc->args));
-+> }
-+> str=strvalue(car(sc->args));
-+>
-+> if(cdr(sc->args)==sc->NIL) {
-+> Error_0(sc,"block-set!: needs three arguments");
-+> }
-+> if(!isnumber(cadr(sc->args))) {
-+> Error_1(sc,"block-set!: not a number:",cadr(sc->args));
-+> }
-+> index=ivalue(cadr(sc->args));
-+> if(index<0 || index>=keynum(car(sc->args))) {
-+> Error_1(sc,"block-set!: out of bounds:",cadr(sc->args));
-+> }
-+>
-+> if(cddr(sc->args)==sc->NIL) {
-+> Error_0(sc,"block-set!: needs three arguments");
-+> }
-+> if(!isinteger(caddr(sc->args))) {
-+> Error_1(sc,"block-set!: not an integer:",caddr(sc->args));
-+> }
-+> c=ivalue(caddr(sc->args))%255;
-+>
-+> str[index]=(char)c;
-+> s_return(sc,car(sc->args));
-+> }
-+
-+ Finally, do the same for the predicate in opexe_3.
-+
-+| case OP_VECTORP: /* vector? */
-+| s_retbool(is_vector(car(sc->args)));
-+> case OP_BLOCKP: /* block? */
-+> s_retbool(is_memblock(car(sc->args)));
-+| case OP_EQ: /* eq? */
-diff --git a/bootshell/init.scm b/bootshell/init.scm
-new file mode 100644
-index 0000000..223e421
---- /dev/null
-+++ b/bootshell/init.scm
-@@ -0,0 +1,716 @@
-+; Initialization file for TinySCHEME 1.41
-+
-+; Per R5RS, up to four deep compositions should be defined
-+(define (caar x) (car (car x)))
-+(define (cadr x) (car (cdr x)))
-+(define (cdar x) (cdr (car x)))
-+(define (cddr x) (cdr (cdr x)))
-+(define (caaar x) (car (car (car x))))
-+(define (caadr x) (car (car (cdr x))))
-+(define (cadar x) (car (cdr (car x))))
-+(define (caddr x) (car (cdr (cdr x))))
-+(define (cdaar x) (cdr (car (car x))))
-+(define (cdadr x) (cdr (car (cdr x))))
-+(define (cddar x) (cdr (cdr (car x))))
-+(define (cdddr x) (cdr (cdr (cdr x))))
-+(define (caaaar x) (car (car (car (car x)))))
-+(define (caaadr x) (car (car (car (cdr x)))))
-+(define (caadar x) (car (car (cdr (car x)))))
-+(define (caaddr x) (car (car (cdr (cdr x)))))
-+(define (cadaar x) (car (cdr (car (car x)))))
-+(define (cadadr x) (car (cdr (car (cdr x)))))
-+(define (caddar x) (car (cdr (cdr (car x)))))
-+(define (cadddr x) (car (cdr (cdr (cdr x)))))
-+(define (cdaaar x) (cdr (car (car (car x)))))
-+(define (cdaadr x) (cdr (car (car (cdr x)))))
-+(define (cdadar x) (cdr (car (cdr (car x)))))
-+(define (cdaddr x) (cdr (car (cdr (cdr x)))))
-+(define (cddaar x) (cdr (cdr (car (car x)))))
-+(define (cddadr x) (cdr (cdr (car (cdr x)))))
-+(define (cdddar x) (cdr (cdr (cdr (car x)))))
-+(define (cddddr x) (cdr (cdr (cdr (cdr x)))))
-+
-+;;;; Utility to ease macro creation
-+(define (macro-expand form)
-+ ((eval (get-closure-code (eval (car form)))) form))
-+
-+(define (macro-expand-all form)
-+ (if (macro? form)
-+ (macro-expand-all (macro-expand form))
-+ form))
-+
-+(define *compile-hook* macro-expand-all)
-+
-+
-+(macro (unless form)
-+ `(if (not ,(cadr form)) (begin ,@(cddr form))))
-+
-+(macro (when form)
-+ `(if ,(cadr form) (begin ,@(cddr form))))
-+
-+; DEFINE-MACRO Contributed by Andy Gaynor
-+(macro (define-macro dform)
-+ (if (symbol? (cadr dform))
-+ `(macro ,@(cdr dform))
-+ (let ((form (gensym)))
-+ `(macro (,(caadr dform) ,form)
-+ (apply (lambda ,(cdadr dform) ,@(cddr dform)) (cdr ,form))))))
-+
-+; Utilities for math. Notice that inexact->exact is primitive,
-+; but exact->inexact is not.
-+(define exact? integer?)
-+(define (inexact? x) (and (real? x) (not (integer? x))))
-+(define (even? n) (= (remainder n 2) 0))
-+(define (odd? n) (not (= (remainder n 2) 0)))
-+(define (zero? n) (= n 0))
-+(define (positive? n) (> n 0))
-+(define (negative? n) (< n 0))
-+(define complex? number?)
-+(define rational? real?)
-+(define (abs n) (if (>= n 0) n (- n)))
-+(define (exact->inexact n) (* n 1.0))
-+(define (<> n1 n2) (not (= n1 n2)))
-+
-+; min and max must return inexact if any arg is inexact; use (+ n 0.0)
-+(define (max . lst)
-+ (foldr (lambda (a b)
-+ (if (> a b)
-+ (if (exact? b) a (+ a 0.0))
-+ (if (exact? a) b (+ b 0.0))))
-+ (car lst) (cdr lst)))
-+(define (min . lst)
-+ (foldr (lambda (a b)
-+ (if (< a b)
-+ (if (exact? b) a (+ a 0.0))
-+ (if (exact? a) b (+ b 0.0))))
-+ (car lst) (cdr lst)))
-+
-+(define (succ x) (+ x 1))
-+(define (pred x) (- x 1))
-+(define gcd
-+ (lambda a
-+ (if (null? a)
-+ 0
-+ (let ((aa (abs (car a)))
-+ (bb (abs (cadr a))))
-+ (if (= bb 0)
-+ aa
-+ (gcd bb (remainder aa bb)))))))
-+(define lcm
-+ (lambda a
-+ (if (null? a)
-+ 1
-+ (let ((aa (abs (car a)))
-+ (bb (abs (cadr a))))
-+ (if (or (= aa 0) (= bb 0))
-+ 0
-+ (abs (* (quotient aa (gcd aa bb)) bb)))))))
-+
-+
-+(define (string . charlist)
-+ (list->string charlist))
-+
-+(define (list->string charlist)
-+ (let* ((len (length charlist))
-+ (newstr (make-string len))
-+ (fill-string!
-+ (lambda (str i len charlist)
-+ (if (= i len)
-+ str
-+ (begin (string-set! str i (car charlist))
-+ (fill-string! str (+ i 1) len (cdr charlist)))))))
-+ (fill-string! newstr 0 len charlist)))
-+
-+(define (string-fill! s e)
-+ (let ((n (string-length s)))
-+ (let loop ((i 0))
-+ (if (= i n)
-+ s
-+ (begin (string-set! s i e) (loop (succ i)))))))
-+
-+(define (string->list s)
-+ (let loop ((n (pred (string-length s))) (l '()))
-+ (if (= n -1)
-+ l
-+ (loop (pred n) (cons (string-ref s n) l)))))
-+
-+(define (string-copy str)
-+ (string-append str))
-+
-+(define (string->anyatom str pred)
-+ (let* ((a (string->atom str)))
-+ (if (pred a) a
-+ (error "string->xxx: not a xxx" a))))
-+
-+(define (string->number str . base)
-+ (let ((n (string->atom str (if (null? base) 10 (car base)))))
-+ (if (number? n) n #f)))
-+
-+(define (anyatom->string n pred)
-+ (if (pred n)
-+ (atom->string n)
-+ (error "xxx->string: not a xxx" n)))
-+
-+(define (number->string n . base)
-+ (atom->string n (if (null? base) 10 (car base))))
-+
-+
-+(define (char-cmp? cmp a b)
-+ (cmp (char->integer a) (char->integer b)))
-+(define (char-ci-cmp? cmp a b)
-+ (cmp (char->integer (char-downcase a)) (char->integer (char-downcase b))))
-+
-+(define (char=? a b) (char-cmp? = a b))
-+(define (char<? a b) (char-cmp? < a b))
-+(define (char>? a b) (char-cmp? > a b))
-+(define (char<=? a b) (char-cmp? <= a b))
-+(define (char>=? a b) (char-cmp? >= a b))
-+
-+(define (char-ci=? a b) (char-ci-cmp? = a b))
-+(define (char-ci<? a b) (char-ci-cmp? < a b))
-+(define (char-ci>? a b) (char-ci-cmp? > a b))
-+(define (char-ci<=? a b) (char-ci-cmp? <= a b))
-+(define (char-ci>=? a b) (char-ci-cmp? >= a b))
-+
-+; Note the trick of returning (cmp x y)
-+(define (string-cmp? chcmp cmp a b)
-+ (let ((na (string-length a)) (nb (string-length b)))
-+ (let loop ((i 0))
-+ (cond
-+ ((= i na)
-+ (if (= i nb) (cmp 0 0) (cmp 0 1)))
-+ ((= i nb)
-+ (cmp 1 0))
-+ ((chcmp = (string-ref a i) (string-ref b i))
-+ (loop (succ i)))
-+ (else
-+ (chcmp cmp (string-ref a i) (string-ref b i)))))))
-+
-+
-+(define (string=? a b) (string-cmp? char-cmp? = a b))
-+(define (string<? a b) (string-cmp? char-cmp? < a b))
-+(define (string>? a b) (string-cmp? char-cmp? > a b))
-+(define (string<=? a b) (string-cmp? char-cmp? <= a b))
-+(define (string>=? a b) (string-cmp? char-cmp? >= a b))
-+
-+(define (string-ci=? a b) (string-cmp? char-ci-cmp? = a b))
-+(define (string-ci<? a b) (string-cmp? char-ci-cmp? < a b))
-+(define (string-ci>? a b) (string-cmp? char-ci-cmp? > a b))
-+(define (string-ci<=? a b) (string-cmp? char-ci-cmp? <= a b))
-+(define (string-ci>=? a b) (string-cmp? char-ci-cmp? >= a b))
-+
-+(define (list . x) x)
-+
-+(define (foldr f x lst)
-+ (if (null? lst)
-+ x
-+ (foldr f (f x (car lst)) (cdr lst))))
-+
-+(define (unzip1-with-cdr . lists)
-+ (unzip1-with-cdr-iterative lists '() '()))
-+
-+(define (unzip1-with-cdr-iterative lists cars cdrs)
-+ (if (null? lists)
-+ (cons cars cdrs)
-+ (let ((car1 (caar lists))
-+ (cdr1 (cdar lists)))
-+ (unzip1-with-cdr-iterative
-+ (cdr lists)
-+ (append cars (list car1))
-+ (append cdrs (list cdr1))))))
-+
-+(define (map proc . lists)
-+ (if (null? lists)
-+ (apply proc)
-+ (if (null? (car lists))
-+ '()
-+ (let* ((unz (apply unzip1-with-cdr lists))
-+ (cars (car unz))
-+ (cdrs (cdr unz)))
-+ (cons (apply proc cars) (apply map (cons proc cdrs)))))))
-+
-+(define (for-each proc . lists)
-+ (if (null? lists)
-+ (apply proc)
-+ (if (null? (car lists))
-+ #t
-+ (let* ((unz (apply unzip1-with-cdr lists))
-+ (cars (car unz))
-+ (cdrs (cdr unz)))
-+ (apply proc cars) (apply map (cons proc cdrs))))))
-+
-+(define (list-tail x k)
-+ (if (zero? k)
-+ x
-+ (list-tail (cdr x) (- k 1))))
-+
-+(define (list-ref x k)
-+ (car (list-tail x k)))
-+
-+(define (last-pair x)
-+ (if (pair? (cdr x))
-+ (last-pair (cdr x))
-+ x))
-+
-+(define (head stream) (car stream))
-+
-+(define (tail stream) (force (cdr stream)))
-+
-+(define (vector-equal? x y)
-+ (and (vector? x) (vector? y) (= (vector-length x) (vector-length y))
-+ (let ((n (vector-length x)))
-+ (let loop ((i 0))
-+ (if (= i n)
-+ #t
-+ (and (equal? (vector-ref x i) (vector-ref y i))
-+ (loop (succ i))))))))
-+
-+(define (list->vector x)
-+ (apply vector x))
-+
-+(define (vector-fill! v e)
-+ (let ((n (vector-length v)))
-+ (let loop ((i 0))
-+ (if (= i n)
-+ v
-+ (begin (vector-set! v i e) (loop (succ i)))))))
-+
-+(define (vector->list v)
-+ (let loop ((n (pred (vector-length v))) (l '()))
-+ (if (= n -1)
-+ l
-+ (loop (pred n) (cons (vector-ref v n) l)))))
-+
-+;; The following quasiquote macro is due to Eric S. Tiedemann.
-+;; Copyright 1988 by Eric S. Tiedemann; all rights reserved.
-+;;
-+;; Subsequently modified to handle vectors: D. Souflis
-+
-+(macro
-+ quasiquote
-+ (lambda (l)
-+ (define (mcons f l r)
-+ (if (and (pair? r)
-+ (eq? (car r) 'quote)
-+ (eq? (car (cdr r)) (cdr f))
-+ (pair? l)
-+ (eq? (car l) 'quote)
-+ (eq? (car (cdr l)) (car f)))
-+ (if (or (procedure? f) (number? f) (string? f))
-+ f
-+ (list 'quote f))
-+ (if (eqv? l vector)
-+ (apply l (eval r))
-+ (list 'cons l r)
-+ )))
-+ (define (mappend f l r)
-+ (if (or (null? (cdr f))
-+ (and (pair? r)
-+ (eq? (car r) 'quote)
-+ (eq? (car (cdr r)) '())))
-+ l
-+ (list 'append l r)))
-+ (define (foo level form)
-+ (cond ((not (pair? form))
-+ (if (or (procedure? form) (number? form) (string? form))
-+ form
-+ (list 'quote form))
-+ )
-+ ((eq? 'quasiquote (car form))
-+ (mcons form ''quasiquote (foo (+ level 1) (cdr form))))
-+ (#t (if (zero? level)
-+ (cond ((eq? (car form) 'unquote) (car (cdr form)))
-+ ((eq? (car form) 'unquote-splicing)
-+ (error "Unquote-splicing wasn't in a list:"
-+ form))
-+ ((and (pair? (car form))
-+ (eq? (car (car form)) 'unquote-splicing))
-+ (mappend form (car (cdr (car form)))
-+ (foo level (cdr form))))
-+ (#t (mcons form (foo level (car form))
-+ (foo level (cdr form)))))
-+ (cond ((eq? (car form) 'unquote)
-+ (mcons form ''unquote (foo (- level 1)
-+ (cdr form))))
-+ ((eq? (car form) 'unquote-splicing)
-+ (mcons form ''unquote-splicing
-+ (foo (- level 1) (cdr form))))
-+ (#t (mcons form (foo level (car form))
-+ (foo level (cdr form)))))))))
-+ (foo 0 (car (cdr l)))))
-+
-+;;;;;Helper for the dynamic-wind definition. By Tom Breton (Tehom)
-+(define (shared-tail x y)
-+ (let ((len-x (length x))
-+ (len-y (length y)))
-+ (define (shared-tail-helper x y)
-+ (if
-+ (eq? x y)
-+ x
-+ (shared-tail-helper (cdr x) (cdr y))))
-+
-+ (cond
-+ ((> len-x len-y)
-+ (shared-tail-helper
-+ (list-tail x (- len-x len-y))
-+ y))
-+ ((< len-x len-y)
-+ (shared-tail-helper
-+ x
-+ (list-tail y (- len-y len-x))))
-+ (#t (shared-tail-helper x y)))))
-+
-+;;;;;Dynamic-wind by Tom Breton (Tehom)
-+
-+;;Guarded because we must only eval this once, because doing so
-+;;redefines call/cc in terms of old call/cc
-+(unless (defined? 'dynamic-wind)
-+ (let
-+ ;;These functions are defined in the context of a private list of
-+ ;;pairs of before/after procs.
-+ ( (*active-windings* '())
-+ ;;We'll define some functions into the larger environment, so
-+ ;;we need to know it.
-+ (outer-env (current-environment)))
-+
-+ ;;Poor-man's structure operations
-+ (define before-func car)
-+ (define after-func cdr)
-+ (define make-winding cons)
-+
-+ ;;Manage active windings
-+ (define (activate-winding! new)
-+ ((before-func new))
-+ (set! *active-windings* (cons new *active-windings*)))
-+ (define (deactivate-top-winding!)
-+ (let ((old-top (car *active-windings*)))
-+ ;;Remove it from the list first so it's not active during its
-+ ;;own exit.
-+ (set! *active-windings* (cdr *active-windings*))
-+ ((after-func old-top))))
-+
-+ (define (set-active-windings! new-ws)
-+ (unless (eq? new-ws *active-windings*)
-+ (let ((shared (shared-tail new-ws *active-windings*)))
-+
-+ ;;Define the looping functions.
-+ ;;Exit the old list. Do deeper ones last. Don't do
-+ ;;any shared ones.
-+ (define (pop-many)
-+ (unless (eq? *active-windings* shared)
-+ (deactivate-top-winding!)
-+ (pop-many)))
-+ ;;Enter the new list. Do deeper ones first so that the
-+ ;;deeper windings will already be active. Don't do any
-+ ;;shared ones.
-+ (define (push-many new-ws)
-+ (unless (eq? new-ws shared)
-+ (push-many (cdr new-ws))
-+ (activate-winding! (car new-ws))))
-+
-+ ;;Do it.
-+ (pop-many)
-+ (push-many new-ws))))
-+
-+ ;;The definitions themselves.
-+ (eval
-+ `(define call-with-current-continuation
-+ ;;It internally uses the built-in call/cc, so capture it.
-+ ,(let ((old-c/cc call-with-current-continuation))
-+ (lambda (func)
-+ ;;Use old call/cc to get the continuation.
-+ (old-c/cc
-+ (lambda (continuation)
-+ ;;Call func with not the continuation itself
-+ ;;but a procedure that adjusts the active
-+ ;;windings to what they were when we made
-+ ;;this, and only then calls the
-+ ;;continuation.
-+ (func
-+ (let ((current-ws *active-windings*))
-+ (lambda (x)
-+ (set-active-windings! current-ws)
-+ (continuation x)))))))))
-+ outer-env)
-+ ;;We can't just say "define (dynamic-wind before thunk after)"
-+ ;;because the lambda it's defined to lives in this environment,
-+ ;;not in the global environment.
-+ (eval
-+ `(define dynamic-wind
-+ ,(lambda (before thunk after)
-+ ;;Make a new winding
-+ (activate-winding! (make-winding before after))
-+ (let ((result (thunk)))
-+ ;;Get rid of the new winding.
-+ (deactivate-top-winding!)
-+ ;;The return value is that of thunk.
-+ result)))
-+ outer-env)))
-+
-+(define call/cc call-with-current-continuation)
-+
-+
-+;;;;; atom? and equal? written by a.k
-+
-+;;;; atom?
-+(define (atom? x)
-+ (not (pair? x)))
-+
-+;;;; equal?
-+(define (equal? x y)
-+ (cond
-+ ((pair? x)
-+ (and (pair? y)
-+ (equal? (car x) (car y))
-+ (equal? (cdr x) (cdr y))))
-+ ((vector? x)
-+ (and (vector? y) (vector-equal? x y)))
-+ ((string? x)
-+ (and (string? y) (string=? x y)))
-+ (else (eqv? x y))))
-+
-+;;;; (do ((var init inc) ...) (endtest result ...) body ...)
-+;;
-+(macro do
-+ (lambda (do-macro)
-+ (apply (lambda (do vars endtest . body)
-+ (let ((do-loop (gensym)))
-+ `(letrec ((,do-loop
-+ (lambda ,(map (lambda (x)
-+ (if (pair? x) (car x) x))
-+ `,vars)
-+ (if ,(car endtest)
-+ (begin ,@(cdr endtest))
-+ (begin
-+ ,@body
-+ (,do-loop
-+ ,@(map (lambda (x)
-+ (cond
-+ ((not (pair? x)) x)
-+ ((< (length x) 3) (car x))
-+ (else (car (cdr (cdr x))))))
-+ `,vars)))))))
-+ (,do-loop
-+ ,@(map (lambda (x)
-+ (if (and (pair? x) (cdr x))
-+ (car (cdr x))
-+ '()))
-+ `,vars)))))
-+ do-macro)))
-+
-+;;;; generic-member
-+(define (generic-member cmp obj lst)
-+ (cond
-+ ((null? lst) #f)
-+ ((cmp obj (car lst)) lst)
-+ (else (generic-member cmp obj (cdr lst)))))
-+
-+(define (memq obj lst)
-+ (generic-member eq? obj lst))
-+(define (memv obj lst)
-+ (generic-member eqv? obj lst))
-+(define (member obj lst)
-+ (generic-member equal? obj lst))
-+
-+;;;; generic-assoc
-+(define (generic-assoc cmp obj alst)
-+ (cond
-+ ((null? alst) #f)
-+ ((cmp obj (caar alst)) (car alst))
-+ (else (generic-assoc cmp obj (cdr alst)))))
-+
-+(define (assq obj alst)
-+ (generic-assoc eq? obj alst))
-+(define (assv obj alst)
-+ (generic-assoc eqv? obj alst))
-+(define (assoc obj alst)
-+ (generic-assoc equal? obj alst))
-+
-+(define (acons x y z) (cons (cons x y) z))
-+
-+;;;; Handy for imperative programs
-+;;;; Used as: (define-with-return (foo x y) .... (return z) ...)
-+(macro (define-with-return form)
-+ `(define ,(cadr form)
-+ (call/cc (lambda (return) ,@(cddr form)))))
-+
-+;;;; Simple exception handling
-+;
-+; Exceptions are caught as follows:
-+;
-+; (catch (do-something to-recover and-return meaningful-value)
-+; (if-something goes-wrong)
-+; (with-these calls))
-+;
-+; "Catch" establishes a scope spanning multiple call-frames
-+; until another "catch" is encountered.
-+;
-+; Exceptions are thrown with:
-+;
-+; (throw "message")
-+;
-+; If used outside a (catch ...), reverts to (error "message)
-+
-+(define *handlers* (list))
-+
-+(define (push-handler proc)
-+ (set! *handlers* (cons proc *handlers*)))
-+
-+(define (pop-handler)
-+ (let ((h (car *handlers*)))
-+ (set! *handlers* (cdr *handlers*))
-+ h))
-+
-+(define (more-handlers?)
-+ (pair? *handlers*))
-+
-+(define (throw . x)
-+ (if (more-handlers?)
-+ (apply (pop-handler))
-+ (apply error x)))
-+
-+(macro (catch form)
-+ (let ((label (gensym)))
-+ `(call/cc (lambda (exit)
-+ (push-handler (lambda () (exit ,(cadr form))))
-+ (let ((,label (begin ,@(cddr form))))
-+ (pop-handler)
-+ ,label)))))
-+
-+(define *error-hook* throw)
-+
-+
-+;;;;; Definition of MAKE-ENVIRONMENT, to be used with two-argument EVAL
-+
-+(macro (make-environment form)
-+ `(apply (lambda ()
-+ ,@(cdr form)
-+ (current-environment))))
-+
-+(define-macro (eval-polymorphic x . envl)
-+ (display envl)
-+ (let* ((env (if (null? envl) (current-environment) (eval (car envl))))
-+ (xval (eval x env)))
-+ (if (closure? xval)
-+ (make-closure (get-closure-code xval) env)
-+ xval)))
-+
-+; Redefine this if you install another package infrastructure
-+; Also redefine 'package'
-+(define *colon-hook* eval)
-+
-+;;;;; I/O
-+
-+(define (input-output-port? p)
-+ (and (input-port? p) (output-port? p)))
-+
-+(define (close-port p)
-+ (cond
-+ ((input-output-port? p) (close-input-port (close-output-port p)))
-+ ((input-port? p) (close-input-port p))
-+ ((output-port? p) (close-output-port p))
-+ (else (throw "Not a port" p))))
-+
-+(define (call-with-input-file s p)
-+ (let ((inport (open-input-file s)))
-+ (if (eq? inport #f)
-+ #f
-+ (let ((res (p inport)))
-+ (close-input-port inport)
-+ res))))
-+
-+(define (call-with-output-file s p)
-+ (let ((outport (open-output-file s)))
-+ (if (eq? outport #f)
-+ #f
-+ (let ((res (p outport)))
-+ (close-output-port outport)
-+ res))))
-+
-+(define (with-input-from-file s p)
-+ (let ((inport (open-input-file s)))
-+ (if (eq? inport #f)
-+ #f
-+ (let ((prev-inport (current-input-port)))
-+ (set-input-port inport)
-+ (let ((res (p)))
-+ (close-input-port inport)
-+ (set-input-port prev-inport)
-+ res)))))
-+
-+(define (with-output-to-file s p)
-+ (let ((outport (open-output-file s)))
-+ (if (eq? outport #f)
-+ #f
-+ (let ((prev-outport (current-output-port)))
-+ (set-output-port outport)
-+ (let ((res (p)))
-+ (close-output-port outport)
-+ (set-output-port prev-outport)
-+ res)))))
-+
-+(define (with-input-output-from-to-files si so p)
-+ (let ((inport (open-input-file si))
-+ (outport (open-input-file so)))
-+ (if (not (and inport outport))
-+ (begin
-+ (close-input-port inport)
-+ (close-output-port outport)
-+ #f)
-+ (let ((prev-inport (current-input-port))
-+ (prev-outport (current-output-port)))
-+ (set-input-port inport)
-+ (set-output-port outport)
-+ (let ((res (p)))
-+ (close-input-port inport)
-+ (close-output-port outport)
-+ (set-input-port prev-inport)
-+ (set-output-port prev-outport)
-+ res)))))
-+
-+; Random number generator (maximum cycle)
-+(define *seed* 1)
-+(define (random-next)
-+ (let* ((a 16807) (m 2147483647) (q (quotient m a)) (r (modulo m a)))
-+ (set! *seed*
-+ (- (* a (- *seed*
-+ (* (quotient *seed* q) q)))
-+ (* (quotient *seed* q) r)))
-+ (if (< *seed* 0) (set! *seed* (+ *seed* m)))
-+ *seed*))
-+;; SRFI-0
-+;; COND-EXPAND
-+;; Implemented as a macro
-+(define *features* '(srfi-0))
-+
-+(define-macro (cond-expand . cond-action-list)
-+ (cond-expand-runtime cond-action-list))
-+
-+(define (cond-expand-runtime cond-action-list)
-+ (if (null? cond-action-list)
-+ #t
-+ (if (cond-eval (caar cond-action-list))
-+ `(begin ,@(cdar cond-action-list))
-+ (cond-expand-runtime (cdr cond-action-list)))))
-+
-+(define (cond-eval-and cond-list)
-+ (foldr (lambda (x y) (and (cond-eval x) (cond-eval y))) #t cond-list))
-+
-+(define (cond-eval-or cond-list)
-+ (foldr (lambda (x y) (or (cond-eval x) (cond-eval y))) #f cond-list))
-+
-+(define (cond-eval condition)
-+ (cond
-+ ((symbol? condition)
-+ (if (member condition *features*) #t #f))
-+ ((eq? condition #t) #t)
-+ ((eq? condition #f) #f)
-+ (else (case (car condition)
-+ ((and) (cond-eval-and (cdr condition)))
-+ ((or) (cond-eval-or (cdr condition)))
-+ ((not) (if (not (null? (cddr condition)))
-+ (error "cond-expand : 'not' takes 1 argument")
-+ (not (cond-eval (cadr condition)))))
-+ (else (error "cond-expand : unknown operator" (car condition)))))))
-+
-+(gc-verbose #f)
-diff --git a/bootshell/main.c b/bootshell/main.c
-new file mode 100644
-index 0000000..f5f3ab5
---- /dev/null
-+++ b/bootshell/main.c
-@@ -0,0 +1,296 @@
-+/* Standard startup-time command line parser
-+
-+ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001, 2007
-+ Free Software Foundation, Inc.
-+*/
-+#include <argp.h>
-+#include <assert.h>
-+#include <ctype.h>
-+#include <stdarg.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <error.h>
-+#include <hurd.h>
-+#include <hurd/fshelp.h>
-+#include <device/device.h>
-+#include <version.h>
-+
-+#if LIBREADLINE_LINKS
-+#include <readline/readline.h>
-+#include <readline/history.h>
-+#endif
-+
-+#include "scheme.h"
-+#include "scheme-private.h"
-+
-+#include "bootshell.h"
-+#include "ffi.h"
-+
-+task_t bootscript_task;
-+task_t rootfs_server_task;
-+task_t exec_server_task;
-+
-+#define _HURD_RUNSYSTEM "/hurd/runsystem.scm"
-+#define _BOOT_COMMAND "(boot)"
-+
-+char *multiboot_command_line;
-+char *boot_init_program;
-+boolean_t boot_pause;
-+char *boot_command = _BOOT_COMMAND;
-+char **global_argv;
-+boolean_t booted;
-+boolean_t interactive;
-+
-+scheme scm;
-+
-+/* We catch exceptions using this port. */
-+mach_port_t exception_port;
-+
-+mach_port_t console;
-+
-+mach_port_t portarray_template[INIT_PORT_MAX];
-+
-+const char *argp_program_version = STANDARD_HURD_VERSION (bootshell);
-+
-+#define OPT_HOST_PRIV_PORT (-1)
-+#define OPT_DEVICE_MASTER_PORT (-2)
-+#define OPT_BOOTSCRIPT_TASK (-3)
-+#define OPT_ROOTFS_SERVER_TASK (-4)
-+#define OPT_EXEC_SERVER_TASK (-5)
-+#define OPT_BOOT_CMDLINE (-6)
-+#define OPT_BOOT_COMMAND (-7)
-+#define OPT_BOOT_INIT_PROGRAM (-8)
-+#define OPT_BOOT_PAUSE (-9)
-+
-+static const struct argp_option options[] =
-+{
-+ {"interactive", 'I', NULL, 0, "start interactive repl"},
-+ {0,0,0,0, "Boot options:", -2},
-+ {"multiboot-command-line", OPT_BOOT_CMDLINE, "ARGS", 0,
-+ "The multiboot kernel command line"},
-+ {"bootflags", 0, 0, OPTION_ALIAS|OPTION_HIDDEN},
-+ {"boot-debug-pause", OPT_BOOT_PAUSE, NULL, 0,
-+ "Pause for keystroke before starting bootstrap programs"},
-+ {"boot-command", OPT_BOOT_COMMAND, "S-EXPRESSION", 0,
-+ "Command to run, default: " _BOOT_COMMAND},
-+ {"host-priv-port", OPT_HOST_PRIV_PORT, "PORT"},
-+ {"device-master-port", OPT_DEVICE_MASTER_PORT, "PORT"},
-+ {"bootscript-task", OPT_BOOTSCRIPT_TASK, "PORT"},
-+ {"rootfs-server-task", OPT_ROOTFS_SERVER_TASK, "PORT"},
-+ {"exec-server-task", OPT_EXEC_SERVER_TASK, "PORT"},
-+ {0}
-+};
-+
-+static error_t
-+parse_opt (int opt, char *arg, struct argp_state *state)
-+{
-+ switch (opt)
-+ {
-+ /* Boot options */
-+ case 'I':
-+ interactive = 1;
-+ break;
-+ case OPT_DEVICE_MASTER_PORT:
-+ _hurd_device_master = atoi (arg); break;
-+ case OPT_HOST_PRIV_PORT:
-+ _hurd_host_priv = atoi (arg); break;
-+ case OPT_BOOTSCRIPT_TASK:
-+ bootscript_task = atoi (arg); break;
-+ case OPT_ROOTFS_SERVER_TASK:
-+ rootfs_server_task = atoi (arg); break;
-+ case OPT_EXEC_SERVER_TASK:
-+ exec_server_task = atoi (arg); break;
-+ case OPT_BOOT_CMDLINE:
-+ multiboot_command_line = arg; break;
-+ case OPT_BOOT_INIT_PROGRAM:
-+ boot_init_program = arg; break;
-+ case OPT_BOOT_PAUSE:
-+ boot_pause = 1; break;
-+ case OPT_BOOT_COMMAND:
-+ boot_command = arg; break;
-+ case ARGP_KEY_END:
-+ global_argv = state->argv; break;
-+ default:
-+ return ARGP_ERR_UNKNOWN;
-+ case ARGP_KEY_INIT:
-+ case ARGP_KEY_SUCCESS:
-+ case ARGP_KEY_ERROR:
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static const char doc[] =
-+ "Start and maintain hurd core servers and system run state";
-+
-+static const struct argp argp =
-+{ options, parse_opt, 0, doc };
-+
-+void
-+panic (const char *msg)
-+{
-+ mach_printf ("%s\n", msg);
-+ _exit (127);
-+}
-+
-+void ffi_update (scheme *sc); //XXX
-+
-+
-+/* A static variable for holding the line. */
-+static char *line_read = (char *)NULL;
-+
-+/* Read a string, and return a pointer to it.
-+ Returns NULL on EOF. */
-+char *
-+rl_gets (const char *prompt)
-+{
-+ /* If the buffer has already been allocated,
-+ return the memory to the free pool. */
-+ if (line_read)
-+ {
-+ free (line_read);
-+ line_read = (char *)NULL;
-+ }
-+
-+#if 0
-+ /* Get a line from the user. */
-+ line_read = readline (prompt);
-+
-+ /* If the line has any text in it,
-+ save it on the history. */
-+ if (line_read && *line_read)
-+ add_history (line_read);
-+#else
-+ printf ("%s", prompt);
-+ fflush (stdout);
-+ line_read = malloc (80);
-+ if (line_read != NULL)
-+ fgets (line_read, 80, stdin);
-+#endif
-+
-+ /* rstrip line */
-+ if (line_read && strlen (line_read) > 0)
-+ for (char *p = &line_read[strlen (line_read) - 1]; isspace (*p); p--)
-+ *p = 0;
-+
-+ return line_read;
-+}
-+
-+int
-+main (int argc, char **argv)
-+{
-+ error_t err;
-+ /* XXX */
-+ setenv ("TERM", "mach", 1);
-+ setenv ("COLS", "80", 1);
-+ setenv ("LINES", "25", 1);
-+
-+ argp_parse (&argp, argc, argv, /*ARGP_NO_ERRS|*/ARGP_IN_ORDER, 0, 0);
-+
-+ {
-+ mach_port_t proc = getproc ();
-+ if (MACH_PORT_VALID (proc))
-+ {
-+ booted = 1;
-+ err = mach_port_deallocate (mach_task_self (), proc);
-+ assert_perror (err);
-+ }
-+ }
-+
-+ if (! booted)
-+ {
-+ err = init_exception_handling ();
-+ if (err)
-+ error (1, err, "init_exception_handling");
-+ }
-+
-+ err = init_fs_server (); // XXX don't start automatically
-+ if (err)
-+ error (1, err, "init_fs_server");
-+
-+ if (MACH_PORT_VALID (_hurd_device_master))
-+ {
-+ err = device_open (_hurd_device_master, D_READ|D_WRITE,
-+ "console", &console);
-+ if (err)
-+ panic ("Failed to open console.");
-+
-+ stdin = mach_open_devstream (console, "r");
-+ stdout = stderr = mach_open_devstream (console, "w");
-+ if (! stdin || ! stdout)
-+ panic ("Failed to open device stream.");
-+
-+ setvbuf (stdout, NULL, _IONBF, 0);
-+ }
-+
-+ if (! scheme_init (&scm))
-+ error (1, errno, "scheme_init");
-+
-+ scheme_set_input_port_file(&scm, stdin);
-+ scheme_set_output_port_file(&scm, stdout);
-+
-+ ffi_init (&scm);
-+
-+ load_embedded_script (&scm, init_scm);
-+ load_embedded_script (&scm, boot_scm);
-+ load_embedded_script (&scm, runsystem_scm);
-+
-+ define_variable (&scm, bootscript_task);
-+ define_variable (&scm, rootfs_server_task);
-+ define_variable (&scm, exec_server_task);
-+ define_variable (&scm, boot_pause);
-+
-+ define_ (&scm, "host-priv",
-+ scm.vptr->mk_integer (&scm, _hurd_host_priv));
-+ define_ (&scm, "device-master",
-+ scm.vptr->mk_integer (&scm, _hurd_device_master));
-+
-+ define_variable_string (&scm, multiboot_command_line);
-+ define_variable_string (&scm, boot_init_program);
-+ define_variable_string (&scm, boot_command);
-+ define_variable (&scm, boot_pause);
-+ {
-+ char *argz = NULL;
-+ size_t argz_len = 0;
-+ err = argz_create (argv, &argz, &argz_len);
-+ assert_perror (err);
-+ define_ (&scm, "argv", ffi_argz2list (&scm, argz, argz_len, NULL));
-+ }
-+
-+ if (MACH_PORT_VALID (bootscript_task))
-+ {
-+ vm_size_t size;
-+ vm_prot_t prot, max_prot;
-+ mach_port_t obj;
-+ vm_offset_t addr = 0, offs;
-+ vm_inherit_t inh;
-+ int shared;
-+
-+ err =
-+ vm_region (bootscript_task, &addr, &size, &prot, &max_prot, &inh, &shared,
-+ &obj, &offs);
-+ if (err)
-+ error (12, err, "vm_region");
-+
-+ vm_offset_t script;
-+ size_t count;
-+ err = vm_read (bootscript_task, addr, size, &script, &count);
-+ if (err)
-+ error (12, err, "vm_read");
-+ scheme_load_mem (&scm, (char *) script, (char *) script + size);
-+ if (scm.retcode) {
-+ fprintf (stderr, "Error: %d\n", scm.retcode);
-+ }
-+ }
-+
-+ if (! interactive)
-+ scheme_load_string (&scm, boot_command);
-+
-+ while (1)
-+ scheme_load_string (&scm, "(interactive-repl)");
-+
-+ /* Not reached. */
-+ scheme_deinit(&scm);
-+ return 0;
-+}
-diff --git a/bootshell/mig-decls.h b/bootshell/mig-decls.h
-new file mode 100644
-index 0000000..120778d
---- /dev/null
-+++ b/bootshell/mig-decls.h
-@@ -0,0 +1,3 @@
-+#include <hurd.h>
-+
-+#define MIG_EOPNOTSUPP ({ abort (); EOPNOTSUPP; })
-diff --git a/bootshell/mig-mutate.h b/bootshell/mig-mutate.h
-new file mode 100644
-index 0000000..eadcbc9
---- /dev/null
-+++ b/bootshell/mig-mutate.h
-@@ -0,0 +1,27 @@
-+/*
-+ Copyright (C) 2014 Free Software Foundation, Inc.
-+ Written by Justus Winter.
-+
-+ This file is part of the GNU Hurd.
-+
-+ The GNU Hurd 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 Hurd 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 Hurd. If not, see <http://www.gnu.org/licenses/>. */
-+
-+#define HURD_DEFAULT_PAYLOAD_TO_PORT 1
-+
-+#define FILE_IMPORTS \
-+ import "mig-decls.h";
-+#define FSYS_IMPORTS \
-+ import "mig-decls.h";
-+#define STARTUP_IMPORTS \
-+ import "mig-decls.h";
-diff --git a/bootshell/opdefines.h b/bootshell/opdefines.h
-new file mode 100644
-index 0000000..ceb4d0e
---- /dev/null
-+++ b/bootshell/opdefines.h
-@@ -0,0 +1,195 @@
-+ _OP_DEF(opexe_0, "load", 1, 1, TST_STRING, OP_LOAD )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_T0LVL )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_T1LVL )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_READ_INTERNAL )
-+ _OP_DEF(opexe_0, "gensym", 0, 0, 0, OP_GENSYM )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_VALUEPRINT )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_EVAL )
-+#if USE_TRACING
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_REAL_EVAL )
-+#endif
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_E0ARGS )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_E1ARGS )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_APPLY )
-+#if USE_TRACING
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_REAL_APPLY )
-+ _OP_DEF(opexe_0, "tracing", 1, 1, TST_NATURAL, OP_TRACING )
-+#endif
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DOMACRO )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LAMBDA )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LAMBDA1 )
-+ _OP_DEF(opexe_0, "make-closure", 1, 2, TST_PAIR TST_ENVIRONMENT, OP_MKCLOSURE )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_QUOTE )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DEF0 )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_DEF1 )
-+ _OP_DEF(opexe_0, "defined?", 1, 2, TST_SYMBOL TST_ENVIRONMENT, OP_DEFP )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_BEGIN )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_IF0 )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_IF1 )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_SET0 )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_SET1 )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET0 )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET1 )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET2 )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET0AST )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET1AST )
-+ _OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET2AST )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET0REC )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET1REC )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET2REC )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_COND0 )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_COND1 )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_DELAY )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_AND0 )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_AND1 )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_OR0 )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_OR1 )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_C0STREAM )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_C1STREAM )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_MACRO0 )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_MACRO1 )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE0 )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE1 )
-+ _OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE2 )
-+ _OP_DEF(opexe_1, "eval", 1, 2, TST_ANY TST_ENVIRONMENT, OP_PEVAL )
-+ _OP_DEF(opexe_1, "apply", 1, INF_ARG, TST_NONE, OP_PAPPLY )
-+ _OP_DEF(opexe_1, "call-with-current-continuation", 1, 1, TST_NONE, OP_CONTINUATION )
-+#if USE_MATH
-+ _OP_DEF(opexe_2, "inexact->exact", 1, 1, TST_NUMBER, OP_INEX2EX )
-+ _OP_DEF(opexe_2, "exp", 1, 1, TST_NUMBER, OP_EXP )
-+ _OP_DEF(opexe_2, "log", 1, 1, TST_NUMBER, OP_LOG )
-+ _OP_DEF(opexe_2, "sin", 1, 1, TST_NUMBER, OP_SIN )
-+ _OP_DEF(opexe_2, "cos", 1, 1, TST_NUMBER, OP_COS )
-+ _OP_DEF(opexe_2, "tan", 1, 1, TST_NUMBER, OP_TAN )
-+ _OP_DEF(opexe_2, "asin", 1, 1, TST_NUMBER, OP_ASIN )
-+ _OP_DEF(opexe_2, "acos", 1, 1, TST_NUMBER, OP_ACOS )
-+ _OP_DEF(opexe_2, "atan", 1, 2, TST_NUMBER, OP_ATAN )
-+ _OP_DEF(opexe_2, "sqrt", 1, 1, TST_NUMBER, OP_SQRT )
-+ _OP_DEF(opexe_2, "expt", 2, 2, TST_NUMBER, OP_EXPT )
-+ _OP_DEF(opexe_2, "floor", 1, 1, TST_NUMBER, OP_FLOOR )
-+ _OP_DEF(opexe_2, "ceiling", 1, 1, TST_NUMBER, OP_CEILING )
-+ _OP_DEF(opexe_2, "truncate", 1, 1, TST_NUMBER, OP_TRUNCATE )
-+ _OP_DEF(opexe_2, "round", 1, 1, TST_NUMBER, OP_ROUND )
-+#endif
-+ _OP_DEF(opexe_2, "+", 0, INF_ARG, TST_NUMBER, OP_ADD )
-+ _OP_DEF(opexe_2, "-", 1, INF_ARG, TST_NUMBER, OP_SUB )
-+ _OP_DEF(opexe_2, "*", 0, INF_ARG, TST_NUMBER, OP_MUL )
-+ _OP_DEF(opexe_2, "/", 1, INF_ARG, TST_NUMBER, OP_DIV )
-+ _OP_DEF(opexe_2, "quotient", 1, INF_ARG, TST_INTEGER, OP_INTDIV )
-+ _OP_DEF(opexe_2, "remainder", 2, 2, TST_INTEGER, OP_REM )
-+ _OP_DEF(opexe_2, "modulo", 2, 2, TST_INTEGER, OP_MOD )
-+ _OP_DEF(opexe_2, "car", 1, 1, TST_PAIR, OP_CAR )
-+ _OP_DEF(opexe_2, "cdr", 1, 1, TST_PAIR, OP_CDR )
-+ _OP_DEF(opexe_2, "cons", 2, 2, TST_NONE, OP_CONS )
-+ _OP_DEF(opexe_2, "set-car!", 2, 2, TST_PAIR TST_ANY, OP_SETCAR )
-+ _OP_DEF(opexe_2, "set-cdr!", 2, 2, TST_PAIR TST_ANY, OP_SETCDR )
-+ _OP_DEF(opexe_2, "char->integer", 1, 1, TST_CHAR, OP_CHAR2INT )
-+ _OP_DEF(opexe_2, "integer->char", 1, 1, TST_NATURAL, OP_INT2CHAR )
-+ _OP_DEF(opexe_2, "char-upcase", 1, 1, TST_CHAR, OP_CHARUPCASE )
-+ _OP_DEF(opexe_2, "char-downcase", 1, 1, TST_CHAR, OP_CHARDNCASE )
-+ _OP_DEF(opexe_2, "symbol->string", 1, 1, TST_SYMBOL, OP_SYM2STR )
-+ _OP_DEF(opexe_2, "atom->string", 1, 2, TST_ANY TST_NATURAL, OP_ATOM2STR )
-+ _OP_DEF(opexe_2, "string->symbol", 1, 1, TST_STRING, OP_STR2SYM )
-+ _OP_DEF(opexe_2, "string->atom", 1, 2, TST_STRING TST_NATURAL, OP_STR2ATOM )
-+ _OP_DEF(opexe_2, "make-string", 1, 2, TST_NATURAL TST_CHAR, OP_MKSTRING )
-+ _OP_DEF(opexe_2, "string-length", 1, 1, TST_STRING, OP_STRLEN )
-+ _OP_DEF(opexe_2, "string-ref", 2, 2, TST_STRING TST_NATURAL, OP_STRREF )
-+ _OP_DEF(opexe_2, "string-set!", 3, 3, TST_STRING TST_NATURAL TST_CHAR, OP_STRSET )
-+ _OP_DEF(opexe_2, "string-append", 0, INF_ARG, TST_STRING, OP_STRAPPEND )
-+ _OP_DEF(opexe_2, "substring", 2, 3, TST_STRING TST_NATURAL, OP_SUBSTR )
-+ _OP_DEF(opexe_2, "vector", 0, INF_ARG, TST_NONE, OP_VECTOR )
-+ _OP_DEF(opexe_2, "make-vector", 1, 2, TST_NATURAL TST_ANY, OP_MKVECTOR )
-+ _OP_DEF(opexe_2, "vector-length", 1, 1, TST_VECTOR, OP_VECLEN )
-+ _OP_DEF(opexe_2, "vector-ref", 2, 2, TST_VECTOR TST_NATURAL, OP_VECREF )
-+ _OP_DEF(opexe_2, "vector-set!", 3, 3, TST_VECTOR TST_NATURAL TST_ANY, OP_VECSET )
-+ _OP_DEF(opexe_3, "not", 1, 1, TST_NONE, OP_NOT )
-+ _OP_DEF(opexe_3, "boolean?", 1, 1, TST_NONE, OP_BOOLP )
-+ _OP_DEF(opexe_3, "eof-object?", 1, 1, TST_NONE, OP_EOFOBJP )
-+ _OP_DEF(opexe_3, "null?", 1, 1, TST_NONE, OP_NULLP )
-+ _OP_DEF(opexe_3, "=", 2, INF_ARG, TST_NUMBER, OP_NUMEQ )
-+ _OP_DEF(opexe_3, "<", 2, INF_ARG, TST_NUMBER, OP_LESS )
-+ _OP_DEF(opexe_3, ">", 2, INF_ARG, TST_NUMBER, OP_GRE )
-+ _OP_DEF(opexe_3, "<=", 2, INF_ARG, TST_NUMBER, OP_LEQ )
-+ _OP_DEF(opexe_3, ">=", 2, INF_ARG, TST_NUMBER, OP_GEQ )
-+ _OP_DEF(opexe_3, "symbol?", 1, 1, TST_ANY, OP_SYMBOLP )
-+ _OP_DEF(opexe_3, "number?", 1, 1, TST_ANY, OP_NUMBERP )
-+ _OP_DEF(opexe_3, "string?", 1, 1, TST_ANY, OP_STRINGP )
-+ _OP_DEF(opexe_3, "integer?", 1, 1, TST_ANY, OP_INTEGERP )
-+ _OP_DEF(opexe_3, "real?", 1, 1, TST_ANY, OP_REALP )
-+ _OP_DEF(opexe_3, "char?", 1, 1, TST_ANY, OP_CHARP )
-+#if USE_CHAR_CLASSIFIERS
-+ _OP_DEF(opexe_3, "char-alphabetic?", 1, 1, TST_CHAR, OP_CHARAP )
-+ _OP_DEF(opexe_3, "char-numeric?", 1, 1, TST_CHAR, OP_CHARNP )
-+ _OP_DEF(opexe_3, "char-whitespace?", 1, 1, TST_CHAR, OP_CHARWP )
-+ _OP_DEF(opexe_3, "char-upper-case?", 1, 1, TST_CHAR, OP_CHARUP )
-+ _OP_DEF(opexe_3, "char-lower-case?", 1, 1, TST_CHAR, OP_CHARLP )
-+#endif
-+ _OP_DEF(opexe_3, "port?", 1, 1, TST_ANY, OP_PORTP )
-+ _OP_DEF(opexe_3, "input-port?", 1, 1, TST_ANY, OP_INPORTP )
-+ _OP_DEF(opexe_3, "output-port?", 1, 1, TST_ANY, OP_OUTPORTP )
-+ _OP_DEF(opexe_3, "procedure?", 1, 1, TST_ANY, OP_PROCP )
-+ _OP_DEF(opexe_3, "pair?", 1, 1, TST_ANY, OP_PAIRP )
-+ _OP_DEF(opexe_3, "list?", 1, 1, TST_ANY, OP_LISTP )
-+ _OP_DEF(opexe_3, "environment?", 1, 1, TST_ANY, OP_ENVP )
-+ _OP_DEF(opexe_3, "vector?", 1, 1, TST_ANY, OP_VECTORP )
-+ _OP_DEF(opexe_3, "eq?", 2, 2, TST_ANY, OP_EQ )
-+ _OP_DEF(opexe_3, "eqv?", 2, 2, TST_ANY, OP_EQV )
-+ _OP_DEF(opexe_4, "force", 1, 1, TST_ANY, OP_FORCE )
-+ _OP_DEF(opexe_4, 0, 0, 0, 0, OP_SAVE_FORCED )
-+ _OP_DEF(opexe_4, "write", 1, 2, TST_ANY TST_OUTPORT, OP_WRITE )
-+ _OP_DEF(opexe_4, "write-char", 1, 2, TST_CHAR TST_OUTPORT, OP_WRITE_CHAR )
-+ _OP_DEF(opexe_4, "display", 1, 2, TST_ANY TST_OUTPORT, OP_DISPLAY )
-+ _OP_DEF(opexe_4, "newline", 0, 1, TST_OUTPORT, OP_NEWLINE )
-+ _OP_DEF(opexe_4, "error", 1, INF_ARG, TST_NONE, OP_ERR0 )
-+ _OP_DEF(opexe_4, 0, 0, 0, 0, OP_ERR1 )
-+ _OP_DEF(opexe_4, "reverse", 1, 1, TST_LIST, OP_REVERSE )
-+ _OP_DEF(opexe_4, "list*", 1, INF_ARG, TST_NONE, OP_LIST_STAR )
-+ _OP_DEF(opexe_4, "append", 0, INF_ARG, TST_NONE, OP_APPEND )
-+#if USE_PLIST
-+ _OP_DEF(opexe_4, "put", 3, 3, TST_NONE, OP_PUT )
-+ _OP_DEF(opexe_4, "get", 2, 2, TST_NONE, OP_GET )
-+#endif
-+ _OP_DEF(opexe_4, "quit", 0, 1, TST_NUMBER, OP_QUIT )
-+ _OP_DEF(opexe_4, "gc", 0, 0, 0, OP_GC )
-+ _OP_DEF(opexe_4, "gc-verbose", 0, 1, TST_NONE, OP_GCVERB )
-+ _OP_DEF(opexe_4, "new-segment", 0, 1, TST_NUMBER, OP_NEWSEGMENT )
-+ _OP_DEF(opexe_4, "oblist", 0, 0, 0, OP_OBLIST )
-+ _OP_DEF(opexe_4, "current-input-port", 0, 0, 0, OP_CURR_INPORT )
-+ _OP_DEF(opexe_4, "current-output-port", 0, 0, 0, OP_CURR_OUTPORT )
-+ _OP_DEF(opexe_4, "open-input-file", 1, 1, TST_STRING, OP_OPEN_INFILE )
-+ _OP_DEF(opexe_4, "open-output-file", 1, 1, TST_STRING, OP_OPEN_OUTFILE )
-+ _OP_DEF(opexe_4, "open-input-output-file", 1, 1, TST_STRING, OP_OPEN_INOUTFILE )
-+#if USE_STRING_PORTS
-+ _OP_DEF(opexe_4, "open-input-string", 1, 1, TST_STRING, OP_OPEN_INSTRING )
-+ _OP_DEF(opexe_4, "open-input-output-string", 1, 1, TST_STRING, OP_OPEN_INOUTSTRING )
-+ _OP_DEF(opexe_4, "open-output-string", 0, 1, TST_STRING, OP_OPEN_OUTSTRING )
-+ _OP_DEF(opexe_4, "get-output-string", 1, 1, TST_OUTPORT, OP_GET_OUTSTRING )
-+#endif
-+ _OP_DEF(opexe_4, "close-input-port", 1, 1, TST_INPORT, OP_CLOSE_INPORT )
-+ _OP_DEF(opexe_4, "close-output-port", 1, 1, TST_OUTPORT, OP_CLOSE_OUTPORT )
-+ _OP_DEF(opexe_4, "interaction-environment", 0, 0, 0, OP_INT_ENV )
-+ _OP_DEF(opexe_4, "current-environment", 0, 0, 0, OP_CURR_ENV )
-+ _OP_DEF(opexe_5, "read", 0, 1, TST_INPORT, OP_READ )
-+ _OP_DEF(opexe_5, "read-char", 0, 1, TST_INPORT, OP_READ_CHAR )
-+ _OP_DEF(opexe_5, "peek-char", 0, 1, TST_INPORT, OP_PEEK_CHAR )
-+ _OP_DEF(opexe_5, "char-ready?", 0, 1, TST_INPORT, OP_CHAR_READY )
-+ _OP_DEF(opexe_5, "set-input-port", 1, 1, TST_INPORT, OP_SET_INPORT )
-+ _OP_DEF(opexe_5, "set-output-port", 1, 1, TST_OUTPORT, OP_SET_OUTPORT )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDSEXPR )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDLIST )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDDOT )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQUOTE )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQQUOTE )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQQUOTEVEC )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDUNQUOTE )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDUQTSP )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDVEC )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_P0LIST )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_P1LIST )
-+ _OP_DEF(opexe_5, 0, 0, 0, 0, OP_PVECFROM )
-+ _OP_DEF(opexe_6, "length", 1, 1, TST_LIST, OP_LIST_LENGTH )
-+ _OP_DEF(opexe_6, "assq", 2, 2, TST_NONE, OP_ASSQ )
-+ _OP_DEF(opexe_6, "get-closure-code", 1, 1, TST_NONE, OP_GET_CLOSURE )
-+ _OP_DEF(opexe_6, "closure?", 1, 1, TST_NONE, OP_CLOSUREP )
-+ _OP_DEF(opexe_6, "macro?", 1, 1, TST_NONE, OP_MACROP )
-+#undef _OP_DEF
-diff --git a/bootshell/runsystem.scm b/bootshell/runsystem.scm
-new file mode 100644
-index 0000000..940b862
---- /dev/null
-+++ b/bootshell/runsystem.scm
-@@ -0,0 +1,175 @@
-+;; The Hurd server bootstrap.
-+;;
-+;; XXX license, how to modify
-+
-+(define timeout 1000) ; 1 second
-+
-+(define (pause)
-+ (if (= 1 boot-pause) (prompt "Press enter to continue...")))
-+
-+;; Tests if a device with the given NAME exists.
-+(define (devprobe? name)
-+ (letport ((device (catch MACH_PORT_NULL
-+ (device-open device-master D_READ name))))
-+ (mach-port-valid? device)))
-+
-+;; Insert RIGHT into TASK. Returns the name of RIGHT in TASK.
-+(define (task-insert-send-right task right)
-+ (let loop ((name 1))
-+ (catch (loop (+ name 1))
-+ (mach-port-insert-right task name right MACH_MSG_TYPE_COPY_SEND)
-+ name)))
-+
-+;; Inserts RIGHT into TASK and returns a command line argument OPTION
-+;; with the value set to the name of RIGHT in TASK.
-+(define (make-arg option task right)
-+ (string-append "--" option "="
-+ (number->string (task-insert-send-right task right))))
-+
-+;; Returns a function that can be passed to `bootstrap-translator' to
-+;; resume a translator loaded by the traditional bootscript mechanism.
-+(define (resume-translator task args)
-+ (lambda (bootstrap)
-+ (task-set-exception-port task (make-send-right exception-port))
-+ (task-set-bootstrap-port task bootstrap)
-+ (pause)
-+ (task-resume task)
-+ (handle-exec-startup bootstrap args timeout)
-+ task))
-+
-+;; Returns a function that can be passed to `bootstrap-translator' to
-+;; start a translator that is loaded from a disk.
-+(define (start-translator task argv)
-+ (lambda (bootstrap)
-+ (letport ((proc (getproc)))
-+ (pause)
-+ (_exec (file-name-lookup (car argv) O_EXEC 0) task argv bootstrap)
-+ (if (mach-port-valid? proc)
-+ (let ((child-proc (proc->task->proc proc task)))
-+ (proc->task->child! proc task)
-+ (proc->mark-exec! child-proc)
-+ (proc->mark-important! child-proc))))))
-+
-+;; Bootstraps a translator using the fsys protocol.
-+(define (bootstrap-translator prepare-task realnode)
-+ (let* ((bootstrap
-+ (mach-port-allocate mach-task-self MACH_PORT_RIGHT_RECEIVE))
-+ (task
-+ (prepare-task (make-send-right bootstrap))))
-+ (handle-fsys-startup bootstrap realnode MACH_MSG_TYPE_COPY_SEND timeout)))
-+
-+;; Bootstraps the proc server using the startup protocol.
-+(define (bootstrap-proc prepare-task)
-+ (let* ((bootstrap
-+ (mach-port-allocate mach-task-self MACH_PORT_RIGHT_RECEIVE))
-+ (task
-+ (prepare-task (make-send-right bootstrap))))
-+ (handle-startup-procinit bootstrap timeout)))
-+
-+;; Bootstraps the auth server using the startup protocol.
-+(define (bootstrap-auth prepare-task)
-+ (let* ((bootstrap
-+ (mach-port-allocate mach-task-self MACH_PORT_RIGHT_RECEIVE))
-+ (task
-+ (prepare-task (make-send-right bootstrap))))
-+ (handle-startup-authinit bootstrap timeout)))
-+
-+;; Bootstraps a translator using the fsys protocol and installs it as
-+;; root filesystem.
-+(define (bind-root prepare-task)
-+ (let ((control
-+ (bootstrap-translator prepare-task (make-send-right rootnode))))
-+ (_bind-root control rootnode)
-+ control))
-+
-+;; Bootstraps a translator using the fsys protocol and installs it as
-+;; active translator for the node PATH.
-+(define (bind path prepare-task)
-+ (letport ((realnode (file-name-lookup path O_NOTRANS 438))
-+ (control (bootstrap-translator prepare-task realnode)))
-+ (set-active-translator path control)
-+ (copy-send-right control)))
-+
-+;; We start servers when the proc server is not yet around. Once the
-+;; proc server is available, we use this function to update its state
-+;; related to TASK.
-+(define (fixup-task task)
-+ (letport ((myproc (getproc))
-+ (p (proc->task->proc myproc task)))
-+ (proc->task->child! myproc task)
-+ (proc->mark-important! p)
-+ (proc->mark-exec! p)))
-+
-+;; Perform a traditional Hurd server bootstrap. Expects suspended
-+;; rootfs and exec servers, with command line arguments prepared by
-+;; the kernel.
-+(define (bootstrap)
-+ (log "Hurd server bootstrap: ")
-+
-+ (log "rootfs ")
-+ (let ((rootfs-control (bind-root (resume-translator rootfs-server-task
-+ '())))
-+ (startup-control (mach-port-allocate mach-task-self
-+ MACH_PORT_RIGHT_RECEIVE))
-+ (proc-task (task-create mach-task-self 0))
-+ (auth-task (task-create mach-task-self 0))
-+ ;; Projections for the cookies returned by bootstrap-*.
-+ (:reply car) (:replyPoly cadr) (:server caddr))
-+ (start-handling-early-startup startup-control)
-+ (set-active-translator "/servers/startup"
-+ (make-send-right startup-control))
-+ (log "exec ")
-+ (bind "/servers/exec" (resume-translator exec-server-task '()))
-+
-+ (let ((pc (bootstrap-proc (start-translator proc-task '("/hurd/proc"))))
-+ (ac (bootstrap-auth (start-translator auth-task '("/hurd/auth")))))
-+ (log "proc ")
-+ (startup-procinit-reply (:reply pc) (:replyPoly pc) ESUCCESS
-+ mach-task-self (:server ac)
-+ host-priv device-master)
-+ (bind-proc (:server pc))
-+ (map fixup-task (list rootfs-server-task exec-server-task proc-task auth-task))
-+
-+ (log "auth ")
-+ (startup-authinit-reply (:reply ac) (:replyPoly ac) ESUCCESS
-+ (proc->task->proc (:server pc) auth-task))
-+ (bind-auth (:server ac))
-+
-+ ;; Give the rootfs its proc and auth port.
-+ (fsys-init rootfs-control
-+ (proc->task->proc (:server pc) rootfs-server-task)
-+ (:server ac))
-+ (mach-port-deallocate mach-task-self (:server pc))
-+ (mach-port-deallocate mach-task-self (:server ac))))
-+
-+ ;; The standalone startup server watches essential servers, and
-+ ;; handles the system shutdown.
-+ (log "startup ")
-+ (bind "/servers/startup"
-+ (start-translator (task-create mach-task-self 0)
-+ '("/hurd/startup-standalone")))
-+
-+ ;; Now that we have startup, register all servers to it.
-+ (let ((startup (file-name-lookup "/servers/startup" 0 0))
-+ ;; Projections.
-+ (:port car) (:name cdr))
-+ ;; We are essential.
-+ (startup-essential-task startup mach-task-self MACH_PORT_NULL
-+ "bootshell" host-priv)
-+ (map (lambda (c)
-+ (startup-essential-task startup (:port c) MACH_PORT_NULL
-+ (:name c) host-priv))
-+ (get-essential-tasks))
-+ (map (lambda (c)
-+ (startup-request-notification startup (:port c) (:name c)))
-+ (get-registered-tasks))
-+ (mach-port-deallocate mach-task-self startup))
-+
-+ (log "done.\n"))
-+
-+(define (boot)
-+ (catch (panic "Hurd bootstrap failed: " (car last-exception) "\n")
-+ (bootstrap))
-+
-+ (shell (lambda (prefix) (prompt-append-prefix
-+ (string-append "runsystem@" (hostname) " " (getcwd) " ") prefix))))
-diff --git a/bootshell/scheme-config.h b/bootshell/scheme-config.h
-new file mode 100644
-index 0000000..20ef332
---- /dev/null
-+++ b/bootshell/scheme-config.h
-@@ -0,0 +1,11 @@
-+#define STANDALONE 0
-+#define USE_MATH 0
-+#define USE_CHAR_CLASSIFIERS 1
-+#define USE_ASCII_NAMES 1
-+#define USE_STRING_PORTS 1
-+#define USE_ERROR_HOOK 1
-+#define USE_TRACING 1
-+#define USE_COLON_HOOK 0
-+#define USE_DL 0
-+#define USE_PLIST 0
-+#define USE_INTERFACE 1
-diff --git a/bootshell/scheme-private.h b/bootshell/scheme-private.h
-new file mode 100644
-index 0000000..3395328
---- /dev/null
-+++ b/bootshell/scheme-private.h
-@@ -0,0 +1,210 @@
-+/* scheme-private.h */
-+
-+#ifndef _SCHEME_PRIVATE_H
-+#define _SCHEME_PRIVATE_H
-+
-+#include "scheme.h"
-+/*------------------ Ugly internals -----------------------------------*/
-+/*------------------ Of interest only to FFI users --------------------*/
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+enum scheme_port_kind {
-+ port_free=0,
-+ port_file=1,
-+ port_string=2,
-+ port_srfi6=4,
-+ port_input=16,
-+ port_output=32,
-+ port_saw_EOF=64
-+};
-+
-+typedef struct port {
-+ unsigned char kind;
-+ union {
-+ struct {
-+ FILE *file;
-+ int closeit;
-+#if SHOW_ERROR_LINE
-+ int curr_line;
-+ char *filename;
-+#endif
-+ } stdio;
-+ struct {
-+ char *start;
-+ char *past_the_end;
-+ char *curr;
-+ } string;
-+ } rep;
-+} port;
-+
-+/* cell structure */
-+struct cell {
-+ unsigned int _flag;
-+ union {
-+ struct {
-+ char *_svalue;
-+ int _length;
-+ } _string;
-+ num _number;
-+ port *_port;
-+ foreign_func _ff;
-+ struct {
-+ struct cell *_car;
-+ struct cell *_cdr;
-+ } _cons;
-+ } _object;
-+};
-+
-+struct scheme {
-+/* arrays for segments */
-+func_alloc malloc;
-+func_dealloc free;
-+
-+/* return code */
-+int retcode;
-+int tracing;
-+
-+
-+#define CELL_SEGSIZE 5000 /* # of cells in one segment */
-+#define CELL_NSEGMENT 10 /* # of segments for cells */
-+char *alloc_seg[CELL_NSEGMENT];
-+pointer cell_seg[CELL_NSEGMENT];
-+int last_cell_seg;
-+
-+/* We use 4 registers. */
-+pointer args; /* register for arguments of function */
-+pointer envir; /* stack register for current environment */
-+pointer code; /* register for current code */
-+pointer dump; /* stack register for next evaluation */
-+
-+int interactive_repl; /* are we in an interactive REPL? */
-+
-+struct cell _sink;
-+pointer sink; /* when mem. alloc. fails */
-+struct cell _NIL;
-+pointer NIL; /* special cell representing empty cell */
-+struct cell _HASHT;
-+pointer T; /* special cell representing #t */
-+struct cell _HASHF;
-+pointer F; /* special cell representing #f */
-+struct cell _EOF_OBJ;
-+pointer EOF_OBJ; /* special cell representing end-of-file object */
-+pointer oblist; /* pointer to symbol table */
-+pointer global_env; /* pointer to global environment */
-+pointer c_nest; /* stack for nested calls from C */
-+
-+/* global pointers to special symbols */
-+pointer LAMBDA; /* pointer to syntax lambda */
-+pointer QUOTE; /* pointer to syntax quote */
-+
-+pointer QQUOTE; /* pointer to symbol quasiquote */
-+pointer UNQUOTE; /* pointer to symbol unquote */
-+pointer UNQUOTESP; /* pointer to symbol unquote-splicing */
-+pointer FEED_TO; /* => */
-+pointer COLON_HOOK; /* *colon-hook* */
-+pointer ERROR_HOOK; /* *error-hook* */
-+pointer SHARP_HOOK; /* *sharp-hook* */
-+pointer COMPILE_HOOK; /* *compile-hook* */
-+
-+pointer free_cell; /* pointer to top of free cells */
-+long fcells; /* # of free cells */
-+
-+pointer inport;
-+pointer outport;
-+pointer save_inport;
-+pointer loadport;
-+
-+#define MAXFIL 64
-+port load_stack[MAXFIL]; /* Stack of open files for port -1 (LOADing) */
-+int nesting_stack[MAXFIL];
-+int file_i;
-+int nesting;
-+
-+char gc_verbose; /* if gc_verbose is not zero, print gc status */
-+char no_memory; /* Whether mem. alloc. has failed */
-+
-+#define LINESIZE 1024
-+char linebuff[LINESIZE];
-+#define STRBUFFSIZE 256
-+char strbuff[STRBUFFSIZE];
-+
-+FILE *tmpfp;
-+int tok;
-+int print_flag;
-+pointer value;
-+int op;
-+
-+void *ext_data; /* For the benefit of foreign functions */
-+long gensym_cnt;
-+
-+struct scheme_interface *vptr;
-+void *dump_base; /* pointer to base of allocated dump stack */
-+int dump_size; /* number of frames allocated for dump stack */
-+};
-+
-+/* operator code */
-+enum scheme_opcodes {
-+#define _OP_DEF(A,B,C,D,E,OP) OP,
-+#include "opdefines.h"
-+ OP_MAXDEFINED
-+};
-+
-+
-+#define cons(sc,a,b) _cons(sc,a,b,0)
-+#define immutable_cons(sc,a,b) _cons(sc,a,b,1)
-+
-+int is_string(pointer p);
-+char *string_value(pointer p);
-+int is_number(pointer p);
-+num nvalue(pointer p);
-+long ivalue(pointer p);
-+double rvalue(pointer p);
-+int is_integer(pointer p);
-+int is_real(pointer p);
-+int is_character(pointer p);
-+long charvalue(pointer p);
-+int is_vector(pointer p);
-+
-+int is_port(pointer p);
-+
-+int is_pair(pointer p);
-+pointer pair_car(pointer p);
-+pointer pair_cdr(pointer p);
-+pointer set_car(pointer p, pointer q);
-+pointer set_cdr(pointer p, pointer q);
-+
-+int is_symbol(pointer p);
-+char *symname(pointer p);
-+int hasprop(pointer p);
-+
-+int is_syntax(pointer p);
-+int is_proc(pointer p);
-+int is_foreign(pointer p);
-+char *syntaxname(pointer p);
-+int is_closure(pointer p);
-+#ifdef USE_MACRO
-+int is_macro(pointer p);
-+#endif
-+pointer closure_code(pointer p);
-+pointer closure_env(pointer p);
-+
-+int is_continuation(pointer p);
-+int is_promise(pointer p);
-+int is_environment(pointer p);
-+int is_immutable(pointer p);
-+void setimmutable(pointer p);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif
-+
-+/*
-+Local variables:
-+c-file-style: "k&r"
-+End:
-+*/
-diff --git a/bootshell/scheme.c b/bootshell/scheme.c
-new file mode 100644
-index 0000000..5ca5641
---- /dev/null
-+++ b/bootshell/scheme.c
-@@ -0,0 +1,5075 @@
-+/* T I N Y S C H E M E 1 . 4 1
-+ * Dimitrios Souflis (dsouflis@acm.org)
-+ * Based on MiniScheme (original credits follow)
-+ * (MINISCM) coded by Atsushi Moriwaki (11/5/1989)
-+ * (MINISCM) E-MAIL : moriwaki@kurims.kurims.kyoto-u.ac.jp
-+ * (MINISCM) This version has been modified by R.C. Secrist.
-+ * (MINISCM)
-+ * (MINISCM) Mini-Scheme is now maintained by Akira KIDA.
-+ * (MINISCM)
-+ * (MINISCM) This is a revised and modified version by Akira KIDA.
-+ * (MINISCM) current version is 0.85k4 (15 May 1994)
-+ *
-+ */
-+
-+#define _SCHEME_SOURCE
-+#include "scheme-private.h"
-+#ifndef WIN32
-+# include <unistd.h>
-+#endif
-+#ifdef WIN32
-+#define snprintf _snprintf
-+#endif
-+#if USE_DL
-+# include "dynload.h"
-+#endif
-+#if USE_MATH
-+# include <math.h>
-+#endif
-+
-+#include <limits.h>
-+#include <float.h>
-+#include <ctype.h>
-+
-+#if USE_STRCASECMP
-+#include <strings.h>
-+# ifndef __APPLE__
-+# define stricmp strcasecmp
-+# endif
-+#endif
-+
-+/* Used for documentation purposes, to signal functions in 'interface' */
-+#define INTERFACE
-+
-+#define TOK_EOF (-1)
-+#define TOK_LPAREN 0
-+#define TOK_RPAREN 1
-+#define TOK_DOT 2
-+#define TOK_ATOM 3
-+#define TOK_QUOTE 4
-+#define TOK_COMMENT 5
-+#define TOK_DQUOTE 6
-+#define TOK_BQUOTE 7
-+#define TOK_COMMA 8
-+#define TOK_ATMARK 9
-+#define TOK_SHARP 10
-+#define TOK_SHARP_CONST 11
-+#define TOK_VEC 12
-+
-+#define BACKQUOTE '`'
-+#define DELIMITERS "()\";\f\t\v\n\r "
-+
-+/*
-+ * Basic memory allocation units
-+ */
-+
-+#define banner "TinyScheme 1.41"
-+
-+#include <string.h>
-+#include <stdlib.h>
-+
-+#ifdef __APPLE__
-+static int stricmp(const char *s1, const char *s2)
-+{
-+ unsigned char c1, c2;
-+ do {
-+ c1 = tolower(*s1);
-+ c2 = tolower(*s2);
-+ if (c1 < c2)
-+ return -1;
-+ else if (c1 > c2)
-+ return 1;
-+ s1++, s2++;
-+ } while (c1 != 0);
-+ return 0;
-+}
-+#endif /* __APPLE__ */
-+
-+#if USE_STRLWR
-+static const char *strlwr(char *s) {
-+ const char *p=s;
-+ while(*s) {
-+ *s=tolower(*s);
-+ s++;
-+ }
-+ return p;
-+}
-+#endif
-+
-+#ifndef prompt
-+# define prompt "ts> "
-+#endif
-+
-+#ifndef InitFile
-+# define InitFile "init.scm"
-+#endif
-+
-+#ifndef FIRST_CELLSEGS
-+# define FIRST_CELLSEGS 3
-+#endif
-+
-+enum scheme_types {
-+ T_STRING=1,
-+ T_NUMBER=2,
-+ T_SYMBOL=3,
-+ T_PROC=4,
-+ T_PAIR=5,
-+ T_CLOSURE=6,
-+ T_CONTINUATION=7,
-+ T_FOREIGN=8,
-+ T_CHARACTER=9,
-+ T_PORT=10,
-+ T_VECTOR=11,
-+ T_MACRO=12,
-+ T_PROMISE=13,
-+ T_ENVIRONMENT=14,
-+ T_LAST_SYSTEM_TYPE=14
-+};
-+
-+/* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
-+#define ADJ 32
-+#define TYPE_BITS 5
-+#define T_MASKTYPE 31 /* 0000000000011111 */
-+#define T_SYNTAX 4096 /* 0001000000000000 */
-+#define T_IMMUTABLE 8192 /* 0010000000000000 */
-+#define T_ATOM 16384 /* 0100000000000000 */ /* only for gc */
-+#define CLRATOM 49151 /* 1011111111111111 */ /* only for gc */
-+#define MARK 32768 /* 1000000000000000 */
-+#define UNMARK 32767 /* 0111111111111111 */
-+
-+
-+static num num_add(num a, num b);
-+static num num_mul(num a, num b);
-+static num num_div(num a, num b);
-+static num num_intdiv(num a, num b);
-+static num num_sub(num a, num b);
-+static num num_rem(num a, num b);
-+static num num_mod(num a, num b);
-+static int num_eq(num a, num b);
-+static int num_gt(num a, num b);
-+static int num_ge(num a, num b);
-+static int num_lt(num a, num b);
-+static int num_le(num a, num b);
-+
-+#if USE_MATH
-+static double round_per_R5RS(double x);
-+#endif
-+static int is_zero_double(double x);
-+static INLINE int num_is_integer(pointer p) {
-+ return ((p)->_object._number.is_fixnum);
-+}
-+
-+static num num_zero;
-+static num num_one;
-+
-+/* macros for cell operations */
-+#define typeflag(p) ((p)->_flag)
-+#define type(p) (typeflag(p)&T_MASKTYPE)
-+
-+INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); }
-+#define strvalue(p) ((p)->_object._string._svalue)
-+#define strlength(p) ((p)->_object._string._length)
-+
-+INTERFACE static int is_list(scheme *sc, pointer p);
-+INTERFACE INLINE int is_vector(pointer p) { return (type(p)==T_VECTOR); }
-+INTERFACE static void fill_vector(pointer vec, pointer obj);
-+INTERFACE static pointer vector_elem(pointer vec, int ielem);
-+INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a);
-+INTERFACE INLINE int is_number(pointer p) { return (type(p)==T_NUMBER); }
-+INTERFACE INLINE int is_integer(pointer p) {
-+ if (!is_number(p))
-+ return 0;
-+ if (num_is_integer(p) || (double)ivalue(p) == rvalue(p))
-+ return 1;
-+ return 0;
-+}
-+
-+INTERFACE INLINE int is_real(pointer p) {
-+ return is_number(p) && (!(p)->_object._number.is_fixnum);
-+}
-+
-+INTERFACE INLINE int is_character(pointer p) { return (type(p)==T_CHARACTER); }
-+INTERFACE INLINE char *string_value(pointer p) { return strvalue(p); }
-+INLINE num nvalue(pointer p) { return ((p)->_object._number); }
-+INTERFACE long ivalue(pointer p) { return (num_is_integer(p)?(p)->_object._number.value.ivalue:(long)(p)->_object._number.value.rvalue); }
-+INTERFACE double rvalue(pointer p) { return (!num_is_integer(p)?(p)->_object._number.value.rvalue:(double)(p)->_object._number.value.ivalue); }
-+#define ivalue_unchecked(p) ((p)->_object._number.value.ivalue)
-+#define rvalue_unchecked(p) ((p)->_object._number.value.rvalue)
-+#define set_num_integer(p) (p)->_object._number.is_fixnum=1;
-+#define set_num_real(p) (p)->_object._number.is_fixnum=0;
-+INTERFACE long charvalue(pointer p) { return ivalue_unchecked(p); }
-+
-+INTERFACE INLINE int is_port(pointer p) { return (type(p)==T_PORT); }
-+INTERFACE INLINE int is_inport(pointer p) { return is_port(p) && p->_object._port->kind & port_input; }
-+INTERFACE INLINE int is_outport(pointer p) { return is_port(p) && p->_object._port->kind & port_output; }
-+
-+INTERFACE INLINE int is_pair(pointer p) { return (type(p)==T_PAIR); }
-+#define car(p) ((p)->_object._cons._car)
-+#define cdr(p) ((p)->_object._cons._cdr)
-+INTERFACE pointer pair_car(pointer p) { return car(p); }
-+INTERFACE pointer pair_cdr(pointer p) { return cdr(p); }
-+INTERFACE pointer set_car(pointer p, pointer q) { return car(p)=q; }
-+INTERFACE pointer set_cdr(pointer p, pointer q) { return cdr(p)=q; }
-+
-+INTERFACE INLINE int is_symbol(pointer p) { return (type(p)==T_SYMBOL); }
-+INTERFACE INLINE char *symname(pointer p) { return strvalue(car(p)); }
-+#if USE_PLIST
-+SCHEME_EXPORT INLINE int hasprop(pointer p) { return (typeflag(p)&T_SYMBOL); }
-+#define symprop(p) cdr(p)
-+#endif
-+
-+INTERFACE INLINE int is_syntax(pointer p) { return (typeflag(p)&T_SYNTAX); }
-+INTERFACE INLINE int is_proc(pointer p) { return (type(p)==T_PROC); }
-+INTERFACE INLINE int is_foreign(pointer p) { return (type(p)==T_FOREIGN); }
-+INTERFACE INLINE char *syntaxname(pointer p) { return strvalue(car(p)); }
-+#define procnum(p) ivalue(p)
-+static const char *procname(pointer x);
-+
-+INTERFACE INLINE int is_closure(pointer p) { return (type(p)==T_CLOSURE); }
-+INTERFACE INLINE int is_macro(pointer p) { return (type(p)==T_MACRO); }
-+INTERFACE INLINE pointer closure_code(pointer p) { return car(p); }
-+INTERFACE INLINE pointer closure_env(pointer p) { return cdr(p); }
-+
-+INTERFACE INLINE int is_continuation(pointer p) { return (type(p)==T_CONTINUATION); }
-+#define cont_dump(p) cdr(p)
-+
-+/* To do: promise should be forced ONCE only */
-+INTERFACE INLINE int is_promise(pointer p) { return (type(p)==T_PROMISE); }
-+
-+INTERFACE INLINE int is_environment(pointer p) { return (type(p)==T_ENVIRONMENT); }
-+#define setenvironment(p) typeflag(p) = T_ENVIRONMENT
-+
-+#define is_atom(p) (typeflag(p)&T_ATOM)
-+#define setatom(p) typeflag(p) |= T_ATOM
-+#define clratom(p) typeflag(p) &= CLRATOM
-+
-+#define is_mark(p) (typeflag(p)&MARK)
-+#define setmark(p) typeflag(p) |= MARK
-+#define clrmark(p) typeflag(p) &= UNMARK
-+
-+INTERFACE INLINE int is_immutable(pointer p) { return (typeflag(p)&T_IMMUTABLE); }
-+/*#define setimmutable(p) typeflag(p) |= T_IMMUTABLE*/
-+INTERFACE INLINE void setimmutable(pointer p) { typeflag(p) |= T_IMMUTABLE; }
-+
-+#define caar(p) car(car(p))
-+#define cadr(p) car(cdr(p))
-+#define cdar(p) cdr(car(p))
-+#define cddr(p) cdr(cdr(p))
-+#define cadar(p) car(cdr(car(p)))
-+#define caddr(p) car(cdr(cdr(p)))
-+#define cdaar(p) cdr(car(car(p)))
-+#define cadaar(p) car(cdr(car(car(p))))
-+#define cadddr(p) car(cdr(cdr(cdr(p))))
-+#define cddddr(p) cdr(cdr(cdr(cdr(p))))
-+
-+#if USE_CHAR_CLASSIFIERS
-+static INLINE int Cisalpha(int c) { return isascii(c) && isalpha(c); }
-+static INLINE int Cisdigit(int c) { return isascii(c) && isdigit(c); }
-+static INLINE int Cisspace(int c) { return isascii(c) && isspace(c); }
-+static INLINE int Cisupper(int c) { return isascii(c) && isupper(c); }
-+static INLINE int Cislower(int c) { return isascii(c) && islower(c); }
-+#endif
-+
-+#if USE_ASCII_NAMES
-+static const char *charnames[32]={
-+ "nul",
-+ "soh",
-+ "stx",
-+ "etx",
-+ "eot",
-+ "enq",
-+ "ack",
-+ "bel",
-+ "bs",
-+ "ht",
-+ "lf",
-+ "vt",
-+ "ff",
-+ "cr",
-+ "so",
-+ "si",
-+ "dle",
-+ "dc1",
-+ "dc2",
-+ "dc3",
-+ "dc4",
-+ "nak",
-+ "syn",
-+ "etb",
-+ "can",
-+ "em",
-+ "sub",
-+ "esc",
-+ "fs",
-+ "gs",
-+ "rs",
-+ "us"
-+};
-+
-+static int is_ascii_name(const char *name, int *pc) {
-+ int i;
-+ for(i=0; i<32; i++) {
-+ if(stricmp(name,charnames[i])==0) {
-+ *pc=i;
-+ return 1;
-+ }
-+ }
-+ if(stricmp(name,"del")==0) {
-+ *pc=127;
-+ return 1;
-+ }
-+ return 0;
-+}
-+
-+#endif
-+
-+static int file_push(scheme *sc, const char *fname);
-+static void file_pop(scheme *sc);
-+static int file_interactive(scheme *sc);
-+static INLINE int is_one_of(char *s, int c);
-+static int alloc_cellseg(scheme *sc, int n);
-+static long binary_decode(const char *s);
-+static INLINE pointer get_cell(scheme *sc, pointer a, pointer b);
-+static pointer _get_cell(scheme *sc, pointer a, pointer b);
-+static pointer reserve_cells(scheme *sc, int n);
-+static pointer get_consecutive_cells(scheme *sc, int n);
-+static pointer find_consecutive_cells(scheme *sc, int n);
-+static void finalize_cell(scheme *sc, pointer a);
-+static int count_consecutive_cells(pointer x, int needed);
-+static pointer find_slot_in_env(scheme *sc, pointer env, pointer sym, int all);
-+static pointer mk_number(scheme *sc, num n);
-+static char *store_string(scheme *sc, int len, const char *str, char fill);
-+static pointer mk_vector(scheme *sc, int len);
-+static pointer mk_atom(scheme *sc, char *q);
-+static pointer mk_sharp_const(scheme *sc, char *name);
-+static pointer mk_port(scheme *sc, port *p);
-+static pointer port_from_filename(scheme *sc, const char *fn, int prop);
-+static pointer port_from_file(scheme *sc, FILE *, int prop);
-+static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop);
-+static port *port_rep_from_filename(scheme *sc, const char *fn, int prop);
-+static port *port_rep_from_file(scheme *sc, FILE *, int prop);
-+static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop);
-+static void port_close(scheme *sc, pointer p, int flag);
-+static void mark(pointer a);
-+static void gc(scheme *sc, pointer a, pointer b);
-+static int basic_inchar(port *pt);
-+static int inchar(scheme *sc);
-+static void backchar(scheme *sc, int c);
-+static char *readstr_upto(scheme *sc, char *delim);
-+static pointer readstrexp(scheme *sc);
-+static INLINE int skipspace(scheme *sc);
-+static int token(scheme *sc);
-+static void printslashstring(scheme *sc, char *s, int len);
-+static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen);
-+static void printatom(scheme *sc, pointer l, int f);
-+static pointer mk_proc(scheme *sc, enum scheme_opcodes op);
-+static pointer mk_closure(scheme *sc, pointer c, pointer e);
-+static pointer mk_continuation(scheme *sc, pointer d);
-+static pointer reverse(scheme *sc, pointer a);
-+static pointer reverse_in_place(scheme *sc, pointer term, pointer list);
-+static pointer revappend(scheme *sc, pointer a, pointer b);
-+static void dump_stack_mark(scheme *);
-+static pointer opexe_0(scheme *sc, enum scheme_opcodes op);
-+static pointer opexe_1(scheme *sc, enum scheme_opcodes op);
-+static pointer opexe_2(scheme *sc, enum scheme_opcodes op);
-+static pointer opexe_3(scheme *sc, enum scheme_opcodes op);
-+static pointer opexe_4(scheme *sc, enum scheme_opcodes op);
-+static pointer opexe_5(scheme *sc, enum scheme_opcodes op);
-+static pointer opexe_6(scheme *sc, enum scheme_opcodes op);
-+static void Eval_Cycle(scheme *sc, enum scheme_opcodes op);
-+static void assign_syntax(scheme *sc, char *name);
-+static int syntaxnum(pointer p);
-+static void assign_proc(scheme *sc, enum scheme_opcodes, char *name);
-+
-+#define num_ivalue(n) (n.is_fixnum?(n).value.ivalue:(long)(n).value.rvalue)
-+#define num_rvalue(n) (!n.is_fixnum?(n).value.rvalue:(double)(n).value.ivalue)
-+
-+static num num_add(num a, num b) {
-+ num ret;
-+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
-+ if(ret.is_fixnum) {
-+ ret.value.ivalue= a.value.ivalue+b.value.ivalue;
-+ } else {
-+ ret.value.rvalue=num_rvalue(a)+num_rvalue(b);
-+ }
-+ return ret;
-+}
-+
-+static num num_mul(num a, num b) {
-+ num ret;
-+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
-+ if(ret.is_fixnum) {
-+ ret.value.ivalue= a.value.ivalue*b.value.ivalue;
-+ } else {
-+ ret.value.rvalue=num_rvalue(a)*num_rvalue(b);
-+ }
-+ return ret;
-+}
-+
-+static num num_div(num a, num b) {
-+ num ret;
-+ ret.is_fixnum=a.is_fixnum && b.is_fixnum && a.value.ivalue%b.value.ivalue==0;
-+ if(ret.is_fixnum) {
-+ ret.value.ivalue= a.value.ivalue/b.value.ivalue;
-+ } else {
-+ ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
-+ }
-+ return ret;
-+}
-+
-+static num num_intdiv(num a, num b) {
-+ num ret;
-+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
-+ if(ret.is_fixnum) {
-+ ret.value.ivalue= a.value.ivalue/b.value.ivalue;
-+ } else {
-+ ret.value.rvalue=num_rvalue(a)/num_rvalue(b);
-+ }
-+ return ret;
-+}
-+
-+static num num_sub(num a, num b) {
-+ num ret;
-+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
-+ if(ret.is_fixnum) {
-+ ret.value.ivalue= a.value.ivalue-b.value.ivalue;
-+ } else {
-+ ret.value.rvalue=num_rvalue(a)-num_rvalue(b);
-+ }
-+ return ret;
-+}
-+
-+static num num_rem(num a, num b) {
-+ num ret;
-+ long e1, e2, res;
-+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
-+ e1=num_ivalue(a);
-+ e2=num_ivalue(b);
-+ res=e1%e2;
-+ /* remainder should have same sign as second operand */
-+ if (res > 0) {
-+ if (e1 < 0) {
-+ res -= labs(e2);
-+ }
-+ } else if (res < 0) {
-+ if (e1 > 0) {
-+ res += labs(e2);
-+ }
-+ }
-+ ret.value.ivalue=res;
-+ return ret;
-+}
-+
-+static num num_mod(num a, num b) {
-+ num ret;
-+ long e1, e2, res;
-+ ret.is_fixnum=a.is_fixnum && b.is_fixnum;
-+ e1=num_ivalue(a);
-+ e2=num_ivalue(b);
-+ res=e1%e2;
-+ /* modulo should have same sign as second operand */
-+ if (res * e2 < 0) {
-+ res += e2;
-+ }
-+ ret.value.ivalue=res;
-+ return ret;
-+}
-+
-+static int num_eq(num a, num b) {
-+ int ret;
-+ int is_fixnum=a.is_fixnum && b.is_fixnum;
-+ if(is_fixnum) {
-+ ret= a.value.ivalue==b.value.ivalue;
-+ } else {
-+ ret=num_rvalue(a)==num_rvalue(b);
-+ }
-+ return ret;
-+}
-+
-+
-+static int num_gt(num a, num b) {
-+ int ret;
-+ int is_fixnum=a.is_fixnum && b.is_fixnum;
-+ if(is_fixnum) {
-+ ret= a.value.ivalue>b.value.ivalue;
-+ } else {
-+ ret=num_rvalue(a)>num_rvalue(b);
-+ }
-+ return ret;
-+}
-+
-+static int num_ge(num a, num b) {
-+ return !num_lt(a,b);
-+}
-+
-+static int num_lt(num a, num b) {
-+ int ret;
-+ int is_fixnum=a.is_fixnum && b.is_fixnum;
-+ if(is_fixnum) {
-+ ret= a.value.ivalue<b.value.ivalue;
-+ } else {
-+ ret=num_rvalue(a)<num_rvalue(b);
-+ }
-+ return ret;
-+}
-+
-+static int num_le(num a, num b) {
-+ return !num_gt(a,b);
-+}
-+
-+#if USE_MATH
-+/* Round to nearest. Round to even if midway */
-+static double round_per_R5RS(double x) {
-+ double fl=floor(x);
-+ double ce=ceil(x);
-+ double dfl=x-fl;
-+ double dce=ce-x;
-+ if(dfl>dce) {
-+ return ce;
-+ } else if(dfl<dce) {
-+ return fl;
-+ } else {
-+ if(fmod(fl,2.0)==0.0) { /* I imagine this holds */
-+ return fl;
-+ } else {
-+ return ce;
-+ }
-+ }
-+}
-+#endif
-+
-+static int is_zero_double(double x) {
-+ return x<DBL_MIN && x>-DBL_MIN;
-+}
-+
-+static long binary_decode(const char *s) {
-+ long x=0;
-+
-+ while(*s!=0 && (*s=='1' || *s=='0')) {
-+ x<<=1;
-+ x+=*s-'0';
-+ s++;
-+ }
-+
-+ return x;
-+}
-+
-+/* allocate new cell segment */
-+static int alloc_cellseg(scheme *sc, int n) {
-+ pointer newp;
-+ pointer last;
-+ pointer p;
-+ char *cp;
-+ long i;
-+ int k;
-+ int adj=ADJ;
-+
-+ if(adj<sizeof(struct cell)) {
-+ adj=sizeof(struct cell);
-+ }
-+
-+ for (k = 0; k < n; k++) {
-+ if (sc->last_cell_seg >= CELL_NSEGMENT - 1)
-+ return k;
-+ cp = (char*) sc->malloc(CELL_SEGSIZE * sizeof(struct cell)+adj);
-+ if (cp == 0)
-+ return k;
-+ i = ++sc->last_cell_seg ;
-+ sc->alloc_seg[i] = cp;
-+ /* adjust in TYPE_BITS-bit boundary */
-+ if(((unsigned long)cp)%adj!=0) {
-+ cp=(char*)(adj*((unsigned long)cp/adj+1));
-+ }
-+ /* insert new segment in address order */
-+ newp=(pointer)cp;
-+ sc->cell_seg[i] = newp;
-+ while (i > 0 && sc->cell_seg[i - 1] > sc->cell_seg[i]) {
-+ p = sc->cell_seg[i];
-+ sc->cell_seg[i] = sc->cell_seg[i - 1];
-+ sc->cell_seg[--i] = p;
-+ }
-+ sc->fcells += CELL_SEGSIZE;
-+ last = newp + CELL_SEGSIZE - 1;
-+ for (p = newp; p <= last; p++) {
-+ typeflag(p) = 0;
-+ cdr(p) = p + 1;
-+ car(p) = sc->NIL;
-+ }
-+ /* insert new cells in address order on free list */
-+ if (sc->free_cell == sc->NIL || p < sc->free_cell) {
-+ cdr(last) = sc->free_cell;
-+ sc->free_cell = newp;
-+ } else {
-+ p = sc->free_cell;
-+ while (cdr(p) != sc->NIL && newp > cdr(p))
-+ p = cdr(p);
-+ cdr(last) = cdr(p);
-+ cdr(p) = newp;
-+ }
-+ }
-+ return n;
-+}
-+
-+static INLINE pointer get_cell_x(scheme *sc, pointer a, pointer b) {
-+ if (sc->free_cell != sc->NIL) {
-+ pointer x = sc->free_cell;
-+ sc->free_cell = cdr(x);
-+ --sc->fcells;
-+ return (x);
-+ }
-+ return _get_cell (sc, a, b);
-+}
-+
-+
-+/* get new cell. parameter a, b is marked by gc. */
-+static pointer _get_cell(scheme *sc, pointer a, pointer b) {
-+ pointer x;
-+
-+ if(sc->no_memory) {
-+ return sc->sink;
-+ }
-+
-+ if (sc->free_cell == sc->NIL) {
-+ const int min_to_be_recovered = sc->last_cell_seg*8;
-+ gc(sc,a, b);
-+ if (sc->fcells < min_to_be_recovered
-+ || sc->free_cell == sc->NIL) {
-+ /* if only a few recovered, get more to avoid fruitless gc's */
-+ if (!alloc_cellseg(sc,1) && sc->free_cell == sc->NIL) {
-+ sc->no_memory=1;
-+ return sc->sink;
-+ }
-+ }
-+ }
-+ x = sc->free_cell;
-+ sc->free_cell = cdr(x);
-+ --sc->fcells;
-+ return (x);
-+}
-+
-+/* make sure that there is a given number of cells free */
-+static pointer reserve_cells(scheme *sc, int n) {
-+ if(sc->no_memory) {
-+ return sc->NIL;
-+ }
-+
-+ /* Are there enough cells available? */
-+ if (sc->fcells < n) {
-+ /* If not, try gc'ing some */
-+ gc(sc, sc->NIL, sc->NIL);
-+ if (sc->fcells < n) {
-+ /* If there still aren't, try getting more heap */
-+ if (!alloc_cellseg(sc,1)) {
-+ sc->no_memory=1;
-+ return sc->NIL;
-+ }
-+ }
-+ if (sc->fcells < n) {
-+ /* If all fail, report failure */
-+ sc->no_memory=1;
-+ return sc->NIL;
-+ }
-+ }
-+ return (sc->T);
-+}
-+
-+static pointer get_consecutive_cells(scheme *sc, int n) {
-+ pointer x;
-+
-+ if(sc->no_memory) { return sc->sink; }
-+
-+ /* Are there any cells available? */
-+ x=find_consecutive_cells(sc,n);
-+ if (x != sc->NIL) { return x; }
-+
-+ /* If not, try gc'ing some */
-+ gc(sc, sc->NIL, sc->NIL);
-+ x=find_consecutive_cells(sc,n);
-+ if (x != sc->NIL) { return x; }
-+
-+ /* If there still aren't, try getting more heap */
-+ if (!alloc_cellseg(sc,1))
-+ {
-+ sc->no_memory=1;
-+ return sc->sink;
-+ }
-+
-+ x=find_consecutive_cells(sc,n);
-+ if (x != sc->NIL) { return x; }
-+
-+ /* If all fail, report failure */
-+ sc->no_memory=1;
-+ return sc->sink;
-+}
-+
-+static int count_consecutive_cells(pointer x, int needed) {
-+ int n=1;
-+ while(cdr(x)==x+1) {
-+ x=cdr(x);
-+ n++;
-+ if(n>needed) return n;
-+ }
-+ return n;
-+}
-+
-+static pointer find_consecutive_cells(scheme *sc, int n) {
-+ pointer *pp;
-+ int cnt;
-+
-+ pp=&sc->free_cell;
-+ while(*pp!=sc->NIL) {
-+ cnt=count_consecutive_cells(*pp,n);
-+ if(cnt>=n) {
-+ pointer x=*pp;
-+ *pp=cdr(*pp+n-1);
-+ sc->fcells -= n;
-+ return x;
-+ }
-+ pp=&cdr(*pp+cnt-1);
-+ }
-+ return sc->NIL;
-+}
-+
-+/* To retain recent allocs before interpreter knows about them -
-+ Tehom */
-+
-+static void push_recent_alloc(scheme *sc, pointer recent, pointer extra)
-+{
-+ pointer holder = get_cell_x(sc, recent, extra);
-+ typeflag(holder) = T_PAIR | T_IMMUTABLE;
-+ car(holder) = recent;
-+ cdr(holder) = car(sc->sink);
-+ car(sc->sink) = holder;
-+}
-+
-+
-+static pointer get_cell(scheme *sc, pointer a, pointer b)
-+{
-+ pointer cell = get_cell_x(sc, a, b);
-+ /* For right now, include "a" and "b" in "cell" so that gc doesn't
-+ think they are garbage. */
-+ /* Tentatively record it as a pair so gc understands it. */
-+ typeflag(cell) = T_PAIR;
-+ car(cell) = a;
-+ cdr(cell) = b;
-+ push_recent_alloc(sc, cell, sc->NIL);
-+ return cell;
-+}
-+
-+static pointer get_vector_object(scheme *sc, int len, pointer init)
-+{
-+ pointer cells = get_consecutive_cells(sc,len/2+len%2+1);
-+ if(sc->no_memory) { return sc->sink; }
-+ /* Record it as a vector so that gc understands it. */
-+ typeflag(cells) = (T_VECTOR | T_ATOM);
-+ ivalue_unchecked(cells)=len;
-+ set_num_integer(cells);
-+ fill_vector(cells,init);
-+ push_recent_alloc(sc, cells, sc->NIL);
-+ return cells;
-+}
-+
-+static INLINE void ok_to_freely_gc(scheme *sc)
-+{
-+ car(sc->sink) = sc->NIL;
-+}
-+
-+
-+#if defined TSGRIND
-+static void check_cell_alloced(pointer p, int expect_alloced)
-+{
-+ /* Can't use putstr(sc,str) because callers have no access to
-+ sc. */
-+ if(typeflag(p) & !expect_alloced)
-+ {
-+ fprintf(stderr,"Cell is already allocated!\n");
-+ }
-+ if(!(typeflag(p)) & expect_alloced)
-+ {
-+ fprintf(stderr,"Cell is not allocated!\n");
-+ }
-+
-+}
-+static void check_range_alloced(pointer p, int n, int expect_alloced)
-+{
-+ int i;
-+ for(i = 0;i<n;i++)
-+ { (void)check_cell_alloced(p+i,expect_alloced); }
-+}
-+
-+#endif
-+
-+/* Medium level cell allocation */
-+
-+/* get new cons cell */
-+pointer _cons(scheme *sc, pointer a, pointer b, int immutable) {
-+ pointer x = get_cell(sc,a, b);
-+
-+ typeflag(x) = T_PAIR;
-+ if(immutable) {
-+ setimmutable(x);
-+ }
-+ car(x) = a;
-+ cdr(x) = b;
-+ return (x);
-+}
-+
-+/* ========== oblist implementation ========== */
-+
-+#ifndef USE_OBJECT_LIST
-+
-+static int hash_fn(const char *key, int table_size);
-+
-+static pointer oblist_initial_value(scheme *sc)
-+{
-+ return mk_vector(sc, 461); /* probably should be bigger */
-+}
-+
-+/* returns the new symbol */
-+static pointer oblist_add_by_name(scheme *sc, const char *name)
-+{
-+ pointer x;
-+ int location;
-+
-+ x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
-+ typeflag(x) = T_SYMBOL;
-+ setimmutable(car(x));
-+
-+ location = hash_fn(name, ivalue_unchecked(sc->oblist));
-+ set_vector_elem(sc->oblist, location,
-+ immutable_cons(sc, x, vector_elem(sc->oblist, location)));
-+ return x;
-+}
-+
-+static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
-+{
-+ int location;
-+ pointer x;
-+ char *s;
-+
-+ location = hash_fn(name, ivalue_unchecked(sc->oblist));
-+ for (x = vector_elem(sc->oblist, location); x != sc->NIL; x = cdr(x)) {
-+ s = symname(car(x));
-+ /* case-insensitive, per R5RS section 2. */
-+ if(stricmp(name, s) == 0) {
-+ return car(x);
-+ }
-+ }
-+ return sc->NIL;
-+}
-+
-+static pointer oblist_all_symbols(scheme *sc)
-+{
-+ int i;
-+ pointer x;
-+ pointer ob_list = sc->NIL;
-+
-+ for (i = 0; i < ivalue_unchecked(sc->oblist); i++) {
-+ for (x = vector_elem(sc->oblist, i); x != sc->NIL; x = cdr(x)) {
-+ ob_list = cons(sc, x, ob_list);
-+ }
-+ }
-+ return ob_list;
-+}
-+
-+#else
-+
-+static pointer oblist_initial_value(scheme *sc)
-+{
-+ return sc->NIL;
-+}
-+
-+static INLINE pointer oblist_find_by_name(scheme *sc, const char *name)
-+{
-+ pointer x;
-+ char *s;
-+
-+ for (x = sc->oblist; x != sc->NIL; x = cdr(x)) {
-+ s = symname(car(x));
-+ /* case-insensitive, per R5RS section 2. */
-+ if(stricmp(name, s) == 0) {
-+ return car(x);
-+ }
-+ }
-+ return sc->NIL;
-+}
-+
-+/* returns the new symbol */
-+static pointer oblist_add_by_name(scheme *sc, const char *name)
-+{
-+ pointer x;
-+
-+ x = immutable_cons(sc, mk_string(sc, name), sc->NIL);
-+ typeflag(x) = T_SYMBOL;
-+ setimmutable(car(x));
-+ sc->oblist = immutable_cons(sc, x, sc->oblist);
-+ return x;
-+}
-+static pointer oblist_all_symbols(scheme *sc)
-+{
-+ return sc->oblist;
-+}
-+
-+#endif
-+
-+static pointer mk_port(scheme *sc, port *p) {
-+ pointer x = get_cell(sc, sc->NIL, sc->NIL);
-+
-+ typeflag(x) = T_PORT|T_ATOM;
-+ x->_object._port=p;
-+ return (x);
-+}
-+
-+pointer mk_foreign_func(scheme *sc, foreign_func f) {
-+ pointer x = get_cell(sc, sc->NIL, sc->NIL);
-+
-+ typeflag(x) = (T_FOREIGN | T_ATOM);
-+ x->_object._ff=f;
-+ return (x);
-+}
-+
-+INTERFACE pointer mk_character(scheme *sc, int c) {
-+ pointer x = get_cell(sc,sc->NIL, sc->NIL);
-+
-+ typeflag(x) = (T_CHARACTER | T_ATOM);
-+ ivalue_unchecked(x)= c;
-+ set_num_integer(x);
-+ return (x);
-+}
-+
-+/* get number atom (integer) */
-+INTERFACE pointer mk_integer(scheme *sc, long num) {
-+ pointer x = get_cell(sc,sc->NIL, sc->NIL);
-+
-+ typeflag(x) = (T_NUMBER | T_ATOM);
-+ ivalue_unchecked(x)= num;
-+ set_num_integer(x);
-+ return (x);
-+}
-+
-+INTERFACE pointer mk_real(scheme *sc, double n) {
-+ pointer x = get_cell(sc,sc->NIL, sc->NIL);
-+
-+ typeflag(x) = (T_NUMBER | T_ATOM);
-+ rvalue_unchecked(x)= n;
-+ set_num_real(x);
-+ return (x);
-+}
-+
-+static pointer mk_number(scheme *sc, num n) {
-+ if(n.is_fixnum) {
-+ return mk_integer(sc,n.value.ivalue);
-+ } else {
-+ return mk_real(sc,n.value.rvalue);
-+ }
-+}
-+
-+/* allocate name to string area */
-+static char *store_string(scheme *sc, int len_str, const char *str, char fill) {
-+ char *q;
-+
-+ q=(char*)sc->malloc(len_str+1);
-+ if(q==0) {
-+ sc->no_memory=1;
-+ return sc->strbuff;
-+ }
-+ if(str!=0) {
-+ snprintf(q, len_str+1, "%s", str);
-+ } else {
-+ memset(q, fill, len_str);
-+ q[len_str]=0;
-+ }
-+ return (q);
-+}
-+
-+/* get new string */
-+INTERFACE pointer mk_string(scheme *sc, const char *str) {
-+ return mk_counted_string(sc,str,strlen(str));
-+}
-+
-+INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) {
-+ pointer x = get_cell(sc, sc->NIL, sc->NIL);
-+ typeflag(x) = (T_STRING | T_ATOM);
-+ strvalue(x) = store_string(sc,len,str,0);
-+ strlength(x) = len;
-+ return (x);
-+}
-+
-+INTERFACE pointer mk_empty_string(scheme *sc, int len, char fill) {
-+ pointer x = get_cell(sc, sc->NIL, sc->NIL);
-+ typeflag(x) = (T_STRING | T_ATOM);
-+ strvalue(x) = store_string(sc,len,0,fill);
-+ strlength(x) = len;
-+ return (x);
-+}
-+
-+INTERFACE static pointer mk_vector(scheme *sc, int len)
-+{ return get_vector_object(sc,len,sc->NIL); }
-+
-+INTERFACE static void fill_vector(pointer vec, pointer obj) {
-+ int i;
-+ int num=ivalue(vec)/2+ivalue(vec)%2;
-+ for(i=0; i<num; i++) {
-+ typeflag(vec+1+i) = T_PAIR;
-+ setimmutable(vec+1+i);
-+ car(vec+1+i)=obj;
-+ cdr(vec+1+i)=obj;
-+ }
-+}
-+
-+INTERFACE static pointer vector_elem(pointer vec, int ielem) {
-+ int n=ielem/2;
-+ if(ielem%2==0) {
-+ return car(vec+1+n);
-+ } else {
-+ return cdr(vec+1+n);
-+ }
-+}
-+
-+INTERFACE static pointer set_vector_elem(pointer vec, int ielem, pointer a) {
-+ int n=ielem/2;
-+ if(ielem%2==0) {
-+ return car(vec+1+n)=a;
-+ } else {
-+ return cdr(vec+1+n)=a;
-+ }
-+}
-+
-+/* get new symbol */
-+INTERFACE pointer mk_symbol(scheme *sc, const char *name) {
-+ pointer x;
-+
-+ /* first check oblist */
-+ x = oblist_find_by_name(sc, name);
-+ if (x != sc->NIL) {
-+ return (x);
-+ } else {
-+ x = oblist_add_by_name(sc, name);
-+ return (x);
-+ }
-+}
-+
-+INTERFACE pointer gensym(scheme *sc) {
-+ pointer x;
-+ char name[40];
-+
-+ for(; sc->gensym_cnt<LONG_MAX; sc->gensym_cnt++) {
-+ snprintf(name,40,"gensym-%ld",sc->gensym_cnt);
-+
-+ /* first check oblist */
-+ x = oblist_find_by_name(sc, name);
-+
-+ if (x != sc->NIL) {
-+ continue;
-+ } else {
-+ x = oblist_add_by_name(sc, name);
-+ return (x);
-+ }
-+ }
-+
-+ return sc->NIL;
-+}
-+
-+/* make symbol or number atom from string */
-+static pointer mk_atom(scheme *sc, char *q) {
-+ char c, *p;
-+ int has_dec_point=0;
-+ int has_fp_exp = 0;
-+
-+#if USE_COLON_HOOK
-+ if((p=strstr(q,"::"))!=0) {
-+ *p=0;
-+ return cons(sc, sc->COLON_HOOK,
-+ cons(sc,
-+ cons(sc,
-+ sc->QUOTE,
-+ cons(sc, mk_atom(sc,p+2), sc->NIL)),
-+ cons(sc, mk_symbol(sc,strlwr(q)), sc->NIL)));
-+ }
-+#endif
-+
-+ p = q;
-+ c = *p++;
-+ if ((c == '+') || (c == '-')) {
-+ c = *p++;
-+ if (c == '.') {
-+ has_dec_point=1;
-+ c = *p++;
-+ }
-+ if (!isdigit(c)) {
-+ return (mk_symbol(sc, strlwr(q)));
-+ }
-+ } else if (c == '.') {
-+ has_dec_point=1;
-+ c = *p++;
-+ if (!isdigit(c)) {
-+ return (mk_symbol(sc, strlwr(q)));
-+ }
-+ } else if (!isdigit(c)) {
-+ return (mk_symbol(sc, strlwr(q)));
-+ }
-+
-+ for ( ; (c = *p) != 0; ++p) {
-+ if (!isdigit(c)) {
-+ if(c=='.') {
-+ if(!has_dec_point) {
-+ has_dec_point=1;
-+ continue;
-+ }
-+ }
-+ else if ((c == 'e') || (c == 'E')) {
-+ if(!has_fp_exp) {
-+ has_dec_point = 1; /* decimal point illegal
-+ from now on */
-+ p++;
-+ if ((*p == '-') || (*p == '+') || isdigit(*p)) {
-+ continue;
-+ }
-+ }
-+ }
-+ return (mk_symbol(sc, strlwr(q)));
-+ }
-+ }
-+ if(has_dec_point) {
-+ return mk_real(sc,atof(q));
-+ }
-+ return (mk_integer(sc, atol(q)));
-+}
-+
-+/* make constant */
-+static pointer mk_sharp_const(scheme *sc, char *name) {
-+ long x;
-+ char tmp[STRBUFFSIZE];
-+
-+ if (!strcmp(name, "t"))
-+ return (sc->T);
-+ else if (!strcmp(name, "f"))
-+ return (sc->F);
-+ else if (*name == 'o') {/* #o (octal) */
-+ snprintf(tmp, STRBUFFSIZE, "0%s", name+1);
-+ sscanf(tmp, "%lo", (long unsigned *)&x);
-+ return (mk_integer(sc, x));
-+ } else if (*name == 'd') { /* #d (decimal) */
-+ sscanf(name+1, "%ld", (long int *)&x);
-+ return (mk_integer(sc, x));
-+ } else if (*name == 'x') { /* #x (hex) */
-+ snprintf(tmp, STRBUFFSIZE, "0x%s", name+1);
-+ sscanf(tmp, "%lx", (long unsigned *)&x);
-+ return (mk_integer(sc, x));
-+ } else if (*name == 'b') { /* #b (binary) */
-+ x = binary_decode(name+1);
-+ return (mk_integer(sc, x));
-+ } else if (*name == '\\') { /* #\w (character) */
-+ int c=0;
-+ if(stricmp(name+1,"space")==0) {
-+ c=' ';
-+ } else if(stricmp(name+1,"newline")==0) {
-+ c='\n';
-+ } else if(stricmp(name+1,"return")==0) {
-+ c='\r';
-+ } else if(stricmp(name+1,"tab")==0) {
-+ c='\t';
-+ } else if(name[1]=='x' && name[2]!=0) {
-+ int c1=0;
-+ if(sscanf(name+2,"%x",(unsigned int *)&c1)==1 && c1 < UCHAR_MAX) {
-+ c=c1;
-+ } else {
-+ return sc->NIL;
-+ }
-+#if USE_ASCII_NAMES
-+ } else if(is_ascii_name(name+1,&c)) {
-+ /* nothing */
-+#endif
-+ } else if(name[2]==0) {
-+ c=name[1];
-+ } else {
-+ return sc->NIL;
-+ }
-+ return mk_character(sc,c);
-+ } else
-+ return (sc->NIL);
-+}
-+
-+/* ========== garbage collector ========== */
-+
-+/*--
-+ * We use algorithm E (Knuth, The Art of Computer Programming Vol.1,
-+ * sec. 2.3.5), the Schorr-Deutsch-Waite link-inversion algorithm,
-+ * for marking.
-+ */
-+static void mark(pointer a) {
-+ pointer t, q, p;
-+
-+ t = (pointer) 0;
-+ p = a;
-+E2: setmark(p);
-+ if(is_vector(p)) {
-+ int i;
-+ int num=ivalue_unchecked(p)/2+ivalue_unchecked(p)%2;
-+ for(i=0; i<num; i++) {
-+ /* Vector cells will be treated like ordinary cells */
-+ mark(p+1+i);
-+ }
-+ }
-+ if (is_atom(p))
-+ goto E6;
-+ /* E4: down car */
-+ q = car(p);
-+ if (q && !is_mark(q)) {
-+ setatom(p); /* a note that we have moved car */
-+ car(p) = t;
-+ t = p;
-+ p = q;
-+ goto E2;
-+ }
-+E5: q = cdr(p); /* down cdr */
-+ if (q && !is_mark(q)) {
-+ cdr(p) = t;
-+ t = p;
-+ p = q;
-+ goto E2;
-+ }
-+E6: /* up. Undo the link switching from steps E4 and E5. */
-+ if (!t)
-+ return;
-+ q = t;
-+ if (is_atom(q)) {
-+ clratom(q);
-+ t = car(q);
-+ car(q) = p;
-+ p = q;
-+ goto E5;
-+ } else {
-+ t = cdr(q);
-+ cdr(q) = p;
-+ p = q;
-+ goto E6;
-+ }
-+}
-+
-+/* garbage collection. parameter a, b is marked. */
-+static void gc(scheme *sc, pointer a, pointer b) {
-+ pointer p;
-+ int i;
-+
-+ if(sc->gc_verbose) {
-+ putstr(sc, "gc...");
-+ }
-+
-+ /* mark system globals */
-+ mark(sc->oblist);
-+ mark(sc->global_env);
-+
-+ /* mark current registers */
-+ mark(sc->args);
-+ mark(sc->envir);
-+ mark(sc->code);
-+ dump_stack_mark(sc);
-+ mark(sc->value);
-+ mark(sc->inport);
-+ mark(sc->save_inport);
-+ mark(sc->outport);
-+ mark(sc->loadport);
-+
-+ /* Mark recent objects the interpreter doesn't know about yet. */
-+ mark(car(sc->sink));
-+ /* Mark any older stuff above nested C calls */
-+ mark(sc->c_nest);
-+
-+ /* mark variables a, b */
-+ mark(a);
-+ mark(b);
-+
-+ /* garbage collect */
-+ clrmark(sc->NIL);
-+ sc->fcells = 0;
-+ sc->free_cell = sc->NIL;
-+ /* free-list is kept sorted by address so as to maintain consecutive
-+ ranges, if possible, for use with vectors. Here we scan the cells
-+ (which are also kept sorted by address) downwards to build the
-+ free-list in sorted order.
-+ */
-+ for (i = sc->last_cell_seg; i >= 0; i--) {
-+ p = sc->cell_seg[i] + CELL_SEGSIZE;
-+ while (--p >= sc->cell_seg[i]) {
-+ if (is_mark(p)) {
-+ clrmark(p);
-+ } else {
-+ /* reclaim cell */
-+ if (typeflag(p) != 0) {
-+ finalize_cell(sc, p);
-+ typeflag(p) = 0;
-+ car(p) = sc->NIL;
-+ }
-+ ++sc->fcells;
-+ cdr(p) = sc->free_cell;
-+ sc->free_cell = p;
-+ }
-+ }
-+ }
-+
-+ if (sc->gc_verbose) {
-+ char msg[80];
-+ snprintf(msg,80,"done: %ld cells were recovered.\n", sc->fcells);
-+ putstr(sc,msg);
-+ }
-+}
-+
-+static void finalize_cell(scheme *sc, pointer a) {
-+ if(is_string(a)) {
-+ sc->free(strvalue(a));
-+ } else if(is_port(a)) {
-+ if(a->_object._port->kind&port_file
-+ && a->_object._port->rep.stdio.closeit) {
-+ port_close(sc,a,port_input|port_output);
-+ }
-+ sc->free(a->_object._port);
-+ }
-+}
-+
-+/* ========== Routines for Reading ========== */
-+
-+static int file_push(scheme *sc, const char *fname) {
-+ FILE *fin = NULL;
-+
-+ if (sc->file_i == MAXFIL-1)
-+ return 0;
-+ fin=fopen(fname,"r");
-+ if(fin!=0) {
-+ sc->file_i++;
-+ sc->load_stack[sc->file_i].kind=port_file|port_input;
-+ sc->load_stack[sc->file_i].rep.stdio.file=fin;
-+ sc->load_stack[sc->file_i].rep.stdio.closeit=1;
-+ sc->nesting_stack[sc->file_i]=0;
-+ sc->loadport->_object._port=sc->load_stack+sc->file_i;
-+
-+#if SHOW_ERROR_LINE
-+ sc->load_stack[sc->file_i].rep.stdio.curr_line = 0;
-+ if(fname)
-+ sc->load_stack[sc->file_i].rep.stdio.filename = store_string(sc, strlen(fname), fname, 0);
-+#endif
-+ }
-+ return fin!=0;
-+}
-+
-+static void file_pop(scheme *sc) {
-+ if(sc->file_i != 0) {
-+ sc->nesting=sc->nesting_stack[sc->file_i];
-+ port_close(sc,sc->loadport,port_input);
-+ sc->file_i--;
-+ sc->loadport->_object._port=sc->load_stack+sc->file_i;
-+ }
-+}
-+
-+static int file_interactive(scheme *sc) {
-+ return sc->file_i==0 && sc->load_stack[0].rep.stdio.file==stdin
-+ && sc->inport->_object._port->kind&port_file;
-+}
-+
-+static port *port_rep_from_filename(scheme *sc, const char *fn, int prop) {
-+ FILE *f;
-+ char *rw;
-+ port *pt;
-+ if(prop==(port_input|port_output)) {
-+ rw="a+";
-+ } else if(prop==port_output) {
-+ rw="w";
-+ } else {
-+ rw="r";
-+ }
-+ f=fopen(fn,rw);
-+ if(f==0) {
-+ return 0;
-+ }
-+ pt=port_rep_from_file(sc,f,prop);
-+ pt->rep.stdio.closeit=1;
-+
-+#if SHOW_ERROR_LINE
-+ if(fn)
-+ pt->rep.stdio.filename = store_string(sc, strlen(fn), fn, 0);
-+
-+ pt->rep.stdio.curr_line = 0;
-+#endif
-+ return pt;
-+}
-+
-+static pointer port_from_filename(scheme *sc, const char *fn, int prop) {
-+ port *pt;
-+ pt=port_rep_from_filename(sc,fn,prop);
-+ if(pt==0) {
-+ return sc->NIL;
-+ }
-+ return mk_port(sc,pt);
-+}
-+
-+static port *port_rep_from_file(scheme *sc, FILE *f, int prop)
-+{
-+ port *pt;
-+
-+ pt = (port *)sc->malloc(sizeof *pt);
-+ if (pt == NULL) {
-+ return NULL;
-+ }
-+ pt->kind = port_file | prop;
-+ pt->rep.stdio.file = f;
-+ pt->rep.stdio.closeit = 0;
-+ return pt;
-+}
-+
-+static pointer port_from_file(scheme *sc, FILE *f, int prop) {
-+ port *pt;
-+ pt=port_rep_from_file(sc,f,prop);
-+ if(pt==0) {
-+ return sc->NIL;
-+ }
-+ return mk_port(sc,pt);
-+}
-+
-+static port *port_rep_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
-+ port *pt;
-+ pt=(port*)sc->malloc(sizeof(port));
-+ if(pt==0) {
-+ return 0;
-+ }
-+ pt->kind=port_string|prop;
-+ pt->rep.string.start=start;
-+ pt->rep.string.curr=start;
-+ pt->rep.string.past_the_end=past_the_end;
-+ return pt;
-+}
-+
-+static pointer port_from_string(scheme *sc, char *start, char *past_the_end, int prop) {
-+ port *pt;
-+ pt=port_rep_from_string(sc,start,past_the_end,prop);
-+ if(pt==0) {
-+ return sc->NIL;
-+ }
-+ return mk_port(sc,pt);
-+}
-+
-+#define BLOCK_SIZE 256
-+
-+static port *port_rep_from_scratch(scheme *sc) {
-+ port *pt;
-+ char *start;
-+ pt=(port*)sc->malloc(sizeof(port));
-+ if(pt==0) {
-+ return 0;
-+ }
-+ start=sc->malloc(BLOCK_SIZE);
-+ if(start==0) {
-+ return 0;
-+ }
-+ memset(start,' ',BLOCK_SIZE-1);
-+ start[BLOCK_SIZE-1]='\0';
-+ pt->kind=port_string|port_output|port_srfi6;
-+ pt->rep.string.start=start;
-+ pt->rep.string.curr=start;
-+ pt->rep.string.past_the_end=start+BLOCK_SIZE-1;
-+ return pt;
-+}
-+
-+static pointer port_from_scratch(scheme *sc) {
-+ port *pt;
-+ pt=port_rep_from_scratch(sc);
-+ if(pt==0) {
-+ return sc->NIL;
-+ }
-+ return mk_port(sc,pt);
-+}
-+
-+static void port_close(scheme *sc, pointer p, int flag) {
-+ port *pt=p->_object._port;
-+ pt->kind&=~flag;
-+ if((pt->kind & (port_input|port_output))==0) {
-+ if(pt->kind&port_file) {
-+
-+#if SHOW_ERROR_LINE
-+ /* Cleanup is here so (close-*-port) functions could work too */
-+ pt->rep.stdio.curr_line = 0;
-+
-+ if(pt->rep.stdio.filename)
-+ sc->free(pt->rep.stdio.filename);
-+#endif
-+
-+ fclose(pt->rep.stdio.file);
-+ }
-+ pt->kind=port_free;
-+ }
-+}
-+
-+/* get new character from input file */
-+static int inchar(scheme *sc) {
-+ int c;
-+ port *pt;
-+
-+ pt = sc->inport->_object._port;
-+ if(pt->kind & port_saw_EOF)
-+ { return EOF; }
-+ c = basic_inchar(pt);
-+ if(c == EOF && sc->inport == sc->loadport) {
-+ /* Instead, set port_saw_EOF */
-+ pt->kind |= port_saw_EOF;
-+
-+ /* file_pop(sc); */
-+ return EOF;
-+ /* NOTREACHED */
-+ }
-+ return c;
-+}
-+
-+static int basic_inchar(port *pt) {
-+ if(pt->kind & port_file) {
-+ return fgetc(pt->rep.stdio.file);
-+ } else {
-+ if(*pt->rep.string.curr == 0 ||
-+ pt->rep.string.curr == pt->rep.string.past_the_end) {
-+ return EOF;
-+ } else {
-+ return *pt->rep.string.curr++;
-+ }
-+ }
-+}
-+
-+/* back character to input buffer */
-+static void backchar(scheme *sc, int c) {
-+ port *pt;
-+ if(c==EOF) return;
-+ pt=sc->inport->_object._port;
-+ if(pt->kind&port_file) {
-+ ungetc(c,pt->rep.stdio.file);
-+ } else {
-+ if(pt->rep.string.curr!=pt->rep.string.start) {
-+ --pt->rep.string.curr;
-+ }
-+ }
-+}
-+
-+static int realloc_port_string(scheme *sc, port *p)
-+{
-+ char *start=p->rep.string.start;
-+ size_t new_size=p->rep.string.past_the_end-start+1+BLOCK_SIZE;
-+ char *str=sc->malloc(new_size);
-+ if(str) {
-+ memset(str,' ',new_size-1);
-+ str[new_size-1]='\0';
-+ strcpy(str,start);
-+ p->rep.string.start=str;
-+ p->rep.string.past_the_end=str+new_size-1;
-+ p->rep.string.curr-=start-str;
-+ sc->free(start);
-+ return 1;
-+ } else {
-+ return 0;
-+ }
-+}
-+
-+INTERFACE void putstr(scheme *sc, const char *s) {
-+ port *pt=sc->outport->_object._port;
-+ if(pt->kind&port_file) {
-+ fputs(s,pt->rep.stdio.file);
-+ } else {
-+ for(;*s;s++) {
-+ if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
-+ *pt->rep.string.curr++=*s;
-+ } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
-+ *pt->rep.string.curr++=*s;
-+ }
-+ }
-+ }
-+}
-+
-+static void putchars(scheme *sc, const char *s, int len) {
-+ port *pt=sc->outport->_object._port;
-+ if(pt->kind&port_file) {
-+ fwrite(s,1,len,pt->rep.stdio.file);
-+ } else {
-+ for(;len;len--) {
-+ if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
-+ *pt->rep.string.curr++=*s++;
-+ } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
-+ *pt->rep.string.curr++=*s++;
-+ }
-+ }
-+ }
-+}
-+
-+INTERFACE void putcharacter(scheme *sc, int c) {
-+ port *pt=sc->outport->_object._port;
-+ if(pt->kind&port_file) {
-+ fputc(c,pt->rep.stdio.file);
-+ } else {
-+ if(pt->rep.string.curr!=pt->rep.string.past_the_end) {
-+ *pt->rep.string.curr++=c;
-+ } else if(pt->kind&port_srfi6&&realloc_port_string(sc,pt)) {
-+ *pt->rep.string.curr++=c;
-+ }
-+ }
-+}
-+
-+/* read characters up to delimiter, but cater to character constants */
-+static char *readstr_upto(scheme *sc, char *delim) {
-+ char *p = sc->strbuff;
-+
-+ while ((p - sc->strbuff < sizeof(sc->strbuff)) &&
-+ !is_one_of(delim, (*p++ = inchar(sc))));
-+
-+ if(p == sc->strbuff+2 && p[-2] == '\\') {
-+ *p=0;
-+ } else {
-+ backchar(sc,p[-1]);
-+ *--p = '\0';
-+ }
-+ return sc->strbuff;
-+}
-+
-+/* read string expression "xxx...xxx" */
-+static pointer readstrexp(scheme *sc) {
-+ char *p = sc->strbuff;
-+ int c;
-+ int c1=0;
-+ enum { st_ok, st_bsl, st_x1, st_x2, st_oct1, st_oct2 } state=st_ok;
-+
-+ for (;;) {
-+ c=inchar(sc);
-+ if(c == EOF || p-sc->strbuff > sizeof(sc->strbuff)-1) {
-+ return sc->F;
-+ }
-+ switch(state) {
-+ case st_ok:
-+ switch(c) {
-+ case '\\':
-+ state=st_bsl;
-+ break;
-+ case '"':
-+ *p=0;
-+ return mk_counted_string(sc,sc->strbuff,p-sc->strbuff);
-+ default:
-+ *p++=c;
-+ break;
-+ }
-+ break;
-+ case st_bsl:
-+ switch(c) {
-+ case '0':
-+ case '1':
-+ case '2':
-+ case '3':
-+ case '4':
-+ case '5':
-+ case '6':
-+ case '7':
-+ state=st_oct1;
-+ c1=c-'0';
-+ break;
-+ case 'x':
-+ case 'X':
-+ state=st_x1;
-+ c1=0;
-+ break;
-+ case 'n':
-+ *p++='\n';
-+ state=st_ok;
-+ break;
-+ case 't':
-+ *p++='\t';
-+ state=st_ok;
-+ break;
-+ case 'r':
-+ *p++='\r';
-+ state=st_ok;
-+ break;
-+ case '"':
-+ *p++='"';
-+ state=st_ok;
-+ break;
-+ default:
-+ *p++=c;
-+ state=st_ok;
-+ break;
-+ }
-+ break;
-+ case st_x1:
-+ case st_x2:
-+ c=toupper(c);
-+ if(c>='0' && c<='F') {
-+ if(c<='9') {
-+ c1=(c1<<4)+c-'0';
-+ } else {
-+ c1=(c1<<4)+c-'A'+10;
-+ }
-+ if(state==st_x1) {
-+ state=st_x2;
-+ } else {
-+ *p++=c1;
-+ state=st_ok;
-+ }
-+ } else {
-+ return sc->F;
-+ }
-+ break;
-+ case st_oct1:
-+ case st_oct2:
-+ if (c < '0' || c > '7')
-+ {
-+ *p++=c1;
-+ backchar(sc, c);
-+ state=st_ok;
-+ }
-+ else
-+ {
-+ if (state==st_oct2 && c1 >= 32)
-+ return sc->F;
-+
-+ c1=(c1<<3)+(c-'0');
-+
-+ if (state == st_oct1)
-+ state=st_oct2;
-+ else
-+ {
-+ *p++=c1;
-+ state=st_ok;
-+ }
-+ }
-+ break;
-+
-+ }
-+ }
-+}
-+
-+/* check c is in chars */
-+static INLINE int is_one_of(char *s, int c) {
-+ if(c==EOF) return 1;
-+ while (*s)
-+ if (*s++ == c)
-+ return (1);
-+ return (0);
-+}
-+
-+/* skip white characters */
-+static INLINE int skipspace(scheme *sc) {
-+ int c = 0, curr_line = 0;
-+
-+ do {
-+ c=inchar(sc);
-+#if SHOW_ERROR_LINE
-+ if(c=='\n')
-+ curr_line++;
-+#endif
-+ } while (isspace(c));
-+
-+/* record it */
-+#if SHOW_ERROR_LINE
-+ if (sc->load_stack[sc->file_i].kind & port_file)
-+ sc->load_stack[sc->file_i].rep.stdio.curr_line += curr_line;
-+#endif
-+
-+ if(c!=EOF) {
-+ backchar(sc,c);
-+ return 1;
-+ }
-+ else
-+ { return EOF; }
-+}
-+
-+/* get token */
-+static int token(scheme *sc) {
-+ int c;
-+ c = skipspace(sc);
-+ if(c == EOF) { return (TOK_EOF); }
-+ switch (c=inchar(sc)) {
-+ case EOF:
-+ return (TOK_EOF);
-+ case '(':
-+ return (TOK_LPAREN);
-+ case ')':
-+ return (TOK_RPAREN);
-+ case '.':
-+ c=inchar(sc);
-+ if(is_one_of(" \n\t",c)) {
-+ return (TOK_DOT);
-+ } else {
-+ backchar(sc,c);
-+ backchar(sc,'.');
-+ return TOK_ATOM;
-+ }
-+ case '\'':
-+ return (TOK_QUOTE);
-+ case ';':
-+ while ((c=inchar(sc)) != '\n' && c!=EOF)
-+ ;
-+
-+#if SHOW_ERROR_LINE
-+ if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
-+ sc->load_stack[sc->file_i].rep.stdio.curr_line++;
-+#endif
-+
-+ if(c == EOF)
-+ { return (TOK_EOF); }
-+ else
-+ { return (token(sc));}
-+ case '"':
-+ return (TOK_DQUOTE);
-+ case BACKQUOTE:
-+ return (TOK_BQUOTE);
-+ case ',':
-+ if ((c=inchar(sc)) == '@') {
-+ return (TOK_ATMARK);
-+ } else {
-+ backchar(sc,c);
-+ return (TOK_COMMA);
-+ }
-+ case '#':
-+ c=inchar(sc);
-+ if (c == '(') {
-+ return (TOK_VEC);
-+ } else if(c == '!') {
-+ while ((c=inchar(sc)) != '\n' && c!=EOF)
-+ ;
-+
-+#if SHOW_ERROR_LINE
-+ if(c == '\n' && sc->load_stack[sc->file_i].kind & port_file)
-+ sc->load_stack[sc->file_i].rep.stdio.curr_line++;
-+#endif
-+
-+ if(c == EOF)
-+ { return (TOK_EOF); }
-+ else
-+ { return (token(sc));}
-+ } else {
-+ backchar(sc,c);
-+ if(is_one_of(" tfodxb\\",c)) {
-+ return TOK_SHARP_CONST;
-+ } else {
-+ return (TOK_SHARP);
-+ }
-+ }
-+ default:
-+ backchar(sc,c);
-+ return (TOK_ATOM);
-+ }
-+}
-+
-+/* ========== Routines for Printing ========== */
-+#define ok_abbrev(x) (is_pair(x) && cdr(x) == sc->NIL)
-+
-+static void printslashstring(scheme *sc, char *p, int len) {
-+ int i;
-+ unsigned char *s=(unsigned char*)p;
-+ putcharacter(sc,'"');
-+ for ( i=0; i<len; i++) {
-+ if(*s==0xff || *s=='"' || *s<' ' || *s=='\\') {
-+ putcharacter(sc,'\\');
-+ switch(*s) {
-+ case '"':
-+ putcharacter(sc,'"');
-+ break;
-+ case '\n':
-+ putcharacter(sc,'n');
-+ break;
-+ case '\t':
-+ putcharacter(sc,'t');
-+ break;
-+ case '\r':
-+ putcharacter(sc,'r');
-+ break;
-+ case '\\':
-+ putcharacter(sc,'\\');
-+ break;
-+ default: {
-+ int d=*s/16;
-+ putcharacter(sc,'x');
-+ if(d<10) {
-+ putcharacter(sc,d+'0');
-+ } else {
-+ putcharacter(sc,d-10+'A');
-+ }
-+ d=*s%16;
-+ if(d<10) {
-+ putcharacter(sc,d+'0');
-+ } else {
-+ putcharacter(sc,d-10+'A');
-+ }
-+ }
-+ }
-+ } else {
-+ putcharacter(sc,*s);
-+ }
-+ s++;
-+ }
-+ putcharacter(sc,'"');
-+}
-+
-+
-+/* print atoms */
-+static void printatom(scheme *sc, pointer l, int f) {
-+ char *p;
-+ int len;
-+ atom2str(sc,l,f,&p,&len);
-+ putchars(sc,p,len);
-+}
-+
-+
-+/* Uses internal buffer unless string pointer is already available */
-+static void atom2str(scheme *sc, pointer l, int f, char **pp, int *plen) {
-+ char *p;
-+
-+ if (l == sc->NIL) {
-+ p = "()";
-+ } else if (l == sc->T) {
-+ p = "#t";
-+ } else if (l == sc->F) {
-+ p = "#f";
-+ } else if (l == sc->EOF_OBJ) {
-+ p = "#<EOF>";
-+ } else if (is_port(l)) {
-+ p = sc->strbuff;
-+ snprintf(p, STRBUFFSIZE, "#<PORT>");
-+ } else if (is_number(l)) {
-+ p = sc->strbuff;
-+ if (f <= 1 || f == 10) /* f is the base for numbers if > 1 */ {
-+ if(num_is_integer(l)) {
-+ snprintf(p, STRBUFFSIZE, "%ld", ivalue_unchecked(l));
-+ } else {
-+ snprintf(p, STRBUFFSIZE, "%.10g", rvalue_unchecked(l));
-+ /* r5rs says there must be a '.' (unless 'e'?) */
-+ f = strcspn(p, ".e");
-+ if (p[f] == 0) {
-+ p[f] = '.'; /* not found, so add '.0' at the end */
-+ p[f+1] = '0';
-+ p[f+2] = 0;
-+ }
-+ }
-+ } else {
-+ long v = ivalue(l);
-+ if (f == 16) {
-+ if (v >= 0)
-+ snprintf(p, STRBUFFSIZE, "%lx", v);
-+ else
-+ snprintf(p, STRBUFFSIZE, "-%lx", -v);
-+ } else if (f == 8) {
-+ if (v >= 0)
-+ snprintf(p, STRBUFFSIZE, "%lo", v);
-+ else
-+ snprintf(p, STRBUFFSIZE, "-%lo", -v);
-+ } else if (f == 2) {
-+ unsigned long b = (v < 0) ? -v : v;
-+ p = &p[STRBUFFSIZE-1];
-+ *p = 0;
-+ do { *--p = (b&1) ? '1' : '0'; b >>= 1; } while (b != 0);
-+ if (v < 0) *--p = '-';
-+ }
-+ }
-+ } else if (is_string(l)) {
-+ if (!f) {
-+ p = strvalue(l);
-+ } else { /* Hack, uses the fact that printing is needed */
-+ *pp=sc->strbuff;
-+ *plen=0;
-+ printslashstring(sc, strvalue(l), strlength(l));
-+ return;
-+ }
-+ } else if (is_character(l)) {
-+ int c=charvalue(l);
-+ p = sc->strbuff;
-+ if (!f) {
-+ p[0]=c;
-+ p[1]=0;
-+ } else {
-+ switch(c) {
-+ case ' ':
-+ snprintf(p,STRBUFFSIZE,"#\\space"); break;
-+ case '\n':
-+ snprintf(p,STRBUFFSIZE,"#\\newline"); break;
-+ case '\r':
-+ snprintf(p,STRBUFFSIZE,"#\\return"); break;
-+ case '\t':
-+ snprintf(p,STRBUFFSIZE,"#\\tab"); break;
-+ default:
-+#if USE_ASCII_NAMES
-+ if(c==127) {
-+ snprintf(p,STRBUFFSIZE, "#\\del");
-+ break;
-+ } else if(c<32) {
-+ snprintf(p, STRBUFFSIZE, "#\\%s", charnames[c]);
-+ break;
-+ }
-+#else
-+ if(c<32) {
-+ snprintf(p,STRBUFFSIZE,"#\\x%x",c); break;
-+ break;
-+ }
-+#endif
-+ snprintf(p,STRBUFFSIZE,"#\\%c",c); break;
-+ break;
-+ }
-+ }
-+ } else if (is_symbol(l)) {
-+ p = symname(l);
-+ } else if (is_proc(l)) {
-+ p = sc->strbuff;
-+ snprintf(p,STRBUFFSIZE,"#<%s PROCEDURE %ld>", procname(l),procnum(l));
-+ } else if (is_macro(l)) {
-+ p = "#<MACRO>";
-+ } else if (is_closure(l)) {
-+ p = "#<CLOSURE>";
-+ } else if (is_promise(l)) {
-+ p = "#<PROMISE>";
-+ } else if (is_foreign(l)) {
-+ p = sc->strbuff;
-+ snprintf(p,STRBUFFSIZE,"#<FOREIGN PROCEDURE %ld>", procnum(l));
-+ } else if (is_continuation(l)) {
-+ p = "#<CONTINUATION>";
-+ } else {
-+ p = "#<ERROR>";
-+ }
-+ *pp=p;
-+ *plen=strlen(p);
-+}
-+/* ========== Routines for Evaluation Cycle ========== */
-+
-+/* make closure. c is code. e is environment */
-+static pointer mk_closure(scheme *sc, pointer c, pointer e) {
-+ pointer x = get_cell(sc, c, e);
-+
-+ typeflag(x) = T_CLOSURE;
-+ car(x) = c;
-+ cdr(x) = e;
-+ return (x);
-+}
-+
-+/* make continuation. */
-+static pointer mk_continuation(scheme *sc, pointer d) {
-+ pointer x = get_cell(sc, sc->NIL, d);
-+
-+ typeflag(x) = T_CONTINUATION;
-+ cont_dump(x) = d;
-+ return (x);
-+}
-+
-+static pointer list_star(scheme *sc, pointer d) {
-+ pointer p, q;
-+ if(cdr(d)==sc->NIL) {
-+ return car(d);
-+ }
-+ p=cons(sc,car(d),cdr(d));
-+ q=p;
-+ while(cdr(cdr(p))!=sc->NIL) {
-+ d=cons(sc,car(p),cdr(p));
-+ if(cdr(cdr(p))!=sc->NIL) {
-+ p=cdr(d);
-+ }
-+ }
-+ cdr(p)=car(cdr(p));
-+ return q;
-+}
-+
-+/* reverse list -- produce new list */
-+static pointer reverse(scheme *sc, pointer a) {
-+/* a must be checked by gc */
-+ pointer p = sc->NIL;
-+
-+ for ( ; is_pair(a); a = cdr(a)) {
-+ p = cons(sc, car(a), p);
-+ }
-+ return (p);
-+}
-+
-+/* reverse list --- in-place */
-+static pointer reverse_in_place(scheme *sc, pointer term, pointer list) {
-+ pointer p = list, result = term, q;
-+
-+ while (p != sc->NIL) {
-+ q = cdr(p);
-+ cdr(p) = result;
-+ result = p;
-+ p = q;
-+ }
-+ return (result);
-+}
-+
-+/* append list -- produce new list (in reverse order) */
-+static pointer revappend(scheme *sc, pointer a, pointer b) {
-+ pointer result = a;
-+ pointer p = b;
-+
-+ while (is_pair(p)) {
-+ result = cons(sc, car(p), result);
-+ p = cdr(p);
-+ }
-+
-+ if (p == sc->NIL) {
-+ return result;
-+ }
-+
-+ return sc->F; /* signal an error */
-+}
-+
-+/* equivalence of atoms */
-+int eqv(pointer a, pointer b) {
-+ if (is_string(a)) {
-+ if (is_string(b))
-+ return (strvalue(a) == strvalue(b));
-+ else
-+ return (0);
-+ } else if (is_number(a)) {
-+ if (is_number(b)) {
-+ if (num_is_integer(a) == num_is_integer(b))
-+ return num_eq(nvalue(a),nvalue(b));
-+ }
-+ return (0);
-+ } else if (is_character(a)) {
-+ if (is_character(b))
-+ return charvalue(a)==charvalue(b);
-+ else
-+ return (0);
-+ } else if (is_port(a)) {
-+ if (is_port(b))
-+ return a==b;
-+ else
-+ return (0);
-+ } else if (is_proc(a)) {
-+ if (is_proc(b))
-+ return procnum(a)==procnum(b);
-+ else
-+ return (0);
-+ } else {
-+ return (a == b);
-+ }
-+}
-+
-+/* true or false value macro */
-+/* () is #t in R5RS */
-+#define is_true(p) ((p) != sc->F)
-+#define is_false(p) ((p) == sc->F)
-+
-+/* ========== Environment implementation ========== */
-+
-+#if !defined(USE_ALIST_ENV) || !defined(USE_OBJECT_LIST)
-+
-+static int hash_fn(const char *key, int table_size)
-+{
-+ unsigned int hashed = 0;
-+ const char *c;
-+ int bits_per_int = sizeof(unsigned int)*8;
-+
-+ for (c = key; *c; c++) {
-+ /* letters have about 5 bits in them */
-+ hashed = (hashed<<5) | (hashed>>(bits_per_int-5));
-+ hashed ^= *c;
-+ }
-+ return hashed % table_size;
-+}
-+#endif
-+
-+#ifndef USE_ALIST_ENV
-+
-+/*
-+ * In this implementation, each frame of the environment may be
-+ * a hash table: a vector of alists hashed by variable name.
-+ * In practice, we use a vector only for the initial frame;
-+ * subsequent frames are too small and transient for the lookup
-+ * speed to out-weigh the cost of making a new vector.
-+ */
-+
-+static void new_frame_in_env(scheme *sc, pointer old_env)
-+{
-+ pointer new_frame;
-+
-+ /* The interaction-environment has about 300 variables in it. */
-+ if (old_env == sc->NIL) {
-+ new_frame = mk_vector(sc, 461);
-+ } else {
-+ new_frame = sc->NIL;
-+ }
-+
-+ sc->envir = immutable_cons(sc, new_frame, old_env);
-+ setenvironment(sc->envir);
-+}
-+
-+static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
-+ pointer variable, pointer value)
-+{
-+ pointer slot = immutable_cons(sc, variable, value);
-+
-+ if (is_vector(car(env))) {
-+ int location = hash_fn(symname(variable), ivalue_unchecked(car(env)));
-+
-+ set_vector_elem(car(env), location,
-+ immutable_cons(sc, slot, vector_elem(car(env), location)));
-+ } else {
-+ car(env) = immutable_cons(sc, slot, car(env));
-+ }
-+}
-+
-+static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
-+{
-+ pointer x,y;
-+ int location;
-+
-+ for (x = env; x != sc->NIL; x = cdr(x)) {
-+ if (is_vector(car(x))) {
-+ location = hash_fn(symname(hdl), ivalue_unchecked(car(x)));
-+ y = vector_elem(car(x), location);
-+ } else {
-+ y = car(x);
-+ }
-+ for ( ; y != sc->NIL; y = cdr(y)) {
-+ if (caar(y) == hdl) {
-+ break;
-+ }
-+ }
-+ if (y != sc->NIL) {
-+ break;
-+ }
-+ if(!all) {
-+ return sc->NIL;
-+ }
-+ }
-+ if (x != sc->NIL) {
-+ return car(y);
-+ }
-+ return sc->NIL;
-+}
-+
-+#else /* USE_ALIST_ENV */
-+
-+static INLINE void new_frame_in_env(scheme *sc, pointer old_env)
-+{
-+ sc->envir = immutable_cons(sc, sc->NIL, old_env);
-+ setenvironment(sc->envir);
-+}
-+
-+static INLINE void new_slot_spec_in_env(scheme *sc, pointer env,
-+ pointer variable, pointer value)
-+{
-+ car(env) = immutable_cons(sc, immutable_cons(sc, variable, value), car(env));
-+}
-+
-+static pointer find_slot_in_env(scheme *sc, pointer env, pointer hdl, int all)
-+{
-+ pointer x,y;
-+ for (x = env; x != sc->NIL; x = cdr(x)) {
-+ for (y = car(x); y != sc->NIL; y = cdr(y)) {
-+ if (caar(y) == hdl) {
-+ break;
-+ }
-+ }
-+ if (y != sc->NIL) {
-+ break;
-+ }
-+ if(!all) {
-+ return sc->NIL;
-+ }
-+ }
-+ if (x != sc->NIL) {
-+ return car(y);
-+ }
-+ return sc->NIL;
-+}
-+
-+#endif /* USE_ALIST_ENV else */
-+
-+static INLINE void new_slot_in_env(scheme *sc, pointer variable, pointer value)
-+{
-+ new_slot_spec_in_env(sc, sc->envir, variable, value);
-+}
-+
-+static INLINE void set_slot_in_env(scheme *sc, pointer slot, pointer value)
-+{
-+ cdr(slot) = value;
-+}
-+
-+static INLINE pointer slot_value_in_env(pointer slot)
-+{
-+ return cdr(slot);
-+}
-+
-+/* ========== Evaluation Cycle ========== */
-+
-+
-+static pointer _Error_1(scheme *sc, const char *s, pointer a) {
-+ const char *str = s;
-+#if USE_ERROR_HOOK
-+ pointer x;
-+ pointer hdl=sc->ERROR_HOOK;
-+#endif
-+
-+#if SHOW_ERROR_LINE
-+ char sbuf[STRBUFFSIZE];
-+
-+ /* make sure error is not in REPL */
-+ if (sc->load_stack[sc->file_i].kind & port_file &&
-+ sc->load_stack[sc->file_i].rep.stdio.file != stdin) {
-+ int ln = sc->load_stack[sc->file_i].rep.stdio.curr_line;
-+ const char *fname = sc->load_stack[sc->file_i].rep.stdio.filename;
-+
-+ /* should never happen */
-+ if(!fname) fname = "<unknown>";
-+
-+ /* we started from 0 */
-+ ln++;
-+ snprintf(sbuf, STRBUFFSIZE, "(%s : %i) %s", fname, ln, s);
-+
-+ str = (const char*)sbuf;
-+ }
-+#endif
-+
-+#if USE_ERROR_HOOK
-+ x=find_slot_in_env(sc,sc->envir,hdl,1);
-+ if (x != sc->NIL) {
-+ if(a!=0) {
-+ sc->code = cons(sc, cons(sc, sc->QUOTE, cons(sc,(a), sc->NIL)), sc->NIL);
-+ } else {
-+ sc->code = sc->NIL;
-+ }
-+ sc->code = cons(sc, mk_string(sc, str), sc->code);
-+ setimmutable(car(sc->code));
-+ sc->code = cons(sc, slot_value_in_env(x), sc->code);
-+ sc->op = (int)OP_EVAL;
-+ return sc->T;
-+ }
-+#endif
-+
-+ if(a!=0) {
-+ sc->args = cons(sc, (a), sc->NIL);
-+ } else {
-+ sc->args = sc->NIL;
-+ }
-+ sc->args = cons(sc, mk_string(sc, str), sc->args);
-+ setimmutable(car(sc->args));
-+ sc->op = (int)OP_ERR0;
-+ return sc->T;
-+}
-+#define Error_1(sc,s, a) return _Error_1(sc,s,a)
-+#define Error_0(sc,s) return _Error_1(sc,s,0)
-+
-+/* Too small to turn into function */
-+# define BEGIN do {
-+# define END } while (0)
-+#define s_goto(sc,a) BEGIN \
-+ sc->op = (int)(a); \
-+ return sc->T; END
-+
-+#define s_return(sc,a) return _s_return(sc,a)
-+
-+#ifndef USE_SCHEME_STACK
-+
-+/* this structure holds all the interpreter's registers */
-+struct dump_stack_frame {
-+ enum scheme_opcodes op;
-+ pointer args;
-+ pointer envir;
-+ pointer code;
-+};
-+
-+#define STACK_GROWTH 3
-+
-+static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code)
-+{
-+ int nframes = (int)sc->dump;
-+ struct dump_stack_frame *next_frame;
-+
-+ /* enough room for the next frame? */
-+ if (nframes >= sc->dump_size) {
-+ sc->dump_size += STACK_GROWTH;
-+ /* alas there is no sc->realloc */
-+ sc->dump_base = realloc(sc->dump_base,
-+ sizeof(struct dump_stack_frame) * sc->dump_size);
-+ }
-+ next_frame = (struct dump_stack_frame *)sc->dump_base + nframes;
-+ next_frame->op = op;
-+ next_frame->args = args;
-+ next_frame->envir = sc->envir;
-+ next_frame->code = code;
-+ sc->dump = (pointer)(nframes+1);
-+}
-+
-+static pointer _s_return(scheme *sc, pointer a)
-+{
-+ int nframes = (int)sc->dump;
-+ struct dump_stack_frame *frame;
-+
-+ sc->value = (a);
-+ if (nframes <= 0) {
-+ return sc->NIL;
-+ }
-+ nframes--;
-+ frame = (struct dump_stack_frame *)sc->dump_base + nframes;
-+ sc->op = frame->op;
-+ sc->args = frame->args;
-+ sc->envir = frame->envir;
-+ sc->code = frame->code;
-+ sc->dump = (pointer)nframes;
-+ return sc->T;
-+}
-+
-+static INLINE void dump_stack_reset(scheme *sc)
-+{
-+ /* in this implementation, sc->dump is the number of frames on the stack */
-+ sc->dump = (pointer)0;
-+}
-+
-+static INLINE void dump_stack_initialize(scheme *sc)
-+{
-+ sc->dump_size = 0;
-+ sc->dump_base = NULL;
-+ dump_stack_reset(sc);
-+}
-+
-+static void dump_stack_free(scheme *sc)
-+{
-+ free(sc->dump_base);
-+ sc->dump_base = NULL;
-+ sc->dump = (pointer)0;
-+ sc->dump_size = 0;
-+}
-+
-+static INLINE void dump_stack_mark(scheme *sc)
-+{
-+ int nframes = (int)sc->dump;
-+ int i;
-+ for(i=0; i<nframes; i++) {
-+ struct dump_stack_frame *frame;
-+ frame = (struct dump_stack_frame *)sc->dump_base + i;
-+ mark(frame->args);
-+ mark(frame->envir);
-+ mark(frame->code);
-+ }
-+}
-+
-+#else
-+
-+static INLINE void dump_stack_reset(scheme *sc)
-+{
-+ sc->dump = sc->NIL;
-+}
-+
-+static INLINE void dump_stack_initialize(scheme *sc)
-+{
-+ dump_stack_reset(sc);
-+}
-+
-+static void dump_stack_free(scheme *sc)
-+{
-+ sc->dump = sc->NIL;
-+}
-+
-+static pointer _s_return(scheme *sc, pointer a) {
-+ sc->value = (a);
-+ if(sc->dump==sc->NIL) return sc->NIL;
-+ sc->op = ivalue(car(sc->dump));
-+ sc->args = cadr(sc->dump);
-+ sc->envir = caddr(sc->dump);
-+ sc->code = cadddr(sc->dump);
-+ sc->dump = cddddr(sc->dump);
-+ return sc->T;
-+}
-+
-+static void s_save(scheme *sc, enum scheme_opcodes op, pointer args, pointer code) {
-+ sc->dump = cons(sc, sc->envir, cons(sc, (code), sc->dump));
-+ sc->dump = cons(sc, (args), sc->dump);
-+ sc->dump = cons(sc, mk_integer(sc, (long)(op)), sc->dump);
-+}
-+
-+static INLINE void dump_stack_mark(scheme *sc)
-+{
-+ mark(sc->dump);
-+}
-+#endif
-+
-+#define s_retbool(tf) s_return(sc,(tf) ? sc->T : sc->F)
-+
-+static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
-+ pointer x, y;
-+
-+ switch (op) {
-+ case OP_LOAD: /* load */
-+ if(file_interactive(sc)) {
-+ fprintf(sc->outport->_object._port->rep.stdio.file,
-+ "Loading %s\n", strvalue(car(sc->args)));
-+ }
-+ if (!file_push(sc,strvalue(car(sc->args)))) {
-+ Error_1(sc,"unable to open", car(sc->args));
-+ }
-+ else
-+ {
-+ sc->args = mk_integer(sc,sc->file_i);
-+ s_goto(sc,OP_T0LVL);
-+ }
-+
-+ case OP_T0LVL: /* top level */
-+ /* If we reached the end of file, this loop is done. */
-+ if(sc->loadport->_object._port->kind & port_saw_EOF)
-+ {
-+ if(sc->file_i == 0)
-+ {
-+ sc->args=sc->NIL;
-+ s_goto(sc,OP_QUIT);
-+ }
-+ else
-+ {
-+ file_pop(sc);
-+ s_return(sc,sc->value);
-+ }
-+ /* NOTREACHED */
-+ }
-+
-+ /* If interactive, be nice to user. */
-+ if(file_interactive(sc))
-+ {
-+ sc->envir = sc->global_env;
-+ dump_stack_reset(sc);
-+ putstr(sc,"\n");
-+ putstr(sc,prompt);
-+ }
-+
-+ /* Set up another iteration of REPL */
-+ sc->nesting=0;
-+ sc->save_inport=sc->inport;
-+ sc->inport = sc->loadport;
-+ s_save(sc,OP_T0LVL, sc->NIL, sc->NIL);
-+ s_save(sc,OP_VALUEPRINT, sc->NIL, sc->NIL);
-+ s_save(sc,OP_T1LVL, sc->NIL, sc->NIL);
-+ s_goto(sc,OP_READ_INTERNAL);
-+
-+ case OP_T1LVL: /* top level */
-+ sc->code = sc->value;
-+ sc->inport=sc->save_inport;
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_READ_INTERNAL: /* internal read */
-+ sc->tok = token(sc);
-+ if(sc->tok==TOK_EOF)
-+ { s_return(sc,sc->EOF_OBJ); }
-+ s_goto(sc,OP_RDSEXPR);
-+
-+ case OP_GENSYM:
-+ s_return(sc, gensym(sc));
-+
-+ case OP_VALUEPRINT: /* print evaluation result */
-+ /* OP_VALUEPRINT is always pushed, because when changing from
-+ non-interactive to interactive mode, it needs to be
-+ already on the stack */
-+ if(sc->tracing) {
-+ putstr(sc,"\nGives: ");
-+ }
-+ if(file_interactive(sc)) {
-+ sc->print_flag = 1;
-+ sc->args = sc->value;
-+ s_goto(sc,OP_P0LIST);
-+ } else {
-+ s_return(sc,sc->value);
-+ }
-+
-+ case OP_EVAL: /* main part of evaluation */
-+#if USE_TRACING
-+ if(sc->tracing) {
-+ /*s_save(sc,OP_VALUEPRINT,sc->NIL,sc->NIL);*/
-+ s_save(sc,OP_REAL_EVAL,sc->args,sc->code);
-+ sc->args=sc->code;
-+ putstr(sc,"\nEval: ");
-+ s_goto(sc,OP_P0LIST);
-+ }
-+ /* fall through */
-+ case OP_REAL_EVAL:
-+#endif
-+ if (is_symbol(sc->code)) { /* symbol */
-+ x=find_slot_in_env(sc,sc->envir,sc->code,1);
-+ if (x != sc->NIL) {
-+ s_return(sc,slot_value_in_env(x));
-+ } else {
-+ Error_1(sc,"eval: unbound variable:", sc->code);
-+ }
-+ } else if (is_pair(sc->code)) {
-+ if (is_syntax(x = car(sc->code))) { /* SYNTAX */
-+ sc->code = cdr(sc->code);
-+ s_goto(sc,syntaxnum(x));
-+ } else {/* first, eval top element and eval arguments */
-+ s_save(sc,OP_E0ARGS, sc->NIL, sc->code);
-+ /* If no macros => s_save(sc,OP_E1ARGS, sc->NIL, cdr(sc->code));*/
-+ sc->code = car(sc->code);
-+ s_goto(sc,OP_EVAL);
-+ }
-+ } else {
-+ s_return(sc,sc->code);
-+ }
-+
-+ case OP_E0ARGS: /* eval arguments */
-+ if (is_macro(sc->value)) { /* macro expansion */
-+ s_save(sc,OP_DOMACRO, sc->NIL, sc->NIL);
-+ sc->args = cons(sc,sc->code, sc->NIL);
-+ sc->code = sc->value;
-+ s_goto(sc,OP_APPLY);
-+ } else {
-+ sc->code = cdr(sc->code);
-+ s_goto(sc,OP_E1ARGS);
-+ }
-+
-+ case OP_E1ARGS: /* eval arguments */
-+ sc->args = cons(sc, sc->value, sc->args);
-+ if (is_pair(sc->code)) { /* continue */
-+ s_save(sc,OP_E1ARGS, sc->args, cdr(sc->code));
-+ sc->code = car(sc->code);
-+ sc->args = sc->NIL;
-+ s_goto(sc,OP_EVAL);
-+ } else { /* end */
-+ sc->args = reverse_in_place(sc, sc->NIL, sc->args);
-+ sc->code = car(sc->args);
-+ sc->args = cdr(sc->args);
-+ s_goto(sc,OP_APPLY);
-+ }
-+
-+#if USE_TRACING
-+ case OP_TRACING: {
-+ int tr=sc->tracing;
-+ sc->tracing=ivalue(car(sc->args));
-+ s_return(sc,mk_integer(sc,tr));
-+ }
-+#endif
-+
-+ case OP_APPLY: /* apply 'code' to 'args' */
-+#if USE_TRACING
-+ if(sc->tracing) {
-+ s_save(sc,OP_REAL_APPLY,sc->args,sc->code);
-+ sc->print_flag = 1;
-+ /* sc->args=cons(sc,sc->code,sc->args);*/
-+ putstr(sc,"\nApply to: ");
-+ s_goto(sc,OP_P0LIST);
-+ }
-+ /* fall through */
-+ case OP_REAL_APPLY:
-+#endif
-+ if (is_proc(sc->code)) {
-+ s_goto(sc,procnum(sc->code)); /* PROCEDURE */
-+ } else if (is_foreign(sc->code))
-+ {
-+ /* Keep nested calls from GC'ing the arglist */
-+ push_recent_alloc(sc,sc->args,sc->NIL);
-+ x=sc->code->_object._ff(sc,sc->args);
-+ s_return(sc,x);
-+ } else if (is_closure(sc->code) || is_macro(sc->code)
-+ || is_promise(sc->code)) { /* CLOSURE */
-+ /* Should not accept promise */
-+ /* make environment */
-+ new_frame_in_env(sc, closure_env(sc->code));
-+ for (x = car(closure_code(sc->code)), y = sc->args;
-+ is_pair(x); x = cdr(x), y = cdr(y)) {
-+ if (y == sc->NIL) {
-+ Error_0(sc,"not enough arguments");
-+ } else {
-+ new_slot_in_env(sc, car(x), car(y));
-+ }
-+ }
-+ if (x == sc->NIL) {
-+ /*--
-+ * if (y != sc->NIL) {
-+ * Error_0(sc,"too many arguments");
-+ * }
-+ */
-+ } else if (is_symbol(x))
-+ new_slot_in_env(sc, x, y);
-+ else {
-+ Error_1(sc,"syntax error in closure: not a symbol:", x);
-+ }
-+ sc->code = cdr(closure_code(sc->code));
-+ sc->args = sc->NIL;
-+ s_goto(sc,OP_BEGIN);
-+ } else if (is_continuation(sc->code)) { /* CONTINUATION */
-+ sc->dump = cont_dump(sc->code);
-+ s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
-+ } else {
-+ Error_0(sc,"illegal function");
-+ }
-+
-+ case OP_DOMACRO: /* do macro */
-+ sc->code = sc->value;
-+ s_goto(sc,OP_EVAL);
-+
-+#if 1
-+ case OP_LAMBDA: /* lambda */
-+ /* If the hook is defined, apply it to sc->code, otherwise
-+ set sc->value fall thru */
-+ {
-+ pointer f=find_slot_in_env(sc,sc->envir,sc->COMPILE_HOOK,1);
-+ if(f==sc->NIL) {
-+ sc->value = sc->code;
-+ /* Fallthru */
-+ } else {
-+ s_save(sc,OP_LAMBDA1,sc->args,sc->code);
-+ sc->args=cons(sc,sc->code,sc->NIL);
-+ sc->code=slot_value_in_env(f);
-+ s_goto(sc,OP_APPLY);
-+ }
-+ }
-+
-+ case OP_LAMBDA1:
-+ s_return(sc,mk_closure(sc, sc->value, sc->envir));
-+
-+#else
-+ case OP_LAMBDA: /* lambda */
-+ s_return(sc,mk_closure(sc, sc->code, sc->envir));
-+
-+#endif
-+
-+ case OP_MKCLOSURE: /* make-closure */
-+ x=car(sc->args);
-+ if(car(x)==sc->LAMBDA) {
-+ x=cdr(x);
-+ }
-+ if(cdr(sc->args)==sc->NIL) {
-+ y=sc->envir;
-+ } else {
-+ y=cadr(sc->args);
-+ }
-+ s_return(sc,mk_closure(sc, x, y));
-+
-+ case OP_QUOTE: /* quote */
-+ s_return(sc,car(sc->code));
-+
-+ case OP_DEF0: /* define */
-+ if(is_immutable(car(sc->code)))
-+ Error_1(sc,"define: unable to alter immutable", car(sc->code));
-+
-+ if (is_pair(car(sc->code))) {
-+ x = caar(sc->code);
-+ sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
-+ } else {
-+ x = car(sc->code);
-+ sc->code = cadr(sc->code);
-+ }
-+ if (!is_symbol(x)) {
-+ Error_0(sc,"variable is not a symbol");
-+ }
-+ s_save(sc,OP_DEF1, sc->NIL, x);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_DEF1: /* define */
-+ x=find_slot_in_env(sc,sc->envir,sc->code,0);
-+ if (x != sc->NIL) {
-+ set_slot_in_env(sc, x, sc->value);
-+ } else {
-+ new_slot_in_env(sc, sc->code, sc->value);
-+ }
-+ s_return(sc,sc->code);
-+
-+
-+ case OP_DEFP: /* defined? */
-+ x=sc->envir;
-+ if(cdr(sc->args)!=sc->NIL) {
-+ x=cadr(sc->args);
-+ }
-+ s_retbool(find_slot_in_env(sc,x,car(sc->args),1)!=sc->NIL);
-+
-+ case OP_SET0: /* set! */
-+ if(is_immutable(car(sc->code)))
-+ Error_1(sc,"set!: unable to alter immutable variable",car(sc->code));
-+ s_save(sc,OP_SET1, sc->NIL, car(sc->code));
-+ sc->code = cadr(sc->code);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_SET1: /* set! */
-+ y=find_slot_in_env(sc,sc->envir,sc->code,1);
-+ if (y != sc->NIL) {
-+ set_slot_in_env(sc, y, sc->value);
-+ s_return(sc,sc->value);
-+ } else {
-+ Error_1(sc,"set!: unbound variable:", sc->code);
-+ }
-+
-+
-+ case OP_BEGIN: /* begin */
-+ if (!is_pair(sc->code)) {
-+ s_return(sc,sc->code);
-+ }
-+ if (cdr(sc->code) != sc->NIL) {
-+ s_save(sc,OP_BEGIN, sc->NIL, cdr(sc->code));
-+ }
-+ sc->code = car(sc->code);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_IF0: /* if */
-+ s_save(sc,OP_IF1, sc->NIL, cdr(sc->code));
-+ sc->code = car(sc->code);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_IF1: /* if */
-+ if (is_true(sc->value))
-+ sc->code = car(sc->code);
-+ else
-+ sc->code = cadr(sc->code); /* (if #f 1) ==> () because
-+ * car(sc->NIL) = sc->NIL */
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_LET0: /* let */
-+ sc->args = sc->NIL;
-+ sc->value = sc->code;
-+ sc->code = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code);
-+ s_goto(sc,OP_LET1);
-+
-+ case OP_LET1: /* let (calculate parameters) */
-+ sc->args = cons(sc, sc->value, sc->args);
-+ if (is_pair(sc->code)) { /* continue */
-+ if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
-+ Error_1(sc, "Bad syntax of binding spec in let :",
-+ car(sc->code));
-+ }
-+ s_save(sc,OP_LET1, sc->args, cdr(sc->code));
-+ sc->code = cadar(sc->code);
-+ sc->args = sc->NIL;
-+ s_goto(sc,OP_EVAL);
-+ } else { /* end */
-+ sc->args = reverse_in_place(sc, sc->NIL, sc->args);
-+ sc->code = car(sc->args);
-+ sc->args = cdr(sc->args);
-+ s_goto(sc,OP_LET2);
-+ }
-+
-+ case OP_LET2: /* let */
-+ new_frame_in_env(sc, sc->envir);
-+ for (x = is_symbol(car(sc->code)) ? cadr(sc->code) : car(sc->code), y = sc->args;
-+ y != sc->NIL; x = cdr(x), y = cdr(y)) {
-+ new_slot_in_env(sc, caar(x), car(y));
-+ }
-+ if (is_symbol(car(sc->code))) { /* named let */
-+ for (x = cadr(sc->code), sc->args = sc->NIL; x != sc->NIL; x = cdr(x)) {
-+ if (!is_pair(x))
-+ Error_1(sc, "Bad syntax of binding in let :", x);
-+ if (!is_list(sc, car(x)))
-+ Error_1(sc, "Bad syntax of binding in let :", car(x));
-+ sc->args = cons(sc, caar(x), sc->args);
-+ }
-+ x = mk_closure(sc, cons(sc, reverse_in_place(sc, sc->NIL, sc->args), cddr(sc->code)), sc->envir);
-+ new_slot_in_env(sc, car(sc->code), x);
-+ sc->code = cddr(sc->code);
-+ sc->args = sc->NIL;
-+ } else {
-+ sc->code = cdr(sc->code);
-+ sc->args = sc->NIL;
-+ }
-+ s_goto(sc,OP_BEGIN);
-+
-+ case OP_LET0AST: /* let* */
-+ if (car(sc->code) == sc->NIL) {
-+ new_frame_in_env(sc, sc->envir);
-+ sc->code = cdr(sc->code);
-+ s_goto(sc,OP_BEGIN);
-+ }
-+ if(!is_pair(car(sc->code)) || !is_pair(caar(sc->code)) || !is_pair(cdaar(sc->code))) {
-+ Error_1(sc,"Bad syntax of binding spec in let* :",car(sc->code));
-+ }
-+ s_save(sc,OP_LET1AST, cdr(sc->code), car(sc->code));
-+ sc->code = cadaar(sc->code);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_LET1AST: /* let* (make new frame) */
-+ new_frame_in_env(sc, sc->envir);
-+ s_goto(sc,OP_LET2AST);
-+
-+ case OP_LET2AST: /* let* (calculate parameters) */
-+ new_slot_in_env(sc, caar(sc->code), sc->value);
-+ sc->code = cdr(sc->code);
-+ if (is_pair(sc->code)) { /* continue */
-+ s_save(sc,OP_LET2AST, sc->args, sc->code);
-+ sc->code = cadar(sc->code);
-+ sc->args = sc->NIL;
-+ s_goto(sc,OP_EVAL);
-+ } else { /* end */
-+ sc->code = sc->args;
-+ sc->args = sc->NIL;
-+ s_goto(sc,OP_BEGIN);
-+ }
-+ default:
-+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
-+ Error_0(sc,sc->strbuff);
-+ }
-+ return sc->T;
-+}
-+
-+static pointer opexe_1(scheme *sc, enum scheme_opcodes op) {
-+ pointer x, y;
-+
-+ switch (op) {
-+ case OP_LET0REC: /* letrec */
-+ new_frame_in_env(sc, sc->envir);
-+ sc->args = sc->NIL;
-+ sc->value = sc->code;
-+ sc->code = car(sc->code);
-+ s_goto(sc,OP_LET1REC);
-+
-+ case OP_LET1REC: /* letrec (calculate parameters) */
-+ sc->args = cons(sc, sc->value, sc->args);
-+ if (is_pair(sc->code)) { /* continue */
-+ if (!is_pair(car(sc->code)) || !is_pair(cdar(sc->code))) {
-+ Error_1(sc, "Bad syntax of binding spec in letrec :",
-+ car(sc->code));
-+ }
-+ s_save(sc,OP_LET1REC, sc->args, cdr(sc->code));
-+ sc->code = cadar(sc->code);
-+ sc->args = sc->NIL;
-+ s_goto(sc,OP_EVAL);
-+ } else { /* end */
-+ sc->args = reverse_in_place(sc, sc->NIL, sc->args);
-+ sc->code = car(sc->args);
-+ sc->args = cdr(sc->args);
-+ s_goto(sc,OP_LET2REC);
-+ }
-+
-+ case OP_LET2REC: /* letrec */
-+ for (x = car(sc->code), y = sc->args; y != sc->NIL; x = cdr(x), y = cdr(y)) {
-+ new_slot_in_env(sc, caar(x), car(y));
-+ }
-+ sc->code = cdr(sc->code);
-+ sc->args = sc->NIL;
-+ s_goto(sc,OP_BEGIN);
-+
-+ case OP_COND0: /* cond */
-+ if (!is_pair(sc->code)) {
-+ Error_0(sc,"syntax error in cond");
-+ }
-+ s_save(sc,OP_COND1, sc->NIL, sc->code);
-+ sc->code = caar(sc->code);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_COND1: /* cond */
-+ if (is_true(sc->value)) {
-+ if ((sc->code = cdar(sc->code)) == sc->NIL) {
-+ s_return(sc,sc->value);
-+ }
-+ if(car(sc->code)==sc->FEED_TO) {
-+ if(!is_pair(cdr(sc->code))) {
-+ Error_0(sc,"syntax error in cond");
-+ }
-+ x=cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL));
-+ sc->code=cons(sc,cadr(sc->code),cons(sc,x,sc->NIL));
-+ s_goto(sc,OP_EVAL);
-+ }
-+ s_goto(sc,OP_BEGIN);
-+ } else {
-+ if ((sc->code = cdr(sc->code)) == sc->NIL) {
-+ s_return(sc,sc->NIL);
-+ } else {
-+ s_save(sc,OP_COND1, sc->NIL, sc->code);
-+ sc->code = caar(sc->code);
-+ s_goto(sc,OP_EVAL);
-+ }
-+ }
-+
-+ case OP_DELAY: /* delay */
-+ x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
-+ typeflag(x)=T_PROMISE;
-+ s_return(sc,x);
-+
-+ case OP_AND0: /* and */
-+ if (sc->code == sc->NIL) {
-+ s_return(sc,sc->T);
-+ }
-+ s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
-+ sc->code = car(sc->code);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_AND1: /* and */
-+ if (is_false(sc->value)) {
-+ s_return(sc,sc->value);
-+ } else if (sc->code == sc->NIL) {
-+ s_return(sc,sc->value);
-+ } else {
-+ s_save(sc,OP_AND1, sc->NIL, cdr(sc->code));
-+ sc->code = car(sc->code);
-+ s_goto(sc,OP_EVAL);
-+ }
-+
-+ case OP_OR0: /* or */
-+ if (sc->code == sc->NIL) {
-+ s_return(sc,sc->F);
-+ }
-+ s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
-+ sc->code = car(sc->code);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_OR1: /* or */
-+ if (is_true(sc->value)) {
-+ s_return(sc,sc->value);
-+ } else if (sc->code == sc->NIL) {
-+ s_return(sc,sc->value);
-+ } else {
-+ s_save(sc,OP_OR1, sc->NIL, cdr(sc->code));
-+ sc->code = car(sc->code);
-+ s_goto(sc,OP_EVAL);
-+ }
-+
-+ case OP_C0STREAM: /* cons-stream */
-+ s_save(sc,OP_C1STREAM, sc->NIL, cdr(sc->code));
-+ sc->code = car(sc->code);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_C1STREAM: /* cons-stream */
-+ sc->args = sc->value; /* save sc->value to register sc->args for gc */
-+ x = mk_closure(sc, cons(sc, sc->NIL, sc->code), sc->envir);
-+ typeflag(x)=T_PROMISE;
-+ s_return(sc,cons(sc, sc->args, x));
-+
-+ case OP_MACRO0: /* macro */
-+ if (is_pair(car(sc->code))) {
-+ x = caar(sc->code);
-+ sc->code = cons(sc, sc->LAMBDA, cons(sc, cdar(sc->code), cdr(sc->code)));
-+ } else {
-+ x = car(sc->code);
-+ sc->code = cadr(sc->code);
-+ }
-+ if (!is_symbol(x)) {
-+ Error_0(sc,"variable is not a symbol");
-+ }
-+ s_save(sc,OP_MACRO1, sc->NIL, x);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_MACRO1: /* macro */
-+ typeflag(sc->value) = T_MACRO;
-+ x = find_slot_in_env(sc, sc->envir, sc->code, 0);
-+ if (x != sc->NIL) {
-+ set_slot_in_env(sc, x, sc->value);
-+ } else {
-+ new_slot_in_env(sc, sc->code, sc->value);
-+ }
-+ s_return(sc,sc->code);
-+
-+ case OP_CASE0: /* case */
-+ s_save(sc,OP_CASE1, sc->NIL, cdr(sc->code));
-+ sc->code = car(sc->code);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_CASE1: /* case */
-+ for (x = sc->code; x != sc->NIL; x = cdr(x)) {
-+ if (!is_pair(y = caar(x))) {
-+ break;
-+ }
-+ for ( ; y != sc->NIL; y = cdr(y)) {
-+ if (eqv(car(y), sc->value)) {
-+ break;
-+ }
-+ }
-+ if (y != sc->NIL) {
-+ break;
-+ }
-+ }
-+ if (x != sc->NIL) {
-+ if (is_pair(caar(x))) {
-+ sc->code = cdar(x);
-+ s_goto(sc,OP_BEGIN);
-+ } else {/* else */
-+ s_save(sc,OP_CASE2, sc->NIL, cdar(x));
-+ sc->code = caar(x);
-+ s_goto(sc,OP_EVAL);
-+ }
-+ } else {
-+ s_return(sc,sc->NIL);
-+ }
-+
-+ case OP_CASE2: /* case */
-+ if (is_true(sc->value)) {
-+ s_goto(sc,OP_BEGIN);
-+ } else {
-+ s_return(sc,sc->NIL);
-+ }
-+
-+ case OP_PAPPLY: /* apply */
-+ sc->code = car(sc->args);
-+ sc->args = list_star(sc,cdr(sc->args));
-+ /*sc->args = cadr(sc->args);*/
-+ s_goto(sc,OP_APPLY);
-+
-+ case OP_PEVAL: /* eval */
-+ if(cdr(sc->args)!=sc->NIL) {
-+ sc->envir=cadr(sc->args);
-+ }
-+ sc->code = car(sc->args);
-+ s_goto(sc,OP_EVAL);
-+
-+ case OP_CONTINUATION: /* call-with-current-continuation */
-+ sc->code = car(sc->args);
-+ sc->args = cons(sc, mk_continuation(sc, sc->dump), sc->NIL);
-+ s_goto(sc,OP_APPLY);
-+
-+ default:
-+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
-+ Error_0(sc,sc->strbuff);
-+ }
-+ return sc->T;
-+}
-+
-+static pointer opexe_2(scheme *sc, enum scheme_opcodes op) {
-+ pointer x;
-+ num v;
-+#if USE_MATH
-+ double dd;
-+#endif
-+
-+ switch (op) {
-+#if USE_MATH
-+ case OP_INEX2EX: /* inexact->exact */
-+ x=car(sc->args);
-+ if(num_is_integer(x)) {
-+ s_return(sc,x);
-+ } else if(modf(rvalue_unchecked(x),&dd)==0.0) {
-+ s_return(sc,mk_integer(sc,ivalue(x)));
-+ } else {
-+ Error_1(sc,"inexact->exact: not integral:",x);
-+ }
-+
-+ case OP_EXP:
-+ x=car(sc->args);
-+ s_return(sc, mk_real(sc, exp(rvalue(x))));
-+
-+ case OP_LOG:
-+ x=car(sc->args);
-+ s_return(sc, mk_real(sc, log(rvalue(x))));
-+
-+ case OP_SIN:
-+ x=car(sc->args);
-+ s_return(sc, mk_real(sc, sin(rvalue(x))));
-+
-+ case OP_COS:
-+ x=car(sc->args);
-+ s_return(sc, mk_real(sc, cos(rvalue(x))));
-+
-+ case OP_TAN:
-+ x=car(sc->args);
-+ s_return(sc, mk_real(sc, tan(rvalue(x))));
-+
-+ case OP_ASIN:
-+ x=car(sc->args);
-+ s_return(sc, mk_real(sc, asin(rvalue(x))));
-+
-+ case OP_ACOS:
-+ x=car(sc->args);
-+ s_return(sc, mk_real(sc, acos(rvalue(x))));
-+
-+ case OP_ATAN:
-+ x=car(sc->args);
-+ if(cdr(sc->args)==sc->NIL) {
-+ s_return(sc, mk_real(sc, atan(rvalue(x))));
-+ } else {
-+ pointer y=cadr(sc->args);
-+ s_return(sc, mk_real(sc, atan2(rvalue(x),rvalue(y))));
-+ }
-+
-+ case OP_SQRT:
-+ x=car(sc->args);
-+ s_return(sc, mk_real(sc, sqrt(rvalue(x))));
-+
-+ case OP_EXPT: {
-+ double result;
-+ int real_result=1;
-+ pointer y=cadr(sc->args);
-+ x=car(sc->args);
-+ if (num_is_integer(x) && num_is_integer(y))
-+ real_result=0;
-+ /* This 'if' is an R5RS compatibility fix. */
-+ /* NOTE: Remove this 'if' fix for R6RS. */
-+ if (rvalue(x) == 0 && rvalue(y) < 0) {
-+ result = 0.0;
-+ } else {
-+ result = pow(rvalue(x),rvalue(y));
-+ }
-+ /* Before returning integer result make sure we can. */
-+ /* If the test fails, result is too big for integer. */
-+ if (!real_result)
-+ {
-+ long result_as_long = (long)result;
-+ if (result != (double)result_as_long)
-+ real_result = 1;
-+ }
-+ if (real_result) {
-+ s_return(sc, mk_real(sc, result));
-+ } else {
-+ s_return(sc, mk_integer(sc, result));
-+ }
-+ }
-+
-+ case OP_FLOOR:
-+ x=car(sc->args);
-+ s_return(sc, mk_real(sc, floor(rvalue(x))));
-+
-+ case OP_CEILING:
-+ x=car(sc->args);
-+ s_return(sc, mk_real(sc, ceil(rvalue(x))));
-+
-+ case OP_TRUNCATE : {
-+ double rvalue_of_x ;
-+ x=car(sc->args);
-+ rvalue_of_x = rvalue(x) ;
-+ if (rvalue_of_x > 0) {
-+ s_return(sc, mk_real(sc, floor(rvalue_of_x)));
-+ } else {
-+ s_return(sc, mk_real(sc, ceil(rvalue_of_x)));
-+ }
-+ }
-+
-+ case OP_ROUND:
-+ x=car(sc->args);
-+ if (num_is_integer(x))
-+ s_return(sc, x);
-+ s_return(sc, mk_real(sc, round_per_R5RS(rvalue(x))));
-+#endif
-+
-+ case OP_ADD: /* + */
-+ v=num_zero;
-+ for (x = sc->args; x != sc->NIL; x = cdr(x)) {
-+ v=num_add(v,nvalue(car(x)));
-+ }
-+ s_return(sc,mk_number(sc, v));
-+
-+ case OP_MUL: /* * */
-+ v=num_one;
-+ for (x = sc->args; x != sc->NIL; x = cdr(x)) {
-+ v=num_mul(v,nvalue(car(x)));
-+ }
-+ s_return(sc,mk_number(sc, v));
-+
-+ case OP_SUB: /* - */
-+ if(cdr(sc->args)==sc->NIL) {
-+ x=sc->args;
-+ v=num_zero;
-+ } else {
-+ x = cdr(sc->args);
-+ v = nvalue(car(sc->args));
-+ }
-+ for (; x != sc->NIL; x = cdr(x)) {
-+ v=num_sub(v,nvalue(car(x)));
-+ }
-+ s_return(sc,mk_number(sc, v));
-+
-+ case OP_DIV: /* / */
-+ if(cdr(sc->args)==sc->NIL) {
-+ x=sc->args;
-+ v=num_one;
-+ } else {
-+ x = cdr(sc->args);
-+ v = nvalue(car(sc->args));
-+ }
-+ for (; x != sc->NIL; x = cdr(x)) {
-+ if (!is_zero_double(rvalue(car(x))))
-+ v=num_div(v,nvalue(car(x)));
-+ else {
-+ Error_0(sc,"/: division by zero");
-+ }
-+ }
-+ s_return(sc,mk_number(sc, v));
-+
-+ case OP_INTDIV: /* quotient */
-+ if(cdr(sc->args)==sc->NIL) {
-+ x=sc->args;
-+ v=num_one;
-+ } else {
-+ x = cdr(sc->args);
-+ v = nvalue(car(sc->args));
-+ }
-+ for (; x != sc->NIL; x = cdr(x)) {
-+ if (ivalue(car(x)) != 0)
-+ v=num_intdiv(v,nvalue(car(x)));
-+ else {
-+ Error_0(sc,"quotient: division by zero");
-+ }
-+ }
-+ s_return(sc,mk_number(sc, v));
-+
-+ case OP_REM: /* remainder */
-+ v = nvalue(car(sc->args));
-+ if (ivalue(cadr(sc->args)) != 0)
-+ v=num_rem(v,nvalue(cadr(sc->args)));
-+ else {
-+ Error_0(sc,"remainder: division by zero");
-+ }
-+ s_return(sc,mk_number(sc, v));
-+
-+ case OP_MOD: /* modulo */
-+ v = nvalue(car(sc->args));
-+ if (ivalue(cadr(sc->args)) != 0)
-+ v=num_mod(v,nvalue(cadr(sc->args)));
-+ else {
-+ Error_0(sc,"modulo: division by zero");
-+ }
-+ s_return(sc,mk_number(sc, v));
-+
-+ case OP_CAR: /* car */
-+ s_return(sc,caar(sc->args));
-+
-+ case OP_CDR: /* cdr */
-+ s_return(sc,cdar(sc->args));
-+
-+ case OP_CONS: /* cons */
-+ cdr(sc->args) = cadr(sc->args);
-+ s_return(sc,sc->args);
-+
-+ case OP_SETCAR: /* set-car! */
-+ if(!is_immutable(car(sc->args))) {
-+ caar(sc->args) = cadr(sc->args);
-+ s_return(sc,car(sc->args));
-+ } else {
-+ Error_0(sc,"set-car!: unable to alter immutable pair");
-+ }
-+
-+ case OP_SETCDR: /* set-cdr! */
-+ if(!is_immutable(car(sc->args))) {
-+ cdar(sc->args) = cadr(sc->args);
-+ s_return(sc,car(sc->args));
-+ } else {
-+ Error_0(sc,"set-cdr!: unable to alter immutable pair");
-+ }
-+
-+ case OP_CHAR2INT: { /* char->integer */
-+ char c;
-+ c=(char)ivalue(car(sc->args));
-+ s_return(sc,mk_integer(sc,(unsigned char)c));
-+ }
-+
-+ case OP_INT2CHAR: { /* integer->char */
-+ unsigned char c;
-+ c=(unsigned char)ivalue(car(sc->args));
-+ s_return(sc,mk_character(sc,(char)c));
-+ }
-+
-+ case OP_CHARUPCASE: {
-+ unsigned char c;
-+ c=(unsigned char)ivalue(car(sc->args));
-+ c=toupper(c);
-+ s_return(sc,mk_character(sc,(char)c));
-+ }
-+
-+ case OP_CHARDNCASE: {
-+ unsigned char c;
-+ c=(unsigned char)ivalue(car(sc->args));
-+ c=tolower(c);
-+ s_return(sc,mk_character(sc,(char)c));
-+ }
-+
-+ case OP_STR2SYM: /* string->symbol */
-+ s_return(sc,mk_symbol(sc,strvalue(car(sc->args))));
-+
-+ case OP_STR2ATOM: /* string->atom */ {
-+ char *s=strvalue(car(sc->args));
-+ long pf = 0;
-+ if(cdr(sc->args)!=sc->NIL) {
-+ /* we know cadr(sc->args) is a natural number */
-+ /* see if it is 2, 8, 10, or 16, or error */
-+ pf = ivalue_unchecked(cadr(sc->args));
-+ if(pf == 16 || pf == 10 || pf == 8 || pf == 2) {
-+ /* base is OK */
-+ }
-+ else {
-+ pf = -1;
-+ }
-+ }
-+ if (pf < 0) {
-+ Error_1(sc, "string->atom: bad base:", cadr(sc->args));
-+ } else if(*s=='#') /* no use of base! */ {
-+ s_return(sc, mk_sharp_const(sc, s+1));
-+ } else {
-+ if (pf == 0 || pf == 10) {
-+ s_return(sc, mk_atom(sc, s));
-+ }
-+ else {
-+ char *ep;
-+ long iv = strtol(s,&ep,(int )pf);
-+ if (*ep == 0) {
-+ s_return(sc, mk_integer(sc, iv));
-+ }
-+ else {
-+ s_return(sc, sc->F);
-+ }
-+ }
-+ }
-+ }
-+
-+ case OP_SYM2STR: /* symbol->string */
-+ x=mk_string(sc,symname(car(sc->args)));
-+ setimmutable(x);
-+ s_return(sc,x);
-+
-+ case OP_ATOM2STR: /* atom->string */ {
-+ long pf = 0;
-+ x=car(sc->args);
-+ if(cdr(sc->args)!=sc->NIL) {
-+ /* we know cadr(sc->args) is a natural number */
-+ /* see if it is 2, 8, 10, or 16, or error */
-+ pf = ivalue_unchecked(cadr(sc->args));
-+ if(is_number(x) && (pf == 16 || pf == 10 || pf == 8 || pf == 2)) {
-+ /* base is OK */
-+ }
-+ else {
-+ pf = -1;
-+ }
-+ }
-+ if (pf < 0) {
-+ Error_1(sc, "atom->string: bad base:", cadr(sc->args));
-+ } else if(is_number(x) || is_character(x) || is_string(x) || is_symbol(x)) {
-+ char *p;
-+ int len;
-+ atom2str(sc,x,(int )pf,&p,&len);
-+ s_return(sc,mk_counted_string(sc,p,len));
-+ } else {
-+ Error_1(sc, "atom->string: not an atom:", x);
-+ }
-+ }
-+
-+ case OP_MKSTRING: { /* make-string */
-+ int fill=' ';
-+ int len;
-+
-+ len=ivalue(car(sc->args));
-+
-+ if(cdr(sc->args)!=sc->NIL) {
-+ fill=charvalue(cadr(sc->args));
-+ }
-+ s_return(sc,mk_empty_string(sc,len,(char)fill));
-+ }
-+
-+ case OP_STRLEN: /* string-length */
-+ s_return(sc,mk_integer(sc,strlength(car(sc->args))));
-+
-+ case OP_STRREF: { /* string-ref */
-+ char *str;
-+ int index;
-+
-+ str=strvalue(car(sc->args));
-+
-+ index=ivalue(cadr(sc->args));
-+
-+ if(index>=strlength(car(sc->args))) {
-+ Error_1(sc,"string-ref: out of bounds:",cadr(sc->args));
-+ }
-+
-+ s_return(sc,mk_character(sc,((unsigned char*)str)[index]));
-+ }
-+
-+ case OP_STRSET: { /* string-set! */
-+ char *str;
-+ int index;
-+ int c;
-+
-+ if(is_immutable(car(sc->args))) {
-+ Error_1(sc,"string-set!: unable to alter immutable string:",car(sc->args));
-+ }
-+ str=strvalue(car(sc->args));
-+
-+ index=ivalue(cadr(sc->args));
-+ if(index>=strlength(car(sc->args))) {
-+ Error_1(sc,"string-set!: out of bounds:",cadr(sc->args));
-+ }
-+
-+ c=charvalue(caddr(sc->args));
-+
-+ str[index]=(char)c;
-+ s_return(sc,car(sc->args));
-+ }
-+
-+ case OP_STRAPPEND: { /* string-append */
-+ /* in 1.29 string-append was in Scheme in init.scm but was too slow */
-+ int len = 0;
-+ pointer newstr;
-+ char *pos;
-+
-+ /* compute needed length for new string */
-+ for (x = sc->args; x != sc->NIL; x = cdr(x)) {
-+ len += strlength(car(x));
-+ }
-+ newstr = mk_empty_string(sc, len, ' ');
-+ /* store the contents of the argument strings into the new string */
-+ for (pos = strvalue(newstr), x = sc->args; x != sc->NIL;
-+ pos += strlength(car(x)), x = cdr(x)) {
-+ memcpy(pos, strvalue(car(x)), strlength(car(x)));
-+ }
-+ s_return(sc, newstr);
-+ }
-+
-+ case OP_SUBSTR: { /* substring */
-+ char *str;
-+ int index0;
-+ int index1;
-+ int len;
-+
-+ str=strvalue(car(sc->args));
-+
-+ index0=ivalue(cadr(sc->args));
-+
-+ if(index0>strlength(car(sc->args))) {
-+ Error_1(sc,"substring: start out of bounds:",cadr(sc->args));
-+ }
-+
-+ if(cddr(sc->args)!=sc->NIL) {
-+ index1=ivalue(caddr(sc->args));
-+ if(index1>strlength(car(sc->args)) || index1<index0) {
-+ Error_1(sc,"substring: end out of bounds:",caddr(sc->args));
-+ }
-+ } else {
-+ index1=strlength(car(sc->args));
-+ }
-+
-+ len=index1-index0;
-+ x=mk_empty_string(sc,len,' ');
-+ memcpy(strvalue(x),str+index0,len);
-+ strvalue(x)[len]=0;
-+
-+ s_return(sc,x);
-+ }
-+
-+ case OP_VECTOR: { /* vector */
-+ int i;
-+ pointer vec;
-+ int len=list_length(sc,sc->args);
-+ if(len<0) {
-+ Error_1(sc,"vector: not a proper list:",sc->args);
-+ }
-+ vec=mk_vector(sc,len);
-+ if(sc->no_memory) { s_return(sc, sc->sink); }
-+ for (x = sc->args, i = 0; is_pair(x); x = cdr(x), i++) {
-+ set_vector_elem(vec,i,car(x));
-+ }
-+ s_return(sc,vec);
-+ }
-+
-+ case OP_MKVECTOR: { /* make-vector */
-+ pointer fill=sc->NIL;
-+ int len;
-+ pointer vec;
-+
-+ len=ivalue(car(sc->args));
-+
-+ if(cdr(sc->args)!=sc->NIL) {
-+ fill=cadr(sc->args);
-+ }
-+ vec=mk_vector(sc,len);
-+ if(sc->no_memory) { s_return(sc, sc->sink); }
-+ if(fill!=sc->NIL) {
-+ fill_vector(vec,fill);
-+ }
-+ s_return(sc,vec);
-+ }
-+
-+ case OP_VECLEN: /* vector-length */
-+ s_return(sc,mk_integer(sc,ivalue(car(sc->args))));
-+
-+ case OP_VECREF: { /* vector-ref */
-+ int index;
-+
-+ index=ivalue(cadr(sc->args));
-+
-+ if(index>=ivalue(car(sc->args))) {
-+ Error_1(sc,"vector-ref: out of bounds:",cadr(sc->args));
-+ }
-+
-+ s_return(sc,vector_elem(car(sc->args),index));
-+ }
-+
-+ case OP_VECSET: { /* vector-set! */
-+ int index;
-+
-+ if(is_immutable(car(sc->args))) {
-+ Error_1(sc,"vector-set!: unable to alter immutable vector:",car(sc->args));
-+ }
-+
-+ index=ivalue(cadr(sc->args));
-+ if(index>=ivalue(car(sc->args))) {
-+ Error_1(sc,"vector-set!: out of bounds:",cadr(sc->args));
-+ }
-+
-+ set_vector_elem(car(sc->args),index,caddr(sc->args));
-+ s_return(sc,car(sc->args));
-+ }
-+
-+ default:
-+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
-+ Error_0(sc,sc->strbuff);
-+ }
-+ return sc->T;
-+}
-+
-+static int is_list(scheme *sc, pointer a)
-+{ return list_length(sc,a) >= 0; }
-+
-+/* Result is:
-+ proper list: length
-+ circular list: -1
-+ not even a pair: -2
-+ dotted list: -2 minus length before dot
-+*/
-+int list_length(scheme *sc, pointer a) {
-+ int i=0;
-+ pointer slow, fast;
-+
-+ slow = fast = a;
-+ while (1)
-+ {
-+ if (fast == sc->NIL)
-+ return i;
-+ if (!is_pair(fast))
-+ return -2 - i;
-+ fast = cdr(fast);
-+ ++i;
-+ if (fast == sc->NIL)
-+ return i;
-+ if (!is_pair(fast))
-+ return -2 - i;
-+ ++i;
-+ fast = cdr(fast);
-+
-+ /* Safe because we would have already returned if `fast'
-+ encountered a non-pair. */
-+ slow = cdr(slow);
-+ if (fast == slow)
-+ {
-+ /* the fast pointer has looped back around and caught up
-+ with the slow pointer, hence the structure is circular,
-+ not of finite length, and therefore not a list */
-+ return -1;
-+ }
-+ }
-+}
-+
-+static pointer opexe_3(scheme *sc, enum scheme_opcodes op) {
-+ pointer x;
-+ num v;
-+ int (*comp_func)(num,num)=0;
-+
-+ switch (op) {
-+ case OP_NOT: /* not */
-+ s_retbool(is_false(car(sc->args)));
-+ case OP_BOOLP: /* boolean? */
-+ s_retbool(car(sc->args) == sc->F || car(sc->args) == sc->T);
-+ case OP_EOFOBJP: /* boolean? */
-+ s_retbool(car(sc->args) == sc->EOF_OBJ);
-+ case OP_NULLP: /* null? */
-+ s_retbool(car(sc->args) == sc->NIL);
-+ case OP_NUMEQ: /* = */
-+ case OP_LESS: /* < */
-+ case OP_GRE: /* > */
-+ case OP_LEQ: /* <= */
-+ case OP_GEQ: /* >= */
-+ switch(op) {
-+ case OP_NUMEQ: comp_func=num_eq; break;
-+ case OP_LESS: comp_func=num_lt; break;
-+ case OP_GRE: comp_func=num_gt; break;
-+ case OP_LEQ: comp_func=num_le; break;
-+ case OP_GEQ: comp_func=num_ge; break;
-+ }
-+ x=sc->args;
-+ v=nvalue(car(x));
-+ x=cdr(x);
-+
-+ for (; x != sc->NIL; x = cdr(x)) {
-+ if(!comp_func(v,nvalue(car(x)))) {
-+ s_retbool(0);
-+ }
-+ v=nvalue(car(x));
-+ }
-+ s_retbool(1);
-+ case OP_SYMBOLP: /* symbol? */
-+ s_retbool(is_symbol(car(sc->args)));
-+ case OP_NUMBERP: /* number? */
-+ s_retbool(is_number(car(sc->args)));
-+ case OP_STRINGP: /* string? */
-+ s_retbool(is_string(car(sc->args)));
-+ case OP_INTEGERP: /* integer? */
-+ s_retbool(is_integer(car(sc->args)));
-+ case OP_REALP: /* real? */
-+ s_retbool(is_number(car(sc->args))); /* All numbers are real */
-+ case OP_CHARP: /* char? */
-+ s_retbool(is_character(car(sc->args)));
-+#if USE_CHAR_CLASSIFIERS
-+ case OP_CHARAP: /* char-alphabetic? */
-+ s_retbool(Cisalpha(ivalue(car(sc->args))));
-+ case OP_CHARNP: /* char-numeric? */
-+ s_retbool(Cisdigit(ivalue(car(sc->args))));
-+ case OP_CHARWP: /* char-whitespace? */
-+ s_retbool(Cisspace(ivalue(car(sc->args))));
-+ case OP_CHARUP: /* char-upper-case? */
-+ s_retbool(Cisupper(ivalue(car(sc->args))));
-+ case OP_CHARLP: /* char-lower-case? */
-+ s_retbool(Cislower(ivalue(car(sc->args))));
-+#endif
-+ case OP_PORTP: /* port? */
-+ s_retbool(is_port(car(sc->args)));
-+ case OP_INPORTP: /* input-port? */
-+ s_retbool(is_inport(car(sc->args)));
-+ case OP_OUTPORTP: /* output-port? */
-+ s_retbool(is_outport(car(sc->args)));
-+ case OP_PROCP: /* procedure? */
-+ /*--
-+ * continuation should be procedure by the example
-+ * (call-with-current-continuation procedure?) ==> #t
-+ * in R^3 report sec. 6.9
-+ */
-+ s_retbool(is_proc(car(sc->args)) || is_closure(car(sc->args))
-+ || is_continuation(car(sc->args)) || is_foreign(car(sc->args)));
-+ case OP_PAIRP: /* pair? */
-+ s_retbool(is_pair(car(sc->args)));
-+ case OP_LISTP: /* list? */
-+ s_retbool(list_length(sc,car(sc->args)) >= 0);
-+
-+ case OP_ENVP: /* environment? */
-+ s_retbool(is_environment(car(sc->args)));
-+ case OP_VECTORP: /* vector? */
-+ s_retbool(is_vector(car(sc->args)));
-+ case OP_EQ: /* eq? */
-+ s_retbool(car(sc->args) == cadr(sc->args));
-+ case OP_EQV: /* eqv? */
-+ s_retbool(eqv(car(sc->args), cadr(sc->args)));
-+ default:
-+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
-+ Error_0(sc,sc->strbuff);
-+ }
-+ return sc->T;
-+}
-+
-+static pointer opexe_4(scheme *sc, enum scheme_opcodes op) {
-+ pointer x, y;
-+
-+ switch (op) {
-+ case OP_FORCE: /* force */
-+ sc->code = car(sc->args);
-+ if (is_promise(sc->code)) {
-+ /* Should change type to closure here */
-+ s_save(sc, OP_SAVE_FORCED, sc->NIL, sc->code);
-+ sc->args = sc->NIL;
-+ s_goto(sc,OP_APPLY);
-+ } else {
-+ s_return(sc,sc->code);
-+ }
-+
-+ case OP_SAVE_FORCED: /* Save forced value replacing promise */
-+ memcpy(sc->code,sc->value,sizeof(struct cell));
-+ s_return(sc,sc->value);
-+
-+ case OP_WRITE: /* write */
-+ case OP_DISPLAY: /* display */
-+ case OP_WRITE_CHAR: /* write-char */
-+ if(is_pair(cdr(sc->args))) {
-+ if(cadr(sc->args)!=sc->outport) {
-+ x=cons(sc,sc->outport,sc->NIL);
-+ s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
-+ sc->outport=cadr(sc->args);
-+ }
-+ }
-+ sc->args = car(sc->args);
-+ if(op==OP_WRITE) {
-+ sc->print_flag = 1;
-+ } else {
-+ sc->print_flag = 0;
-+ }
-+ s_goto(sc,OP_P0LIST);
-+
-+ case OP_NEWLINE: /* newline */
-+ if(is_pair(sc->args)) {
-+ if(car(sc->args)!=sc->outport) {
-+ x=cons(sc,sc->outport,sc->NIL);
-+ s_save(sc,OP_SET_OUTPORT, x, sc->NIL);
-+ sc->outport=car(sc->args);
-+ }
-+ }
-+ putstr(sc, "\n");
-+ s_return(sc,sc->T);
-+
-+ case OP_ERR0: /* error */
-+ sc->retcode=-1;
-+ if (!is_string(car(sc->args))) {
-+ sc->args=cons(sc,mk_string(sc," -- "),sc->args);
-+ setimmutable(car(sc->args));
-+ }
-+ putstr(sc, "Error: ");
-+ putstr(sc, strvalue(car(sc->args)));
-+ sc->args = cdr(sc->args);
-+ s_goto(sc,OP_ERR1);
-+
-+ case OP_ERR1: /* error */
-+ putstr(sc, " ");
-+ if (sc->args != sc->NIL) {
-+ s_save(sc,OP_ERR1, cdr(sc->args), sc->NIL);
-+ sc->args = car(sc->args);
-+ sc->print_flag = 1;
-+ s_goto(sc,OP_P0LIST);
-+ } else {
-+ putstr(sc, "\n");
-+ if(sc->interactive_repl) {
-+ s_goto(sc,OP_T0LVL);
-+ } else {
-+ return sc->NIL;
-+ }
-+ }
-+
-+ case OP_REVERSE: /* reverse */
-+ s_return(sc,reverse(sc, car(sc->args)));
-+
-+ case OP_LIST_STAR: /* list* */
-+ s_return(sc,list_star(sc,sc->args));
-+
-+ case OP_APPEND: /* append */
-+ x = sc->NIL;
-+ y = sc->args;
-+ if (y == x) {
-+ s_return(sc, x);
-+ }
-+
-+ /* cdr() in the while condition is not a typo. If car() */
-+ /* is used (append '() 'a) will return the wrong result.*/
-+ while (cdr(y) != sc->NIL) {
-+ x = revappend(sc, x, car(y));
-+ y = cdr(y);
-+ if (x == sc->F) {
-+ Error_0(sc, "non-list argument to append");
-+ }
-+ }
-+
-+ s_return(sc, reverse_in_place(sc, car(y), x));
-+
-+#if USE_PLIST
-+ case OP_PUT: /* put */
-+ if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
-+ Error_0(sc,"illegal use of put");
-+ }
-+ for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
-+ if (caar(x) == y) {
-+ break;
-+ }
-+ }
-+ if (x != sc->NIL)
-+ cdar(x) = caddr(sc->args);
-+ else
-+ symprop(car(sc->args)) = cons(sc, cons(sc, y, caddr(sc->args)),
-+ symprop(car(sc->args)));
-+ s_return(sc,sc->T);
-+
-+ case OP_GET: /* get */
-+ if (!hasprop(car(sc->args)) || !hasprop(cadr(sc->args))) {
-+ Error_0(sc,"illegal use of get");
-+ }
-+ for (x = symprop(car(sc->args)), y = cadr(sc->args); x != sc->NIL; x = cdr(x)) {
-+ if (caar(x) == y) {
-+ break;
-+ }
-+ }
-+ if (x != sc->NIL) {
-+ s_return(sc,cdar(x));
-+ } else {
-+ s_return(sc,sc->NIL);
-+ }
-+#endif /* USE_PLIST */
-+ case OP_QUIT: /* quit */
-+ if(is_pair(sc->args)) {
-+ sc->retcode=ivalue(car(sc->args));
-+ }
-+ return (sc->NIL);
-+
-+ case OP_GC: /* gc */
-+ gc(sc, sc->NIL, sc->NIL);
-+ s_return(sc,sc->T);
-+
-+ case OP_GCVERB: /* gc-verbose */
-+ { int was = sc->gc_verbose;
-+
-+ sc->gc_verbose = (car(sc->args) != sc->F);
-+ s_retbool(was);
-+ }
-+
-+ case OP_NEWSEGMENT: /* new-segment */
-+ if (!is_pair(sc->args) || !is_number(car(sc->args))) {
-+ Error_0(sc,"new-segment: argument must be a number");
-+ }
-+ alloc_cellseg(sc, (int) ivalue(car(sc->args)));
-+ s_return(sc,sc->T);
-+
-+ case OP_OBLIST: /* oblist */
-+ s_return(sc, oblist_all_symbols(sc));
-+
-+ case OP_CURR_INPORT: /* current-input-port */
-+ s_return(sc,sc->inport);
-+
-+ case OP_CURR_OUTPORT: /* current-output-port */
-+ s_return(sc,sc->outport);
-+
-+ case OP_OPEN_INFILE: /* open-input-file */
-+ case OP_OPEN_OUTFILE: /* open-output-file */
-+ case OP_OPEN_INOUTFILE: /* open-input-output-file */ {
-+ int prop=0;
-+ pointer p;
-+ switch(op) {
-+ case OP_OPEN_INFILE: prop=port_input; break;
-+ case OP_OPEN_OUTFILE: prop=port_output; break;
-+ case OP_OPEN_INOUTFILE: prop=port_input|port_output; break;
-+ }
-+ p=port_from_filename(sc,strvalue(car(sc->args)),prop);
-+ if(p==sc->NIL) {
-+ s_return(sc,sc->F);
-+ }
-+ s_return(sc,p);
-+ }
-+
-+#if USE_STRING_PORTS
-+ case OP_OPEN_INSTRING: /* open-input-string */
-+ case OP_OPEN_INOUTSTRING: /* open-input-output-string */ {
-+ int prop=0;
-+ pointer p;
-+ switch(op) {
-+ case OP_OPEN_INSTRING: prop=port_input; break;
-+ case OP_OPEN_INOUTSTRING: prop=port_input|port_output; break;
-+ }
-+ p=port_from_string(sc, strvalue(car(sc->args)),
-+ strvalue(car(sc->args))+strlength(car(sc->args)), prop);
-+ if(p==sc->NIL) {
-+ s_return(sc,sc->F);
-+ }
-+ s_return(sc,p);
-+ }
-+ case OP_OPEN_OUTSTRING: /* open-output-string */ {
-+ pointer p;
-+ if(car(sc->args)==sc->NIL) {
-+ p=port_from_scratch(sc);
-+ if(p==sc->NIL) {
-+ s_return(sc,sc->F);
-+ }
-+ } else {
-+ p=port_from_string(sc, strvalue(car(sc->args)),
-+ strvalue(car(sc->args))+strlength(car(sc->args)),
-+ port_output);
-+ if(p==sc->NIL) {
-+ s_return(sc,sc->F);
-+ }
-+ }
-+ s_return(sc,p);
-+ }
-+ case OP_GET_OUTSTRING: /* get-output-string */ {
-+ port *p;
-+
-+ if ((p=car(sc->args)->_object._port)->kind&port_string) {
-+ off_t size;
-+ char *str;
-+
-+ size=p->rep.string.curr-p->rep.string.start+1;
-+ str=sc->malloc(size);
-+ if(str != NULL) {
-+ pointer s;
-+
-+ memcpy(str,p->rep.string.start,size-1);
-+ str[size-1]='\0';
-+ s=mk_string(sc,str);
-+ sc->free(str);
-+ s_return(sc,s);
-+ }
-+ }
-+ s_return(sc,sc->F);
-+ }
-+#endif
-+
-+ case OP_CLOSE_INPORT: /* close-input-port */
-+ port_close(sc,car(sc->args),port_input);
-+ s_return(sc,sc->T);
-+
-+ case OP_CLOSE_OUTPORT: /* close-output-port */
-+ port_close(sc,car(sc->args),port_output);
-+ s_return(sc,sc->T);
-+
-+ case OP_INT_ENV: /* interaction-environment */
-+ s_return(sc,sc->global_env);
-+
-+ case OP_CURR_ENV: /* current-environment */
-+ s_return(sc,sc->envir);
-+
-+ }
-+ return sc->T;
-+}
-+
-+static pointer opexe_5(scheme *sc, enum scheme_opcodes op) {
-+ pointer x;
-+
-+ if(sc->nesting!=0) {
-+ int n=sc->nesting;
-+ sc->nesting=0;
-+ sc->retcode=-1;
-+ Error_1(sc,"unmatched parentheses:",mk_integer(sc,n));
-+ }
-+
-+ switch (op) {
-+ /* ========== reading part ========== */
-+ case OP_READ:
-+ if(!is_pair(sc->args)) {
-+ s_goto(sc,OP_READ_INTERNAL);
-+ }
-+ if(!is_inport(car(sc->args))) {
-+ Error_1(sc,"read: not an input port:",car(sc->args));
-+ }
-+ if(car(sc->args)==sc->inport) {
-+ s_goto(sc,OP_READ_INTERNAL);
-+ }
-+ x=sc->inport;
-+ sc->inport=car(sc->args);
-+ x=cons(sc,x,sc->NIL);
-+ s_save(sc,OP_SET_INPORT, x, sc->NIL);
-+ s_goto(sc,OP_READ_INTERNAL);
-+
-+ case OP_READ_CHAR: /* read-char */
-+ case OP_PEEK_CHAR: /* peek-char */ {
-+ int c;
-+ if(is_pair(sc->args)) {
-+ if(car(sc->args)!=sc->inport) {
-+ x=sc->inport;
-+ x=cons(sc,x,sc->NIL);
-+ s_save(sc,OP_SET_INPORT, x, sc->NIL);
-+ sc->inport=car(sc->args);
-+ }
-+ }
-+ c=inchar(sc);
-+ if(c==EOF) {
-+ s_return(sc,sc->EOF_OBJ);
-+ }
-+ if(sc->op==OP_PEEK_CHAR) {
-+ backchar(sc,c);
-+ }
-+ s_return(sc,mk_character(sc,c));
-+ }
-+
-+ case OP_CHAR_READY: /* char-ready? */ {
-+ pointer p=sc->inport;
-+ int res;
-+ if(is_pair(sc->args)) {
-+ p=car(sc->args);
-+ }
-+ res=p->_object._port->kind&port_string;
-+ s_retbool(res);
-+ }
-+
-+ case OP_SET_INPORT: /* set-input-port */
-+ sc->inport=car(sc->args);
-+ s_return(sc,sc->value);
-+
-+ case OP_SET_OUTPORT: /* set-output-port */
-+ sc->outport=car(sc->args);
-+ s_return(sc,sc->value);
-+
-+ case OP_RDSEXPR:
-+ switch (sc->tok) {
-+ case TOK_EOF:
-+ s_return(sc,sc->EOF_OBJ);
-+ /* NOTREACHED */
-+/*
-+ * Commented out because we now skip comments in the scanner
-+ *
-+ case TOK_COMMENT: {
-+ int c;
-+ while ((c=inchar(sc)) != '\n' && c!=EOF)
-+ ;
-+ sc->tok = token(sc);
-+ s_goto(sc,OP_RDSEXPR);
-+ }
-+*/
-+ case TOK_VEC:
-+ s_save(sc,OP_RDVEC,sc->NIL,sc->NIL);
-+ /* fall through */
-+ case TOK_LPAREN:
-+ sc->tok = token(sc);
-+ if (sc->tok == TOK_RPAREN) {
-+ s_return(sc,sc->NIL);
-+ } else if (sc->tok == TOK_DOT) {
-+ Error_0(sc,"syntax error: illegal dot expression");
-+ } else {
-+ sc->nesting_stack[sc->file_i]++;
-+ s_save(sc,OP_RDLIST, sc->NIL, sc->NIL);
-+ s_goto(sc,OP_RDSEXPR);
-+ }
-+ case TOK_QUOTE:
-+ s_save(sc,OP_RDQUOTE, sc->NIL, sc->NIL);
-+ sc->tok = token(sc);
-+ s_goto(sc,OP_RDSEXPR);
-+ case TOK_BQUOTE:
-+ sc->tok = token(sc);
-+ if(sc->tok==TOK_VEC) {
-+ s_save(sc,OP_RDQQUOTEVEC, sc->NIL, sc->NIL);
-+ sc->tok=TOK_LPAREN;
-+ s_goto(sc,OP_RDSEXPR);
-+ } else {
-+ s_save(sc,OP_RDQQUOTE, sc->NIL, sc->NIL);
-+ }
-+ s_goto(sc,OP_RDSEXPR);
-+ case TOK_COMMA:
-+ s_save(sc,OP_RDUNQUOTE, sc->NIL, sc->NIL);
-+ sc->tok = token(sc);
-+ s_goto(sc,OP_RDSEXPR);
-+ case TOK_ATMARK:
-+ s_save(sc,OP_RDUQTSP, sc->NIL, sc->NIL);
-+ sc->tok = token(sc);
-+ s_goto(sc,OP_RDSEXPR);
-+ case TOK_ATOM:
-+ s_return(sc,mk_atom(sc, readstr_upto(sc, DELIMITERS)));
-+ case TOK_DQUOTE:
-+ x=readstrexp(sc);
-+ if(x==sc->F) {
-+ Error_0(sc,"Error reading string");
-+ }
-+ setimmutable(x);
-+ s_return(sc,x);
-+ case TOK_SHARP: {
-+ pointer f=find_slot_in_env(sc,sc->envir,sc->SHARP_HOOK,1);
-+ if(f==sc->NIL) {
-+ Error_0(sc,"undefined sharp expression");
-+ } else {
-+ sc->code=cons(sc,slot_value_in_env(f),sc->NIL);
-+ s_goto(sc,OP_EVAL);
-+ }
-+ }
-+ case TOK_SHARP_CONST:
-+ if ((x = mk_sharp_const(sc, readstr_upto(sc, DELIMITERS))) == sc->NIL) {
-+ Error_0(sc,"undefined sharp expression");
-+ } else {
-+ s_return(sc,x);
-+ }
-+ default:
-+ Error_0(sc,"syntax error: illegal token");
-+ }
-+ break;
-+
-+ case OP_RDLIST: {
-+ sc->args = cons(sc, sc->value, sc->args);
-+ sc->tok = token(sc);
-+/* We now skip comments in the scanner
-+ while (sc->tok == TOK_COMMENT) {
-+ int c;
-+ while ((c=inchar(sc)) != '\n' && c!=EOF)
-+ ;
-+ sc->tok = token(sc);
-+ }
-+*/
-+ if (sc->tok == TOK_EOF)
-+ { s_return(sc,sc->EOF_OBJ); }
-+ else if (sc->tok == TOK_RPAREN) {
-+ int c = inchar(sc);
-+ if (c != '\n')
-+ backchar(sc,c);
-+#if SHOW_ERROR_LINE
-+ else if (sc->load_stack[sc->file_i].kind & port_file)
-+ sc->load_stack[sc->file_i].rep.stdio.curr_line++;
-+#endif
-+ sc->nesting_stack[sc->file_i]--;
-+ s_return(sc,reverse_in_place(sc, sc->NIL, sc->args));
-+ } else if (sc->tok == TOK_DOT) {
-+ s_save(sc,OP_RDDOT, sc->args, sc->NIL);
-+ sc->tok = token(sc);
-+ s_goto(sc,OP_RDSEXPR);
-+ } else {
-+ s_save(sc,OP_RDLIST, sc->args, sc->NIL);;
-+ s_goto(sc,OP_RDSEXPR);
-+ }
-+ }
-+
-+ case OP_RDDOT:
-+ if (token(sc) != TOK_RPAREN) {
-+ Error_0(sc,"syntax error: illegal dot expression");
-+ } else {
-+ sc->nesting_stack[sc->file_i]--;
-+ s_return(sc,reverse_in_place(sc, sc->value, sc->args));
-+ }
-+
-+ case OP_RDQUOTE:
-+ s_return(sc,cons(sc, sc->QUOTE, cons(sc, sc->value, sc->NIL)));
-+
-+ case OP_RDQQUOTE:
-+ s_return(sc,cons(sc, sc->QQUOTE, cons(sc, sc->value, sc->NIL)));
-+
-+ case OP_RDQQUOTEVEC:
-+ s_return(sc,cons(sc, mk_symbol(sc,"apply"),
-+ cons(sc, mk_symbol(sc,"vector"),
-+ cons(sc,cons(sc, sc->QQUOTE,
-+ cons(sc,sc->value,sc->NIL)),
-+ sc->NIL))));
-+
-+ case OP_RDUNQUOTE:
-+ s_return(sc,cons(sc, sc->UNQUOTE, cons(sc, sc->value, sc->NIL)));
-+
-+ case OP_RDUQTSP:
-+ s_return(sc,cons(sc, sc->UNQUOTESP, cons(sc, sc->value, sc->NIL)));
-+
-+ case OP_RDVEC:
-+ /*sc->code=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
-+ s_goto(sc,OP_EVAL); Cannot be quoted*/
-+ /*x=cons(sc,mk_proc(sc,OP_VECTOR),sc->value);
-+ s_return(sc,x); Cannot be part of pairs*/
-+ /*sc->code=mk_proc(sc,OP_VECTOR);
-+ sc->args=sc->value;
-+ s_goto(sc,OP_APPLY);*/
-+ sc->args=sc->value;
-+ s_goto(sc,OP_VECTOR);
-+
-+ /* ========== printing part ========== */
-+ case OP_P0LIST:
-+ if(is_vector(sc->args)) {
-+ putstr(sc,"#(");
-+ sc->args=cons(sc,sc->args,mk_integer(sc,0));
-+ s_goto(sc,OP_PVECFROM);
-+ } else if(is_environment(sc->args)) {
-+ putstr(sc,"#<ENVIRONMENT>");
-+ s_return(sc,sc->T);
-+ } else if (!is_pair(sc->args)) {
-+ printatom(sc, sc->args, sc->print_flag);
-+ s_return(sc,sc->T);
-+ } else if (car(sc->args) == sc->QUOTE && ok_abbrev(cdr(sc->args))) {
-+ putstr(sc, "'");
-+ sc->args = cadr(sc->args);
-+ s_goto(sc,OP_P0LIST);
-+ } else if (car(sc->args) == sc->QQUOTE && ok_abbrev(cdr(sc->args))) {
-+ putstr(sc, "`");
-+ sc->args = cadr(sc->args);
-+ s_goto(sc,OP_P0LIST);
-+ } else if (car(sc->args) == sc->UNQUOTE && ok_abbrev(cdr(sc->args))) {
-+ putstr(sc, ",");
-+ sc->args = cadr(sc->args);
-+ s_goto(sc,OP_P0LIST);
-+ } else if (car(sc->args) == sc->UNQUOTESP && ok_abbrev(cdr(sc->args))) {
-+ putstr(sc, ",@");
-+ sc->args = cadr(sc->args);
-+ s_goto(sc,OP_P0LIST);
-+ } else {
-+ putstr(sc, "(");
-+ s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
-+ sc->args = car(sc->args);
-+ s_goto(sc,OP_P0LIST);
-+ }
-+
-+ case OP_P1LIST:
-+ if (is_pair(sc->args)) {
-+ s_save(sc,OP_P1LIST, cdr(sc->args), sc->NIL);
-+ putstr(sc, " ");
-+ sc->args = car(sc->args);
-+ s_goto(sc,OP_P0LIST);
-+ } else if(is_vector(sc->args)) {
-+ s_save(sc,OP_P1LIST,sc->NIL,sc->NIL);
-+ putstr(sc, " . ");
-+ s_goto(sc,OP_P0LIST);
-+ } else {
-+ if (sc->args != sc->NIL) {
-+ putstr(sc, " . ");
-+ printatom(sc, sc->args, sc->print_flag);
-+ }
-+ putstr(sc, ")");
-+ s_return(sc,sc->T);
-+ }
-+ case OP_PVECFROM: {
-+ int i=ivalue_unchecked(cdr(sc->args));
-+ pointer vec=car(sc->args);
-+ int len=ivalue_unchecked(vec);
-+ if(i==len) {
-+ putstr(sc,")");
-+ s_return(sc,sc->T);
-+ } else {
-+ pointer elem=vector_elem(vec,i);
-+ ivalue_unchecked(cdr(sc->args))=i+1;
-+ s_save(sc,OP_PVECFROM, sc->args, sc->NIL);
-+ sc->args=elem;
-+ if (i > 0)
-+ putstr(sc," ");
-+ s_goto(sc,OP_P0LIST);
-+ }
-+ }
-+
-+ default:
-+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
-+ Error_0(sc,sc->strbuff);
-+
-+ }
-+ return sc->T;
-+}
-+
-+static pointer opexe_6(scheme *sc, enum scheme_opcodes op) {
-+ pointer x, y;
-+ long v;
-+
-+ switch (op) {
-+ case OP_LIST_LENGTH: /* length */ /* a.k */
-+ v=list_length(sc,car(sc->args));
-+ if(v<0) {
-+ Error_1(sc,"length: not a list:",car(sc->args));
-+ }
-+ s_return(sc,mk_integer(sc, v));
-+
-+ case OP_ASSQ: /* assq */ /* a.k */
-+ x = car(sc->args);
-+ for (y = cadr(sc->args); is_pair(y); y = cdr(y)) {
-+ if (!is_pair(car(y))) {
-+ Error_0(sc,"unable to handle non pair element");
-+ }
-+ if (x == caar(y))
-+ break;
-+ }
-+ if (is_pair(y)) {
-+ s_return(sc,car(y));
-+ } else {
-+ s_return(sc,sc->F);
-+ }
-+
-+
-+ case OP_GET_CLOSURE: /* get-closure-code */ /* a.k */
-+ sc->args = car(sc->args);
-+ if (sc->args == sc->NIL) {
-+ s_return(sc,sc->F);
-+ } else if (is_closure(sc->args)) {
-+ s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
-+ } else if (is_macro(sc->args)) {
-+ s_return(sc,cons(sc, sc->LAMBDA, closure_code(sc->value)));
-+ } else {
-+ s_return(sc,sc->F);
-+ }
-+ case OP_CLOSUREP: /* closure? */
-+ /*
-+ * Note, macro object is also a closure.
-+ * Therefore, (closure? <#MACRO>) ==> #t
-+ */
-+ s_retbool(is_closure(car(sc->args)));
-+ case OP_MACROP: /* macro? */
-+ s_retbool(is_macro(car(sc->args)));
-+ default:
-+ snprintf(sc->strbuff,STRBUFFSIZE,"%d: illegal operator", sc->op);
-+ Error_0(sc,sc->strbuff);
-+ }
-+ return sc->T; /* NOTREACHED */
-+}
-+
-+typedef pointer (*dispatch_func)(scheme *, enum scheme_opcodes);
-+
-+typedef int (*test_predicate)(pointer);
-+static int is_any(pointer p) { return 1;}
-+
-+static int is_nonneg(pointer p) {
-+ return ivalue(p)>=0 && is_integer(p);
-+}
-+
-+/* Correspond carefully with following defines! */
-+static struct {
-+ test_predicate fct;
-+ const char *kind;
-+} tests[]={
-+ {0,0}, /* unused */
-+ {is_any, 0},
-+ {is_string, "string"},
-+ {is_symbol, "symbol"},
-+ {is_port, "port"},
-+ {is_inport,"input port"},
-+ {is_outport,"output port"},
-+ {is_environment, "environment"},
-+ {is_pair, "pair"},
-+ {0, "pair or '()"},
-+ {is_character, "character"},
-+ {is_vector, "vector"},
-+ {is_number, "number"},
-+ {is_integer, "integer"},
-+ {is_nonneg, "non-negative integer"}
-+};
-+
-+#define TST_NONE 0
-+#define TST_ANY "\001"
-+#define TST_STRING "\002"
-+#define TST_SYMBOL "\003"
-+#define TST_PORT "\004"
-+#define TST_INPORT "\005"
-+#define TST_OUTPORT "\006"
-+#define TST_ENVIRONMENT "\007"
-+#define TST_PAIR "\010"
-+#define TST_LIST "\011"
-+#define TST_CHAR "\012"
-+#define TST_VECTOR "\013"
-+#define TST_NUMBER "\014"
-+#define TST_INTEGER "\015"
-+#define TST_NATURAL "\016"
-+
-+typedef struct {
-+ dispatch_func func;
-+ char *name;
-+ int min_arity;
-+ int max_arity;
-+ char *arg_tests_encoding;
-+} op_code_info;
-+
-+#define INF_ARG 0xffff
-+
-+static op_code_info dispatch_table[]= {
-+#define _OP_DEF(A,B,C,D,E,OP) {A,B,C,D,E},
-+#include "opdefines.h"
-+ { 0 }
-+};
-+
-+static const char *procname(pointer x) {
-+ int n=procnum(x);
-+ const char *name=dispatch_table[n].name;
-+ if(name==0) {
-+ name="ILLEGAL!";
-+ }
-+ return name;
-+}
-+
-+/* kernel of this interpreter */
-+static void Eval_Cycle(scheme *sc, enum scheme_opcodes op) {
-+ sc->op = op;
-+ for (;;) {
-+ op_code_info *pcd=dispatch_table+sc->op;
-+ if (pcd->name!=0) { /* if built-in function, check arguments */
-+ char msg[STRBUFFSIZE];
-+ int ok=1;
-+ int n=list_length(sc,sc->args);
-+
-+ /* Check number of arguments */
-+ if(n<pcd->min_arity) {
-+ ok=0;
-+ snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
-+ pcd->name,
-+ pcd->min_arity==pcd->max_arity?"":" at least",
-+ pcd->min_arity);
-+ }
-+ if(ok && n>pcd->max_arity) {
-+ ok=0;
-+ snprintf(msg, STRBUFFSIZE, "%s: needs%s %d argument(s)",
-+ pcd->name,
-+ pcd->min_arity==pcd->max_arity?"":" at most",
-+ pcd->max_arity);
-+ }
-+ if(ok) {
-+ if(pcd->arg_tests_encoding!=0) {
-+ int i=0;
-+ int j;
-+ const char *t=pcd->arg_tests_encoding;
-+ pointer arglist=sc->args;
-+ do {
-+ pointer arg=car(arglist);
-+ j=(int)t[0];
-+ if(j==TST_LIST[0]) {
-+ if(arg!=sc->NIL && !is_pair(arg)) break;
-+ } else {
-+ if(!tests[j].fct(arg)) break;
-+ }
-+
-+ if(t[1]!=0) {/* last test is replicated as necessary */
-+ t++;
-+ }
-+ arglist=cdr(arglist);
-+ i++;
-+ } while(i<n);
-+ if(i<n) {
-+ ok=0;
-+ snprintf(msg, STRBUFFSIZE, "%s: argument %d must be: %s",
-+ pcd->name,
-+ i+1,
-+ tests[j].kind);
-+ }
-+ }
-+ }
-+ if(!ok) {
-+ if(_Error_1(sc,msg,0)==sc->NIL) {
-+ return;
-+ }
-+ pcd=dispatch_table+sc->op;
-+ }
-+ }
-+ ok_to_freely_gc(sc);
-+ if (pcd->func(sc, (enum scheme_opcodes)sc->op) == sc->NIL) {
-+ return;
-+ }
-+ if(sc->no_memory) {
-+ fprintf(stderr,"No memory!\n");
-+ return;
-+ }
-+ }
-+}
-+
-+/* ========== Initialization of internal keywords ========== */
-+
-+static void assign_syntax(scheme *sc, char *name) {
-+ pointer x;
-+
-+ x = oblist_add_by_name(sc, name);
-+ typeflag(x) |= T_SYNTAX;
-+}
-+
-+static void assign_proc(scheme *sc, enum scheme_opcodes op, char *name) {
-+ pointer x, y;
-+
-+ x = mk_symbol(sc, name);
-+ y = mk_proc(sc,op);
-+ new_slot_in_env(sc, x, y);
-+}
-+
-+static pointer mk_proc(scheme *sc, enum scheme_opcodes op) {
-+ pointer y;
-+
-+ y = get_cell(sc, sc->NIL, sc->NIL);
-+ typeflag(y) = (T_PROC | T_ATOM);
-+ ivalue_unchecked(y) = (long) op;
-+ set_num_integer(y);
-+ return y;
-+}
-+
-+/* Hard-coded for the given keywords. Remember to rewrite if more are added! */
-+static int syntaxnum(pointer p) {
-+ const char *s=strvalue(car(p));
-+ switch(strlength(car(p))) {
-+ case 2:
-+ if(s[0]=='i') return OP_IF0; /* if */
-+ else return OP_OR0; /* or */
-+ case 3:
-+ if(s[0]=='a') return OP_AND0; /* and */
-+ else return OP_LET0; /* let */
-+ case 4:
-+ switch(s[3]) {
-+ case 'e': return OP_CASE0; /* case */
-+ case 'd': return OP_COND0; /* cond */
-+ case '*': return OP_LET0AST; /* let* */
-+ default: return OP_SET0; /* set! */
-+ }
-+ case 5:
-+ switch(s[2]) {
-+ case 'g': return OP_BEGIN; /* begin */
-+ case 'l': return OP_DELAY; /* delay */
-+ case 'c': return OP_MACRO0; /* macro */
-+ default: return OP_QUOTE; /* quote */
-+ }
-+ case 6:
-+ switch(s[2]) {
-+ case 'm': return OP_LAMBDA; /* lambda */
-+ case 'f': return OP_DEF0; /* define */
-+ default: return OP_LET0REC; /* letrec */
-+ }
-+ default:
-+ return OP_C0STREAM; /* cons-stream */
-+ }
-+}
-+
-+/* initialization of TinyScheme */
-+#if USE_INTERFACE
-+INTERFACE static pointer s_cons(scheme *sc, pointer a, pointer b) {
-+ return cons(sc,a,b);
-+}
-+INTERFACE static pointer s_immutable_cons(scheme *sc, pointer a, pointer b) {
-+ return immutable_cons(sc,a,b);
-+}
-+
-+static struct scheme_interface vtbl ={
-+ scheme_define,
-+ s_cons,
-+ s_immutable_cons,
-+ reserve_cells,
-+ mk_integer,
-+ mk_real,
-+ mk_symbol,
-+ gensym,
-+ mk_string,
-+ mk_counted_string,
-+ mk_character,
-+ mk_vector,
-+ mk_foreign_func,
-+ putstr,
-+ putcharacter,
-+
-+ is_string,
-+ string_value,
-+ is_number,
-+ nvalue,
-+ ivalue,
-+ rvalue,
-+ is_integer,
-+ is_real,
-+ is_character,
-+ charvalue,
-+ is_list,
-+ is_vector,
-+ list_length,
-+ ivalue,
-+ fill_vector,
-+ vector_elem,
-+ set_vector_elem,
-+ is_port,
-+ is_pair,
-+ pair_car,
-+ pair_cdr,
-+ set_car,
-+ set_cdr,
-+
-+ is_symbol,
-+ symname,
-+
-+ is_syntax,
-+ is_proc,
-+ is_foreign,
-+ syntaxname,
-+ is_closure,
-+ is_macro,
-+ closure_code,
-+ closure_env,
-+
-+ is_continuation,
-+ is_promise,
-+ is_environment,
-+ is_immutable,
-+ setimmutable,
-+
-+ scheme_load_file,
-+ scheme_load_string
-+};
-+#endif
-+
-+scheme *scheme_init_new() {
-+ scheme *sc=(scheme*)malloc(sizeof(scheme));
-+ if(!scheme_init(sc)) {
-+ free(sc);
-+ return 0;
-+ } else {
-+ return sc;
-+ }
-+}
-+
-+scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free) {
-+ scheme *sc=(scheme*)malloc(sizeof(scheme));
-+ if(!scheme_init_custom_alloc(sc,malloc,free)) {
-+ free(sc);
-+ return 0;
-+ } else {
-+ return sc;
-+ }
-+}
-+
-+
-+int scheme_init(scheme *sc) {
-+ return scheme_init_custom_alloc(sc,malloc,free);
-+}
-+
-+int scheme_init_custom_alloc(scheme *sc, func_alloc malloc, func_dealloc free) {
-+ int i, n=sizeof(dispatch_table)/sizeof(dispatch_table[0]);
-+ pointer x;
-+
-+ num_zero.is_fixnum=1;
-+ num_zero.value.ivalue=0;
-+ num_one.is_fixnum=1;
-+ num_one.value.ivalue=1;
-+
-+#if USE_INTERFACE
-+ sc->vptr=&vtbl;
-+#endif
-+ sc->gensym_cnt=0;
-+ sc->malloc=malloc;
-+ sc->free=free;
-+ sc->last_cell_seg = -1;
-+ sc->sink = &sc->_sink;
-+ sc->NIL = &sc->_NIL;
-+ sc->T = &sc->_HASHT;
-+ sc->F = &sc->_HASHF;
-+ sc->EOF_OBJ=&sc->_EOF_OBJ;
-+ sc->free_cell = &sc->_NIL;
-+ sc->fcells = 0;
-+ sc->no_memory=0;
-+ sc->inport=sc->NIL;
-+ sc->outport=sc->NIL;
-+ sc->save_inport=sc->NIL;
-+ sc->loadport=sc->NIL;
-+ sc->nesting=0;
-+ sc->interactive_repl=0;
-+
-+ if (alloc_cellseg(sc,FIRST_CELLSEGS) != FIRST_CELLSEGS) {
-+ sc->no_memory=1;
-+ return 0;
-+ }
-+ sc->gc_verbose = 0;
-+ dump_stack_initialize(sc);
-+ sc->code = sc->NIL;
-+ sc->tracing=0;
-+
-+ /* init sc->NIL */
-+ typeflag(sc->NIL) = (T_ATOM | MARK);
-+ car(sc->NIL) = cdr(sc->NIL) = sc->NIL;
-+ /* init T */
-+ typeflag(sc->T) = (T_ATOM | MARK);
-+ car(sc->T) = cdr(sc->T) = sc->T;
-+ /* init F */
-+ typeflag(sc->F) = (T_ATOM | MARK);
-+ car(sc->F) = cdr(sc->F) = sc->F;
-+ /* init sink */
-+ typeflag(sc->sink) = (T_PAIR | MARK);
-+ car(sc->sink) = sc->NIL;
-+ /* init c_nest */
-+ sc->c_nest = sc->NIL;
-+
-+ sc->oblist = oblist_initial_value(sc);
-+ /* init global_env */
-+ new_frame_in_env(sc, sc->NIL);
-+ sc->global_env = sc->envir;
-+ /* init else */
-+ x = mk_symbol(sc,"else");
-+ new_slot_in_env(sc, x, sc->T);
-+
-+ assign_syntax(sc, "lambda");
-+ assign_syntax(sc, "quote");
-+ assign_syntax(sc, "define");
-+ assign_syntax(sc, "if");
-+ assign_syntax(sc, "begin");
-+ assign_syntax(sc, "set!");
-+ assign_syntax(sc, "let");
-+ assign_syntax(sc, "let*");
-+ assign_syntax(sc, "letrec");
-+ assign_syntax(sc, "cond");
-+ assign_syntax(sc, "delay");
-+ assign_syntax(sc, "and");
-+ assign_syntax(sc, "or");
-+ assign_syntax(sc, "cons-stream");
-+ assign_syntax(sc, "macro");
-+ assign_syntax(sc, "case");
-+
-+ for(i=0; i<n; i++) {
-+ if(dispatch_table[i].name!=0) {
-+ assign_proc(sc, (enum scheme_opcodes)i, dispatch_table[i].name);
-+ }
-+ }
-+
-+ /* initialization of global pointers to special symbols */
-+ sc->LAMBDA = mk_symbol(sc, "lambda");
-+ sc->QUOTE = mk_symbol(sc, "quote");
-+ sc->QQUOTE = mk_symbol(sc, "quasiquote");
-+ sc->UNQUOTE = mk_symbol(sc, "unquote");
-+ sc->UNQUOTESP = mk_symbol(sc, "unquote-splicing");
-+ sc->FEED_TO = mk_symbol(sc, "=>");
-+ sc->COLON_HOOK = mk_symbol(sc,"*colon-hook*");
-+ sc->ERROR_HOOK = mk_symbol(sc, "*error-hook*");
-+ sc->SHARP_HOOK = mk_symbol(sc, "*sharp-hook*");
-+ sc->COMPILE_HOOK = mk_symbol(sc, "*compile-hook*");
-+
-+ return !sc->no_memory;
-+}
-+
-+void scheme_set_input_port_file(scheme *sc, FILE *fin) {
-+ sc->inport=port_from_file(sc,fin,port_input);
-+}
-+
-+void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end) {
-+ sc->inport=port_from_string(sc,start,past_the_end,port_input);
-+}
-+
-+void scheme_set_output_port_file(scheme *sc, FILE *fout) {
-+ sc->outport=port_from_file(sc,fout,port_output);
-+}
-+
-+void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end) {
-+ sc->outport=port_from_string(sc,start,past_the_end,port_output);
-+}
-+
-+void scheme_set_external_data(scheme *sc, void *p) {
-+ sc->ext_data=p;
-+}
-+
-+void scheme_deinit(scheme *sc) {
-+ int i;
-+
-+#if SHOW_ERROR_LINE
-+ char *fname;
-+#endif
-+
-+ sc->oblist=sc->NIL;
-+ sc->global_env=sc->NIL;
-+ dump_stack_free(sc);
-+ sc->envir=sc->NIL;
-+ sc->code=sc->NIL;
-+ sc->args=sc->NIL;
-+ sc->value=sc->NIL;
-+ if(is_port(sc->inport)) {
-+ typeflag(sc->inport) = T_ATOM;
-+ }
-+ sc->inport=sc->NIL;
-+ sc->outport=sc->NIL;
-+ if(is_port(sc->save_inport)) {
-+ typeflag(sc->save_inport) = T_ATOM;
-+ }
-+ sc->save_inport=sc->NIL;
-+ if(is_port(sc->loadport)) {
-+ typeflag(sc->loadport) = T_ATOM;
-+ }
-+ sc->loadport=sc->NIL;
-+ sc->gc_verbose=0;
-+ gc(sc,sc->NIL,sc->NIL);
-+
-+ for(i=0; i<=sc->last_cell_seg; i++) {
-+ sc->free(sc->alloc_seg[i]);
-+ }
-+
-+#if SHOW_ERROR_LINE
-+ for(i=0; i<=sc->file_i; i++) {
-+ if (sc->load_stack[i].kind & port_file) {
-+ fname = sc->load_stack[i].rep.stdio.filename;
-+ if(fname)
-+ sc->free(fname);
-+ }
-+ }
-+#endif
-+}
-+
-+void scheme_load_file(scheme *sc, FILE *fin)
-+{ scheme_load_named_file(sc,fin,0); }
-+
-+void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename) {
-+ dump_stack_reset(sc);
-+ sc->envir = sc->global_env;
-+ sc->file_i=0;
-+ sc->load_stack[0].kind=port_input|port_file;
-+ sc->load_stack[0].rep.stdio.file=fin;
-+ sc->loadport=mk_port(sc,sc->load_stack);
-+ sc->retcode=0;
-+ if(fin==stdin) {
-+ sc->interactive_repl=1;
-+ }
-+
-+#if SHOW_ERROR_LINE
-+ sc->load_stack[0].rep.stdio.curr_line = 0;
-+ if(fin!=stdin && filename)
-+ sc->load_stack[0].rep.stdio.filename = store_string(sc, strlen(filename), filename, 0);
-+#endif
-+
-+ sc->inport=sc->loadport;
-+ sc->args = mk_integer(sc,sc->file_i);
-+ Eval_Cycle(sc, OP_T0LVL);
-+ typeflag(sc->loadport)=T_ATOM;
-+ if(sc->retcode==0) {
-+ sc->retcode=sc->nesting!=0;
-+ }
-+}
-+
-+void scheme_load_string(scheme *sc, const char *cmd) {
-+ dump_stack_reset(sc);
-+ sc->envir = sc->global_env;
-+ sc->file_i=0;
-+ sc->load_stack[0].kind=port_input|port_string;
-+ sc->load_stack[0].rep.string.start=(char*)cmd; /* This func respects const */
-+ sc->load_stack[0].rep.string.past_the_end=(char*)cmd+strlen(cmd);
-+ sc->load_stack[0].rep.string.curr=(char*)cmd;
-+ sc->loadport=mk_port(sc,sc->load_stack);
-+ sc->retcode=0;
-+ sc->interactive_repl=0;
-+ sc->inport=sc->loadport;
-+ sc->args = mk_integer(sc,sc->file_i);
-+ Eval_Cycle(sc, OP_T0LVL);
-+ typeflag(sc->loadport)=T_ATOM;
-+ if(sc->retcode==0) {
-+ sc->retcode=sc->nesting!=0;
-+ }
-+}
-+
-+void scheme_define(scheme *sc, pointer envir, pointer symbol, pointer value) {
-+ pointer x;
-+
-+ x=find_slot_in_env(sc,envir,symbol,0);
-+ if (x != sc->NIL) {
-+ set_slot_in_env(sc, x, value);
-+ } else {
-+ new_slot_spec_in_env(sc, envir, symbol, value);
-+ }
-+}
-+
-+#if !STANDALONE
-+void scheme_register_foreign_func(scheme * sc, scheme_registerable * sr)
-+{
-+ scheme_define(sc,
-+ sc->global_env,
-+ mk_symbol(sc,sr->name),
-+ mk_foreign_func(sc, sr->f));
-+}
-+
-+void scheme_register_foreign_func_list(scheme * sc,
-+ scheme_registerable * list,
-+ int count)
-+{
-+ int i;
-+ for(i = 0; i < count; i++)
-+ {
-+ scheme_register_foreign_func(sc, list + i);
-+ }
-+}
-+
-+pointer scheme_apply0(scheme *sc, const char *procname)
-+{ return scheme_eval(sc, cons(sc,mk_symbol(sc,procname),sc->NIL)); }
-+
-+void save_from_C_call(scheme *sc)
-+{
-+ pointer saved_data =
-+ cons(sc,
-+ car(sc->sink),
-+ cons(sc,
-+ sc->envir,
-+ sc->dump));
-+ /* Push */
-+ sc->c_nest = cons(sc, saved_data, sc->c_nest);
-+ /* Truncate the dump stack so TS will return here when done, not
-+ directly resume pre-C-call operations. */
-+ dump_stack_reset(sc);
-+}
-+void restore_from_C_call(scheme *sc)
-+{
-+ car(sc->sink) = caar(sc->c_nest);
-+ sc->envir = cadar(sc->c_nest);
-+ sc->dump = cdr(cdar(sc->c_nest));
-+ /* Pop */
-+ sc->c_nest = cdr(sc->c_nest);
-+}
-+
-+/* "func" and "args" are assumed to be already eval'ed. */
-+pointer scheme_call(scheme *sc, pointer func, pointer args)
-+{
-+ int old_repl = sc->interactive_repl;
-+ sc->interactive_repl = 0;
-+ save_from_C_call(sc);
-+ sc->envir = sc->global_env;
-+ sc->args = args;
-+ sc->code = func;
-+ sc->retcode = 0;
-+ Eval_Cycle(sc, OP_APPLY);
-+ sc->interactive_repl = old_repl;
-+ restore_from_C_call(sc);
-+ return sc->value;
-+}
-+
-+pointer scheme_eval(scheme *sc, pointer obj)
-+{
-+ int old_repl = sc->interactive_repl;
-+ sc->interactive_repl = 0;
-+ save_from_C_call(sc);
-+ sc->args = sc->NIL;
-+ sc->code = obj;
-+ sc->retcode = 0;
-+ Eval_Cycle(sc, OP_EVAL);
-+ sc->interactive_repl = old_repl;
-+ restore_from_C_call(sc);
-+ return sc->value;
-+}
-+
-+
-+#endif
-+
-+/* ========== Main ========== */
-+
-+#if STANDALONE
-+
-+#if defined(__APPLE__) && !defined (OSX)
-+int main()
-+{
-+ extern MacTS_main(int argc, char **argv);
-+ char** argv;
-+ int argc = ccommand(&argv);
-+ MacTS_main(argc,argv);
-+ return 0;
-+}
-+int MacTS_main(int argc, char **argv) {
-+#else
-+int main(int argc, char **argv) {
-+#endif
-+ scheme sc;
-+ FILE *fin;
-+ char *file_name=InitFile;
-+ int retcode;
-+ int isfile=1;
-+
-+ if(argc==1) {
-+ printf(banner);
-+ }
-+ if(argc==2 && strcmp(argv[1],"-?")==0) {
-+ printf("Usage: tinyscheme -?\n");
-+ printf("or: tinyscheme [<file1> <file2> ...]\n");
-+ printf("followed by\n");
-+ printf(" -1 <file> [<arg1> <arg2> ...]\n");
-+ printf(" -c <Scheme commands> [<arg1> <arg2> ...]\n");
-+ printf("assuming that the executable is named tinyscheme.\n");
-+ printf("Use - as filename for stdin.\n");
-+ return 1;
-+ }
-+ if(!scheme_init(&sc)) {
-+ fprintf(stderr,"Could not initialize!\n");
-+ return 2;
-+ }
-+ scheme_set_input_port_file(&sc, stdin);
-+ scheme_set_output_port_file(&sc, stdout);
-+#if USE_DL
-+ scheme_define(&sc,sc.global_env,mk_symbol(&sc,"load-extension"),mk_foreign_func(&sc, scm_load_ext));
-+#endif
-+ argv++;
-+ if(access(file_name,0)!=0) {
-+ char *p=getenv("TINYSCHEMEINIT");
-+ if(p!=0) {
-+ file_name=p;
-+ }
-+ }
-+ do {
-+ if(strcmp(file_name,"-")==0) {
-+ fin=stdin;
-+ } else if(strcmp(file_name,"-1")==0 || strcmp(file_name,"-c")==0) {
-+ pointer args=sc.NIL;
-+ isfile=file_name[1]=='1';
-+ file_name=*argv++;
-+ if(strcmp(file_name,"-")==0) {
-+ fin=stdin;
-+ } else if(isfile) {
-+ fin=fopen(file_name,"r");
-+ }
-+ for(;*argv;argv++) {
-+ pointer value=mk_string(&sc,*argv);
-+ args=cons(&sc,value,args);
-+ }
-+ args=reverse_in_place(&sc,sc.NIL,args);
-+ scheme_define(&sc,sc.global_env,mk_symbol(&sc,"*args*"),args);
-+
-+ } else {
-+ fin=fopen(file_name,"r");
-+ }
-+ if(isfile && fin==0) {
-+ fprintf(stderr,"Could not open file %s\n",file_name);
-+ } else {
-+ if(isfile) {
-+ scheme_load_named_file(&sc,fin,file_name);
-+ } else {
-+ scheme_load_string(&sc,file_name);
-+ }
-+ if(!isfile || fin!=stdin) {
-+ if(sc.retcode!=0) {
-+ fprintf(stderr,"Errors encountered reading %s\n",file_name);
-+ }
-+ if(isfile) {
-+ fclose(fin);
-+ }
-+ }
-+ }
-+ file_name=*argv++;
-+ } while(file_name!=0);
-+ if(argc==1) {
-+ scheme_load_named_file(&sc,stdin,0);
-+ }
-+ retcode=sc.retcode;
-+ scheme_deinit(&sc);
-+
-+ return retcode;
-+}
-+
-+#endif
-+
-+/*
-+Local variables:
-+c-file-style: "k&r"
-+End:
-+*/
-+
-+/* XXX: Hurd addition. */
-+void
-+scheme_load_mem (scheme *sc, const char *cmd_start, const char *cmd_end)
-+{
-+ dump_stack_reset(sc);
-+ sc->envir = sc->global_env;
-+ sc->file_i=0;
-+ sc->load_stack[0].kind=port_input|port_string;
-+ /* This func respects const */
-+ sc->load_stack[0].rep.string.start=(char*) cmd_start;
-+ sc->load_stack[0].rep.string.past_the_end=(char*) cmd_end;
-+ sc->load_stack[0].rep.string.curr=(char*) cmd_start;
-+ sc->loadport=mk_port(sc,sc->load_stack);
-+ sc->retcode=0;
-+ sc->interactive_repl=0;
-+ sc->inport=sc->loadport;
-+ sc->args = mk_integer(sc,sc->file_i);
-+ Eval_Cycle(sc, OP_T0LVL);
-+ typeflag(sc->loadport)=T_ATOM;
-+ if(sc->retcode==0) {
-+ sc->retcode=sc->nesting!=0;
-+ }
-+}
-diff --git a/bootshell/scheme.h b/bootshell/scheme.h
-new file mode 100644
-index 0000000..fbc542b
---- /dev/null
-+++ b/bootshell/scheme.h
-@@ -0,0 +1,255 @@
-+/* SCHEME.H */
-+
-+#ifndef _SCHEME_H
-+#define _SCHEME_H
-+
-+#include <stdio.h>
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/*
-+ * Default values for #define'd symbols
-+ */
-+#ifndef STANDALONE /* If used as standalone interpreter */
-+# define STANDALONE 1
-+#endif
-+
-+#ifndef _MSC_VER
-+# define USE_STRCASECMP 1
-+# ifndef USE_STRLWR
-+# define USE_STRLWR 1
-+# endif
-+# define SCHEME_EXPORT
-+#else
-+# define USE_STRCASECMP 0
-+# define USE_STRLWR 0
-+# ifdef _SCHEME_SOURCE
-+# define SCHEME_EXPORT __declspec(dllexport)
-+# else
-+# define SCHEME_EXPORT __declspec(dllimport)
-+# endif
-+#endif
-+
-+#if USE_NO_FEATURES
-+# define USE_MATH 0
-+# define USE_CHAR_CLASSIFIERS 0
-+# define USE_ASCII_NAMES 0
-+# define USE_STRING_PORTS 0
-+# define USE_ERROR_HOOK 0
-+# define USE_TRACING 0
-+# define USE_COLON_HOOK 0
-+# define USE_DL 0
-+# define USE_PLIST 0
-+#endif
-+
-+/*
-+ * Leave it defined if you want continuations, and also for the Sharp Zaurus.
-+ * Undefine it if you only care about faster speed and not strict Scheme compatibility.
-+ */
-+#define USE_SCHEME_STACK
-+
-+#if USE_DL
-+# define USE_INTERFACE 1
-+#endif
-+
-+
-+#ifndef USE_MATH /* If math support is needed */
-+# define USE_MATH 1
-+#endif
-+
-+#ifndef USE_CHAR_CLASSIFIERS /* If char classifiers are needed */
-+# define USE_CHAR_CLASSIFIERS 1
-+#endif
-+
-+#ifndef USE_ASCII_NAMES /* If extended escaped characters are needed */
-+# define USE_ASCII_NAMES 1
-+#endif
-+
-+#ifndef USE_STRING_PORTS /* Enable string ports */
-+# define USE_STRING_PORTS 1
-+#endif
-+
-+#ifndef USE_TRACING
-+# define USE_TRACING 1
-+#endif
-+
-+#ifndef USE_PLIST
-+# define USE_PLIST 0
-+#endif
-+
-+/* To force system errors through user-defined error handling (see *error-hook*) */
-+#ifndef USE_ERROR_HOOK
-+# define USE_ERROR_HOOK 1
-+#endif
-+
-+#ifndef USE_COLON_HOOK /* Enable qualified qualifier */
-+# define USE_COLON_HOOK 1
-+#endif
-+
-+#ifndef USE_STRCASECMP /* stricmp for Unix */
-+# define USE_STRCASECMP 0
-+#endif
-+
-+#ifndef USE_STRLWR
-+# define USE_STRLWR 1
-+#endif
-+
-+#ifndef STDIO_ADDS_CR /* Define if DOS/Windows */
-+# define STDIO_ADDS_CR 0
-+#endif
-+
-+#ifndef INLINE
-+# define INLINE
-+#endif
-+
-+#ifndef USE_INTERFACE
-+# define USE_INTERFACE 0
-+#endif
-+
-+#ifndef SHOW_ERROR_LINE /* Show error line in file */
-+# define SHOW_ERROR_LINE 1
-+#endif
-+
-+typedef struct scheme scheme;
-+typedef struct cell *pointer;
-+
-+typedef void * (*func_alloc)(size_t);
-+typedef void (*func_dealloc)(void *);
-+
-+/* num, for generic arithmetic */
-+typedef struct num {
-+ char is_fixnum;
-+ union {
-+ long ivalue;
-+ double rvalue;
-+ } value;
-+} num;
-+
-+SCHEME_EXPORT scheme *scheme_init_new();
-+SCHEME_EXPORT scheme *scheme_init_new_custom_alloc(func_alloc malloc, func_dealloc free);
-+SCHEME_EXPORT int scheme_init(scheme *sc);
-+SCHEME_EXPORT int scheme_init_custom_alloc(scheme *sc, func_alloc, func_dealloc);
-+SCHEME_EXPORT void scheme_deinit(scheme *sc);
-+void scheme_set_input_port_file(scheme *sc, FILE *fin);
-+void scheme_set_input_port_string(scheme *sc, char *start, char *past_the_end);
-+SCHEME_EXPORT void scheme_set_output_port_file(scheme *sc, FILE *fin);
-+void scheme_set_output_port_string(scheme *sc, char *start, char *past_the_end);
-+SCHEME_EXPORT void scheme_load_file(scheme *sc, FILE *fin);
-+SCHEME_EXPORT void scheme_load_named_file(scheme *sc, FILE *fin, const char *filename);
-+SCHEME_EXPORT void scheme_load_string(scheme *sc, const char *cmd);
-+SCHEME_EXPORT pointer scheme_apply0(scheme *sc, const char *procname);
-+SCHEME_EXPORT pointer scheme_call(scheme *sc, pointer func, pointer args);
-+SCHEME_EXPORT pointer scheme_eval(scheme *sc, pointer obj);
-+void scheme_set_external_data(scheme *sc, void *p);
-+SCHEME_EXPORT void scheme_define(scheme *sc, pointer env, pointer symbol, pointer value);
-+
-+typedef pointer (*foreign_func)(scheme *, pointer);
-+
-+pointer _cons(scheme *sc, pointer a, pointer b, int immutable);
-+pointer mk_integer(scheme *sc, long num);
-+pointer mk_real(scheme *sc, double num);
-+pointer mk_symbol(scheme *sc, const char *name);
-+pointer gensym(scheme *sc);
-+pointer mk_string(scheme *sc, const char *str);
-+pointer mk_counted_string(scheme *sc, const char *str, int len);
-+pointer mk_empty_string(scheme *sc, int len, char fill);
-+pointer mk_character(scheme *sc, int c);
-+pointer mk_foreign_func(scheme *sc, foreign_func f);
-+void putstr(scheme *sc, const char *s);
-+int list_length(scheme *sc, pointer a);
-+int eqv(pointer a, pointer b);
-+
-+
-+#if USE_INTERFACE
-+struct scheme_interface {
-+ void (*scheme_define)(scheme *sc, pointer env, pointer symbol, pointer value);
-+ pointer (*cons)(scheme *sc, pointer a, pointer b);
-+ pointer (*immutable_cons)(scheme *sc, pointer a, pointer b);
-+ pointer (*reserve_cells)(scheme *sc, int n);
-+ pointer (*mk_integer)(scheme *sc, long num);
-+ pointer (*mk_real)(scheme *sc, double num);
-+ pointer (*mk_symbol)(scheme *sc, const char *name);
-+ pointer (*gensym)(scheme *sc);
-+ pointer (*mk_string)(scheme *sc, const char *str);
-+ pointer (*mk_counted_string)(scheme *sc, const char *str, int len);
-+ pointer (*mk_character)(scheme *sc, int c);
-+ pointer (*mk_vector)(scheme *sc, int len);
-+ pointer (*mk_foreign_func)(scheme *sc, foreign_func f);
-+ void (*putstr)(scheme *sc, const char *s);
-+ void (*putcharacter)(scheme *sc, int c);
-+
-+ int (*is_string)(pointer p);
-+ char *(*string_value)(pointer p);
-+ int (*is_number)(pointer p);
-+ num (*nvalue)(pointer p);
-+ long (*ivalue)(pointer p);
-+ double (*rvalue)(pointer p);
-+ int (*is_integer)(pointer p);
-+ int (*is_real)(pointer p);
-+ int (*is_character)(pointer p);
-+ long (*charvalue)(pointer p);
-+ int (*is_list)(scheme *sc, pointer p);
-+ int (*is_vector)(pointer p);
-+ int (*list_length)(scheme *sc, pointer vec);
-+ long (*vector_length)(pointer vec);
-+ void (*fill_vector)(pointer vec, pointer elem);
-+ pointer (*vector_elem)(pointer vec, int ielem);
-+ pointer (*set_vector_elem)(pointer vec, int ielem, pointer newel);
-+ int (*is_port)(pointer p);
-+
-+ int (*is_pair)(pointer p);
-+ pointer (*pair_car)(pointer p);
-+ pointer (*pair_cdr)(pointer p);
-+ pointer (*set_car)(pointer p, pointer q);
-+ pointer (*set_cdr)(pointer p, pointer q);
-+
-+ int (*is_symbol)(pointer p);
-+ char *(*symname)(pointer p);
-+
-+ int (*is_syntax)(pointer p);
-+ int (*is_proc)(pointer p);
-+ int (*is_foreign)(pointer p);
-+ char *(*syntaxname)(pointer p);
-+ int (*is_closure)(pointer p);
-+ int (*is_macro)(pointer p);
-+ pointer (*closure_code)(pointer p);
-+ pointer (*closure_env)(pointer p);
-+
-+ int (*is_continuation)(pointer p);
-+ int (*is_promise)(pointer p);
-+ int (*is_environment)(pointer p);
-+ int (*is_immutable)(pointer p);
-+ void (*setimmutable)(pointer p);
-+ void (*load_file)(scheme *sc, FILE *fin);
-+ void (*load_string)(scheme *sc, const char *input);
-+};
-+#endif
-+
-+#if !STANDALONE
-+typedef struct scheme_registerable
-+{
-+ foreign_func f;
-+ const char * name;
-+}
-+scheme_registerable;
-+
-+void scheme_register_foreign_func_list(scheme * sc,
-+ scheme_registerable * list,
-+ int n);
-+
-+#endif /* !STANDALONE */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif
-+
-+
-+/*
-+Local variables:
-+c-file-style: "k&r"
-+End:
-+*/
-diff --git a/bootshell/startup.c b/bootshell/startup.c
-new file mode 100644
-index 0000000..abb600c
---- /dev/null
-+++ b/bootshell/startup.c
-@@ -0,0 +1,487 @@
-+#include <assert.h>
-+#include <errno.h>
-+#include <error.h>
-+#include <hurd.h>
-+#include <hurd/startup.h>
-+#include <mach.h>
-+#include <mach/message.h>
-+#include <mach/mig_support.h>
-+#include <mach/notify.h>
-+#include <pthread.h>
-+#include <stdio.h>
-+#include <string.h>
-+
-+#include "startup_reply_U.h"
-+// eek #include "startup_S.h"
-+// eek #include "fsys_S.h"
-+extern boolean_t startup_server (mach_msg_header_t *, mach_msg_header_t *);
-+extern boolean_t fsys_server (mach_msg_header_t *, mach_msg_header_t *);
-+
-+#include "bootshell.h"
-+#include "ffi.h"
-+
-+/* Handling of `startup_essential_task'. */
-+
-+static mach_port_t early_startup_port;
-+
-+/* This structure keeps track of each registered essential task. */
-+struct port_string_tuple
-+ {
-+ struct port_string_tuple *next;
-+ task_t port;
-+ char *name;
-+ };
-+
-+static struct port_string_tuple *essential_tasks;
-+static struct port_string_tuple *registered_tasks;
-+
-+/* Record an essential task in the list. */
-+static error_t
-+add_tuple (struct port_string_tuple **list, mach_port_t port, const char *name)
-+{
-+ struct port_string_tuple *et;
-+
-+ et = malloc (sizeof *et);
-+ if (et == NULL)
-+ goto out;
-+
-+ et->port = port;
-+ et->name = strdup (name);
-+ if (et->name == NULL)
-+ goto out;
-+
-+ et->next = *list;
-+ *list = et;
-+ return 0;
-+
-+ out:
-+ free (et);
-+ return ENOMEM;
-+}
-+
-+/* fsys_goaway for early-boot /servers/startup. */
-+error_t
-+S_fsys_goaway (mach_port_t fsys,
-+ int flags)
-+{
-+ if (fsys != early_startup_port)
-+ return EOPNOTSUPP;
-+ // XXX keep going = 0
-+ return 0;
-+}
-+
-+/* fsys_getroot for early-boot /servers/startup. */
-+error_t
-+S_fsys_getroot (mach_port_t fsys,
-+ mach_port_t dotdotnode,
-+ uid_t *uids, size_t nuids,
-+ uid_t *gids, size_t ngids,
-+ int flags,
-+ retry_type *do_retry,
-+ char *retry_name,
-+ mach_port_t *ret,
-+ mach_msg_type_name_t *rettype)
-+{
-+ if (fsys != early_startup_port)
-+ return EOPNOTSUPP;
-+
-+ *do_retry = FS_RETRY_NORMAL;
-+ *retry_name = '\0';
-+ *ret = early_startup_port;
-+ *rettype = MACH_MSG_TYPE_MAKE_SEND;
-+ return 0;
-+}
-+
-+error_t
-+S_startup_essential_task (startup_t server,
-+ mach_port_t reply_port,
-+ mach_msg_type_name_t reply_portPoly,
-+ mach_port_t task,
-+ mach_port_t excpt,
-+ string_t name,
-+ mach_port_t credential)
-+{
-+ error_t err;
-+ if (server != early_startup_port)
-+ return EOPNOTSUPP;
-+ if (credential != _hurd_host_priv)
-+ return EPERM;
-+
-+ err = mach_port_deallocate (mach_task_self (), credential);
-+ assert_perror (err);
-+
-+ if (MACH_PORT_VALID (excpt))
-+ {
-+ error (0, 0,
-+ "Oh dear, someone actually send us their exception port.\n"
-+ "I'm going to destroy it. Please investigate.");
-+ err = mach_port_destroy (mach_task_self (), excpt);
-+ assert_perror (err);
-+ }
-+
-+ err = add_tuple (&essential_tasks, task, name);
-+ if (err)
-+ return err;
-+
-+ return 0;
-+}
-+
-+kern_return_t
-+S_startup_request_notification (mach_port_t server,
-+ mach_port_t notify,
-+ char *name)
-+{
-+ if (server != early_startup_port)
-+ return EOPNOTSUPP;
-+
-+ return add_tuple (&registered_tasks, notify, name);
-+}
-+
-+static boolean_t
-+early_startup_demuxer (mach_msg_header_t *request,
-+ mach_msg_header_t *reply)
-+{
-+ /* XXX hardcoded msgh_ids */
-+ if (request->msgh_id == 29000 /* startup_essential_task */
-+ || request->msgh_id == 29001) /* startup_request_notification */
-+ return startup_server (request, reply);
-+ else if (request->msgh_id == 22001 /* fsys_goaway */
-+ || request->msgh_id == 22002) /* fsys_getroot */
-+ return fsys_server (request, reply);
-+
-+ /* Return MIG_BAD_ID. */
-+ mig_reply_setup (request, reply);
-+ return FALSE;
-+}
-+
-+static void *
-+service_early_startup_requests (void *arg)
-+{
-+ // XXX while (keep_going) ...
-+ while (1)
-+ mach_msg_server (early_startup_demuxer, 0,
-+ early_startup_port);
-+
-+ /* Not reached. */
-+ return NULL;
-+}
-+
-+static error_t
-+start_handling_early_startup (mach_port_t startup_port)
-+{
-+ error_t err;
-+ pthread_t t;
-+
-+ if (MACH_PORT_VALID (early_startup_port))
-+ return EINVAL;
-+ early_startup_port = startup_port;
-+
-+ /* Make a thread to service `startup_essential_task' requests. */
-+ err = pthread_create (&t, NULL, service_early_startup_requests,
-+ NULL);
-+ if (err)
-+ return err;
-+ pthread_detach (t);
-+
-+ return err;
-+}
-+
-+pointer
-+do__start_handling_early_startup (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("start-handling-early-startup");
-+ SC_ARG (sc, mach_port_t, server_port, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = start_handling_early_startup (server_port);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__get_essential_tasks (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("get-essential-tasks");
-+ SC_ARGS_DONE (sc);
-+ pointer result = sc->NIL;
-+ struct port_string_tuple *et;
-+ for (et = essential_tasks; et; et = et->next)
-+#define IMC(A, B) _cons (sc, (A), (B), 1)
-+ result = IMC (IMC (mk_integer (sc, et->port),
-+ mk_string (sc, et->name)),
-+ result);
-+#undef IMC
-+ SC_RETURN_POINTER (sc, result);
-+}
-+
-+pointer
-+do__get_registered_tasks (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("get-registered-tasks");
-+ SC_ARGS_DONE (sc);
-+ pointer result = sc->NIL;
-+ struct port_string_tuple *rt;
-+ for (rt = registered_tasks; rt; rt = rt->next)
-+#define IMC(A, B) _cons (sc, (A), (B), 1)
-+ result = IMC (IMC (mk_integer (sc, rt->port),
-+ mk_string (sc, rt->name)),
-+ result);
-+#undef IMC
-+ SC_RETURN_POINTER (sc, result);
-+}
-+
-+/* Client stubs for startup. */
-+pointer
-+do__startup_essential_task (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("startup-essential-task");
-+ SC_ARG (sc, mach_port_t, startup, number, args);
-+ SC_ARG (sc, mach_port_t, task, number, args);
-+ SC_ARG (sc, mach_port_t, exception, number, args);
-+ SC_ARG (sc, char *, name, string, args);
-+ SC_ARG (sc, mach_port_t, credential, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = startup_essential_task (startup, task, exception, name, credential);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__startup_request_notification (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("startup-request-notification");
-+ SC_ARG (sc, mach_port_t, startup, number, args);
-+ SC_ARG (sc, mach_port_t, notify_port, number, args);
-+ SC_ARG (sc, char *, name, string, args);
-+ SC_ARGS_DONE (sc);
-+ err = startup_request_notification (startup,
-+ notify_port, MACH_MSG_TYPE_COPY_SEND,
-+ name);
-+ SC_RETURN (sc);
-+}
-+
-+pointer
-+do__startup_reboot (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("startup-reboot");
-+ SC_ARG (sc, mach_port_t, startup, number, args);
-+ SC_ARG (sc, mach_port_t, credential, number, args);
-+ SC_ARG (sc, int, flags, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = startup_reboot (startup, credential, flags);
-+ SC_RETURN (sc);
-+}
-+
-+/* Handling of `startup_procinit'. */
-+
-+/* XXX would be nice not to use a global variable, maybe with
-+ payloads. */
-+static struct
-+{
-+ /* Filled by caller. */
-+ mach_port_t bootstrap_port;
-+
-+ /* Filled by the server function. */
-+ mach_port_t reply;
-+ mach_msg_type_name_t replyPoly;
-+ process_t procserver;
-+} startup_procinit_args;
-+
-+kern_return_t
-+S_startup_procinit (startup_t bootstrap,
-+ mach_port_t reply,
-+ mach_msg_type_name_t replyPoly,
-+ process_t procserver,
-+ mach_port_t *startuptask,
-+ auth_t *auth,
-+ mach_port_t *hostpriv,
-+ mach_msg_type_name_t *hostprivPoly,
-+ mach_port_t *devmaster,
-+ mach_msg_type_name_t *devmasterPoly)
-+{
-+ if (bootstrap != startup_procinit_args.bootstrap_port)
-+ return EOPNOTSUPP;
-+
-+ startup_procinit_args.reply = reply;
-+ startup_procinit_args.replyPoly = replyPoly;
-+ startup_procinit_args.procserver = procserver;
-+ return MIG_NO_REPLY;
-+}
-+
-+boolean_t
-+startup_procinit_demuxer (mach_msg_header_t *request,
-+ mach_msg_header_t *reply)
-+{
-+ if (request->msgh_id != 29003) /* XXX hardcoded msgh_id */
-+ {
-+ /* Return MIG_BAD_ID. */
-+ mig_reply_setup (request, reply);
-+ return FALSE;
-+ }
-+ return startup_server (request, reply);
-+}
-+
-+error_t
-+service_startup_procinit_request (mach_port_t bootstrap,
-+ mach_msg_timeout_t timeout,
-+ mach_port_t *reply,
-+ mach_msg_type_name_t *replyPoly,
-+ process_t *procserver)
-+{
-+ error_t err;
-+ mach_msg_id_t msgh_id;
-+
-+ if (! MACH_PORT_VALID (bootstrap))
-+ return EINVAL;
-+
-+ startup_procinit_args.bootstrap_port = bootstrap;
-+
-+ err = mach_msg_server_timeout_once (startup_procinit_demuxer, 0, bootstrap,
-+ MACH_RCV_TIMEOUT|MACH_SEND_TIMEOUT,
-+ timeout, &msgh_id);
-+ if (err != MACH_MSG_SUCCESS)
-+ return err;
-+
-+ *reply = startup_procinit_args.reply;
-+ *replyPoly = startup_procinit_args.replyPoly;
-+ *procserver = startup_procinit_args.procserver;
-+ return 0;
-+}
-+
-+pointer
-+do__handle_startup_procinit (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("handle-startup-procinit");
-+ SC_ARG (sc, mach_port_t, bootstrap, number, args);
-+ SC_ARG (sc, mach_msg_timeout_t, timeout, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t reply;
-+ mach_msg_type_name_t replyPoly;
-+ mach_port_t proc;
-+ err = service_startup_procinit_request (bootstrap, timeout,
-+ &reply, &replyPoly, &proc);
-+#define IMC(A, B) _cons (sc, sc->vptr->mk_integer (sc, A), (B), 1)
-+ SC_RETURN_POINTER (sc, IMC (reply, IMC (replyPoly, IMC (proc, sc->NIL))));
-+#undef IMC
-+}
-+
-+pointer
-+do__startup_procinit_reply (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("startup-procinit-reply");
-+ SC_ARG (sc, mach_port_t, reply, number, args);
-+ SC_ARG (sc, mach_msg_type_name_t, replyPoly, number, args);
-+ SC_ARG (sc, int, retCode, number, args);
-+ SC_ARG (sc, mach_port_t, startup_task, number, args);
-+ SC_ARG (sc, mach_port_t, authserver, number, args);
-+ SC_ARG (sc, mach_port_t, host_priv, number, args);
-+ SC_ARG (sc, mach_port_t, device_master, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = startup_procinit_reply (reply, replyPoly, retCode,
-+ startup_task, authserver,
-+ host_priv, MACH_MSG_TYPE_COPY_SEND,
-+ device_master, MACH_MSG_TYPE_COPY_SEND);
-+ SC_RETURN (sc);
-+}
-+
-+/* Handling of `startup_authinit'. */
-+
-+/* XXX would be nice not to use a global variable, maybe with
-+ payloads. */
-+static struct
-+{
-+ /* Filled by caller. */
-+ mach_port_t bootstrap_port;
-+
-+ /* Filled by the server function. */
-+ mach_port_t reply;
-+ mach_msg_type_name_t replyPoly;
-+ mach_port_t authserver;
-+} startup_authinit_args;
-+
-+/* Called by the auth server when it starts up. */
-+
-+kern_return_t
-+S_startup_authinit (startup_t bootstrap,
-+ mach_port_t reply,
-+ mach_msg_type_name_t replyPoly,
-+ mach_port_t auth,
-+ mach_port_t *proc,
-+ mach_msg_type_name_t *procPoly)
-+{
-+ if (bootstrap != startup_authinit_args.bootstrap_port)
-+ return EOPNOTSUPP;
-+
-+ startup_authinit_args.reply = reply;
-+ startup_authinit_args.replyPoly = replyPoly;
-+ startup_authinit_args.authserver = auth;
-+ return MIG_NO_REPLY;
-+}
-+
-+boolean_t
-+startup_authinit_demuxer (mach_msg_header_t *request,
-+ mach_msg_header_t *reply)
-+{
-+ if (request->msgh_id != 29004) /* XXX hardcoded msgh_id */
-+ {
-+ /* Return MIG_BAD_ID. */
-+ mig_reply_setup (request, reply);
-+ return FALSE;
-+ }
-+ return startup_server (request, reply);
-+}
-+
-+error_t
-+service_startup_authinit_request (mach_port_t bootstrap,
-+ mach_msg_timeout_t timeout,
-+ mach_port_t *reply,
-+ mach_msg_type_name_t *replyPoly,
-+ mach_port_t *authserver)
-+{
-+ error_t err;
-+ mach_msg_id_t msgh_id;
-+
-+ if (! MACH_PORT_VALID (bootstrap))
-+ return EINVAL;
-+
-+ startup_authinit_args.bootstrap_port = bootstrap;
-+
-+ err = mach_msg_server_timeout_once (startup_authinit_demuxer, 0, bootstrap,
-+ MACH_RCV_TIMEOUT|MACH_SEND_TIMEOUT,
-+ timeout, &msgh_id);
-+ if (err != MACH_MSG_SUCCESS)
-+ return err;
-+
-+ *reply = startup_authinit_args.reply;
-+ *replyPoly = startup_authinit_args.replyPoly;
-+ *authserver = startup_authinit_args.authserver;
-+ return 0;
-+}
-+
-+pointer
-+do__handle_startup_authinit (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("handle-startup-authinit");
-+ SC_ARG (sc, mach_port_t, bootstrap, number, args);
-+ SC_ARG (sc, mach_msg_timeout_t, timeout, number, args);
-+ SC_ARGS_DONE (sc);
-+ mach_port_t reply;
-+ mach_msg_type_name_t replyPoly;
-+ mach_port_t auth;
-+ err = service_startup_authinit_request (bootstrap, timeout,
-+ &reply, &replyPoly, &auth);
-+#define IMC(A, B) _cons (sc, sc->vptr->mk_integer (sc, A), (B), 1)
-+ SC_RETURN_POINTER (sc, IMC (reply, IMC (replyPoly, IMC (auth, sc->NIL))));
-+#undef IMC
-+}
-+
-+pointer
-+do__startup_authinit_reply (scheme *sc, pointer args)
-+{
-+ SC_FFI_PROLOG ("startup-authinit-reply");
-+ SC_ARG (sc, mach_port_t, reply, number, args);
-+ SC_ARG (sc, mach_msg_type_name_t, replyPoly, number, args);
-+ SC_ARG (sc, int, retCode, number, args);
-+ SC_ARG (sc, mach_port_t, authproc, number, args);
-+ SC_ARGS_DONE (sc);
-+ err = startup_authinit_reply (reply, replyPoly, retCode, authproc,
-+ MACH_MSG_TYPE_COPY_SEND);
-+ SC_RETURN (sc);
-+}
-diff --git a/bootshell/startup.h b/bootshell/startup.h
-new file mode 100644
-index 0000000..69f760f
---- /dev/null
-+++ b/bootshell/startup.h
-@@ -0,0 +1,12 @@
-+#include <ffi.h>
-+
-+pointer do__handle_startup_procinit (scheme *sc, pointer args);
-+pointer do__handle_startup_authinit (scheme *sc, pointer args);
-+pointer do__startup_procinit_reply (scheme *sc, pointer args);
-+pointer do__startup_authinit_reply (scheme *sc, pointer args);
-+pointer do__start_handling_early_startup (scheme *sc, pointer args);
-+pointer do__get_essential_tasks (scheme *sc, pointer args);
-+pointer do__get_registered_tasks (scheme *sc, pointer args);
-+pointer do__startup_essential_task (scheme *sc, pointer args);
-+pointer do__startup_request_notification (scheme *sc, pointer args);
-+pointer do__startup_reboot (scheme *sc, pointer args);
-diff --git a/bootshell/utils.c b/bootshell/utils.c
-new file mode 100644
-index 0000000..31c3f4a
---- /dev/null
-+++ b/bootshell/utils.c
-@@ -0,0 +1,121 @@
-+#include <assert.h>
-+#include <hurd.h>
-+#include <mach.h>
-+#include <mach/message.h>
-+#include <stdarg.h>
-+#include <stdio.h>
-+
-+mach_msg_return_t
-+mach_msg_server_timeout_once (boolean_t (*demux) (mach_msg_header_t *request,
-+ mach_msg_header_t *reply),
-+ mach_msg_size_t max_size,
-+ mach_port_t rcv_name,
-+ mach_msg_option_t option,
-+ mach_msg_timeout_t timeout,
-+ mach_msg_id_t *msgh_id)
-+{
-+ mig_reply_header_t *request, *reply;
-+ mach_msg_return_t mr;
-+
-+ if (! MACH_PORT_VALID (rcv_name))
-+ return EINVAL;
-+
-+ if (max_size == 0)
-+ {
-+#ifdef MACH_RCV_LARGE
-+ option |= MACH_RCV_LARGE;
-+ max_size = 2 * __vm_page_size; /* Generic. Good? XXX */
-+#else
-+ max_size = 4 * __vm_page_size; /* XXX */
-+#endif
-+ }
-+
-+ request = alloca (max_size);
-+ reply = alloca (max_size);
-+
-+ mr = mach_msg (&request->Head, MACH_RCV_MSG|option,
-+ 0, max_size, rcv_name,
-+ timeout, MACH_PORT_NULL);
-+ if (mr != MACH_MSG_SUCCESS)
-+ return mr;
-+
-+ *msgh_id = request->Head.msgh_id;
-+
-+ /* We have a request message. Pass it to DEMUX for processing. */
-+ (void) (*demux) (&request->Head, &reply->Head);
-+ assert (reply->Head.msgh_size <= max_size);
-+
-+ switch (reply->RetCode)
-+ {
-+ case KERN_SUCCESS:
-+ /* Hunky dory. */
-+ break;
-+
-+ case MIG_NO_REPLY:
-+ /* The server function wanted no reply sent.
-+ Loop for another request. */
-+ return 0;
-+
-+ default:
-+ /* Some error; destroy the request message to release any
-+ port rights or VM it holds. Don't destroy the reply port
-+ right, so we can send an error message. */
-+ request->Head.msgh_remote_port = MACH_PORT_NULL;
-+ mach_msg_destroy (&request->Head);
-+ break;
-+ }
-+
-+ if (reply->Head.msgh_remote_port == MACH_PORT_NULL)
-+ {
-+ /* No reply port, so destroy the reply. */
-+ if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
-+ mach_msg_destroy (&reply->Head);
-+ return reply->RetCode;
-+ }
-+
-+ /* Send the reply. */
-+ mr = mach_msg (&reply->Head,
-+ MACH_SEND_MSG|option,
-+ reply->Head.msgh_size, max_size, rcv_name,
-+ timeout, MACH_PORT_NULL);
-+
-+ /* See if a message error occurred. */
-+ if (mr == MACH_SEND_INVALID_DEST)
-+ /* The reply can't be delivered, so destroy it. This error
-+ indicates only that the requester went away, so we
-+ continue and get the next request. */
-+ mach_msg_destroy (&request->Head);
-+
-+ return mr != 0 ? mr : request->RetCode;
-+}
-+
-+/* Fill in default response. */
-+void
-+mig_reply_setup (
-+ const mach_msg_header_t *in,
-+ mach_msg_header_t *out)
-+{
-+ static const mach_msg_type_t RetCodeType = {
-+ /* msgt_name = */ MACH_MSG_TYPE_INTEGER_32,
-+ /* msgt_size = */ 32,
-+ /* msgt_number = */ 1,
-+ /* msgt_inline = */ TRUE,
-+ /* msgt_longform = */ FALSE,
-+ /* msgt_deallocate = */ FALSE,
-+ /* msgt_unused = */ 0
-+ };
-+
-+#define InP (in)
-+#define OutP ((mig_reply_header_t *) out)
-+ OutP->Head.msgh_bits =
-+ MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InP->msgh_bits), 0);
-+ OutP->Head.msgh_size = sizeof *OutP;
-+ OutP->Head.msgh_remote_port = InP->msgh_remote_port;
-+ OutP->Head.msgh_local_port = MACH_PORT_NULL;
-+ OutP->Head.msgh_seqno = 0;
-+ OutP->Head.msgh_id = InP->msgh_id + 100;
-+ OutP->RetCodeType = RetCodeType;
-+ OutP->RetCode = MIG_BAD_ID;
-+#undef InP
-+#undef OutP
-+}
---
-2.1.4
-
diff --git a/debian/patches/0010-potfu_bootshell_fixbuild.patch b/debian/patches/0010-potfu_bootshell_fixbuild.patch
deleted file mode 100644
index 7f475cad..00000000
--- a/debian/patches/0010-potfu_bootshell_fixbuild.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From 8905e266cc72b915cae5be6630907ba08789cd06 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Wed, 14 Jan 2015 02:13:46 +0100
-Subject: [PATCH hurd 10/11] potfu_bootshell_fixbuild
-
----
- bootshell/Makefile | 4 +++-
- bootshell/ffi.h | 11 ++++++-----
- bootshell/main.c | 6 +++---
- 3 files changed, 12 insertions(+), 9 deletions(-)
-
-diff --git a/bootshell/Makefile b/bootshell/Makefile
-index 97e30f7..2b22696 100644
---- a/bootshell/Makefile
-+++ b/bootshell/Makefile
-@@ -52,7 +52,9 @@ LDFLAGS += -static
- MIGSFLAGS := -imacros mig-mutate.h
-
- %.o: %.scm
-- $(LD) -r --format=binary $< -o $@
-+ cat <$< >.$@
-+ $(LD) -r --format=binary .$@ -o $@
-+ rm .$@
-
- NOWARN := conversion sign-conversion switch unused-function
- CFLAGS := $(filter-out $(foreach flag,$NOWARN,-W$(flag)),$(CFLAGS))
-diff --git a/bootshell/ffi.h b/bootshell/ffi.h
-index b1b3f97..60ab50d 100644
---- a/bootshell/ffi.h
-+++ b/bootshell/ffi.h
-@@ -94,8 +94,9 @@
- void scheme_load_mem (scheme *, const char *, const char *);
-
- #define declare_embedded_script(X) \
-- extern char X##_start[] asm("_binary_"#X"_start"); \
-- extern char X##_end[] asm("_binary_"#X"_end")
-+ extern char X##_size[] asm("_binary__"#X"_o_size"); \
-+ extern char X##_start[] asm("_binary__"#X"_o_start"); \
-+ extern char X##_end[] asm("_binary__"#X"_o_end")
-
- #define load_embedded_script(S, X) \
- ({ \
-@@ -104,9 +105,9 @@ void scheme_load_mem (scheme *, const char *, const char *);
- fprintf (stderr, "Errors encountered evaluating %s\n", #X); \
- })
-
--declare_embedded_script (init_scm);
--declare_embedded_script (boot_scm);
--declare_embedded_script (runsystem_scm);
-+declare_embedded_script (init);
-+declare_embedded_script (boot);
-+declare_embedded_script (runsystem);
-
- void ffi_update (scheme *sc);
- void ffi_init (scheme *sc);
-diff --git a/bootshell/main.c b/bootshell/main.c
-index f5f3ab5..823a143 100644
---- a/bootshell/main.c
-+++ b/bootshell/main.c
-@@ -232,9 +232,9 @@ main (int argc, char **argv)
-
- ffi_init (&scm);
-
-- load_embedded_script (&scm, init_scm);
-- load_embedded_script (&scm, boot_scm);
-- load_embedded_script (&scm, runsystem_scm);
-+ load_embedded_script (&scm, init);
-+ load_embedded_script (&scm, boot);
-+ load_embedded_script (&scm, runsystem);
-
- define_variable (&scm, bootscript_task);
- define_variable (&scm, rootfs_server_task);
---
-2.1.4
-
diff --git a/debian/patches/0011-bootshell-improve-error-message.patch b/debian/patches/0011-bootshell-improve-error-message.patch
deleted file mode 100644
index 6d4ae6e1..00000000
--- a/debian/patches/0011-bootshell-improve-error-message.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 13246988637409ac6487ac4ac2909e14d7fbb812 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Tue, 13 Jan 2015 17:16:46 +0100
-Subject: [PATCH hurd 11/11] bootshell: improve error message
-
-* bootshell/scheme.c (opexe_0): Mention the expression in the error
-message.
----
- bootshell/scheme.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/bootshell/scheme.c b/bootshell/scheme.c
-index 5ca5641..6f583f5 100644
---- a/bootshell/scheme.c
-+++ b/bootshell/scheme.c
-@@ -2679,7 +2679,7 @@ static pointer opexe_0(scheme *sc, enum scheme_opcodes op) {
- sc->dump = cont_dump(sc->code);
- s_return(sc,sc->args != sc->NIL ? car(sc->args) : sc->NIL);
- } else {
-- Error_0(sc,"illegal function");
-+ Error_1(sc,"illegal function:", sc->code);
- }
-
- case OP_DOMACRO: /* do macro */
---
-2.1.4
-
diff --git a/debian/patches/series b/debian/patches/series
index 7bf3ac1a..bde0ea07 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -47,14 +47,3 @@ libports-payloads.patch
proc-task-notify-0005-proc-fix-build.patch
merge-me-0001-libports-avoid-acquiring-global-lock-in-message-disp.patch
merge-me-0002-startup-faster-reboots.patch
-0001-libports-silence-pointless-error-message.patch
-0002-startup-give-the-tasks-we-create-a-name.patch
-0003-auth-simplify-expression.patch
-0004-auth-remove-implicit-assumption-about-the-bootstrap-.patch
-0005-proc-call-startup_essential_task-earlier.patch
-0006-libshouldbeinlibc-provide-mach_print-XXX.patch
-0007-libdiskfs-fixes-XXX.patch
-0008-trans-add-startup-standalone-XXX.patch
-0009-XXX-bootshell.patch
-0010-potfu_bootshell_fixbuild.patch
-0011-bootshell-improve-error-message.patch