-- file PGSInterface.Mesa
-- last modified by Satterthwaite, August 13, 1982 12:36 pm

DIRECTORY
  CharIO: TYPE USING [CR, PutChar, PutString],
  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],
  PGSConDefs: TYPE USING [],
  PGSOps: TYPE USING [PGSPhase, Generate, LockedSource, NoSource, BadSemantics],
  PGSParseData: TYPE,
  OSMiscOps: TYPE USING [FindFile],
  Runtime USING [GetBcdTime, GetTableBase],
  Stream: TYPE USING [Delete, Handle],
  Strings: TYPE USING [String, AppendString],
  Time: TYPE USING [Append, Unpack],
  TTY: TYPE USING [Handle, PutChar],
  UserTerminal: TYPE USING [CursorArray, GetCursorPattern, SetCursorPattern];

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

 -- command interface

  tty: TTY.Handle;
  
  log: Stream.Handle ← NIL;
  commandStream: Stream.Handle ← NIL;
  CR: CHARACTER = CharIO.CR;

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

  zone: UNCOUNTED ZONE ← NIL;

  AcquireZone: PUBLIC PROC RETURNS [UNCOUNTED ZONE] = {
    RETURN [zone]};
    

-- parse table management

  tableSeg: LONG POINTER = Runtime.GetTableBase[LOOPHOLE[PGSParseData]];

  AcquireTable: PUBLIC PROC RETURNS [LONG POINTER] = {
    RETURN [tableSeg]};

  ReleaseTable: PUBLIC PROC = {};


 -- 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: BOOLEAN ← 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: BOOLEAN;
    herald: STRING ← [50];
    savedCursor: UserTerminal.CursorArray;
    commandObject: CommandUtil.CommandObject;
    commandLine: PACKED ARRAY [ 0.. 100) OF CHARACTER;
  
    zone ← Heap.Create[initial: 16, increment: 8];
    Strings.AppendString[to:herald, from:"Cedar 3.3 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];
    LogChar[CR]; LogString["Command: "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];

    LogChar[CR]; LogString["    "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[tty, command.data[i]] ENDLOOP};
  
  Exec.AddCommand["PGS.~"L, Main];
  
  }.