%include "SysInc:Command.inc"
%include "IBM:EBCDIC.inc"
%include "IBM:MTdefs.inc"

%begin
   %external %routine %spec to upper (%string(*)%name s)
   %external %predicate %spec end of input
   %external %integer %fn %spec StoI (%string(31) s)

   %const %integer true = 0,  false = 1

   %const %integer keys = 10
   %const %string(15) %array key(1:keys) =
      "ANALYSE",
      "READ",
      "WRITE",
      "WIDTH",
      "ISO",
      "LIMIT",
      "FILE",
      "BLOCK",
      "EBCDIC",
      "ISO"
   %switch S(1:3)

   %own %integer option = 0              {READ, WRITE, APPEND etc}
   %own %integer ISO tape = false        {Tape assumed EBCDIC by default}
   %own %integer width = 132             {Page width for dump output}
   %own %integer limit = 80              {Default bytes dumped/block by ANALYSE}
   %own %integer file no = 1             {Position within tape}
   %own %integer block size = 2048       {Default}
   %own %integer convert = false         {ISO:EBCDIC conversions?}
   %const %integer Stream err = 9        {IMP stream I/O error event no.}
   %const %integer Pack err = 10         {Invalid filename}
   %const %integer MT err = 13           {Error from IBM tapes package}
   %const %integer new option = 14       {DECODEPARM wants to change options}
   %const %integer TTY = 0               {IMP command/report stream no.}
   %routine %spec stop                   {Wind down tape & quit}

   %routine decode parm
      %string(63)%name p == command_parameter
      %string(63) x, val
      %integer j, k
      %switch C(0:keys)
      %if command_modifier = '?' {PTAPE?} %or p -> ("HELP") %start
         Print string ("*LAYOUT IBM:TAPES.LAY for information")
         Newline
         Stop
      %finish
      p = p . ","
      %while p -> x . (",") . p %cycle   {Peel off options}
         val = ""
         %if x -> x . ("=") . val %start; %finish
         k = 0
         %for j = 1,1,keys %cycle
            k = j %and %exit %if x = key(j)
         %repeat
         -> C(k)
         C(0): { unrecognised keyword }
               Print string (x)
               Print string ("=".val) %if val # ""
               Print symbol ('?');  newline
               %return

         C(1): {ANALYSE}
         C(2): {READ}
         C(3): {WRITE}
               %if option # 0 %start
                  Print string (key(option)." and ".x."?")
                  Newline
                  %signal new option
               %finish
               option = k
               %continue

         C(4): {WIDTH=characters}
               width = StoI(val)
               %continue

         C(5): {ISO}
               ISO tape = true
               %continue

         C(6): {LIMIT=n}
               limit = StoI(val)         {max no. of chars in block ANALYSE}
               %continue

         C(7): {FILE=n}
               file no = StoI(val)
               %continue

         C(8): {BLOCK=n}
               block size = StoI(val)
               %if block size < 18 %start
                  block size = 18
                  Print string ("*Block size set to 18 bytes (minimum)")
                  Newline
               %finish
               %continue

         C(9): {EBCDIC}
               convert = true
               %continue

         C(10):{ISO}
               convert = false
               %continue

      %repeat
   %end

   %routine get tape
      %cycle
         Claim tape
         %exit %if tape error = 0
         Release tape
         Print string ("*Warning: tape force-released")
         Newline
      %repeat
      Rewind
   %end

   %routine stop
      Rewind
      Release tape
      %stop
   %end

   %routine find (%integer f)
      {F is a file number.  FILE NO (global) is the file no. we
      {are currently at within the tape (one at beginning of tape).
      {Physical files are separated by tape marks. 
      %byte %array junk(1:20)
      %if f <= 1 %start
         Rewind
         file no = 1
         %return
      %finish
      %while file no < f %cycle
         skip forward
         file no = file no + 1
      %repeat
      %while file no > f %cycle
         skip reverse                    {back past last TM}
         skip reverse                    {back over prev file}
         read tape (addr(junk(1)),20)    {move over TM at start of file}
         file no = file no - 1
      %repeat
   %end

   {********* Main Program *********}

   %on %event MT err, stream err, new option %start
      %if event_event = stream err %start
         Stop
      %finish
      %if event_event = MT err %start
         Print string ("**Magtape error ")
         Write (tape error,1)
         stop
      %finish
      -> S(option)
   %finish

   Prompt ("Parm: ")
   Decode parm %if command_parameter # ""
   %while option = 0 %cycle
      Read (command_parameter)
      To upper (command_parameter)
      Decode parm
   %repeat
   -> S(option)

S(1): {*********** ANALYSE ***********}

      %begin
         %external %routine %spec TEMP LIBRARY (%string(31) filename)
         %external %routine %spec DUMP BLOCK   %c
            (%name from, %integer bytes, page width, flags)
         %const %integer {FLAGS masks} %c
            Hex = 1<<1, ASCII = 1<<3, EBCDIC = 1<<6
         %const %integer max block = 8000
         %byte %array B(1:max block)
         %integer after TM = true        {Frig to force dump of block #1}
         %integer number, size           {Count up groups of blocks}
         %integer j, flags

         %routine show (%integer number, size)
            %if number # 0 %start
               Write (number,4)
               Print string (" block")
               Print symbol ('s') %unless number = 1
               Print string (" of")
               Write (size,1)
               Print string (" bytes")
               Newline
            %finish
         %end

         Temp library ("IBM:DUMPER")
         Get tape
         number = 0;  size = 0
         %cycle
            Read tape (addr(B(1)),max block)
            %if bytes transferred # size %start   {New group}
               Show (number, size)
               size = bytes transferred
               number = 0
            %finish
            number = number + 1
            %signal MT err %if tape error&(~128) # 0   {mask out TM flag}
            %if TM # 0 %start
               number = 0                {suppress SHOW for tapemarks}
               Print string ("Tape mark")
               Newline
               %exit %if after TM = true {two consecutive tapemarks?}
               after TM = true
            %else
               %if after TM = true %or command_modifier = '!' %start
                  j = bytes transferred
                  j = limit %if j > limit
                  flags = hex+ASCII
                  flags = flags+EBCDIC %if convert = true
                  Dump block (B(1), j, width, flags)
               %finish
               after TM = false
            %finish
         %repeat
         Show (number,size)
         Stop
      %end

S(2): {************* READ *************}

      %begin
         %const %integer max block = 8000
         %byte %array B(1:max block)
         %integer failed, j
         %string(31) file
         Get tape
         Prompt ("File: ")
         %cycle
            Read (file)
            To upper (file)
            %if char no(file,1) = '*' %start
               file = sub string(file,2,length(file))
               Stop %if file = ""
               command_parameter = file
               Decode parm
               %continue
            %finish
            %begin
               %on * %start
                  Print string ("*".event_message)
                  Newline
                  failed = true
                  %return
               %finish
               Open output (3,file)
               failed = false
            %end
            Find (file no)
            Select output (3)
            %cycle
               Read tape (addr(B(1)), max block)
               To ISO (bytes transferred,B(1)) %if convert = true
               %exit %if TM # 0
               Print symbol (B(j)) %for j = 1,1,bytes transferred
            %repeat
            Close output
            file no = file no + 1
         %repeat
      %end

S(3): {************** WRITE ***************}

      %begin
         %const %integer max block = 8000
         %byte %array B(1:max block)
         %integer len, j
         %string(31) file
         %integer {Bool} failed = false
         %integer eof
         Get tape
         %cycle
            Prompt ("File: ")
            Select input (tty)
            Read (file)
            To upper (file)
            %if char no(file,1) = '*' %start
               file = sub string(file,2,length(file))
               %exit %if file = ""
               Decode parm
               %continue
            %finish
            Find (file no)
            Tape mark;  backspace        {For grotty tape hardware}
            %begin
               %on * %start
                  Print string ("*".event_message)
                  Newline
                  failed = true
                  %return
               %finish
               Open input (3,file)
               failed = false
            %end
            %continue %if failed = true
            Prompt ("Text: ")
            Select input (3)
            %cycle
               B(j) = 0 %for j = 1,1,18  {Min tape block is 18: padded with 0's}
               eof = false
               %begin                    {Read up to one tape block from file}
                  %integer j
                  %on stream err %start {end of file?}
                     eof = true
                     %return
                  %finish
                  %for j = 1,1,block size %cycle
                     Read symbol (B(j))
                     len = j
                  %repeat
               %end
               len = 18 %if len < 18
               To EBCDIC (len,B(1)) %if convert = true
               Write tape (addr(B(1)),len)
            %repeat %until eof = true
            Tape mark;  tape mark        {**eot**}
            Backspace                    {next file overwrites last mark}
            file no = file no + 1
         %repeat
      %end

%end %of %program
