Annotation of embedaddon/ntp/sntp/libopts/cook.c, revision 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>