home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mm / mm-ccmd-0.91-20031009.tar.gz / mm-ccmd-0.91-20031009.tar / work / ccmd / cmqst.c < prev    next >
C/C++ Source or Header  |  2000-01-02  |  9KB  |  274 lines

  1. /*
  2.  Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  the City of New York.  Permission is granted to any individual or
  4.  institution to use, copy, or redistribute this software so long as it
  5.  is not sold for profit, provided this copyright notice is retained.
  6.  
  7.  Author: Andrew Lowry
  8. */
  9. /* cmqst
  10. **
  11. ** This module contains the standard break table and handlers for
  12. ** parsing quoted strings.  Parsing succeeds if the current input
  13. ** contains a quote, followed by an acceptable content string,
  14. ** followed by a quote and any character other than a quote.
  15. ** Doubled quotes are converted to singleton quotes.  An exception
  16. ** is when the doubled quote occurs at the beginning of the field,
  17. ** in which case an empty string is parsed.  The parsed
  18. ** string is returned, without opening or closing quotes, via
  19. ** the atom buffer.  The characters that are allowed inside the
  20. ** quoted string are precisely those that do not break in non-first
  21. ** position.  By default, this includes all printing characters.
  22. ** Note that this default implies that question marks lose their
  23. ** standard actions.
  24. **
  25. ** The first-position break array can be used to indicate which
  26. ** characters are allowed to serve as quotes.  If the first character
  27. ** is any of these characters, it becomes the quote character for
  28. ** the field, and the ASCII quote character (") is treated as an
  29. ** ordinary character.  Thus, when quote is not the field delimiter,
  30. ** it need not be doubled, but the field delimiter must be doubled.
  31. ** For example, the following would yield equivalent results:
  32. **
  33. **        "The character, ""\,"" is called ""back-slash."""
  34. **        \The character, "\\," is called "back-slash."\
  35. **
  36. ** By default, the ASCII quote and apostrophe are the only
  37. ** characters allowed to be quotes (" and ').
  38. **
  39. ** Full completion, when invoked immediately following a singleton quote,
  40. ** inserts a space after the quote.  Otherwise it beeps.  Partial completion
  41. ** always beeps.  The standard help string is "Quoted string," unless
  42. ** the first-position break array is not identical to the standard,
  43. ** in which case "Delimited string" is used instead.  If the delimiter
  44. ** is already present in the buffer, the message "String terminated by 
  45. ** 'x'" is used, where x is the delimiter.
  46. **/
  47.  
  48. #define    QSTERR            /* declare cmqst parse errors here */
  49.  
  50. #include "ccmdlib.h"        /* get ccmd package symbols */
  51. #include "cmfncs.h"        /* and internal symbols */
  52.  
  53. /* Forward declarations of handler routines */
  54.  
  55. PASSEDSTATIC int qstprs(), qsthlp(), qstcplt();
  56.  
  57. static int fndqst(char *text, int textlen, fdb *fdbp, char *quote,
  58.           int *qstlen, char **term);
  59.  
  60. static brktab qstbrk = {
  61.   {                    /* chars that can serve as quote */
  62.     0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0xff, 0xff, /* allow " and ' */
  63.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  64.   },
  65.   {                    /* chars that can be in strings */
  66.     0xff, 0xbf, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, /* tab and all */
  67.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01  /*  printable chars */
  68.   }
  69. };
  70.  
  71. ftspec ft_qst = { qstprs, qsthlp, qstcplt, 0, &qstbrk }; /* handler structure */
  72.  
  73.  
  74.  
  75. /* qstprs - If the current input contains a proper quoted string,
  76. ** copy it into the atom buffer and return, with the CSB flag set
  77. ** to prevent automatic atom buffer copying.
  78. **/
  79.  
  80. PASSEDSTATIC int
  81. qstprs(text,textlen,fdbp,parselen,value)
  82. char *text;
  83. int textlen,*parselen;
  84. fdb *fdbp;
  85. pval *value;
  86. {
  87.   char quote;            /* character used as quote */
  88.   int qstlen;            /* length of (undoubled) quoted string */
  89.   char *term;            /* pointer to char after closing quote */
  90.   int ret;            /* returned by auxiliary routine */
  91.   int i;
  92.  
  93.   ret = fndqst(text,textlen,fdbp,"e,&qstlen,&term); /* find the string */
  94.   if (ret != CMxOK)
  95.     return(ret);        /* propagate errors */
  96.  
  97.   if (term == NULL)        /* not terminated...  */
  98.     return(CMxINC);        /* they might double final quote */
  99.  
  100.   if ((qstlen+1) > cmcsb._cmabc)
  101.     return(CMxAOVF);        /* no room to return string */
  102.  
  103.   *parselen = term - text;    /* set buffer consumption */
  104.  
  105.   for (i = 0; i < qstlen; i++)    /* copy chars to atom buffer */
  106.     if (*(++text) == quote)    /* quote char? (will fail if quoted) */
  107.       cmcsb._cmabp[i] = *(++text) & CC_CHR; /* yes, must be doubled */
  108.     else
  109.       cmcsb._cmabp[i] = *text & CC_CHR; /* otherwise copy it in */
  110.   cmcsb._cmabp[qstlen] = NULCHAR; /* tie off with null character */
  111.   cmcsb._cmflg |= CM_NAC;    /* don't let ccmd copy to atom */
  112.   value->_pvstr = cmcsb._cmabp;
  113.   return(CMxOK);        /* all done */
  114. }
  115.  
  116.  
  117.  
  118. /* qsthlp - Decide what the quote situation is, then give the appropriate
  119. ** message.
  120. **/
  121.  
  122. PASSEDSTATIC int
  123. qsthlp(text,textlen,fdbp,cust,lines)
  124. char *text;
  125. int textlen,cust;
  126. fdb *fdbp;
  127. int lines;
  128. {
  129.   brktab *btab;            /* break table in use */
  130.   int qmsg = TRUE;        /* use "Quote" message if TRUE */
  131.   int i;
  132.   char c;
  133.  
  134.   if (fdbp->_cmbrk != NULL)
  135.     btab = fdbp->_cmbrk;    /* get user break table */
  136.   else
  137.     btab = &qstbrk;
  138.  
  139.   for (i = 0; i < 16; i++)    /* check for matching 1st char brk array */
  140.     if (btab->_br1st[i] != qstbrk._br1st[i]) {
  141.       qmsg = FALSE;        /* no match - use other message */
  142.       break;
  143.     }
  144.     
  145.   if (qmsg)            /* standard quote set? */
  146.     cmxputs("quoted string");    /* use standard message */
  147.   else if (textlen == 0)    /* nonstandard quotes... delimiter given? */
  148.     cmxputs("delimited string"); /* use alternate message */
  149.   else {            /* quote known... include it in message */
  150.     cmxputs("string terminated by "); /* beginning of message */
  151.     c = *text & CC_CHR;    /* get quote character */
  152.     if (c == TAB)
  153.       cmxputs("tab");        /* take care of some special cases */
  154.     else if (c == NEWLINE)
  155.       cmxputs("newline");
  156.     else if (c == '\'')
  157.       cmxputs("\" \' \"");
  158.     else {
  159.       cmxputc('\'');        /* standard case... surround with squotes */
  160.       cmechx(c);
  161.       cmxputc('\'');
  162.     }
  163.   }
  164.   return(lines-1);
  165. }
  166.  
  167.  
  168.  
  169. /* qstcplt - Beep for anything but full completion when a proper
  170. ** quoted string is there but not yet terminated.  In that case,
  171. ** if the quote character is a space, beep.  Else return a single
  172. ** space as completion text.
  173. **/
  174.  
  175. PASSEDSTATIC int
  176. qstcplt(text,textlen,fdbp,full,cplt,cpltlen)
  177. char *text,**cplt;
  178. int textlen,full,*cpltlen;
  179. fdb *fdbp;
  180. {
  181.   char quote;            /* character used as quote */
  182.   int qstlen;            /* length of (undoubled) quoted string */
  183.   char *term;            /* pointer to char after closing quote */
  184.   int ret;            /* returned by auxiliary routine */
  185.  
  186.   ret = fndqst(text,textlen,fdbp,"e,&qstlen,&term); /* find the string */
  187.  
  188.   *cplt = NULL;            /* no completion text */
  189.   if (!full || (ret == CMxINC)) /* partial completion or no closing quote? */
  190.     return(CMP_BEL);        /* then just beep at them */
  191.   else if (quote == SPACE)    /* also beep if quote char is space */
  192.     return(CMP_BEL);
  193.   else
  194.     return(CMP_SPC | CMP_GO);    /* otherwise, stuff a space and wakeup */
  195. }
  196.  
  197.  
  198.  
  199. /* fndqst - Auxiliary routine for quoted string handlers.
  200. **
  201. ** Purpose:
  202. **   Isolate a quoted string in the given text.
  203. **
  204. ** Input arguments:
  205. **   text - A pointer to the text to be scanned.
  206. **   textlen - The number of chars to be scanned.
  207. **   fdbp - A pointer to the FDB for the current parse.
  208. **
  209. ** Output arguments:
  210. **   quote - The character being used for quoting.
  211. **   qstlen - The number of chars in the string (counting doubled quot
  212. **     characters only once, and not counting opening and closing
  213. **     quotes).
  214. **   term - A pointer to the character terminating the field, that is,
  215. **     following the closing quote (not the closing quote itself).  NULL
  216. **     if there is no such character (the text ran out).
  217. **
  218. ** Returns: Standard return code.
  219. **/
  220.  
  221. static int
  222. fndqst(char *text, int textlen, fdb *fdbp, char *quote,
  223.        int *qstlen, char **term)
  224. {
  225.   int qseen = FALSE;        /* TRUE when last char was a quote char */
  226.   char c;            /* characters from text */
  227.   brktab *btab;            /* break table for the parse */
  228.  
  229.   if (textlen == 0)
  230.     return(CMxINC);        /* nothing to parse */
  231.  
  232.   if ((btab = fdbp->_cmbrk) == NULL) /* get supplied break table */
  233.     btab = &qstbrk;        /* or use default */
  234.  
  235.   *qstlen = 0;            /* start length count at zero */
  236.   *quote = *text++;        /* pick up quote character */
  237.   textlen--;            /* and count it */
  238.   
  239.   if ((*quote & CC_QUO) == 0) {    /* first char unquoted? */
  240.     if (BREAK1(btab,*quote))    /* and a 1st position break char? */
  241.       return(QSTxQC);        /* bad quote character */
  242.   }
  243.   else
  244.     *quote &= CC_CHR;        /* turn off quoted flag in returned char */
  245.  
  246.   while (textlen-- > 0) {    /* scan characters */
  247.     c = *text++;        /* pick up next char */
  248.     if ((c & CC_CHR) == *quote) /* quote character? */
  249.       if (qseen) {        /* second in a doubled pair? */
  250.     (*qstlen)++;        /* yup, bump length count */
  251.     qseen = FALSE;        /* and turn off flag */
  252.       }
  253.       else
  254.     qseen = TRUE;        /* by itself - set flag */
  255.  
  256.     else            /* not a quote */
  257.       if (qseen) {        /* following a quote? */
  258.     *term = text-1;        /* yup, it's the terminator */
  259.     return(CMxOK);        /* so we're done */
  260.       }
  261.       else {            /* otherwise part of the string */
  262.     if ((c & CC_QUO) == 0)    /* if it's unquoted */
  263.           if (BREAKR(btab,c))    /* make sure it's allowed */
  264.         return(QSTxBC);
  265.     (*qstlen)++;        /* ok, bump count */
  266.       }
  267.   }
  268.   *term = NULL;            /* fall thru when no terminator present */
  269.   if (qseen)
  270.     return(CMxOK);        /* last char was quote - it's complete */
  271.   else
  272.     return(CMxINC);        /* else still waiting */
  273. }
  274.