-- CorrectMwWl.mesa
-- Last modified November 2, 1979  5:08 PM by Taft

DIRECTORY
  ImageDefs: FROM "ImageDefs" USING [StopMesa],
  IODefs: FROM "IODefs",
  MiscDefs: FROM "MiscDefs" USING [CommandLineCFA],
  SegmentDefs: FROM "SegmentDefs",
  StreamDefs: FROM "StreamDefs",
  StringDefs: FROM "StringDefs";


CorrectMwWl: PROGRAM
  IMPORTS ImageDefs, IODefs, MiscDefs, SegmentDefs, StreamDefs, StringDefs =
  BEGIN OPEN IODefs, StreamDefs, StringDefs;

  Coordinate: TYPE = CARDINAL;  -- 25-mil units
  gridUnit: Coordinate = 2;  -- 50-mil grid
  inStream, outStream: StreamHandle;

  AdjustCoordinates: PROCEDURE [x, y: Coordinate]
    RETURNS [xNew, yNew: Coordinate, changed: BOOLEAN] =
    BEGIN
    -- Note that x is rounded up but y is rounded down!!
    xNew ← (x + gridUnit/2) - (x + gridUnit/2) MOD gridUnit;
    yNew ← (y + gridUnit/2 -1) - (y + gridUnit/2 -1) MOD gridUnit;
    changed ← xNew#x OR yNew#y;
    END;


  currentChar: CHARACTER ← NUL;

  ReadToken: PROCEDURE [s: STRING, copy: BOOLEAN] RETURNS [c: CHARACTER] =
    -- If the next token is a separator character, returns it.
    -- If it is an atom, copies it into s and returns NUL.
    -- Lets through the signal StreamError[inStream, StreamAccess] after
    -- the last token has been returned.
    -- Copies all characters to outStream iff copy is TRUE.
    BEGIN
    s.length ← 0;
    DO
      SELECT currentChar FROM
        NUL => NULL;
        SP =>
          IF s.length#0 THEN RETURN [NUL]
          ELSE IF copy THEN outStream.put[outStream, currentChar];
        '; =>
          BEGIN
          IF copy THEN outStream.put[outStream, currentChar];
          UNTIL currentChar=CR DO
            currentChar ← inStream.get[inStream !
              StreamError => IF error=StreamAccess THEN
                BEGIN currentChar ← CR; CONTINUE END];
            IF copy AND currentChar#CR THEN
              outStream.put[outStream, currentChar];
            ENDLOOP;
          LOOP;
          END;
        '<, '>, '{, '}, ',, CR =>
          BEGIN
          IF s.length=0 THEN
            BEGIN
            IF copy THEN outStream.put[outStream, currentChar];
            c ← currentChar; currentChar ← NUL;
            END
          ELSE c ← NUL;
          RETURN;
          END;
        ENDCASE =>
          BEGIN
          IF copy THEN outStream.put[outStream, currentChar];
          AppendChar[s, currentChar];
          END;
      currentChar ← inStream.get[inStream !
        StreamError => IF error=StreamAccess AND s.length#0 THEN
          BEGIN currentChar ← CR; CONTINUE END];
      ENDLOOP;
    END;


  ReportChangedCoordinates: PROCEDURE [
    netName, pinName: STRING, x, y, xNew, yNew: Coordinate] =
    BEGIN
    WriteCoordinates: PROCEDURE [x, y: Coordinate] =
      BEGIN
      WriteChar['{]; WriteNumber[x, [10, FALSE, FALSE, 3]];
      WriteChar[',]; WriteNumber[y, [10, FALSE, FALSE, 3]];
      WriteChar['}];
      END;
    WriteString[netName]; WriteChar[':];
    THROUGH [netName.length..20] DO WriteChar[' ] ENDLOOP;
    WriteString[pinName];
    THROUGH [pinName.length..10] DO WriteChar[' ] ENDLOOP;
    WriteCoordinates[x, y];
    WriteString["  =>  "L];
    WriteCoordinates[xNew, yNew];
    WriteChar[CR];
    END;


  MalformedWireList: SIGNAL = CODE;

  CorrectWireList: PROCEDURE =
    BEGIN
    ENABLE StreamError => IF error=StreamAccess THEN GOTO Done;
    netName: STRING = [100];
    pinName: STRING = [100];
    tempName: STRING = [100];
    token: CHARACTER;
    x, y, xNew, yNew: Coordinate;
    changed: BOOLEAN;

    UNTIL ReadToken[tempName, TRUE]=NUL AND
      EqualString[tempName, "@"L] DO NULL ENDLOOP;

    DO
      token ← ReadToken[netName, TRUE];
      IF token=CR THEN LOOP;
      IF token#NUL THEN SIGNAL MalformedWireList;
      IF netName[netName.length-1]#': THEN SIGNAL MalformedWireList;
      netName.length ← netName.length-1;
      UNTIL ReadToken[tempName, TRUE]=CR DO NULL ENDLOOP;

      DO
        token ← ReadToken[pinName, TRUE];
        IF token=CR THEN
          BEGIN token ← ReadToken[pinName, TRUE]; IF token=CR THEN EXIT END;
        IF token#NUL THEN SIGNAL MalformedWireList;
        UNTIL ReadToken[tempName, TRUE]='{ DO NULL ENDLOOP;
        IF ReadToken[tempName, FALSE]#NUL THEN SIGNAL MalformedWireList;
        x ← StringToDecimal[tempName];
        IF ReadToken[tempName, FALSE]#', THEN SIGNAL MalformedWireList;
        IF ReadToken[tempName, FALSE]#NUL THEN SIGNAL MalformedWireList;
        y ← StringToDecimal[tempName];
        [xNew, yNew, changed] ← AdjustCoordinates[x, y];
        IF changed THEN
          ReportChangedCoordinates[netName, pinName, x, y, xNew, yNew];
        OutNumber[outStream, xNew, [10, FALSE, FALSE, 0]];
        outStream.put[outStream, ',];
        OutNumber[outStream, yNew, [10, FALSE, FALSE, 0]];
        IF ReadToken[tempName, TRUE]#'} THEN SIGNAL MalformedWireList;
        ENDLOOP;
      ENDLOOP;
    EXITS
      Done => NULL;
    END;


  comStream: StreamHandle;

  BeginCommandScan: PROCEDURE =
    BEGIN
    comStream ← NewByteStream["Com.cm"L, Read];
    JumpToFA[comStream, @MiscDefs.CommandLineCFA[].fa];
    END;

  EndCommandScan: PROCEDURE =
    BEGIN
    GetFA[comStream, @MiscDefs.CommandLineCFA[].fa];
    comStream.destroy[comStream];
    END;

  GetCommandAtom: PROCEDURE [s, prompt: STRING] =
    BEGIN
    ENABLE StreamError => IF error=StreamAccess THEN
      BEGIN ENABLE Rubout => RETRY;
      WriteChar[CR]; WriteString[prompt];
      ReadID[s];
      GOTO Done;
      END;
    c: CHARACTER;
    s.length ← 0;
    DO
      c ← comStream.get[comStream];
      SELECT c FROM
        SP, TAB => IF s.length#0 THEN EXIT;
        CR => EXIT;
        ENDCASE => AppendChar[s, c];
      ENDLOOP;
    EXITS
      Done => NULL;
    END;


  ParseCommandLine: PROCEDURE =
    BEGIN
    inName: STRING = [50];
    outName: STRING = [50];
    i: CARDINAL;

    BeginCommandScan[];

      BEGIN ENABLE SegmentDefs.FileNameError => RETRY;
      GetCommandAtom[inName, "Input wire list file: "L];
      inStream ← NewByteStream[inName, Read];
      END;

    EndCommandScan[];

    FOR i DECREASING IN [0..inName.length) DO
      IF inName[i]='. THEN BEGIN inName.length ← i; EXIT END;
      ENDLOOP;
    AppendString[outName, inName];
    AppendString[outName, ".cwl"L];
    outStream ← NewByteStream[outName, Write+Append];
    outName.length ← 0;
    AppendString[outName, inName];
    AppendString[outName, ".log"L];
    logStream ← NewByteStream[outName, Write+Append];
    splitStream.put ← SplitPut;
    END;


  logStream, displayStream: StreamHandle;
  splitStreamObject: Other StreamObject;
  splitStream: POINTER TO Other StreamObject = @splitStreamObject;

  SplitPut: PROCEDURE [stream: StreamHandle, c: CHARACTER] =
    BEGIN
    logStream.put[logStream, c];
    displayStream.put[displayStream, c];
    END;

  -- Main body.

  ParseCommandLine[];
  displayStream ← GetOutputStream[];
  SetOutputStream[splitStream];
  CorrectWireList[];
  SetOutputStream[displayStream];
  inStream.destroy[inStream];
  outStream.destroy[outStream];
  logStream.destroy[logStream];
  ImageDefs.StopMesa[];

  END.