acpi.4: Add some missing references.
[dragonfly.git] / contrib / bind-9.3 / lib / isc / lex.c
blob3511d6bd0e704641aae1bb4c0f6c17a06a9aec1b
1 /*
2 * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1998-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.66.2.6.2.10 2006/01/04 23:50:21 marka Exp $ */
20 #include <config.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <stdlib.h>
26 #include <isc/buffer.h>
27 #include <isc/file.h>
28 #include <isc/lex.h>
29 #include <isc/mem.h>
30 #include <isc/msgs.h>
31 #include <isc/parseint.h>
32 #include <isc/print.h>
33 #include <isc/stdio.h>
34 #include <isc/string.h>
35 #include <isc/util.h>
37 typedef struct inputsource {
38 isc_result_t result;
39 isc_boolean_t is_file;
40 isc_boolean_t need_close;
41 isc_boolean_t at_eof;
42 isc_buffer_t * pushback;
43 unsigned int ignored;
44 void * input;
45 char * name;
46 unsigned long line;
47 unsigned long saved_line;
48 ISC_LINK(struct inputsource) link;
49 } inputsource;
51 #define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!')
52 #define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC)
54 struct isc_lex {
55 /* Unlocked. */
56 unsigned int magic;
57 isc_mem_t * mctx;
58 size_t max_token;
59 char * data;
60 unsigned int comments;
61 isc_boolean_t comment_ok;
62 isc_boolean_t last_was_eol;
63 unsigned int paren_count;
64 unsigned int saved_paren_count;
65 isc_lexspecials_t specials;
66 LIST(struct inputsource) sources;
69 static inline isc_result_t
70 grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
71 char *new;
73 new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
74 if (new == NULL)
75 return (ISC_R_NOMEMORY);
76 memcpy(new, lex->data, lex->max_token + 1);
77 *currp = new + (*currp - lex->data);
78 if (*prevp != NULL)
79 *prevp = new + (*prevp - lex->data);
80 isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
81 lex->data = new;
82 *remainingp += lex->max_token;
83 lex->max_token *= 2;
84 return (ISC_R_SUCCESS);
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;
92 * Create a lexer.
95 REQUIRE(lexp != NULL && *lexp == NULL);
96 REQUIRE(max_token > 0U);
98 lex = isc_mem_get(mctx, sizeof(*lex));
99 if (lex == NULL)
100 return (ISC_R_NOMEMORY);
101 lex->data = isc_mem_get(mctx, max_token + 1);
102 if (lex->data == NULL) {
103 isc_mem_put(mctx, lex, sizeof(*lex));
104 return (ISC_R_NOMEMORY);
106 lex->mctx = mctx;
107 lex->max_token = max_token;
108 lex->comments = 0;
109 lex->comment_ok = ISC_TRUE;
110 lex->last_was_eol = ISC_TRUE;
111 lex->paren_count = 0;
112 lex->saved_paren_count = 0;
113 memset(lex->specials, 0, 256);
114 INIT_LIST(lex->sources);
115 lex->magic = LEX_MAGIC;
117 *lexp = lex;
119 return (ISC_R_SUCCESS);
122 void
123 isc_lex_destroy(isc_lex_t **lexp) {
124 isc_lex_t *lex;
127 * Destroy the lexer.
130 REQUIRE(lexp != NULL);
131 lex = *lexp;
132 REQUIRE(VALID_LEX(lex));
134 while (!EMPTY(lex->sources))
135 RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
136 if (lex->data != NULL)
137 isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
138 lex->magic = 0;
139 isc_mem_put(lex->mctx, lex, sizeof(*lex));
141 *lexp = NULL;
144 unsigned int
145 isc_lex_getcomments(isc_lex_t *lex) {
147 * Return the current lexer commenting styles.
150 REQUIRE(VALID_LEX(lex));
152 return (lex->comments);
155 void
156 isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
158 * Set allowed lexer commenting styles.
161 REQUIRE(VALID_LEX(lex));
163 lex->comments = comments;
166 void
167 isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
169 * Put the current list of specials into 'specials'.
172 REQUIRE(VALID_LEX(lex));
174 memcpy(specials, lex->specials, 256);
177 void
178 isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
180 * The characters in 'specials' are returned as tokens. Along with
181 * whitespace, they delimit strings and numbers.
184 REQUIRE(VALID_LEX(lex));
186 memcpy(lex->specials, specials, 256);
189 static inline isc_result_t
190 new_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close,
191 void *input, const char *name)
193 inputsource *source;
194 isc_result_t result;
196 source = isc_mem_get(lex->mctx, sizeof(*source));
197 if (source == NULL)
198 return (ISC_R_NOMEMORY);
199 source->result = ISC_R_SUCCESS;
200 source->is_file = is_file;
201 source->need_close = need_close;
202 source->at_eof = ISC_FALSE;
203 source->input = input;
204 source->name = isc_mem_strdup(lex->mctx, name);
205 if (source->name == NULL) {
206 isc_mem_put(lex->mctx, source, sizeof(*source));
207 return (ISC_R_NOMEMORY);
209 source->pushback = NULL;
210 result = isc_buffer_allocate(lex->mctx, &source->pushback,
211 lex->max_token);
212 if (result != ISC_R_SUCCESS) {
213 isc_mem_free(lex->mctx, source->name);
214 isc_mem_put(lex->mctx, source, sizeof(*source));
215 return (result);
217 source->ignored = 0;
218 source->line = 1;
219 ISC_LIST_INITANDPREPEND(lex->sources, source, link);
221 return (ISC_R_SUCCESS);
224 isc_result_t
225 isc_lex_openfile(isc_lex_t *lex, const char *filename) {
226 isc_result_t result;
227 FILE *stream = NULL;
230 * Open 'filename' and make it the current input source for 'lex'.
233 REQUIRE(VALID_LEX(lex));
235 result = isc_stdio_open(filename, "r", &stream);
236 if (result != ISC_R_SUCCESS)
237 return (result);
239 result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename);
240 if (result != ISC_R_SUCCESS)
241 (void)fclose(stream);
242 return (result);
245 isc_result_t
246 isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
247 char name[128];
250 * Make 'stream' the current input source for 'lex'.
253 REQUIRE(VALID_LEX(lex));
255 snprintf(name, sizeof(name), "stream-%p", stream);
257 return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));
260 isc_result_t
261 isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
262 char name[128];
265 * Make 'buffer' the current input source for 'lex'.
268 REQUIRE(VALID_LEX(lex));
270 snprintf(name, sizeof(name), "buffer-%p", buffer);
272 return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));
275 isc_result_t
276 isc_lex_close(isc_lex_t *lex) {
277 inputsource *source;
280 * Close the most recently opened object (i.e. file or buffer).
283 REQUIRE(VALID_LEX(lex));
285 source = HEAD(lex->sources);
286 if (source == NULL)
287 return (ISC_R_NOMORE);
289 ISC_LIST_UNLINK(lex->sources, source, link);
290 if (source->is_file) {
291 if (source->need_close)
292 (void)fclose((FILE *)(source->input));
294 isc_mem_free(lex->mctx, source->name);
295 isc_buffer_free(&source->pushback);
296 isc_mem_put(lex->mctx, source, sizeof(*source));
298 return (ISC_R_SUCCESS);
301 typedef enum {
302 lexstate_start,
303 lexstate_crlf,
304 lexstate_string,
305 lexstate_number,
306 lexstate_maybecomment,
307 lexstate_ccomment,
308 lexstate_ccommentend,
309 lexstate_eatline,
310 lexstate_qstring
311 } lexstate;
313 #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
315 static void
316 pushback(inputsource *source, int c) {
317 REQUIRE(source->pushback->current > 0);
318 if (c == EOF) {
319 source->at_eof = ISC_FALSE;
320 return;
322 source->pushback->current--;
323 if (c == '\n')
324 source->line--;
327 static isc_result_t
328 pushandgrow(isc_lex_t *lex, inputsource *source, int c) {
329 if (isc_buffer_availablelength(source->pushback) == 0) {
330 isc_buffer_t *tbuf = NULL;
331 unsigned int oldlen;
332 isc_region_t used;
333 isc_result_t result;
335 oldlen = isc_buffer_length(source->pushback);
336 result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2);
337 if (result != ISC_R_SUCCESS)
338 return (result);
339 isc_buffer_usedregion(source->pushback, &used);
340 result = isc_buffer_copyregion(tbuf, &used);
341 INSIST(result == ISC_R_SUCCESS);
342 tbuf->current = source->pushback->current;
343 isc_buffer_free(&source->pushback);
344 source->pushback = tbuf;
346 isc_buffer_putuint8(source->pushback, (isc_uint8_t)c);
347 return (ISC_R_SUCCESS);
350 isc_result_t
351 isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
352 inputsource *source;
353 int c;
354 isc_boolean_t done = ISC_FALSE;
355 isc_boolean_t no_comments = ISC_FALSE;
356 isc_boolean_t escaped = ISC_FALSE;
357 lexstate state = lexstate_start;
358 lexstate saved_state = lexstate_start;
359 isc_buffer_t *buffer;
360 FILE *stream;
361 char *curr, *prev;
362 size_t remaining;
363 isc_uint32_t as_ulong;
364 unsigned int saved_options;
365 isc_result_t result;
368 * Get the next token.
371 REQUIRE(VALID_LEX(lex));
372 source = HEAD(lex->sources);
373 REQUIRE(tokenp != NULL);
375 if (source == NULL) {
376 if ((options & ISC_LEXOPT_NOMORE) != 0) {
377 tokenp->type = isc_tokentype_nomore;
378 return (ISC_R_SUCCESS);
380 return (ISC_R_NOMORE);
383 if (source->result != ISC_R_SUCCESS)
384 return (source->result);
386 lex->saved_paren_count = lex->paren_count;
387 source->saved_line = source->line;
389 if (isc_buffer_remaininglength(source->pushback) == 0 &&
390 source->at_eof)
392 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
393 lex->paren_count != 0) {
394 lex->paren_count = 0;
395 return (ISC_R_UNBALANCED);
397 if ((options & ISC_LEXOPT_EOF) != 0) {
398 tokenp->type = isc_tokentype_eof;
399 return (ISC_R_SUCCESS);
401 return (ISC_R_EOF);
404 isc_buffer_compact(source->pushback);
406 saved_options = options;
407 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
408 options &= ~IWSEOL;
410 curr = lex->data;
411 *curr = '\0';
413 prev = NULL;
414 remaining = lex->max_token;
416 #ifdef HAVE_FLOCKFILE
417 if (source->is_file)
418 flockfile(source->input);
419 #endif
421 do {
422 if (isc_buffer_remaininglength(source->pushback) == 0) {
423 if (source->is_file) {
424 stream = source->input;
426 #if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED)
427 c = getc_unlocked(stream);
428 #else
429 c = getc(stream);
430 #endif
431 if (c == EOF) {
432 if (ferror(stream)) {
433 source->result = ISC_R_IOERROR;
434 result = source->result;
435 goto done;
437 source->at_eof = ISC_TRUE;
439 } else {
440 buffer = source->input;
442 if (buffer->current == buffer->used) {
443 c = EOF;
444 source->at_eof = ISC_TRUE;
445 } else {
446 c = *((char *)buffer->base +
447 buffer->current);
448 buffer->current++;
451 if (c != EOF) {
452 source->result = pushandgrow(lex, source, c);
453 if (source->result != ISC_R_SUCCESS) {
454 result = source->result;
455 goto done;
460 if (!source->at_eof) {
461 if (state == lexstate_start)
462 /* Token has not started yet. */
463 source->ignored =
464 isc_buffer_consumedlength(source->pushback);
465 c = isc_buffer_getuint8(source->pushback);
466 } else {
467 c = EOF;
470 if (c == '\n')
471 source->line++;
473 if (lex->comment_ok && !no_comments) {
474 if (!escaped && c == ';' &&
475 ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE)
476 != 0)) {
477 saved_state = state;
478 state = lexstate_eatline;
479 no_comments = ISC_TRUE;
480 continue;
481 } else if (c == '/' &&
482 (lex->comments &
483 (ISC_LEXCOMMENT_C|
484 ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
485 saved_state = state;
486 state = lexstate_maybecomment;
487 no_comments = ISC_TRUE;
488 continue;
489 } else if (c == '#' &&
490 ((lex->comments & ISC_LEXCOMMENT_SHELL)
491 != 0)) {
492 saved_state = state;
493 state = lexstate_eatline;
494 no_comments = ISC_TRUE;
495 continue;
499 no_read:
500 /* INSIST(c == EOF || (c >= 0 && c <= 255)); */
501 switch (state) {
502 case lexstate_start:
503 if (c == EOF) {
504 lex->last_was_eol = ISC_FALSE;
505 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
506 lex->paren_count != 0) {
507 lex->paren_count = 0;
508 result = ISC_R_UNBALANCED;
509 goto done;
511 if ((options & ISC_LEXOPT_EOF) == 0) {
512 result = ISC_R_EOF;
513 goto done;
515 tokenp->type = isc_tokentype_eof;
516 done = ISC_TRUE;
517 } else if (c == ' ' || c == '\t') {
518 if (lex->last_was_eol &&
519 (options & ISC_LEXOPT_INITIALWS)
520 != 0) {
521 lex->last_was_eol = ISC_FALSE;
522 tokenp->type = isc_tokentype_initialws;
523 tokenp->value.as_char = c;
524 done = ISC_TRUE;
526 } else if (c == '\n') {
527 if ((options & ISC_LEXOPT_EOL) != 0) {
528 tokenp->type = isc_tokentype_eol;
529 done = ISC_TRUE;
531 lex->last_was_eol = ISC_TRUE;
532 } else if (c == '\r') {
533 if ((options & ISC_LEXOPT_EOL) != 0)
534 state = lexstate_crlf;
535 } else if (c == '"' &&
536 (options & ISC_LEXOPT_QSTRING) != 0) {
537 lex->last_was_eol = ISC_FALSE;
538 no_comments = ISC_TRUE;
539 state = lexstate_qstring;
540 } else if (lex->specials[c]) {
541 lex->last_was_eol = ISC_FALSE;
542 if ((c == '(' || c == ')') &&
543 (options & ISC_LEXOPT_DNSMULTILINE) != 0) {
544 if (c == '(') {
545 if (lex->paren_count == 0)
546 options &= ~IWSEOL;
547 lex->paren_count++;
548 } else {
549 if (lex->paren_count == 0) {
550 result = ISC_R_UNBALANCED;
551 goto done;
553 lex->paren_count--;
554 if (lex->paren_count == 0)
555 options =
556 saved_options;
558 continue;
560 tokenp->type = isc_tokentype_special;
561 tokenp->value.as_char = c;
562 done = ISC_TRUE;
563 } else if (isdigit((unsigned char)c) &&
564 (options & ISC_LEXOPT_NUMBER) != 0) {
565 lex->last_was_eol = ISC_FALSE;
566 state = lexstate_number;
567 goto no_read;
568 } else {
569 lex->last_was_eol = ISC_FALSE;
570 state = lexstate_string;
571 goto no_read;
573 break;
574 case lexstate_crlf:
575 if (c != '\n')
576 pushback(source, c);
577 tokenp->type = isc_tokentype_eol;
578 done = ISC_TRUE;
579 lex->last_was_eol = ISC_TRUE;
580 break;
581 case lexstate_number:
582 if (c == EOF || !isdigit((unsigned char)c)) {
583 if (c == ' ' || c == '\t' || c == '\r' ||
584 c == '\n' || c == EOF ||
585 lex->specials[c]) {
586 int base;
587 if ((options & ISC_LEXOPT_CNUMBER) != 0)
588 base = 0;
589 else
590 base = 10;
591 pushback(source, c);
593 result = isc_parse_uint32(&as_ulong,
594 lex->data,
595 base);
596 if (result == ISC_R_SUCCESS) {
597 tokenp->type =
598 isc_tokentype_number;
599 tokenp->value.as_ulong =
600 as_ulong;
601 } else if (result == ISC_R_BADNUMBER) {
602 isc_tokenvalue_t *v;
604 tokenp->type =
605 isc_tokentype_string;
606 v = &(tokenp->value);
607 v->as_textregion.base =
608 lex->data;
609 v->as_textregion.length =
610 lex->max_token -
611 remaining;
612 } else
613 goto done;
614 done = ISC_TRUE;
615 continue;
616 } else if (!(options & ISC_LEXOPT_CNUMBER) ||
617 ((c != 'x' && c != 'X') ||
618 (curr != &lex->data[1]) ||
619 (lex->data[0] != '0'))) {
620 /* Above test supports hex numbers */
621 state = lexstate_string;
624 if (remaining == 0U) {
625 result = grow_data(lex, &remaining,
626 &curr, &prev);
627 if (result != ISC_R_SUCCESS)
628 goto done;
630 INSIST(remaining > 0U);
631 *curr++ = c;
632 *curr = '\0';
633 remaining--;
634 break;
635 case lexstate_string:
637 * EOF needs to be checked before lex->specials[c]
638 * as lex->specials[EOF] is not a good idea.
640 if (c == '\r' || c == '\n' || c == EOF ||
641 (!escaped &&
642 (c == ' ' || c == '\t' || lex->specials[c]))) {
643 pushback(source, c);
644 if (source->result != ISC_R_SUCCESS) {
645 result = source->result;
646 goto done;
648 tokenp->type = isc_tokentype_string;
649 tokenp->value.as_textregion.base = lex->data;
650 tokenp->value.as_textregion.length =
651 lex->max_token - remaining;
652 done = ISC_TRUE;
653 continue;
655 if ((options & ISC_LEXOPT_ESCAPE) != 0)
656 escaped = (!escaped && c == '\\') ?
657 ISC_TRUE : ISC_FALSE;
658 if (remaining == 0U) {
659 result = grow_data(lex, &remaining,
660 &curr, &prev);
661 if (result != ISC_R_SUCCESS)
662 goto done;
664 INSIST(remaining > 0U);
665 *curr++ = c;
666 *curr = '\0';
667 remaining--;
668 break;
669 case lexstate_maybecomment:
670 if (c == '*' &&
671 (lex->comments & ISC_LEXCOMMENT_C) != 0) {
672 state = lexstate_ccomment;
673 continue;
674 } else if (c == '/' &&
675 (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
676 state = lexstate_eatline;
677 continue;
679 pushback(source, c);
680 c = '/';
681 no_comments = ISC_FALSE;
682 state = saved_state;
683 goto no_read;
684 case lexstate_ccomment:
685 if (c == EOF) {
686 result = ISC_R_UNEXPECTEDEND;
687 goto done;
689 if (c == '*')
690 state = lexstate_ccommentend;
691 break;
692 case lexstate_ccommentend:
693 if (c == EOF) {
694 result = ISC_R_UNEXPECTEDEND;
695 goto done;
697 if (c == '/') {
699 * C-style comments become a single space.
700 * We do this to ensure that a comment will
701 * act as a delimiter for strings and
702 * numbers.
704 c = ' ';
705 no_comments = ISC_FALSE;
706 state = saved_state;
707 goto no_read;
708 } else if (c != '*')
709 state = lexstate_ccomment;
710 break;
711 case lexstate_eatline:
712 if (c == EOF) {
713 result = ISC_R_UNEXPECTEDEND;
714 goto done;
716 if (c == '\n') {
717 no_comments = ISC_FALSE;
718 state = saved_state;
719 goto no_read;
721 break;
722 case lexstate_qstring:
723 if (c == EOF) {
724 result = ISC_R_UNEXPECTEDEND;
725 goto done;
727 if (c == '"') {
728 if (escaped) {
729 escaped = ISC_FALSE;
731 * Overwrite the preceding backslash.
733 INSIST(prev != NULL);
734 *prev = '"';
735 } else {
736 tokenp->type = isc_tokentype_qstring;
737 tokenp->value.as_textregion.base =
738 lex->data;
739 tokenp->value.as_textregion.length =
740 lex->max_token - remaining;
741 no_comments = ISC_FALSE;
742 done = ISC_TRUE;
744 } else {
745 if (c == '\n' && !escaped &&
746 (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
747 pushback(source, c);
748 result = ISC_R_UNBALANCEDQUOTES;
749 goto done;
751 if (c == '\\' && !escaped)
752 escaped = ISC_TRUE;
753 else
754 escaped = ISC_FALSE;
755 if (remaining == 0U) {
756 result = grow_data(lex, &remaining,
757 &curr, &prev);
758 if (result != ISC_R_SUCCESS)
759 goto done;
761 INSIST(remaining > 0U);
762 prev = curr;
763 *curr++ = c;
764 *curr = '\0';
765 remaining--;
767 break;
768 default:
769 FATAL_ERROR(__FILE__, __LINE__,
770 isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX,
771 ISC_MSG_UNEXPECTEDSTATE,
772 "Unexpected state %d"),
773 state);
774 /* Does not return. */
777 } while (!done);
779 result = ISC_R_SUCCESS;
780 done:
781 #ifdef HAVE_FLOCKFILE
782 if (source->is_file)
783 funlockfile(source->input);
784 #endif
785 return (result);
788 isc_result_t
789 isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
790 isc_tokentype_t expect, isc_boolean_t eol)
792 unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
793 ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
794 isc_result_t result;
796 if (expect == isc_tokentype_qstring)
797 options |= ISC_LEXOPT_QSTRING;
798 else if (expect == isc_tokentype_number)
799 options |= ISC_LEXOPT_NUMBER;
800 result = isc_lex_gettoken(lex, options, token);
801 if (result == ISC_R_RANGE)
802 isc_lex_ungettoken(lex, token);
803 if (result != ISC_R_SUCCESS)
804 return (result);
806 if (eol && ((token->type == isc_tokentype_eol) ||
807 (token->type == isc_tokentype_eof)))
808 return (ISC_R_SUCCESS);
809 if (token->type == isc_tokentype_string &&
810 expect == isc_tokentype_qstring)
811 return (ISC_R_SUCCESS);
812 if (token->type != expect) {
813 isc_lex_ungettoken(lex, token);
814 if (token->type == isc_tokentype_eol ||
815 token->type == isc_tokentype_eof)
816 return (ISC_R_UNEXPECTEDEND);
817 if (expect == isc_tokentype_number)
818 return (ISC_R_BADNUMBER);
819 return (ISC_R_UNEXPECTEDTOKEN);
821 return (ISC_R_SUCCESS);
824 void
825 isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
826 inputsource *source;
828 * Unget the current token.
831 REQUIRE(VALID_LEX(lex));
832 source = HEAD(lex->sources);
833 REQUIRE(source != NULL);
834 REQUIRE(tokenp != NULL);
835 REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
836 tokenp->type == isc_tokentype_eof);
838 UNUSED(tokenp);
840 isc_buffer_first(source->pushback);
841 lex->paren_count = lex->saved_paren_count;
842 source->line = source->saved_line;
843 source->at_eof = ISC_FALSE;
846 void
847 isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
849 inputsource *source;
851 REQUIRE(VALID_LEX(lex));
852 source = HEAD(lex->sources);
853 REQUIRE(source != NULL);
854 REQUIRE(tokenp != NULL);
855 REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
856 tokenp->type == isc_tokentype_eof);
858 UNUSED(tokenp);
860 INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
861 r->base = (unsigned char *)isc_buffer_base(source->pushback) +
862 source->ignored;
863 r->length = isc_buffer_consumedlength(source->pushback) -
864 source->ignored;
868 char *
869 isc_lex_getsourcename(isc_lex_t *lex) {
870 inputsource *source;
872 REQUIRE(VALID_LEX(lex));
873 source = HEAD(lex->sources);
875 if (source == NULL)
876 return (NULL);
878 return (source->name);
881 unsigned long
882 isc_lex_getsourceline(isc_lex_t *lex) {
883 inputsource *source;
885 REQUIRE(VALID_LEX(lex));
886 source = HEAD(lex->sources);
888 if (source == NULL)
889 return (0);
891 return (source->line);
895 isc_result_t
896 isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
897 inputsource *source;
898 char *newname;
900 REQUIRE(VALID_LEX(lex));
901 source = HEAD(lex->sources);
903 if (source == NULL)
904 return(ISC_R_NOTFOUND);
905 newname = isc_mem_strdup(lex->mctx, name);
906 if (newname == NULL)
907 return (ISC_R_NOMEMORY);
908 isc_mem_free(lex->mctx, source->name);
909 source->name = newname;
910 return (ISC_R_SUCCESS);
913 isc_boolean_t
914 isc_lex_isfile(isc_lex_t *lex) {
915 inputsource *source;
917 REQUIRE(VALID_LEX(lex));
919 source = HEAD(lex->sources);
921 if (source == NULL)
922 return (ISC_FALSE);
924 return (source->is_file);