home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / AZTEC-C / COMND004.ARK / CMDPF1.C < prev    next >
C/C++ Source or Header  |  1986-06-17  |  19KB  |  715 lines

  1. /*    cmdpf1.c    COMND module; COMND parsing routines, set # 1
  2.  
  3.     Copyright (C) 1985 Mark E. Mallett
  4.  
  5.     Permission is hereby granted to distribute this file indiscriminately.
  6.  
  7.     This file contains parsing routines for various individual
  8. function codes, as well as the function-code decoder (?).
  9.  
  10. Edit history
  11.  
  12. When    Who    What
  13. ------    ---    --------------------------------
  14. 84xxxx    MEM    Create file.
  15.  
  16.  
  17.     Routines included are:
  18.  
  19.         CMDpf        Function parsing controller.
  20.         CFPini        Initialize parse
  21.         CFPnoi        Noise word (guide word) parsing
  22.         CFPcfm        Confirm (carriage return)
  23.         CFPkey        Parse keyword from table of keywords
  24.         CFPgky        General keyword parser
  25.         CFPktf        Keyword table fetch routine
  26. */
  27.  
  28.  
  29. #include "stdio.h"            /* Standard system defs */
  30. #include "comnd.h"            /* COMND interface definitions */
  31. #include "comndi.h"            /* COMND internal definitions */
  32.  
  33.  
  34. /* External/forward routines */
  35.  
  36. extern    int    CFPcfm();        /* Confirm */
  37. extern    int    CFPdat();        /* Date and Time */
  38. extern    int    CFPgsk();        /* General Storage Keyword */
  39. extern    int    CFPini();        /* Initialize parse */
  40. extern    int    CFPkey();        /* Keyword parse */
  41. extern    char    **CFPktf();        /* Keyword fetch routine */
  42. extern    int    CFPnoi();        /* Noise words (guide string) */
  43. extern    int    CFPnum();        /* Number */
  44. extern    int    CFPswi();        /* Switch */
  45. extern    int    CFPtok();        /* Token */
  46. extern    int    CFPtxt();        /* Text to end of line */
  47. extern    int    CFPuqs();        /* Unquoted string */
  48.  
  49. /* External data */
  50.  
  51. extern    int    CMDbel;            /* Beep flag */
  52.  
  53. /* Internal (public) routines */
  54.  
  55.  
  56.  
  57. /* Internal (public) data */
  58.  
  59.  
  60. /* Local (static) data */
  61.  
  62.  
  63.  
  64. static    WORD    CCkey[] = {        /* CC for keywords */
  65.             0x0000,        /* ^@ ^A ^B ^C ^D ^E ^F ^G */
  66.             0x3000,        /* ^H ^I ^J ^K ^L ^M ^N ^O */
  67.             0x0000,        /* ^P ^Q ^R ^S ^T ^U ^V ^W */
  68.             0x0000,        /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
  69.             0xC000,        /* sp  !  "  #  $  %  &  ' */
  70.             0x0023,        /*  (  )  *  +  ,  -  .  / */
  71.             0x5555,        /*  0  1  2  3  4  5  6  7 */
  72.             0x5000,        /*  8  9  :  ;  <  =  >  ? */
  73.             0x2AAA,        /*  @  A  B  C  D  E  F  G */
  74.             0xAAAA,        /*  H  I  J  K  L  M  N  O */
  75.             0xAAAA,        /*  P  Q  R  S  T  U  V  W */
  76.             0xA802,        /*  X  Y  Z  [  \  ]  ^  _ */
  77.             0x2AAA,        /*  `  a  b  c  d  e  f  g */
  78.             0xAAAA,        /*  h  i  j  k  l  m  n  o */
  79.             0xAAAA,        /*  p  q  r  s  t  u  v  w */
  80.             0xA800        /*  x  y  z  {  |  }  ~ dl */
  81.               };
  82.  
  83. static    WORD    CCuqs[] = {        /* CC for unquoted string */
  84.             0xFFFF,        /* ^@ ^A ^B ^C ^D ^E ^F ^G */
  85.             0xFFFF,        /* ^H ^I ^J ^K ^L ^M ^N ^O */
  86.             0xFFFF,        /* ^P ^Q ^R ^S ^T ^U ^V ^W */
  87.             0xFCFF,        /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
  88.             0xEAAA,        /* sp  !  "  #  $  %  &  ' */
  89.             0xAAEB,        /*  (  )  *  +  ,  -  .  / */
  90.             0xAAAA,        /*  0  1  2  3  4  5  6  7 */
  91.             0xAAAA,        /*  8  9  :  ;  <  =  >  ? */
  92.             0xAAAA,        /*  @  A  B  C  D  E  F  G */
  93.             0xAAAA,        /*  H  I  J  K  L  M  N  O */
  94.             0xAAAA,        /*  P  Q  R  S  T  U  V  W */
  95.             0xAAAA,        /*  X  Y  Z  [  \  ]  ^  _ */
  96.             0xAAAA,        /*  `  a  b  c  d  e  f  g */
  97.             0xAAAA,        /*  h  i  j  k  l  m  n  o */
  98.             0xAAAA,        /*  p  q  r  s  t  u  v  w */
  99.             0xAAAB        /*  x  y  z  {  |  }  ~ dl */
  100.               };
  101.  
  102.  
  103. static    int    (*Cfptbl[])() = {    /* Command function routine table */
  104.             CFPini,        /* Initialize parse */
  105.             CFPkey,        /* Keyword parse */
  106.             CFPnum,        /* Number */
  107.             CFPnoi,        /* Noise words (guide string) */
  108.             CFPcfm,        /* Confirm */
  109.             CFPgsk,        /* General Storage Keyword */
  110.             CFPswi,        /* Switch */
  111.             CFPtxt,        /* Text to end of line */
  112.             CFPtok,        /* Token */
  113.             CFPuqs,        /* unquoted string */
  114.             CFPdat        /* Date and time */
  115.                   };
  116.  
  117. static    WORD    **Ccctbl[] = {        /* Default CC tables for each fc */
  118.             NULL,        /* _CMINI */
  119.             CCkey,        /* _CMKEY */
  120.             NULL,        /* _CMNUM */
  121.             NULL,        /* _CMNOI */
  122.             NULL,        /* _CMCFM */
  123.             CCkey,        /* _CMGSK */
  124.             CCkey,        /* _CMSWI */
  125.             NULL,        /* _CMTXT */
  126.             NULL,        /* _CMTOK */
  127.             CCuqs,        /* _CMUQS */
  128.             NULL        /* _CMDTM */
  129.                 };
  130.  
  131.  
  132.  
  133. /*
  134.  
  135. *//* CMDpf (CSBptr, CFBptr)
  136.  
  137.     Process parse for a particular function block
  138.  
  139. This routine attempts to parse the remaining input according to
  140. the command function block (CFBptr).  It is responsible for calling
  141. the appropriate parse routine, and passing the result code back to
  142. the main COMND executor.
  143.  
  144.  
  145. Accepts :
  146.  
  147.     CSBptr        Address of command state block
  148.     CFBptr        Address of command function block
  149.  
  150. Returns :
  151.  
  152.     <value>        parse result, of form _CPxxx as defined in the
  153.             include file "comndi.h".
  154.  
  155. */
  156.  
  157. CMDpf (CSBptr, CFBptr)
  158.  
  159. CSB        *CSBptr;        /* Addr of command state block */
  160. CFB        *CFBptr;        /* Addr of command function block */
  161.  
  162. {
  163. IND    int        i;        /* Index */
  164. IND    WORD        *ccptr;        /* Addr of CC table, if any */
  165.  
  166. i = CFBptr -> CFB_FNC;            /* Get function code */
  167. if ((i < 0) || (i > _CMMAX))        /* If out of legit range */
  168.     {
  169.     CSBptr -> CSB_RCD = _CRIFC;        /* Set invalid function code status */
  170.     return (_CPABT);            /* Abort, right away. */
  171.     }
  172.  
  173. ccptr = Ccctbl[i];            /* Get default CC table */
  174. if (ccptr)                /* If any (if meaningful here) */
  175.     if (CFBptr->CFB_FLG & _CFCC)    /* If user-supplied bit set */
  176.     ccptr = CFBptr -> CFB_CC;    /*   then use his/hers! */
  177. return ((*Cfptbl[i])(CSBptr, CFBptr, ccptr));    /* Process it */
  178. }
  179. /*
  180.  
  181. *//* CFBini (CSBptr, CFBptr, ccptr)
  182.  
  183.     Function parse for type=_CMINI, initialize the parse
  184.  
  185.  
  186. This routine is called to initialize a parse for a line.
  187.  
  188. Accepts :
  189.  
  190.     CSBptr        Address of command state block
  191.     CFBptr        Address of command function block
  192.     ccptr        Address of CC table (where appropriate)
  193.  
  194.  
  195. Returns :
  196.  
  197.     <value>        Parse status, _CPxxx as defined in comndi.h.
  198.  
  199. */
  200.  
  201. CFPini (CSBptr, CFBptr, ccptr)
  202.  
  203. CSB        *CSBptr;        /* Addr of command state block */
  204. CFB        *CFBptr;        /* Addr of command function block */
  205. WORD        *ccptr;            /* Addr of CC table */
  206.  
  207. {
  208. CSBptr -> CSB_FLN = -1;            /* No text filled, yet */
  209.                     /* -1 enables ^H recovery */
  210. return (_CPSUCC);            /* This parse MATCHED, by jove */
  211. }
  212. /*
  213.  
  214. *//* CFPnoi (CSBptr, CFBptr, ccptr)
  215.  
  216.     Function parse for type=_CMNOI, noise words (guide string)
  217.  
  218. This routine attempts a parse of a particular guide string.  The
  219. guide words are given in the CFB_DEF pointer area, and are matched if
  220. enclosed in parentheses (the parens are NOT included in the supplied
  221. string).
  222.  
  223. Accepts :
  224.  
  225.     CSBptr        Address of command state block
  226.     CFBptr        Address of command function block
  227.     ccptr        Address of CC table (where appropriate)
  228.  
  229.  
  230. Returns :
  231.  
  232.     <value>        Parse status, _CPxxx as defined in comndi.h.
  233.  
  234. */
  235.  
  236. CFPnoi (CSBptr, CFBptr, ccptr)
  237.  
  238. CSB        *CSBptr;        /* Addr of command state block */
  239. CFB        *CFBptr;        /* Addr of command function block */
  240. WORD        *ccptr;            /* Addr of CC table */
  241.  
  242. {
  243. IND    char    *dptr;            /* Default string pointer */
  244. IND    int    cix;            /* Command index */
  245. IND    int    c,c1;            /* Character */
  246.  
  247. cix = CMDspc (CSBptr);            /* Skip spaces */
  248. dptr = CFBptr -> CFB_DEF;        /* Get addr of default string */
  249. if (CSBptr -> CSB_RFL & _CFPFE)        /* If previous ended in escape */
  250.     c = _CCCMP;                /* Flag completion wanted */
  251. else                    /* Otherwise */
  252.     c = CMDgcc(CSBptr, cix++);        /*  get next char */
  253.  
  254. if (c == _CCCMP)            /* If completion wanted at start */
  255.     {
  256.     CMDcpl (CSBptr, "(");        /* Complete... opening paren */
  257.     CMDcpl (CSBptr, dptr);        /* Complete... guide words */
  258.     CMDcpl (CSBptr, ") ");        /* Complete... closing paren */
  259.     return (_CPCPE);            /* Return successful parse */
  260.     }
  261.  
  262. if (c == _CCINC)            /* If incomplete */
  263.     return (_CPAGN);            /*  try again */
  264.  
  265. if (c != '(')                /* If not open paren */
  266.     return (_CPSUCC);            /*  guide words are optional */
  267.  
  268. while (TRUE)                /* Loop on chars in input */
  269.     {
  270.     while (TRUE)            /* Get non-blank char from input */
  271.     {
  272.     c = CMDgcc (CSBptr, cix++);
  273.     if ((c != ' ') && (c != '    '))
  274.         break;
  275.     }
  276.  
  277.     while (TRUE)            /* Get non-blank char from default */
  278.     {
  279.     c1 = *dptr++;
  280.     if ((c1 != ' ') && (c1 != '    '))
  281.         break;
  282.     }
  283.  
  284.     if ((c == _CCCMP)            /* completion ? */
  285.      || (c == _CCHLP)            /* Give help ? */
  286.      || (c == _CCEND)            /* End? */
  287.       )
  288.     break;                /*  quit the loop */
  289.  
  290.     c = toupper(c);            /* Compare in same case */
  291.     c1 = toupper(c1);            /*     .     */
  292.     if (c1 != c)            /* If not the same */
  293.     break;                /*  then leave this loop. */
  294.     }
  295.  
  296. /* Found non-match, or special request */
  297.  
  298. if (c == _CCCMP)            /* If completion wanted, */
  299.     {
  300.     CMDcpl (CSBptr, --dptr);        /* Complete with rest of string */
  301.     CMDcpl (CSBptr, ") ");        /* Complete with closing paren */
  302.     return (_CPCPE);            /* Return success */
  303.     }
  304.  
  305. if (c == _CCHLP)            /* Give help ? */
  306.     {
  307.     if (CMDhlp (CFBptr, "guide string: ("))
  308.     {
  309.     CMDpzs (CFBptr -> CFB_DEF);    /* Print string */
  310.     CMDpzs (")");
  311.     CMDfob();            /* Make sure it is seen */
  312.     }
  313.     return (_CPGVH);            /* Indicate we gave help */
  314.     }
  315.  
  316. if (c == _CCEND)            /* If end of input */
  317.     return (_CPNOP);            /*  no parse */
  318.  
  319. if (c == _CCINC)            /* If incomplete */
  320.     return (_CPAGN);            /*  try again */
  321.  
  322. if ((c1 == NUL) && (c == ')'))        /* If end of guideword */
  323.     {
  324.     CMDcpt (CSBptr, cix);        /* Set parse checkpoint */
  325.     return (_CPSUCC);            /* Return success! */
  326.     }
  327.  
  328. return (_CPNOP);            /* Sorry, no parse */
  329. }
  330. /*
  331.  
  332. *//* CFPcfm (CSBptr, CFBptr, ccptr)
  333.  
  334.     Function parse for type=_CMCFM, confirm with carriage return
  335.  
  336.  
  337. Accepts :
  338.  
  339.     CSBptr        Address of command state block
  340.     CFBptr        Address of command function block
  341.     ccptr        Address of CC table (where appropriate)
  342.  
  343.  
  344. Returns :
  345.  
  346.     <value>        Parse status, _CPxxx as defined in comndi.h.
  347.  
  348. */
  349.  
  350. CFPcfm (CSBptr, CFBptr, ccptr)
  351.  
  352. CSB        *CSBptr;        /* Addr of command state block */
  353. CFB        *CFBptr;        /* Addr of command function block */
  354. WORD        *ccptr;            /* Addr of CC table */
  355.  
  356. {
  357. IND    int    c;            /* Character */
  358.  
  359. c = CMDgcc (CSBptr, CMDspc(CSBptr));    /* Get the character that's next */
  360. switch (c)                /* Process it */
  361.     {
  362.     case _CCINC:            /* Incomplete */
  363.     return (_CPAGN);        /*  just continue parsing */
  364.  
  365.     case _CCCMP:            /* Completion... */
  366.     CMDbel++;            /* Indicate our desire to beep */
  367.     return (_CPAGN);        /* Try again. */
  368.  
  369.     case _CCHLP:            /* Help */
  370.     CMDhlp (CFBptr, "confirm with carriage return");
  371.     return (_CPGVH);        /* Indicate help given */
  372.  
  373.     case _CCEND:            /* End? */
  374.     return (_CPSUCC);        /*  we was successful */
  375.  
  376.     default:                /* Anything else */
  377.     return (_CPNOP);        /*  no parse */
  378.     }
  379. }
  380. /*
  381. *//* CFPkey (CSBptr, CFBptr, ccptr)
  382.  
  383.     Function parse for type=_CMKEY, keyword parse.
  384.  
  385. This routine handles parsing for type _CMKEY, a table of keywords.
  386. Basically, it hands off to CFPgky, the general keyword parser.
  387.  
  388. Accepts :
  389.  
  390.     CSBptr        Address of command state block
  391.     CFBptr        Address of command function block
  392.     ccptr        Address of CC table (where appropriate)
  393.  
  394. Returns :
  395.  
  396.     <value>        Parse result, one of the _CPxxx values, as defined
  397.             in "comndi.h"
  398.  
  399. */
  400.  
  401. CFPkey (CSBptr, CFBptr, ccptr)
  402.  
  403. CSB        *CSBptr;        /* Addr of command state block */
  404. CFB        *CFBptr;        /* Addr of command function block */
  405. WORD        *ccptr;            /* Addr of CC table */
  406.  
  407. {
  408. return (CFPgky (CSBptr, CFBptr, CFBptr -> CFB_DAT, CFPktf, ccptr));
  409. }
  410. /*
  411. *//* CFPgsk (CSBptr, CFBptr, ccptr)
  412.  
  413.     Function parse for type=_CMGSK, general keyword.
  414.  
  415. This routine handles parsing for type _CMGSK, where a method of fetching
  416. each candidate keyword is provided.  CFB_DAT contains the address of a
  417. CGK block, which in turns specifies a routine to call to get a pointer
  418. to a keyword's pointer when given a specified base (also in CGK) and
  419. the address of the previous pointer.
  420.  
  421. This routine calls CFBgky, the general keyword parser.
  422.  
  423.  
  424. Accepts :
  425.  
  426.     CSBptr        Address of command state block
  427.     CFBptr        Address of command function block
  428.     ccptr        Address of CC table (where appropriate)
  429.  
  430. Returns :
  431.  
  432.     <value>        Parse result, one of the _CPxxx values, as defined
  433.             in "comndi.h"
  434.  
  435. */
  436.  
  437. CFPgsk (CSBptr, CFBptr, ccptr)
  438.  
  439. CSB        *CSBptr;        /* Addr of command state block */
  440. CFB        *CFBptr;        /* Addr of command function block */
  441. WORD        *ccptr;            /* Addr of CC table */
  442.  
  443. {
  444. IND    CGK    *CGKptr;        /* Points to COMND Genl Kwd block */
  445.  
  446. CGKptr = (CGK *) CFBptr -> CFB_DAT;    /* Get addr of CGK block */
  447. return (CFPgky (CSBptr, CFBptr, CGKptr->CGK_BAS, CGKptr->CGK_KFR, ccptr));
  448. }
  449. /*
  450.  
  451. *//* CFPgky (CSBptr, CFBptr, base, kfr, ccptr)
  452.  
  453.     General keyword parse.
  454.  
  455. This routine handles parsing for strings, using a general keyword fetch
  456. mechanism.
  457.  
  458. Accepts :
  459.  
  460.     CSBptr        Address of command state block
  461.     CFBptr        Address of command function block
  462.     base        A base variable to pass to the keyword fetch
  463.               routine (we don't need to know what it is).
  464.     kfr        Address of the routine to fetch strings.
  465.     ccptr        Addr of CC table to use.
  466.  
  467.  
  468. Returns :
  469.  
  470.     <value>        Parse status, _CPxxx as defined in comndi.h.
  471.  
  472. */
  473.  
  474. CFPgky (CSBptr, CFBptr, base, kfr, ccptr)
  475.  
  476. CSB        *CSBptr;        /* Addr of command state block */
  477. CFB        *CFBptr;        /* Addr of command function block */
  478. char        *base;            /* Some base pointer */
  479. char        **(*kfr)();        /* Addr of routine to fetch ptr
  480.                        to next string */
  481. WORD        *ccptr;            /* Addr of CC table */
  482.  
  483. {
  484. IND    int    ec;            /* End char (action char, if any) */
  485. IND    BYTE    c,c1;            /* A character */
  486. IND    char    **entptr;        /* Entry pointer pointer */
  487. IND    char    *entstr;        /* Entry string pointer */
  488. IND    char    **matptr,**mat1;    /* Two previous matches */
  489. IND    char    *matend;        /* End of matched string */
  490. IND    BYTE    *wrdptr;        /* Pointer to the word */
  491. IND    int    cix;            /* Command index */
  492. IND    int    hcol;            /* Help display column # */
  493. IND    char    *hptr;            /* start of help pointer */
  494. IND    int    i;            /* Scratch */
  495.  
  496. hptr = NULL;                /* Init start-of-help pointer */
  497. if (CFBptr -> CFB_FLG & _CFHPP)        /* If user-supplied help */
  498.     hptr = "";                /* don't US say "keyword" */
  499. if (hptr == NULL)            /* Now if no start-of-help */
  500.     hptr = "keyword, ";            /*  use our own */
  501.  
  502.  
  503. /* Collect the command string into the atom buffer, for starts. */
  504.  
  505. cix = CMDcab (CSBptr,             /* Collect atom buffer */
  506.         CSBptr -> CSB_ABF,    /*  where to put it */
  507.         CSBptr -> CSB_ASZ,    /*  how big it is */
  508.         ccptr,            /* Char table */
  509.         &ec,            /* What the end char is */
  510.         CMDspc(CSBptr));    /* Initial parse index */
  511.  
  512. if (ec == _CCINV)            /* If invalid delimiter */
  513.     return (_CPNOP);            /*  return no-parse */
  514.  
  515. /* Now attempt to match the string in the atom buffer according to
  516.    strings given. */
  517.  
  518. entptr = NULL;                /* Init entry pointer */
  519. matptr = NULL;                /* No match yet */
  520. mat1 = NULL;                /* No first match */
  521.  
  522. while ((entptr = (*kfr)(base, entptr)) != NULL)
  523.                     /* End of table is a null entry */
  524.     {
  525.     entstr = *entptr;            /* Get pointer to string */
  526.     wrdptr = CSBptr -> CSB_ABF;        /* Get pointer to atom buffer */
  527.     while (TRUE)            /* Scan to end of word */
  528.     {
  529.     c = *wrdptr++;
  530.     c = toupper(c);            /* Get its uppercase */
  531.     c1 = *entstr++;            /* Get next char from table ent */
  532.     if (c == NUL)            /* If end of our string */
  533.         break;            /*  go check more */
  534.     if (c != toupper(c1))        /* if mismatch */
  535.         break;            /*  be done */
  536.     }
  537.  
  538.     if (c == NUL)            /* If end of word, we matched */
  539.     {
  540.     if (ec == _CCHLP)        /* Give help ? */
  541.         {
  542.         if (!matptr)        /* No other match... */
  543.         matptr = entptr;    /* Remember it */
  544.         else            /* Must print as help */
  545.         {
  546.         if (!mat1)        /* If must print help message */
  547.             {
  548.             mat1 = matptr;
  549.             if (CMDhlp (CFBptr, hptr))
  550.             {
  551.             CMDpzs ("one of the following:\n");
  552.              CMDpzs (*matptr);
  553.             hcol = strlen (*matptr);
  554.             }
  555.             }
  556.         i = hcol;
  557.         hcol = (hcol+16)&(-16);        /* Next tab stop */
  558.         if (!(CFBptr -> CFB_FLG & _CFSDH)) /* If not suppressed */
  559.             {
  560.             if (hcol + strlen(*entptr) > 79)
  561.             {
  562.             hcol = 0;
  563.             CMDpoc ('\n');
  564.             }
  565.             else
  566.             {
  567. #ifdef USETABS
  568.             CMDpoc ('\011');
  569.             if (hcol-i > 8)
  570.                 CMDpoc ('\011');
  571. #else
  572.             while (i++ < hcol)
  573.                 CMDpoc(' ');
  574. #endif
  575.             }
  576.             CMDpzs (*entptr);
  577.             hcol += strlen(*entptr);
  578.             }
  579.         }
  580.         continue;
  581.         }
  582.  
  583.     if (c1 == NUL)            /* If also end of entry , real match */
  584.         {
  585.         matptr = entptr;        /* Set match to this entry */
  586.         matend = entstr-1;        /* Remember completion ptr */
  587.         mat1 = NULL;        /* Disambiguate */
  588.         break;            /* Go return it. */
  589.         }
  590.  
  591.     else
  592.         {
  593.         if (matptr)            /* Any other ambig match ? */
  594.         mat1 = matptr;        /*  flag it */
  595.         else            /* Otherwise */
  596.         {
  597.         matptr = entptr;    /*  remember this one */
  598.         matend = entstr-1;    /* Point to rest-of-string */
  599.         }
  600.         }
  601.     }
  602.     }
  603.  
  604. /* Here, scanned table. */
  605.  
  606. if (mat1 && matptr)            /* If multiply matched */
  607.     {
  608.     switch (ec)                /* Process according to final char */
  609.     {
  610.     case _CCHLP:            /* Gave help already? */
  611.         CMDfob();            /* Show what we did */
  612.         return (_CPGVH);        /* Return that status */
  613.  
  614.     case _CCCMP:            /* Complete */
  615.         CMDbel++;            /* Say we would beep */
  616.  
  617.     case _CCINC:            /* Incomplete input? */
  618.         return (_CPAGN);        /* Try again */
  619.  
  620.     case _CCEND:            /* End of line */
  621.         return (_CPNOP);        /* No match. */
  622.  
  623.     default:
  624.         return (_CPNOP);        /* Ambiguous with some other junk,
  625.                        give failure.  */
  626.     }
  627.     }
  628.  
  629. if (matptr)                /* Any match at all ? */
  630.     {
  631.     CSBptr->CSB_RVL._ADR = matptr;    /* Pass back the result. */
  632.     switch (ec)                /* Process according to action char */
  633.     {
  634.     case _CCHLP:            /* Give help */
  635.         if (CMDhlp (CFBptr, hptr))
  636.         {
  637.         CMDpzs ("only choice is: ");
  638.         CMDpzs (*matptr);
  639.         }
  640.         CMDfob();
  641.         return (_CPGVH);        /* Gave help */
  642.  
  643.     case _CCCMP:            /* Complete */
  644.         CMDcpl (CSBptr, matend);    /* Complete with end of match */
  645.         CMDcpl (CSBptr, " ");    /* Add space */
  646.         return (_CPCPE);        /* Completed with escape */
  647.  
  648.     case _CCINC:            /* Incomplete */
  649.         return (_CPAGN);        /* Try again with more */
  650.  
  651.     default:            /* Anything else */
  652.         if (*CSBptr -> CSB_ABF == NUL)
  653.         return (_CPNOP);    /* If null entry, no parse */
  654.         CMDcpt (CSBptr, cix);    /* Checkpoint parse to here */
  655.         return (_CPSUCC);        /* Success */
  656.     }
  657.     }
  658.  
  659. else                    /* No match at all */
  660.     {
  661.     switch (ec)                /* Depends on final char */
  662.     {
  663.     default:            /* Anything */
  664.         return (_CPNOP);        /*  no parse */
  665.     }
  666.     }
  667. }
  668. /*
  669.  
  670. *//* CFPktf (base, str)
  671.  
  672.     Returns address of next string in a table of pointers to strings
  673.  
  674. This is a general keyword address fetcher for use in the _CMKEY parse
  675. function.  It accepts the address of a string ptr, and returns the address
  676. of the next one.
  677.  
  678.  
  679. Accepts :
  680.  
  681.     base        Address of the base of the table
  682.     str        Address of a pointer to the previous string, or
  683.             NULL to indicate fetching the first string.
  684.  
  685.  
  686. Note: this routine deals in address of POINTERS because it points to
  687. the table entry, in general, where the table is composed of pointers
  688. to strings.  Get it?
  689.  
  690. Returns :
  691.  
  692.     <value>        Address of the next string, or
  693.             NULL if no more.
  694.  
  695. */
  696.  
  697. char **CFPktf (base, str)
  698.  
  699. char        *base[];        /* Table address */
  700. char        **str;            /* Addr of string pointer */
  701.  
  702. {
  703. if (str == NULL)            /* If pointer is NULL */
  704.     {
  705.     if (*base == NULL)            /* If empty table */
  706.     return (NULL);            /*  return end */
  707.     return (base);            /* Return base address */
  708.     }
  709.  
  710. if (*++str == NULL)            /* If next entry is NULL */
  711.     return (NULL);            /*  then return END */
  712. else                    /* Otherwise */
  713.     return (str);            /*  return the pointer */
  714. }
  715.