begin;  !DECODE for CalComp plot files.  A.D. Culloch, Fela AG, Schweiz, JUN-83
   string(2) fn spec Xbyte ( integer X )

   !Imp77 event numbers
   constant integer Imp IO Error = 9

   constant integer Report Stream = 0;  !SYS$OUTPUT
   constant integer Decode Stream = 1;  !Main output: decoded file
   constant integer ListingStream = 2;  !Listing output channel #2, (hex dump)

   !Plotter switch-settable parameters
   constant integer Sync Chars = 1;     !Valid values are 1 or 2
   constant integer Sync Char  = 2;     !ISO code for sync character = <2>
   constant integer End Msg Char = 3;   !ISO

   !Other plotter parameters
   integer Radix = 64

   !Global data buffer
   byte array Buffer(1:128)
   !and control information
   integer Bias;                        !Character code offset for this buffer
   integer Bp = 0, Blen = 0;            !Initially empty
   integer Record Number = 0;           !Counts input data records

   integer Col

   routine Report ( string(255) Mess )
      integer Prev = Out Stream;        !Current output stream number
      Select Output ( Report Stream )
      Print String ( "At data record ".ItoS(Record Number,0).": ")
      Print Symbol ( '<' )
      Print String ( Mess )
      Print Symbol ( '>' )
      Newline
      Select Output (Prev)
   end

   routine Refill Buffer
      integer Sym
      on Imp IO Error start
         stop
      finish
Sync: !Skip junk, past the sync sequence
      while Next Symbol # Sync Char cycle
         Print Symbol(Next Symbol)
         Skip Symbol
      repeat
      Skip Symbol
      if Sync Chars = 2 start
         if Next Symbol # Sync Char start
            Print Symbol(Next Symbol)
            Report("Missing second sync char")
            ->Sync
         finish
         Skip Symbol
      finish
      Record Number = Record Number + 1
      Read Symbol (Bias)
      unless Bias > End Msg Char start
         Report("Bias <".ItoS(Bias,0)."> leq end message char")
      finish
      !Read message proper
      Blen = 0
      cycle
         Read Symbol(Sym)
         exit if Sym = End Msg Char
         Blen = Blen + 1
         if Blen <= 128 start
            Buffer(Blen) = Sym
         finish
      repeat
      !For the moment, ignore things like the response request sequence
      !Reset control pointers describing the buffer
      Bp = 0
      Col = 1;  Newline
   end

   routine Get Unbiased Symbol ( integer name Sym )
      own integer Old
      Bp = Bp + 1
      if Bp > Blen start;               !Buffer exhausted
         Refill Buffer
         Get Unbiased Symbol(Sym)
      else;                             !Extract next character
         Sym = Buffer(Bp)
         Old = Out Stream
         Select Output(Listing Stream)
         Print String(Xbyte(Sym))
         Space
         Newline and Col = 0 if Col = 20
         Col = Col + 1
         Select Output(Old)
      finish
   end

   routine Get Symbol ( integer name Sym );      !Biased
      Get Unbiased Symbol (Sym)
      Sym = Sym-Bias
   end

   routine Parse String ( string(*) name S )
      integer Len, Sym, j
      Get Symbol(Len)
      S = ""
      for j = 1, 1, Len cycle
         Get Unbiased Symbol(Sym)
         S = S . To String(Sym)
      repeat
   end

   routine Parse Split String ( string(*) name S )
      integer Len, Sym1, Sym2, j
      Get Symbol(Len)
      S = ""
      for j = 1, 1, Len cycle
         Get Symbol(Sym1);  Get Symbol(Sym2)
         S = S . To String((Sym1&16_f)<<4 ! Sym2&16_f)
      repeat
   end

   integer function Sign ( integer I )
      if I < 0 start
         result = -1
      else if I = 0
         result = 0
      else
         result = +1
      finish
   end

   routine Parse Delta ( integer Delta Code, integer name X, Y )
      constant integer Delta Codes = 49
      constant byte array Delta(0:Delta Codes-1) =
         8_21, 8_51, 8_55, 8_34, 8_54, 8_50, 8_20,
         8_61, 8_25, 8_71, 8_40, 8_70, 8_24, 8_60,
         8_65, 8_75, 8_31, 8_44, 8_30, 8_74, 8_64,
         8_35, 8_41, 8_45,  0,   8_46, 8_42, 8_36,
         8_67, 8_77, 8_33, 8_47, 8_32, 8_76, 8_66,
         8_63, 8_27, 8_73, 8_43, 8_72, 8_26, 8_62,
         8_23, 8_53, 8_57, 8_37, 8_56, 8_52, 8_22
      integer j, Xdig, Ydig, Xsign, Ysign, k, Sym
      for j = 0, 1, Delta Codes-1 cycle
         if Delta Code = Delta(j) start
            Ydig  = - ( j//7-3 )
            Xdig  = Rem(j,7)-3
            Xsign = Sign(Xdig)
            Ysign = Sign(Ydig)
            X     = 0
            Y     = 0
            for k = 1, 1, |Xdig| cycle
               Get Symbol(Sym)
               X = Radix*X + Sym
            repeat
            for k = 1, 1, |Ydig| cycle
               Get Symbol(Sym)
               Y = Radix*Y + Sym
            repeat
            Report("Delta > 32767") if X > 32767 or Y > 32767
            X = Xsign*X
            Y = Ysign*Y
            return
         finish
      repeat
      Report("illegal delta-command")
   end

   routine Print Filtered String ( string(255) S )
      integer j
      for j = 1, 1, Length(S) cycle
         if ' ' <= Char No(S,j) < 127 start
            Print Symbol(Char No(S,j))
         else
            Print String("<".ItoS(Char No(S,j),0).">")
         finish
      repeat
   end

   routine Print Quoted String ( string(255) S )
      Print Symbol('"')
      Print Filtered String(S)
      Print Symbol('"')
   end

   routine Print Delta ( integer X, Y )
      Print Symbol('(')
      Write(X,0)
      Print Symbol(',')
      Write(Y,0)
      Print Symbol(')')
   end

   string(2) fn Xbyte ( integer Byte )
      constant byte array Hex Char(0 : 16_F) =
         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
         'a', 'b', 'c', 'd', 'e', 'f'
      result = To String(Hex Char(Byte>>4 & 16_F)) . c
                To String(Hex Char(Byte    & 16_F))
   end

   routine Parse Escape Sequence
      constant integer Commands = 9
      constant string(31) array Command Text(0:Commands) =
         "noDoubleBuffer",
         "doubleBuffer",
         "suffixLength",
         "turnaround",
         "goodResponse",
         "badResponse",
         "reqSeq",
         "maxWait",
         "wait",
         "disDel"
      switch  C(1:Commands)
      integer Command, Sym, j
      string(255) S

      Get Symbol(Command)
      unless 0 <= Command <= Commands start
         Report("*Fatal error: Undefined escape command: 16_".Xbyte(Command))
         stop
      finish
      Space
      Print String(Command Text(Command))
      Print Symbol('[')

      -> C(Command)

      C(2):   !suffixLength
      C(3):   !turnaround
      C(7):   !maxWait
              Get Symbol(Sym)
              Write(Sym, 0)
              ->L
              
      C(4):   !goodResponse
      C(5):   !badResponse
      C(6):   !reqSeq
      C(8):   !wait
              Parse Split String (S)
              Print Quoted String(S)
              ->L

      C(*):   !no parameters

L:    Print Symbol(']')
   end

   constant integer Commands = 16_f

   routine Parse Parameters ( integer Command )
      switch C(0:Commands)
      integer Sym, j, k, x, y
      string(255) S

      ->C(Command)

      C(*):   !Default, no parameters
              return

      C(1):   !searchAddress
              x = 0
              for j = 1, 1, 3 cycle
                 Get Symbol(k)
                 x = Radix*x + k
              repeat
              Write(x, 0)
              return

      C(4):   !penSelect
      C(7):   !defineRadix
      C(9):   !scale
              Get Symbol(j)
              Write(j,0);               !pen number
              Radix = j if Command = 7
              return

      C(5):   !symbolString
              Parse String(S)
              Print Quoted String(S)
              return

      C(6):   !symbolScale
              Get Symbol(Sym)
              Parse Delta(Sym, X, Y)
              Print Delta(X, Y)
              return

      C(8):   !escape
              Parse Escape Sequence
              return

      C(16_b):!passThru
              Print String("<16_")
              Get Symbol(j);  Get Symbol(k)
              Print String(Xbyte(j&16_f<<4 ! k&16_f).">")
              return

      C(16_c):!circle
              Get Symbol(j)
              unless 0 <= j <= 3 start
                 Report("Invalid circle subcode 16_".Xbyte(j))
                 stop
              finish
              for j = 1, 1, 2 cycle;       !Start-point, end-point
                 Get Symbol(Sym)
                 Parse Delta(Sym, X, Y)
                 Print Delta(X, Y)
              repeat
              return

      C(16_d):!dash
              Get Symbol(j)
              if j = 0 start
                 Print String("on")
              else if j = 1
                 Print String("off (solid)")
              else
                 Report("More than 16 dash line segments") if j > 16
                 Print Symbol('[')
                 for k = 1, 1, j cycle
                    Get Symbol(Sym)
                    Parse Delta(Sym, X, Y)
                    Print Delta(X, Y)
                 repeat
                 Print Symbol(']')
                 if j&1 # 0 and Y # 0 {in last delta} start
                    Report("Logic error in last dash delta")
                    stop
                 finish
              finish
              return

      C(16_e):!operMsg
              Get Symbol(Sym)
              if 0 <= Sym <= 5 start
                 Print String("plotSymbol 16_")
                 Get Symbol(j)
                 Print String(Xbyte(Sym<<4 ! j))
                 unless 0 <= j <= 15 start
                    Report("invalid plotSymbol subcommand")
                    stop
                 finish
              else if 6 <= Sym <= 7
                 Parse String(S)
                 Print Quoted String(S)
              else if 8 <= Sym <= 16_c
                 Print String("selectSymbolSet")
                 Write(Sym-8, 1)
              else if Sym = 16_d
                 Print String("defineUserSymbol 16_")
                 Get Symbol(Sym)
                 Get Symbol(j)
                 Print String(Xbyte(Sym<<4 ! j))
                 Get Symbol(j);   !offset-pair count
                 for k = 1, 1, j cycle
                    Get Symbol(X);  Get Symbol(Y)
                    Print Delta(X, Y)
                 repeat
              else if Sym = 16_e
                 Print String("erase")
              else if Sym = 16_f
                 Print String("plotAnySym 16_")
                 Get Symbol(Sym);  Get Symbol(j)
                 Print String(Xbyte(Sym<<4 ! j))
              else
                 Report("Invalid subcode 16_".Xbyte(Sym))
                 stop
              finish
              return

   end

   constant string(31) array Command(0:Commands) =
      "noOp",
      "searchAddress",
      "penDown",
      "penUp",
      "penSelect",
      "symbolString",
      "symbolScale",
      "defineRadix",
      "escape",
      "scale",
      "pause",
      "passThru",
      "circle",
      "dash",
      "operMsg",
      "endOfPlot"

   integer j, k, x, y
   integer Sym;                         !Current input byte
   open input (1, cliparam)
   Select Output(Decode Stream)
   cycle;                               !Main loop: process command bytes
      Get Symbol(Sym);                  !Bias has already been removed.
      continue if Sym = 0;              !Completely ignore noops
      unless 16_0 <= Sym <= 16_3f start
         Report("*Fatal error: undefined command code: 16_".Xbyte(Sym))
         stop
      finish
      if Sym > 16_f start;              !Delta Command
         Print String("delta ")
         Parse Delta(Sym, X, Y)
         Print Delta(X, Y)
      else
         Print String(Command(Sym))
         Print Symbol('(');             !Followed by command parameters
         Parse Parameters(Sym)
         Print Symbol(')')
      finish
      Newline
   repeat
endofprogram