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

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