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>