DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T v

⟦b6f2f687e⟧ TextFile

    Length: 15278 (0x3bae)
    Types: TextFile
    Names: »vms.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/gnu-31mar87/scheme/microcode/vms.c« 

TextFile

/*          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