Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / lib / isc / lex.c
blob8749ed0b0ba36fb00e7123cee21bc8e85c7a8f91
1 /*
2 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1998-2003 Internet Software Consortium.
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.
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.
18 /* $Id: lex.c,v 1.86 2007/09/17 09:56:29 shane Exp $ */
20 /*! \file */
22 #include <config.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <stdlib.h>
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>
39 typedef struct inputsource {
40 isc_result_t result;
41 isc_boolean_t is_file;
42 isc_boolean_t need_close;
43 isc_boolean_t at_eof;
44 isc_buffer_t * pushback;
45 unsigned int ignored;
46 void * input;
47 char * name;
48 unsigned long line;
49 unsigned long saved_line;
50 ISC_LINK(struct inputsource) link;
51 } inputsource;
53 #define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!')
54 #define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC)
56 struct isc_lex {
57 /* Unlocked. */
58 unsigned int magic;
59 isc_mem_t * mctx;
60 size_t max_token;
61 char * data;
62 unsigned int comments;
63 isc_boolean_t comment_ok;
64 isc_boolean_t last_was_eol;
65 unsigned int paren_count;
66 unsigned int saved_paren_count;
67 isc_lexspecials_t specials;
68 LIST(struct inputsource) sources;
71 static inline isc_result_t
72 grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
73 char *new;
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);
89 isc_result_t
90 isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
91 isc_lex_t *lex;
94 * Create a lexer.
97 REQUIRE(lexp != NULL && *lexp == NULL);
98 REQUIRE(max_token > 0U);
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);
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;
119 *lexp = lex;
121 return (ISC_R_SUCCESS);
124 void
125 isc_lex_destroy(isc_lex_t **lexp) {
126 isc_lex_t *lex;
129 * Destroy the lexer.
132 REQUIRE(lexp != NULL);
133 lex = *lexp;
134 REQUIRE(VALID_LEX(lex));
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));
143 *lexp = NULL;
146 unsigned int
147 isc_lex_getcomments(isc_lex_t *lex) {
149 * Return the current lexer commenting styles.
152 REQUIRE(VALID_LEX(lex));
154 return (lex->comments);
157 void
158 isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
160 * Set allowed lexer commenting styles.
163 REQUIRE(VALID_LEX(lex));
165 lex->comments = comments;
168 void
169 isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
171 * Put the current list of specials into 'specials'.
174 REQUIRE(VALID_LEX(lex));
176 memcpy(specials, lex->specials, 256);
179 void
180 isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
182 * The characters in 'specials' are returned as tokens. Along with
183 * whitespace, they delimit strings and numbers.
186 REQUIRE(VALID_LEX(lex));
188 memcpy(lex->specials, specials, 256);
191 static inline isc_result_t
192 new_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close,
193 void *input, const char *name)
195 inputsource *source;
196 isc_result_t result;
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);
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);
219 source->ignored = 0;
220 source->line = 1;
221 ISC_LIST_INITANDPREPEND(lex->sources, source, link);
223 return (ISC_R_SUCCESS);
226 isc_result_t
227 isc_lex_openfile(isc_lex_t *lex, const char *filename) {
228 isc_result_t result;
229 FILE *stream = NULL;
232 * Open 'filename' and make it the current input source for 'lex'.
235 REQUIRE(VALID_LEX(lex));
237 result = isc_stdio_open(filename, "r", &stream);
238 if (result != ISC_R_SUCCESS)
239 return (result);
241 result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename);
242 if (result != ISC_R_SUCCESS)
243 (void)fclose(stream);
244 return (result);
247 isc_result_t
248 isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
249 char name[128];
252 * Make 'stream' the current input source for 'lex'.
255 REQUIRE(VALID_LEX(lex));
257 snprintf(name, sizeof(name), "stream-%p", stream);
259 return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));
262 isc_result_t
263 isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
264 char name[128];
267 * Make 'buffer' the current input source for 'lex'.
270 REQUIRE(VALID_LEX(lex));
272 snprintf(name, sizeof(name), "buffer-%p", buffer);
274 return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));
277 isc_result_t
278 isc_lex_close(isc_lex_t *lex) {
279 inputsource *source;
282 * Close the most recently opened object (i.e. file or buffer).
285 REQUIRE(VALID_LEX(lex));
287 source = HEAD(lex->sources);
288 if (source == NULL)
289 return (ISC_R_NOMORE);
291 ISC_LIST_UNLINK(lex->sources, source, link);
292 if (source->is_file) {
293 if (source->need_close)
294 (void)fclose((FILE *)(source->input));
296 isc_mem_free(lex->mctx, source->name);
297 isc_buffer_free(&source->pushback);
298 isc_mem_put(lex->mctx, source, sizeof(*source));
300 return (ISC_R_SUCCESS);
303 typedef enum {
304 lexstate_start,
305 lexstate_crlf,
306 lexstate_string,
307 lexstate_number,
308 lexstate_maybecomment,
309 lexstate_ccomment,
310 lexstate_ccommentend,
311 lexstate_eatline,
312 lexstate_qstring
313 } lexstate;
315 #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
317 static void
318 pushback(inputsource *source, int c) {
319 REQUIRE(source->pushback->current > 0);
320 if (c == EOF) {
321 source->at_eof = ISC_FALSE;
322 return;
324 source->pushback->current--;
325 if (c == '\n')
326 source->line--;
329 static isc_result_t
330 pushandgrow(isc_lex_t *lex, inputsource *source, int c) {
331 if (isc_buffer_availablelength(source->pushback) == 0) {
332 isc_buffer_t *tbuf = NULL;
333 unsigned int oldlen;
334 isc_region_t used;
335 isc_result_t result;
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;
348 isc_buffer_putuint8(source->pushback, (isc_uint8_t)c);
349 return (ISC_R_SUCCESS);
352 isc_result_t
353 isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
354 inputsource *source;
355 int c;
356 isc_boolean_t done = ISC_FALSE;
357 isc_boolean_t no_comments = ISC_FALSE;
358 isc_boolean_t escaped = ISC_FALSE;
359 lexstate state = lexstate_start;
360 lexstate saved_state = lexstate_start;
361 isc_buffer_t *buffer;
362 FILE *stream;
363 char *curr, *prev;
364 size_t remaining;
365 isc_uint32_t as_ulong;
366 unsigned int saved_options;
367 isc_result_t result;
370 * Get the next token.
373 REQUIRE(VALID_LEX(lex));
374 source = HEAD(lex->sources);
375 REQUIRE(tokenp != NULL);
377 if (source == NULL) {
378 if ((options & ISC_LEXOPT_NOMORE) != 0) {
379 tokenp->type = isc_tokentype_nomore;
380 return (ISC_R_SUCCESS);
382 return (ISC_R_NOMORE);
385 if (source->result != ISC_R_SUCCESS)
386 return (source->result);
388 lex->saved_paren_count = lex->paren_count;
389 source->saved_line = source->line;
391 if (isc_buffer_remaininglength(source->pushback) == 0 &&
392 source->at_eof)
394 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
395 lex->paren_count != 0) {
396 lex->paren_count = 0;
397 return (ISC_R_UNBALANCED);
399 if ((options & ISC_LEXOPT_EOF) != 0) {
400 tokenp->type = isc_tokentype_eof;
401 return (ISC_R_SUCCESS);
403 return (ISC_R_EOF);
406 isc_buffer_compact(source->pushback);
408 saved_options = options;
409 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
410 options &= ~IWSEOL;
412 curr = lex->data;
413 *curr = '\0';
415 prev = NULL;
416 remaining = lex->max_token;
418 #ifdef HAVE_FLOCKFILE
419 if (source->is_file)
420 flockfile(source->input);
421 #endif
423 do {
424 if (isc_buffer_remaininglength(source->pushback) == 0) {
425 if (source->is_file) {
426 stream = source->input;
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;
439 source->at_eof = ISC_TRUE;
441 } else {
442 buffer = source->input;
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++;
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;
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;
472 if (c == '\n')
473 source->line++;
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;
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;
513 if ((options & ISC_LEXOPT_EOF) == 0) {
514 result = ISC_R_EOF;
515 goto done;
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;
528 } else if (c == '\n') {
529 if ((options & ISC_LEXOPT_EOL) != 0) {
530 tokenp->type = isc_tokentype_eol;
531 done = ISC_TRUE;
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;
555 lex->paren_count--;
556 if (lex->paren_count == 0)
557 options =
558 saved_options;
560 continue;
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;
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);
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;
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;
631 } else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
632 (c == '8' || c == '9')) {
633 state = lexstate_string;
635 if (remaining == 0U) {
636 result = grow_data(lex, &remaining,
637 &curr, &prev);
638 if (result != ISC_R_SUCCESS)
639 goto done;
641 INSIST(remaining > 0U);
642 *curr++ = c;
643 *curr = '\0';
644 remaining--;
645 break;
646 case lexstate_string:
648 * EOF needs to be checked before lex->specials[c]
649 * as lex->specials[EOF] is not a good idea.
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;
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;
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;
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;
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;
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;
708 if (c == '/') {
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.
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;
728 break;
729 case lexstate_qstring:
730 if (c == EOF) {
731 result = ISC_R_UNEXPECTEDEND;
732 goto done;
734 if (c == '"') {
735 if (escaped) {
736 escaped = ISC_FALSE;
738 * Overwrite the preceding backslash.
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;
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;
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;
768 INSIST(remaining > 0U);
769 prev = curr;
770 *curr++ = c;
771 *curr = '\0';
772 remaining--;
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. */
784 } while (!done);
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);
795 isc_result_t
796 isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
797 isc_tokentype_t expect, isc_boolean_t eol)
799 unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
800 ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
801 isc_result_t result;
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);
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);
828 return (ISC_R_SUCCESS);
831 isc_result_t
832 isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol)
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;
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);
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);
855 return (ISC_R_SUCCESS);
858 void
859 isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
860 inputsource *source;
862 * Unget the current token.
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);
872 UNUSED(tokenp);
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;
880 void
881 isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
883 inputsource *source;
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);
892 UNUSED(tokenp);
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;
902 char *
903 isc_lex_getsourcename(isc_lex_t *lex) {
904 inputsource *source;
906 REQUIRE(VALID_LEX(lex));
907 source = HEAD(lex->sources);
909 if (source == NULL)
910 return (NULL);
912 return (source->name);
915 unsigned long
916 isc_lex_getsourceline(isc_lex_t *lex) {
917 inputsource *source;
919 REQUIRE(VALID_LEX(lex));
920 source = HEAD(lex->sources);
922 if (source == NULL)
923 return (0);
925 return (source->line);
929 isc_result_t
930 isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
931 inputsource *source;
932 char *newname;
934 REQUIRE(VALID_LEX(lex));
935 source = HEAD(lex->sources);
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);
947 isc_boolean_t
948 isc_lex_isfile(isc_lex_t *lex) {
949 inputsource *source;
951 REQUIRE(VALID_LEX(lex));
953 source = HEAD(lex->sources);
955 if (source == NULL)
956 return (ISC_FALSE);
958 return (source->is_file);