"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/isc/lex.c" (7 Sep 2020, 24185 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "lex.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 
   13 /*! \file */
   14 
   15 #include <config.h>
   16 
   17 #include <ctype.h>
   18 #include <errno.h>
   19 #include <inttypes.h>
   20 #include <stdbool.h>
   21 #include <stdlib.h>
   22 
   23 #include <isc/buffer.h>
   24 #include <isc/file.h>
   25 #include <isc/lex.h>
   26 #include <isc/mem.h>
   27 #include <isc/msgs.h>
   28 #include <isc/parseint.h>
   29 #include <isc/print.h>
   30 #include <isc/stdio.h>
   31 #include <isc/string.h>
   32 #include <isc/util.h>
   33 
   34 typedef struct inputsource {
   35     isc_result_t            result;
   36     bool            is_file;
   37     bool            need_close;
   38     bool            at_eof;
   39     bool            last_was_eol;
   40     isc_buffer_t *          pushback;
   41     unsigned int            ignored;
   42     void *              input;
   43     char *              name;
   44     unsigned long           line;
   45     unsigned long           saved_line;
   46     ISC_LINK(struct inputsource)    link;
   47 } inputsource;
   48 
   49 #define LEX_MAGIC           ISC_MAGIC('L', 'e', 'x', '!')
   50 #define VALID_LEX(l)            ISC_MAGIC_VALID(l, LEX_MAGIC)
   51 
   52 struct isc_lex {
   53     /* Unlocked. */
   54     unsigned int            magic;
   55     isc_mem_t *         mctx;
   56     size_t              max_token;
   57     char *              data;
   58     unsigned int            comments;
   59     bool            comment_ok;
   60     bool            last_was_eol;
   61     unsigned int            brace_count;
   62     unsigned int            paren_count;
   63     unsigned int            saved_paren_count;
   64     isc_lexspecials_t       specials;
   65     LIST(struct inputsource)    sources;
   66 };
   67 
   68 static inline isc_result_t
   69 grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
   70     char *tmp;
   71 
   72     tmp = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
   73     if (tmp == NULL)
   74         return (ISC_R_NOMEMORY);
   75     memmove(tmp, lex->data, lex->max_token + 1);
   76     *currp = tmp + (*currp - lex->data);
   77     if (*prevp != NULL)
   78         *prevp = tmp + (*prevp - lex->data);
   79     isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
   80     lex->data = tmp;
   81     *remainingp += lex->max_token;
   82     lex->max_token *= 2;
   83     return (ISC_R_SUCCESS);
   84 }
   85 
   86 isc_result_t
   87 isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
   88     isc_lex_t *lex;
   89 
   90     /*
   91      * Create a lexer.
   92      */
   93     REQUIRE(lexp != NULL && *lexp == NULL);
   94 
   95     if (max_token == 0U)
   96         max_token = 1;
   97 
   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);
  105     }
  106     lex->mctx = mctx;
  107     lex->max_token = max_token;
  108     lex->comments = 0;
  109     lex->comment_ok = true;
  110     lex->last_was_eol = true;
  111     lex->brace_count = 0;
  112     lex->paren_count = 0;
  113     lex->saved_paren_count = 0;
  114     memset(lex->specials, 0, 256);
  115     INIT_LIST(lex->sources);
  116     lex->magic = LEX_MAGIC;
  117 
  118     *lexp = lex;
  119 
  120     return (ISC_R_SUCCESS);
  121 }
  122 
  123 void
  124 isc_lex_destroy(isc_lex_t **lexp) {
  125     isc_lex_t *lex;
  126 
  127     REQUIRE(lexp != NULL);
  128     REQUIRE(VALID_LEX((*lexp)));
  129 
  130     lex = *lexp;
  131 
  132     /*
  133      * Destroy the lexer.
  134      */
  135     while (!EMPTY(lex->sources))
  136         RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
  137     if (lex->data != NULL)
  138         isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
  139     lex->magic = 0;
  140     isc_mem_put(lex->mctx, lex, sizeof(*lex));
  141 
  142     *lexp = NULL;
  143 }
  144 
  145 unsigned int
  146 isc_lex_getcomments(isc_lex_t *lex) {
  147     /*
  148      * Return the current lexer commenting styles.
  149      */
  150 
  151     REQUIRE(VALID_LEX(lex));
  152 
  153     return (lex->comments);
  154 }
  155 
  156 void
  157 isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
  158     /*
  159      * Set allowed lexer commenting styles.
  160      */
  161 
  162     REQUIRE(VALID_LEX(lex));
  163 
  164     lex->comments = comments;
  165 }
  166 
  167 void
  168 isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
  169     /*
  170      * Put the current list of specials into 'specials'.
  171      */
  172 
  173     REQUIRE(VALID_LEX(lex));
  174 
  175     memmove(specials, lex->specials, 256);
  176 }
  177 
  178 void
  179 isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
  180     /*
  181      * The characters in 'specials' are returned as tokens.  Along with
  182      * whitespace, they delimit strings and numbers.
  183      */
  184 
  185     REQUIRE(VALID_LEX(lex));
  186 
  187     memmove(lex->specials, specials, 256);
  188 }
  189 
  190 static inline isc_result_t
  191 new_source(isc_lex_t *lex, bool is_file, bool need_close,
  192        void *input, const char *name)
  193 {
  194     inputsource *source;
  195     isc_result_t result;
  196 
  197     source = isc_mem_get(lex->mctx, sizeof(*source));
  198     if (source == NULL)
  199         return (ISC_R_NOMEMORY);
  200     source->result = ISC_R_SUCCESS;
  201     source->is_file = is_file;
  202     source->need_close = need_close;
  203     source->at_eof = false;
  204     source->last_was_eol = lex->last_was_eol;
  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                      (unsigned int)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, true, 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, true, 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, false, 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     lex->last_was_eol = source->last_was_eol;
  293     if (source->is_file) {
  294         if (source->need_close)
  295             (void)fclose((FILE *)(source->input));
  296     }
  297     isc_mem_free(lex->mctx, source->name);
  298     isc_buffer_free(&source->pushback);
  299     isc_mem_put(lex->mctx, source, sizeof(*source));
  300 
  301     return (ISC_R_SUCCESS);
  302 }
  303 
  304 typedef enum {
  305     lexstate_start,
  306     lexstate_crlf,
  307     lexstate_string,
  308     lexstate_number,
  309     lexstate_maybecomment,
  310     lexstate_ccomment,
  311     lexstate_ccommentend,
  312     lexstate_eatline,
  313     lexstate_qstring,
  314     lexstate_btext
  315 } lexstate;
  316 
  317 #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
  318 
  319 static void
  320 pushback(inputsource *source, int c) {
  321     REQUIRE(source->pushback->current > 0);
  322     if (c == EOF) {
  323         source->at_eof = false;
  324         return;
  325     }
  326     source->pushback->current--;
  327     if (c == '\n')
  328         source->line--;
  329 }
  330 
  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;
  338 
  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;
  349     }
  350     isc_buffer_putuint8(source->pushback, (uint8_t)c);
  351     return (ISC_R_SUCCESS);
  352 }
  353 
  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     bool done = false;
  359     bool no_comments = false;
  360     bool escaped = 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     uint32_t as_ulong;
  368     unsigned int saved_options;
  369     isc_result_t result;
  370 
  371     /*
  372      * Get the next token.
  373      */
  374 
  375     REQUIRE(VALID_LEX(lex));
  376     source = HEAD(lex->sources);
  377     REQUIRE(tokenp != NULL);
  378 
  379     if (source == NULL) {
  380         if ((options & ISC_LEXOPT_NOMORE) != 0) {
  381             tokenp->type = isc_tokentype_nomore;
  382             return (ISC_R_SUCCESS);
  383         }
  384         return (ISC_R_NOMORE);
  385     }
  386 
  387     if (source->result != ISC_R_SUCCESS)
  388         return (source->result);
  389 
  390     lex->saved_paren_count = lex->paren_count;
  391     source->saved_line = source->line;
  392 
  393     if (isc_buffer_remaininglength(source->pushback) == 0 &&
  394         source->at_eof)
  395     {
  396         if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
  397             lex->paren_count != 0)
  398         {
  399             lex->paren_count = 0;
  400             return (ISC_R_UNBALANCED);
  401         }
  402         if ((options & ISC_LEXOPT_BTEXT) != 0 &&
  403             lex->brace_count != 0)
  404         {
  405             lex->brace_count = 0;
  406             return (ISC_R_UNBALANCED);
  407         }
  408         if ((options & ISC_LEXOPT_EOF) != 0) {
  409             tokenp->type = isc_tokentype_eof;
  410             return (ISC_R_SUCCESS);
  411         }
  412         return (ISC_R_EOF);
  413     }
  414 
  415     isc_buffer_compact(source->pushback);
  416 
  417     saved_options = options;
  418     if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
  419         options &= ~IWSEOL;
  420 
  421     curr = lex->data;
  422     *curr = '\0';
  423 
  424     prev = NULL;
  425     remaining = lex->max_token;
  426 
  427 #ifdef HAVE_FLOCKFILE
  428     if (source->is_file)
  429         flockfile(source->input);
  430 #endif
  431 
  432     do {
  433         if (isc_buffer_remaininglength(source->pushback) == 0) {
  434             if (source->is_file) {
  435                 stream = source->input;
  436 
  437 #if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED)
  438                 c = getc_unlocked(stream);
  439 #else
  440                 c = getc(stream);
  441 #endif
  442                 if (c == EOF) {
  443                     if (ferror(stream)) {
  444                         source->result = ISC_R_IOERROR;
  445                         result = source->result;
  446                         goto done;
  447                     }
  448                     source->at_eof = true;
  449                 }
  450             } else {
  451                 buffer = source->input;
  452 
  453                 if (buffer->current == buffer->used) {
  454                     c = EOF;
  455                     source->at_eof = true;
  456                 } else {
  457                     c = *((unsigned char *)buffer->base +
  458                           buffer->current);
  459                     buffer->current++;
  460                 }
  461             }
  462             if (c != EOF) {
  463                 source->result = pushandgrow(lex, source, c);
  464                 if (source->result != ISC_R_SUCCESS) {
  465                     result = source->result;
  466                     goto done;
  467                 }
  468             }
  469         }
  470 
  471         if (!source->at_eof) {
  472             if (state == lexstate_start)
  473                 /* Token has not started yet. */
  474                 source->ignored =
  475                    isc_buffer_consumedlength(source->pushback);
  476             c = isc_buffer_getuint8(source->pushback);
  477         } else {
  478             c = EOF;
  479         }
  480 
  481         if (c == '\n')
  482             source->line++;
  483 
  484         if (lex->comment_ok && !no_comments) {
  485             if (!escaped && c == ';' &&
  486                 ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE)
  487                  != 0)) {
  488                 saved_state = state;
  489                 state = lexstate_eatline;
  490                 no_comments = true;
  491                 continue;
  492             } else if (c == '/' &&
  493                    (lex->comments &
  494                     (ISC_LEXCOMMENT_C|
  495                      ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
  496                 saved_state = state;
  497                 state = lexstate_maybecomment;
  498                 no_comments = true;
  499                 continue;
  500             } else if (c == '#' &&
  501                    ((lex->comments & ISC_LEXCOMMENT_SHELL)
  502                     != 0)) {
  503                 saved_state = state;
  504                 state = lexstate_eatline;
  505                 no_comments = true;
  506                 continue;
  507             }
  508         }
  509 
  510     no_read:
  511         /* INSIST(c == EOF || (c >= 0 && c <= 255)); */
  512         switch (state) {
  513         case lexstate_start:
  514             if (c == EOF) {
  515                 lex->last_was_eol = false;
  516                 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
  517                     lex->paren_count != 0) {
  518                     lex->paren_count = 0;
  519                     result = ISC_R_UNBALANCED;
  520                     goto done;
  521                 }
  522                 if ((options & ISC_LEXOPT_BTEXT) != 0 &&
  523                     lex->brace_count != 0) {
  524                     lex->brace_count = 0;
  525                     result = ISC_R_UNBALANCED;
  526                     goto done;
  527                 }
  528                 if ((options & ISC_LEXOPT_EOF) == 0) {
  529                     result = ISC_R_EOF;
  530                     goto done;
  531                 }
  532                 tokenp->type = isc_tokentype_eof;
  533                 done = true;
  534             } else if (c == ' ' || c == '\t') {
  535                 if (lex->last_was_eol &&
  536                     (options & ISC_LEXOPT_INITIALWS)
  537                     != 0) {
  538                     lex->last_was_eol = false;
  539                     tokenp->type = isc_tokentype_initialws;
  540                     tokenp->value.as_char = c;
  541                     done = true;
  542                 }
  543             } else if (c == '\n') {
  544                 if ((options & ISC_LEXOPT_EOL) != 0) {
  545                     tokenp->type = isc_tokentype_eol;
  546                     done = true;
  547                 }
  548                 lex->last_was_eol = true;
  549             } else if (c == '\r') {
  550                 if ((options & ISC_LEXOPT_EOL) != 0)
  551                     state = lexstate_crlf;
  552             } else if (c == '"' &&
  553                    (options & ISC_LEXOPT_QSTRING) != 0) {
  554                 lex->last_was_eol = false;
  555                 no_comments = true;
  556                 state = lexstate_qstring;
  557             } else if (lex->specials[c]) {
  558                 lex->last_was_eol = false;
  559                 if ((c == '(' || c == ')') &&
  560                     (options & ISC_LEXOPT_DNSMULTILINE) != 0)
  561                 {
  562                     if (c == '(') {
  563                         if (lex->paren_count == 0)
  564                             options &= ~IWSEOL;
  565                         lex->paren_count++;
  566                     } else {
  567                         if (lex->paren_count == 0) {
  568                             result =
  569                                   ISC_R_UNBALANCED;
  570                             goto done;
  571                         }
  572                         lex->paren_count--;
  573                         if (lex->paren_count == 0)
  574                             options = saved_options;
  575                     }
  576                     continue;
  577                 } else if (c == '{' &&
  578                        (options & ISC_LEXOPT_BTEXT) != 0)
  579                 {
  580                     if (lex->brace_count != 0) {
  581                         result = ISC_R_UNBALANCED;
  582                         goto done;
  583                     }
  584                     lex->brace_count++;
  585                     options &= ~IWSEOL;
  586                     state = lexstate_btext;
  587                     no_comments = true;
  588                     continue;
  589                 }
  590                 tokenp->type = isc_tokentype_special;
  591                 tokenp->value.as_char = c;
  592                 done = true;
  593             } else if (isdigit((unsigned char)c) &&
  594                    (options & ISC_LEXOPT_NUMBER) != 0) {
  595                 lex->last_was_eol = false;
  596                 if ((options & ISC_LEXOPT_OCTAL) != 0 &&
  597                     (c == '8' || c == '9'))
  598                     state = lexstate_string;
  599                 else
  600                     state = lexstate_number;
  601                 goto no_read;
  602             } else {
  603                 lex->last_was_eol = false;
  604                 state = lexstate_string;
  605                 goto no_read;
  606             }
  607             break;
  608         case lexstate_crlf:
  609             if (c != '\n')
  610                 pushback(source, c);
  611             tokenp->type = isc_tokentype_eol;
  612             done = true;
  613             lex->last_was_eol = true;
  614             break;
  615         case lexstate_number:
  616             if (c == EOF || !isdigit((unsigned char)c)) {
  617                 if (c == ' ' || c == '\t' || c == '\r' ||
  618                     c == '\n' || c == EOF ||
  619                     lex->specials[c]) {
  620                     int base;
  621                     if ((options & ISC_LEXOPT_OCTAL) != 0)
  622                         base = 8;
  623                     else if ((options & ISC_LEXOPT_CNUMBER) != 0)
  624                         base = 0;
  625                     else
  626                         base = 10;
  627                     pushback(source, c);
  628 
  629                     result = isc_parse_uint32(&as_ulong,
  630                                   lex->data,
  631                                   base);
  632                     if (result == ISC_R_SUCCESS) {
  633                         tokenp->type =
  634                             isc_tokentype_number;
  635                         tokenp->value.as_ulong =
  636                             as_ulong;
  637                     } else if (result == ISC_R_BADNUMBER) {
  638                         isc_tokenvalue_t *v;
  639 
  640                         tokenp->type =
  641                             isc_tokentype_string;
  642                         v = &(tokenp->value);
  643                         v->as_textregion.base =
  644                             lex->data;
  645                         v->as_textregion.length =
  646                             (unsigned int)
  647                             (lex->max_token -
  648                              remaining);
  649                     } else
  650                         goto done;
  651                     done = true;
  652                     continue;
  653                 } else if ((options & ISC_LEXOPT_CNUMBER) == 0 ||
  654                        ((c != 'x' && c != 'X') ||
  655                         (curr != &lex->data[1]) ||
  656                         (lex->data[0] != '0'))) {
  657                     /* Above test supports hex numbers */
  658                     state = lexstate_string;
  659                 }
  660             } else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
  661                    (c == '8' || c == '9')) {
  662                 state = lexstate_string;
  663             }
  664             if (remaining == 0U) {
  665                 result = grow_data(lex, &remaining,
  666                            &curr, &prev);
  667                 if (result != ISC_R_SUCCESS)
  668                     goto done;
  669             }
  670             INSIST(remaining > 0U);
  671             *curr++ = c;
  672             *curr = '\0';
  673             remaining--;
  674             break;
  675         case lexstate_string:
  676             /*
  677              * EOF needs to be checked before lex->specials[c]
  678              * as lex->specials[EOF] is not a good idea.
  679              */
  680             if (c == '\r' || c == '\n' || c == EOF ||
  681                 (!escaped &&
  682                  (c == ' ' || c == '\t' || lex->specials[c]))) {
  683                 pushback(source, c);
  684                 if (source->result != ISC_R_SUCCESS) {
  685                     result = source->result;
  686                     goto done;
  687                 }
  688                 tokenp->type = isc_tokentype_string;
  689                 tokenp->value.as_textregion.base = lex->data;
  690                 tokenp->value.as_textregion.length =
  691                     (unsigned int)
  692                     (lex->max_token - remaining);
  693                 done = true;
  694                 continue;
  695             }
  696             if ((options & ISC_LEXOPT_ESCAPE) != 0)
  697                 escaped = (!escaped && c == '\\') ?
  698                         true : false;
  699             if (remaining == 0U) {
  700                 result = grow_data(lex, &remaining,
  701                            &curr, &prev);
  702                 if (result != ISC_R_SUCCESS)
  703                     goto done;
  704             }
  705             INSIST(remaining > 0U);
  706             *curr++ = c;
  707             *curr = '\0';
  708             remaining--;
  709             break;
  710         case lexstate_maybecomment:
  711             if (c == '*' &&
  712                 (lex->comments & ISC_LEXCOMMENT_C) != 0) {
  713                 state = lexstate_ccomment;
  714                 continue;
  715             } else if (c == '/' &&
  716                 (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
  717                 state = lexstate_eatline;
  718                 continue;
  719             }
  720             pushback(source, c);
  721             c = '/';
  722             no_comments = false;
  723             state = saved_state;
  724             goto no_read;
  725         case lexstate_ccomment:
  726             if (c == EOF) {
  727                 result = ISC_R_UNEXPECTEDEND;
  728                 goto done;
  729             }
  730             if (c == '*')
  731                 state = lexstate_ccommentend;
  732             break;
  733         case lexstate_ccommentend:
  734             if (c == EOF) {
  735                 result = ISC_R_UNEXPECTEDEND;
  736                 goto done;
  737             }
  738             if (c == '/') {
  739                 /*
  740                  * C-style comments become a single space.
  741                  * We do this to ensure that a comment will
  742                  * act as a delimiter for strings and
  743                  * numbers.
  744                  */
  745                 c = ' ';
  746                 no_comments = false;
  747                 state = saved_state;
  748                 goto no_read;
  749             } else if (c != '*')
  750                 state = lexstate_ccomment;
  751             break;
  752         case lexstate_eatline:
  753             if ((c == '\n') || (c == EOF)) {
  754                 no_comments = false;
  755                 state = saved_state;
  756                 goto no_read;
  757             }
  758             break;
  759         case lexstate_qstring:
  760             if (c == EOF) {
  761                 result = ISC_R_UNEXPECTEDEND;
  762                 goto done;
  763             }
  764             if (c == '"') {
  765                 if (escaped) {
  766                     escaped = false;
  767                     /*
  768                      * Overwrite the preceding backslash.
  769                      */
  770                     INSIST(prev != NULL);
  771                     *prev = '"';
  772                 } else {
  773                     tokenp->type = isc_tokentype_qstring;
  774                     tokenp->value.as_textregion.base =
  775                         lex->data;
  776                     tokenp->value.as_textregion.length =
  777                         (unsigned int)
  778                         (lex->max_token - remaining);
  779                     no_comments = false;
  780                     done = true;
  781                 }
  782             } else {
  783                 if (c == '\n' && !escaped &&
  784                 (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
  785                     pushback(source, c);
  786                     result = ISC_R_UNBALANCEDQUOTES;
  787                     goto done;
  788                 }
  789                 if (c == '\\' && !escaped)
  790                     escaped = true;
  791                 else
  792                     escaped = false;
  793                 if (remaining == 0U) {
  794                     result = grow_data(lex, &remaining,
  795                                &curr, &prev);
  796                     if (result != ISC_R_SUCCESS)
  797                         goto done;
  798                 }
  799                 INSIST(remaining > 0U);
  800                 prev = curr;
  801                 *curr++ = c;
  802                 *curr = '\0';
  803                 remaining--;
  804             }
  805             break;
  806         case lexstate_btext:
  807             if (c == EOF) {
  808                 result = ISC_R_UNEXPECTEDEND;
  809                 goto done;
  810             }
  811             if (c == '{') {
  812                 if (escaped) {
  813                     escaped = false;
  814                 } else {
  815                     lex->brace_count++;
  816                 }
  817             } else if (c == '}') {
  818                 if (escaped) {
  819                     escaped = false;
  820                 } else {
  821                     INSIST(lex->brace_count > 0);
  822                     lex->brace_count--;
  823                 }
  824 
  825                 if (lex->brace_count == 0) {
  826                     tokenp->type = isc_tokentype_btext;
  827                     tokenp->value.as_textregion.base =
  828                         lex->data;
  829                     tokenp->value.as_textregion.length =
  830                         (unsigned int) (lex->max_token -
  831                                 remaining);
  832                     no_comments = false;
  833                     done = true;
  834                     break;
  835                 }
  836             }
  837 
  838             if (c == '\\' && !escaped)
  839                 escaped = true;
  840             else
  841                 escaped = false;
  842 
  843             if (remaining == 0U) {
  844                 result = grow_data(lex, &remaining,
  845                            &curr, &prev);
  846                 if (result != ISC_R_SUCCESS)
  847                     goto done;
  848             }
  849             INSIST(remaining > 0U);
  850             prev = curr;
  851             *curr++ = c;
  852             *curr = '\0';
  853             remaining--;
  854             break;
  855         default:
  856             FATAL_ERROR(__FILE__, __LINE__,
  857                     isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX,
  858                            ISC_MSG_UNEXPECTEDSTATE,
  859                            "Unexpected state %d"),
  860                     state);
  861         }
  862 
  863     } while (!done);
  864 
  865     result = ISC_R_SUCCESS;
  866  done:
  867 #ifdef HAVE_FLOCKFILE
  868     if (source->is_file)
  869         funlockfile(source->input);
  870 #endif
  871     return (result);
  872 }
  873 
  874 isc_result_t
  875 isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
  876                isc_tokentype_t expect, bool eol)
  877 {
  878     unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
  879                    ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
  880     isc_result_t result;
  881 
  882     if (expect == isc_tokentype_qstring)
  883         options |= ISC_LEXOPT_QSTRING;
  884     else if (expect == isc_tokentype_number)
  885         options |= ISC_LEXOPT_NUMBER;
  886     result = isc_lex_gettoken(lex, options, token);
  887     if (result == ISC_R_RANGE)
  888         isc_lex_ungettoken(lex, token);
  889     if (result != ISC_R_SUCCESS)
  890         return (result);
  891 
  892     if (eol && ((token->type == isc_tokentype_eol) ||
  893             (token->type == isc_tokentype_eof)))
  894         return (ISC_R_SUCCESS);
  895     if (token->type == isc_tokentype_string &&
  896         expect == isc_tokentype_qstring)
  897         return (ISC_R_SUCCESS);
  898     if (token->type != expect) {
  899         isc_lex_ungettoken(lex, token);
  900         if (token->type == isc_tokentype_eol ||
  901             token->type == isc_tokentype_eof)
  902             return (ISC_R_UNEXPECTEDEND);
  903         if (expect == isc_tokentype_number)
  904             return (ISC_R_BADNUMBER);
  905         return (ISC_R_UNEXPECTEDTOKEN);
  906     }
  907     return (ISC_R_SUCCESS);
  908 }
  909 
  910 isc_result_t
  911 isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, bool eol)
  912 {
  913     unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
  914                    ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE|
  915                    ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL;
  916     isc_result_t result;
  917 
  918     result = isc_lex_gettoken(lex, options, token);
  919     if (result == ISC_R_RANGE)
  920         isc_lex_ungettoken(lex, token);
  921     if (result != ISC_R_SUCCESS)
  922         return (result);
  923 
  924     if (eol && ((token->type == isc_tokentype_eol) ||
  925             (token->type == isc_tokentype_eof)))
  926         return (ISC_R_SUCCESS);
  927     if (token->type != isc_tokentype_number) {
  928         isc_lex_ungettoken(lex, token);
  929         if (token->type == isc_tokentype_eol ||
  930             token->type == isc_tokentype_eof)
  931             return (ISC_R_UNEXPECTEDEND);
  932         return (ISC_R_BADNUMBER);
  933     }
  934     return (ISC_R_SUCCESS);
  935 }
  936 
  937 void
  938 isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
  939     inputsource *source;
  940 
  941     REQUIRE(VALID_LEX(lex));
  942     REQUIRE(HEAD(lex->sources) != NULL);
  943     REQUIRE(tokenp != NULL);
  944 
  945     source = HEAD(lex->sources);
  946 
  947     REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
  948         tokenp->type == isc_tokentype_eof);
  949 
  950     /*
  951      * Unget the current token.
  952      */
  953     UNUSED(tokenp);
  954 
  955     isc_buffer_first(source->pushback);
  956     lex->paren_count = lex->saved_paren_count;
  957     source->line = source->saved_line;
  958     source->at_eof = false;
  959 }
  960 
  961 void
  962 isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
  963 {
  964     inputsource *source;
  965 
  966     REQUIRE(VALID_LEX(lex));
  967     REQUIRE(HEAD(lex->sources) != NULL);
  968     REQUIRE(tokenp != NULL);
  969 
  970     source = HEAD(lex->sources);
  971 
  972     REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
  973         tokenp->type == isc_tokentype_eof);
  974 
  975     UNUSED(tokenp);
  976 
  977     INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
  978     r->base = (unsigned char *)isc_buffer_base(source->pushback) +
  979           source->ignored;
  980     r->length = isc_buffer_consumedlength(source->pushback) -
  981             source->ignored;
  982 }
  983 
  984 char *
  985 isc_lex_getsourcename(isc_lex_t *lex) {
  986     inputsource *source;
  987 
  988     REQUIRE(VALID_LEX(lex));
  989     source = HEAD(lex->sources);
  990 
  991     if (source == NULL)
  992         return (NULL);
  993 
  994     return (source->name);
  995 }
  996 
  997 unsigned long
  998 isc_lex_getsourceline(isc_lex_t *lex) {
  999     inputsource *source;
 1000 
 1001     REQUIRE(VALID_LEX(lex));
 1002     source = HEAD(lex->sources);
 1003 
 1004     if (source == NULL)
 1005         return (0);
 1006 
 1007     return (source->line);
 1008 }
 1009 
 1010 isc_result_t
 1011 isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
 1012     inputsource *source;
 1013     char *newname;
 1014 
 1015     REQUIRE(VALID_LEX(lex));
 1016     source = HEAD(lex->sources);
 1017 
 1018     if (source == NULL)
 1019         return (ISC_R_NOTFOUND);
 1020     newname = isc_mem_strdup(lex->mctx, name);
 1021     if (newname == NULL)
 1022         return (ISC_R_NOMEMORY);
 1023     isc_mem_free(lex->mctx, source->name);
 1024     source->name = newname;
 1025     return (ISC_R_SUCCESS);
 1026 }
 1027 
 1028 isc_result_t
 1029 isc_lex_setsourceline(isc_lex_t *lex, unsigned long line) {
 1030     inputsource *source;
 1031 
 1032     REQUIRE(VALID_LEX(lex));
 1033     source = HEAD(lex->sources);
 1034 
 1035     if (source == NULL)
 1036         return (ISC_R_NOTFOUND);
 1037 
 1038     source->line = line;
 1039     return (ISC_R_SUCCESS);
 1040 }
 1041 
 1042 bool
 1043 isc_lex_isfile(isc_lex_t *lex) {
 1044     inputsource *source;
 1045 
 1046     REQUIRE(VALID_LEX(lex));
 1047 
 1048     source = HEAD(lex->sources);
 1049 
 1050     if (source == NULL)
 1051         return (false);
 1052 
 1053     return (source->is_file);
 1054 }