1 /* $NetBSD: lex.c,v 1.6 2019/10/17 16:47:01 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14 15 /*! \file */ 16 17 #include <config.h> 18 19 #include <ctype.h> 20 #include <errno.h> 21 #include <inttypes.h> 22 #include <stdbool.h> 23 #include <stdlib.h> 24 25 #include <isc/buffer.h> 26 #include <isc/file.h> 27 #include <isc/lex.h> 28 #include <isc/mem.h> 29 #include <isc/parseint.h> 30 #include <isc/print.h> 31 #include <isc/stdio.h> 32 #include <isc/string.h> 33 #include <isc/util.h> 34 35 typedef struct inputsource { 36 isc_result_t result; 37 bool is_file; 38 bool need_close; 39 bool at_eof; 40 bool last_was_eol; 41 isc_buffer_t * pushback; 42 unsigned int ignored; 43 void * input; 44 char * name; 45 unsigned long line; 46 unsigned long saved_line; 47 ISC_LINK(struct inputsource) link; 48 } inputsource; 49 50 #define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!') 51 #define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC) 52 53 struct isc_lex { 54 /* Unlocked. */ 55 unsigned int magic; 56 isc_mem_t * mctx; 57 size_t max_token; 58 char * data; 59 unsigned int comments; 60 bool comment_ok; 61 bool last_was_eol; 62 unsigned int brace_count; 63 unsigned int paren_count; 64 unsigned int saved_paren_count; 65 isc_lexspecials_t specials; 66 LIST(struct inputsource) sources; 67 }; 68 69 static inline isc_result_t 70 grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) { 71 char *tmp; 72 73 tmp = isc_mem_get(lex->mctx, lex->max_token * 2 + 1); 74 if (tmp == NULL) 75 return (ISC_R_NOMEMORY); 76 memmove(tmp, lex->data, lex->max_token + 1); 77 *currp = tmp + (*currp - lex->data); 78 if (*prevp != NULL) 79 *prevp = tmp + (*prevp - lex->data); 80 isc_mem_put(lex->mctx, lex->data, lex->max_token + 1); 81 lex->data = tmp; 82 *remainingp += lex->max_token; 83 lex->max_token *= 2; 84 return (ISC_R_SUCCESS); 85 } 86 87 isc_result_t 88 isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) { 89 isc_lex_t *lex; 90 91 /* 92 * Create a lexer. 93 */ 94 REQUIRE(lexp != NULL && *lexp == NULL); 95 96 if (max_token == 0U) 97 max_token = 1; 98 99 lex = isc_mem_get(mctx, sizeof(*lex)); 100 if (lex == NULL) 101 return (ISC_R_NOMEMORY); 102 lex->data = isc_mem_get(mctx, max_token + 1); 103 if (lex->data == NULL) { 104 isc_mem_put(mctx, lex, sizeof(*lex)); 105 return (ISC_R_NOMEMORY); 106 } 107 lex->mctx = mctx; 108 lex->max_token = max_token; 109 lex->comments = 0; 110 lex->comment_ok = true; 111 lex->last_was_eol = true; 112 lex->brace_count = 0; 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 memmove(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 memmove(lex->specials, specials, 256); 189 } 190 191 static inline isc_result_t 192 new_source(isc_lex_t *lex, bool is_file, bool 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 = false; 205 source->last_was_eol = lex->last_was_eol; 206 source->input = input; 207 source->name = isc_mem_strdup(lex->mctx, name); 208 if (source->name == NULL) { 209 isc_mem_put(lex->mctx, source, sizeof(*source)); 210 return (ISC_R_NOMEMORY); 211 } 212 source->pushback = NULL; 213 result = isc_buffer_allocate(lex->mctx, &source->pushback, 214 (unsigned int)lex->max_token); 215 if (result != ISC_R_SUCCESS) { 216 isc_mem_free(lex->mctx, source->name); 217 isc_mem_put(lex->mctx, source, sizeof(*source)); 218 return (result); 219 } 220 source->ignored = 0; 221 source->line = 1; 222 ISC_LIST_INITANDPREPEND(lex->sources, source, link); 223 224 return (ISC_R_SUCCESS); 225 } 226 227 isc_result_t 228 isc_lex_openfile(isc_lex_t *lex, const char *filename) { 229 isc_result_t result; 230 FILE *stream = NULL; 231 232 /* 233 * Open 'filename' and make it the current input source for 'lex'. 234 */ 235 236 REQUIRE(VALID_LEX(lex)); 237 238 result = isc_stdio_open(filename, "r", &stream); 239 if (result != ISC_R_SUCCESS) 240 return (result); 241 242 result = new_source(lex, true, true, stream, filename); 243 if (result != ISC_R_SUCCESS) 244 (void)fclose(stream); 245 return (result); 246 } 247 248 isc_result_t 249 isc_lex_openstream(isc_lex_t *lex, FILE *stream) { 250 char name[128]; 251 252 /* 253 * Make 'stream' the current input source for 'lex'. 254 */ 255 256 REQUIRE(VALID_LEX(lex)); 257 258 snprintf(name, sizeof(name), "stream-%p", stream); 259 260 return (new_source(lex, true, false, stream, name)); 261 } 262 263 isc_result_t 264 isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) { 265 char name[128]; 266 267 /* 268 * Make 'buffer' the current input source for 'lex'. 269 */ 270 271 REQUIRE(VALID_LEX(lex)); 272 273 snprintf(name, sizeof(name), "buffer-%p", buffer); 274 275 return (new_source(lex, false, false, buffer, name)); 276 } 277 278 isc_result_t 279 isc_lex_close(isc_lex_t *lex) { 280 inputsource *source; 281 282 /* 283 * Close the most recently opened object (i.e. file or buffer). 284 */ 285 286 REQUIRE(VALID_LEX(lex)); 287 288 source = HEAD(lex->sources); 289 if (source == NULL) 290 return (ISC_R_NOMORE); 291 292 ISC_LIST_UNLINK(lex->sources, source, link); 293 lex->last_was_eol = source->last_was_eol; 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_btext 316 } lexstate; 317 318 #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL) 319 320 static void 321 pushback(inputsource *source, int c) { 322 REQUIRE(source->pushback->current > 0); 323 if (c == EOF) { 324 source->at_eof = false; 325 return; 326 } 327 source->pushback->current--; 328 if (c == '\n') 329 source->line--; 330 } 331 332 static isc_result_t 333 pushandgrow(isc_lex_t *lex, inputsource *source, int c) { 334 if (isc_buffer_availablelength(source->pushback) == 0) { 335 isc_buffer_t *tbuf = NULL; 336 unsigned int oldlen; 337 isc_region_t used; 338 isc_result_t result; 339 340 oldlen = isc_buffer_length(source->pushback); 341 result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2); 342 if (result != ISC_R_SUCCESS) 343 return (result); 344 isc_buffer_usedregion(source->pushback, &used); 345 result = isc_buffer_copyregion(tbuf, &used); 346 INSIST(result == ISC_R_SUCCESS); 347 tbuf->current = source->pushback->current; 348 isc_buffer_free(&source->pushback); 349 source->pushback = tbuf; 350 } 351 isc_buffer_putuint8(source->pushback, (uint8_t)c); 352 return (ISC_R_SUCCESS); 353 } 354 355 isc_result_t 356 isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { 357 inputsource *source; 358 int c; 359 bool done = false; 360 bool no_comments = false; 361 bool escaped = false; 362 lexstate state = lexstate_start; 363 lexstate saved_state = lexstate_start; 364 isc_buffer_t *buffer; 365 FILE *stream; 366 char *curr, *prev; 367 size_t remaining; 368 uint32_t as_ulong; 369 unsigned int saved_options; 370 isc_result_t result; 371 372 /* 373 * Get the next token. 374 */ 375 376 REQUIRE(VALID_LEX(lex)); 377 source = HEAD(lex->sources); 378 REQUIRE(tokenp != NULL); 379 380 if (source == NULL) { 381 if ((options & ISC_LEXOPT_NOMORE) != 0) { 382 tokenp->type = isc_tokentype_nomore; 383 return (ISC_R_SUCCESS); 384 } 385 return (ISC_R_NOMORE); 386 } 387 388 if (source->result != ISC_R_SUCCESS) 389 return (source->result); 390 391 lex->saved_paren_count = lex->paren_count; 392 source->saved_line = source->line; 393 394 if (isc_buffer_remaininglength(source->pushback) == 0 && 395 source->at_eof) 396 { 397 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && 398 lex->paren_count != 0) 399 { 400 lex->paren_count = 0; 401 return (ISC_R_UNBALANCED); 402 } 403 if ((options & ISC_LEXOPT_BTEXT) != 0 && 404 lex->brace_count != 0) 405 { 406 lex->brace_count = 0; 407 return (ISC_R_UNBALANCED); 408 } 409 if ((options & ISC_LEXOPT_EOF) != 0) { 410 tokenp->type = isc_tokentype_eof; 411 return (ISC_R_SUCCESS); 412 } 413 return (ISC_R_EOF); 414 } 415 416 isc_buffer_compact(source->pushback); 417 418 saved_options = options; 419 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0) 420 options &= ~IWSEOL; 421 422 curr = lex->data; 423 *curr = '\0'; 424 425 prev = NULL; 426 remaining = lex->max_token; 427 428 #ifdef HAVE_FLOCKFILE 429 if (source->is_file) 430 flockfile(source->input); 431 #endif 432 433 do { 434 if (isc_buffer_remaininglength(source->pushback) == 0) { 435 if (source->is_file) { 436 stream = source->input; 437 438 #if defined(HAVE_FLOCKFILE) && defined(HAVE_GETC_UNLOCKED) 439 c = getc_unlocked(stream); 440 #else 441 c = getc(stream); 442 #endif 443 if (c == EOF) { 444 if (ferror(stream)) { 445 source->result = ISC_R_IOERROR; 446 result = source->result; 447 goto done; 448 } 449 source->at_eof = true; 450 } 451 } else { 452 buffer = source->input; 453 454 if (buffer->current == buffer->used) { 455 c = EOF; 456 source->at_eof = true; 457 } else { 458 c = *((unsigned char *)buffer->base + 459 buffer->current); 460 buffer->current++; 461 } 462 } 463 if (c != EOF) { 464 source->result = pushandgrow(lex, source, c); 465 if (source->result != ISC_R_SUCCESS) { 466 result = source->result; 467 goto done; 468 } 469 } 470 } 471 472 if (!source->at_eof) { 473 if (state == lexstate_start) 474 /* Token has not started yet. */ 475 source->ignored = 476 isc_buffer_consumedlength(source->pushback); 477 c = isc_buffer_getuint8(source->pushback); 478 } else { 479 c = EOF; 480 } 481 482 if (c == '\n') 483 source->line++; 484 485 if (lex->comment_ok && !no_comments) { 486 if (!escaped && c == ';' && 487 ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE) 488 != 0)) { 489 saved_state = state; 490 state = lexstate_eatline; 491 no_comments = true; 492 continue; 493 } else if (c == '/' && 494 (lex->comments & 495 (ISC_LEXCOMMENT_C| 496 ISC_LEXCOMMENT_CPLUSPLUS)) != 0) { 497 saved_state = state; 498 state = lexstate_maybecomment; 499 no_comments = true; 500 continue; 501 } else if (c == '#' && 502 ((lex->comments & ISC_LEXCOMMENT_SHELL) 503 != 0)) { 504 saved_state = state; 505 state = lexstate_eatline; 506 no_comments = true; 507 continue; 508 } 509 } 510 511 no_read: 512 /* INSIST(c == EOF || (c >= 0 && c <= 255)); */ 513 switch (state) { 514 case lexstate_start: 515 if (c == EOF) { 516 lex->last_was_eol = false; 517 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && 518 lex->paren_count != 0) { 519 lex->paren_count = 0; 520 result = ISC_R_UNBALANCED; 521 goto done; 522 } 523 if ((options & ISC_LEXOPT_BTEXT) != 0 && 524 lex->brace_count != 0) { 525 lex->brace_count = 0; 526 result = ISC_R_UNBALANCED; 527 goto done; 528 } 529 if ((options & ISC_LEXOPT_EOF) == 0) { 530 result = ISC_R_EOF; 531 goto done; 532 } 533 tokenp->type = isc_tokentype_eof; 534 done = true; 535 } else if (c == ' ' || c == '\t') { 536 if (lex->last_was_eol && 537 (options & ISC_LEXOPT_INITIALWS) 538 != 0) { 539 lex->last_was_eol = false; 540 tokenp->type = isc_tokentype_initialws; 541 tokenp->value.as_char = c; 542 done = true; 543 } 544 } else if (c == '\n') { 545 if ((options & ISC_LEXOPT_EOL) != 0) { 546 tokenp->type = isc_tokentype_eol; 547 done = true; 548 } 549 lex->last_was_eol = true; 550 } else if (c == '\r') { 551 if ((options & ISC_LEXOPT_EOL) != 0) 552 state = lexstate_crlf; 553 } else if (c == '"' && 554 (options & ISC_LEXOPT_QSTRING) != 0) { 555 lex->last_was_eol = false; 556 no_comments = true; 557 state = lexstate_qstring; 558 } else if (lex->specials[c]) { 559 lex->last_was_eol = false; 560 if ((c == '(' || c == ')') && 561 (options & ISC_LEXOPT_DNSMULTILINE) != 0) 562 { 563 if (c == '(') { 564 if (lex->paren_count == 0) 565 options &= ~IWSEOL; 566 lex->paren_count++; 567 } else { 568 if (lex->paren_count == 0) { 569 result = 570 ISC_R_UNBALANCED; 571 goto done; 572 } 573 lex->paren_count--; 574 if (lex->paren_count == 0) 575 options = saved_options; 576 } 577 continue; 578 } else if (c == '{' && 579 (options & ISC_LEXOPT_BTEXT) != 0) 580 { 581 if (lex->brace_count != 0) { 582 result = ISC_R_UNBALANCED; 583 goto done; 584 } 585 lex->brace_count++; 586 options &= ~IWSEOL; 587 state = lexstate_btext; 588 no_comments = true; 589 continue; 590 } 591 tokenp->type = isc_tokentype_special; 592 tokenp->value.as_char = c; 593 done = true; 594 } else if (isdigit((unsigned char)c) && 595 (options & ISC_LEXOPT_NUMBER) != 0) { 596 lex->last_was_eol = false; 597 if ((options & ISC_LEXOPT_OCTAL) != 0 && 598 (c == '8' || c == '9')) 599 state = lexstate_string; 600 else 601 state = lexstate_number; 602 goto no_read; 603 } else { 604 lex->last_was_eol = false; 605 state = lexstate_string; 606 goto no_read; 607 } 608 break; 609 case lexstate_crlf: 610 if (c != '\n') 611 pushback(source, c); 612 tokenp->type = isc_tokentype_eol; 613 done = true; 614 lex->last_was_eol = true; 615 break; 616 case lexstate_number: 617 if (c == EOF || !isdigit((unsigned char)c)) { 618 if (c == ' ' || c == '\t' || c == '\r' || 619 c == '\n' || c == EOF || 620 lex->specials[c]) { 621 int base; 622 if ((options & ISC_LEXOPT_OCTAL) != 0) 623 base = 8; 624 else if ((options & ISC_LEXOPT_CNUMBER) != 0) 625 base = 0; 626 else 627 base = 10; 628 pushback(source, c); 629 630 result = isc_parse_uint32(&as_ulong, 631 lex->data, 632 base); 633 if (result == ISC_R_SUCCESS) { 634 tokenp->type = 635 isc_tokentype_number; 636 tokenp->value.as_ulong = 637 as_ulong; 638 } else if (result == ISC_R_BADNUMBER) { 639 isc_tokenvalue_t *v; 640 641 tokenp->type = 642 isc_tokentype_string; 643 v = &(tokenp->value); 644 v->as_textregion.base = 645 lex->data; 646 v->as_textregion.length = 647 (unsigned int) 648 (lex->max_token - 649 remaining); 650 } else 651 goto done; 652 done = true; 653 continue; 654 } else if ((options & ISC_LEXOPT_CNUMBER) == 0 || 655 ((c != 'x' && c != 'X') || 656 (curr != &lex->data[1]) || 657 (lex->data[0] != '0'))) { 658 /* Above test supports hex numbers */ 659 state = lexstate_string; 660 } 661 } else if ((options & ISC_LEXOPT_OCTAL) != 0 && 662 (c == '8' || c == '9')) { 663 state = lexstate_string; 664 } 665 if (remaining == 0U) { 666 result = grow_data(lex, &remaining, 667 &curr, &prev); 668 if (result != ISC_R_SUCCESS) 669 goto done; 670 } 671 INSIST(remaining > 0U); 672 *curr++ = c; 673 *curr = '\0'; 674 remaining--; 675 break; 676 case lexstate_string: 677 /* 678 * EOF needs to be checked before lex->specials[c] 679 * as lex->specials[EOF] is not a good idea. 680 */ 681 if (c == '\r' || c == '\n' || c == EOF || 682 (!escaped && 683 (c == ' ' || c == '\t' || lex->specials[c]))) { 684 pushback(source, c); 685 if (source->result != ISC_R_SUCCESS) { 686 result = source->result; 687 goto done; 688 } 689 tokenp->type = isc_tokentype_string; 690 tokenp->value.as_textregion.base = lex->data; 691 tokenp->value.as_textregion.length = 692 (unsigned int) 693 (lex->max_token - remaining); 694 done = true; 695 continue; 696 } 697 if ((options & ISC_LEXOPT_ESCAPE) != 0) 698 escaped = (!escaped && c == '\\') ? 699 true : false; 700 if (remaining == 0U) { 701 result = grow_data(lex, &remaining, 702 &curr, &prev); 703 if (result != ISC_R_SUCCESS) 704 goto done; 705 } 706 INSIST(remaining > 0U); 707 *curr++ = c; 708 *curr = '\0'; 709 remaining--; 710 break; 711 case lexstate_maybecomment: 712 if (c == '*' && 713 (lex->comments & ISC_LEXCOMMENT_C) != 0) { 714 state = lexstate_ccomment; 715 continue; 716 } else if (c == '/' && 717 (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) { 718 state = lexstate_eatline; 719 continue; 720 } 721 pushback(source, c); 722 c = '/'; 723 no_comments = false; 724 state = saved_state; 725 goto no_read; 726 case lexstate_ccomment: 727 if (c == EOF) { 728 result = ISC_R_UNEXPECTEDEND; 729 goto done; 730 } 731 if (c == '*') 732 state = lexstate_ccommentend; 733 break; 734 case lexstate_ccommentend: 735 if (c == EOF) { 736 result = ISC_R_UNEXPECTEDEND; 737 goto done; 738 } 739 if (c == '/') { 740 /* 741 * C-style comments become a single space. 742 * We do this to ensure that a comment will 743 * act as a delimiter for strings and 744 * numbers. 745 */ 746 c = ' '; 747 no_comments = false; 748 state = saved_state; 749 goto no_read; 750 } else if (c != '*') 751 state = lexstate_ccomment; 752 break; 753 case lexstate_eatline: 754 if ((c == '\n') || (c == EOF)) { 755 no_comments = false; 756 state = saved_state; 757 goto no_read; 758 } 759 break; 760 case lexstate_qstring: 761 if (c == EOF) { 762 result = ISC_R_UNEXPECTEDEND; 763 goto done; 764 } 765 if (c == '"') { 766 if (escaped) { 767 escaped = false; 768 /* 769 * Overwrite the preceding backslash. 770 */ 771 INSIST(prev != NULL); 772 *prev = '"'; 773 } else { 774 tokenp->type = isc_tokentype_qstring; 775 tokenp->value.as_textregion.base = 776 lex->data; 777 tokenp->value.as_textregion.length = 778 (unsigned int) 779 (lex->max_token - remaining); 780 no_comments = false; 781 done = true; 782 } 783 } else { 784 if (c == '\n' && !escaped && 785 (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) { 786 pushback(source, c); 787 result = ISC_R_UNBALANCEDQUOTES; 788 goto done; 789 } 790 if (c == '\\' && !escaped) 791 escaped = true; 792 else 793 escaped = false; 794 if (remaining == 0U) { 795 result = grow_data(lex, &remaining, 796 &curr, &prev); 797 if (result != ISC_R_SUCCESS) 798 goto done; 799 } 800 INSIST(remaining > 0U); 801 prev = curr; 802 *curr++ = c; 803 *curr = '\0'; 804 remaining--; 805 } 806 break; 807 case lexstate_btext: 808 if (c == EOF) { 809 result = ISC_R_UNEXPECTEDEND; 810 goto done; 811 } 812 if (c == '{') { 813 if (escaped) { 814 escaped = false; 815 } else { 816 lex->brace_count++; 817 } 818 } else if (c == '}') { 819 if (escaped) { 820 escaped = false; 821 } else { 822 INSIST(lex->brace_count > 0); 823 lex->brace_count--; 824 } 825 826 if (lex->brace_count == 0) { 827 tokenp->type = isc_tokentype_btext; 828 tokenp->value.as_textregion.base = 829 lex->data; 830 tokenp->value.as_textregion.length = 831 (unsigned int) (lex->max_token - 832 remaining); 833 no_comments = false; 834 done = true; 835 break; 836 } 837 } 838 839 if (c == '\\' && !escaped) 840 escaped = true; 841 else 842 escaped = false; 843 844 if (remaining == 0U) { 845 result = grow_data(lex, &remaining, 846 &curr, &prev); 847 if (result != ISC_R_SUCCESS) 848 goto done; 849 } 850 INSIST(remaining > 0U); 851 prev = curr; 852 *curr++ = c; 853 *curr = '\0'; 854 remaining--; 855 break; 856 default: 857 FATAL_ERROR(__FILE__, __LINE__, 858 "Unexpected state %d", 859 state); 860 } 861 862 } while (!done); 863 864 result = ISC_R_SUCCESS; 865 done: 866 #ifdef HAVE_FLOCKFILE 867 if (source->is_file) 868 funlockfile(source->input); 869 #endif 870 return (result); 871 } 872 873 isc_result_t 874 isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token, 875 isc_tokentype_t expect, bool eol) 876 { 877 unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | 878 ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE; 879 isc_result_t result; 880 881 if (expect == isc_tokentype_qstring) 882 options |= ISC_LEXOPT_QSTRING; 883 else if (expect == isc_tokentype_number) 884 options |= ISC_LEXOPT_NUMBER; 885 result = isc_lex_gettoken(lex, options, token); 886 if (result == ISC_R_RANGE) 887 isc_lex_ungettoken(lex, token); 888 if (result != ISC_R_SUCCESS) 889 return (result); 890 891 if (eol && ((token->type == isc_tokentype_eol) || 892 (token->type == isc_tokentype_eof))) 893 return (ISC_R_SUCCESS); 894 if (token->type == isc_tokentype_string && 895 expect == isc_tokentype_qstring) 896 return (ISC_R_SUCCESS); 897 if (token->type != expect) { 898 isc_lex_ungettoken(lex, token); 899 if (token->type == isc_tokentype_eol || 900 token->type == isc_tokentype_eof) 901 return (ISC_R_UNEXPECTEDEND); 902 if (expect == isc_tokentype_number) 903 return (ISC_R_BADNUMBER); 904 return (ISC_R_UNEXPECTEDTOKEN); 905 } 906 return (ISC_R_SUCCESS); 907 } 908 909 isc_result_t 910 isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, bool eol) 911 { 912 unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | 913 ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE| 914 ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL; 915 isc_result_t result; 916 917 result = isc_lex_gettoken(lex, options, token); 918 if (result == ISC_R_RANGE) 919 isc_lex_ungettoken(lex, token); 920 if (result != ISC_R_SUCCESS) 921 return (result); 922 923 if (eol && ((token->type == isc_tokentype_eol) || 924 (token->type == isc_tokentype_eof))) 925 return (ISC_R_SUCCESS); 926 if (token->type != isc_tokentype_number) { 927 isc_lex_ungettoken(lex, token); 928 if (token->type == isc_tokentype_eol || 929 token->type == isc_tokentype_eof) 930 return (ISC_R_UNEXPECTEDEND); 931 return (ISC_R_BADNUMBER); 932 } 933 return (ISC_R_SUCCESS); 934 } 935 936 void 937 isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) { 938 inputsource *source; 939 /* 940 * Unget the current token. 941 */ 942 943 REQUIRE(VALID_LEX(lex)); 944 source = HEAD(lex->sources); 945 REQUIRE(source != NULL); 946 REQUIRE(tokenp != NULL); 947 REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 || 948 tokenp->type == isc_tokentype_eof); 949 950 UNUSED(tokenp); 951 952 isc_buffer_first(source->pushback); 953 lex->paren_count = lex->saved_paren_count; 954 source->line = source->saved_line; 955 source->at_eof = false; 956 } 957 958 void 959 isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r) 960 { 961 inputsource *source; 962 963 REQUIRE(VALID_LEX(lex)); 964 source = HEAD(lex->sources); 965 REQUIRE(source != NULL); 966 REQUIRE(tokenp != NULL); 967 REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 || 968 tokenp->type == isc_tokentype_eof); 969 970 UNUSED(tokenp); 971 972 INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback)); 973 r->base = (unsigned char *)isc_buffer_base(source->pushback) + 974 source->ignored; 975 r->length = isc_buffer_consumedlength(source->pushback) - 976 source->ignored; 977 } 978 979 char * 980 isc_lex_getsourcename(isc_lex_t *lex) { 981 inputsource *source; 982 983 REQUIRE(VALID_LEX(lex)); 984 source = HEAD(lex->sources); 985 986 if (source == NULL) 987 return (NULL); 988 989 return (source->name); 990 } 991 992 unsigned long 993 isc_lex_getsourceline(isc_lex_t *lex) { 994 inputsource *source; 995 996 REQUIRE(VALID_LEX(lex)); 997 source = HEAD(lex->sources); 998 999 if (source == NULL) 1000 return (0); 1001 1002 return (source->line); 1003 } 1004 1005 isc_result_t 1006 isc_lex_setsourcename(isc_lex_t *lex, const char *name) { 1007 inputsource *source; 1008 char *newname; 1009 1010 REQUIRE(VALID_LEX(lex)); 1011 source = HEAD(lex->sources); 1012 1013 if (source == NULL) 1014 return (ISC_R_NOTFOUND); 1015 newname = isc_mem_strdup(lex->mctx, name); 1016 if (newname == NULL) 1017 return (ISC_R_NOMEMORY); 1018 isc_mem_free(lex->mctx, source->name); 1019 source->name = newname; 1020 return (ISC_R_SUCCESS); 1021 } 1022 1023 isc_result_t 1024 isc_lex_setsourceline(isc_lex_t *lex, unsigned long line) { 1025 inputsource *source; 1026 1027 REQUIRE(VALID_LEX(lex)); 1028 source = HEAD(lex->sources); 1029 1030 if (source == NULL) 1031 return (ISC_R_NOTFOUND); 1032 1033 source->line = line; 1034 return (ISC_R_SUCCESS); 1035 } 1036 1037 bool 1038 isc_lex_isfile(isc_lex_t *lex) { 1039 inputsource *source; 1040 1041 REQUIRE(VALID_LEX(lex)); 1042 1043 source = HEAD(lex->sources); 1044 1045 if (source == NULL) 1046 return (false); 1047 1048 return (source->is_file); 1049 } 1050