-- file CrossPGSInterface.mesa
-- last modified by Satterthwaite, January 12, 1983 8:53 am

DIRECTORY
  CommandUtil: TYPE USING [
    PairList, Echo, Failed, FreePairList, FreeString, Parse, CommandPtr, 
    CommandObject],
  Exec: TYPE USING [AddCommand, commandLine, w],
  FileStream: TYPE USING [Create, SetLength],
  Heap: TYPE USING [Create, Delete],
  OSMiscOps: TYPE USING [FindFile],
  PGSConDefs: TYPE USING [],
  PGSOps: TYPE USING [PGSPhase, Generate, LockedSource, NoSource, BadSemantics],
  Runtime USING [GetBcdTime],
  Stream: TYPE USING [Delete, Handle, PutChar],
  Strings: TYPE USING [String, AppendString],
  Time: TYPE USING [Append, Unpack],
  TTY: TYPE USING [Handle, PutChar],
  UserTerminal: TYPE USING [CursorArray, GetCursorPattern, SetCursorPattern];

CrossPGSInterface: PROGRAM
    IMPORTS
      CommandUtil, Exec, FileStream, Heap, OSMiscOps,
      PGSOps, Runtime, Stream, Strings, Time, TTY, UserTerminal
    EXPORTS PGSConDefs = {

 -- command interface

  tty: TTY.Handle;
  
  log: Stream.Handle ← NIL;
  commandStream: Stream.Handle ← NIL;
  CR: CHAR = '\n;

  LogChar: PROC [c: CHAR] = {
    IF log # NIL THEN log.PutChar[c];
    tty.PutChar[c]};
    
  LogString: PROC [s: Strings.String] = {
    FOR i: CARDINAL IN [0..s.length) DO LogChar[s[i]] ENDLOOP};
    
    
-- scratch region and scratch zone management

  zone: PUBLIC UNCOUNTED ZONE ← NIL;


-- cursor management

  preCursor: UserTerminal.CursorArray = [ 
   0, 0, 0, 0, 76b, 146b, 300b, 4300b, 76336b, 4304b, 314b, 164b, 0, 0, 0, 0];
  pgsCursor: UserTerminal.CursorArray = [ 
   37000b, 63000b, 140000b, 140010b, 157174b, 142010b, 146000b, 72000b,
   0b, 177777b, 111111b, 177777b, 111111b, 177777b, 111111b, 177777b];
 
  StartPhase: PROC [phase: PGSOps.PGSPhase] RETURNS [goOn: BOOL ← TRUE] = {
    SELECT phase FROM
      $format => UserTerminal.SetCursorPattern[preCursor];
      $lalr => UserTerminal.SetCursorPattern[pgsCursor];
      ENDCASE};


-- * * * * * * HERE IT BEGINS * * * * * *

  Main: PROC = {
    source: Strings.String;
    args, results: CommandUtil.PairList;
    switches: Strings.String;
    ok, warnings: BOOL;
    herald: STRING ← [50];
    savedCursor: UserTerminal.CursorArray;
    commandObject: CommandUtil.CommandObject;
    commandLine: PACKED ARRAY [0.. 100) OF CHAR;
  
    zone ← Heap.Create[initial:16, increment:8];
    Strings.AppendString[to:herald, from:"Cedar Trinity Cross PGS of "L];
    Time.Append[herald, Time.Unpack[Runtime.GetBcdTime[]]];
    herald.length ← herald.length - 3;
  
    tty ← Exec.w;
    log ← FileStream.Create[OSMiscOps.FindFile["pgs.log"L, write]];
    FileStream.SetLength[log, 0];
    LogString[herald]; LogChar[CR];

    savedCursor ← UserTerminal.GetCursorPattern[];

   -- set up command stream

    BEGIN
    commandObject.data ← @commandLine;
    BuildCommand[@commandObject];
    LogString["\nCommand: "L];
    EchoCommand[@commandObject];
    [source, args, results, switches] ← CommandUtil.Parse[
		s: @commandObject,
		opX: 0, resultX: 2+("mesa"L).length
	  ! CommandUtil.Failed => GO TO badSyntax];
    CommandUtil.Echo[log, source, args, results, switches];
    IF source = NIL THEN GO TO noOp;

    [ok, warnings] ← PGSOps.Generate[source, args, results, switches, StartPhase, TRUE
       ! PGSOps.NoSource => GO TO noSource;
         PGSOps.LockedSource => GO TO lockedSource;
         PGSOps.BadSemantics => GO TO badSemantics];

    LogString["\n    "L];
    LogString[SELECT TRUE FROM
      ~ok => "Errors logged, bad output"L,
      warnings => "Warnings logged"L,
      ENDCASE => "Completed successfully"L];
    EXITS
      noOp => NULL;
      noSource => LogString[" -- Cannot be opened"L];
      lockedSource => LogString[" -- Cannot be modified"L];
      badSyntax => LogString["Unparsable command"L];
      badSemantics => LogString[" -- Illegal command"L];
    END;

    source ← CommandUtil.FreeString[source];
    args ← CommandUtil.FreePairList[args];
    results ← CommandUtil.FreePairList[results];
    switches ← CommandUtil.FreeString[switches];
    Heap.Delete[zone];  zone ← NIL;

    LogChar[CR]; LogChar[CR]; Stream.Delete[log];  log ← NIL;
    UserTerminal.SetCursorPattern[savedCursor]};
  
  BuildCommand: PROC [command: CommandUtil.CommandPtr] = {
    command.pos ← command.len ← 0;
    FOR i: CARDINAL IN [Exec.commandLine.i .. Exec.commandLine.s.length) DO
      IF command.len >= 100 THEN EXIT;
      command.data[command.len] ← Exec.commandLine.s[i];
      command.len ← command.len + 1;
      ENDLOOP};
  
  EchoCommand: PROC [command: CommandUtil.CommandPtr] = {
    first: CARDINAL ← command.pos;
    last: CARDINAL ← command.len;
    WHILE first < command.len AND command.data[first] = '  DO first ← first+1 ENDLOOP;
    WHILE last > command.pos AND command.data[last-1] = CR DO last ← last-1 ENDLOOP;
    FOR i: CARDINAL IN [first .. last) DO tty.PutChar[command.data[i]] ENDLOOP};
  
  Exec.AddCommand["CrossPGS.~"L, Main];
  
  }.