📄 lex.c
字号:
/* * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. *//* $Id: lex.c,v 1.66.2.6.2.8 2004/08/28 06:25:21 marka Exp $ */#include <config.h>#include <ctype.h>#include <errno.h>#include <stdlib.h>#include <isc/buffer.h>#include <isc/file.h>#include <isc/lex.h>#include <isc/mem.h>#include <isc/msgs.h>#include <isc/parseint.h>#include <isc/print.h>#include <isc/stdio.h>#include <isc/string.h>#include <isc/util.h>typedef struct inputsource { isc_result_t result; isc_boolean_t is_file; isc_boolean_t need_close; isc_boolean_t at_eof; isc_buffer_t * pushback; unsigned int ignored; void * input; char * name; unsigned long line; unsigned long saved_line; ISC_LINK(struct inputsource) link;} inputsource;#define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!')#define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC)struct isc_lex { /* Unlocked. */ unsigned int magic; isc_mem_t * mctx; size_t max_token; char * data; unsigned int comments; isc_boolean_t comment_ok; isc_boolean_t last_was_eol; unsigned int paren_count; unsigned int saved_paren_count; isc_lexspecials_t specials; LIST(struct inputsource) sources;};static inline isc_result_tgrow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) { char *new; new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1); if (new == NULL) return (ISC_R_NOMEMORY); memcpy(new, lex->data, lex->max_token + 1); *currp = new + (*currp - lex->data); if (*prevp != NULL) *prevp = new + (*prevp - lex->data); isc_mem_put(lex->mctx, lex->data, lex->max_token + 1); lex->data = new; *remainingp += lex->max_token; lex->max_token *= 2; return (ISC_R_SUCCESS);}isc_result_tisc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) { isc_lex_t *lex; /* * Create a lexer. */ REQUIRE(lexp != NULL && *lexp == NULL); REQUIRE(max_token > 0U); lex = isc_mem_get(mctx, sizeof(*lex)); if (lex == NULL) return (ISC_R_NOMEMORY); lex->data = isc_mem_get(mctx, max_token + 1); if (lex->data == NULL) { isc_mem_put(mctx, lex, sizeof(*lex)); return (ISC_R_NOMEMORY); } lex->mctx = mctx; lex->max_token = max_token; lex->comments = 0; lex->comment_ok = ISC_TRUE; lex->last_was_eol = ISC_TRUE; lex->paren_count = 0; lex->saved_paren_count = 0; memset(lex->specials, 0, 256); INIT_LIST(lex->sources); lex->magic = LEX_MAGIC; *lexp = lex; return (ISC_R_SUCCESS);}voidisc_lex_destroy(isc_lex_t **lexp) { isc_lex_t *lex; /* * Destroy the lexer. */ REQUIRE(lexp != NULL); lex = *lexp; REQUIRE(VALID_LEX(lex)); while (!EMPTY(lex->sources)) RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS); if (lex->data != NULL) isc_mem_put(lex->mctx, lex->data, lex->max_token + 1); lex->magic = 0; isc_mem_put(lex->mctx, lex, sizeof(*lex)); *lexp = NULL;}unsigned intisc_lex_getcomments(isc_lex_t *lex) { /* * Return the current lexer commenting styles. */ REQUIRE(VALID_LEX(lex)); return (lex->comments);}voidisc_lex_setcomments(isc_lex_t *lex, unsigned int comments) { /* * Set allowed lexer commenting styles. */ REQUIRE(VALID_LEX(lex)); lex->comments = comments;}voidisc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) { /* * Put the current list of specials into 'specials'. */ REQUIRE(VALID_LEX(lex)); memcpy(specials, lex->specials, 256);}voidisc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) { /* * The characters in 'specials' are returned as tokens. Along with * whitespace, they delimit strings and numbers. */ REQUIRE(VALID_LEX(lex)); memcpy(lex->specials, specials, 256);}static inline isc_result_tnew_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close, void *input, const char *name){ inputsource *source; isc_result_t result; source = isc_mem_get(lex->mctx, sizeof(*source)); if (source == NULL) return (ISC_R_NOMEMORY); source->result = ISC_R_SUCCESS; source->is_file = is_file; source->need_close = need_close; source->at_eof = ISC_FALSE; source->input = input; source->name = isc_mem_strdup(lex->mctx, name); if (source->name == NULL) { isc_mem_put(lex->mctx, source, sizeof(*source)); return (ISC_R_NOMEMORY); } source->pushback = NULL; result = isc_buffer_allocate(lex->mctx, &source->pushback, lex->max_token); if (result != ISC_R_SUCCESS) { isc_mem_free(lex->mctx, source->name); isc_mem_put(lex->mctx, source, sizeof(*source)); return (result); } source->ignored = 0; source->line = 1; ISC_LIST_INITANDPREPEND(lex->sources, source, link); return (ISC_R_SUCCESS);}isc_result_tisc_lex_openfile(isc_lex_t *lex, const char *filename) { isc_result_t result; FILE *stream = NULL; /* * Open 'filename' and make it the current input source for 'lex'. */ REQUIRE(VALID_LEX(lex)); result = isc_stdio_open(filename, "r", &stream); if (result != ISC_R_SUCCESS) return (result); result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename); if (result != ISC_R_SUCCESS) (void)fclose(stream); return (result);}isc_result_tisc_lex_openstream(isc_lex_t *lex, FILE *stream) { char name[128]; /* * Make 'stream' the current input source for 'lex'. */ REQUIRE(VALID_LEX(lex)); snprintf(name, sizeof(name), "stream-%p", stream); return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));}isc_result_tisc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) { char name[128]; /* * Make 'buffer' the current input source for 'lex'. */ REQUIRE(VALID_LEX(lex)); snprintf(name, sizeof(name), "buffer-%p", buffer); return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));}isc_result_tisc_lex_close(isc_lex_t *lex) { inputsource *source; /* * Close the most recently opened object (i.e. file or buffer). */ REQUIRE(VALID_LEX(lex)); source = HEAD(lex->sources); if (source == NULL) return (ISC_R_NOMORE); ISC_LIST_UNLINK(lex->sources, source, link); if (source->is_file) { if (source->need_close) (void)fclose((FILE *)(source->input)); } isc_mem_free(lex->mctx, source->name); isc_buffer_free(&source->pushback); isc_mem_put(lex->mctx, source, sizeof(*source)); return (ISC_R_SUCCESS);}typedef enum { lexstate_start, lexstate_crlf, lexstate_string, lexstate_number, lexstate_maybecomment, lexstate_ccomment, lexstate_ccommentend, lexstate_eatline, lexstate_qstring} lexstate;#define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)static voidpushback(inputsource *source, int c) { REQUIRE(source->pushback->current > 0); if (c == EOF) { source->at_eof = ISC_FALSE; return; } source->pushback->current--; if (c == '\n') source->line--;}static isc_result_tpushandgrow(isc_lex_t *lex, inputsource *source, int c) { if (isc_buffer_availablelength(source->pushback) == 0) { isc_buffer_t *tbuf = NULL; unsigned int oldlen; isc_region_t used; isc_result_t result; oldlen = isc_buffer_length(source->pushback); result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2); if (result != ISC_R_SUCCESS) return (result); isc_buffer_usedregion(source->pushback, &used); result = isc_buffer_copyregion(tbuf, &used); INSIST(result == ISC_R_SUCCESS); tbuf->current = source->pushback->current; isc_buffer_free(&source->pushback); source->pushback = tbuf; } isc_buffer_putuint8(source->pushback, (isc_uint8_t)c); return (ISC_R_SUCCESS);}isc_result_tisc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { inputsource *source; int c; isc_boolean_t done = ISC_FALSE; isc_boolean_t no_comments = ISC_FALSE; isc_boolean_t escaped = ISC_FALSE; lexstate state = lexstate_start; lexstate saved_state = lexstate_start; isc_buffer_t *buffer; FILE *stream; char *curr, *prev; size_t remaining; isc_uint32_t as_ulong; unsigned int saved_options; isc_result_t result; /* * Get the next token. */ REQUIRE(VALID_LEX(lex)); source = HEAD(lex->sources); REQUIRE(tokenp != NULL); lex->saved_paren_count = lex->paren_count; source->saved_line = source->line; if (source == NULL) { if ((options & ISC_LEXOPT_NOMORE) != 0) { tokenp->type = isc_tokentype_nomore; return (ISC_R_SUCCESS); } return (ISC_R_NOMORE); } if (source->result != ISC_R_SUCCESS) return (source->result); if (isc_buffer_remaininglength(source->pushback) == 0 && source->at_eof) { if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count != 0) { lex->paren_count = 0; return (ISC_R_UNBALANCED); } if ((options & ISC_LEXOPT_EOF) != 0) { tokenp->type = isc_tokentype_eof; return (ISC_R_SUCCESS); } return (ISC_R_EOF); } isc_buffer_compact(source->pushback); saved_options = options; if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0) options &= ~IWSEOL; curr = lex->data; *curr = '\0'; prev = NULL; remaining = lex->max_token;#ifdef HAVE_FLOCKFILE if (source->is_file) flockfile(source->input);#endif do { if (isc_buffer_remaininglength(source->pushback) == 0) { if (source->is_file) { stream = source->input;#if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED) c = getc_unlocked(stream);#else c = getc(stream);#endif if (c == EOF) { if (ferror(stream)) { source->result = ISC_R_IOERROR; result = source->result; goto done; } source->at_eof = ISC_TRUE; } } else { buffer = source->input; if (buffer->current == buffer->used) { c = EOF; source->at_eof = ISC_TRUE; } else { c = *((char *)buffer->base + buffer->current); buffer->current++; } } if (c != EOF) { source->result = pushandgrow(lex, source, c); if (source->result != ISC_R_SUCCESS) { result = source->result; goto done; } } } if (!source->at_eof) { if (state == lexstate_start)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -