home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c / ucjlm2.txt < prev    next >
Text File  |  2020-01-01  |  115KB  |  4,093 lines

  1. (* This file is the concatenated source for Kermit for the Joyce-Loebl Magiscan
  2.    image processor, running UCSD p-System. Before compiling you will need to
  3.    split the file at the clearly marked points, saving each section into a
  4.    TEXT file of the appropriate name *)
  5.  
  6.  
  7. **** File DISK.TEXT ************************************************************
  8. (*$S+*)
  9.  
  10. { This Unit is based on the SLVDIMS of Joyce Loebl }
  11. { Created by H Balen 22-Aug-84 }
  12. { Modified by H Balen 13-May-85 }
  13.  
  14. Unit DiskUnit;
  15.  
  16.    Interface
  17.    
  18.    
  19.    Uses
  20.       M2Types,M2IpRoot,M2Sys;
  21.       
  22.    type
  23.      GreyVal = 0..255;
  24.      LType = packed array[0..255] of GreyVal;
  25.      L2Type = packed array[0..255] of char;
  26.      LineType = record
  27.                   case Boolean of
  28.                     True :(i : LType);
  29.                     False:(b : L2Type)
  30.                     end;
  31.      BufferType = record
  32.                    case integer of
  33.                     0 :(i : packed array[0..511] of GreyVal);
  34.                     1 :(b : packed array[0..1] of L2Type);
  35.                     2 :(Im : Image )
  36.                     end;
  37.    var
  38.      Fl : File;
  39.      
  40.    procedure ImSve( Im : Image;
  41.                      FName : String );
  42.    procedure ImLd( var Im : Image;
  43.                      FName  : String );
  44.  
  45. Implementation
  46.  
  47. procedure ImSve;
  48. { This procedure saves an image, up to eight bits }
  49.  
  50. var
  51.    Line  : LineType;
  52.    Buffer: BufferType;
  53.    A,B,C,D : Image;
  54.    Blk   : integer;
  55.  
  56.  
  57. procedure Deposit( Im : Image );
  58. { This procedure writes the necessary data to the disk
  59.   in units of 512 bytes,and Images of Half size       }
  60.  
  61. var
  62.   Blks,RowNum : Integer;
  63.   Row    : PointSet;
  64.   
  65.   procedure GetLine( LinePs : PointSet;
  66.                      Im     : Image ;
  67.                     var GVal: LType );
  68.   { This procedure gets a 256 byte line from the picture }
  69.   
  70.   type
  71.      Idynarray = array[1..1]of Integer;
  72.   
  73.   var
  74.      Mrk : ^Integer;
  75.      Idyn: ^Idynarray;
  76.      i   : integer;
  77.   
  78.   begin
  79.   { Mark the Heap, and create space }
  80.   mark(Mrk);
  81.   New(Idyn);
  82.   { Sample the image over the pointset and collect data }
  83.   ImSmp(LinePs,Im,Idyn^[0],i);
  84.   { Transfer the sampled data to the array for returning }
  85.   for i := 0 to 255 do
  86.      GVal[i] := Idyn^[i];
  87.   { Clear the heap }
  88.   Release(Mrk)
  89.   end{ GetLine };
  90.  
  91. begin
  92. { Define a pointset for sampling purposes }
  93. DefWindow(Row,0,0,256,1);
  94. { Get the necessary part of the image and save it }
  95. for RowNum := 0 to 255 do
  96.    begin
  97.    { Move pointset to current sample line }
  98.    Row.Origin.Y := RowNum;
  99.    { Sample the current line / collect the Data Values }
  100.    GetLine(Row,Im,Line.i);
  101.    if Odd(RowNum) then
  102.      begin{ Write to the Disk }
  103.      { Copy to buffer }
  104.      Buffer.b[1] := Line.b;
  105.      { Actual write to disk }
  106.      Blks := BlockWrite(Fl,Buffer.i,1)
  107.      end
  108.     else{ Still to fill the Buffer }
  109.       Buffer.b[0] := Line.b
  110.    end
  111. end{ Deposit };
  112.  
  113. begin{ Save }
  114. { Open the file }
  115. Rewrite(Fl,FName);
  116. { Collect the attributes of the image }
  117. Buffer.Im := Im;
  118. { Put image attributes at the beginning of the file }
  119. Blk := BlockWrite(Fl,Buffer.Im,1);
  120. { Deal with necessary image size }
  121. case Im.Res of
  122.    Half: Deposit(Im);
  123.    Full: begin
  124.          with Im do
  125.            begin
  126.            { Split the image into 4 Half size images }
  127.            DefImage(A,Origin.X,Origin.Y,Half,LsBit,NoBits);
  128.            DefImage(B,Origin.X+256,Origin.Y,Half,LsBit,NoBits);
  129.            DefImage(C,Origin.X+256,Origin.Y+256,Half,LsBit,NoBits);
  130.            DefImage(D,Origin.X,Origin.Y+256,Half,LsBit,NoBits);
  131.            { Save the image on disk }
  132.            Deposit(A);
  133.            Deposit(B);
  134.            Deposit(C);
  135.            Deposit(D)
  136.            end{ with }
  137.          end
  138.    end{ Case };
  139. { Close the file }
  140. Close(Fl,Lock)
  141. end{ Save };
  142.  
  143.  
  144. procedure ImLd;
  145. { This procedure ReLoads a previously saved image }
  146.  
  147. var
  148.    Buffer : BufferType;
  149.    Line   : LineType;
  150.    A,B,C,D: Image;
  151.    L,N,Blk: Integer;
  152.    Error  : Boolean;
  153.  
  154.  
  155. procedure ReDraw( var Im : Image );
  156. { This procedure draws a Half size image on the screen }
  157.  
  158. var
  159.   RowNum,Blks : integer;
  160.   Row    : PointSet;
  161.   
  162.   
  163.   procedure PutRow( LinePs : PointSet;
  164.                    var Im  : Image;
  165.                    var GVal: LType );
  166.   { This procedure gets the current row and draws it }
  167.   
  168.   type
  169.     Idynarray = array[1..1] of integer;
  170.   
  171.   var
  172.     Mrk : ^integer;
  173.     Idyn: ^Idynarray;
  174.     i   : integer;
  175.   
  176.   begin
  177.   { Mark Heap and make room }
  178.   mark(Mrk);
  179.   New(Idyn);
  180.   { Get the current line }
  181.   for i := 0 to 255 do
  182.     Idyn^[i] := GVal[i];
  183.   { Draw the line }
  184.   DrawFn(LinePs,Im,Idyn^[0]);
  185.   { Tidy the Heap }
  186.   release(Mrk)
  187.   end{ PutRow };
  188.  
  189.  
  190. begin
  191. { Define a PointSet for the current line }
  192. DefWindow(Row,0,0,256,1);
  193. { Draw the Half image to screen }
  194. for RowNum := 0 to 255 do
  195.   begin
  196.   { Move the PointSet to the current Line position }
  197.   Row.Origin.Y := RowNum;
  198.   if Odd(RowNum) then
  199.     begin{ Read the Buffer }
  200.     Line.b := Buffer.b[1];
  201.     { and put on screen }
  202.     PutRow(Row,Im,Line.i)
  203.     end
  204.    else
  205.      begin{ Fill the Buffer from the Disk }
  206.      Blks := BlockRead(Fl,Buffer.i,1);
  207.      { Then read it and put on screen }
  208.      Line.b := Buffer.b[0];
  209.      PutRow(Row,Im,Line.i)
  210.      end
  211.   end
  212. end{ ReDraw };
  213.  
  214. begin
  215. { Take care of possible file name fault }
  216. (*$I-*)
  217. Reset(Fl,FName);
  218. Error := IOResult <> 0;
  219. (*$I+*)
  220. { If we have the correct file then }
  221. if not Error then
  222.   begin{ Get the details of the stored image }
  223.   Blk := BlockRead(Fl,Buffer.Im,1);
  224.   { If the stored image does not match the declared image }
  225.   if (Buffer.Im.Res <> Im.Res) then{ error }
  226.     writeln(' ReLoad : Image Resolution incompatible ')
  227.    else{ Everything ok }
  228.     begin
  229.     { Take care of image size }
  230.     case Im.Res of
  231.      Half: ReDraw(Im);
  232.      Full: begin
  233.            with Im do
  234.             begin
  235.             { Split image into 4 Half size images }
  236.             L := LsBit;N := NoBits;
  237.             DefImage(A,Origin.X,Origin.Y,Half,L,N);
  238.             DefImage(B,Origin.X+256,Origin.Y,Half,L,N);
  239.             DefImage(C,Origin.X+256,Origin.Y+256,Half,L,N);
  240.             DefImage(D,Origin.X,Origin.Y+256,Half,L,N);
  241.             { Get each image and draw it }
  242.             ReDraw(A);
  243.             ReDraw(B);
  244.             ReDraw(C);
  245.             ReDraw(D);
  246.             end{ With };
  247.            end;
  248.      end{ Case }
  249.     end;
  250.    Close(Fl)
  251.    end{ Not Error }
  252.   else{ Error in file name }
  253.     writeln(' ReLoad : Image file open error ')
  254. end{ ReLoad };
  255.  
  256.  
  257.  
  258. end{ Save }.
  259.  
  260. **** File FILEUNIT.TEXT ********************************************************
  261.  
  262. (*$S+*)
  263. { This unit contains the primitives necessary to store
  264.   the incoming data on the disk specified }
  265.   
  266. Unit FileHandle;
  267.  
  268. Interface
  269.  
  270.    Uses
  271.      M2Types,M2IpRoot,M2Sys,
  272.      (*$U Disk.Code*)DiskUnit;
  273.    
  274.    
  275.    const
  276.      BufEnd = 512;
  277.    
  278.    type
  279.      BuffType = packed array[1..BufEnd] of char;
  280.      FStates  = (TxtFile,BinFile,ImgFile,CodeFile); { File States }
  281.    
  282.    var
  283.      FileBuf    : BuffType;
  284.      BuffPosn   : integer;
  285.      Disk       : String[3];
  286.      TF         : Text;
  287.      F          : File;
  288.      TranState  : FStates;
  289.      EOI        : boolean; { End of Image ! }
  290.  
  291.    
  292.    
  293.    procedure FileInit;
  294.    
  295.    procedure CloseF(var Name   : string;
  296.                         Save   : boolean );
  297.    
  298.    function ReadOpenF(var Name     : string ;
  299.                           State    : FStates ): boolean;
  300.    
  301.    function WriteOpenF(var Name     : string ;
  302.                            State    : FStates ): boolean;
  303.    
  304.    procedure SaveBuff(var Buff : BuffType;
  305.                       var Posn : integer;
  306.                        NewLine : boolean  );
  307.    
  308.    procedure ReadBuff(var Buff : BuffType;
  309.                       var Posn : integer );
  310.  
  311.    procedure LoadIm(var Name : string );
  312.  
  313.  
  314.  
  315. Implementation
  316.  
  317. var
  318.   Im,TxtIm       : Image;
  319.   Tab            : IOTab;
  320.   Line           : PointSet;
  321.   YPosn          : integer;
  322.  
  323. (* ---------------------------------------------------- *)
  324.  
  325. procedure GetLine(var Line   : PointSet;
  326.                       Im     : Image;
  327.                   var Buff   : BuffType );
  328.  
  329. type
  330.   IdynArray = array[1..1]of Integer;
  331.  
  332. var
  333.   Mrk     : ^integer;
  334.   Idyn    : ^IdynArray;
  335.   i       : integer;
  336.  
  337. begin
  338. mark(Mrk);
  339. New(Idyn);
  340. ImSmp(Line,Im,Idyn^[0],i);
  341. for i := 0 to 511 do
  342.   Buff[i+1] := chr(Idyn^[i]);
  343. Release(Mrk)
  344. end{GetLine};
  345.  
  346. (* ---------------------------------------------------- *)
  347.  
  348. procedure PutLine(var Line   : PointSet;
  349.                       Im     : image;
  350.                   var Buff   : BuffType );
  351.  
  352. type
  353.   IdynArray = array[1..1]of Integer;
  354.  
  355. var
  356.   Mrk     : ^integer;
  357.   Idyn    : ^IdynArray;
  358.   i       : integer;
  359.  
  360. begin
  361. mark(Mrk);
  362. New(Idyn);
  363. for i := 1 to BufEnd do
  364.   Idyn^[i-1] := ord(Buff[i]);
  365. DrawFn(Line,Im,Idyn^[0]);
  366. Release(Mrk)
  367. end{PutLine};
  368.  
  369. (* ---------------------------------------------------- *)
  370.  
  371. procedure InitF;
  372.  
  373. begin
  374. SysInit;
  375. DefImage(Im,0,512,Full,8,8);
  376. DefImage(TxtIm,0,512,Full,0,1);
  377. DefWindow(Line,0,512,512,1);
  378. LinearIO(Tab,0,255);
  379. Live(Im,Tab,Tab);
  380. Photo;
  381. Display(Im,Tab);
  382. ClearIm(Im);
  383. OvLay(TxtIm,XSat+Yellow);
  384. YPosn := 511;
  385. EOI := TranState <> ImgFile
  386. end{InitF};
  387.  
  388. (* ---------------------------------------------------- *)
  389.  
  390. procedure LoadIm;
  391.  
  392. var
  393.   Ok   : boolean;
  394.  
  395. begin
  396. if TranState = ImgFile then
  397.   begin
  398.   InitF;
  399.   (*$I-*)
  400.   Reset(F,concat(disk,name));
  401.   Ok := ioresult = 0;
  402.   (*$I+*)
  403.   write(chr(ff));
  404.   if Ok then
  405.     begin
  406.     writeln('LOADING THE IMAGE');
  407.     ImLd(Im,concat(disk,name))
  408.     end
  409.    else
  410.      begin
  411.      writeln('FILE DOES NOT EXIST');
  412.      CursorOn;
  413.      ScrollOn
  414.      end
  415.   end
  416.  else
  417.    writeln('Transfer type is not IMAGE')
  418. end{LoadIm};
  419.  
  420. (* ---------------------------------------------------- *)
  421.  
  422. procedure EmptyBuff(var FileBuffer : BuffType;
  423.                     var Posn       : integer );
  424. { This procedure Empties the buffer }
  425.  
  426. var
  427.   i   : integer;
  428.  
  429. begin
  430. for i := 1 to BufEnd do
  431.   FileBuffer[i] := chr(0); { set all to nulls }
  432. Posn := 1 { set the position at the begining }
  433. end{EmptyBuff};
  434.  
  435. (* ---------------------------------------------------- *)
  436.  
  437. procedure FileInit;
  438. { This procedure initialises the unit,
  439.   the disk is set up in the main program }
  440.  
  441. begin
  442. EmptyBuff(FileBuf,BuffPosn);
  443. TranState := TxtFile;
  444. EOI := TranState <> ImgFile
  445. end{fInit};
  446.  
  447. (* ---------------------------------------------------- *)
  448.  
  449. procedure CloseF;
  450. { This procedure closes the file, neatly. }
  451.  
  452. var
  453.   Blk,i  : integer;
  454.   s      : string;
  455.   Key    : char;
  456.  
  457. begin
  458. if Save then
  459.   begin { we wish to save the file }
  460.   case TranState of
  461.     TxtFile          : begin
  462.                        s := copy('',0,0);
  463.                        if (BuffPosn <= BufEnd) and (BuffPosn > 1) then
  464.                          begin
  465.                          for i := 1 to pred(BuffPosn) do
  466.                           begin
  467.                           s := concat(s,' ');
  468.                           s[Length(s)] := FileBuf[i]
  469.                           end;
  470.                          write(TF,s);
  471.                          end;
  472.                        Close(TF,Lock)
  473.                        end;
  474.     ImgFile          : begin
  475.                        if (BuffPosn > 1) and (YPosn >= 0) then
  476.                          begin
  477.                          Line.Origin.Y := YPosn;
  478.                          PutLine(Line,Im,FileBuf)
  479.                          end;
  480.                        EOI := True;
  481.                        write('DO YOU WISH TO SAVE THE IMAGE ? ');
  482.                        repeat
  483.                          read(KeyBoard,Key)
  484.                        until Key in ['Y','y','N','n'];
  485.                        if Key in ['Y','y'] then
  486.                          ImSve(Im,concat(disk,name))
  487.                        end;
  488.     CodeFile,BinFile : begin
  489.                        if BuffPosn > 1 then
  490.                          Blk := BlockWrite(F,FileBuf,1);
  491.                        Close(F,Lock);
  492.                        end
  493.     end{case};
  494.   EmptyBuff(FileBuf,BuffPosn)
  495.   end
  496.  else
  497.    begin { This makes sure the file will be closed }
  498.    close(TF);
  499.    close(F)
  500.    end;
  501. CursorOn;
  502. ScrollON
  503. end{CloseF};
  504.  
  505. (* ---------------------------------------------------- *)
  506.  
  507. function ReadOpenF;
  508. { This procedure opens the file for reading }
  509.  
  510. var
  511.   OK  : boolean;
  512.   Blk : integer;
  513.   
  514. begin
  515. EmptyBuff(FileBuf,BuffPosn);
  516. EOI := TranState <> ImgFile;
  517. if TranState <> ImgFile then
  518.   begin
  519.   (*$I-*)
  520.   reset(F,concat(disk,name));
  521.   OK := ioresult = 0;
  522.   (*$I+*)
  523.   if (State = TxtFile) then
  524.     begin
  525.     Blk := BlockRead(F,FileBuf,1);
  526.     Blk := BlockRead(F,FileBuf,1)
  527.     end
  528.   end
  529.  else
  530.    begin{ this is an image file }
  531.    OK := True;
  532.    end;
  533. ReadOpenF := OK
  534. end{OpenF};
  535.  
  536. (* ---------------------------------------------------- *)
  537.  
  538. function WriteOpenF;
  539. { This procedure opens the file for writing }
  540.  
  541. var
  542.   OK  : boolean;
  543.   Blk : integer;
  544.   
  545. begin
  546. EmptyBuff(FileBuf,BuffPosn);
  547. (*$I-*)
  548. if TranState <> TxtFile then
  549.   begin
  550.   if TranState = ImgFile then
  551.     begin
  552.     write(chr(ff));
  553.     InitF;
  554.     ClearIm(Im);
  555.     OK := True
  556.     end
  557.    else
  558.      begin
  559.      rewrite(F,concat(disk,name));
  560.      OK := ioresult = 0
  561.      end
  562.   end
  563.  else
  564.    begin
  565.    ReWrite(TF,concat(disk,name));
  566.    OK := ioresult = 0
  567.    end;
  568. (*$I+*)
  569. WriteOpenF := OK
  570. end{OpenF};
  571.  
  572. (* ---------------------------------------------------- *)
  573.  
  574. procedure SaveBuff;
  575. { This procedure empties the buffer into the current file }
  576.  
  577. var
  578.   Blk,i : integer;
  579.   s     : string;
  580.  
  581. begin
  582. { If it is a text file then }
  583. if TranState = TxtFile then
  584.   begin{ Insert a string ! }
  585.   s := copy('',0,0);
  586.   for i := 1 to pred(Posn) do
  587.     begin
  588.     s := concat(s,' ');
  589.     s[Length(s)] := Buff[i]
  590.     end;
  591.   if NewLine then
  592.     begin
  593.     if Length(s) = 0 then
  594.       writeln(TF)
  595.      else
  596.        writeln(TF,s)
  597.     end
  598.    else
  599.      write(TF,s);
  600.   EmptyBuff(Buff,Posn)
  601.   end
  602.  else{ insert the buffer as it is when full }
  603.    if Posn > BufEnd then
  604.      begin
  605.      if TranState = ImgFile then
  606.        begin
  607.        if YPosn >= 0 then
  608.          begin
  609.          Line.Origin.Y := YPosn;
  610.          PutLine(Line,Im,Buff);
  611.          YPosn := YPosn -1
  612.          end
  613.         else
  614.           EOI := True;
  615.        EmptyBuff(Buff,Posn)
  616.        end
  617.       else
  618.         begin
  619.         Blk := BlockWrite(F,Buff,1);
  620.         EmptyBuff(Buff,Posn)
  621.         end
  622.      end
  623. end{SaveBuff};
  624.  
  625. (* ---------------------------------------------------- *)
  626.  
  627. procedure ReadBuff;
  628. { This procedure fills the buffer from the file when
  629.   necessary }
  630.  
  631. var
  632.   Blk    : integer;
  633.  
  634. begin
  635. if ((Posn <= 1) or (Posn > BufEnd)) and (not EOF(F)) and (TranState <> ImgFile) then
  636.   begin
  637.   Blk := BlockRead(F,Buff,1);
  638.   Posn := 1
  639.   end
  640.  else
  641.    if ((Posn <=1) or (Posn > BufEnd)) and (TranState = ImgFile) then
  642.      begin
  643.      if YPosn >= 0 then
  644.        begin
  645.        Posn := 1;
  646.        Line.Origin.Y := YPosn;
  647.        GetLine(Line,Im,Buff);
  648.        YPosn := YPosn - 1
  649.        end
  650.       else
  651.         EOI := True;
  652.      end
  653. end{ReadBuff};
  654.  
  655. (* ---------------------------------------------------- *)
  656.  
  657. end{FileHandle}.
  658.  
  659. **** File BINUTILS.TEXT ********************************************************
  660.  
  661. { This contains the routines for eight bit quoting }
  662.  
  663. (* ---------------------------------------------------- *)
  664.  
  665. procedure Bbufemp(* var buffer : pakettype;
  666.                       Len    : integer  *);
  667. { procedure to empty the buffe into a file }
  668.  
  669. var
  670.   r      : char;
  671.   i      : integer;
  672.  
  673. begin
  674. i := 0;
  675.  
  676. while i < Len do { while not at the end of packet do }
  677.   begin
  678.   r := buffer[i];
  679.   if (r = myquote) then { if myquote the a control char ? }
  680.     begin{get quoted character}
  681.     i := i + 1;
  682.     r := buffer[i];
  683.     if (aand(ord(r),127) <> ord(myquote)) and
  684.        (aand(ord(r),127) <> ord(mybquote)) then
  685.       r := ctl(r) { controlify the character }
  686.     end
  687.    else
  688.      if (r = myBquote) then { if mybquote then eight bit should be set }
  689.        begin{get the binary character}
  690.        i := i + 1;
  691.        r := buffer[i];
  692.        if (aand(ord(r),127) = ord(myquote)) then { is a control char }
  693.          begin
  694.          i := i + 1;
  695.          r := buffer[i];
  696.          if (aand(ord(r),127) <> ord(myquote)) and
  697.             (aand(ord(r),127) <> ord(mybquote)) then
  698.            r := ctl(chr(aand(ord(r),127)));
  699.          end;
  700.        r := chr(aand(ord(r),127) + 128) { add in eight bit }
  701.        end
  702.       else
  703.         begin{get the normal character}
  704.         r := chr(aand(ord(r),127))
  705.         end;
  706.   i := i + 1;
  707.   FileBuf[BuffPosn] := r; { put in the file buffer }
  708.   BuffPosn := BuffPosn + 1;
  709.   if BuffPosn > BufEnd then { if file buffer full then save it }
  710.     SaveBuff(FileBuf,BuffPosn,False)
  711.   end{while}
  712.   
  713. end{Bbufemp};
  714.  
  715. (* ---------------------------------------------------- *)
  716.  
  717. function Bbufill(*var buffer: packettype): integer*);
  718. { This fills a packet from the file }
  719.  
  720. var i,j,k : integer;
  721.     r     : char;
  722.     OK    : boolean;
  723.  
  724. begin
  725. OK := ((not eof(f)) and (TranState <> ImgFile)) or
  726.       ((not EOI) and (TranState = ImgFile));
  727.  
  728. i := 0;
  729. (* while file has some data & packet has some room we'll keep going *)
  730. while ((buffposn <= bufend) or OK) and (i < spsiz-8) do
  731.   begin
  732.   ReadBuff(FileBuf,BuffPosn);(* while *)
  733.   if (buffposn <= bufend) then     (* if we're within buffer bounds *)
  734.     begin
  735.     r := filebuf[buffposn];      (* get a character *)
  736.     buffposn := buffposn + 1;         (* increase buffer pointer *)
  737.     if ord(r) > 127 then
  738.       begin{we have the eight bit set }
  739.       buffer[i] := bquote;
  740.       i := i + 1;
  741.       r := chr(aand(ord(r),127));{ convert to 7 bit }
  742.       if (r in ctlset) then
  743.         begin
  744.         buffer[i] := quote;
  745.         i := i + 1;
  746.         if (r <> quote) and (r <> bquote) then
  747.           r := ctl(r);
  748.         end
  749.       end
  750.      else
  751.        if (r in ctlset) then     (* if a control char *)
  752.          begin
  753.          buffer[i] := quote;      (* put the quote in buffer *)
  754.          i := i + 1;
  755.          if (r <> quote) and (r <> bquote) then
  756.              r := ctl(r);   (* and un-controllify char *)
  757.          end;
  758.     buffer[i] := r; { update the buffer }
  759.     i := i + 1;
  760.     end;
  761.   OK := ((not eof(f)) and (TranState <> ImgFile)) or
  762.         ((not EOI) and (TranState = ImgFile));
  763.   end{while};
  764. if (i = 0) then                         (* if we're at end of file, *)
  765.   Bbufill := (at_eof)                    (* indicate it *)
  766.  else                                    (* else *)
  767.    Bbufill := i                           (* return # of chars in packet *)
  768. end; (* Bbufill *)
  769.  
  770. (* ---------------------------------------------------- *)
  771.  
  772. **** File HANDLE.TEXT **********************************************************
  773.  
  774. .TITL   HANDLER
  775.  
  776. .PROC   GETBUF < FUNCTION GETBUF( SOH, EOP, TIMEOUT : INTEGER;
  777.                                   VAR S        : STRING ):BOOLEAN; >
  778.  
  779. ;-----------------------------------------------------------;
  780. ;                                                           ;
  781. ; written by H Balen    March 1986                          ;
  782. ;                                                           ;
  783. ; This is a microcode routine to receive a packet for the   ;
  784. ; Magiscans KERMIT program.                                 ;
  785. ;                                                           ; 
  786. ; SOH = 'my_soh' start of packet                            ;
  787. ; EOP = 'my_eop' end of the packet                          ;
  788. ; TIMEOUT = number of loops before giving up                ;
  789. ; S = the buffer in which to store the data                 ;
  790. ;                                                           ;
  791. ;                                                           ;
  792. ;-----------------------------------------------------------;
  793.  
  794.  
  795. .REG EOP
  796. .REG SOH
  797. .REG STRPTR
  798. .REG INDPSN
  799. .REG WPSN
  800. .REG CBYTE
  801. .REG VALUE
  802. .REG WRDPTR
  803. .REG TCOUNT
  804. .REG TIMOUT
  805.  
  806. GETBUF: NOP                     :JSR DUMP2      ; Zero the count
  807.         ZER TCOUNT              :JSR ACPOP      ; and the posn
  808.         MOV AC,STRPTR           :JSR ACPOP      ; Set the string and word pointers
  809.         MOV AC,TIMOUT           :JSR ACPOP      ; get wait
  810.         MOV AC,EOP              :JSR ACPOP      ; get special characters
  811.         MOV AC,SOH
  812.         
  813. LAB1:   ZER INDPSN
  814.         MOV STRPTR,AC
  815.         MOV AC,WRDPTR
  816.  
  817. LOOP:   INC TCOUNT                              ; check the time out
  818.         MOV TIMOUT,AC
  819.         SUB AC,COUNT,#
  820.         MOV %0004,AC            :JMP LEAVE ZR
  821.         SUB AC,C16,RMSK                         ; check the status register
  822.         MOV C255,AC             :JSR STATSET
  823.         AND IO(RS),C1,AC
  824.         NOP                     :JMP LOOP NZ
  825.         
  826.         MOV %0038,IOA                           ; read the port
  827.         MOV IO,AC
  828.         AND AC,%7F,AC
  829.         
  830.         SUB AC,SOH,#                            ; check the special chars
  831.         SUB AC,EOP,#            :JMP LAB1 ZR
  832.         MOV AC,CBYTE            :JMP PEND ZR
  833.         
  834.         NOP                     :JSR STORUP     ; store the byte
  835.         NOP                     :JMP LOOP       ; continue to loop
  836.  
  837. PEND:   MOV STRPTR,MAF                          ; routine to leave the microcode procedure
  838.         MOV MM,AC                               ; store the length of the string
  839.         AND AC,%FF00,AC
  840.         MOV AC,VALUE
  841.         MOV INDPSN,AC
  842.         AND AC,%00FF,AC
  843.         OR  AC,VALUE,AC
  844.         MOV AC,MM
  845.         MOV C1,AC
  846. FEND:   NOP                     :JSR ACPUSH
  847.         NOP                     :JMP ENDIPC
  848. LEAVE:  ZER AC                  :JMP FEND
  849.  
  850. STORUP: INC INDPSN                              ; find the index
  851.         MOV INDPSN,AC
  852.         MOV WRDPTR,MAF
  853.         AND AC,C1,#                             ; if the index is odd then store in high byte of word
  854.         MOV MM,AC               :JMP ODD NZ
  855.         AND AC,%FF00,AC                         ; else store in the low byte
  856.         MOV AC,VALUE
  857.         MOV CBYTE,AC
  858.         AND AC,%00FF,AC
  859.         OR  AC,VALUE,AC
  860.         MOV AC,MM               :RET
  861.         
  862. ODD:    AND AC,%00FF,AC                         ; store in high byte
  863.         MOV AC,VALUE
  864.         MOV CBYTE,AC
  865.         AND AC(8L),%FF00,AC
  866.         OR  AC,VALUE,AC
  867.         MOV AC,MM
  868.         INC WRDPTR              :RET
  869.  
  870. **** File HELP.TEXT ************************************************************
  871.  
  872. segment procedure help;
  873. {UCSD Pascal KERMIT for the Terak p-System, from Kate MacGregor, Cornell U}
  874. { Adapted for the Magiscan 2 by H Balen, Lancaster U }
  875.  
  876. procedure keypress;
  877.  
  878. var
  879.   ch: char;
  880.  
  881. begin
  882. writeln;
  883. writeln('---------------Press any key to continue---------------');
  884. repeat
  885. until readch(terminal,ch);
  886. writeln(chr(ff){clearscreen})
  887. end; (* keypress *)
  888.  
  889. procedure help1;
  890.  
  891. var ch: char;
  892.  
  893. begin
  894. write(chr(ff));
  895. if (noun = nullsym) then
  896.   begin
  897.   writeln('KERMIT is a family of  programs that do reliable file transfer');
  898.   writeln('between computers over TTY lines.  KERMIT can also be used to ');
  899.   writeln('make the microcomputer behave as a terminal for a mainframe.  ');
  900.   writeln('These are the commands for theUCSD p-system version, ');
  901.   writeln('KERMIT-UCSD:');
  902.   writeln
  903.   end; (* if *)
  904. if (noun = nullsym) or (noun = consym) then
  905.   begin
  906.   writeln('  CONNECT     To make a "virutual terminal" connection to ');
  907.   writeln('              a remote system. To break the connection and');
  908.   writeln('              "escape" back to the micro, type the escape ');
  909.   writeln('              sequence (CTRL-] C, that is Control rightbracket');
  910.   writeln('              followed immediately by the letter C.)');
  911.   writeln;
  912.   end; (* if *)
  913. if (noun = nullsym) or (noun = exitsym) then
  914.   begin
  915.   writeln('  EXIT        To return back to main command level of the');
  916.   writeln('              p-system.');
  917.   writeln;
  918.   end; (* if *)
  919. if (noun = nullsym) or (noun = helpsym) then
  920.   begin
  921.   writeln('  HELP        To get a list of KERMIT commands.');
  922.   writeln;
  923.   end; (* if *)
  924. if (noun = nullsym) or (noun = quitsym) then
  925.   begin
  926.   writeln('  QUIT        Same as EXIT.');
  927.   writeln;
  928.   end; (* if *)
  929. if (noun = nullsym) or (noun = recsym) then
  930.   begin
  931.   writeln('  RECEIVE     To accept a file from the remote system.');
  932.   writeln;
  933.   end; (* if *)
  934. end; (* help1 *)
  935.  
  936. procedure help2;
  937.  
  938. var
  939.   ch  : char;
  940.  
  941. begin
  942. if (noun = nullsym) or (noun = loadsym) then
  943.   begin
  944.   writeln('  LOAD        To load an image from the current disk.');
  945.   writeln;
  946.   end; (* if *)
  947. if (noun = nullsym) or (noun = sendsym) then
  948.   begin
  949.   writeln('  SEND        To send a file or group of files to the remote');
  950.   writeln('              system.');
  951.   writeln;
  952.   end; (* if *)
  953. if (noun = nullsym) then
  954.     keypress;
  955. end{help2};
  956.  
  957. procedure help3;
  958.  
  959. var ch: char;
  960.  
  961. begin
  962. if (noun = nullsym) or (noun = setsym) then
  963.   begin
  964.   writeln('  SET         To establish system-dependent parameters.  The ');
  965.   writeln('              SET options are as follows: ');
  966.   writeln;
  967.   if (adj = nullsym) or (adj = baudsym) then
  968.     begin
  969.     writeln('              BAUD             75 to 9600, default is 1200. ');
  970.     writeln('                               This sets the baud rate for the');
  971.     writeln('                               system, should be done before');
  972.     writeln('                               a conect, and is a mutiple of');
  973.     writeln('                               75 by a power of two.');
  974.     writeln;
  975.     end;{if}
  976.   if (adj = nullsym) or (adj = debugsym) then
  977.     begin
  978.     writeln('              DEBUG            To set debug mode ON or OFF ');
  979.     writeln('                               (default is OFF).');
  980.     writeln;
  981.     end; (* if *)
  982.   if (adj = nullsym) or (adj = dirsym) then
  983.     begin
  984.     writeln('              DISK             4/5/9/10, default is 5. This');
  985.     writeln('                               sets the drive to be one of');
  986.     writeln('                               the volumes/disks in existance');
  987.     writeln('                               on the M2.');
  988.     writeln;
  989.     end;{if}
  990.   if (adj = nullsym) then
  991.       keypress;
  992.   end; (* if *)
  993. end; (* help3 *)
  994.  
  995. procedure help4;
  996.  
  997. begin
  998. if (noun = nullsym) or (noun = setsym) then
  999.   begin
  1000.   if (adj = nullsym) or (adj = escsym) then
  1001.     begin
  1002.     writeln('              ESCAPE           To change the escape sequence');
  1003.     writeln('                               that lets you return to the ');
  1004.     writeln('                               PC Kermit from the remote host.');
  1005.     writeln('                               The default is CTRL-] c.');
  1006.     writeln;
  1007.     end; (* if *)
  1008.   if (adj = nullsym) or (adj = filewarnsym) then
  1009.     begin
  1010.     writeln('              FILE-WARNING     ON/OFF, default is OFF.  If');
  1011.     writeln('                               ON, Kermit will warn you and');
  1012.     writeln('                               rename an incoming file so as');
  1013.     writeln('                               not to write over a file that');
  1014.     writeln('                               currently exists with the');
  1015.     writeln('                               same name');
  1016.     writeln;
  1017.     end; (* if *)
  1018.   end; (* if *)
  1019. end; (* help4 *)
  1020.  
  1021. procedure help5;
  1022.  
  1023. begin
  1024. if (noun = setsym) or (noun = nullsym) then
  1025.   begin
  1026.   if (adj = nullsym) or (adj = ibmsym) then
  1027.     begin
  1028.     writeln('              IBM              ON/OFF, default is OFF.  This');
  1029.     writeln('                               flag should be ON only when ');
  1030.     writeln('                               transfering files between the');
  1031.     writeln('                               micro and an IBM VM/CMS system.');
  1032.     writeln('                               It also causes the parity to be');
  1033.     writeln('                               set appropriately (mark) and ');
  1034.     writeln('                               activates local echoing');
  1035.     writeln;
  1036.     end; (* if *)
  1037.   if (adj = nullsym) then
  1038.       keypress;
  1039.   if (adj = nullsym) or (adj = localsym) then
  1040.     begin
  1041.     writeln('              LOCAL-ECHO       ON/OFF, default is OFF. This');
  1042.     writeln('                               sets the duplex.  It should be');
  1043.     writeln('                               ON when using the IBM and OFF ');
  1044.     writeln('                               for the DEC-20.');
  1045.     writeln;
  1046.     end; (* if *)
  1047.   end; (* if *)
  1048. end; (* help5 *)
  1049.  
  1050. procedure Help6;
  1051.  
  1052. begin
  1053. if (noun = setsym) or (noun = nullsym) then
  1054.   begin
  1055.   if (adj = nullsym) or (adj = paritysym) then
  1056.     begin
  1057.     writeln('              PARITY           EVEN, ODD, MARK, SPACE, ');
  1058.     writeln('                               or NONE. NONE is the default');
  1059.     writeln('                               but if the IBM flag is set, ');
  1060.     writeln('                               parity is set to MARK. This ');
  1061.     writeln('                               flag selects the parity for ');
  1062.     writeln('                               outgoing and incoming ');
  1063.     writeln('                               characters during CONNECT and');
  1064.     writeln('                               file transfer to match the');
  1065.     writeln('                               requirements of the host.');
  1066.     writeln;
  1067.     end; (* if *)
  1068.   if (noun = paritysym) then
  1069.     KeyPress
  1070.   end{if};
  1071. if (noun = transym) or (noun = nullsym) then
  1072.   begin
  1073.   writeln('  TRANSFER    To set the type of transfer, the types can ');
  1074.   writeln('              be TEXT, CODE, DATA, IMAGE. The format of the ');
  1075.   writeln('              command is TRANSFER TYPE <type>          ');
  1076.   writeln;
  1077.   if (noun = transym) then
  1078.     KeyPress;
  1079.   end; (* if *)
  1080. end{help6};
  1081.  
  1082. procedure Help7;
  1083.   
  1084. begin
  1085. if (noun = nullsym) or (noun = showsym) then
  1086.   begin
  1087.   writeln('  SHOW        To see the values of parameters that can be');
  1088.   writeln('              modified via the SET command.  Options are the');
  1089.   writeln('              same as for SET,  except that a SHOW ALL ');
  1090.   writeln('              command has been added.');
  1091.   KeyPress;
  1092.   end; (* if *)
  1093. end{Help7};
  1094.  
  1095. begin
  1096. help1;
  1097. help2;
  1098. help3;
  1099. help4;
  1100. help5;
  1101. help6;
  1102. help7
  1103. end; (* help *)
  1104.  
  1105. **** File KERMIT.TEXT **********************************************************
  1106.  
  1107. program kermit;
  1108. {UCSD Pascal KERMIT for the Terak p-System, from Kate MacGregor, Cornell U}
  1109. {Adapted to Pascal Microengine by Tim Shimeall, UCI}
  1110. {Changes:
  1111. - Added device declarations copied from Microengine hardware documentation
  1112. - Replaced external assembly language routines with Pascal versions
  1113. - Modified debug messages to be label values printed
  1114. - Changed format of packetwrite display to show header fields
  1115. - Implemented machine-dependent packet timeout
  1116. - Added debug packetwrites in recsw
  1117. - Added wrap-around debug info region
  1118. - Added legality check in showparms
  1119. - Removed lf elimination check in echo procedure
  1120. - Unitwrite calls replaced by calls to device driving routines
  1121. - Most uses of char_int_rec replaced by ord and chr
  1122. - Removed queue (no interrupts) 
  1123. - Used sets for integer ops to getaround Microengine bug
  1124. - Changed parser from a unit to a segment procedure to allow swapping
  1125. - Split utility procs into separate files for editing and transfer convinience
  1126. }
  1127.  
  1128. {Adapted to Joyce Loebl's Magiscan 2 Image processing computer,
  1129.  by Henry Balen, Lancaster University }
  1130. {Changes:
  1131. - added ability for the parser to recognize digits,
  1132.   this enabled a Baudrate command to be implemented
  1133. - added a command to set a work disk, set disk #.
  1134. - The IO subroutines were put into an unit RS232 and
  1135.   changed to suit the Magiscan.
  1136. - put the parser back into an unit since the Magiscan has 128K
  1137.   available.
  1138. - modified the constants for the screen because the Magiscan only
  1139.   has 64 columns.
  1140. - Added a unit SysUnit to enable the user to interogate the
  1141.   current work disk and delete files if so wishes.
  1142. - Added a unit FileHandle which gives routines for accessing
  1143.   files for reading and writing, the old version of this didn't
  1144.   close a file if there was an unsuccessful receive/send this
  1145.   is now fixed.
  1146. - Modified the Buffer empty and fill routines to use these.
  1147. - Added the ability to do eight bit prefixing and the necessary
  1148.   routines for this.
  1149. - Have added a new command called TRANSFER ( do a TRANSFER
  1150.   TYPE <type> ), which enables transfers of image,data,code and
  1151.   text 'types'.
  1152. - There is also image LOAD routine implemented, this allows
  1153.   the images to be loaded from disk and transfered to the Host
  1154.   straight from image memory.
  1155. }
  1156. { Futher changes by H Balen, now of Joyce Loebl, March 1986 }
  1157. {
  1158. - The receive packet routine has been put in the magiscan's
  1159.   microcode, data can now be succesfully received and transmitted
  1160.   at 9600 baud (except images ! max =4800 ), though the screen
  1161.   cannot scroll fast enough for incoming characters greater
  1162.   than 1200.
  1163. - Two new options have been included - they are the MUX delay
  1164.   which tells the Magiscan how many cycles the wait when
  1165.   sending characters, and the option of using the winchester 
  1166.   on #9.
  1167. }
  1168.  
  1169. (*$R-*) (* turn range checking off *)
  1170. (*$S+*) (* turn swapping on *)
  1171. (* $L PRINTER: *) (* no listing *)
  1172.  
  1173. Uses
  1174.   M2Types,M2IpRoot,M2Sys,
  1175.   (*$U DISK.CODE*)DiskUnit,
  1176.   (*$U RS232.Code*)RS232,
  1177.   (*$U SysUnit.Code*)SysUnit,
  1178.   (*$U ParUnit.Code*)ParseUnit,
  1179.   (*$U FileUnit.Code*)FileHandle,
  1180.   (*$U HANDLE.CODE*)HANDLER; { the microcode }
  1181.  
  1182. const blksize = 512;
  1183.       oport = 8;          (* output port # *)
  1184.       (* clearscreen = 12;   charcter which erases screen *)
  1185.       { bell = 7; }           (* ASCII bell *)
  1186.       esc = 27;           (* ASCII escape *)
  1187.       maxpack = 93;       (* maximum packet size minus 1 *)
  1188.       soh = 1;            (* start of header *)
  1189.       sp = 32;            (* ASCII space *)
  1190.       cr = 13;            (* ASCII CR *)
  1191.       lf = 10;            (* ASCII line feed *)
  1192.       dle = 16;           (* ASCII DLE (space compression prefix for psystem) *)
  1193.       del = 127;          (* delete *)
  1194.       my_esc = 29;        (* default esc char for connect (^]) *)
  1195.       maxtry = 5;         (* number of times to retry sending packet *)
  1196.       my_quote = '#';     (* quote character I'll use *)
  1197.       my_bquote = '&';    { binary quate character I'll use }
  1198.       my_pad = 0;         (* number of padding chars I need *)
  1199.       my_pchar = 0;       (* padding character I need *)
  1200.       my_eol = 13;        (* end of line character i need *)
  1201.       my_time = 5;        (* seconds after which I should be timed out *)
  1202.       maxtim = 20;        (* maximum timeout interval *)
  1203.       mintim = 2;         (* minimum time out interval *)
  1204.       at_eof = -1;        (* value to return if at eof *)
  1205.       eoln_sym = 13;      (* pascal eoln sym *)
  1206.       back_space = 8;     (* pascal backspace sym *)
  1207.  
  1208.  
  1209. (* screen control information *)
  1210.   (* console line on which to put specified info *)
  1211.       title_line = 1;
  1212.       statusline = 2;
  1213.       packet_line = 3;
  1214.       retry_line = 4;
  1215.       file_line = 5;
  1216.       error_line = 6;
  1217.       prompt_line = 7;
  1218.       debug_line = 9;
  1219.       debug_max = 12; (* Max lines of debug to show at once *)
  1220.   (* position on line to put info *)
  1221.       statuspos = 54;
  1222.       packet_pos = 19;
  1223.       retry_pos = 17;
  1224.       file_pos = 11;
  1225.       
  1226.       Intsize = 15;
  1227.  
  1228. type packettype = packed array[0..maxpack] of char;
  1229.      parity_type = (evenpar, oddpar, markpar, spacepar, nopar);
  1230.  
  1231.      char_int_rec = record (* allows character to be treated as integer... *)
  1232.                            (* is system dependent *)
  1233.                       case boolean of
  1234.                           true: (i: integer);
  1235.                           false: (ch: char)
  1236.                     end; (* record *)
  1237.  
  1238.      int_bool_rec = record (* allows integer to be treated as boolean... *)
  1239.                            (* used for numeric AND,OR,XOR...system dependent *)
  1240.                            (* replaced by set version to escape microengine
  1241.                               bug *)
  1242.                       case boolean of
  1243.                           true: (i: integer);
  1244.                           false: (b: set of 0..intsize);
  1245.                     end; (* record *)
  1246.  
  1247.      Port = (Terminal,Modem);
  1248.      
  1249.      
  1250. var state: char; (* current state *)
  1251.     s: string;
  1252.     eol, bquote, quote, esc_char: char;
  1253.     fwarn, ibm, half_duplex, debug: boolean;
  1254.     delay, i, size, rpsiz, spsiz, pad, n, num_try, oldtry, timint: integer;
  1255.     recpkt, packet: packettype;
  1256.     padchar, ch: char;
  1257.     debf: text; (* file for debug output *)
  1258.     debnext:0..7; (* offset for next debug message *)
  1259.     parity: parity_type;
  1260.     xon: char;
  1261.     vol, Baud: integer;
  1262.     parity_array: packed array[char] of char;
  1263.     ctlset: set of char;
  1264.     rec_ok, send_ok: boolean;
  1265.     
  1266.  
  1267. function read_ch(p: port; var ch: char): boolean;
  1268. forward;
  1269.  
  1270. function aand(x,y: integer): integer;
  1271. forward;
  1272.  
  1273. function aor(x,y: integer): integer;
  1274. forward;
  1275.  
  1276. function xor(x,y: integer): integer;
  1277. forward;
  1278.  
  1279. procedure error(p: packettype; len: integer);
  1280. forward;
  1281.  
  1282. procedure ino_error(i: integer);
  1283. forward;
  1284.  
  1285. procedure debugwrite(s: string);
  1286. forward;
  1287.  
  1288. procedure debugint(s: string; i: integer);
  1289. forward;
  1290.  
  1291. procedure writescreen(s: string);
  1292. forward;
  1293.  
  1294. procedure refresh_screen(numtry, num: integer);
  1295. forward;
  1296.  
  1297. function min(x,y: integer): integer;
  1298. forward;
  1299.  
  1300. function tochar(ch: char): char;
  1301. forward;
  1302.  
  1303. function unchar(ch: char): char;
  1304. forward;
  1305.  
  1306. function ctl(ch: char): char;
  1307. forward;
  1308.  
  1309. function getfil(filename: string): boolean;
  1310. forward;
  1311.  
  1312. procedure Bbufemp(buffer: packettype; len: integer);
  1313. forward;
  1314.  
  1315. function Bbufill(var buffer: packettype): integer;
  1316. forward;
  1317.  
  1318. procedure bufemp(buffer: packettype; var f: text; len: integer);
  1319. forward;
  1320.  
  1321. function bufill(var buffer: packettype): integer;
  1322. forward;
  1323.  
  1324. procedure spar(var packet: packettype);
  1325. forward;
  1326.  
  1327. procedure rpar(var packet: packettype);
  1328. forward;
  1329.  
  1330. procedure spack(ptype: char; num:integer; len: integer; data: packettype);
  1331. forward;
  1332.  
  1333. function getch(var r: char; p: port): boolean;
  1334. forward;
  1335.  
  1336. function getsoh(p: port): boolean;
  1337. forward;
  1338.  
  1339. function rpack(var len, num: integer; var data: packettype): char;
  1340. forward;
  1341.  
  1342. procedure read_str(p: port; var s: string);
  1343. forward;
  1344.  
  1345. procedure packetwrite(p: packettype; len: integer);
  1346. forward;
  1347.  
  1348. procedure show_parms;
  1349. forward;
  1350.  
  1351.  
  1352. (*$I HELP.TEXT*) (* Segment Procedure Help *)
  1353. (*$I SENDSW.TEXT*) (* Segment Procedure Sendsw *)
  1354. (*$I RECSW.TEXT*) (* Segment Procedure Recsw *)
  1355. (*$I UTILS.TEXT *) (* General Utility procedures *)
  1356. (*$I BINUTILS.TEXT*) { Routines for Binary transfer }
  1357. (*$I RSUTILS.TEXT *) (* Utility procedures for send and receive *)
  1358.  
  1359. procedure connect;
  1360.  
  1361. (* connect to remote host (terminal emulation *)
  1362.  
  1363. var ch: char;
  1364.     close: boolean;
  1365.  
  1366.   procedure read_esc;
  1367.  
  1368.   (* read charcter after esc char and interpret it *)
  1369.  
  1370.     begin
  1371.       repeat
  1372.       until read_ch(terminal,ch);       (* wait until they've typed something in
  1373.  *)
  1374.       if (ch in ['a'..'z']) then  (* uppercase it *)
  1375.           ch := chr(ord(ch) - ord('a') + ord('A'));
  1376.       if ch in [{'B',}'C','S','D','?'] then
  1377.           begin
  1378.           writeln;
  1379.           case ch of
  1380.               (*'B': sendbrk;        B: send a break to the IBM *)
  1381.               'C': close := true; (* C: end connection *)
  1382.               'S': begin          (* S: show status *)
  1383.                    noun := allsym;
  1384.                    showparms
  1385.                    end; (* S *)
  1386.               'D':begin
  1387.                   vol := ord(disk[2]) - ord('0');
  1388.                   if vol in [9,10] then
  1389.                     writeln('Cannot DIR a Winchester')
  1390.                    else
  1391.                      PrintNames(vol,value)
  1392.                   end; (* D *)
  1393.               '?': begin          (* ?: show options *)
  1394.                   (* writeln('B    Send a BREAK signal.'); *)
  1395.                   writeln('C    Close Connection, return to ');
  1396.                   writeln('     KERMIT-UCSD command level.');
  1397.                   writeln('S    Show Status of connection');
  1398.                   writeln('D    displays the current directory');
  1399.                   writeln('?    Print this list');
  1400.                   write('^',ctl(esc_char),'   send the escape ');
  1401.                   writeln('character itself to the');
  1402.                   writeln('     remote host.');
  1403.                 end; (* ? *)
  1404.             end (* case *)
  1405.            end
  1406.       else if ch = esc_char then  (* ESC-char: send it out *)
  1407.         begin
  1408.           if half_duplex then
  1409.             begin
  1410.               echo(ch);
  1411.               while not istbtr do;
  1412.               sndbbt(ch);
  1413.             end (* if *)
  1414.         end (* else if *)
  1415.       else                        (* anything else: ignore *)
  1416.           write(chr(bell))
  1417.     end; (* read_esc *)
  1418.  
  1419.   begin (* connect *)
  1420.     writeln('Connecting to host...type CTRL-',ctl(esc_char),' C to exit');
  1421.     close := false;
  1422.     repeat
  1423.         if read_ch(modem,ch) then        (* if char from host then *)
  1424.             echo(ch);                   (* echo it *)
  1425.  
  1426.         if read_ch(terminal,ch) then        (* if char from keyboard then *)
  1427.             if ch <> esc_char then      (* if not ESC-char then *)
  1428.               begin
  1429.                 if half_duplex then       (* echo it if half-duplex *)
  1430.                     echo(ch);
  1431.                 while not istbtr do;
  1432.                 sndbbt(ch)               (* send it out the port *)
  1433.               end (* if *)
  1434.             else (* ch = esc_char *)    (* else is ESC-char so *)
  1435.               read_esc;                   (* interpret next char *)
  1436.     until close;                      (* if still connected, get more *)
  1437.     writeln('Disconnected')
  1438.   end; (* connect *)
  1439.  
  1440. procedure fill_parity_array;
  1441.  
  1442. (* parity value table for even parity...not(entry) = odd parity *)
  1443.  
  1444. const min = 0;
  1445.       max = 126;
  1446.  
  1447. var i, shifter, counter: integer;
  1448.     minch, maxch, ch: char;
  1449.     r: char_int_rec;
  1450.  
  1451.   begin
  1452.     minch := chr(min);
  1453.     maxch := chr(max);
  1454.     case parity of
  1455.       evenpar:
  1456.         begin
  1457.           for ch := minch to maxch do
  1458.             begin
  1459.               r.ch := ch;               (* put char into variant record *)
  1460.               shifter := aand(r.i,255); (* mask off parity bit *)
  1461.               counter := 0;
  1462.               for i := 1 to 7 do        (* count the 1's *)
  1463.                 begin
  1464.                   if odd(shifter) then
  1465.                       counter := counter + 1;
  1466.                   shifter := shifter div 2
  1467.                 end; (* for i *)
  1468.               if odd(counter) then       (* stick a 1 on if necessary *)
  1469.                   parity_array[ch] := chr(aor(ord(ch),128))
  1470.               else
  1471.                   parity_array[ch] := chr(aand(ord(ch),127))
  1472.             end; (* for ch *)
  1473.         end; (* case even *)
  1474.       oddpar:
  1475.         begin
  1476.           for ch := minch to maxch do
  1477.             begin
  1478.               r.ch := ch;                (* put char into variant record *)
  1479.               shifter := aand(r.i,255);  (* mask off parity bit *)
  1480.               counter := 0;
  1481.               for i := 1 to 7 do         (* count the 1's *)
  1482.                 begin
  1483.                   if odd(shifter) then
  1484.                       counter := counter + 1;
  1485.                   shifter := shifter div 2
  1486.                 end; (* for i *)
  1487.               if odd(counter) then        (* stick a 1 on if necessary *)
  1488.                   parity_array[ch] := chr(aand(ord(ch),127))
  1489.               else
  1490.                   parity_array[ch] := chr(aor(ord(ch),128))
  1491.             end; (* for ch *)
  1492.         end; (* case odd *)
  1493.       markpar:
  1494.           for ch := minch to maxch do     (* stick a 1 on all chars *)
  1495.               parity_array[ch] := chr(aor(ord(ch),128));
  1496.       spacepar:
  1497.           for ch := minch to maxch do     (* mask off parity on all chars *)
  1498.               parity_array[ch] := chr(aand(ord(ch),127));
  1499.       nopar:
  1500.           for ch := minch to maxch do     (* don't mess w/parity bit at all *)
  1501.               parity_array[ch] := ch;
  1502.     end; (* case *)
  1503.   end; (* fill_parity_array *)
  1504.  
  1505. procedure write_bool(s: string; b: boolean);
  1506.  
  1507. (* writes message & 'on' if b, 'off' if not b *)
  1508.   begin
  1509.     write(s);
  1510.     case b of
  1511.         true: writeln('on');
  1512.         false: writeln('off');
  1513.       end; (* case *)
  1514.   end; (* write_bool *)
  1515.  
  1516. procedure writeTrans;
  1517. { writes the transfer state }
  1518.  
  1519. begin
  1520. write('Transfer Type : ');
  1521. case TranState of
  1522.   CodeFile : writeln('BINARY');
  1523.   ImgFile : writeln('IMAGE');
  1524.   TxtFile : writeln('TEXT');
  1525. "BinFile : writeln('DATA')
  1526.   end
  1527. end{writeTrans};
  1528.  
  1529. procedure show_parms;
  1530.  
  1531. (* shows the various settable parameters *)
  1532.  
  1533.   begin
  1534.     writeln;
  1535.     if noun in [allsym, debugsym, ibmsym, escsym, filewarnsym,
  1536.                 muxsym, transym, disksym, localsym, baudsym, paritysym] then
  1537.     case noun of
  1538.         allsym:
  1539.           begin
  1540.             write_bool('Debugging is ',debug);
  1541.             writeln('Escape character is ^',ctl(esc_char));
  1542.             write_bool('File warning is ',fwarn);
  1543.             write_bool('IBM is ',ibm);
  1544.             write_bool('Local echo is ',halfduplex);
  1545.             case parity of
  1546.                 evenpar: write('Even');
  1547.                 markpar: write('Mark');
  1548.                 nopar: write('No');
  1549.                 oddpar: write('Odd');
  1550.                 spacepar: write('Space');
  1551.               end; (* case *)
  1552.             writeln(' parity');
  1553.             writeln('Baudrate is ',Baud);
  1554.             writeln('Drive is ',disk);
  1555.             writeln('MUX is ',MUXDelay);
  1556.             writetrans
  1557.           end; (* allsym *)
  1558.         debugsym: write_bool('Debugging is ',debug);
  1559.         escsym: writeln('Escape character is ^',ctl(esc_char));
  1560.         filewarnsym: write_bool('File warning is ',fwarn);
  1561.         ibmsym: write_bool('IBM is ',ibm);
  1562.         localsym: write_bool('Local echo is ',halfduplex);
  1563.         baudsym : writeln('Baudrate is ',Baud);
  1564.         disksym : writeln('Drive is ',disk);
  1565.         transym : writetrans;
  1566.         muxsym : writeln('MUX is ',MUXDelay);
  1567.         paritysym: begin
  1568.             case parity of
  1569.                 evenpar: write('Even');
  1570.                 markpar: write('Mark');
  1571.                 nopar: write('No');
  1572.                 oddpar: write('Odd');
  1573.                 end;
  1574.             writeln(' parity');
  1575.            end; (* paritysym *)
  1576.         typesym : writetrans
  1577.       end (* case *)
  1578.       else write(chr(bell));
  1579.   end; (* show_sym *)
  1580.  
  1581. procedure set_parms;
  1582.  
  1583. (* sets the parameters *)
  1584.  
  1585.   begin
  1586.     case noun of
  1587.         debugsym: case adj of
  1588.                       onsym: begin
  1589.                           debug := true;
  1590.                           (*$I-*)
  1591.                           rewrite(debf,'CONSOLE:')
  1592.                           (*I+*)
  1593.                         end; (* onsym *)
  1594.                       offsym: debug := false
  1595.                     end; (* case adj *)
  1596.         escsym: escchar := newescchar;
  1597.         filewarnsym: fwarn := (adj = onsym);
  1598.         ibmsym: case adj of
  1599.                     onsym: begin
  1600.                           ibm := true;
  1601.                           parity := markpar;
  1602.                           half_duplex := true;
  1603.                           fillparityarray
  1604.                           end; (* onsym *)
  1605.                     offsym: begin
  1606.                             ibm := false;
  1607.                             parity := nopar;
  1608.                             half_duplex := false;
  1609.                             fillparityarray
  1610.                             end; (* onsym *)
  1611.                   end; (* case adj *)
  1612.         localsym: halfduplex := (adj = onsym);
  1613.         paritysym: begin
  1614.                    case adj of
  1615.                        evensym: parity := evenpar;
  1616.                        marksym: parity := markpar;
  1617.                        nonesym: parity := nopar;
  1618.                        oddsym: parity := oddpar;
  1619.                        spacesym: parity := spacepar;
  1620.                      end; (* case *)
  1621.                    fill_parity_array;
  1622.                   end; (* paritysym *)
  1623.         MUXsym  : begin
  1624.                   MUXDelay := value
  1625.                   end (* baudsym *);
  1626.         baudsym : begin
  1627.                   Baud := value;
  1628.                   BaudRate(Baud)
  1629.                   end (* baudsym *);
  1630.         disksym : begin
  1631.                   if value in [4,5,9] then
  1632.                     begin
  1633.                     disk := ' ';
  1634.                     disk[1] := chr(ord('0')+value);
  1635.                     disk := concat('#',disk);
  1636.                     disk := concat(disk,':')
  1637.                     end
  1638.                    else
  1639.                      writeln('Drive does not exist ')
  1640.                   end (* disksym *)
  1641.                                 
  1642.       end; (* case *)
  1643.   end; (* set_parms *)
  1644.  
  1645. procedure initialize;
  1646.  
  1647. var ch: char;
  1648.  
  1649.   begin
  1650.     pad := mypad;
  1651.     padchar := chr(mypchar);
  1652.     eol := chr(my_eol);
  1653.     esc_char := chr(my_esc);
  1654.     
  1655.     quote := my_quote;
  1656.     bquote := my_bquote;
  1657.     ctlset := [chr(1)..chr(31),chr(del),quote,bquote];
  1658.     TranState := TxtFile;
  1659.     TimInt := My_Time;
  1660.     
  1661.     half_duplex := false;
  1662.     debug := false;
  1663.     debnext:=0;
  1664.     fwarn := false;
  1665.     spsiz := max_pack;
  1666.     rpsiz := max_pack;
  1667.     n := 0;
  1668.     parity := nopar;
  1669.     initvocab;
  1670.     fill_parity_array;
  1671.     ibm := false;
  1672.     xon := chr(17);
  1673.     {bufpos := 1;}
  1674.     initM;
  1675.     Baud := 1200;
  1676.     
  1677.     FileInit;
  1678.     value := 0;
  1679.     disk  := '#5:'
  1680.   end; (* initialize *)
  1681.  
  1682. procedure closeup;
  1683.  
  1684.   begin
  1685.     writeln(chr(ff){clearscreen});
  1686.   end; (* closeup *)
  1687.  
  1688.   begin (* kermit *)
  1689.     initialize;
  1690.     { Load in the microcode }
  1691.     OVLYLOAD('HANDLE');
  1692.     
  1693.     repeat
  1694.         write('Kermit-UCSD> ');
  1695.         readstr(terminal,line);
  1696.         case parse of
  1697.             unconfirmed: writeln('Unconfirmed');
  1698.             parm_expected: writeln('Parameter expected');
  1699.             ambiguous: writeln('Ambiguous');
  1700.             unrec: writeln('Unrecognized command');
  1701.             fn_expected: writeln('File name expected');
  1702.             ch_expected: writeln('Single character expected');
  1703.             null: case verb of
  1704.                       consym: connect;
  1705.                       helpsym: help;
  1706.                       Loadsym: begin
  1707.                                uppercase(filename);
  1708.                                LoadIm(filename)
  1709.                                end;
  1710.                       recsym: begin
  1711.                               recsw(rec_ok);
  1712.                               gotoxy(0,debugline);
  1713.                               write(chr(bell));
  1714.                               if rec_ok then
  1715.                                   writeln('successful receive')
  1716.                               else
  1717.                                   writeln('unsuccessful receive');
  1718.                               gotoxy(0,promptline);
  1719.                               end; (* recsym *)
  1720.                       sendsym: begin
  1721.                                uppercase(filename);
  1722.                                sendsw(send_ok);
  1723.                                gotoxy(0,debugline);
  1724.                                write(chr(bell));
  1725.                                if send_ok then
  1726.                                    writeln('successful send')
  1727.                                else
  1728.                                    writeln('unsuccessful send');
  1729.                                (*$I-*) (* set i/o checking off *)
  1730.                                closeF(filename,False);
  1731.                                (*$I+*) (* set i/o checking back on *)
  1732.                                gotoxy(0,promptline);
  1733.                                end; (* sendsym *)
  1734.                       delsym: begin
  1735.                               uppercase(filename);
  1736.                               vol := ord(disk[2]) - ord('0');
  1737.                               Delfile(filename,vol)
  1738.                               end; (* delsym *)
  1739.                       setsym: set_parms;
  1740.                      transym: begin
  1741.                               if noun = Typesym then
  1742.                                 case adj of
  1743.                                   binsym   : TranState := CodeFile;
  1744.                                   datasym  : TranState := BinFile;
  1745.                                   textsym  : TranState := TxtFile;
  1746.                                   imagesym : TranState := ImgFile;
  1747.                                   end
  1748.                                 else
  1749.                                   write(Bell)
  1750.                               end;
  1751.                       show_sym: show_parms;
  1752.                       dirsym : begin
  1753.                                vol := ord(disk[2]) - ord('0');
  1754.                                if vol in [9,10] then
  1755.                                  writeln('Cannot DIR a Winchester')
  1756.                                 else
  1757.                                   PrintNames(vol,value)
  1758.                                end (* dirsym *)
  1759.                   end; (* case verb *)
  1760.         end; (* case parse *)
  1761.         { unitclear(1); }(* clear any trash in input *)
  1762.         { unitclear(2); } (* Don't clear the screen ! *)
  1763.      until (verb = exitsym) or (verb = quitsym);
  1764.      closeup
  1765.    end.(* kermit *)
  1766.  
  1767. **** File PARUNIT.TEXT *********************************************************
  1768.  
  1769. (*$R-*) (* turn range checking off *)
  1770. (*$S+*) (* turn swapping on *)
  1771. (* $L+*) (* no listing *)
  1772.  
  1773. Unit ParseUnit;
  1774.  
  1775. { This is a unit because the magiscan does have enough memory
  1776.   to hold it without swapping }
  1777.  
  1778. Interface
  1779.   
  1780. Uses
  1781.   M2Types,M2IpRoot,M2Sys;
  1782.  
  1783.    
  1784.   (* Parser Types *)
  1785.    
  1786.   type
  1787.     statustype = (null, at_eol, unconfirmed, parm_expected, ambiguous,
  1788.                   unrec, fn_expected, ch_expected);
  1789.     
  1790.     vocab = (nullsym, zerosym, onesym, twosym, threesym, foursym,
  1791.              fivesym, sixsym, sevensym, eightsym, ninesym,
  1792.              allsym, baudsym, binsym, consym, datasym,
  1793.              debugsym, delsym, dirsym, disksym, escsym, evensym, 
  1794.              exitsym, filewarnsym, helpsym, ibmsym, imagesym, loadsym, localsym,
  1795.              marksym, muxsym, nonesym, oddsym, offsym, onsym, paritysym,
  1796.              quitsym, recsym, sendsym, setsym, showsym,
  1797.              spacesym, textsym, transym, typesym );
  1798.   
  1799.   (* Parser vars *)
  1800.   var
  1801.     noun, verb, adj     : vocab;
  1802.     status              : statustype;
  1803.     vocablist           : array[vocab] of string[13];
  1804.     value               : integer;
  1805.     filename, line      : string;
  1806.     newescchar          : char;
  1807.     expected            : set of vocab;
  1808.  
  1809.   procedure uppercase(var s: string);
  1810.   
  1811.   procedure initvocab;
  1812.   
  1813.   function parse: statustype;
  1814.  
  1815.  
  1816. Implementation
  1817.  
  1818.  
  1819. (* ---------------------------------------------------- *)
  1820.  
  1821. procedure uppercase;
  1822.  
  1823. var
  1824.   i: integer;
  1825.  
  1826. begin
  1827. for i := 1 to length(s) do
  1828.   if s[i] in ['a'..'z'] then
  1829.     s[i] := chr(ord(s[i]) - ord('a') + ord('A'))
  1830. end; (* uppercase *)
  1831.  
  1832. (* ---------------------------------------------------- *)
  1833.  
  1834. function parse;
  1835.  
  1836. type
  1837.   states = (start, fin, get_filename, get_set_parm, get_parity, get_on_off,
  1838.             get_char, get_show_parm, get_help_show, get_help_parm,
  1839.             get_value, exitstate, get_trans, get_type);
  1840.  
  1841. var
  1842.   status: statustype;
  1843.   word: vocab;
  1844.   state: states;
  1845.  
  1846.   procedure eatspaces(var s: string);
  1847.   
  1848.   var done: boolean;
  1849.       i: integer;
  1850.   
  1851.     begin
  1852.       done := (length(s) = 0);
  1853.       while not done do
  1854.         begin
  1855.           if s[1] = ' ' then
  1856.             begin
  1857.               i := length(s) - 1;
  1858.               s := copy(s,2,i);
  1859.               done := length(s) = 0
  1860.             end (* if *)
  1861.           else
  1862.               done := true
  1863.         end (* while *)
  1864.     end; (* eatspaces *)
  1865.   
  1866.   procedure isolate_word(var line, s: string);
  1867.   
  1868.   var i: integer;
  1869.       done: boolean;
  1870.   
  1871.     begin
  1872.       done := false;
  1873.       i := 1;
  1874.       s := copy(' ',0,0);
  1875.       while (i <= length(line)) and not done do
  1876.         begin
  1877.           if line[i] = ' ' then
  1878.               done := true
  1879.           else
  1880.               s := concat(s,copy(line,i,1));
  1881.           i := i + 1;
  1882.         end; (* while *)
  1883.       line := copy(line,i,length(line)-i+1);
  1884.     end; (* isolate_word *)
  1885.   
  1886.   function get_fn(var line, fn: string): boolean;
  1887.   
  1888.   var i, l: integer;
  1889.   
  1890.     begin
  1891.       get_fn := true;
  1892.       isolate_word(line, fn);
  1893.       l := length(fn);
  1894.       if (l < 1) then
  1895.           get_fn := false
  1896.     end; (* get_fn *)
  1897.   
  1898.   function getch(var ch: char): boolean;
  1899.   
  1900.   var s: string;
  1901.   
  1902.     begin
  1903.       isolate_word(line,s);
  1904.       if length(s) <> 1 then
  1905.           getch := false
  1906.       else
  1907.         begin
  1908.           ch := s[1];
  1909.           get_ch := true
  1910.         end (* else *)
  1911.     end; (* getch *)
  1912.   
  1913.   
  1914.   function get_sym(var word: vocab): statustype;
  1915.   
  1916.   var i: vocab;
  1917.       s: string;
  1918.       stat: statustype;
  1919.       done: boolean;
  1920.       matches: integer;
  1921.   
  1922.     begin
  1923.       eat_spaces(line);
  1924.       if length(line) = 0 then
  1925.           getsym := ateol
  1926.       else
  1927.         begin
  1928.           stat := null;
  1929.           done := false;
  1930.           isolate_word(line,s);
  1931.           i := allsym;
  1932.           matches := 0;
  1933.           repeat
  1934.              if (pos(s,vocablist[i]) = 1) and (i in expected) then
  1935.                 begin
  1936.                   matches := matches + 1;
  1937.                   word := i
  1938.                 end
  1939.               else if (s[1] < vocablist[i,1]) then
  1940.                   done := true;
  1941.               if (i = typesym) then
  1942.                   done := true
  1943.               else
  1944.                   i := succ(i)
  1945.           until (matches > 1) or done;
  1946.           if matches > 1 then
  1947.               stat := ambiguous
  1948.           else if (matches = 0) then
  1949.               stat := unrec;
  1950.           getsym := stat
  1951.         end (* else *)
  1952.     end; (* getsym *)
  1953.   
  1954.   function get_val(var value : integer): statustype;
  1955.   
  1956.   var i: vocab;
  1957.       s: string;
  1958.       stat: statustype;
  1959.       gotval,done: boolean;
  1960.       
  1961.       function NewVal(Value  : integer;
  1962.                       S      : vocab  ) : integer;
  1963.       
  1964.       begin
  1965.       case S of
  1966.         zerosym  : NewVal := Value * 10 + 0;
  1967.         onesym   : NewVal := Value * 10 + 1;
  1968.         twosym   : NewVal := Value * 10 + 2;
  1969.         threesym : NewVal := Value * 10 + 3;
  1970.         foursym  : NewVal := Value * 10 + 4;
  1971.         fivesym  : NewVal := Value * 10 + 5;
  1972.         sixsym   : NewVal := Value * 10 + 6;
  1973.         sevensym : NewVal := Value * 10 + 7;
  1974.         eightsym : NewVal := Value * 10 + 8;
  1975.         ninesym  : NewVal := Value * 10 + 9
  1976.         end{case}
  1977.       end{NewVal};
  1978.       
  1979.       function NextDigit : boolean;
  1980.       
  1981.       var
  1982.         i   : integer;
  1983.       
  1984.       begin
  1985.       if length(s) <= 1 then
  1986.         NextDigit := False
  1987.        else
  1988.          begin
  1989.          i := length(s) - 1;
  1990.          s := copy(s,2,i);
  1991.          NextDigit := True
  1992.          end
  1993.       end{NextDigit};
  1994.       
  1995.   
  1996.     begin
  1997.       eat_spaces(line);
  1998.       if length(line) = 0 then
  1999.         getval := ateol
  2000.       else
  2001.         begin
  2002.           stat := null;
  2003.           done := false;
  2004.           isolate_word(line,s);
  2005.           value := 0;
  2006.           repeat
  2007.             
  2008.             GotVal := False;
  2009.             for i := zerosym to ninesym do
  2010.               if (s[1] = vocablist[i][1]) then
  2011.                 begin
  2012.                 Value := NewVal(value,i);
  2013.                 GotVal := True
  2014.                 end;
  2015.             if not GotVal then
  2016.               begin
  2017.               stat := unrec;
  2018.               done := True
  2019.               end
  2020.              else
  2021.                done := not NextDigit
  2022.             
  2023.           until done;
  2024.           getval := stat
  2025.         end (* else *)
  2026.     end; (* getval *)
  2027.   
  2028. begin
  2029. state := start;
  2030. parse := null;
  2031. noun := nullsym;
  2032. verb := nullsym;
  2033. adj := nullsym;
  2034. uppercase(line);
  2035. repeat
  2036.    case state of
  2037.      start:
  2038.          begin
  2039.            expected := [consym, exitsym, helpsym, quitsym,
  2040.                         recsym, delsym, dirsym, sendsym,
  2041.                         setsym, showsym, transym, loadsym];
  2042.          status := getsym(verb);
  2043.          if status = ateol then
  2044.            begin
  2045.              parse := null;
  2046.              exit(parse)
  2047.            end (* if *)
  2048.          else
  2049.            if (status <> unrec) and (status <>  ambiguous) then
  2050.              case verb of
  2051.                   dirsym, consym: state := fin;
  2052.                   exitsym, quitsym: state := fin;
  2053.                   helpsym: state := get_help_parm;
  2054.                   recsym: state := fin;
  2055.                   loadsym, delsym, sendsym: state := getfilename;
  2056.                   setsym: state := get_set_parm;
  2057.                   showsym: state := get_show_parm;
  2058.                   transym: state := get_trans;
  2059.                 end (* case *);
  2060.           end; (* case start *)
  2061.       fin:
  2062.           begin
  2063.             expected := [];
  2064.             status := getsym(verb);
  2065.             if status = ateol then
  2066.               begin
  2067.                 parse := null;
  2068.                 exit(parse)
  2069.               end (* if status *)
  2070.             else
  2071.                 status := unconfirmed
  2072.           end; (* case fin *)
  2073.       getfilename:
  2074.         begin
  2075.           expected := [];
  2076.           if getfn(line,filename) then
  2077.             begin
  2078.               status := null;
  2079.               state := fin
  2080.             end (* if *)
  2081.           else
  2082.               status := fnexpected
  2083.         end; (* case get file name *)
  2084.       get_trans:
  2085.           begin
  2086.           expected := [typesym];
  2087.             status := getsym(noun);
  2088.             if status = ateol then
  2089.                 status := parm_expected
  2090.             else if (status <> unrec) and (status <>  ambiguous) then
  2091.                 case noun of
  2092.                   typesym: state := get_type;
  2093.                 end (* case *)
  2094.         end; (* case get_set_parm *)
  2095.       get_set_parm:
  2096.           begin
  2097.           expected := [paritysym, localsym, ibmsym, escsym, muxsym,
  2098.                       disksym, debugsym, filewarnsym, baudsym];
  2099.             status := getsym(noun);
  2100.             if status = ateol then
  2101.                 status := parm_expected
  2102.             else if (status <> unrec) and (status <>  ambiguous) then
  2103.                 case noun of
  2104.                   paritysym: state := get_parity;
  2105.                   localsym: state := get_on_off;
  2106.                   ibmsym: state := get_on_off;
  2107.                   escsym: state := getchar;
  2108.                   debugsym: state := getonoff;
  2109.                   filewarnsym: state := getonoff;
  2110.                   muxsym, baudsym : state := getvalue;
  2111.                   disksym : state := getvalue;
  2112.                   transym : state := get_on_off;
  2113.                 end (* case *)
  2114.         end; (* case get_set_parm *)
  2115.       get_type:
  2116.           begin
  2117.             expected := [binsym, datasym, imagesym, textsym];
  2118.             status := getsym(adj);
  2119.             if status = ateol then
  2120.                 status := parm_expected
  2121.             else if (status <> unrec) and (status <> ambiguous) then
  2122.                 state := fin
  2123.           end; (* case get_parity  *)
  2124.       get_parity:
  2125.           begin
  2126.             expected := [marksym, spacesym, nonesym, evensym, oddsym];
  2127.             status := getsym(adj);
  2128.             if status = ateol then
  2129.                 status := parm_expected
  2130.             else if (status <> unrec) and (status <> ambiguous) then
  2131.                 state := fin
  2132.           end; (* case get_parity  *)
  2133.       get_value:
  2134.              begin
  2135.                expected := [zerosym, onesym, twosym,
  2136.                             threesym, foursym, fivesym,
  2137.                             sixsym, sevensym, eightsym,
  2138.                             ninesym];
  2139.                status := getval(value);
  2140.                if status = ateol then
  2141.                    status := parm_expected
  2142.                 else 
  2143.                  if (status <> unrec) and (status <> ambiguous) then
  2144.                    state := fin
  2145.              end; (* get_speed *)
  2146.       get_on_off:
  2147.           begin
  2148.             expected := [onsym, offsym];
  2149.             status := getsym(adj);
  2150.             if status = ateol then
  2151.                 status := parm_expected
  2152.             else if (status <> unrec) and (status <> ambiguous) then
  2153.                 state := fin
  2154.           end; (* get_on_off *)
  2155.       get_char:
  2156.           if getch(newescchar) then
  2157.              state := fin
  2158.           else
  2159.              status := ch_expected;
  2160.       get_show_parm:
  2161.           begin
  2162.           expected := [allsym, paritysym, localsym, ibmsym, escsym, 
  2163.                        muxsym, transym, disksym, baudsym, debugsym, filewarnsym];
  2164.             status := getsym(noun);
  2165.             if status = ateol then
  2166.                 status := parm_expected
  2167.             else if (status <> unrec) and (status <>  ambiguous) then
  2168.                 state := fin
  2169.           end; (* case get_show_parm *)
  2170.       get_help_show:
  2171.           begin
  2172.             expected := [paritysym, localsym, ibmsym, escsym,
  2173.                         debugsym, filewarnsym];
  2174.             status := getsym(adj);
  2175.             if (status = at_eol) then
  2176.               begin
  2177.                 status := null;
  2178.                 state := fin
  2179.               end
  2180.             else if (status <> unrec) and (status <>  ambiguous) then
  2181.                 state := fin
  2182.           end; (* case get_help_show *)
  2183.       get_help_parm:
  2184.           begin
  2185.             expected := [consym, delsym, exitsym, helpsym,
  2186.                         quitsym, recsym, dirsym, transym, sendsym,
  2187.                         setsym, showsym];
  2188.             status := getsym(noun);
  2189.             if status = ateol then
  2190.               begin
  2191.                 parse := null;
  2192.                 exit(parse)
  2193.               end;
  2194.             if (status <> unrec) and (status <>  ambiguous) then
  2195.                 case noun of
  2196.                   consym: state := fin;
  2197.                   sendsym: state := fin;
  2198.                   recsym: state := fin;
  2199.                   setsym: state := get_help_show;
  2200.                   showsym: state := fin;
  2201.                   helpsym: state := fin;
  2202.                   exitsym, quitsym: state := fin;
  2203.                 end (* case *)
  2204.           end; (* case get_help_show *)
  2205.     end (* case *)
  2206. until (status <> null);
  2207. parse := status
  2208. end; (* parse *)
  2209.  
  2210. (* ---------------------------------------------------- *)
  2211.  
  2212. procedure initvocab;
  2213.  
  2214. var i: integer;
  2215.  
  2216.   begin
  2217.     vocablist[zerosym] :=     '0';
  2218.     vocablist[onesym] :=      '1';
  2219.     vocablist[twosym] :=      '2';
  2220.     vocablist[threesym] :=    '3';
  2221.     vocablist[foursym] :=     '4';
  2222.     vocablist[fivesym] :=     '5';
  2223.     vocablist[sixsym] :=      '6';
  2224.     vocablist[sevensym] :=    '7';
  2225.     vocablist[eightsym] :=    '8';
  2226.     vocablist[ninesym] :=     '9';
  2227.     vocablist[allsym] :=      'ALL';
  2228.     vocablist[baudsym] :=     'BAUDRATE';
  2229.     vocablist[binsym] :=      'BINARY';
  2230.     vocablist[consym] :=      'CONNECT';
  2231.     vocablist[datasym] :=     'DATA';
  2232.     vocablist[debugsym] :=    'DEBUG';
  2233.     vocablist[delsym] :=      'DELETE';
  2234.     vocablist[dirsym] :=      'DIRECTORY';
  2235.     vocablist[disksym] :=     'DISK';
  2236.     vocablist[escsym] :=      'ESCAPE';
  2237.     vocablist[evensym] :=     'EVEN';
  2238.     vocablist[exitsym] :=     'EXIT';
  2239.     vocablist[filewarnsym] := 'FILE-WARNING';
  2240.     vocablist[helpsym] :=     'HELP';
  2241.     vocablist[ibmsym] :=      'IBM';
  2242.     vocablist[imagesym] :=    'IMAGE';
  2243.     vocablist[loadsym] :=     'LOAD';
  2244.     vocablist[localsym] :=    'LOCAL-ECHO';
  2245.     vocablist[marksym] :=     'MARK';
  2246.     vocablist[muxsym] :=      'MUX';
  2247.     vocablist[nonesym] :=     'NONE';
  2248.     vocablist[oddsym] :=      'ODD';
  2249.     vocablist[offsym] :=      'OFF';
  2250.     vocablist[onsym] :=       'ON';
  2251.     vocablist[paritysym] :=   'PARITY';
  2252.     vocablist[quitsym] :=     'QUIT';
  2253.     vocablist[recsym] :=      'RECEIVE';
  2254.     vocablist[sendsym] :=     'SEND';
  2255.     vocablist[setsym] :=      'SET';
  2256.     vocablist[showsym] :=     'SHOW';
  2257.     vocablist[spacesym] :=    'SPACE';
  2258.     vocablist[transym] :=     'TRANSFER';
  2259.     vocablist[textsym] :=     'TEXT';
  2260.     vocablist[typesym] :=     'TYPE';
  2261.   end; (* initvocab *)
  2262.  
  2263.  
  2264.  
  2265. (* ---------------------------------------------------- *)
  2266.  
  2267.  
  2268.  
  2269. end{Parse}.
  2270.  
  2271. **** File RECSW.TEXT ***********************************************************
  2272.  
  2273. (* RECEIVE SECTION *)
  2274. {UCSD Pascal KERMIT for the Terak p-System, from Kate MacGregor, Cornell U}
  2275. {Modified for the Magiscan 2 by H Balen, Lancaster U }
  2276.  
  2277. segment procedure recsw(var rec_ok: boolean);
  2278.  
  2279. function rdata: char;
  2280.  
  2281. (* send file data *)
  2282.  
  2283. var Blk, num, len: integer;
  2284.     ch: char;
  2285.  
  2286.   begin
  2287.  
  2288.     repeat
  2289.         if numtry > maxtry then
  2290.           begin
  2291.             debugwrite('too many intial retries in rdata');
  2292.             state := 'a';
  2293.             exit(rdata)
  2294.           end;
  2295.  
  2296.         num_try := num_try + 1;
  2297.  
  2298.         ch := rpack(len,num,recpkt);   (* receive a packet *)
  2299.         if debug and (ch<>chr(0)) then packetwrite(recpkt,len);
  2300.  
  2301.         refresh_screen(numtry,n);
  2302.  
  2303.         if (ch = 'D') then             (* got data packet *)
  2304.           begin
  2305.             if (num <> (n mod 64)) then (* wrong packet *)
  2306.               begin
  2307.                 if (oldtry > maxtry) then
  2308.                   begin
  2309.                     debugwrite('too many data retries in rdata');
  2310.                     rdata := 'a';      (* too many tries, abort *)
  2311.                     exit(rdata)
  2312.                   end; (* if *)
  2313.  
  2314.                 n := n - 1;
  2315.  
  2316.                 if (num = (n mod 64)) then (* previous packet again *)
  2317.                   begin                (* so re-ACK it *)
  2318.                     debugint('re-acking ',num);
  2319.                     spack('Y',num,6,packet);
  2320.                     numtry := 0;       (* reset try counter *)
  2321.                                        (* stay in same state *)
  2322.                   end (* if *)
  2323.                 else begin             (* wrong number *)
  2324.                     debugwrite('wrong data sequence no. in rdata');
  2325.                     state := 'a'       (* so abort *)
  2326.                     end
  2327.               end (* if *)
  2328.             else                       (* right packet *)
  2329.               begin
  2330.                 if TranState = TxtFile then
  2331.                   bufemp(recpkt,f,len)  (* write data to file *)
  2332.                  else
  2333.                    Bbufemp(recpkt,len);
  2334.                 spack('Y',(n mod 64),0,packet); (* ACK packet *)
  2335.                 oldtry := numtry;      (* reset try counters *)
  2336.                 if numtry > 1 then
  2337.                     if istbrr then     (* clear buffer *)
  2338.                       begin
  2339.                         ch:=rcvbbt;
  2340.                         ch:='D';
  2341.                       end;
  2342.                 numtry := 0;
  2343.                 n := n + 1             (* bump packet number *)
  2344.                                        (* stay in data send state *)
  2345.               end (* else *)
  2346.           end (* if 'D' *)
  2347.         else if (ch = 'F') then        (* file header *)
  2348.           begin
  2349.             if (oldtry > maxtry) then
  2350.               begin
  2351.                 debugwrite('too many file head tries in rdata');
  2352.                 rdata := 'a';          (* too many tries, abort *)
  2353.                 exit(rdata)
  2354.               end; (* if *)
  2355.  
  2356.             n := n - 1;
  2357.  
  2358.             if (num = (n mod 64)) then (* previous packet again *)
  2359.               begin                    (* so re-ACK it *)
  2360.                 debugint('re-acking file header ',num);
  2361.                 spack('Y',num,0,packet);
  2362.                 if istbrr then begin
  2363.                   ch:=rcvbbt; (* and empty out buffer *)
  2364.                   ch:='F';
  2365.                   end;
  2366.                 numtry := 0;           (* reset try counter *)
  2367.                 state := state;        (* stay in same state *)
  2368.               end (* if *)
  2369.             else begin
  2370.               debugwrite('file info not previous packet in rdata');
  2371.                 state := 'a'           (* not previous packet, abort *)
  2372.                 end
  2373.           end (* if 'F' *)
  2374.         else if (ch = 'Z') then        (* end of file *)
  2375.           begin
  2376.             if (num <> (n mod 64)) then(* wrong packet, abort *)
  2377.               begin
  2378.                 debugwrite('wrong eof packet in rdata');
  2379.                 rdata := 'a';
  2380.                 exit(rdata)
  2381.               end; (* if *)
  2382.             spack('Y',n mod 64,0,packet); (* ok, ACK it *)
  2383.             { CloseF(filename,True); }
  2384.             n :=  n + 1;               (* bump packet counter *)
  2385.             state := 'b';              (* go to break state *)
  2386.             oldtry := numtry;
  2387.             numtry := 0;
  2388.           end (* else if 'Z' *)
  2389.         else if (ch = 'E') then        (* error packet *)
  2390.           begin
  2391.             error(recpkt,len);         (* display error *)
  2392.             state := 'a'               (* and abort *)
  2393.           end (* if 'E' *)
  2394.         else if (ch <> chr(0)) then begin (* some other packet type, *)
  2395.             state := 'a';                 (* abort *)
  2396.             debugwrite('wierd rdata packet');
  2397.             end
  2398.     until (state <> 'd');
  2399.     rdata := state
  2400.   end; (* rdata *)
  2401.  
  2402. function rfile: char;
  2403.  
  2404. (* receive file header *)
  2405.  
  2406. var num, len: integer;
  2407.     ch: char;
  2408.     oldfn: string;
  2409.     i: integer;
  2410.  
  2411. procedure makename(recpkt: packettype; var fn: string; l: integer);
  2412.  
  2413. function exist(fn: string): boolean;
  2414.  
  2415. (* returns true if file named fn exists *)
  2416.  
  2417. var f: file;
  2418.     OK : boolean;
  2419.  
  2420.   begin
  2421.     (*$I-*) (* turn off i/o checking *)
  2422.     reset(f,concat(disk,fn));
  2423.     OK := (ioresult = 0);
  2424.     if OK then
  2425.       close(f);
  2426.     Exist := OK
  2427.     (*$I+*)
  2428.   end; (* exist *)
  2429.  
  2430. procedure checkname(var fn: string);
  2431.  
  2432. (* if file fn exists, makes a new name which doesn't *)
  2433. (* does this by changing letters in file name until it *)
  2434. (* finds some combination which doesn't exitst *)
  2435.  
  2436. var ch: char;
  2437.     i: integer;
  2438.  
  2439.   begin
  2440.     i := 1;
  2441.     while (i <= length(fn)) and exist(fn) do
  2442.       begin
  2443.         ch := 'A';
  2444.         while (ch in ['A'..'Z']) and exist(fn) do
  2445.           begin
  2446.             fn[i] := ch;
  2447.             ch := succ(ch);
  2448.           end; (* while *)
  2449.         i := i + 1
  2450.       end; (* while *)
  2451.     end; (* checkname *)
  2452.  
  2453.   begin (* makename *)
  2454.     fn := copy('               ',1,15);    (* stretch length *)
  2455.     moveleft(recpkt[0],fn[1],l);           (* get filename from packet *)
  2456.     oldfn := copy(fn, 1,l);                (* save fn sent to show user *)
  2457.     fn := copy(fn,1,min(15,l));            (* set length of filename *)
  2458.                                            (* and make sure <= 15 *)
  2459.     uppercase(fn);
  2460.     {
  2461.     if length(fn) > 10 then
  2462.       fn := copy(fn,1,10);           (* can only be 15 long in all *)
  2463.     }
  2464.     if TranState = TxtFile then
  2465.       begin
  2466.       if pos('.TEXT',fn) <> (length(fn)-4) then
  2467.         begin
  2468.         if length(fn) > 10 then
  2469.           fn := copy(fn,1,10);           (* can only be 15 long in all *)
  2470.         fn := concat(fn,'.TEXT');          (* and we'll add .TEXT *)
  2471.         end; (* if *)
  2472.       end
  2473.      else
  2474.        if TranState = CodeFile then
  2475.          begin{ Same as above except this is a code file }
  2476.          if pos('.CODE',fn) <> (length(fn)-4) then
  2477.            begin
  2478.            if length(fn) > 10 then
  2479.              fn := copy(fn,1,10);
  2480.            fn := concat(fn,'.CODE')
  2481.            end
  2482.          end
  2483.         else
  2484.           begin { Same as last two but this is a data file }
  2485.           if pos('.DATA',fn) <> (length(fn)-4) then
  2486.             begin
  2487.             if length(fn) > 10 then
  2488.               fn := copy(fn,1,10);
  2489.             fn := concat(fn,'.DATA')
  2490.             end;
  2491.           end;
  2492.     if fwarn then                          (* if file warning is on *)
  2493.         checkname(fn);                       (* must check that name unique *)
  2494.   end; (* makename *)
  2495.  
  2496.   begin (* rfile *)
  2497.     if debug then
  2498.         debugwrite('rfile');
  2499.  
  2500.     if (numtry > maxtry) then         (* if too many tries, give up *)
  2501.       begin
  2502.         rfile := 'a';
  2503.         exit(rfile)
  2504.       end;
  2505.     numtry := numtry + 1;
  2506.  
  2507.     ch := rpack(len,num,recpkt);      (* receive a packet *)
  2508.     if debug and (ch<>chr(0)) then packetwrite(recpkt,len);
  2509.     refresh_screen(numtry,n);
  2510.  
  2511.     if ch = 'S' then                  (* send init, maybe our ACK lost *)
  2512.       begin
  2513.         if (oldtry > maxtry) then     (* too many tries, abort *)
  2514.           begin
  2515.             debugwrite('too many tries in rfile init');
  2516.             rfile := 'a';
  2517.             exit(rfile)
  2518.           end; (* if *)
  2519.  
  2520.         n := n - 1;
  2521.  
  2522.         if num = (n mod 64) then      (* previous packet mod 64? *)
  2523.           begin                       (* yes, ACK it again *)
  2524.             debugint('re-acking init ',num);
  2525.             spar(packet);             (* with our send init params *)
  2526.             spack('Y',num,7,packet);
  2527.             numtry := 0;              (* reset try counter *)
  2528.             rfile := state;           (* stay in same state *)
  2529.           end (* if *)
  2530.         else                          (* not previous packet, abort *)
  2531.           state := 'a'
  2532.       end (* if 'S' *)
  2533.     else if (ch = 'Z') then           (* end of file *)
  2534.       begin
  2535.         if (oldtry > maxtry) then     (* too many tries, abort *)
  2536.           begin
  2537.             debugwrite('too many tries in filehead eof');
  2538.             rfile := 'a';
  2539.             exit(rfile)
  2540.           end; (* if *)
  2541.  
  2542.         n := n - 1;
  2543.  
  2544.         if num = (n mod 64) then       (* previous packet mod 64? *)
  2545.           begin                       (* yes, ACK it again *)
  2546.             debugint('re-acking eof ',num);
  2547.             spack('Y',num,0,packet);
  2548.             numtry := 0;
  2549.             rfile := state            (* stay in same state *)
  2550.           end (* if *)
  2551.         else
  2552.             rfile := 'a'              (* no, abort *)
  2553.       end (* else if *)
  2554.     else if (ch = 'F') then           (* file header *)
  2555.       begin                           (* which is what we really want *)
  2556.         if (num <> (n mod 64)) then   (* if wrong packet, abort *)
  2557.           begin
  2558.             debugwrite('wrong seq. of file header');
  2559.             rfile := 'a';
  2560.             exit(rfile)
  2561.           end;
  2562.  
  2563.         makename(recpkt,filename,len); (* get filename, make unique if filew *)
  2564.         gotoxy(filepos,fileline);
  2565.         write(oldfn,' ==> ',filename);
  2566.  
  2567.         if not getfil(filename) then  (* try to open new file *)
  2568.           begin
  2569.             inoerror(ioresult);        (* if unsuccessful, tell them *)
  2570.             rfile := 'a';             (* and abort *)
  2571.             exit(rfile)
  2572.           end; (* if *)
  2573.  
  2574.         spack('Y',n mod 64,0,packet); (* ACK file header *)
  2575.         oldtry := numtry;             (* reset try counters *)
  2576.         numtry := 0;
  2577.         n := n + 1;                   (* bump packet number *)
  2578.         rfile := 'd';                 (* switch to data state *)
  2579.       end (* else if *)
  2580.     else if ch = 'B' then             (* break transmission *)
  2581.       begin
  2582.         if (num <> (n mod 64)) then            (* wrong packet, abort *)
  2583.           begin
  2584.             debugwrite('wrong sequence in break packet');
  2585.             rfile := 'a';
  2586.             exit(rfile)
  2587.           end;
  2588.         spack('Y',n mod 64,0,packet); (* say ok *)
  2589.         rfile := 'c'                  (* go to complete state *)
  2590.       end (* else if *)
  2591.     else if (ch = 'E') then
  2592.       begin
  2593.         error(recpkt,len);
  2594.         rfile := 'a'
  2595.       end
  2596.     else if (ch = chr(0)) then        (* returned false *)
  2597.         rfile := state                (* so stay in same state *)
  2598.     else begin                        (* some weird state, so abort *)
  2599.         rfile := 'a';
  2600.         debugwrite('wierd rfile packet');
  2601.         end
  2602.   end; (* rfile *)
  2603.  
  2604. function rbreak: char;
  2605.  
  2606. (* receive file header *)
  2607.  
  2608. var num, len: integer;
  2609.     ch: char;
  2610.     i: integer;
  2611.  
  2612.   begin (* rbreak *)
  2613.     if debug then
  2614.         debugwrite('rbreak');
  2615.  
  2616.     if (numtry > maxtry) then         (* if too many tries, give up *)
  2617.       begin
  2618.         rbreak := 'a';
  2619.         exit(rbreak)
  2620.       end;
  2621.     numtry := numtry + 1;
  2622.  
  2623.     ch := rpack(len,num,recpkt);      (* receive a packet *)
  2624.     if debug and (ch<>chr(0)) then packetwrite(recpkt,len);
  2625.     refresh_screen(numtry,n);
  2626.     
  2627.     if (ch = 'Z') then
  2628.       begin{ is previous eof packet }
  2629.  
  2630.       n := n -1;
  2631.       if (num = (n mod 64)) then (* previous packet again *)
  2632.         begin                (* so re-ACK it *)
  2633.           debugint('re-acking ',num);
  2634.           spack('Y',num,6,packet);
  2635.           numtry := 0;       (* reset try counter *)
  2636.                              (* stay in same state *)
  2637.         end (* if *)
  2638.       else begin             (* wrong number *)
  2639.           debugwrite('wrong data sequence no. in rbreak');
  2640.           state := 'a'       (* so abort *)
  2641.           end
  2642.       end
  2643.    else
  2644.     if ch = 'B' then             (* break transmission *)
  2645.       begin
  2646.         if (num <> (n mod 64)) then            (* wrong packet, abort *)
  2647.           begin
  2648.             debugwrite('wrong sequence in break packet');
  2649.             rbreak := 'a';
  2650.             exit(rbreak)
  2651.           end;
  2652.         spack('Y',n mod 64,0,packet); (* say ok *)
  2653.         rbreak := 'c'                  (* go to complete state *)
  2654.       end (* else if *)
  2655.     else if (ch = 'E') then
  2656.       begin
  2657.         error(recpkt,len);
  2658.         rbreak := 'a'
  2659.       end
  2660.     else if (ch = chr(0)) then        (* returned false *)
  2661.         rbreak := state                (* so stay in same state *)
  2662.     else begin                        (* some weird state, so abort *)
  2663.         rbreak := 'a';
  2664.         debugwrite('wierd break packet');
  2665.         end
  2666.   end; (* rbreak *)
  2667.   
  2668. function rinit: char;
  2669.  
  2670. (* receive initialization *)
  2671.  
  2672. var num, len: integer;  (* packet number and length *)
  2673.     ch: char;
  2674.  
  2675.   begin
  2676.     if debug then
  2677.         debugwrite('rinit');
  2678.  
  2679.     numtry := numtry + 1;
  2680.  
  2681.     ch := rpack(len,num,recpkt); (* receive a packet *)
  2682.     if debug and (ch<>chr(0)) then packetwrite(recpkt,len);
  2683.     refresh_screen(num_try,n);
  2684.  
  2685.     if (ch = 'S') then           (* send init packet *)
  2686.       begin
  2687.         rpar(recpkt);            (* get other side's init data *)
  2688.         spar(packet);            (* fill packet with my init data *)
  2689.         if TranState <> TxtFile then
  2690.           ctl_set := [chr(1)..chr(31),chr(del),quote,bquote]
  2691.          else
  2692.            ctl_set := [chr(1)..chr(31),chr(del),quote];
  2693.         spack('Y',n mod 64,7,packet); (* ACK with my params *)
  2694.         oldtry := numtry;        (* save old try count *)
  2695.         numtry := 0;             (* start a new counter *)
  2696.         n := n + 1;              (* bump packet number *)
  2697.         rinit := 'f';            (* enter file send state *)
  2698.       end (* if 'S' *)
  2699.     else if (ch = 'E') then
  2700.       begin
  2701.         rinit := 'a';
  2702.         error(recpkt,len)
  2703.       end (* if 'E' *)
  2704.     else if (ch = chr(0)) then
  2705.         rinit := 'r'             (* stay in same state *)
  2706.     else begin
  2707.         rinit := 'a';             (* abort *)
  2708.         debugwrite('wierd rinit packet');
  2709.         end
  2710.   end; (* rinit *)
  2711.  
  2712. (* state table switcher for receiving packets *)
  2713.  
  2714.   begin (* recswok *)
  2715.     writescreen('Receiving');
  2716.     state := 'r';            (* initial state is send *)
  2717.     n := 0;                  (* set packet # *)
  2718.     numtry := 0;             (* no tries yet *)
  2719.  
  2720.     while true do
  2721.         if state in ['d', 'f', 'r', 'c', 'a', 'b'] then
  2722.           case state of
  2723.               'd': state := rdata;
  2724.               'f': state := rfile;
  2725.               'r': state := rinit;
  2726.               'b': state := rbreak;
  2727.               'c': begin
  2728.                      rec_ok := true;
  2729.                      CloseF(filename,true);
  2730.                      exit(recsw)
  2731.                    end; (* case c *)
  2732.               'a': begin
  2733.                      rec_ok := false;
  2734.                      CloseF(filename,false);
  2735.                      exit(recsw)
  2736.                    end (* case a *)
  2737.             end (* case *)
  2738.         else (* state not in legal states *)
  2739.           begin
  2740.             rec_ok := false;
  2741.             CloseF(filename,False);
  2742.             exit(recsw)
  2743.           end (* else *)
  2744.   end; (* recsw *)
  2745.  
  2746. **** File RS232.TEXT ***********************************************************
  2747.  
  2748. (*$S+*)
  2749.  
  2750. { This unit contains the subroutines necessary for
  2751.   accessing/using the RS232 interface of the Magiscan }
  2752.  
  2753. Unit RS232;
  2754.  
  2755. { Written by H Balen 1-Aug-85 }
  2756. { Modified by H Balen 23-Sep-85 }
  2757.  
  2758. Interface
  2759.  
  2760.  
  2761. Uses
  2762.   M2Types,M2IpRoot,M2Sys;
  2763.  
  2764. var
  2765.   MuxDelay    : integer;
  2766.   
  2767.   procedure InitM;
  2768.   
  2769.   function ISTATR : boolean;
  2770.   
  2771.   function ISTBRR : boolean;
  2772.   
  2773.   function ISTBOR : boolean;
  2774.  
  2775.   function ISTBFE : boolean;
  2776.  
  2777.   function ISTBTR : boolean;
  2778.   
  2779.   procedure SNDBBT( BT : char );
  2780.   
  2781.   procedure SNDABT( BT : char );
  2782.   
  2783.   function RCVBBT : Char;
  2784.   
  2785.   
  2786.  
  2787. Implementation
  2788.  
  2789. { All the routines below have the same function as those
  2790.   in the text file WDPROCS for the UCM version of kermit }
  2791.  
  2792. const
  2793.   RxBit   = 4;
  2794.   TxBit   = 5;
  2795.   Uart    = 56;
  2796.   Control = 57;
  2797.   Status  = 57;
  2798.   
  2799.   { RS232 dependant constants for the status registar }
  2800.   OverError = 4;
  2801.   FrameError = 5;
  2802.  
  2803. type
  2804.   RegByte = record
  2805.                case Boolean of
  2806.                  True : ( Value : integer );
  2807.         
  2808. (* ---------------------------------------------------- *)
  2809.  
  2810. function ISTBOR;
  2811. {  Is it true that data OverRun occurred ?,}
  2812.  
  2813. var
  2814.   Byte : RegByte;
  2815.  
  2816. begin
  2817. Byte.Value := IORead(Status);
  2818. ISTBOR := Byte.B[OverError]
  2819. end{ISTBOR};
  2820.  
  2821. (* ---------------------------------------------------- *)
  2822.  
  2823. function ISTBFE;
  2824. { Is it true that Framing-Error occured? }
  2825.  
  2826. var
  2827.   Byte  : RegByte;
  2828.  
  2829. begin
  2830. Byte.Value := IORead(Status);
  2831. ISTBFE := Byte.B[FrameError]
  2832. end{ISTBFE};
  2833.  
  2834. (* ---------------------------------------------------- *)
  2835.  
  2836. function ISTBTR;
  2837. { Is it true that transmit is ready ? }
  2838.  
  2839. begin
  2840. ISTBTR := not IOStatus(TxBit)
  2841. end{ISTBR};
  2842.  
  2843. (* ---------------------------------------------------- *)
  2844.  
  2845. procedure InitM;
  2846. { This initialises the RS232 port }
  2847.  
  2848. begin
  2849. IOWrite(64,Control); { Internal Reset }
  2850. IOWrite(78,Control); { Set the mode }
  2851. IOWrite(55,Control); { Error Reset }
  2852. BaudRate(1200);
  2853. MuxDelay := 0;
  2854. end{RSInit};
  2855.  
  2856. (* ---------------------------------------------------- *)
  2857.  
  2858. procedure SNDBBT;
  2859. { After getting back a TRUE result from isttr, this function
  2860.   SNDBBT is used to actually send the byte of data from the
  2861.   CPU to the device. Note that any attempt to call SNDBBT before
  2862.   getting TRUE from isttr can result in clobering the previous
  2863.   data }
  2864.  
  2865. var
  2866.   i   : integer;
  2867.  
  2868. begin
  2869. for i := 0 to (10 * MuxDelay) do;
  2870. {[UnitWrite(8,i,1);}
  2871. IOWrite(ord(BT),Uart);
  2872. end{SendToUART};
  2873.  
  2874. (* ---------------------------------------------------- *)
  2875.  
  2876. procedure SNDABT;
  2877. { Same as the SNDBBT except this is for the keyboard }
  2878.  
  2879. const
  2880.   Ret  = 13;
  2881.   LF   = 10;
  2882.  
  2883. begin
  2884. if ord(BT) <> Ret then
  2885.   if ord(BT) = LF then{ If we have a LF then }
  2886.     write(chr(Ret)) { send a CR instead }
  2887.    else
  2888.      write(BT) { else send the character itself }
  2889. end{SNABT};
  2890.  
  2891. (* ---------------------------------------------------- *)
  2892.  
  2893. function RCVBBT;
  2894.  
  2895. var
  2896.   Ch    : char;
  2897.  
  2898. begin
  2899. RCVBBT := chr( IORead(Uart) )
  2900. {UnitRead(7,Ch,1);
  2901. RCVBBT := Ch}
  2902. end{RxUART};
  2903.  
  2904. (* ---------------------------------------------------- *)
  2905.  
  2906. end{RS232}.
  2907.  
  2908. **** File RSUTILS.TEXT *********************************************************
  2909.  
  2910. (*$S+*)
  2911.  
  2912. { This unit contains the subroutines necessary for
  2913.   accessing/using the RS232 interface of the Magiscan }
  2914.  
  2915. Unit RS232;
  2916.  
  2917. { Written by H Balen 1-Aug-85 }
  2918. { Modified by H Balen 23-Sep-85 }
  2919.  
  2920. Interface
  2921.  
  2922.  
  2923. Uses
  2924.   M2Types,M2IpRoot,M2Sys;
  2925.  
  2926. var
  2927.   MuxDelay    : integer;
  2928.   
  2929.   procedure InitM;
  2930.   
  2931.   function ISTATR : boolean;
  2932.   
  2933.   function ISTBRR : boolean;
  2934.   
  2935.   function ISTBOR : boolean;
  2936.  
  2937.   function ISTBFE : boolean;
  2938.  
  2939.   function ISTBTR : boolean;
  2940.   
  2941.   procedure SNDBBT( BT : char );
  2942.   
  2943.   procedure SNDABT( BT : char );
  2944.   
  2945.   function RCVBBT : Char;
  2946.   
  2947.   
  2948.  
  2949. Implementation
  2950.  
  2951. { All the routines below have the same function as those
  2952.   in the text file WDPROCS for the UCM version of kermit }
  2953.  
  2954. const
  2955.   RxBit   = 4;
  2956.   TxBit   = 5;
  2957.   Uart    = 56;
  2958.   Control = 57;
  2959.   Status  = 57;
  2960.   
  2961.   { RS232 dependant constants for the status registar }
  2962.   OverError = 4;
  2963.   FrameError = 5;
  2964.  
  2965. type
  2966.   RegByte = record
  2967.                case Boolean of
  2968.                  True : ( Value : integer );
  2969.         
  2970. (* ---------------------------------------------------- *)
  2971.  
  2972. function ISTBOR;
  2973. {  Is it true that data OverRun occurred ?,}
  2974.  
  2975. var
  2976.   Byte : RegByte;
  2977.  
  2978. begin
  2979. Byte.Value := IORead(Status);
  2980. ISTBOR := Byte.B[OverError]
  2981. end{ISTBOR};
  2982.  
  2983. (* ---------------------------------------------------- *)
  2984.  
  2985. function ISTBFE;
  2986. { Is it true that Framing-Error occured? }
  2987.  
  2988. var
  2989.   Byte  : RegByte;
  2990.  
  2991. begin
  2992. Byte.Value := IORead(Status);
  2993. ISTBFE := Byte.B[FrameError]
  2994. end{ISTBFE};
  2995.  
  2996. (* ---------------------------------------------------- *)
  2997.  
  2998. function ISTBTR;
  2999. { Is it true that transmit is ready ? }
  3000.  
  3001. begin
  3002. ISTBTR := not IOStatus(TxBit)
  3003. end{ISTBR};
  3004.  
  3005. (* ---------------------------------------------------- *)
  3006.  
  3007. procedure InitM;
  3008. { This initialises the RS232 port }
  3009.  
  3010. begin
  3011. IOWrite(64,Control); { Internal Reset }
  3012. IOWrite(78,Control); { Set the mode }
  3013. IOWrite(55,Control); { Error Reset }
  3014. BaudRate(1200);
  3015. MuxDelay := 0;
  3016. end{RSInit};
  3017.  
  3018. (* ---------------------------------------------------- *)
  3019.  
  3020. procedure SNDBBT;
  3021. { After getting back a TRUE result from isttr, this function
  3022.   SNDBBT is used to actually send the byte of data from the
  3023.   CPU to the device. Note that any attempt to call SNDBBT before
  3024.   getting TRUE from isttr can result in clobering the previous
  3025.   data }
  3026.  
  3027. var
  3028.   i   : integer;
  3029.  
  3030. begin
  3031. for i := 0 to (10 * MuxDelay) do;
  3032. {[UnitWrite(8,i,1);}
  3033. IOWrite(ord(BT),Uart);
  3034. end{SendToUART};
  3035.  
  3036. (* ---------------------------------------------------- *)
  3037.  
  3038. procedure SNDABT;
  3039. { Same as the SNDBBT except this is for the keyboard }
  3040.  
  3041. const
  3042.   Ret  = 13;
  3043.   LF   = 10;
  3044.  
  3045. begin
  3046. if ord(BT) <> Ret then
  3047.   if ord(BT) = LF then{ If we have a LF then }
  3048.     write(chr(Ret)) { send a CR instead }
  3049.    else
  3050.      write(BT) { else send the character itself }
  3051. end{SNABT};
  3052.  
  3053. (* ---------------------------------------------------- *)
  3054.  
  3055. function RCVBBT;
  3056.  
  3057. var
  3058.   Ch    : char;
  3059.  
  3060. begin
  3061. RCVBBT := chr( IORead(Uart) )
  3062. {UnitRead(7,Ch,1);
  3063. RCVBBT := Ch}
  3064. end{RxUART};
  3065.  
  3066. (* ---------------------------------------------------- *)
  3067.  
  3068. end{RS232}.
  3069.  
  3070. **** File SENDSW.TEXT **********************************************************
  3071.  
  3072. (* Send Section *)
  3073. {UCSD Pascal KERMIT for the Terak p-System, from Kate MacGregor, Cornell U}
  3074. { adapted by H Balen for the Magiscan 2, Lancaster U }
  3075.  
  3076. segment procedure sendsw(var send_ok: boolean);
  3077.  
  3078. var io_status: integer;
  3079.  
  3080. procedure openfile;
  3081.  
  3082. (* resets file & gets past first 2 blocks *)
  3083. var
  3084.   OK   : boolean;
  3085.  
  3086.   begin
  3087.   OK := ReadOpenF(filename,TranState);
  3088.   io_status := io_result;
  3089.   end; (* openfile *)
  3090.  
  3091. function sinit: char;
  3092.  
  3093. (* send init packet & receive other side's *)
  3094.  
  3095. var num, len, i: integer;  (* packet number and length *)
  3096.     ch: char;
  3097.  
  3098.   begin
  3099.     if debug then
  3100.         debugwrite('sinit');
  3101.  
  3102.     if numtry > maxtry then
  3103.       begin
  3104.         sinit := 'a';
  3105.         exit(sinit)
  3106.       end;
  3107.  
  3108.     num_try := num_try + 1;
  3109.     spar(packet);
  3110.  
  3111.     if istbrr then ch:=rcvbbt; (* clear modem buffer *)
  3112.  
  3113.     refresh_screen(numtry,n);
  3114.  
  3115.     spack('S',n mod 64,7,packet);
  3116.  
  3117.     ch := rpack(len,num,recpkt);
  3118.  
  3119.     if (ch = 'N') then
  3120.       begin
  3121.         sinit := 's';
  3122.         exit(sinit)
  3123.       end (* if 'N' *)
  3124.     else if (ch = 'Y') then
  3125.       begin
  3126.         if ((n mod 64) <> num) then       (* not the right ack *)
  3127.           begin
  3128.             sinit := state;
  3129.             exit(sinit)
  3130.           end;
  3131.         rpar(recpkt);
  3132.         if (eol = chr(0)) then   (* if they didn't spec eol *)
  3133.             eol := chr(my_eol);    (* use mine *)
  3134.         if (quote = chr(0)) then (* if they didn't spec quote *)
  3135.             quote := my_quote;     (* use mine *)
  3136.         ctl_set := [chr(1)..chr(31),chr(del),quote];
  3137.         if TranState <> TxtFile then
  3138.           begin
  3139.           if (bquote = 'Y') then
  3140.             bquote := my_bquote;
  3141.           ctl_set := [chr(1)..chr(31),chr(del),quote,bquote];
  3142.           end;
  3143.         numtry := 0;
  3144.         n := n + 1;              (* increase packet number *)
  3145.         sinit := 'f';
  3146.         exit(sinit)
  3147.       end (* else if 'Y' *)
  3148.     else if (ch = 'E') then
  3149.       begin
  3150.         error(recpkt,len);
  3151.         sinit := 'a'
  3152.       end (* if 'E' *)
  3153.     else if (ch = chr(0)) then
  3154.         sinit := state
  3155.     else if (ch <> 'N') then
  3156.         sinit := 'a'
  3157.   end; (* sinit *)
  3158.  
  3159. function sdata: char;
  3160.  
  3161. (* send file data *)
  3162.  
  3163. var num, len: integer;
  3164.     ch: char;
  3165.     packarray: array[false..true] of packettype;
  3166.     sizearray: array[false..true] of integer;
  3167.     current: boolean;
  3168.     b: boolean;
  3169.  
  3170. function other(b: boolean): boolean;
  3171.  
  3172. (* complements a boolean which is used as array index *)
  3173.  
  3174.   begin
  3175.     if b then
  3176.         other := false
  3177.     else
  3178.         other := true
  3179.   end; (* other *)
  3180.  
  3181.   begin
  3182.     current := true;
  3183.     packarray[current] := packet;
  3184.     sizearray[current] := size;
  3185.     while (state = 'd') do
  3186.       begin
  3187.         if (numtry > maxtry) then             (* if too many tries, give up *)
  3188.             state := 'a';
  3189.  
  3190.         b := other(current);
  3191.         numtry := numtry + 1;
  3192.  
  3193.         refresh_screen(numtry,n);
  3194.                                           (* send a data packet *)
  3195.         spack('D',n mod 64,sizearray[current],packarray[current]);
  3196.  
  3197.         ch := rpack(len,num,recpkt);      (* receive a packet *)
  3198.                                           (* set up next packet *)
  3199.         if TranState = TxtFile then
  3200.           sizearray[b] := bufill(packarray[b])
  3201.          else
  3202.            sizearray[b] := Bbufill(packarray[b]);
  3203.  
  3204.         if ch = 'N' then                  (* NAK, so just stay in this state *)
  3205.             if ((n+1) mod 64 <> num) then (* unless NAK for next, which *)
  3206.                 sdata := state
  3207.             else                          (* is just like ACK for this packet *)
  3208.               begin
  3209.                 if num > 0 then
  3210.                     num := (num - 1)      (* in which case, decrement num *)
  3211.                 else
  3212.                     num := 63;
  3213.                 ch := 'Y';                (* and indicate an ACK *)
  3214.               end; (* else *)
  3215.  
  3216.         if (ch = 'Y') then
  3217.            begin
  3218.              if ((n mod 64) <> num) then (* if wrong ACK *)
  3219.                begin
  3220.                  sdata := state;         (* stay in same state *)
  3221.                  exit(sdata);            (* get out of here *)
  3222.                end; (* if *)
  3223.              if numtry > 1 then          (* if anything in buffer, flush it *)
  3224.                  if istbrr then begin
  3225.                    ch:=rcvbbt;
  3226.                    ch:='Y';
  3227.                    end;
  3228.              numtry := 0;
  3229.              n := n + 1;
  3230.              current := b;
  3231.              if sizearray[current] = ateof then
  3232.                  state := 'z'            (* set state to eof *)
  3233.              else
  3234.                  state := 'd'            (* else stay in data state *)
  3235.            end (* if *)
  3236.           else if (ch = 'E') then
  3237.             begin
  3238.               error(recpkt,len);
  3239.               state := 'a'
  3240.             end (* if 'E' *)
  3241.           else if (ch = chr(0)) then      (* receive failure, so stay in d *)
  3242.             begin
  3243.             end
  3244.           else if (ch <> 'N') then
  3245.            eger;
  3246.  
  3247.   begin
  3248.     for i := 1 to length(s) do
  3249.         if s[i] in ['a'..'z'] then
  3250.             s[i] := chr(ord('A') + ord(s[i]) - ord('a'))
  3251.   end; (* uppercase *)
  3252.  
  3253.   begin
  3254.     count := 0;
  3255.     l := length(fn);
  3256.     for i := 1 to l do                                  (* count '.'s in fn *)
  3257.         if fn[i] = '.' then
  3258.             count := count + 1;
  3259.     for i := 1 to count-1 do                            (* remove all but 1 *)
  3260.       begin
  3261.         j := 1;
  3262.         while (j < l) and (fn[j] <> '.') do
  3263.             j := j + 1;
  3264.             delete(fn,j,1);l := l - 1
  3265.       end; (* for i *)
  3266.     l := length(fn);
  3267.     i := pos(':',fn);
  3268.     if (i <> 0) then
  3269.       begin
  3270.         fn := copy(fn,i,l-i);
  3271.         l := length(fn)
  3272.       end;
  3273.     i := 1;
  3274.     while (i <= length(fn)) do
  3275.         if not(fn[i] in ['a'..'z','A'..'Z','.','0'..'9']) then
  3276.             delete(fn,i,1)
  3277.         else
  3278.             i := i + 1;
  3279.     uppercase(fn)
  3280.   end; (* legalize *)
  3281.  
  3282.   begin
  3283.     if debug then
  3284.         debugwrite('sfile');
  3285.  
  3286.     if (numtry > maxtry) then          (* if too many tries, give up *)
  3287.       begin
  3288.         sfile := 'a';
  3289.         exit(sfile)
  3290.       end;
  3291.     numtry := numtry + 1;
  3292.  
  3293.     oldfn := filename;
  3294.     legalize(filename);                (* make filename acceptable to remote *)
  3295.     len := length(filename);
  3296.  
  3297.     moveleft(filename[1],fn[0],len);   (* move filename into a packettype *)
  3298.  
  3299.     gotoxy(filepos,fileline);
  3300.     write(oldfn,' ==> ',filename);
  3301.  
  3302.     refresh_screen(numtry,n);
  3303.  
  3304.     spack('F',n mod 64,len,fn);               (* send file header packet *)
  3305.  
  3306.     ch := rpack(len,num,recpkt);
  3307.     
  3308.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  3309.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  3310.             begin
  3311.             sfile := 'f';
  3312.             exit(sfile)                (* is just like ACK for this packet *)
  3313.             end
  3314.         else
  3315.           begin
  3316.             if (num > 0) then
  3317.                 num := (num - 1)       (* in which case, decrement num *)
  3318.             else
  3319.                 num := 63;
  3320.             ch := 'Y';                 (* and indicate an ACK *)
  3321.           end; (* else *)
  3322.  
  3323.     if (ch = 'Y') then
  3324.       begin
  3325.         if ((n mod 64) <> num) then  (* if wrong ACK, stay in F state *)
  3326.             begin
  3327.             sfile := 'f';
  3328.             exit(sfile)
  3329.             end;
  3330.         if TranState = TxtFile then
  3331.           size := bufill(packet)     (* get first data from file *)
  3332.          else
  3333.            size := Bbufill(packet);
  3334.         numtry := 0;
  3335.         n := n + 1;
  3336.         sfile := 'd';
  3337.       end (* if *)
  3338.     else if (ch = 'E') then
  3339.       begin
  3340.         error(recpkt,len);
  3341.         sfile := 'a'
  3342.       end (* if 'E' *)
  3343.     else if (ch <> chr(0)) and (ch <> 'N') then (* don't recognize it *)
  3344.         sfile := 'a'
  3345.   end; (* sfile *)
  3346.  
  3347. function seof: char;
  3348.  
  3349. (* send end of file *)
  3350.  
  3351. var num, len: integer;
  3352.     ch: char;
  3353.  
  3354.   begin
  3355.     if debug then
  3356.         debugwrite('seof');
  3357.  
  3358.     if (numtry > maxtry) then          (* if too many tries, give up *)
  3359.       begin
  3360.         seof := 'a';
  3361.         exit(seof)
  3362.       end;
  3363.     numtry := numtry + 1;
  3364.  
  3365.     refresh_screen(numtry,n);
  3366.  
  3367.     spack('Z',(n mod 64),0,packet);    (* send end of file packet *)
  3368.  
  3369.     if debug then
  3370.         debugwrite('seof1');
  3371.  
  3372.     ch := rpack(len,num,recpkt);
  3373.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  3374.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  3375.             exit(seof)                 (* is just like ACK for this packet *)
  3376.         else
  3377.           begin
  3378.             if num > 0 then
  3379.                 num := (num - 1)       (* in which case, decrement num *)
  3380.             else
  3381.                 num := 63;
  3382.             ch := 'Y';                 (* and indicate an ACK *)
  3383.           end; (* else *)
  3384.  
  3385.     if (ch = 'Y') then
  3386.       begin
  3387.         if debug then
  3388.             debugwrite('seof2');
  3389.         if ((n mod 64) <> num) then     (* if wrong ACK, stay in F state *)
  3390.             exit(seof);
  3391.         numtry := 0;
  3392.         n := n + 1;
  3393.         if debug then
  3394.             debugwrite(concat('closing ',s));
  3395.         CloseF(filename,False);
  3396.         seof := 'b'
  3397.       end (* if *)
  3398.     else if (ch = 'E') then
  3399.       begin
  3400.         error(recpkt,len);
  3401.         seof := 'a'
  3402.       end (* if 'E' *)
  3403.     else if (ch = chr(0)) then         (* receive failed, so stay in z state *)
  3404.       begin
  3405.       end
  3406.     else if (ch <> 'N') then           (* other error, just abort *)
  3407.         seof := 'a'
  3408.   end; (* seof *)
  3409.  
  3410. function sbreak: char;
  3411.  
  3412. var num, len: integer;
  3413.     ch: char;
  3414.  
  3415. (* send break (end of transmission) *)
  3416.  
  3417.   begin
  3418.     if debug then
  3419.         debugwrite('sbreak');
  3420.  
  3421.     if (numtry > maxtry) then          (* if too many tries, give up *)
  3422.       begin
  3423.         sbreak := 'a';
  3424.         exit(sbreak)
  3425.       end;
  3426.     numtry := numtry + 1;
  3427.  
  3428.     refresh_screen(numtry,n);
  3429.  
  3430.     spack('B',(n mod 64),0,packet);    (* send end of file packet *)
  3431.  
  3432.     ch := rpack(len,num,recpkt);
  3433.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  3434.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  3435.             exit(sbreak)               (* is just like ACK for this packet *)
  3436.         else
  3437.           begin
  3438.             if num > 0 then
  3439.                 num := (num - 1)       (* in which case, decrement num *)
  3440.             else
  3441.                 num := 63;
  3442.             ch := 'Y';                 (* and indicate an ACK *)
  3443.           end; (* else *)
  3444.  
  3445.     if (ch = 'Y') then
  3446.       begin
  3447.         if ((n mod 64) <> num) then    (* if wrong ACK, stay in B state *)
  3448.             exit(sbreak);
  3449.         numtry := 0;
  3450.         n := n + 1;
  3451.         sbreak := 'c'                  (* else, switch state to complete *)
  3452.       end (* if *)
  3453.     else if (ch = 'E') then
  3454.       begin
  3455.         error(recpkt,len);
  3456.         sbreak := 'a'
  3457.       end (* if 'E' *)
  3458.     else if (ch = chr(0)) then         (* receive failed, so stay in z state *)
  3459.       begin
  3460.       end
  3461.     else if (ch <> 'N') then           (* other error, just abort *)
  3462.         sbreak := 'a'
  3463.   end; (* sbreak *)
  3464.  
  3465. (* state table switcher for sending *)
  3466.  
  3467.   begin (* sendsw *)
  3468.  
  3469.     if debug then
  3470.         debugwrite(concat('Opening ',filename));
  3471.  
  3472.     openfile;
  3473.     if io_status <> 0 then
  3474.       begin
  3475.         writeln(chr(ff){clear_screen});
  3476.         ino_error(io_status);
  3477.         send_ok := false;
  3478.         exit(sendsw)
  3479.       end;
  3480.  
  3481.     write_screen('Sending');
  3482.     state := 's';
  3483.     n := 0;       (* set packet # *)
  3484.     numtry := 0;
  3485.     while true do
  3486.         if state in ['d', 'f', 'z', 's', 'b', 'c', 'a'] then
  3487.           case state of
  3488.               'd': state := sdata;
  3489.               'f': state := sfile;
  3490.               'z': state := seof;
  3491.               's': state := sinit;
  3492.               'b': state := sbreak;
  3493.               'c': begin
  3494.                      send_ok := true;
  3495.                      exit(sendsw)
  3496.                    end; (* case c *)
  3497.               'a': begin
  3498.                      send_ok := false;
  3499.                      exit(sendsw)
  3500.                    end (* case a *)
  3501.             end (* case *)
  3502.         else (* state not in legal states *)
  3503.           begin
  3504.             send_ok := false;
  3505.             CloseF(filename,send_ok);
  3506.             exit(sendsw)
  3507.           end (* else *)
  3508.   end; (* sendsw *)
  3509.  
  3510. **** File SYSUNIT.TEXT *********************************************************
  3511.  
  3512. (*$S+*)
  3513.  
  3514. { This unit allows the users to access the directory information
  3515.   held on each disk }
  3516. Unit SysUnit;
  3517.  
  3518.  
  3519.   Interface
  3520.   
  3521.   
  3522.   Uses
  3523.      M2Types,M2IpRoot,M2Sys;
  3524.   
  3525.   type
  3526.     FileType = String[15];
  3527.     Volume = 4..12;
  3528.   
  3529.   var
  3530.     D      : File;
  3531.     
  3532.   
  3533.   procedure DelFile( G  : FileType;
  3534.                      Vol : Volume );
  3535.   
  3536.   procedure PrintNames( Vol   : Volume;
  3537.                        var NbrOfFiles : integer );
  3538.   
  3539.  
  3540. Implementation
  3541.  
  3542. { These are the declerations that we don't really want the  
  3543.   user to see, as they may do silly things }
  3544.    
  3545.    const
  3546.      FirstBlk = 8;
  3547.      LastBlk  = 839;
  3548.    
  3549.    type
  3550.      FileArray = Packed array[0..77] of FileType;
  3551.      
  3552.      Daterec = packed record
  3553.                   Month  : 0..12;
  3554.                   Day    : 0..31;
  3555.                   Year   : 0..100
  3556.                   end;
  3557.      
  3558.      FileKind = (UnTyped,XDsk,Code,Text,Info,Data,Graf,Foto,
  3559.                  SecureDir);
  3560.      
  3561.      DirEntry = Packed Record
  3562.                    DFirstBlk  : integer;
  3563.                    DLastBlk   : integer;
  3564.                    case DFKind : FileKind of
  3565.                    
  3566.                       SecureDir,UnTyped : (Filler1 : 0..2048;
  3567.                                            Dvid    : String[7];
  3568.                                            DevoBlk : integer;
  3569.                                            DNumFiles: 0..77;
  3570.                                            DLoadTime: integer;
  3571.                                            DLastBoot: DateRec );
  3572.                                            
  3573.                       XDsk,Code,Text,Info,Data,Graf,Foto :
  3574.                                         (Filler  : 0..1024;
  3575.                                          Status  : Boolean;
  3576.                                          Dtid    : String[15];
  3577.                                          DLastByte: 1..512;
  3578.                                          DAccess : DateRec )
  3579.                       end;
  3580.       
  3581.      Directory = array[0..77] of DirEntry;
  3582.      
  3583.  
  3584. (* ---------------------------------------------------- *)
  3585.  
  3586. function IsFile(Name  : FileType;
  3587.                 Vol   : Volume ) : Boolean;
  3588. { This checks if the file, name, exists on the disk, vol }
  3589.  
  3590. var
  3591.   G  : String;
  3592.   i  : integer;
  3593.  
  3594. begin
  3595. if (Not ( Vol in [4,5,11,12] )) or (Length(Name) < 1) then
  3596.   begin
  3597.   IsFile := False;
  3598.   Exit(IsFile)
  3599.   end;
  3600.  
  3601. case Vol of
  3602.    4  : G := Concat('#4:',Name);
  3603.    5  : G := Concat('#5:',Name);
  3604.    11 : G := Concat('#11:',Name);
  3605.    12 : G := Concat('#12:',Name);
  3606.    end;
  3607.  
  3608. (*$I-*)
  3609. Reset(D,g);
  3610. i := IOResult;
  3611. if i = 0 then Close(D,lock);
  3612. (*$I+*)
  3613. IsFile := i = 0
  3614. end{IsFile};
  3615.  
  3616. (* ---------------------------------------------------- *)
  3617.  
  3618. procedure DelFile;
  3619. { This procedure deletes a file from disk }
  3620.  
  3621. var
  3622.   i,j,NbrOfFiles  : Integer;
  3623.   DD              : Directory;
  3624.   Dummy           : DirEntry;
  3625.   Found           : Boolean;
  3626.   Key             : char;
  3627.  
  3628. begin
  3629.  
  3630. { Tell the user what we are doing }
  3631. write('#',vol,':',G,' =====> ');
  3632. { Check that the name is valid and exists }
  3633. if (Not (Vol in [4,5,11,12])) or (Length(G)<1)
  3634.     or Not (IsFile(G,Vol)) then
  3635.   begin
  3636.   writeln('Does not exist');
  3637.   Exit(DelFile);
  3638.   end;
  3639.  
  3640. { Inform that it has been deleted ! }
  3641. writeln('Deleted');
  3642. { Ask if the user wishes to update the directory,
  3643.   this will do the actual delete ! }
  3644. write('Update Directory (Y/N) ?');
  3645. repeat
  3646.   read(keyboard,Key)
  3647. until Key in ['Y','y','N','n'];
  3648. writeln(Key);
  3649.  
  3650. { If we do update the directory then we have to delete }
  3651. if Key in ['Y','y'] then
  3652.   begin
  3653.   { Get the directory info }
  3654.   UnitRead(Vol,DD,SizeOf(DD),4);
  3655.   NbrOfFiles := DD[0].DNumFiles;
  3656.   
  3657.   i := 0;
  3658.   Found := False;
  3659.   
  3660.   { Find the file }
  3661.   while not Found do
  3662.     begin
  3663.     with DD[i] do
  3664.       if (Not (DFKind in [SecureDir,UnTyped])) and
  3665.         (DTid = G) then
  3666.        Found := True
  3667.        else
  3668.          i := i + 1;
  3669.     if i > NbrOfFiles then Exit(DelFile)
  3670.     end;
  3671.   
  3672.   { delete from the directory info }
  3673.   Dummy := DD[i];
  3674.   For j:= i To pred(NbrOfFiles) do
  3675.     DD[j] := DD[j+1];
  3676.   DD[NbrOfFiles] := Dummy;
  3677.   DD[0].DNumFiles := NbrOfFiles -1;
  3678.   
  3679.   { Update the actual directory on the disk }
  3680.   UnitWrite(Vol,DD,SizeOf(DD),4)
  3681.   end;
  3682.   
  3683. end{DelFile};
  3684.  
  3685. (* ---------------------------------------------------- *)
  3686.  
  3687. procedure PrintNames;
  3688. { This procedure displays a directory on the screen for
  3689.   the user to view }
  3690.  
  3691. const
  3692.   StrtPos  = 20;
  3693.   FinisPos = 26;
  3694.   DatePos  = 32;
  3695.   TyPos    = 42;
  3696.  
  3697. var
  3698.   i,k  : integer;
  3699.   DD   : Directory;
  3700.   
  3701.   (* -------------------------------------------------- *)
  3702.   
  3703.   procedure PrintDAcc(var DAccess  : DateRec );
  3704.   
  3705.   begin
  3706.   GotoXY(DatePos,k);
  3707.   with DAccess do
  3708.     begin
  3709.     write(Day,'-');
  3710.     case Month of
  3711.       1  : write('Jan');
  3712.       2  : write('Feb');
  3713.       3  : write('Mar');
  3714.       4  : write('Apr');
  3715.       5  : write('May');
  3716.       6  : write('Jun');
  3717.       7  : write('Jul');
  3718.       8  : write('Aug');
  3719.       9  : write('Sep');
  3720.       10 : write('Oct');
  3721.       11 : write('Nov');
  3722.       12 : write('Dec')
  3723.       end{case};
  3724.     write('-',Year)
  3725.     end{with};
  3726.   end{PrintDAcc};
  3727.   
  3728.   (* -------------------------------------------------- *)
  3729.   
  3730.   procedure PrintTy( DFKind  : FileKind );
  3731.   
  3732.   begin
  3733.   GotoXY(TyPos,k);
  3734.   case DFKind of
  3735.      SecureDir : write(' SecureDir ');
  3736.      UnTyped   : write(' UnTyped   ');
  3737.      XDsk      : write(' XDsk      ');
  3738.      Code      : write(' Code      ');
  3739.      Text      : write(' Text      ');
  3740.      Info      : write(' Info      ');
  3741.      Data      : write(' Data      ');
  3742.      Graf      : write(' Graf      ');
  3743.      Foto      : write(' Foto      ');
  3744.      end;
  3745.   end{PrintTy};
  3746.   
  3747.   (* -------------------------------------------------- *)
  3748.  
  3749. begin
  3750. { Get the directory information }
  3751. UnitRead(Vol,DD,SizeOf(DD),4);
  3752. NbrOfFiles := DD[0].DNumFiles;
  3753.  
  3754. { write which disk ths info is from }
  3755. writeln(chr(ff),'DIRECTORY OF #',Vol,':');
  3756.  
  3757. k := 1;
  3758.  
  3759. { Take care of the first entry }
  3760. with DD[1] do
  3761.   begin
  3762.   if DFirstBlk > FirstBlk then
  3763.     begin
  3764.     write('<UNUSED>');
  3765.     GotoXY(StrtPos,k); write(FirstBlk);
  3766.     GotoXY(FinisPos,k);write(pred(DFirstBlk));
  3767.     k := k + 1;
  3768.     writeln
  3769.     end
  3770.   end;
  3771.  
  3772. { For each entry display on the screen }
  3773. for i := 1 to NbrOfFiles do
  3774.   with DD[i] do
  3775.     begin
  3776.     write(Dtid);
  3777.     GotoXY(StrtPos,k); write(DFirstBlk);
  3778.     GotoXY(FinisPos,k);write(DLastBlk);
  3779.     PrintDAcc(DAccess);
  3780.     PrintTy(DFKind);
  3781.     writeln; k := succ(k);
  3782.     if i < NbrofFiles then
  3783.       if (DLastBlk < DD[succ(i)].DFirstBlk) then
  3784.         begin
  3785.         write('<UNUSED>');
  3786.         GotoXY(StrtPos,k); write(DLastBlk);
  3787.         GotoXY(FinisPos,k);write(pred(DD[succ(i)].DFirstBlk));
  3788.         k := k + 1;
  3789.         writeln
  3790.         end;
  3791.     { if we have reached the bottom of the screen and still
  3792.       have more to do... wrap around }
  3793.     if (k mod 31) = 0 then
  3794.       begin
  3795.       Pause;
  3796.       writeln(chr(ff),' DIRECTORY CONTD');
  3797.       k := 1
  3798.       end;
  3799.     end;
  3800.  
  3801. { Take care of the last entry, if blank etc }
  3802. with DD[NbrOfFiles] do
  3803.   begin
  3804.   if DlastBlk < LastBlk then
  3805.     begin
  3806.     write('<UNUSED>');
  3807.     GotoXY(StrtPos,k); write(succ(DLastBlk));
  3808.     GotoXY(FinisPos,k);write(LastBlk);
  3809.     k := k + 1;
  3810.     writeln
  3811.     end
  3812.   end
  3813.  
  3814.  
  3815. end{PrintNames};
  3816.   
  3817. (* ---------------------------------------------------- *)
  3818.  
  3819. end{SysUnit}.
  3820.  
  3821. **** File UTILS.TXT ************************************************************
  3822.  
  3823. function ready(p:port):boolean;
  3824. begin
  3825.   ready:= ((p=terminal) and (not IoStatus(2))) or ((p=modem) and istbrr);
  3826. end;
  3827.  
  3828. function pget(p:port):char;
  3829. begin
  3830.   if p=terminal then pget := chr( aand(IORead(80),127) ) { get from the keyboard }
  3831.   else pget :=rcvbbt;
  3832. end;
  3833.  
  3834. procedure read_str(*var p: port; var s: string*);
  3835.  
  3836. (* acts like readln(s) but takes input from specified port *)
  3837.  
  3838. var i: integer;
  3839.  
  3840.   begin
  3841.     i := 0;
  3842.     s := copy('',0,0);
  3843.     repeat
  3844.       repeat                              (* get a character *)
  3845.       until ready(p);
  3846.       ch:=pget(p);
  3847.       if (ord(ch) = backspace) then       (* if it's a backspace then *)
  3848.         begin
  3849.           if (i > 0) then                   (* if not at beginning of line *)
  3850.             begin
  3851.               write(ch);                      (* go back a space on screen *)
  3852.               write(' ');                     (* erase char on screen *)
  3853.               write(ch);                      (* go back a space again *)
  3854.               i := i - 1;                     (* adjust string counter *)
  3855.               s := copy(s,1,i)                (* adjust string *)
  3856.             end (* if *)
  3857.         end (* if *)
  3858.       else if (ord(ch) <> eoln_sym) then  (* otherwise if not at eoln  then *)
  3859.         begin
  3860.           write(ch);                        (* echo char on screen *)
  3861.           i := i + 1;                       (* inc string counter *)
  3862.           s := concat(s,' ');
  3863.           s[i] := ch;                       (* put char in string *)
  3864.         end; (* if *)
  3865.     until (ord(ch) = eoln_sym);           (* if not eoln, get another char *)
  3866.     s := copy(s,1,i);                     (* correct string length *)
  3867.     writeln                               (* write a line on the screen *)
  3868.   end; (* read_str *)
  3869.  
  3870. function read_ch(*p: port; var ch: char): boolean*);
  3871.  
  3872. (* read a character from an input port *)
  3873.  
  3874.   begin
  3875.   if ready(p) then            (* if a char there *)
  3876.     begin
  3877.       ch := pget(p);      (* get the char *)
  3878.       read_ch := true;               (* and return true *)
  3879.     end (* if *)
  3880.   else                             (* otherwise *)
  3881.       read_ch := false;              (* return false *)
  3882.   end; (* read_ch *)
  3883.  
  3884. function getch(*var r: char; p: port): boolean*);
  3885.  
  3886. (* gets a character, strips parity, returns true if it got a char which *)
  3887. (* isn't Kermit SOH, false if it gets SOH or nothing after maxtry *)
  3888.  
  3889. const maxtry = 10000;
  3890.  
  3891. var count: integer;
  3892.  
  3893.   begin
  3894.     count := 0;
  3895.     getch := false;
  3896.     repeat
  3897.         count := count + 1;
  3898.     until ready(p) or (count > maxtry);         (* wait for a character *)
  3899.     if (count > maxtry) then                    (* if wait too long then *)
  3900.         begin
  3901.         getch := false; { act as if SOH ! }
  3902.         exit(getch)                             (* get out of here *)
  3903.         end;
  3904.     r:=pget(p);                                 (* get the character *)
  3905.     r := chr(aand(ord(r),127));                 (* strip parity from char *)
  3906.     getch := (r <> chr(soh));                   (* return true if not SOH *)
  3907.   end; (* getch *)
  3908.  
  3909.  
  3910. function aand(*x,y: integer): integer*);
  3911.  
  3912. (* arithmetic and--takes 2 integers and ands them, yeilding an integer *)
  3913.  
  3914. var xrec, yrec, temp: int_bool_rec;
  3915.  
  3916.   begin
  3917.     xrec.i := x;                  (* put the two numbers in variant record *)
  3918.     yrec.i := y;
  3919.     temp.b := xrec.b * yrec.b;  (* use as sets to 'and' them *)
  3920.     aand := temp.i                (* return integer result *)
  3921.   end; (* aand *)
  3922.  
  3923. function aor(*x,y: integer): integer*);
  3924.  
  3925. (* arithmetic or *)
  3926.  
  3927. var xrec, yrec, temp: int_bool_rec;
  3928.  
  3929.   begin
  3930.     xrec.i := x;                  (* put two numbers in variant record *)
  3931.     yrec.i := y;
  3932.     temp.b := xrec.b + yrec.b;   (* use as sets to 'or' them *)
  3933.     aor := temp.i                 (* return integer result *)
  3934.   end; (* aor *)
  3935.  
  3936. function xor(*x,y: integer): integer*);
  3937.  
  3938. (* exclisive or *)
  3939.  
  3940. var xrec, yrec, temp: int_bool_rec;
  3941.  
  3942.   begin
  3943.     xrec.i := x;                  (* put two numbers in variant record *)
  3944.     yrec.i := y;
  3945.                                   (* use as sets to 'xor' them *)
  3946.     temp.b := (xrec.b - yrec.b) + (yrec.b - xrec.b);
  3947.     xor := temp.i                 (* return integer result *)
  3948.   end; (* xor *)
  3949.  
  3950. procedure error(*p: packettype; len: integer*);
  3951.  
  3952. (* writes error message sent by remote host *)
  3953.  
  3954. var i: integer;
  3955.  
  3956.   begin
  3957.     gotoxy(0,errorline);
  3958.     for i := 0 to len-1 do
  3959.         write(p[i]);
  3960.     gotoxy(0,promptline);
  3961.   end; (* error *)
  3962.  
  3963. procedure ino_error(*i: integer*);
  3964.  
  3965.   begin
  3966.     gotoxy(0,errorline);
  3967.     writeln;         (* erase to end of line *)
  3968.     gotoxy(0,errorline);
  3969.     case i of
  3970.         0: writeln('No error');
  3971.         1: writeln('Bad Block, Parity error (CRC)');
  3972.         2: writeln('Bad Unit Number');
  3973.         3: writeln('Bad Mode, Illegal operation');
  3974.         4: writeln('Undefined hardware error');
  3975.         5: writeln('Lost unit, Unit is no longer on-line');
  3976.         6: writeln('Lost file, File is no longer in directory');
  3977.         7: writeln('Bad Title, Illegal file name');
  3978.         8: writeln('No room, insufficient space');
  3979.         9: writeln('No unit, No such volume on line');
  3980.         10: writeln('No file, No such file on volume');
  3981.         11: writeln('Duplicate file');
  3982.         12: writeln('Not closed, attempt to open an open file');
  3983.         13: writeln('Not open, attempt to close a closed file');
  3984.         14: writeln('Bad format, error in reading real or integer');
  3985.         15: writeln('Ring buffer overflow')
  3986.       end; (* case *)
  3987.     gotoxy(0,promptline)
  3988.   end; (* ino_error *)
  3989.  
  3990. procedure debugwrite(*s: string*);
  3991.  
  3992. (* writes a debugging message *)
  3993. var i: integer;
  3994.  
  3995.   begin
  3996.     if debug then
  3997.       begin
  3998.         gotoxy(0,debugline+debnext);
  3999.         writeln;
  4000.         gotoxy(0,debugline+debnext);
  4001.         debnext:=(debnext+1) mod debug_max;
  4002.         write(s);                   (* write debugging message *)
  4003.       end (* if debug *)
  4004.   end; (* debugwrite *)
  4005.  
  4006. procedure debugint(*s: string; i: integer*);
  4007.  
  4008. (* write a debugging message and an integer *)
  4009.  
  4010.   begin
  4011.     if debug then
  4012.       begin
  4013.         debugwrite(s);
  4014.         write(i)
  4015.       end (* if debug *)
  4016.   end; (* debugint *)
  4017.  
  4018. procedure writescreen(*s: string*);
  4019.  
  4020. (* sets up the screen for receiving or sending files *)
  4021.  
  4022.   begin
  4023.     write(chr(ff){clearscreen});
  4024.     gotoxy(0,titleline);
  4025.     write('                        Kermit UCSD p-system');
  4026.     gotoxy(statuspos,statusline);
  4027.     write(s);
  4028.     gotoxy(0,packetline);
  4029.     write('Number of Packets: ');
  4030.     gotoxy(0,retryline);
  4031.     write('Number of Tries: ');
  4032.     gotoxy(0,fileline);
  4033.     write('File Name: ');
  4034.   end; (* writescreen *)
  4035.  
  4036. procedure refresh_screen(*numtry, num: integer*);
  4037.  
  4038. (* keeps track of packet count on screen *)
  4039.  
  4040.   begin
  4041.     gotoxy(retrypos,retryline);
  4042.     write(numtry: 5);
  4043.     gotoxy(packetpos,packetline);
  4044.     write(num: 5)
  4045.   end; (* refresh_screen *)
  4046.  
  4047. function min(*x,y: integer): integer*);
  4048.  
  4049. (* returns smaller of two integers *)
  4050.  
  4051.   begin
  4052.     if x < y then
  4053.         min := x
  4054.     else
  4055.         min := y
  4056.   end; (* min *)
  4057.  
  4058. function tochar(*ch: char): char*);
  4059.  
  4060. (* tochar converts a control character to a printable one by adding space *)
  4061.  
  4062.   begin
  4063.     tochar := chr(ord(ch) + ord(' '))
  4064.   end; (* tochar *)
  4065.  
  4066. function unchar(*ch: char): char*);
  4067.  
  4068. (* unchar undoes tochar *)
  4069.  
  4070.   begin
  4071.     unchar := chr(ord(ch) - ord(' '))
  4072.   end; (* unchar *)
  4073.  
  4074. function ctl(*ch: char): char*);
  4075.  
  4076. (* ctl toggles control bit: ^A becomes A, A becomes ^A *)
  4077.  
  4078.   begin
  4079.     ctl := chr(xor(ord(ch),64))
  4080.   end; (* ctl *)
  4081.  
  4082. procedure echo(ch: char);
  4083.  
  4084. (* echos a character on the screen *)
  4085.  
  4086.   begin
  4087.     ch := chr(aand(ord(ch),127)); (* mask off parity bit *)
  4088.     repeat until ISTATR;
  4089.     sndabt(ch)
  4090.   end; (* echo *)
  4091.  
  4092. **** End of concatenated source files ******************************************
  4093.