home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / sperryunivac1100p.zip / univac.pas < prev   
Pascal/Delphi Source File  |  1984-10-04  |  28KB  |  1,179 lines

  1. {$F Here we go.....}
  2.  
  3. PROCESSOR Kermit (input, output);   
  4.  
  5. CONST   
  6. maxtry = 5; 
  7. maxbuf = 200 ;  
  8. maxlin = 80;
  9. maxwrt = 132;   
  10.  
  11. ascnul = 0; 
  12. ascsoh = 1; 
  13. asclf  = 10;
  14. asccr  = 13;
  15. ascsp  = 32; { }
  16. ascns  = 35; {#}
  17. ascamp = 38; {&}
  18. ascast = 42; {*}
  19. ascper = 46; {.}
  20. ascb   = 66; {B}
  21. ascd   = 68; {D}
  22. asce   = 69; {E}
  23. ascf   = 70; {F}
  24. ascn   = 78; {N}
  25. ascr   = 82; {R}
  26. ascs   = 83; {S}
  27. asct   = 84; {T}
  28. ascy   = 89; {Y}
  29. ascz   = 90; {Z}
  30. asctil = 126; {~}   
  31. ascdel = 127; {rubout}  
  32.  
  33. mark = ascsoh;  
  34.  
  35. TYPE
  36. kermitstates = (kcommand,   
  37.                 kexit,  
  38.                 wexit,  
  39.                 sinitiate,  
  40.                 sheader,
  41.                 sdata,  
  42.                 sbreak, 
  43.                 rinitiate,  
  44.                 rheader,
  45.                 rdata); 
  46. filestatus = (closed, open, endfile);   
  47. ascval = 0..255 ;   
  48. ascbuf = RECORD 
  49.                ln: INTEGER; 
  50.                ch: ARRAY[1..maxbuf] OF ascval;  
  51.             END;
  52. line = PACKED ARRAY [1..maxlin] OF CHAR;
  53.  
  54. {System dependent TYPE} 
  55.  
  56. ident= PACKED ARRAY[1..12] OF CHAR; 
  57. sbits = SET of 0..35;   
  58.  
  59. VAR 
  60.  
  61. version: string;
  62. iniflg: boolean; {Set true after first initialization}  
  63. server: boolean; {If true, Kermit1100 waits for packets from remote}
  64. state: kermitstates;
  65. filbuf,wrtbuf,redbuf,sndbuf,rcvbuf: ascbuf; 
  66. redix:  integer;
  67. rfile,wfile,lfile: text;
  68. fname,rfname,lname: line;   
  69. fnlen,rfnlen: INTEGER;  
  70. rstatus, wstatus,lstatus: filestatus;   
  71. seq,rcvseq: INTEGER;
  72. rlen: INTEGER;  
  73. stype,rcvtyp: ascval;   
  74. numtry: INTEGER;
  75. numcserr: INTEGER;  
  76. ineoln: boolean;
  77. sndonly: boolean;   
  78. sndlog, rcvlog, wrtlog, redlog: boolean;
  79. bstrip:  boolean;   
  80. creol:  boolean;
  81. lfeol:  boolean;
  82. crlfeol:  boolean;  
  83. gotcr:  boolean;
  84.  
  85. locbsiz:  ascval;   
  86. loctout:  ascval;   
  87. locnpad:  ascval;   
  88. locpad:   ascval;   
  89. loceol:   ascval;   
  90. locquo:   ascval;   
  91. optqu8:   ascval;   
  92. locqu8:   ascval;   
  93. locrep:   ascval;   
  94.  
  95. rembsiz:  ascval;   
  96. remdsiz:  ascval; {Maximum number of data characters to send (remdsiz-3)}   
  97. remtout:  ascval;   
  98. remnpad:  ascval;   
  99. rempad:   ascval;   
  100. remeol:   ascval;   
  101. remquo:   ascval;   
  102. remqu8:   ascval;   
  103. remrep:   ascval;   
  104.  
  105. {System dependent VAR}  
  106. ruse,wuse,luse: ident;  
  107. a0,a1,a2: integer;  
  108.  
  109. {Forward reference procedures } 
  110.  
  111. PROCEDURE error(msg:string);FORWARD;
  112.  
  113. {System dependent procedures to read and write files}   
  114.  
  115. PROCEDURE readelt1(VAR f:text; filename:ident; name:line; VAR ok:boolean);  
  116.    EXTERN;  
  117. PROCEDURE openelt1(VAR f:text; filename:ident; name:line; VAR ok:boolean);  
  118.    EXTERN;  
  119. PROCEDURE closeelt1(VAR f:text; filename:ident; name:line); EXTERN; 
  120. PROCEDURE param_string(field:INTEGER; VAR param:STRING); EXTERN;
  121. PROCEDURE csf(image:line; VAR status:sbits);EXTERN; 
  122. PROCEDURE write_now(VAR f:text);EXTERN; 
  123.  
  124. {   
  125. System dependent procedure to get a file name from the procedure call card. 
  126. }   
  127. PROCEDURE getspec(field: INTEGER; VAR l: line; VAR len: INTEGER);   
  128. VAR s: string[80];  
  129.     i: INTEGER; 
  130.  
  131. BEGIN   
  132. param_string(field,s);  
  133. len:=LENGTH(s); 
  134. FOR i:=1 TO len DO l[i]:=s[i];  
  135. FOR i:=len+1 TO 80 DO l[i]:=' ';
  136. END;
  137.  
  138. {$F Character manipulation routines}
  139.  
  140. {System dependent:  It is assumed that the function ord(c) where
  141.  c is of type char will return the ASCII code for the character c.} 
  142.  
  143. {System dependent:  It is assumed that the function chr(i) where
  144.  i is an integer ASCII code from 0 to 255 will return the appropriate   
  145.  character} 
  146.  
  147. FUNCTION makechar (i: INTEGER): ascval; 
  148.  
  149. BEGIN   
  150. makechar:=ascsp+i;  
  151. END;
  152.  
  153. FUNCTION unchar (a: ascval): INTEGER;   
  154.  
  155. BEGIN   
  156. unchar:=a-ascsp;
  157. END;
  158.  
  159. FUNCTION tog64(a: ascval): ascval;  
  160.  
  161. BEGIN   
  162. tog64:=bxor(64,a); {System dependent}   
  163. END;
  164.  
  165. FUNCTION tog128(a: ascval): ascval; 
  166.  
  167. BEGIN   
  168. tog128:=bxor(128,a); {System dependent} 
  169. END;
  170.  
  171. FUNCTION checksum (sum: INTEGER): ascval;   
  172.  
  173. BEGIN   
  174. checksum := (((sum MOD 256) DIV 64) +  sum)  MOD 64;
  175. END;
  176. {$F Open and close log file}
  177. PROCEDURE logopn; {System dependent}
  178. VAR i,t: INTEGER;   
  179.     lstat: boolean; 
  180.     csfsta: sbits;  
  181.  
  182. BEGIN   
  183. csf('@asg,az kermitlog. ',csfsta);  
  184. IF 35 IN csfsta THEN
  185.    BEGIN
  186.    csf('@asg,t kermitlog.,///256 . ',csfsta);   
  187.    END; 
  188. IF 35 IN csfsta THEN
  189.    BEGIN
  190.    writeln(lfile,'Error assigning logfile: KERMITLOG'); 
  191.    END  
  192. ELSE
  193.    BEGIN
  194.    lname:='KERMITLOG.mdttt . '; 
  195.    er(44{TDATE$},a0);   
  196.    a1:=bshr(band(170000000000b,a0),10)+bshr(band(3700000000b,a0),9) 
  197.       +band(77777b,bshr(a0,2)); 
  198.    FOR i:=1 TO 5 DO 
  199.       BEGIN 
  200.       t:=band(31,bshlc(a1,11+5*i))+48;  
  201.       IF t>57 THEN t:=t+7;  
  202.       lname[10+i]:=chr(t);  
  203.       END;  
  204.    luse:='L$F$I$L$E$$$';
  205.    openelt1(lfile,luse,lname,lstat);
  206.    IF lstat=false THEN  
  207.       BEGIN 
  208.       writeln('Error opening log element:  ',lname);
  209.       END   
  210.    ELSE 
  211.       BEGIN 
  212.       lstatus:=open;
  213.       write(lfile,'Kermit1100 ',version,' Logfile ');   
  214.       write_now(lfile); {Write date and time into logfile}  
  215.       writeln(lfile);   
  216.       writeln(output,'Logging to ',lname);  
  217.       END;  
  218.    END; 
  219. END;
  220.  
  221. PROCEDURE logcls; {System dependent}
  222.  
  223. BEGIN   
  224. IF lstatus=open THEN
  225.    BEGIN
  226.    closeelt1(lfile,luse,lname); 
  227.    END; 
  228. END;
  229. {$F Buffer routines}
  230.  
  231. PROCEDURE bufinit(VAR buf:ascbuf);  
  232.  
  233. BEGIN   
  234. buf.ln:=0;  
  235. END;
  236.  
  237. PROCEDURE putbuf(VAR buf: ascbuf; a:ascval);
  238.  
  239. BEGIN   
  240. IF NOT (buf.ln<maxbuf) THEN 
  241.    BEGIN
  242.    error('Size of ascii buffer exceeded');  
  243.    END  
  244. ELSE
  245.    BEGIN
  246.    buf.ln:=buf.ln+1;
  247.    buf.ch[buf.ln]:=a;   
  248.    END; 
  249. END;
  250.  
  251. PROCEDURE lintobuf(l: line; len: integer; VAR buf: ascbuf); 
  252. VAR i:integer;  
  253.  
  254. BEGIN   
  255. bufinit(buf);   
  256. FOR i:=1 TO len DO putbuf(buf,ord(l[i]));   
  257. END;
  258.  
  259. PROCEDURE buftolin(buf: ascbuf; VAR l: line; VAR len: integer); 
  260. VAR i:integer;  
  261.     a:ascval;   
  262.  
  263. BEGIN   
  264. len:=buf.ln;
  265. IF len>maxlin THEN len:=maxlin; 
  266. FOR i:=1 TO len DO  
  267.    BEGIN
  268.    a:=buf.ch[i];
  269.    IF a>127 THEN a:=a-127;  
  270.    l[i]:=chr(a);
  271.    END; 
  272. FOR i:=len+1 to maxlin DO l[i]:=' ';
  273. END;
  274. {$F Process parameters to and from remote Kermit}   
  275. PROCEDURE putpar;   
  276. VAR temp: ascval;   
  277.  
  278. BEGIN   
  279. bufinit(filbuf);
  280. putbuf(filbuf,makechar(locbsiz));   
  281. putbuf(filbuf,makechar(loctout));   
  282. putbuf(filbuf,makechar(locnpad));   
  283. putbuf(filbuf,tog64(locpad));   
  284. putbuf(filbuf,makechar(loceol));
  285. putbuf(filbuf,locquo);  
  286. temp:=ascsp;
  287. IF locqu8<>0 THEN temp:=locqu8; 
  288. putbuf(filbuf,temp);
  289. putbuf(filbuf,ascsp); {Only know how do to 1 character checksum}
  290. temp:=ascsp;
  291. IF locrep<>0 THEN temp:=locrep; 
  292. putbuf(filbuf,temp);
  293. END;
  294.  
  295. PROCEDURE getpar;   
  296.  
  297. BEGIN   
  298. IF rcvbuf.ln > 0 THEN rembsiz:=unchar(rcvbuf.ch[1]);
  299. IF rcvbuf.ln > 1 THEN remtout:=unchar(rcvbuf.ch[2]);
  300. IF rcvbuf.ln > 2 THEN remnpad:=unchar(rcvbuf.ch[3]);
  301. IF rcvbuf.ln > 3 THEN rempad:=tog64(rcvbuf.ch[4]);  
  302. IF rcvbuf.ln > 4 THEN remeol:=unchar(rcvbuf.ch[5]); 
  303. IF rcvbuf.ln > 5 THEN remquo:=rcvbuf.ch[6]; 
  304. IF rcvbuf.ln > 6 THEN remqu8:=rcvbuf.ch[7]; 
  305. IF rcvbuf.ln > 8 THEN remrep:=rcvbuf.ch[9]; 
  306.  
  307. remdsiz:=rembsiz-3; 
  308. IF state=rinitiate THEN {Our parameters have not been sent} 
  309.    BEGIN
  310.    IF locqu8=0 THEN remqu8:=0;  
  311.    IF ((32<remqu8) AND (remqu8<63)) OR ((95<remqu8) AND (remqu8<127))   
  312.    AND (remqu8<>remquo) THEN
  313.       BEGIN 
  314.       locqu8:=ascy; {Remote Kermit specified 8-bit quote character} 
  315.       END   
  316.    ELSE IF remqu8=ascy THEN 
  317.       BEGIN 
  318.       locqu8:=ascamp;   
  319.       IF (locqu8=remquo) OR (locqu8=remrep) THEN locqu8:=asctil;
  320.       IF (locqu8=remquo) OR (locqu8=remrep) THEN locqu8:=ascns; 
  321.       remqu8:=locqu8;   
  322.       END   
  323.    ELSE 
  324.       BEGIN 
  325.       locqu8:=0;        {Don't do 8-bit quoting}
  326.       remqu8:=0;
  327.       END;  
  328.    IF ((32<remrep) AND (remrep<63)) OR ((95<remrep) AND (remrep<127))   
  329.    AND (remrep<>remquo) AND (remrep<>remqu8) AND (locrep<>0) THEN   
  330.       BEGIN 
  331.       locrep:=remrep; {Agree to do repeat counts}   
  332.       END   
  333.    ELSE 
  334.       BEGIN 
  335.       remrep:=0;
  336.       locrep:=0;
  337.       END;  
  338.    END  
  339. ELSE {Our parameters have already been sent}
  340.    BEGIN
  341.    IF (remqu8<>ascy) AND (remqu8<>locqu8) THEN  
  342.       BEGIN 
  343.       locqu8:=0; {Don't do 8-bit quoting}   
  344.       END;  
  345.    IF remrep<>locrep THEN locrep:=0; {Don't do repeat counts}   
  346.    END; 
  347. END;
  348. {$F Input a packet or a command}
  349. PROCEDURE rcvpkt;   
  350. {   
  351. This procedure reads all terminal input to Kermit, both packets and 
  352. command lines.  On exit, the following global parameters are set:   
  353.  
  354.    rcvtyp = 0 - No SOH encountered, could be command line   
  355.             1 - SOH encountered, but packet incomplete  
  356.             2 - Checksum error  
  357.             Other - ASCII value of packet type from good packet 
  358.  
  359.    rcvseq = -1 - Not a valid packet 
  360.             -2 - End of input file encountered  
  361.             0...63 - Sequence number from valid packet  
  362.  
  363.    rcvbuf.ln - number of ascii values input since last SOH or   
  364.                if no SOH, from beginning of line
  365.    rcvbuf.ch - array of ascii values input  
  366. }   
  367. VAR c: CHAR;
  368.     av,rt: ascval;  
  369.     rst,rsq,cs:INTEGER; 
  370.  
  371. BEGIN   
  372. IF rcvlog THEN write(lfile,'rcv <');
  373. IF ineoln THEN  
  374.    BEGIN
  375.    readln(input);   
  376.    END; 
  377. rcvtyp:=0;  
  378. IF eof(input) THEN  
  379.    BEGIN
  380.    rcvseq:=-2;  
  381.    IF rcvlog THEN write(lfile,'@'); 
  382.    END  
  383. ELSE
  384.    BEGIN
  385.    rcvseq:=-1;  
  386.    rst:=0;  
  387.    ineoln:=eoln(input); 
  388.    bufinit(rcvbuf); 
  389.    WHILE NOT ineoln DO  
  390.       BEGIN 
  391.       IF eoln(input) THEN   
  392.          BEGIN  
  393.          {  
  394.          The 1100 EXEC truncates some trailing spaces.  Since a 
  395.          valid packet can end in one or more spaces, we will assume 
  396.          that short packets should end in spaces and hope that  
  397.          the checksum filters out errors.   
  398.          }  
  399.          av:=ascsp; 
  400.          END
  401.       ELSE  
  402.          BEGIN  
  403.          read(input,c); 
  404.          IF rcvlog THEN write(lfile,c); 
  405.          av:=ord(c);
  406.          END;   
  407.       IF av=mark THEN rst:=1;   
  408.       CASE rst OF   
  409.  
  410.          0: {Mark character never encountered.} 
  411.             BEGIN   
  412.             putbuf(rcvbuf,av);  
  413.             ineoln:=eoln(input);
  414.             END;
  415.  
  416.          1: {Mark character.}   
  417.             BEGIN   
  418.             rcvtyp:=1;  
  419.             rcvseq:=-1; 
  420.             bufinit(rcvbuf);
  421.             ineoln:=eoln(input);
  422.             rst:=2; 
  423.             END;
  424.  
  425.          2: {Length of the packet.} 
  426.             BEGIN   
  427.             cs:=av; {Initialize checksum}   
  428.             rlen:=unchar(av)-3; 
  429.             rst:=3; 
  430.             END;
  431.  
  432.          3: {Packet number.}
  433.             BEGIN   
  434.             cs:=cs+av;  
  435.             rsq:=unchar(av);
  436.             rst:=4; 
  437.             END;
  438.  
  439.          4: {Packet type.}  
  440.             BEGIN   
  441.             cs:=cs+av;  
  442.             rt:=av; {remember the packet type}  
  443.             rst:=5; 
  444.             IF rlen=0 THEN rst:=6;  
  445.             END;
  446.  
  447.          5: {Data portion.} 
  448.             BEGIN   
  449.             cs:=cs+av;  
  450.             putbuf(rcvbuf,av);  
  451.             IF rcvbuf.ln = rlen THEN rst:=6;
  452.             END;
  453.  
  454.          6: {Checksum.} 
  455.             BEGIN   
  456.             IF checksum(cs)=unchar(av) THEN 
  457.                BEGIN
  458.                rcvtyp:=rt;  
  459.                rcvseq:=rsq; 
  460.                ineoln:=true; {Ignore the rest of the line}  
  461.                END  
  462.             ELSE
  463.                BEGIN
  464.                numcserr:=numcserr+1;
  465.                rst:=0; {Look for another mark}  
  466.                rcvtyp:=2;  {Indicate checksum error}
  467.                ineoln:=eoln(input); 
  468.                END; 
  469.             END;
  470.          END;   
  471.       END;  
  472.    END; 
  473. IF rcvlog THEN writeln(lfile,'>');  
  474. END;
  475. {$F Build and send packets} 
  476. PROCEDURE makepacket(ptype: ascval; seq, len: INTEGER); 
  477. VAR i: INTEGER; 
  478.     c: ascval;  
  479.     cs: INTEGER;
  480.  
  481. BEGIN   
  482. bufinit(sndbuf);
  483. FOR i:=1 TO remnpad DO  
  484.    BEGIN
  485.    putbuf(sndbuf,rempad);   
  486.    END; 
  487. putbuf(sndbuf,mark);
  488. c:=makechar(len+3); 
  489. cs:=c;                              {Initialize checksum}   
  490. putbuf(sndbuf,c);   
  491. c:=makechar(seq);   
  492. cs:=cs+c;   
  493. putbuf(sndbuf,c);   
  494. c:=ptype;   
  495. cs:=cs+c;   
  496. putbuf(sndbuf,c);   
  497. FOR i:=1 to len DO  
  498.    BEGIN
  499.    c:=filbuf.ch[i]; 
  500.    cs:=cs+c;
  501.    putbuf(sndbuf,c);
  502. END;
  503. c:=makechar(checksum(cs));  
  504. putbuf(sndbuf,c);   
  505. {   
  506. The 1100 EXEC may strip trailing spaces from the end of output images.  
  507. This can cause a problem if the checksum is a space.  To eliminate this 
  508. problem, a period will be inserted in the output image after the
  509. checksum whenever the checksum is a space.  
  510. }   
  511. putbuf(sndbuf,ascper);  
  512. {   
  513. The 1100 O/S puts a CR LF on the end of each output line.   
  514. If the remote EOL character is not CR or LF, then it must   
  515. be added to the packet. 
  516. }   
  517. IF (remeol<>asccr) AND (remeol<>asclf) THEN 
  518.    BEGIN
  519.    putbuf(sndbuf,remeol);   
  520.    END; 
  521. END;
  522.  
  523. PROCEDURE sndpkt;   
  524. VAR 
  525.    i:INTEGER;   
  526.  
  527. BEGIN   
  528. IF sndlog THEN write(lfile,'snd <');
  529. FOR i:=1 TO sndbuf.ln DO
  530.    BEGIN
  531.    write(output,chr(sndbuf.ch[i])); 
  532.    IF sndlog THEN write(lfile,chr(sndbuf.ch[i]));   
  533. END;
  534. writeln(output);
  535. IF sndlog THEN writeln(lfile,'>');  
  536. END;
  537. {$F File output}
  538.  
  539. PROCEDURE wrtrec;   
  540. VAR 
  541.    i:INTEGER;   
  542.    c:char;  
  543.  
  544. BEGIN   
  545. IF wrtlog THEN write(lfile,'wrt [');
  546. FOR i:=1 TO wrtbuf.ln DO
  547.    BEGIN
  548.    {$A- Turn off range checking, ASCII value may be >127}   
  549.    c:=chr(wrtbuf.ch[i]);
  550.    {$A+ Turn on range checking} 
  551.    write(wfile,c) ; 
  552.    IF wrtlog THEN write(lfile,c);   
  553.    END; 
  554. writeln(wfile); 
  555. IF wrtlog THEN writeln(lfile,']');  
  556. bufinit(wrtbuf);
  557. END;
  558.  
  559. PROCEDURE wrtcls; {System dependent}
  560.  
  561. BEGIN   
  562. IF wstatus=open THEN
  563.    BEGIN
  564.    IF wrtbuf.ln>0 THEN wrtrec;  
  565.    closeelt1(wfile,wuse,fname); 
  566.    END; 
  567. wstatus:=closed;
  568. END;
  569.  
  570. PROCEDURE wrtopn; {System dependent}
  571. VAR 
  572. wstat: boolean; 
  573.  
  574. BEGIN   
  575. wrtcls; 
  576. wuse:='W$F$I$L$E$$$';   
  577. openelt1(wfile,wuse,fname,wstat);   
  578. IF wstat THEN wstatus:=open;
  579. bufinit(wrtbuf);
  580. END;
  581.  
  582. PROCEDURE wrtasc(a:ascval); 
  583.  
  584. BEGIN   
  585. IF wrtbuf.ln >=maxwrt THEN wrtrec;  
  586. putbuf(wrtbuf,a);   
  587. END;
  588. {$F Process data portion of data packet}
  589. PROCEDURE putrec(buf: ascbuf);  
  590. VAR 
  591.    i,j,repcnt:INTEGER;  
  592.    a:ascval;
  593.    qflag: boolean;  
  594.  
  595. BEGIN   
  596. i:=1;   
  597. WHILE i<= buf.ln DO 
  598.    BEGIN
  599.    a:=buf.ch[i]; i:=i+1;
  600.    repcnt:=1;   
  601.    IF a=remrep THEN 
  602.       BEGIN 
  603.       repcnt:=unchar(buf.ch[i]); i:=i+1;
  604.       a:=buf.ch[i]; i:=i+1; 
  605.       END;  
  606.    qflag:= a=remqu8;
  607.    IF qflag THEN
  608.       BEGIN 
  609.       a:=buf.ch[i]; i:=i+1; 
  610.       END;  
  611.    IF a=remquo THEN 
  612.       BEGIN 
  613.       a:=buf.ch[i]; i:=i+1; 
  614.       IF (a<>remquo) AND (a<>remqu8) AND (a<>remrep) THEN a:=tog64(a);  
  615.       END;  
  616.    IF qflag THEN a:=tog128(a);  
  617.    FOR j:=1 to repcnt DO
  618.       BEGIN 
  619.       IF a=asclf THEN   
  620.          BEGIN  
  621.          IF lfeol OR gotcr THEN 
  622.             BEGIN   
  623.             wrtrec; 
  624.             gotcr:=false;   
  625.             END 
  626.          ELSE   
  627.             BEGIN   
  628.             wrtasc(a);  
  629.             END;
  630.          END
  631.       ELSE  
  632.          BEGIN  
  633.          IF gotcr THEN  
  634.             BEGIN   
  635.             wrtasc(asccr);  
  636.             gotcr:=false;   
  637.             END;
  638.          IF a=asccr THEN
  639.             BEGIN   
  640.             IF creol THEN   
  641.                BEGIN
  642.                wrtrec;  
  643.                END  
  644.             ELSE IF crlfeol THEN
  645.                BEGIN
  646.                gotcr:=true; 
  647.                END  
  648.             ELSE
  649.                BEGIN
  650.                wrtasc(a);   
  651.                END; 
  652.             END 
  653.          ELSE   
  654.             BEGIN   
  655.             wrtasc(a);  
  656.             END;
  657.          END;   
  658.       END;  
  659.    END; 
  660. END;
  661. {$F File input} 
  662. PROCEDURE redrec;   
  663. VAR c: CHAR;
  664.     a: ascval;  
  665.     nonblank: INTEGER;  
  666.  
  667. BEGIN   
  668. bufinit(redbuf);
  669. IF redix >= 0 THEN readln(rfile);   
  670. redix:=0;   
  671. IF NOT eof(rfile) THEN  
  672.    BEGIN
  673.    nonblank:=0; 
  674.    IF redlog THEN write(lfile,'red ['); 
  675.    WHILE NOT eoln(rfile) DO 
  676.       BEGIN 
  677.       read(rfile,c);
  678.       IF redlog THEN write(lfile,c);
  679.       a:=ord(c);
  680.       putbuf(redbuf,a); 
  681.       IF a <> ascsp THEN nonblank := redbuf.ln; 
  682.       END;  
  683.    IF redlog THEN writeln(lfile,']');   
  684.    IF bstrip THEN redbuf.ln := nonblank;
  685.    IF creol OR crlfeol THEN putbuf(redbuf,asccr);   
  686.    IF lfeol OR crlfeol THEN putbuf(redbuf,asclf);   
  687.    END; 
  688. END;
  689.  
  690. PROCEDURE redopn; {System dependent}
  691. VAR 
  692. rstat: boolean; 
  693.  
  694. BEGIN   
  695. rstatus:=closed;
  696. ruse:='R$F$I$L$E$$$';   
  697. readelt1(rfile,ruse,fname,rstat);   
  698. IF rstat THEN rstatus:=open;
  699. redix:=-1;  
  700. redbuf.ln:=-1;  
  701. END;
  702.  
  703. PROCEDURE redcls;   
  704.  
  705. BEGIN   
  706. rstatus:=closed;
  707. END;
  708.  
  709. {$F Build data portion of data packet}  
  710. PROCEDURE getrec;   
  711. VAR a: ascval;  
  712.     exit: BOOLEAN;  
  713.     prevln,previx,tix: INTEGER; 
  714.  
  715. BEGIN   
  716. bufinit(filbuf);
  717. IF eof(rfile) THEN  
  718.    BEGIN
  719.    rstatus:=endfile;
  720.    END  
  721. ELSE
  722.    BEGIN
  723.    exit:=false; 
  724.    REPEAT   
  725.       IF redix >= redbuf.ln THEN
  726.          BEGIN  
  727.          redrec; {get another record and strip spaces}  
  728.          IF eof(rfile) THEN 
  729.             BEGIN   
  730.             exit:=true; 
  731.             IF filbuf.ln=0 THEN rstatus:=endfile;   
  732.             END;
  733.          END;   
  734.       IF redix < redbuf.ln THEN 
  735.          BEGIN  
  736.          prevln:=filbuf.ln; 
  737.          previx:=redix; 
  738.          redix:=redix+1;
  739.          a:=redbuf.ch[redix];   
  740.          IF locrep<>0 THEN  
  741.             BEGIN   
  742.             tix:=redix+1;   
  743.             WHILE (a=redbuf.ch[tix]) AND (tix<=redbuf.ln) DO tix:=tix+1;
  744.             tix:=tix-redix;   {tix is now the repeat count} 
  745.             IF tix>3 THEN   
  746.                BEGIN
  747.                IF tix>94 THEN tix:=94;  
  748.                putbuf(filbuf,locrep);   
  749.                putbuf(filbuf,makechar(tix));
  750.                redix:=redix-1+tix;  
  751.                END; 
  752.             END;
  753.          IF (a>127) THEN
  754.             BEGIN   
  755.             IF locqu8<>0 THEN putbuf(filbuf,locqu8);
  756.             a:=tog128(a);   
  757.             END;
  758.          IF (a<32) OR (a=ascdel) THEN   
  759.             BEGIN   
  760.             putbuf(filbuf,locquo);  
  761.             a:=tog64(a);
  762.             END;
  763.          IF (a=locquo) OR (a=locqu8) OR (a=locrep) THEN 
  764.             BEGIN   
  765.             putbuf(filbuf,locquo);  
  766.             END;
  767.          putbuf(filbuf,a);  
  768.          IF filbuf.ln >= remdsiz THEN   
  769.             BEGIN   
  770.             exit:=true; 
  771.             IF filbuf.ln>remdsiz then   
  772.                BEGIN
  773.                {Character expansion caused buffer length to be  
  774.                 exceeded.  Back up.}
  775.                filbuf.ln:=prevln;   
  776.                redix:=previx;   
  777.                END; 
  778.             END;
  779.          END;   
  780.    UNTIL exit;  
  781.    END; 
  782. END;
  783.  
  784. {$F Send states}
  785. PROCEDURE sendinitiate; 
  786.  
  787. BEGIN   
  788. IF fnlen>0 THEN 
  789.    BEGIN
  790.    redopn;  
  791.    IF rstatus=open THEN 
  792.       BEGIN 
  793.       putpar; {Put parameters into buffer}  
  794.       makepacket(ascs,seq,filbuf.ln); {Make packet with our parameters} 
  795.       numtry:=0;
  796.       state:=sheader;   
  797.       END   
  798.    ELSE 
  799.       BEGIN 
  800.       error('Error opening read file'); 
  801.       state:=kexit; 
  802.       END;  
  803.    END  
  804. ELSE
  805.    BEGIN
  806.    error('No read file specified'); 
  807.    state:=kexit;
  808.    END; 
  809. END;
  810.  
  811. PROCEDURE sendheader;   
  812.  
  813. BEGIN   
  814. IF rcvtyp=ascy THEN 
  815.    BEGIN
  816.    IF not sndonly THEN getpar; {Get parameters from ACK of 'S' packet}  
  817.    IF rfnlen>0 THEN 
  818.       BEGIN 
  819.       lintobuf(rfname,rfnlen,filbuf); {Send remote file name.}  
  820.       END   
  821.    ELSE 
  822.       BEGIN 
  823.       lintobuf(fname,fnlen,filbuf);   {Send local file name.}   
  824.       END;  
  825.    numtry:=0;   
  826.    seq:=(seq+1) mod 64; 
  827.    makepacket(ascf,seq,filbuf.ln);  
  828.    state:=sdata 
  829.    END; 
  830. END;
  831.  
  832. PROCEDURE senddata; 
  833.  
  834. BEGIN   
  835. IF rcvtyp=ascy THEN 
  836.    BEGIN
  837.    getrec;  
  838.    numtry:=0;   
  839.    seq:=(seq+1) mod 64; 
  840.    IF rstatus = open THEN   
  841.       BEGIN 
  842.       makepacket(ascd,seq,filbuf.ln);   
  843.       END   
  844.    ELSE 
  845.       BEGIN 
  846.       makepacket(ascz,seq,0);   
  847.       state:=sbreak;
  848.       fnlen:=0; 
  849.       END;  
  850.    END; 
  851. END;
  852.  
  853. PROCEDURE sendbreak;
  854.  
  855. BEGIN   
  856. IF rcvtyp=ascy THEN 
  857.    BEGIN
  858.    numtry:=0;   
  859.    seq:=(seq+1) mod 64; 
  860.    makepacket(ascb,seq,0);  
  861.    END; 
  862. state:=wexit;   
  863. END;
  864. {$F Receive states} 
  865. PROCEDURE receiveinitiate;  
  866.  
  867. BEGIN   
  868. IF rcvtyp=ascs  THEN
  869.    BEGIN
  870.    getpar; {Get parameters from packet} 
  871.    putpar; {Put parameters into buffer} 
  872.    makepacket(ascy,seq,filbuf.ln); {Make ACK packet with our parameters}
  873.    seq:=rcvseq; 
  874.    numtry:=0;   
  875.    seq:=(seq+1) mod 64; 
  876.    state:=rheader;  
  877.    END  
  878. ELSE
  879.    BEGIN
  880.    error('Wrong packet in receive initiation'); 
  881.    state:=kexit;
  882.    END; 
  883. END;
  884.  
  885. PROCEDURE receiveheader;
  886.  
  887. BEGIN   
  888. IF rcvtyp=ascf THEN 
  889.    BEGIN
  890.    IF fnlen=0 THEN  
  891.       BEGIN 
  892.       buftolin(rcvbuf,fname,fnlen); 
  893.       END;  
  894.    IF fnlen>0 THEN  
  895.       BEGIN 
  896.       wrtopn;   
  897.       IF wstatus=open THEN  
  898.          BEGIN  
  899.          makepacket(ascy,seq,0);
  900.          numtry:=0; 
  901.          seq:=(seq+1) mod 64;   
  902.          state:=rdata;  
  903.          END
  904.       ELSE  
  905.          BEGIN  
  906.          error('Error opening write file'); 
  907.          state:=kexit;  
  908.          END;   
  909.       END   
  910.    ELSE 
  911.       BEGIN 
  912.       error('No output file specified');
  913.       state:=kexit; 
  914.       END;  
  915.    END  
  916. ELSE IF rcvtyp=ascb THEN
  917.    BEGIN
  918.    makepacket(ascy,seq,0);  
  919.    sndpkt;  
  920.    state:=kexit;
  921.    END  
  922. ELSE
  923.    BEGIN
  924.    error('Wrong packet receiveing file header');
  925.    state:=kexit;
  926.    END; 
  927. END;
  928.  
  929. PROCEDURE receivedata;  
  930.  
  931. BEGIN   
  932. IF rcvtyp=ascd THEN 
  933.    BEGIN
  934.    putrec(rcvbuf);  
  935.    makepacket(ascy,seq,0);  
  936.    numtry:=0;   
  937.    seq:=(seq+1) mod 64; 
  938.    END  
  939. ELSE IF rcvtyp=ascz THEN
  940.    BEGIN
  941.    wrtcls;  
  942.    fnlen:=0;
  943.    makepacket(ascy,seq,0);  
  944.    numtry:=0;   
  945.    seq:=(seq+1) mod 64; 
  946.    state:=rheader;  
  947.    END  
  948. ELSE
  949.    BEGIN
  950.    error('Unexpected packet receiving data');   
  951.    state:=kexit;
  952.    END; 
  953. END;
  954. {$F Error processing}   
  955.  
  956. {Process fatal errors}  
  957.  
  958. PROCEDURE error; {parameters appear above in forward reference} 
  959. VAR i,l:integer;
  960.  
  961. BEGIN   
  962. l:=length(msg); 
  963. IF l>maxbuf-6 THEN l:=maxbuf-6; 
  964. bufinit(filbuf);
  965. FOR i:=1 to 3 DO putbuf(filbuf,ascsp); {Make message readable in packet}
  966. FOR i:=1 to l DO putbuf(filbuf,ord(msg[i]));
  967. FOR i:=1 to 3 DO putbuf(filbuf,ascsp); {Make message readable in packet}
  968. makepacket(asce,seq,filbuf.ln); 
  969. sndpkt; 
  970. state:=kexit;   
  971. END;
  972. {$F Command state}  
  973. PROCEDURE kermitcommand;
  974.  
  975. BEGIN   
  976. REPEAT  
  977.    rcvpkt;  
  978.    IF rcvseq>-1 THEN
  979.       BEGIN 
  980.       IF rcvtyp=ascs THEN   
  981.          BEGIN  
  982.          state:=rinitiate;  
  983.          END
  984.       ELSE IF rcvtyp=ascr THEN  
  985.          BEGIN  
  986.          IF fnlen=0 THEN
  987.             BEGIN   
  988.             buftolin(rcvbuf,fname,fnlen);   
  989.             END;
  990.          state:=sinitiate;  
  991.          END
  992.       ELSE  
  993.          BEGIN  
  994.          error('Unexpected packet type');   
  995.          END;   
  996.       END   
  997.    ELSE IF rcvseq=-1 THEN   
  998.       BEGIN 
  999.       writeln('No commands implemented');   
  1000.       END   
  1001.    ELSE IF rcvseq=-2 THEN   
  1002.       BEGIN 
  1003.       state:=kexit; 
  1004.       server:=false;
  1005.       END;  
  1006. UNTIL state<>kcommand;  
  1007. END;
  1008. {$F Get processor call options and file specifications} 
  1009.  
  1010. PROCEDURE getoptions; {System dependent}
  1011.  
  1012. BEGIN   
  1013. getspec(1,fname,fnlen);   {Get local file name, if any.}
  1014. getspec(2,rfname,rfnlen); {Get remote file name, if any.}   
  1015. IF 'S' IN options THEN state:=sinitiate;
  1016. IF 'R' IN options THEN state:=rinitiate;
  1017. IF 'T' IN options THEN  
  1018.    BEGIN
  1019.    sndonly:=true;   
  1020.    state:=sinitiate;
  1021.    server:=false;   
  1022.    END; 
  1023. IF 'B' IN options THEN  
  1024.    BEGIN
  1025.    locbsiz:=94; 
  1026.    END; 
  1027. IF 'C' IN options THEN  
  1028.    BEGIN
  1029.    crlfeol:=false;  
  1030.    creol:=true; 
  1031.    lfeol:=false;
  1032.    END; 
  1033. IF 'L' IN options THEN  
  1034.    BEGIN
  1035.    sndlog:=true;
  1036.    rcvlog:=true;
  1037.    wrtlog:=true;
  1038.    redlog:=true;
  1039.    END; 
  1040. optqu8:=0; {Assume no eight-bit quoting will be done}   
  1041. IF 'Q' IN options THEN  
  1042.    BEGIN
  1043.    optqu8:=ascamp; {Eight-bit quoting may be done}  
  1044.    END; 
  1045. IF ('W' IN options) AND ('S' IN options) THEN   
  1046.    BEGIN
  1047.    a1:=30000;   
  1048.    er(48{TWAIT$},a0,a1);
  1049.    END; 
  1050. END;
  1051. {$F Initialization state}   
  1052. PROCEDURE kermitinitialize; 
  1053. VAR lstat: boolean; 
  1054.  
  1055. BEGIN   
  1056. state:=kcommand;
  1057. numtry:=0;  
  1058. seq:=0; 
  1059. fnlen:=0; {Indicate no file name yet}   
  1060. bstrip:=true;   
  1061.  
  1062. locbsiz:=78;
  1063. loctout:=12;
  1064. locnpad:=0; 
  1065. locpad:=0;  
  1066. loceol:=asccr;  
  1067. locquo:=ascns;  
  1068. {  locqu8 will be set after options are processed. }
  1069. locrep:=asctil; {Initialize to 0 to turn off repeat counts} 
  1070.  
  1071. rembsiz:=78;
  1072. remdsiz:=rembsiz-3; 
  1073. remtout:=12;
  1074. remnpad:=0; 
  1075. rempad:=0;  
  1076. remeol:=asccr;  
  1077. remqu8:=0;  
  1078. remrep:=0;  
  1079.  
  1080. bufinit(sndbuf);
  1081.  
  1082. {The following should only be done on the first call to initialize} 
  1083. IF iniflg=false THEN
  1084.    BEGIN
  1085.    sndonly:=false;  
  1086.    sndlog:=false;   
  1087.    rcvlog:=false;   
  1088.    wrtlog:=false;   
  1089.    redlog:=false;   
  1090.    crlfeol:=true;   
  1091.    creol:=false;
  1092.    lfeol:=false;
  1093.    rstatus:=closed; 
  1094.    wstatus:=closed; 
  1095.    lstatus:=closed; 
  1096.  
  1097.    {System dependent initialization}
  1098.    ineoln:=false;  {Indicate no readln necessary for first line}
  1099.    getoptions;     {Process options and file specifications}
  1100.    IF sndlog OR rcvlog OR wrtlog OR redlog THEN logopn  
  1101.    END; 
  1102. locqu8:=optqu8; {Eight-bit quoting done only with Q-option} 
  1103. iniflg:=true;   
  1104. END;
  1105. {$F Main block} 
  1106.  
  1107.  
  1108. BEGIN   
  1109. version:= '2.0';
  1110. writeln(output,'Kermit 1100 ',version); 
  1111. iniflg:=false;  
  1112. server:=true;   
  1113. WHILE server DO 
  1114.    BEGIN
  1115.    kermitinitialize;
  1116.    IF state=kcommand THEN kermitcommand;
  1117.    IF state=sinitiate THEN sendinitiate;
  1118.    IF state=rinitiate THEN receiveinitiate; 
  1119.    WHILE state<>kexit DO
  1120.       BEGIN 
  1121.       REPEAT
  1122.          sndpkt;
  1123.          numtry:=numtry+1;  
  1124.          IF sndonly THEN
  1125.             BEGIN   
  1126.             rcvseq:=seq;
  1127.             rcvtyp:=ascy;   
  1128.             rcvbuf.ln:=0;   
  1129.             END 
  1130.          ELSE   
  1131.             BEGIN   
  1132.             rcvpkt; 
  1133.             END;
  1134.          IF rcvtyp=ascn THEN
  1135.             BEGIN   
  1136.             {We have just received a NAK.  The Kermit protocol would
  1137.             be much simpler and no less effective if the NAK had never  
  1138.             been included.  However, since this is not universally  
  1139.             appreciated, one has to deal with them.  To do so, we   
  1140.             will convert a NAK into an ACK with the previous sequence   
  1141.             number.}
  1142.             rcvseq:=(rcvseq-1) mod 64;  
  1143.             rcvtyp:=ascy;   
  1144.             END 
  1145.          ELSE IF rcvseq=-2 THEN {End of file on input}  
  1146.             BEGIN   
  1147.             error('End of file on input data'); 
  1148.             state:=kexit;   
  1149.             server:=false;  
  1150.             END;
  1151.       UNTIL (rcvseq=seq) OR (numtry>=maxtry) OR (state=kexit);  
  1152.       IF (rcvseq<>seq) AND (state<>kexit) THEN  
  1153.          BEGIN  
  1154.          error('Failed to receive expected packet');
  1155.          state:=kexit;  
  1156.          END
  1157.       ELSE IF rcvtyp=asce THEN {Just received error packet} 
  1158.          BEGIN  
  1159.          state:=kexit   
  1160.          END
  1161.       ELSE  
  1162.          BEGIN  
  1163.          CASE state OF  
  1164.             sheader     :sendheader;
  1165.             sdata       :senddata;  
  1166.             sbreak      :sendbreak; 
  1167.             rheader     :receiveheader; 
  1168.             rdata       :receivedata;   
  1169.             wexit       :state:=kexit; {Go around one more time, then exit} 
  1170.             kexit       :;  
  1171.             END;
  1172.          END
  1173.    END; 
  1174.    wrtcls;  
  1175.    END; 
  1176. logcls; 
  1177. writeln('Kermit End');  
  1178. END .   
  1179.