-- MesaExec.Mesa Edited by Sandman on July 1, 1980  8:16 AM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  BcdOps USING [BcdBase],
  ControlDefs USING [
    ControlModule, GFT, GlobalFrameHandle, NullControl, NullGlobalFrame],
  CoreSwapDefs USING [CantSwap],
  ImageDefs USING [StopMesa],
  IODefs USING [
    CR, DEL, LineOverflow, NewLine, ReadChar, ReadID, ReadLine, ReadNumber,
    Rubout, SP, WriteChar, WriteOctal, WriteString],
  LoaderOps USING [FileNotFound, Load, New, VersionMismatch],
  MiscDefs USING [CallDebugger],
  StringDefs USING [AppendChar, InvalidNumber, LowerCase, StringBoundsFault];

MesaExec: PROGRAM
  IMPORTS CoreSwapDefs, ImageDefs, IODefs, LoaderOps, MiscDefs, StringDefs =
  BEGIN

  -- System Signals are converted to these to prevent NubCommand
  -- from catching user generated signals

  Delete: SIGNAL = CODE; -- nee Rubout

  StringTooLong: ERROR = CODE; -- nee LineOverflow

  BadFile: ERROR [badname: STRING] = CODE; -- nee FileNameError

  BadVersion: SIGNAL [badname: STRING] = CODE; -- nee VersionMismatch

  BadNumber: ERROR = CODE; -- nee InvalidNumber

  GlobalFrameHandle: TYPE = ControlDefs.GlobalFrameHandle;
  NullGlobalFrame: GlobalFrameHandle = ControlDefs.NullGlobalFrame;

  module: STRING ← [40];
  defaultframe: GlobalFrameHandle ← NullGlobalFrame;

  DoCommand: PROCEDURE =
    BEGIN OPEN ControlDefs;
    p: PROCESS;
    f: GlobalFrameHandle;
    f ← Command[];
    IF f # NullGlobalFrame THEN {p ← FORK StartModule[[frame[f]]]; JOIN p; };
    RETURN
    END;

  Command: PROCEDURE RETURNS [GlobalFrameHandle] =
    BEGIN OPEN IODefs;
    nCommand: STRING = "New"L;
    sCommand: STRING = "Start"L;
    dCommand: STRING = "Debug"L;
    qCommand: STRING = "Quit"L;
    cCommand: STRING = "--"L;
    c: CHARACTER;
    f: GlobalFrameHandle;
    DO
      WriteEOL[];
      WriteChar['>];
      SELECT StringDefs.LowerCase[c ← ReadChar[]] FROM
	'n => BEGIN WriteString[nCommand]; LoadModule[]; END;
	's =>
	  BEGIN WriteString[sCommand]; f ← GetFrame[]; WriteEOL[]; RETURN[f]; END;
	'd =>
	  BEGIN
	  WriteString[dCommand];
	  Confirm[];
	  MiscDefs.CallDebugger["You called?"L];
	  END;
	'q => BEGIN WriteString[qCommand]; Confirm[]; ImageDefs.StopMesa[]; END;
	'- => BEGIN WriteString[cCommand]; GetComment[]; END;
	CR, SP => NULL;
	ENDCASE =>
	  BEGIN
	  WriteChar[c];
	  WriteString[" Commands are:"L];
	  WriteChar[' ];
	  WriteString[nCommand];
	  WriteChar[' ];
	  WriteString[sCommand];
	  WriteChar[' ];
	  WriteString[dCommand];
	  WriteChar[' ];
	  WriteString[qCommand];
	  WriteChar[' ];
	  WriteString[cCommand];
	  END;
      ENDLOOP;
    END;

  GetComment: PROCEDURE =
    BEGIN OPEN IODefs;
    s: STRING ← [256];
    ReadLine[s ! Rubout => ERROR Delete; LineOverflow => ERROR StringTooLong];
    RETURN
    END;

  LoadModule: PROCEDURE =
    BEGIN OPEN IODefs;
    i: CARDINAL ← 0;
    g: ControlDefs.ControlModule;
    frameLinks: BOOLEAN;
    WriteString[" Filename: "L];
    ReadID[module ! Rubout => ERROR Delete; LineOverflow => ERROR StringTooLong];
    frameLinks ← CheckSwitch[module];
    DefaultExtension[module, ".bcd"L];
    g ← LoadNew[module, frameLinks];
    IF g # ControlDefs.NullControl THEN defaultframe ← g.frame;
    RETURN
    END;

  LoadNew: PROCEDURE [name: STRING, framelinks: BOOLEAN]
    RETURNS [g: ControlDefs.ControlModule] =
    BEGIN OPEN LoaderOps;
    bcd: BcdOps.BcdBase;
    bcd ← Load[name ! BadFile, UNWIND => NULL; ANY => ERROR BadFile[name]];
    g ← New[
      bcd, framelinks, FALSE ! BadFile, BadVersion, UNWIND => NULL;
      VersionMismatch => BEGIN SIGNAL BadVersion[name]; RESUME END;
      FileNotFound => ERROR BadFile[name]; ANY => ERROR BadFile[name]];
    IODefs.WriteString[" -- "L];
    IODefs.WriteOctal[g];
    WriteEOL[];
    RETURN
    END;

  StartModule: PROCEDURE [f: ControlDefs.ControlModule] =
    BEGIN
    IF f.multiple OR ~f.frame.started THEN
      START LOOPHOLE[f, PROGRAM][ ! ABORTED => CONTINUE]
    ELSE RESTART LOOPHOLE[f, PROGRAM][ ! ABORTED => CONTINUE];
    RETURN
    END;

  GetFrame: PROCEDURE RETURNS [f: GlobalFrameHandle] =
    BEGIN OPEN IODefs;
    WriteString[" Global frame: "L];
    f ← ReadNumber[
      defaultframe, 8 ! LineOverflow => ERROR StringTooLong;
      Rubout => ERROR Delete; StringDefs.InvalidNumber => ERROR BadNumber];
    IF ControlDefs.GFT[f.gfi].frame # f THEN
      BEGIN WriteString[" not a global frame!"L]; ERROR ABORTED END;
    defaultframe ← f;
    RETURN
    END;

  CheckSwitch: PROCEDURE [s: STRING] RETURNS [BOOLEAN] =
    BEGIN
    i, newLength, oldLength: CARDINAL;
    oldLength ← s.length;
    FOR i DECREASING IN [0..oldLength) DO
      IF s[i] = '/ THEN BEGIN newLength ← i; EXIT END;
      REPEAT FINISHED => RETURN[TRUE];
      ENDLOOP;
    s.length ← newLength;
    FOR i IN [newLength + 1..oldLength) DO
      IF s[i] = 'l THEN RETURN[FALSE]; ENDLOOP;
    RETURN[TRUE]
    END;

  DefaultExtension: PROCEDURE [idstring: STRING, ext: STRING] =
    BEGIN
    i: CARDINAL;
    FOR i IN [0..idstring.length) DO
      IF idstring[i] = '. THEN EXIT;
      REPEAT
	FINISHED =>
	  FOR i IN [0..ext.length) DO
	    StringDefs.AppendChar[
	      idstring, ext[i] !
	      StringDefs.StringBoundsFault => ERROR StringTooLong];
	    ENDLOOP;
      ENDLOOP;
    END;

  Confirm: PROCEDURE =
    BEGIN OPEN IODefs;
    c: STRING = " [Confirm] "L;
    WriteString[c];
    SELECT ReadChar[] FROM
      CR => NULL;
      DEL => ERROR Delete;
      ENDCASE =>
	BEGIN
	WriteChar['?];
	DO IF ReadChar[] = DEL THEN ERROR Delete ELSE WriteChar['?]; ENDLOOP;
	END;
    WriteChar[CR];
    RETURN
    END;

  WriteEOL: PROCEDURE =
    BEGIN OPEN IODefs; IF ~NewLine[] THEN WriteChar[CR]; RETURN END;

  Done: SIGNAL = CODE;

  ErrorName: TYPE = {XXX, file, number, toolong, nodebug, aborted, diffver};

  WriteError: PROCEDURE [error: ErrorName] =
    BEGIN
    IODefs.WriteString[
      SELECT error FROM
	file => "!File: "L,
	number => "!Number"L,
	toolong => "!String too long"L,
	nodebug => "External Debugger not installed, type DEL to abort "L,
	aborted => "...Aborted..."L,
	diffver => " referenced in different versions"L,
	ENDCASE => " XXX"L]
    END;

  StartExecutive: PROCEDURE =
    BEGIN OPEN IODefs;
    DO
      DoCommand[
	! Delete => BEGIN WriteError[XXX]; CONTINUE END; ABORTED => CONTINUE;
	BadFile --[badname: STRING]-- =>
	  BEGIN WriteEOL[]; WriteError[file]; WriteString[badname]; CONTINUE END;
	BadNumber => BEGIN WriteEOL[]; WriteError[number]; CONTINUE END;
	StringTooLong => BEGIN WriteEOL[]; WriteError[toolong]; CONTINUE END;
	CoreSwapDefs.CantSwap =>
	  BEGIN
	  WriteEOL[];
	  WriteError[nodebug];
	  UNTIL ReadChar[] = DEL DO WriteChar['?] ENDLOOP;
	  WriteError[aborted];
	  CONTINUE
	  END;
	BadVersion --[badname: STRING]-- =>
	  BEGIN
	  WriteEOL[];
	  WriteError[file];
	  WriteString[badname];
	  WriteError[diffver];
	  RESUME
	  END; UNWIND => CONTINUE];
      ENDLOOP;
    END;

  StartExecutive[];

  END..