home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
intelmdsb
/
mdsmit.p80
< prev
next >
Wrap
Text File
|
2020-01-01
|
17KB
|
645 lines
$TITLE ('KERMIT - MAIN MODULE')
kermit:
/* COPYRIGHT (C) 1985, Trustees of Columbia University in the City of New */
/* York. Permission is granted to any individual or institution to use, */
/* copy, or redistribute this software so long as it is not sold for */
/* profit, provided this copyright notice is retained. /*
/* Contains the following public routines: */
/* cmdtail, exhelp, ioinit, newline, nin, nout, print, procbaud, spin, */
/* strcmp, synerr, token, upcase, and varcmp */
/* NOTE: See the comment below regarding the default "escape" character */
do;
declare true literally '0FFH';
declare false literally '00H';
/* UART control bits */
declare port1cmd literally '0F5H';
declare port1dat literally '0F4H';
declare port1clk literally '0F0H';
declare timing1 literally '036H';
declare port2cmd literally '0F7H';
declare port2dat literally '0F6H';
declare port2clk literally '0F1H';
declare timing2 literally '076H';
declare modesel literally '0F3H';
declare reset literally '040H';
declare EnaTxRx literally '025H';
declare tx$rdy literally '01H';
declare rx$rdy literally '02H';
declare null literally '000H';
declare lf literally '0AH';
declare cr literally '0DH';
declare crlf literally 'cr,lf,null';
declare space literally '20H';
declare dollar literally '24H';
declare bel literally '07H';
declare buflen literally '122';
declare buffer(buflen) byte;
declare (cmdstr, temp, cmdptr) address;
declare taking byte public initial(false); /* within "TAKE" file */
declare continue byte initial(true);
/* ****** Default mode settings ****** */
/* Note that the default setting for the Kermit "escape" character */
/* differs from common Kermit usage. This is due to the fact that */
/* some Intel workstations (e.g. Series III) cannot generate a */
/* "control-right bracket" character. If you are using only Series */
/* IV workstations, you can change the initial value below to suit, */
/* for example, to 29 for control-right bracket. Alternately, you */
/* can use the "SET ESCAPE" command (manually or in an .INI file) */
/* to alter the escape character each time you invoke Kermit. */
declare escchar byte public initial(29); /* control-right bracket */
declare baudrate address public initial(2400); /* port baud rate */
declare parity byte public initial(0); /* parity */
/* (0 = None, 1 = Mark, 2 = Space, 3 = Even, 4 = Odd) */
declare stopbits byte public initial(2); /* number of stop bits */
/* (0 = 1 stop bit, 1 = 1 1/2 stop bits, 2 = 2 stop bits) */
declare port byte public initial(2); /* communications port */
declare maxtry byte public initial(5); /* number of retries */
declare debug byte public initial(false);
declare halfduplex byte public initial(false);
declare warning$flag byte public initial(false); /* dup-named file switch */
declare take$echo byte public initial(false); /* echo take commands switch */
declare def$drive(5) byte public initial(0,0,0,0,0); /* default drive */
declare prompt(20) byte public initial('ISIS-Kermit>',null); /* Kerm. prompt */
declare def$prompt(20) byte public initial('ISIS-Kermit>',null); /* Default */
declare filename address public;
declare state byte public;
declare msgnum byte public;
declare tries byte public;
declare oldtry byte public;
/* Masks for comm input and output bytes */
declare input$and byte public;
declare output$and byte public;
declare output$or byte public;
declare cmd byte;
declare speed byte;
/* Kermit parameter defaults */
declare pksize literally '94';
declare mytime literally '5';
declare mynumpads literally '0';
declare mypadchr literally '0';
declare myeol literally 'cr';
declare myquote literally '023H';
/* Current Kermit parameters */
declare spsize byte public initial(pksize); /* present packet size */
declare timeint byte public initial(mytime); /* present time out */
declare numpads byte public initial(mynumpads); /* how many pads to send */
declare padchar byte public initial(mypadchr); /* present pad character */
declare eol byte public initial(myeol); /* present eol character */
declare quote byte public initial(myquote); /* present quote character */
/* Subroutine declarations */
co: procedure(char)external;
declare char byte;
end co;
ci: procedure byte external;
end ci;
getc: procedure (port) byte external;
declare port byte;
end getc;
ready: procedure (port) byte external;
declare port byte;
end ready ;
read: procedure(jfn, buf, max, count, status)external;
declare(jfn, buf, max, count, status)address;
end read;
error: procedure(errnum)external;
declare(errnum)address;
end error;
bye:
procedure external;
end bye;
connect:
procedure external;
end connect;
cwd:
procedure external;
end cwd;
exit: procedure external; end exit;
finish:
procedure external;
end finish;
get: procedure external;
end get;
help: procedure external;
end help;
logout:
procedure external;
end logout;
recv: procedure external;
end recv;
send: procedure external;
end send;
set: procedure external;
end set;
show:
procedure external;
end show;
take:
procedure external;
end take;
takeline: procedure (addr) external;
declare addr address;
end takeline;
takeini: procedure external;
end takeini;
newline:
procedure public;
call co(cr);
call co(lf);
end newline;
/* SPIN: Searches a string for a character greater than blank */
spin: procedure(string)address public;
declare string address;
declare char based string byte;
do while (char <> null) and (char < 021H);
string = string + 1;
end;
return string;
end spin;
strcmp: procedure(s1,s2)byte public;
declare(s1,s2)address;
declare c1 based s1 byte;
declare c2 based s2 byte;
declare retval byte;
retval = 0;
s1 = spin(s1);
s2 = spin(s2);
if not(c1 = c2) then retval = c1 - c2;
do while (c1 > 0) and (c2 > 0) and (retval=0);
retval = c1 - c2;
s1 = s1+1;
s2 = s2+1;
end;
return retval;
end strcmp;
/* varcmp: Compare two variable length strings */
/* This routine compares corresponding characters in two strings. */
/* If it finds a null in the first string, it returns the number */
/* of characters which matched, excluding the null. If it finds */
/* a null in the second string or a mismatch, it returns a zero. */
varcmp: procedure(s1,s2)byte public;
declare(s1,s2)address;
declare c1 based s1 byte;
declare c2 based s2 byte;
declare cnt byte;
cnt = 0;
/* s1 = spin(s1); */
/* s2 = spin(s2); */
do while c1 > 0;
if c2 = 0 then return 0;
if c1 <> c2 then return 0;
s1 = s1+1;
s2 = s2+1;
cnt = cnt + 1;
end;
return cnt;
end varcmp;
/* TOKEN: returns a pointer to a null-terminated token pointed */
/* to prior to the call by cmdptr. After the call, cmdptr points */
/* to the end of the original string, or the first character after */
/* the null character replacing the first whitespace after the first */
/* token. */
token: procedure address public;
declare result address;
declare char based cmdptr byte;
result = 0;
cmdptr = spin(cmdptr);
if char <> null then
do;
result = cmdptr;
do while char > ' ';
cmdptr = cmdptr + 1;
end;
if char <> null then
do;
char = null;
cmdptr = cmdptr + 1;
end;
end;
return result;
end token;
/* CMDTAIL: returns a pointer to the first nonblank character of the */
/* remainder of the command line, or zero if there were no more */
/* nonblank characters in the command line. */
cmdtail: procedure address public;
declare char based cmdptr byte;
cmdptr = spin(cmdptr);
if char = null then return 0;
else return cmdptr;
end cmdtail;
nout: procedure(n) public;
declare n address;
declare (quotient, digit) address;
declare numbuf(8) byte;
declare index byte;
if n = 0 then
do;
call co('0');
return;
end;
index = 1;
do while (n > 0);
digit = n mod 10;
numbuf(index) = digit + '0';
index = index + 1;
n = n / 10;
end;
do while ((index := index - 1) > 0);
call co(numbuf(index));
end;
end nout;
nin: procedure(string) address public;
declare string address;
declare result address;
declare c based string byte;
result = 0;
if (string <> 0) then do;
string = spin(string);
do while (c >= '0') and (c <= '9');
result = result * 10 + (c - '0');
string = string + 1;
end;
end;
return result;
end nin;
print: procedure(msg) public;
declare msg address;
declare c based msg byte;
do while (c > 0) and (c <> '$');
if c = '\' then
call newline;
else
call co(c);
msg = msg + 1;
end;
end print;
synerr: procedure public;
call print(.('Syntax error\$'));
end synerr;
/* IOINIT: This routine takes a port number, 0,1 or 2, and a speed in the */
/* range 0-8 and initializes the required port to work at the required */
/* speed. The routine returns no parameters. */
ioinit: procedure public;
declare baud structure (code0(9) byte, code1(9) byte, mult(9) byte)
/* Low-order byte of counter values */
data (0BAH, 80H, 40H, 20H, 10H, 20H, 10H, 08H, 04H,
/* High-order byte of counter values */
02H, 0H, 0H, 0H, 0H, 0H, 0H, 0H, 0H,
/* 8251A command byte baud rate multiplier control bits */
02H, 03H, 03H, 03H, 03H, 02H, 02H, 02H, 02H);
/* 8251A command byte parity and length control bits */
/* (0=None, 1=Mark, 2=Space, 3=Even, 4=Odd) */
declare paritymask(5) byte data (0CH, 0CH, 0CH, 38H, 18H);
/* 8251A command byte stop bits control bits */
/* (0 = 1 stop bit, 1 = 1 1/2 stop bits, 2 = 2 stop bits) */
declare stopmask(3) byte data (40H, 80H, 0C0H);
/* Mask bytes for comm. input and output bytes */
declare inp$mask$and(9) byte
data (0FFH, 7FH, 0FFH, 7FH, 7FH);
declare out$mask$and(9) byte
data (0FFH, 0FFH, 07FH, 0FFH, 0FFH);
declare out$mask$or(9) byte
data (0H, 80H, 0H, 0H, 0H);
declare (c, status) byte;
if debug then call print(.('\initializing serial port\$'));
do case port;
do;
if debug then call print(.('port 0 initialized\$'));
end;
do;
if debug then call print(.('port 1 initialized\$'));
/* Put the USART into a known state by writing */
/* three zero command bytes to it */
output(port1cmd) = 0H;
output(port1cmd) = 0H;
output(port1cmd) = 0H;
/* Reset the USART */
output(port1cmd) = reset;
output(modesel) = timing1;
output(port1clk) = baud.code0(speed);
output(port1clk) = baud.code1(speed);
output(port1cmd) = (stopmask(stopbits) or paritymask(parity)
or baud.mult(speed));
input$and = inp$mask$and(parity);
output$and = out$mask$and(parity);
output$or = out$mask$or(parity);
if debug then
do;
call print(.('Mode command: $'));
call nout(stopmask(stopbits) or paritymask(parity)
or baud.mult(speed));
call newline;
end;
output(port1cmd) = EnaTxRx;
if ready(1) > 0 then c = getc(1); /* discard any char */
end;
do;
if debug then call print(.('port 2 initialized\$'));
/* Put the USART into a known state by writing */
/* three zero command bytes to it */
output(port2cmd) = 0H;
output(port2cmd) = 0H;
output(port2cmd) = 0H;
/* Reset the USART */
output(port2cmd) = reset;
output(modesel) = timing2;
output(port2clk) = baud.code0(speed);
output(port2clk) = baud.code1(speed);
output(port2cmd) = (stopmask(stopbits) or paritymask(parity)
or baud.mult(speed));
input$and = inp$mask$and(parity);
output$and = out$mask$and(parity);
output$or = out$mask$or(parity);
if debug then
do;
call print(.('Mode command: $'));
call nout(stopmask(stopbits) or paritymask(parity)
or baud.mult(speed));
call newline;
end;
output(port2cmd) = EnaTxRx;
if ready(2) > 0 then c = getc(2); /* discard any char */
end;
end;
end ioinit;
usage: procedure;
call print(.('usage: kermit (110|150|300|600|1200|2400|4800|9600$'));
call print(.('|19200) (1|2)\$'));
call exit;
end usage;
procbaud: procedure (newbaud) byte public;
declare rate(9) address
data(110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200);
declare (result, i, done) byte;
declare newbaud address;
result = false; /* tentative result of "bad rate" */
i = 0;
done = false;
do while (done = false);
if i > 8 then done = true; /* off end of table */
else
if newbaud < rate(i) then done = true; /* not found */
else
if newbaud = rate(i) then
do;
done = true;
result = true;
end;
else
i = i + 1; /* try next */
end;
if result = true then
do;
baudrate = newbaud;
speed = i;
end;
return result;
end procbaud;
readln: procedure;
declare (count, status) address;
call read(1, .buffer, buflen, .count, .status);
if status > 0 then
do;
call print(.('READLN FAILED\$'));
call error(status);
call exit;
end;
buffer(count-2) = 0;
cmdptr = .buffer;
end readln;
/* Convert the contents of a string from lower case to upper case */
upcase: procedure(addr) public;
declare addr address;
declare chr based addr byte;
declare capdiff byte;
capdiff = 'a' - 'A';
do while chr <> 0;
if (chr >= 'a') and (chr <= 'z') then chr = chr - capdiff;
addr = addr + 1;
end;
end upcase;
/* Display help for the EXIT command */
exhelp: procedure public;
call print(.('\EXIT\\$'));
call print(.(' The EXIT command causes KERMIT to terminate and $'));
call print(.('return to ISIS.\\$'));
call print(.('Syntax:\\$'));
call print(.(' EXIT\\$'));
end exhelp;
/* Get the next command to be executed */
getcmd: procedure;
cmdstr = 0;
do while (cmdstr = 0);
if taking then
do; /* Get the command from the "TAKE" file */
call takeline(.buffer);
cmdptr = .buffer;
if takeecho and taking then
do; /* (Takeline will have turned "taking" off at EOF) */
call print(.('TAKE command>$'));
call print(cmdptr);
call newline;
end;
end;
else
do; /* Get the command from the console */
call print(.prompt); /* Display the prompt */
call readln;
end;
cmdstr = token; /* Get the command "word" */
call upcase(cmdstr); /* Convert to upper case */
end;
end getcmd;
/* Execute a Kermit command */
docmd: procedure;
if (varcmp(cmdstr,.('BYE',null)) >= 1) then cmd = 1;
else
if (varcmp(cmdstr,.('CONNECT',null)) >= 2) then cmd = 2;
else
if (varcmp(cmdstr,.('CWD',null)) >= 2) then cmd = 3;
else
if (varcmp(cmdstr,.('EXIT',null)) >= 1) then cmd = 4;
else
if (varcmp(cmdstr,.('FINISH',null)) >= 1) then cmd = 5;
else
if (varcmp(cmdstr,.('GET',null)) >= 1) then cmd = 6;
else
if (varcmp(cmdstr,.('HELP',null)) >= 1) then cmd = 7;
else
if (varcmp(cmdstr,.('LOGOUT',null)) >= 1) then cmd = 8;
else
if (varcmp(cmdstr,.('RECEIVE',null)) >= 1) then cmd = 9;
else
if (varcmp(cmdstr,.('SEND',null)) >= 3) then cmd = 10;
else
if (varcmp(cmdstr,.('SET',null)) >= 3) then cmd = 11;
else
if (varcmp(cmdstr,.('SHOW',null)) >= 2) then cmd = 12;
else
if (varcmp(cmdstr,.('TAKE',null)) >= 1) then cmd = 13;
else
do;
call print(.('Invalid or ambiguous command name\$'));
cmd = 0;
end;
if (cmd = 1 or cmd = 2 or cmd = 4 or cmd = 5 or cmd = 8 or cmd = 12) then
if token > 0 then /* Only some commands can have operands */
do;
call print(.('Extraneous operand(s) specified\$'));
cmd = 0;
end;
do case cmd;
/* 0 = Command error previously diagnosed */
do;
/* Null action */
end;
/* 1 = BYE command */
do;
call bye;
continue = false;
end;
/* 2 = CONNECT command */
call connect;
/* 3 = CWD command */
call cwd;
/* 4 = EXIT command */
continue = false;
/* 5 = FINISH command */
call finish;
/* 6 = GET command */
call get;
/* 7 = HELP command */
call help;
/* 8 = LOGOUT command */
call logout;
/* 9 = RECEIVE command */
call recv;
/* 10 = SEND command */
call send;
/* 11 = SET command */
call set;
/* 12 = SHOW command */
call show;
/* 13 = TAKE command */
call take;
end;
end docmd;
/* *** main program *** */
/* Fetch the command line arguments */
call readln;
/* Read desired baud rate, if supplied */
temp = token;
if temp > 0 then baudrate = nin(temp);
/* Get desired port, if supplied */
temp = token;
if temp > 0 then port = nin(temp);
/* Check for garbage on the end of the line */
if token > 0 then call usage;
if (port < 1) or (port > 2) then call usage;
if (procbaud(baudrate) = false) then call usage; /* bad baudrate */
call ioinit;
/* Initialize a "TAKE" condition from "KERMIT.INI" if it exists */
call takeini;
if not taking then
do; /* The "INI" file may change the port and/or baud rate */
call print(.('Serial port $'));
call nout(port);
call print(.(', Baud rate $'));
call nout(baudrate);
call newline;
end;
do while (continue);
call getcmd; /* Get the next command line */
call docmd; /* Execute the command */
end;
call exit;
end kermit;