|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T u
Length: 29220 (0x7224)
Types: TextFile
Names: »unix.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/gnu-31mar87/scheme/microcode/unix.c«
/* Hey EMACS, this is -*- C -*- code! */
/****************************************************************
* *
* Copyright (c) 1985 *
* 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. *
* *
****************************************************************/
/* File: UNIX.C
Contains operating system (Unix) dependent primitives and routines.
*/
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
\f
#define SYSTEM_NAME "unix"
/* Sun systems are bsd but have some of the files elsewhere ? */
#if defined(bsd) && !defined(sun)
#include <sys/timeb.h>
#include <sys/time.h>
#include <sgtty.h>
#ifdef vax
#define SYSTEM_VARIANT "bsd (vax)"
#endif
#ifdef celerity
#define SYSTEM_VARIANT "bsd (Celerity)"
#endif
#ifndef SYSTEM_VARIANT
#define SYSTEM_VARIANT "bsd (unknown)"
#endif
#else
#if defined(nu) || defined(sun)
#include <sys/timeb.h>
#include <time.h>
#include <sgtty.h>
#ifdef nu
#define SYSTEM_VARIANT "nu (lose)"
#else
#define SYSTEM_VARIANT "bsd (sun)"
#endif
#else /* hpux, ATT */
#include <time.h>
#include <sys/times.h>
#include <termio.h>
#ifdef system3
#include <mknod.h>
#ifdef hpux
#define SYSTEM_VARIANT "hpux (III)"
#else
#define SYSTEM_VARIANT "AT&T (III)"
#endif
#else
#include <sys/mknod.h>
#ifdef hpux
#define SYSTEM_VARIANT "hpux (V)"
#else
#define SYSTEM_VARIANT "ATT (V)"
#endif
#endif
#endif
#endif
\f
/* Fixnum multiplication */
#ifdef vax
#define Mul_handled
/* Note that "register" is used here (not "fast") since the
assembly code requires knowledge of the location of
the variables and they therefore must be in registers.
This is a kludge. It depends on what register variables
get assigned to what registers. It should be entirely
coded in assembly language. -- JINX
*/
Pointer Mul(Arg1, Arg2)
long Arg1, Arg2;
{ register long A, B, C;
Sign_Extend(Arg1, A); Sign_Extend(Arg2, B);
asm(" emul r11,r10,$0,r10"); /* A is in 11, B in 10 */
C = A;
A = B; /* What is all this shuffling? -- JINX */
B = C;
/* B should have high order result, A low order */
if ((B==0 && (A&(-1<<23)) == 0) ||
(B==-1 && (A&(-1<<23)) == (-1<<23)))
return Make_Non_Pointer(TC_FIXNUM, A);
else return NIL;
}
#endif
\f
/* 68k family code. Uses hp9000s200 conventions for the new compiler. */
#if defined(hp9000s200) && defined(new_cc)
#define Mul_handled
/* The following constants are hard coded in the assembly language
* code below. The code assumes that d0 and d1 are scratch registers
* for the compiler.
*/
#if (NIL != 0) || (TC_FIXNUM != 0x1A)
#include "Error: types changed. Change assembly language appropriately"
#endif
#ifdef MC68020
static long Fixnum_Range[2] = {SMALLEST_FIXNUM , BIGGEST_FIXNUM};
asm(" text");
asm(" global _Mul");
asm("_Mul:");
asm(" bfexts 4(%sp){&8:&24},%d0");
asm(" bfexts 8(%sp){&8:&24},%d1");
asm(" muls.l %d1,%d0");
asm(" bvs.b result_is_nil");
asm(" cmp2.l %d0,_Fixnum_Range");
asm(" bcs.b result_is_nil");
asm(" moveq &0x1A,%d1");
asm(" bfins %d1,%d0{&0:&8}");
asm(" rts");
asm("result_is_nil:");
asm(" clr.l %d0");
asm(" rts");
#else /* not MC68020, but 68k family */
\f
/* 20(sp) = arg0; 24(sp) = arg1 because of movem */
asm(" text");
asm(" global _Mul");
asm("_Mul:");
asm(" movem.l %d2-%d5,-(%sp)");
asm(" clr.b %d5");
asm(" tst.b 21(%sp)");
asm(" slt 20(%sp)");
asm(" bge.b coerce_1");
asm(" moveq &1,%d5");
asm(" neg.l 20(%sp)");
asm("coerce_1:");
asm(" tst.b 25(%sp)");
asm(" slt 24(%sp)");
asm(" bge.b after_coerce");
asm(" eori.b &1,%d5");
asm(" neg.l 24(%sp)");
asm("after_coerce:");
asm(" move.l 20(%sp),%d0");
asm(" move.l 24(%sp),%d1");
asm(" move.w %d0,%d2");
asm(" mulu %d1,%d2");
asm(" move.w %d1,%d4");
asm(" swap %d1");
asm(" move.w %d1,%d3");
asm(" mulu %d0,%d3");
asm(" swap %d0");
asm(" mulu %d0,%d4");
asm(" add.l %d4,%d3");
asm(" bcs.b result_is_nil");
asm(" mulu %d0,%d1");
asm(" bne.b result_is_nil");
asm(" swap %d2");
asm(" add.w %d3,%d2");
asm(" bcs.b result_is_nil");
asm(" swap %d3");
asm(" tst.w %d3");
asm(" bne.b result_is_nil");
asm(" cmpi.w %d2,&0x7F");
asm(" bgt.b result_is_nil");
asm(" swap %d2");
asm(" tst.b %d5");
asm(" beq.b sign_is_right");
asm(" neg.l %d2");
asm("sign_is_right:");
asm(" move.l %d2,-(%sp)");
asm(" move.b &0x1A,(%sp)");
asm(" move.l (%sp)+,%d0");
asm(" movem.l (%sp)+,%d2-%d5");
asm(" rts");
asm("result_is_nil:");
asm(" clr.l %d0");
asm(" movem.l (%sp)+,%d2-%d5");
asm(" rts");
\f
#endif /* not MC68020 */
#endif /* hp9000s200 */
#ifndef Mul_handled
/* Portable case */
#include "mul.c"
#endif
/* OpSys dependent I/O operations. */
#define dump_output_buffer() fflush(stdout)
#define flush_input_buffer() ioctl(fileno(stdin), TIOCFLUSH, NULL);
void OS_Flush_Output_Buffer()
{ dump_output_buffer();
}
static Boolean stdin_is_a_kbd, stdout_is_a_crt, Under_Emacs;
forward char TYI_Immediate(), TYI_Buffered();
forward void OS_Re_Init();
char OS_tty_tyi(Immediate, Interrupted)
Boolean Immediate, *Interrupted;
{ char C;
if (stdin_is_a_kbd)
C = (Immediate ?
TYI_Immediate(Interrupted) :
TYI_Buffered(Interrupted));
else if (!Under_Emacs)
{ *Interrupted = false;
if ((C = getchar()) == EOF)
Microcode_Termination(TERM_EOF);
}
else if (Immediate)
{ char Spurious;
C = TYI_Buffered(Interrupted);
/* Read Spurious New Line */
if (!(*Interrupted))
{ Spurious = TYI_Buffered(Interrupted);
if ((Spurious != '\n') && (!(*Interrupted)))
ungetc(Spurious, stdin);
/* We got a real character before. */
*Interrupted = false;
}
}
else C = TYI_Buffered(Interrupted);
return C;
}
#ifdef bsd
#define make_a_directory(path) mkdir((path), 511)
#else
#define make_a_directory(path) mknod((path), 0040666, ((dev_t) 0))
#endif
Built_In_Primitive(Prim_Make_Directory, 1, "MAKE-DIRECTORY")
{ int Mask;
Primitive_1_Arg();
Arg_1_Type(TC_CHARACTER_STRING);
Mask = umask(0);
if (make_a_directory(Scheme_String_To_C_String(Arg1)) != 0)
{ umask(Mask);
Primitive_Error(ERR_ARG_1_BAD_RANGE);
}
umask(Mask);
return NIL;
}
\f
#if defined(system3)
getcwd(buffer, length)
char *buffer;
long length;
{ FILE *the_pipe = popen("pwd", "r");
char *finder = buffer;
if (the_pipe == NULL)
{ fprintf(stderr, "popen failed.\n");
_exit(1);
}
fgets(buffer, length, the_pipe);
/* Remove extraneous newline */
while((*finder != '\0') && (*finder != '\n')) finder++;
if (*finder == '\n') *finder = '\0';
pclose(the_pipe);
return;
}
#endif
Built_In_Primitive(Prim_Prefix_Volume, 1, "PREFIX-VOLUME")
{ char Old_Path[FILE_NAME_LENGTH];
Primitive_1_Arg();
Arg_1_Type(TC_CHARACTER_STRING);
getcwd(Old_Path, FILE_NAME_LENGTH);
if (chdir(Scheme_String_To_C_String(Arg1)) != 0)
Primitive_Error(ERR_ARG_1_BAD_RANGE);
return C_String_To_Scheme_String(Old_Path);
}
Built_In_Primitive(Prim_Remove_File, 1, "REMOVE-FILE")
{ Primitive_1_Arg();
Arg_1_Type(TC_CHARACTER_STRING);
if (unlink(Scheme_String_To_C_String(Arg1)) != 0)
Primitive_Error(ERR_ARG_1_BAD_RANGE);
return NIL;
}
Built_In_Primitive(Prim_Delete_File, 1, "DELETE-FILE")
{ return Prim_Remove_File();
}
\f
/* File operations continued */
/* Prim_Link_File takes a third argument which specifies whether the
* link is to be physical (#!TRUE) or symbolic (#!FALSE). Of course,
* this is only meaningful if both kinds exist.
* Note that symbolic links are made regardless of the existence of the
* source file.
* It returns #!TRUE if it managed to link in the specified way, #!FALSE
* if it had to link in a different way (symbolic was specified but not
* available).
*/
Built_In_Primitive(Prim_Link_File, 3, "LINK-FILE")
{ char *Real_File, *Symbolic_File;
long Result;
Pointer Answer;
Primitive_3_Args();
Arg_1_Type(TC_CHARACTER_STRING);
Arg_2_Type(TC_CHARACTER_STRING);
Real_File = Scheme_String_To_C_String(Arg1);
Symbolic_File = Scheme_String_To_C_String(Arg2);
#ifdef bsd
Result = ((Arg3 == TRUTH) ?
link(Real_File, Symbolic_File) :
symlink(Real_File, Symbolic_File));
Answer = TRUTH;
#else
Result = link(Real_File, Symbolic_File);
Answer = ((Arg3 == TRUTH) ? TRUTH : NIL);
#endif
if (Result != 0) Primitive_Error(ERR_EXTERNAL_RETURN);
return Answer;
}
/* Somewhat kludged. Simply reduces to a hard-link then
a delete file. It should be fixed for cross-structure rename.
*/
Built_In_Primitive(Prim_Rename_File, 2, "RENAME-FILE")
{ char *Source_File, *Destination_File;
Primitive_2_Args();
Arg_1_Type(TC_CHARACTER_STRING);
Arg_2_Type(TC_CHARACTER_STRING);
Source_File = Scheme_String_To_C_String(Arg1);
Destination_File = Scheme_String_To_C_String(Arg2);
if (link(Source_File, Destination_File) != 0)
Primitive_Error(ERR_EXTERNAL_RETURN);
unlink(Source_File);
return TRUTH;
}
\f
/* Terminal hacking. */
extern char *getenv(), *tgetstr(), *tgoto();
char *CM, *BC, *UP, *CL, *CE, *term;
int LI, CO;
outc(C)
char C;
{ putchar(C);
}
void OS_Clear_Screen()
{ if (Can_Do_Cursor) tputs(CL, LI, outc);
else putchar('\f');
dump_output_buffer();
}
long NColumns()
{ return (Can_Do_Cursor? CO : 79);
}
long NLines()
{ return (Can_Do_Cursor? LI : 24);
}
Built_In_Primitive(Prim_Clear_To_End_Of_Line, 0, "CLEAR-TO-END-OF-LINE")
{ if (Can_Do_Cursor) tputs(CE, 1, outc);
return NIL;
}
Built_In_Primitive(Prim_Move_Cursor, 2, "MOVE-CURSOR")
{ Primitive_2_Args();
Arg_1_Type(TC_FIXNUM);
Arg_2_Type(TC_FIXNUM);
if (Can_Do_Cursor)
tputs(tgoto(CM, Get_Integer(Arg1), Get_Integer(Arg2)), 1, outc);
return NIL;
}
\f
/* Time and dates. */
#if defined(bsd) || defined(nu)
long Start_Time, Start_Milli_Time;
long System_Clock()
{ struct timeb TimeBlock;
long DeltaT, DeltaMilliT, NowT, NowMilliT;
ftime(&TimeBlock);
NowT = TimeBlock.time;
NowMilliT = TimeBlock.millitm;
DeltaT = NowT - Start_Time;
DeltaMilliT = NowMilliT - Start_Milli_Time;
return (DeltaT*100) + (DeltaMilliT/10);
}
void Init_System_Clock()
{ struct timeb Time;
ftime(&Time);
Start_Time = Time.time;
Start_Milli_Time = Time.millitm;
return;
}
#else
#if defined(hpux) || defined(ATT)
long Start_Time;
long System_Clock()
{ struct tms buff;
long Temp;
times(&buff);
Temp = (buff.tms_utime+buff.tms_stime);
Temp -= Start_Time;
return (100*Temp)/60;
}
void Init_System_Clock()
{ struct tms buff;
times(&buff);
Start_Time = buff.tms_utime + buff.tms_stime;
return;
}
#else
/* Should be fixed some day. */
long System_Clock()
{ fprintf(stderr, "\nUnimplemented utility: System Clock.");
return 0;
}
void Init_System_Clock()
{ return;
}
#endif
#endif
\f
#if defined(bsd) || defined(hpux) || defined(nu)
extern struct tm *(localtime());
#define Date_Part(C_Name, S_Name, Which)\
Built_In_Primitive(C_Name, 0, S_Name) \
{ struct tm *Time; \
long Ans, The_Time; \
\
time(&The_Time); \
Time = localtime(&The_Time); \
return FIXNUM_0 + (Time->Which); \
}
Date_Part(Prim_Current_Year, "YEAR", tm_year);
Date_Part(Prim_Current_Month, "MONTH", tm_mon + 1);
Date_Part(Prim_Current_Day, "DAY", tm_mday);
Date_Part(Prim_Current_Hour, "HOUR", tm_hour);
Date_Part(Prim_Current_Minute, "MINUTE", tm_min);
Date_Part(Prim_Current_Second, "SECOND", tm_sec);
#else
NIY(Prim_Current_Year, 0, "YEAR")
NIY(Prim_Current_Month, 0, "MONTH")
NIY(Prim_Current_Day, 0, "DAY")
NIY(Prim_Current_Hour, 0, "HOUR")
NIY(Prim_Current_Minute, 0, "MINUTE")
NIY(Prim_Current_Second, 0, "SECOND")
#endif
\f
/* actual keyboard I/O */
#if defined(CBREAK) /* bsd */
#define Immediate_Declarations() \
struct sgttyb TTY_Block
#define Immediate_Prolog() \
flush_input_buffer(); \
gtty(fileno(stdin), &TTY_Block); \
TTY_Block.sg_flags |= CBREAK; \
stty(fileno(stdin), &TTY_Block)
#define Immediate_Epilog() \
TTY_Block.sg_flags &= ~CBREAK; \
stty(fileno(stdin), &TTY_Block)
#else
#if defined(TCFLSH) /* hpux, ATT */
#define TIOCFLUSH TCFLSH
#ifndef VINTR
#define VINTR 0
#define VQUIT 1
#define VEOF 4
#define VMIN 4
#define VTIME 5
#endif
#define Immediate_Declarations() \
struct termio The_Chars; \
char Old_VMIN, Old_VTIME; \
unsigned short lflag
#define Immediate_Prolog() \
flush_input_buffer(); \
ioctl(fileno(stdin), TCGETA, &The_Chars); \
lflag = The_Chars.c_lflag; \
The_Chars.c_lflag &= ~ICANON; \
Old_VMIN = The_Chars.c_cc[VMIN]; \
Old_VTIME = The_Chars.c_cc[VTIME]; \
The_Chars.c_cc[VMIN] = (char) 1; /* Min # of chars. */ \
The_Chars.c_cc[VTIME] = (char) 1; /* Time-out */ \
ioctl(fileno(stdin), TCSETA, &The_Chars)
#define Immediate_Epilog() \
The_Chars.c_cc[VMIN] = Old_VMIN; \
The_Chars.c_cc[VTIME] = Old_VTIME; \
The_Chars.c_lflag = lflag; \
ioctl(fileno(stdin), TCSETA, &The_Chars)
#else /* ??? */
/* No immediate IO */
#define Immediate_Declarations()
#define Immediate_Prolog()
#define Immediate_Epilog()
#endif
#endif
/* These are pretty trivial */
#define Buffered_Declarations()
#define Buffered_Prolog()
#define Buffered_Epilog()
\f
/* Keyboard Interrupts */
#define CONTROL_A 'A'
#define CONTROL_B 'B'
#define CONTROL_G 'G'
#define CONTROL_U 'U'
#define CONTROL_X 'X'
#define CONTROL_BIT 0100
#define C_A (CONTROL_A - CONTROL_BIT)
#define C_G (CONTROL_G - CONTROL_BIT)
#define DISABLE_EOF -1
char Int_Char;
int Scheme_Process_Id;
Built_In_Primitive(Prim_Chk_And_Cln_Input_Channel, 2,
"CHECK-AND-CLEAN-UP-INPUT-CHANNEL")
{ return TRUTH;
}
Built_In_Primitive(Prim_Get_Next_Interrupt_Char, 0,
"GET-NEXT-INTERRUPT-CHARACTER")
{ Pointer Result = FIXNUM_0 + Int_Char;
Int_Char = 0;
IntCode &= ~INT_Character;
return Result;
}
\f
/* Keyboard Interrupts and I/O synchronization */
#define FIRST_TIME 0
#define INTERRUPT 1
#define REDO 2
#define Interrupt_available (((IntCode & IntEnb) & INT_Character) != 0)
typedef struct { Boolean in_input_wait; jmp_buf storage; } reader_context;
static reader_context real_read_env, *saved_read_env;
#define Keyboard_Input_Procedure(Name, decl, prolog, epilog) \
char Name(Interrupted) \
Boolean *Interrupted; \
{ int Which_Way; \
char C; \
decl; \
Which_Way = setjmp(saved_read_env->storage); \
while(true) \
{ switch (Which_Way) \
{ case FIRST_TIME: \
prolog; \
case REDO: \
saved_read_env->in_input_wait = true; \
if (Interrupt_available) \
{ saved_read_env->in_input_wait = false; \
epilog; \
longjmp(saved_read_env->storage, INTERRUPT); \
} \
C = getchar(); \
saved_read_env->in_input_wait = false; \
epilog; \
if (C == EOF) Microcode_Termination(TERM_EOF); \
if (Photo_Open) putc(C, Photo_File_Handle); \
*Interrupted = false; \
return C; \
case INTERRUPT: \
epilog; \
*Interrupted = true; \
return EOF; \
default: continue; \
} \
} \
}
Keyboard_Input_Procedure(TYI_Immediate,
Immediate_Declarations(),
Immediate_Prolog(),
Immediate_Epilog())
Keyboard_Input_Procedure(TYI_Buffered,
Buffered_Declarations(),
Buffered_Prolog(),
Buffered_Epilog())
\f
/* Interrupt Handlers */
#define save_read_context(extra) \
reader_context next_buffer, *old_env; \
extra; \
next_buffer.in_input_wait = false; \
old_env = saved_read_env; \
saved_read_env = &next_buffer
#define restore_read_context(extra, action) \
if (old_env->in_input_wait) \
{ old_env->in_input_wait = false; \
saved_read_env = old_env; \
extra; \
longjmp(saved_read_env->storage, action); \
} \
extra; \
saved_read_env = old_env; \
return
#define disable_interrupt(signal_name) \
signal(signal_name, SIG_IGN)
#define enable_interrupt(signal_name, routine) \
signal(signal_name, routine)
#define interrupt_start(signal_name) \
save_read_context(disable_interrupt(signal_name))
#define interrupt_end(signal_name, routine, action) \
restore_read_context(enable_interrupt(signal_name, routine), action)
\f
static int (*old_Real_Timer_handler)();
static int (*old_Virtual_Timer_handler)();
static int (*old_INT_handler)();
static int (*old_QUIT_handler)();
static int (*old_TERM_handler)();
#ifdef SIGTSTP
/* Assumes there is sigsetmask */
static int (*old_TSTP_handler)();
#define NO_SIGNALS_ALLOWED -1
#define TSTP_MASK ~(1 << (SIGTSTP - 1))
#define BOGUS_SIGNAL 0
/* sig should only be SIGTSTP or BOGUS_SIGNAL in the following */
Suspend_Me(sig)
int sig;
{ int saved_mask = sigsetmask(NO_SIGNALS_ALLOWED);
interrupt_start(SIGTSTP);
OS_Quit();
sigsetmask(saved_mask & TSTP_MASK);
kill(Scheme_Process_Id, SIGTSTP);
sigsetmask(NO_SIGNALS_ALLOWED);
OS_Re_Init();
sigsetmask(saved_mask);
interrupt_end(SIGTSTP, Suspend_Me, REDO);
}
void Restartable_Exit()
{ Suspend_Me(BOGUS_SIGNAL);
return;
}
#else
void Restartable_Exit()
{ fprintf(stderr, "\nUnimplemented utility: Restartable_Exit.");
return;
}
#endif
\f
/* Interrupt handlers (continued) */
Control_G(sig)
int sig;
{ interrupt_start(sig);
putchar('\007');
dump_output_buffer();
IntCode |= INT_Character;
Int_Char = CONTROL_G;
New_Compiler_MemTop();
interrupt_end(sig, Control_G, INTERRUPT);
}
/* Kill Scheme after undoing terminal garbage */
Kill_Me(sig)
int sig;
{ OS_Quit();
exit(1);
}
#if defined(COMPILE_FUTURES) && defined(ITIMER_VIRTUAL)
Timer_Interrupt(sig)
int sig;
{ interrupt_start(sig);
IntCode |= INT_Timer;
New_Compiler_MemTop();
interrupt_end(sig, Timer_Interrupt, INTERRUPT);
}
#endif
\f
/* Procedure needed in Ask_Me */
#define C_STRING_LENGTH 256
Examine_Memory()
{ Pointer *Where;
char input_string[10];
int free;
Boolean interrupted;
printf("Enter location to examine (0x prefix for hex) : ");
dump_output_buffer();
/* Considerably haired up to go through standard (safe) interface.
Taken from debug.c */
if (interrupted) return;
for (free = 0; free < C_STRING_LENGTH; free++)
{ input_string[free] = OS_tty_tyi(false, &interrupted);
if (interrupted) return;
if (input_string[free] == '\n')
{ input_string[free] = '\0';
break;
}
}
/* Check to see if address is in Hex (0x prefix). */
if ((input_string[0] == '0') && (input_string[1] == 'x'))
sscanf(input_string + 2, "%x", &Where);
else
sscanf(input_string, "%d", &Where);
Print_Expression(*Where, "Contents");
CRLF();
}
\f
/* Interactive interrupt handler. */
Ask_Me(sig)
int sig;
{ char command;
Boolean Interrupted;
interrupt_start(sig);
putchar('\007');
putchar('\n');
Loop:
printf("Interrupt character (? for help): ");
dump_output_buffer();
command = OS_tty_tyi(true, &Interrupted);
if (Interrupted) goto exit_gracefully;
switch (command)
{ case 'B':
case 'b': Int_Char = CONTROL_B; break;
case 'E':
case 'e': putchar('\n');
Examine_Memory();
goto exit_gracefully;
case 'D':
case 'd': putchar('\n');
Handle_Debug_Flags();
goto exit_gracefully;
case 'T':
case 't': putchar('\n');
Back_Trace();
goto exit_gracefully;
case 'G':
case 'g': Int_Char = CONTROL_G; break;
case 'P':
case 'p':
case 'U':
case 'u': Int_Char = CONTROL_U; break;
case 'F':
case 'f':
case 'X':
case 'x': Int_Char = CONTROL_X; break;
case 'Z':
case 'z': putchar('\n');
Restartable_Exit();
goto exit_gracefully;
\f
case 'Q':
case 'q': putchar('\n'); Microcode_Termination(TERM_HALT);
case '\f': OS_Clear_Screen(); goto exit_gracefully;
case 'H':
case 'h':
putchar('\n');
printf(
"The interrupt character is ^G (cntrl-G). Unless redefined, when\n");
printf(
"typed, the running (Scheme) program will be aborted and the top level\n");
printf("read-eval-print loop will resume control.\n");
printf(
"The quit character is ^A. When typed, it offers various options.\n");
printf("Type ^A? for a list of the options.\n");
goto exit_gracefully;
case 'I':
case 'i': if (!stdin_is_a_kbd || Under_Emacs) putchar('I');
printf("gnored.\n");
exit_gracefully:
interrupt_end(sig, Ask_Me,
(Interrupted ? INTERRUPT : REDO));
default: putchar('\n');
printf("B: Enter a breakpoint loop.\n");
printf("D: Debugging: change interpreter flags.\n");
printf("E: Examine memory location.\n");
printf("F or X: Abort to current REP loop.\n");
printf("G: Goto to top level read-eval-print (REP) loop.\n");
printf("H: Print simple information on interrupts.\n");
printf("I: Ignore interrupt request.\n");
printf("P or U: Up to previous (lower numbered) REP loop.\n");
printf("Q: Quit instantly, killing Scheme.\n");
printf("T: Stack trace.\n");
printf("Z: Quit instantly, suspending Scheme.\n");
printf("^L: Clear the screen.\n");
goto Loop;
}
IntCode |= INT_Character;
New_Compiler_MemTop();
interrupt_end(sig, Ask_Me, INTERRUPT);
}
\f
#define TERMCAP_BUFFER_SIZE 1024
#ifndef bsd
#define Break_Terminal_Connection() setpgrp()
#else
#define Break_Terminal_Connection()
#endif
OS_Init()
{ char termcaps[TERMCAP_BUFFER_SIZE];
static char tcb[TERMCAP_BUFFER_SIZE];
char *tcp = &tcb[0];
OS_Name = SYSTEM_NAME;
OS_Variant = SYSTEM_VARIANT;
Init_System_Clock();
real_read_env.in_input_wait = false;
saved_read_env = &real_read_env;
/* Find process information */
Under_Emacs =
Parse_Option("-emacs", Saved_argc, Saved_argv, true) != NOT_THERE;
Scheme_Process_Id = getpid();
\f
stdin_is_a_kbd = isatty(fileno(stdin));
/* The ultimate in C style -- by Jinx */
if ((!(stdout_is_a_crt = isatty(fileno(stdout)))) ||
((term = getenv("TERM")) == NULL) ||
(tgetent(termcaps, term) <= 0) ||
((CM = tgetstr("cm", &tcp)) == NULL))
Can_Do_Cursor = false;
else /* Find terminal information */
{ LI = tgetnum("li");
CO = tgetnum("co");
UP = tgetstr("up", &tcp);
CL = tgetstr("cl", &tcp);
CE = tgetstr("ce", &tcp);
BC = tgetflag("bs") ? "\b" : tgetstr("bc", &tcp);
Can_Do_Cursor = true;
}
Int_Char = 0;
printf("MIT Scheme, UNIX version\n");
if (stdout_is_a_crt && stdin_is_a_kbd)
printf("^AH (CTRL-A, then H) shows help on interrupt keys.\n");
if (!stdin_is_a_kbd && !stdout_is_a_crt && !Under_Emacs)
Break_Terminal_Connection();
dump_output_buffer();
/* Swap in Scheme IO */
OS_Re_Init();
}
\f
static char Orig_Interrupt, Orig_Quit, Orig_EOF;
#if defined(bsd) || defined(nu)
static long Orig_flags;
#define hack_crt(old, new) \
{ int crt_pgrp; \
ioctl(fileno(stdout), TIOCGPGRP, &crt_pgrp); \
if (getpgrp(Scheme_Process_Id) == crt_pgrp) \
{ struct sgttyb sg; \
gtty(fileno(stdout), &sg); \
Orig_flags = old; \
sg.sg_flags = new; \
ioctl(fileno(stdout), TIOCSETN, &sg); \
} \
}
#define hack_kbd(Ni, Oi, Nq, Oq, Ne, Oe) \
{ int crt_pgrp; \
ioctl(fileno(stdin), TIOCGPGRP, &crt_pgrp); \
if (getpgrp(Scheme_Process_Id) == crt_pgrp) \
basic_hack_kbd(Ni, Oi, Nq, Oq, Ne, Oe); \
}
#else
#if defined(TCSETA) /* hpux, ATT */
/* Make hpux/system V look like bsd so hack_kbd works */
#define tchars termio
#define TIOCGETC TCGETA
#define TIOCSETC TCSETA
#define t_intrc c_cc[VINTR]
#define t_quitc c_cc[VQUIT]
#define t_eofc c_cc[VEOF]
#define hack_crt(old, new)
#define hack_kbd(Ni, Oi, Nq, Oq, Ne, Oe) \
basic_hack_kbd(Ni, Oi, Nq, Oq, Ne, Oe)
#else /* ??? */
#define hack_crt(old, new)
#define hack_kbd(Ni, Oi, Nq, Oq, Ne, Oe)
#endif
#endif
/* This swaps interrupt characters */
#define basic_hack_kbd(Nintr, Ointr, Nquit, Oquit, NEOF, OEOF) \
{ struct tchars Terminal_Chars; \
ioctl(fileno(stdin), TIOCGETC, &Terminal_Chars); \
Orig_Interrupt = Ointr; \
Orig_Quit = Oquit; \
Orig_EOF = OEOF; \
Terminal_Chars.t_intrc = Nintr; \
Terminal_Chars.t_quitc = Nquit; \
Terminal_Chars.t_eofc = NEOF; \
ioctl(fileno(stdin), TIOCSETC, &Terminal_Chars); \
}
\f
void OS_Re_Init()
{ if (stdin_is_a_kbd)
hack_kbd(C_G, Terminal_Chars.t_intrc,
C_A, Terminal_Chars.t_quitc,
DISABLE_EOF, Terminal_Chars.t_eofc);
if (stdin_is_a_kbd || Under_Emacs)
{ old_QUIT_handler = signal(SIGQUIT, Ask_Me);
#ifdef SIGTSTP
old_TSTP_handler = signal(SIGTSTP, Suspend_Me);
#endif
}
#if defined(COMPILE_FUTURES) && defined(ITIMER_VIRTUAL)
old_Virtual_Timer_handler = signal(SIGVTALRM, Timer_Interrupt);
old_Real_Timer_handler = signal(SIGALRM, Timer_Interrupt);
#endif
old_INT_handler = signal(SIGINT, Control_G);
old_TERM_handler = signal(SIGTERM, Kill_Me);
if (stdout_is_a_crt)
hack_crt(sg.sg_flags, (sg.sg_flags & (~XTABS)));
}
\f
OS_Quit()
{ dump_output_buffer();
if (stdout_is_a_crt)
hack_crt(Orig_flags, Orig_flags);
signal(SIGTERM, old_TERM_handler);
signal(SIGINT, old_INT_handler);
#if defined(COMPILE_FUTURES) && defined(ITIMER_VIRTUAL)
signal(SIGVTALRM, old_Virtual_Timer_handler);
signal(SIGALRM, old_Real_Timer_handler);
#endif
if (stdin_is_a_kbd || Under_Emacs)
{ signal(SIGQUIT, old_QUIT_handler);
#ifdef SIGTSTP
signal(SIGTSTP, old_TSTP_handler);
#endif
}
if (stdin_is_a_kbd)
hack_kbd(Orig_Interrupt, Orig_Interrupt,
Orig_Quit, Orig_Quit,
Orig_EOF, Orig_EOF);
}
\f
/* Fasload and Fasdump use the following routines */
void Load_Data(Count, To_Where)
long Count;
char *To_Where;
{ fread(To_Where, sizeof(Pointer), Count, File_Handle);
return;
}
Boolean Open_Dump_File(Name, flag)
char *Name, *flag;
{ return Open_File(Name, flag, &File_Handle);
}
void Write_Data(Count, From_Where)
long Count;
char *From_Where;
{ fwrite(From_Where, sizeof(Pointer), Count, File_Handle);
return;
}
\f
#if defined(COMPILE_FUTURES) && defined(ITIMER_VIRTUAL)
void Clear_Timer()
{ struct itimerval New_Value, Old_Value;
New_Value.it_value.tv_sec = 0;
New_Value.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &New_Value, &Old_Value);
setitimer(ITIMER_VIRTUAL, &New_Value, &Old_Value);
return;
}
void Set_Timer(Days, Centi_Seconds)
long Days, Centi_Seconds;
{ struct itimerval New_Value, Old_Value;
long Which_Timer = ITIMER_VIRTUAL;
Clear_Timer();
if (Centi_Seconds < 0)
{ Centi_Seconds = -Centi_Seconds;
Which_Timer = ITIMER_REAL;
}
New_Value.it_value.tv_sec =
(Days*24*60*60*60) + (Centi_Seconds/100);
New_Value.it_value.tv_usec = (Centi_Seconds % 100) *10000;
New_Value.it_interval.tv_sec = 0; /* Turn off after it rings */
New_Value.it_interval.tv_usec = 0;
setitimer(Which_Timer, &New_Value, &Old_Value);
return;
}
#else
void Clear_Timer()
{ fprintf(stderr, "\nCan't clear a timer under this OS.");
return;
}
void Set_Timer()
{ fprintf(stderr, "\nCan't set a timer under this OS.");
return;
}
#endif