File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / sntp / libopts / cook.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 7 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /**
    2:  * \file cook.c
    3:  *
    4:  *  Time-stamp:      "2011-03-12 15:05:26 bkorb"
    5:  *
    6:  *  This file contains the routines that deal with processing quoted strings
    7:  *  into an internal format.
    8:  *
    9:  *  This file is part of AutoOpts, a companion to AutoGen.
   10:  *  AutoOpts is free software.
   11:  *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
   12:  *
   13:  *  AutoOpts is available under any one of two licenses.  The license
   14:  *  in use must be one of these two and the choice is under the control
   15:  *  of the user of the license.
   16:  *
   17:  *   The GNU Lesser General Public License, version 3 or later
   18:  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
   19:  *
   20:  *   The Modified Berkeley Software Distribution License
   21:  *      See the file "COPYING.mbsd"
   22:  *
   23:  *  These files have the following md5sums:
   24:  *
   25:  *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
   26:  *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
   27:  *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
   28:  */
   29: 
   30: /* = = = START-STATIC-FORWARD = = = */
   31: static ag_bool
   32: contiguous_quote(char ** pps, char * pq, int * lnct_p);
   33: /* = = = END-STATIC-FORWARD = = = */
   34: 
   35: /*=export_func  ao_string_cook_escape_char
   36:  * private:
   37:  *
   38:  * what:  escape-process a string fragment
   39:  * arg:   + char const*  + pzScan  + points to character after the escape +
   40:  * arg:   + char*        + pRes    + Where to put the result byte +
   41:  * arg:   + unsigned int + nl_ch   + replacement char if scanned char is \n +
   42:  *
   43:  * ret-type: unsigned int
   44:  * ret-desc: The number of bytes consumed processing the escaped character.
   45:  *
   46:  * doc:
   47:  *
   48:  *  This function converts "t" into "\t" and all your other favorite
   49:  *  escapes, including numeric ones:  hex and ocatal, too.
   50:  *  The returned result tells the caller how far to advance the
   51:  *  scan pointer (passed in).  The default is to just pass through the
   52:  *  escaped character and advance the scan by one.
   53:  *
   54:  *  Some applications need to keep an escaped newline, others need to
   55:  *  suppress it.  This is accomplished by supplying a '\n' replacement
   56:  *  character that is different from \n, if need be.  For example, use
   57:  *  0x7F and never emit a 0x7F.
   58:  *
   59:  * err:  @code{NULL} is returned if the string is mal-formed.
   60: =*/
   61: unsigned int
   62: ao_string_cook_escape_char( char const* pzIn, char* pRes, u_int nl )
   63: {
   64:     unsigned int  res = 1;
   65: 
   66:     switch (*pRes = *pzIn++) {
   67:     case NUL:         /* NUL - end of input string */
   68:         return 0;
   69:     case '\r':
   70:         if (*pzIn != '\n')
   71:             return 1;
   72:         res++;
   73:         /* FALLTHROUGH */
   74:     case '\n':        /* NL  - emit newline        */
   75:         *pRes = (char)nl;
   76:         return res;
   77: 
   78:     case 'a': *pRes = '\a'; break;
   79:     case 'b': *pRes = '\b'; break;
   80:     case 'f': *pRes = '\f'; break;
   81:     case 'n': *pRes = '\n'; break;
   82:     case 'r': *pRes = '\r'; break;
   83:     case 't': *pRes = '\t'; break;
   84:     case 'v': *pRes = '\v'; break;
   85: 
   86:     case 'x':
   87:     case 'X':         /* HEX Escape       */
   88:         if (IS_HEX_DIGIT_CHAR(*pzIn))  {
   89:             char z[4], *pz = z;
   90: 
   91:             do *(pz++) = *(pzIn++);
   92:             while (IS_HEX_DIGIT_CHAR(*pzIn) && (pz < z + 2));
   93:             *pz = NUL;
   94:             *pRes = (unsigned char)strtoul(z, NULL, 16);
   95:             res += pz - z;
   96:         }
   97:         break;
   98: 
   99:     case '0': case '1': case '2': case '3':
  100:     case '4': case '5': case '6': case '7':
  101:     {
  102:         /*
  103:          *  IF the character copied was an octal digit,
  104:          *  THEN set the output character to an octal value
  105:          */
  106:         char z[4], *pz = z + 1;
  107:         unsigned long val;
  108:         z[0] = *pRes;
  109: 
  110:         while (IS_OCT_DIGIT_CHAR(*pzIn) && (pz < z + 3))
  111:             *(pz++) = *(pzIn++);
  112:         *pz = NUL;
  113:         val = strtoul(z, NULL, 8);
  114:         if (val > 0xFF)
  115:             val = 0xFF;
  116:         *pRes = (unsigned char)val;
  117:         res = pz - z;
  118:         break;
  119:     }
  120: 
  121:     default: ;
  122:     }
  123: 
  124:     return res;
  125: }
  126: 
  127: 
  128: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  129:  *
  130:  *  A quoted string has been found.
  131:  *  Find the end of it and compress any escape sequences.
  132:  */
  133: static ag_bool
  134: contiguous_quote(char ** pps, char * pq, int * lnct_p)
  135: {
  136:     char * ps = *pps + 1;
  137: 
  138:     for (;;) {
  139:         while (IS_WHITESPACE_CHAR(*ps))
  140:             if (*(ps++) == '\n')
  141:                 (*lnct_p)++;
  142: 
  143:         /*
  144:          *  IF the next character is a quote character,
  145:          *  THEN we will concatenate the strings.
  146:          */
  147:         switch (*ps) {
  148:         case '"':
  149:         case '\'':
  150:             *pq  = *(ps++);  /* assign new quote character and return */
  151:             *pps = ps;
  152:             return AG_TRUE;
  153: 
  154:         case '/':
  155:             /*
  156:              *  Allow for a comment embedded in the concatenated string.
  157:              */
  158:             switch (ps[1]) {
  159:             default:
  160:                 *pps = NULL;
  161:                 return AG_FALSE;
  162: 
  163:             case '/':
  164:                 /*
  165:                  *  Skip to end of line
  166:                  */
  167:                 ps = strchr(ps, '\n');
  168:                 if (ps == NULL) {
  169:                     *pps = NULL;
  170:                     return AG_FALSE;
  171:                 }
  172:                 break;
  173: 
  174:             case '*':
  175:             {
  176:                 char* p = strstr( ps+2, "*/" );
  177:                 /*
  178:                  *  Skip to terminating star slash
  179:                  */
  180:                 if (p == NULL) {
  181:                     *pps = NULL;
  182:                     return AG_FALSE;
  183:                 }
  184: 
  185:                 while (ps < p) {
  186:                     if (*(ps++) == '\n')
  187:                         (*lnct_p)++;
  188:                 }
  189: 
  190:                 ps = p + 2;
  191:             }
  192:             }
  193:             continue;
  194: 
  195:         default:
  196:             /*
  197:              *  The next non-whitespace character is not a quote.
  198:              *  The series of quoted strings has come to an end.
  199:              */
  200:             *pps = ps;
  201:             return AG_FALSE;
  202:         }
  203:     }
  204: }
  205: 
  206: /*=export_func  ao_string_cook
  207:  * private:
  208:  *
  209:  * what:  concatenate and escape-process strings
  210:  * arg:   + char* + pzScan  + The *MODIFIABLE* input buffer +
  211:  * arg:   + int*  + lnct_p  + The (possibly NULL) pointer to a line count +
  212:  *
  213:  * ret-type: char*
  214:  * ret-desc: The address of the text following the processed strings.
  215:  *           The return value is NULL if the strings are ill-formed.
  216:  *
  217:  * doc:
  218:  *
  219:  *  A series of one or more quoted strings are concatenated together.
  220:  *  If they are quoted with double quotes (@code{"}), then backslash
  221:  *  escapes are processed per the C programming language.  If they are
  222:  *  single quote strings, then the backslashes are honored only when they
  223:  *  precede another backslash or a single quote character.
  224:  *
  225:  * err:  @code{NULL} is returned if the string(s) is/are mal-formed.
  226: =*/
  227: char *
  228: ao_string_cook(char * pzScan, int * lnct_p)
  229: {
  230:     int   l = 0;
  231:     char  q = *pzScan;
  232: 
  233:     /*
  234:      *  It is a quoted string.  Process the escape sequence characters
  235:      *  (in the set "abfnrtv") and make sure we find a closing quote.
  236:      */
  237:     char* pzD = pzScan++;
  238:     char* pzS = pzScan;
  239: 
  240:     if (lnct_p == NULL)
  241:         lnct_p = &l;
  242: 
  243:     for (;;) {
  244:         /*
  245:          *  IF the next character is the quote character, THEN we may end the
  246:          *  string.  We end it unless the next non-blank character *after* the
  247:          *  string happens to also be a quote.  If it is, then we will change
  248:          *  our quote character to the new quote character and continue
  249:          *  condensing text.
  250:          */
  251:         while (*pzS == q) {
  252:             *pzD = NUL; /* This is probably the end of the line */
  253:             if (! contiguous_quote(&pzS, &q, lnct_p))
  254:                 return pzS;
  255:         }
  256: 
  257:         /*
  258:          *  We are inside a quoted string.  Copy text.
  259:          */
  260:         switch (*(pzD++) = *(pzS++)) {
  261:         case NUL:
  262:             return NULL;
  263: 
  264:         case '\n':
  265:             (*lnct_p)++;
  266:             break;
  267: 
  268:         case '\\':
  269:             /*
  270:              *  IF we are escaping a new line,
  271:              *  THEN drop both the escape and the newline from
  272:              *       the result string.
  273:              */
  274:             if (*pzS == '\n') {
  275:                 pzS++;
  276:                 pzD--;
  277:                 (*lnct_p)++;
  278:             }
  279: 
  280:             /*
  281:              *  ELSE IF the quote character is '"' or '`',
  282:              *  THEN we do the full escape character processing
  283:              */
  284:             else if (q != '\'') {
  285:                 int ct = ao_string_cook_escape_char( pzS, pzD-1, (u_int)'\n' );
  286:                 if (ct == 0)
  287:                     return NULL;
  288: 
  289:                 pzS += ct;
  290:             }     /* if (q != '\'')                  */
  291: 
  292:             /*
  293:              *  OTHERWISE, we only process "\\", "\'" and "\#" sequences.
  294:              *  The latter only to easily hide preprocessing directives.
  295:              */
  296:             else switch (*pzS) {
  297:             case '\\':
  298:             case '\'':
  299:             case '#':
  300:                 pzD[-1] = *pzS++;
  301:             }
  302:         }     /* switch (*(pzD++) = *(pzS++))    */
  303:     }         /* for (;;)                        */
  304: }
  305: /*
  306:  * Local Variables:
  307:  * mode: C
  308:  * c-file-style: "stroustrup"
  309:  * indent-tabs-mode: nil
  310:  * End:
  311:  * end of autoopts/cook.c */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>