Annotation of embedaddon/ntp/sntp/libopts/cook.c, revision 1.1.1.1

1.1       misho       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>