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