Return to lex.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc |
1.1 ! misho 1: /* ! 2: * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") ! 3: * Copyright (C) 1998-2003 Internet Software Consortium. ! 4: * ! 5: * Permission to use, copy, modify, and/or distribute this software for any ! 6: * purpose with or without fee is hereby granted, provided that the above ! 7: * copyright notice and this permission notice appear in all copies. ! 8: * ! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ! 10: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ! 11: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ! 12: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ! 13: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ! 14: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ! 15: * PERFORMANCE OF THIS SOFTWARE. ! 16: */ ! 17: ! 18: /* $Id: lex.c,v 1.86 2007/09/17 09:56:29 shane Exp $ */ ! 19: ! 20: /*! \file */ ! 21: ! 22: #include <config.h> ! 23: ! 24: #include <ctype.h> ! 25: #include <errno.h> ! 26: #include <stdlib.h> ! 27: ! 28: #include <isc/buffer.h> ! 29: #include <isc/file.h> ! 30: #include <isc/lex.h> ! 31: #include <isc/mem.h> ! 32: #include <isc/msgs.h> ! 33: #include <isc/parseint.h> ! 34: #include <isc/print.h> ! 35: #include <isc/stdio.h> ! 36: #include <isc/string.h> ! 37: #include <isc/util.h> ! 38: ! 39: typedef struct inputsource { ! 40: isc_result_t result; ! 41: isc_boolean_t is_file; ! 42: isc_boolean_t need_close; ! 43: isc_boolean_t at_eof; ! 44: isc_buffer_t * pushback; ! 45: unsigned int ignored; ! 46: void * input; ! 47: char * name; ! 48: unsigned long line; ! 49: unsigned long saved_line; ! 50: ISC_LINK(struct inputsource) link; ! 51: } inputsource; ! 52: ! 53: #define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!') ! 54: #define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC) ! 55: ! 56: struct isc_lex { ! 57: /* Unlocked. */ ! 58: unsigned int magic; ! 59: isc_mem_t * mctx; ! 60: size_t max_token; ! 61: char * data; ! 62: unsigned int comments; ! 63: isc_boolean_t comment_ok; ! 64: isc_boolean_t last_was_eol; ! 65: unsigned int paren_count; ! 66: unsigned int saved_paren_count; ! 67: isc_lexspecials_t specials; ! 68: LIST(struct inputsource) sources; ! 69: }; ! 70: ! 71: static inline isc_result_t ! 72: grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) { ! 73: char *new; ! 74: ! 75: new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1); ! 76: if (new == NULL) ! 77: return (ISC_R_NOMEMORY); ! 78: memcpy(new, lex->data, lex->max_token + 1); ! 79: *currp = new + (*currp - lex->data); ! 80: if (*prevp != NULL) ! 81: *prevp = new + (*prevp - lex->data); ! 82: isc_mem_put(lex->mctx, lex->data, lex->max_token + 1); ! 83: lex->data = new; ! 84: *remainingp += lex->max_token; ! 85: lex->max_token *= 2; ! 86: return (ISC_R_SUCCESS); ! 87: } ! 88: ! 89: isc_result_t ! 90: isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) { ! 91: isc_lex_t *lex; ! 92: ! 93: /* ! 94: * Create a lexer. ! 95: */ ! 96: ! 97: REQUIRE(lexp != NULL && *lexp == NULL); ! 98: REQUIRE(max_token > 0U); ! 99: ! 100: lex = isc_mem_get(mctx, sizeof(*lex)); ! 101: if (lex == NULL) ! 102: return (ISC_R_NOMEMORY); ! 103: lex->data = isc_mem_get(mctx, max_token + 1); ! 104: if (lex->data == NULL) { ! 105: isc_mem_put(mctx, lex, sizeof(*lex)); ! 106: return (ISC_R_NOMEMORY); ! 107: } ! 108: lex->mctx = mctx; ! 109: lex->max_token = max_token; ! 110: lex->comments = 0; ! 111: lex->comment_ok = ISC_TRUE; ! 112: lex->last_was_eol = ISC_TRUE; ! 113: lex->paren_count = 0; ! 114: lex->saved_paren_count = 0; ! 115: memset(lex->specials, 0, 256); ! 116: INIT_LIST(lex->sources); ! 117: lex->magic = LEX_MAGIC; ! 118: ! 119: *lexp = lex; ! 120: ! 121: return (ISC_R_SUCCESS); ! 122: } ! 123: ! 124: void ! 125: isc_lex_destroy(isc_lex_t **lexp) { ! 126: isc_lex_t *lex; ! 127: ! 128: /* ! 129: * Destroy the lexer. ! 130: */ ! 131: ! 132: REQUIRE(lexp != NULL); ! 133: lex = *lexp; ! 134: REQUIRE(VALID_LEX(lex)); ! 135: ! 136: while (!EMPTY(lex->sources)) ! 137: RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS); ! 138: if (lex->data != NULL) ! 139: isc_mem_put(lex->mctx, lex->data, lex->max_token + 1); ! 140: lex->magic = 0; ! 141: isc_mem_put(lex->mctx, lex, sizeof(*lex)); ! 142: ! 143: *lexp = NULL; ! 144: } ! 145: ! 146: unsigned int ! 147: isc_lex_getcomments(isc_lex_t *lex) { ! 148: /* ! 149: * Return the current lexer commenting styles. ! 150: */ ! 151: ! 152: REQUIRE(VALID_LEX(lex)); ! 153: ! 154: return (lex->comments); ! 155: } ! 156: ! 157: void ! 158: isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) { ! 159: /* ! 160: * Set allowed lexer commenting styles. ! 161: */ ! 162: ! 163: REQUIRE(VALID_LEX(lex)); ! 164: ! 165: lex->comments = comments; ! 166: } ! 167: ! 168: void ! 169: isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) { ! 170: /* ! 171: * Put the current list of specials into 'specials'. ! 172: */ ! 173: ! 174: REQUIRE(VALID_LEX(lex)); ! 175: ! 176: memcpy(specials, lex->specials, 256); ! 177: } ! 178: ! 179: void ! 180: isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) { ! 181: /* ! 182: * The characters in 'specials' are returned as tokens. Along with ! 183: * whitespace, they delimit strings and numbers. ! 184: */ ! 185: ! 186: REQUIRE(VALID_LEX(lex)); ! 187: ! 188: memcpy(lex->specials, specials, 256); ! 189: } ! 190: ! 191: static inline isc_result_t ! 192: new_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close, ! 193: void *input, const char *name) ! 194: { ! 195: inputsource *source; ! 196: isc_result_t result; ! 197: ! 198: source = isc_mem_get(lex->mctx, sizeof(*source)); ! 199: if (source == NULL) ! 200: return (ISC_R_NOMEMORY); ! 201: source->result = ISC_R_SUCCESS; ! 202: source->is_file = is_file; ! 203: source->need_close = need_close; ! 204: source->at_eof = ISC_FALSE; ! 205: source->input = input; ! 206: source->name = isc_mem_strdup(lex->mctx, name); ! 207: if (source->name == NULL) { ! 208: isc_mem_put(lex->mctx, source, sizeof(*source)); ! 209: return (ISC_R_NOMEMORY); ! 210: } ! 211: source->pushback = NULL; ! 212: result = isc_buffer_allocate(lex->mctx, &source->pushback, ! 213: lex->max_token); ! 214: if (result != ISC_R_SUCCESS) { ! 215: isc_mem_free(lex->mctx, source->name); ! 216: isc_mem_put(lex->mctx, source, sizeof(*source)); ! 217: return (result); ! 218: } ! 219: source->ignored = 0; ! 220: source->line = 1; ! 221: ISC_LIST_INITANDPREPEND(lex->sources, source, link); ! 222: ! 223: return (ISC_R_SUCCESS); ! 224: } ! 225: ! 226: isc_result_t ! 227: isc_lex_openfile(isc_lex_t *lex, const char *filename) { ! 228: isc_result_t result; ! 229: FILE *stream = NULL; ! 230: ! 231: /* ! 232: * Open 'filename' and make it the current input source for 'lex'. ! 233: */ ! 234: ! 235: REQUIRE(VALID_LEX(lex)); ! 236: ! 237: result = isc_stdio_open(filename, "r", &stream); ! 238: if (result != ISC_R_SUCCESS) ! 239: return (result); ! 240: ! 241: result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename); ! 242: if (result != ISC_R_SUCCESS) ! 243: (void)fclose(stream); ! 244: return (result); ! 245: } ! 246: ! 247: isc_result_t ! 248: isc_lex_openstream(isc_lex_t *lex, FILE *stream) { ! 249: char name[128]; ! 250: ! 251: /* ! 252: * Make 'stream' the current input source for 'lex'. ! 253: */ ! 254: ! 255: REQUIRE(VALID_LEX(lex)); ! 256: ! 257: snprintf(name, sizeof(name), "stream-%p", stream); ! 258: ! 259: return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name)); ! 260: } ! 261: ! 262: isc_result_t ! 263: isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) { ! 264: char name[128]; ! 265: ! 266: /* ! 267: * Make 'buffer' the current input source for 'lex'. ! 268: */ ! 269: ! 270: REQUIRE(VALID_LEX(lex)); ! 271: ! 272: snprintf(name, sizeof(name), "buffer-%p", buffer); ! 273: ! 274: return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name)); ! 275: } ! 276: ! 277: isc_result_t ! 278: isc_lex_close(isc_lex_t *lex) { ! 279: inputsource *source; ! 280: ! 281: /* ! 282: * Close the most recently opened object (i.e. file or buffer). ! 283: */ ! 284: ! 285: REQUIRE(VALID_LEX(lex)); ! 286: ! 287: source = HEAD(lex->sources); ! 288: if (source == NULL) ! 289: return (ISC_R_NOMORE); ! 290: ! 291: ISC_LIST_UNLINK(lex->sources, source, link); ! 292: if (source->is_file) { ! 293: if (source->need_close) ! 294: (void)fclose((FILE *)(source->input)); ! 295: } ! 296: isc_mem_free(lex->mctx, source->name); ! 297: isc_buffer_free(&source->pushback); ! 298: isc_mem_put(lex->mctx, source, sizeof(*source)); ! 299: ! 300: return (ISC_R_SUCCESS); ! 301: } ! 302: ! 303: typedef enum { ! 304: lexstate_start, ! 305: lexstate_crlf, ! 306: lexstate_string, ! 307: lexstate_number, ! 308: lexstate_maybecomment, ! 309: lexstate_ccomment, ! 310: lexstate_ccommentend, ! 311: lexstate_eatline, ! 312: lexstate_qstring ! 313: } lexstate; ! 314: ! 315: #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL) ! 316: ! 317: static void ! 318: pushback(inputsource *source, int c) { ! 319: REQUIRE(source->pushback->current > 0); ! 320: if (c == EOF) { ! 321: source->at_eof = ISC_FALSE; ! 322: return; ! 323: } ! 324: source->pushback->current--; ! 325: if (c == '\n') ! 326: source->line--; ! 327: } ! 328: ! 329: static isc_result_t ! 330: pushandgrow(isc_lex_t *lex, inputsource *source, int c) { ! 331: if (isc_buffer_availablelength(source->pushback) == 0) { ! 332: isc_buffer_t *tbuf = NULL; ! 333: unsigned int oldlen; ! 334: isc_region_t used; ! 335: isc_result_t result; ! 336: ! 337: oldlen = isc_buffer_length(source->pushback); ! 338: result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2); ! 339: if (result != ISC_R_SUCCESS) ! 340: return (result); ! 341: isc_buffer_usedregion(source->pushback, &used); ! 342: result = isc_buffer_copyregion(tbuf, &used); ! 343: INSIST(result == ISC_R_SUCCESS); ! 344: tbuf->current = source->pushback->current; ! 345: isc_buffer_free(&source->pushback); ! 346: source->pushback = tbuf; ! 347: } ! 348: isc_buffer_putuint8(source->pushback, (isc_uint8_t)c); ! 349: return (ISC_R_SUCCESS); ! 350: } ! 351: ! 352: isc_result_t ! 353: isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { ! 354: inputsource *source; ! 355: int c; ! 356: isc_boolean_t done = ISC_FALSE; ! 357: isc_boolean_t no_comments = ISC_FALSE; ! 358: isc_boolean_t escaped = ISC_FALSE; ! 359: lexstate state = lexstate_start; ! 360: lexstate saved_state = lexstate_start; ! 361: isc_buffer_t *buffer; ! 362: FILE *stream; ! 363: char *curr, *prev; ! 364: size_t remaining; ! 365: isc_uint32_t as_ulong; ! 366: unsigned int saved_options; ! 367: isc_result_t result; ! 368: ! 369: /* ! 370: * Get the next token. ! 371: */ ! 372: ! 373: REQUIRE(VALID_LEX(lex)); ! 374: source = HEAD(lex->sources); ! 375: REQUIRE(tokenp != NULL); ! 376: ! 377: if (source == NULL) { ! 378: if ((options & ISC_LEXOPT_NOMORE) != 0) { ! 379: tokenp->type = isc_tokentype_nomore; ! 380: return (ISC_R_SUCCESS); ! 381: } ! 382: return (ISC_R_NOMORE); ! 383: } ! 384: ! 385: if (source->result != ISC_R_SUCCESS) ! 386: return (source->result); ! 387: ! 388: lex->saved_paren_count = lex->paren_count; ! 389: source->saved_line = source->line; ! 390: ! 391: if (isc_buffer_remaininglength(source->pushback) == 0 && ! 392: source->at_eof) ! 393: { ! 394: if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && ! 395: lex->paren_count != 0) { ! 396: lex->paren_count = 0; ! 397: return (ISC_R_UNBALANCED); ! 398: } ! 399: if ((options & ISC_LEXOPT_EOF) != 0) { ! 400: tokenp->type = isc_tokentype_eof; ! 401: return (ISC_R_SUCCESS); ! 402: } ! 403: return (ISC_R_EOF); ! 404: } ! 405: ! 406: isc_buffer_compact(source->pushback); ! 407: ! 408: saved_options = options; ! 409: if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0) ! 410: options &= ~IWSEOL; ! 411: ! 412: curr = lex->data; ! 413: *curr = '\0'; ! 414: ! 415: prev = NULL; ! 416: remaining = lex->max_token; ! 417: ! 418: #ifdef HAVE_FLOCKFILE ! 419: if (source->is_file) ! 420: flockfile(source->input); ! 421: #endif ! 422: ! 423: do { ! 424: if (isc_buffer_remaininglength(source->pushback) == 0) { ! 425: if (source->is_file) { ! 426: stream = source->input; ! 427: ! 428: #if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED) ! 429: c = getc_unlocked(stream); ! 430: #else ! 431: c = getc(stream); ! 432: #endif ! 433: if (c == EOF) { ! 434: if (ferror(stream)) { ! 435: source->result = ISC_R_IOERROR; ! 436: result = source->result; ! 437: goto done; ! 438: } ! 439: source->at_eof = ISC_TRUE; ! 440: } ! 441: } else { ! 442: buffer = source->input; ! 443: ! 444: if (buffer->current == buffer->used) { ! 445: c = EOF; ! 446: source->at_eof = ISC_TRUE; ! 447: } else { ! 448: c = *((char *)buffer->base + ! 449: buffer->current); ! 450: buffer->current++; ! 451: } ! 452: } ! 453: if (c != EOF) { ! 454: source->result = pushandgrow(lex, source, c); ! 455: if (source->result != ISC_R_SUCCESS) { ! 456: result = source->result; ! 457: goto done; ! 458: } ! 459: } ! 460: } ! 461: ! 462: if (!source->at_eof) { ! 463: if (state == lexstate_start) ! 464: /* Token has not started yet. */ ! 465: source->ignored = ! 466: isc_buffer_consumedlength(source->pushback); ! 467: c = isc_buffer_getuint8(source->pushback); ! 468: } else { ! 469: c = EOF; ! 470: } ! 471: ! 472: if (c == '\n') ! 473: source->line++; ! 474: ! 475: if (lex->comment_ok && !no_comments) { ! 476: if (!escaped && c == ';' && ! 477: ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE) ! 478: != 0)) { ! 479: saved_state = state; ! 480: state = lexstate_eatline; ! 481: no_comments = ISC_TRUE; ! 482: continue; ! 483: } else if (c == '/' && ! 484: (lex->comments & ! 485: (ISC_LEXCOMMENT_C| ! 486: ISC_LEXCOMMENT_CPLUSPLUS)) != 0) { ! 487: saved_state = state; ! 488: state = lexstate_maybecomment; ! 489: no_comments = ISC_TRUE; ! 490: continue; ! 491: } else if (c == '#' && ! 492: ((lex->comments & ISC_LEXCOMMENT_SHELL) ! 493: != 0)) { ! 494: saved_state = state; ! 495: state = lexstate_eatline; ! 496: no_comments = ISC_TRUE; ! 497: continue; ! 498: } ! 499: } ! 500: ! 501: no_read: ! 502: /* INSIST(c == EOF || (c >= 0 && c <= 255)); */ ! 503: switch (state) { ! 504: case lexstate_start: ! 505: if (c == EOF) { ! 506: lex->last_was_eol = ISC_FALSE; ! 507: if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && ! 508: lex->paren_count != 0) { ! 509: lex->paren_count = 0; ! 510: result = ISC_R_UNBALANCED; ! 511: goto done; ! 512: } ! 513: if ((options & ISC_LEXOPT_EOF) == 0) { ! 514: result = ISC_R_EOF; ! 515: goto done; ! 516: } ! 517: tokenp->type = isc_tokentype_eof; ! 518: done = ISC_TRUE; ! 519: } else if (c == ' ' || c == '\t') { ! 520: if (lex->last_was_eol && ! 521: (options & ISC_LEXOPT_INITIALWS) ! 522: != 0) { ! 523: lex->last_was_eol = ISC_FALSE; ! 524: tokenp->type = isc_tokentype_initialws; ! 525: tokenp->value.as_char = c; ! 526: done = ISC_TRUE; ! 527: } ! 528: } else if (c == '\n') { ! 529: if ((options & ISC_LEXOPT_EOL) != 0) { ! 530: tokenp->type = isc_tokentype_eol; ! 531: done = ISC_TRUE; ! 532: } ! 533: lex->last_was_eol = ISC_TRUE; ! 534: } else if (c == '\r') { ! 535: if ((options & ISC_LEXOPT_EOL) != 0) ! 536: state = lexstate_crlf; ! 537: } else if (c == '"' && ! 538: (options & ISC_LEXOPT_QSTRING) != 0) { ! 539: lex->last_was_eol = ISC_FALSE; ! 540: no_comments = ISC_TRUE; ! 541: state = lexstate_qstring; ! 542: } else if (lex->specials[c]) { ! 543: lex->last_was_eol = ISC_FALSE; ! 544: if ((c == '(' || c == ')') && ! 545: (options & ISC_LEXOPT_DNSMULTILINE) != 0) { ! 546: if (c == '(') { ! 547: if (lex->paren_count == 0) ! 548: options &= ~IWSEOL; ! 549: lex->paren_count++; ! 550: } else { ! 551: if (lex->paren_count == 0) { ! 552: result = ISC_R_UNBALANCED; ! 553: goto done; ! 554: } ! 555: lex->paren_count--; ! 556: if (lex->paren_count == 0) ! 557: options = ! 558: saved_options; ! 559: } ! 560: continue; ! 561: } ! 562: tokenp->type = isc_tokentype_special; ! 563: tokenp->value.as_char = c; ! 564: done = ISC_TRUE; ! 565: } else if (isdigit((unsigned char)c) && ! 566: (options & ISC_LEXOPT_NUMBER) != 0) { ! 567: lex->last_was_eol = ISC_FALSE; ! 568: if ((options & ISC_LEXOPT_OCTAL) != 0 && ! 569: (c == '8' || c == '9')) ! 570: state = lexstate_string; ! 571: else ! 572: state = lexstate_number; ! 573: goto no_read; ! 574: } else { ! 575: lex->last_was_eol = ISC_FALSE; ! 576: state = lexstate_string; ! 577: goto no_read; ! 578: } ! 579: break; ! 580: case lexstate_crlf: ! 581: if (c != '\n') ! 582: pushback(source, c); ! 583: tokenp->type = isc_tokentype_eol; ! 584: done = ISC_TRUE; ! 585: lex->last_was_eol = ISC_TRUE; ! 586: break; ! 587: case lexstate_number: ! 588: if (c == EOF || !isdigit((unsigned char)c)) { ! 589: if (c == ' ' || c == '\t' || c == '\r' || ! 590: c == '\n' || c == EOF || ! 591: lex->specials[c]) { ! 592: int base; ! 593: if ((options & ISC_LEXOPT_OCTAL) != 0) ! 594: base = 8; ! 595: else if ((options & ISC_LEXOPT_CNUMBER) != 0) ! 596: base = 0; ! 597: else ! 598: base = 10; ! 599: pushback(source, c); ! 600: ! 601: result = isc_parse_uint32(&as_ulong, ! 602: lex->data, ! 603: base); ! 604: if (result == ISC_R_SUCCESS) { ! 605: tokenp->type = ! 606: isc_tokentype_number; ! 607: tokenp->value.as_ulong = ! 608: as_ulong; ! 609: } else if (result == ISC_R_BADNUMBER) { ! 610: isc_tokenvalue_t *v; ! 611: ! 612: tokenp->type = ! 613: isc_tokentype_string; ! 614: v = &(tokenp->value); ! 615: v->as_textregion.base = ! 616: lex->data; ! 617: v->as_textregion.length = ! 618: lex->max_token - ! 619: remaining; ! 620: } else ! 621: goto done; ! 622: done = ISC_TRUE; ! 623: continue; ! 624: } else if (!(options & ISC_LEXOPT_CNUMBER) || ! 625: ((c != 'x' && c != 'X') || ! 626: (curr != &lex->data[1]) || ! 627: (lex->data[0] != '0'))) { ! 628: /* Above test supports hex numbers */ ! 629: state = lexstate_string; ! 630: } ! 631: } else if ((options & ISC_LEXOPT_OCTAL) != 0 && ! 632: (c == '8' || c == '9')) { ! 633: state = lexstate_string; ! 634: } ! 635: if (remaining == 0U) { ! 636: result = grow_data(lex, &remaining, ! 637: &curr, &prev); ! 638: if (result != ISC_R_SUCCESS) ! 639: goto done; ! 640: } ! 641: INSIST(remaining > 0U); ! 642: *curr++ = c; ! 643: *curr = '\0'; ! 644: remaining--; ! 645: break; ! 646: case lexstate_string: ! 647: /* ! 648: * EOF needs to be checked before lex->specials[c] ! 649: * as lex->specials[EOF] is not a good idea. ! 650: */ ! 651: if (c == '\r' || c == '\n' || c == EOF || ! 652: (!escaped && ! 653: (c == ' ' || c == '\t' || lex->specials[c]))) { ! 654: pushback(source, c); ! 655: if (source->result != ISC_R_SUCCESS) { ! 656: result = source->result; ! 657: goto done; ! 658: } ! 659: tokenp->type = isc_tokentype_string; ! 660: tokenp->value.as_textregion.base = lex->data; ! 661: tokenp->value.as_textregion.length = ! 662: lex->max_token - remaining; ! 663: done = ISC_TRUE; ! 664: continue; ! 665: } ! 666: if ((options & ISC_LEXOPT_ESCAPE) != 0) ! 667: escaped = (!escaped && c == '\\') ? ! 668: ISC_TRUE : ISC_FALSE; ! 669: if (remaining == 0U) { ! 670: result = grow_data(lex, &remaining, ! 671: &curr, &prev); ! 672: if (result != ISC_R_SUCCESS) ! 673: goto done; ! 674: } ! 675: INSIST(remaining > 0U); ! 676: *curr++ = c; ! 677: *curr = '\0'; ! 678: remaining--; ! 679: break; ! 680: case lexstate_maybecomment: ! 681: if (c == '*' && ! 682: (lex->comments & ISC_LEXCOMMENT_C) != 0) { ! 683: state = lexstate_ccomment; ! 684: continue; ! 685: } else if (c == '/' && ! 686: (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) { ! 687: state = lexstate_eatline; ! 688: continue; ! 689: } ! 690: pushback(source, c); ! 691: c = '/'; ! 692: no_comments = ISC_FALSE; ! 693: state = saved_state; ! 694: goto no_read; ! 695: case lexstate_ccomment: ! 696: if (c == EOF) { ! 697: result = ISC_R_UNEXPECTEDEND; ! 698: goto done; ! 699: } ! 700: if (c == '*') ! 701: state = lexstate_ccommentend; ! 702: break; ! 703: case lexstate_ccommentend: ! 704: if (c == EOF) { ! 705: result = ISC_R_UNEXPECTEDEND; ! 706: goto done; ! 707: } ! 708: if (c == '/') { ! 709: /* ! 710: * C-style comments become a single space. ! 711: * We do this to ensure that a comment will ! 712: * act as a delimiter for strings and ! 713: * numbers. ! 714: */ ! 715: c = ' '; ! 716: no_comments = ISC_FALSE; ! 717: state = saved_state; ! 718: goto no_read; ! 719: } else if (c != '*') ! 720: state = lexstate_ccomment; ! 721: break; ! 722: case lexstate_eatline: ! 723: if ((c == '\n') || (c == EOF)) { ! 724: no_comments = ISC_FALSE; ! 725: state = saved_state; ! 726: goto no_read; ! 727: } ! 728: break; ! 729: case lexstate_qstring: ! 730: if (c == EOF) { ! 731: result = ISC_R_UNEXPECTEDEND; ! 732: goto done; ! 733: } ! 734: if (c == '"') { ! 735: if (escaped) { ! 736: escaped = ISC_FALSE; ! 737: /* ! 738: * Overwrite the preceding backslash. ! 739: */ ! 740: INSIST(prev != NULL); ! 741: *prev = '"'; ! 742: } else { ! 743: tokenp->type = isc_tokentype_qstring; ! 744: tokenp->value.as_textregion.base = ! 745: lex->data; ! 746: tokenp->value.as_textregion.length = ! 747: lex->max_token - remaining; ! 748: no_comments = ISC_FALSE; ! 749: done = ISC_TRUE; ! 750: } ! 751: } else { ! 752: if (c == '\n' && !escaped && ! 753: (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) { ! 754: pushback(source, c); ! 755: result = ISC_R_UNBALANCEDQUOTES; ! 756: goto done; ! 757: } ! 758: if (c == '\\' && !escaped) ! 759: escaped = ISC_TRUE; ! 760: else ! 761: escaped = ISC_FALSE; ! 762: if (remaining == 0U) { ! 763: result = grow_data(lex, &remaining, ! 764: &curr, &prev); ! 765: if (result != ISC_R_SUCCESS) ! 766: goto done; ! 767: } ! 768: INSIST(remaining > 0U); ! 769: prev = curr; ! 770: *curr++ = c; ! 771: *curr = '\0'; ! 772: remaining--; ! 773: } ! 774: break; ! 775: default: ! 776: FATAL_ERROR(__FILE__, __LINE__, ! 777: isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX, ! 778: ISC_MSG_UNEXPECTEDSTATE, ! 779: "Unexpected state %d"), ! 780: state); ! 781: /* Does not return. */ ! 782: } ! 783: ! 784: } while (!done); ! 785: ! 786: result = ISC_R_SUCCESS; ! 787: done: ! 788: #ifdef HAVE_FLOCKFILE ! 789: if (source->is_file) ! 790: funlockfile(source->input); ! 791: #endif ! 792: return (result); ! 793: } ! 794: ! 795: isc_result_t ! 796: isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token, ! 797: isc_tokentype_t expect, isc_boolean_t eol) ! 798: { ! 799: unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ! 800: ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE; ! 801: isc_result_t result; ! 802: ! 803: if (expect == isc_tokentype_qstring) ! 804: options |= ISC_LEXOPT_QSTRING; ! 805: else if (expect == isc_tokentype_number) ! 806: options |= ISC_LEXOPT_NUMBER; ! 807: result = isc_lex_gettoken(lex, options, token); ! 808: if (result == ISC_R_RANGE) ! 809: isc_lex_ungettoken(lex, token); ! 810: if (result != ISC_R_SUCCESS) ! 811: return (result); ! 812: ! 813: if (eol && ((token->type == isc_tokentype_eol) || ! 814: (token->type == isc_tokentype_eof))) ! 815: return (ISC_R_SUCCESS); ! 816: if (token->type == isc_tokentype_string && ! 817: expect == isc_tokentype_qstring) ! 818: return (ISC_R_SUCCESS); ! 819: if (token->type != expect) { ! 820: isc_lex_ungettoken(lex, token); ! 821: if (token->type == isc_tokentype_eol || ! 822: token->type == isc_tokentype_eof) ! 823: return (ISC_R_UNEXPECTEDEND); ! 824: if (expect == isc_tokentype_number) ! 825: return (ISC_R_BADNUMBER); ! 826: return (ISC_R_UNEXPECTEDTOKEN); ! 827: } ! 828: return (ISC_R_SUCCESS); ! 829: } ! 830: ! 831: isc_result_t ! 832: isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol) ! 833: { ! 834: unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ! 835: ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE| ! 836: ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL; ! 837: isc_result_t result; ! 838: ! 839: result = isc_lex_gettoken(lex, options, token); ! 840: if (result == ISC_R_RANGE) ! 841: isc_lex_ungettoken(lex, token); ! 842: if (result != ISC_R_SUCCESS) ! 843: return (result); ! 844: ! 845: if (eol && ((token->type == isc_tokentype_eol) || ! 846: (token->type == isc_tokentype_eof))) ! 847: return (ISC_R_SUCCESS); ! 848: if (token->type != isc_tokentype_number) { ! 849: isc_lex_ungettoken(lex, token); ! 850: if (token->type == isc_tokentype_eol || ! 851: token->type == isc_tokentype_eof) ! 852: return (ISC_R_UNEXPECTEDEND); ! 853: return (ISC_R_BADNUMBER); ! 854: } ! 855: return (ISC_R_SUCCESS); ! 856: } ! 857: ! 858: void ! 859: isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) { ! 860: inputsource *source; ! 861: /* ! 862: * Unget the current token. ! 863: */ ! 864: ! 865: REQUIRE(VALID_LEX(lex)); ! 866: source = HEAD(lex->sources); ! 867: REQUIRE(source != NULL); ! 868: REQUIRE(tokenp != NULL); ! 869: REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 || ! 870: tokenp->type == isc_tokentype_eof); ! 871: ! 872: UNUSED(tokenp); ! 873: ! 874: isc_buffer_first(source->pushback); ! 875: lex->paren_count = lex->saved_paren_count; ! 876: source->line = source->saved_line; ! 877: source->at_eof = ISC_FALSE; ! 878: } ! 879: ! 880: void ! 881: isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r) ! 882: { ! 883: inputsource *source; ! 884: ! 885: REQUIRE(VALID_LEX(lex)); ! 886: source = HEAD(lex->sources); ! 887: REQUIRE(source != NULL); ! 888: REQUIRE(tokenp != NULL); ! 889: REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 || ! 890: tokenp->type == isc_tokentype_eof); ! 891: ! 892: UNUSED(tokenp); ! 893: ! 894: INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback)); ! 895: r->base = (unsigned char *)isc_buffer_base(source->pushback) + ! 896: source->ignored; ! 897: r->length = isc_buffer_consumedlength(source->pushback) - ! 898: source->ignored; ! 899: } ! 900: ! 901: ! 902: char * ! 903: isc_lex_getsourcename(isc_lex_t *lex) { ! 904: inputsource *source; ! 905: ! 906: REQUIRE(VALID_LEX(lex)); ! 907: source = HEAD(lex->sources); ! 908: ! 909: if (source == NULL) ! 910: return (NULL); ! 911: ! 912: return (source->name); ! 913: } ! 914: ! 915: unsigned long ! 916: isc_lex_getsourceline(isc_lex_t *lex) { ! 917: inputsource *source; ! 918: ! 919: REQUIRE(VALID_LEX(lex)); ! 920: source = HEAD(lex->sources); ! 921: ! 922: if (source == NULL) ! 923: return (0); ! 924: ! 925: return (source->line); ! 926: } ! 927: ! 928: ! 929: isc_result_t ! 930: isc_lex_setsourcename(isc_lex_t *lex, const char *name) { ! 931: inputsource *source; ! 932: char *newname; ! 933: ! 934: REQUIRE(VALID_LEX(lex)); ! 935: source = HEAD(lex->sources); ! 936: ! 937: if (source == NULL) ! 938: return(ISC_R_NOTFOUND); ! 939: newname = isc_mem_strdup(lex->mctx, name); ! 940: if (newname == NULL) ! 941: return (ISC_R_NOMEMORY); ! 942: isc_mem_free(lex->mctx, source->name); ! 943: source->name = newname; ! 944: return (ISC_R_SUCCESS); ! 945: } ! 946: ! 947: isc_boolean_t ! 948: isc_lex_isfile(isc_lex_t *lex) { ! 949: inputsource *source; ! 950: ! 951: REQUIRE(VALID_LEX(lex)); ! 952: ! 953: source = HEAD(lex->sources); ! 954: ! 955: if (source == NULL) ! 956: return (ISC_FALSE); ! 957: ! 958: return (source->is_file); ! 959: }