Initial revision
authorChris Hanson <org/chris-hanson/cph>
Mon, 28 Nov 1994 03:43:02 +0000 (03:43 +0000)
committerChris Hanson <org/chris-hanson/cph>
Mon, 28 Nov 1994 03:43:02 +0000 (03:43 +0000)
22 files changed:
v7/src/microcode/os2.c [new file with mode: 0644]
v7/src/microcode/os2.h [new file with mode: 0644]
v7/src/microcode/os2api.h [new file with mode: 0644]
v7/src/microcode/os2conio.c [new file with mode: 0644]
v7/src/microcode/os2cthrd.c [new file with mode: 0644]
v7/src/microcode/os2cthrd.h [new file with mode: 0644]
v7/src/microcode/os2ctty.c [new file with mode: 0644]
v7/src/microcode/os2ctty.h [new file with mode: 0644]
v7/src/microcode/os2env.c [new file with mode: 0644]
v7/src/microcode/os2file.c [new file with mode: 0644]
v7/src/microcode/os2fs.c [new file with mode: 0644]
v7/src/microcode/os2io.c [new file with mode: 0644]
v7/src/microcode/os2io.h [new file with mode: 0644]
v7/src/microcode/os2msg.c [new file with mode: 0644]
v7/src/microcode/os2msg.h [new file with mode: 0644]
v7/src/microcode/os2pipe.c [new file with mode: 0644]
v7/src/microcode/os2term.c [new file with mode: 0644]
v7/src/microcode/os2thrd.c [new file with mode: 0644]
v7/src/microcode/os2thrd.h [new file with mode: 0644]
v7/src/microcode/os2top.c [new file with mode: 0644]
v7/src/microcode/os2tty.c [new file with mode: 0644]
v7/src/microcode/pros2fs.c [new file with mode: 0644]

diff --git a/v7/src/microcode/os2.c b/v7/src/microcode/os2.c
new file mode 100644 (file)
index 0000000..c6ab6d8
--- /dev/null
@@ -0,0 +1,199 @@
+/* -*-C-*-
+
+$Id: os2.c,v 1.1 1994/11/28 03:42:53 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+\f
+void *
+OS_malloc (unsigned int size)
+{
+  void * result = (malloc (size));
+  if (result == 0)
+    OS2_error_system_call (ERROR_NOT_ENOUGH_MEMORY, syscall_malloc);
+  return (result);
+}
+
+void *
+OS_realloc (void * ptr, unsigned int size)
+{
+  void * result = (realloc (ptr, size));
+  if (result == 0)
+    OS2_error_system_call (ERROR_NOT_ENOUGH_MEMORY, syscall_realloc);
+  return (result);
+}
+
+void
+OS_free (void * ptr)
+{
+  free (ptr);
+}
+\f
+HMTX
+OS2_create_mutex_semaphore (void)
+{
+  HMTX result;
+  STD_API_CALL (dos_create_mutex_sem, (0, (&result), 0, 0));
+  return (result);
+}
+
+void
+OS2_close_mutex_semaphore (HMTX s)
+{
+  STD_API_CALL (dos_close_mutex_sem, (s));
+}
+
+void
+OS2_request_mutex_semaphore (HMTX s)
+{
+  STD_API_CALL (dos_request_mutex_sem, (s, SEM_INDEFINITE_WAIT));
+}
+
+void
+OS2_release_mutex_semaphore (HMTX s)
+{
+  STD_API_CALL (dos_release_mutex_sem, (s));
+}
+
+HEV
+OS2_create_event_semaphore (void)
+{
+  HEV result;
+  STD_API_CALL (dos_create_event_sem, (0, (&result), 0, 0));
+  return (result);
+}
+
+void
+OS2_close_event_semaphore (HEV s)
+{
+  STD_API_CALL (dos_close_event_sem, (s));
+}
+
+int
+OS2_post_event_semaphore (HEV s)
+{
+  XTD_API_CALL
+    (dos_post_event_sem, (s),
+     {
+       if (rc == ERROR_ALREADY_POSTED)
+        return (1);
+     });
+  return (0);
+}
+
+ULONG
+OS2_reset_event_semaphore (HEV s)
+{
+  ULONG post_count;
+  XTD_API_CALL
+    (dos_reset_event_sem, (s, (&post_count)),
+     {
+       if (rc == ERROR_ALREADY_RESET)
+        return (0);
+     });
+  return (post_count);
+}
+
+int
+OS2_wait_event_semaphore (HEV s, int blockp)
+{
+  XTD_API_CALL
+    (dos_wait_event_sem,
+     (s, (blockp ? SEM_INDEFINITE_WAIT : SEM_IMMEDIATE_RETURN)),
+     {
+       if ((rc == ERROR_TIMEOUT) && (!blockp))
+        return (0);
+     });
+  return (1);
+}
+\f
+HQUEUE
+OS2_create_queue (ULONG priority)
+{
+  static unsigned int n = 0;
+  char buffer [64];
+  HQUEUE result;
+  sprintf (buffer, "\\queues\\scm%d\\%d.que", OS2_scheme_pid, (n++));
+  STD_API_CALL (dos_create_queue, ((&result), priority, buffer));
+  return (result);
+}
+
+void
+OS2_close_queue (HQUEUE q)
+{
+  STD_API_CALL (dos_close_queue, (q));
+}
+
+void
+OS2_write_queue (HQUEUE q, ULONG type, ULONG length, PVOID data, ULONG priority)
+{
+  STD_API_CALL (dos_write_queue, (q, type, length, data, priority));
+}
+
+int
+OS2_read_queue (HQUEUE q, ULONG * type, ULONG * length, PVOID * data, HEV s)
+{
+  REQUESTDATA request;
+  BYTE priority;
+  (request.pid) = OS2_scheme_pid;
+  if (s != NULLHANDLE)
+    (void) OS2_reset_event_semaphore (s);
+  XTD_API_CALL
+    (dos_read_queue,
+     (q, (&request), length, data, 0,
+      ((s == NULLHANDLE) ? DCWW_WAIT : DCWW_NOWAIT), (&priority), s),
+     {
+       if ((rc == ERROR_QUE_EMPTY) && (s != NULLHANDLE))
+        return (0);
+     });
+  (*type) = (request.ulData);
+  return (1);
+}
+
+ULONG
+OS2_system_variable (ULONG index)
+{
+  ULONG result;
+  STD_API_CALL
+    (dos_query_sys_info, (index, index, (&result), (sizeof (result))));
+  return (result);
+}
+
+void
+OS2_logic_error_1 (const char * description,
+                  const char * file,
+                  unsigned int line)
+{
+  outf_fatal ("\nFatal error in file \"%s\", line %d:\n%s\nGet a wizard.\n",
+             description, file, line);
+  termination_init_error ();
+}
diff --git a/v7/src/microcode/os2.h b/v7/src/microcode/os2.h
new file mode 100644 (file)
index 0000000..18b3efa
--- /dev/null
@@ -0,0 +1,92 @@
+/* -*-C-*-
+
+$Id: os2.h,v 1.1 1994/11/28 03:42:53 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+/* OS/2 system include file */
+
+#ifndef SCM_OS2_H
+#define SCM_OS2_H
+
+#include "dstack.h"
+#include "osscheme.h"
+#include "syscall.h"
+
+#define INCL_DOS
+#define INCL_DOSERRORS
+#define INCL_KBD
+#define INCL_VIO
+#include <os2.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <setjmp.h>
+#include <limits.h>
+
+#include "os2api.h"
+#include "os2msg.h"
+#include "os2io.h"
+#include "os2thrd.h"
+#include "os2ctty.h"
+#include "os2cthrd.h"
+
+#define OS2_MAX_FILE_HANDLES() 20
+
+#define FILE_ANY                                                       \
+  (FILE_NORMAL | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED)
+
+extern HMTX OS2_create_mutex_semaphore  (void);
+extern void OS2_close_mutex_semaphore   (HMTX);
+extern void OS2_request_mutex_semaphore (HMTX);
+extern void OS2_release_mutex_semaphore (HMTX);
+
+extern HEV   OS2_create_event_semaphore (void);
+extern void  OS2_close_event_semaphore  (HEV);
+extern int   OS2_post_event_semaphore   (HEV);
+extern ULONG OS2_reset_event_semaphore  (HEV);
+extern int   OS2_wait_event_semaphore   (HEV, int);
+
+extern HQUEUE OS2_create_queue (ULONG);
+extern void   OS2_close_queue  (HQUEUE);
+extern void   OS2_write_queue  (HQUEUE, ULONG, ULONG, PVOID, ULONG);
+extern int    OS2_read_queue   (HQUEUE, ULONG *, ULONG *, PVOID *, HEV);
+
+extern ULONG OS2_system_variable (ULONG);
+
+/* Logic errors are fatal and can't be caught.  These are errors that
+   should never happen, and if one does occur the program cannot
+   proceed.  */
+#define OS2_logic_error(d) OS2_logic_error_1 ((d), __FILE__, __LINE__)
+extern void OS2_logic_error_1 (const char *, const char *, unsigned int);
+
+#endif /* SCM_OS2_H */
diff --git a/v7/src/microcode/os2api.h b/v7/src/microcode/os2api.h
new file mode 100644 (file)
index 0000000..4bb2113
--- /dev/null
@@ -0,0 +1,209 @@
+/* -*-C-*-
+
+$Id: os2api.h,v 1.1 1994/11/28 03:42:54 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#ifndef SCM_OS2API_H
+#define SCM_OS2API_H
+
+#define XTD_API_CALL(proc, args, if_error)                             \
+{                                                                      \
+  while (1)                                                            \
+    {                                                                  \
+      APIRET rc = (proc args);                                         \
+      if (rc == NO_ERROR)                                              \
+       break;                                                          \
+      if (rc != ERROR_INTERRUPT)                                       \
+       {                                                               \
+         if_error;                                                     \
+         OS2_error_system_call (rc, syscall_ ## proc);                 \
+       }                                                               \
+    }                                                                  \
+}
+
+#define STD_API_CALL(proc, args) XTD_API_CALL (proc, args, {})
+
+#ifdef CLOSED_API_CALLS
+
+extern APIRET dos_async_timer (ULONG, HSEM, PHTIMER);
+extern APIRET dos_close (HFILE);
+extern APIRET dos_close_event_sem (HEV);
+extern APIRET dos_close_mutex_sem (HMTX);
+extern APIRET dos_close_queue (HQUEUE);
+extern APIRET dos_create_dir (PSZ, PEAOP2);
+extern APIRET dos_create_event_sem (PSZ, PHEV, ULONG, BOOL32);
+extern APIRET dos_create_mutex_sem (PSZ, PHMTX, ULONG, BOOL32);
+extern APIRET dos_create_pipe (PHFILE, PHFILE, ULONG);
+extern APIRET dos_create_queue (PHQUEUE, ULONG, PSZ);
+extern APIRET dos_create_thread (PTID, PFNTHREAD, ULONG, ULONG, ULONG);
+extern APIRET dos_delete (PSZ);
+extern APIRET dos_delete_dir (PSZ);
+extern void   dos_exit (ULONG, ULONG);
+extern APIRET dos_find_close (HDIR);
+extern APIRET dos_find_first (PSZ, PHDIR, ULONG, PVOID, ULONG, PULONG, ULONG);
+extern APIRET dos_find_next (HDIR, PVOID, ULONG, PULONG);
+extern APIRET dos_get_info_blocks (PTIB *, PPIB *);
+extern APIRET dos_get_message (PCHAR *, ULONG, PCHAR, ULONG, ULONG, PSZ, PULONG);
+extern APIRET dos_kill_thread (TID);
+extern APIRET dos_move (PSZ, PSZ);
+extern APIRET dos_open (PSZ, PHFILE, PULONG, ULONG, ULONG, ULONG, ULONG, PEAOP2);
+extern APIRET dos_post_event_sem (HEV);
+extern APIRET dos_query_current_dir (ULONG, PBYTE, PULONG);
+extern APIRET dos_query_current_disk (PULONG, PULONG);
+extern APIRET dos_query_file_info (HFILE, ULONG, PVOID, ULONG);
+extern APIRET dos_query_h_type (HFILE, PULONG, PULONG);
+extern APIRET dos_query_n_p_h_state (HPIPE, PULONG);
+extern APIRET dos_query_path_info (PSZ, ULONG, PVOID, ULONG);
+extern APIRET dos_query_sys_info (ULONG, ULONG, PVOID, ULONG);
+extern APIRET dos_read (HFILE, PVOID, ULONG, PULONG);
+extern APIRET dos_read_queue (HQUEUE, PREQUESTDATA, PULONG, PPVOID, ULONG, BOOL32, PBYTE, HEV);
+extern APIRET dos_release_mutex_sem (HMTX);
+extern APIRET dos_request_mutex_sem (HMTX, ULONG);
+extern APIRET dos_reset_event_sem (HEV, PULONG);
+extern APIRET dos_scan_env (PSZ, PSZ *);
+extern APIRET dos_set_current_dir (PSZ);
+extern APIRET dos_set_default_disk (ULONG);
+extern APIRET dos_set_file_ptr (HFILE, LONG, ULONG, PULONG);
+extern APIRET dos_set_file_size (HFILE, ULONG);
+extern APIRET dos_set_path_info (PSZ, ULONG, PVOID, ULONG, ULONG);
+extern APIRET dos_start_timer (ULONG, HSEM, PHTIMER);
+extern APIRET dos_stop_timer (PHTIMER);
+extern APIRET dos_wait_event_sem (HEV, ULONG);
+extern APIRET dos_write (HFILE, PVOID, ULONG, PULONG);
+extern APIRET dos_write_queue (HQUEUE, ULONG, ULONG, PVOID, ULONG);
+extern APIRET kbd_char_in (PKBDKEYINFO, USHORT, HKBD);
+extern APIRET vio_wrt_tty (PCH, USHORT, HVIO);
+
+#else /* not CLOSED_API_CALLS */
+
+#define dos_async_timer                DosAsyncTimer
+#define dos_close              DosClose
+#define dos_close_event_sem    DosCloseEventSem
+#define dos_close_mutex_sem    DosCloseMutexSem
+#define dos_close_queue                DosCloseQueue
+#define dos_create_dir         DosCreateDir
+#define dos_create_event_sem   DosCreateEventSem
+#define dos_create_mutex_sem   DosCreateMutexSem
+#define dos_create_pipe                DosCreatePipe
+#define dos_create_queue       DosCreateQueue
+#define dos_create_thread      DosCreateThread
+#define dos_delete             DosDelete
+#define dos_delete_dir         DosDeleteDir
+#define dos_exit               DosExit
+#define dos_find_close         DosFindClose
+#define dos_find_first         DosFindFirst
+#define dos_find_next          DosFindNext
+#define dos_get_info_blocks    DosGetInfoBlocks
+#define dos_get_message                DosGetMessage
+#define dos_kill_thread                DosKillThread
+#define dos_move               DosMove
+#define dos_open               DosOpen
+#define dos_post_event_sem     DosPostEventSem
+#define dos_query_current_dir  DosQueryCurrentDir
+#define dos_query_current_disk DosQueryCurrentDisk
+#define dos_query_file_info    DosQueryFileInfo
+#define dos_query_h_type       DosQueryHType
+#define dos_query_n_p_h_state  DosQueryNPHState
+#define dos_query_path_info    DosQueryPathInfo
+#define dos_query_sys_info     DosQuerySysInfo
+#define dos_read               DosRead
+#define dos_read_queue         DosReadQueue
+#define dos_release_mutex_sem  DosReleaseMutexSem
+#define dos_request_mutex_sem  DosRequestMutexSem
+#define dos_reset_event_sem    DosResetEventSem
+#define dos_scan_env           DosScanEnv
+#define dos_set_current_dir    DosSetCurrentDir
+#define dos_set_default_disk   DosSetDefaultDisk
+#define dos_set_file_ptr       DosSetFilePtr
+#define dos_set_file_size      DosSetFileSize
+#define dos_set_path_info      DosSetPathInfo
+#define dos_start_timer                DosStartTimer
+#define dos_stop_timer         DosStopTimer
+#define dos_wait_event_sem     DosWaitEventSem
+#define dos_write              DosWrite
+#define dos_write_queue                DosWriteQueue
+#define kbd_char_in            KbdCharIn
+#define vio_wrt_tty            VioWrtTTY
+
+#define syscall_dos_async_timer                syscall_DosAsyncTimer
+#define syscall_dos_close              syscall_DosClose
+#define syscall_dos_close_event_sem    syscall_DosCloseEventSem
+#define syscall_dos_close_mutex_sem    syscall_DosCloseMutexSem
+#define syscall_dos_close_queue                syscall_DosCloseQueue
+#define syscall_dos_create_dir         syscall_DosCreateDir
+#define syscall_dos_create_event_sem   syscall_DosCreateEventSem
+#define syscall_dos_create_mutex_sem   syscall_DosCreateMutexSem
+#define syscall_dos_create_pipe                syscall_DosCreatePipe
+#define syscall_dos_create_queue       syscall_DosCreateQueue
+#define syscall_dos_create_thread      syscall_DosCreateThread
+#define syscall_dos_delete             syscall_DosDelete
+#define syscall_dos_delete_dir         syscall_DosDeleteDir
+#define syscall_dos_exit               syscall_DosExit
+#define syscall_dos_find_close         syscall_DosFindClose
+#define syscall_dos_find_first         syscall_DosFindFirst
+#define syscall_dos_find_next          syscall_DosFindNext
+#define syscall_dos_get_info_blocks    syscall_DosGetInfoBlocks
+#define syscall_dos_get_message                syscall_DosGetMessage
+#define syscall_dos_kill_thread                syscall_DosKillThread
+#define syscall_dos_move               syscall_DosMove
+#define syscall_dos_open               syscall_DosOpen
+#define syscall_dos_post_event_sem     syscall_DosPostEventSem
+#define syscall_dos_query_current_dir  syscall_DosQueryCurrentDir
+#define syscall_dos_query_current_disk syscall_DosQueryCurrentDisk
+#define syscall_dos_query_file_info    syscall_DosQueryFileInfo
+#define syscall_dos_query_h_type       syscall_DosQueryHType
+#define syscall_dos_query_n_p_h_state  syscall_DosQueryNPHState
+#define syscall_dos_query_path_info    syscall_DosQueryPathInfo
+#define syscall_dos_query_sys_info     syscall_DosQuerySysInfo
+#define syscall_dos_read               syscall_DosRead
+#define syscall_dos_read_queue         syscall_DosReadQueue
+#define syscall_dos_release_mutex_sem  syscall_DosReleaseMutexSem
+#define syscall_dos_request_mutex_sem  syscall_DosRequestMutexSem
+#define syscall_dos_reset_event_sem    syscall_DosResetEventSem
+#define syscall_dos_scan_env           syscall_DosScanEnv
+#define syscall_dos_set_current_dir    syscall_DosSetCurrentDir
+#define syscall_dos_set_default_disk   syscall_DosSetDefaultDisk
+#define syscall_dos_set_file_ptr       syscall_DosSetFilePtr
+#define syscall_dos_set_file_size      syscall_DosSetFileSize
+#define syscall_dos_set_path_info      syscall_DosSetPathInfo
+#define syscall_dos_start_timer                syscall_DosStartTimer
+#define syscall_dos_stop_timer         syscall_DosStopTimer
+#define syscall_dos_wait_event_sem     syscall_DosWaitEventSem
+#define syscall_dos_write              syscall_DosWrite
+#define syscall_dos_write_queue                syscall_DosWriteQueue
+#define syscall_kbd_char_in            syscall_KbdCharIn
+#define syscall_vio_wrt_tty            syscall_VioWrtTTY
+#define syscall_VIO16WRTTTY            syscall_VioWrtTTY
+
+#endif /* not CLOSED_API_CALLS */
+
+#endif /* SCM_OS2API_H */
diff --git a/v7/src/microcode/os2conio.c b/v7/src/microcode/os2conio.c
new file mode 100644 (file)
index 0000000..c654a83
--- /dev/null
@@ -0,0 +1,490 @@
+/* -*-C-*-
+
+$Id: os2conio.c,v 1.1 1994/11/28 03:42:54 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+#ifdef USE_PMIO
+#include <pmio.h>
+#endif
+\f
+typedef struct line_buffer_s
+{
+  msg_t * message;
+  struct line_buffer_s * next;
+} line_buffer_t;
+
+static void console_thread (void *);
+#ifndef USE_PMIO
+static int  getch (void);
+#endif
+static void grab_console_lock (void);
+static void release_console_lock (void);
+
+static void init_line_buffer (void);
+static line_buffer_t * make_line_buffer (line_buffer_t *);
+static void push_line_buffer (void);
+static void pop_line_buffer (void);
+static line_buffer_t * reverse_line_buffer (void);
+
+static void process_input_char (char);
+static void do_rubout (void);
+static void add_to_line (char);
+static void do_newline (void);
+static void do_self_insert (char);
+static void add_char_to_line_buffer (char);
+static void finish_line (void);
+static void send_char (char);
+static void send_readahead (msg_t *);
+static void handle_console_interrupt (msg_t *);
+
+static void console_operator
+  (Tchannel, chop_t, choparg_t, choparg_t, choparg_t);;
+static void flush_input (void);
+static void console_input_buffered (Tchannel, int, int *);
+static void console_output_cooked (Tchannel, int, int *);
+
+static void write_char (char, int);
+static void write_output (const char *, size_t, int);
+static void write_output_1 (const char *, const char *);
+static unsigned int char_output_length (char);
+
+#define LINEFEED  '\012'
+
+static HMTX console_lock;
+static int input_buffered_p;
+static int output_cooked_p;
+static qid_t console_writer_qid;
+static channel_context_t * console_context;
+static line_buffer_t * line_buffer;
+
+void
+OS2_initialize_console (void)
+{
+#ifdef USE_PMIO
+  pmio_fontspec = "6.System VIO";
+  set_width (80);
+  set_height (40);
+  start_pmio ();
+#endif
+  console_lock = (OS2_create_mutex_semaphore ());
+  input_buffered_p = 1;
+  output_cooked_p = 1;
+  console_context = (OS2_make_channel_context ());
+  OS2_open_qid ((CHANNEL_CONTEXT_READER_QID (console_context)),
+               OS2_scheme_tqueue);
+  console_writer_qid = (CHANNEL_CONTEXT_WRITER_QID (console_context));
+  OS2_open_qid (console_writer_qid, (OS2_make_std_tqueue ()));
+  (void) OS2_beginthread (console_thread, 0, 0x4000);
+}
+\f
+static void
+console_thread (void * arg)
+{
+  grab_console_lock ();
+  init_line_buffer ();
+  release_console_lock ();
+  (void) OS2_thread_initialize (console_writer_qid);
+  while (1)
+    {
+      int c = (getch ());
+      if (c == EOF)
+       break;
+      {
+       int code = (OS2_keyboard_interrupt_handler (c));
+       if (code == '\0')
+         process_input_char (c);
+       else
+         {
+           msg_t * message = (OS2_create_message (mt_console_interrupt));
+           (SM_CONSOLE_INTERRUPT_CODE (message)) = code;
+           OS2_send_message (OS2_interrupt_qid, message);
+           /* Flush buffers only for certain chars? */
+           flush_input ();
+         }
+      }
+    }
+  OS2_endthread ();
+}
+
+#ifndef USE_PMIO
+static int
+getch (void)
+{
+  while (1)
+    {
+#if 1
+      KBDKEYINFO info;
+      XTD_API_CALL
+       (kbd_char_in, ((&info), IO_WAIT, 0),
+        {
+          if (rc == ERROR_KBD_INVALID_HANDLE)
+            return (EOF);
+        });
+      if ((info . fbStatus) == 0x40)
+       return (info . chChar);
+#else
+      int c = (_getch ());
+      if (c == EOF)
+       return (EOF);
+      else if ((c == 0) || (c == 0xe0))
+       {
+         /* Discard extended keycodes. */
+         if ((_getch ()) == EOF)
+           return (EOF);
+       }
+      else
+       return (c);
+#endif
+    }
+}
+#endif /* not USE_PMIO */
+
+static void
+grab_console_lock (void)
+{
+  OS2_request_mutex_semaphore (console_lock);
+}
+
+static void
+release_console_lock (void)
+{
+  OS2_release_mutex_semaphore (console_lock);
+}
+\f
+static void
+init_line_buffer (void)
+{
+  line_buffer = 0;
+  push_line_buffer ();
+}
+
+static line_buffer_t *
+make_line_buffer (line_buffer_t * next)
+{
+  line_buffer_t * buffer = (OS_malloc (sizeof (line_buffer_t)));
+  msg_t * message = (OS2_make_readahead ());
+  (SM_READAHEAD_SIZE (message)) = 0;
+  (buffer -> message) = message;
+  (buffer -> next) = next;
+  return (buffer);
+}
+
+static void
+push_line_buffer (void)
+{
+  line_buffer = (make_line_buffer (line_buffer));
+}
+
+static void
+pop_line_buffer (void)
+{
+  line_buffer_t * buffer = line_buffer;
+  OS2_destroy_message (buffer -> message);
+  line_buffer = (buffer -> next);
+  OS_free (buffer);
+}
+
+static line_buffer_t *
+reverse_line_buffer (void)
+{
+  line_buffer_t * this = line_buffer;
+  line_buffer_t * prev = 0;
+  line_buffer_t * next;
+  line_buffer = 0;
+  while (1)
+    {
+      next = (this -> next);
+      (this -> next) = prev;
+      if (next == 0)
+       break;
+      prev = this;
+      this = next;
+    }
+  push_line_buffer ();
+  return (this);
+}
+
+#define LINE_BUFFER_SIZE (SM_READAHEAD_SIZE (line_buffer -> message))
+#define LINE_BUFFER_DATA (SM_READAHEAD_DATA (line_buffer -> message))
+\f
+static void
+process_input_char (char c)
+{
+  if (!input_buffered_p)
+    send_char (c);
+  else switch (c)
+    {
+    case '\b':
+    case '\177':
+      do_rubout ();
+      break;
+    case '\r':
+      do_self_insert (LINEFEED);
+      finish_line ();
+      break;
+    default:
+      do_self_insert (c);
+      break;
+    }
+}
+
+static void
+do_self_insert (char c)
+{
+  add_char_to_line_buffer (c);
+  write_char (c, 1);
+}
+
+static void
+add_char_to_line_buffer (char c)
+{
+  grab_console_lock ();
+  if (LINE_BUFFER_SIZE == SM_READAHEAD_MAX)
+    push_line_buffer ();
+  (LINE_BUFFER_DATA [LINE_BUFFER_SIZE ++]) = c;
+  release_console_lock ();
+}
+
+static void
+do_rubout (void)
+{
+  grab_console_lock ();
+  if (LINE_BUFFER_SIZE == 0)
+    {
+      if ((line_buffer -> next) == 0)
+       {
+         release_console_lock ();
+         write_char ('\a', 0);
+         return;
+       }
+      pop_line_buffer ();
+    }
+  {
+    unsigned int n
+      = (char_output_length (LINE_BUFFER_DATA [-- LINE_BUFFER_SIZE]));
+    unsigned int i;
+    release_console_lock ();
+    for (i = 0; (i < n); i += 1)
+      write_char ('\b', 0);
+    for (i = 0; (i < n); i += 1)
+      write_char (' ', 0);
+    for (i = 0; (i < n); i += 1)
+      write_char ('\b', 0);
+  }
+}
+\f
+static void
+finish_line (void)
+{
+  line_buffer_t * buffer;
+  grab_console_lock ();
+  buffer = (reverse_line_buffer ());
+  release_console_lock ();
+  while (buffer != 0)
+    {
+      send_readahead (buffer -> message);
+      buffer = (buffer -> next);
+      OS_free (buffer);
+    }
+}
+
+static void
+send_char (char c)
+{
+  msg_t * message = (OS2_make_readahead ());
+  (SM_READAHEAD_SIZE (message)) = 1;
+  ((SM_READAHEAD_DATA (message)) [0]) = c;
+  send_readahead (message);
+}
+
+static void
+send_readahead (msg_t * message)
+{
+  OS2_send_message (console_writer_qid, message);
+  OS2_wait_for_readahead_ack (console_writer_qid);
+}
+\f
+void
+OS2_initialize_console_channel (Tchannel channel)
+{
+  (CHANNEL_OPERATOR_CONTEXT (channel)) = console_context;
+  (CHANNEL_OPERATOR (channel)) = console_operator;
+}
+
+static void
+console_operator (Tchannel channel, chop_t operation,
+                 choparg_t arg1, choparg_t arg2, choparg_t arg3)
+{
+  switch (operation)
+    {
+    case chop_read:
+      (* ((long *) arg3))
+       = (channel_thread_read (channel, ((char *) arg1), ((size_t) arg2)));
+      break;
+    case chop_write:
+      write_output (((const char *) arg1), ((size_t) arg2), output_cooked_p);
+      (* ((long *) arg3)) = ((size_t) arg2);
+      break;
+    case chop_close:
+    case chop_output_flush:
+    case chop_output_drain:
+      break;
+    case chop_input_flush:
+      flush_input ();
+      break;
+    case chop_input_buffered:
+      console_input_buffered (channel, ((int) arg1), ((int *) arg2));
+      break;
+    case chop_output_cooked:
+      console_output_cooked (channel, ((int) arg1), ((int *) arg2));
+      break;
+    default:
+      OS2_logic_error ("Unknown operation for console.");
+      break;
+    }
+}
+
+static void
+flush_input (void)
+{
+  grab_console_lock ();
+  while ((line_buffer -> next) != 0)
+    pop_line_buffer ();
+  LINE_BUFFER_SIZE = 0;
+  release_console_lock ();
+}
+
+static void
+console_input_buffered (Tchannel channel, int new, int * pold)
+{
+  if (new < 0)
+    (* pold) = input_buffered_p;
+  else
+    {
+      int old = input_buffered_p;
+      input_buffered_p = new;
+      if (old && (!new))
+       {
+         grab_console_lock ();
+         finish_line ();
+       }
+    }
+}
+
+static void
+console_output_cooked (Tchannel channel, int new, int * pold)
+{
+  if (new < 0)
+    (* pold) = output_cooked_p;
+  else
+    output_cooked_p = new;
+}
+\f
+static void
+write_char (char c, int cooked_p)
+{
+  write_output ((&c), 1, cooked_p);
+}
+
+static void
+write_output (const char * data, size_t size, int cooked_p)
+{
+  const char * scan = data;
+  const char * end = (scan + size);
+  char output_translation [256];
+  char * out = output_translation;
+  char * out_limit = (out + ((sizeof (output_translation)) - 4));
+  char c;
+  if (!cooked_p)
+    write_output_1 (scan, end);
+  else
+    while (1)
+      {
+       if ((scan == end) || (out >= out_limit))
+         {
+           write_output_1 (output_translation, out);
+           if (scan == end)
+             break;
+           out = output_translation;
+         }
+       c = (*scan++);
+       if (isprint (c))
+         (*out++) = c;
+       else if (c == LINEFEED)
+         {
+           (*out++) = '\r';
+           (*out++) = c;
+         }
+       else if (c < 0x20)
+         {
+           (*out++) = '^';
+           (*out++) = ('@' + c);
+         }
+       else
+         {
+           (*out++) = '\\';
+           (*out++) = ('0' + ((c >> 6) & 3));
+           (*out++) = ('0' + ((c >> 3) & 7));
+           (*out++) = ('0' + (c & 7));
+         }
+      }
+}
+
+static void
+write_output_1 (const char * scan, const char * end)
+{
+#ifdef USE_PMIO
+  put_raw ((end - scan), scan);
+#else /* not USE_PMIO */
+#if 1
+  STD_API_CALL (vio_wrt_tty, (((PCH) scan), (end - scan), 0));
+#else
+  while (1)
+    {
+      ULONG n;
+      APIRET rc = (dos_write (1, ((void *) scan), (end - scan), (& n)));
+      if (rc != NO_ERROR)
+       break;
+      scan += n;
+      if (scan == end)
+       break;
+    }
+#endif
+#endif /* not USE_PMIO */
+}
+
+static unsigned int
+char_output_length (char c)
+{
+  return ((isprint (c)) ? 1 : (c < 0x20) ? 2 : 4);
+}
diff --git a/v7/src/microcode/os2cthrd.c b/v7/src/microcode/os2cthrd.c
new file mode 100644 (file)
index 0000000..863534d
--- /dev/null
@@ -0,0 +1,137 @@
+/* -*-C-*-
+
+$Id: os2cthrd.c,v 1.1 1994/11/28 03:42:55 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+/* Scheme side of channel thread interface */
+
+#include "os2.h"
+\f
+void
+OS2_initialize_channel_thread_messages (void)
+{
+  SET_MSG_TYPE_LENGTH (mt_readahead, sm_readahead_t);
+  SET_MSG_TYPE_LENGTH (mt_readahead_ack, sm_readahead_ack_t);
+}
+
+channel_context_t *
+OS2_make_channel_context (void)
+{
+  channel_context_t * context = (OS_malloc (sizeof (channel_context_t)));
+  OS2_make_qid_pair ((& (CHANNEL_CONTEXT_READER_QID (context))),
+                    (& (CHANNEL_CONTEXT_WRITER_QID (context))));
+  (CHANNEL_CONTEXT_READAHEAD (context)) = 0;
+  (CHANNEL_CONTEXT_READAHEAD_INDEX (context)) = 0;
+  (CHANNEL_CONTEXT_EOFP (context)) = 0;
+  return (context);
+}
+
+long
+channel_thread_read (Tchannel channel, char * buffer, size_t size)
+{
+  channel_context_t * context = (CHANNEL_OPERATOR_CONTEXT (channel));
+  qid_t qid = (CHANNEL_CONTEXT_READER_QID (context));
+  msg_t * message;
+  unsigned int index;
+  unsigned int navail;
+  if (CHANNEL_CONTEXT_EOFP (context))
+    return (0);
+  message = (CHANNEL_CONTEXT_READAHEAD (context));
+  index = (CHANNEL_CONTEXT_READAHEAD_INDEX (context));
+  if (message == 0)
+    {
+      if (CHANNEL_NONBLOCKING (channel))
+       {
+         message = (OS2_receive_message (qid, 0));
+         if (message == 0)
+           {
+             (CHANNEL_CONTEXT_READAHEAD (context)) = 0;
+             return (-1);
+           }
+       }
+      else
+       message = (OS2_receive_message (qid, 1));
+      /* Acknowledge the message so that the readahead thread will
+        know that it is safe to start reading some more.  */
+      OS2_send_message (qid, (OS2_make_readahead_ack ()));
+      if (OS2_error_message_p (message))
+       OS2_handle_error_message (message);
+      if ((MSG_TYPE (message)) != mt_readahead)
+       OS2_logic_error ("Illegal message from channel thread.");
+      index = 0;
+    }
+  if ((SM_READAHEAD_SIZE (message)) == 0)
+    {
+      OS2_destroy_message (message);
+      (CHANNEL_CONTEXT_READAHEAD (context)) = 0;
+      (CHANNEL_CONTEXT_EOFP (context)) = 1;
+      return (0);
+    }
+  navail = ((SM_READAHEAD_SIZE (message)) - index);
+  if (navail <= size)
+    {
+      FASTCOPY ((SM_READAHEAD_DATA (message)), buffer, navail);
+      OS2_destroy_message (message);
+      (CHANNEL_CONTEXT_READAHEAD (context)) = 0;
+      return (navail);
+    }
+  else
+    {
+      FASTCOPY ((SM_READAHEAD_DATA (message)), buffer, size);
+      (CHANNEL_CONTEXT_READAHEAD (context)) = message;
+      (CHANNEL_CONTEXT_READAHEAD_INDEX (context)) = (index + size);
+      return (size);
+    }
+}
+
+void
+OS2_wait_for_readahead_ack (qid_t qid)
+{
+  /* Wait for an acknowledgement before starting another read.
+     This regulates the amount of data in the queue.  */
+  msg_t * message = (OS2_receive_message (qid, 1));
+  if ((MSG_TYPE (message)) != mt_readahead_ack)
+    OS2_logic_error ("Expected readahead_ack message.");
+  OS2_destroy_message (message);
+}
+
+void
+channel_thread_close (Tchannel channel)
+{
+  channel_context_t * context = (CHANNEL_OPERATOR_CONTEXT (channel));
+  /* Closing handle should force input thread to kill itself.  */
+  STD_API_CALL (dos_close, (CHANNEL_HANDLE (channel)));
+  if ((CHANNEL_CONTEXT_READAHEAD (context)) != 0)
+    OS2_destroy_message (CHANNEL_CONTEXT_READAHEAD (context));
+  OS2_close_qid (CHANNEL_CONTEXT_READER_QID (context));
+  OS_free (context);
+}
diff --git a/v7/src/microcode/os2cthrd.h b/v7/src/microcode/os2cthrd.h
new file mode 100644 (file)
index 0000000..23d3470
--- /dev/null
@@ -0,0 +1,75 @@
+/* -*-C-*-
+
+$Id: os2cthrd.h,v 1.1 1994/11/28 03:42:55 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#ifndef SCM_OS2CTHRD_H
+#define SCM_OS2CTHRD_H
+\f
+#ifndef SM_READAHEAD_MAX
+#define SM_READAHEAD_MAX 4096
+#endif
+
+typedef struct
+{
+  qid_t reader_qid;
+  qid_t writer_qid;
+  msg_t * readahead;
+  unsigned int readahead_index;
+  char eofp;
+} channel_context_t;
+#define CHANNEL_CONTEXT_READER_QID(c) ((c) -> reader_qid)
+#define CHANNEL_CONTEXT_WRITER_QID(c) ((c) -> writer_qid)
+#define CHANNEL_CONTEXT_READAHEAD(c) ((c) -> readahead)
+#define CHANNEL_CONTEXT_READAHEAD_INDEX(c) ((c) -> readahead_index)
+#define CHANNEL_CONTEXT_EOFP(c) ((c) -> eofp)
+
+typedef struct
+{
+  DECLARE_MSG_HEADER_FIELDS;
+  ULONG size;
+  char data [SM_READAHEAD_MAX];
+} sm_readahead_t;
+#define SM_READAHEAD_SIZE(m) (((sm_readahead_t *) (m)) -> size)
+#define SM_READAHEAD_DATA(m) (((sm_readahead_t *) (m)) -> data)
+
+#define OS2_make_readahead() OS2_create_message (mt_readahead)
+#define OS2_make_readahead_ack() OS2_create_message (mt_readahead_ack)
+
+typedef msg_t sm_readahead_ack_t;
+
+extern channel_context_t * OS2_make_channel_context (void);
+extern long channel_thread_read (Tchannel, char *, size_t);
+extern void OS2_wait_for_readahead_ack (qid_t);
+extern void channel_thread_close (Tchannel);
+
+#endif /* SCM_OS2CTHRD_H */
diff --git a/v7/src/microcode/os2ctty.c b/v7/src/microcode/os2ctty.c
new file mode 100644 (file)
index 0000000..eb0a01a
--- /dev/null
@@ -0,0 +1,210 @@
+/* -*-C-*-
+
+$Id: os2ctty.c,v 1.1 1994/11/28 03:42:55 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+#include "osctty.h"
+#include "ossig.h"
+\f
+#define CONTROL_B_ENABLE               (0x1)
+#define CONTROL_G_ENABLE               (0x2)
+#define CONTROL_U_ENABLE               (0x4)
+#define CONTROL_X_ENABLE               (0x8)
+#define INTERACTIVE_INTERRUPT_ENABLE   (0x10)
+#define TERMINATE_INTERRUPT_ENABLE     (0x20)
+
+#define ALL_ENABLES                                                    \
+  (CONTROL_B_ENABLE | CONTROL_G_ENABLE | CONTROL_U_ENABLE              \
+   | CONTROL_X_ENABLE | INTERACTIVE_INTERRUPT_ENABLE                   \
+   | TERMINATE_INTERRUPT_ENABLE)
+
+#define CONTROL_B                      '\002'
+#define CONTROL_G                      '\007'
+#define CONTROL_U                      '\025'
+#define CONTROL_X                      '\030'
+#define CONTROL_C                      '\003'
+
+#define KB_INT_CHARS_SIZE 5
+#define KB_INT_TABLE_SIZE 256
+
+static char keyboard_interrupt_characters [KB_INT_CHARS_SIZE];
+static enum interrupt_handler keyboard_interrupt_handlers [KB_INT_CHARS_SIZE];
+static enum interrupt_handler keyboard_interrupt_table [KB_INT_TABLE_SIZE];
+static enum interrupt_handler keyboard_break_interrupt;
+static Tinterrupt_enables keyboard_interrupt_enables;
+
+static void
+update_keyboard_interrupt_characters (void)
+{
+  unsigned int i;
+  for (i = 0; (i < KB_INT_TABLE_SIZE); i += 1)
+    (keyboard_interrupt_table[i]) = interrupt_handler_ignore;
+  for (i = 0; (i < KB_INT_CHARS_SIZE); i += 1)
+    (keyboard_interrupt_table [keyboard_interrupt_characters [i]]) =
+      (keyboard_interrupt_handlers[i]);
+}
+
+void
+OS2_initialize_keyboard_interrupts (void)
+{
+  (keyboard_interrupt_characters[0]) = CONTROL_B;
+  (keyboard_interrupt_handlers[0]) = interrupt_handler_control_b;
+  (keyboard_interrupt_characters[1]) = CONTROL_G;
+  (keyboard_interrupt_handlers[1]) = interrupt_handler_control_g;
+  (keyboard_interrupt_characters[2]) = CONTROL_U;
+  (keyboard_interrupt_handlers[2]) = interrupt_handler_control_u;
+  (keyboard_interrupt_characters[3]) = CONTROL_X;
+  (keyboard_interrupt_handlers[3]) = interrupt_handler_control_x;
+  (keyboard_interrupt_characters[4]) = CONTROL_C;
+  (keyboard_interrupt_handlers[4]) = interrupt_handler_interactive;
+  keyboard_break_interrupt = interrupt_handler_terminate;
+  update_keyboard_interrupt_characters ();
+  keyboard_interrupt_enables = ALL_ENABLES;
+}
+\f
+void
+OS_ctty_get_interrupt_enables (Tinterrupt_enables * mask)
+{
+  (*mask) = keyboard_interrupt_enables;
+}
+
+void
+OS_ctty_set_interrupt_enables (Tinterrupt_enables * mask)
+{
+  keyboard_interrupt_enables = ((*mask) & ALL_ENABLES);
+}
+
+unsigned int
+OS_ctty_num_int_chars (void)
+{
+  return (KB_INT_CHARS_SIZE + 1);
+}
+
+cc_t
+OS_tty_map_interrupt_char (cc_t int_char)
+{
+  return (int_char);
+}
+
+cc_t *
+OS_ctty_get_int_chars (void)
+{
+  static cc_t characters [KB_INT_CHARS_SIZE + 1];
+  unsigned int i;
+  for (i = 0; (i < KB_INT_CHARS_SIZE); i += 1)
+    (characters[i]) = (keyboard_interrupt_characters[i]);
+  (characters[i]) = '\0';      /* dummy for control-break */
+  return (characters);
+}
+
+void
+OS_ctty_set_int_chars (cc_t * characters)
+{
+  unsigned int i;
+  for (i = 0; (i < KB_INT_CHARS_SIZE); i += 1)
+    (keyboard_interrupt_characters[i]) = (characters[i]);
+  update_keyboard_interrupt_characters ();
+}
+
+cc_t *
+OS_ctty_get_int_char_handlers (void)
+{
+  static cc_t handlers [KB_INT_CHARS_SIZE + 1];
+  unsigned int i;
+  for (i = 0; (i < KB_INT_CHARS_SIZE); i += 1)
+    (handlers[i]) = ((cc_t) (keyboard_interrupt_handlers[i]));
+  (handlers[i]) = ((cc_t) keyboard_break_interrupt);
+  return (handlers);
+}
+
+void
+OS_ctty_set_int_char_handlers (cc_t * handlers)
+{
+  unsigned int i;
+  for (i = 0; (i < KB_INT_CHARS_SIZE); i += 1)
+    (keyboard_interrupt_handlers[i]) =
+      ((enum interrupt_handler) (handlers[i]));
+  keyboard_break_interrupt = ((enum interrupt_handler) (handlers[i]));
+  update_keyboard_interrupt_characters ();
+}
+\f
+static char
+check_if_enabled (enum interrupt_handler handler)
+{
+  unsigned int bitmask;
+  char result;
+  switch (handler)
+    {
+    case interrupt_handler_control_b:
+      bitmask = CONTROL_B_ENABLE;
+      result = 'B';
+      break;
+    case interrupt_handler_control_g:
+      bitmask = CONTROL_G_ENABLE;
+      result = 'G';
+      break;
+    case interrupt_handler_control_u:
+      bitmask = CONTROL_U_ENABLE;
+      result = 'U';
+      break;
+    case interrupt_handler_control_x:
+      bitmask = CONTROL_X_ENABLE;
+      result = 'X';
+      break;
+    case interrupt_handler_interactive:
+      bitmask = INTERACTIVE_INTERRUPT_ENABLE;
+      result = '!';
+      break;
+    case interrupt_handler_terminate:
+      bitmask = TERMINATE_INTERRUPT_ENABLE;
+      result = '@';
+      break;
+    default:
+      bitmask = 0;
+      result = '\0';
+      break;
+    }
+  return (((keyboard_interrupt_enables & bitmask) == 0) ? '\0' : result);
+}
+
+char
+OS2_keyboard_interrupt_handler (char c)
+{
+  return (check_if_enabled (keyboard_interrupt_table[c]));
+}
+
+char
+OS2_keyboard_break_interrupt_handler (void)
+{
+  return (check_if_enabled (keyboard_break_interrupt));
+}
diff --git a/v7/src/microcode/os2ctty.h b/v7/src/microcode/os2ctty.h
new file mode 100644 (file)
index 0000000..7c666f5
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*-C-*-
+
+$Id: os2ctty.h,v 1.1 1994/11/28 03:42:56 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#ifndef SCM_OS2CTTY_H
+#define SCM_OS2CTTY_H
+
+extern char OS2_keyboard_interrupt_handler (char);
+extern char OS2_keyboard_break_interrupt_handler (void);
+
+#endif /* SCM_OS2CTTY_H */
diff --git a/v7/src/microcode/os2env.c b/v7/src/microcode/os2env.c
new file mode 100644 (file)
index 0000000..9cabb48
--- /dev/null
@@ -0,0 +1,301 @@
+/* -*-C-*-
+
+$Id: os2env.c,v 1.1 1994/11/28 03:42:56 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "scheme.h"
+#undef END_OF_CHAIN
+#include "os2.h"
+#include "osenv.h"
+#include <time.h>
+#include <sys\types.h>
+
+#ifdef __IBMC__
+
+#include <sys\timeb.h>
+
+#else /* not __IBMC__ */
+#ifdef __GCC2__
+
+#include <errno.h>
+#include <sys/times.h>
+
+#endif /* __GCC2__ */
+#endif /* not __IBMC__ */
+
+static void initialize_real_time_clock (void);
+static double get_real_time_clock (void);
+
+static void initialize_timer (void);
+static void timer_thread (void *);
+static void handle_timer_event (msg_t *);
+
+void
+OS2_initialize_environment (void)
+{
+  initialize_real_time_clock ();
+  initialize_timer ();
+}
+\f
+time_t
+OS_encoded_time (void)
+{
+  time_t t = (time (0));
+  if (t < 0)
+    OS2_error_system_call (errno, syscall_time);
+  return (t);
+}
+
+void
+OS_decode_time (time_t t, struct time_structure * buffer)
+{
+  struct tm * ts = (localtime (&t));
+  if (ts == 0)
+    OS2_error_system_call (errno, syscall_localtime);
+  (buffer -> year) = ((ts -> tm_year) + 1900);
+  (buffer -> month) = ((ts -> tm_mon) + 1);
+  (buffer -> day) = (ts -> tm_mday);
+  (buffer -> hour) = (ts -> tm_hour);
+  (buffer -> minute) = (ts -> tm_min);
+  (buffer -> second) = (ts -> tm_sec);
+  {
+    /* In localtime() encoding, 0 is Sunday; in ours, it's Monday. */
+    int wday = (ts -> tm_wday);
+    (buffer -> day_of_week) = ((wday == 0) ? 6 : (wday - 1));
+  }
+}  
+
+time_t
+OS_encode_time (struct time_structure * buffer)
+{
+  struct tm ts;
+  (ts . tm_year) = ((buffer -> year) - 1900);
+  (ts . tm_mon) = ((buffer -> month) - 1);
+  (ts . tm_mday) = (buffer -> day);
+  (ts . tm_hour) = (buffer -> hour);
+  (ts . tm_min) = (buffer -> minute);
+  (ts . tm_sec) = (buffer -> second);
+  (ts . tm_isdst) = -1;        /* Let mktime figure it out */
+  {
+    time_t t = (mktime (&ts));
+    if (t < 0)
+      OS2_error_system_call (errno, syscall_mktime);
+    return (t);
+  }
+}
+
+static double initial_rtc;
+
+static void
+initialize_real_time_clock (void)
+{
+  initial_rtc = (get_real_time_clock ());
+}
+
+double
+OS_real_time_clock (void)
+{
+  return ((get_real_time_clock ()) - initial_rtc);
+}
+
+static double
+get_real_time_clock (void)
+{
+#ifdef __IBMC__
+  struct timeb rtc;
+  _ftime (&rtc);
+  return ((((double) (rtc . time)) * 1000.0) + ((double) (rtc . millitm)));
+#else /* not __IBMC__ */
+#ifdef __GCC2__
+  struct tms rtc;
+  times (&rtc);
+  return (((double) (rtc . tms_utime)) * (1000.0 / ((double) CLK_TCK)));
+#endif /* __GCC2__ */
+#endif /* not __IBMC__ */
+}
+
+double
+OS_process_clock (void)
+{
+  /* This must not signal an error in normal use. */
+  return (OS_real_time_clock ());
+}
+\f
+static HEV timer_event;
+static int timer_handle_valid;
+static HTIMER timer_handle;
+static TID timer_tid;
+
+static void
+initialize_timer (void)
+{
+  timer_event = (OS2_create_event_semaphore ());
+  timer_handle_valid = 0;
+  timer_tid = (OS2_beginthread (timer_thread, 0, 0));
+}
+
+void
+OS2_kill_timer_thread (void)
+{
+  OS2_kill_thread (timer_tid);
+}
+
+static void
+timer_thread (void * arg)
+{
+  (void) OS2_thread_initialize (QID_NONE);
+  while (1)
+    {
+      ULONG count = (OS2_reset_event_semaphore (timer_event));
+      while (count > 0)
+       {
+         OS2_send_message (OS2_interrupt_qid,
+                           (OS2_create_message (mt_timer_event)));
+         count -= 1;
+       }
+      (void) OS2_wait_event_semaphore (timer_event, 1);
+    }
+}
+
+void
+OS_real_timer_set (clock_t first, clock_t interval)
+{
+  /* **** No support for (first != interval), but runtime system never
+     does that anyway.  */
+  OS_real_timer_clear ();
+  if (interval != 0)
+    {
+      STD_API_CALL (dos_start_timer, (interval,
+                                     ((HSEM) (&timer_event)),
+                                     (&timer_handle)));
+      timer_handle_valid = 1;
+    }
+  else if (first != 0)
+    {
+      STD_API_CALL (dos_async_timer, (first,
+                                     ((HSEM) (&timer_event)),
+                                     (&timer_handle)));
+      timer_handle_valid = 1;
+    }
+}
+
+void
+OS_real_timer_clear (void)
+{
+  if (timer_handle_valid)
+    {
+      STD_API_CALL (dos_stop_timer, (timer_handle));
+      timer_handle_valid = 0;
+    }
+  (void) OS2_reset_event_semaphore (timer_event);
+}
+\f
+void
+OS_process_timer_set (clock_t first, clock_t interval)
+{
+  OS2_error_unimplemented_primitive ();
+}
+
+void
+OS_process_timer_clear (void)
+{
+}
+
+void
+OS_profile_timer_set (clock_t first, clock_t interval)
+{
+  OS2_error_unimplemented_primitive ();
+}
+
+void
+OS_profile_timer_clear (void)
+{
+}
+\f
+static size_t current_dir_path_size = 0;
+static char * current_dir_path = 0;
+
+const char *
+OS_working_dir_pathname (void)
+{
+  ULONG drive_number;
+  {
+    ULONG drive_map;
+    STD_API_CALL (dos_query_current_disk, ((&drive_number), (&drive_map)));
+  }
+  if ((current_dir_path_size == 0) || (current_dir_path == 0))
+    {
+      current_dir_path_size = 1024;
+      current_dir_path = (OS_malloc (current_dir_path_size));
+    }
+  while (1)
+    {
+      ULONG size = (current_dir_path_size - 3);
+      {
+       APIRET rc =
+         (dos_query_current_dir
+          (drive_number, (current_dir_path + 3), (&size)));
+       if (rc == NO_ERROR)
+         break;
+       if (rc != ERROR_BUFFER_OVERFLOW)
+         OS2_error_system_call (rc, syscall_dos_query_current_dir);
+      }
+      do
+       current_dir_path_size *= 2;
+      while ((current_dir_path_size - 3) < size);
+      OS_free (current_dir_path);
+      current_dir_path = (OS_malloc (current_dir_path_size));
+    }
+  (current_dir_path[0]) = ('a' + drive_number - 1);
+  (current_dir_path[1]) = ':';
+  (current_dir_path[2]) = '\\';
+  return (current_dir_path);
+}
+
+void
+OS_set_working_dir_pathname (const char * name)
+{
+  extern char * OS2_remove_trailing_backslash (const char *);
+  unsigned int length;
+  name = (OS2_remove_trailing_backslash (name));
+  /* **** Documentation doesn't clarify whether DosSetCurrentDir will
+     handle the drive prefix correctly or not.  */
+  length = (strlen (name));
+  if ((length >= 2) && ((name[1]) == ':'))
+    {
+      STD_API_CALL
+       (dos_set_default_disk,
+        ((name[0]) - ((islower (name[0])) ? 'a' : 'A') + 1));
+      name += 2;
+    }
+  STD_API_CALL (dos_set_current_dir, ((char *) name));
+}
diff --git a/v7/src/microcode/os2file.c b/v7/src/microcode/os2file.c
new file mode 100644 (file)
index 0000000..495a2c5
--- /dev/null
@@ -0,0 +1,179 @@
+/* -*-C-*-
+
+$Id: os2file.c,v 1.1 1994/11/28 03:42:57 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+#include "osfile.h"
+
+static ULONG set_file_pointer (Tchannel, ULONG, LONG);
+
+#define OS2_OPEN_MODE(m)                                               \
+  ((((m) & CHANNEL_READ) == 0)                                         \
+   ? (OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE)                    \
+   : (((m) & CHANNEL_WRITE) == 0)                                      \
+   ? (OPEN_ACCESS_READONLY  | OPEN_SHARE_DENYNONE)                     \
+   : (OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYWRITE))
+\f
+static Tchannel
+open_file (const char * filename, ULONG attr, ULONG flags, unsigned int mode)
+{
+  HFILE handle;
+  ULONG action;
+  STD_API_CALL
+    (dos_open, (((char *) filename), (&handle), (&action), 0, attr, flags,
+               (OS2_OPEN_MODE (mode)), 0));
+  return (OS2_make_channel (handle, mode));
+}
+
+Tchannel
+OS_open_input_file (const char * filename)
+{
+  return
+    (open_file (filename,
+               FILE_NORMAL,
+               (OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW),
+               CHANNEL_READ));
+}
+
+Tchannel
+OS_open_output_file (const char * filename)
+{
+  return
+    (open_file (filename,
+               FILE_NORMAL,
+               (OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW),
+               CHANNEL_WRITE));
+}
+
+Tchannel
+OS_open_io_file (const char * filename)
+{
+  return
+    (open_file (filename,
+               FILE_NORMAL,
+               (OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW),
+               (CHANNEL_READ | CHANNEL_WRITE)));
+}
+
+Tchannel
+OS_open_append_file (const char * filename)
+{
+  Tchannel channel =
+    (open_file (filename,
+               FILE_NORMAL,
+               (OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW),
+               CHANNEL_WRITE));
+  transaction_begin ();
+  OS_channel_close_on_abort (channel);
+  (void) set_file_pointer (channel, FILE_END, 0);
+  transaction_commit ();
+  return (channel);
+}
+\f
+static Tchannel
+open_file_noerror (const char * filename, ULONG attr, ULONG flags,
+                  unsigned int mode)
+{
+  HFILE handle;
+  ULONG action;
+  if ((dos_open (((char *) filename), (&handle), (&action), 0, attr, flags,
+                (OS2_OPEN_MODE (mode)), 0))
+      != NO_ERROR)
+    return (NO_CHANNEL);
+  {
+    Tchannel channel = (OS2_make_channel (handle, mode));
+    if ((CHANNEL_TYPE (channel)) == channel_type_file)
+      return (channel);
+    OS_channel_close_noerror (channel);
+    return (NO_CHANNEL);
+  }
+}
+
+Tchannel
+OS_open_load_file (const char * filename)
+{
+  return
+    (open_file_noerror
+     (filename,
+      FILE_NORMAL,
+      (OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW),
+      CHANNEL_READ));
+}
+
+Tchannel
+OS_open_dump_file (const char * filename)
+{
+  return
+    (open_file_noerror
+     (filename,
+      FILE_NORMAL,
+      (OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW),
+      CHANNEL_WRITE));
+}
+
+off_t
+OS_file_length (Tchannel channel)
+{
+  FILESTATUS3 buffer;
+  if ((CHANNEL_TYPE (channel)) != channel_type_file)
+    OS2_error_system_call (ERROR_INVALID_HANDLE, syscall_dos_query_file_info);
+  STD_API_CALL
+    (dos_query_file_info,
+     ((CHANNEL_HANDLE (channel)), FIL_STANDARD,
+      (&buffer), (sizeof (buffer))));
+  return (buffer.cbFile);
+}
+
+off_t
+OS_file_position (Tchannel channel)
+{
+  return (set_file_pointer (channel, FILE_CURRENT, 0));
+}
+
+void
+OS_file_set_position (Tchannel channel, off_t position)
+{
+  if ((set_file_pointer (channel, FILE_BEGIN, position)) != position)
+    OS2_error_anonymous ();
+}
+
+static ULONG
+set_file_pointer (Tchannel channel, ULONG type, LONG distance)
+{
+  ULONG fp;
+  if ((CHANNEL_TYPE (channel)) != channel_type_file)
+    OS2_error_system_call (ERROR_INVALID_HANDLE, syscall_dos_set_file_ptr);
+  STD_API_CALL
+    (dos_set_file_ptr, ((CHANNEL_HANDLE (channel)), distance, type, (&fp)));
+  return (fp);
+}
diff --git a/v7/src/microcode/os2fs.c b/v7/src/microcode/os2fs.c
new file mode 100644 (file)
index 0000000..659233b
--- /dev/null
@@ -0,0 +1,377 @@
+/* -*-C-*-
+
+$Id: os2fs.c,v 1.1 1994/11/28 03:42:57 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+#include "osfs.h"
+
+#ifdef __GCC2__
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#endif
+
+static const char * make_pathname (const char *, const char *);
+static const char * filename_extension (const char *);
+extern char * OS2_remove_trailing_backslash (const char *);
+\f
+FILESTATUS3 *
+OS2_read_file_status (const char * filename)
+{
+  static FILESTATUS3 info;
+  XTD_API_CALL
+    (dos_query_path_info,
+     ((OS2_remove_trailing_backslash (filename)),
+      FIL_STANDARD, (&info), (sizeof (info))),
+     {
+       if ((rc == ERROR_FILE_NOT_FOUND)
+          || (rc == ERROR_PATH_NOT_FOUND)
+          /* ERROR_ACCESS_DENIED can occur if the file is a symbolic
+             link on a unix system mounted via NFS, and if the
+             symbolic link points to a nonexistent file.  */
+          || (rc == ERROR_ACCESS_DENIED))
+        return (0);
+     });
+  return (&info);
+}
+
+void
+OS2_write_file_status (const char * filename, FILESTATUS3 * info)
+{
+  STD_API_CALL
+    (dos_set_path_info,
+     ((OS2_remove_trailing_backslash (filename)),
+      FIL_STANDARD, info, (sizeof (FILESTATUS3)), 0));
+}
+
+enum file_existence
+OS_file_existence_test (const char * filename)
+{
+  return ((OS2_read_file_status (filename))
+         ? file_does_exist
+         : file_doesnt_exist);
+}
+
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+
+int
+OS_file_access (const char * filename, unsigned int mode)
+{
+  FILESTATUS3 * info = (OS2_read_file_status (filename));
+  if (!info)
+    return (0);
+  if (((mode & W_OK) != 0) && (((info -> attrFile) & FILE_READONLY) != 0))
+    return (0);
+  if ((mode & X_OK) != 0)
+    {
+      if (((info -> attrFile) & FILE_DIRECTORY) != 0)
+       return (0);
+      {
+       const char * extension = (filename_extension (filename));
+       if (! (((stricmp (extension, ".exe")) == 0)
+              || ((stricmp (extension, ".com")) == 0)
+              || ((stricmp (extension, ".cmd")) == 0)
+              || ((stricmp (extension, ".bat")) == 0)))
+         return (0);
+      }
+    }
+  return (1);
+}
+
+int
+OS_file_directory_p (const char * filename)
+{
+  FILESTATUS3 * info = (OS2_read_file_status (filename));
+  return ((info == 0) ? 0 : (((info -> attrFile) & FILE_DIRECTORY) != 0));
+}
+
+const char *
+OS_file_soft_link_p (const char * filename)
+{
+  return (0);
+}
+\f
+void
+OS_file_remove (const char * filename)
+{
+  {
+    FILESTATUS3 * info = (OS2_read_file_status (filename));
+    if (info == 0)
+      return;
+    if (((info -> attrFile) & FILE_READONLY) != 0)
+      {
+       (info -> attrFile) &=~ FILE_READONLY;
+       STD_API_CALL
+         (dos_set_path_info,
+          (((char *) filename), FIL_STANDARD, info, (sizeof (*info)), 0));
+      }
+  }
+  STD_API_CALL (dos_delete, ((char *) filename));
+}
+
+void
+OS_file_remove_link (const char * filename)
+{
+  OS_file_remove (filename);
+}
+
+void
+OS_file_rename (const char * from_name, const char * to_name)
+{
+  STD_API_CALL (dos_move, (((char *) from_name), ((char *) to_name)));
+}
+
+void
+OS_file_link_hard (const char * from_name, const char * to_name)
+{
+  OS2_error_unimplemented_primitive ();
+}
+
+void
+OS_file_link_soft (const char * from_name, const char * to_name)
+{
+  OS2_error_unimplemented_primitive ();
+}
+
+void
+OS_directory_make (const char * directory_name)
+{
+  STD_API_CALL
+    (dos_create_dir, ((OS2_remove_trailing_backslash (directory_name)), 0));
+}
+
+void
+OS_directory_delete (const char * directory_name)
+{
+  STD_API_CALL
+    (dos_delete_dir, (OS2_remove_trailing_backslash (directory_name)));
+}
+\f
+typedef struct
+{
+  const char * search_pattern;
+  HDIR handle;
+  FILEFINDBUF3 info;
+  ULONG count;
+} dir_search_state;
+
+static dir_search_state * dir_search_states;
+static unsigned int n_dir_search_states;
+
+void
+OS2_initialize_directory_reader (void)
+{
+  dir_search_states = 0;
+  n_dir_search_states = 0;
+}
+
+static unsigned int
+allocate_dir_search_state (const char * search_pattern)
+{
+  if (n_dir_search_states == 0)
+    {
+      dir_search_state * states =
+       ((dir_search_state *) (OS_malloc ((sizeof (dir_search_state)) * 4)));
+      dir_search_states = states;
+      n_dir_search_states = 4;
+      {
+       dir_search_state * scan = dir_search_states;
+       dir_search_state * end = (scan + n_dir_search_states);
+       ((scan++) -> search_pattern) = search_pattern;
+       while (scan < end)
+         ((scan++) -> search_pattern) = 0;
+      }
+      return (0);
+    }
+  {
+    dir_search_state * scan = dir_search_states;
+    dir_search_state * end = (scan + n_dir_search_states);
+    while (scan < end)
+      if (((scan++) -> search_pattern) == 0)
+       {
+         ((--scan) -> search_pattern) = search_pattern;
+         return (scan - dir_search_states);
+       }
+  }
+  {
+    unsigned int result = n_dir_search_states;
+    unsigned int n_states = (2 * n_dir_search_states);
+    dir_search_state * states =
+      ((dir_search_state *)
+       (OS_realloc (((void *) dir_search_states),
+                   ((sizeof (dir_search_state)) * n_states))));
+    {
+      dir_search_state * scan = (states + result);
+      dir_search_state * end = (states + n_states);
+      ((scan++) -> search_pattern) = search_pattern;
+      while (scan < end)
+       ((scan++) -> search_pattern) = 0;
+    }
+    dir_search_states = states;
+    n_dir_search_states = n_states;
+    return (result);
+  }
+}
+
+#define REFERENCE_DIR_SEARCH_STATE(index) (& (dir_search_states[(index)]))
+#define DEALLOCATE_DIR_SEARCH_STATE(state)                             \
+{                                                                      \
+  if ((state -> search_pattern) != 0)                                  \
+    {                                                                  \
+      OS_free ((void *) (state -> search_pattern));                    \
+      (state -> search_pattern) = 0;                                   \
+    }                                                                  \
+}
+\f
+int
+OS_directory_valid_p (long index)
+{
+  return
+    ((0 <= index)
+     && (index < n_dir_search_states)
+     && (((REFERENCE_DIR_SEARCH_STATE (index)) -> search_pattern) != 0));
+}
+
+unsigned int
+OS_directory_open (const char * search_pattern)
+{
+  unsigned int index = (allocate_dir_search_state (search_pattern));
+  dir_search_state * s = (REFERENCE_DIR_SEARCH_STATE (index));
+  (s -> handle) = HDIR_CREATE;
+  (s -> count) = 1;
+  XTD_API_CALL
+    (dos_find_first,
+     (((char *) (s -> search_pattern)), (& (s -> handle)), FILE_ANY,
+      (& (s -> info)), (sizeof (s -> info)), (& (s -> count)), FIL_STANDARD),
+     {
+       if (rc == ERROR_NO_MORE_FILES)
+        {
+          (s -> count) = 0;
+          goto done;
+        }
+     });
+ done:
+  return (index);
+}
+
+static void
+dir_find_next (dir_search_state * s)
+{
+  (s -> count) = 1;
+  XTD_API_CALL
+    (dos_find_next,
+     ((s -> handle), (& (s -> info)), (sizeof (s -> info)), (& (s -> count))),
+     {
+       if (rc == ERROR_NO_MORE_FILES)
+        {
+          (s -> count) = 0;
+          return;
+        }
+     });
+}
+
+static const char *
+dir_current_name (dir_search_state * s)
+{
+  static char result [CCHMAXPATH];
+  strcpy (result, ((s -> info) . achName));
+  dir_find_next (s);
+  return (result);
+}
+
+const char *
+OS_directory_read (unsigned int index)
+{
+  dir_search_state * s = (REFERENCE_DIR_SEARCH_STATE (index));
+  return (((s -> count) == 0) ? 0 : (dir_current_name (s)));
+}
+
+const char *
+OS_directory_read_matching (unsigned int index, const char * prefix)
+{
+  dir_search_state * s = (REFERENCE_DIR_SEARCH_STATE (index));
+  unsigned int n = (strlen (prefix));
+  while (1)
+    {
+      if ((s -> count) == 0)
+       return (0);
+      if ((strnicmp (((s -> info) . achName), prefix, n)) == 0)
+       return (dir_current_name (s));
+      dir_find_next (s);
+    }
+}
+
+void
+OS_directory_close (unsigned int index)
+{
+  dir_search_state * s = (REFERENCE_DIR_SEARCH_STATE (index));
+  STD_API_CALL (dos_find_close, (s -> handle));
+  DEALLOCATE_DIR_SEARCH_STATE (s);
+}
+\f
+static const char *
+filename_extension (const char * filename)
+{
+  const char * start;
+  const char * period;
+  start = (strrchr (filename, '\\'));
+  start = ((start == 0) ? filename : (start + 1));
+  period = (strrchr (start, '.'));
+  return ((period == 0) ? (filename + (strlen (filename))) : period);
+}
+
+static const char *
+make_pathname (const char * directory, const char * name)
+{
+  unsigned int dirlen = (strlen (directory));
+  unsigned int namlen = (strlen (name));
+  char * result = (OS_malloc (dirlen + namlen + 2));
+  strcpy (result, directory);
+  if ((dirlen > 0) && ((result [dirlen - 1]) != '\\'))
+    strcat (result, "\\");
+  strcat (result, name);
+  return (result);
+}
+
+char *
+OS2_remove_trailing_backslash (const char * filename)
+{
+  static char result [CCHMAXPATH];
+  unsigned int len = (strlen (filename));
+  if ((len == 0) || ((filename [len - 1]) != '\\'))
+    return ((char *) filename);
+  FASTCOPY (filename, result, (len - 1));
+  (result [len - 1]) = '\0';
+  return (result);
+}
diff --git a/v7/src/microcode/os2io.c b/v7/src/microcode/os2io.c
new file mode 100644 (file)
index 0000000..1584326
--- /dev/null
@@ -0,0 +1,316 @@
+/* -*-C-*-
+
+$Id: os2io.c,v 1.1 1994/11/28 03:42:57 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+
+extern void add_reload_cleanup (void (*) (void));
+extern void OS2_initialize_console_channel (Tchannel);
+extern void OS2_initialize_pipe_channel (Tchannel);
+\f
+static enum channel_type handle_channel_type (LHANDLE);
+
+size_t OS_channel_table_size;
+struct channel * OS2_channel_table;
+Tchannel * OS2_channel_pointer_table;
+const int OS_have_select_p = 0;
+
+void
+OS2_initialize_channels (void)
+{
+  OS_channel_table_size = (OS2_MAX_FILE_HANDLES ());
+  OS2_channel_table =
+    (OS_malloc (OS_channel_table_size * (sizeof (struct channel))));
+  OS2_channel_pointer_table =
+    (OS_malloc (OS_channel_table_size * (sizeof (Tchannel))));
+  {
+    Tchannel channel;
+    for (channel = 0; (channel < OS_channel_table_size); channel += 1)
+      {
+       (CHANNEL_OPEN (channel)) = 0;
+       (OS2_channel_pointer_table [channel]) = channel;
+      }
+  }
+  add_reload_cleanup (OS2_channel_close_all_noerror);
+  SET_MSG_TYPE_LENGTH (mt_readahead, sm_readahead_t);
+  SET_MSG_TYPE_LENGTH (mt_readahead_ack, sm_readahead_ack_t);
+}
+
+void
+OS2_reset_channels (void)
+{
+  OS_free (OS2_channel_table);
+  OS2_channel_table = 0;
+  OS_channel_table_size = 0;
+}
+
+void
+OS2_channel_operation (Tchannel channel, chop_t operation,
+                      choparg_t arg1, choparg_t arg2, choparg_t arg3)
+{
+  ((* (CHANNEL_OPERATOR (channel))) (channel, operation, arg1, arg2, arg3));
+}
+\f
+Tchannel
+OS2_make_channel (LHANDLE handle, unsigned int mode)
+{
+  Tchannel channel = 0;
+  enum channel_type type;
+  transaction_begin ();
+  OS2_handle_close_on_abort (handle);
+  while (1)
+    {
+      if (channel == OS_channel_table_size)
+       OS2_error_out_of_channels ();
+      if (! (CHANNEL_OPEN (channel)))
+       break;
+      channel += 1;
+    }
+  type = (handle_channel_type (handle));
+  (CHANNEL_HANDLE (channel)) = handle;
+  (CHANNEL_TYPE (channel)) = type;
+  (CHANNEL_OPEN (channel)) = 1;
+  (CHANNEL_INTERNAL (channel)) = 0;
+  (CHANNEL_NONBLOCKING (channel)) = 0;
+  (CHANNEL_INPUTP (channel)) = ((mode & CHANNEL_READ) != 0);
+  (CHANNEL_OUTPUTP (channel)) = ((mode & CHANNEL_WRITE) != 0);
+  (CHANNEL_OPERATOR (channel)) = 0;
+  switch (type)
+    {
+    case channel_type_console:
+      OS2_initialize_console_channel (channel);
+      break;
+    case channel_type_unnamed_pipe:
+      OS2_initialize_pipe_channel (channel);
+      break;
+    }
+  transaction_commit ();
+  return (channel);
+}
+
+static enum channel_type
+handle_channel_type (LHANDLE handle)
+{
+  /* **** For now, limit channel types to those that we know how to
+     handle in a reasonable way.  Later we can add other types if
+     needed.  However, we probably won't need other types since pipes
+     and files are sufficient to do nearly anything, and the console
+     will be flushed when the PM support is installed.  */
+  ULONG type;
+  ULONG flags;
+  if ((dos_query_h_type (handle, (&type), (&flags))) == NO_ERROR)
+    switch (type & 0xff)
+      {
+      case FHT_DISKFILE:
+       return (channel_type_file);
+      case FHT_CHRDEV:
+       if ((flags & 0x3) != 0)
+         return (channel_type_console);
+       else if ((flags & 0x4) != 0)
+         /* return (channel_type_null); */
+         break;
+       else if ((flags & 0x8) != 0)
+         /* return (channel_type_clock); */
+         break;
+       else
+         /* return (channel_type_character_device); */
+         break;
+      case FHT_PIPE:
+       {
+         APIRET rc = (dos_query_n_p_h_state (handle, (&flags)));
+         if ((rc == NO_ERROR) || (rc == ERROR_PIPE_NOT_CONNECTED))
+           /* return (channel_type_named_pipe); */
+           break;
+         else
+           return (channel_type_unnamed_pipe);
+       }
+      }
+  OS2_error_anonymous ();
+  return (channel_type_unknown);
+}
+\f
+void
+OS_channel_close (Tchannel channel)
+{
+  if (! (CHANNEL_INTERNAL (channel)))
+    {
+      if (CHANNEL_ABSTRACT_P (channel))
+       OS2_channel_operation (channel, chop_close, 0, 0, 0);
+      else
+       STD_API_CALL (dos_close, (CHANNEL_HANDLE (channel)));
+      (CHANNEL_OPEN (channel)) = 0;
+    }
+}
+
+void
+OS2_channel_close_all_noerror (void)
+{
+  Tchannel channel;
+  for (channel = 0; (channel < OS_channel_table_size); channel += 1)
+    if (CHANNEL_OPEN (channel))
+      OS_channel_close_noerror (channel);
+}
+
+void
+OS_channel_close_noerror (Tchannel channel)
+{
+  transaction_begin ();
+  OS2_ignore_errors ();
+  OS_channel_close (channel);
+  transaction_commit ();
+}
+
+static void
+OS_channel_close_on_abort_1 (void * cp)
+{
+  OS_channel_close_noerror (* ((Tchannel *) cp));
+}
+
+void
+OS_channel_close_on_abort (Tchannel channel)
+{
+  Tchannel * cp = (dstack_alloc (sizeof (Tchannel)));
+  (*cp) = (channel);
+  transaction_record_action (tat_abort, OS_channel_close_on_abort_1, cp);
+}
+
+static void
+OS2_handle_close_on_abort_1 (void * hp)
+{
+  (void) dos_close (* ((LHANDLE *) hp));
+}
+
+void
+OS2_handle_close_on_abort (LHANDLE h)
+{
+  LHANDLE * hp = (dstack_alloc (sizeof (LHANDLE)));
+  (*hp) = h;
+  transaction_record_action (tat_abort, OS2_handle_close_on_abort_1, hp);
+}
+
+int
+OS_channel_open_p (Tchannel channel)
+{
+  return (CHANNEL_OPEN (channel));
+}
+
+enum channel_type
+OS_channel_type (Tchannel channel)
+{
+  return (CHANNEL_TYPE (channel));
+}
+\f
+long
+OS_channel_read (Tchannel channel, void * buffer, size_t nbytes)
+{
+  long n;
+  if (nbytes == 0)
+    return (0);
+  if (CHANNEL_ABSTRACT_P (channel))
+    OS2_channel_operation (channel, chop_read,
+                          ((choparg_t) buffer),
+                          ((choparg_t) nbytes),
+                          ((choparg_t) (& n)));
+  else
+    STD_API_CALL
+      (dos_read, ((CHANNEL_HANDLE (channel)), buffer, nbytes,
+                 ((ULONG *) (& n))));
+  return (n);
+}
+
+long
+OS_channel_write (Tchannel channel, const void * buffer, size_t nbytes)
+{
+  long n;
+  if (nbytes == 0)
+    return (0);
+  if (CHANNEL_ABSTRACT_P (channel))
+    OS2_channel_operation (channel,
+                          chop_write,
+                          ((choparg_t) buffer),
+                          ((choparg_t) nbytes),
+                          ((choparg_t) (& n)));
+  else
+    STD_API_CALL
+      (dos_write, ((CHANNEL_HANDLE (channel)), ((void *) buffer), nbytes,
+                  ((ULONG *) (& n))));
+  return (n);
+}
+
+int
+OS_channel_nonblocking_p (Tchannel channel)
+{
+  return (CHANNEL_NONBLOCKING (channel));
+}
+
+void
+OS_channel_nonblocking (Tchannel channel)
+{
+  (CHANNEL_NONBLOCKING (channel)) = 1;
+}
+
+void
+OS_channel_blocking (Tchannel channel)
+{
+  (CHANNEL_NONBLOCKING (channel)) = 0;
+}
+\f
+size_t
+OS_channel_read_load_file (Tchannel channel, void * buffer, size_t nbytes)
+{
+  ULONG nread;
+  if ((dos_read ((CHANNEL_HANDLE (channel)), buffer, nbytes, (&nread))) != 0)
+    return (0);
+  return (nread);
+}
+
+size_t
+OS_channel_write_dump_file (Tchannel channel,
+                           const void * buffer,
+                           size_t nbytes)
+{
+  ULONG nwrite;
+  if ((dos_write
+       ((CHANNEL_HANDLE (channel)), ((void *) buffer), nbytes, (&nwrite)))
+      != 0)
+    return (0);
+  return (nwrite);
+}
+
+void
+OS_channel_write_string (Tchannel channel, const char * string)
+{
+  unsigned long length = (strlen (string));
+  if ((OS_channel_write (channel, string, length)) != length)
+    OS2_error_anonymous ();
+}
diff --git a/v7/src/microcode/os2io.h b/v7/src/microcode/os2io.h
new file mode 100644 (file)
index 0000000..8e39d16
--- /dev/null
@@ -0,0 +1,100 @@
+/* -*-C-*-
+
+$Id: os2io.h,v 1.1 1994/11/28 03:42:58 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#ifndef SCM_OS2IO_H
+#define SCM_OS2IO_H
+
+#include "osio.h"
+\f
+typedef enum
+{
+  chop_close,
+  chop_read,
+  chop_write,
+  chop_input_buffered,
+  chop_input_flush,
+  chop_output_cooked,
+  chop_output_flush,
+  chop_output_drain
+} chop_t;
+
+typedef void * choparg_t;
+typedef void (* channel_op_t)
+     (Tchannel, chop_t, choparg_t, choparg_t, choparg_t);
+
+struct channel
+{
+  LHANDLE handle;
+  channel_op_t operator;
+  void * operator_context;
+  enum channel_type type;
+  unsigned int open : 1;
+  unsigned int internal : 1;
+  unsigned int nonblocking : 1;
+  unsigned int inputp : 1;
+  unsigned int outputp : 1;
+};
+
+#define _CHANNEL(c) (OS2_channel_table [(c)])
+#define CHANNEL_POINTER(c) (& (OS2_channel_pointer_table [(c)]))
+#define CHANNEL_HANDLE(c) ((_CHANNEL (c)) . handle)
+#define CHANNEL_OPERATOR(c) ((_CHANNEL (c)) . operator)
+#define CHANNEL_OPERATOR_CONTEXT(c) ((_CHANNEL (c)) . operator_context)
+#define CHANNEL_TYPE(c) ((_CHANNEL (c)) . type)
+#define CHANNEL_OPEN(c) ((_CHANNEL (c)) . open)
+#define CHANNEL_INTERNAL(c) ((_CHANNEL (c)) . internal)
+#define CHANNEL_NONBLOCKING(c) ((_CHANNEL (c)) . nonblocking)
+#define CHANNEL_INPUTP(c) ((_CHANNEL (c)) . inputp)
+#define CHANNEL_OUTPUTP(c) ((_CHANNEL (c)) . outputp)
+
+#define CHANNEL_ABSTRACT_P(c) ((CHANNEL_OPERATOR (c)) != 0)
+
+#define channel_type_console channel_type_os2_console
+#define channel_type_unnamed_pipe channel_type_os2_unnamed_pipe
+#define channel_type_named_pipe channel_type_os2_named_pipe
+
+/* Channel modes: */
+#define CHANNEL_READ   1
+#define CHANNEL_WRITE  2
+
+extern struct channel * OS2_channel_table;
+extern Tchannel * OS2_channel_pointer_table;
+extern Tchannel OS2_make_channel (LHANDLE, unsigned int);
+extern void OS2_channel_close_all_noerror (void);
+extern void OS_channel_close_on_abort (Tchannel);
+extern void OS2_handle_close_on_abort (LHANDLE);
+extern void OS2_channel_operation
+  (Tchannel, chop_t, choparg_t, choparg_t, choparg_t);
+
+#endif /* SCM_OS2IO_H */
diff --git a/v7/src/microcode/os2msg.c b/v7/src/microcode/os2msg.c
new file mode 100644 (file)
index 0000000..990a80c
--- /dev/null
@@ -0,0 +1,506 @@
+/* -*-C-*-
+
+$Id: os2msg.c,v 1.1 1994/11/28 03:42:58 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+/* Master Message Queue */
+
+#include "os2.h"
+
+static qid_t allocate_qid (void);
+static void OS2_initialize_message_lengths (void);
+static void read_and_dispatch_nonblocking (tqueue_t *);
+static void read_and_dispatch_one_blocking (tqueue_t *);
+static void write_subqueue (msg_t *);
+static msg_t * read_subqueue (qid_t);
+static int subqueue_emptyp (qid_t);
+static int read_tqueue (tqueue_t *, int);
+static void write_tqueue (tqueue_t *, msg_t *);
+static int read_std_tqueue (tqueue_t *, int);
+static void write_std_tqueue (tqueue_t *, msg_t *);
+static tqueue_t * make_scm_tqueue (void);
+static int read_scm_tqueue (tqueue_t *, int);
+static void write_scm_tqueue (tqueue_t *, msg_t *);
+static void process_interrupt_messages (void);
+static int read_pm_tqueue (tqueue_t *, int);
+static void write_pm_tqueue (tqueue_t *, msg_t *);
+\f
+typedef struct msg_list_s
+{
+  msg_t * message;
+  struct msg_list_s * next;
+} msg_list_t;
+
+typedef struct
+{
+  unsigned int allocatedp : 1; /* queue allocated? */
+  unsigned int openp : 1;      /* queue open? */
+  qid_t twin;                  /* other end of connection */
+  tqueue_t * tqueue;           /* thread queue for reception */
+  msg_list_t * subqueue_head;  /* head of receiving subqueue */
+  msg_list_t * subqueue_tail;  /* tail of receiving subqueue */
+} iqid_t;
+
+static iqid_t queue_array [QID_MAX + 1];
+static HMTX qid_lock;
+
+tqueue_t * OS2_scheme_tqueue;
+static qid_t OS2_interrupt_qid_local;
+qid_t OS2_interrupt_qid;
+
+#define _QID(q) (queue_array [(q)])
+#define QID_ALLOCATEDP(q) ((_QID (q)) . allocatedp)
+#define QID_TWIN(q) ((_QID (q)) . twin)
+#define QID_TQUEUE(q) ((_QID (q)) . tqueue)
+#define QID_SUBQUEUE_HEAD(q) ((_QID (q)) . subqueue_head)
+#define QID_SUBQUEUE_TAIL(q) ((_QID (q)) . subqueue_tail)
+
+#define MSG_QUEUE_TYPE(m) 0
+#define MSG_QUEUE_PRIORITY(m) 0
+
+void
+OS2_initialize_message_queues (void)
+{
+  {
+    qid_t qid = 0;
+    while (1)
+      {
+       (QID_ALLOCATEDP (qid)) = 0;
+       (QID_TQUEUE (qid)) = 0;
+       (QID_TWIN (qid)) = QID_NONE;
+       (QID_SUBQUEUE_HEAD (qid)) = 0;
+       (QID_SUBQUEUE_TAIL (qid)) = 0;
+       if (qid == QID_MAX)
+         break;
+       qid += 1;
+      }
+  }
+  OS2_initialize_message_lengths ();
+  SET_MSG_TYPE_LENGTH (mt_console_interrupt, sm_console_interrupt_t);
+  SET_MSG_TYPE_LENGTH (mt_timer_event, sm_timer_event_t);
+  qid_lock = (OS2_create_mutex_semaphore ());
+  OS2_scheme_tqueue = (make_scm_tqueue ());
+  OS2_make_qid_pair ((&OS2_interrupt_qid_local), (&OS2_interrupt_qid));
+  OS2_open_qid (OS2_interrupt_qid_local, OS2_scheme_tqueue);
+}
+\f
+void
+OS2_make_qid_pair (qid_t * pq1, qid_t * pq2)
+{
+  qid_t q1 = (allocate_qid ());
+  qid_t q2 = (allocate_qid ());
+  (QID_TWIN (q1)) = q2;
+  (QID_TWIN (q2)) = q1;
+  (*pq1) = q1;
+  (*pq2) = q2;
+}
+
+static qid_t
+allocate_qid (void)
+{
+  unsigned int qid = 0;
+  OS2_request_mutex_semaphore (qid_lock);
+  while (1)
+    {
+      if ((QID_ALLOCATEDP (qid)) == 0)
+       break;
+      if (qid == QID_MAX)
+       OS2_logic_error ("No more QIDs available.");
+      qid += 1;
+    }
+  (QID_ALLOCATEDP (qid)) = 1;
+  (QID_TQUEUE (qid)) = 0;
+  (QID_TWIN (qid)) = QID_NONE;
+  (QID_SUBQUEUE_HEAD (qid)) = 0;
+  (QID_SUBQUEUE_TAIL (qid)) = 0;
+  OS2_release_mutex_semaphore (qid_lock);
+  return (qid);
+}
+
+void
+OS2_open_qid (qid_t qid, tqueue_t * tqueue)
+{
+  if ((QID_TQUEUE (qid)) != 0)
+    OS2_logic_error ("Reopening already open QID.");
+  if (tqueue == 0)
+    OS2_logic_error ("Null tqueue passed to OS2_open_qid.");
+  (QID_TQUEUE (qid)) = tqueue;
+}
+
+int
+OS2_qid_openp (qid_t qid)
+{
+  return ((QID_TQUEUE (qid)) != 0);
+}
+
+void
+OS2_close_qid (qid_t qid)
+{
+  {
+    msg_list_t * elt = (QID_SUBQUEUE_HEAD (qid));
+    while (elt != 0)
+      {
+       msg_list_t * next = (elt -> next);
+       OS_free (elt);
+       elt = next;
+      }
+  }
+  (QID_SUBQUEUE_HEAD (qid)) = 0;
+  (QID_SUBQUEUE_TAIL (qid)) = 0;
+  (QID_TQUEUE (qid)) = 0;
+  OS2_request_mutex_semaphore (qid_lock);
+  {
+    qid_t twin = (QID_TWIN (qid));
+    if (twin != QID_NONE)
+      {
+       (QID_TWIN (twin)) = QID_NONE;
+       (QID_TWIN (qid)) = QID_NONE;
+      }
+  }
+  (QID_ALLOCATEDP (qid)) = 0;
+  OS2_release_mutex_semaphore (qid_lock);
+}
+\f
+/* Message Lengths */
+
+#define MESSAGE_LENGTH(t) (message_lengths [(unsigned int) (t)])
+static msg_length_t message_lengths [MSG_TYPE_SUP];
+
+static void
+OS2_initialize_message_lengths (void)
+{
+  unsigned int type = 0;
+  while (1)
+    {
+      (MESSAGE_LENGTH (type)) = 0;
+      if (type == MSG_TYPE_MAX)
+       break;
+      type += 1;
+    }
+}
+
+msg_length_t
+OS2_message_type_length (msg_type_t type)
+{
+  msg_length_t length = (MESSAGE_LENGTH (type));
+  if (length == 0)
+    OS2_logic_error ("Message type has unknown length.");
+  return (length);
+}
+
+void
+OS2_set_message_type_length (msg_type_t type, msg_length_t length)
+{
+  (MESSAGE_LENGTH (type)) = length;
+}
+\f
+/* Message Transmission and Reception */
+
+msg_t *
+OS2_create_message (msg_type_t type)
+{
+  /* Do allocation carefully to prevent infinite loop when signalling
+     "out of memory" condition.  */
+  msg_t * message =
+    (malloc ((unsigned long) (OS2_message_type_length (type))));
+  if (message == 0)
+    if ((type == mt_syscall_error)
+       && ((SM_SYSCALL_ERROR_CODE (message)) == ERROR_NOT_ENOUGH_MEMORY)
+       && ((SM_SYSCALL_ERROR_NAME (message)) == syscall_malloc))
+      OS2_logic_error ("Unable to allocate memory for error message.");
+    else
+      OS2_error_system_call (ERROR_NOT_ENOUGH_MEMORY, syscall_malloc);
+  (_MSG_TYPE (message)) = ((unsigned char) type);
+  return (message);
+}
+
+void
+OS2_destroy_message (msg_t * message)
+{
+  OS_free ((void *) message);
+}
+
+void
+OS2_send_message (qid_t qid, msg_t * message)
+{
+  qid_t twin = (QID_TWIN (qid));
+  tqueue_t * tqueue = (QID_TQUEUE (twin));
+  if (tqueue == 0)
+    OS2_logic_error ("Write to closed QID.");
+  (MSG_SENDER (message)) = twin;
+  write_tqueue (tqueue, message);
+}
+
+msg_t *
+OS2_receive_message (qid_t qid, int blockp)
+{
+  tqueue_t * tqueue = (QID_TQUEUE (qid));
+  msg_t * message;
+  while (1)
+    {
+      read_and_dispatch_nonblocking (tqueue);
+      if ((TQUEUE_TYPE (tqueue)) == tqt_scm)
+       {
+         process_interrupt_messages ();
+         deliver_pending_interrupts ();
+       }
+      message = (read_subqueue (qid));
+      if ((!blockp) || (message != 0))
+       break;
+      read_and_dispatch_one_blocking (tqueue);
+    }
+  return (message);
+}
+
+static void
+read_and_dispatch_nonblocking (tqueue_t * tqueue)
+{
+  while (read_tqueue (tqueue, 0))
+    ;
+}
+
+static void
+read_and_dispatch_one_blocking (tqueue_t * tqueue)
+{
+  (void) read_tqueue (tqueue, 1);
+}
+\f
+static void
+write_subqueue (msg_t * message)
+{
+  qid_t qid = (MSG_SENDER (message));
+  msg_list_t * tail = (QID_SUBQUEUE_TAIL (qid));
+  msg_list_t * elt = (OS_malloc (sizeof (struct msg_list_s)));
+  (elt -> message) = message;
+  (elt -> next) = 0;
+  if (tail == 0)
+    (QID_SUBQUEUE_HEAD (qid)) = elt;
+  else
+    (tail -> next) = elt;
+  (QID_SUBQUEUE_TAIL (qid)) = elt;
+}
+
+static msg_t *
+read_subqueue (qid_t qid)
+{
+  msg_list_t * head = (QID_SUBQUEUE_HEAD (qid));
+  if (head == 0)
+    return (0);
+  {
+    msg_t * message = (head -> message);
+    (QID_SUBQUEUE_HEAD (qid)) = (head -> next);
+    if ((head -> next) == 0)
+      (QID_SUBQUEUE_TAIL (qid)) = 0;
+    OS_free (head);
+    return (message);
+  }
+}
+
+static int
+subqueue_emptyp (qid_t qid)
+{
+  return ((QID_SUBQUEUE_HEAD (qid)) == 0);
+}
+
+static int
+read_tqueue (tqueue_t * tqueue, int blockp)
+{
+  switch (TQUEUE_TYPE (tqueue))
+    {
+    case tqt_std:
+      return (read_std_tqueue (tqueue, blockp));
+    case tqt_scm:
+      return (read_scm_tqueue (tqueue, blockp));
+    case tqt_pm:
+      return (read_pm_tqueue (tqueue, blockp));
+    }
+}
+
+static void
+write_tqueue (tqueue_t * tqueue, msg_t * message)
+{
+  switch (TQUEUE_TYPE (tqueue))
+    {
+    case tqt_std:
+      write_std_tqueue (tqueue, message);
+      break;
+    case tqt_scm:
+      write_scm_tqueue (tqueue, message);
+      break;
+    case tqt_pm:
+      write_pm_tqueue (tqueue, message);
+      break;
+    }
+}
+\f
+typedef struct
+{
+  tqueue_type_t type;
+  HQUEUE queue;                        /* queue */
+  HEV event;                   /* associated event semaphore */
+} std_tqueue_t;
+#define STD_TQUEUE_QUEUE(q) (((std_tqueue_t *) (q)) -> queue)
+#define STD_TQUEUE_EVENT(q) (((std_tqueue_t *) (q)) -> event)
+
+tqueue_t *
+OS2_make_std_tqueue (void)
+{
+  tqueue_t * tqueue = (OS_malloc (sizeof (std_tqueue_t)));
+  (TQUEUE_TYPE (tqueue)) = tqt_std;
+  (STD_TQUEUE_QUEUE (tqueue)) = (OS2_create_queue (QUE_FIFO));
+  (STD_TQUEUE_EVENT (tqueue)) = (OS2_create_event_semaphore ());
+  return (tqueue);
+}
+
+static int
+read_std_tqueue (tqueue_t * tqueue, int blockp)
+{
+  ULONG type;
+  ULONG length;
+  PVOID data;
+  msg_t * message;
+  const char * s = "Non-message read from message queue.";
+
+  if (!OS2_read_queue ((STD_TQUEUE_QUEUE (tqueue)),
+                      (&type),
+                      (&length),
+                      (&data),
+                      (blockp ? NULLHANDLE : (STD_TQUEUE_EVENT (tqueue)))))
+    return (0);
+  if (length < (sizeof (msg_t)))
+    OS2_logic_error (s);
+  message = ((msg_t *) data);
+  if ((type != 0) || (length != (MSG_LENGTH (message))))
+    OS2_logic_error (s);
+  write_subqueue (message);
+  return (1);
+}
+
+static void
+write_std_tqueue (tqueue_t * tqueue, msg_t * message)
+{
+  OS2_write_queue ((STD_TQUEUE_QUEUE (tqueue)),
+                  0,
+                  (MSG_LENGTH (message)),
+                  ((PVOID) message),
+                  0);
+}
+\f
+static tqueue_t *
+make_scm_tqueue (void)
+{
+  tqueue_t * tqueue = (OS2_make_std_tqueue ());
+  (TQUEUE_TYPE (tqueue)) = tqt_scm;
+  return (tqueue);
+}
+
+static int
+read_scm_tqueue (tqueue_t * tqueue, int blockp)
+{
+  /* The handling of the interrupt bit is a little tricky.  We clear
+     the bit, then handle any events, and finally clear the bit again.
+     If the bit is set during the second clear, we must loop since
+     another event might have been queued in the window between the
+     last read and the second clear -- and since we cleared the bit no
+     one else is going to look at the queue until another event comes
+     along.
+     
+     This code serves two purposes.  First, this is the only way to
+     reliably clear the interrupt bit to avoid having an event stuck
+     in the queue and the Scheme thread not bothering to look.
+     Second, if we arrive at this read-dispatch loop by some means
+     other than the attention-interrupt mechanism, this will clear the
+     bit and thus avoid ever invoking the mechanism.  */
+  int result = 0;
+  (void) test_and_clear_attention_interrupt ();
+  do
+    if (read_std_tqueue (tqueue, blockp))
+      {
+       result = 1;
+       /* If blockp was set, after we have read one message we read
+          any remaining messages in non-blocking mode.  */
+       blockp = 0;
+      }
+  while (test_and_clear_attention_interrupt ());
+  return (result);
+}
+
+static void
+write_scm_tqueue (tqueue_t * tqueue, msg_t * message)
+{
+  write_std_tqueue (tqueue, message);
+  request_attention_interrupt ();
+}
+
+void
+OS2_handle_attention_interrupt (void)
+{
+  read_and_dispatch_nonblocking (QID_TQUEUE (OS2_interrupt_qid_local));
+  process_interrupt_messages ();
+}
+
+static void
+process_interrupt_messages (void)
+{
+  /* Reads all of the interrupts out of the interrupt queue, and sets
+     the corresponding bits in the interrupt word.  */
+  while (1)
+    {
+      msg_t * message = (read_subqueue (OS2_interrupt_qid_local));
+      if (message == 0)
+       break;
+      switch (MSG_TYPE (message))
+       {
+       case mt_console_interrupt:
+         tty_set_next_interrupt_char (SM_CONSOLE_INTERRUPT_CODE (message));
+         break;
+       case mt_timer_event:
+         request_timer_interrupt ();
+         break;
+       default:
+         OS2_logic_error ("Illegal message type in interrupt queue.");
+         break;
+       }
+      OS2_destroy_message (message);
+    }
+}
+\f
+static int
+read_pm_tqueue (tqueue_t * tqueue, int blockp)
+{
+  return (0);
+}
+
+static void
+write_pm_tqueue (tqueue_t * tqueue, msg_t * message)
+{
+}
diff --git a/v7/src/microcode/os2msg.h b/v7/src/microcode/os2msg.h
new file mode 100644 (file)
index 0000000..ac02bae
--- /dev/null
@@ -0,0 +1,120 @@
+/* -*-C-*-
+
+$Id: os2msg.h,v 1.1 1994/11/28 03:42:59 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#ifndef SCM_OS2MSG_H
+#define SCM_OS2MSG_H
+\f
+typedef enum
+{
+  mt_readahead,
+  mt_readahead_ack,
+  mt_console_interrupt,
+  mt_error,
+  mt_kill_request,
+  mt_syscall_error,
+  mt_timer_event,
+  mt_supremum
+} msg_type_t;
+#define MSG_TYPE_SUP ((unsigned int) mt_supremum)
+#define MSG_TYPE_MAX (MSG_TYPE_SUP - 1)
+
+typedef unsigned char qid_t;
+#define QID_MAX (UCHAR_MAX - 1)
+#define QID_NONE UCHAR_MAX
+
+typedef unsigned short msg_length_t;
+#define MSG_LENGTH_MAX USHRT_MAX
+
+/* Fields of message header:
+   type: small integer classifying the type of message
+   sender: qid identifying the message sender (used for replies)
+   */
+
+#define DECLARE_MSG_HEADER_FIELDS                                      \
+  unsigned char type;                                                  \
+  qid_t sender
+
+typedef struct
+{
+  DECLARE_MSG_HEADER_FIELDS;
+} msg_t;
+
+#define _MSG(m) ((msg_t *) (m))
+#define _MSG_TYPE(m) ((_MSG (m)) -> type)
+#define MSG_TYPE(m) ((msg_type_t) (_MSG_TYPE (m)))
+#define MSG_SENDER(m) ((_MSG (m)) -> sender)
+
+typedef enum
+{
+  tqt_std,
+  tqt_scm,
+  tqt_pm
+} tqueue_type_t;
+
+typedef struct
+{
+  tqueue_type_t type;
+} tqueue_t;
+#define TQUEUE_TYPE(q) (((tqueue_t *) (q)) -> type)
+
+extern tqueue_t * OS2_scheme_tqueue;
+extern qid_t OS2_interrupt_qid;
+
+extern void OS2_make_qid_pair (qid_t *, qid_t *);
+extern void OS2_open_qid (qid_t, tqueue_t *);
+extern int OS2_qid_openp (qid_t);
+extern void OS2_close_qid (qid_t);
+extern msg_length_t OS2_message_type_length (msg_type_t);
+extern void OS2_set_message_type_length (msg_type_t, msg_length_t);
+extern msg_t * OS2_create_message (msg_type_t);
+extern void OS2_destroy_message (msg_t *);
+extern void OS2_send_message (qid_t, msg_t *);
+extern msg_t * OS2_receive_message (qid_t, int);
+extern tqueue_t * OS2_make_std_tqueue (void);
+
+#define MSG_LENGTH(m) (OS2_message_type_length (MSG_TYPE (m)))
+
+#define SET_MSG_TYPE_LENGTH(t, s)                                      \
+  OS2_set_message_type_length ((t), (sizeof (s)))
+
+typedef struct
+{
+  DECLARE_MSG_HEADER_FIELDS;
+  int code;
+} sm_console_interrupt_t;
+#define SM_CONSOLE_INTERRUPT_CODE(m) (((sm_console_interrupt_t *) (m)) -> code)
+
+typedef msg_t sm_timer_event_t;
+
+#endif /* SCM_OS2MSG_H */
diff --git a/v7/src/microcode/os2pipe.c b/v7/src/microcode/os2pipe.c
new file mode 100644 (file)
index 0000000..50bfa22
--- /dev/null
@@ -0,0 +1,125 @@
+/* -*-C-*-
+
+$Id: os2pipe.c,v 1.1 1994/11/28 03:42:59 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+
+static void input_pipe_operator
+  (Tchannel, chop_t, choparg_t, choparg_t, choparg_t);
+static void input_pipe_thread (void *);
+\f
+void
+OS_make_pipe (Tchannel * readerp, Tchannel * writerp)
+{
+  HFILE hread;
+  HFILE hwrite;
+  STD_API_CALL (dos_create_pipe, ((&hread), (&hwrite), 4096));
+  transaction_begin ();
+  OS2_handle_close_on_abort (hwrite);
+  (*readerp) = (OS2_make_channel (hread, CHANNEL_READ));
+  transaction_commit ();
+  transaction_begin ();
+  OS_channel_close_on_abort (*readerp);
+  (*writerp) = (OS2_make_channel (hwrite, CHANNEL_WRITE));
+  transaction_commit ();
+}
+\f
+void
+OS2_initialize_pipe_channel (Tchannel channel)
+{
+  if (CHANNEL_INPUTP (channel))
+    {
+      channel_context_t * context = (OS2_make_channel_context ());
+      (CHANNEL_OPERATOR_CONTEXT (channel)) = context;
+      OS2_open_qid ((CHANNEL_CONTEXT_READER_QID (context)), OS2_scheme_tqueue);
+      (void) OS2_beginthread
+       (input_pipe_thread, (CHANNEL_POINTER (channel)), 0);
+      (CHANNEL_OPERATOR (channel)) = input_pipe_operator;
+    }
+}
+
+static void
+input_pipe_operator (Tchannel channel, chop_t operation,
+                    choparg_t arg1, choparg_t arg2, choparg_t arg3)
+{
+  switch (operation)
+    {
+    case chop_read:
+      (* ((long *) arg3))
+       = (channel_thread_read (channel, ((char *) arg1), ((size_t) arg2)));
+      break;
+    case chop_close:
+      channel_thread_close (channel);
+      break;
+    default:
+      OS2_logic_error ("Unknown operation for input pipe.");
+      break;
+    }
+}
+
+static void
+input_pipe_thread (void * arg)
+{
+  Tchannel channel = (* ((Tchannel *) arg));
+  LHANDLE handle = (CHANNEL_HANDLE (channel));
+  channel_context_t * context = (CHANNEL_OPERATOR_CONTEXT (channel));
+  qid_t qid = (CHANNEL_CONTEXT_WRITER_QID (context));
+  OS2_open_qid (qid, (OS2_make_std_tqueue ()));
+  (void) OS2_thread_initialize (qid);
+  while (1)
+    {
+      msg_t * message = (OS2_make_readahead ());
+      APIRET rc
+       = (dos_read (handle,
+                    (SM_READAHEAD_DATA (message)),
+                    (sizeof (SM_READAHEAD_DATA (message))),
+                    (& (SM_READAHEAD_SIZE (message)))));
+      int eofp;
+      if (rc == NO_ERROR)
+       eofp = ((SM_READAHEAD_SIZE (message)) == 0);
+      else
+       {
+         OS2_destroy_message (message);
+         if (rc == ERROR_INVALID_HANDLE)
+           /* Handle was closed on us -- no need to do anything else.  */
+           break;
+         message = (OS2_make_syscall_error (rc, syscall_dos_read));
+         eofp = (rc == ERROR_BROKEN_PIPE);
+       }
+      OS2_send_message (qid, message);
+      if (eofp)
+       break;
+      OS2_wait_for_readahead_ack (qid);
+    }
+  OS2_endthread ();
+}
diff --git a/v7/src/microcode/os2term.c b/v7/src/microcode/os2term.c
new file mode 100644 (file)
index 0000000..c22a2dd
--- /dev/null
@@ -0,0 +1,163 @@
+/* -*-C-*-
+
+$Id: os2term.c,v 1.1 1994/11/28 03:43:00 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+\f
+unsigned int
+OS_terminal_get_ispeed (Tchannel channel)
+{
+  return (9600);
+}
+
+unsigned int
+OS_terminal_get_ospeed (Tchannel channel)
+{
+  return (9600);
+}
+
+void
+OS_terminal_set_ispeed (Tchannel channel, unsigned int baud)
+{
+}
+
+void
+OS_terminal_set_ospeed (Tchannel channel, unsigned int baud)
+{
+}
+
+unsigned int
+arg_baud_index (unsigned int argument)
+{
+  return (arg_nonnegative_integer (argument));
+}
+
+unsigned int
+OS_baud_index_to_rate (unsigned int index)
+{
+  return (index);
+}
+
+int
+OS_baud_rate_to_index (unsigned int rate)
+{
+  return (rate);
+}
+
+unsigned int
+OS_terminal_state_size (void)
+{
+  return (0);
+}
+
+void
+OS_terminal_get_state (Tchannel channel, PTR statep)
+{
+}
+
+void
+OS_terminal_set_state (Tchannel channel, PTR statep)
+{
+}
+\f
+int
+OS_terminal_cooked_output_p (Tchannel channel)
+{
+  int flag;
+  OS2_channel_operation (channel, chop_output_cooked,
+                        ((choparg_t) (-1)), ((choparg_t) (&flag)), 0);
+  return (flag);
+}
+
+void
+OS_terminal_raw_output (Tchannel channel)
+{
+  OS2_channel_operation (channel, chop_output_cooked, ((choparg_t) 0), 0, 0);
+}
+
+void
+OS_terminal_cooked_output (Tchannel channel)
+{
+  OS2_channel_operation (channel, chop_output_cooked, ((choparg_t) 1), 0, 0);
+}
+
+int
+OS_terminal_buffered_p (Tchannel channel)
+{
+  int flag;
+  OS2_channel_operation (channel, chop_input_buffered,
+                        ((choparg_t) (-1)), ((choparg_t) (&flag)), 0);
+  return (flag);
+}
+
+void
+OS_terminal_buffered (Tchannel channel)
+{
+  OS2_channel_operation (channel, chop_input_buffered, ((choparg_t) 0), 0, 0);
+}
+
+void
+OS_terminal_nonbuffered (Tchannel channel)
+{
+  OS2_channel_operation (channel, chop_input_buffered, ((choparg_t) 1), 0, 0);
+}
+
+void
+OS_terminal_flush_input (Tchannel channel)
+{
+  OS2_channel_operation (channel, chop_input_flush, 0, 0, 0);
+}
+
+void
+OS_terminal_flush_output (Tchannel channel)
+{
+  OS2_channel_operation (channel, chop_output_flush, 0, 0, 0);
+}
+
+void
+OS_terminal_drain_output (Tchannel channel)
+{
+  OS2_channel_operation (channel, chop_output_drain, 0, 0, 0);
+}
+
+int
+OS_job_control_p (void)
+{
+  return (0);
+}
+
+int
+OS_have_ptys_p (void)
+{
+  return (0);
+}
diff --git a/v7/src/microcode/os2thrd.c b/v7/src/microcode/os2thrd.c
new file mode 100644 (file)
index 0000000..d62f2f5
--- /dev/null
@@ -0,0 +1,250 @@
+/* -*-C-*-
+
+$Id: os2thrd.c,v 1.1 1994/11/28 03:43:00 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+#include "prims.h"
+#include "errors.h"
+\f
+TID
+OS2_beginthread (thread_procedure_t procedure,
+                void * argument,
+                unsigned int stack_size)
+{
+  ULONG ss
+    = ((stack_size < 0x2000)
+       ? 0x2000
+       : ((stack_size + 0xfff) & (~0xfff)));
+#ifdef __IBMC__
+  int result = (_beginthread (procedure, 0, ss, argument));
+  if (result < 0)
+    OS2_error_system_call (ERROR_MAX_THRDS_REACHED, syscall_beginthread);
+  return (result);
+#else /* not __IBMC__ */
+  TID tid;
+  STD_API_CALL (dos_create_thread,
+               ((&tid), ((PFNTHREAD) procedure), ((ULONG) argument), 0, ss));
+  return (tid);
+#endif /* not __IBMC__ */
+}
+
+void
+OS2_endthread (void)
+{
+#ifdef __IBMC__
+  _endthread ();
+#else
+  dos_exit (EXIT_THREAD, 0);
+#endif
+}
+
+void
+OS2_kill_thread (TID tid)
+{
+  STD_API_CALL (dos_kill_thread, (tid));
+}
+
+#ifndef __IBMC__
+#define MAX_TID 999
+static thread_store_t * thread_store_array [MAX_TID + 1];
+
+thread_store_t **
+OS2_threadstore (void)
+{
+  PTIB ptib;
+  PPIB ppib;
+  TID tid;
+  STD_API_CALL (dos_get_info_blocks, ((&ptib), (&ppib)));
+  tid = (ptib -> tib_ptib2 -> tib2_ultid);
+  if (tid > MAX_TID)
+    OS2_logic_error ("Unexpectedly large TID.");
+  return (& (thread_store_array [tid]));
+}
+#endif
+\f
+PID OS2_scheme_pid;
+TID OS2_scheme_tid;
+
+static void thread_initialize_1 (qid_t);
+static int  thread_initialize_error_hook (void);
+static void restore_errors (void *);
+static void signal_error (msg_t *);
+static void ignore_error (msg_t *);
+static void send_error (msg_t *);
+
+void
+OS2_initialize_scheme_thread (void)
+{
+  SET_MSG_TYPE_LENGTH (mt_syscall_error, sm_syscall_error_t);
+  SET_MSG_TYPE_LENGTH (mt_error, sm_error_t);
+  SET_MSG_TYPE_LENGTH (mt_kill_request, sm_kill_request_t);
+  {
+    PTIB ptib;
+    PPIB ppib;
+    STD_API_CALL (dos_get_info_blocks, ((&ptib), (&ppib)));
+    OS2_scheme_pid = (ppib -> pib_ulpid);
+    OS2_scheme_tid = (ptib -> tib_ptib2 -> tib2_ultid);
+  }
+  thread_initialize_1 (QID_NONE);
+  (THREAD_ERROR_HOOK ()) = signal_error;
+}
+
+int
+OS2_thread_initialize (qid_t error_qid)
+{
+  thread_initialize_1 (error_qid);
+  return (thread_initialize_error_hook ());
+}
+
+static void
+thread_initialize_1 (qid_t error_qid)
+{
+  (* (OS2_threadstore ())) = (OS_malloc (sizeof (thread_store_t)));
+  (THREAD_ERROR_QUEUE ()) = error_qid;
+}
+
+static int
+thread_initialize_error_hook (void)
+{
+  (THREAD_ERROR_HOOK ()) = send_error;
+  return (setjmp (THREAD_ERROR_RESTART ()));
+}
+\f
+int
+OS2_error_message_p (msg_t * message)
+{
+  msg_type_t type = (MSG_TYPE (message));
+  return ((type == mt_syscall_error) || (type == mt_error));
+}
+
+void
+OS2_handle_error_message (msg_t * message)
+{
+  (* (THREAD_ERROR_HOOK ())) (message);
+}
+
+void
+OS2_ignore_errors (void)
+{
+  error_hook_t * hp = (dstack_alloc (sizeof (error_hook_t)));
+  (*hp) = (THREAD_ERROR_HOOK ());
+  transaction_record_action (tat_always, restore_errors, hp);
+  (THREAD_ERROR_HOOK ()) = ignore_error;
+}
+
+static void
+restore_errors (void * hp)
+{
+  (THREAD_ERROR_HOOK ()) = (* ((error_hook_t *) hp));
+}
+
+void
+OS2_error_system_call (int code, enum syscall_names name)
+{
+  OS2_handle_error_message (OS2_make_syscall_error (code, name));
+}
+
+void
+OS2_error_anonymous (void)
+{
+  OS2_handle_error_message (OS2_make_error (ERR_EXTERNAL_RETURN));
+}
+
+void
+OS2_error_unimplemented_primitive (void)
+{
+  OS2_handle_error_message (OS2_make_error (ERR_UNDEFINED_PRIMITIVE));
+}
+
+void
+OS2_error_out_of_channels (void)
+{
+  OS2_handle_error_message (OS2_make_error (ERR_OUT_OF_FILE_HANDLES));
+}
+\f
+static void
+signal_error (msg_t * message)
+{
+  switch (MSG_TYPE (message))
+    {
+    case mt_syscall_error:
+      {
+       int code = (SM_SYSCALL_ERROR_CODE (message));
+       enum syscall_names name = (SM_SYSCALL_ERROR_NAME (message));
+       OS2_destroy_message (message);
+       error_system_call (code, name);
+      }
+      break;
+    case mt_error:
+      {
+       long code = (SM_ERROR_CODE (message));
+       OS2_destroy_message (message);
+       signal_error_from_primitive (code);
+      }
+      break;
+    default:
+      OS2_logic_error ("Non-error message passed to signal_error.");
+      break;
+    }
+}
+
+static void
+ignore_error (msg_t * message)
+{
+}
+
+static void
+send_error (msg_t * message)
+{
+  if ((THREAD_ERROR_QUEUE ()) == QID_NONE)
+    OS2_logic_error ("send_error called when no error queue defined.");
+  OS2_send_message ((THREAD_ERROR_QUEUE ()), message);
+  longjmp ((THREAD_ERROR_RESTART ()), 1);
+}
+
+msg_t *
+OS2_make_syscall_error (int code, enum syscall_names name)
+{
+  msg_t * message = (OS2_create_message (mt_syscall_error));
+  (SM_SYSCALL_ERROR_CODE (message)) = code;
+  (SM_SYSCALL_ERROR_NAME (message)) = name;
+  return (message);
+}
+
+msg_t *
+OS2_make_error (long code)
+{
+  msg_t * message = (OS2_create_message (mt_error));
+  (SM_ERROR_CODE (message)) = code;
+  return (message);
+}
diff --git a/v7/src/microcode/os2thrd.h b/v7/src/microcode/os2thrd.h
new file mode 100644 (file)
index 0000000..a8af33d
--- /dev/null
@@ -0,0 +1,94 @@
+/* -*-C-*-
+
+$Id: os2thrd.h,v 1.1 1994/11/28 03:43:01 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#ifndef SCM_OS2THRD_H
+#define SCM_OS2THRD_H
+\f
+typedef void (* thread_procedure_t) (void *);
+typedef void (* error_hook_t) (msg_t *);
+
+typedef struct
+{
+  error_hook_t error_hook;
+  jmp_buf error_restart;
+  qid_t error_queue;
+} thread_store_t;
+#define THREAD_ERROR_HOOK() ((* (OS2_threadstore ())) -> error_hook)
+#define THREAD_ERROR_RESTART() ((* (OS2_threadstore ())) -> error_restart)
+#define THREAD_ERROR_QUEUE() ((* (OS2_threadstore ())) -> error_queue)
+
+typedef struct
+{
+  DECLARE_MSG_HEADER_FIELDS;
+  int code;
+  enum syscall_names name;
+} sm_syscall_error_t;
+#define SM_SYSCALL_ERROR_CODE(m) (((sm_syscall_error_t *) (m)) -> code)
+#define SM_SYSCALL_ERROR_NAME(m) (((sm_syscall_error_t *) (m)) -> name)
+
+typedef struct
+{
+  DECLARE_MSG_HEADER_FIELDS;
+  long code;
+} sm_error_t;
+#define SM_ERROR_CODE(m) (((sm_error_t *) (m)) -> code)
+
+typedef msg_t sm_kill_request_t;
+#define OS2_make_kill_request() OS2_create_message (mt_kill_request)
+
+extern TID  OS2_beginthread (thread_procedure_t, void *, unsigned int);
+extern void OS2_endthread (void);
+extern void OS2_kill_thread (TID);
+
+#ifdef __IBMC__
+#define OS2_threadstore() ((thread_store_t **) (_threadstore ()))
+#else
+extern thread_store_t ** OS2_threadstore (void);
+#endif
+
+extern PID OS2_scheme_pid;
+extern TID OS2_scheme_tid;
+
+extern int  OS2_thread_initialize (qid_t);
+extern int  OS2_error_message_p (msg_t *);
+extern void OS2_handle_error_message (msg_t *);
+extern void OS2_ignore_errors (void);
+extern void OS2_error_system_call (int, enum syscall_names);
+extern void OS2_error_anonymous (void);
+extern void OS2_error_unimplemented_primitive (void);
+extern void OS2_error_out_of_channels (void);
+extern msg_t * OS2_make_syscall_error (int, enum syscall_names);
+extern msg_t * OS2_make_error (long);
+
+#endif /* SCM_OS2THRD_H */
diff --git a/v7/src/microcode/os2top.c b/v7/src/microcode/os2top.c
new file mode 100644 (file)
index 0000000..40c76a4
--- /dev/null
@@ -0,0 +1,1557 @@
+/* -*-C-*-
+
+$Id: os2top.c,v 1.1 1994/11/28 03:43:01 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+#include "ostop.h"
+#include "option.h"
+
+extern void OS2_initialize_channels (void);
+extern void OS2_initialize_channel_thread_messages (void);
+extern void OS2_initialize_console (void);
+extern void OS2_initialize_directory_reader (void);
+extern void OS2_initialize_environment (void);
+extern void OS2_initialize_keyboard_interrupts (void);
+extern void OS2_initialize_message_queues (void);
+extern void OS2_initialize_scheme_thread (void);
+extern void OS2_initialize_tty (void);
+
+extern const char * OS_Name;
+extern const char * OS_Variant;
+
+static const char * OS2_version_string (void);
+static void initialize_locks (void);
+\f
+int
+OS_under_emacs_p (void)
+{
+  return (option_emacs_subprocess);
+}
+
+void
+OS_initialize (void)
+{
+  transaction_initialize ();
+  initialize_locks ();
+  OS2_initialize_message_queues ();
+  OS2_initialize_scheme_thread ();
+  OS2_initialize_channels ();
+  OS2_initialize_channel_thread_messages ();
+  OS2_initialize_keyboard_interrupts ();
+  OS2_initialize_console ();
+  OS2_initialize_environment ();
+  OS2_initialize_directory_reader ();
+  OS2_initialize_tty ();
+  OS_Name = "OS/2";
+  {
+    const char * version = (OS2_version_string ());
+    OS_Variant = (OS_malloc ((strlen (OS_Name)) + (strlen (version)) + 2));
+    sprintf (((char *) OS_Variant), "%s %s", OS_Name, version);
+  }
+  outf_console ("MIT Scheme running under %s\n", OS_Variant);
+  outf_flush_console ();
+}
+
+static const char *
+OS2_version_string (void)
+{
+  ULONG major = (OS2_system_variable (QSV_VERSION_MAJOR));
+  ULONG minor = (OS2_system_variable (QSV_VERSION_MINOR));
+  char revision = (OS2_system_variable (QSV_VERSION_REVISION));
+  static char result [64];
+  char sminor [16];
+  char srev [2];
+  if ((major == 20) && (minor == 30))
+    {
+      major = 30;
+      minor = 0;
+    }
+  if ((minor < 10) && (minor != 0))
+    sprintf (sminor, "0%d", minor);
+  else
+    sprintf (sminor, "%d",
+            (((minor < 100) && ((minor % 10) == 0)) ? (minor / 10) : minor));
+  if (revision == '\0')
+    sprintf (srev, "");
+  else
+    sprintf (srev, "%c", revision);
+  sprintf (result, "%d.%s%s", (major / 10), sminor, srev);
+  return (result);
+}
+
+void
+OS2_exit_scheme (int value)
+{
+  extern void OS2_kill_timer_thread (void);
+  OS2_kill_timer_thread ();
+  OS2_channel_close_all_noerror ();
+  exit (value);
+}
+
+void
+OS_reset (void)
+{
+  execute_reload_cleanups ();
+}
+\f
+void
+OS_quit (int code, int abnormal_p)
+{
+  outf_flush_console ();
+  OS_restore_external_state ();
+}
+
+void
+OS_save_external_state (void)
+{
+}
+
+void
+OS_save_internal_state (void)
+{
+}
+
+void
+OS_restore_internal_state (void)
+{
+}
+
+void
+OS_restore_external_state (void)
+{
+}
+
+void
+preserve_signal_mask (void)
+{
+}
+
+void
+block_signals (void)
+{
+}
+
+void
+unblock_signals (void)
+{
+}
+
+void
+OS_restartable_exit (void)
+{
+}
+
+long
+OS_set_trap_state (long arg)
+{
+  return (arg);
+}
+
+#ifdef __IBMC__
+void
+bcopy (const char * from, char * to, unsigned int n)
+{
+  FASTCOPY (from, to, n);
+}
+#endif
+\f
+static HMTX interrupt_registers_lock;
+
+static void
+initialize_locks (void)
+{
+  interrupt_registers_lock = (OS2_create_mutex_semaphore ());
+}
+
+void
+OS_grab_interrupt_registers (void)
+{
+  OS2_request_mutex_semaphore (interrupt_registers_lock);
+}
+
+void
+OS_release_interrupt_registers (void)
+{
+  OS2_release_mutex_semaphore (interrupt_registers_lock);
+}
+\f
+/* Machine-generated procedure, do not edit: */
+enum syserr_names
+OS_error_code_to_syserr (int code)
+{
+  switch (code)
+    {
+    case ERROR_INVALID_FUNCTION:       return (syserr_invalid_function);
+    case ERROR_FILE_NOT_FOUND: return (syserr_file_not_found);
+    case ERROR_PATH_NOT_FOUND: return (syserr_path_not_found);
+    case ERROR_TOO_MANY_OPEN_FILES:    return (syserr_too_many_open_files);
+    case ERROR_ACCESS_DENIED:  return (syserr_access_denied);
+    case ERROR_INVALID_HANDLE: return (syserr_invalid_handle);
+    case ERROR_ARENA_TRASHED:  return (syserr_arena_trashed);
+    case ERROR_NOT_ENOUGH_MEMORY:      return (syserr_not_enough_memory);
+    case ERROR_INVALID_BLOCK:  return (syserr_invalid_block);
+    case ERROR_BAD_ENVIRONMENT:        return (syserr_bad_environment);
+    case ERROR_BAD_FORMAT:     return (syserr_bad_format);
+    case ERROR_INVALID_ACCESS: return (syserr_invalid_access);
+    case ERROR_INVALID_DATA:   return (syserr_invalid_data);
+    case ERROR_INVALID_DRIVE:  return (syserr_invalid_drive);
+    case ERROR_CURRENT_DIRECTORY:      return (syserr_current_directory);
+    case ERROR_NOT_SAME_DEVICE:        return (syserr_not_same_device);
+    case ERROR_NO_MORE_FILES:  return (syserr_no_more_files);
+    case ERROR_WRITE_PROTECT:  return (syserr_write_protect);
+    case ERROR_BAD_UNIT:       return (syserr_bad_unit);
+    case ERROR_NOT_READY:      return (syserr_not_ready);
+    case ERROR_BAD_COMMAND:    return (syserr_bad_command);
+    case ERROR_CRC:    return (syserr_crc);
+    case ERROR_BAD_LENGTH:     return (syserr_bad_length);
+    case ERROR_SEEK:   return (syserr_seek);
+    case ERROR_NOT_DOS_DISK:   return (syserr_not_dos_disk);
+    case ERROR_SECTOR_NOT_FOUND:       return (syserr_sector_not_found);
+    case ERROR_OUT_OF_PAPER:   return (syserr_out_of_paper);
+    case ERROR_WRITE_FAULT:    return (syserr_write_fault);
+    case ERROR_READ_FAULT:     return (syserr_read_fault);
+    case ERROR_GEN_FAILURE:    return (syserr_gen_failure);
+    case ERROR_SHARING_VIOLATION:      return (syserr_sharing_violation);
+    case ERROR_LOCK_VIOLATION: return (syserr_lock_violation);
+    case ERROR_WRONG_DISK:     return (syserr_wrong_disk);
+    case ERROR_FCB_UNAVAILABLE:        return (syserr_fcb_unavailable);
+    case ERROR_SHARING_BUFFER_EXCEEDED:        return (syserr_sharing_buffer_exceeded);
+    case ERROR_CODE_PAGE_MISMATCHED:   return (syserr_code_page_mismatched);
+    case ERROR_HANDLE_EOF:     return (syserr_handle_eof);
+    case ERROR_HANDLE_DISK_FULL:       return (syserr_handle_disk_full);
+    case ERROR_NOT_SUPPORTED:  return (syserr_not_supported);
+    case ERROR_REM_NOT_LIST:   return (syserr_rem_not_list);
+    case ERROR_DUP_NAME:       return (syserr_dup_name);
+    case ERROR_BAD_NETPATH:    return (syserr_bad_netpath);
+    case ERROR_NETWORK_BUSY:   return (syserr_network_busy);
+    case ERROR_DEV_NOT_EXIST:  return (syserr_dev_not_exist);
+    case ERROR_TOO_MANY_CMDS:  return (syserr_too_many_cmds);
+    case ERROR_ADAP_HDW_ERR:   return (syserr_adap_hdw_err);
+    case ERROR_BAD_NET_RESP:   return (syserr_bad_net_resp);
+    case ERROR_UNEXP_NET_ERR:  return (syserr_unexp_net_err);
+    case ERROR_BAD_REM_ADAP:   return (syserr_bad_rem_adap);
+    case ERROR_PRINTQ_FULL:    return (syserr_printq_full);
+    case ERROR_NO_SPOOL_SPACE: return (syserr_no_spool_space);
+    case ERROR_PRINT_CANCELLED:        return (syserr_print_cancelled);
+    case ERROR_NETNAME_DELETED:        return (syserr_netname_deleted);
+    case ERROR_NETWORK_ACCESS_DENIED:  return (syserr_network_access_denied);
+    case ERROR_BAD_DEV_TYPE:   return (syserr_bad_dev_type);
+    case ERROR_BAD_NET_NAME:   return (syserr_bad_net_name);
+    case ERROR_TOO_MANY_NAMES: return (syserr_too_many_names);
+    case ERROR_TOO_MANY_SESS:  return (syserr_too_many_sess);
+    case ERROR_SHARING_PAUSED: return (syserr_sharing_paused);
+    case ERROR_REQ_NOT_ACCEP:  return (syserr_req_not_accep);
+    case ERROR_REDIR_PAUSED:   return (syserr_redir_paused);
+    case ERROR_SBCS_ATT_WRITE_PROT:    return (syserr_sbcs_att_write_prot);
+    case ERROR_SBCS_GENERAL_FAILURE:   return (syserr_sbcs_general_failure);
+    case ERROR_XGA_OUT_MEMORY: return (syserr_xga_out_memory);
+    case ERROR_FILE_EXISTS:    return (syserr_file_exists);
+    case ERROR_DUP_FCB:        return (syserr_dup_fcb);
+    case ERROR_CANNOT_MAKE:    return (syserr_cannot_make);
+    case ERROR_FAIL_I24:       return (syserr_fail_i24);
+    case ERROR_OUT_OF_STRUCTURES:      return (syserr_out_of_structures);
+    case ERROR_ALREADY_ASSIGNED:       return (syserr_already_assigned);
+    case ERROR_INVALID_PASSWORD:       return (syserr_invalid_password);
+    case ERROR_INVALID_PARAMETER:      return (syserr_invalid_parameter);
+    case ERROR_NET_WRITE_FAULT:        return (syserr_net_write_fault);
+    case ERROR_NO_PROC_SLOTS:  return (syserr_no_proc_slots);
+    case ERROR_NOT_FROZEN:     return (syserr_not_frozen);
+    case ERR_TSTOVFL:  return (syserr_tstovfl);
+    case ERR_TSTDUP:   return (syserr_tstdup);
+    case ERROR_NO_ITEMS:       return (syserr_no_items);
+    case ERROR_INTERRUPT:      return (syserr_interrupt);
+    case ERROR_DEVICE_IN_USE:  return (syserr_device_in_use);
+    case ERROR_TOO_MANY_SEMAPHORES:    return (syserr_too_many_semaphores);
+    case ERROR_EXCL_SEM_ALREADY_OWNED: return (syserr_excl_sem_already_owned);
+    case ERROR_SEM_IS_SET:     return (syserr_sem_is_set);
+    case ERROR_TOO_MANY_SEM_REQUESTS:  return (syserr_too_many_sem_requests);
+    case ERROR_INVALID_AT_INTERRUPT_TIME:      return (syserr_invalid_at_interrupt_time);
+    case ERROR_SEM_OWNER_DIED: return (syserr_sem_owner_died);
+    case ERROR_SEM_USER_LIMIT: return (syserr_sem_user_limit);
+    case ERROR_DISK_CHANGE:    return (syserr_disk_change);
+    case ERROR_DRIVE_LOCKED:   return (syserr_drive_locked);
+    case ERROR_BROKEN_PIPE:    return (syserr_broken_pipe);
+    case ERROR_OPEN_FAILED:    return (syserr_open_failed);
+    case ERROR_BUFFER_OVERFLOW:        return (syserr_buffer_overflow);
+    case ERROR_DISK_FULL:      return (syserr_disk_full);
+    case ERROR_NO_MORE_SEARCH_HANDLES: return (syserr_no_more_search_handles);
+    case ERROR_INVALID_TARGET_HANDLE:  return (syserr_invalid_target_handle);
+    case ERROR_PROTECTION_VIOLATION:   return (syserr_protection_violation);
+    case ERROR_VIOKBD_REQUEST: return (syserr_viokbd_request);
+    case ERROR_INVALID_CATEGORY:       return (syserr_invalid_category);
+    case ERROR_INVALID_VERIFY_SWITCH:  return (syserr_invalid_verify_switch);
+    case ERROR_BAD_DRIVER_LEVEL:       return (syserr_bad_driver_level);
+    case ERROR_CALL_NOT_IMPLEMENTED:   return (syserr_call_not_implemented);
+    case ERROR_SEM_TIMEOUT:    return (syserr_sem_timeout);
+    case ERROR_INSUFFICIENT_BUFFER:    return (syserr_insufficient_buffer);
+    case ERROR_INVALID_NAME:   return (syserr_invalid_name);
+    case ERROR_INVALID_LEVEL:  return (syserr_invalid_level);
+    case ERROR_NO_VOLUME_LABEL:        return (syserr_no_volume_label);
+    case ERROR_MOD_NOT_FOUND:  return (syserr_mod_not_found);
+    case ERROR_PROC_NOT_FOUND: return (syserr_proc_not_found);
+    case ERROR_WAIT_NO_CHILDREN:       return (syserr_wait_no_children);
+    case ERROR_CHILD_NOT_COMPLETE:     return (syserr_child_not_complete);
+    case ERROR_DIRECT_ACCESS_HANDLE:   return (syserr_direct_access_handle);
+    case ERROR_NEGATIVE_SEEK:  return (syserr_negative_seek);
+    case ERROR_SEEK_ON_DEVICE: return (syserr_seek_on_device);
+    case ERROR_IS_JOIN_TARGET: return (syserr_is_join_target);
+    case ERROR_IS_JOINED:      return (syserr_is_joined);
+    case ERROR_IS_SUBSTED:     return (syserr_is_substed);
+    case ERROR_NOT_JOINED:     return (syserr_not_joined);
+    case ERROR_NOT_SUBSTED:    return (syserr_not_substed);
+    case ERROR_JOIN_TO_JOIN:   return (syserr_join_to_join);
+    case ERROR_SUBST_TO_SUBST: return (syserr_subst_to_subst);
+    case ERROR_JOIN_TO_SUBST:  return (syserr_join_to_subst);
+    case ERROR_SUBST_TO_JOIN:  return (syserr_subst_to_join);
+    case ERROR_BUSY_DRIVE:     return (syserr_busy_drive);
+    case ERROR_SAME_DRIVE:     return (syserr_same_drive);
+    case ERROR_DIR_NOT_ROOT:   return (syserr_dir_not_root);
+    case ERROR_DIR_NOT_EMPTY:  return (syserr_dir_not_empty);
+    case ERROR_IS_SUBST_PATH:  return (syserr_is_subst_path);
+    case ERROR_IS_JOIN_PATH:   return (syserr_is_join_path);
+    case ERROR_PATH_BUSY:      return (syserr_path_busy);
+    case ERROR_IS_SUBST_TARGET:        return (syserr_is_subst_target);
+    case ERROR_SYSTEM_TRACE:   return (syserr_system_trace);
+    case ERROR_INVALID_EVENT_COUNT:    return (syserr_invalid_event_count);
+    case ERROR_TOO_MANY_MUXWAITERS:    return (syserr_too_many_muxwaiters);
+    case ERROR_INVALID_LIST_FORMAT:    return (syserr_invalid_list_format);
+    case ERROR_LABEL_TOO_LONG: return (syserr_label_too_long);
+    case ERROR_TOO_MANY_TCBS:  return (syserr_too_many_tcbs);
+    case ERROR_SIGNAL_REFUSED: return (syserr_signal_refused);
+    case ERROR_DISCARDED:      return (syserr_discarded);
+    case ERROR_NOT_LOCKED:     return (syserr_not_locked);
+    case ERROR_BAD_THREADID_ADDR:      return (syserr_bad_threadid_addr);
+    case ERROR_BAD_ARGUMENTS:  return (syserr_bad_arguments);
+    case ERROR_BAD_PATHNAME:   return (syserr_bad_pathname);
+    case ERROR_SIGNAL_PENDING: return (syserr_signal_pending);
+    case ERROR_UNCERTAIN_MEDIA:        return (syserr_uncertain_media);
+    case ERROR_MAX_THRDS_REACHED:      return (syserr_max_thrds_reached);
+    case ERROR_MONITORS_NOT_SUPPORTED: return (syserr_monitors_not_supported);
+    case ERROR_UNC_DRIVER_NOT_INSTALLED:       return (syserr_unc_driver_not_installed);
+    case ERROR_LOCK_FAILED:    return (syserr_lock_failed);
+    case ERROR_SWAPIO_FAILED:  return (syserr_swapio_failed);
+    case ERROR_SWAPIN_FAILED:  return (syserr_swapin_failed);
+    case ERROR_BUSY:   return (syserr_busy);
+    case ERROR_CANCEL_VIOLATION:       return (syserr_cancel_violation);
+    case ERROR_ATOMIC_LOCK_NOT_SUPPORTED:      return (syserr_atomic_lock_not_supported);
+    case ERROR_READ_LOCKS_NOT_SUPPORTED:       return (syserr_read_locks_not_supported);
+    case ERROR_INVALID_SEGMENT_NUMBER: return (syserr_invalid_segment_number);
+    case ERROR_INVALID_CALLGATE:       return (syserr_invalid_callgate);
+    case ERROR_INVALID_ORDINAL:        return (syserr_invalid_ordinal);
+    case ERROR_ALREADY_EXISTS: return (syserr_already_exists);
+    case ERROR_NO_CHILD_PROCESS:       return (syserr_no_child_process);
+    case ERROR_CHILD_ALIVE_NOWAIT:     return (syserr_child_alive_nowait);
+    case ERROR_INVALID_FLAG_NUMBER:    return (syserr_invalid_flag_number);
+    case ERROR_SEM_NOT_FOUND:  return (syserr_sem_not_found);
+    case ERROR_INVALID_STARTING_CODESEG:       return (syserr_invalid_starting_codeseg);
+    case ERROR_INVALID_STACKSEG:       return (syserr_invalid_stackseg);
+    case ERROR_INVALID_MODULETYPE:     return (syserr_invalid_moduletype);
+    case ERROR_INVALID_EXE_SIGNATURE:  return (syserr_invalid_exe_signature);
+    case ERROR_EXE_MARKED_INVALID:     return (syserr_exe_marked_invalid);
+    case ERROR_BAD_EXE_FORMAT: return (syserr_bad_exe_format);
+    case ERROR_ITERATED_DATA_EXCEEDS_64k:      return (syserr_iterated_data_exceeds_64k);
+    case ERROR_INVALID_MINALLOCSIZE:   return (syserr_invalid_minallocsize);
+    case ERROR_DYNLINK_FROM_INVALID_RING:      return (syserr_dynlink_from_invalid_ring);
+    case ERROR_IOPL_NOT_ENABLED:       return (syserr_iopl_not_enabled);
+    case ERROR_INVALID_SEGDPL: return (syserr_invalid_segdpl);
+    case ERROR_AUTODATASEG_EXCEEDS_64k:        return (syserr_autodataseg_exceeds_64k);
+    case ERROR_RING2SEG_MUST_BE_MOVABLE:       return (syserr_ring2seg_must_be_movable);
+    case ERROR_RELOC_CHAIN_XEEDS_SEGLIM:       return (syserr_reloc_chain_xeeds_seglim);
+    case ERROR_INFLOOP_IN_RELOC_CHAIN: return (syserr_infloop_in_reloc_chain);
+    case ERROR_ENVVAR_NOT_FOUND:       return (syserr_envvar_not_found);
+    case ERROR_NOT_CURRENT_CTRY:       return (syserr_not_current_ctry);
+    case ERROR_NO_SIGNAL_SENT: return (syserr_no_signal_sent);
+    case ERROR_FILENAME_EXCED_RANGE:   return (syserr_filename_exced_range);
+    case ERROR_RING2_STACK_IN_USE:     return (syserr_ring2_stack_in_use);
+    case ERROR_META_EXPANSION_TOO_LONG:        return (syserr_meta_expansion_too_long);
+    case ERROR_INVALID_SIGNAL_NUMBER:  return (syserr_invalid_signal_number);
+    case ERROR_THREAD_1_INACTIVE:      return (syserr_thread_1_inactive);
+    case ERROR_INFO_NOT_AVAIL: return (syserr_info_not_avail);
+    case ERROR_LOCKED: return (syserr_locked);
+    case ERROR_BAD_DYNALINK:   return (syserr_bad_dynalink);
+    case ERROR_TOO_MANY_MODULES:       return (syserr_too_many_modules);
+    case ERROR_NESTING_NOT_ALLOWED:    return (syserr_nesting_not_allowed);
+    case ERROR_CANNOT_SHRINK:  return (syserr_cannot_shrink);
+    case ERROR_ZOMBIE_PROCESS: return (syserr_zombie_process);
+    case ERROR_STACK_IN_HIGH_MEMORY:   return (syserr_stack_in_high_memory);
+    case ERROR_INVALID_EXITROUTINE_RING:       return (syserr_invalid_exitroutine_ring);
+    case ERROR_GETBUF_FAILED:  return (syserr_getbuf_failed);
+    case ERROR_FLUSHBUF_FAILED:        return (syserr_flushbuf_failed);
+    case ERROR_TRANSFER_TOO_LONG:      return (syserr_transfer_too_long);
+    case ERROR_FORCENOSWAP_FAILED:     return (syserr_forcenoswap_failed);
+    case ERROR_SMG_NO_TARGET_WINDOW:   return (syserr_smg_no_target_window);
+    case ERROR_NO_CHILDREN:    return (syserr_no_children);
+    case ERROR_INVALID_SCREEN_GROUP:   return (syserr_invalid_screen_group);
+    case ERROR_BAD_PIPE:       return (syserr_bad_pipe);
+    case ERROR_PIPE_BUSY:      return (syserr_pipe_busy);
+    case ERROR_NO_DATA:        return (syserr_no_data);
+    case ERROR_PIPE_NOT_CONNECTED:     return (syserr_pipe_not_connected);
+    case ERROR_MORE_DATA:      return (syserr_more_data);
+    case ERROR_VC_DISCONNECTED:        return (syserr_vc_disconnected);
+    case ERROR_CIRCULARITY_REQUESTED:  return (syserr_circularity_requested);
+    case ERROR_DIRECTORY_IN_CDS:       return (syserr_directory_in_cds);
+    case ERROR_INVALID_FSD_NAME:       return (syserr_invalid_fsd_name);
+    case ERROR_INVALID_PATH:   return (syserr_invalid_path);
+    case ERROR_INVALID_EA_NAME:        return (syserr_invalid_ea_name);
+    case ERROR_EA_LIST_INCONSISTENT:   return (syserr_ea_list_inconsistent);
+    case ERROR_EA_LIST_TOO_LONG:       return (syserr_ea_list_too_long);
+    case ERROR_NO_META_MATCH:  return (syserr_no_meta_match);
+    case ERROR_FINDNOTIFY_TIMEOUT:     return (syserr_findnotify_timeout);
+    case ERROR_NO_MORE_ITEMS:  return (syserr_no_more_items);
+    case ERROR_SEARCH_STRUC_REUSED:    return (syserr_search_struc_reused);
+    case ERROR_CHAR_NOT_FOUND: return (syserr_char_not_found);
+    case ERROR_TOO_MUCH_STACK: return (syserr_too_much_stack);
+    case ERROR_INVALID_ATTR:   return (syserr_invalid_attr);
+    case ERROR_INVALID_STARTING_RING:  return (syserr_invalid_starting_ring);
+    case ERROR_INVALID_DLL_INIT_RING:  return (syserr_invalid_dll_init_ring);
+    case ERROR_CANNOT_COPY:    return (syserr_cannot_copy);
+    case ERROR_DIRECTORY:      return (syserr_directory);
+    case ERROR_OPLOCKED_FILE:  return (syserr_oplocked_file);
+    case ERROR_OPLOCK_THREAD_EXISTS:   return (syserr_oplock_thread_exists);
+    case ERROR_VOLUME_CHANGED: return (syserr_volume_changed);
+    case ERROR_FINDNOTIFY_HANDLE_IN_USE:       return (syserr_findnotify_handle_in_use);
+    case ERROR_FINDNOTIFY_HANDLE_CLOSED:       return (syserr_findnotify_handle_closed);
+    case ERROR_NOTIFY_OBJECT_REMOVED:  return (syserr_notify_object_removed);
+    case ERROR_ALREADY_SHUTDOWN:       return (syserr_already_shutdown);
+    case ERROR_EAS_DIDNT_FIT:  return (syserr_eas_didnt_fit);
+    case ERROR_EA_FILE_CORRUPT:        return (syserr_ea_file_corrupt);
+    case ERROR_EA_TABLE_FULL:  return (syserr_ea_table_full);
+    case ERROR_INVALID_EA_HANDLE:      return (syserr_invalid_ea_handle);
+    case ERROR_NO_CLUSTER:     return (syserr_no_cluster);
+    case ERROR_CREATE_EA_FILE: return (syserr_create_ea_file);
+    case ERROR_CANNOT_OPEN_EA_FILE:    return (syserr_cannot_open_ea_file);
+    case ERROR_EAS_NOT_SUPPORTED:      return (syserr_eas_not_supported);
+    case ERROR_NEED_EAS_FOUND: return (syserr_need_eas_found);
+    case ERROR_DUPLICATE_HANDLE:       return (syserr_duplicate_handle);
+    case ERROR_DUPLICATE_NAME: return (syserr_duplicate_name);
+    case ERROR_EMPTY_MUXWAIT:  return (syserr_empty_muxwait);
+    case ERROR_MUTEX_OWNED:    return (syserr_mutex_owned);
+    case ERROR_NOT_OWNER:      return (syserr_not_owner);
+    case ERROR_PARAM_TOO_SMALL:        return (syserr_param_too_small);
+    case ERROR_TOO_MANY_HANDLES:       return (syserr_too_many_handles);
+    case ERROR_TOO_MANY_OPENS: return (syserr_too_many_opens);
+    case ERROR_WRONG_TYPE:     return (syserr_wrong_type);
+    case ERROR_UNUSED_CODE:    return (syserr_unused_code);
+    case ERROR_THREAD_NOT_TERMINATED:  return (syserr_thread_not_terminated);
+    case ERROR_INIT_ROUTINE_FAILED:    return (syserr_init_routine_failed);
+    case ERROR_MODULE_IN_USE:  return (syserr_module_in_use);
+    case ERROR_NOT_ENOUGH_WATCHPOINTS: return (syserr_not_enough_watchpoints);
+    case ERROR_TOO_MANY_POSTS: return (syserr_too_many_posts);
+    case ERROR_ALREADY_POSTED: return (syserr_already_posted);
+    case ERROR_ALREADY_RESET:  return (syserr_already_reset);
+    case ERROR_SEM_BUSY:       return (syserr_sem_busy);
+    case ERROR_INVALID_PROCID: return (syserr_invalid_procid);
+    case ERROR_INVALID_PDELTA: return (syserr_invalid_pdelta);
+    case ERROR_NOT_DESCENDANT: return (syserr_not_descendant);
+    case ERROR_NOT_SESSION_MANAGER:    return (syserr_not_session_manager);
+    case ERROR_INVALID_PCLASS: return (syserr_invalid_pclass);
+    case ERROR_INVALID_SCOPE:  return (syserr_invalid_scope);
+    case ERROR_INVALID_THREADID:       return (syserr_invalid_threadid);
+    case ERROR_DOSSUB_SHRINK:  return (syserr_dossub_shrink);
+    case ERROR_DOSSUB_NOMEM:   return (syserr_dossub_nomem);
+    case ERROR_DOSSUB_OVERLAP: return (syserr_dossub_overlap);
+    case ERROR_DOSSUB_BADSIZE: return (syserr_dossub_badsize);
+    case ERROR_DOSSUB_BADFLAG: return (syserr_dossub_badflag);
+    case ERROR_DOSSUB_BADSELECTOR:     return (syserr_dossub_badselector);
+    case ERROR_MR_MSG_TOO_LONG:        return (syserr_mr_msg_too_long);
+    case ERROR_MR_MID_NOT_FOUND:       return (syserr_mr_mid_not_found);
+    case ERROR_MR_UN_ACC_MSGF: return (syserr_mr_un_acc_msgf);
+    case ERROR_MR_INV_MSGF_FORMAT:     return (syserr_mr_inv_msgf_format);
+    case ERROR_MR_INV_IVCOUNT: return (syserr_mr_inv_ivcount);
+    case ERROR_MR_UN_PERFORM:  return (syserr_mr_un_perform);
+    case ERROR_TS_WAKEUP:      return (syserr_ts_wakeup);
+    case ERROR_TS_SEMHANDLE:   return (syserr_ts_semhandle);
+    case ERROR_TS_NOTIMER:     return (syserr_ts_notimer);
+    case ERROR_TS_HANDLE:      return (syserr_ts_handle);
+    case ERROR_TS_DATETIME:    return (syserr_ts_datetime);
+    case ERROR_SYS_INTERNAL:   return (syserr_sys_internal);
+    case ERROR_QUE_CURRENT_NAME:       return (syserr_que_current_name);
+    case ERROR_QUE_PROC_NOT_OWNED:     return (syserr_que_proc_not_owned);
+    case ERROR_QUE_PROC_OWNED: return (syserr_que_proc_owned);
+    case ERROR_QUE_DUPLICATE:  return (syserr_que_duplicate);
+    case ERROR_QUE_ELEMENT_NOT_EXIST:  return (syserr_que_element_not_exist);
+    case ERROR_QUE_NO_MEMORY:  return (syserr_que_no_memory);
+    case ERROR_QUE_INVALID_NAME:       return (syserr_que_invalid_name);
+    case ERROR_QUE_INVALID_PRIORITY:   return (syserr_que_invalid_priority);
+    case ERROR_QUE_INVALID_HANDLE:     return (syserr_que_invalid_handle);
+    case ERROR_QUE_LINK_NOT_FOUND:     return (syserr_que_link_not_found);
+    case ERROR_QUE_MEMORY_ERROR:       return (syserr_que_memory_error);
+    case ERROR_QUE_PREV_AT_END:        return (syserr_que_prev_at_end);
+    case ERROR_QUE_PROC_NO_ACCESS:     return (syserr_que_proc_no_access);
+    case ERROR_QUE_EMPTY:      return (syserr_que_empty);
+    case ERROR_QUE_NAME_NOT_EXIST:     return (syserr_que_name_not_exist);
+    case ERROR_QUE_NOT_INITIALIZED:    return (syserr_que_not_initialized);
+    case ERROR_QUE_UNABLE_TO_ACCESS:   return (syserr_que_unable_to_access);
+    case ERROR_QUE_UNABLE_TO_ADD:      return (syserr_que_unable_to_add);
+    case ERROR_QUE_UNABLE_TO_INIT:     return (syserr_que_unable_to_init);
+    case ERROR_VIO_INVALID_MASK:       return (syserr_vio_invalid_mask);
+    case ERROR_VIO_PTR:        return (syserr_vio_ptr);
+    case ERROR_VIO_APTR:       return (syserr_vio_aptr);
+    case ERROR_VIO_RPTR:       return (syserr_vio_rptr);
+    case ERROR_VIO_CPTR:       return (syserr_vio_cptr);
+    case ERROR_VIO_LPTR:       return (syserr_vio_lptr);
+    case ERROR_VIO_MODE:       return (syserr_vio_mode);
+    case ERROR_VIO_WIDTH:      return (syserr_vio_width);
+    case ERROR_VIO_ATTR:       return (syserr_vio_attr);
+    case ERROR_VIO_ROW:        return (syserr_vio_row);
+    case ERROR_VIO_COL:        return (syserr_vio_col);
+    case ERROR_VIO_TOPROW:     return (syserr_vio_toprow);
+    case ERROR_VIO_BOTROW:     return (syserr_vio_botrow);
+    case ERROR_VIO_RIGHTCOL:   return (syserr_vio_rightcol);
+    case ERROR_VIO_LEFTCOL:    return (syserr_vio_leftcol);
+    case ERROR_SCS_CALL:       return (syserr_scs_call);
+    case ERROR_SCS_VALUE:      return (syserr_scs_value);
+    case ERROR_VIO_WAIT_FLAG:  return (syserr_vio_wait_flag);
+    case ERROR_VIO_UNLOCK:     return (syserr_vio_unlock);
+    case ERROR_SGS_NOT_SESSION_MGR:    return (syserr_sgs_not_session_mgr);
+    case ERROR_SMG_INVALID_SESSION_ID: return (syserr_smg_invalid_session_id);
+    case ERROR_SMG_NO_SESSIONS:        return (syserr_smg_no_sessions);
+    case ERROR_SMG_SESSION_NOT_FOUND:  return (syserr_smg_session_not_found);
+    case ERROR_SMG_SET_TITLE:  return (syserr_smg_set_title);
+    case ERROR_KBD_PARAMETER:  return (syserr_kbd_parameter);
+    case ERROR_KBD_NO_DEVICE:  return (syserr_kbd_no_device);
+    case ERROR_KBD_INVALID_IOWAIT:     return (syserr_kbd_invalid_iowait);
+    case ERROR_KBD_INVALID_LENGTH:     return (syserr_kbd_invalid_length);
+    case ERROR_KBD_INVALID_ECHO_MASK:  return (syserr_kbd_invalid_echo_mask);
+    case ERROR_KBD_INVALID_INPUT_MASK: return (syserr_kbd_invalid_input_mask);
+    case ERROR_MON_INVALID_PARMS:      return (syserr_mon_invalid_parms);
+    case ERROR_MON_INVALID_DEVNAME:    return (syserr_mon_invalid_devname);
+    case ERROR_MON_INVALID_HANDLE:     return (syserr_mon_invalid_handle);
+    case ERROR_MON_BUFFER_TOO_SMALL:   return (syserr_mon_buffer_too_small);
+    case ERROR_MON_BUFFER_EMPTY:       return (syserr_mon_buffer_empty);
+    case ERROR_MON_DATA_TOO_LARGE:     return (syserr_mon_data_too_large);
+    case ERROR_MOUSE_NO_DEVICE:        return (syserr_mouse_no_device);
+    case ERROR_MOUSE_INV_HANDLE:       return (syserr_mouse_inv_handle);
+    case ERROR_MOUSE_INV_PARMS:        return (syserr_mouse_inv_parms);
+    case ERROR_MOUSE_CANT_RESET:       return (syserr_mouse_cant_reset);
+    case ERROR_MOUSE_DISPLAY_PARMS:    return (syserr_mouse_display_parms);
+    case ERROR_MOUSE_INV_MODULE:       return (syserr_mouse_inv_module);
+    case ERROR_MOUSE_INV_ENTRY_PT:     return (syserr_mouse_inv_entry_pt);
+    case ERROR_MOUSE_INV_MASK: return (syserr_mouse_inv_mask);
+    case NO_ERROR_MOUSE_NO_DATA:       return (syserr_mouse_no_data);
+    case NO_ERROR_MOUSE_PTR_DRAWN:     return (syserr_mouse_ptr_drawn);
+    case ERROR_INVALID_FREQUENCY:      return (syserr_invalid_frequency);
+    case ERROR_NLS_NO_COUNTRY_FILE:    return (syserr_nls_no_country_file);
+    case ERROR_NLS_OPEN_FAILED:        return (syserr_nls_open_failed);
+    case ERROR_NO_COUNTRY_OR_CODEPAGE: return (syserr_no_country_or_codepage);
+    case ERROR_NLS_TABLE_TRUNCATED:    return (syserr_nls_table_truncated);
+    case ERROR_NLS_BAD_TYPE:   return (syserr_nls_bad_type);
+    case ERROR_NLS_TYPE_NOT_FOUND:     return (syserr_nls_type_not_found);
+    case ERROR_VIO_SMG_ONLY:   return (syserr_vio_smg_only);
+    case ERROR_VIO_INVALID_ASCIIZ:     return (syserr_vio_invalid_asciiz);
+    case ERROR_VIO_DEREGISTER: return (syserr_vio_deregister);
+    case ERROR_VIO_NO_POPUP:   return (syserr_vio_no_popup);
+    case ERROR_VIO_EXISTING_POPUP:     return (syserr_vio_existing_popup);
+    case ERROR_KBD_SMG_ONLY:   return (syserr_kbd_smg_only);
+    case ERROR_KBD_INVALID_ASCIIZ:     return (syserr_kbd_invalid_asciiz);
+    case ERROR_KBD_INVALID_MASK:       return (syserr_kbd_invalid_mask);
+    case ERROR_KBD_REGISTER:   return (syserr_kbd_register);
+    case ERROR_KBD_DEREGISTER: return (syserr_kbd_deregister);
+    case ERROR_MOUSE_SMG_ONLY: return (syserr_mouse_smg_only);
+    case ERROR_MOUSE_INVALID_ASCIIZ:   return (syserr_mouse_invalid_asciiz);
+    case ERROR_MOUSE_INVALID_MASK:     return (syserr_mouse_invalid_mask);
+    case ERROR_MOUSE_REGISTER: return (syserr_mouse_register);
+    case ERROR_MOUSE_DEREGISTER:       return (syserr_mouse_deregister);
+    case ERROR_SMG_BAD_ACTION: return (syserr_smg_bad_action);
+    case ERROR_SMG_INVALID_CALL:       return (syserr_smg_invalid_call);
+    case ERROR_SCS_SG_NOTFOUND:        return (syserr_scs_sg_notfound);
+    case ERROR_SCS_NOT_SHELL:  return (syserr_scs_not_shell);
+    case ERROR_VIO_INVALID_PARMS:      return (syserr_vio_invalid_parms);
+    case ERROR_VIO_FUNCTION_OWNED:     return (syserr_vio_function_owned);
+    case ERROR_VIO_RETURN:     return (syserr_vio_return);
+    case ERROR_SCS_INVALID_FUNCTION:   return (syserr_scs_invalid_function);
+    case ERROR_SCS_NOT_SESSION_MGR:    return (syserr_scs_not_session_mgr);
+    case ERROR_VIO_REGISTER:   return (syserr_vio_register);
+    case ERROR_VIO_NO_MODE_THREAD:     return (syserr_vio_no_mode_thread);
+    case ERROR_VIO_NO_SAVE_RESTORE_THD:        return (syserr_vio_no_save_restore_thd);
+    case ERROR_VIO_IN_BG:      return (syserr_vio_in_bg);
+    case ERROR_VIO_ILLEGAL_DURING_POPUP:       return (syserr_vio_illegal_during_popup);
+    case ERROR_SMG_NOT_BASESHELL:      return (syserr_smg_not_baseshell);
+    case ERROR_SMG_BAD_STATUSREQ:      return (syserr_smg_bad_statusreq);
+    case ERROR_QUE_INVALID_WAIT:       return (syserr_que_invalid_wait);
+    case ERROR_VIO_LOCK:       return (syserr_vio_lock);
+    case ERROR_MOUSE_INVALID_IOWAIT:   return (syserr_mouse_invalid_iowait);
+    case ERROR_VIO_INVALID_HANDLE:     return (syserr_vio_invalid_handle);
+    case ERROR_VIO_ILLEGAL_DURING_LOCK:        return (syserr_vio_illegal_during_lock);
+    case ERROR_VIO_INVALID_LENGTH:     return (syserr_vio_invalid_length);
+    case ERROR_KBD_INVALID_HANDLE:     return (syserr_kbd_invalid_handle);
+    case ERROR_KBD_NO_MORE_HANDLE:     return (syserr_kbd_no_more_handle);
+    case ERROR_KBD_CANNOT_CREATE_KCB:  return (syserr_kbd_cannot_create_kcb);
+    case ERROR_KBD_CODEPAGE_LOAD_INCOMPL:      return (syserr_kbd_codepage_load_incompl);
+    case ERROR_KBD_INVALID_CODEPAGE_ID:        return (syserr_kbd_invalid_codepage_id);
+    case ERROR_KBD_NO_CODEPAGE_SUPPORT:        return (syserr_kbd_no_codepage_support);
+    case ERROR_KBD_FOCUS_REQUIRED:     return (syserr_kbd_focus_required);
+    case ERROR_KBD_FOCUS_ALREADY_ACTIVE:       return (syserr_kbd_focus_already_active);
+    case ERROR_KBD_KEYBOARD_BUSY:      return (syserr_kbd_keyboard_busy);
+    case ERROR_KBD_INVALID_CODEPAGE:   return (syserr_kbd_invalid_codepage);
+    case ERROR_KBD_UNABLE_TO_FOCUS:    return (syserr_kbd_unable_to_focus);
+    case ERROR_SMG_SESSION_NON_SELECT: return (syserr_smg_session_non_select);
+    case ERROR_SMG_SESSION_NOT_FOREGRND:       return (syserr_smg_session_not_foregrnd);
+    case ERROR_SMG_SESSION_NOT_PARENT: return (syserr_smg_session_not_parent);
+    case ERROR_SMG_INVALID_START_MODE: return (syserr_smg_invalid_start_mode);
+    case ERROR_SMG_INVALID_RELATED_OPT:        return (syserr_smg_invalid_related_opt);
+    case ERROR_SMG_INVALID_BOND_OPTION:        return (syserr_smg_invalid_bond_option);
+    case ERROR_SMG_INVALID_SELECT_OPT: return (syserr_smg_invalid_select_opt);
+    case ERROR_SMG_START_IN_BACKGROUND:        return (syserr_smg_start_in_background);
+    case ERROR_SMG_INVALID_STOP_OPTION:        return (syserr_smg_invalid_stop_option);
+    case ERROR_SMG_BAD_RESERVE:        return (syserr_smg_bad_reserve);
+    case ERROR_SMG_PROCESS_NOT_PARENT: return (syserr_smg_process_not_parent);
+    case ERROR_SMG_INVALID_DATA_LENGTH:        return (syserr_smg_invalid_data_length);
+    case ERROR_SMG_NOT_BOUND:  return (syserr_smg_not_bound);
+    case ERROR_SMG_RETRY_SUB_ALLOC:    return (syserr_smg_retry_sub_alloc);
+    case ERROR_KBD_DETACHED:   return (syserr_kbd_detached);
+    case ERROR_VIO_DETACHED:   return (syserr_vio_detached);
+    case ERROR_MOU_DETACHED:   return (syserr_mou_detached);
+    case ERROR_VIO_FONT:       return (syserr_vio_font);
+    case ERROR_VIO_USER_FONT:  return (syserr_vio_user_font);
+    case ERROR_VIO_BAD_CP:     return (syserr_vio_bad_cp);
+    case ERROR_VIO_NO_CP:      return (syserr_vio_no_cp);
+    case ERROR_VIO_NA_CP:      return (syserr_vio_na_cp);
+    case ERROR_INVALID_CODE_PAGE:      return (syserr_invalid_code_page);
+    case ERROR_CPLIST_TOO_SMALL:       return (syserr_cplist_too_small);
+    case ERROR_CP_NOT_MOVED:   return (syserr_cp_not_moved);
+    case ERROR_MODE_SWITCH_INIT:       return (syserr_mode_switch_init);
+    case ERROR_CODE_PAGE_NOT_FOUND:    return (syserr_code_page_not_found);
+    case ERROR_UNEXPECTED_SLOT_RETURNED:       return (syserr_unexpected_slot_returned);
+    case ERROR_SMG_INVALID_TRACE_OPTION:       return (syserr_smg_invalid_trace_option);
+    case ERROR_VIO_INTERNAL_RESOURCE:  return (syserr_vio_internal_resource);
+    case ERROR_VIO_SHELL_INIT: return (syserr_vio_shell_init);
+    case ERROR_SMG_NO_HARD_ERRORS:     return (syserr_smg_no_hard_errors);
+    case ERROR_CP_SWITCH_INCOMPLETE:   return (syserr_cp_switch_incomplete);
+    case ERROR_VIO_TRANSPARENT_POPUP:  return (syserr_vio_transparent_popup);
+    case ERROR_CRITSEC_OVERFLOW:       return (syserr_critsec_overflow);
+    case ERROR_CRITSEC_UNDERFLOW:      return (syserr_critsec_underflow);
+    case ERROR_VIO_BAD_RESERVE:        return (syserr_vio_bad_reserve);
+    case ERROR_INVALID_ADDRESS:        return (syserr_invalid_address);
+    case ERROR_ZERO_SELECTORS_REQUESTED:       return (syserr_zero_selectors_requested);
+    case ERROR_NOT_ENOUGH_SELECTORS_AVA:       return (syserr_not_enough_selectors_ava);
+    case ERROR_INVALID_SELECTOR:       return (syserr_invalid_selector);
+    case ERROR_SMG_INVALID_PROGRAM_TYPE:       return (syserr_smg_invalid_program_type);
+    case ERROR_SMG_INVALID_PGM_CONTROL:        return (syserr_smg_invalid_pgm_control);
+    case ERROR_SMG_INVALID_INHERIT_OPT:        return (syserr_smg_invalid_inherit_opt);
+    case ERROR_VIO_EXTENDED_SG:        return (syserr_vio_extended_sg);
+    case ERROR_VIO_NOT_PRES_MGR_SG:    return (syserr_vio_not_pres_mgr_sg);
+    case ERROR_VIO_SHIELD_OWNED:       return (syserr_vio_shield_owned);
+    case ERROR_VIO_NO_MORE_HANDLES:    return (syserr_vio_no_more_handles);
+    case ERROR_VIO_SEE_ERROR_LOG:      return (syserr_vio_see_error_log);
+    case ERROR_VIO_ASSOCIATED_DC:      return (syserr_vio_associated_dc);
+    case ERROR_KBD_NO_CONSOLE: return (syserr_kbd_no_console);
+    case ERROR_MOUSE_NO_CONSOLE:       return (syserr_mouse_no_console);
+    case ERROR_MOUSE_INVALID_HANDLE:   return (syserr_mouse_invalid_handle);
+    case ERROR_SMG_INVALID_DEBUG_PARMS:        return (syserr_smg_invalid_debug_parms);
+    case ERROR_KBD_EXTENDED_SG:        return (syserr_kbd_extended_sg);
+    case ERROR_MOU_EXTENDED_SG:        return (syserr_mou_extended_sg);
+    case ERROR_SMG_INVALID_ICON_FILE:  return (syserr_smg_invalid_icon_file);
+    case ERROR_TRC_PID_NON_EXISTENT:   return (syserr_trc_pid_non_existent);
+    case ERROR_TRC_COUNT_ACTIVE:       return (syserr_trc_count_active);
+    case ERROR_TRC_SUSPENDED_BY_COUNT: return (syserr_trc_suspended_by_count);
+    case ERROR_TRC_COUNT_INACTIVE:     return (syserr_trc_count_inactive);
+    case ERROR_TRC_COUNT_REACHED:      return (syserr_trc_count_reached);
+    case ERROR_NO_MC_TRACE:    return (syserr_no_mc_trace);
+    case ERROR_MC_TRACE:       return (syserr_mc_trace);
+    case ERROR_TRC_COUNT_ZERO: return (syserr_trc_count_zero);
+    case ERROR_SMG_TOO_MANY_DDS:       return (syserr_smg_too_many_dds);
+    case ERROR_SMG_INVALID_NOTIFICATION:       return (syserr_smg_invalid_notification);
+    case ERROR_LF_INVALID_FUNCTION:    return (syserr_lf_invalid_function);
+    case ERROR_LF_NOT_AVAIL:   return (syserr_lf_not_avail);
+    case ERROR_LF_SUSPENDED:   return (syserr_lf_suspended);
+    case ERROR_LF_BUF_TOO_SMALL:       return (syserr_lf_buf_too_small);
+    case ERROR_LF_BUFFER_FULL: return (syserr_lf_buffer_full);
+    case ERROR_LF_INVALID_RECORD:      return (syserr_lf_invalid_record);
+    case ERROR_LF_INVALID_SERVICE:     return (syserr_lf_invalid_service);
+    case ERROR_LF_GENERAL_FAILURE:     return (syserr_lf_general_failure);
+    case ERROR_LF_INVALID_ID:  return (syserr_lf_invalid_id);
+    case ERROR_LF_INVALID_HANDLE:      return (syserr_lf_invalid_handle);
+    case ERROR_LF_NO_ID_AVAIL: return (syserr_lf_no_id_avail);
+    case ERROR_LF_TEMPLATE_AREA_FULL:  return (syserr_lf_template_area_full);
+    case ERROR_LF_ID_IN_USE:   return (syserr_lf_id_in_use);
+    case ERROR_MOU_NOT_INITIALIZED:    return (syserr_mou_not_initialized);
+    case ERROR_MOUINITREAL_DONE:       return (syserr_mouinitreal_done);
+    case ERROR_DOSSUB_CORRUPTED:       return (syserr_dossub_corrupted);
+    case ERROR_MOUSE_CALLER_NOT_SUBSYS:        return (syserr_mouse_caller_not_subsys);
+    case ERROR_ARITHMETIC_OVERFLOW:    return (syserr_arithmetic_overflow);
+    case ERROR_TMR_NO_DEVICE:  return (syserr_tmr_no_device);
+    case ERROR_TMR_INVALID_TIME:       return (syserr_tmr_invalid_time);
+    case ERROR_PVW_INVALID_ENTITY:     return (syserr_pvw_invalid_entity);
+    case ERROR_PVW_INVALID_ENTITY_TYPE:        return (syserr_pvw_invalid_entity_type);
+    case ERROR_PVW_INVALID_SPEC:       return (syserr_pvw_invalid_spec);
+    case ERROR_PVW_INVALID_RANGE_TYPE: return (syserr_pvw_invalid_range_type);
+    case ERROR_PVW_INVALID_COUNTER_BLK:        return (syserr_pvw_invalid_counter_blk);
+    case ERROR_PVW_INVALID_TEXT_BLK:   return (syserr_pvw_invalid_text_blk);
+    case ERROR_PRF_NOT_INITIALIZED:    return (syserr_prf_not_initialized);
+    case ERROR_PRF_ALREADY_INITIALIZED:        return (syserr_prf_already_initialized);
+    case ERROR_PRF_NOT_STARTED:        return (syserr_prf_not_started);
+    case ERROR_PRF_ALREADY_STARTED:    return (syserr_prf_already_started);
+    case ERROR_PRF_TIMER_OUT_OF_RANGE: return (syserr_prf_timer_out_of_range);
+    case ERROR_PRF_TIMER_RESET:        return (syserr_prf_timer_reset);
+    case ERROR_VDD_LOCK_USEAGE_DENIED: return (syserr_vdd_lock_useage_denied);
+    case ERROR_TIMEOUT:        return (syserr_timeout);
+    case ERROR_VDM_DOWN:       return (syserr_vdm_down);
+    case ERROR_VDM_LIMIT:      return (syserr_vdm_limit);
+    case ERROR_VDD_NOT_FOUND:  return (syserr_vdd_not_found);
+    case ERROR_INVALID_CALLER: return (syserr_invalid_caller);
+    case ERROR_PID_MISMATCH:   return (syserr_pid_mismatch);
+    case ERROR_INVALID_VDD_HANDLE:     return (syserr_invalid_vdd_handle);
+    case ERROR_VLPT_NO_SPOOLER:        return (syserr_vlpt_no_spooler);
+    case ERROR_VCOM_DEVICE_BUSY:       return (syserr_vcom_device_busy);
+    case ERROR_VLPT_DEVICE_BUSY:       return (syserr_vlpt_device_busy);
+    case ERROR_NESTING_TOO_DEEP:       return (syserr_nesting_too_deep);
+    case ERROR_VDD_MISSING:    return (syserr_vdd_missing);
+    case ERROR_BIDI_INVALID_LENGTH:    return (syserr_bidi_invalid_length);
+    case ERROR_BIDI_INVALID_INCREMENT: return (syserr_bidi_invalid_increment);
+    case ERROR_BIDI_INVALID_COMBINATION:       return (syserr_bidi_invalid_combination);
+    case ERROR_BIDI_INVALID_RESERVED:  return (syserr_bidi_invalid_reserved);
+    case ERROR_BIDI_INVALID_EFFECT:    return (syserr_bidi_invalid_effect);
+    case ERROR_BIDI_INVALID_CSDREC:    return (syserr_bidi_invalid_csdrec);
+    case ERROR_BIDI_INVALID_CSDSTATE:  return (syserr_bidi_invalid_csdstate);
+    case ERROR_BIDI_INVALID_LEVEL:     return (syserr_bidi_invalid_level);
+    case ERROR_BIDI_INVALID_TYPE_SUPPORT:      return (syserr_bidi_invalid_type_support);
+    case ERROR_BIDI_INVALID_ORIENTATION:       return (syserr_bidi_invalid_orientation);
+    case ERROR_BIDI_INVALID_NUM_SHAPE: return (syserr_bidi_invalid_num_shape);
+    case ERROR_BIDI_INVALID_CSD:       return (syserr_bidi_invalid_csd);
+    case ERROR_BIDI_NO_SUPPORT:        return (syserr_bidi_no_support);
+    case NO_ERROR_BIDI_RW_INCOMPLETE:  return (syserr_bidi_rw_incomplete);
+    case ERROR_IMP_INVALID_PARM:       return (syserr_imp_invalid_parm);
+    case ERROR_IMP_INVALID_LENGTH:     return (syserr_imp_invalid_length);
+    case MSG_HPFS_DISK_ERROR_WARN:     return (syserr_hpfs_disk_error_warn);
+    case ERROR_MON_BAD_BUFFER: return (syserr_mon_bad_buffer);
+    case ERROR_MODULE_CORRUPTED:       return (syserr_module_corrupted);
+    case ERROR_SM_OUTOF_SWAPFILE:      return (syserr_sm_outof_swapfile);
+    case ERROR_LF_TIMEOUT:     return (syserr_lf_timeout);
+    case ERROR_LF_SUSPEND_SUCCESS:     return (syserr_lf_suspend_success);
+    case ERROR_LF_RESUME_SUCCESS:      return (syserr_lf_resume_success);
+    case ERROR_LF_REDIRECT_SUCCESS:    return (syserr_lf_redirect_success);
+    case ERROR_LF_REDIRECT_FAILURE:    return (syserr_lf_redirect_failure);
+    case ERROR_SWAPPER_NOT_ACTIVE:     return (syserr_swapper_not_active);
+    case ERROR_INVALID_SWAPID: return (syserr_invalid_swapid);
+    case ERROR_IOERR_SWAP_FILE:        return (syserr_ioerr_swap_file);
+    case ERROR_SWAP_TABLE_FULL:        return (syserr_swap_table_full);
+    case ERROR_SWAP_FILE_FULL: return (syserr_swap_file_full);
+    case ERROR_CANT_INIT_SWAPPER:      return (syserr_cant_init_swapper);
+    case ERROR_SWAPPER_ALREADY_INIT:   return (syserr_swapper_already_init);
+    case ERROR_PMM_INSUFFICIENT_MEMORY:        return (syserr_pmm_insufficient_memory);
+    case ERROR_PMM_INVALID_FLAGS:      return (syserr_pmm_invalid_flags);
+    case ERROR_PMM_INVALID_ADDRESS:    return (syserr_pmm_invalid_address);
+    case ERROR_PMM_LOCK_FAILED:        return (syserr_pmm_lock_failed);
+    case ERROR_PMM_UNLOCK_FAILED:      return (syserr_pmm_unlock_failed);
+    case ERROR_PMM_MOVE_INCOMPLETE:    return (syserr_pmm_move_incomplete);
+    case ERROR_UCOM_DRIVE_RENAMED:     return (syserr_ucom_drive_renamed);
+    case ERROR_UCOM_FILENAME_TRUNCATED:        return (syserr_ucom_filename_truncated);
+    case ERROR_UCOM_BUFFER_LENGTH:     return (syserr_ucom_buffer_length);
+    case ERROR_MON_CHAIN_HANDLE:       return (syserr_mon_chain_handle);
+    case ERROR_MON_NOT_REGISTERED:     return (syserr_mon_not_registered);
+    case ERROR_SMG_ALREADY_TOP:        return (syserr_smg_already_top);
+    case ERROR_PMM_ARENA_MODIFIED:     return (syserr_pmm_arena_modified);
+    case ERROR_SMG_PRINTER_OPEN:       return (syserr_smg_printer_open);
+    case ERROR_PMM_SET_FLAGS_FAILED:   return (syserr_pmm_set_flags_failed);
+    case ERROR_INVALID_DOS_DD: return (syserr_invalid_dos_dd);
+    case ERROR_BLOCKED:        return (syserr_blocked);
+    case ERROR_NOBLOCK:        return (syserr_noblock);
+    case ERROR_INSTANCE_SHARED:        return (syserr_instance_shared);
+    case ERROR_NO_OBJECT:      return (syserr_no_object);
+    case ERROR_PARTIAL_ATTACH: return (syserr_partial_attach);
+    case ERROR_INCACHE:        return (syserr_incache);
+    case ERROR_SWAP_IO_PROBLEMS:       return (syserr_swap_io_problems);
+    case ERROR_CROSSES_OBJECT_BOUNDARY:        return (syserr_crosses_object_boundary);
+    case ERROR_LONGLOCK:       return (syserr_longlock);
+    case ERROR_SHORTLOCK:      return (syserr_shortlock);
+    case ERROR_UVIRTLOCK:      return (syserr_uvirtlock);
+    case ERROR_ALIASLOCK:      return (syserr_aliaslock);
+    case ERROR_ALIAS:  return (syserr_alias);
+    case ERROR_NO_MORE_HANDLES:        return (syserr_no_more_handles);
+    case ERROR_SCAN_TERMINATED:        return (syserr_scan_terminated);
+    case ERROR_TERMINATOR_NOT_FOUND:   return (syserr_terminator_not_found);
+    case ERROR_NOT_DIRECT_CHILD:       return (syserr_not_direct_child);
+    case ERROR_DELAY_FREE:     return (syserr_delay_free);
+    case ERROR_GUARDPAGE:      return (syserr_guardpage);
+    case ERROR_SWAPERROR:      return (syserr_swaperror);
+    case ERROR_LDRERROR:       return (syserr_ldrerror);
+    case ERROR_NOMEMORY:       return (syserr_nomemory);
+    case ERROR_NOACCESS:       return (syserr_noaccess);
+    case ERROR_NO_DLL_TERM:    return (syserr_no_dll_term);
+    case ERROR_CPSIO_CODE_PAGE_INVALID:        return (syserr_cpsio_code_page_invalid);
+    case ERROR_CPSIO_NO_SPOOLER:       return (syserr_cpsio_no_spooler);
+    case ERROR_CPSIO_FONT_ID_INVALID:  return (syserr_cpsio_font_id_invalid);
+    case ERROR_CPSIO_INTERNAL_ERROR:   return (syserr_cpsio_internal_error);
+    case ERROR_CPSIO_INVALID_PTR_NAME: return (syserr_cpsio_invalid_ptr_name);
+    case ERROR_CPSIO_NOT_ACTIVE:       return (syserr_cpsio_not_active);
+    case ERROR_CPSIO_PID_FULL: return (syserr_cpsio_pid_full);
+    case ERROR_CPSIO_PID_NOT_FOUND:    return (syserr_cpsio_pid_not_found);
+    case ERROR_CPSIO_READ_CTL_SEQ:     return (syserr_cpsio_read_ctl_seq);
+    case ERROR_CPSIO_READ_FNT_DEF:     return (syserr_cpsio_read_fnt_def);
+    case ERROR_CPSIO_WRITE_ERROR:      return (syserr_cpsio_write_error);
+    case ERROR_CPSIO_WRITE_FULL_ERROR: return (syserr_cpsio_write_full_error);
+    case ERROR_CPSIO_WRITE_HANDLE_BAD: return (syserr_cpsio_write_handle_bad);
+    case ERROR_CPSIO_SWIT_LOAD:        return (syserr_cpsio_swit_load);
+    case ERROR_CPSIO_INV_COMMAND:      return (syserr_cpsio_inv_command);
+    case ERROR_CPSIO_NO_FONT_SWIT:     return (syserr_cpsio_no_font_swit);
+    case ERROR_ENTRY_IS_CALLGATE:      return (syserr_entry_is_callgate);
+    default:   return (syserr_unknown);
+    }
+}
+\f
+#ifdef __GCC2__
+/* Grumble... stupid linking bug.  */
+#define dos_error_message(rc) 0
+#else /* not __GCC2__ */
+
+static const char *
+dos_error_message (APIRET rc)
+{
+  unsigned int blength_increment = 64;
+  unsigned int blength = blength_increment;
+  char * buffer = (malloc (blength));
+  ULONG mlength;
+
+  if (buffer == 0)
+    return (0);
+  while (1)
+    {
+      if ((dos_get_message
+          (0, 0, buffer, blength, rc, "OSO001.MSG", (&mlength)))
+         != NO_ERROR)
+       {
+         free (buffer);
+         return (0);
+       }
+      if (mlength < blength)
+       {
+         while ((mlength > 0) && (isspace (buffer [mlength - 1])))
+           mlength -= 1;
+         buffer = (realloc (buffer, (mlength + 1)));
+         if (buffer != 0)
+           (buffer[mlength]) = '\0';
+         return (buffer);
+       }
+      blength += blength_increment;
+      buffer = (realloc (buffer, (blength)));
+      if (buffer == 0)
+       return (0);
+    }
+}
+
+#endif /* not __GCC2__ */
+
+const char *
+OS_error_code_to_message (unsigned int syserr)
+{
+  static const char * last_message = 0;
+  if (last_message != 0)
+    free ((void *) last_message);
+  last_message = (dos_error_message (syserr));
+  return (last_message);
+}
+\f
+static char * syscall_names_table [] =
+{
+  "dos-async-timer",
+  "dos-close",
+  "dos-close-event-sem",
+  "dos-close-mutex-sem",
+  "dos-close-queue",
+  "dos-create-dir",
+  "dos-create-event-sem",
+  "dos-create-mutex-sem",
+  "dos-create-pipe",
+  "dos-create-queue",
+  "dos-create-thread",
+  "dos-delete",
+  "dos-delete-dir",
+  "dos-exit",
+  "dos-find-close",
+  "dos-find-first",
+  "dos-find-next",
+  "dos-get-info-blocks",
+  "dos-get-message",
+  "dos-kill-thread",
+  "dos-move",
+  "dos-open",
+  "dos-post-event-sem",
+  "dos-query-current-dir",
+  "dos-query-current-disk",
+  "dos-query-file-info",
+  "dos-query-h-type",
+  "dos-query-n-p-h-state",
+  "dos-query-path-info",
+  "dos-query-sys-info",
+  "dos-read",
+  "dos-read-queue",
+  "dos-release-mutex-sem",
+  "dos-request-mutex-sem",
+  "dos-reset-event-sem",
+  "dos-scan-env",
+  "dos-set-current-dir",
+  "dos-set-default-disk",
+  "dos-set-file-ptr",
+  "dos-set-file-size",
+  "dos-set-path-info",
+  "dos-start-timer",
+  "dos-stop-timer",
+  "dos-wait-event-sem",
+  "dos-write",
+  "dos-write-queue",
+  "beginthread",
+  "kbd-char-in",
+  "localtime",
+  "malloc",
+  "mktime",
+  "realloc",
+  "time",
+  "vio-wrt-tty"
+};
+
+void
+OS_syscall_names (unsigned int * length, unsigned char *** names)
+{
+  (*length) = ((sizeof (syscall_names_table)) / (sizeof (char *)));
+  (*names) = ((unsigned char **) syscall_names_table);
+}
+\f
+/* Machine-generated table, do not edit: */
+static char * syserr_names_table [] =
+{
+  "INVALID-FUNCTION",
+  "FILE-NOT-FOUND",
+  "PATH-NOT-FOUND",
+  "TOO-MANY-OPEN-FILES",
+  "ACCESS-DENIED",
+  "INVALID-HANDLE",
+  "ARENA-TRASHED",
+  "NOT-ENOUGH-MEMORY",
+  "INVALID-BLOCK",
+  "BAD-ENVIRONMENT",
+  "BAD-FORMAT",
+  "INVALID-ACCESS",
+  "INVALID-DATA",
+  "INVALID-DRIVE",
+  "CURRENT-DIRECTORY",
+  "NOT-SAME-DEVICE",
+  "NO-MORE-FILES",
+  "WRITE-PROTECT",
+  "BAD-UNIT",
+  "NOT-READY",
+  "BAD-COMMAND",
+  "CRC",
+  "BAD-LENGTH",
+  "SEEK",
+  "NOT-DOS-DISK",
+  "SECTOR-NOT-FOUND",
+  "OUT-OF-PAPER",
+  "WRITE-FAULT",
+  "READ-FAULT",
+  "GEN-FAILURE",
+  "SHARING-VIOLATION",
+  "LOCK-VIOLATION",
+  "WRONG-DISK",
+  "FCB-UNAVAILABLE",
+  "SHARING-BUFFER-EXCEEDED",
+  "CODE-PAGE-MISMATCHED",
+  "HANDLE-EOF",
+  "HANDLE-DISK-FULL",
+  "NOT-SUPPORTED",
+  "REM-NOT-LIST",
+  "DUP-NAME",
+  "BAD-NETPATH",
+  "NETWORK-BUSY",
+  "DEV-NOT-EXIST",
+  "TOO-MANY-CMDS",
+  "ADAP-HDW-ERR",
+  "BAD-NET-RESP",
+  "UNEXP-NET-ERR",
+  "BAD-REM-ADAP",
+  "PRINTQ-FULL",
+  "NO-SPOOL-SPACE",
+  "PRINT-CANCELLED",
+  "NETNAME-DELETED",
+  "NETWORK-ACCESS-DENIED",
+  "BAD-DEV-TYPE",
+  "BAD-NET-NAME",
+  "TOO-MANY-NAMES",
+  "TOO-MANY-SESS",
+  "SHARING-PAUSED",
+  "REQ-NOT-ACCEP",
+  "REDIR-PAUSED",
+  "SBCS-ATT-WRITE-PROT",
+  "SBCS-GENERAL-FAILURE",
+  "XGA-OUT-MEMORY",
+  "FILE-EXISTS",
+  "DUP-FCB",
+  "CANNOT-MAKE",
+  "FAIL-I24",
+  "OUT-OF-STRUCTURES",
+  "ALREADY-ASSIGNED",
+  "INVALID-PASSWORD",
+  "INVALID-PARAMETER",
+  "NET-WRITE-FAULT",
+  "NO-PROC-SLOTS",
+  "NOT-FROZEN",
+  "SYS-COMP-NOT-LOADED",
+  "TSTOVFL",
+  "TSTDUP",
+  "NO-ITEMS",
+  "INTERRUPT",
+  "DEVICE-IN-USE",
+  "TOO-MANY-SEMAPHORES",
+  "EXCL-SEM-ALREADY-OWNED",
+  "SEM-IS-SET",
+  "TOO-MANY-SEM-REQUESTS",
+  "INVALID-AT-INTERRUPT-TIME",
+  "SEM-OWNER-DIED",
+  "SEM-USER-LIMIT",
+  "DISK-CHANGE",
+  "DRIVE-LOCKED",
+  "BROKEN-PIPE",
+  "OPEN-FAILED",
+  "BUFFER-OVERFLOW",
+  "DISK-FULL",
+  "NO-MORE-SEARCH-HANDLES",
+  "INVALID-TARGET-HANDLE",
+  "PROTECTION-VIOLATION",
+  "VIOKBD-REQUEST",
+  "INVALID-CATEGORY",
+  "INVALID-VERIFY-SWITCH",
+  "BAD-DRIVER-LEVEL",
+  "CALL-NOT-IMPLEMENTED",
+  "SEM-TIMEOUT",
+  "INSUFFICIENT-BUFFER",
+  "INVALID-NAME",
+  "INVALID-LEVEL",
+  "NO-VOLUME-LABEL",
+  "MOD-NOT-FOUND",
+  "PROC-NOT-FOUND",
+  "WAIT-NO-CHILDREN",
+  "CHILD-NOT-COMPLETE",
+  "DIRECT-ACCESS-HANDLE",
+  "NEGATIVE-SEEK",
+  "SEEK-ON-DEVICE",
+  "IS-JOIN-TARGET",
+  "IS-JOINED",
+  "IS-SUBSTED",
+  "NOT-JOINED",
+  "NOT-SUBSTED",
+  "JOIN-TO-JOIN",
+  "SUBST-TO-SUBST",
+  "JOIN-TO-SUBST",
+  "SUBST-TO-JOIN",
+  "BUSY-DRIVE",
+  "SAME-DRIVE",
+  "DIR-NOT-ROOT",
+  "DIR-NOT-EMPTY",
+  "IS-SUBST-PATH",
+  "IS-JOIN-PATH",
+  "PATH-BUSY",
+  "IS-SUBST-TARGET",
+  "SYSTEM-TRACE",
+  "INVALID-EVENT-COUNT",
+  "TOO-MANY-MUXWAITERS",
+  "INVALID-LIST-FORMAT",
+  "LABEL-TOO-LONG",
+  "TOO-MANY-TCBS",
+  "SIGNAL-REFUSED",
+  "DISCARDED",
+  "NOT-LOCKED",
+  "BAD-THREADID-ADDR",
+  "BAD-ARGUMENTS",
+  "BAD-PATHNAME",
+  "SIGNAL-PENDING",
+  "UNCERTAIN-MEDIA",
+  "MAX-THRDS-REACHED",
+  "MONITORS-NOT-SUPPORTED",
+  "UNC-DRIVER-NOT-INSTALLED",
+  "LOCK-FAILED",
+  "SWAPIO-FAILED",
+  "SWAPIN-FAILED",
+  "BUSY",
+  "CANCEL-VIOLATION",
+  "ATOMIC-LOCK-NOT-SUPPORTED",
+  "READ-LOCKS-NOT-SUPPORTED",
+  "INVALID-SEGMENT-NUMBER",
+  "INVALID-CALLGATE",
+  "INVALID-ORDINAL",
+  "ALREADY-EXISTS",
+  "NO-CHILD-PROCESS",
+  "CHILD-ALIVE-NOWAIT",
+  "INVALID-FLAG-NUMBER",
+  "SEM-NOT-FOUND",
+  "INVALID-STARTING-CODESEG",
+  "INVALID-STACKSEG",
+  "INVALID-MODULETYPE",
+  "INVALID-EXE-SIGNATURE",
+  "EXE-MARKED-INVALID",
+  "BAD-EXE-FORMAT",
+  "ITERATED-DATA-EXCEEDS-64K",
+  "INVALID-MINALLOCSIZE",
+  "DYNLINK-FROM-INVALID-RING",
+  "IOPL-NOT-ENABLED",
+  "INVALID-SEGDPL",
+  "AUTODATASEG-EXCEEDS-64K",
+  "RING2SEG-MUST-BE-MOVABLE",
+  "RELOC-CHAIN-XEEDS-SEGLIM",
+  "INFLOOP-IN-RELOC-CHAIN",
+  "ENVVAR-NOT-FOUND",
+  "NOT-CURRENT-CTRY",
+  "NO-SIGNAL-SENT",
+  "FILENAME-EXCED-RANGE",
+  "RING2-STACK-IN-USE",
+  "META-EXPANSION-TOO-LONG",
+  "INVALID-SIGNAL-NUMBER",
+  "THREAD-1-INACTIVE",
+  "INFO-NOT-AVAIL",
+  "LOCKED",
+  "BAD-DYNALINK",
+  "TOO-MANY-MODULES",
+  "NESTING-NOT-ALLOWED",
+  "CANNOT-SHRINK",
+  "ZOMBIE-PROCESS",
+  "STACK-IN-HIGH-MEMORY",
+  "INVALID-EXITROUTINE-RING",
+  "GETBUF-FAILED",
+  "FLUSHBUF-FAILED",
+  "TRANSFER-TOO-LONG",
+  "FORCENOSWAP-FAILED",
+  "SMG-NO-TARGET-WINDOW",
+  "NO-CHILDREN",
+  "INVALID-SCREEN-GROUP",
+  "BAD-PIPE",
+  "PIPE-BUSY",
+  "NO-DATA",
+  "PIPE-NOT-CONNECTED",
+  "MORE-DATA",
+  "VC-DISCONNECTED",
+  "CIRCULARITY-REQUESTED",
+  "DIRECTORY-IN-CDS",
+  "INVALID-FSD-NAME",
+  "INVALID-PATH",
+  "INVALID-EA-NAME",
+  "EA-LIST-INCONSISTENT",
+  "EA-LIST-TOO-LONG",
+  "NO-META-MATCH",
+  "FINDNOTIFY-TIMEOUT",
+  "NO-MORE-ITEMS",
+  "SEARCH-STRUC-REUSED",
+  "CHAR-NOT-FOUND",
+  "TOO-MUCH-STACK",
+  "INVALID-ATTR",
+  "INVALID-STARTING-RING",
+  "INVALID-DLL-INIT-RING",
+  "CANNOT-COPY",
+  "DIRECTORY",
+  "OPLOCKED-FILE",
+  "OPLOCK-THREAD-EXISTS",
+  "VOLUME-CHANGED",
+  "FINDNOTIFY-HANDLE-IN-USE",
+  "FINDNOTIFY-HANDLE-CLOSED",
+  "NOTIFY-OBJECT-REMOVED",
+  "ALREADY-SHUTDOWN",
+  "EAS-DIDNT-FIT",
+  "EA-FILE-CORRUPT",
+  "EA-TABLE-FULL",
+  "INVALID-EA-HANDLE",
+  "NO-CLUSTER",
+  "CREATE-EA-FILE",
+  "CANNOT-OPEN-EA-FILE",
+  "EAS-NOT-SUPPORTED",
+  "NEED-EAS-FOUND",
+  "DUPLICATE-HANDLE",
+  "DUPLICATE-NAME",
+  "EMPTY-MUXWAIT",
+  "MUTEX-OWNED",
+  "NOT-OWNER",
+  "PARAM-TOO-SMALL",
+  "TOO-MANY-HANDLES",
+  "TOO-MANY-OPENS",
+  "WRONG-TYPE",
+  "UNUSED-CODE",
+  "THREAD-NOT-TERMINATED",
+  "INIT-ROUTINE-FAILED",
+  "MODULE-IN-USE",
+  "NOT-ENOUGH-WATCHPOINTS",
+  "TOO-MANY-POSTS",
+  "ALREADY-POSTED",
+  "ALREADY-RESET",
+  "SEM-BUSY",
+  "INVALID-PROCID",
+  "INVALID-PDELTA",
+  "NOT-DESCENDANT",
+  "NOT-SESSION-MANAGER",
+  "INVALID-PCLASS",
+  "INVALID-SCOPE",
+  "INVALID-THREADID",
+  "DOSSUB-SHRINK",
+  "DOSSUB-NOMEM",
+  "DOSSUB-OVERLAP",
+  "DOSSUB-BADSIZE",
+  "DOSSUB-BADFLAG",
+  "DOSSUB-BADSELECTOR",
+  "MR-MSG-TOO-LONG",
+  "MR-MID-NOT-FOUND",
+  "MR-UN-ACC-MSGF",
+  "MR-INV-MSGF-FORMAT",
+  "MR-INV-IVCOUNT",
+  "MR-UN-PERFORM",
+  "TS-WAKEUP",
+  "TS-SEMHANDLE",
+  "TS-NOTIMER",
+  "TS-HANDLE",
+  "TS-DATETIME",
+  "SYS-INTERNAL",
+  "QUE-CURRENT-NAME",
+  "QUE-PROC-NOT-OWNED",
+  "QUE-PROC-OWNED",
+  "QUE-DUPLICATE",
+  "QUE-ELEMENT-NOT-EXIST",
+  "QUE-NO-MEMORY",
+  "QUE-INVALID-NAME",
+  "QUE-INVALID-PRIORITY",
+  "QUE-INVALID-HANDLE",
+  "QUE-LINK-NOT-FOUND",
+  "QUE-MEMORY-ERROR",
+  "QUE-PREV-AT-END",
+  "QUE-PROC-NO-ACCESS",
+  "QUE-EMPTY",
+  "QUE-NAME-NOT-EXIST",
+  "QUE-NOT-INITIALIZED",
+  "QUE-UNABLE-TO-ACCESS",
+  "QUE-UNABLE-TO-ADD",
+  "QUE-UNABLE-TO-INIT",
+  "VIO-INVALID-MASK",
+  "VIO-PTR",
+  "VIO-APTR",
+  "VIO-RPTR",
+  "VIO-CPTR",
+  "VIO-LPTR",
+  "VIO-MODE",
+  "VIO-WIDTH",
+  "VIO-ATTR",
+  "VIO-ROW",
+  "VIO-COL",
+  "VIO-TOPROW",
+  "VIO-BOTROW",
+  "VIO-RIGHTCOL",
+  "VIO-LEFTCOL",
+  "SCS-CALL",
+  "SCS-VALUE",
+  "VIO-WAIT-FLAG",
+  "VIO-UNLOCK",
+  "SGS-NOT-SESSION-MGR",
+  "SMG-INVALID-SESSION-ID",
+  "SMG-NO-SESSIONS",
+  "SMG-SESSION-NOT-FOUND",
+  "SMG-SET-TITLE",
+  "KBD-PARAMETER",
+  "KBD-NO-DEVICE",
+  "KBD-INVALID-IOWAIT",
+  "KBD-INVALID-LENGTH",
+  "KBD-INVALID-ECHO-MASK",
+  "KBD-INVALID-INPUT-MASK",
+  "MON-INVALID-PARMS",
+  "MON-INVALID-DEVNAME",
+  "MON-INVALID-HANDLE",
+  "MON-BUFFER-TOO-SMALL",
+  "MON-BUFFER-EMPTY",
+  "MON-DATA-TOO-LARGE",
+  "MOUSE-NO-DEVICE",
+  "MOUSE-INV-HANDLE",
+  "MOUSE-INV-PARMS",
+  "MOUSE-CANT-RESET",
+  "MOUSE-DISPLAY-PARMS",
+  "MOUSE-INV-MODULE",
+  "MOUSE-INV-ENTRY-PT",
+  "MOUSE-INV-MASK",
+  "MOUSE-NO-DATA",
+  "MOUSE-PTR-DRAWN",
+  "INVALID-FREQUENCY",
+  "NLS-NO-COUNTRY-FILE",
+  "NLS-OPEN-FAILED",
+  "NO-COUNTRY-OR-CODEPAGE",
+  "NLS-TABLE-TRUNCATED",
+  "NLS-BAD-TYPE",
+  "NLS-TYPE-NOT-FOUND",
+  "VIO-SMG-ONLY",
+  "VIO-INVALID-ASCIIZ",
+  "VIO-DEREGISTER",
+  "VIO-NO-POPUP",
+  "VIO-EXISTING-POPUP",
+  "KBD-SMG-ONLY",
+  "KBD-INVALID-ASCIIZ",
+  "KBD-INVALID-MASK",
+  "KBD-REGISTER",
+  "KBD-DEREGISTER",
+  "MOUSE-SMG-ONLY",
+  "MOUSE-INVALID-ASCIIZ",
+  "MOUSE-INVALID-MASK",
+  "MOUSE-REGISTER",
+  "MOUSE-DEREGISTER",
+  "SMG-BAD-ACTION",
+  "SMG-INVALID-CALL",
+  "SCS-SG-NOTFOUND",
+  "SCS-NOT-SHELL",
+  "VIO-INVALID-PARMS",
+  "VIO-FUNCTION-OWNED",
+  "VIO-RETURN",
+  "SCS-INVALID-FUNCTION",
+  "SCS-NOT-SESSION-MGR",
+  "VIO-REGISTER",
+  "VIO-NO-MODE-THREAD",
+  "VIO-NO-SAVE-RESTORE-THD",
+  "VIO-IN-BG",
+  "VIO-ILLEGAL-DURING-POPUP",
+  "SMG-NOT-BASESHELL",
+  "SMG-BAD-STATUSREQ",
+  "QUE-INVALID-WAIT",
+  "VIO-LOCK",
+  "MOUSE-INVALID-IOWAIT",
+  "VIO-INVALID-HANDLE",
+  "VIO-ILLEGAL-DURING-LOCK",
+  "VIO-INVALID-LENGTH",
+  "KBD-INVALID-HANDLE",
+  "KBD-NO-MORE-HANDLE",
+  "KBD-CANNOT-CREATE-KCB",
+  "KBD-CODEPAGE-LOAD-INCOMPL",
+  "KBD-INVALID-CODEPAGE-ID",
+  "KBD-NO-CODEPAGE-SUPPORT",
+  "KBD-FOCUS-REQUIRED",
+  "KBD-FOCUS-ALREADY-ACTIVE",
+  "KBD-KEYBOARD-BUSY",
+  "KBD-INVALID-CODEPAGE",
+  "KBD-UNABLE-TO-FOCUS",
+  "SMG-SESSION-NON-SELECT",
+  "SMG-SESSION-NOT-FOREGRND",
+  "SMG-SESSION-NOT-PARENT",
+  "SMG-INVALID-START-MODE",
+  "SMG-INVALID-RELATED-OPT",
+  "SMG-INVALID-BOND-OPTION",
+  "SMG-INVALID-SELECT-OPT",
+  "SMG-START-IN-BACKGROUND",
+  "SMG-INVALID-STOP-OPTION",
+  "SMG-BAD-RESERVE",
+  "SMG-PROCESS-NOT-PARENT",
+  "SMG-INVALID-DATA-LENGTH",
+  "SMG-NOT-BOUND",
+  "SMG-RETRY-SUB-ALLOC",
+  "KBD-DETACHED",
+  "VIO-DETACHED",
+  "MOU-DETACHED",
+  "VIO-FONT",
+  "VIO-USER-FONT",
+  "VIO-BAD-CP",
+  "VIO-NO-CP",
+  "VIO-NA-CP",
+  "INVALID-CODE-PAGE",
+  "CPLIST-TOO-SMALL",
+  "CP-NOT-MOVED",
+  "MODE-SWITCH-INIT",
+  "CODE-PAGE-NOT-FOUND",
+  "UNEXPECTED-SLOT-RETURNED",
+  "SMG-INVALID-TRACE-OPTION",
+  "VIO-INTERNAL-RESOURCE",
+  "VIO-SHELL-INIT",
+  "SMG-NO-HARD-ERRORS",
+  "CP-SWITCH-INCOMPLETE",
+  "VIO-TRANSPARENT-POPUP",
+  "CRITSEC-OVERFLOW",
+  "CRITSEC-UNDERFLOW",
+  "VIO-BAD-RESERVE",
+  "INVALID-ADDRESS",
+  "ZERO-SELECTORS-REQUESTED",
+  "NOT-ENOUGH-SELECTORS-AVA",
+  "INVALID-SELECTOR",
+  "SMG-INVALID-PROGRAM-TYPE",
+  "SMG-INVALID-PGM-CONTROL",
+  "SMG-INVALID-INHERIT-OPT",
+  "VIO-EXTENDED-SG",
+  "VIO-NOT-PRES-MGR-SG",
+  "VIO-SHIELD-OWNED",
+  "VIO-NO-MORE-HANDLES",
+  "VIO-SEE-ERROR-LOG",
+  "VIO-ASSOCIATED-DC",
+  "KBD-NO-CONSOLE",
+  "MOUSE-NO-CONSOLE",
+  "MOUSE-INVALID-HANDLE",
+  "SMG-INVALID-DEBUG-PARMS",
+  "KBD-EXTENDED-SG",
+  "MOU-EXTENDED-SG",
+  "SMG-INVALID-ICON-FILE",
+  "TRC-PID-NON-EXISTENT",
+  "TRC-COUNT-ACTIVE",
+  "TRC-SUSPENDED-BY-COUNT",
+  "TRC-COUNT-INACTIVE",
+  "TRC-COUNT-REACHED",
+  "NO-MC-TRACE",
+  "MC-TRACE",
+  "TRC-COUNT-ZERO",
+  "SMG-TOO-MANY-DDS",
+  "SMG-INVALID-NOTIFICATION",
+  "LF-INVALID-FUNCTION",
+  "LF-NOT-AVAIL",
+  "LF-SUSPENDED",
+  "LF-BUF-TOO-SMALL",
+  "LF-BUFFER-FULL",
+  "LF-INVALID-RECORD",
+  "LF-INVALID-SERVICE",
+  "LF-GENERAL-FAILURE",
+  "LF-INVALID-ID",
+  "LF-INVALID-HANDLE",
+  "LF-NO-ID-AVAIL",
+  "LF-TEMPLATE-AREA-FULL",
+  "LF-ID-IN-USE",
+  "MOU-NOT-INITIALIZED",
+  "MOUINITREAL-DONE",
+  "DOSSUB-CORRUPTED",
+  "MOUSE-CALLER-NOT-SUBSYS",
+  "ARITHMETIC-OVERFLOW",
+  "TMR-NO-DEVICE",
+  "TMR-INVALID-TIME",
+  "PVW-INVALID-ENTITY",
+  "PVW-INVALID-ENTITY-TYPE",
+  "PVW-INVALID-SPEC",
+  "PVW-INVALID-RANGE-TYPE",
+  "PVW-INVALID-COUNTER-BLK",
+  "PVW-INVALID-TEXT-BLK",
+  "PRF-NOT-INITIALIZED",
+  "PRF-ALREADY-INITIALIZED",
+  "PRF-NOT-STARTED",
+  "PRF-ALREADY-STARTED",
+  "PRF-TIMER-OUT-OF-RANGE",
+  "PRF-TIMER-RESET",
+  "VDD-LOCK-USEAGE-DENIED",
+  "TIMEOUT",
+  "VDM-DOWN",
+  "VDM-LIMIT",
+  "VDD-NOT-FOUND",
+  "INVALID-CALLER",
+  "PID-MISMATCH",
+  "INVALID-VDD-HANDLE",
+  "VLPT-NO-SPOOLER",
+  "VCOM-DEVICE-BUSY",
+  "VLPT-DEVICE-BUSY",
+  "NESTING-TOO-DEEP",
+  "VDD-MISSING",
+  "BIDI-INVALID-LENGTH",
+  "BIDI-INVALID-INCREMENT",
+  "BIDI-INVALID-COMBINATION",
+  "BIDI-INVALID-RESERVED",
+  "BIDI-INVALID-EFFECT",
+  "BIDI-INVALID-CSDREC",
+  "BIDI-INVALID-CSDSTATE",
+  "BIDI-INVALID-LEVEL",
+  "BIDI-INVALID-TYPE-SUPPORT",
+  "BIDI-INVALID-ORIENTATION",
+  "BIDI-INVALID-NUM-SHAPE",
+  "BIDI-INVALID-CSD",
+  "BIDI-NO-SUPPORT",
+  "BIDI-RW-INCOMPLETE",
+  "IMP-INVALID-PARM",
+  "IMP-INVALID-LENGTH",
+  "HPFS-DISK-ERROR-WARN",
+  "MON-BAD-BUFFER",
+  "MODULE-CORRUPTED",
+  "SM-OUTOF-SWAPFILE",
+  "LF-TIMEOUT",
+  "LF-SUSPEND-SUCCESS",
+  "LF-RESUME-SUCCESS",
+  "LF-REDIRECT-SUCCESS",
+  "LF-REDIRECT-FAILURE",
+  "SWAPPER-NOT-ACTIVE",
+  "INVALID-SWAPID",
+  "IOERR-SWAP-FILE",
+  "SWAP-TABLE-FULL",
+  "SWAP-FILE-FULL",
+  "CANT-INIT-SWAPPER",
+  "SWAPPER-ALREADY-INIT",
+  "PMM-INSUFFICIENT-MEMORY",
+  "PMM-INVALID-FLAGS",
+  "PMM-INVALID-ADDRESS",
+  "PMM-LOCK-FAILED",
+  "PMM-UNLOCK-FAILED",
+  "PMM-MOVE-INCOMPLETE",
+  "UCOM-DRIVE-RENAMED",
+  "UCOM-FILENAME-TRUNCATED",
+  "UCOM-BUFFER-LENGTH",
+  "MON-CHAIN-HANDLE",
+  "MON-NOT-REGISTERED",
+  "SMG-ALREADY-TOP",
+  "PMM-ARENA-MODIFIED",
+  "SMG-PRINTER-OPEN",
+  "PMM-SET-FLAGS-FAILED",
+  "INVALID-DOS-DD",
+  "BLOCKED",
+  "NOBLOCK",
+  "INSTANCE-SHARED",
+  "NO-OBJECT",
+  "PARTIAL-ATTACH",
+  "INCACHE",
+  "SWAP-IO-PROBLEMS",
+  "CROSSES-OBJECT-BOUNDARY",
+  "LONGLOCK",
+  "SHORTLOCK",
+  "UVIRTLOCK",
+  "ALIASLOCK",
+  "ALIAS",
+  "NO-MORE-HANDLES",
+  "SCAN-TERMINATED",
+  "TERMINATOR-NOT-FOUND",
+  "NOT-DIRECT-CHILD",
+  "DELAY-FREE",
+  "GUARDPAGE",
+  "SWAPERROR",
+  "LDRERROR",
+  "NOMEMORY",
+  "NOACCESS",
+  "NO-DLL-TERM",
+  "CPSIO-CODE-PAGE-INVALID",
+  "CPSIO-NO-SPOOLER",
+  "CPSIO-FONT-ID-INVALID",
+  "CPSIO-INTERNAL-ERROR",
+  "CPSIO-INVALID-PTR-NAME",
+  "CPSIO-NOT-ACTIVE",
+  "CPSIO-PID-FULL",
+  "CPSIO-PID-NOT-FOUND",
+  "CPSIO-READ-CTL-SEQ",
+  "CPSIO-READ-FNT-DEF",
+  "CPSIO-WRITE-ERROR",
+  "CPSIO-WRITE-FULL-ERROR",
+  "CPSIO-WRITE-HANDLE-BAD",
+  "CPSIO-SWIT-LOAD",
+  "CPSIO-INV-COMMAND",
+  "CPSIO-NO-FONT-SWIT",
+  "ENTRY-IS-CALLGATE",
+  "UNKNOWN"
+};
+
+void
+OS_syserr_names (unsigned int * length, unsigned char *** names)
+{
+  (*length) = ((sizeof (syserr_names_table)) / (sizeof (char *)));
+  (*names) = ((unsigned char **) syserr_names_table);
+}
diff --git a/v7/src/microcode/os2tty.c b/v7/src/microcode/os2tty.c
new file mode 100644 (file)
index 0000000..804e13b
--- /dev/null
@@ -0,0 +1,96 @@
+/* -*-C-*-
+
+$Id: os2tty.c,v 1.1 1994/11/28 03:43:02 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "os2.h"
+#include "ostty.h"
+#ifdef USE_PMIO
+#include <pmio.h>
+#endif
+\f
+static Tchannel input_channel;
+static Tchannel output_channel;
+
+void
+OS2_initialize_tty (void)
+{
+  extern Tchannel EXFUN (OS_open_fd, (int fd));
+  input_channel = (OS2_make_channel (0, CHANNEL_READ));
+  (CHANNEL_INTERNAL (input_channel)) = 1;
+  output_channel = (OS2_make_channel (1, CHANNEL_WRITE));
+  (CHANNEL_INTERNAL (output_channel)) = 1;
+}
+
+Tchannel
+OS_tty_input_channel (void)
+{
+  return (input_channel);
+}
+
+Tchannel
+OS_tty_output_channel (void)
+{
+  return (output_channel);
+}
+
+unsigned int
+OS_tty_x_size (void)
+{
+#ifdef USE_PMIO
+  return (get_screen_width ());
+#else
+  return (80);
+#endif
+}
+
+unsigned int
+OS_tty_y_size (void)
+{
+#ifdef USE_PMIO
+  return (get_screen_height ());
+#else
+  return (24);
+#endif
+}
+
+const char *
+OS_tty_command_beep (void)
+{
+  return ("\a");
+}
+
+const char *
+OS_tty_command_clear (void)
+{
+  return ("\f");
+}
diff --git a/v7/src/microcode/pros2fs.c b/v7/src/microcode/pros2fs.c
new file mode 100644 (file)
index 0000000..596d52d
--- /dev/null
@@ -0,0 +1,369 @@
+/* -*-C-*-
+
+$Id: pros2fs.c,v 1.1 1994/11/28 03:43:02 cph Exp $
+
+Copyright (c) 1994 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. */
+
+#include "scheme.h"
+#undef END_OF_CHAIN
+#include "prims.h"
+#include "os2.h"
+#include "osfs.h"
+
+extern FILESTATUS3 * OS2_read_file_status (const char *);
+extern void OS2_write_file_status (const char *, FILESTATUS3 *);
+
+#ifndef FILE_TOUCH_OPEN_TRIES
+#define FILE_TOUCH_OPEN_TRIES 5
+#endif
+
+static SCHEME_OBJECT time_to_integer (FDATE *, FTIME *);
+static void integer_to_time (SCHEME_OBJECT, FDATE *, FTIME *);
+static SCHEME_OBJECT file_touch (const char *);
+static void protect_handle (LHANDLE);
+\f
+DEFINE_PRIMITIVE ("FILE-ATTRIBUTES", Prim_file_attributes, 1, 1,
+  "Return attributes of FILE, as an integer.")
+{
+  PRIMITIVE_HEADER (1);
+  {
+    FILESTATUS3 * info = (OS2_read_file_status (STRING_ARG (1)));
+    PRIMITIVE_RETURN
+      ((info == 0)
+       ? SHARP_F
+       : (LONG_TO_UNSIGNED_FIXNUM (info -> attrFile)));
+  }
+}
+
+DEFINE_PRIMITIVE ("SET-FILE-ATTRIBUTES!", Prim_set_file_attributes, 2, 2,
+  "Set the attributes of FILE to ATTRIBUTES.")
+{
+  PRIMITIVE_HEADER (2);
+  {
+    FILESTATUS3 * info = (OS2_read_file_status (STRING_ARG (1)));
+    if (info == 0)
+      error_bad_range_arg (1);
+    (info -> attrFile) = (arg_index_integer (2, 0x10000));
+    OS2_write_file_status ((STRING_ARG (1)), info);
+    PRIMITIVE_RETURN (UNSPECIFIC);
+  }
+}
+
+DEFINE_PRIMITIVE ("FILE-LENGTH", Prim_file_length, 1, 1,
+  "Return attributes of FILE, as an integer.")
+{
+  PRIMITIVE_HEADER (1);
+  {
+    FILESTATUS3 * info = (OS2_read_file_status (STRING_ARG (1)));
+    PRIMITIVE_RETURN
+      ((info == 0)
+       ? SHARP_F
+       : (LONG_TO_UNSIGNED_FIXNUM (info -> cbFile)));
+  }
+}
+
+DEFINE_PRIMITIVE ("GET-ENVIRONMENT-VARIABLE", Prim_get_environment_variable, 1, 1,
+  "Look up the value of a variable in the user's shell environment.\n\
+The argument, a variable name, must be a string.\n\
+The result is either a string (the variable's value),\n\
+ or #F indicating that the variable does not exist.")
+{
+  PRIMITIVE_HEADER (1);
+  {
+    PSZ result;
+    XTD_API_CALL
+      (dos_scan_env, ((STRING_ARG (1)), (& result)),
+       {
+        if (rc == ERROR_ENVVAR_NOT_FOUND)
+          PRIMITIVE_RETURN (SHARP_F);
+       });
+    PRIMITIVE_RETURN (char_pointer_to_string (result));
+  }
+}
+
+DEFINE_PRIMITIVE ("FILE-EQ?", Prim_file_eq_p, 2, 2,
+  "True iff the two file arguments are the same file.")
+{
+  PRIMITIVE_HEADER (2);
+  CHECK_ARG (1, STRING_P);
+  CHECK_ARG (2, STRING_P);
+  {
+    unsigned long length = (STRING_LENGTH (ARG_REF (1)));
+    const char * s1 = (STRING_LOC ((ARG_REF (1)), 0));
+    const char * s2 = (STRING_LOC ((ARG_REF (2)), 0));
+    const char * e1 = (s1 + length);
+    if ((STRING_LENGTH (ARG_REF (2))) != length)
+      PRIMITIVE_RETURN (SHARP_F);
+    while (s1 < e1)
+      if ((char_upcase (*s1++)) != (char_upcase (*s2++)))
+       PRIMITIVE_RETURN (SHARP_F);
+    PRIMITIVE_RETURN (SHARP_T);
+  }
+}
+\f
+DEFINE_PRIMITIVE ("FILE-MOD-TIME", Prim_file_mod_time, 1, 1, 0)
+{
+  PRIMITIVE_HEADER (1);
+  {
+    FILESTATUS3 * info = (OS2_read_file_status (STRING_ARG (1)));
+    PRIMITIVE_RETURN
+      ((info == 0)
+       ? SHARP_F
+       : (time_to_integer ((& (info -> fdateLastWrite)),
+                          (& (info -> ftimeLastWrite)))));
+  }
+}
+
+DEFINE_PRIMITIVE ("FILE-ACCESS-TIME", Prim_file_acc_time, 1, 1, 0)
+{
+  PRIMITIVE_HEADER (1);
+  {
+    FILESTATUS3 * info = (OS2_read_file_status (STRING_ARG (1)));
+    PRIMITIVE_RETURN
+      ((info == 0)
+       ? SHARP_F
+       : (time_to_integer ((& (info -> fdateLastAccess)),
+                          (& (info -> ftimeLastAccess)))));
+  }
+}
+
+DEFINE_PRIMITIVE ("SET-FILE-TIMES!", Prim_set_file_times, 3, 3,
+  "Change the access and modification times of FILE.\n\
+The second and third arguments are the respective times.\n\
+The file must exist and you must be the owner (or superuser).")
+{
+  PRIMITIVE_HEADER (3);
+  {
+    FILESTATUS3 * info = (OS2_read_file_status (STRING_ARG (1)));
+    SCHEME_OBJECT atime = (ARG_REF (2));
+    SCHEME_OBJECT mtime = (ARG_REF (3));
+    if (info == 0)
+      error_bad_range_arg (1);
+    if (atime != SHARP_F)
+      {
+       if (!INTEGER_P (atime))
+         error_wrong_type_arg (2);
+       if (integer_negative_p (atime))
+         error_bad_range_arg (2);
+       integer_to_time (atime,
+                        (& (info -> fdateLastAccess)),
+                        (& (info -> ftimeLastAccess)));
+      }
+    if (mtime != SHARP_F)
+      {
+       if (!INTEGER_P (mtime))
+         error_wrong_type_arg (3);
+       if (integer_negative_p (mtime))
+         error_bad_range_arg (3);
+       integer_to_time (mtime,
+                        (& (info -> fdateLastWrite)),
+                        (& (info -> ftimeLastWrite)));
+      }
+    OS2_write_file_status ((STRING_ARG (1)), info);
+  }
+  PRIMITIVE_RETURN (UNSPECIFIC);
+}
+
+DEFINE_PRIMITIVE ("FILE-TOUCH", Prim_file_touch, 1, 1,
+  "Given a file name, change the times of the file to the current time.\n\
+If the file does not exist, create it.\n\
+Both the access time and modification time are changed.\n\
+Return #F if the file existed and its time was modified.\n\
+Otherwise the file did not exist and it was created.")
+{
+  PRIMITIVE_HEADER (1);
+  PRIMITIVE_RETURN (file_touch ((CONST char *) (STRING_ARG (1))));
+}
+\f
+static SCHEME_OBJECT
+time_to_integer (FDATE * date, FTIME * time)
+{
+  unsigned long id;
+  unsigned long it;
+  id = (date -> year);
+  id = ((id << 4) | (date -> month));
+  id = ((id << 5) | (date -> day));
+  it = (time -> hours);
+  it = ((it << 6) | (time -> minutes));
+  it = ((it << 5) | (time -> twosecs));
+  return
+    (integer_add ((integer_multiply ((LONG_TO_UNSIGNED_FIXNUM (id)),
+                                    (LONG_TO_UNSIGNED_FIXNUM (0x10000)))),
+                 (LONG_TO_UNSIGNED_FIXNUM (it))));
+}
+
+static void
+integer_to_time (SCHEME_OBJECT encoding, FDATE * date, FTIME * time)
+{
+  unsigned long id;
+  unsigned long it;
+  {
+    SCHEME_OBJECT q;
+    SCHEME_OBJECT r;
+    (void) integer_divide
+      (encoding, (LONG_TO_UNSIGNED_FIXNUM (0x10000)), (&q), (&r));
+    it = (UNSIGNED_FIXNUM_TO_LONG (r));
+    /* If encoding is larger than 32 bits, ignore MS bits.  */
+    (void) integer_divide
+      (q, (LONG_TO_UNSIGNED_FIXNUM (0x10000)), (&q), (&r));
+    id = (UNSIGNED_FIXNUM_TO_LONG (r));
+  }
+  (date -> day) = (id & 0x1f);
+  id >>= 5;
+  (date -> month) = (id & 0x0f);
+  id >>= 4;
+  (date -> year) = id;
+  (time -> twosecs) = (it & 0x1f);
+  it >>= 5;
+  (time -> minutes) = (it & 0x3f);
+  it >>= 6;
+  (time -> hours) = it;
+}
+\f
+static SCHEME_OBJECT
+file_touch (const char * filename)
+{
+  HFILE handle;
+  ULONG action;
+  APIRET rc;
+  unsigned int count = 0;
+
+  transaction_begin ();
+  while (1)
+    {
+      APIRET rc
+       = (dos_open (((char *) filename),
+                    (&handle),
+                    (&action),
+                    0,
+                    FILE_NORMAL,
+                    (OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW),
+                    (OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE),
+                    0));
+      if (rc == NO_ERROR)
+       break;
+      if ((rc != NO_ERROR)
+         && (rc != ERROR_FILE_NOT_FOUND)
+         && (rc != ERROR_PATH_NOT_FOUND)
+         && ((++ count) >= FILE_TOUCH_OPEN_TRIES))
+       OS2_error_system_call (rc, syscall_dos_open);
+    }
+  protect_handle (handle);
+  if (action == FILE_CREATED)
+    {
+      transaction_commit ();
+      return (SHARP_T);
+    }
+  /* Existing file -- we'll write something to it to make sure that it
+     has its times updated properly upon close.  This was needed for
+     unix implementation, but it is not known whether it is needed in
+     OS/2.  In any case, it does no harm to do this.  */
+  {
+    FILESTATUS3 info;
+    char buffer [1];
+    ULONG n;
+    STD_API_CALL (dos_query_file_info,
+                 (handle, FIL_STANDARD, (& info), (sizeof (info))));
+    if ((info . cbFile) == 0)
+      {
+       /* Zero-length file: write a byte, then reset the length.  */
+       (buffer[0]) = '\0';
+       STD_API_CALL (dos_write, (handle, buffer, 1, (& n)));
+       STD_API_CALL (dos_set_file_size, (handle, 0));
+      }
+    else
+      {
+       /* Read the first byte, then write it back in place.  */
+       STD_API_CALL (dos_read, (handle, buffer, 1, (&n)));
+       STD_API_CALL (dos_set_file_ptr, (handle, 0, FILE_BEGIN, (& n)));
+       STD_API_CALL (dos_write, (handle, buffer, 1, (& n)));
+      }
+  }
+  transaction_commit ();
+  return (SHARP_F);
+}
+
+static void
+protect_handle_1 (void * hp)
+{
+  (void) dos_close (* ((LHANDLE *) hp));
+}
+
+static void
+protect_handle (LHANDLE h)
+{
+  LHANDLE * hp = (dstack_alloc (sizeof (LHANDLE)));
+  (*hp) = h;
+  transaction_record_action (tat_always, protect_handle_1, hp);
+}
+\f
+DEFINE_PRIMITIVE ("FILE-INFO", Prim_file_info, 1, 1,
+  "Given a file name, return information about the file.\n\
+If the file exists and its information is accessible,\n\
+ the result is a vector of 6 items.\n\
+Otherwise the result is #F.")
+{
+  FILESTATUS3 * info;
+  SCHEME_OBJECT result;
+  SCHEME_OBJECT modes;
+  PRIMITIVE_HEADER (1);
+
+  info = (OS2_read_file_status (STRING_ARG (1)));
+  if (info == 0)
+    PRIMITIVE_RETURN (SHARP_F);
+  result = (allocate_marked_vector (TC_VECTOR, 6, true));
+  modes = (allocate_string (5));
+  VECTOR_SET (result, 0,
+             ((((info -> attrFile) & FILE_DIRECTORY) != 0)
+              ? SHARP_T
+              : SHARP_F));
+  VECTOR_SET (result, 1,
+             (time_to_integer ((& (info -> fdateLastAccess)),
+                               (& (info -> ftimeLastAccess)))));
+  VECTOR_SET (result, 2,
+             (time_to_integer ((& (info -> fdateLastWrite)),
+                               (& (info -> ftimeLastWrite)))));
+  VECTOR_SET (result, 3,
+             (time_to_integer ((& (info -> fdateCreation)),
+                               (& (info -> ftimeCreation)))));
+  VECTOR_SET (result, 4, (long_to_integer (info -> cbFile)));
+  {
+    unsigned int attr = (info -> attrFile);
+    char * s = ((char *) (STRING_LOC (modes, 0)));
+    (s[0]) = (((attr & FILE_READONLY)  != 0) ? 'r' : '_');
+    (s[1]) = (((attr & FILE_HIDDEN)    != 0) ? 'h' : '_');
+    (s[2]) = (((attr & FILE_SYSTEM)    != 0) ? 's' : '_');
+    (s[3]) = (((attr & FILE_ARCHIVED)  != 0) ? 'a' : '_');
+    (s[4]) = (((attr & FILE_DIRECTORY) != 0) ? 'd' : '_');
+  }
+  VECTOR_SET (result, 5, modes);
+  PRIMITIVE_RETURN (result);
+}