home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c / ucmicro.pas < prev    next >
Pascal/Delphi Source File  |  2020-01-01  |  88KB  |  2,734 lines

  1. {>>>> KERMIT.TEXT}
  2. program kermit;
  3. {UCSD Pascal KERMIT for the Terak p-System, from Kate MacGregor, Cornell U}
  4. {Adapted to Pascal Microengine by Tim Shimeall, UCI}
  5. {Changes:
  6. - Added device declarations copied from Microengine hardware documentation
  7. - Replaced external assembly language routines with Pascal versions
  8. - Modified debug messages to be label values printed
  9. - Changed format of packetwrite display to show header fields
  10. - Implemented machine-dependent packet timeout
  11. - Added debug packetwrites in recsw
  12. - Added wrap-around debug info region
  13. - Added legality check in showparms
  14. - Removed lf elimination check in echo procedure
  15. - Unitwrite calls replaced by calls to device driving routines
  16. - Most uses of char_int_rec replaced by ord and chr
  17. - Removed queue (no interrupts) 
  18. - Used sets for integer ops to getaround Microengine bug
  19. - Changed parser from a unit to a segment procedure to allow swapping
  20. - Split utility procs into separate files for editing and transfer convinience
  21.  
  22. }
  23. (*$R-*) (* turn range checking off *)
  24. (*$S+*) (* turn swapping on *)
  25. (* $L+*) (* no listing *)
  26.  
  27. const blksize = 512;
  28.       oport = 8;          (* output port # *)
  29.       (* clearscreen = 12;   charcter which erases screen *)
  30.       bell = 7;           (* ASCII bell *)
  31.       esc = 27;           (* ASCII escape *)
  32.       maxpack = 93;       (* maximum packet size minus 1 *)
  33.       soh = 1;            (* start of header *)
  34.       sp = 32;            (* ASCII space *)
  35.       cr = 13;            (* ASCII CR *)
  36.       lf = 10;            (* ASCII line feed *)
  37.       dle = 16;           (* ASCII DLE (space compression prefix for psystem) *)
  38.       del = 127;          (* delete *)
  39.       my_esc = 29;        (* default esc char for connect (^]) *)
  40.       maxtry = 5;         (* number of times to retry sending packet *)
  41.       my_quote = '#';     (* quote character I'll use *)
  42.       my_pad = 0;         (* number of padding chars I need *)
  43.       my_pchar = 0;       (* padding character I need *)
  44.       my_eol = 13;        (* end of line character i need *)
  45.       my_time = 5;        (* seconds after which I should be timed out *)
  46.       maxtim = 20;        (* maximum timeout interval *)
  47.       mintim = 2;         (* minimum time out interval *)
  48.       at_eof = -1;        (* value to return if at eof *)
  49.       eoln_sym = 13;      (* pascal eoln sym *)
  50.       back_space = 8;     (* pascal backspace sym *)
  51.  
  52. (* MICROENGINE dependent constants *)
  53.       intsize = 15;       (* number of bits in an integer minus 1 *)
  54.       Channel0=-992; {FC20 = serial Port B register}
  55.       Channel1=-1008; {FC10 = serial Port A register}
  56.      (* Elements of the status vector in the "StatCmdRec" declared below*)
  57.       RegEmpty=0;
  58.       DataReceived=1;
  59.       OverError=2;
  60.       FrameError=4;
  61.      (* bits 3,5,6,and 7 are not used, since they rely on specific wiring,
  62.        and seem to be unreliable *)
  63.  
  64. (* screen control information *)
  65.   (* console line on which to put specified info *)
  66.       title_line = 1;
  67.       statusline = 2;
  68.       packet_line = 3;
  69.       retry_line = 4;
  70.       file_line = 5;
  71.       error_line = 6;
  72.       prompt_line = 7;
  73.       debug_line = 9;
  74.       debug_max = 12; (* Max lines of debug to show at once *)
  75.   (* position on line to put info *)
  76.       statuspos = 70;
  77.       packet_pos = 19;
  78.       retry_pos = 17;
  79.       file_pos = 11;
  80.  
  81. type packettype = packed array[0..maxpack] of char;
  82.      parity_type = (evenpar, oddpar, markpar, spacepar, nopar);
  83.  
  84.      char_int_rec = record (* allows character to be treated as integer... *)
  85.                            (* is system dependent *)
  86.                       case boolean of
  87.                           true: (i: integer);
  88.                           false: (ch: char)
  89.                     end; (* record *)
  90.  
  91.      int_bool_rec = record (* allows integer to be treated as boolean... *)
  92.                            (* used for numeric AND,OR,XOR...system dependent *)
  93.                            (* replaced by set version to escape microengine
  94.                               bug *)
  95.                       case boolean of
  96.                           true: (i: integer);
  97.                           false: (b: set of 0..intsize);
  98.                     end; (* record *)
  99.  
  100. (* MICROENGINE Dependent Types *)
  101.      Port = (Terminal,Modem);
  102.      Statcmdrec = RECORD CASE BOOLEAN OF  (* Only the Status field is used
  103.                                              in this code, but the declaration
  104.                                              is from Western Digital doc. *)
  105.                     TRUE:(Command:INTEGER);
  106.                     FALSE:(Status:PACKED ARRAY [0:7] OF BOOLEAN);
  107.                     END;
  108.     SerialRec = RECORD
  109.                  SerData:INTEGER;
  110.                  StatSynDle:StatCmdRec;
  111.                  Control2:INTEGER;
  112.                  Control1:INTEGER;
  113.                  filler:ARRAY [0..3] OF INTEGER;
  114.                  Switch:StatCmdRec;
  115.                  END;
  116.    
  117.    (* Parser Types *)
  118.      statustype = (null, at_eol, unconfirmed, parm_expected, ambiguous,
  119.                    unrec, fn_expected, ch_expected);
  120.      vocab = (nullsym, allsym, consym, debugsym, escsym, evensym, exitsym,
  121.               filewarnsym,helpsym, ibmsym, localsym, marksym, nonesym,
  122.               oddsym, offsym, onsym, paritysym, quitsym, recsym, sendsym,
  123.               setsym, showsym, spacesym);
  124.  
  125. var state: char; (* current state *)
  126.     f: file of char; (* file to be received *)
  127.     oldf: file; (* file to be sent *)
  128.     s: string;
  129.     eol, quote, esc_char: char;
  130.     fwarn, ibm, half_duplex, debug: boolean;
  131.     i, size, rpsiz, spsiz, pad, n, num_try, oldtry, timint: integer;
  132.     recpkt, packet: packettype;
  133.     padchar, ch: char;
  134.     debf: text; (* file for debug output *)
  135.     debnext:0..7; (* offset for next debug message *)
  136.     parity: parity_type;
  137.     xon: char;
  138.     filebuf: packed array[1..1024] of char;
  139.     bufpos, bufend: integer;
  140.     parity_array: packed array[char] of char;
  141.     ctlset: set of char;
  142.     rec_ok, send_ok: boolean;
  143.  
  144. (* MICROENGINE Dependent Variable declarations *)
  145.      PortA,PortB:RECORD CASE BOOLEAN OF
  146.                 TRUE:(DevAdd:INTEGER);
  147.                 FALSE:(Serial:^SerialRec);
  148.                 END;
  149.    (* Parser vars *)
  150.    
  151.     noun, verb, adj: vocab;
  152.     status: statustype;
  153.     vocablist: array[vocab] of string[13];
  154.     filename, line: string;
  155.     newescchar: char;
  156.     expected: set of vocab;
  157.  
  158. function read_ch(p: port; var ch: char): boolean;
  159. forward;
  160.  
  161. function aand(x,y: integer): integer;
  162. forward;
  163.  
  164. function aor(x,y: integer): integer;
  165. forward;
  166.  
  167. function xor(x,y: integer): integer;
  168. forward;
  169.  
  170. procedure error(p: packettype; len: integer);
  171. forward;
  172.  
  173. procedure io_error(i: integer);
  174. forward;
  175.  
  176. procedure debugwrite(s: string);
  177. forward;
  178.  
  179. procedure debugint(s: string; i: integer);
  180. forward;
  181.  
  182. procedure writescreen(s: string);
  183. forward;
  184.  
  185. procedure refresh_screen(numtry, num: integer);
  186. forward;
  187.  
  188. function min(x,y: integer): integer;
  189. forward;
  190.  
  191. function tochar(ch: char): char;
  192. forward;
  193.  
  194. function unchar(ch: char): char;
  195. forward;
  196.  
  197. function ctl(ch: char): char;
  198. forward;
  199.  
  200. function getfil(filename: string): boolean;
  201. forward;
  202.  
  203. procedure bufemp(buffer: packettype; var f: text; len: integer);
  204. forward;
  205.  
  206. function bufill(var buffer: packettype): integer;
  207. forward;
  208.  
  209. procedure spar(var packet: packettype);
  210. forward;
  211.  
  212. procedure rpar(var packet: packettype);
  213. forward;
  214.  
  215. procedure spack(ptype: char; num:integer; len: integer; data: packettype);
  216. forward;
  217.  
  218. function getch(var r: char; p: port): boolean;
  219. forward;
  220.  
  221. function getsoh(p: port): boolean;
  222. forward;
  223.  
  224. function rpack(var len, num: integer; var data: packettype): char;
  225. forward;
  226.  
  227. procedure read_str(p: port; var s: string);
  228. forward;
  229.  
  230. procedure packetwrite(p: packettype; len: integer);
  231. forward;
  232.  
  233. procedure show_parms;
  234. forward;
  235.  
  236. procedure uppercase(var s: string); forward;
  237.  
  238.  
  239. (*$I WDFORW.TEXT *) (* Forward Declarations for WDPROCS.TEXT *)
  240. (*$I HELP.TEXT*) (* Segment Procedure Help *)
  241. (*$I SENDSW.TEXT*) (* Segment Procedure Sendsw *)
  242. (*$I RECSW.TEXT*) (* Segment Procedure Recsw *)
  243. (*$I PARSE.TEXT*) (* Segment Function Parse *)
  244. (*$I WDPROCS.TEXT*) (* MICROENGINE dependent routines*)
  245. (*$I UTILS.TEXT *) (* General Utility procedures *)
  246. (*$I RSUTILS.TEXT *) (* Utility procedures for send and receive *)
  247.  
  248. procedure connect;
  249.  
  250. (* connect to remote host (terminal emulation *)
  251.  
  252. var ch: char;
  253.     close: boolean;
  254.  
  255.   procedure read_esc;
  256.  
  257.   (* read charcter after esc char and interpret it *)
  258.  
  259.     begin
  260.       repeat
  261.       until read_ch(terminal,ch);       (* wait until they've typed something in *)
  262.       if (ch in ['a'..'z']) then  (* uppercase it *)
  263.           ch := chr(ord(ch) - ord('a') + ord('A'));
  264.       if ch in [{'B',}'C','S','?'] then
  265.           case ch of
  266.               (*'B': sendbrk;        B: send a break to the IBM *)
  267.               'C': close := true; (* C: end connection *)
  268.               'S': begin          (* S: show status *)
  269.                   noun := allsym;
  270.                   showparms
  271.                 end; (* S *)
  272.               '?': begin          (* ?: show options *)
  273.                   (* writeln('B    Send a BREAK signal.'); *)
  274.                   write('C    Close Connection, return to ');
  275.                   writeln('KERMIT-UCSD command level.');
  276.                   writeln('S    Show Status of connection');
  277.                   writeln('?    Print this list');
  278.                   write('^',esc_char,'   send the escape ');
  279.                   writeln('character itself to the');
  280.                   writeln('     remote host.')
  281.                 end; (* ? *)
  282.             end (* case *)
  283.       else if ch = esc_char then  (* ESC-char: send it out *)
  284.         begin
  285.           if half_duplex then
  286.             begin
  287.               echo(ch);
  288.               while not istbtr do;
  289.               sndbbt(ch);
  290.             end (* if *)
  291.         end (* else if *)
  292.       else                        (* anything else: ignore *)
  293.           write(chr(bell))
  294.     end; (* read_esc *)
  295.  
  296.   begin (* connect *)
  297.     writeln('Connecting to host...type CTRL-',ctl(esc_char),' C to exit');
  298.     close := false;
  299.     repeat
  300.         if read_ch(modem,ch) then        (* if char from host then *)
  301.             echo(ch);                   (* echo it *)
  302.  
  303.         if read_ch(terminal,ch) then        (* if char from keyboard then *)
  304.             if ch <> esc_char then      (* if not ESC-char then *)
  305.               begin
  306.                 if half_duplex then       (* echo it if half-duplex *)
  307.                     echo(ch);
  308.                 while not istbtr do;
  309.                 sndbbt(ch)               (* send it out the port *)
  310.               end (* if *)
  311.             else (* ch = esc_char *)    (* else is ESC-char so *)
  312.               read_esc;                   (* interpret next char *)
  313.     until close;                      (* if still connected, get more *)
  314.     writeln('Disconnected')
  315.   end; (* connect *)
  316.  
  317. procedure fill_parity_array;
  318.  
  319. (* parity value table for even parity...not(entry) = odd parity *)
  320.  
  321. const min = 0;
  322.       max = 126;
  323.  
  324. var i, shifter, counter: integer;
  325.     minch, maxch, ch: char;
  326.     r: char_int_rec;
  327.  
  328.   begin
  329.     minch := chr(min);
  330.     maxch := chr(max);
  331.     case parity of
  332.       evenpar:
  333.         begin
  334.           for ch := minch to maxch do
  335.             begin
  336.               r.ch := ch;               (* put char into variant record *)
  337.               shifter := aand(r.i,255); (* mask off parity bit *)
  338.               counter := 0;
  339.               for i := 1 to 7 do        (* count the 1's *)
  340.                 begin
  341.                   if odd(shifter) then
  342.                       counter := counter + 1;
  343.                   shifter := shifter div 2
  344.                 end; (* for i *)
  345.               if odd(counter) then       (* stick a 1 on if necessary *)
  346.                   parity_array[ch] := chr(aor(ord(ch),128))
  347.               else
  348.                   parity_array[ch] := chr(aand(ord(ch),127))
  349.             end; (* for ch *)
  350.         end; (* case even *)
  351.       oddpar:
  352.         begin
  353.           for ch := minch to maxch do
  354.             begin
  355.               r.ch := ch;                (* put char into variant record *)
  356.               shifter := aand(r.i,255);  (* mask off parity bit *)
  357.               counter := 0;
  358.               for i := 1 to 7 do         (* count the 1's *)
  359.                 begin
  360.                   if odd(shifter) then
  361.                       counter := counter + 1;
  362.                   shifter := shifter div 2
  363.                 end; (* for i *)
  364.               if odd(counter) then        (* stick a 1 on if necessary *)
  365.                   parity_array[ch] := chr(aand(ord(ch),127))
  366.               else
  367.                   parity_array[ch] := chr(aor(ord(ch),128))
  368.             end; (* for ch *)
  369.         end; (* case odd *)
  370.       markpar:
  371.           for ch := minch to maxch do     (* stick a 1 on all chars *)
  372.               parity_array[ch] := chr(aor(ord(ch),128));
  373.       spacepar:
  374.           for ch := minch to maxch do     (* mask off parity on all chars *)
  375.               parity_array[ch] := chr(aand(ord(ch),127));
  376.       nopar:
  377.           for ch := minch to maxch do     (* don't mess w/parity bit at all *)
  378.               parity_array[ch] := ch;
  379.     end; (* case *)
  380.   end; (* fill_parity_array *)
  381.  
  382. procedure write_bool(s: string; b: boolean);
  383.  
  384. (* writes message & 'on' if b, 'off' if not b *)
  385.   begin
  386.     write(s);
  387.     case b of
  388.         true: writeln('on');
  389.         false: writeln('off');
  390.       end; (* case *)
  391.   end; (* write_bool *)
  392.  
  393. procedure show_parms;
  394.  
  395. (* shows the various settable parameters *)
  396.  
  397.   begin
  398.     if noun in [allsym, debugsym, ibmsym, escsym, filewarnsym, localsym,
  399.                 paritysym] then
  400.     case noun of
  401.         allsym:
  402.           begin
  403.             write_bool('Debugging is ',debug);
  404.             writeln('Escape character is ^',ctl(esc_char));
  405.             write_bool('File warning is ',fwarn);
  406.             write_bool('IBM is ',ibm);
  407.             write_bool('Local echo is ',halfduplex);
  408.             case parity of
  409.                 evenpar: write('Even');
  410.                 markpar: write('Mark');
  411.                 nopar: write('No');
  412.                 oddpar: write('Odd');
  413.                 spacepar: write('Space');
  414.               end; (* case *)
  415.             writeln(' parity');
  416.           end; (* allsym *)
  417.         debugsym: write_bool('Debugging is ',debug);
  418.         escsym: writeln('Escape character is ^',ctl(esc_char));
  419.         filewarnsym: write_bool('File warning is ',fwarn);
  420.         ibmsym: write_bool('IBM is ',ibm);
  421.         localsym: write_bool('Local echo is ',halfduplex);
  422.         paritysym: begin
  423.             case parity of
  424.                 evenpar: write('Even');
  425.                 markpar: write('Mark');
  426.                 nopar: write('No');
  427.                 oddpar: write('Odd');
  428.             (' parity');
  429.            end; (* paritysym *)
  430.       end (* case *)
  431.       else write(chr(bell));
  432.   end; (* show_sym *)
  433.  
  434. procedure set_parms;
  435.  
  436. (* sets the parameters *)
  437.  
  438.   begin
  439.     case noun of
  440.         debugsym: case adj of
  441.                       onsym: begin
  442.                           debug := true;
  443.                           (*$I-*)
  444.                           rewrite(debf,'CONSOLE:')
  445.                           (*I+*)
  446.                         end; (* onsym *)
  447.                       offsym: debug := false
  448.                     end; (* case adj *)
  449.         escsym: escchar := newescchar;
  450.         filewarnsym: fwarn := (adj = onsym);
  451.         ibmsym: case adj of
  452.                     onsym: begin
  453.                         ibm := true;
  454.                         parity := markpar;
  455.                         half_duplex := true;
  456.                         fillparityarray
  457.                       end; (* onsym *)
  458.                     offsym: begin
  459.                         ibm := false;
  460.                         parity := nopar;
  461.                         half_duplex := false;
  462.                         fillparityarray
  463.                       end; (* onsym *)
  464.                   end; (* case adj *)
  465.         localsym: halfduplex := (adj = onsym);
  466.         paritysym: begin
  467.               case adj of
  468.                   evensym: parity := evenpar;
  469.                   marksym: parity := markpar;
  470.                   nonesym: parity := nopar;
  471.                   oddsym: parity := oddpar;
  472.                   spacesym: parity := spacepar;
  473.                 end; (* case *)
  474.               fill_parity_array;
  475.              end; (* paritysym *)
  476.       end; (* case *)
  477.   end; (* set_parms *)
  478.  
  479. procedure initialize;
  480.  
  481. var ch: char;
  482.  
  483.   begin
  484.     pad := mypad;
  485.     padchar := chr(mypchar);
  486.     eol := chr(my_eol);
  487.     esc_char := chr(my_esc);
  488.     quote := my_quote;
  489.     ctlset := [chr(1)..chr(31),chr(del),quote];
  490.     half_duplex := false;
  491.     debug := false;
  492.     debnext:=0;
  493.     fwarn := false;
  494.     spsiz := max_pack;
  495.     rpsiz := max_pack;
  496.     n := 0;
  497.     parity := nopar;
  498.     initvocab;
  499.     fill_parity_array;
  500.     ibm := false;
  501.     xon := chr(17);
  502.     bufpos := 1;
  503.     bufend := 0;
  504.     init;
  505.   end; (* initialize *)
  506.  
  507. procedure closeup;
  508.  
  509.   begin
  510.     finit;
  511.     writeln(chr(esc),'E'{clearscreen});
  512.   end; (* closeup *)
  513.  
  514.   begin (* kermit *)
  515.     initialize;
  516.     repeat
  517.         write('Kermit-UCSD> ');
  518.         readstr(terminal,line);
  519.         case parse of
  520.             unconfirmed: writeln('Unconfirmed');
  521.             parm_expected: writeln('Parameter expected');
  522.             ambiguous: writeln('Ambiguous');
  523.             unrec: writeln('Unrecognized command');
  524.             fn_expected: writeln('File name expected');
  525.             ch_expected: writeln('Single character expected');
  526.             null: case verb of
  527.                       consym: connect;
  528.                       helpsym: help;
  529.                       recsym: begin
  530.                           recsw(rec_ok);
  531.                           gotoxy(0,debugline);
  532.                           write(chr(bell));
  533.                           if rec_ok then
  534.                               writeln('successful receive')
  535.                           else
  536.                               writeln('unsuccessful receive');
  537.                           (*$I-*) (* set i/o checking off *)
  538.                           close(oldf);
  539.                           (*$I+*) (* set i/o checking back on *)
  540.                           gotoxy(0,promptline);
  541.                         end; (* recsym *)
  542.                       sendsym: begin
  543.                           uppercase(filename);
  544.                           sendsw(send_ok);
  545.                           gotoxy(0,debugline);
  546.                           write(chr(bell));
  547.                           if send_ok then
  548.                               writeln('successful send')
  549.                           else
  550.                               writeln('unsuccessful send');
  551.                           (*$I-*) (* set i/o checking off *)
  552.                           close(oldf);
  553.                           (*$I+*) (* set i/o checking back on *)
  554.                           gotoxy(0,promptline);
  555.                         end; (* sendsym *)
  556.                       setsym: set_parms;
  557.                       show_sym: show_parms;
  558.                   end; (* case verb *)
  559.         end; (* case parse *)
  560.         unitclear(1); (* clear any trash in input *)
  561.         unitclear(2);
  562.      until (verb = exitsym) or (verb = quitsym);
  563.      closeup
  564.    end. (* kermit *)
  565.  
  566. {>>>>WDFORW.TEXT}
  567. procedure INIT; forward;
  568. function ISTARR:boolean ; forward;
  569. function ISTBRR:boolean; forward;
  570. function ISTAOR:boolean ; forward;
  571. function ISTBOR:boolean ; forward;
  572. function ISTAFE:boolean ; forward;
  573. function ISTBFE:boolean; forward;
  574. function ISTATR:boolean ; forward;
  575. function ISTBTR :boolean; forward;
  576. function RCVABT:CHAR ; forward;
  577. function RCVBBT:CHAR ; forward;
  578. procedure SNDABT (BT:CHAR); forward;
  579. procedure SNDBBT (BT:CHAR); forward;
  580. procedure FINIT; forward;
  581.  
  582. {>>>> HELP.TEXT}
  583. segment procedure help;
  584. {UCSD Pascal KERMIT for the Terak p-System, from Kate MacGregor, Cornell U}
  585.  
  586. procedure keypress;
  587.  
  588. var ch: char;
  589.  
  590.   begin
  591.     writeln('---------------Press any key to continue---------------');
  592.     repeat
  593.     until readch(terminal,ch);
  594.     writeln(chr(esc),'E'{clearscreen})
  595.   end; (* keypress *)
  596.  
  597. procedure help1;
  598.  
  599. var ch: char;
  600.  
  601. begin
  602. if (noun = nullsym) then
  603. begin
  604. writeln('KERMIT is a family of  programs that do reliable file transfer');
  605. write('between computers over TTY lines.  KERMIT can also be ');
  606. writeln('used to make the ');
  607. writeln('microcomputer behave as a terminal for a mainframe.  These are the ');
  608. writeln('commands for theUCSD p-system version, KERMIT-UCSD:');
  609. writeln
  610. end; (* if *)
  611. if (noun = nullsym) or (noun = consym) then
  612. begin
  613. writeln('  CONNECT     To make a "virutual terminal" connection to a remote');
  614. writeln('              system.');
  615. writeln;
  616. write('              To break the connection and "escape" back to the micro,');
  617. writeln;
  618. writeln('              type the escape sequence (CTRL-] C, that is Control ');
  619. writeln('              rightbracket followed immediately by the letter C.)');
  620. writeln;
  621. end; (* if *)
  622. if (noun = nullsym) or (noun = exitsym) then
  623. begin
  624. writeln('  EXIT        To return back to main command level of the p-system.');
  625. writeln;
  626. end; (* if *)
  627. if (noun = nullsym) or (noun = helpsym) then
  628. begin
  629. writeln('  HELP        To get a list of KERMIT commands.');
  630. writeln;
  631. end; (* if *)
  632. if (noun = nullsym) or (noun = quitsym) then
  633. begin
  634. writeln('  QUIT        Same as EXIT.');
  635. writeln;
  636. end; (* if *)
  637. if (noun = nullsym) or (noun = recsym) then
  638. begin
  639. writeln('  RECEIVE     To accept a file from the remote system.');
  640. writeln;
  641. end; (* if *)
  642. end; (* help1 *)
  643.  
  644. procedure help2;
  645.  
  646. var ch: char;
  647.  
  648. begin
  649. if (noun = nullsym) or (noun = sendsym) then
  650. begin
  651. writeln('  SEND        To send a file or group of files to the remote system.');
  652. writeln;
  653. end; (* if *)
  654. if (noun = nullsym) then
  655.     keypress;
  656. if (noun = nullsym) or (noun = setsym) then
  657. begin
  658. writeln('  SET         To establish system-dependent parameters.  The ');
  659. writeln('              SET options are as follows: ');
  660. writeln;
  661. if (adj = nullsym) or (adj = debugsym) then
  662. begin
  663. writeln('              DEBUG            To set debug mode ON or OFF ');
  664. writeln('                               (default is OFF).');
  665. writeln;
  666. end; (* if *)
  667. if (adj = nullsym) or (adj = escsym) then
  668. begin
  669. writeln('              ESCAPE           To change the escape sequence that ');
  670. writeln('                               lets you return to the PC Kermit from');
  671. write('                               the remote host.');
  672. writeln('  The default is CTRL-] c.');
  673. writeln;
  674. end; (* if *)
  675. if (adj = nullsym) or (adj = filewarnsym) then
  676. begin
  677. writeln('              FILE-WARNING     ON/OFF, default is OFF.  If ON, ');
  678. writeln('                               Kermit will warn you and rename an ');
  679. writeln('                               incoming file so as not to write over');
  680. writeln('                               a file that currently exists with the');
  681. writeln('                               same name');
  682. writeln;
  683. end; (* if *)
  684. if (adj = nullsym) then
  685.     keypress;
  686. end; (* if *)
  687. end; (* help2 *)
  688.  
  689. procedure help3;
  690.  
  691. begin
  692. if (noun = nullsym) or (noun = setsym) then
  693. begin
  694. if (adj = nullsym) or (adj = ibmsym) then
  695. begin
  696. writeln('              IBM              ON/OFF, default is OFF.  This flag ');
  697. write('                               should be ON only when ');
  698. writeln('transfering files');
  699. writeln('                               between the micro and an IBM VM/CMS');
  700. writeln('                               system.  It also causes the parity to');
  701. write('                               be set appropriately ');
  702. writeln('(mark) and activates');
  703. writeln('                               local echoing');
  704. writeln;
  705. end; (* if *)
  706. if (adj = nullsym) or (adj = localsym) then
  707. begin
  708. write('              LOCAL-ECHO       ON/OFF, default is OFF.  This sets the');
  709. writeln;
  710. writeln('                               duplex.  It should be ON when using ');
  711. writeln('                               the IBM and OFF for the DEC-20.');
  712. writeln;
  713. end; (* if *)
  714. end; (* if *)
  715. end; (* help3 *)
  716.  
  717. procedure help4;
  718.  
  719. begin
  720. if (noun = setsym) or (noun = nullsym) then
  721. begin
  722. if (adj = nullsym) or (adj = paritysym) then
  723. begin
  724. writeln('              PARITY           EVEN, ODD, MARK, SPACE, or NONE.');
  725. writeln('                               NONE is the default but if the IBM ');
  726. writeln('                               flag is set, parity is set to MARK.  ');
  727. writeln('                               This flag selects the parity for ');
  728. write('                               outgoing and incoming characters during');
  729. writeln;
  730. write('                               CONNECT and file transfer to match the');
  731. writeln;
  732. writeln('                               requirements of the host.');
  733. writeln;
  734. end; (* if *)
  735. end; (* if *)
  736. if (noun = nullsym) or (noun = showsym) then
  737. begin
  738. writeln('  SHOW        To see the values of parameters that can be modified');
  739. writeln('              via the SET command.  Options are the same as for SET,');
  740. writeln('              except that a SHOW ALL command has been added.');
  741. end; (* if *)
  742. end; (* help4 *)
  743.  
  744. begin
  745. help1;
  746. help2;
  747. help3;
  748. help4
  749. end; (* help *)
  750.   
  751. {>>>> SENDSW.TEXT}
  752.  
  753. (* Send Section *)
  754. {UCSD Pascal KERMIT for the Terak p-System, from Kate MacGregor, Cornell U}
  755.  
  756. segment procedure sendsw(var send_ok: boolean);
  757.  
  758. var io_status: integer;
  759.  
  760. procedure openfile;
  761.  
  762. (* resets file & gets past first 2 blocks *)
  763.  
  764.   begin
  765.     (*$I-*) (* turn off compiler i/o checking temporarily *)
  766.     reset(oldf,filename);
  767.     (*$I+*) (* turn compiler i/o checking back on *)
  768.     io_status := io_result;
  769.     if (iostatus = 0) then
  770.       if (pos('.TEXT',filename) = length(filename) - 4) then
  771.                                           (* is a text file, so *)
  772.           i := blockread(oldf,filebuf,2); (* skip past 2 block header *)
  773.   end; (* openfile *)
  774.  
  775. function sinit: char;
  776.  
  777. (* send init packet & receive other side's *)
  778.  
  779. var num, len, i: integer;  (* packet number and length *)
  780.     ch: char;
  781.  
  782.   begin
  783.     if debug then
  784.         debugwrite('sinit');
  785.  
  786.     if numtry > maxtry then
  787.       begin
  788.         sinit := 'a';
  789.         exit(sinit)
  790.       end;
  791.  
  792.     num_try := num_try + 1;
  793.     spar(packet);
  794.  
  795.     if istbrr then ch:=rcvbbt; (* clear modem buffer *)
  796.  
  797.     refresh_screen(numtry,n);
  798.  
  799.     spack('S',n mod 64,6,packet);
  800.  
  801.     ch := rpack(len,num,recpkt);
  802.  
  803.     if (ch = 'N') then
  804.       begin
  805.         sinit := 's';
  806.         exit(sinit)
  807.       end (* if 'N' *)
  808.     else if (ch = 'Y') then
  809.       begin
  810.         if ((n mod 64) <> num) then       (* not the right ack *)
  811.           begin
  812.             sinit := state;
  813.             exit(sinit)
  814.           end;
  815.         rpar(recpkt);
  816.         if (eol = chr(0)) then   (* if they didn't spec eol *)
  817.             eol := chr(my_eol);    (* use mine *)
  818.         if (quote = chr(0)) then (* if they didn't spec quote *)
  819.             quote := my_quote;     (* use mine *)
  820.         ctl_set := [chr(1)..chr(31),chr(del),quote];
  821.         numtry := 0;
  822.         n := n + 1;              (* increase packet number *)
  823.         sinit := 'f';
  824.         exit(sinit)
  825.       end (* else if 'Y' *)
  826.     else if (ch = 'E') then
  827.       begin
  828.         error(recpkt,len);
  829.         sinit := 'a'
  830.       end (* if 'E' *)
  831.     else if (ch = chr(0)) then
  832.         sinit := state
  833.     else if (ch <> 'N') then
  834.         sinit := 'a'
  835.   end; (* sinit *)
  836.  
  837. function sdata: char;
  838.  
  839. (* send file data *)
  840.  
  841. var num, len: integer;
  842.     ch: char;
  843.     packarray: array[false..true] of packettype;
  844.     sizearray: array[false..true] of integer;
  845.     current: boolean;
  846.     b: boolean;
  847.  
  848. function other(b: boolean): boolean;
  849.  
  850. (* complements a boolean which is used as array index *)
  851.  
  852.   begin
  853.     if b then
  854.         other := false
  855.     else
  856.         other := true
  857.   end; (* other *)
  858.  
  859.   begin
  860.     current := true;
  861.     packarray[current] := packet;
  862.     sizearray[current] := size;
  863.     while (state = 'd') do
  864.       begin
  865.         if (numtry > maxtry) then             (* if too many tries, give up *)
  866.             state := 'a';
  867.  
  868.         b := other(current);
  869.         numtry := numtry + 1;
  870.  
  871.                                           (* send a data packet *)
  872.         spack('D',n mod 64,sizearray[current],packarray[current]);
  873.  
  874.         refresh_screen(numtry,n);
  875.                                           (* set up next packet *)
  876.         sizearray[b] := bufill(packarray[b]);
  877.  
  878.         ch := rpack(len,num,recpkt);      (* receive a packet *)
  879.         if ch = 'N' then                  (* NAK, so just stay in this state *)
  880.             if ((n+1) mod 64 <> num) then (* unless NAK for next, which *)
  881.                 sdata := state
  882.             else                          (* is just like ACK for this packet *)
  883.               begin
  884.                 if num > 0 then
  885.                     num := (num - 1)      (* in which case, decrement num *)
  886.                 else
  887.                     num := 63;
  888.                 ch := 'Y';                (* and indicate an ACK *)
  889.               end; (* else *)
  890.  
  891.         if (ch = 'Y') then
  892.            begin
  893.              if ((n mod 64) <> num) then (* if wrong ACK *)
  894.                begin
  895.                  sdata := state;         (* stay in same state *)
  896.                  exit(sdata);            (* get out of here *)
  897.                end; (* if *)
  898.              if numtry > 1 then          (* if anything in buffer, flush it *)
  899.                  if istbrr then begin
  900.                    ch:=rcvbbt;
  901.                    ch:='Y';
  902.                    end;
  903.              numtry := 0;
  904.              n := n + 1;
  905.              current := b;
  906.              if sizearray[current] = ateof then
  907.                  state := 'z'            (* set state to eof *)
  908.              else
  909.                  state := 'd'            (* else stay in data state *)
  910.            end (* if *)
  911.           else if (ch = 'E') then
  912.             begin
  913.               error(recpkt,len);
  914.               state := 'a'
  915.             end (* if 'E' *)
  916.           else if (ch = chr(0)) then      (* receive failure, so stay in d *)
  917.             begin
  918.             end
  919.           else if (ch <> 'N') then
  920.             state := 'a'                  (* on any other goto abort state *)
  921.       end; (* while *)
  922.     size := sizearray[current];
  923.     packet := packarray[current];
  924.     sdata := state
  925.   end; (* sdata *)
  926.  
  927. function sfile: char;
  928.  
  929. (* send file header *)
  930.  
  931. var num, len, i: integer;
  932.     ch: char;
  933.     fn: packettype;
  934.     oldfn: string;
  935.  
  936. procedure legalize(var fn: string);
  937.  
  938. (* make sure file name will be legal to other computer *)
  939.  
  940. var count, i, j, l: integer;
  941.  
  942. procedure uppercase(var s: string);
  943.  
  944. var i: integer;
  945.  
  946.   begin
  947.     for i := 1 to length(s) do
  948.         if s[i] in ['a'..'z'] then
  949.             s[i] := chr(ord('A') + ord(s[i]) - ord('a'))
  950.   end; (* uppercase *)
  951.  
  952.   begin
  953.     count := 0;
  954.     l := length(fn);
  955.     for i := 1 to l do                                  (* count '.'s in fn *)
  956.         if fn[i] = '.' then
  957.             count := count + 1;
  958.     for i := 1 to count-1 do                            (* remove all but 1 *)
  959.       begin
  960.         j := 1;
  961.         while (j < l) and (fn[j] <> '.') do
  962.             j := j + 1;
  963.             delete(fn,j,1);l := l - 1
  964.       end; (* for i *)
  965.     l := length(fn);
  966.     i := pos(':',fn);
  967.     if (i <> 0) then
  968.       begin
  969.         fn := copy(fn,i,l-i);
  970.         l := length(fn)
  971.       end;
  972.     i := 1;
  973.     while (i <= length(fn)) do
  974.         if not(fn[i] in ['a'..'z','A'..'Z','.','0'..'9']) then
  975.             delete(fn,i,1)
  976.         else
  977.             i := i + 1;
  978.     uppercase(fn)
  979.   end; (* legalize *)
  980.  
  981.   begin
  982.     if debug then
  983.         debugwrite('sfile');
  984.  
  985.     if (numtry > maxtry) then          (* if too many tries, give up *)
  986.       begin
  987.         sfile := 'a';
  988.         exit(sfile)
  989.       end;
  990.     numtry := numtry + 1;
  991.  
  992.     oldfn := filename;
  993.     legalize(filename);                (* make filename acceptable to remote *)
  994.     len := length(filename);
  995.  
  996.     moveleft(filename[1],fn[0],len);   (* move filename into a packettype *)
  997.  
  998.     gotoxy(filepos,fileline);
  999.     write(oldfn,' ==> ',filename);
  1000.  
  1001.     refresh_screen(numtry,n);
  1002.  
  1003.     spack('F',n mod 64,len,fn);               (* send file header packet *)
  1004.  
  1005.     size := bufill(packet);            (* get first data from file *)
  1006.                                        (* while waiting for response *)
  1007.  
  1008.     ch := rpack(len,num,recpkt);
  1009.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  1010.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  1011.             exit(sfile)                (* is just like ACK for this packet *)
  1012.         else
  1013.           begin
  1014.             if (num > 0) then
  1015.                 num := (num - 1)       (* in which case, decrement num *)
  1016.             else
  1017.                 num := 63;
  1018.             ch := 'Y';                 (* and indicate an ACK *)
  1019.           end; (* else *)
  1020.  
  1021.     if (ch = 'Y') then
  1022.       begin
  1023.         if ((n mod 64) <> num) then  (* if wrong ACK, stay in F state *)
  1024.             exit(sfile);
  1025.         numtry := 0;
  1026.         n := n + 1;
  1027.         sfile := 'd';
  1028.       end (* if *)
  1029.     else if (ch = 'E') then
  1030.       begin
  1031.         error(recpkt,len);
  1032.         sfile := 'a'
  1033.       end (* if 'E' *)
  1034.     else if (ch <> chr(0)) and (ch <> 'N') then (* don't recognize it *)
  1035.         sfile := 'a'
  1036.   end; (* sfile *)
  1037.  
  1038. function seof: char;
  1039.  
  1040. (* send end of file *)
  1041.  
  1042. var num, len: integer;
  1043.     ch: char;
  1044.  
  1045.   begin
  1046.     if debug then
  1047.         debugwrite('seof');
  1048.  
  1049.     if (numtry > maxtry) then          (* if too many tries, give up *)
  1050.       begin
  1051.         seof := 'a';
  1052.         exit(seof)
  1053.       end;
  1054.     numtry := numtry + 1;
  1055.  
  1056.     refresh_screen(numtry,n);
  1057.  
  1058.     spack('Z',(n mod 64),0,packet);    (* send end of file packet *)
  1059.  
  1060.     if debug then
  1061.         debugwrite('seof1');
  1062.  
  1063.     ch := rpack(len,num,recpkt);
  1064.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  1065.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  1066.             exit(seof)                 (* is just like ACK for this packet *)
  1067.         else
  1068.           begin
  1069.             if num > 0 then
  1070.                 num := (num - 1)       (* in which case, decrement num *)
  1071.             else
  1072.                 num := 63;
  1073.             ch := 'Y';                 (* and indicate an ACK *)
  1074.           end; (* else *)
  1075.  
  1076.     if (ch = 'Y') then
  1077.       begin
  1078.         if debug then
  1079.             debugwrite('seof2');
  1080.         if ((n mod 64) <> num) then     (* if wrong ACK, stay in F state *)
  1081.             exit(seof);
  1082.         numtry := 0;
  1083.         n := n + 1;
  1084.         if debug then
  1085.             debugwrite(concat('closing ',s));
  1086.         close(oldf);
  1087.         seof := 'b'
  1088.       end (* if *)
  1089.     else if (ch = 'E') then
  1090.       begin
  1091.         error(recpkt,len);
  1092.         seof := 'a'
  1093.       end (* if 'E' *)
  1094.     else if (ch = chr(0)) then         (* receive failed, so stay in z state *)
  1095.       begin
  1096.       end
  1097.     else if (ch <> 'N') then           (* other error, just abort *)
  1098.         seof := 'a'
  1099.   end; (* seof *)
  1100.  
  1101. function sbreak: char;
  1102.  
  1103. var num, len: integer;
  1104.     ch: char;
  1105.  
  1106. (* send break (end of transmission) *)
  1107.  
  1108.   begin
  1109.     if debug then
  1110.         debugwrite('sbreak');
  1111.  
  1112.     if (numtry > maxtry) then          (* if too many tries, give up *)
  1113.       begin
  1114.         sbreak := 'a';
  1115.         exit(sbreak)
  1116.       end;
  1117.     numtry := numtry + 1;
  1118.  
  1119.     refresh_screen(numtry,n);
  1120.  
  1121.     spack('B',(n mod 64),0,packet);    (* send end of file packet *)
  1122.  
  1123.     ch := rpack(len,num,recpkt);
  1124.     if ch = 'N' then                   (* NAK, so just stay in this state *)
  1125.         if ((n+1) mod 64 <> num) then  (* unless NAK for next packet, which *)
  1126.             exit(sbreak)               (* is just like ACK for this packet *)
  1127.         else
  1128.           begin
  1129.             if num > 0 then
  1130.                 num := (num - 1)       (* in which case, decrement num *)
  1131.             else
  1132.                 num := 63;
  1133.             ch := 'Y';                 (* and indicate an ACK *)
  1134.           end; (* else *)
  1135.  
  1136.     if (ch = 'Y') then
  1137.       begin
  1138.         if ((n mod 64) <> num) then    (* if wrong ACK, stay in B state *)
  1139.             exit(sbreak);
  1140.         numtry := 0;
  1141.         n := n + 1;
  1142.         sbreak := 'c'                  (* else, switch state to complete *)
  1143.       end (* if *)
  1144.     else if (ch = 'E') then
  1145.       begin
  1146.         error(recpkt,len);
  1147.         sbreak := 'a'
  1148.       end (* if 'E' *)
  1149.     else if (ch = chr(0)) then         (* receive failed, so stay in z state *)
  1150.       begin
  1151.       end
  1152.     else if (ch <> 'N') then           (* other error, just abort *)
  1153.         sbreak := 'a'
  1154.   end; (* sbreak *)
  1155.  
  1156. (* state table switcher for sending *)
  1157.  
  1158.   begin (* sendsw *)
  1159.  
  1160.     if debug then
  1161.         debugwrite(concat('Opening ',filename));
  1162.  
  1163.     openfile;
  1164.     if io_status <> 0 then
  1165.       begin
  1166.         writeln(chr(esc),'E'{clear_screen});
  1167.         io_error(io_status);
  1168.         send_ok := false;
  1169.         exit(sendsw)
  1170.       end;
  1171.  
  1172.     write_screen('Sending');
  1173.     state := 's';
  1174.     n := 0;       (* set packet # *)
  1175.     numtry := 0;
  1176.     while true do
  1177.         if state in ['d', 'f', 'z', 's', 'b', 'c', 'a'] then
  1178.           case state of
  1179.               'd': state := sdata;
  1180.               'f': state := sfile;
  1181.               'z': state := seof;
  1182.               's': state := sinit;
  1183.               'b': state := sbreak;
  1184.               'c': begin
  1185.                      send_ok := true;
  1186.                      exit(sendsw)
  1187.                    end; (* case c *)
  1188.               'a': begin
  1189.                      send_ok := false;
  1190.                      exit(sendsw)
  1191.                    end (* case a *)
  1192.             end (* case *)
  1193.         else (* state not in legal states *)
  1194.           begin
  1195.             send_ok := false;
  1196.             exit(sendsw)
  1197.           end (* else *)
  1198.   end; (* sendsw *)
  1199.  
  1200. {>>>> RECSW.TEXT}
  1201.  
  1202. (* RECEIVE SECTION *)
  1203. {UCSD Pascal KERMIT for the Terak p-System, from Kate MacGregor, Cornell U}
  1204.  
  1205. segment procedure recsw(var rec_ok: boolean);
  1206.  
  1207. function rdata: char;
  1208.  
  1209. (* send file data *)
  1210.  
  1211. var num, len: integer;
  1212.     ch: char;
  1213.  
  1214.   begin
  1215.  
  1216.     repeat
  1217.         if numtry > maxtry then
  1218.           begin
  1219.             debugwrite('too many intial retries in rdata');
  1220.             state := 'a';
  1221.             exit(rdata)
  1222.           end;
  1223.  
  1224.         num_try := num_try + 1;
  1225.  
  1226.         ch := rpack(len,num,recpkt);   (* receive a packet *)
  1227.         if debug and (ch<>chr(0)) then packetwrite(recpkt,len);
  1228.  
  1229.         refresh_screen(numtry,n);
  1230.  
  1231.         if (ch = 'D') then             (* got data packet *)
  1232.           begin
  1233.             if (num <> (n mod 64)) then (* wrong packet *)
  1234.               begin
  1235.                 if (oldtry > maxtry) then
  1236.                   begin
  1237.                     debugwrite('too many data retries in rdata');
  1238.                     rdata := 'a';      (* too many tries, abort *)
  1239.                     exit(rdata)
  1240.                   end; (* if *)
  1241.  
  1242.                 n := n - 1;
  1243.  
  1244.                 if (num = (n mod 64)) then (* previous packet again *)
  1245.                   begin                (* so re-ACK it *)
  1246.                     debugint('re-acking ',num);
  1247.                     spack('Y',num,6,packet);
  1248.                     numtry := 0;       (* reset try counter *)
  1249.                                        (* stay in same state *)
  1250.                   end (* if *)
  1251.                 else begin             (* wrong number *)
  1252.                     debugwrite('wrong data sequence no. in rdata');
  1253.                     state := 'a'       (* so abort *)
  1254.                     end
  1255.               end (* if *)
  1256.             else                       (* right packet *)
  1257.               begin
  1258.                 bufemp(recpkt,f,len);  (* write data to file *)
  1259.                 spack('Y',(n mod 64),0,packet); (* ACK packet *)
  1260.                 oldtry := numtry;      (* reset try counters *)
  1261.                 if numtry > 1 then
  1262.                     if istbrr then     (* clear buffer *)
  1263.                       begin
  1264.                         ch:=rcvbbt;
  1265.                         ch:='D';
  1266.                       end;
  1267.                 numtry := 0;
  1268.                 n := n + 1             (* bump packet number *)
  1269.                                        (* stay in data send state *)
  1270.               end (* else *)
  1271.           end (* if 'D' *)
  1272.         else if (ch = 'F') then        (* file header *)
  1273.           begin
  1274.             if (oldtry > maxtry) then
  1275.               begin
  1276.                 debugwrite('too many file head tries in rdata');
  1277.                 rdata := 'a';          (* too many tries, abort *)
  1278.                 exit(rdata)
  1279.               end; (* if *)
  1280.  
  1281.             n := n - 1;
  1282.  
  1283.             if (num = (n mod 64)) then (* previous packet again *)
  1284.               begin                    (* so re-ACK it *)
  1285.                 debugint('re-acking file header ',num);
  1286.                 spack('Y',num,0,packet);
  1287.                 if istbrr then begin
  1288.                   ch:=rcvbbt; (* and empty out buffer *)
  1289.                   ch:='F';
  1290.                   end;
  1291.                 numtry := 0;           (* reset try counter *)
  1292.                 state := state;        (* stay in same state *)
  1293.               end (* if *)
  1294.             else begin
  1295.               debugwrite('file info not previous packet in rdata');
  1296.                 state := 'a'           (* not previous packet, abort *)
  1297.                 end
  1298.           end (* if 'F' *)
  1299.         else if (ch = 'Z') then        (* end of file *)
  1300.           begin
  1301.             if (num <> (n mod 64)) then(* wrong packet, abort *)
  1302.               begin
  1303.                 debugwrite('wrong eof packet in rdata');
  1304.                 rdata := 'a';
  1305.                 exit(rdata)
  1306.               end; (* if *)
  1307.             spack('Y',n mod 64,0,packet); (* ok, ACK it *)
  1308.             close(f,lock);             (* close up the file *)
  1309.             n :=  n + 1;               (* bump packet counter *)
  1310.             state := 'f';              (* go to complete state *)
  1311.           end (* else if 'Z' *)
  1312.         else if (ch = 'E') then        (* error packet *)
  1313.           begin
  1314.             error(recpkt,len);         (* display error *)
  1315.             state := 'a'               (* and abort *)
  1316.           end (* if 'E' *)
  1317.         else if (ch <> chr(0)) then begin (* some other packet type, *)
  1318.             state := 'a';                 (* abort *)
  1319.             debugwrite('wierd rdata packet');
  1320.             end
  1321.     until (state <> 'd');
  1322.     rdata := state
  1323.   end; (* rdata *)
  1324.  
  1325. function rfile: char;
  1326.  
  1327. (* receive file header *)
  1328.  
  1329. var num, len: integer;
  1330.     ch: char;
  1331.     oldfn: string;
  1332.     i: integer;
  1333.  
  1334. procedure makename(recpkt: packettype; var fn: string; l: integer);
  1335.  
  1336. function exist(fn: string): boolean;
  1337.  
  1338. (* returns true if file named fn exists *)
  1339.  
  1340. var f: file;
  1341.  
  1342.   begin
  1343.     (*$I-*) (* turn off i/o checking *)
  1344.     reset(f,fn);
  1345.     exist := (ioresult = 0)
  1346.     (*$I+*)
  1347.   end; (* exist *)
  1348.  
  1349. procedure checkname(var fn: string);
  1350.  
  1351. (* if file fn exists, makes a new name which doesn't *)
  1352. (* does this by changing letters in file name until it *)
  1353. (* finds some combination which doesn't exitst *)
  1354.  
  1355. var ch: char;
  1356.     i: integer;
  1357.  
  1358.   begin
  1359.     i := 1;
  1360.     while (i <= length(fn)) and exist(fn) do
  1361.       begin
  1362.         ch := 'A';
  1363.         while (ch in ['A'..'Z']) and exist(fn) do
  1364.           begin
  1365.             fn[i] := ch;
  1366.             ch := succ(ch);
  1367.           end; (* while *)
  1368.         i := i + 1
  1369.       end; (* while *)
  1370.     end; (* checkname *)
  1371.  
  1372.   begin (* makename *)
  1373.     fn := copy('               ',1,15);    (* stretch length *)
  1374.     moveleft(recpkt[0],fn[1],l);           (* get filename from packet *)
  1375.     oldfn := copy(fn, 1,l);                (* save fn sent to show user *)
  1376.     fn := copy(fn,1,min(15,l));            (* set length of filename *)
  1377.                                            (* and make sure <= 15 *)
  1378.     uppercase(fn);
  1379.     if pos('.TEXT',fn) <> length(fn)-4 then
  1380.       begin
  1381.         if length(fn) > 10 then
  1382.             fn := copy(fn,1,10);           (* can only be 15 long in all *)
  1383.         fn := concat(fn,'.TEXT');          (* and we'll add .TEXT *)
  1384.       end; (* if *)
  1385.     if fwarn then                          (* if file warning is on *)
  1386.         checkname(fn);                       (* must check that name unique *)
  1387.   end; (* makename *)
  1388.  
  1389.   begin (* rfile *)
  1390.     if debug then
  1391.         debugwrite('rfile');
  1392.  
  1393.     if (numtry > maxtry) then         (* if too many tries, give up *)
  1394.       begin
  1395.         rfile := 'a';
  1396.         exit(rfile)
  1397.       end;
  1398.     numtry := numtry + 1;
  1399.  
  1400.     ch := rpack(len,num,recpkt);      (* receive a packet *)
  1401.     if debug and (ch<>chr(0)) then packetwrite(recpkt,len);
  1402.     refresh_screen(numtry,n);
  1403.  
  1404.     if ch = 'S' then                  (* send init, maybe our ACK lost *)
  1405.       begin
  1406.         if (oldtry > maxtry) then     (* too many tries, abort *)
  1407.           begin
  1408.             debugwrite('too many tries in rfile init');
  1409.             rfile := 'a';
  1410.             exit(rfile)
  1411.           end; (* if *)
  1412.  
  1413.         n := n - 1;
  1414.  
  1415.         if num = (n mod 64) then      (* previous packet mod 64? *)
  1416.           begin                       (* yes, ACK it again *)
  1417.             debugint('re-acking init ',num);
  1418.             spar(packet);             (* with our send init params *)
  1419.             spack('Y',num,7,packet);
  1420.             numtry := 0;              (* reset try counter *)
  1421.             rfile := state;           (* stay in same state *)
  1422.           end (* if *)
  1423.         else                          (* not previous packet, abort *)
  1424.           state := 'a'
  1425.       end (* if 'S' *)
  1426.     else if (ch = 'Z') then           (* end of file *)
  1427.       begin
  1428.         if (oldtry > maxtry) then     (* too many tries, abort *)
  1429.           begin
  1430.             debugwrite('too many tries in filehead eof');
  1431.             rfile := 'a';
  1432.             exit(rfile)
  1433.           end; (* if *)
  1434.  
  1435.         n := n - 1;
  1436.  
  1437.         if num = (n mod 64) then       (* previous packet mod 64? *)
  1438.           begin                       (* yes, ACK it again *)
  1439.             debugint('re-acking eof ',num);
  1440.             spack('Y',num,0,packet);
  1441.             numtry := 0;
  1442.             rfile := state            (* stay in same state *)
  1443.           end (* if *)
  1444.         else
  1445.             rfile := 'a'              (* no, abort *)
  1446.       end (* else if *)
  1447.     else if (ch = 'F') then           (* file header *)
  1448.       begin                           (* which is what we really want *)
  1449.         if (num <> (n mod 64)) then   (* if wrong packet, abort *)
  1450.           begin
  1451.             debugwrite('wrong seq. of file header');
  1452.             rfile := 'a';
  1453.             exit(rfile)
  1454.           end;
  1455.  
  1456.         makename(recpkt,filename,len); (* get filename, make unique if filew *)
  1457.         gotoxy(filepos,fileline);
  1458.         write(oldfn,' ==> ',filename);
  1459.  
  1460.         if not getfil(filename) then  (* try to open new file *)
  1461.           begin
  1462.             ioerror(ioresult);        (* if unsuccessful, tell them *)
  1463.             rfile := 'a';             (* and abort *)
  1464.             exit(rfile)
  1465.           end; (* if *)
  1466.  
  1467.         spack('Y',n mod 64,0,packet); (* ACK file header *)
  1468.         oldtry := numtry;             (* reset try counters *)
  1469.         numtry := 0;
  1470.         n := n + 1;                   (* bump packet number *)
  1471.         rfile := 'd';                 (* switch to data state *)
  1472.       end (* else if *)
  1473.     else if ch = 'B' then             (* break transmission *)
  1474.       begin
  1475.         if (num <> (n mod 64)) then            (* wrong packet, abort *)
  1476.           begin
  1477.             debugwrite('wrong sequence in break packet');
  1478.             rfile := 'a';
  1479.             exit(rfile)
  1480.           end;
  1481.         spack('Y',n mod 64,0,packet); (* say ok *)
  1482.         rfile := 'c'                  (* go to complete state *)
  1483.       end (* else if *)
  1484.     else if (ch = 'E') then
  1485.       begin
  1486.         error(recpkt,len);
  1487.         rfile := 'a'
  1488.       end
  1489.     else if (ch = chr(0)) then        (* returned false *)
  1490.         rfile := state                (* so stay in same state *)
  1491.     else begin                        (* some weird state, so abort *)
  1492.         rfile := 'a';
  1493.         debugwrite('wierd rfile packet');
  1494.         end
  1495.   end; (* rfile *)
  1496.  
  1497. function rinit: char;
  1498.  
  1499. (* receive initialization *)
  1500.  
  1501. var num, len: integer;  (* packet number and length *)
  1502.     ch: char;
  1503.  
  1504.   begin
  1505.     if debug then
  1506.         debugwrite('rinit');
  1507.  
  1508.     numtry := numtry + 1;
  1509.  
  1510.     ch := rpack(len,num,recpkt); (* receive a packet *)
  1511.     if debug and (ch<>chr(0)) then packetwrite(recpkt,len);
  1512.     refresh_screen(num_try,n);
  1513.  
  1514.     if (ch = 'S') then           (* send init packet *)
  1515.       begin
  1516.         rpar(recpkt);            (* get other side's init data *)
  1517.         spar(packet);            (* fill packet with my init data *)
  1518.         ctl_set := [chr(1)..chr(31),chr(del),quote];
  1519.         spack('Y',n mod 64,7,packet); (* ACK with my params *)
  1520.         oldtry := numtry;        (* save old try count *)
  1521.         numtry := 0;             (* start a new counter *)
  1522.         n := n + 1;              (* bump packet number *)
  1523.         rinit := 'f';            (* enter file send state *)
  1524.       end (* if 'S' *)
  1525.     else if (ch = 'E') then
  1526.       begin
  1527.         rinit := 'a';
  1528.         error(recpkt,len)
  1529.       end (* if 'E' *)
  1530.     else if (ch = chr(0)) then
  1531.         rinit := 'r'             (* stay in same state *)
  1532.     else begin
  1533.         rinit := 'a';             (* abort *)
  1534.         debugwrite('wierd rinit packet');
  1535.         end
  1536.   end; (* rinit *)
  1537.  
  1538. (* state table switcher for receiving packets *)
  1539.  
  1540.   begin (* recswok *)
  1541.     writescreen('Receiving');
  1542.     state := 'r';            (* initial state is send *)
  1543.     n := 0;                  (* set packet # *)
  1544.     numtry := 0;             (* no tries yet *)
  1545.  
  1546.     while true do
  1547.         if state in ['d', 'f', 'r', 'c', 'a'] then
  1548.           case state of
  1549.               'd': state := rdata;
  1550.               'f': state := rfile;
  1551.               'r': state := rinit;
  1552.               'c': begin
  1553.                      rec_ok := true;
  1554.                      exit(recsw)
  1555.                    end; (* case c *)
  1556.               'a': begin
  1557.                      rec_ok := false;
  1558.                      exit(recsw)
  1559.                    end (* case a *)
  1560.             end (* case *)
  1561.         else (* state not in legal states *)
  1562.           begin
  1563.             rec_ok := false;
  1564.             exit(recsw)
  1565.           end (* else *)
  1566.   end; (* recsw *)
  1567.   
  1568.  
  1569. {>>>> PARSE.TEXT}
  1570.  
  1571. segment function parse: statustype;
  1572. (* NOTE: due to procedures at the end of this file, this must be the
  1573. LAST segment declared *)
  1574.  
  1575. type states = (start, fin, get_filename, get_set_parm, get_parity, get_on_off,
  1576.                get_char, get_show_parm, get_help_show, get_help_parm,
  1577.                exitstate);
  1578.  
  1579. var status: statustype;
  1580.     word: vocab;
  1581.     state: states;
  1582.  
  1583. procedure eatspaces(var s: string);
  1584.  
  1585. var done: boolean;
  1586.     i: integer;
  1587.  
  1588.   begin
  1589.     done := (length(s) = 0);
  1590.     while not done do
  1591.       begin
  1592.         if s[1] = ' ' then
  1593.           begin
  1594.             i := length(s) - 1;
  1595.             s := copy(s,2,i);
  1596.             done := length(s) = 0
  1597.           end (* if *)
  1598.         else
  1599.             done := true
  1600.       end (* while *)
  1601.   end; (* eatspaces *)
  1602.  
  1603. procedure isolate_word(var line, s: string);
  1604.  
  1605. var i: integer;
  1606.     done: boolean;
  1607.  
  1608.   begin
  1609.     done := false;
  1610.     i := 1;
  1611.     s := copy(' ',0,0);
  1612.     while (i <= length(line)) and not done do
  1613.       begin
  1614.         if line[i] = ' ' then
  1615.             done := true
  1616.         else
  1617.             s := concat(s,copy(line,i,1));
  1618.         i := i + 1;
  1619.       end; (* while *)
  1620.     line := copy(line,i,length(line)-i+1);
  1621.   end; (* isolate_word *)
  1622.  
  1623. function get_fn(var line, fn: string): boolean;
  1624.  
  1625. var i, l: integer;
  1626.  
  1627.   begin
  1628.     get_fn := true;
  1629.     isolate_word(line, fn);
  1630.     l := length(fn);
  1631.     if (l < 1) then
  1632.         get_fn := false
  1633.   end; (* get_fn *)
  1634.  
  1635. function getch(var ch: char): boolean;
  1636.  
  1637. var s: string;
  1638.  
  1639.   begin
  1640.     isolate_word(line,s);
  1641.     if length(s) <> 1 then
  1642.         getch := false
  1643.     else
  1644.       begin
  1645.         ch := s[1];
  1646.         get_ch := true
  1647.       end (* else *)
  1648.   end; (* getch *)
  1649.  
  1650.  
  1651. function get_sym(var word: vocab): statustype;
  1652.  
  1653. var i: vocab;
  1654.     s: string;
  1655.     stat: statustype;
  1656.     done: boolean;
  1657.     matches: integer;
  1658.  
  1659.   begin
  1660.     eat_spaces(line);
  1661.     if length(line) = 0 then
  1662.         getsym := ateol
  1663.     else
  1664.       begin
  1665.         stat := null;
  1666.         done := false;
  1667.         isolate_word(line,s);
  1668.         i := allsym;
  1669.         matches := 0;
  1670.         repeat
  1671.             if (pos(s,vocablist[i]) = 1) and (i in expected) then
  1672.               begin
  1673.                 matches := matches + 1;
  1674.                 word := i
  1675.               end
  1676.             else if (s[1] < vocablist[i,1]) then
  1677.                 done := true;
  1678.             if (i = spacesym) then
  1679.                 done := true
  1680.             else
  1681.                 i := succ(i)
  1682.         until (matches > 1) or done;
  1683.         if matches > 1 then
  1684.             stat := ambiguous
  1685.         else if (matches = 0) then
  1686.             stat := unrec;
  1687.         getsym := stat
  1688.       end (* else *)
  1689.   end; (* getsym *)
  1690.  
  1691.   begin
  1692.     state := start;
  1693.     parse := null;
  1694.     noun := nullsym;
  1695.     verb := nullsym;
  1696.     adj := nullsym;
  1697.     uppercase(line);
  1698.     repeat
  1699.         case state of
  1700.           start:
  1701.               begin
  1702.                 expected := [consym, exitsym, helpsym, quitsym, recsym, sendsym,
  1703.                              setsym, showsym];
  1704.                 status := getsym(verb);
  1705.                 if status = ateol then
  1706.                   begin
  1707.                     parse := null;
  1708.                     exit(parse)
  1709.                   end (* if *)
  1710.                 else if (status <> unrec) and (status <>  ambiguous) then
  1711.                     case verb of
  1712.                       consym: state := fin;
  1713.                       exitsym, quitsym: state := fin;
  1714.                       helpsym: state := get_help_parm;
  1715.                       recsym: state := fin;
  1716.                       sendsym: state := getfilename;
  1717.                       setsym: state := get_set_parm;
  1718.                       showsym: state := get_show_parm;
  1719.                     end (* case *)
  1720.               end; (* case start *)
  1721.           fin:
  1722.               begin
  1723.                 expected := [];
  1724.                 status := getsym(verb);
  1725.                 if status = ateol then
  1726.                   begin
  1727.                     parse := null;
  1728.                     exit(parse)
  1729.                   end (* if status *)
  1730.                 else
  1731.                     status := unconfirmed
  1732.               end; (* case fin *)
  1733.           getfilename:
  1734.             begin
  1735.               expected := [];
  1736.               if getfn(line,filename) then
  1737.                 begin
  1738.                   status := null;
  1739.                   state := fin
  1740.                 end (* if *)
  1741.               else
  1742.                   status := fnexpected
  1743.             end; (* case get file name *)
  1744.           get_set_parm:
  1745.               begin
  1746.                 expected := [paritysym, localsym, ibmsym, escsym,
  1747.                              debugsym, filewarnsym];
  1748.                 status := getsym(noun);
  1749.                 if status = ateol then
  1750.                     status := parm_expected
  1751.                 else if (status <> unrec) and (status <>  ambiguous) then
  1752.                     case noun of
  1753.                       paritysym: state := get_parity;
  1754.                       localsym: state := get_on_off;
  1755.                       ibmsym: state := get_on_off;
  1756.                       escsym: state := getchar;
  1757.                       debugsym: state := getonoff;
  1758.                       filewarnsym: state := getonoff;
  1759.                     end (* case *)
  1760.             end; (* case get_set_parm *)
  1761.           get_parity:
  1762.               begin
  1763.                 expected := [marksym, spacesym, nonesym, evensym, oddsym];
  1764.                 status := getsym(adj);
  1765.                 if status = ateol then
  1766.                     status := parm_expected
  1767.                 else if (status <> unrec) and (status <> ambiguous) then
  1768.                     state := fin
  1769.               end; (* case get_parity  *)
  1770.           get_on_off:
  1771.               begin
  1772.                 expected := [onsym, offsym];
  1773.                 status := getsym(adj);
  1774.                 if status = ateol then
  1775.                     status := parm_expected
  1776.                 else if (status <> unrec) and (status <> ambiguous) then
  1777.                     state := fin
  1778.               end; (* get_on_off *)
  1779.           get_char:
  1780.               if getch(newescchar) then
  1781.                  state := fin
  1782.               else
  1783.                  status := ch_expected;
  1784.           get_show_parm:
  1785.               begin
  1786.                 expected := [allsym, paritysym, localsym, ibmsym, escsym,
  1787.                              debugsym, filewarnsym];
  1788.                 status := getsym(noun);
  1789.                 if status = ateol then
  1790.                     status := parm_expected
  1791.                 else if (status <> unrec) and (status <>  ambiguous) then
  1792.                     state := fin
  1793.               end; (* case get_show_parm *)
  1794.           get_help_show:
  1795.               begin
  1796.                 expected := [paritysym, localsym, ibmsym, escsym,
  1797.                            debugsym, filewarnsym];
  1798.                 status := getsym(adj);
  1799.                 if (status = at_eol) then
  1800.                   begin
  1801.                     status := null;
  1802.                     state := fin
  1803.                   end
  1804.                 else if (status <> unrec) and (status <>  ambiguous) then
  1805.                     state := fin
  1806.               end; (* case get_help_show *)
  1807.           get_help_parm:
  1808.               begin
  1809.                 expected := [consym, exitsym, helpsym, quitsym, recsym,
  1810.                              sendsym, setsym, showsym];
  1811.                 status := getsym(noun);
  1812.                 if status = ateol then
  1813.                   begin
  1814.                     parse := null;
  1815.                     exit(parse)
  1816.                   end;
  1817.                 if (status <> unrec) and (status <>  ambiguous) then
  1818.                     case noun of
  1819.                       consym: state := fin;
  1820.                       sendsym: state := fin;
  1821.                       recsym: state := fin;
  1822.                       setsym: state := get_help_show;
  1823.                       showsym: state := fin;
  1824.                       helpsym: state := fin;
  1825.                       exitsym, quitsym: state := fin;
  1826.                     end (* case *)
  1827.               end; (* case get_help_show *)
  1828.         end (* case *)
  1829.     until (status <> null);
  1830.     parse := status
  1831.   end; (* parse *)
  1832.  
  1833. procedure initvocab;
  1834.  
  1835. var i: integer;
  1836.  
  1837.   begin
  1838.     vocablist[allsym] :=      'ALL';
  1839.     vocablist[consym] :=      'CONNECT';
  1840.     vocablist[debugsym] :=    'DEBUG';
  1841.     vocablist[escsym] :=      'ESCAPE';
  1842.     vocablist[evensym] :=     'EVEN';
  1843.     vocablist[exitsym] :=     'EXIT';
  1844.     vocablist[filewarnsym] := 'FILE-WARNING';
  1845.     vocablist[helpsym] :=     'HELP';
  1846.     vocablist[ibmsym] :=      'IBM';
  1847.     vocablist[localsym] :=    'LOCAL-ECHO';
  1848.     vocablist[marksym] :=     'MARK';
  1849.     vocablist[nonesym] :=     'NONE';
  1850.     vocablist[oddsym] :=      'ODD';
  1851.     vocablist[offsym] :=      'OFF';
  1852.     vocablist[onsym] :=       'ON';
  1853.     vocablist[paritysym] :=   'PARITY';
  1854.     vocablist[quitsym] :=     'QUIT';
  1855.     vocablist[recsym] :=      'RECEIVE';
  1856.     vocablist[sendsym] :=     'SEND';
  1857.     vocablist[setsym] :=      'SET';
  1858.     vocablist[showsym] :=     'SHOW';
  1859.     vocablist[spacesym] :=    'SPACE';
  1860.   end; (* initvocab *)
  1861.  
  1862. procedure uppercase(*var s: string*);
  1863.  
  1864. var i: integer;
  1865.  
  1866.   begin
  1867.     for i := 1 to length(s) do
  1868.         if s[i] in ['a'..'z'] then
  1869.             s[i] := chr(ord(s[i]) - ord('a') + ord('A'))
  1870.   end; (* uppercase *)
  1871.  
  1872. {>>>>WDPROCS.TEXT}
  1873. (* These drivers were adapted from routines written by Tim Shimeall
  1874.    for a PCNET implementation, based on information from Western
  1875.    Digital.  
  1876.  
  1877.    On the Microengine, there are two RS232C Serial Ports.  Port A is 
  1878.    reserved for the system terminal.  Port B is available for all other
  1879.    devices which may be desired to hang off a Microengine.  In this code,
  1880.    it is assumed that Port B holds the modem. 
  1881. *)
  1882. (* All functions are duplicated on ports A and B for simplicity *)
  1883.  
  1884. PROCEDURE Init;
  1885. BEGIN (* InitM *)
  1886.    PortB.DevAdd:= Channel0;
  1887.    PortA.DevAdd:= Channel1;
  1888.    WITH PortB.Serial^ DO BEGIN
  1889.      {The following two lines set the serial port to the following
  1890.       commands:
  1891.          Control1:
  1892.            1 - Full Duplex Operation
  1893.            0 - Break or Transmit NOT transparent
  1894.            0 - Send 2 stop bits on Transmitted 8-bit data
  1895.            0 - No echo of Recieved data
  1896.            0 - Parity checking/generation OFF
  1897.            1 - Reciever is enabled (chars in Rec. holding reg.)
  1898.            1 - REQUEST TO SEND is enabled if CTS is low
  1899.            1 - DTR is ON
  1900.           Control2:
  1901.            0 - 8 bits
  1902.            0 - 8 bits
  1903.            0 - Asynchronous character mode
  1904.            0 - even parity
  1905.            0 - select reciever rate 1
  1906.            0 - +
  1907.            0   | - Clock select to rate 1 (32X)
  1908.            1 - +
  1909.        }
  1910.      Control1:=135; {87 hex}
  1911.      Control2:=1;
  1912.      END;
  1913.    WITH PortA.Serial^ DO BEGIN
  1914.      Control1:=135;
  1915.      Control2:=1;
  1916.      END;
  1917. END; (*InitM*)
  1918.  
  1919. (*---------------------UART FLAG CHECKING-------------------------------*)
  1920.  
  1921. function ISTARR(*:boolean *);
  1922. (* ARR -- IS True Port A Receive Ready?
  1923.  
  1924. This checks the UART status bit corresponding to Receive Data
  1925. Available. If data is available a true result is returned.*)
  1926. BEGIN
  1927.   ISTARR:=PortA.Serial^.StatSynDle.status[DataReceived];
  1928. END;
  1929.  
  1930. function ISTBRR(*:boolean*);
  1931. (* BRR -- IS True Port B Receive Ready?*)
  1932. BEGIN
  1933.   ISTBRR:=PortB.Serial^.StatSynDle.status[DataReceived];
  1934. END;
  1935.  
  1936. function ISTAOR(*:boolean*);
  1937. (* AOR -- IS it True that data OverRun occurred?:0 istor<ditto>
  1938.  
  1939. Immediately after RCVBT is called, ISTOR may be called to check for
  1940. data overrun. This function isn't necessary, but it helps diagnose
  1941. software that is losing data because it is too slow to receive data
  1942. before that data starts getting shifted out of the way to make way for
  1943. later data that has already started to arrive.
  1944. *)
  1945. BEGIN
  1946.   ISTAOR:=PortA.Serial^.StatSynDle.Status[OverError];
  1947. END;
  1948.  
  1949. function ISTBOR(*:boolean*);
  1950. BEGIN
  1951.   ISTBOR:=PortB.Serial^.StatSynDle.Status[OverError];
  1952. END;
  1953.  
  1954. function ISTAFE(*:boolean *);
  1955. (* FE -- IS it True that Framing-Error occurred?:0 istfe<ditto>
  1956.  
  1957. Immediately after RCVBT is called, ISTFE may be called to check for
  1958. framing error. This function isn't necessary, but it helps diagnose
  1959. various errors such as phone-line-noise and wrong-speed-UART. Normally
  1960. ISTOR will be called before ISTFE since data overrun is a more serious
  1961. error than framing-error and thus pre-empts framing-error. The entire
  1962. sequence is thus: ISTRR, RCVBT, ISTOR, ISTFE.
  1963. *)
  1964. BEGIN
  1965.   ISTAFE:=PortA.Serial^.StatSynDle.Status[FrameError];
  1966. END;
  1967.  
  1968. function ISTBFE(*:boolean*);
  1969. BEGIN
  1970.   ISTBFE:=PortB.Serial^.StatSynDle.Status[FrameError];
  1971. END;
  1972.  
  1973. function ISTATR(*:boolean *);
  1974. (* TR -- IS it True that Transmit is Ready?:0 isttr<used in FDX&SDWBT>
  1975.  
  1976. ISTTR is analagous to ISTRR, it tells whether it's safe to transmit
  1977. (rather than to receive) a byte of data. Internally it tells whether
  1978. the previous byte has cleared the device so that the buffer is empty
  1979. to accept another byte. In the device descripion it's usually called
  1980. Transmit Buffer Empty. For instantaneous devices such as memory-mapped
  1981. CRTs, this function will always return TRUE. For most other devices
  1982. such as UARTs and ACIAs (connected directly to terminals, or to
  1983. modems), ISTTR will return TRUE initially, then return FALSE as soon
  1984. as a byte is sent to the device, and then return TRUE when actual
  1985. transmission is done. For double-buffered devices it may only go FALSE
  1986. only after two characters are sent to it, one of which is actually en
  1987. route and the other of which is merely occupying the extra buffer.
  1988. *)
  1989. BEGIN
  1990.   ISTATR:=PortA.Serial^.StatSynDle.Status[RegEmpty];
  1991. END;
  1992.  
  1993. function ISTBTR(*:boolean*);
  1994. BEGIN
  1995.   ISTBTR:=PortB.Serial^.StatSynDle.Status[RegEmpty];
  1996. END;
  1997.  
  1998. (*------------------Primitive character sending and receiving---------------*)
  1999.  
  2000. function RCVABT(*:CHAR*) ;
  2001. (* ReCeiVe ByTe of data from device:0 rcvbt<used in FDX and RCWBT>
  2002.  
  2003. This is the function that is called after ISTRR returns true, to
  2004. actually fetch the waiting data from the UART or ACIA into the
  2005. computer, freeing the device to accept the next byte of data. These
  2006. two functions, testing for data ready and actually fetching the data,
  2007. are kept separate for two reasons: (1) they are separate hardware
  2008. functions in most existing devices, ISTRR being a read of the status
  2009. port with testing for a bit and RCVBT being a read of the data
  2010. port, and (2) often they must be separate in the software, such as
  2011. when it's necessary to verify both that data is available and there's
  2012. a place to put it before fetching the data, such as in a terminal emulator.
  2013.  
  2014. Note that calling RCVBT any time other than after getting a true
  2015. result from ISTRR is invalid, yielding random garbage such as part of
  2016. an incoming byte shifted. Note also that RCVBT fetches all 8 bits of
  2017. the incoming byte of data, returning an 8-bit number with each bit in
  2018. its normal position, for example the first-arrived bit is the 1 bit,
  2019. then the 2 bit, etc., with the "parity" bit which is the last-arrived
  2020. appearing simply as an 8th bit (hexadecimal value 80). No checking of
  2021. parity is allowed, nor is stripping off of the parity bit. When only 7
  2022. bits are desired, a higher-level function will strip off the parity bit.*)
  2023. BEGIN
  2024.   RCVABT:=CHR(PortA.Serial^.SerData);
  2025. END;
  2026.  
  2027. function RCVBBT(*:CHAR*);
  2028. BEGIN
  2029.   RCVBBT:=CHR(PortB.Serial^.SerData);
  2030. END;
  2031.  
  2032. procedure SNDABT(* (BT:CHAR)*);
  2033. (* SeND ByTe of data:0 sndbt<used in FDX&SDWBT>
  2034.  
  2035. After getting back a TRUE result from isttr, this function SNDBT is
  2036. used to actually send the byte of data from the CPU to the device, so
  2037. as to effect sending it out the I/O port (modem or local CRT). Note
  2038. that any attempt to call SNDBT without first getting TRUE from isttr
  2039. can result in clobbering previous data that is still in transit from
  2040. the UART or ACIA bit by bit, causing both that previous byte and this
  2041. new byte to be lost/garbaged. *)
  2042. BEGIN (* SNDABT*)
  2043.   PortA.Serial^.SerData:=ORD(BT);
  2044. END(*SNDABT*);
  2045.  
  2046. procedure SNDBBT(* (BT:CHAR)*);
  2047. (* SeND ByTe of data:0 sndbt<used in FDX&SDWBT>
  2048.  
  2049. After getting back a TRUE result from isttr, this function SNDBT is
  2050. used to actually send the byte of data from the CPU to the device, so
  2051. as to effect sending it out the I/O port (modem or local CRT). Note
  2052. that any attempt to call SNDBT without first getting TRUE from isttr
  2053. can result in clobbering previous data that is still in transit from
  2054. the UART or ACIA bit by bit, causing both that previous byte and this
  2055. new byte to be lost/garbaged. *)
  2056. BEGIN (* SNDBBT*)
  2057.   PortB.Serial^.SerData:=ORD(BT);
  2058. END(*SNDBBT*);
  2059.      
  2060. procedure finit;
  2061. BEGIN
  2062.   PortB.Serial^.Control1:=0; {Turn off DTR, which causes modem to hang up}
  2063. END;
  2064.  
  2065.  
  2066. {>>>>UTILS.TEXT}
  2067. function ready(p:port):boolean;
  2068. begin
  2069.   ready:= ((p=terminal) and istarr) or ((p=modem) and istbrr);
  2070. end;
  2071.  
  2072. function pget(p:port):char;
  2073. begin
  2074.   if p=terminal then pget:=rcvabt
  2075.   else pget:=rcvbbt;
  2076. end;
  2077.  
  2078. procedure read_str(*var p: port; var s: string*);
  2079.  
  2080. (* acts like readln(s) but takes input from specified port *)
  2081.  
  2082. var i: integer;
  2083.  
  2084.   begin
  2085.     i := 0;
  2086.     s := copy('',0,0);
  2087.     repeat
  2088.       repeat                              (* get a character *)
  2089.       until ready(p);
  2090.       ch:=pget(p);
  2091.       if (ord(ch) = backspace) then       (* if it's a backspace then *)
  2092.         begin
  2093.           if (i > 0) then                   (* if not at beginning of line *)
  2094.             begin
  2095.               write(ch);                      (* go back a space on screen *)
  2096.               write(' ');                     (* erase char on screen *)
  2097.               write(ch);                      (* go back a space again *)
  2098.               i := i - 1;                     (* adjust string counter *)
  2099.               s := copy(s,1,i)                (* adjust string *)
  2100.             end (* if *)
  2101.         end (* if *)
  2102.       else if (ord(ch) <> eoln_sym) then  (* otherwise if not at eoln  then *)
  2103.         begin
  2104.           write(ch);                        (* echo char on screen *)
  2105.           i := i + 1;                       (* inc string counter *)
  2106.           s := concat(s,' ');
  2107.           s[i] := ch;                       (* put char in string *)
  2108.         end; (* if *)
  2109.     until (ord(ch) = eoln_sym);           (* if not eoln, get another char *)
  2110.     s := copy(s,1,i);                     (* correct string length *)
  2111.     writeln                               (* write a line on the screen *)
  2112.   end; (* read_str *)
  2113.  
  2114. function read_ch(*p: port; var ch: char): boolean*);
  2115.  
  2116. (* read a character from an input port *)
  2117.  
  2118.   begin
  2119.         if ready(p) then            (* if a char there *)
  2120.           begin
  2121.             ch := pget(p);      (* get the char *)
  2122.             read_ch := true;               (* and return true *)
  2123.           end (* if *)
  2124.         else                             (* otherwise *)
  2125.             read_ch := false;              (* return false *)
  2126.   end; (* read_ch *)
  2127.  
  2128. function getch(*var r: char; p: port): boolean*);
  2129.  
  2130. (* gets a character, strips parity, returns true if it got a char which *)
  2131. (* isn't Kermit SOH, false if it gets SOH or nothing after maxtry *)
  2132.  
  2133. const maxtry = 10000;
  2134.  
  2135. var count: integer;
  2136.  
  2137.   begin
  2138.     count := 0;
  2139.     getch := false;
  2140.     repeat
  2141.         count := count + 1;
  2142.     until ready(p) or (count > maxtry);         (* wait for a character *)
  2143.     if (count > maxtry) then                    (* if wait too long then *)
  2144.         exit(getch);                            (* get out of here *)
  2145.     r:=pget(p);                                 (* get the character *)
  2146.     r := chr(aand(ord(r),127));                 (* strip parity from char *)
  2147.     getch := (r <> chr(soh));                   (* return true if not SOH *)
  2148.   end; (* getch *)
  2149.  
  2150.  
  2151. function aand(*x,y: integer): integer*);
  2152.  
  2153. (* arithmetic and--takes 2 integers and ands them, yeilding an integer *)
  2154.  
  2155. var xrec, yrec, temp: int_bool_rec;
  2156.  
  2157.   begin
  2158.     xrec.i := x;                  (* put the two numbers in variant record *)
  2159.     yrec.i := y;
  2160.     temp.b := xrec.b * yrec.b;  (* use as sets to 'and' them *)
  2161.     aand := temp.i                (* return integer result *)
  2162.   end; (* aand *)
  2163.  
  2164. function aor(*x,y: integer): integer*);
  2165.  
  2166. (* arithmetic or *)
  2167.  
  2168. var xrec, yrec, temp: int_bool_rec;
  2169.  
  2170.   begin
  2171.     xrec.i := x;                  (* put two numbers in variant record *)
  2172.     yrec.i := y;
  2173.     temp.b := xrec.b + yrec.b;   (* use as sets to 'or' them *)
  2174.     aor := temp.i                 (* return integer result *)
  2175.   end; (* aor *)
  2176.  
  2177. function xor(*x,y: integer): integer*);
  2178.  
  2179. (* exclisive or *)
  2180.  
  2181. var xrec, yrec, temp: int_bool_rec;
  2182.  
  2183.   begin
  2184.     xrec.i := x;                  (* put two numbers in variant record *)
  2185.     yrec.i := y;
  2186.                                   (* use as sets to 'xor' them *)
  2187.     temp.b := (xrec.b - yrec.b) + (yrec.b - xrec.b);
  2188.     xor := temp.i                 (* return integer result *)
  2189.   end; (* xor *)
  2190.  
  2191. procedure error(*p: packettype; len: integer*);
  2192.  
  2193. (* writes error message sent by remote host *)
  2194.  
  2195. var i: integer;
  2196.  
  2197.   begin
  2198.     gotoxy(0,errorline);
  2199.     for i := 0 to len-1 do
  2200.         write(p[i]);
  2201.     gotoxy(0,promptline);
  2202.   end; (* error *)
  2203.  
  2204. procedure io_error(*i: integer*);
  2205.  
  2206.   begin
  2207.     gotoxy(0,errorline);
  2208.     write(chr(27),'K');         (* erase to end of line *)
  2209.     case i of
  2210.         0: writeln('No error');
  2211.         1: writeln('Bad Block, Parity error (CRC)');
  2212.         2: writeln('Bad Unit Number');
  2213.         3: writeln('Bad Mode, Illegal operation');
  2214.         4: writeln('Undefined hardware error');
  2215.         5: writeln('Lost unit, Unit is no longer on-line');
  2216.         6: writeln('Lost file, File is no longer in directory');
  2217.         7: writeln('Bad Title, Illegal file name');
  2218.         8: writeln('No room, insufficient space');
  2219.         9: writeln('No unit, No such volume on line');
  2220.         10: writeln('No file, No such file on volume');
  2221.         11: writeln('Duplicate file');
  2222.         12: writeln('Not closed, attempt to open an open file');
  2223.         13: writeln('Not open, attempt to close a closed file');
  2224.         14: writeln('Bad format, error in reading real or integer');
  2225.         15: writeln('Ring buffer overflow')
  2226.       end; (* case *)
  2227.     gotoxy(0,promptline)
  2228.   end; (* io_error *)
  2229.  
  2230. procedure debugwrite(*s: string*);
  2231.  
  2232. (* writes a debugging message *)
  2233. var i: integer;
  2234.  
  2235.   begin
  2236.     if debug then
  2237.       begin
  2238.         gotoxy(0,debugline+debnext);
  2239.         debnext:=(debnext+1) mod debug_max;
  2240.         write(chr(27),'K');         (* erase to end of line *)
  2241.         write(s);                   (* write debugging message *)
  2242.       end (* if debug *)
  2243.   end; (* debugwrite *)
  2244.  
  2245. procedure debugint(*s: string; i: integer*);
  2246.  
  2247. (* write a debugging message and an integer *)
  2248.  
  2249.   begin
  2250.     if debug then
  2251.       begin
  2252.         debugwrite(s);
  2253.         write(i)
  2254.       end (* if debug *)
  2255.   end; (* debugint *)
  2256.  
  2257. procedure writescreen(*s: string*);
  2258.  
  2259. (* sets up the screen for receiving or sending files *)
  2260.  
  2261.   begin
  2262.     write(chr(esc),'E'{clearscreen});
  2263.     gotoxy(0,titleline);
  2264.     write('                        Kermit UCSD p-system');
  2265.     gotoxy(statuspos,statusline);
  2266.     write(s);
  2267.     gotoxy(0,packetline);
  2268.     write('Number of Packets: ');
  2269.     gotoxy(0,retryline);
  2270.     write('Number of Tries: ');
  2271.     gotoxy(0,fileline);
  2272.     write('File Name: ');
  2273.   end; (* writescreen *)
  2274.  
  2275. procedure refresh_screen(*numtry, num: integer*);
  2276.  
  2277. (* keeps track of packet count on screen *)
  2278.  
  2279.   begin
  2280.     gotoxy(retrypos,retryline);
  2281.     write(numtry: 5);
  2282.     gotoxy(packetpos,packetline);
  2283.     write(num: 5)
  2284.   end; (* refresh_screen *)
  2285.  
  2286. function min(*x,y: integer): integer*);
  2287.  
  2288. (* returns smaller of two integers *)
  2289.  
  2290.   begin
  2291.     if x < y then
  2292.         min := x
  2293.     else
  2294.         min := y
  2295.   end; (* min *)
  2296.  
  2297. function tochar(*ch: char): char*);
  2298.  
  2299. (* tochar converts a control character to a printable one by adding space *)
  2300.  
  2301.   begin
  2302.     tochar := chr(ord(ch) + ord(' '))
  2303.   end; (* tochar *)
  2304.  
  2305. function unchar(*ch: char): char*);
  2306.  
  2307. (* unchar undoes tochar *)
  2308.  
  2309.   begin
  2310.     unchar := chr(ord(ch) - ord(' '))
  2311.   end; (* unchar *)
  2312.  
  2313. function ctl(*ch: char): char*);
  2314.  
  2315. (* ctl toggles control bit: ^A becomes A, A becomes ^A *)
  2316.  
  2317.   begin
  2318.     ctl := chr(xor(ord(ch),64))
  2319.   end; (* ctl *)
  2320.  
  2321. procedure echo(ch: char);
  2322.  
  2323. (* echos a character on the screen *)
  2324.  
  2325.   begin
  2326.     ch := chr(aand(ord(ch),127)); (* mask off parity bit *)
  2327.     repeat until istatr;
  2328.     sndabt(ch)
  2329.   end; (* echo *)
  2330.  
  2331. {>>>>RSUTILS.TEXT}
  2332. function getfil(*filename: string): boolean*);
  2333.  
  2334. (* opens a file for writing *)
  2335.  
  2336.   begin
  2337.     (*$I-*) (* turn i/o checking off *)
  2338.     rewrite(f,filename);
  2339.     (*$I-*) (* turn i/o checking on *)
  2340.     getfil := (ioresult = 0)
  2341.   end; (* getfil *)
  2342.  
  2343. procedure bufemp(*buffer: packettype; var f: text; len: integer*);
  2344.  
  2345. (* empties a packet into a file *)
  2346.  
  2347. var i,ls: integer;
  2348.     r: char;
  2349.     s: string;
  2350.  
  2351.   begin
  2352.     s := copy('',0,0);
  2353.     ls := 0;
  2354.     i := 0;
  2355.     while i < len do
  2356.       begin
  2357.         r := buffer[i];          (* get a character *)
  2358.         if (r = myquote) then    (* if character is control quote *)
  2359.           begin
  2360.             i := i + 1;               (* skip over quote and *)
  2361.             r := buffer[i];        (* get quoted character *)
  2362.             if (aand(ord(r),127) <> ord(myquote)) then
  2363.                 r := ctl(r);       (* controllify it *)
  2364.           end; (* if *)
  2365.         if (ord(r) = cr) then          (* else if a carriage return then *)
  2366.           begin
  2367.             i := i + 3;               (* skip over that and line feed *)
  2368.             (*$I-*)                   (* turn i/o checking off *)
  2369.             writeln(f,s);             (* and write out line to file *)
  2370.             s := copy('',0,0);        (* empty the string var *)
  2371.             ls := 0;
  2372.             if (io_result <> 0) then  (* if io_error *)
  2373.               begin
  2374.                 io_error(ioresult);     (* tell them and *)
  2375.                 state := 'a';           (* abort *)
  2376.               end (* if *)
  2377.           end
  2378.       (*$I+*)                      (* turn i/o checking back on *)
  2379.       else                        (* else, is a regular char, so *)
  2380.           begin
  2381.             r:= chr(aand(ord(r),127));     (* mask off parity bit *)
  2382.             s := concat(s,' ');       (* and add character to out string *)
  2383.             ls := ls + 1;
  2384.             s[ls] := r;
  2385.             i := i + 1                (* increase buffer pointer *)
  2386.           end; (* else *)
  2387.       end; (* while *)              (* and get another char *)
  2388.       (*$I-*)                     (* turn i/o checking off *)
  2389.       write(f,s);                 (* and write out line to file *)
  2390.       if (io_result <> 0) then    (* if io_error *)
  2391.         begin
  2392.           io_error(ioresult);       (* tell them and *)
  2393.           state := 'a';             (* abort *)
  2394.         end (* if *)
  2395.       (*$I+*)                      (* turn i/o checking back on *)
  2396.   end; (* bufemp *)
  2397.  
  2398. function bufill(*var buffer: packettype): integer*);
  2399.  
  2400. (* fill a packet with data from a file...manages a 2 block buffer *)
  2401.  
  2402. var i, j, k, t7, count: integer;
  2403.     r: char;
  2404.  
  2405.   begin
  2406.     i := 0;
  2407.     (* while file has some data & packet has some room we'll keep going *)
  2408.     while ((bufpos <= bufend) or (not eof(oldf))) and (i < spsiz-9) do
  2409.       begin
  2410.         (* if we need more data from disk then *)
  2411.         if (bufpos > bufend) and (not eof(oldf)) then
  2412.           begin
  2413.             (* read a couple of blocks *)
  2414.             bufend := blockread(oldf,filebuf[1],2) * blksize;
  2415.             (* and adjust buffer pointer *)
  2416.             bufpos := 1
  2417.           end; (* if *)
  2418.         if (bufpos <= bufend) then     (* if we're within buffer bounds *)
  2419.           begin
  2420.             r := filebuf[bufpos];      (* get a character *)
  2421.             bufpos := bufpos + 1;         (* increase buffer pointer *)
  2422.             if (ord(r) = dle) then           (* if it's space compression char, *)
  2423.               begin
  2424.                 count := ord(unchar(filebuf[bufpos])); (* get # of spaces *)
  2425.                 bufpos := bufpos + 1;       (* read past # *)
  2426.                 r := ' ';                (* and make current char a space *)
  2427.               end (* else if *)
  2428.             else                           (* otherwise, it's just a char *)
  2429.                 count := 1;                (* so only 1 copy of it *)
  2430.             if (r in ctlset) then     (* if a control char *)
  2431.               begin
  2432.                 if (ord(r) = cr) then         (* if a carriage return *)
  2433.                   begin
  2434.                     buffer[i] := quote;      (* put (quoted) CR in buffer *)
  2435.                     i := i + 1;
  2436.                     buffer[i] := ctl(chr(cr));
  2437.                     i := i + 1;
  2438.                     r := chr(lf);            (* and we'll stick a LF after *)
  2439.                   end; (* if *)
  2440.                 if r <> chr(0) then          (* if not a NUL then *)
  2441.                   begin
  2442.                     buffer[i] := quote;      (* put the quote in buffer *)
  2443.                     i := i + 1;
  2444.                     if r <> quote then
  2445.                         r := ctl(r);   (* and un-controllify char *)
  2446.                   end (* if *)
  2447.               end; (* if *)
  2448.           end; (* if *)
  2449.         j := 1;
  2450.         while (j <= count) and (i <= spsiz - 5) do
  2451.           begin                           (* put all the chars in buffer *)
  2452.             if (ord(r) <> 0) then            (* so long as not a NUL *)
  2453.               begin
  2454.                 buffer[i] := r;
  2455.                 i := i + 1;
  2456.               end (* if *)
  2457.             else                          (* is a NUL so *)
  2458.                 if (bufpos > blksize) then  (* skip to end of block *)
  2459.                     bufpos := bufend + 1    (* since rest will be NULs *)
  2460.                 else
  2461.                     bufpos := blksize + 1;
  2462.             j := j + 1
  2463.           end; (* while *)
  2464.       end; (* while *)
  2465.     if (i = 0) then                         (* if we're at end of file, *)
  2466.         bufill := (at_eof)                    (* indicate it *)
  2467.     else                                    (* else *)
  2468.       begin
  2469.         if (j <= count) then                  (* if didn't all fit in packet *)
  2470.           begin
  2471.             bufpos := bufpos - 2;               (* put buf pointer at DLE *)
  2472.                                                 (* and update compress count *)
  2473.             filebuf[bufpos + 1] := tochar(chr(count-j+1));
  2474.           end; (* if *)
  2475.         bufill := i                           (* return # of chars in packet *)
  2476.       end; (* else *)
  2477.   end; (* bufill *)
  2478.  
  2479. procedure spar(*var packet: packettype*);
  2480.  
  2481. (* fills data array with my send-init parameters *)
  2482.  
  2483.   begin
  2484.     packet[0] := tochar(chr(maxpack));   (* biggest packet i can receive *)
  2485.     packet[1] := tochar(chr(mytime));    (* when i want to be timed out *)
  2486.     packet[2] := tochar(chr(mypad));     (* how much padding i need *)
  2487.     packet[3] := ctl(chr(mypchar));      (* padding char i want *)
  2488.     packet[4] := tochar(chr(myeol));     (* end of line character i want *)
  2489.     packet[5] := myquote;                (* control-quote char i want *)
  2490.     packet[6] := 'N';                    (* I won't do 8-bit quoting *)
  2491.   end; (* spar *)
  2492.  
  2493. procedure rpar(*var packet: packettype*);
  2494.  
  2495. (* gets their init params *)
  2496. var s:string;
  2497.   begin
  2498.     s:='rpar:spsize:## timint:## pad:## padchar:### eol:### quote:###';
  2499.     spsiz := ord(unchar(packet[0]));     (* max send packet size *)
  2500.     s[13]:=chr(ord('0')+(spsiz div 10));
  2501.     s[14]:=chr(ord('0')+(spsiz mod 10));
  2502.     timint := ord(unchar(packet[1]));    (* when i should time out *)
  2503.     s[23]:=chr(ord('0')+(timint div 10));
  2504.     s[24]:=chr(ord('0')+(timint mod 10));
  2505.     pad := ord(unchar(packet[2]));       (* number of pads to send *)
  2506.     s[30]:=chr(ord('0')+(pad div 10));
  2507.     s[31]:=chr(ord('0')+(pad mod 10));
  2508.     padchar := ctl(packet[3]);           (* padding char to send *)
  2509.     s[41]:=chr(ord('0')+(ord(padchar) div 100));
  2510.     s[42]:=chr(ord('0')+((ord(padchar) mod 100) div 10));
  2511.     s[43]:=chr(ord('0')+(ord(padchar) mod 10));
  2512.     eol := unchar(packet[4]);            (* eol char i must send *)
  2513.     s[49]:=chr(ord('0')+(ord(eol) div 100));
  2514.     s[50]:=chr(ord('0')+((ord(eol) mod 100) div 10));
  2515.     s[51]:=chr(ord('0')+(ord(eol) mod 10));
  2516.     quote := packet[5];                  (* incoming data quote char *)
  2517.     s[59]:=chr(ord('0')+(ord(quote) div 100));
  2518.     s[60]:=chr(ord('0')+((ord(quote) mod 100) div 10));
  2519.     s[61]:=chr(ord('0')+(ord(quote) mod 10));
  2520.     debugwrite(s);
  2521.   end; (* rpar *)
  2522.  
  2523. procedure packetwrite(*p: packettype; len: integer*);
  2524.  
  2525. (* writes out all of a packet for debugging purposes *)
  2526.  
  2527. var i: integer;
  2528.     s: string;
  2529.   begin
  2530.     s:='length:## Sequence:## Type: #';
  2531.     if p[0]=chr(soh) then s:=concat('SOH ',s);
  2532.     s[8]:=chr(ord('0')+(ord(p[1]) div 10));
  2533.     s[9]:=chr(ord('0')+(ord(p[1]) mod 10));
  2534.     s[20]:=chr(ord('0')+(ord(p[2]) div 10));
  2535.     s[21]:=chr(ord('0')+(ord(p[2]) mod 10));
  2536.     s[length(s)]:=p[3];
  2537.     debugwrite(s);
  2538.     gotoxy(0,debugline+debnext);
  2539.     debnext:=(debnext+1) mod debug_max;
  2540.     for i := 4 to len+3 do
  2541.       begin
  2542.         if i = 84 then
  2543.           begin
  2544.             gotoxy(0,debugline+debnext);
  2545.             debnext:=(debnext+1) mod debug_max;
  2546.             write(chr(27),'K');
  2547.           end; (* if *)
  2548.         write(p[i])
  2549.       end; (* for *)
  2550.   end; (* packetwrite *)
  2551.  
  2552. procedure spack(*ptype: char; num: integer; len: integer; data: packettype*);
  2553.  
  2554. (* send a packet *)
  2555.  
  2556. const maxtry = 10000;
  2557.  
  2558. var bufp, i, count: integer;
  2559.     chksum: char;
  2560.     buffer: packettype;
  2561.     ch: char;
  2562.  
  2563.   begin
  2564.     if ibm and (state <> 's') then           (* if ibm and not SINIT then *)
  2565.       begin
  2566.         count := 0;
  2567.         repeat                                 (* wait for an xon *)
  2568.             repeat
  2569.                 count := count + 1
  2570.             until (readch(modem,ch)) or (count > maxtry );
  2571.         until (ch = xon) or (count > maxtry);
  2572.         if count > maxtry then                 (* if wait too long then *)
  2573.           begin
  2574.             exit(spack)                          (* get out *)
  2575.           end; (* if *)
  2576.       end; (* if *)
  2577.  
  2578.     bufp := 0;
  2579.     for i := 1 to pad do begin
  2580.         while not istbtr do ;
  2581.         sndbbt(padchar);                     (* write out any padding chars *)
  2582.         end;
  2583.     buffer[bufp] := chr(soh);                (* packet sync character *)
  2584.     bufp := bufp + 1;
  2585.     chksum := tochar(chr(len + 3));          (* init chksum *)
  2586.     buffer[bufp] := tochar(chr(len + 3));    (* character count *)
  2587.     bufp := bufp + 1;
  2588.     chksum := chr(ord(chksum) + ord(tochar(chr(num))));
  2589.     buffer[bufp] := tochar(chr(num));
  2590.     bufp := bufp + 1;
  2591.     chksum := chr(ord(chksum) + ord(ptype));
  2592.     buffer[bufp] := ptype;                   (* packet type *)
  2593.     bufp := bufp + 1;
  2594.  
  2595.     for i := 0 to len - 1 do                 (* loop through data chars *)
  2596.       begin
  2597.         buffer[bufp] := data[i];             (* store char *)
  2598.         bufp := bufp + 1;
  2599.         chksum := chr(ord(chksum) + ord(data[i]))
  2600.       end; (* for i *)
  2601.                                              (* compute final chksum *)
  2602.     chksum := chr(aand(ord(chksum) + (aand(ord(chksum),192) div 64), 63));
  2603.     buffer[bufp] := tochar(chksum);
  2604.     bufp := bufp + 1;
  2605.     buffer[bufp] := eol;
  2606.  
  2607.     if (parity <> nopar) then
  2608.         for i := 0 to bufp do                 (* set correct parity on buffer *)
  2609.             buffer[i] := parity_array[buffer[i]];
  2610.  
  2611.     for i:=0 to bufp do begin
  2612.       while not istbtr do;
  2613.       sndbbt(buffer[i]);    (* send the packet out *)
  2614.       end;
  2615.  
  2616.     debugwrite('sending');
  2617.     if debug then
  2618.         packetwrite(buffer,len);
  2619.   end; (* spack *)
  2620.  
  2621. function getsoh(*p: port): boolean*);
  2622.  
  2623. (* reads characters until it finds an SOH; returns false if has to read more *)
  2624. (* than maxtry chars *)
  2625.  
  2626. const maxtry = 10000; (* allows about 1 second of trying *)
  2627.  
  2628. var ch: char;
  2629.     seconds,count: integer;
  2630.  
  2631.   begin
  2632.     count := 0;
  2633.     seconds:=0;
  2634.     get_soh := true;
  2635.     repeat
  2636.         repeat
  2637.             count := count + 1;
  2638.             if count>maxtry then begin
  2639.              seconds:=seconds+1;
  2640.              count:=0;
  2641.              end;
  2642.         until ready(p) or (seconds > timint); (* wait for a character *)
  2643.         if (seconds > timint) then
  2644.           begin
  2645.             get_soh := false;
  2646.             exit(get_soh); 
  2647.           end; 
  2648.         ch := pget(p);                           (* get the character *)
  2649.         ch := chr(aand(ord(ch),127));            (* strip parity of char *)
  2650.     until (ch = chr(SOH))                        (* if not SOH, get more *)
  2651.   end; (* getsoh *)
  2652.  
  2653. (*$G+*) (* turn on goto option...need it for next routine *)
  2654.  
  2655. function rpack(*var len, num: integer; var data: packettype): char*);
  2656.  
  2657. (* read a packet *)
  2658.  
  2659. label 1; (* used to emulate C's CONTINUE statement *)
  2660.  
  2661. const maxtry = 10000; (* allows for about 1 second of checking *)
  2662.  
  2663. var seconds, count, i, ichksum: integer;
  2664.     chksum, ptype: char;
  2665.     r: char;
  2666.  
  2667.   begin
  2668.     count := 0; 
  2669.     seconds := 0;
  2670.  
  2671.     if not getsoh(modem) and (state<>'r') then (*if don't get synch char then *)
  2672.       begin
  2673.         rpack := 'N';                        (* treat as a NAK *)
  2674.         num := n mod 64;
  2675.         exit(rpack)                          (* and get out of here *)
  2676.       end;
  2677.  
  2678.   1: count := count + 1;
  2679.      if (count>maxtry)and(state<>'r') then (* end of one second *)
  2680.         if seconds<timint then begin       (* and aren't waiting for init *)
  2681.           count:=0;
  2682.           seconds:=seconds+1;
  2683.         end
  2684.         else begin                       (* if we've tried too many times *)
  2685.           rpack := 'N';                      (* treat as NAK *)
  2686.           exit(rpack)                        (* and get out of here *)
  2687.         end; (* if *)
  2688.  
  2689.     if not getch(r,modem) then                (* get a char and *)
  2690.             goto 1;                        (* resynch if soh *)
  2691.  
  2692.     ichksum := ord(r);                     (* start checksum *)
  2693.     len := ord(unchar(r)) - 3;             (* character count *)
  2694.  
  2695.     if not getch(r,modem) then             (* get a char and *)
  2696.         goto 1;                            (* resynch if soh *)
  2697.     ichksum := ichksum + ord(r);
  2698.     num := ord(unchar(r));                 (* packet number *)
  2699.  
  2700.     if not getch(r,modem) then             (* get a char and *)
  2701.         goto 1;                            (* resynch if soh *)
  2702.     ichksum := ichksum + ord(r);
  2703.     ptype := r;                            (* packet type *)
  2704.  
  2705.     for i := 0 to len-1 do                 (* get any data *)
  2706.       begin
  2707.         if not getch(r,modem) then            (* get a char and *)
  2708.             goto 1;                        (* resynch if soh *)
  2709.         ichksum := ichksum + ord(r);
  2710.         data[i] := r;
  2711.       end; (* for i *)
  2712.     data[len] := chr(0);                   (* mark end of data *)
  2713.  
  2714.     if not getch(r,modem) then                (* get a char and *)
  2715.         goto 1;                            (* resynch if soh *)
  2716.  
  2717.                                            (* compute final checksum *)
  2718.     chksum := chr(aand(ichksum + (aand(ichksum,192) div 64), 63));
  2719.  
  2720.     if (chksum <> unchar(r)) then       (* if checksum bad *)
  2721.         rpack := chr(0)                      (* return 'false' indicator *)
  2722.     else                                   (* else *)
  2723.         rpack := ptype;                      (* return packet type *)
  2724.  
  2725.     if debug then
  2726.       begin
  2727.         gotoxy(0,debugline+debnext);
  2728.         debnext:= (debnext+1) mod debug_max;
  2729.         write('rpack: len:',len,' num:',num,' ptype:',ptype);
  2730.       end; (* if *)
  2731.   end; (* rpack *)
  2732.  
  2733. (*$G-*) (* turn off goto option...don't need it anymore *)
  2734.