Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / isc / lex.c
blob5ea241b59b0875e3ad80394c287e5a40302b1177
1 /* $NetBSD: lex.c,v 1.6 2014/12/10 04:37:59 christos Exp $ */
3 /*
4 * Copyright (C) 2004, 2005, 2007, 2013, 2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1998-2003 Internet Software Consortium.
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.
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.
20 /* Id: lex.c,v 1.86 2007/09/17 09:56:29 shane Exp */
22 /*! \file */
24 #include <config.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <stdlib.h>
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>
41 typedef struct inputsource {
42 isc_result_t result;
43 isc_boolean_t is_file;
44 isc_boolean_t need_close;
45 isc_boolean_t at_eof;
46 isc_buffer_t * pushback;
47 unsigned int ignored;
48 void * input;
49 char * name;
50 unsigned long line;
51 unsigned long saved_line;
52 ISC_LINK(struct inputsource) link;
53 } inputsource;
55 #define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!')
56 #define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC)
58 struct isc_lex {
59 /* Unlocked. */
60 unsigned int magic;
61 isc_mem_t * mctx;
62 size_t max_token;
63 char * data;
64 unsigned int comments;
65 isc_boolean_t comment_ok;
66 isc_boolean_t last_was_eol;
67 unsigned int paren_count;
68 unsigned int saved_paren_count;
69 isc_lexspecials_t specials;
70 LIST(struct inputsource) sources;
73 static inline isc_result_t
74 grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
75 char *new;
77 new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
78 if (new == NULL)
79 return (ISC_R_NOMEMORY);
80 memmove(new, lex->data, lex->max_token + 1);
81 *currp = new + (*currp - lex->data);
82 if (*prevp != NULL)
83 *prevp = new + (*prevp - lex->data);
84 isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
85 lex->data = new;
86 *remainingp += lex->max_token;
87 lex->max_token *= 2;
88 return (ISC_R_SUCCESS);
91 isc_result_t
92 isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
93 isc_lex_t *lex;
96 * Create a lexer.
99 REQUIRE(lexp != NULL && *lexp == NULL);
100 REQUIRE(max_token > 0U);
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);
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;
121 *lexp = lex;
123 return (ISC_R_SUCCESS);
126 void
127 isc_lex_destroy(isc_lex_t **lexp) {
128 isc_lex_t *lex;
131 * Destroy the lexer.
134 REQUIRE(lexp != NULL);
135 lex = *lexp;
136 REQUIRE(VALID_LEX(lex));
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));
145 *lexp = NULL;
148 unsigned int
149 isc_lex_getcomments(isc_lex_t *lex) {
151 * Return the current lexer commenting styles.
154 REQUIRE(VALID_LEX(lex));
156 return (lex->comments);
159 void
160 isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
162 * Set allowed lexer commenting styles.
165 REQUIRE(VALID_LEX(lex));
167 lex->comments = comments;
170 void
171 isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
173 * Put the current list of specials into 'specials'.
176 REQUIRE(VALID_LEX(lex));
178 memmove(specials, lex->specials, 256);
181 void
182 isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
184 * The characters in 'specials' are returned as tokens. Along with
185 * whitespace, they delimit strings and numbers.
188 REQUIRE(VALID_LEX(lex));
190 memmove(lex->specials, specials, 256);
193 static inline isc_result_t
194 new_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close,
195 void *input, const char *name)
197 inputsource *source;
198 isc_result_t result;
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);
213 source->pushback = NULL;
214 result = isc_buffer_allocate(lex->mctx, &source->pushback,
215 (unsigned int)lex->max_token);
216 if (result != ISC_R_SUCCESS) {
217 isc_mem_free(lex->mctx, source->name);
218 isc_mem_put(lex->mctx, source, sizeof(*source));
219 return (result);
221 source->ignored = 0;
222 source->line = 1;
223 ISC_LIST_INITANDPREPEND(lex->sources, source, link);
225 return (ISC_R_SUCCESS);
228 isc_result_t
229 isc_lex_openfile(isc_lex_t *lex, const char *filename) {
230 isc_result_t result;
231 FILE *stream = NULL;
234 * Open 'filename' and make it the current input source for 'lex'.
237 REQUIRE(VALID_LEX(lex));
239 result = isc_stdio_open(filename, "r", &stream);
240 if (result != ISC_R_SUCCESS)
241 return (result);
243 result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename);
244 if (result != ISC_R_SUCCESS)
245 (void)fclose(stream);
246 return (result);
249 isc_result_t
250 isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
251 char name[128];
254 * Make 'stream' the current input source for 'lex'.
257 REQUIRE(VALID_LEX(lex));
259 snprintf(name, sizeof(name), "stream-%p", stream);
261 return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));
264 isc_result_t
265 isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
266 char name[128];
269 * Make 'buffer' the current input source for 'lex'.
272 REQUIRE(VALID_LEX(lex));
274 snprintf(name, sizeof(name), "buffer-%p", buffer);
276 return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));
279 isc_result_t
280 isc_lex_close(isc_lex_t *lex) {
281 inputsource *source;
284 * Close the most recently opened object (i.e. file or buffer).
287 REQUIRE(VALID_LEX(lex));
289 source = HEAD(lex->sources);
290 if (source == NULL)
291 return (ISC_R_NOMORE);
293 ISC_LIST_UNLINK(lex->sources, source, link);
294 if (source->is_file) {
295 if (source->need_close)
296 (void)fclose((FILE *)(source->input));
298 isc_mem_free(lex->mctx, source->name);
299 isc_buffer_free(&source->pushback);
300 isc_mem_put(lex->mctx, source, sizeof(*source));
302 return (ISC_R_SUCCESS);
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;
317 #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
319 static void
320 pushback(inputsource *source, int c) {
321 REQUIRE(source->pushback->current > 0);
322 if (c == EOF) {
323 source->at_eof = ISC_FALSE;
324 return;
326 source->pushback->current--;
327 if (c == '\n')
328 source->line--;
331 static isc_result_t
332 pushandgrow(isc_lex_t *lex, inputsource *source, int c) {
333 if (isc_buffer_availablelength(source->pushback) == 0) {
334 isc_buffer_t *tbuf = NULL;
335 unsigned int oldlen;
336 isc_region_t used;
337 isc_result_t result;
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;
350 isc_buffer_putuint8(source->pushback, (isc_uint8_t)c);
351 return (ISC_R_SUCCESS);
354 isc_result_t
355 isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
356 inputsource *source;
357 int c;
358 isc_boolean_t done = ISC_FALSE;
359 isc_boolean_t no_comments = ISC_FALSE;
360 isc_boolean_t escaped = ISC_FALSE;
361 lexstate state = lexstate_start;
362 lexstate saved_state = lexstate_start;
363 isc_buffer_t *buffer;
364 FILE *stream;
365 char *curr, *prev;
366 size_t remaining;
367 isc_uint32_t as_ulong;
368 unsigned int saved_options;
369 isc_result_t result;
372 * Get the next token.
375 REQUIRE(VALID_LEX(lex));
376 source = HEAD(lex->sources);
377 REQUIRE(tokenp != NULL);
379 if (source == NULL) {
380 if ((options & ISC_LEXOPT_NOMORE) != 0) {
381 tokenp->type = isc_tokentype_nomore;
382 return (ISC_R_SUCCESS);
384 return (ISC_R_NOMORE);
387 if (source->result != ISC_R_SUCCESS)
388 return (source->result);
390 lex->saved_paren_count = lex->paren_count;
391 source->saved_line = source->line;
393 if (isc_buffer_remaininglength(source->pushback) == 0 &&
394 source->at_eof)
396 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
397 lex->paren_count != 0) {
398 lex->paren_count = 0;
399 return (ISC_R_UNBALANCED);
401 if ((options & ISC_LEXOPT_EOF) != 0) {
402 tokenp->type = isc_tokentype_eof;
403 return (ISC_R_SUCCESS);
405 return (ISC_R_EOF);
408 isc_buffer_compact(source->pushback);
410 saved_options = options;
411 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
412 options &= ~IWSEOL;
414 curr = lex->data;
415 *curr = '\0';
417 prev = NULL;
418 remaining = lex->max_token;
420 #ifdef HAVE_FLOCKFILE
421 if (source->is_file)
422 flockfile(source->input);
423 #endif
425 do {
426 if (isc_buffer_remaininglength(source->pushback) == 0) {
427 if (source->is_file) {
428 stream = source->input;
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;
441 source->at_eof = ISC_TRUE;
443 } else {
444 buffer = source->input;
446 if (buffer->current == buffer->used) {
447 c = EOF;
448 source->at_eof = ISC_TRUE;
449 } else {
450 c = *((unsigned char *)buffer->base +
451 buffer->current);
452 buffer->current++;
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;
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;
474 if (c == '\n')
475 source->line++;
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;
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;
515 if ((options & ISC_LEXOPT_EOF) == 0) {
516 result = ISC_R_EOF;
517 goto done;
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;
530 } else if (c == '\n') {
531 if ((options & ISC_LEXOPT_EOL) != 0) {
532 tokenp->type = isc_tokentype_eol;
533 done = ISC_TRUE;
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;
557 lex->paren_count--;
558 if (lex->paren_count == 0)
559 options =
560 saved_options;
562 continue;
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;
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);
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;
614 tokenp->type =
615 isc_tokentype_string;
616 v = &(tokenp->value);
617 v->as_textregion.base =
618 lex->data;
619 v->as_textregion.length =
620 (unsigned int)
621 (lex->max_token -
622 remaining);
623 } else
624 goto done;
625 done = ISC_TRUE;
626 continue;
627 } else if (!(options & ISC_LEXOPT_CNUMBER) ||
628 ((c != 'x' && c != 'X') ||
629 (curr != &lex->data[1]) ||
630 (lex->data[0] != '0'))) {
631 /* Above test supports hex numbers */
632 state = lexstate_string;
634 } else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
635 (c == '8' || c == '9')) {
636 state = lexstate_string;
638 if (remaining == 0U) {
639 result = grow_data(lex, &remaining,
640 &curr, &prev);
641 if (result != ISC_R_SUCCESS)
642 goto done;
644 INSIST(remaining > 0U);
645 *curr++ = c;
646 *curr = '\0';
647 remaining--;
648 break;
649 case lexstate_string:
651 * EOF needs to be checked before lex->specials[c]
652 * as lex->specials[EOF] is not a good idea.
654 if (c == '\r' || c == '\n' || c == EOF ||
655 (!escaped &&
656 (c == ' ' || c == '\t' || lex->specials[c]))) {
657 pushback(source, c);
658 if (source->result != ISC_R_SUCCESS) {
659 result = source->result;
660 goto done;
662 tokenp->type = isc_tokentype_string;
663 tokenp->value.as_textregion.base = lex->data;
664 tokenp->value.as_textregion.length =
665 (unsigned int)
666 (lex->max_token - remaining);
667 done = ISC_TRUE;
668 continue;
670 if ((options & ISC_LEXOPT_ESCAPE) != 0)
671 escaped = (!escaped && c == '\\') ?
672 ISC_TRUE : ISC_FALSE;
673 if (remaining == 0U) {
674 result = grow_data(lex, &remaining,
675 &curr, &prev);
676 if (result != ISC_R_SUCCESS)
677 goto done;
679 INSIST(remaining > 0U);
680 *curr++ = c;
681 *curr = '\0';
682 remaining--;
683 break;
684 case lexstate_maybecomment:
685 if (c == '*' &&
686 (lex->comments & ISC_LEXCOMMENT_C) != 0) {
687 state = lexstate_ccomment;
688 continue;
689 } else if (c == '/' &&
690 (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
691 state = lexstate_eatline;
692 continue;
694 pushback(source, c);
695 c = '/';
696 no_comments = ISC_FALSE;
697 state = saved_state;
698 goto no_read;
699 case lexstate_ccomment:
700 if (c == EOF) {
701 result = ISC_R_UNEXPECTEDEND;
702 goto done;
704 if (c == '*')
705 state = lexstate_ccommentend;
706 break;
707 case lexstate_ccommentend:
708 if (c == EOF) {
709 result = ISC_R_UNEXPECTEDEND;
710 goto done;
712 if (c == '/') {
714 * C-style comments become a single space.
715 * We do this to ensure that a comment will
716 * act as a delimiter for strings and
717 * numbers.
719 c = ' ';
720 no_comments = ISC_FALSE;
721 state = saved_state;
722 goto no_read;
723 } else if (c != '*')
724 state = lexstate_ccomment;
725 break;
726 case lexstate_eatline:
727 if ((c == '\n') || (c == EOF)) {
728 no_comments = ISC_FALSE;
729 state = saved_state;
730 goto no_read;
732 break;
733 case lexstate_qstring:
734 if (c == EOF) {
735 result = ISC_R_UNEXPECTEDEND;
736 goto done;
738 if (c == '"') {
739 if (escaped) {
740 escaped = ISC_FALSE;
742 * Overwrite the preceding backslash.
744 INSIST(prev != NULL);
745 *prev = '"';
746 } else {
747 tokenp->type = isc_tokentype_qstring;
748 tokenp->value.as_textregion.base =
749 lex->data;
750 tokenp->value.as_textregion.length =
751 (unsigned int)
752 (lex->max_token - remaining);
753 no_comments = ISC_FALSE;
754 done = ISC_TRUE;
756 } else {
757 if (c == '\n' && !escaped &&
758 (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
759 pushback(source, c);
760 result = ISC_R_UNBALANCEDQUOTES;
761 goto done;
763 if (c == '\\' && !escaped)
764 escaped = ISC_TRUE;
765 else
766 escaped = ISC_FALSE;
767 if (remaining == 0U) {
768 result = grow_data(lex, &remaining,
769 &curr, &prev);
770 if (result != ISC_R_SUCCESS)
771 goto done;
773 INSIST(remaining > 0U);
774 prev = curr;
775 *curr++ = c;
776 *curr = '\0';
777 remaining--;
779 break;
780 default:
781 FATAL_ERROR(__FILE__, __LINE__,
782 isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX,
783 ISC_MSG_UNEXPECTEDSTATE,
784 "Unexpected state %d"),
785 state);
786 /* Does not return. */
789 } while (!done);
791 result = ISC_R_SUCCESS;
792 done:
793 #ifdef HAVE_FLOCKFILE
794 if (source->is_file)
795 funlockfile(source->input);
796 #endif
797 return (result);
800 isc_result_t
801 isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
802 isc_tokentype_t expect, isc_boolean_t eol)
804 unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
805 ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
806 isc_result_t result;
808 if (expect == isc_tokentype_qstring)
809 options |= ISC_LEXOPT_QSTRING;
810 else if (expect == isc_tokentype_number)
811 options |= ISC_LEXOPT_NUMBER;
812 result = isc_lex_gettoken(lex, options, token);
813 if (result == ISC_R_RANGE)
814 isc_lex_ungettoken(lex, token);
815 if (result != ISC_R_SUCCESS)
816 return (result);
818 if (eol && ((token->type == isc_tokentype_eol) ||
819 (token->type == isc_tokentype_eof)))
820 return (ISC_R_SUCCESS);
821 if (token->type == isc_tokentype_string &&
822 expect == isc_tokentype_qstring)
823 return (ISC_R_SUCCESS);
824 if (token->type != expect) {
825 isc_lex_ungettoken(lex, token);
826 if (token->type == isc_tokentype_eol ||
827 token->type == isc_tokentype_eof)
828 return (ISC_R_UNEXPECTEDEND);
829 if (expect == isc_tokentype_number)
830 return (ISC_R_BADNUMBER);
831 return (ISC_R_UNEXPECTEDTOKEN);
833 return (ISC_R_SUCCESS);
836 isc_result_t
837 isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol)
839 unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
840 ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE|
841 ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL;
842 isc_result_t result;
844 result = isc_lex_gettoken(lex, options, token);
845 if (result == ISC_R_RANGE)
846 isc_lex_ungettoken(lex, token);
847 if (result != ISC_R_SUCCESS)
848 return (result);
850 if (eol && ((token->type == isc_tokentype_eol) ||
851 (token->type == isc_tokentype_eof)))
852 return (ISC_R_SUCCESS);
853 if (token->type != isc_tokentype_number) {
854 isc_lex_ungettoken(lex, token);
855 if (token->type == isc_tokentype_eol ||
856 token->type == isc_tokentype_eof)
857 return (ISC_R_UNEXPECTEDEND);
858 return (ISC_R_BADNUMBER);
860 return (ISC_R_SUCCESS);
863 void
864 isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
865 inputsource *source;
867 * Unget the current token.
870 REQUIRE(VALID_LEX(lex));
871 source = HEAD(lex->sources);
872 REQUIRE(source != NULL);
873 REQUIRE(tokenp != NULL);
874 REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
875 tokenp->type == isc_tokentype_eof);
877 UNUSED(tokenp);
879 isc_buffer_first(source->pushback);
880 lex->paren_count = lex->saved_paren_count;
881 source->line = source->saved_line;
882 source->at_eof = ISC_FALSE;
885 void
886 isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
888 inputsource *source;
890 REQUIRE(VALID_LEX(lex));
891 source = HEAD(lex->sources);
892 REQUIRE(source != NULL);
893 REQUIRE(tokenp != NULL);
894 REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
895 tokenp->type == isc_tokentype_eof);
897 UNUSED(tokenp);
899 INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
900 r->base = (unsigned char *)isc_buffer_base(source->pushback) +
901 source->ignored;
902 r->length = isc_buffer_consumedlength(source->pushback) -
903 source->ignored;
907 char *
908 isc_lex_getsourcename(isc_lex_t *lex) {
909 inputsource *source;
911 REQUIRE(VALID_LEX(lex));
912 source = HEAD(lex->sources);
914 if (source == NULL)
915 return (NULL);
917 return (source->name);
920 unsigned long
921 isc_lex_getsourceline(isc_lex_t *lex) {
922 inputsource *source;
924 REQUIRE(VALID_LEX(lex));
925 source = HEAD(lex->sources);
927 if (source == NULL)
928 return (0);
930 return (source->line);
934 isc_result_t
935 isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
936 inputsource *source;
937 char *newname;
939 REQUIRE(VALID_LEX(lex));
940 source = HEAD(lex->sources);
942 if (source == NULL)
943 return(ISC_R_NOTFOUND);
944 newname = isc_mem_strdup(lex->mctx, name);
945 if (newname == NULL)
946 return (ISC_R_NOMEMORY);
947 isc_mem_free(lex->mctx, source->name);
948 source->name = newname;
949 return (ISC_R_SUCCESS);
952 isc_boolean_t
953 isc_lex_isfile(isc_lex_t *lex) {
954 inputsource *source;
956 REQUIRE(VALID_LEX(lex));
958 source = HEAD(lex->sources);
960 if (source == NULL)
961 return (ISC_FALSE);
963 return (source->is_file);