Annotation of embedaddon/ntp/lib/isc/lex.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
                      3:  * Copyright (C) 1998-2003  Internet Software Consortium.
                      4:  *
                      5:  * Permission to use, copy, modify, and/or distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
                     10:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
                     11:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
                     12:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
                     13:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
                     14:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     15:  * PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: 
                     18: /* $Id: lex.c,v 1.86 2007/09/17 09:56:29 shane Exp $ */
                     19: 
                     20: /*! \file */
                     21: 
                     22: #include <config.h>
                     23: 
                     24: #include <ctype.h>
                     25: #include <errno.h>
                     26: #include <stdlib.h>
                     27: 
                     28: #include <isc/buffer.h>
                     29: #include <isc/file.h>
                     30: #include <isc/lex.h>
                     31: #include <isc/mem.h>
                     32: #include <isc/msgs.h>
                     33: #include <isc/parseint.h>
                     34: #include <isc/print.h>
                     35: #include <isc/stdio.h>
                     36: #include <isc/string.h>
                     37: #include <isc/util.h>
                     38: 
                     39: typedef struct inputsource {
                     40:        isc_result_t                    result;
                     41:        isc_boolean_t                   is_file;
                     42:        isc_boolean_t                   need_close;
                     43:        isc_boolean_t                   at_eof;
                     44:        isc_buffer_t *                  pushback;
                     45:        unsigned int                    ignored;
                     46:        void *                          input;
                     47:        char *                          name;
                     48:        unsigned long                   line;
                     49:        unsigned long                   saved_line;
                     50:        ISC_LINK(struct inputsource)    link;
                     51: } inputsource;
                     52: 
                     53: #define LEX_MAGIC                      ISC_MAGIC('L', 'e', 'x', '!')
                     54: #define VALID_LEX(l)                   ISC_MAGIC_VALID(l, LEX_MAGIC)
                     55: 
                     56: struct isc_lex {
                     57:        /* Unlocked. */
                     58:        unsigned int                    magic;
                     59:        isc_mem_t *                     mctx;
                     60:        size_t                          max_token;
                     61:        char *                          data;
                     62:        unsigned int                    comments;
                     63:        isc_boolean_t                   comment_ok;
                     64:        isc_boolean_t                   last_was_eol;
                     65:        unsigned int                    paren_count;
                     66:        unsigned int                    saved_paren_count;
                     67:        isc_lexspecials_t               specials;
                     68:        LIST(struct inputsource)        sources;
                     69: };
                     70: 
                     71: static inline isc_result_t
                     72: grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
                     73:        char *new;
                     74: 
                     75:        new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
                     76:        if (new == NULL)
                     77:                return (ISC_R_NOMEMORY);
                     78:        memcpy(new, lex->data, lex->max_token + 1);
                     79:        *currp = new + (*currp - lex->data);
                     80:        if (*prevp != NULL)
                     81:                *prevp = new + (*prevp - lex->data);
                     82:        isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
                     83:        lex->data = new;
                     84:        *remainingp += lex->max_token;
                     85:        lex->max_token *= 2;
                     86:        return (ISC_R_SUCCESS);
                     87: }
                     88: 
                     89: isc_result_t
                     90: isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
                     91:        isc_lex_t *lex;
                     92: 
                     93:        /*
                     94:         * Create a lexer.
                     95:         */
                     96: 
                     97:        REQUIRE(lexp != NULL && *lexp == NULL);
                     98:        REQUIRE(max_token > 0U);
                     99: 
                    100:        lex = isc_mem_get(mctx, sizeof(*lex));
                    101:        if (lex == NULL)
                    102:                return (ISC_R_NOMEMORY);
                    103:        lex->data = isc_mem_get(mctx, max_token + 1);
                    104:        if (lex->data == NULL) {
                    105:                isc_mem_put(mctx, lex, sizeof(*lex));
                    106:                return (ISC_R_NOMEMORY);
                    107:        }
                    108:        lex->mctx = mctx;
                    109:        lex->max_token = max_token;
                    110:        lex->comments = 0;
                    111:        lex->comment_ok = ISC_TRUE;
                    112:        lex->last_was_eol = ISC_TRUE;
                    113:        lex->paren_count = 0;
                    114:        lex->saved_paren_count = 0;
                    115:        memset(lex->specials, 0, 256);
                    116:        INIT_LIST(lex->sources);
                    117:        lex->magic = LEX_MAGIC;
                    118: 
                    119:        *lexp = lex;
                    120: 
                    121:        return (ISC_R_SUCCESS);
                    122: }
                    123: 
                    124: void
                    125: isc_lex_destroy(isc_lex_t **lexp) {
                    126:        isc_lex_t *lex;
                    127: 
                    128:        /*
                    129:         * Destroy the lexer.
                    130:         */
                    131: 
                    132:        REQUIRE(lexp != NULL);
                    133:        lex = *lexp;
                    134:        REQUIRE(VALID_LEX(lex));
                    135: 
                    136:        while (!EMPTY(lex->sources))
                    137:                RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
                    138:        if (lex->data != NULL)
                    139:                isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
                    140:        lex->magic = 0;
                    141:        isc_mem_put(lex->mctx, lex, sizeof(*lex));
                    142: 
                    143:        *lexp = NULL;
                    144: }
                    145: 
                    146: unsigned int
                    147: isc_lex_getcomments(isc_lex_t *lex) {
                    148:        /*
                    149:         * Return the current lexer commenting styles.
                    150:         */
                    151: 
                    152:        REQUIRE(VALID_LEX(lex));
                    153: 
                    154:        return (lex->comments);
                    155: }
                    156: 
                    157: void
                    158: isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
                    159:        /*
                    160:         * Set allowed lexer commenting styles.
                    161:         */
                    162: 
                    163:        REQUIRE(VALID_LEX(lex));
                    164: 
                    165:        lex->comments = comments;
                    166: }
                    167: 
                    168: void
                    169: isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
                    170:        /*
                    171:         * Put the current list of specials into 'specials'.
                    172:         */
                    173: 
                    174:        REQUIRE(VALID_LEX(lex));
                    175: 
                    176:        memcpy(specials, lex->specials, 256);
                    177: }
                    178: 
                    179: void
                    180: isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
                    181:        /*
                    182:         * The characters in 'specials' are returned as tokens.  Along with
                    183:         * whitespace, they delimit strings and numbers.
                    184:         */
                    185: 
                    186:        REQUIRE(VALID_LEX(lex));
                    187: 
                    188:        memcpy(lex->specials, specials, 256);
                    189: }
                    190: 
                    191: static inline isc_result_t
                    192: new_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close,
                    193:           void *input, const char *name)
                    194: {
                    195:        inputsource *source;
                    196:        isc_result_t result;
                    197: 
                    198:        source = isc_mem_get(lex->mctx, sizeof(*source));
                    199:        if (source == NULL)
                    200:                return (ISC_R_NOMEMORY);
                    201:        source->result = ISC_R_SUCCESS;
                    202:        source->is_file = is_file;
                    203:        source->need_close = need_close;
                    204:        source->at_eof = ISC_FALSE;
                    205:        source->input = input;
                    206:        source->name = isc_mem_strdup(lex->mctx, name);
                    207:        if (source->name == NULL) {
                    208:                isc_mem_put(lex->mctx, source, sizeof(*source));
                    209:                return (ISC_R_NOMEMORY);
                    210:        }
                    211:        source->pushback = NULL;
                    212:        result = isc_buffer_allocate(lex->mctx, &source->pushback,
                    213:                                     lex->max_token);
                    214:        if (result != ISC_R_SUCCESS) {
                    215:                isc_mem_free(lex->mctx, source->name);
                    216:                isc_mem_put(lex->mctx, source, sizeof(*source));
                    217:                return (result);
                    218:        }
                    219:        source->ignored = 0;
                    220:        source->line = 1;
                    221:        ISC_LIST_INITANDPREPEND(lex->sources, source, link);
                    222: 
                    223:        return (ISC_R_SUCCESS);
                    224: }
                    225: 
                    226: isc_result_t
                    227: isc_lex_openfile(isc_lex_t *lex, const char *filename) {
                    228:        isc_result_t result;
                    229:        FILE *stream = NULL;
                    230: 
                    231:        /*
                    232:         * Open 'filename' and make it the current input source for 'lex'.
                    233:         */
                    234: 
                    235:        REQUIRE(VALID_LEX(lex));
                    236: 
                    237:        result = isc_stdio_open(filename, "r", &stream);
                    238:        if (result != ISC_R_SUCCESS)
                    239:                return (result);
                    240: 
                    241:        result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename);
                    242:        if (result != ISC_R_SUCCESS)
                    243:                (void)fclose(stream);
                    244:        return (result);
                    245: }
                    246: 
                    247: isc_result_t
                    248: isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
                    249:        char name[128];
                    250: 
                    251:        /*
                    252:         * Make 'stream' the current input source for 'lex'.
                    253:         */
                    254: 
                    255:        REQUIRE(VALID_LEX(lex));
                    256: 
                    257:        snprintf(name, sizeof(name), "stream-%p", stream);
                    258: 
                    259:        return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));
                    260: }
                    261: 
                    262: isc_result_t
                    263: isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
                    264:        char name[128];
                    265: 
                    266:        /*
                    267:         * Make 'buffer' the current input source for 'lex'.
                    268:         */
                    269: 
                    270:        REQUIRE(VALID_LEX(lex));
                    271: 
                    272:        snprintf(name, sizeof(name), "buffer-%p", buffer);
                    273: 
                    274:        return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));
                    275: }
                    276: 
                    277: isc_result_t
                    278: isc_lex_close(isc_lex_t *lex) {
                    279:        inputsource *source;
                    280: 
                    281:        /*
                    282:         * Close the most recently opened object (i.e. file or buffer).
                    283:         */
                    284: 
                    285:        REQUIRE(VALID_LEX(lex));
                    286: 
                    287:        source = HEAD(lex->sources);
                    288:        if (source == NULL)
                    289:                return (ISC_R_NOMORE);
                    290: 
                    291:        ISC_LIST_UNLINK(lex->sources, source, link);
                    292:        if (source->is_file) {
                    293:                if (source->need_close)
                    294:                        (void)fclose((FILE *)(source->input));
                    295:        }
                    296:        isc_mem_free(lex->mctx, source->name);
                    297:        isc_buffer_free(&source->pushback);
                    298:        isc_mem_put(lex->mctx, source, sizeof(*source));
                    299: 
                    300:        return (ISC_R_SUCCESS);
                    301: }
                    302: 
                    303: typedef enum {
                    304:        lexstate_start,
                    305:        lexstate_crlf,
                    306:        lexstate_string,
                    307:        lexstate_number,
                    308:        lexstate_maybecomment,
                    309:        lexstate_ccomment,
                    310:        lexstate_ccommentend,
                    311:        lexstate_eatline,
                    312:        lexstate_qstring
                    313: } lexstate;
                    314: 
                    315: #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
                    316: 
                    317: static void
                    318: pushback(inputsource *source, int c) {
                    319:        REQUIRE(source->pushback->current > 0);
                    320:        if (c == EOF) {
                    321:                source->at_eof = ISC_FALSE;
                    322:                return;
                    323:        }
                    324:        source->pushback->current--;
                    325:        if (c == '\n')
                    326:                source->line--;
                    327: }
                    328: 
                    329: static isc_result_t
                    330: pushandgrow(isc_lex_t *lex, inputsource *source, int c) {
                    331:        if (isc_buffer_availablelength(source->pushback) == 0) {
                    332:                isc_buffer_t *tbuf = NULL;
                    333:                unsigned int oldlen;
                    334:                isc_region_t used;
                    335:                isc_result_t result;
                    336: 
                    337:                oldlen = isc_buffer_length(source->pushback);
                    338:                result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2);
                    339:                if (result != ISC_R_SUCCESS)
                    340:                        return (result);
                    341:                isc_buffer_usedregion(source->pushback, &used);
                    342:                result = isc_buffer_copyregion(tbuf, &used);
                    343:                INSIST(result == ISC_R_SUCCESS);
                    344:                tbuf->current = source->pushback->current;
                    345:                isc_buffer_free(&source->pushback);
                    346:                source->pushback = tbuf;
                    347:        }
                    348:        isc_buffer_putuint8(source->pushback, (isc_uint8_t)c);
                    349:        return (ISC_R_SUCCESS);
                    350: }
                    351: 
                    352: isc_result_t
                    353: isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
                    354:        inputsource *source;
                    355:        int c;
                    356:        isc_boolean_t done = ISC_FALSE;
                    357:        isc_boolean_t no_comments = ISC_FALSE;
                    358:        isc_boolean_t escaped = ISC_FALSE;
                    359:        lexstate state = lexstate_start;
                    360:        lexstate saved_state = lexstate_start;
                    361:        isc_buffer_t *buffer;
                    362:        FILE *stream;
                    363:        char *curr, *prev;
                    364:        size_t remaining;
                    365:        isc_uint32_t as_ulong;
                    366:        unsigned int saved_options;
                    367:        isc_result_t result;
                    368: 
                    369:        /*
                    370:         * Get the next token.
                    371:         */
                    372: 
                    373:        REQUIRE(VALID_LEX(lex));
                    374:        source = HEAD(lex->sources);
                    375:        REQUIRE(tokenp != NULL);
                    376: 
                    377:        if (source == NULL) {
                    378:                if ((options & ISC_LEXOPT_NOMORE) != 0) {
                    379:                        tokenp->type = isc_tokentype_nomore;
                    380:                        return (ISC_R_SUCCESS);
                    381:                }
                    382:                return (ISC_R_NOMORE);
                    383:        }
                    384: 
                    385:        if (source->result != ISC_R_SUCCESS)
                    386:                return (source->result);
                    387: 
                    388:        lex->saved_paren_count = lex->paren_count;
                    389:        source->saved_line = source->line;
                    390: 
                    391:        if (isc_buffer_remaininglength(source->pushback) == 0 &&
                    392:            source->at_eof)
                    393:        {
                    394:                if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
                    395:                    lex->paren_count != 0) {
                    396:                        lex->paren_count = 0;
                    397:                        return (ISC_R_UNBALANCED);
                    398:                }
                    399:                if ((options & ISC_LEXOPT_EOF) != 0) {
                    400:                        tokenp->type = isc_tokentype_eof;
                    401:                        return (ISC_R_SUCCESS);
                    402:                }
                    403:                return (ISC_R_EOF);
                    404:        }
                    405: 
                    406:        isc_buffer_compact(source->pushback);
                    407: 
                    408:        saved_options = options;
                    409:        if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
                    410:                options &= ~IWSEOL;
                    411: 
                    412:        curr = lex->data;
                    413:        *curr = '\0';
                    414: 
                    415:        prev = NULL;
                    416:        remaining = lex->max_token;
                    417: 
                    418: #ifdef HAVE_FLOCKFILE
                    419:        if (source->is_file)
                    420:                flockfile(source->input);
                    421: #endif
                    422: 
                    423:        do {
                    424:                if (isc_buffer_remaininglength(source->pushback) == 0) {
                    425:                        if (source->is_file) {
                    426:                                stream = source->input;
                    427: 
                    428: #if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED)
                    429:                                c = getc_unlocked(stream);
                    430: #else
                    431:                                c = getc(stream);
                    432: #endif
                    433:                                if (c == EOF) {
                    434:                                        if (ferror(stream)) {
                    435:                                                source->result = ISC_R_IOERROR;
                    436:                                                result = source->result;
                    437:                                                goto done;
                    438:                                        }
                    439:                                        source->at_eof = ISC_TRUE;
                    440:                                }
                    441:                        } else {
                    442:                                buffer = source->input;
                    443: 
                    444:                                if (buffer->current == buffer->used) {
                    445:                                        c = EOF;
                    446:                                        source->at_eof = ISC_TRUE;
                    447:                                } else {
                    448:                                        c = *((char *)buffer->base +
                    449:                                              buffer->current);
                    450:                                        buffer->current++;
                    451:                                }
                    452:                        }
                    453:                        if (c != EOF) {
                    454:                                source->result = pushandgrow(lex, source, c);
                    455:                                if (source->result != ISC_R_SUCCESS) {
                    456:                                        result = source->result;
                    457:                                        goto done;
                    458:                                }
                    459:                        }
                    460:                }
                    461: 
                    462:                if (!source->at_eof) {
                    463:                        if (state == lexstate_start)
                    464:                                /* Token has not started yet. */
                    465:                                source->ignored =
                    466:                                   isc_buffer_consumedlength(source->pushback);
                    467:                        c = isc_buffer_getuint8(source->pushback);
                    468:                } else {
                    469:                        c = EOF;
                    470:                }
                    471: 
                    472:                if (c == '\n')
                    473:                        source->line++;
                    474: 
                    475:                if (lex->comment_ok && !no_comments) {
                    476:                        if (!escaped && c == ';' &&
                    477:                            ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE)
                    478:                             != 0)) {
                    479:                                saved_state = state;
                    480:                                state = lexstate_eatline;
                    481:                                no_comments = ISC_TRUE;
                    482:                                continue;
                    483:                        } else if (c == '/' &&
                    484:                                   (lex->comments &
                    485:                                    (ISC_LEXCOMMENT_C|
                    486:                                     ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
                    487:                                saved_state = state;
                    488:                                state = lexstate_maybecomment;
                    489:                                no_comments = ISC_TRUE;
                    490:                                continue;
                    491:                        } else if (c == '#' &&
                    492:                                   ((lex->comments & ISC_LEXCOMMENT_SHELL)
                    493:                                    != 0)) {
                    494:                                saved_state = state;
                    495:                                state = lexstate_eatline;
                    496:                                no_comments = ISC_TRUE;
                    497:                                continue;
                    498:                        }
                    499:                }
                    500: 
                    501:        no_read:
                    502:                /* INSIST(c == EOF || (c >= 0 && c <= 255)); */
                    503:                switch (state) {
                    504:                case lexstate_start:
                    505:                        if (c == EOF) {
                    506:                                lex->last_was_eol = ISC_FALSE;
                    507:                                if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
                    508:                                    lex->paren_count != 0) {
                    509:                                        lex->paren_count = 0;
                    510:                                        result = ISC_R_UNBALANCED;
                    511:                                        goto done;
                    512:                                }
                    513:                                if ((options & ISC_LEXOPT_EOF) == 0) {
                    514:                                        result = ISC_R_EOF;
                    515:                                        goto done;
                    516:                                }
                    517:                                tokenp->type = isc_tokentype_eof;
                    518:                                done = ISC_TRUE;
                    519:                        } else if (c == ' ' || c == '\t') {
                    520:                                if (lex->last_was_eol &&
                    521:                                    (options & ISC_LEXOPT_INITIALWS)
                    522:                                    != 0) {
                    523:                                        lex->last_was_eol = ISC_FALSE;
                    524:                                        tokenp->type = isc_tokentype_initialws;
                    525:                                        tokenp->value.as_char = c;
                    526:                                        done = ISC_TRUE;
                    527:                                }
                    528:                        } else if (c == '\n') {
                    529:                                if ((options & ISC_LEXOPT_EOL) != 0) {
                    530:                                        tokenp->type = isc_tokentype_eol;
                    531:                                        done = ISC_TRUE;
                    532:                                }
                    533:                                lex->last_was_eol = ISC_TRUE;
                    534:                        } else if (c == '\r') {
                    535:                                if ((options & ISC_LEXOPT_EOL) != 0)
                    536:                                        state = lexstate_crlf;
                    537:                        } else if (c == '"' &&
                    538:                                   (options & ISC_LEXOPT_QSTRING) != 0) {
                    539:                                lex->last_was_eol = ISC_FALSE;
                    540:                                no_comments = ISC_TRUE;
                    541:                                state = lexstate_qstring;
                    542:                        } else if (lex->specials[c]) {
                    543:                                lex->last_was_eol = ISC_FALSE;
                    544:                                if ((c == '(' || c == ')') &&
                    545:                                    (options & ISC_LEXOPT_DNSMULTILINE) != 0) {
                    546:                                        if (c == '(') {
                    547:                                                if (lex->paren_count == 0)
                    548:                                                        options &= ~IWSEOL;
                    549:                                                lex->paren_count++;
                    550:                                        } else {
                    551:                                                if (lex->paren_count == 0) {
                    552:                                                    result = ISC_R_UNBALANCED;
                    553:                                                    goto done;
                    554:                                                }
                    555:                                                lex->paren_count--;
                    556:                                                if (lex->paren_count == 0)
                    557:                                                        options =
                    558:                                                                saved_options;
                    559:                                        }
                    560:                                        continue;
                    561:                                }
                    562:                                tokenp->type = isc_tokentype_special;
                    563:                                tokenp->value.as_char = c;
                    564:                                done = ISC_TRUE;
                    565:                        } else if (isdigit((unsigned char)c) &&
                    566:                                   (options & ISC_LEXOPT_NUMBER) != 0) {
                    567:                                lex->last_was_eol = ISC_FALSE;
                    568:                                if ((options & ISC_LEXOPT_OCTAL) != 0 &&
                    569:                                    (c == '8' || c == '9'))
                    570:                                        state = lexstate_string;
                    571:                                else
                    572:                                        state = lexstate_number;
                    573:                                goto no_read;
                    574:                        } else {
                    575:                                lex->last_was_eol = ISC_FALSE;
                    576:                                state = lexstate_string;
                    577:                                goto no_read;
                    578:                        }
                    579:                        break;
                    580:                case lexstate_crlf:
                    581:                        if (c != '\n')
                    582:                                pushback(source, c);
                    583:                        tokenp->type = isc_tokentype_eol;
                    584:                        done = ISC_TRUE;
                    585:                        lex->last_was_eol = ISC_TRUE;
                    586:                        break;
                    587:                case lexstate_number:
                    588:                        if (c == EOF || !isdigit((unsigned char)c)) {
                    589:                                if (c == ' ' || c == '\t' || c == '\r' ||
                    590:                                    c == '\n' || c == EOF ||
                    591:                                    lex->specials[c]) {
                    592:                                        int base;
                    593:                                        if ((options & ISC_LEXOPT_OCTAL) != 0)
                    594:                                                base = 8;
                    595:                                        else if ((options & ISC_LEXOPT_CNUMBER) != 0)
                    596:                                                base = 0;
                    597:                                        else
                    598:                                                base = 10;
                    599:                                        pushback(source, c);
                    600: 
                    601:                                        result = isc_parse_uint32(&as_ulong,
                    602:                                                                  lex->data,
                    603:                                                                  base);
                    604:                                        if (result == ISC_R_SUCCESS) {
                    605:                                                tokenp->type =
                    606:                                                        isc_tokentype_number;
                    607:                                                tokenp->value.as_ulong =
                    608:                                                        as_ulong;
                    609:                                        } else if (result == ISC_R_BADNUMBER) {
                    610:                                                isc_tokenvalue_t *v;
                    611: 
                    612:                                                tokenp->type =
                    613:                                                        isc_tokentype_string;
                    614:                                                v = &(tokenp->value);
                    615:                                                v->as_textregion.base =
                    616:                                                        lex->data;
                    617:                                                v->as_textregion.length =
                    618:                                                        lex->max_token -
                    619:                                                        remaining;
                    620:                                        } else
                    621:                                                goto done;
                    622:                                        done = ISC_TRUE;
                    623:                                        continue;
                    624:                                } else if (!(options & ISC_LEXOPT_CNUMBER) ||
                    625:                                           ((c != 'x' && c != 'X') ||
                    626:                                           (curr != &lex->data[1]) ||
                    627:                                           (lex->data[0] != '0'))) {
                    628:                                        /* Above test supports hex numbers */
                    629:                                        state = lexstate_string;
                    630:                                }
                    631:                        } else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
                    632:                                   (c == '8' || c == '9')) {
                    633:                                state = lexstate_string;
                    634:                        }
                    635:                        if (remaining == 0U) {
                    636:                                result = grow_data(lex, &remaining,
                    637:                                                   &curr, &prev);
                    638:                                if (result != ISC_R_SUCCESS)
                    639:                                        goto done;
                    640:                        }
                    641:                        INSIST(remaining > 0U);
                    642:                        *curr++ = c;
                    643:                        *curr = '\0';
                    644:                        remaining--;
                    645:                        break;
                    646:                case lexstate_string:
                    647:                        /*
                    648:                         * EOF needs to be checked before lex->specials[c]
                    649:                         * as lex->specials[EOF] is not a good idea.
                    650:                         */
                    651:                        if (c == '\r' || c == '\n' || c == EOF ||
                    652:                            (!escaped &&
                    653:                             (c == ' ' || c == '\t' || lex->specials[c]))) {
                    654:                                pushback(source, c);
                    655:                                if (source->result != ISC_R_SUCCESS) {
                    656:                                        result = source->result;
                    657:                                        goto done;
                    658:                                }
                    659:                                tokenp->type = isc_tokentype_string;
                    660:                                tokenp->value.as_textregion.base = lex->data;
                    661:                                tokenp->value.as_textregion.length =
                    662:                                        lex->max_token - remaining;
                    663:                                done = ISC_TRUE;
                    664:                                continue;
                    665:                        }
                    666:                        if ((options & ISC_LEXOPT_ESCAPE) != 0)
                    667:                                escaped = (!escaped && c == '\\') ?
                    668:                                                ISC_TRUE : ISC_FALSE;
                    669:                        if (remaining == 0U) {
                    670:                                result = grow_data(lex, &remaining,
                    671:                                                   &curr, &prev);
                    672:                                if (result != ISC_R_SUCCESS)
                    673:                                        goto done;
                    674:                        }
                    675:                        INSIST(remaining > 0U);
                    676:                        *curr++ = c;
                    677:                        *curr = '\0';
                    678:                        remaining--;
                    679:                        break;
                    680:                case lexstate_maybecomment:
                    681:                        if (c == '*' &&
                    682:                            (lex->comments & ISC_LEXCOMMENT_C) != 0) {
                    683:                                state = lexstate_ccomment;
                    684:                                continue;
                    685:                        } else if (c == '/' &&
                    686:                            (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
                    687:                                state = lexstate_eatline;
                    688:                                continue;
                    689:                        }
                    690:                        pushback(source, c);
                    691:                        c = '/';
                    692:                        no_comments = ISC_FALSE;
                    693:                        state = saved_state;
                    694:                        goto no_read;
                    695:                case lexstate_ccomment:
                    696:                        if (c == EOF) {
                    697:                                result = ISC_R_UNEXPECTEDEND;
                    698:                                goto done;
                    699:                        }
                    700:                        if (c == '*')
                    701:                                state = lexstate_ccommentend;
                    702:                        break;
                    703:                case lexstate_ccommentend:
                    704:                        if (c == EOF) {
                    705:                                result = ISC_R_UNEXPECTEDEND;
                    706:                                goto done;
                    707:                        }
                    708:                        if (c == '/') {
                    709:                                /*
                    710:                                 * C-style comments become a single space.
                    711:                                 * We do this to ensure that a comment will
                    712:                                 * act as a delimiter for strings and
                    713:                                 * numbers.
                    714:                                 */
                    715:                                c = ' ';
                    716:                                no_comments = ISC_FALSE;
                    717:                                state = saved_state;
                    718:                                goto no_read;
                    719:                        } else if (c != '*')
                    720:                                state = lexstate_ccomment;
                    721:                        break;
                    722:                case lexstate_eatline:
                    723:                        if ((c == '\n') || (c == EOF)) {
                    724:                                no_comments = ISC_FALSE;
                    725:                                state = saved_state;
                    726:                                goto no_read;
                    727:                        }
                    728:                        break;
                    729:                case lexstate_qstring:
                    730:                        if (c == EOF) {
                    731:                                result = ISC_R_UNEXPECTEDEND;
                    732:                                goto done;
                    733:                        }
                    734:                        if (c == '"') {
                    735:                                if (escaped) {
                    736:                                        escaped = ISC_FALSE;
                    737:                                        /*
                    738:                                         * Overwrite the preceding backslash.
                    739:                                         */
                    740:                                        INSIST(prev != NULL);
                    741:                                        *prev = '"';
                    742:                                } else {
                    743:                                        tokenp->type = isc_tokentype_qstring;
                    744:                                        tokenp->value.as_textregion.base =
                    745:                                                lex->data;
                    746:                                        tokenp->value.as_textregion.length =
                    747:                                                lex->max_token - remaining;
                    748:                                        no_comments = ISC_FALSE;
                    749:                                        done = ISC_TRUE;
                    750:                                }
                    751:                        } else {
                    752:                                if (c == '\n' && !escaped &&
                    753:                            (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
                    754:                                        pushback(source, c);
                    755:                                        result = ISC_R_UNBALANCEDQUOTES;
                    756:                                        goto done;
                    757:                                }
                    758:                                if (c == '\\' && !escaped)
                    759:                                        escaped = ISC_TRUE;
                    760:                                else
                    761:                                        escaped = ISC_FALSE;
                    762:                                if (remaining == 0U) {
                    763:                                        result = grow_data(lex, &remaining,
                    764:                                                           &curr, &prev);
                    765:                                        if (result != ISC_R_SUCCESS)
                    766:                                                goto done;
                    767:                                }
                    768:                                INSIST(remaining > 0U);
                    769:                                prev = curr;
                    770:                                *curr++ = c;
                    771:                                *curr = '\0';
                    772:                                remaining--;
                    773:                        }
                    774:                        break;
                    775:                default:
                    776:                        FATAL_ERROR(__FILE__, __LINE__,
                    777:                                    isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX,
                    778:                                                   ISC_MSG_UNEXPECTEDSTATE,
                    779:                                                   "Unexpected state %d"),
                    780:                                    state);
                    781:                        /* Does not return. */
                    782:                }
                    783: 
                    784:        } while (!done);
                    785: 
                    786:        result = ISC_R_SUCCESS;
                    787:  done:
                    788: #ifdef HAVE_FLOCKFILE
                    789:        if (source->is_file)
                    790:                funlockfile(source->input);
                    791: #endif
                    792:        return (result);
                    793: }
                    794: 
                    795: isc_result_t
                    796: isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
                    797:                       isc_tokentype_t expect, isc_boolean_t eol)
                    798: {
                    799:        unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
                    800:                               ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
                    801:        isc_result_t result;
                    802: 
                    803:        if (expect == isc_tokentype_qstring)
                    804:                options |= ISC_LEXOPT_QSTRING;
                    805:        else if (expect == isc_tokentype_number)
                    806:                options |= ISC_LEXOPT_NUMBER;
                    807:        result = isc_lex_gettoken(lex, options, token);
                    808:        if (result == ISC_R_RANGE)
                    809:                isc_lex_ungettoken(lex, token);
                    810:        if (result != ISC_R_SUCCESS)
                    811:                return (result);
                    812: 
                    813:        if (eol && ((token->type == isc_tokentype_eol) ||
                    814:                    (token->type == isc_tokentype_eof)))
                    815:                return (ISC_R_SUCCESS);
                    816:        if (token->type == isc_tokentype_string &&
                    817:            expect == isc_tokentype_qstring)
                    818:                return (ISC_R_SUCCESS);
                    819:        if (token->type != expect) {
                    820:                isc_lex_ungettoken(lex, token);
                    821:                if (token->type == isc_tokentype_eol ||
                    822:                    token->type == isc_tokentype_eof)
                    823:                        return (ISC_R_UNEXPECTEDEND);
                    824:                if (expect == isc_tokentype_number)
                    825:                        return (ISC_R_BADNUMBER);
                    826:                return (ISC_R_UNEXPECTEDTOKEN);
                    827:        }
                    828:        return (ISC_R_SUCCESS);
                    829: }
                    830: 
                    831: isc_result_t
                    832: isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol)
                    833: {
                    834:        unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
                    835:                               ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE|
                    836:                               ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL;
                    837:        isc_result_t result;
                    838: 
                    839:        result = isc_lex_gettoken(lex, options, token);
                    840:        if (result == ISC_R_RANGE)
                    841:                isc_lex_ungettoken(lex, token);
                    842:        if (result != ISC_R_SUCCESS)
                    843:                return (result);
                    844: 
                    845:        if (eol && ((token->type == isc_tokentype_eol) ||
                    846:                    (token->type == isc_tokentype_eof)))
                    847:                return (ISC_R_SUCCESS);
                    848:        if (token->type != isc_tokentype_number) {
                    849:                isc_lex_ungettoken(lex, token);
                    850:                if (token->type == isc_tokentype_eol ||
                    851:                    token->type == isc_tokentype_eof)
                    852:                        return (ISC_R_UNEXPECTEDEND);
                    853:                return (ISC_R_BADNUMBER);
                    854:        }
                    855:        return (ISC_R_SUCCESS);
                    856: }
                    857: 
                    858: void
                    859: isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
                    860:        inputsource *source;
                    861:        /*
                    862:         * Unget the current token.
                    863:         */
                    864: 
                    865:        REQUIRE(VALID_LEX(lex));
                    866:        source = HEAD(lex->sources);
                    867:        REQUIRE(source != NULL);
                    868:        REQUIRE(tokenp != NULL);
                    869:        REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
                    870:                tokenp->type == isc_tokentype_eof);
                    871: 
                    872:        UNUSED(tokenp);
                    873: 
                    874:        isc_buffer_first(source->pushback);
                    875:        lex->paren_count = lex->saved_paren_count;
                    876:        source->line = source->saved_line;
                    877:        source->at_eof = ISC_FALSE;
                    878: }
                    879: 
                    880: void
                    881: isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
                    882: {
                    883:        inputsource *source;
                    884: 
                    885:        REQUIRE(VALID_LEX(lex));
                    886:        source = HEAD(lex->sources);
                    887:        REQUIRE(source != NULL);
                    888:        REQUIRE(tokenp != NULL);
                    889:        REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
                    890:                tokenp->type == isc_tokentype_eof);
                    891: 
                    892:        UNUSED(tokenp);
                    893: 
                    894:        INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
                    895:        r->base = (unsigned char *)isc_buffer_base(source->pushback) +
                    896:                  source->ignored;
                    897:        r->length = isc_buffer_consumedlength(source->pushback) -
                    898:                    source->ignored;
                    899: }
                    900: 
                    901: 
                    902: char *
                    903: isc_lex_getsourcename(isc_lex_t *lex) {
                    904:        inputsource *source;
                    905: 
                    906:        REQUIRE(VALID_LEX(lex));
                    907:        source = HEAD(lex->sources);
                    908: 
                    909:        if (source == NULL)
                    910:                return (NULL);
                    911: 
                    912:        return (source->name);
                    913: }
                    914: 
                    915: unsigned long
                    916: isc_lex_getsourceline(isc_lex_t *lex) {
                    917:        inputsource *source;
                    918: 
                    919:        REQUIRE(VALID_LEX(lex));
                    920:        source = HEAD(lex->sources);
                    921: 
                    922:        if (source == NULL)
                    923:                return (0);
                    924: 
                    925:        return (source->line);
                    926: }
                    927: 
                    928: 
                    929: isc_result_t
                    930: isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
                    931:        inputsource *source;
                    932:        char *newname;
                    933: 
                    934:        REQUIRE(VALID_LEX(lex));
                    935:        source = HEAD(lex->sources);
                    936: 
                    937:        if (source == NULL)
                    938:                return(ISC_R_NOTFOUND);
                    939:        newname = isc_mem_strdup(lex->mctx, name);
                    940:        if (newname == NULL)
                    941:                return (ISC_R_NOMEMORY);
                    942:        isc_mem_free(lex->mctx, source->name);
                    943:        source->name = newname;
                    944:        return (ISC_R_SUCCESS);
                    945: }
                    946: 
                    947: isc_boolean_t
                    948: isc_lex_isfile(isc_lex_t *lex) {
                    949:        inputsource *source;
                    950: 
                    951:        REQUIRE(VALID_LEX(lex));
                    952: 
                    953:        source = HEAD(lex->sources);
                    954: 
                    955:        if (source == NULL)
                    956:                return (ISC_FALSE);
                    957: 
                    958:        return (source->is_file);
                    959: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>