{ Externals called by Parse } FUNCTION Exists({ Using } VAR s:string): { Returning } boolean; EXTERNAL; { open (RT-11) -- open a file for reading or writing } FUNCTION Sopen (VAR name : string; omode : integer) : filedesc; EXTERNAL; { close (omsi) -- close a file } PROCEDURE Sclose (fd : filedesc); EXTERNAL; { close all files on exit } PROCEDURE closeall; EXTERNAL; PROCEDURE CtoS({ Using } x:cstring; { Returning } VAR s:string); { convert constant to STIP string } EXTERNAL; { getcf (UCB) -- get one character from file } FUNCTION getcf (VAR c: character; fd : filedesc) : character; EXTERNAL; { putcf (UCB) -- put a single character on file fd } PROCEDURE putcf (c : character; fd : filedesc); EXTERNAL; PROCEDURE GTLINE(VAR commandLine : string80); EXTERNAL; { getarg (RT-11) -- copy n-th command line argument into s } FUNCTION getarg (n : integer; VAR s : string; maxs : integer) : boolean; EXTERNAL; { number of arguments -- RT-11 } FUNCTION nargs : integer; EXTERNAL; { putstr (UCB) -- put out string on file } PROCEDURE putstr (VAR s : string; f : filedesc); EXTERNAL; PROCEDURE PutCln({ Using } x:cstring; { Using } fd:filedesc); { output literal followed by NEWLINE } EXTERNAL; PROCEDURE stiphalt; { used by external procedures for halt } EXTERNAL; { fcopy -- copy file fin to file fout } PROCEDURE fcopy (fin, fout : filedesc); VAR c : character; BEGIN WHILE (getcf(c, fin) <> ENDFILE) DO putcf(c, fout) END; PROCEDURE OverHd({ Using } p,f: Stats; { Returning } VAR o:integer); { Calculate OverHead as % } { 0verHead := (p-f)*100/f } VAR temp : real; BEGIN IF (f <> 0.0) THEN BEGIN temp := (p-f)*100/f; o := round(temp); END ELSE o := 0; END; PROCEDURE CalRat({ Using } f: Stats; { Using } t:integer; { Returning } VAR r:integer); { Calculate Effective Baud Rate } { Rate = f*10/t } VAR temp : real; BEGIN IF t <> 0 THEN BEGIN temp := f*10/t; r := round(temp); END ELSE r := 0; END; { mustopen -- open file or die } FUNCTION mustopen (VAR name : string; mode : integer) : filedesc; VAR fd : filedesc; BEGIN fd :=Sopen(name, mode); IF (fd = IOERROR) THEN BEGIN putstr(name, STDERR); Putcln(': can''t open file ',STDERR); stiphalt; END; mustopen := fd END; PROCEDURE Setargs; { Set up list of filenames for KERMIT } VAR idx : 1.. MAXSTR; i:integer; fname : string; junk : boolean; BEGIN cmdargs := 0; { initialize } idx := 1; WHILE ( cmdlin[idx]<>ENDSTR) DO BEGIN WHILE (cmdlin[idx] = BLANK) DO idx := idx+1; IF (cmdlin[idx]<>ENDSTR) THEN BEGIN cmdargs := cmdargs+1; cmdidx[cmdargs] := idx; WHILE ((cmdlin[idx]<>ENDSTR) AND (cmdlin[idx]<>BLANK)) DO idx := idx+1; IF (cmdlin[idx] <> ENDSTR) THEN BEGIN cmdlin[idx] := ENDSTR; idx := idx+1; END; IF (cmdlin[cmdidx[cmdargs]] = LESS) THEN BEGIN cmdidx[cmdargs] := cmdidx[cmdargs] + 1; junk := getarg(cmdargs,fname,MAXSTR); redirect[STDIN] := mustopen(fname,IOREAD); cmdargs := cmdargs -1 END ELSE IF (cmdlin[cmdidx[cmdargs]] = GREATER) THEN BEGIN cmdidx[cmdargs] := cmdidx[cmdargs] + 1; junk := getarg(cmdargs,fname,MAXSTR); redirect[STDOUT] := mustopen(fname,IOWRITE); cmdargs := cmdargs -1 END END END END; { Beginning of PARSER } { Based on the Parser in the VAX KERMIT by Bruce Pinn (UTCS) } {$E+} PROCEDURE PromptAndParseUser(VAR exitProgram : boolean; VAR RunType : command); CONST { CONSTANTS for Parser } NULL = -1; RANGENULL = -2; INVALIDCOMMAND = 1; INVALIDSETCOMMAND = 2; INVALIDSHOWCOMMAND = 3; NOTIMPLEMENTED = 4; INVALIDFILESPEC = 5; INVALIDSETCVALUE = 6; INVALIDSETDVALUE = 7; INVALIDSETOVALUE = 8; INVALIDSETRANGE = 9; SENDPARMS = 10; RECEIVEPARMS = 11; LOCALPARMS = 12; BLANKLINE = 13; NOHELPAVAILABLE = 14; uSET = 3; uMSEND = 3; uMRECEIVE = 1; uSHOW = 2; uSTATUS = 2; uCONNECT = 1; uHELP = 1; uQUESTION = 1; uEXIT = 1; uQUIT = 1; uSEND = 1; uRECEIVE = 1; uDEBUGGING = 3; uFILEWARNING = 1; uFILERECORD = 5; uEIGHTBIT = 2; uLOCALECHO = 2; uLINE = 2; uESCAPE = 2; uDELAY = 3; uPACKETLENGTH = 3; uPADDING = 4; uPADCHAR = 4; uTIMEOUT = 1; uENDOFLINE = 1; uQUOTE = 1; uALL = 1; uON = 2; uOFF = 2; uBADTOKEN = 1; uCR = 2; uLF = 1; uCLF = 2; uPARITY = 1; uEVEN = 1; uODD = 1; uNONE = 1; uSPEED = 2; uVERBOSE = 1; uTESTING = 1; oSET = 0; oSHOW = 1; oSTATUS = 2; oCONNECT = 3; oHELP = 4; oEXIT = 5; oQUIT = 6; oSEND = 7; oRECEIVE = 8; oDEBUGGING = 9; oFILEWARNING = 10; oLOCALECHO = 11; oLINE = 12; oESCAPE = 13; oDELAY = 14; oPACKETLENGTH = 15; oPADDING = 16; oPADCHAR = 17; oTIMEOUT = 18; oENDOFLINE = 19; oQUOTE = 20; oQUESTIONM = 23; oALL = 24; oBADTOKEN = 25; oFILERECORD = 26; oCR = 27; oLF = 28; oCLF = 29; oPARITY = 30; oSPEED = 34; oVERBOSE = 35; oTESTING = 36; oEIGHTBIT = 37; oMAINTYPE = 1; oSETTYPE = 2; oSHOWTYPE = 3; oSENDTYPE = 4; oRECEIVETYPE = 5; oDEBUGTYPE = 6; oFILEWARNTYPE = 7; oFILERECTYPE = 8; oLOCECHOTYPE = 9; oPARITYTYPE = 10; oEIGHTBITTYPE = 11; DECIMAL = 0; SDECIMAL = 1; OCTAL = 2; CHRACTER = 3; IDECIMAL = 4; o300BAUD = 300; o600BAUD = 600; o1200BAUD = 1200; o2400BAUD = 2400; o4800BAUD = 4800; o9600BAUD = 9600; cBADTOKEN = 'XX '; cSET = 'SET '; cSHOW = 'SHOW '; cSTATUS = 'STATUS '; cCONNECT = 'CONNECT '; cHELP = 'HELP '; cEXIT = 'EXIT '; cQUIT = 'QUIT '; cQUESTION = '? '; cSEND = 'SEND '; cRECEIVE = 'RECEIVE '; cDEBUGGING = 'DEBUGGING '; cFILEWARNING = 'FILE-WARNING '; cLOCALECHO = 'LOCAL-ECHO '; cLINE = cBADTOKEN; cESCAPE = cBADTOKEN; cDELAY = 'DELAY '; cPACKETLENGTH = 'PACKET-LENGTH'; cPADDING = 'PADDING '; cPADCHAR = 'PADCHAR '; cTIMEOUT = 'TIMEOUT '; cENDOFLINE = 'END-OF-LINE '; cQUOTE = 'QUOTE '; cALL = 'ALL '; cON = 'ON '; cOFF = 'OFF '; cEIGHTBIT = 'EIGHT-BIT '; cFILERECORD = cBADTOKEN; cCR = 'CR '; cLF = 'LF '; cCLF = 'CLF '; cPARITY = 'PARITY '; cEVEN = 'EVEN '; cODD = 'ODD '; cNONE = 'NONE '; cSPEED = cBADTOKEN; cVERBOSE = 'VERBOSE '; cTESTING = 'TESTING '; PROCEDURE SetEchoAndParity; VAR tempecho,tempparity : integer; BEGIN IF (localEcho = oON) THEN tempecho := 1 ELSE tempecho := 0; IF parity = oNONE THEN tempparity := -1 ELSE IF parity = oEVEN THEN tempparity := 0 ELSE tempparity := 1; {$C .GLOBL PARFLG .GLOBL ECHO MOV tempecho(SP),ECHO MOV tempparity(SP),PARFLG } END; { Determine length of string. } FUNCTION LenString(VAR tempStr : string80) : integer; VAR i : integer; endofstring : boolean; BEGIN i := 80; endofstring := false; WHILE ((i >= 1) AND NOT(endofstring)) DO IF (tempStr[i] = ' ') THEN i := i - 1 ELSE endofstring := true; LenString := i; END; { Copy command line into temporary string until either EOS or blank } PROCEDURE SkipBlanks(VAR command : string80; VAR commandLen : integer); VAR i, k, j : integer; endOfString : boolean; BEGIN i := 1; endofString := false; WHILE ((i <= commandLen) AND (NOT(endofString))) DO IF (command[i] = ' ') THEN i := i + 1 ELSE endofString := true; k := 1; FOR j:=i TO commandLen DO BEGIN command[k] := command[j]; k := k + 1; END; commandLen := commandLen - i; END; { Copy command line into temporary string until either EOS or blank } PROCEDURE CopyToken(VAR command : string80; VAR commandLen : integer; VAR tempStr : string13; VAR totChars : integer); VAR i, j, k : integer; noBlank : boolean; tempToken : string80; BEGIN FOR i:=1 TO SMALLSIZE DO tempStr[i] := ' '; i := 1; noblank := true; WHILE ((i <= commandLen) AND (noblank)) DO IF (command[i] <> ' ') THEN BEGIN tempToken[i] := command[i]; i := i + 1; END ELSE noBlank := false; totChars := i - 1; IF (totChars <= SMALLSIZE) THEN FOR i:=1 TO totChars DO tempStr[i] := tempToken[i] ELSE BEGIN totChars := 2; tempStr := cBADTOKEN; END; k := 1; FOR j:=(totChars+1) TO commandLen DO BEGIN command[k] := command[j]; k := k + 1; END; commandLen := commandLen - (totChars - 1); END; { Routine to compare strings for symbol comparison. } FUNCTION CompareStr(command, symbol : string13; commandLen, symbolLen : integer) : boolean; VAR i : integer; sameStr : boolean; BEGIN sameStr := true; i := 1; WHILE (sameStr AND (i <= commandLen)) DO IF command[i] <> symbol[i] THEN sameStr := false ELSE i := i + 1; i := i - 1; CompareStr := sameStr AND (i >= symbolLen); END; PROCEDURE StrUpcase(VAR command : string80; commandLen : integer); VAR i, diff : integer; BEGIN diff := ord('a') - ord('A'); FOR i:=1 TO commandLen DO IF ((command[i] >= 'a') AND (command[i] <= 'z')) THEN command[i] := chr(ord(command[i]) - diff); END; FUNCTION IsNumeric( token : string13; VAR tokLen, value : integer; typeToken : integer) : boolean; VAR goodChar : boolean; upBound : char; base, i : integer; BEGIN value := 0; i := 1; goodChar := true; upBound := '9'; base := 10; IF (typeToken = OCTAL) THEN BEGIN upBound := '7'; base := 8; END; WHILE ((i <= tokLen) AND (goodChar)) DO IF ((token[i] >= '0') AND (token[i] <= upBound)) THEN BEGIN value := (value*base) + (ord(token[i]) - ord('0')); i := i + 1; END ELSE BEGIN goodChar := false; value := 0; END; goodChar := goodChar AND (tokLen > 0); IF (typeToken = OCTAL) THEN IsNumeric := goodChar AND ((value >= 0) AND (value <= 31)) ELSE IF (typeToken = SDECIMAL) THEN IsNumeric := goodChar AND ((value >= MINPACKETSIZE) AND (value <= MAXPACKETSIZE)) ELSE IF (typeToken = IDECIMAL) THEN IsNumeric := goodChar AND ((value = o300BAUD) OR (value = o600BAUD) OR (value = o1200BAUD) OR (value = o2400BAUD) OR (value = o4800BAUD) OR (value = o9600BAUD)) ELSE IsNumeric := goodChar AND ((value >= 0) AND (value <= 99)) END; { Print the ? help writeln for main menu. } PROCEDURE PrintMainHelp; BEGIN writeln(' send '); writeln(' receive []'); writeln(' status'); writeln(' connect'); writeln(' set