Annotation of embedaddon/ntp/lib/isc/lex.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
3: * Copyright (C) 1998-2003 Internet Software Consortium.
4: *
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.
8: *
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.
16: */
17:
18: /* $Id: lex.c,v 1.86 2007/09/17 09:56:29 shane Exp $ */
19:
20: /*! \file */
21:
22: #include <config.h>
23:
24: #include <ctype.h>
25: #include <errno.h>
26: #include <stdlib.h>
27:
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>
38:
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;
52:
53: #define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!')
54: #define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC)
55:
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;
69: };
70:
71: static inline isc_result_t
72: grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
73: char *new;
74:
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);
87: }
88:
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;
92:
93: /*
94: * Create a lexer.
95: */
96:
97: REQUIRE(lexp != NULL && *lexp == NULL);
98: REQUIRE(max_token > 0U);
99:
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);
107: }
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;
118:
119: *lexp = lex;
120:
121: return (ISC_R_SUCCESS);
122: }
123:
124: void
125: isc_lex_destroy(isc_lex_t **lexp) {
126: isc_lex_t *lex;
127:
128: /*
129: * Destroy the lexer.
130: */
131:
132: REQUIRE(lexp != NULL);
133: lex = *lexp;
134: REQUIRE(VALID_LEX(lex));
135:
136: while (!EMPTY(lex->sources))
137: RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
138: if (lex->data != NULL)
139: isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
140: lex->magic = 0;
141: isc_mem_put(lex->mctx, lex, sizeof(*lex));
142:
143: *lexp = NULL;
144: }
145:
146: unsigned int
147: isc_lex_getcomments(isc_lex_t *lex) {
148: /*
149: * Return the current lexer commenting styles.
150: */
151:
152: REQUIRE(VALID_LEX(lex));
153:
154: return (lex->comments);
155: }
156:
157: void
158: isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
159: /*
160: * Set allowed lexer commenting styles.
161: */
162:
163: REQUIRE(VALID_LEX(lex));
164:
165: lex->comments = comments;
166: }
167:
168: void
169: isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
170: /*
171: * Put the current list of specials into 'specials'.
172: */
173:
174: REQUIRE(VALID_LEX(lex));
175:
176: memcpy(specials, lex->specials, 256);
177: }
178:
179: void
180: isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
181: /*
182: * The characters in 'specials' are returned as tokens. Along with
183: * whitespace, they delimit strings and numbers.
184: */
185:
186: REQUIRE(VALID_LEX(lex));
187:
188: memcpy(lex->specials, specials, 256);
189: }
190:
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)
194: {
195: inputsource *source;
196: isc_result_t result;
197:
198: source = isc_mem_get(lex->mctx, sizeof(*source));
199: if (source == NULL)
200: return (ISC_R_NOMEMORY);
201: source->result = ISC_R_SUCCESS;
202: source->is_file = is_file;
203: source->need_close = need_close;
204: source->at_eof = 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);
210: }
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);
218: }
219: source->ignored = 0;
220: source->line = 1;
221: ISC_LIST_INITANDPREPEND(lex->sources, source, link);
222:
223: return (ISC_R_SUCCESS);
224: }
225:
226: isc_result_t
227: isc_lex_openfile(isc_lex_t *lex, const char *filename) {
228: isc_result_t result;
229: FILE *stream = NULL;
230:
231: /*
232: * Open 'filename' and make it the current input source for 'lex'.
233: */
234:
235: REQUIRE(VALID_LEX(lex));
236:
237: result = isc_stdio_open(filename, "r", &stream);
238: if (result != ISC_R_SUCCESS)
239: return (result);
240:
241: result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename);
242: if (result != ISC_R_SUCCESS)
243: (void)fclose(stream);
244: return (result);
245: }
246:
247: isc_result_t
248: isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
249: char name[128];
250:
251: /*
252: * Make 'stream' the current input source for 'lex'.
253: */
254:
255: REQUIRE(VALID_LEX(lex));
256:
257: snprintf(name, sizeof(name), "stream-%p", stream);
258:
259: return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));
260: }
261:
262: isc_result_t
263: isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
264: char name[128];
265:
266: /*
267: * Make 'buffer' the current input source for 'lex'.
268: */
269:
270: REQUIRE(VALID_LEX(lex));
271:
272: snprintf(name, sizeof(name), "buffer-%p", buffer);
273:
274: return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));
275: }
276:
277: isc_result_t
278: isc_lex_close(isc_lex_t *lex) {
279: inputsource *source;
280:
281: /*
282: * Close the most recently opened object (i.e. file or buffer).
283: */
284:
285: REQUIRE(VALID_LEX(lex));
286:
287: source = HEAD(lex->sources);
288: if (source == NULL)
289: return (ISC_R_NOMORE);
290:
291: ISC_LIST_UNLINK(lex->sources, source, link);
292: if (source->is_file) {
293: if (source->need_close)
294: (void)fclose((FILE *)(source->input));
295: }
296: isc_mem_free(lex->mctx, source->name);
297: isc_buffer_free(&source->pushback);
298: isc_mem_put(lex->mctx, source, sizeof(*source));
299:
300: return (ISC_R_SUCCESS);
301: }
302:
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;
314:
315: #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
316:
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;
323: }
324: source->pushback->current--;
325: if (c == '\n')
326: source->line--;
327: }
328:
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;
336:
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;
347: }
348: isc_buffer_putuint8(source->pushback, (isc_uint8_t)c);
349: return (ISC_R_SUCCESS);
350: }
351:
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;
368:
369: /*
370: * Get the next token.
371: */
372:
373: REQUIRE(VALID_LEX(lex));
374: source = HEAD(lex->sources);
375: REQUIRE(tokenp != NULL);
376:
377: if (source == NULL) {
378: if ((options & ISC_LEXOPT_NOMORE) != 0) {
379: tokenp->type = isc_tokentype_nomore;
380: return (ISC_R_SUCCESS);
381: }
382: return (ISC_R_NOMORE);
383: }
384:
385: if (source->result != ISC_R_SUCCESS)
386: return (source->result);
387:
388: lex->saved_paren_count = lex->paren_count;
389: source->saved_line = source->line;
390:
391: if (isc_buffer_remaininglength(source->pushback) == 0 &&
392: source->at_eof)
393: {
394: if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
395: lex->paren_count != 0) {
396: lex->paren_count = 0;
397: return (ISC_R_UNBALANCED);
398: }
399: if ((options & ISC_LEXOPT_EOF) != 0) {
400: tokenp->type = isc_tokentype_eof;
401: return (ISC_R_SUCCESS);
402: }
403: return (ISC_R_EOF);
404: }
405:
406: isc_buffer_compact(source->pushback);
407:
408: saved_options = options;
409: if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
410: options &= ~IWSEOL;
411:
412: curr = lex->data;
413: *curr = '\0';
414:
415: prev = NULL;
416: remaining = lex->max_token;
417:
418: #ifdef HAVE_FLOCKFILE
419: if (source->is_file)
420: flockfile(source->input);
421: #endif
422:
423: do {
424: if (isc_buffer_remaininglength(source->pushback) == 0) {
425: if (source->is_file) {
426: stream = source->input;
427:
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;
438: }
439: source->at_eof = ISC_TRUE;
440: }
441: } else {
442: buffer = source->input;
443:
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++;
451: }
452: }
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;
458: }
459: }
460: }
461:
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;
470: }
471:
472: if (c == '\n')
473: source->line++;
474:
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;
498: }
499: }
500:
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;
512: }
513: if ((options & ISC_LEXOPT_EOF) == 0) {
514: result = ISC_R_EOF;
515: goto done;
516: }
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;
527: }
528: } else if (c == '\n') {
529: if ((options & ISC_LEXOPT_EOL) != 0) {
530: tokenp->type = isc_tokentype_eol;
531: done = ISC_TRUE;
532: }
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;
554: }
555: lex->paren_count--;
556: if (lex->paren_count == 0)
557: options =
558: saved_options;
559: }
560: continue;
561: }
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;
578: }
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);
600:
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;
611:
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;
630: }
631: } else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
632: (c == '8' || c == '9')) {
633: state = lexstate_string;
634: }
635: if (remaining == 0U) {
636: result = grow_data(lex, &remaining,
637: &curr, &prev);
638: if (result != ISC_R_SUCCESS)
639: goto done;
640: }
641: INSIST(remaining > 0U);
642: *curr++ = c;
643: *curr = '\0';
644: remaining--;
645: break;
646: case lexstate_string:
647: /*
648: * EOF needs to be checked before lex->specials[c]
649: * as lex->specials[EOF] is not a good idea.
650: */
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;
658: }
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;
665: }
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;
674: }
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;
689: }
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;
699: }
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;
707: }
708: if (c == '/') {
709: /*
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.
714: */
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;
727: }
728: break;
729: case lexstate_qstring:
730: if (c == EOF) {
731: result = ISC_R_UNEXPECTEDEND;
732: goto done;
733: }
734: if (c == '"') {
735: if (escaped) {
736: escaped = ISC_FALSE;
737: /*
738: * Overwrite the preceding backslash.
739: */
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;
750: }
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;
757: }
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;
767: }
768: INSIST(remaining > 0U);
769: prev = curr;
770: *curr++ = c;
771: *curr = '\0';
772: remaining--;
773: }
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. */
782: }
783:
784: } while (!done);
785:
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);
793: }
794:
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)
798: {
799: unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
800: ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
801: isc_result_t result;
802:
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);
812:
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);
827: }
828: return (ISC_R_SUCCESS);
829: }
830:
831: isc_result_t
832: isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol)
833: {
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;
838:
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);
844:
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);
854: }
855: return (ISC_R_SUCCESS);
856: }
857:
858: void
859: isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
860: inputsource *source;
861: /*
862: * Unget the current token.
863: */
864:
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);
871:
872: UNUSED(tokenp);
873:
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;
878: }
879:
880: void
881: isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
882: {
883: inputsource *source;
884:
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);
891:
892: UNUSED(tokenp);
893:
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;
899: }
900:
901:
902: char *
903: isc_lex_getsourcename(isc_lex_t *lex) {
904: inputsource *source;
905:
906: REQUIRE(VALID_LEX(lex));
907: source = HEAD(lex->sources);
908:
909: if (source == NULL)
910: return (NULL);
911:
912: return (source->name);
913: }
914:
915: unsigned long
916: isc_lex_getsourceline(isc_lex_t *lex) {
917: inputsource *source;
918:
919: REQUIRE(VALID_LEX(lex));
920: source = HEAD(lex->sources);
921:
922: if (source == NULL)
923: return (0);
924:
925: return (source->line);
926: }
927:
928:
929: isc_result_t
930: isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
931: inputsource *source;
932: char *newname;
933:
934: REQUIRE(VALID_LEX(lex));
935: source = HEAD(lex->sources);
936:
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);
945: }
946:
947: isc_boolean_t
948: isc_lex_isfile(isc_lex_t *lex) {
949: inputsource *source;
950:
951: REQUIRE(VALID_LEX(lex));
952:
953: source = HEAD(lex->sources);
954:
955: if (source == NULL)
956: return (ISC_FALSE);
957:
958: return (source->is_file);
959: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>