|
|
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 v
Length: 15278 (0x3bae)
Types: TextFile
Names: »vms.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/gnu-31mar87/scheme/microcode/vms.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. *
* *
****************************************************************/
\f
/* File: VMS.C
Contains operating system (VMS) dependent primitives and routines.
*/
#include <types.h>
#include <timeb.h>
#include <signal.h>
#include <time.h>
#include <descrip.h>
#include "vmsio.h"
#include ssdef
#include jpidef
/* Forward references */
forward int Sift_Out_Interrupt();
forward Suspend_Me(), OS_Quit(), OS_Re_Init();
/* The following is hackery for checking multiply overflow */
#if false
/* Macro_EMUL is currently broken, it should be fixed.
* The extra procedure call should be eliminated also.
*/
Mul(A, B)
fast long A, B;
{ fast long C;
return Macro_EMUL(A,B);
}
#else
#include "mul.c"
#endif
\f
/* Operating system dependent IO operations */
#define dump_output_buffer() fflush(stdout)
NIY(Prim_Remove_File, 1, "REMOVE-FILE")
NIY(Prim_Delete_File, 1, "DELETE-FILE")
NIY(Prim_Link_File, 3, "LINK-FILE")
NIY(Prim_Rename_File, 3, "RENAME-FILE")
NIY(Prim_Make_Directory, 1, "MAKE-DIRECTORY")
NIY(Prim_Prefix_Volume, 1, "PREFIX-VOLUME")
NIY(Prim_Move_Cursor, 2, "MOVE-CURSOR")
NIY(Prim_Clear_To_End_Of_Line, 0, "CLEAR-TO-END-OF-LINE")
void OS_Flush_Output_Buffer()
{ dump_output_buffer();
}
void OS_Clear_Screen()
{ putchar('\f');
}
/* These are faked since I have no idea how to do them right. */
long NColumns()
{ return 79;
}
long NLines()
{ return 24;
}
void Restartable_Exit()
{ Suspend_Me(false);
return;
}
\f
/* Time and dates. */
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;
}
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_Day, "DAY", tm_mday);
Date_Part(Prim_Current_Hour, "HOUR", tm_hour);
Date_Part(Prim_Current_Minute, "MINUTE", tm_min);
Date_Part(Prim_Current_Month, "MONTH", tm_mon + 1);
Date_Part(Prim_Current_Second, "SECOND", tm_sec);
Date_Part(Prim_Current_Year, "YEAR", tm_year);
\f
/* Scheme keyboard interrupts */
#define CONTROL_A 'A'
#define CONTROL_B 'B'
#define CONTROL_F 'F'
#define CONTROL_G 'G'
#define CONTROL_M 'M'
#define CONTROL_P 'P'
#define CONTROL_U 'U'
#define CONTROL_X 'X'
#define CONTROL_Z 'Z'
#define CONTROL_BIT 0100 /* Octal, control bit in ASCII */
#define C_A (CONTROL_A - CONTROL_BIT)
#define C_B (CONTROL_B - CONTROL_BIT)
#define C_F (CONTROL_F - CONTROL_BIT)
#define C_G (CONTROL_G - CONTROL_BIT)
#define C_M (CONTROL_M - CONTROL_BIT)
#define C_P (CONTROL_P - CONTROL_BIT)
#define C_X (CONTROL_X - CONTROL_BIT)
#define C_Z (CONTROL_Z - CONTROL_BIT)
#define Control_A_Bit (1 << C_A)
#define Control_B_Bit (1 << C_B)
#define Control_F_Bit (1 << C_F)
#define Control_G_Bit (1 << C_G)
#define Control_P_Bit (1 << C_P)
#define Control_X_Bit (1 << C_X)
#define Control_Z_Bit (1 << C_Z)
#define CR_Bit (1 << C_M)
#define MASK_SIZE 32 /* In bits */
#define Scheme_Interrupt_Mask (Control_G_Bit | Control_P_Bit | \
Control_F_Bit | Control_B_Bit | \
Control_A_Bit | Control_Z_Bit )
#define Normal_Terminator_Mask CR_Bit
#define INTERRUPT 1
#define REDO 2
\f
/* Interrupts & IO synchronization */
static long TT_Channel;
struct Block { short Status;
short Count;
long Ptr;
};
static struct Block
Scheme_Interrupt_Descriptor = {0, 0, Scheme_Interrupt_Mask};
static struct Block
Scheme_Read_Terminator =
{0, 0, (Scheme_Interrupt_Mask | Normal_Terminator_Mask)};
#define Is_Terminator(c) \
((c >= MASK_SIZE) ? \
false : (((1 << c) & Normal_Terminator_Mask) != 0))
Set_Interrupt_Mask(Mask, AST)
struct Block *Mask;
long *AST;
{ long Return_Status;
struct Block IO_Status_Block = {0, 0, 0};
Return_Status = SYS$QIO(0, TT_Channel, IO$_SETMODE|IO$M_OUTBAND,
&IO_Status_Block, 0, 0,
AST, Mask, 0xFFFFFFFF,
0, 0, 0);
if (Return_Status != SS$_NORMAL)
printf("\nStatus = %x Unable to Setmode", Return_Status);
return;
}
#define Setup_Scheme_Interrupts() \
Set_Interrupt_Mask(&Scheme_Interrupt_Descriptor, \
((long *) Sift_Out_Interrupt))
#define Clear_Scheme_Interrupts() \
Set_Interrupt_Mask(((struct Block *) 0), ((long *) 0))
#define interrupt_start(signal_name, routine, restore_handler)
#define interrupt_end(action) return action
\f
/* Keyboard input low level */
#define INPUT_BUF_SIZE 512 /* Over 6 full lines of text */
#define NO_INTERRUPTS -1 /* Not a valid character */
static char Input_Buffer[INPUT_BUF_SIZE];
static char *Input_Pointer;
static char *Input_End;
#define Initialize_Input() \
Input_Pointer = Input_End = &Input_Buffer[0]
int fill_input_buffer(size, keep_type_ahead)
int size;
Boolean keep_type_ahead;
{ struct Block IO_Status_Block = {0, 0, 0};
long Return_Status;
int terminator;
Clear_Scheme_Interrupts();
do
{ Return_Status =
SYS$QIOW(0,TT_Channel,
(IO$_READVBLK | (keep_type_ahead ? 0 : IO$M_PURGE)),
&IO_Status_Block,0,0,
&Input_Buffer[0],size,0,
&Scheme_Read_Terminator,0,0);
} while (Return_Status != SS$_NORMAL);
Setup_Scheme_Interrupts();
Input_Pointer = &Input_Buffer[0];
Input_End = &Input_Buffer[IO_Status_Block.Count];
/* Interrupt? */
terminator = (IO_Status_Block.Ptr & 0377);
if (terminator == 0) return NO_INTERRUPTS;
if (Is_Terminator(terminator))
{ *Input_End++ = ((terminator == C_M) ? '\n' : terminator);
return NO_INTERRUPTS;
}
return terminator;
}
\f
/* Keyboard input */
extern char OS_tty_tyi();
char OS_tty_tyi(Immediate, Interrupted)
Boolean Immediate, *Interrupted;
{ *Interrupted = false;
while (Input_Pointer >= Input_End) /* Should be == ... */
{ int result = fill_input_buffer((Immediate ? 1 : INPUT_BUF_SIZE), true);
if ((result != NO_INTERRUPTS) &&
(Sift_Out_Interrupt(result) == INTERRUPT))
{ *Interrupted = true;
return EOF;
}
}
return (*Input_Pointer++ & 0377);
}
/* Flushes type ahead and ignores other interrupts */
char Interrupt_Getchar()
{ int result;
do
{ Initialize_Input();
result = fill_input_buffer(1, false);
} while (result != NO_INTERRUPTS);
return *Input_Pointer++;
}
Built_In_Primitive(Prim_Chk_And_Cln_Input_Channel, 2,
"CHECK-AND-CLEAN-UP-INPUT-CHANNEL")
{ Initialize_Input();
return TRUTH;
}
char Int_Char;
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
/* Interrupt handlers */
long Ask_Me()
{ char command;
putchar('\007');
putchar('\n');
Loop:
printf("Interrupt character (? for help): ");
command = Interrupt_Getchar();
switch (command)
{ case 'B':
case 'b': Int_Char = CONTROL_B; break;
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;
\f
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 'H':
case 'h': printf("\nThe following control characters are available at\n");
printf("any time in Scheme:\n\n");
printf("^A: interactive choice of interrupt\n");
printf("^B: create and enter a breakpoint REP loop\n");
printf("^F: abort to current REP loop\n");
printf("^G: abort to top level REP loop\n");
printf("^P: abort to previous (lower number) REP loop\n");
printf("^Z: exit Scheme temporarily\n");
printf("<returning to Scheme>\n\n");
goto exit_gracefully;
case 'Q':
case 'q':
putchar('\n');
Microcode_Termination(TERM_HALT);
case 'Z':
case 'z':
putchar('\n');
Suspend_Me(true);
goto exit_gracefully;
case '\f': OS_Clear_Screen(); goto exit_gracefully;
case 'I':
case 'i': printf("gnored.\n");
exit_gracefully: return REDO;
default: putchar('\n');
printf("B: Enter a breakpoint loop\n");
printf("D: Debugging: change interpreter flags\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 information about interrupt characters\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: Exit Scheme temporarily\n");
printf("^L: Clear the screen\n");
goto Loop;
}
IntCode |= INT_Character;
New_Compiler_MemTop();
return INTERRUPT;
}
\f
/* Interrupt handlers, continued */
int Sift_Out_Interrupt(Interrupt_Char)
char Interrupt_Char;
{ interrupt_start(0, 0, false);
switch(Interrupt_Char)
{
case C_A:
{ long Result = Ask_Me();
interrupt_end(Result);
}
case C_B:
Int_Char = CONTROL_B; break;
case C_G:
Int_Char = CONTROL_G; break;
case C_F: /* You type ^F to get an ^X interrupt! */
Int_Char = CONTROL_X; break;
case C_P: /* You type ^P to get an ^U interrupt! */
Int_Char = CONTROL_U; break;
case C_Z:
{ Suspend_Me(true);
interrupt_end(REDO);
}
default:
printf("\nAST error! Sift_Out_Interrupt %x",Interrupt_Char);
Int_Char = 0;
interrupt_end(REDO);
}
printf("^%c", Int_Char);
IntCode |= INT_Character;
New_Compiler_MemTop();
interrupt_end(INTERRUPT);
}
\f
/* Temporary exit to parent process */
#define LAST_ITEM 0
Suspend_Me(from_interrupt)
Boolean from_interrupt;
{ int result;
short nbytes = 0;
long pid = -1;
struct Block ignore_me;
struct item_desc {
short length;
short code;
long *buffer;
short *ret_length;
} item_block[2];
item_block[0].code = JPI$_OWNER;
item_block[0].length = sizeof(long);
item_block[0].buffer = &pid;
item_block[0].ret_length = &nbytes;
item_block[1].code = LAST_ITEM;
item_block[1].length = 0;
item_block[1].buffer = NULL;
item_block[1].ret_length = NULL;
result = SYS$GETJPI( 0, NULL, NULL, &item_block[0], &ignore_me, NULL, 0);
if (result != SS$_NORMAL)
{ printf("SYS$GETJPI returned %d != SS$_NORMAL; Continuing\n", result);
return;
}
if (result == 0)
{ printf("Scheme is running at top level, it cannot detach\n");
return;
}
OS_Quit();
result = LIB$ATTACH(&pid);
if (result != SS$_NORMAL)
printf("LIB$ATTACH returned %d; Continuing\n", result);
OS_Re_Init();
return;
}
\f
/* Initializes OS dependent information for Scheme */
OS_Init()
{ OS_Name = "vms";
OS_Variant = NULL;
printf("MIT Scheme, VMS version\n");
printf("^AH (CTRL-A, then H) shows help on interrupt keys.\n");
Int_Char = 0;
TT_Channel = 0;
Init_System_Clock();
OS_Re_Init();
return;
}
OS_Re_Init()
{ static $DESCRIPTOR(Device_Name,"SYS$INPUT");
if (TT_Channel == 0)
{ long Return_Status = SYS$ASSIGN(&Device_Name,&TT_Channel,3,0);
if (Return_Status != SS$_NORMAL)
{ fprintf(stderr, "\nUnable to find Terminal: SYS$ASSIGN\n");
Microcode_Termination(TERM_EOF);
}
else Setup_Scheme_Interrupts();
}
else Setup_Scheme_Interrupts();
Initialize_Input();
return;
}
OS_Quit()
{ if (TT_Channel != 0) Clear_Scheme_Interrupts();
return;
}
\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;
}
#ifdef COMPILE_FUTURES
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