Annotation of embedaddon/ntp/lib/isc/lex.c, revision 1.1
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>