home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / pub / sinclairqla / qlkcmd.c next >
C/C++ Source or Header  |  2020-01-01  |  19KB  |  655 lines

  1. /*
  2.     CMD_C - command interpreter for QL-Kermit
  3.  
  4.     Based on ckucmd.c, (C) Columbia University
  5. */
  6.  
  7.  
  8. /* Include files */
  9.  
  10. #include "flp1_ctype_h"                          /* Character types */
  11.  
  12. #include "ram1_ker_h"                            /* Kermit definitions */
  13. #include "ram1_cmd_h"                            /* Command parser definitions */
  14.  
  15.  
  16. /* External variables */
  17.  
  18. extern char cmdbuf[];                            /* Command buffer */
  19.  
  20.  
  21. /* Local variables */
  22.  
  23. #define PROML      60                            /* Maximum prompt length */
  24.  
  25. char cmprom[PROML+2];                            /* Prompt string */
  26.  
  27. int cc = 0;                                      /* Character count */
  28. int cmflgs;                                      /* Command flags */
  29.  
  30. char *dfprom = "Kermit> ";                       /* Default prompt */
  31.  
  32. char atmbuf[ATMBL+4];                            /* Atom buffer */
  33. char filbuf[ATMBL+4];                            /* File name buffer */
  34.  
  35. static bool psetf = FALSE;                       /* Prompt set flag */
  36.  
  37. static char *bp;                                 /* Command buffer position */
  38. static char *pp;                                 /* Start of current field */
  39. static char *np;                                 /* Start of next field */
  40.  
  41.  
  42.  
  43. /* CMSETP - Set the program prompt */
  44.  
  45. cmsetp(s)
  46. char *s;
  47. {
  48.     char *strncpy();
  49.  
  50.     psetf = TRUE;                                /* Flag that prompt is set */
  51.     strncpy(cmprom,s,PROML-1);                   /* Copy the string */
  52.     cmprom[PROML] = NUL;                         /* Ensure null terminator */
  53. }
  54.  
  55.  
  56. /* PROMPT - Issue the program prompt */
  57.  
  58. prompt()
  59. {
  60.     if (!psetf) cmsetp(dfprom);                  /* If not set, use default */
  61.     printf("%s",cmprom);                         /* Print the prompt */
  62. }
  63.  
  64.  
  65. /* CMRES - Reset pointers to beginning of command buffer */
  66.  
  67. cmres()
  68. {
  69.     cc = 0;                                      /* Reset character counter */
  70.     pp = np = bp = cmdbuf;                       /* Point to command buffer */
  71.     cmflgs = -5;                                 /* Parse not yet started */
  72. }
  73.  
  74.  
  75. /* CMINI - Clear the command and atom buffers, reset pointers */
  76.  
  77. cmini()
  78. {
  79.     for (bp = cmdbuf; bp<cmdbuf+CMDBL; bp++) *bp = NUL;
  80.     *atmbuf = NUL;
  81.     cmres();
  82. }
  83.  
  84.  
  85. /* CMNUM - Parse a numeric field
  86.  
  87.     Returns:
  88.        -3 if no input present when required,
  89.        -2 if user typed an illegal number,
  90.        -1 if reparse needed,
  91.         0 otherwise, with *n set to number that was parsed
  92. */
  93.  
  94. int cmnum(xdef,n,xhlp)
  95. char *xdef;
  96. int *n;
  97. char *xhlp;
  98. {
  99.     char *s;
  100.     int x;
  101.  
  102.     x = cmfld(xdef,&s,xhlp);
  103.     if (x<0) return(x);                          /* Parse the field */
  104.  
  105.     if (digits(atmbuf))                          /* Check for valid number */
  106.     {
  107.          *n = atoi(atmbuf);                      /* and convert field */
  108.          return(x);
  109.     }
  110.     else
  111.     {
  112.          error("Not a number - %s",s);
  113.          return(-2);
  114.     }
  115. }
  116.  
  117.  
  118. /* CMFLD - Parse an arbitrary field
  119.  
  120.     Returns:
  121.        -3 if no input present when required,
  122.        -2 if field too big for buffer,
  123.        -1 if reparse needed,
  124.        0 otherwise, xp pointing to string result
  125. */
  126.  
  127. int cmfld(xdef,xp,xhlp)
  128. char *xdef;
  129. char **xp;
  130. char *xhlp;
  131. {
  132.     int x,xc;
  133.  
  134.     cc = xc = 0;                                 /* Initialize counts & pointers */
  135.     *xp = "";
  136.     if ((x = cmflgs)!=1) x = getwd();            /* Get a word if required */
  137.     else cc = setatm(xdef);                      /* or use default, if any */
  138.     *xp = atmbuf;                                /* Point to result */
  139.  
  140.     forever
  141.     {
  142.          xc += cc;                               /* Count the characters */
  143.          switch (x)
  144.          {
  145. case -4:                                         /* EOF */
  146. case -2:                                         /* Out of space */
  147. case -1:      return(x);                         /* Reparse needed */
  148.  
  149. case 0:                                          /* SP or NL */
  150. case 1:       if (xc==0) *xp = xdef;             /* If no input, return default */
  151.               else *xp = atmbuf;
  152.               if (**xp==NUL) x = -3;             /* If field empty, return -3 */
  153.               return(x);
  154.  
  155. case 2:       if (xc==0)                         /* ESC */
  156.               {                                  /* If at beginning of field, */
  157.                    printf("%s ",xdef);
  158.                    addbuf(xdef);                 /* supply default */
  159.                    cc = setatm(xdef);            /* Return as if whole field */
  160.                    return(0);                    /* typed, followed by space */
  161.               }
  162.               endcase;
  163.  
  164. case 3:       if (xc==0)                         /* Question mark */
  165.               {                                  /* If at beginning of field, */
  166.                    help(xhlp,"Complete this field");
  167.                    endcase;                      /* Retype and continue */
  168.               }
  169.          }
  170.          x = getwd();
  171.     }
  172. }
  173.  
  174.  
  175. /* CMTXT - Get a text string, including confirmation
  176.  
  177.     Supply default 'xdef' if null string typed
  178.     Returns:
  179.        -1 if reparse needed or buffer overflows
  180.         1 otherwise, with cmflgs = return code,
  181.           **xp = result string.
  182. */
  183.  
  184. int cmtxt(xdef,xp,xhlp)
  185. char *xdef;
  186. char **xp;
  187. char *xhlp;
  188. {
  189.     int x;
  190.     static int xc;
  191.  
  192.     cc = 0;                                      /* Start atmbuf counter off */
  193.     if (cmflgs==-1)                              /* If reparsing, */
  194.     {
  195.          xc = strlen(*xp);                       /* get back total text length, */
  196.     }
  197.     else
  198.     {                                            /* otherwise */
  199.          *xp = "";                               /* start afresh */
  200.          xc = 0;
  201.     }
  202.     *atmbuf = NUL;                               /* Empty atom buffer */
  203.  
  204.     if ((x = cmflgs)!=1)
  205.     {
  206.          x = getwd();                            /* Get first word */
  207.          *xp = pp;                               /* Save pointer to it */
  208.     }
  209.  
  210.     forever
  211.     {
  212.          xc += cc;                               /* Char count for all words */
  213.          switch (x)
  214.          {
  215. case -4:                                         /* EOF */
  216. case -2:                                         /* Overflow */
  217. case -1:      return(x);                         /* Reparse needed */
  218.  
  219. case 0:       xc++;                              /* Space, just count it */
  220.               endcase;
  221.  
  222. case 1:       if (xc==0) *xp = xdef;             /* CR or LF */
  223.               return(x);
  224.  
  225. case 2:       if (xc==0)                         /* ESC */
  226.               {
  227.                    printf("%s ",xdef);           /* If at start, use default */
  228.                    cc = addbuf(xdef);
  229.               }
  230.               endcase;
  231.  
  232. case 3:       if (xc==0)                         /* Question mark */
  233.               {
  234.                    help(xhlp,"Text string");
  235.                    endcase;
  236.               }
  237.          }
  238.          x = getwd();
  239.     }
  240. }
  241.  
  242.  
  243. /* CMKEY - Parse a keyword
  244.  
  245.     Call with:
  246.        *table = keyword table, in 'struct keytab' format,
  247.        n = number of entries in table,
  248.        *xdef = default keyword;
  249.  
  250.     Returns:
  251.        -3 if no input supplied and no default available
  252.        -2 if input doesn't uniquely match a keyword in the table
  253.        -1 if user deleted too much, command reparse required
  254.        or value associated with keyword
  255. */
  256.  
  257. int cmkey(table,n,xdef,xhlp)
  258. struct keytab table[];
  259. int n;
  260. char *xdef,*xhlp;
  261. {
  262.     int y,z,zz,xc,i,j;
  263.     char *xp;
  264.  
  265.     xc = cc = 0;                                 /* Clear character counters */
  266.     if ((zz = cmflgs)==1) setatm(xdef);          /* Command already entered? */
  267.     else zz = getwd();
  268.  
  269.     forever
  270.     {
  271.          xc += cc;
  272.          switch(zz)
  273.          {
  274. case -4:                                         /* EOF */
  275. case -2:                                         /* Overflow */
  276. case -1:      return(zz);                        /* Reparse needed */
  277.  
  278. case 0:                                          /* Word terminated with space */
  279. case 1:       if (cc==0) setatm(xdef);           /* or newline */
  280.               y = lookup(table,atmbuf,n,&z);
  281.               switch (y)
  282.               {
  283. case -2:           if (zz==0) printf("\n");
  284.                    error("Ambiguous command or parameter - %s",atmbuf);
  285.                    return(cmflgs = -2);
  286.  
  287. case -1:           if (zz==0) printf("\n");
  288.                    error("Unknown command or parameter - %s",atmbuf);
  289.                    return(cmflgs = -2);
  290.  
  291. default:           endcase;
  292.               }
  293.               return(y);
  294.  
  295. case 2:       if (cc==0)                         /* Word terminated with ESC */
  296.               {
  297.                    if (*xdef!=NUL)               /* If at start, */
  298.                    {
  299.                         printf("%s ",xdef);      /* supply default if any */
  300.                         addbuf(xdef);
  301.                         cc = setatm(xdef);
  302.                    }
  303.                    else endcase;
  304.               }
  305.  
  306.               y = lookup(table,atmbuf,n,&z);     /* Something in atmbuf */
  307.               if (y==-2) endcase;                /* Ambiguous */
  308.               if (y==-1)                         /* Not found */
  309.               {
  310.                    error("Unknown command or parameter - %s",atmbuf);
  311.                    return(cmflgs = -2);
  312.               }
  313.  
  314.               xp = table[z].kwd+cc;
  315.               printf("%s ",xp);
  316.               addbuf(xp);
  317.               return(y);
  318.  
  319. case 3:       if (cc==0)                         /* Question mark */
  320.               {                                  /* If at start of field, */
  321.                    printf("?");
  322.                    if (xhlp==NULL) printf("\nHELP: One of the following -");
  323.                    else printf("\nHELP: %s, one of the following -",xhlp);
  324.                    for (i = 0, j = 0; i<n; i++)  /* dump table */
  325.                         if (!test(table[i].flgs,CM_INV))
  326.                              printf("%c %-17s",(((j++%2)==0) ? '\n' : ' '),table[i].kwd);
  327.                    printf("\n%s%s",cmprom,cmdbuf);
  328.                    endcase;
  329.               }
  330.          }
  331.          zz = getwd();
  332.     }
  333. }
  334.  
  335.  
  336. /* CMCFM - Parse command confirmation (end of line)
  337.  
  338.     Returns:
  339.        -2 if user typed anything but whitespace or newline
  340.        -1 if reparse needed
  341.         0 if confirmation was received
  342. */
  343.  
  344. int cmcfm()
  345. {
  346.     int x,xc;
  347.  
  348.     xc = cc = 0;
  349.     if (cmflgs==1) return(0);                    /* Unnecessary if already entered */
  350.  
  351.     forever
  352.     {
  353.          x = getwd();
  354.          xc += cc;
  355.          switch (x)
  356.          {
  357. case -4:                                         /* EOF */
  358. case -2:                                         /* Overflow */
  359. case -1:      return(x);                         /* Reparse needed */
  360.  
  361. case 0:       continue;                          /* SP */
  362.  
  363. case 1:       if (xc>0)                          /* End of line */
  364.               {
  365.                    error("Not confirmed - %s",atmbuf);
  366.                    return(-2);
  367.               }
  368.               else return(0);
  369.  
  370. case 2:       continue;                          /* ESC */
  371.  
  372. case 3:       if (xc>0)                          /* Question mark */
  373.               {
  374.                    error("Not confirmed - %s",atmbuf);
  375.                    return(-2);
  376.               }
  377.               help("Type ENTER to confirm",NULL);
  378.               continue;
  379.          }
  380.     }
  381. }
  382.  
  383.  
  384. /* LOOKUP - Lookup the string in the given array of strings
  385.  
  386.     Call with:
  387.        table = a 'struct keytab' table
  388.        word = the target string to look up in the table
  389.        n = the number of elements in the table
  390.        *x = an integer for returning the table array index
  391.  
  392.     The keyword table must be arranged in ascending alphabetical order,
  393.     and all letters must be lowercase.
  394.  
  395.     Returns the keyword's associated value (zero or greater) if found,
  396.     with the variable x set to the array index, or:
  397.        -3 if nothing to look up (target was null),
  398.        -2 if ambiguous,
  399.        -1 if not found.
  400.  
  401.     A match is successful if the target matches a keyword exactly, or if
  402.     the target is a prefix of exactly one keyword.    It is ambiguous if
  403.     the target matches two or more keywords from the table.
  404. */
  405.  
  406. int lookup(table,cmd,n,x)
  407. struct keytab table[];
  408. char *cmd;
  409. int n;
  410. int *x;
  411. {
  412.     int i,v,cmdlen;
  413.  
  414. /* Lowercase & get length of target, if it's null return code -3 */
  415.  
  416.     if ((((cmdlen = lower(cmd)))==0) || (n<1)) return(-3);
  417.  
  418. /* Not null, look it up */
  419.  
  420.     for (i = 0; i<n-1; i++)
  421.     {
  422.          if (!strcmp(table[i].kwd,cmd) ||
  423.             ((v = !strncmp(table[i].kwd,cmd,cmdlen)) &&
  424.             strncmp(table[i+1].kwd,cmd,cmdlen)))
  425.          {
  426.               *x = i;
  427.               return(table[i].val);
  428.          }
  429.          if (v) return(-2);
  430.     }
  431.  
  432. /* Last (or only) element */
  433.  
  434.     if (!strncmp(table[n-1].kwd,cmd,cmdlen))
  435.     {
  436.          *x = n-1;
  437.          return(table[n-1].val);
  438.     }
  439.     else return(-1);
  440. }
  441.  
  442.  
  443. /* GETWD - Gets a "word" from the command input stream
  444.  
  445.     Returns:
  446.        -4 if end of file (e.g. pipe broken)
  447.        -2 if command buffer overflows
  448.        -1 if user did some deleting
  449.         0 if word terminates with SP or TAB
  450.         1 if  ..      ..      ..  CR
  451.         2 if  ..      ..      ..  ESC
  452.         3 if  ..      ..      ..  ?
  453.  
  454.     With:
  455.        pp pointing to beginning of word in buffer
  456.        bp pointing to after current position
  457.        atmbuf containing a copy of the word
  458.        cc containing the number of characters in the word copied to atmbuf
  459. */
  460.  
  461. int getwd()
  462. {
  463.     unsigned char c;                             /* Current character */
  464.     bool echof = FALSE;                          /* Flag for screen echo */
  465.     static bool inword = FALSE;                  /* Flag for start of word */
  466.  
  467.     pp = np;                                     /* Start of current field */
  468.  
  469.     while (bp<cmdbuf+CMDBL)
  470.     {
  471.          echof = FALSE;
  472.          if ((c = *bp)==NUL)                     /* No more in buffer */
  473.          {                                       /* Get next input character */
  474.               echof = TRUE;                      /* Let's see this on screen */
  475.               c = getch();
  476.          }
  477.  
  478.          if (c==FF) c = LF;                      /* Replace formfeed with newline, */
  479.          if (c==CR) c = LF;                      /* carriage return with newline, */
  480.          if (c==HT) c = SP;                      /* and tab with space */
  481.  
  482.          if (c==SP)                              /* If space */
  483.          {
  484.               *bp++ = c;                         /* deposit it in buffer */
  485.               if (echof) putch(c);               /* echo it */
  486.               if (!inword)                       /* If leading, gobble it */
  487.               {
  488.                    pp++;
  489.                    continue;
  490.               }
  491.               else                               /* If terminating, return */
  492.               {
  493.                    np = bp;
  494.                    setatm(pp);
  495.                    inword = FALSE;
  496.                    return(cmflgs = 0);
  497.               }
  498.          }
  499.  
  500.          if (c==LF)                              /* End of line */
  501.          {
  502.               *bp = NUL;                         /* End the string */
  503.               if (echof) putch(c);               /* and echo the typein */
  504.               np = bp;                           /* Where to start next field */
  505.               setatm(pp);                        /* Copy this field to atom buffer */
  506.               inword = FALSE;
  507.               return(cmflgs = 1);
  508.          }
  509.  
  510.          if (c==F1)                              /* Help trigger */
  511.          {
  512.               *bp = NUL;
  513.               setatm(pp);
  514.               return(cmflgs = 3);
  515.          }
  516.  
  517.          if (c==ESC || c==F4)                    /* Complete the field */
  518.          {
  519.               *bp = NUL;
  520.               setatm(pp);
  521.               return(cmflgs = 2);
  522.          }
  523.  
  524.          if (c==DEL || c==F5 || c==DELC)         /* Character delete */
  525.          {
  526.               echof = FALSE;
  527.               if (bp>cmdbuf)                     /* If still in buffer, */
  528.               {
  529.                    delch();                      /* erase character from screen, */
  530.                    bp--;                         /* point behind it, */
  531.                    if (*bp==SP) inword = FALSE;  /* Flag if current field gone */
  532.                    *bp = NUL;                    /* Erase character from buffer */
  533.               }
  534.               else cmres();                      /* If all gone, start again */
  535.  
  536.               if (pp<=bp) continue;
  537.               else return(cmflgs = -1);
  538.          }
  539.  
  540.          if (c==LDEL || c==F3)                   /* Line delete */
  541.          {
  542.               while ((bp--)>cmdbuf)
  543.               {
  544.                    delch();                      /* Run back to beginning */
  545.                    *bp = NUL;
  546.               }
  547.               cmres();                           /* Restart the command */
  548.               inword = FALSE;
  549.               return(cmflgs = -1);
  550.          }
  551.  
  552.          if (c==RDIS)                            /* Redisplay */
  553.          {
  554.               *bp = NUL;
  555.               printf("\n%s%s",cmprom,cmdbuf);
  556.               continue;
  557.          }
  558.  
  559.          if (echof) putch(c);                    /* If tty input, echo */
  560.          inword = TRUE;                          /* Flag we're in a word */
  561.          if (c!=LF) *bp++ = c;                   /* and deposit it */
  562.     }
  563.  
  564. /* Get here if buffer full */
  565.  
  566.     error("Buffer full");
  567.     return(cmflgs = -2);
  568. }
  569.  
  570.  
  571. /* ADDBUF - Add the string *cp to the command buffer */
  572.  
  573. int addbuf(cp)
  574. char *cp;
  575. {
  576.     int len = 0;
  577.  
  578.     while ((*cp!=NUL) && (bp<cmdbuf+CMDBL))
  579.     {
  580.          *bp++ = *cp++;                          /* Copy and */
  581.          len++;                                  /* count the characters */
  582.     }
  583.     *bp++ = SP;                                  /* Put a space at the end */
  584.     *bp = NUL;                                   /* Terminate with a null */
  585.     np = bp;                                     /* Update the next-field pointer */
  586.     return(len);                                 /* Return the length */
  587. }
  588.  
  589.  
  590. /* SETATM - Deposit a string in the atom buffer */
  591.  
  592. int setatm(cp)
  593. char *cp;
  594. {
  595.     char *ap;
  596.  
  597.     cc = 0;
  598.     ap = atmbuf;
  599.     *ap = NUL;
  600.     while (*cp==SP) cp++;
  601.     while ((*cp!=SP) && (*cp!=LF) && (*cp!=NUL) && (*cp!=CR))
  602.     {
  603.          *ap++ = *cp++;
  604.          cc++;
  605.     }
  606.     *ap++ = NUL;
  607.     return(cc);                                  /* Return length */
  608. }
  609.  
  610.  
  611. /* DIGITS - Verify that all the characters in s are digits */
  612.  
  613. bool digits(s)
  614. char *s;
  615. {
  616.     while (*s!=0) if (!isdigit(*s++)) return(FALSE);
  617.     return(TRUE);
  618. }
  619.  
  620.  
  621. /* LOWER - Lowercase a string, return length */
  622.  
  623. int lower(s)
  624. char *s;
  625. {
  626.     int n = 0;
  627.  
  628.     while (*s!=0)
  629.     {
  630.          if (isupper(*s)) *s = tolower(*s);
  631.          s++, n++;
  632.     }
  633.     return(n);
  634. }
  635.  
  636.  
  637. /* TEST - Bit test, test whether any bits from m are on in x */
  638.  
  639. bool test(x,m)
  640. int x,m;
  641. {
  642.     return((x&m)!=0);
  643. }
  644.  
  645.  
  646. /* HELP - Print the help text string, and replay line */
  647.  
  648. help(xhlp,null)
  649. char *xhlp,*null;
  650. {
  651.     printf("?");
  652.     printf("\nHELP: %s",((xhlp!=NULL) ? xhlp : null));
  653.     printf("\n%s%s",cmprom,cmdbuf);
  654. }
  655.