15185a700Sflorian /*
25185a700Sflorian * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian *
45185a700Sflorian * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian * copyright notice and this permission notice appear in all copies.
75185a700Sflorian *
85185a700Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian */
165185a700Sflorian
17*ac19a2a7Sjsg /* $Id: lex.c,v 1.15 2022/06/25 12:14:18 jsg Exp $ */
185185a700Sflorian
195185a700Sflorian /*! \file */
205185a700Sflorian
215185a700Sflorian #include <stdlib.h>
225185a700Sflorian
235185a700Sflorian #include <isc/buffer.h>
245185a700Sflorian
255185a700Sflorian #include <isc/lex.h>
265185a700Sflorian
271cf3f1c7Sjung #include <errno.h>
285185a700Sflorian #include <string.h>
295185a700Sflorian #include <isc/util.h>
305185a700Sflorian
311cf3f1c7Sjung #include "unix/errno2result.h"
321cf3f1c7Sjung
335185a700Sflorian typedef struct inputsource {
345185a700Sflorian isc_result_t result;
351fb015a8Sflorian int is_file;
361fb015a8Sflorian int need_close;
371fb015a8Sflorian int at_eof;
381fb015a8Sflorian int last_was_eol;
395185a700Sflorian isc_buffer_t * pushback;
405185a700Sflorian unsigned int ignored;
415185a700Sflorian void * input;
425185a700Sflorian char * name;
435185a700Sflorian unsigned long line;
445185a700Sflorian unsigned long saved_line;
455185a700Sflorian ISC_LINK(struct inputsource) link;
465185a700Sflorian } inputsource;
475185a700Sflorian
485185a700Sflorian struct isc_lex {
495185a700Sflorian /* Unlocked. */
505185a700Sflorian size_t max_token;
515185a700Sflorian char * data;
525185a700Sflorian unsigned int comments;
531fb015a8Sflorian int comment_ok;
541fb015a8Sflorian int last_was_eol;
555185a700Sflorian unsigned int paren_count;
565185a700Sflorian unsigned int saved_paren_count;
575185a700Sflorian isc_lexspecials_t specials;
585185a700Sflorian LIST(struct inputsource) sources;
595185a700Sflorian };
605185a700Sflorian
615185a700Sflorian static inline isc_result_t
grow_data(isc_lex_t * lex,size_t * remainingp,char ** currp,char ** prevp)625185a700Sflorian grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
635185a700Sflorian char *tmp;
645185a700Sflorian
655185a700Sflorian tmp = malloc(lex->max_token * 2 + 1);
665185a700Sflorian if (tmp == NULL)
675185a700Sflorian return (ISC_R_NOMEMORY);
685185a700Sflorian memmove(tmp, lex->data, lex->max_token + 1);
695185a700Sflorian *currp = tmp + (*currp - lex->data);
705185a700Sflorian if (*prevp != NULL)
715185a700Sflorian *prevp = tmp + (*prevp - lex->data);
725185a700Sflorian free(lex->data);
735185a700Sflorian lex->data = tmp;
745185a700Sflorian *remainingp += lex->max_token;
755185a700Sflorian lex->max_token *= 2;
765185a700Sflorian return (ISC_R_SUCCESS);
775185a700Sflorian }
785185a700Sflorian
795185a700Sflorian isc_result_t
isc_lex_create(size_t max_token,isc_lex_t ** lexp)805185a700Sflorian isc_lex_create(size_t max_token, isc_lex_t **lexp) {
815185a700Sflorian isc_lex_t *lex;
825185a700Sflorian
835185a700Sflorian /*
845185a700Sflorian * Create a lexer.
855185a700Sflorian */
865185a700Sflorian REQUIRE(lexp != NULL && *lexp == NULL);
875185a700Sflorian
885185a700Sflorian if (max_token == 0U)
895185a700Sflorian max_token = 1;
905185a700Sflorian
915185a700Sflorian lex = malloc(sizeof(*lex));
925185a700Sflorian if (lex == NULL)
935185a700Sflorian return (ISC_R_NOMEMORY);
945185a700Sflorian lex->data = malloc(max_token + 1);
955185a700Sflorian if (lex->data == NULL) {
965185a700Sflorian free(lex);
975185a700Sflorian return (ISC_R_NOMEMORY);
985185a700Sflorian }
995185a700Sflorian lex->max_token = max_token;
1005185a700Sflorian lex->comments = 0;
1011fb015a8Sflorian lex->comment_ok = 1;
1021fb015a8Sflorian lex->last_was_eol = 1;
1035185a700Sflorian lex->paren_count = 0;
1045185a700Sflorian lex->saved_paren_count = 0;
1055185a700Sflorian memset(lex->specials, 0, 256);
1065185a700Sflorian INIT_LIST(lex->sources);
1075185a700Sflorian
1085185a700Sflorian *lexp = lex;
1095185a700Sflorian
1105185a700Sflorian return (ISC_R_SUCCESS);
1115185a700Sflorian }
1125185a700Sflorian
1135185a700Sflorian void
isc_lex_destroy(isc_lex_t ** lexp)1145185a700Sflorian isc_lex_destroy(isc_lex_t **lexp) {
1155185a700Sflorian isc_lex_t *lex;
1165185a700Sflorian
1175185a700Sflorian /*
1185185a700Sflorian * Destroy the lexer.
1195185a700Sflorian */
1205185a700Sflorian
1215185a700Sflorian REQUIRE(lexp != NULL);
1225185a700Sflorian lex = *lexp;
1235185a700Sflorian
1245185a700Sflorian while (!EMPTY(lex->sources))
1255185a700Sflorian RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
1265185a700Sflorian if (lex->data != NULL)
1275185a700Sflorian free(lex->data);
1285185a700Sflorian free(lex);
1295185a700Sflorian
1305185a700Sflorian *lexp = NULL;
1315185a700Sflorian }
1325185a700Sflorian
1335185a700Sflorian void
isc_lex_setcomments(isc_lex_t * lex,unsigned int comments)1345185a700Sflorian isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
1355185a700Sflorian /*
1365185a700Sflorian * Set allowed lexer commenting styles.
1375185a700Sflorian */
1385185a700Sflorian
1395185a700Sflorian lex->comments = comments;
1405185a700Sflorian }
1415185a700Sflorian
1425185a700Sflorian void
isc_lex_setspecials(isc_lex_t * lex,isc_lexspecials_t specials)1435185a700Sflorian isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
1445185a700Sflorian /*
1455185a700Sflorian * The characters in 'specials' are returned as tokens. Along with
1465185a700Sflorian * whitespace, they delimit strings and numbers.
1475185a700Sflorian */
1485185a700Sflorian
1495185a700Sflorian memmove(lex->specials, specials, 256);
1505185a700Sflorian }
1515185a700Sflorian
1525185a700Sflorian static inline isc_result_t
new_source(isc_lex_t * lex,int is_file,int need_close,void * input,const char * name)1531fb015a8Sflorian new_source(isc_lex_t *lex, int is_file, int need_close,
1545185a700Sflorian void *input, const char *name)
1555185a700Sflorian {
1565185a700Sflorian inputsource *source;
1575185a700Sflorian isc_result_t result;
1585185a700Sflorian
1595185a700Sflorian source = malloc(sizeof(*source));
1605185a700Sflorian if (source == NULL)
1615185a700Sflorian return (ISC_R_NOMEMORY);
1625185a700Sflorian source->result = ISC_R_SUCCESS;
1635185a700Sflorian source->is_file = is_file;
1645185a700Sflorian source->need_close = need_close;
1651fb015a8Sflorian source->at_eof = 0;
1665185a700Sflorian source->last_was_eol = lex->last_was_eol;
1675185a700Sflorian source->input = input;
1685185a700Sflorian source->name = strdup(name);
1695185a700Sflorian if (source->name == NULL) {
1705185a700Sflorian free(source);
1715185a700Sflorian return (ISC_R_NOMEMORY);
1725185a700Sflorian }
1735185a700Sflorian source->pushback = NULL;
1745185a700Sflorian result = isc_buffer_allocate(&source->pushback,
1755185a700Sflorian (unsigned int)lex->max_token);
1765185a700Sflorian if (result != ISC_R_SUCCESS) {
1775185a700Sflorian free(source->name);
1785185a700Sflorian free(source);
1795185a700Sflorian return (result);
1805185a700Sflorian }
1815185a700Sflorian source->ignored = 0;
1825185a700Sflorian source->line = 1;
1835185a700Sflorian ISC_LIST_INITANDPREPEND(lex->sources, source, link);
1845185a700Sflorian
1855185a700Sflorian return (ISC_R_SUCCESS);
1865185a700Sflorian }
1875185a700Sflorian
1885185a700Sflorian isc_result_t
isc_lex_openfile(isc_lex_t * lex,const char * filename)1895185a700Sflorian isc_lex_openfile(isc_lex_t *lex, const char *filename) {
1901cf3f1c7Sjung isc_result_t result = ISC_R_SUCCESS;
1915185a700Sflorian FILE *stream = NULL;
1925185a700Sflorian
1935185a700Sflorian /*
1945185a700Sflorian * Open 'filename' and make it the current input source for 'lex'.
1955185a700Sflorian */
1965185a700Sflorian
1971cf3f1c7Sjung if ((stream = fopen(filename, "r")) == NULL)
1981cf3f1c7Sjung return (isc__errno2result(errno));
1995185a700Sflorian
2001fb015a8Sflorian result = new_source(lex, 1, 1, stream, filename);
2015185a700Sflorian if (result != ISC_R_SUCCESS)
2025185a700Sflorian (void)fclose(stream);
2035185a700Sflorian return (result);
2045185a700Sflorian }
2055185a700Sflorian
2065185a700Sflorian isc_result_t
isc_lex_close(isc_lex_t * lex)2075185a700Sflorian isc_lex_close(isc_lex_t *lex) {
2085185a700Sflorian inputsource *source;
2095185a700Sflorian
2105185a700Sflorian /*
2115185a700Sflorian * Close the most recently opened object (i.e. file or buffer).
2125185a700Sflorian */
2135185a700Sflorian
2145185a700Sflorian source = HEAD(lex->sources);
2155185a700Sflorian if (source == NULL)
2165185a700Sflorian return (ISC_R_NOMORE);
2175185a700Sflorian
2185185a700Sflorian ISC_LIST_UNLINK(lex->sources, source, link);
2195185a700Sflorian lex->last_was_eol = source->last_was_eol;
2205185a700Sflorian if (source->is_file) {
2215185a700Sflorian if (source->need_close)
2225185a700Sflorian (void)fclose((FILE *)(source->input));
2235185a700Sflorian }
2245185a700Sflorian free(source->name);
2255185a700Sflorian isc_buffer_free(&source->pushback);
2265185a700Sflorian free(source);
2275185a700Sflorian
2285185a700Sflorian return (ISC_R_SUCCESS);
2295185a700Sflorian }
2305185a700Sflorian
2315185a700Sflorian typedef enum {
2325185a700Sflorian lexstate_start,
2335185a700Sflorian lexstate_string,
2345185a700Sflorian lexstate_maybecomment,
2355185a700Sflorian lexstate_ccomment,
2365185a700Sflorian lexstate_ccommentend,
2375185a700Sflorian lexstate_eatline,
2385185a700Sflorian lexstate_qstring
2395185a700Sflorian } lexstate;
2405185a700Sflorian
2415185a700Sflorian static void
pushback(inputsource * source,int c)2425185a700Sflorian pushback(inputsource *source, int c) {
2435185a700Sflorian REQUIRE(source->pushback->current > 0);
2445185a700Sflorian if (c == EOF) {
2451fb015a8Sflorian source->at_eof = 0;
2465185a700Sflorian return;
2475185a700Sflorian }
2485185a700Sflorian source->pushback->current--;
2495185a700Sflorian if (c == '\n')
2505185a700Sflorian source->line--;
2515185a700Sflorian }
2525185a700Sflorian
2535185a700Sflorian static isc_result_t
pushandgrow(inputsource * source,int c)2545185a700Sflorian pushandgrow(inputsource *source, int c) {
2555185a700Sflorian if (isc_buffer_availablelength(source->pushback) == 0) {
2565185a700Sflorian isc_buffer_t *tbuf = NULL;
2575185a700Sflorian unsigned int oldlen;
2585185a700Sflorian isc_region_t used;
2595185a700Sflorian isc_result_t result;
2605185a700Sflorian
2615185a700Sflorian oldlen = isc_buffer_length(source->pushback);
2625185a700Sflorian result = isc_buffer_allocate(&tbuf, oldlen * 2);
2635185a700Sflorian if (result != ISC_R_SUCCESS)
2645185a700Sflorian return (result);
2655185a700Sflorian isc_buffer_usedregion(source->pushback, &used);
2665185a700Sflorian result = isc_buffer_copyregion(tbuf, &used);
2675185a700Sflorian INSIST(result == ISC_R_SUCCESS);
2685185a700Sflorian tbuf->current = source->pushback->current;
2695185a700Sflorian isc_buffer_free(&source->pushback);
2705185a700Sflorian source->pushback = tbuf;
2715185a700Sflorian }
2725185a700Sflorian isc_buffer_putuint8(source->pushback, (uint8_t)c);
2735185a700Sflorian return (ISC_R_SUCCESS);
2745185a700Sflorian }
2755185a700Sflorian
2765185a700Sflorian isc_result_t
isc_lex_gettoken(isc_lex_t * lex,unsigned int options,isc_token_t * tokenp)2775185a700Sflorian isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
2785185a700Sflorian inputsource *source;
2795185a700Sflorian int c;
2801fb015a8Sflorian int done = 0;
2811fb015a8Sflorian int no_comments = 0;
2821fb015a8Sflorian int escaped = 0;
2835185a700Sflorian lexstate state = lexstate_start;
2845185a700Sflorian lexstate saved_state = lexstate_start;
2855185a700Sflorian isc_buffer_t *buffer;
2865185a700Sflorian FILE *stream;
2875185a700Sflorian char *curr, *prev;
2885185a700Sflorian size_t remaining;
2895185a700Sflorian isc_result_t result;
2905185a700Sflorian
2915185a700Sflorian /*
2925185a700Sflorian * Get the next token.
2935185a700Sflorian */
2945185a700Sflorian
2955185a700Sflorian source = HEAD(lex->sources);
2965185a700Sflorian REQUIRE(tokenp != NULL);
2975185a700Sflorian
2985185a700Sflorian if (source == NULL) {
2995185a700Sflorian if ((options & ISC_LEXOPT_NOMORE) != 0) {
3005185a700Sflorian tokenp->type = isc_tokentype_nomore;
3015185a700Sflorian return (ISC_R_SUCCESS);
3025185a700Sflorian }
3035185a700Sflorian return (ISC_R_NOMORE);
3045185a700Sflorian }
3055185a700Sflorian
3065185a700Sflorian if (source->result != ISC_R_SUCCESS)
3075185a700Sflorian return (source->result);
3085185a700Sflorian
3095185a700Sflorian lex->saved_paren_count = lex->paren_count;
3105185a700Sflorian source->saved_line = source->line;
3115185a700Sflorian
3125185a700Sflorian if (isc_buffer_remaininglength(source->pushback) == 0 &&
3135185a700Sflorian source->at_eof)
3145185a700Sflorian {
3155185a700Sflorian if ((options & ISC_LEXOPT_EOF) != 0) {
3165185a700Sflorian tokenp->type = isc_tokentype_eof;
3175185a700Sflorian return (ISC_R_SUCCESS);
3185185a700Sflorian }
3195185a700Sflorian return (ISC_R_EOF);
3205185a700Sflorian }
3215185a700Sflorian
3225185a700Sflorian isc_buffer_compact(source->pushback);
3235185a700Sflorian
3245185a700Sflorian curr = lex->data;
3255185a700Sflorian *curr = '\0';
3265185a700Sflorian
3275185a700Sflorian prev = NULL;
3285185a700Sflorian remaining = lex->max_token;
3295185a700Sflorian
3305185a700Sflorian if (source->is_file)
3315185a700Sflorian flockfile(source->input);
3325185a700Sflorian
3335185a700Sflorian do {
3345185a700Sflorian if (isc_buffer_remaininglength(source->pushback) == 0) {
3355185a700Sflorian if (source->is_file) {
3365185a700Sflorian stream = source->input;
3375185a700Sflorian
3385185a700Sflorian c = getc_unlocked(stream);
3395185a700Sflorian if (c == EOF) {
3405185a700Sflorian if (ferror(stream)) {
3415185a700Sflorian source->result = ISC_R_IOERROR;
3425185a700Sflorian result = source->result;
3435185a700Sflorian goto done;
3445185a700Sflorian }
3451fb015a8Sflorian source->at_eof = 1;
3465185a700Sflorian }
3475185a700Sflorian } else {
3485185a700Sflorian buffer = source->input;
3495185a700Sflorian
3505185a700Sflorian if (buffer->current == buffer->used) {
3515185a700Sflorian c = EOF;
3521fb015a8Sflorian source->at_eof = 1;
3535185a700Sflorian } else {
3545185a700Sflorian c = *((unsigned char *)buffer->base +
3555185a700Sflorian buffer->current);
3565185a700Sflorian buffer->current++;
3575185a700Sflorian }
3585185a700Sflorian }
3595185a700Sflorian if (c != EOF) {
3605185a700Sflorian source->result = pushandgrow(source, c);
3615185a700Sflorian if (source->result != ISC_R_SUCCESS) {
3625185a700Sflorian result = source->result;
3635185a700Sflorian goto done;
3645185a700Sflorian }
3655185a700Sflorian }
3665185a700Sflorian }
3675185a700Sflorian
3685185a700Sflorian if (!source->at_eof) {
3695185a700Sflorian if (state == lexstate_start)
3705185a700Sflorian /* Token has not started yet. */
3715185a700Sflorian source->ignored =
3725185a700Sflorian isc_buffer_consumedlength(source->pushback);
3735185a700Sflorian c = isc_buffer_getuint8(source->pushback);
3745185a700Sflorian } else {
3755185a700Sflorian c = EOF;
3765185a700Sflorian }
3775185a700Sflorian
3785185a700Sflorian if (c == '\n')
3795185a700Sflorian source->line++;
3805185a700Sflorian
3815185a700Sflorian if (lex->comment_ok && !no_comments) {
382e6d3fd4aSflorian if (c == '/' &&
3835185a700Sflorian (lex->comments &
3845185a700Sflorian (ISC_LEXCOMMENT_C|
3855185a700Sflorian ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
3865185a700Sflorian saved_state = state;
3875185a700Sflorian state = lexstate_maybecomment;
3881fb015a8Sflorian no_comments = 1;
3895185a700Sflorian continue;
3905185a700Sflorian } else if (c == '#' &&
3915185a700Sflorian ((lex->comments & ISC_LEXCOMMENT_SHELL)
3925185a700Sflorian != 0)) {
3935185a700Sflorian saved_state = state;
3945185a700Sflorian state = lexstate_eatline;
3951fb015a8Sflorian no_comments = 1;
3965185a700Sflorian continue;
3975185a700Sflorian }
3985185a700Sflorian }
3995185a700Sflorian
4005185a700Sflorian no_read:
4015185a700Sflorian /* INSIST(c == EOF || (c >= 0 && c <= 255)); */
4025185a700Sflorian switch (state) {
4035185a700Sflorian case lexstate_start:
4045185a700Sflorian if (c == EOF) {
4051fb015a8Sflorian lex->last_was_eol = 0;
4065185a700Sflorian if ((options & ISC_LEXOPT_EOF) == 0) {
4075185a700Sflorian result = ISC_R_EOF;
4085185a700Sflorian goto done;
4095185a700Sflorian }
4105185a700Sflorian tokenp->type = isc_tokentype_eof;
4111fb015a8Sflorian done = 1;
412cf681e04Sflorian } else if (c == ' ' || c == '\t') {
413cf681e04Sflorian lex->last_was_eol = 0;
4145185a700Sflorian } else if (c == '\n') {
4151fb015a8Sflorian lex->last_was_eol = 1;
416cf681e04Sflorian } else if (c == '\r') {
417cf681e04Sflorian lex->last_was_eol = 0;
4185185a700Sflorian } else if (c == '"' &&
4195185a700Sflorian (options & ISC_LEXOPT_QSTRING) != 0) {
4201fb015a8Sflorian lex->last_was_eol = 0;
4211fb015a8Sflorian no_comments = 1;
4225185a700Sflorian state = lexstate_qstring;
4235185a700Sflorian } else if (lex->specials[c]) {
4241fb015a8Sflorian lex->last_was_eol = 0;
4255185a700Sflorian tokenp->type = isc_tokentype_special;
4265185a700Sflorian tokenp->value.as_char = c;
4271fb015a8Sflorian done = 1;
4285185a700Sflorian } else {
4291fb015a8Sflorian lex->last_was_eol = 0;
4305185a700Sflorian state = lexstate_string;
4315185a700Sflorian goto no_read;
4325185a700Sflorian }
4335185a700Sflorian break;
4345185a700Sflorian case lexstate_string:
4355185a700Sflorian /*
4365185a700Sflorian * EOF needs to be checked before lex->specials[c]
4375185a700Sflorian * as lex->specials[EOF] is not a good idea.
4385185a700Sflorian */
4395185a700Sflorian if (c == '\r' || c == '\n' || c == EOF ||
4405185a700Sflorian (!escaped &&
4415185a700Sflorian (c == ' ' || c == '\t' || lex->specials[c]))) {
4425185a700Sflorian pushback(source, c);
4435185a700Sflorian if (source->result != ISC_R_SUCCESS) {
4445185a700Sflorian result = source->result;
4455185a700Sflorian goto done;
4465185a700Sflorian }
4475185a700Sflorian tokenp->type = isc_tokentype_string;
4485185a700Sflorian tokenp->value.as_textregion.base = lex->data;
4495185a700Sflorian tokenp->value.as_textregion.length =
4505185a700Sflorian (unsigned int)
4515185a700Sflorian (lex->max_token - remaining);
4521fb015a8Sflorian done = 1;
4535185a700Sflorian continue;
4545185a700Sflorian }
4555185a700Sflorian if (remaining == 0U) {
4565185a700Sflorian result = grow_data(lex, &remaining,
4575185a700Sflorian &curr, &prev);
4585185a700Sflorian if (result != ISC_R_SUCCESS)
4595185a700Sflorian goto done;
4605185a700Sflorian }
4615185a700Sflorian INSIST(remaining > 0U);
4625185a700Sflorian *curr++ = c;
4635185a700Sflorian *curr = '\0';
4645185a700Sflorian remaining--;
4655185a700Sflorian break;
4665185a700Sflorian case lexstate_maybecomment:
4675185a700Sflorian if (c == '*' &&
4685185a700Sflorian (lex->comments & ISC_LEXCOMMENT_C) != 0) {
4695185a700Sflorian state = lexstate_ccomment;
4705185a700Sflorian continue;
4715185a700Sflorian } else if (c == '/' &&
4725185a700Sflorian (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
4735185a700Sflorian state = lexstate_eatline;
4745185a700Sflorian continue;
4755185a700Sflorian }
4765185a700Sflorian pushback(source, c);
4775185a700Sflorian c = '/';
4781fb015a8Sflorian no_comments = 0;
4795185a700Sflorian state = saved_state;
4805185a700Sflorian goto no_read;
4815185a700Sflorian case lexstate_ccomment:
4825185a700Sflorian if (c == EOF) {
4835185a700Sflorian result = ISC_R_UNEXPECTEDEND;
4845185a700Sflorian goto done;
4855185a700Sflorian }
4865185a700Sflorian if (c == '*')
4875185a700Sflorian state = lexstate_ccommentend;
4885185a700Sflorian break;
4895185a700Sflorian case lexstate_ccommentend:
4905185a700Sflorian if (c == EOF) {
4915185a700Sflorian result = ISC_R_UNEXPECTEDEND;
4925185a700Sflorian goto done;
4935185a700Sflorian }
4945185a700Sflorian if (c == '/') {
4955185a700Sflorian /*
4965185a700Sflorian * C-style comments become a single space.
4975185a700Sflorian * We do this to ensure that a comment will
4985185a700Sflorian * act as a delimiter for strings and
4995185a700Sflorian * numbers.
5005185a700Sflorian */
5015185a700Sflorian c = ' ';
5021fb015a8Sflorian no_comments = 0;
5035185a700Sflorian state = saved_state;
5045185a700Sflorian goto no_read;
5055185a700Sflorian } else if (c != '*')
5065185a700Sflorian state = lexstate_ccomment;
5075185a700Sflorian break;
5085185a700Sflorian case lexstate_eatline:
5095185a700Sflorian if ((c == '\n') || (c == EOF)) {
5101fb015a8Sflorian no_comments = 0;
5115185a700Sflorian state = saved_state;
5125185a700Sflorian goto no_read;
5135185a700Sflorian }
5145185a700Sflorian break;
5155185a700Sflorian case lexstate_qstring:
5165185a700Sflorian if (c == EOF) {
5175185a700Sflorian result = ISC_R_UNEXPECTEDEND;
5185185a700Sflorian goto done;
5195185a700Sflorian }
5205185a700Sflorian if (c == '"') {
5215185a700Sflorian if (escaped) {
5221fb015a8Sflorian escaped = 0;
5235185a700Sflorian /*
5245185a700Sflorian * Overwrite the preceding backslash.
5255185a700Sflorian */
5265185a700Sflorian INSIST(prev != NULL);
5275185a700Sflorian *prev = '"';
5285185a700Sflorian } else {
5295185a700Sflorian tokenp->type = isc_tokentype_qstring;
5305185a700Sflorian tokenp->value.as_textregion.base =
5315185a700Sflorian lex->data;
5325185a700Sflorian tokenp->value.as_textregion.length =
5335185a700Sflorian (unsigned int)
5345185a700Sflorian (lex->max_token - remaining);
5351fb015a8Sflorian no_comments = 0;
5361fb015a8Sflorian done = 1;
5375185a700Sflorian }
5385185a700Sflorian } else {
5395185a700Sflorian if (c == '\n' && !escaped &&
5405185a700Sflorian (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
5415185a700Sflorian pushback(source, c);
5425185a700Sflorian result = ISC_R_UNBALANCEDQUOTES;
5435185a700Sflorian goto done;
5445185a700Sflorian }
5455185a700Sflorian if (c == '\\' && !escaped)
5461fb015a8Sflorian escaped = 1;
5475185a700Sflorian else
5481fb015a8Sflorian escaped = 0;
5495185a700Sflorian if (remaining == 0U) {
5505185a700Sflorian result = grow_data(lex, &remaining,
5515185a700Sflorian &curr, &prev);
5525185a700Sflorian if (result != ISC_R_SUCCESS)
5535185a700Sflorian goto done;
5545185a700Sflorian }
5555185a700Sflorian INSIST(remaining > 0U);
5565185a700Sflorian prev = curr;
5575185a700Sflorian *curr++ = c;
5585185a700Sflorian *curr = '\0';
5595185a700Sflorian remaining--;
5605185a700Sflorian }
5615185a700Sflorian break;
5625185a700Sflorian default:
5635185a700Sflorian FATAL_ERROR(__FILE__, __LINE__, "Unexpected state %d",
5645185a700Sflorian state);
5655185a700Sflorian /* Does not return. */
5665185a700Sflorian }
5675185a700Sflorian
5685185a700Sflorian } while (!done);
5695185a700Sflorian
5705185a700Sflorian result = ISC_R_SUCCESS;
5715185a700Sflorian done:
5725185a700Sflorian if (source->is_file)
5735185a700Sflorian funlockfile(source->input);
5745185a700Sflorian return (result);
5755185a700Sflorian }
5765185a700Sflorian
5775185a700Sflorian void
isc_lex_ungettoken(isc_lex_t * lex,isc_token_t * tokenp)5785185a700Sflorian isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
5795185a700Sflorian inputsource *source;
5805185a700Sflorian /*
5815185a700Sflorian * Unget the current token.
5825185a700Sflorian */
5835185a700Sflorian
5845185a700Sflorian source = HEAD(lex->sources);
5855185a700Sflorian REQUIRE(source != NULL);
5865185a700Sflorian REQUIRE(tokenp != NULL);
5875185a700Sflorian REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
5885185a700Sflorian tokenp->type == isc_tokentype_eof);
5895185a700Sflorian
5905185a700Sflorian UNUSED(tokenp);
5915185a700Sflorian
5925185a700Sflorian isc_buffer_first(source->pushback);
5935185a700Sflorian lex->paren_count = lex->saved_paren_count;
5945185a700Sflorian source->line = source->saved_line;
5951fb015a8Sflorian source->at_eof = 0;
5965185a700Sflorian }
5975185a700Sflorian
5985185a700Sflorian void
isc_lex_getlasttokentext(isc_lex_t * lex,isc_token_t * tokenp,isc_region_t * r)5995185a700Sflorian isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
6005185a700Sflorian {
6015185a700Sflorian inputsource *source;
6025185a700Sflorian
6035185a700Sflorian source = HEAD(lex->sources);
6045185a700Sflorian REQUIRE(source != NULL);
6055185a700Sflorian REQUIRE(tokenp != NULL);
6065185a700Sflorian REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
6075185a700Sflorian tokenp->type == isc_tokentype_eof);
6085185a700Sflorian
6095185a700Sflorian UNUSED(tokenp);
6105185a700Sflorian
6115185a700Sflorian INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
6125185a700Sflorian r->base = (unsigned char *)isc_buffer_base(source->pushback) +
6135185a700Sflorian source->ignored;
6145185a700Sflorian r->length = isc_buffer_consumedlength(source->pushback) -
6155185a700Sflorian source->ignored;
6165185a700Sflorian }
6175185a700Sflorian
6185185a700Sflorian char *
isc_lex_getsourcename(isc_lex_t * lex)6195185a700Sflorian isc_lex_getsourcename(isc_lex_t *lex) {
6205185a700Sflorian inputsource *source;
6215185a700Sflorian
6225185a700Sflorian source = HEAD(lex->sources);
6235185a700Sflorian
6245185a700Sflorian if (source == NULL)
6255185a700Sflorian return (NULL);
6265185a700Sflorian
6275185a700Sflorian return (source->name);
6285185a700Sflorian }
6295185a700Sflorian
6305185a700Sflorian unsigned long
isc_lex_getsourceline(isc_lex_t * lex)6315185a700Sflorian isc_lex_getsourceline(isc_lex_t *lex) {
6325185a700Sflorian inputsource *source;
6335185a700Sflorian
6345185a700Sflorian source = HEAD(lex->sources);
6355185a700Sflorian
6365185a700Sflorian if (source == NULL)
6375185a700Sflorian return (0);
6385185a700Sflorian
6395185a700Sflorian return (source->line);
6405185a700Sflorian }
641