home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / ccmd / cmnoi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-19  |  10.7 KB  |  319 lines

  1. /*
  2.  Author: Andrew Lowry
  3.  
  4.  Columbia University Center for Computing Activities, July 1986.
  5.  Copyright (C) 1986, 1987, Trustees of Columbia University in the City
  6.  of New York.  Permission is granted to any individual or institution
  7.  to use, copy, or redistribute this software so long as it is not sold
  8.  for profit, provided this copyright notice is retained.
  9. */
  10. /* cmnoi
  11. **
  12. ** This module contains the default break table and handlers for
  13. ** parsing noise words.  Parsing succeeds if the current input
  14. ** begins with a left paren, then matches the given noise word
  15. ** modulo case and whitespace, then closes with a right paren.
  16. ** If the current input begins with anything other than a left
  17. ** paren, parsing also succeeds, but no characters are consumed.
  18. ** Unusual handling is performed when the current input is empty
  19. ** and the CM_PFE flag is on in the CSB.  In this case, the noise
  20. ** word with parentheses is stuffed into the command buffer, and
  21. ** another parse attempt is requested.  (We cannot merely succeed,
  22. ** since the characters we stuff into the buffer are not in the
  23. ** text buffer that was passed to us.  The caller must rebuild
  24. ** this text buffer for us.)  Another unusual case is when the
  25. ** input is empty and the CM_ACT flag is on in the CSB, indicating
  26. ** that action is pending.  In this case, the parse succeeds,
  27. ** consuming no characters, so that the action will apply to
  28. ** the next real field, not to the noise word.  Finally, 
  29. ** noise word parses do not affect the atom buffer.
  30. **
  31. ** Completion can only occur with a non-empty buffer (due to the
  32. ** special action with CM_ACT and an empty buffer just described).
  33. ** (This is not true if completion is immediate on some key, but if
  34. ** that's the case, something strange is probably going on anyway.)
  35. ** The completion text consists of the remainder of the noise word,
  36. ** with closing paren and trailing space.  Partial completion will
  37. ** complete only up to and including the next punctuation, and will
  38. ** not add a trailing blank.
  39. **
  40. ** Help, like completion, should never occur at the beginning of
  41. ** a noise word.  It consists of the string, "Noise word."
  42. **
  43. ** The break table has no effect on the parsing of a noise word.
  44. ** The default is set to include only the printing characters
  45. ** other than question mark, so that standard actions will be
  46. ** active.  For first character, everything but left paren breaks,
  47. ** so that CM_WKF parsing will work correctly.
  48. **/
  49.  
  50. #define    NOIERR            /* declare cmnoi parse errors here */
  51.  
  52. #include "ccmdlib.h"        /* get ccmd package symbols */
  53. #include "cmfncs.h"        /* and internal symbols */
  54.  
  55. /* Forward declarations of handlers */
  56.  
  57. int noiprs(), noihlp(), noicplt();
  58.  
  59. static brktab noibrk = {
  60.   {                    /* only open paren allowed first */
  61.     0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff,
  62.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  63.   },
  64.   {                    /* all print chars but '?' */
  65.     0xff, 0xbf, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
  66.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
  67.   }
  68. };
  69.  
  70. ftspec ft_noi = { noiprs, noihlp, noicplt, 0, &noibrk }; /* handler structure */
  71.  
  72.  
  73.  
  74. /* noiprs - If current input is empty and CM_PFE is on, stuff the noise
  75. ** word and ask for another try.  If empty and CM_ACT is on, succeed
  76. ** consuming nothing.  If nonempty and 1st char is not paren, succeed
  77. ** consuming nothing.  Otherwise succeed if the rest matches the noise
  78. ** word string followed by a right paren and another character.
  79. **/
  80.  
  81. PASSEDSTATIC int
  82. noiprs(text,textlen,fdbp,parselen,value)
  83. char *text;
  84. int textlen,*parselen;
  85. fdb *fdbp;
  86. pval *value;
  87. {
  88.   int ret;            /* results of stuffs */
  89.   char *term;            /* pointer to char after close paren */
  90.   char *cplt;            /* unused arg to fndnoi */
  91.  
  92.   cmcsb._cmflg |= CM_NAC;    /* protect the atom buffer */
  93.   if (textlen == 0)        /* empty buffer? */
  94.     if (cmcsb._cmflg & CM_PFE) { /* and prior field got completion? */
  95.       ret = cmsti1('(',0);    /* yup, give an open paren */
  96.       if (ret == CMxOK)
  97.     ret = cmsti((char *) fdbp->_cmdat,0); /* followed by the noise */
  98.       if (ret == CMxOK)
  99.     ret = cmsti(") ",0);    /* followed by close paren and space */
  100.       if (ret == CMxOK)
  101.     ret = CMxAGN;        /* and request another try */
  102.       return(ret);
  103.     }
  104.     else if (cmcsb._cmflg & CM_ACT) { /* empty and action waiting? */
  105.       *parselen = 0;        /* consume nothing */
  106.       return(CMxOK);        /* and succeed */
  107.     }
  108.     else
  109.       return(CMxINC);        /* empty, no PFE, no action waiting */
  110.     
  111.   if ((*text & CC_CHR) != '(') { /* nonempty buffer not a noise word? */
  112.     *parselen = 0;        /* then consume nothing */
  113.     return(CMxOK);        /* and succeed - noise is optional */
  114.   }
  115.  
  116.                 /* find noise in the input */
  117.   ret = fndnoi(text+1,textlen-1,(char *) fdbp->_cmdat,&cplt,&term);
  118.   if (ret != CMxOK)
  119.     return(ret);        /* propagate errors */
  120.   if (term == NULL)
  121.     return(CMxINC);        /* not terminated -- need more input */
  122.   *parselen = term-text;    /* compute length of noise */
  123.   return(CMxOK);        /* and succeed */
  124. }
  125.  
  126.  
  127.  
  128. /* noihlp - Always print "Noise word" */
  129.  
  130. PASSEDSTATIC int
  131. noihlp(text,textlen,fdbp,cust)
  132. char *text;
  133. int textlen,cust;
  134. fdb *fdbp;
  135. {
  136.   cmxputs("noise word");
  137.   return(CMxOK);
  138. }
  139.  
  140.  
  141.  
  142. /* noicplt - Just finish up the noise where the current input
  143. ** leaves off.  Full completion also adds a space, partial
  144. ** completion never does.
  145. **/
  146.  
  147. PASSEDSTATIC int
  148. noicplt(text,textlen,fdbp,full,cplt,cpltlen)
  149. char *text,**cplt;
  150. int textlen,full,*cpltlen;
  151. fdb *fdbp;
  152. {
  153.   int ret;            /* return code from aux routine */
  154.   char *term;            /* char after noise word if any */
  155.   char c;            /* chars in completion */  
  156.   static char *work = NULL;    /* dynamic area to build completion */
  157.   char *cp;            /* for copying completion text */
  158.   char *malloc();        /* declare non-int library routine */
  159.   int badalc = FALSE;        /* true if malloc fails below */
  160.  
  161.   if (work != NULL) {        /* buffer hanging around from last time? */
  162.     free(work);            /* get rid of it */
  163.     work = NULL;        /* and mark it released */
  164.   }
  165.                 /* find noise in the input */
  166.   ret = fndnoi(text+1,textlen-1,(char *) fdbp->_cmdat,cplt,&term);
  167.   
  168.   *cpltlen = -1;        /* always complete to end of string */
  169.   if (*cplt == NULL) {        /* noise is all there */
  170.     if (ret == CMxINC)        /* no closing paren */
  171.       *cplt = ")";        /* so give them one */
  172.   }
  173.   else {            /* noise not all there */
  174.     work = malloc(strlen(*cplt)+2); /* noise, paren, and null */
  175.     if (work != NULL) {        /* allocation succeeded? */
  176.       cp = work;        /* point to work space */
  177.       while (*cp++ = *(*cplt)++); /* copy remainder of noise word */
  178.       *(--cp) = ')';        /* finish with right paren */
  179.       *(++cp) = NULCHAR;    /* and tie off with a null */
  180.       *cplt = work;        /* point to constructed text */
  181.     }
  182.     else
  183.       badalc = TRUE;        /* flag allocation failure */
  184.   }
  185.   if (full)            /* full completion */
  186.     if (badalc)        
  187.       return(0);        /* just fill in if allocation failed */
  188.     else
  189.       return(CMP_SPC | CMP_GO); /* otherwise add a space and a wakeup */
  190.   else
  191.     return(CMP_PNC);        /* partial - complete to punctuation */
  192. }
  193.  
  194.  
  195.  
  196. /* fndnoi - Auxiliary routine for noise word handlers 
  197. **
  198. ** Determines how much of the noise word is in the input buffer,
  199. ** and indicates where completion, if any, should start.
  200. **
  201. ** Input parameters:
  202. **   text - The input text to be parsed.
  203. **   textlen - Size of the input text.
  204. **   noise - Pointer to the noise word.
  205. **
  206. ** Output parameters:
  207. **   cplt - A pointer to the start of completion text within the noise.
  208. **   term - A pointer to the character following the right paren if there
  209. **     was one in the input.
  210. **
  211. ** Returns: Standard error code.  CMxOK means complete noise word with
  212. **   following terminator.  CMxINC means good match so far, but needs
  213. **   more for a CMxOK.  Anything else is error.
  214. **/
  215.  
  216. static int
  217. fndnoi(text,textlen,noise,cplt,term)
  218. char *text,*noise,**cplt,**term;
  219. int textlen;
  220. {
  221.   char cc,tc;            /* completion and text chars */
  222.   int ret;
  223.   int inws = FALSE;        /* TRUE during whitespace in completion */
  224.  
  225.   *term = NULL;            /* assume no terminator */
  226.   *cplt = noise;        /* start completion all the way back */
  227.  
  228.   ret = skipws(&text,&textlen,FALSE); /* optional space after open paren */
  229.   if (ret != CMxOK)
  230.     return(ret);            /* propagate errors */
  231.   
  232.   while ((cc = **cplt) != NULCHAR) /* loop to end of noise */
  233.     if ((cc == SPACE) || (cc == TAB)) /* hit some white space */
  234.       if (inws)
  235.     (*cplt)++;        /* already in it... keep looking */
  236.       else {
  237.     ret = skipws(&text,&textlen,TRUE); /* mandatory ws in text */
  238.     if (ret != CMxOK)
  239.       return(ret);        /* propagate problems */
  240.         inws = TRUE;        /* don't need it again */
  241.     (*cplt)++;        /* and consume the character */
  242.       }
  243.     else if (textlen == 0)    /* more noise and no more text? */
  244.       return(CMxINC);        /* yup, ask for more text */
  245.     else {
  246.       inws = FALSE;        /* no longer in white space */
  247.       tc = (*text++) & CC_CHR;    /* try to match noise */
  248.       if ((cc >= 'a') && (cc <= 'z'))
  249.     cc -= 'a'-'A';        /* uppercase both chars */
  250.       if ((tc >= 'a') && (tc <= 'z'))
  251.     tc -= 'a'-'A';
  252.       if (cc != tc)        /* different chars? */
  253.     return(NOIxNP);        /* then no parse */
  254.       textlen--;        /* else update counts and pointers */
  255.       (*cplt)++;
  256.     }                /* and keep looping */
  257.  
  258.   *cplt = NULL;            /* got through whole noise - no completion */
  259.  
  260.   ret = skipws(&text,&textlen,FALSE); /* optional space before closing */
  261.   if (ret != CMxOK)
  262.     return(ret);
  263.  
  264.   if (textlen == 0)        /* nothing left? */
  265.     return(CMxINC);        /* we still need a closing paren */
  266.   else if ((*text & CC_CHR) != ')') /* next char not closing paren? */
  267.     return(NOIxNP);        /* then bad parse */
  268.   else {
  269.     if (textlen > 1)        /* something after closing paren? */
  270.       *term = text+1;        /* yup, give them a pointer to it */
  271.     return(CMxOK);        /* entire noise word parsed ok */
  272.   }
  273. }
  274.  
  275.  
  276.  
  277. /* skipws - aux routine for fndnoi.
  278. **
  279. ** Purpose:
  280. **   Skips spaces and tabs in the input text.  Fails if there are none
  281. **   and the mandatory flag was on in the call.
  282.  
  283. ** Input parameters:
  284. **   text - Pointer to text to be scanned.
  285. **   textlen - Number of chars in text.
  286. **   mandatory - TRUE if an error should result if no space is there.
  287. **
  288. ** Output parameters:
  289. **   text, textlen - updated according to chars skipped.
  290. **
  291. ** Returns: Standard error code.
  292. **/
  293.  
  294. static int
  295. skipws(text,textlen,mandatory)
  296. char **text;
  297. int *textlen,mandatory;
  298. {
  299.   char c;
  300.   while (*textlen > 0) {    /* scan whole text */
  301.     c = **text & CC_CHR;    /* get next char */
  302.     if ((c == SPACE) || (c == TAB)) {
  303.       (*text)++;        /* found white space - skip it */
  304.       (*textlen)--;        /* count it */
  305.       mandatory = FALSE;    /* and no longer mandatory */
  306.     }
  307.     else
  308.       break;            /* exit loop when non-ws found */
  309.   }
  310.  
  311.   if (mandatory)        /* no ws found and it was required? */
  312.     if (*textlen == 0)        /* yes, no input? */
  313.       return(CMxINC);        /* then it's incomplete */
  314.     else
  315.       return(NOIxNP);        /* otherwise bad parse */
  316.   else
  317.     return(CMxOK);        /* otherwise it's fine */
  318. }
  319.