home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / intelmdsb / mdsmit.p80 < prev    next >
Text File  |  2020-01-01  |  17KB  |  645 lines

  1. $TITLE ('KERMIT - MAIN MODULE')
  2. kermit:
  3.  
  4. /* COPYRIGHT (C) 1985, Trustees of Columbia University in the City of New */
  5. /* York.  Permission is granted to any individual or institution to use,  */
  6. /* copy, or redistribute this software so long as it is not sold for      */
  7. /* profit, provided this copyright notice is retained. /*
  8.  
  9. /* Contains the following public routines: */
  10. /*    cmdtail, exhelp, ioinit, newline, nin, nout, print, procbaud, spin, */
  11. /*        strcmp, synerr, token, upcase, and varcmp */
  12.  
  13. /* NOTE: See the comment below regarding the default "escape" character */
  14.  
  15. do;
  16.  
  17. declare true literally '0FFH';
  18. declare false literally '00H';
  19.  
  20. /* UART control bits */
  21. declare port1cmd literally '0F5H';
  22. declare port1dat literally '0F4H';
  23. declare port1clk literally '0F0H';
  24. declare timing1 literally '036H';
  25. declare port2cmd literally '0F7H';
  26. declare port2dat literally '0F6H';
  27. declare port2clk literally '0F1H';
  28. declare timing2 literally '076H';
  29. declare modesel literally '0F3H';
  30. declare reset literally '040H';
  31. declare EnaTxRx literally '025H';
  32. declare tx$rdy literally '01H';
  33. declare rx$rdy literally '02H';
  34.  
  35. declare null literally '000H';
  36. declare lf literally '0AH';
  37. declare cr literally '0DH';
  38. declare crlf literally 'cr,lf,null';
  39. declare space literally '20H';
  40. declare dollar literally '24H';
  41. declare bel literally '07H';
  42.  
  43. declare buflen literally '122';
  44. declare buffer(buflen) byte;
  45. declare (cmdstr, temp, cmdptr) address;
  46. declare taking byte public initial(false); /* within "TAKE" file */
  47. declare continue byte initial(true);
  48.  
  49. /* ****** Default mode settings ****** */
  50. /* Note that the default setting for the Kermit "escape" character */
  51. /*   differs from common Kermit usage.  This is due to the fact that */
  52. /*   some Intel workstations (e.g. Series III) cannot generate a */
  53. /*   "control-right bracket" character.  If you are using only Series */
  54. /*   IV workstations, you can change the initial value below to suit, */
  55. /*   for example, to 29 for control-right bracket.  Alternately, you */
  56. /*   can use the "SET ESCAPE" command (manually or in an .INI file) */
  57. /*   to alter the escape character each time you invoke Kermit. */
  58. declare escchar byte public initial(29); /* control-right bracket */
  59. declare baudrate address public initial(2400); /* port baud rate */
  60. declare parity byte public initial(0); /* parity */
  61. /*   (0 = None, 1 = Mark, 2 = Space, 3 = Even, 4 = Odd) */
  62. declare stopbits byte public initial(2); /* number of stop bits */
  63. /*   (0 = 1 stop bit, 1 = 1 1/2 stop bits, 2 = 2 stop bits) */
  64. declare port byte public initial(2); /* communications port */
  65. declare maxtry byte public initial(5); /* number of retries */
  66. declare debug byte public initial(false);
  67. declare halfduplex byte public initial(false);
  68. declare warning$flag byte public initial(false); /* dup-named file switch */
  69. declare take$echo byte public initial(false); /* echo take commands switch */
  70. declare def$drive(5) byte public initial(0,0,0,0,0); /* default drive */
  71. declare prompt(20) byte public initial('ISIS-Kermit>',null); /* Kerm. prompt */
  72. declare def$prompt(20) byte public initial('ISIS-Kermit>',null); /* Default */
  73.  
  74. declare filename address public;
  75.  
  76. declare state byte public;
  77. declare msgnum byte public;
  78. declare tries byte public;
  79. declare oldtry byte public;
  80.  
  81. /* Masks for comm input and output bytes */
  82. declare input$and byte public;
  83. declare output$and byte public;
  84. declare output$or byte public;
  85.  
  86. declare cmd byte;
  87. declare speed byte;
  88.  
  89. /* Kermit parameter defaults */
  90. declare pksize literally '94';
  91. declare mytime literally '5';
  92. declare mynumpads literally '0';
  93. declare mypadchr literally '0';
  94. declare myeol literally 'cr';
  95. declare myquote literally '023H';
  96.  
  97. /* Current Kermit parameters */
  98. declare spsize byte public initial(pksize); /* present packet size */
  99. declare timeint byte public initial(mytime); /* present time out */
  100. declare numpads byte public initial(mynumpads); /* how many pads to send */
  101. declare padchar byte public initial(mypadchr); /* present pad character */
  102. declare eol byte public initial(myeol); /* present eol character */
  103. declare quote byte public initial(myquote); /* present quote character */
  104.  
  105. /* Subroutine declarations */
  106.  
  107. co:    procedure(char)external;
  108.     declare char byte;
  109. end co;
  110.  
  111. ci:    procedure byte external;
  112. end ci;
  113.  
  114. getc:    procedure (port) byte external;
  115.     declare port byte;
  116. end getc;
  117.  
  118. ready:    procedure (port) byte external;
  119.     declare port byte;
  120. end ready ;
  121.  
  122. read:    procedure(jfn, buf, max, count, status)external;
  123.     declare(jfn, buf, max, count, status)address;
  124. end read;
  125.  
  126. error:    procedure(errnum)external;
  127.     declare(errnum)address;
  128. end error;
  129.  
  130. bye:
  131.     procedure external;
  132. end bye;
  133.  
  134. connect:
  135.     procedure external;
  136. end connect;
  137.  
  138. cwd:
  139.     procedure external;
  140. end cwd;
  141.  
  142. exit:    procedure external; end exit;
  143.  
  144. finish:
  145.     procedure external;
  146. end finish;
  147.  
  148. get:    procedure external;
  149. end get;
  150.  
  151. help:    procedure external;
  152. end help;
  153.  
  154. logout:
  155.     procedure external;
  156. end logout;
  157.  
  158. recv:   procedure external;
  159. end recv;
  160.  
  161. send:   procedure external;
  162. end send;
  163.  
  164. set:    procedure external;
  165. end set;
  166.  
  167. show:
  168.     procedure external;
  169. end show;
  170.  
  171. take:
  172.     procedure external;
  173. end take;
  174.  
  175. takeline:    procedure (addr) external;
  176.     declare addr address;
  177. end takeline;
  178.  
  179. takeini:        procedure external;
  180. end takeini;
  181.  
  182. newline:
  183.     procedure public;
  184.     call co(cr);
  185.     call co(lf);
  186. end newline;
  187.  
  188. /* SPIN: Searches a string for a character greater than blank */
  189. spin:    procedure(string)address public;
  190.     declare string address;
  191.     declare char based string byte;
  192.  
  193.     do while (char <> null) and (char < 021H);
  194.       string = string + 1;
  195.     end;
  196.     return string;
  197. end spin;
  198.  
  199. strcmp:    procedure(s1,s2)byte public;
  200.     declare(s1,s2)address;
  201.     declare c1 based s1 byte;
  202.     declare c2 based s2 byte;
  203.     declare retval byte;
  204.  
  205.     retval = 0;
  206.     s1 = spin(s1);
  207.     s2 = spin(s2);
  208.     if not(c1 = c2) then retval = c1 - c2;
  209.     do while (c1 > 0) and (c2 > 0) and (retval=0);
  210.       retval = c1 - c2;
  211.       s1 = s1+1;
  212.       s2 = s2+1;
  213.     end;
  214.     return retval;
  215.  
  216. end strcmp;
  217.  
  218. /* varcmp: Compare two variable length strings */
  219. /*  This routine compares corresponding characters in two strings. */
  220. /*  If it finds a null in the first string, it returns the number */
  221. /*  of characters which matched, excluding the null.  If it finds */
  222. /*  a null in the second string or a mismatch, it returns a zero. */
  223.  
  224. varcmp:    procedure(s1,s2)byte public;
  225.     declare(s1,s2)address;
  226.     declare c1 based s1 byte;
  227.     declare c2 based s2 byte;
  228.     declare cnt byte;
  229.  
  230.     cnt = 0;
  231.     /* s1 = spin(s1); */
  232.     /* s2 = spin(s2); */
  233.     do while c1 > 0;
  234.       if c2 = 0 then return 0;
  235.       if c1 <> c2 then return 0;
  236.       s1 = s1+1;
  237.       s2 = s2+1;
  238.       cnt = cnt + 1;
  239.     end;
  240.     return cnt;
  241.  
  242. end varcmp;
  243.  
  244. /* TOKEN: returns a pointer to a null-terminated token pointed    */
  245. /* to prior to the call by cmdptr.  After the call, cmdptr points    */
  246. /* to the end of the original string, or the first character after    */
  247. /* the null character replacing the first whitespace after the first    */
  248. /* token.    */
  249.  
  250. token:     procedure address public;
  251.     declare result address;
  252.     declare char based cmdptr byte;
  253.  
  254.     result = 0;
  255.     cmdptr = spin(cmdptr);
  256.     if char <> null then 
  257.       do;
  258.         result = cmdptr;
  259.         do while char > ' ';
  260.           cmdptr = cmdptr + 1;
  261.         end;
  262.         if char <> null then
  263.           do;
  264.             char = null;
  265.             cmdptr = cmdptr + 1;
  266.           end;
  267.       end;
  268.     return result;
  269. end token;
  270.  
  271. /* CMDTAIL: returns a pointer to the first nonblank character of the */
  272. /* remainder of the command line, or zero if there were no more */
  273. /* nonblank characters in the command line. */
  274.  
  275. cmdtail:     procedure address public;
  276.     declare char based cmdptr byte;
  277.  
  278.     cmdptr = spin(cmdptr);
  279.     if char = null then return 0;
  280.     else return cmdptr;
  281. end cmdtail;
  282.  
  283. nout:    procedure(n) public;
  284.     declare n address;
  285.     declare (quotient, digit) address;
  286.     declare numbuf(8) byte;
  287.     declare index byte;
  288.  
  289.     if n = 0 then
  290.       do;
  291.         call co('0');
  292.         return;
  293.       end;
  294.     index = 1;
  295.     do while (n > 0);
  296.       digit = n mod 10;
  297.       numbuf(index) = digit + '0';
  298.       index = index + 1;
  299.       n = n / 10;
  300.     end;
  301.     do while ((index := index - 1) > 0);
  302.       call co(numbuf(index));
  303.     end;
  304. end nout;
  305.  
  306. nin:    procedure(string) address public;
  307.     declare string address;
  308.     declare result address;
  309.     declare c based string byte;
  310.  
  311.     result = 0;
  312.     if (string <> 0) then do;
  313.       string = spin(string);
  314.       do while (c >= '0') and (c <= '9');
  315.         result = result * 10 + (c - '0');
  316.         string = string + 1;
  317.       end;
  318.     end;
  319.     return result;
  320. end nin;
  321.  
  322. print:    procedure(msg) public;
  323.     declare msg address;
  324.     declare c based msg byte;
  325.  
  326.     do while (c > 0) and (c <> '$');
  327.       if c = '\' then
  328.         call newline;
  329.       else
  330.         call co(c);
  331.       msg = msg + 1;
  332.         end;
  333. end print;
  334.  
  335.  
  336. synerr:   procedure public;
  337.     call print(.('Syntax error\$'));
  338. end synerr;
  339.  
  340. /* IOINIT:  This routine takes a port number, 0,1 or 2, and a speed in the */
  341. /* range 0-8 and initializes the required port to work at the required     */
  342. /* speed.  The routine returns no parameters.                              */
  343.  
  344. ioinit:    procedure public;
  345.     declare baud structure (code0(9) byte, code1(9) byte, mult(9) byte)
  346.       /* Low-order byte of counter values */
  347.       data (0BAH, 80H, 40H, 20H, 10H, 20H, 10H, 08H, 04H,
  348.       /* High-order byte of counter values */
  349.       02H, 0H, 0H, 0H, 0H, 0H, 0H, 0H, 0H,
  350.       /* 8251A command byte baud rate multiplier control bits */
  351.       02H, 03H, 03H, 03H, 03H, 02H, 02H, 02H, 02H);
  352.     /* 8251A command byte parity and length control bits */
  353.     /*   (0=None, 1=Mark, 2=Space, 3=Even, 4=Odd) */
  354.     declare paritymask(5) byte data (0CH, 0CH, 0CH, 38H, 18H);
  355.  
  356.     /* 8251A command byte stop bits control bits */
  357.     /*   (0 = 1 stop bit, 1 = 1 1/2 stop bits, 2 = 2 stop bits) */
  358.     declare stopmask(3) byte data (40H, 80H, 0C0H);
  359.  
  360.     /* Mask bytes for comm. input and output bytes */
  361.     declare inp$mask$and(9) byte
  362.       data (0FFH, 7FH, 0FFH, 7FH, 7FH);
  363.     declare out$mask$and(9) byte
  364.       data (0FFH, 0FFH, 07FH, 0FFH, 0FFH);
  365.     declare out$mask$or(9) byte
  366.       data (0H, 80H, 0H, 0H, 0H);
  367.     declare (c, status) byte;
  368.  
  369.     if debug then call print(.('\initializing serial port\$'));
  370.     do case port;
  371.       do;
  372.         if debug then call print(.('port 0 initialized\$'));
  373.       end;
  374.       do;
  375.         if debug then call print(.('port 1 initialized\$'));
  376.         /* Put the USART into a known state by writing */
  377.         /*   three zero command bytes to it */
  378.         output(port1cmd) = 0H;
  379.         output(port1cmd) = 0H;
  380.         output(port1cmd) = 0H;
  381.         /* Reset the USART */
  382.         output(port1cmd) = reset;
  383.         output(modesel) = timing1;
  384.         output(port1clk) = baud.code0(speed);
  385.         output(port1clk) = baud.code1(speed);
  386.         output(port1cmd) = (stopmask(stopbits) or paritymask(parity)
  387.           or baud.mult(speed));
  388.         input$and = inp$mask$and(parity);
  389.         output$and = out$mask$and(parity);
  390.         output$or = out$mask$or(parity);
  391.         if debug then
  392.           do;
  393.             call print(.('Mode command: $'));
  394.             call nout(stopmask(stopbits) or paritymask(parity)
  395.               or baud.mult(speed));
  396.             call newline;
  397.           end;
  398.         output(port1cmd) = EnaTxRx;
  399.         if ready(1) > 0 then c = getc(1); /* discard any char */
  400.       end;
  401.       do;
  402.         if debug then call print(.('port 2 initialized\$'));
  403.         /* Put the USART into a known state by writing */
  404.         /*   three zero command bytes to it */
  405.         output(port2cmd) = 0H;
  406.         output(port2cmd) = 0H;
  407.         output(port2cmd) = 0H;
  408.         /* Reset the USART */
  409.         output(port2cmd) = reset;
  410.         output(modesel) = timing2;
  411.         output(port2clk) = baud.code0(speed);
  412.         output(port2clk) = baud.code1(speed);
  413.         output(port2cmd) = (stopmask(stopbits) or paritymask(parity)
  414.           or baud.mult(speed));
  415.         input$and = inp$mask$and(parity);
  416.         output$and = out$mask$and(parity);
  417.         output$or = out$mask$or(parity);
  418.         if debug then
  419.           do;
  420.             call print(.('Mode command: $'));
  421.             call nout(stopmask(stopbits) or paritymask(parity)
  422.               or baud.mult(speed));
  423.             call newline;
  424.           end;
  425.         output(port2cmd) = EnaTxRx;
  426.         if ready(2) > 0 then c = getc(2); /* discard any char */
  427.       end;
  428.     end;
  429. end ioinit;
  430.  
  431. usage:    procedure;
  432.     call print(.('usage: kermit (110|150|300|600|1200|2400|4800|9600$'));
  433.     call print(.('|19200) (1|2)\$'));
  434.     call exit;
  435. end usage;
  436.  
  437. procbaud:    procedure (newbaud) byte public;
  438.     declare rate(9) address
  439.         data(110, 150, 300, 600, 1200, 2400, 4800, 9600, 19200);
  440.     declare (result, i, done) byte;
  441.     declare newbaud address;
  442.  
  443.     result = false; /* tentative result of "bad rate" */
  444.     i = 0;
  445.     done = false;
  446.     do while (done = false);
  447.       if i > 8 then done = true; /* off end of table */
  448.       else
  449.         if newbaud < rate(i) then done = true; /* not found */
  450.         else
  451.           if newbaud = rate(i) then
  452.             do;
  453.               done = true;
  454.               result = true;
  455.             end;
  456.           else
  457.             i = i + 1; /* try next */
  458.     end;
  459.     if result = true then
  460.       do;
  461.         baudrate = newbaud;
  462.         speed = i;
  463.       end;
  464.     return result;
  465. end procbaud;
  466.  
  467. readln:    procedure;
  468.     declare (count, status) address;
  469.  
  470.     call read(1, .buffer, buflen, .count, .status);
  471.     if status > 0 then
  472.           do;
  473.         call print(.('READLN FAILED\$'));
  474.         call error(status);
  475.         call exit;
  476.       end;
  477.     buffer(count-2) = 0;
  478.     cmdptr = .buffer;
  479. end readln;
  480.  
  481. /* Convert the contents of a string from lower case to upper case */
  482. upcase: procedure(addr) public;
  483.     declare addr address;
  484.     declare chr based addr byte;
  485.     declare capdiff byte;
  486.     capdiff = 'a' - 'A';
  487.     do while chr <> 0;
  488.       if (chr >= 'a') and (chr <= 'z') then chr = chr - capdiff;
  489.       addr = addr + 1;
  490.     end;
  491. end upcase;
  492.  
  493. /* Display help for the EXIT command */
  494. exhelp:    procedure public;
  495.     call print(.('\EXIT\\$'));
  496.     call print(.('  The EXIT command causes KERMIT to terminate and $'));
  497.     call print(.('return to ISIS.\\$'));
  498.     call print(.('Syntax:\\$'));
  499.     call print(.('    EXIT\\$'));
  500. end exhelp;
  501.  
  502. /* Get the next command to be executed */
  503. getcmd: procedure;
  504.     cmdstr = 0;
  505.     do while (cmdstr = 0);
  506.       if taking then
  507.         do; /* Get the command from the "TAKE" file */
  508.           call takeline(.buffer);
  509.           cmdptr = .buffer;
  510.           if takeecho and taking then
  511.             do; /* (Takeline will have turned "taking" off at EOF) */
  512.               call print(.('TAKE command>$'));
  513.               call print(cmdptr);
  514.               call newline;
  515.             end;
  516.         end;
  517.       else
  518.         do; /* Get the command from the console */
  519.           call print(.prompt); /* Display the prompt */
  520.           call readln;
  521.         end;
  522.       cmdstr = token; /* Get the command "word" */
  523.       call upcase(cmdstr); /* Convert to upper case */
  524.     end;
  525. end getcmd;
  526.  
  527. /* Execute a Kermit command */
  528. docmd: procedure;
  529.     if (varcmp(cmdstr,.('BYE',null)) >= 1) then cmd = 1;
  530.     else
  531.     if (varcmp(cmdstr,.('CONNECT',null)) >= 2) then cmd = 2;
  532.     else
  533.     if (varcmp(cmdstr,.('CWD',null)) >= 2) then cmd = 3;
  534.     else
  535.     if (varcmp(cmdstr,.('EXIT',null)) >= 1) then cmd = 4;
  536.     else
  537.     if (varcmp(cmdstr,.('FINISH',null)) >= 1) then cmd = 5;
  538.     else
  539.     if (varcmp(cmdstr,.('GET',null)) >= 1) then cmd = 6;
  540.     else
  541.     if (varcmp(cmdstr,.('HELP',null)) >= 1) then cmd = 7;
  542.     else
  543.     if (varcmp(cmdstr,.('LOGOUT',null)) >= 1) then cmd = 8;
  544.     else
  545.     if (varcmp(cmdstr,.('RECEIVE',null)) >= 1) then cmd = 9;
  546.     else
  547.     if (varcmp(cmdstr,.('SEND',null)) >= 3) then cmd = 10;
  548.     else
  549.     if (varcmp(cmdstr,.('SET',null)) >= 3) then cmd = 11;
  550.     else
  551.     if (varcmp(cmdstr,.('SHOW',null)) >= 2) then cmd = 12;
  552.     else
  553.     if (varcmp(cmdstr,.('TAKE',null)) >= 1) then cmd = 13;
  554.     else
  555.       do;
  556.         call print(.('Invalid or ambiguous command name\$'));
  557.         cmd = 0;
  558.       end;
  559.  
  560.     if (cmd = 1 or cmd = 2 or cmd = 4 or cmd = 5 or cmd = 8 or cmd = 12) then
  561.       if token > 0 then /* Only some commands can have operands */
  562.         do;
  563.           call print(.('Extraneous operand(s) specified\$'));
  564.           cmd = 0;
  565.         end;
  566.  
  567.     do case cmd;
  568.       /* 0 = Command error previously diagnosed */
  569.       do;
  570.         /* Null action */
  571.       end;
  572.       /* 1 = BYE command */
  573.       do;
  574.         call bye;
  575.         continue = false;
  576.       end;
  577.       /* 2 = CONNECT command */
  578.       call connect;
  579.       /* 3 = CWD command */
  580.       call cwd;
  581.       /* 4 = EXIT command */
  582.       continue = false;
  583.       /* 5 = FINISH command */
  584.       call finish;
  585.       /* 6 = GET command */
  586.       call get;
  587.       /* 7 = HELP command */
  588.       call help;
  589.       /* 8 = LOGOUT command */
  590.       call logout;
  591.       /* 9 = RECEIVE command */
  592.       call recv;
  593.       /* 10 = SEND command */
  594.       call send;
  595.       /* 11 = SET command */
  596.       call set;
  597.       /* 12 = SHOW command */
  598.       call show;
  599.       /* 13 = TAKE command */
  600.       call take;
  601.     end;
  602. end docmd;
  603.  
  604. /* *** main program *** */
  605.  
  606. /* Fetch the command line arguments */
  607. call readln;
  608.  
  609. /* Read desired baud rate, if supplied */
  610. temp = token;
  611. if temp > 0 then baudrate = nin(temp);
  612.  
  613. /* Get desired port, if supplied */
  614. temp = token;
  615. if temp > 0 then port = nin(temp);
  616.  
  617. /* Check for garbage on the end of the line */
  618. if token > 0 then call usage;
  619.  
  620. if (port < 1) or (port > 2) then call usage;
  621.  
  622. if (procbaud(baudrate) = false) then call usage; /* bad baudrate */
  623.  
  624. call ioinit;
  625.  
  626. /* Initialize a "TAKE" condition from "KERMIT.INI" if it exists */
  627. call takeini;
  628.  
  629. if not taking then
  630.   do; /* The "INI" file may change the port and/or baud rate */
  631.     call print(.('Serial port $'));
  632.     call nout(port);
  633.     call print(.(', Baud rate $'));
  634.     call nout(baudrate);
  635.     call newline;
  636.   end;
  637.  
  638. do while (continue);
  639.     call getcmd; /* Get the next command line */
  640.     call docmd; /* Execute the command */
  641. end;
  642. call exit;
  643.  
  644. end kermit;
  645.