1/* $NetBSD: lex.c,v 1.6 2020/05/25 20:47:20 christos Exp $ */ 2 3/* 4 * Copyright (C) 2004, 2005, 2007 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 41typedef 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 58struct 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 73static inline isc_result_t 74grow_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 memcpy(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 91isc_result_t 92isc_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 126void 127isc_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 148unsigned int 149isc_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 159void 160isc_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 170void 171isc_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 memcpy(specials, lex->specials, 256); 179} 180 181void 182isc_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 memcpy(lex->specials, specials, 256); 191} 192 193static inline isc_result_t 194new_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 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 228isc_result_t 229isc_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 249isc_result_t 250isc_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 264isc_result_t 265isc_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 279isc_result_t 280isc_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 305typedef 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 319static void 320pushback(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 331static isc_result_t 332pushandgrow(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 354isc_result_t 355isc_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 = *((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 lex->max_token - 621 remaining; 622 } else 623 goto done; 624 done = ISC_TRUE; 625 continue; 626 } else if (!(options & ISC_LEXOPT_CNUMBER) || 627 ((c != 'x' && c != 'X') || 628 (curr != &lex->data[1]) || 629 (lex->data[0] != '0'))) { 630 /* Above test supports hex numbers */ 631 state = lexstate_string; 632 } 633 } else if ((options & ISC_LEXOPT_OCTAL) != 0 && 634 (c == '8' || c == '9')) { 635 state = lexstate_string; 636 } 637 if (remaining == 0U) { 638 result = grow_data(lex, &remaining, 639 &curr, &prev); 640 if (result != ISC_R_SUCCESS) 641 goto done; 642 } 643 INSIST(remaining > 0U); 644 *curr++ = c; 645 *curr = '\0'; 646 remaining--; 647 break; 648 case lexstate_string: 649 /* 650 * EOF needs to be checked before lex->specials[c] 651 * as lex->specials[EOF] is not a good idea. 652 */ 653 if (c == '\r' || c == '\n' || c == EOF || 654 (!escaped && 655 (c == ' ' || c == '\t' || lex->specials[c]))) { 656 pushback(source, c); 657 if (source->result != ISC_R_SUCCESS) { 658 result = source->result; 659 goto done; 660 } 661 tokenp->type = isc_tokentype_string; 662 tokenp->value.as_textregion.base = lex->data; 663 tokenp->value.as_textregion.length = 664 lex->max_token - remaining; 665 done = ISC_TRUE; 666 continue; 667 } 668 if ((options & ISC_LEXOPT_ESCAPE) != 0) 669 escaped = (!escaped && c == '\\') ? 670 ISC_TRUE : ISC_FALSE; 671 if (remaining == 0U) { 672 result = grow_data(lex, &remaining, 673 &curr, &prev); 674 if (result != ISC_R_SUCCESS) 675 goto done; 676 } 677 INSIST(remaining > 0U); 678 *curr++ = c; 679 *curr = '\0'; 680 remaining--; 681 break; 682 case lexstate_maybecomment: 683 if (c == '*' && 684 (lex->comments & ISC_LEXCOMMENT_C) != 0) { 685 state = lexstate_ccomment; 686 continue; 687 } else if (c == '/' && 688 (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) { 689 state = lexstate_eatline; 690 continue; 691 } 692 pushback(source, c); 693 c = '/'; 694 no_comments = ISC_FALSE; 695 state = saved_state; 696 goto no_read; 697 case lexstate_ccomment: 698 if (c == EOF) { 699 result = ISC_R_UNEXPECTEDEND; 700 goto done; 701 } 702 if (c == '*') 703 state = lexstate_ccommentend; 704 break; 705 case lexstate_ccommentend: 706 if (c == EOF) { 707 result = ISC_R_UNEXPECTEDEND; 708 goto done; 709 } 710 if (c == '/') { 711 /* 712 * C-style comments become a single space. 713 * We do this to ensure that a comment will 714 * act as a delimiter for strings and 715 * numbers. 716 */ 717 c = ' '; 718 no_comments = ISC_FALSE; 719 state = saved_state; 720 goto no_read; 721 } else if (c != '*') 722 state = lexstate_ccomment; 723 break; 724 case lexstate_eatline: 725 if ((c == '\n') || (c == EOF)) { 726 no_comments = ISC_FALSE; 727 state = saved_state; 728 goto no_read; 729 } 730 break; 731 case lexstate_qstring: 732 if (c == EOF) { 733 result = ISC_R_UNEXPECTEDEND; 734 goto done; 735 } 736 if (c == '"') { 737 if (escaped) { 738 escaped = ISC_FALSE; 739 /* 740 * Overwrite the preceding backslash. 741 */ 742 INSIST(prev != NULL); 743 *prev = '"'; 744 } else { 745 tokenp->type = isc_tokentype_qstring; 746 tokenp->value.as_textregion.base = 747 lex->data; 748 tokenp->value.as_textregion.length = 749 lex->max_token - remaining; 750 no_comments = ISC_FALSE; 751 done = ISC_TRUE; 752 } 753 } else { 754 if (c == '\n' && !escaped && 755 (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) { 756 pushback(source, c); 757 result = ISC_R_UNBALANCEDQUOTES; 758 goto done; 759 } 760 if (c == '\\' && !escaped) 761 escaped = ISC_TRUE; 762 else 763 escaped = ISC_FALSE; 764 if (remaining == 0U) { 765 result = grow_data(lex, &remaining, 766 &curr, &prev); 767 if (result != ISC_R_SUCCESS) 768 goto done; 769 } 770 INSIST(remaining > 0U); 771 prev = curr; 772 *curr++ = c; 773 *curr = '\0'; 774 remaining--; 775 } 776 break; 777 default: 778 FATAL_ERROR(__FILE__, __LINE__, 779 isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX, 780 ISC_MSG_UNEXPECTEDSTATE, 781 "Unexpected state %d"), 782 state); 783 /* Does not return. */ 784 } 785 786 } while (!done); 787 788 result = ISC_R_SUCCESS; 789 done: 790#ifdef HAVE_FLOCKFILE 791 if (source->is_file) 792 funlockfile(source->input); 793#endif 794 return (result); 795} 796 797isc_result_t 798isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token, 799 isc_tokentype_t expect, isc_boolean_t eol) 800{ 801 unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | 802 ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE; 803 isc_result_t result; 804 805 if (expect == isc_tokentype_qstring) 806 options |= ISC_LEXOPT_QSTRING; 807 else if (expect == isc_tokentype_number) 808 options |= ISC_LEXOPT_NUMBER; 809 result = isc_lex_gettoken(lex, options, token); 810 if (result == ISC_R_RANGE) 811 isc_lex_ungettoken(lex, token); 812 if (result != ISC_R_SUCCESS) 813 return (result); 814 815 if (eol && ((token->type == isc_tokentype_eol) || 816 (token->type == isc_tokentype_eof))) 817 return (ISC_R_SUCCESS); 818 if (token->type == isc_tokentype_string && 819 expect == isc_tokentype_qstring) 820 return (ISC_R_SUCCESS); 821 if (token->type != expect) { 822 isc_lex_ungettoken(lex, token); 823 if (token->type == isc_tokentype_eol || 824 token->type == isc_tokentype_eof) 825 return (ISC_R_UNEXPECTEDEND); 826 if (expect == isc_tokentype_number) 827 return (ISC_R_BADNUMBER); 828 return (ISC_R_UNEXPECTEDTOKEN); 829 } 830 return (ISC_R_SUCCESS); 831} 832 833isc_result_t 834isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol) 835{ 836 unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | 837 ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE| 838 ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL; 839 isc_result_t result; 840 841 result = isc_lex_gettoken(lex, options, token); 842 if (result == ISC_R_RANGE) 843 isc_lex_ungettoken(lex, token); 844 if (result != ISC_R_SUCCESS) 845 return (result); 846 847 if (eol && ((token->type == isc_tokentype_eol) || 848 (token->type == isc_tokentype_eof))) 849 return (ISC_R_SUCCESS); 850 if (token->type != isc_tokentype_number) { 851 isc_lex_ungettoken(lex, token); 852 if (token->type == isc_tokentype_eol || 853 token->type == isc_tokentype_eof) 854 return (ISC_R_UNEXPECTEDEND); 855 return (ISC_R_BADNUMBER); 856 } 857 return (ISC_R_SUCCESS); 858} 859 860void 861isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) { 862 inputsource *source; 863 /* 864 * Unget the current token. 865 */ 866 867 REQUIRE(VALID_LEX(lex)); 868 source = HEAD(lex->sources); 869 REQUIRE(source != NULL); 870 REQUIRE(tokenp != NULL); 871 REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 || 872 tokenp->type == isc_tokentype_eof); 873 874 UNUSED(tokenp); 875 876 isc_buffer_first(source->pushback); 877 lex->paren_count = lex->saved_paren_count; 878 source->line = source->saved_line; 879 source->at_eof = ISC_FALSE; 880} 881 882void 883isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r) 884{ 885 inputsource *source; 886 887 REQUIRE(VALID_LEX(lex)); 888 source = HEAD(lex->sources); 889 REQUIRE(source != NULL); 890 REQUIRE(tokenp != NULL); 891 REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 || 892 tokenp->type == isc_tokentype_eof); 893 894 UNUSED(tokenp); 895 896 INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback)); 897 r->base = (unsigned char *)isc_buffer_base(source->pushback) + 898 source->ignored; 899 r->length = isc_buffer_consumedlength(source->pushback) - 900 source->ignored; 901} 902 903 904char * 905isc_lex_getsourcename(isc_lex_t *lex) { 906 inputsource *source; 907 908 REQUIRE(VALID_LEX(lex)); 909 source = HEAD(lex->sources); 910 911 if (source == NULL) 912 return (NULL); 913 914 return (source->name); 915} 916 917unsigned long 918isc_lex_getsourceline(isc_lex_t *lex) { 919 inputsource *source; 920 921 REQUIRE(VALID_LEX(lex)); 922 source = HEAD(lex->sources); 923 924 if (source == NULL) 925 return (0); 926 927 return (source->line); 928} 929 930 931isc_result_t 932isc_lex_setsourcename(isc_lex_t *lex, const char *name) { 933 inputsource *source; 934 char *newname; 935 936 REQUIRE(VALID_LEX(lex)); 937 source = HEAD(lex->sources); 938 939 if (source == NULL) 940 return(ISC_R_NOTFOUND); 941 newname = isc_mem_strdup(lex->mctx, name); 942 if (newname == NULL) 943 return (ISC_R_NOMEMORY); 944 isc_mem_free(lex->mctx, source->name); 945 source->name = newname; 946 return (ISC_R_SUCCESS); 947} 948 949isc_boolean_t 950isc_lex_isfile(isc_lex_t *lex) { 951 inputsource *source; 952 953 REQUIRE(VALID_LEX(lex)); 954 955 source = HEAD(lex->sources); 956 957 if (source == NULL) 958 return (ISC_FALSE); 959 960 return (source->is_file); 961} 962