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 39typedef 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 56struct 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 71static inline isc_result_t 72grow_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 89isc_result_t 90isc_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 124void 125isc_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 146unsigned int 147isc_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 157void 158isc_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 168void 169isc_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 179void 180isc_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 191static inline isc_result_t 192new_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 226isc_result_t 227isc_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 247isc_result_t 248isc_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 262isc_result_t 263isc_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 277isc_result_t 278isc_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 303typedef 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 317static void 318pushback(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 329static isc_result_t 330pushandgrow(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 352isc_result_t 353isc_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 795isc_result_t 796isc_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 831isc_result_t 832isc_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 858void 859isc_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 880void 881isc_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 902char * 903isc_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 915unsigned long 916isc_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 929isc_result_t 930isc_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 947isc_boolean_t 948isc_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} 960