-- file Interface.Mesa
-- last modified by Sandman, Jan 15, 1980 2:07 PM

DIRECTORY
  AltoDisplay: FROM "altodisplay"
    USING [DCB, DCBHandle, DCBchainHead, MaxBitsPerLine, MaxScanLines],
  AltoFileDefs: FROM "altofiledefs" USING [FP],
  CharIO: FROM "chario"
    USING [
      CR, NumberFormat, PutChar, PutDecimal,  PutLine, PutNumber, PutString],
  CompilerOps: FROM "compilerops"
    USING [TableId, Transaction, Compile, NoSource, Punt, Sequencer],
  DirectoryDefs: FROM "directorydefs" USING [EnumerateDirectory],
  ImageDefs: FROM "imagedefs"
    USING [
      CleanupItem, CleanupMask, CleanupProcedure, FileRequest,
      AddCleanupProcedure, AddFileRequest,
      AbortMesa, ImageTime, RunImage, StopMesa],
  InlineDefs: FROM "inlinedefs" USING [DIVMOD],
  KeyDefs: FROM "keydefs" USING [Keys, KeyBits],
  MiscDefs: FROM "miscdefs" USING [CallDebugger, CommandLineCFA],
  OsStaticDefs: FROM "osstaticdefs" USING [OsStatics],
  SDDefs: FROM "sddefs" USING [sAddFileRequest, SD],
  SegmentDefs: FROM "segmentdefs"
    USING [
      FileHandle, FileSegmentHandle,  DefaultVersion,
      DestroyFile, InsertFile, LockFile, NewFile, NewFileSegment, UnlockFile],
  StreamDefs: FROM "streamdefs"
    USING [
      StreamHandle, StreamObject, Append, Read, Write,
      CloseDiskStream, CreateByteStream, JumpToFA, OpenDiskStream],
  StringDefs: FROM "stringdefs"
    USING [
      AppendChar, AppendString, EquivalentString,
      MesaToBcplString, WordsForBcplString],
  SystemDefs: FROM "systemdefs"
    USING [
      AllocateHeapNode, AllocateHeapString, FreeHeapString, FreeHeapNode],
  TimeDefs: FROM "timedefs" USING [DefaultTime, AppendDayTime, UnpackDT];

Interface: PROGRAM [
    explicitSwapping: BOOLEAN,
    tableSegment: ARRAY CompilerOps.TableId OF SegmentDefs.FileSegmentHandle]
    IMPORTS
      CharIO, CompilerOps, DirectoryDefs, ImageDefs, InlineDefs,
      MiscDefs, SegmentDefs, StreamDefs, StringDefs, SystemDefs, TimeDefs
    EXPORTS CompilerOps = 
  BEGIN
  OPEN StreamDefs;

-- command line input control

  commandStream: StreamHandle;
  comCmRequest: ImageDefs.FileRequest ← [
    name: "Com.Cm.", file: NIL, access: Read, link: ];
  
  SetCommandInput: PROCEDURE =
    BEGIN
    c: CHARACTER;
    commandStream ← CreateByteStream[comCmRequest.file, Read];
    IF ~image
      THEN JumpToFA[commandStream, @(MiscDefs.CommandLineCFA[]).fa]
      ELSE
	BEGIN
	[] ← SkipStreamBlanks[];
	UNTIL commandStream.endof[commandStream] OR
	(c←commandStream.get[commandStream]) = '  OR c = CharIO.CR
	  DO NULL ENDLOOP;
	END;
    END;

  SkipStreamBlanks: PROCEDURE RETURNS [c: CHARACTER] =
    BEGIN OPEN CharIO;
    UNTIL commandStream.endof[commandStream]
      DO
      c ← commandStream.get[commandStream];
      IF c # '  AND c # CR THEN EXIT;
      ENDLOOP;
    END;

  CommandLineID: PROCEDURE [s: STRING] =
    BEGIN  OPEN CharIO;
    c: CHARACTER;
    s.length ← 0;
    c ← SkipStreamBlanks[];
    UNTIL commandStream.endof[commandStream] OR c = '  OR c = CR
      DO
      StringDefs.AppendChar[s, c];
      c ← commandStream.get[commandStream];
      ENDLOOP;
    END;


-- special output stream control

  log: StreamHandle;

  logName: STRING = "Compiler.Log.";
  logRequest: ImageDefs.FileRequest ← [
    name: logName, file: NIL, access: Write+Append, link: ];

  SetTypescript: PROCEDURE =
    BEGIN OPEN SegmentDefs;
    IF logRequest.file = NIL
      THEN logRequest.file ← NewFile[logName, Write+Append, DefaultVersion];
    log ← CreateByteStream[logRequest.file, Write+Append];
    END;

  NewLine: PROCEDURE = BEGIN CharIO.PutChar[log, CharIO.CR] END;


  errorStream: StreamHandle;

  ErrorPut: PROCEDURE [s: StreamHandle, c: CHARACTER] =
    BEGIN OPEN SegmentDefs;
    errorName: STRING;
    IF errorStream = NIL
      THEN
	BEGIN
	errorName ←
	  SystemDefs.AllocateHeapString[rootName.length + (".errlog"L).length];
	StringDefs.AppendString[errorName, rootName];
	StringDefs.AppendString[errorName, ".errlog"L];
	errorStream ← CreateByteStream[
	  IF errorFile=NIL
	    THEN SegmentDefs.NewFile[errorName, Write+Append, SegmentDefs.DefaultVersion]
	    ELSE errorFile,
	  Write+Append];
	WriteHerald[errorStream, errorName];
	errorStream.put[errorStream, CharIO.CR];
	SystemDefs.FreeHeapString[errorName];
	END;
    errorStream.put[errorStream, c];
    END;

  ErrorDestroy: PROCEDURE [s: StreamHandle] =
    BEGIN
    SELECT TRUE FROM
      errorStream # NIL => errorStream.destroy[errorStream];
      errorFile # NIL => SegmentDefs.DestroyFile[errorFile];
      ENDCASE;
    SystemDefs.FreeHeapNode[s];
    END;


  WriteHerald: PROCEDURE [s: StreamHandle, id: STRING] =
    BEGIN OPEN TimeDefs, CharIO;
    time: STRING ← [20];
    PutString [s, "Alto/Mesa Compiler 6.0c of "L];
    time.length ← 0;  AppendDayTime[time, UnpackDT[ImageDefs.ImageTime[]]];
    PutLine[s, time];
    IF id # NIL THEN BEGIN PutString[s, id]; PutString[s, " -- "L] END;
    time.length ← 0;  AppendDayTime[time, UnpackDT[DefaultTime]];
    PutLine[s, time];
    END;

  WriteTime: PROCEDURE [sec: CARDINAL] =
    BEGIN  OPEN CharIO;
    hr, min: CARDINAL;
    f: NumberFormat ← [base:10, unsigned:TRUE, zerofill:FALSE, columns:1];

    W: PROCEDURE [t: CARDINAL] =
      BEGIN
      IF t # 0 OR f.zerofill THEN
	BEGIN
	PutNumber[log, t, f];  PutChar[log, ':];
	f ← [base:10, unsigned:TRUE, zerofill:TRUE, columns:2];
	END;
      END;

    [min, sec] ← InlineDefs.DIVMOD[sec, 60];
    [hr, min] ← InlineDefs.DIVMOD[min, 60];
    W[hr];  W[min];  PutNumber[log, sec, f];
    END;

-- cleanup of files/streams

  compilerCleanupItem: ImageDefs.CleanupItem ← [
      proc: CompilerCleanup,
      mask: ImageDefs.CleanupMask[InLd] + ImageDefs.CleanupMask[OutLd],
      link: ];

  CompilerCleanup: ImageDefs.CleanupProcedure =
    BEGIN
    SELECT why FROM
      OutLd => IF errorStream # NIL THEN CloseDiskStream[errorStream];
      InLd =>  IF errorStream # NIL THEN OpenDiskStream[errorStream];
      ENDCASE;
    END;


-- table storage management
  
  tableRequest: ImageDefs.FileRequest ← [
    name: "Swatee.", file: NIL, access: Read+Write+Append, link: ];

-- compiler sequencing

  Initialize: PROCEDURE =
    BEGIN
    IF log # NIL THEN CloseDiskStream[log];
    IF commandStream # NIL THEN CloseDiskStream[commandStream];
    moduleStartTime ← secondsClock.low;
    END;

  Finalize: PROCEDURE =
    BEGIN
    SELECT TRUE FROM
      parms.nErrors = 0 =>
	IF parms.object.stream # NIL
	  THEN parms.object.stream.destroy[parms.object.stream];
      ENDCASE =>
	BEGIN
	IF parms.object.stream # NIL
	  THEN
	    BEGIN
	    objectFile ← WITH s: parms.object.stream SELECT FROM
	      Disk => objectFile ← s.file,
	      ENDCASE => ERROR;
	    SegmentDefs.LockFile[objectFile];
	    parms.object.stream.destroy[parms.object.stream];
	    SegmentDefs.UnlockFile[objectFile];
	    END;
	IF objectFile # NIL
	  THEN
	    BEGIN
	    IF oldObjectFile THEN SegmentDefs.UnlockFile[objectFile];
	    SegmentDefs.DestroyFile[objectFile];
	    END;
	END;
    IF parms.source.stream # NIL
      THEN parms.source.stream.destroy[parms.source.stream];
    IF parms.error.stream # NIL
      THEN parms.error.stream.destroy[parms.error.stream];
    IF commandStream # NIL THEN OpenDiskStream[commandStream];
    IF log # NIL THEN OpenDiskStream[log];
    END;

  WriteClosing: PROCEDURE =
    BEGIN OPEN CharIO;
    IF (cursorLoc.y ← cursorLoc.y+16) > AltoDisplay.MaxScanLines-64
      THEN cursorLoc.y ← 64;
    PutString[log, sourceName];  PutString[log, " -- "L];
    IF parms.nErrors # 0
      THEN
	BEGIN
	cursorLoc.x ← MIN[AltoDisplay.MaxBitsPerLine-64, cursorLoc.x+16];
	errors ← TRUE;  PutString[log, "aborted, "L];
	PutDecimal[log, parms.nErrors];  PutString[log, " errors "L];
	IF parms.nWarnings # 0 THEN
	  BEGIN
	  warnings ← TRUE;  PutString[log, "and "L];
	  PutDecimal[log, parms.nWarnings];  PutString[log, " warnings "L];
	  END;
	PutString[log, "on "L];
	PutString[log, rootName]; PutString[log, ".errlog"L];
	END
      ELSE
	BEGIN
	PutString[log, "source tokens: "L];
	PutNumber[log, parms.sourceTokens,
	    [base:10,zerofill:FALSE,unsigned:TRUE,columns:1]];
	PutString[log, ", time: "L];
	WriteTime[secondsClock.low-moduleStartTime];
	IF parms.objectBytes # 0 THEN
	  BEGIN
	  NewLine[]; 
	  PutString[log, "  code bytes: "L]; PutDecimal[log, parms.objectBytes];
	  PutString[log, ", links: "L]; PutDecimal[log, parms.linkCount];
	  PutString[log, ", frame size: "L];
	  PutDecimal[log, parms.objectFrameSize];
	  END;
	IF parms.nWarnings # 0 THEN
	  BEGIN
	  warnings ← TRUE;  NewLine[];
	  PutDecimal[log, parms.nWarnings];  PutString[log, " warnings on "L];
	  PutString[log, rootName];  PutString[log, ".errlog"L];
	  END;
	END;
    END;


  StopCompiler: PROCEDURE =
    BEGIN
    IF moduleCount > 1 THEN
      BEGIN OPEN CharIO;
      NewLine[];  PutString[log, "Total elapsed time: "L];
      WriteTime[secondsClock.low-compilerStartTime];  NewLine[];
      END;
    log.destroy[log];
    IF (errors OR warnings) AND SwitchDefaults['p]
      THEN
	BEGIN
	CursorBits: TYPE = ARRAY [0..16) OF WORD;
	Cursor: POINTER TO CursorBits = LOOPHOLE[431B];
	BlankCursor: CursorBits = ALL[0];
	QueryCursor: CursorBits = 
	  [2000B, 74000B, 140000B, 12767B, 12525B, 53566B, 111113B, 163100B,
	  0B, 0B, 154000B, 53520B, 62520B, 53360B, 155440B, 140B];
	      savedCursor: CursorBits = Cursor↑;
	KeyBits: TYPE = ARRAY [0..SIZE[KeyDefs.KeyBits]-1) OF WORD;
	Keys: POINTER TO KeyBits = LOOPHOLE[KeyDefs.Keys+1];
	savedKeys: KeyBits = Keys↑;
	RTC: POINTER TO
	    MACHINE DEPENDENT RECORD [high: [0..4096), low: [0..16)] =
	  LOOPHOLE[430B];
	savedTime: CARDINAL;
	state: {off, on1, on2};
	Cursor↑ ← BlankCursor;  state ← off;  savedTime ← RTC.high;
	  DO
	  IF RTC.high # savedTime
	    THEN
	      BEGIN
	      SELECT state FROM
		off => BEGIN Cursor↑ ← QueryCursor; state ← on1 END;
		on1 => state ← on2;
		on2 => BEGIN Cursor↑ ← BlankCursor; state ← off END;
		ENDCASE;
	      savedTime ← RTC.high;
	      END;
	  IF Keys↑ # savedKeys THEN EXIT;
	  ENDLOOP;
	Cursor↑ ← savedCursor;
	END;
    END;


  transaction: CompilerOps.Transaction;
  parms: POINTER TO CompilerOps.Transaction = @transaction;

  SwitchDefaults: PACKED ARRAY CHARACTER ['a..'z] OF BOOLEAN ← [
  --a/k/u  b/l/v  c/m/w  d/n/x  e/o/y  f/p/z  g/q    h/r    i/s    j/t --
    TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,  TRUE, FALSE,
    FALSE, FALSE, FALSE, FALSE, FALSE,  TRUE, FALSE, FALSE,  TRUE, FALSE,
    FALSE, FALSE,  TRUE, FALSE, FALSE, FALSE];

  sourceName: STRING ← [40];
  objectName: STRING ← [40];
  rootName: STRING ← [40];

  sourceFile: SegmentDefs.FileHandle;
  errorFile: SegmentDefs.FileHandle;
  objectFile: SegmentDefs.FileHandle;
  oldObjectFile: BOOLEAN;

  FindFiles: PROCEDURE [fp: POINTER TO AltoFileDefs.FP, s: STRING] RETURNS [BOOLEAN] =
    BEGIN
    IF s.length = sourceName.length
    AND StringDefs.EquivalentString[sourceName, s]
      THEN  sourceFile ← SegmentDefs.InsertFile[fp, Read];
    IF s.length = objectName.length
    AND StringDefs.EquivalentString[objectName, s]
      THEN
	BEGIN
	objectFile ← SegmentDefs.InsertFile[fp, Write+Append];
	SegmentDefs.LockFile[objectFile];  oldObjectFile ← TRUE;
	END;
    IF s.length = rootName.length + (".errlog."L).length
      THEN
	BEGIN
	errorName: STRING ← [40];
	StringDefs.AppendString[errorName, rootName];
	StringDefs.AppendString[errorName, ".errlog."L];
	IF StringDefs.EquivalentString[errorName, s]
	  THEN  errorFile ← SegmentDefs.InsertFile[fp, Write+Append];
	END;
    RETURN [sourceFile # NIL AND errorFile # NIL AND objectFile # NIL]
    END;

  errors, warnings: BOOLEAN;
  moduleCount: CARDINAL;
  compilerStartTime, moduleStartTime: CARDINAL;
  secondsClock: POINTER TO MACHINE DEPENDENT RECORD [high, low: CARDINAL] =
    LOOPHOLE[572B];


  -- * * * * * *  M A I N   B O D Y   C O D E  * * * * * *

  image: BOOLEAN = (SDDefs.SD[SDDefs.sAddFileRequest] # 0);

  dcbSpace: ARRAY [0..SIZE[AltoDisplay.DCB]+1) OF UNSPECIFIED;
  dcb, saveDCB: AltoDisplay.DCBHandle;

  CursorXY: TYPE = MACHINE DEPENDENT RECORD [x,y: CARDINAL];
  cursorLoc: POINTER TO CursorXY = LOOPHOLE[426B];
  saveCursorXY: CursorXY;

-- add cleanup procedure
  ImageDefs.AddCleanupProcedure[@compilerCleanupItem];
  IF image
    THEN
      BEGIN
      ImageDefs.AddFileRequest[@comCmRequest];
      ImageDefs.AddFileRequest[@logRequest];
      ImageDefs.AddFileRequest[@tableRequest];
      STOP;  -- wait for restart
      END
    ELSE
      BEGIN
      fp: AltoFileDefs.FP ← MiscDefs.CommandLineCFA[].fp;
      comCmRequest.file ← SegmentDefs.InsertFile[@fp, Read];
      END;

  dcb ← @dcbSpace[0];
  IF LOOPHOLE[dcb, CARDINAL] MOD 2 # 0 THEN dcb ← dcb + 1;
  dcb↑ ← AltoDisplay.DCB[NIL, high, black, 0, 0, NIL, 0];
  saveDCB ← AltoDisplay.DCBchainHead↑;  AltoDisplay.DCBchainHead↑ ← dcb;
  saveCursorXY ← cursorLoc↑;  cursorLoc↑ ← [64,64];

  errorStream ← NIL;

  IF tableRequest.file = NIL THEN
    tableRequest.file ← SegmentDefs.NewFile[
	"Swatee.", Read+Write+Append, SegmentDefs.DefaultVersion];
  START CompilerOps.Sequencer[
		explicitSwapping, tableRequest.file, tableSegment];

  compilerStartTime ← secondsClock.low;  moduleCount ← 0;

-- do the compilation

  SetCommandInput[];  SetTypescript[];
  WriteHerald[log, NIL];  errors ← warnings ← FALSE;

    DO
    OPEN CharIO;
      BEGIN
      i, sourceLength: CARDINAL;
      c: CHARACTER;
      sense, sourceExtension: BOOLEAN;

      CompleteFileName: PROCEDURE RETURNS [fileName: STRING, bcpl: BOOLEAN] =
	BEGIN  OPEN StringDefs;
	j: CARDINAL;
	extension: STRING ← [40];
	fileName ← SystemDefs.AllocateHeapString[40];
	AppendString[fileName, rootName];
	IF ~sourceExtension
	  THEN  AppendString[extension, "image"L]
	  ELSE
	    FOR j IN [rootName.length+1 .. sourceLength)
	      DO  AppendChar[extension, sourceName[j]]  ENDLOOP;
	bcpl ← EquivalentString[extension, "run"L];
	AppendChar[fileName, '.];  AppendString[fileName, extension];
	RETURN
	END;

      WriteCommandFile: PROCEDURE [fileName: STRING] =
	BEGIN
	j: CARDINAL;
	copy: StreamHandle;
	copy ← CreateByteStream[
		  SegmentDefs.NewFile[
		    "com.cm."L, Write+Append, SegmentDefs.DefaultVersion],
		  Write+Append];
	FOR j IN [0..fileName.length) DO copy.put[copy, fileName[j]] ENDLOOP;
	IF sourceName.length > i+1
	  THEN
	    BEGIN
	    copy.put[copy, '/];
	    FOR j IN (i..sourceName.length)
	      DO copy.put[copy, sourceName[j]] ENDLOOP;
	    END;
	IF commandStream = NIL OR commandStream.endof[commandStream]
	  THEN  copy.put[copy, CR]
	  ELSE
	    BEGIN
	    copy.put[copy, ' ];
	    UNTIL commandStream.endof[commandStream]
	      DO  copy.put[copy, commandStream.get[commandStream]]  ENDLOOP;
	    END;
	IF commandStream # NIL THEN commandStream.destroy[commandStream];
	copy.destroy[copy];
	RETURN
	END;

      Run: PROCEDURE [fileName: STRING, bcpl: BOOLEAN] =
	BEGIN
	IF bcpl
	  THEN
	    BEGIN
	    p: POINTER = OsStaticDefs.OsStatics.EventVector;
	    EVItem: TYPE = MACHINE DEPENDENT RECORD [
		type: [0..7777B], length: [0..17B]];
	    p↑ ← EVItem[6, StringDefs.WordsForBcplString[fileName.length]+1];
	    StringDefs.MesaToBcplString[fileName, p+1];
	    ImageDefs.StopMesa[];
	    END
	  ELSE
	    BEGIN  OPEN SegmentDefs;
	    ImageDefs.RunImage[NewFileSegment[
	      file: NewFile[fileName, Read, DefaultVersion],
	      base: 1,
	      pages: 1,
	      access: Read]];
	    END;
	END;

      parms.switches ← SwitchDefaults;  parms.switches['p] ← FALSE;
      parms.debugPass ← LAST[CARDINAL];
      CommandLineID[sourceName];
      IF sourceName.length = 0 THEN EXIT;
      NewLine[];  PutString[log, "Compile: "]; PutString[log, sourceName];
      IF sourceName[0] = 04C THEN GO TO debugger;        -- ↑D => debug
      rootName.length ← 0;  sourceExtension ← FALSE;
      FOR i IN [0..sourceName.length)
	DO
	c ← sourceName[i];
	SELECT c FROM
	  '. => sourceExtension ← TRUE;
	  '/ => GO TO Switches;
	  ENDCASE;
	IF ~sourceExtension
	  THEN StringDefs.AppendChar[rootName, c];
	REPEAT
	  Switches =>
	    BEGIN
	    sourceLength ← i;  i ← i+1;  sense ← TRUE;
	    WHILE i < sourceName.length
	      DO
	      SELECT (c ← sourceName[i]) FROM
		'-, '~ => sense ← ~sense;
		'r, 'R =>
		  BEGIN
		  fileName: STRING;
		  bcpl: BOOLEAN;
		  [fileName, bcpl] ← CompleteFileName[];
		  WriteCommandFile[fileName];
		  StopCompiler[];
		  Run[fileName, bcpl ! ANY => ImageDefs.AbortMesa];
		  -- never returns
		  END;
		'c, 'C =>
		  BEGIN  sense ← TRUE;
		  FOR i IN [0..sourceLength)
		    DO
		    SELECT (c ← sourceName[i]) FROM
		      '-, '~ => sense ← ~sense;
		      IN ['a..'z] =>
			BEGIN SwitchDefaults[c] ← sense; EXIT END;
		      IN ['A..'Z] =>
			BEGIN SwitchDefaults[c+('a-'A)] ← sense; EXIT END;
		      ENDCASE => EXIT;
		    ENDLOOP;
		  GO TO skip
		  END;
		IN ['a..'z] =>
		  BEGIN parms.switches[c] ← sense; sense ← TRUE END;
		IN ['A..'Z] =>
		  BEGIN parms.switches[c+('a-'A)] ← sense; sense ← TRUE END;
		IN ['1..'5] => 
		  BEGIN  parms.debugPass ← c-'0;  sense ← TRUE  END;
		ENDCASE;
	      i ← i+1;
	      ENDLOOP;
	    END;
	  FINISHED => sourceLength ← sourceName.length;
	ENDLOOP;
      NewLine[];
      sourceName.length ← sourceLength;
      IF ~sourceExtension THEN StringDefs.AppendString[sourceName, ".mesa"];
      IF sourceName[sourceName.length-1] # '.
	THEN StringDefs.AppendChar[sourceName, '.];
      parms.source ← [name: sourceName, stream: NIL];

      parms.error.name ← NIL;  errorStream ← NIL;
      parms.error.stream ←
	SystemDefs.AllocateHeapNode[SIZE[Other StreamObject]];
      parms.error.stream↑ ← 
	[NULL, NULL, NULL, ErrorPut, NULL, ErrorDestroy, NIL, Other[,]];

      objectName.length ← 0;
      StringDefs.AppendString[objectName, rootName];
      StringDefs.AppendString[objectName, ".bcd."];
      parms.object ← [name: objectName, stream: NIL];

      BEGIN  OPEN SegmentDefs;
      ENABLE ANY => CONTINUE;
      sourceFile ← errorFile ← objectFile ← NIL;  oldObjectFile ← FALSE;
      DirectoryDefs.EnumerateDirectory[FindFiles];
      IF sourceFile # NIL
	THEN  parms.source.stream ← CreateByteStream[sourceFile, Read];
      END;

      moduleCount ← moduleCount + 1;

      Initialize[];
      CompilerOps.Compile[parms
	! CompilerOps.NoSource => GO TO noSource;
	  CompilerOps.Punt => GO TO punt];
      Finalize[];  WriteClosing[];

      EXITS
	skip =>  NULL;
	noSource =>
	  BEGIN
	  Finalize[];   errors ← TRUE;
	  PutString[log, sourceName]; PutString[log, " -- File error"];
	  END;
	debugger =>  MiscDefs.CallDebugger[NIL];
      END;
    NewLine[];
    IF (errors OR warnings) AND parms.switches['p] THEN GO TO truncateList;
    REPEAT
      truncateList => SwitchDefaults['p] ← TRUE;
      punt => BEGIN Finalize[]; WriteClosing[]; NewLine[] END;
    ENDLOOP;

  StopCompiler[];
  cursorLoc↑ ← saveCursorXY;  AltoDisplay.DCBchainHead↑ ← saveDCB;
  ImageDefs.StopMesa[];

  END.