Return to cook.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / sntp / libopts |
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 */