lex.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2013-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1998-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: lex.c,v 1.86 2007/09/17 09:56:29 shane Exp $ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <ctype.h>
00025 #include <errno.h>
00026 #include <stdlib.h>
00027 
00028 #include <isc/buffer.h>
00029 #include <isc/file.h>
00030 #include <isc/lex.h>
00031 #include <isc/mem.h>
00032 #include <isc/msgs.h>
00033 #include <isc/parseint.h>
00034 #include <isc/print.h>
00035 #include <isc/stdio.h>
00036 #include <isc/string.h>
00037 #include <isc/util.h>
00038 
00039 typedef struct inputsource {
00040         isc_result_t                    result;
00041         isc_boolean_t                   is_file;
00042         isc_boolean_t                   need_close;
00043         isc_boolean_t                   at_eof;
00044         isc_boolean_t                   last_was_eol;
00045         isc_buffer_t *                  pushback;
00046         unsigned int                    ignored;
00047         void *                          input;
00048         char *                          name;
00049         unsigned long                   line;
00050         unsigned long                   saved_line;
00051         ISC_LINK(struct inputsource)    link;
00052 } inputsource;
00053 
00054 #define LEX_MAGIC                       ISC_MAGIC('L', 'e', 'x', '!')
00055 #define VALID_LEX(l)                    ISC_MAGIC_VALID(l, LEX_MAGIC)
00056 
00057 struct isc_lex {
00058         /* Unlocked. */
00059         unsigned int                    magic;
00060         isc_mem_t *                     mctx;
00061         size_t                          max_token;
00062         char *                          data;
00063         unsigned int                    comments;
00064         isc_boolean_t                   comment_ok;
00065         isc_boolean_t                   last_was_eol;
00066         unsigned int                    paren_count;
00067         unsigned int                    saved_paren_count;
00068         isc_lexspecials_t               specials;
00069         LIST(struct inputsource)        sources;
00070 };
00071 
00072 static inline isc_result_t
00073 grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
00074         char *new;
00075 
00076         new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
00077         if (new == NULL)
00078                 return (ISC_R_NOMEMORY);
00079         memmove(new, lex->data, lex->max_token + 1);
00080         *currp = new + (*currp - lex->data);
00081         if (*prevp != NULL)
00082                 *prevp = new + (*prevp - lex->data);
00083         isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
00084         lex->data = new;
00085         *remainingp += lex->max_token;
00086         lex->max_token *= 2;
00087         return (ISC_R_SUCCESS);
00088 }
00089 
00090 isc_result_t
00091 isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
00092         isc_lex_t *lex;
00093 
00094         /*
00095          * Create a lexer.
00096          */
00097 
00098         REQUIRE(lexp != NULL && *lexp == NULL);
00099         REQUIRE(max_token > 0U);
00100 
00101         lex = isc_mem_get(mctx, sizeof(*lex));
00102         if (lex == NULL)
00103                 return (ISC_R_NOMEMORY);
00104         lex->data = isc_mem_get(mctx, max_token + 1);
00105         if (lex->data == NULL) {
00106                 isc_mem_put(mctx, lex, sizeof(*lex));
00107                 return (ISC_R_NOMEMORY);
00108         }
00109         lex->mctx = mctx;
00110         lex->max_token = max_token;
00111         lex->comments = 0;
00112         lex->comment_ok = ISC_TRUE;
00113         lex->last_was_eol = ISC_TRUE;
00114         lex->paren_count = 0;
00115         lex->saved_paren_count = 0;
00116         memset(lex->specials, 0, 256);
00117         INIT_LIST(lex->sources);
00118         lex->magic = LEX_MAGIC;
00119 
00120         *lexp = lex;
00121 
00122         return (ISC_R_SUCCESS);
00123 }
00124 
00125 void
00126 isc_lex_destroy(isc_lex_t **lexp) {
00127         isc_lex_t *lex;
00128 
00129         /*
00130          * Destroy the lexer.
00131          */
00132 
00133         REQUIRE(lexp != NULL);
00134         lex = *lexp;
00135         REQUIRE(VALID_LEX(lex));
00136 
00137         while (!EMPTY(lex->sources))
00138                 RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
00139         if (lex->data != NULL)
00140                 isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
00141         lex->magic = 0;
00142         isc_mem_put(lex->mctx, lex, sizeof(*lex));
00143 
00144         *lexp = NULL;
00145 }
00146 
00147 unsigned int
00148 isc_lex_getcomments(isc_lex_t *lex) {
00149         /*
00150          * Return the current lexer commenting styles.
00151          */
00152 
00153         REQUIRE(VALID_LEX(lex));
00154 
00155         return (lex->comments);
00156 }
00157 
00158 void
00159 isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
00160         /*
00161          * Set allowed lexer commenting styles.
00162          */
00163 
00164         REQUIRE(VALID_LEX(lex));
00165 
00166         lex->comments = comments;
00167 }
00168 
00169 void
00170 isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
00171         /*
00172          * Put the current list of specials into 'specials'.
00173          */
00174 
00175         REQUIRE(VALID_LEX(lex));
00176 
00177         memmove(specials, lex->specials, 256);
00178 }
00179 
00180 void
00181 isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
00182         /*
00183          * The characters in 'specials' are returned as tokens.  Along with
00184          * whitespace, they delimit strings and numbers.
00185          */
00186 
00187         REQUIRE(VALID_LEX(lex));
00188 
00189         memmove(lex->specials, specials, 256);
00190 }
00191 
00192 static inline isc_result_t
00193 new_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close,
00194            void *input, const char *name)
00195 {
00196         inputsource *source;
00197         isc_result_t result;
00198 
00199         source = isc_mem_get(lex->mctx, sizeof(*source));
00200         if (source == NULL)
00201                 return (ISC_R_NOMEMORY);
00202         source->result = ISC_R_SUCCESS;
00203         source->is_file = is_file;
00204         source->need_close = need_close;
00205         source->at_eof = ISC_FALSE;
00206         source->last_was_eol = lex->last_was_eol;
00207         source->input = input;
00208         source->name = isc_mem_strdup(lex->mctx, name);
00209         if (source->name == NULL) {
00210                 isc_mem_put(lex->mctx, source, sizeof(*source));
00211                 return (ISC_R_NOMEMORY);
00212         }
00213         source->pushback = NULL;
00214         result = isc_buffer_allocate(lex->mctx, &source->pushback,
00215                                      (unsigned int)lex->max_token);
00216         if (result != ISC_R_SUCCESS) {
00217                 isc_mem_free(lex->mctx, source->name);
00218                 isc_mem_put(lex->mctx, source, sizeof(*source));
00219                 return (result);
00220         }
00221         source->ignored = 0;
00222         source->line = 1;
00223         ISC_LIST_INITANDPREPEND(lex->sources, source, link);
00224 
00225         return (ISC_R_SUCCESS);
00226 }
00227 
00228 isc_result_t
00229 isc_lex_openfile(isc_lex_t *lex, const char *filename) {
00230         isc_result_t result;
00231         FILE *stream = NULL;
00232 
00233         /*
00234          * Open 'filename' and make it the current input source for 'lex'.
00235          */
00236 
00237         REQUIRE(VALID_LEX(lex));
00238 
00239         result = isc_stdio_open(filename, "r", &stream);
00240         if (result != ISC_R_SUCCESS)
00241                 return (result);
00242 
00243         result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename);
00244         if (result != ISC_R_SUCCESS)
00245                 (void)fclose(stream);
00246         return (result);
00247 }
00248 
00249 isc_result_t
00250 isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
00251         char name[128];
00252 
00253         /*
00254          * Make 'stream' the current input source for 'lex'.
00255          */
00256 
00257         REQUIRE(VALID_LEX(lex));
00258 
00259         snprintf(name, sizeof(name), "stream-%p", stream);
00260 
00261         return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));
00262 }
00263 
00264 isc_result_t
00265 isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
00266         char name[128];
00267 
00268         /*
00269          * Make 'buffer' the current input source for 'lex'.
00270          */
00271 
00272         REQUIRE(VALID_LEX(lex));
00273 
00274         snprintf(name, sizeof(name), "buffer-%p", buffer);
00275 
00276         return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));
00277 }
00278 
00279 isc_result_t
00280 isc_lex_close(isc_lex_t *lex) {
00281         inputsource *source;
00282 
00283         /*
00284          * Close the most recently opened object (i.e. file or buffer).
00285          */
00286 
00287         REQUIRE(VALID_LEX(lex));
00288 
00289         source = HEAD(lex->sources);
00290         if (source == NULL)
00291                 return (ISC_R_NOMORE);
00292 
00293         ISC_LIST_UNLINK(lex->sources, source, link);
00294         lex->last_was_eol = source->last_was_eol;
00295         if (source->is_file) {
00296                 if (source->need_close)
00297                         (void)fclose((FILE *)(source->input));
00298         }
00299         isc_mem_free(lex->mctx, source->name);
00300         isc_buffer_free(&source->pushback);
00301         isc_mem_put(lex->mctx, source, sizeof(*source));
00302 
00303         return (ISC_R_SUCCESS);
00304 }
00305 
00306 typedef enum {
00307         lexstate_start,
00308         lexstate_crlf,
00309         lexstate_string,
00310         lexstate_number,
00311         lexstate_maybecomment,
00312         lexstate_ccomment,
00313         lexstate_ccommentend,
00314         lexstate_eatline,
00315         lexstate_qstring
00316 } lexstate;
00317 
00318 #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
00319 
00320 static void
00321 pushback(inputsource *source, int c) {
00322         REQUIRE(source->pushback->current > 0);
00323         if (c == EOF) {
00324                 source->at_eof = ISC_FALSE;
00325                 return;
00326         }
00327         source->pushback->current--;
00328         if (c == '\n')
00329                 source->line--;
00330 }
00331 
00332 static isc_result_t
00333 pushandgrow(isc_lex_t *lex, inputsource *source, int c) {
00334         if (isc_buffer_availablelength(source->pushback) == 0) {
00335                 isc_buffer_t *tbuf = NULL;
00336                 unsigned int oldlen;
00337                 isc_region_t used;
00338                 isc_result_t result;
00339 
00340                 oldlen = isc_buffer_length(source->pushback);
00341                 result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2);
00342                 if (result != ISC_R_SUCCESS)
00343                         return (result);
00344                 isc_buffer_usedregion(source->pushback, &used);
00345                 result = isc_buffer_copyregion(tbuf, &used);
00346                 INSIST(result == ISC_R_SUCCESS);
00347                 tbuf->current = source->pushback->current;
00348                 isc_buffer_free(&source->pushback);
00349                 source->pushback = tbuf;
00350         }
00351         isc_buffer_putuint8(source->pushback, (isc_uint8_t)c);
00352         return (ISC_R_SUCCESS);
00353 }
00354 
00355 isc_result_t
00356 isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
00357         inputsource *source;
00358         int c;
00359         isc_boolean_t done = ISC_FALSE;
00360         isc_boolean_t no_comments = ISC_FALSE;
00361         isc_boolean_t escaped = ISC_FALSE;
00362         lexstate state = lexstate_start;
00363         lexstate saved_state = lexstate_start;
00364         isc_buffer_t *buffer;
00365         FILE *stream;
00366         char *curr, *prev;
00367         size_t remaining;
00368         isc_uint32_t as_ulong;
00369         unsigned int saved_options;
00370         isc_result_t result;
00371 
00372         /*
00373          * Get the next token.
00374          */
00375 
00376         REQUIRE(VALID_LEX(lex));
00377         source = HEAD(lex->sources);
00378         REQUIRE(tokenp != NULL);
00379 
00380         if (source == NULL) {
00381                 if ((options & ISC_LEXOPT_NOMORE) != 0) {
00382                         tokenp->type = isc_tokentype_nomore;
00383                         return (ISC_R_SUCCESS);
00384                 }
00385                 return (ISC_R_NOMORE);
00386         }
00387 
00388         if (source->result != ISC_R_SUCCESS)
00389                 return (source->result);
00390 
00391         lex->saved_paren_count = lex->paren_count;
00392         source->saved_line = source->line;
00393 
00394         if (isc_buffer_remaininglength(source->pushback) == 0 &&
00395             source->at_eof)
00396         {
00397                 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
00398                     lex->paren_count != 0) {
00399                         lex->paren_count = 0;
00400                         return (ISC_R_UNBALANCED);
00401                 }
00402                 if ((options & ISC_LEXOPT_EOF) != 0) {
00403                         tokenp->type = isc_tokentype_eof;
00404                         return (ISC_R_SUCCESS);
00405                 }
00406                 return (ISC_R_EOF);
00407         }
00408 
00409         isc_buffer_compact(source->pushback);
00410 
00411         saved_options = options;
00412         if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
00413                 options &= ~IWSEOL;
00414 
00415         curr = lex->data;
00416         *curr = '\0';
00417 
00418         prev = NULL;
00419         remaining = lex->max_token;
00420 
00421 #ifdef HAVE_FLOCKFILE
00422         if (source->is_file)
00423                 flockfile(source->input);
00424 #endif
00425 
00426         do {
00427                 if (isc_buffer_remaininglength(source->pushback) == 0) {
00428                         if (source->is_file) {
00429                                 stream = source->input;
00430 
00431 #if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED)
00432                                 c = getc_unlocked(stream);
00433 #else
00434                                 c = getc(stream);
00435 #endif
00436                                 if (c == EOF) {
00437                                         if (ferror(stream)) {
00438                                                 source->result = ISC_R_IOERROR;
00439                                                 result = source->result;
00440                                                 goto done;
00441                                         }
00442                                         source->at_eof = ISC_TRUE;
00443                                 }
00444                         } else {
00445                                 buffer = source->input;
00446 
00447                                 if (buffer->current == buffer->used) {
00448                                         c = EOF;
00449                                         source->at_eof = ISC_TRUE;
00450                                 } else {
00451                                         c = *((unsigned char *)buffer->base +
00452                                               buffer->current);
00453                                         buffer->current++;
00454                                 }
00455                         }
00456                         if (c != EOF) {
00457                                 source->result = pushandgrow(lex, source, c);
00458                                 if (source->result != ISC_R_SUCCESS) {
00459                                         result = source->result;
00460                                         goto done;
00461                                 }
00462                         }
00463                 }
00464 
00465                 if (!source->at_eof) {
00466                         if (state == lexstate_start)
00467                                 /* Token has not started yet. */
00468                                 source->ignored =
00469                                    isc_buffer_consumedlength(source->pushback);
00470                         c = isc_buffer_getuint8(source->pushback);
00471                 } else {
00472                         c = EOF;
00473                 }
00474 
00475                 if (c == '\n')
00476                         source->line++;
00477 
00478                 if (lex->comment_ok && !no_comments) {
00479                         if (!escaped && c == ';' &&
00480                             ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE)
00481                              != 0)) {
00482                                 saved_state = state;
00483                                 state = lexstate_eatline;
00484                                 no_comments = ISC_TRUE;
00485                                 continue;
00486                         } else if (c == '/' &&
00487                                    (lex->comments &
00488                                     (ISC_LEXCOMMENT_C|
00489                                      ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
00490                                 saved_state = state;
00491                                 state = lexstate_maybecomment;
00492                                 no_comments = ISC_TRUE;
00493                                 continue;
00494                         } else if (c == '#' &&
00495                                    ((lex->comments & ISC_LEXCOMMENT_SHELL)
00496                                     != 0)) {
00497                                 saved_state = state;
00498                                 state = lexstate_eatline;
00499                                 no_comments = ISC_TRUE;
00500                                 continue;
00501                         }
00502                 }
00503 
00504         no_read:
00505                 /* INSIST(c == EOF || (c >= 0 && c <= 255)); */
00506                 switch (state) {
00507                 case lexstate_start:
00508                         if (c == EOF) {
00509                                 lex->last_was_eol = ISC_FALSE;
00510                                 if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
00511                                     lex->paren_count != 0) {
00512                                         lex->paren_count = 0;
00513                                         result = ISC_R_UNBALANCED;
00514                                         goto done;
00515                                 }
00516                                 if ((options & ISC_LEXOPT_EOF) == 0) {
00517                                         result = ISC_R_EOF;
00518                                         goto done;
00519                                 }
00520                                 tokenp->type = isc_tokentype_eof;
00521                                 done = ISC_TRUE;
00522                         } else if (c == ' ' || c == '\t') {
00523                                 if (lex->last_was_eol &&
00524                                     (options & ISC_LEXOPT_INITIALWS)
00525                                     != 0) {
00526                                         lex->last_was_eol = ISC_FALSE;
00527                                         tokenp->type = isc_tokentype_initialws;
00528                                         tokenp->value.as_char = c;
00529                                         done = ISC_TRUE;
00530                                 }
00531                         } else if (c == '\n') {
00532                                 if ((options & ISC_LEXOPT_EOL) != 0) {
00533                                         tokenp->type = isc_tokentype_eol;
00534                                         done = ISC_TRUE;
00535                                 }
00536                                 lex->last_was_eol = ISC_TRUE;
00537                         } else if (c == '\r') {
00538                                 if ((options & ISC_LEXOPT_EOL) != 0)
00539                                         state = lexstate_crlf;
00540                         } else if (c == '"' &&
00541                                    (options & ISC_LEXOPT_QSTRING) != 0) {
00542                                 lex->last_was_eol = ISC_FALSE;
00543                                 no_comments = ISC_TRUE;
00544                                 state = lexstate_qstring;
00545                         } else if (lex->specials[c]) {
00546                                 lex->last_was_eol = ISC_FALSE;
00547                                 if ((c == '(' || c == ')') &&
00548                                     (options & ISC_LEXOPT_DNSMULTILINE) != 0) {
00549                                         if (c == '(') {
00550                                                 if (lex->paren_count == 0)
00551                                                         options &= ~IWSEOL;
00552                                                 lex->paren_count++;
00553                                         } else {
00554                                                 if (lex->paren_count == 0) {
00555                                                     result = ISC_R_UNBALANCED;
00556                                                     goto done;
00557                                                 }
00558                                                 lex->paren_count--;
00559                                                 if (lex->paren_count == 0)
00560                                                         options =
00561                                                                 saved_options;
00562                                         }
00563                                         continue;
00564                                 }
00565                                 tokenp->type = isc_tokentype_special;
00566                                 tokenp->value.as_char = c;
00567                                 done = ISC_TRUE;
00568                         } else if (isdigit((unsigned char)c) &&
00569                                    (options & ISC_LEXOPT_NUMBER) != 0) {
00570                                 lex->last_was_eol = ISC_FALSE;
00571                                 if ((options & ISC_LEXOPT_OCTAL) != 0 &&
00572                                     (c == '8' || c == '9'))
00573                                         state = lexstate_string;
00574                                 else
00575                                         state = lexstate_number;
00576                                 goto no_read;
00577                         } else {
00578                                 lex->last_was_eol = ISC_FALSE;
00579                                 state = lexstate_string;
00580                                 goto no_read;
00581                         }
00582                         break;
00583                 case lexstate_crlf:
00584                         if (c != '\n')
00585                                 pushback(source, c);
00586                         tokenp->type = isc_tokentype_eol;
00587                         done = ISC_TRUE;
00588                         lex->last_was_eol = ISC_TRUE;
00589                         break;
00590                 case lexstate_number:
00591                         if (c == EOF || !isdigit((unsigned char)c)) {
00592                                 if (c == ' ' || c == '\t' || c == '\r' ||
00593                                     c == '\n' || c == EOF ||
00594                                     lex->specials[c]) {
00595                                         int base;
00596                                         if ((options & ISC_LEXOPT_OCTAL) != 0)
00597                                                 base = 8;
00598                                         else if ((options & ISC_LEXOPT_CNUMBER) != 0)
00599                                                 base = 0;
00600                                         else
00601                                                 base = 10;
00602                                         pushback(source, c);
00603 
00604                                         result = isc_parse_uint32(&as_ulong,
00605                                                                   lex->data,
00606                                                                   base);
00607                                         if (result == ISC_R_SUCCESS) {
00608                                                 tokenp->type =
00609                                                         isc_tokentype_number;
00610                                                 tokenp->value.as_ulong =
00611                                                         as_ulong;
00612                                         } else if (result == ISC_R_BADNUMBER) {
00613                                                 isc_tokenvalue_t *v;
00614 
00615                                                 tokenp->type =
00616                                                         isc_tokentype_string;
00617                                                 v = &(tokenp->value);
00618                                                 v->as_textregion.base =
00619                                                         lex->data;
00620                                                 v->as_textregion.length =
00621                                                         (unsigned int)
00622                                                         (lex->max_token -
00623                                                          remaining);
00624                                         } else
00625                                                 goto done;
00626                                         done = ISC_TRUE;
00627                                         continue;
00628                                 } else if (!(options & ISC_LEXOPT_CNUMBER) ||
00629                                            ((c != 'x' && c != 'X') ||
00630                                            (curr != &lex->data[1]) ||
00631                                            (lex->data[0] != '0'))) {
00632                                         /* Above test supports hex numbers */
00633                                         state = lexstate_string;
00634                                 }
00635                         } else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
00636                                    (c == '8' || c == '9')) {
00637                                 state = lexstate_string;
00638                         }
00639                         if (remaining == 0U) {
00640                                 result = grow_data(lex, &remaining,
00641                                                    &curr, &prev);
00642                                 if (result != ISC_R_SUCCESS)
00643                                         goto done;
00644                         }
00645                         INSIST(remaining > 0U);
00646                         *curr++ = c;
00647                         *curr = '\0';
00648                         remaining--;
00649                         break;
00650                 case lexstate_string:
00651                         /*
00652                          * EOF needs to be checked before lex->specials[c]
00653                          * as lex->specials[EOF] is not a good idea.
00654                          */
00655                         if (c == '\r' || c == '\n' || c == EOF ||
00656                             (!escaped &&
00657                              (c == ' ' || c == '\t' || lex->specials[c]))) {
00658                                 pushback(source, c);
00659                                 if (source->result != ISC_R_SUCCESS) {
00660                                         result = source->result;
00661                                         goto done;
00662                                 }
00663                                 tokenp->type = isc_tokentype_string;
00664                                 tokenp->value.as_textregion.base = lex->data;
00665                                 tokenp->value.as_textregion.length =
00666                                         (unsigned int)
00667                                         (lex->max_token - remaining);
00668                                 done = ISC_TRUE;
00669                                 continue;
00670                         }
00671                         if ((options & ISC_LEXOPT_ESCAPE) != 0)
00672                                 escaped = (!escaped && c == '\\') ?
00673                                                 ISC_TRUE : ISC_FALSE;
00674                         if (remaining == 0U) {
00675                                 result = grow_data(lex, &remaining,
00676                                                    &curr, &prev);
00677                                 if (result != ISC_R_SUCCESS)
00678                                         goto done;
00679                         }
00680                         INSIST(remaining > 0U);
00681                         *curr++ = c;
00682                         *curr = '\0';
00683                         remaining--;
00684                         break;
00685                 case lexstate_maybecomment:
00686                         if (c == '*' &&
00687                             (lex->comments & ISC_LEXCOMMENT_C) != 0) {
00688                                 state = lexstate_ccomment;
00689                                 continue;
00690                         } else if (c == '/' &&
00691                             (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
00692                                 state = lexstate_eatline;
00693                                 continue;
00694                         }
00695                         pushback(source, c);
00696                         c = '/';
00697                         no_comments = ISC_FALSE;
00698                         state = saved_state;
00699                         goto no_read;
00700                 case lexstate_ccomment:
00701                         if (c == EOF) {
00702                                 result = ISC_R_UNEXPECTEDEND;
00703                                 goto done;
00704                         }
00705                         if (c == '*')
00706                                 state = lexstate_ccommentend;
00707                         break;
00708                 case lexstate_ccommentend:
00709                         if (c == EOF) {
00710                                 result = ISC_R_UNEXPECTEDEND;
00711                                 goto done;
00712                         }
00713                         if (c == '/') {
00714                                 /*
00715                                  * C-style comments become a single space.
00716                                  * We do this to ensure that a comment will
00717                                  * act as a delimiter for strings and
00718                                  * numbers.
00719                                  */
00720                                 c = ' ';
00721                                 no_comments = ISC_FALSE;
00722                                 state = saved_state;
00723                                 goto no_read;
00724                         } else if (c != '*')
00725                                 state = lexstate_ccomment;
00726                         break;
00727                 case lexstate_eatline:
00728                         if ((c == '\n') || (c == EOF)) {
00729                                 no_comments = ISC_FALSE;
00730                                 state = saved_state;
00731                                 goto no_read;
00732                         }
00733                         break;
00734                 case lexstate_qstring:
00735                         if (c == EOF) {
00736                                 result = ISC_R_UNEXPECTEDEND;
00737                                 goto done;
00738                         }
00739                         if (c == '"') {
00740                                 if (escaped) {
00741                                         escaped = ISC_FALSE;
00742                                         /*
00743                                          * Overwrite the preceding backslash.
00744                                          */
00745                                         INSIST(prev != NULL);
00746                                         *prev = '"';
00747                                 } else {
00748                                         tokenp->type = isc_tokentype_qstring;
00749                                         tokenp->value.as_textregion.base =
00750                                                 lex->data;
00751                                         tokenp->value.as_textregion.length =
00752                                                 (unsigned int)
00753                                                 (lex->max_token - remaining);
00754                                         no_comments = ISC_FALSE;
00755                                         done = ISC_TRUE;
00756                                 }
00757                         } else {
00758                                 if (c == '\n' && !escaped &&
00759                             (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
00760                                         pushback(source, c);
00761                                         result = ISC_R_UNBALANCEDQUOTES;
00762                                         goto done;
00763                                 }
00764                                 if (c == '\\' && !escaped)
00765                                         escaped = ISC_TRUE;
00766                                 else
00767                                         escaped = ISC_FALSE;
00768                                 if (remaining == 0U) {
00769                                         result = grow_data(lex, &remaining,
00770                                                            &curr, &prev);
00771                                         if (result != ISC_R_SUCCESS)
00772                                                 goto done;
00773                                 }
00774                                 INSIST(remaining > 0U);
00775                                 prev = curr;
00776                                 *curr++ = c;
00777                                 *curr = '\0';
00778                                 remaining--;
00779                         }
00780                         break;
00781                 default:
00782                         FATAL_ERROR(__FILE__, __LINE__,
00783                                     isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX,
00784                                                    ISC_MSG_UNEXPECTEDSTATE,
00785                                                    "Unexpected state %d"),
00786                                     state);
00787                         /* Does not return. */
00788                 }
00789 
00790         } while (!done);
00791 
00792         result = ISC_R_SUCCESS;
00793  done:
00794 #ifdef HAVE_FLOCKFILE
00795         if (source->is_file)
00796                 funlockfile(source->input);
00797 #endif
00798         return (result);
00799 }
00800 
00801 isc_result_t
00802 isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
00803                        isc_tokentype_t expect, isc_boolean_t eol)
00804 {
00805         unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
00806                                ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
00807         isc_result_t result;
00808 
00809         if (expect == isc_tokentype_qstring)
00810                 options |= ISC_LEXOPT_QSTRING;
00811         else if (expect == isc_tokentype_number)
00812                 options |= ISC_LEXOPT_NUMBER;
00813         result = isc_lex_gettoken(lex, options, token);
00814         if (result == ISC_R_RANGE)
00815                 isc_lex_ungettoken(lex, token);
00816         if (result != ISC_R_SUCCESS)
00817                 return (result);
00818 
00819         if (eol && ((token->type == isc_tokentype_eol) ||
00820                     (token->type == isc_tokentype_eof)))
00821                 return (ISC_R_SUCCESS);
00822         if (token->type == isc_tokentype_string &&
00823             expect == isc_tokentype_qstring)
00824                 return (ISC_R_SUCCESS);
00825         if (token->type != expect) {
00826                 isc_lex_ungettoken(lex, token);
00827                 if (token->type == isc_tokentype_eol ||
00828                     token->type == isc_tokentype_eof)
00829                         return (ISC_R_UNEXPECTEDEND);
00830                 if (expect == isc_tokentype_number)
00831                         return (ISC_R_BADNUMBER);
00832                 return (ISC_R_UNEXPECTEDTOKEN);
00833         }
00834         return (ISC_R_SUCCESS);
00835 }
00836 
00837 isc_result_t
00838 isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol)
00839 {
00840         unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
00841                                ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE|
00842                                ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL;
00843         isc_result_t result;
00844 
00845         result = isc_lex_gettoken(lex, options, token);
00846         if (result == ISC_R_RANGE)
00847                 isc_lex_ungettoken(lex, token);
00848         if (result != ISC_R_SUCCESS)
00849                 return (result);
00850 
00851         if (eol && ((token->type == isc_tokentype_eol) ||
00852                     (token->type == isc_tokentype_eof)))
00853                 return (ISC_R_SUCCESS);
00854         if (token->type != isc_tokentype_number) {
00855                 isc_lex_ungettoken(lex, token);
00856                 if (token->type == isc_tokentype_eol ||
00857                     token->type == isc_tokentype_eof)
00858                         return (ISC_R_UNEXPECTEDEND);
00859                 return (ISC_R_BADNUMBER);
00860         }
00861         return (ISC_R_SUCCESS);
00862 }
00863 
00864 void
00865 isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
00866         inputsource *source;
00867         /*
00868          * Unget the current token.
00869          */
00870 
00871         REQUIRE(VALID_LEX(lex));
00872         source = HEAD(lex->sources);
00873         REQUIRE(source != NULL);
00874         REQUIRE(tokenp != NULL);
00875         REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
00876                 tokenp->type == isc_tokentype_eof);
00877 
00878         UNUSED(tokenp);
00879 
00880         isc_buffer_first(source->pushback);
00881         lex->paren_count = lex->saved_paren_count;
00882         source->line = source->saved_line;
00883         source->at_eof = ISC_FALSE;
00884 }
00885 
00886 void
00887 isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
00888 {
00889         inputsource *source;
00890 
00891         REQUIRE(VALID_LEX(lex));
00892         source = HEAD(lex->sources);
00893         REQUIRE(source != NULL);
00894         REQUIRE(tokenp != NULL);
00895         REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
00896                 tokenp->type == isc_tokentype_eof);
00897 
00898         UNUSED(tokenp);
00899 
00900         INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
00901         r->base = (unsigned char *)isc_buffer_base(source->pushback) +
00902                   source->ignored;
00903         r->length = isc_buffer_consumedlength(source->pushback) -
00904                     source->ignored;
00905 }
00906 
00907 
00908 char *
00909 isc_lex_getsourcename(isc_lex_t *lex) {
00910         inputsource *source;
00911 
00912         REQUIRE(VALID_LEX(lex));
00913         source = HEAD(lex->sources);
00914 
00915         if (source == NULL)
00916                 return (NULL);
00917 
00918         return (source->name);
00919 }
00920 
00921 unsigned long
00922 isc_lex_getsourceline(isc_lex_t *lex) {
00923         inputsource *source;
00924 
00925         REQUIRE(VALID_LEX(lex));
00926         source = HEAD(lex->sources);
00927 
00928         if (source == NULL)
00929                 return (0);
00930 
00931         return (source->line);
00932 }
00933 
00934 
00935 isc_result_t
00936 isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
00937         inputsource *source;
00938         char *newname;
00939 
00940         REQUIRE(VALID_LEX(lex));
00941         source = HEAD(lex->sources);
00942 
00943         if (source == NULL)
00944                 return(ISC_R_NOTFOUND);
00945         newname = isc_mem_strdup(lex->mctx, name);
00946         if (newname == NULL)
00947                 return (ISC_R_NOMEMORY);
00948         isc_mem_free(lex->mctx, source->name);
00949         source->name = newname;
00950         return (ISC_R_SUCCESS);
00951 }
00952 
00953 isc_boolean_t
00954 isc_lex_isfile(isc_lex_t *lex) {
00955         inputsource *source;
00956 
00957         REQUIRE(VALID_LEX(lex));
00958 
00959         source = HEAD(lex->sources);
00960 
00961         if (source == NULL)
00962                 return (ISC_FALSE);
00963 
00964         return (source->is_file);
00965 }

Generated on Tue Apr 28 17:41:04 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha