    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