home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / ncr9800 / ckvcmd.c < prev    next >
C/C++ Source or Header  |  1990-07-12  |  44KB  |  1,378 lines

  1. char     *cmdv = "VRX/E cmd package V2(023), 06 June 90";
  2.  
  3. /*  C K V C M D  --  Interactive command package for NCR-VRX  */
  4.  
  5. /**********************************************************************
  6. *                                                                       *
  7. * IVS / MCS-Kermit REL 2                                              *
  8. * source code                                                         *
  9. *                                                                     *
  10. * Change History:                                                     *
  11. *                                                                     *
  12. *                1. Modify C-Kermit(4E) source code to                *
  13. *                   produce new module for MCS/IVS-Kermit             *
  14. *                   ORIGINAL RELEASE                                  *
  15. *                   June 22, 1990                                     *
  16. *                                                                     *
  17. *                                                                     *
  18. ***********************************************************************/
  19.  
  20.  
  21. /*
  22.  V2 adds support for Data General and Apollo Aegis.
  23. */
  24. /*
  25.  Modelled after the DECSYSTEM-20 command parser (the COMND JSYS)
  26.  
  27.  Features:
  28.  . parses and verifies keywords, text strings, numbers, and other data
  29.  . displays appropriate menu or help message when user types "?"
  30.  . does keyword and filename completion when user types ESC
  31.  . accepts any unique abbreviation for a keyword
  32.  . allows keywords to have attributes, like "invisible"
  33.  . can supply defaults for fields omitted by user
  34.  . provides command line editing (character, word, and line deletion)
  35.  . accepts input from keyboard, command files, or redirected stdin
  36.  . allows for full or half duplex operation, character or line input
  37.  . settable prompt, protected from deletion
  38.  
  39.  Functions:
  40.   cmsetp - Set prompt (cmprom is prompt string, cmerrp is error msg prefix)
  41.   cmsavp - Save current prompt
  42.   prompt - Issue prompt
  43.   cmini  - Clear the command buffer (before parsing a new command)
  44.   cmres  - Reset command buffer pointers (before reparsing)
  45.   cmkey  - Parse a keyword
  46.   cmnum  - Parse a number
  47.   cmifi  - Parse an input file name
  48.   cmofi  - Parse an output file name
  49.   cmfld  - Parse an arbitrary field
  50.   cmtxt  - Parse a text string
  51.   cmcfm  - Parse command confirmation (end of line)
  52.   stripq - Strip out backslash quotes from a string.
  53.  
  54.  Return codes:
  55.   -3: no input provided when required
  56.   -2: input was invalid
  57.   -1: reparse required (user deleted into a preceding field)
  58.    0 or greater: success
  59.   See individual functions for greater detail.
  60.  
  61.  Before using these routines, the caller should #include ckucmd.h, and
  62.  set the program's prompt by calling cmsetp().  If the file parsing
  63.  functions cmifi and cmofi are to be used, this module must be linked
  64.  with a ck?fio file system support module for the appropriate system,
  65.  e.g. ckufio for NCR-VRX.  If the caller puts the terminal in
  66.  character wakeup ("cbreak") mode with no echo, then these functions will
  67.  provide line editing -- character, word, and line deletion, as well as
  68.  keyword and filename completion upon ESC and help strings, keyword, or
  69.  file menus upon '?'.  If the caller puts the terminal into character
  70.  wakeup/noecho mode, care should be taken to restore it before exit from
  71.  or interruption of the program.  If the character wakeup mode is not
  72.  set, the system's own line editor may be used.
  73.  
  74.  Author: Frank da Cruz (SY.FDC@CU20B),
  75.  Columbia University Center for Computing Activities, January 1985.
  76.  Copyright (C) 1985, Trustees of Columbia University in the City of New York.
  77.  Permission is granted to any individual or institution to use, copy, or
  78.  redistribute this software so long as it is not sold for profit, provided this
  79.  copyright notice is retained.
  80. */
  81.  
  82. /* Includes */
  83.  
  84. #include <stdio.h>                      /* Standard C I/O package */
  85. #include <ctype.h>                      /* Character types */
  86. #include "ckucmd.h"                     /* Command parsing definitions */
  87. #include "ckcdeb.h"                     /* Formats for debug() */
  88. #ifdef MCS_FLAG
  89. #include "mcs.h"
  90. #endif
  91.  
  92. /* external variables */
  93.  
  94. extern int     deblog;
  95. extern void    errhdlr();               /* replaces perror */
  96. extern int     debug();
  97.  
  98. extern int ncmd;
  99. extern struct keytab cmdtab[];
  100.  
  101.  
  102. /* Local variables */
  103.  
  104. int   psetf = 0,                  /* Flag that prompt has been set */
  105.       cc = 0,                     /* Character count */
  106.       dpx = 0;                    /* Duplex (0 = full) */
  107.  
  108. int   hw = HLPLW,                 /* Help line width */
  109.       hc = HLPCW,                 /* Help line column width */
  110.       hh,                         /* Current help column number */
  111.       hx;                         /* Current help line position */
  112.  
  113. #define PROML 60                      /* Maximum length for prompt */
  114.  
  115. char     cmprom[PROML+1];             /* Program's prompt */
  116. char     *dfprom = "Command? ";       /* Default prompt */
  117.  
  118. char     cmerrp[PROML+1];             /* Program's error message prefix */
  119.  
  120. int      cmflgs;                      /* Command flags */
  121.  
  122. char     cmdbuf[CMDBL+4];             /* Command buffer */
  123. char     hlpbuf[HLPBL+4];             /* Help string buffer */
  124. char     atmbuf[ATMBL+4];             /* Atom buffer */
  125. char     filbuf[ATMBL+4];             /* File name buffer */
  126.  
  127. /* Command buffer pointers */
  128.  
  129. static char     *bp,                /* Current command buffer position */
  130. *pp,                                /* Start of current field */
  131. *np;                                /* Start of next field */
  132.  
  133. long     zchki();                           /* From ck?fio.c. */
  134.  
  135.  
  136. /*  C M S E T P  --  Set the program prompt.  */
  137.  
  138. cmsetp(s)
  139. char     *s;
  140. {
  141.      char     *sx, *sy, *strncpy();
  142.      psetf = 1;                          /* Flag that prompt has been set. */
  143.      strncpy(cmprom, s, PROML - 1);      /* Copy the string. */
  144.      cmprom[PROML] = NUL;                /* Ensure null terminator. */
  145.      sx = cmprom;
  146.      sy = cmerrp;           /* Also use as error message prefix. */
  147.      while (*sy++ = *sx++)  ;            /* Copy */
  148.      sy -= 2;
  149.      if (*sy == '>')
  150.           *sy = NUL; /* Delete any final '>'. */
  151. }
  152.  
  153.  
  154. /*  C M S A V P  --  Save a copy of the current prompt.  */
  155.  
  156. cmsavp(s, n)
  157. int     n;
  158. char     s[];
  159. {
  160.      extern char     *strncpy();                         /* +1   */
  161.      strncpy(s, cmprom, n - 1);
  162.      s[n] = NUL;
  163. }
  164.  
  165.  
  166. /*  P R O M P T  --  Issue the program prompt.  */
  167.  
  168. prompt()
  169. {
  170.      if (psetf == 0)
  171.           cmsetp(dfprom);     /* If no prompt set, set default. */
  172. #ifndef MCS_FLAG
  173.      printf("\r%s", cmprom);              /* Print the prompt. */
  174. #else
  175.        sprintf(print_str,"\r%s", cmprom);
  176.        mcs_printf(print_str);             /* Print the prompt. */
  177. #endif
  178. }
  179.  
  180.  
  181. /*  C M R E S  --  Reset pointers to beginning of command buffer.  */
  182.  
  183. cmres()
  184. {
  185.      cc = 0;                             /* Reset character counter. */
  186.      pp = np = bp = cmdbuf;              /* Point to command buffer. */
  187.      cmflgs = -5;                        /* Parse not yet started. */
  188. }
  189.  
  190.  
  191. /*  C M I N I  --  Clear the command and atom buffers, reset pointers.  */
  192.  
  193. /*
  194. The argument specifies who is to echo the user's typein --
  195.   1 means the cmd package echoes
  196.   0 somebody else (system, front end, terminal) echoes
  197. */
  198. cmini(d)
  199. int     d;
  200. {
  201.      for (bp = cmdbuf; bp < cmdbuf + CMDBL; bp++)
  202.           *bp = NUL;
  203.      *atmbuf = NUL;
  204.      dpx = d;
  205.      cmres();
  206. }
  207.  
  208.  
  209. stripq(s)
  210. char     *s;
  211. {                    /* Function to strip '\' quotes */
  212.      char     *t;
  213.      while (*s) {
  214.           if (*s == '\\') {
  215.                for (t = s; *t != '\0'; t++)
  216.                     *t = *(t + 1);
  217.           }
  218.           s++;
  219.      }
  220. }
  221.  
  222.  
  223. /*  C M N U M  --  Parse a number in the indicated radix  */
  224.  
  225. /*  For now, only works for positive numbers in base 10.  */
  226.  
  227. /*
  228.  Returns
  229.    -3 if no input present when required,
  230.    -2 if user typed an illegal number,
  231.    -1 if reparse needed,
  232.     0 otherwise, with n set to number that was parsed
  233. */
  234. cmnum(xhlp, xdef, radix, n)
  235. char     *xhlp, *xdef;
  236. int     radix, *n;
  237. {
  238.      int     x;
  239.      char    *s;       /* will point to atmbuf or xdef */
  240.  
  241.      if (radix != 10) {                  /* Just do base 10 for now */
  242. #ifndef MCS_FLAG
  243.           printf("cmnum: illegal radix - %d\n", radix);
  244. #else
  245.           sprintf(print_str,"cmnum: illegal radix - %d\n", radix);
  246.           mcs_printf(print_str);
  247. #endif
  248.           return(-1);
  249.      }
  250.  
  251.      x = cmfld(xhlp, xdef, &s);
  252.  
  253.      if (deblog) debug(F101, "cmnum: cmfld", "", x);
  254.  
  255.      if (x < 0)
  256.           return(x);    /* Parse a field */
  257.  
  258.      if (digits(s)) {               /* Convert to number */
  259.           *n = atoi(s);
  260.           return(x);
  261.      } else {
  262. #ifndef MCS_FLAG
  263.       /* In IVS-Kermit, back spaces are handled by IVS, so there is
  264.        * no chance of encountering a back space character. */
  265.  
  266.           printf("\n?not a number - %s\n", s);
  267.           return(-2);
  268. #else
  269.       /* In MCS-Kermit, the kermit logic itself handles back space
  270.        * characters.  So, if the current field is not a number,
  271.        * then maybe the user entered back spaces later on in the
  272.        * command line.  In order to reparse the command, we will
  273.        * dummy up the return value and integer pointer.  The setnum
  274.        * routine will see the changes and put out an error message
  275.        * if no back spaces were entered.  If back spaces were
  276.        * entered, then the setnum routine will return a value that
  277.        * will cause the entire command to be reparsed. */
  278.  
  279.       /*  sprintf(print_str,"\n?not a number - %s\n", s);
  280.        *  mcs_printf(print_str); */
  281.  
  282.           *n = -562;     /* unusual number to signify error */
  283.           return(0);
  284. #endif
  285.      }
  286. }
  287.  
  288.  
  289. /*  C M O F I  --  Parse the name of an output file  */
  290.  
  291. /*
  292.  Depends on the external function zchko(); if zchko() not available, use
  293.  cmfld() to parse output file names.
  294.  
  295.  Returns
  296.    -3 if no input present when required,
  297.    -2 if permission would be denied to create the file,
  298.    -1 if reparse needed,
  299.     0 or 1 otherwise, with xp pointing to name.
  300. */
  301. cmofi(xhlp, xdef, xp)
  302. char     *xhlp, *xdef, **xp;
  303. {
  304.      int     x;
  305.      char     *s;
  306.  
  307.      if (*xhlp == NUL)
  308.           xhlp = "Output file";
  309.      *xp = "";
  310.  
  311.      if ((x = cmfld(xhlp, xdef, &s)) < 0)
  312.           return(x);
  313.  
  314.      if (chkwld(s)) {
  315. #ifndef MCS_FLAG
  316.           printf("\n?Wildcards not allowed - %s\n", s);
  317. #else
  318.           sprintf(print_str,"\n?Wildcards not allowed - %s\n", s);
  319.           mcs_printf(print_str);
  320. #endif
  321.           return(-2);
  322.      }
  323.      if (zchko(s) < 0) {
  324. #ifndef MCS_FLAG
  325.           printf("\n?Write permission denied - %s\n", s);
  326. #else
  327.           sprintf(print_str,"\n?Write permission denied - %s\n", s);
  328.           mcs_printf(print_str);
  329. #endif
  330.           return(-2);
  331.      } else {
  332.           *xp = s;
  333.           return(x);
  334.      }
  335. }
  336.  
  337.  
  338. /*  C M I F I  --  Parse the name of an existing file  */
  339.  
  340. /*
  341.  This function depends on the external functions:
  342.    zchki()  - Check if input file exists and is readable.
  343.    zxpand() - Expand a wild file specification into a list.
  344.    znext()  - Return next file name from list.
  345.  If these functions aren't available, then use cmfld() to parse filenames.
  346. */
  347. /*
  348.  Returns
  349.    -4 EOF
  350.    -3 if no input present when required,
  351.    -2 if file does not exist or is not readable,
  352.    -1 if reparse needed,
  353.     0 or 1 otherwise, with:
  354.         xp pointing to name,
  355.         wild = 1 if name contains '*' or '?', 0 otherwise.
  356. */
  357. cmifi(xhlp, xdef, xp, wild)
  358. char     *xhlp, *xdef, **xp;
  359. int     *wild;
  360. {
  361.      int     i, x, xc;
  362.      long     y;
  363.      char     *sp;
  364.  
  365.      cc = xc = 0;                        /* Initialize counts & pointers */
  366.      *xp = "";
  367.      if ((x = cmflgs) != 1) {            /* Already confirmed? */
  368.           x = gtword();                   /* No, get a word */
  369.      } else {
  370.           cc = setatm(xdef);              /* If so, use default, if any. */
  371.      }
  372.      *xp = atmbuf;                       /* Point to result. */
  373.      *wild = chkwld(*xp);
  374.  
  375.      while (1) {
  376.           xc += cc;                       /* Count the characters. */
  377.           if (deblog) debug(F111, "cmifi: gtword", atmbuf, xc);
  378.           switch (x) {
  379.           case -4:                    /* EOF */
  380.           case -2:                    /* Out of space. */
  381.           case -1:                    /* Reparse needed */
  382.                return(x);
  383.  
  384.           case 0:                     /* SP or NL */
  385.           case 1:
  386.                if (xc == 0)
  387.                     *xp = xdef;    /* If no input, return default. */
  388.                else
  389.                     *xp = atmbuf;
  390.                if (**xp == NUL)
  391.                     return(-3); /* If field empty, return -3. */
  392.  
  393.                /* If filespec is wild, see if there are any matches */
  394.  
  395.                *wild = chkwld(*xp);
  396.                if (deblog) debug(F101, " *wild", "", *wild);
  397.                if (*wild != 0) {
  398.                     y = zxpand(*xp);
  399.                     if (y == 0) {
  400. #ifndef MCS_FLAG
  401.                          printf("\n?No files match - %s\n", *xp);
  402. #else
  403.                          sprintf(print_str,"\n?No files match - %s\n", *xp);
  404.                          mcs_printf(print_str);
  405. #endif
  406.                          return(-2);
  407.                     } else if (y < 0) {
  408. #ifndef MCS_FLAG
  409.                          printf("\n?Too many files match - %s\n", *xp);
  410. #else
  411.                          sprintf(print_str,"\n?Too many files match - %s\n",
  412.                                  *xp);
  413.                          mcs_printf(print_str);
  414. #endif
  415.                          return(-2);
  416.                     } else
  417.                          return(x);
  418.                }
  419.  
  420.                /* If not wild, see if it exists and is readable. */
  421.  
  422.                y = zchki(*xp);
  423.                if (y == -3) {
  424. #ifndef MCS_FLAG
  425.                     printf("\n?Read permission denied - %s\n", *xp);
  426. #else
  427.                     sprintf(print_str,"\n?Read permission denied - %s\n", *xp);
  428.                     mcs_printf(print_str);
  429. #endif
  430.                     return(-2);
  431.                } else if (y == -2) {
  432. #ifndef MCS_FLAG
  433.                     printf("\n?File not readable - %s\n", *xp);
  434. #else
  435.                     sprintf(print_str,"\n?File not readable - %s\n", *xp);
  436.                     mcs_printf(print_str);
  437. #endif
  438.                     return(-2);
  439.                } else if (y < 0) {
  440. #ifndef MCS_FLAG
  441.                     printf("\n?File not found - %s\n", *xp);
  442. #else
  443.                     sprintf(print_str,"\n?File not found - %s\n", *xp);
  444.                     mcs_printf(print_str);
  445. #endif
  446.                     return(-2);
  447.                }
  448.                return(x);
  449.  
  450.     /*       case 2:                     * ESC *
  451.     *           if (xc == 0) {
  452.     *               if (*xdef != '\0') {
  453.     *                   printf("%s ",xdef); * If at beginning of field, *
  454.     *                   addbuf(xdef);   * supply default. *
  455.     *                   cc = setatm(xdef);
  456.     *               } else {            * No default *
  457.     *                   putchar(BEL);
  458.     *               }
  459.     *               break;
  460.     *           }
  461.     *           if (*wild = chkwld(*xp)) {  * No completion if wild *
  462.     *               putchar(BEL);
  463.     *               break;
  464.     *           }
  465.     *           sp = atmbuf + cc;
  466.     *           *sp++ = '*';
  467.     *           *sp-- = '\0';
  468.     *           y = zxpand(atmbuf);     * Add * and expand list. *
  469.     *           *sp = '\0';             * Remove *. *
  470.     *
  471.     *           if (y == 0) {
  472.     *               printf("\n?No files match - %s\n",atmbuf);
  473.     *               return(-2);
  474.     *           } else if (y < 0) {
  475.     *               printf("\n?Too many files match - %s\n",atmbuf);
  476.     *               return(-2);
  477.     *           } else if (y > 1) {     * Not unique, just beep. *
  478.     *              putchar(BEL);
  479.     *           } else {                * Unique, complete it.  *
  480.     *               znext(filbuf);      * Get whole name of file. *
  481.     *               sp = filbuf + cc;   * Point past what user typed. *
  482.     *               printf("%s ",sp);   * Complete the name. *
  483.     *               addbuf(sp);         * Add the characters to cmdbuf. *
  484.     *               setatm(pp);         * And to atmbuf. *
  485.     *               *xp = atmbuf;       * Return pointer to atmbuf. *
  486.     *               return(cmflgs = 0);
  487.     *           }
  488.     *           break;
  489.     */
  490.  
  491.           case 3:                     /* Question mark */
  492.                if (*xhlp == NUL)
  493. #ifndef MCS_FLAG
  494.                     printf(" Input file specification");
  495. #else
  496.                     mcs_printf(" Input file specification");
  497. #endif
  498.                else
  499. #ifndef MCS_FLAG
  500.                     printf(" %s", xhlp);
  501. #else
  502.                     sprintf(print_str," %s", xhlp);
  503.                     mcs_printf(print_str);
  504. #endif
  505.                if (xc > 0) {
  506.                     sp = atmbuf + cc;   /* Insert * at end */
  507.                     *sp++ = '*';
  508.                     *sp-- = '\0';
  509.                     y = zxpand(atmbuf);
  510.                     *sp = '\0';
  511.                     if (y == 0) {
  512. #ifndef MCS_FLAG
  513.                          printf("\n?No files match - %s\n", atmbuf);
  514. #else
  515.                          sprintf(print_str,"\n?No files match - %s\n", atmbuf);
  516.                          mcs_printf(print_str);
  517. #endif
  518.                          return(-2);
  519.                     } else if (y < 0) {
  520. #ifndef MCS_FLAG
  521.                          printf("\n?Too many file match - %s\n",
  522.                               atmbuf);
  523. #else
  524.                          sprintf(print_str,"\n?Too many file match - %s\n",
  525.                               atmbuf);
  526.                          mcs_printf(print_str);
  527. #endif
  528.                          return(-2);
  529.                     } else {
  530. #ifndef MCS_FLAG
  531.                          printf(", one of the following:\n");
  532. #else
  533.                          mcs_printf(", one of the following:\n");
  534. #endif
  535.                          clrhlp();
  536.                          for (i = 0; i < y; i++) {
  537.                               znext(filbuf);
  538.                               addhlp(filbuf);
  539.                          }
  540.                          dmphlp();
  541.                     }
  542.                } else
  543. #ifndef MCS_FLAG
  544.                     printf("\n");
  545. #else
  546.                     mcs_printf("\n");
  547. #endif
  548. #ifndef MCS_FLAG
  549.                printf("%s%s", cmprom, cmdbuf);
  550. #else
  551.                sprintf(print_str,"%s%s", cmprom, cmdbuf);
  552.                mcs_printf(print_str);
  553. #endif
  554.                break;
  555.           }
  556.           x = gtword();
  557.      }
  558. }
  559.  
  560.  
  561.  
  562. /*  C H K W L D  --  Check for wildcard characters '*' or '?'  */
  563.  
  564. chkwld(s)
  565. char     *s;
  566. {
  567.  
  568.      for ( ; *s != '\0'; s++) {
  569.           if ((*s == '*') || (*s == '?'))
  570.                return(1);
  571.      }
  572.      return(0);
  573. }
  574.  
  575.  
  576. /*  C M F L D  --  Parse an arbitrary field  */
  577. /*
  578.  Returns
  579.    -3 if no input present when required,
  580.    -2 if field too big for buffer,
  581.    -1 if reparse needed,
  582.     0 otherwise, xp pointing to string result.
  583. */
  584. cmfld(xhlp, xdef, xp)
  585. char     *xhlp, *xdef, **xp;
  586. {
  587.      int     x, xc;
  588.  
  589.      cc = xc = 0;                        /* Initialize counts & pointers */
  590.      *xp = "";
  591.      if ((x = cmflgs) != 1) {            /* Already confirmed? */
  592.           x = gtword();                   /* No, get a word */
  593.      } else {
  594.           cc = setatm(xdef);              /* If so, use default, if any. */
  595.      }
  596.      *xp = atmbuf;                       /* Point to result. */
  597.  
  598.      while (1) {
  599.           xc += cc;                       /* Count the characters. */
  600.           if (deblog) debug(F111, "cmfld: gtword", atmbuf, xc);
  601.           if (deblog) debug(F101, " x", "", x);
  602.           switch (x) {
  603.           case -4:                    /* EOF */
  604.           case -2:                    /* Out of space. */
  605.           case -1:                    /* Reparse needed */
  606.                return(x);
  607.           case 0:                     /* SP or NL */
  608.           case 1:
  609.                if (xc == 0)
  610.                     *xp = xdef;    /* If no input, return default. */
  611.                else
  612.                     *xp = atmbuf;
  613.                if (**xp == NUL)
  614.                     x = -3;    /* If field empty, return -3. */
  615.                return(x);
  616.  
  617.    /*      case 2:                     * ESC *
  618.     *            if (xc == 0) {
  619.     *                printf("%s ",xdef); * If at beginning of field, *
  620.     *                addbuf(xdef);       * supply default. *
  621.     *                cc = setatm(xdef);  * Return as if whole field *
  622.     *                return(0);          * typed, followed by space. *
  623.     *            } else {
  624.     *                putchar(BEL);       * Beep if already into field. *
  625.     *            }
  626.     *            break;
  627.     */
  628.  
  629.           case 3:                     /* Question mark */
  630.                if (*xhlp == NUL)
  631. #ifndef MCS_FLAG
  632.                     printf(" Please complete this field");
  633. #else
  634.                     mcs_printf(" Please complete this field");
  635. #endif
  636.                else
  637. #ifndef MCS_FLAG
  638.                     printf(" %s", xhlp);
  639. #else
  640.                     sprintf(print_str," %s", xhlp);
  641.                     mcs_printf(print_str);
  642. #endif
  643. #ifndef MCS_FLAG
  644.                printf("\n%s%s", cmprom, cmdbuf);
  645. #else
  646.                sprintf(print_str,"\n%s%s", cmprom, cmdbuf);
  647.                mcs_printf(print_str);
  648. #endif
  649.                break;
  650.           }
  651.           x = gtword();
  652.      }
  653. }
  654.  
  655.  
  656. /*  C M T X T  --  Get a text string, including confirmation  */
  657.  
  658. /*
  659.   Print help message 'xhlp' if ? typed, supply default 'xdef' if null
  660.   string typed.  Returns
  661.  
  662.    -1 if reparse needed or buffer overflows.
  663.     1 otherwise.
  664.  
  665.   with cmflgs set to return code, and xp pointing to result string.
  666. */
  667.  
  668. cmtxt(xhlp, xdef, xp)
  669. char     *xhlp;
  670. char     *xdef;
  671. char     **xp;
  672. {
  673.      int     x;
  674.      static int     xc;
  675.  
  676.      if (deblog) debug(F101, "cmtxt: cmflgs", "", cmflgs);
  677.      cc = 0;                             /* Start atmbuf counter off at 0 */
  678.      if (cmflgs == -1) {                 /* If reparsing, */
  679.           xc = strlen(*xp);               /* get back the total text length, */
  680.      } else {                            /* otherwise, */
  681.           *xp = "";                       /* start fresh. */
  682.           xc = 0;
  683.      }
  684.      *atmbuf = NUL;                      /* And empty atom buffer. */
  685.      if ((x = cmflgs) != 1) {
  686.           x = gtword();                   /* Get first word. */
  687.           *xp = pp;                       /* Save pointer to it. */
  688.      }
  689.      while (1) {
  690.           xc += cc;                       /* Char count for all words. */
  691.           if (deblog) debug(F111, "cmtxt: gtword", atmbuf, xc);
  692.           if (deblog) debug(F101, " x", "", x);
  693.           switch (x) {
  694.           case -4:                    /* EOF */
  695.           case -2:                    /* Overflow */
  696.           case -1:                    /* Deletion */
  697.                return(x);
  698.           case 0:                     /* Space */
  699.                xc++;                   /* Just count it */
  700.                break;
  701.           case 1:                     /* CR or LF */
  702.                if (xc == 0)
  703.                     *xp = xdef;
  704.                return(x);
  705.  
  706.    /*     case 2:                     * ESC *
  707.     *           if (xc == 0) {
  708.     *               printf("%s ",xdef);
  709.     *               cc = addbuf(xdef);
  710.     *           } else {
  711.     *               putchar(BEL);
  712.     *           }
  713.     *           break;
  714.     */
  715.  
  716.           case 3:                     /* Question Mark */
  717.                if (*xhlp == NUL)
  718. #ifndef MCS_FLAG
  719.                     printf(" Text string");
  720. #else
  721.                     mcs_printf(" Text string");
  722. #endif
  723.                else
  724. #ifndef MCS_FLAG
  725.                     printf(" %s", xhlp);
  726. #else
  727.                     sprintf(print_str," %s", xhlp);
  728.                     mcs_printf(print_str);
  729. #endif
  730. #ifndef MCS_FLAG
  731.                  printf("\n%s%s", cmprom, cmdbuf);
  732. #else
  733.                  sprintf(print_str,"\n%s%s", cmprom, cmdbuf);
  734.                  mcs_printf(print_str);
  735. #endif
  736.                break;
  737.           default:
  738. #ifndef MCS_FLAG
  739.                printf("\n?Unexpected return code from gtword() - %d\n",
  740.                     x);
  741. #else
  742.                sprintf(print_str,
  743.                    "\n?Unexpected return code from gtword() - %d\n",x);
  744.                mcs_printf(print_str);
  745. #endif
  746.                return(-2);
  747.           }
  748.           x = gtword();
  749.      }
  750. }
  751.  
  752.  
  753. /*  C M K E Y  --  Parse a keyword  */
  754.  
  755. /*
  756.  Call with:
  757.    table    --  keyword table, in 'struct keytab' format;
  758.    n        --  number of entries in table;
  759.    xhlp     --  pointer to help string;
  760.    xdef     --  pointer to default keyword;
  761.  
  762.  Returns:
  763.    -3       --  no input supplied and no default available
  764.    -2       --  input doesn't uniquely match a keyword in the table
  765.    -1       --  user deleted too much, command reparse required
  766.     n >= 0  --  value associated with keyword
  767. */
  768.  
  769. cmkey(table, n, xhlp, xdef)
  770. struct keytab table[];
  771. int     n;
  772. char     *xhlp, *xdef;
  773. {
  774.      int     i, y, z, zz, xc;
  775.      char    *xp;
  776.  
  777.      xc = cc = 0;                        /* Clear character counters. */
  778.  
  779.      if ((zz = cmflgs) == 1)             /* Command already entered? */
  780.           setatm(xdef);
  781.      else
  782.           zz = gtword();
  783.  
  784.      if (deblog) {
  785.           debug(F101, "cmkey: table length", "", n);
  786.           debug(F101, " cmflgs", "", cmflgs);
  787.           debug(F101, " zz", "", zz);
  788.      }
  789.      while (1) {
  790.           xc += cc;
  791.           if (deblog) debug(F111, "cmkey: gtword", atmbuf, xc);
  792.  
  793.           switch (zz) {
  794.           case -4:                        /* EOF */
  795.           case -2:                        /* Buffer overflow */
  796.           case -1:                        /* Or user did some deleting. */
  797.                return(zz);
  798.  
  799.           case 0:                         /* User terminated word with space */
  800.           case 1:                         /* or newline */
  801.                if (cc == 0) setatm(xdef);
  802.                y = lookup(table, atmbuf, n, &z);
  803.                switch (y) {
  804.                case -2:
  805. #ifndef MCS_FLAG
  806.                     printf("\n?Ambiguous - %s\n", atmbuf);
  807. #else
  808.                     sprintf(print_str,"\n?Ambiguous - %s\n", atmbuf);
  809.                     mcs_printf(print_str);
  810. #endif
  811.                     return(cmflgs = -2);
  812.                case -1:
  813.                     /* User entered an item not in the current table.
  814.                      * They might have entered a help command like,
  815.                      * 'SET ?' but have backspaced to enter a new
  816.                      * command.  In IVS-Kermit, we don't see the
  817.                      * space characters, so we need to handle the
  818.                      * situation here.  Check the command table.  If
  819.                      * a match is found, reset the command table and
  820.                      * reparse the whole command again.
  821.                      */
  822.                     y = lookup(cmdtab,atmbuf,ncmd,&z);
  823.                     if (y >= 0) {              /* must be new command */
  824.                       cmres();                 /* reset buffer pointers */
  825.                       strcpy(cmdbuf,atmbuf);   /* move new cmd into buf */
  826.                       strcat(cmdbuf," ");      /* space is word terminator */
  827.                       np = cmdbuf + strlen(cmdbuf); /* reset next field ptr */
  828.                       return(cmflgs = -1);     /* reparse the command */
  829.                     }
  830.  
  831.                     /* user entered invalid command */
  832. #ifndef MCS_FLAG
  833.                     printf("\n?Invalid - %s\n", atmbuf);
  834. #else
  835.                     sprintf(print_str,"\n?Invalid - %s\n", atmbuf);
  836.                     mcs_printf(print_str);
  837. #endif
  838.                     return(cmflgs = -2);
  839.                default:
  840.                     break;
  841.                }
  842.                return(y);
  843.  
  844.    /*     case 2:          * User terminated word with ESC *
  845.     *        if (cc == 0) {
  846.     *            if (*xdef != NUL) {     * Nothing in atmbuf *
  847.     *                printf("%s ",xdef); * Supply default if any *
  848.     *                addbuf(xdef);
  849.     *                cc = setatm(xdef);
  850.     *                if (deblog) debug(F111,"cmkey: default",atmbuf,cc);
  851.     *            } else {
  852.     *                putchar(BEL);       * No default, just beep *
  853.     *                break;
  854.     *            }
  855.     *        }
  856.     *        y = lookup(table,atmbuf,n,&z); * Something in atmbuf *
  857.     *        if (deblog) debug(F111,"cmkey: esc",atmbuf,y);
  858.     *        if (y == -2) {
  859.     *            putchar(BEL);
  860.     *            break;
  861.     *        }
  862.     *        if (y == -1) {
  863.     *            printf("\n?Invalid - %s\n",atmbuf);
  864.     *            return(cmflgs = -2);
  865.     *        }
  866.     *        xp = table[z].kwd + cc;
  867.     *        printf("%s ",xp);
  868.     *        addbuf(xp);
  869.     *        if (deblog) debug(F110,"cmkey: addbuf",cmdbuf,0);
  870.     *        return(y);
  871.     */
  872.  
  873.           case 3:                         /* User terminated word with "?" */
  874.                y = lookup(table, atmbuf, n, &z);
  875.                if (y > -1) {
  876. #ifndef MCS_FLAG
  877.                     printf(" %s\n%s%s", table[z].kwd, cmprom, cmdbuf);
  878. #else
  879.                     sprintf(print_str," %s\n%s%s", table[z].kwd,
  880.                             cmprom, cmdbuf);
  881.                     mcs_printf(print_str);
  882. #endif
  883.                     break;
  884.                } else if (y == -1) {
  885. #ifndef MCS_FLAG
  886.                     printf("\n?Invalid\n");
  887. #else
  888.                     mcs_printf("\n?Invalid\n");
  889. #endif
  890.                     return(cmflgs = -2);
  891.                }
  892.  
  893.                if (*xhlp == NUL)
  894. #ifndef MCS_FLAG
  895.                     printf(" One of the following:\n");
  896. #else
  897.                     mcs_printf(" One of the following:\n");
  898. #endif
  899.                else
  900. #ifndef MCS_FLAG
  901.                     printf(" %s, one of the following:\n", xhlp);
  902. #else
  903.                     sprintf(print_str," %s, one of the following:\n", xhlp);
  904.                     mcs_printf(print_str);
  905. #endif
  906.  
  907.                clrhlp();
  908.                for (i = 0; i < n; i++) {
  909.                     if (!strncmp(table[i].kwd, atmbuf, cc)
  910.                         && !test(table[i].flgs, CM_INV))
  911.                          addhlp(table[i].kwd);
  912.                }
  913.                dmphlp();
  914. #ifndef MCS_FLAG
  915.                printf("%s%s", "Again>", cmdbuf);
  916. #else
  917.                sprintf(print_str,"%s%s", "Again>",cmdbuf);
  918.                mcs_printf(print_str);
  919. #endif
  920.                break;
  921.  
  922.           default:
  923. #ifndef MCS_FLAG
  924.                printf("\n%d - Unexpected return code from gtword\n", zz);
  925. #else
  926.                sprintf(print_str,
  927.                   "\n%d - Unexpected return code from gtword\n", zz);
  928.                mcs_printf(print_str);
  929. #endif
  930.                return(cmflgs = -2);
  931.           }
  932.           zz = gtword();
  933.      }
  934. }
  935.  
  936.  
  937. /*  C M C F M  --  Parse command confirmation (end of line)  */
  938.  
  939. /*
  940.  Returns
  941.    -2: User typed anything but whitespace or newline
  942.    -1: Reparse needed
  943.     0: Confirmation was received
  944. */
  945.  
  946. cmcfm()
  947. {
  948.      int     x, xc;
  949.  
  950.      if (deblog) debug(F101, "cmcfm: cmflgs", "", cmflgs);
  951.  
  952.      xc = cc = 0;
  953.      if (cmflgs == 1)
  954.           return(0);
  955.  
  956.      while (1) {
  957.           x = gtword();
  958.           xc += cc;
  959.           if (deblog) debug(F111, "cmcfm: gtword", atmbuf, xc);
  960.           switch (x) {
  961.           case -4:                    /* EOF */
  962.           case -2:
  963.           case -1:
  964.                return(x);
  965.  
  966.           case 0:                     /* Space */
  967.                continue;
  968.           case 1:                     /* End of line */
  969.                if (xc > 0) {
  970. #ifndef MCS_FLAG
  971.                     printf("?Not confirmed - %s\n", atmbuf);
  972. #else
  973.                     sprintf(print_str,"?Not confirmed - %s\n", atmbuf);
  974.                     mcs_printf(print_str);
  975. #endif
  976.                     return(-2);
  977.                } else
  978.                     return(0);
  979.  
  980.   /*      case 2:
  981.    *            putchar(BEL);
  982.    *            continue;
  983.    */
  984.  
  985.           case 3:
  986.                if (xc > 0) {
  987. #ifndef MCS_FLAG
  988.                     printf("\n?Not confirmed - %s\n", atmbuf);
  989. #else
  990.                     sprintf(print_str,"\n?Not confirmed - %s\n", atmbuf);
  991.                     mcs_printf(print_str);
  992. #endif
  993.                     return(-2);
  994.                }
  995. #ifndef MCS_FLAG
  996.                printf("\n Type a carriage return to confirm the command\n");
  997.                printf("%s%s", cmprom, cmdbuf);
  998. #else
  999.                mcs_printf("\n Type a carriage return to confirm the command\n");
  1000.                sprintf(print_str,"%s%s", cmprom, cmdbuf);
  1001.                mcs_printf(print_str);
  1002. #endif
  1003.                continue;
  1004.           }
  1005.      }
  1006. }
  1007.  
  1008.  
  1009. /* Keyword help routines */
  1010.  
  1011.  
  1012. /*  C L R H L P -- Initialize/Clear the help line buffer  */
  1013.  
  1014. clrhlp()
  1015. {                              /* Clear the help buffer */
  1016.      hlpbuf[0] = NUL;
  1017.      hh = hx = 0;
  1018. }
  1019.  
  1020.  
  1021. /*  A D D H L P  --  Add a string to the help line buffer  */
  1022.  
  1023. addhlp(s)
  1024. char     *s;
  1025. {                    /* Add a word to the help buffer */
  1026.      int     j;
  1027.  
  1028.      hh++;                               /* Count this column */
  1029.  
  1030.      for (j = 0; (j < hc) && (*s != NUL); j++) { /* Fill the column */
  1031.           hlpbuf[hx++] = *s++;
  1032.      }
  1033.      if (*s != NUL)                      /* Still some chars left in string? */
  1034.           hlpbuf[hx-1] = '+';             /* Mark as too long for column. */
  1035.  
  1036.      if (hh < (hw / hc)) {               /* Pad col with spaces if necessary */
  1037.           for (; j < hc; j++) {
  1038.                hlpbuf[hx++] = SP;
  1039.           }
  1040.      } else {                            /* If last column, */
  1041.           hlpbuf[hx++] = NUL;             /* no spaces. */
  1042.           dmphlp();                       /* Print it. */
  1043.           return;
  1044.      }
  1045. }
  1046.  
  1047.  
  1048. /*  D M P H L P  --  Dump the help line buffer  */
  1049.  
  1050. dmphlp()
  1051. {                              /* Print the help buffer */
  1052.      hlpbuf[hx++] = NUL;
  1053. #ifndef MCS_FLAG
  1054.      printf(" %s\n", hlpbuf);
  1055. #else
  1056.      sprintf(print_str," %s\n", hlpbuf);
  1057.      mcs_printf(print_str);
  1058. #endif
  1059.      clrhlp();
  1060. }
  1061.  
  1062.  
  1063. /*  L O O K U P  --  Lookup the string in the given array of strings  */
  1064.  
  1065. /*
  1066.  Call this way:  v = lookup(table,word,n,&x);
  1067.  
  1068.    table - a 'struct keytab' table.
  1069.    word  - the target string to look up in the table.
  1070.    n     - the number of elements in the table.
  1071.    x     - address of an integer for returning the table array index.
  1072.  
  1073.  The keyword table must be arranged in ascending alphabetical order, and
  1074.  all letters must be lowercase.
  1075.  
  1076.  Returns the keyword's associated value ( zero or greater ) if found,
  1077.  with the variable x set to the array index, or:
  1078.  
  1079.   -3 if nothing to look up (target was null),
  1080.   -2 if ambiguous,
  1081.   -1 if not found.
  1082.  
  1083.  A match is successful if the target matches a keyword exactly, or if
  1084.  the target is a prefix of exactly one keyword.  It is ambiguous if the
  1085.  target matches two or more keywords from the table.
  1086. */
  1087.  
  1088. lookup(table, cmd, n, x)
  1089. char     *cmd;
  1090. struct keytab table[];
  1091. int     n, *x;
  1092. {
  1093.  
  1094.      int     i, v, cmdlen;
  1095.  
  1096.      /* Lowercase & get length of target, if it's null return code -3. */
  1097.  
  1098.      if ((((cmdlen = lower(cmd))) == 0) || (n < 1))
  1099.           return(-3);
  1100.  
  1101.      /* Not null, look it up */
  1102.  
  1103.      for (i = 0; i < n - 1; i++) {
  1104.           if (!strcmp(table[i].kwd, cmd) ||  ((v = !strncmp(table[i].kwd,
  1105.                cmd, cmdlen)) &&  strncmp(table[i+1].kwd, cmd, cmdlen))) {
  1106.                *x = i;
  1107.                return(table[i].val);
  1108.           }
  1109.           if (v) return(-2);
  1110.      }
  1111.  
  1112.      /* Last (or only) element */
  1113.  
  1114.      if (!strncmp(table[n-1].kwd, cmd, cmdlen)) {
  1115.           *x = n - 1;
  1116.           return(table[n-1].val);
  1117.      } else
  1118.           return(-1);
  1119. }
  1120.  
  1121.  
  1122. /*  G E T W D  --  Gets a "word" from the command input stream  */
  1123.  
  1124. /*
  1125. Usage: retcode = gtword();
  1126.  
  1127. Returns:
  1128.  -4 if end of file (e.g. pipe broken)
  1129.  -2 if command buffer overflows
  1130.  -1 if user did some deleting
  1131.   0 if word terminates with SP or tab
  1132.   1 if ... CR
  1133.   3 if ... ?
  1134.  
  1135. With:
  1136.   pp pointing to beginning of word in buffer
  1137.   bp pointing to after current position
  1138.   atmbuf containing a copy of the word
  1139.   cc containing the number of characters in the word copied to atmbuf
  1140. */
  1141. gtword()
  1142. {
  1143.      int     c;                              /* Current char */
  1144.      static int     inword = 0;              /* Flag for start of word found */
  1145.      int     quote = 0;                      /* Flag for quote character */
  1146.      int     echof = 0;                      /* Flag for whether to echo */
  1147.      int     ignore = 0;
  1148.  
  1149.      pp = np;                                /* Start of current field */
  1150.      if (deblog) {
  1151.           debug(F101, "gtword: cmdbuf", "", (int) cmdbuf);
  1152.           debug(F101, " bp", "", (int) bp);
  1153.           debug(F101, " pp", "", (int) pp);
  1154.           debug(F110, " cmdbuf", cmdbuf, 0);
  1155.      }
  1156.  
  1157.      while (bp < cmdbuf + CMDBL) {         /* Loop */
  1158.  
  1159.           ignore = echof = 0;              /* Flag for whether to echo */
  1160.  
  1161.           if ((c = *bp) == NUL) {          /* Get next character */
  1162.                if (dpx) echof = 1;         /* from reparse buffer */
  1163.                c = getchar();              /* or from tty. */
  1164.                if (c == EOF) {
  1165.                     errhdlr("ckucmd: gtword getchar");
  1166.                     return(-4);
  1167.                }
  1168.                c &= 127;                   /* Strip any parity bit. */
  1169.           } else
  1170.                ignore = 1;
  1171.  
  1172.           if (quote == 0) {
  1173.                if (!ignore && (c == '\\')) { /* Quote character */
  1174.                     quote = 1;
  1175.                     continue;
  1176.                }
  1177.                if (c == FF) {               /* Formfeed. */
  1178.                     c = NL;                 /* Replace with newline */
  1179.                     SYSTEM("clear");        /* and clear the screen. */
  1180.                }
  1181.  
  1182.                if (c == HT)
  1183.                     c = ESC;                /* Substitute ESC for tab */
  1184.  
  1185.                if (c == SP) {               /* If space */
  1186.                     *bp++ = c;              /* deposit it in buffer. */
  1187.                     if (echof)
  1188.                          putchar(c);        /* echo it. */
  1189.                     if (inword == 0) {      /* If leading, gobble it. */
  1190.                          pp++;
  1191.                          continue;
  1192.                     } else {                /* If terminating, return. */
  1193.                          np = bp;
  1194.                          setatm(pp);
  1195.                          inword = 0;
  1196.                          return(cmflgs = 0);
  1197.                     }
  1198.                }
  1199.                if (c == NL || c == CR) {    /* CR, LF */
  1200.                     *bp = NUL;              /* End the string */
  1201.                     if (echof) {            /* If echoing, */
  1202.                          putchar(c);        /* echo the typein */
  1203.                          if (c == CR) putchar(NL);
  1204.                     }
  1205.                     np = bp;           /* Where to start next field. */
  1206.                     setatm(pp);        /* Copy this field to atom buffer. */
  1207.                     inword = 0;
  1208.                     return(cmflgs = 1);
  1209.                }
  1210.                if (!ignore && (c == '?')) { /* Question mark */
  1211.                     putchar(c);
  1212.                     *bp = NUL;
  1213.                     setatm(pp);
  1214.  
  1215.                    /* Question mark triggers help message. So, we want
  1216.                     to flush the rest of the input line including the
  1217.                     new line so that the command is not accidently
  1218.                     executed after the help message. */
  1219.  
  1220.                     while ((c = getchar()) != NL && c != CR) ;
  1221.  
  1222.                     return(cmflgs = 3);
  1223.               }
  1224.  
  1225.    /*         if (c == ESC) {             * ESC *
  1226.     *            *bp = NUL;
  1227.     *            setatm(pp);
  1228.     *            return(cmflgs = 2);
  1229.     *        }
  1230.     */
  1231.              if (c == BS || c == RUB) {  /* Character deletion */
  1232.                 if (bp > cmdbuf) {      /* If still in buffer... */
  1233. #ifndef MCS_FLAG
  1234.                     printf("\b \b");    /* erase character from screen, */
  1235. #else
  1236.                     mcs_printf("\b \b");
  1237. #endif
  1238.                     bp--;               /* point behind it, */
  1239.                     if (*bp == SP) inword = 0; /* Flag if current field gone */
  1240.                     *bp = NUL;          /* Erase character from buffer. */
  1241.                 } else {                /* Otherwise, */
  1242.                     putchar(BEL);       /* beep, */
  1243.                     cmres();            /* and start parsing a new command. */
  1244.                 }
  1245.                 if (pp < bp) continue;
  1246.                 else {
  1247.                   cmres();                      /* DRE 5-16-90  Test */
  1248.                   return(cmflgs = -1);
  1249.                 }
  1250.             }
  1251.  
  1252.    /*       if (c == LDEL) {            * ^U, line deletion *
  1253.     *            while ((bp--) > cmdbuf) {
  1254.     *                printf("\b \b");
  1255.     *                *bp = NUL;
  1256.     *            }
  1257.     *            cmres();                * Restart the command. *
  1258.     *            inword = 0;
  1259.     *            return(cmflgs = -1);
  1260.     *        }
  1261.     *
  1262.     *  if (c == WDEL) {            * ^W, word deletion *
  1263.     *            if (bp <= cmdbuf) {     * Beep if nothing to delete *
  1264.     *                putchar(BEL);
  1265.     *                cmres();
  1266.     *                return(cmflgs = -1);
  1267.     *            }
  1268.     *            bp--;
  1269.     *            for ( ; (bp >= cmdbuf) && (*bp == SP) ; bp--) {
  1270.     *                printf("\b \b");
  1271.     *                *bp = NUL;
  1272.     *            }
  1273.     *            for ( ; (bp >= cmdbuf) && (*bp != SP) ; bp--) {
  1274.     *                printf("\b \b");
  1275.     *                *bp = NUL;
  1276.     *            }
  1277.     *            bp++;
  1278.     *            inword = 0;
  1279.     *            return(cmflgs = -1);
  1280.     *        }
  1281.     *        if (c == RDIS) {            * ^R, redisplay *
  1282.     *            *bp = NUL;
  1283.     *            printf("\n%s%s",cmprom,cmdbuf);
  1284.     *            continue;
  1285.     *        }
  1286.     */
  1287.           }
  1288.           if (echof) putchar(c);          /* If tty input, echo */
  1289.           inword = 1;                     /* Flag we're in a word. */
  1290.           if (quote == 0 || c != NL)
  1291.                *bp++ = c;   /* And deposit it. */
  1292.           quote = 0;                      /* Turn off quote. */
  1293.      }                                   /* end of big while */
  1294.      putchar(BEL);                       /* Get here if... */
  1295. #ifndef MCS_FLAG
  1296.      printf("\n?Buffer full\n");
  1297. #else
  1298.      mcs_printf("\n?Buffer full\n");
  1299. #endif
  1300.      return(cmflgs = -2);
  1301. }
  1302.  
  1303.  
  1304. /* Utility functions */
  1305.  
  1306. /* A D D B U F  -- Add the string pointed to by cp to the command buffer  */
  1307.  
  1308. addbuf(cp)
  1309. char     *cp;
  1310. {
  1311.      int     len = 0;
  1312.      while ((*cp != NUL) && (bp < cmdbuf + CMDBL)) {
  1313.           *bp++ = *cp++;                  /* Copy and */
  1314.           len++;                          /* count the characters. */
  1315.      }
  1316.      *bp++ = SP;                         /* Put a space at the end */
  1317.      *bp = NUL;                          /* Terminate with a null */
  1318.      np = bp;                            /* Update the next-field pointer */
  1319.      return(len);                        /* Return the length */
  1320. }
  1321.  
  1322.  
  1323. /*  S E T A T M  --  Deposit a string in the atom buffer  */
  1324.  
  1325. setatm(cp)
  1326. char     *cp;
  1327. {
  1328.      char     *ap;
  1329.      cc = 0;
  1330.      ap = atmbuf;
  1331.      *ap = NUL;
  1332.      while (*cp == SP)  cp++;
  1333.      while ((*cp != SP) && (*cp != NL) && (*cp != NUL) && (*cp != CR)) {
  1334.           *ap++ = *cp++;
  1335.           cc++;
  1336.      }
  1337.      *ap++ = NUL;
  1338.      return(cc);                         /* Return length */
  1339. }
  1340.  
  1341.  
  1342. /*  D I G I T S  -- Verify that all the characters in line are digits  */
  1343.  
  1344. digits(s)
  1345. char     *s;
  1346. {
  1347.      while (*s) {
  1348.           if (!isdigit(*s))
  1349.                return(0);
  1350.           s++;
  1351.      }
  1352.      return(1);
  1353. }
  1354.  
  1355.  
  1356. /*  L O W E R  --  Lowercase a string  */
  1357.  
  1358. lower(s)
  1359. char     *s;
  1360. {
  1361.      int     n = 0;
  1362.      while (*s) {
  1363.           if (isupper(*s))
  1364.                *s = tolower(*s);
  1365.           s++, n++;
  1366.      }
  1367.      return(n);
  1368. }
  1369.  
  1370.  
  1371. /*  T E S T  --  Bit test  */
  1372.  
  1373. test(x, m)
  1374. int     x, m;
  1375. { /*  Returns 1 if any bits from m are on in x, else 0  */
  1376.      return((x & m) ? 1 : 0);
  1377. }
  1378.