1258945Sroberto/* 2258945Sroberto * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * Copyright (C) 1998-2003 Internet Software Consortium. 4258945Sroberto * 5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any 6258945Sroberto * purpose with or without fee is hereby granted, provided that the above 7258945Sroberto * copyright notice and this permission notice appear in all copies. 8258945Sroberto * 9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11258945Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15258945Sroberto * PERFORMANCE OF THIS SOFTWARE. 16258945Sroberto */ 17258945Sroberto 18258945Sroberto/* $Id: lex.c,v 1.86 2007/09/17 09:56:29 shane Exp $ */ 19258945Sroberto 20258945Sroberto/*! \file */ 21258945Sroberto 22258945Sroberto#include <config.h> 23258945Sroberto 24258945Sroberto#include <ctype.h> 25258945Sroberto#include <errno.h> 26258945Sroberto#include <stdlib.h> 27258945Sroberto 28258945Sroberto#include <isc/buffer.h> 29258945Sroberto#include <isc/file.h> 30258945Sroberto#include <isc/lex.h> 31258945Sroberto#include <isc/mem.h> 32258945Sroberto#include <isc/msgs.h> 33258945Sroberto#include <isc/parseint.h> 34258945Sroberto#include <isc/print.h> 35258945Sroberto#include <isc/stdio.h> 36258945Sroberto#include <isc/string.h> 37258945Sroberto#include <isc/util.h> 38258945Sroberto 39258945Srobertotypedef struct inputsource { 40258945Sroberto isc_result_t result; 41258945Sroberto isc_boolean_t is_file; 42258945Sroberto isc_boolean_t need_close; 43258945Sroberto isc_boolean_t at_eof; 44258945Sroberto isc_buffer_t * pushback; 45258945Sroberto unsigned int ignored; 46258945Sroberto void * input; 47258945Sroberto char * name; 48258945Sroberto unsigned long line; 49258945Sroberto unsigned long saved_line; 50258945Sroberto ISC_LINK(struct inputsource) link; 51258945Sroberto} inputsource; 52258945Sroberto 53258945Sroberto#define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!') 54258945Sroberto#define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC) 55258945Sroberto 56258945Srobertostruct isc_lex { 57258945Sroberto /* Unlocked. */ 58258945Sroberto unsigned int magic; 59258945Sroberto isc_mem_t * mctx; 60258945Sroberto size_t max_token; 61258945Sroberto char * data; 62258945Sroberto unsigned int comments; 63258945Sroberto isc_boolean_t comment_ok; 64258945Sroberto isc_boolean_t last_was_eol; 65258945Sroberto unsigned int paren_count; 66258945Sroberto unsigned int saved_paren_count; 67258945Sroberto isc_lexspecials_t specials; 68258945Sroberto LIST(struct inputsource) sources; 69258945Sroberto}; 70258945Sroberto 71258945Srobertostatic inline isc_result_t 72258945Srobertogrow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) { 73258945Sroberto char *new; 74258945Sroberto 75258945Sroberto new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1); 76258945Sroberto if (new == NULL) 77258945Sroberto return (ISC_R_NOMEMORY); 78258945Sroberto memcpy(new, lex->data, lex->max_token + 1); 79258945Sroberto *currp = new + (*currp - lex->data); 80258945Sroberto if (*prevp != NULL) 81258945Sroberto *prevp = new + (*prevp - lex->data); 82258945Sroberto isc_mem_put(lex->mctx, lex->data, lex->max_token + 1); 83258945Sroberto lex->data = new; 84258945Sroberto *remainingp += lex->max_token; 85258945Sroberto lex->max_token *= 2; 86258945Sroberto return (ISC_R_SUCCESS); 87258945Sroberto} 88258945Sroberto 89258945Srobertoisc_result_t 90258945Srobertoisc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) { 91258945Sroberto isc_lex_t *lex; 92258945Sroberto 93258945Sroberto /* 94258945Sroberto * Create a lexer. 95258945Sroberto */ 96258945Sroberto 97258945Sroberto REQUIRE(lexp != NULL && *lexp == NULL); 98258945Sroberto REQUIRE(max_token > 0U); 99258945Sroberto 100258945Sroberto lex = isc_mem_get(mctx, sizeof(*lex)); 101258945Sroberto if (lex == NULL) 102258945Sroberto return (ISC_R_NOMEMORY); 103258945Sroberto lex->data = isc_mem_get(mctx, max_token + 1); 104258945Sroberto if (lex->data == NULL) { 105258945Sroberto isc_mem_put(mctx, lex, sizeof(*lex)); 106258945Sroberto return (ISC_R_NOMEMORY); 107258945Sroberto } 108258945Sroberto lex->mctx = mctx; 109258945Sroberto lex->max_token = max_token; 110258945Sroberto lex->comments = 0; 111258945Sroberto lex->comment_ok = ISC_TRUE; 112258945Sroberto lex->last_was_eol = ISC_TRUE; 113258945Sroberto lex->paren_count = 0; 114258945Sroberto lex->saved_paren_count = 0; 115258945Sroberto memset(lex->specials, 0, 256); 116258945Sroberto INIT_LIST(lex->sources); 117258945Sroberto lex->magic = LEX_MAGIC; 118258945Sroberto 119258945Sroberto *lexp = lex; 120258945Sroberto 121258945Sroberto return (ISC_R_SUCCESS); 122258945Sroberto} 123258945Sroberto 124258945Srobertovoid 125258945Srobertoisc_lex_destroy(isc_lex_t **lexp) { 126258945Sroberto isc_lex_t *lex; 127258945Sroberto 128258945Sroberto /* 129258945Sroberto * Destroy the lexer. 130258945Sroberto */ 131258945Sroberto 132258945Sroberto REQUIRE(lexp != NULL); 133258945Sroberto lex = *lexp; 134258945Sroberto REQUIRE(VALID_LEX(lex)); 135258945Sroberto 136258945Sroberto while (!EMPTY(lex->sources)) 137258945Sroberto RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS); 138258945Sroberto if (lex->data != NULL) 139258945Sroberto isc_mem_put(lex->mctx, lex->data, lex->max_token + 1); 140258945Sroberto lex->magic = 0; 141258945Sroberto isc_mem_put(lex->mctx, lex, sizeof(*lex)); 142258945Sroberto 143258945Sroberto *lexp = NULL; 144258945Sroberto} 145258945Sroberto 146258945Srobertounsigned int 147258945Srobertoisc_lex_getcomments(isc_lex_t *lex) { 148258945Sroberto /* 149258945Sroberto * Return the current lexer commenting styles. 150258945Sroberto */ 151258945Sroberto 152258945Sroberto REQUIRE(VALID_LEX(lex)); 153258945Sroberto 154258945Sroberto return (lex->comments); 155258945Sroberto} 156258945Sroberto 157258945Srobertovoid 158258945Srobertoisc_lex_setcomments(isc_lex_t *lex, unsigned int comments) { 159258945Sroberto /* 160258945Sroberto * Set allowed lexer commenting styles. 161258945Sroberto */ 162258945Sroberto 163258945Sroberto REQUIRE(VALID_LEX(lex)); 164258945Sroberto 165258945Sroberto lex->comments = comments; 166258945Sroberto} 167258945Sroberto 168258945Srobertovoid 169258945Srobertoisc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) { 170258945Sroberto /* 171258945Sroberto * Put the current list of specials into 'specials'. 172258945Sroberto */ 173258945Sroberto 174258945Sroberto REQUIRE(VALID_LEX(lex)); 175258945Sroberto 176258945Sroberto memcpy(specials, lex->specials, 256); 177258945Sroberto} 178258945Sroberto 179258945Srobertovoid 180258945Srobertoisc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) { 181258945Sroberto /* 182258945Sroberto * The characters in 'specials' are returned as tokens. Along with 183258945Sroberto * whitespace, they delimit strings and numbers. 184258945Sroberto */ 185258945Sroberto 186258945Sroberto REQUIRE(VALID_LEX(lex)); 187258945Sroberto 188258945Sroberto memcpy(lex->specials, specials, 256); 189258945Sroberto} 190258945Sroberto 191258945Srobertostatic inline isc_result_t 192258945Srobertonew_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close, 193258945Sroberto void *input, const char *name) 194258945Sroberto{ 195258945Sroberto inputsource *source; 196258945Sroberto isc_result_t result; 197258945Sroberto 198258945Sroberto source = isc_mem_get(lex->mctx, sizeof(*source)); 199258945Sroberto if (source == NULL) 200258945Sroberto return (ISC_R_NOMEMORY); 201258945Sroberto source->result = ISC_R_SUCCESS; 202258945Sroberto source->is_file = is_file; 203258945Sroberto source->need_close = need_close; 204258945Sroberto source->at_eof = ISC_FALSE; 205258945Sroberto source->input = input; 206258945Sroberto source->name = isc_mem_strdup(lex->mctx, name); 207258945Sroberto if (source->name == NULL) { 208258945Sroberto isc_mem_put(lex->mctx, source, sizeof(*source)); 209258945Sroberto return (ISC_R_NOMEMORY); 210258945Sroberto } 211258945Sroberto source->pushback = NULL; 212258945Sroberto result = isc_buffer_allocate(lex->mctx, &source->pushback, 213258945Sroberto lex->max_token); 214258945Sroberto if (result != ISC_R_SUCCESS) { 215258945Sroberto isc_mem_free(lex->mctx, source->name); 216258945Sroberto isc_mem_put(lex->mctx, source, sizeof(*source)); 217258945Sroberto return (result); 218258945Sroberto } 219258945Sroberto source->ignored = 0; 220258945Sroberto source->line = 1; 221258945Sroberto ISC_LIST_INITANDPREPEND(lex->sources, source, link); 222258945Sroberto 223258945Sroberto return (ISC_R_SUCCESS); 224258945Sroberto} 225258945Sroberto 226258945Srobertoisc_result_t 227258945Srobertoisc_lex_openfile(isc_lex_t *lex, const char *filename) { 228258945Sroberto isc_result_t result; 229258945Sroberto FILE *stream = NULL; 230258945Sroberto 231258945Sroberto /* 232258945Sroberto * Open 'filename' and make it the current input source for 'lex'. 233258945Sroberto */ 234258945Sroberto 235258945Sroberto REQUIRE(VALID_LEX(lex)); 236258945Sroberto 237258945Sroberto result = isc_stdio_open(filename, "r", &stream); 238258945Sroberto if (result != ISC_R_SUCCESS) 239258945Sroberto return (result); 240258945Sroberto 241258945Sroberto result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename); 242258945Sroberto if (result != ISC_R_SUCCESS) 243258945Sroberto (void)fclose(stream); 244258945Sroberto return (result); 245258945Sroberto} 246258945Sroberto 247258945Srobertoisc_result_t 248258945Srobertoisc_lex_openstream(isc_lex_t *lex, FILE *stream) { 249258945Sroberto char name[128]; 250258945Sroberto 251258945Sroberto /* 252258945Sroberto * Make 'stream' the current input source for 'lex'. 253258945Sroberto */ 254258945Sroberto 255258945Sroberto REQUIRE(VALID_LEX(lex)); 256258945Sroberto 257258945Sroberto snprintf(name, sizeof(name), "stream-%p", stream); 258258945Sroberto 259258945Sroberto return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name)); 260258945Sroberto} 261258945Sroberto 262258945Srobertoisc_result_t 263258945Srobertoisc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) { 264258945Sroberto char name[128]; 265258945Sroberto 266258945Sroberto /* 267258945Sroberto * Make 'buffer' the current input source for 'lex'. 268258945Sroberto */ 269258945Sroberto 270258945Sroberto REQUIRE(VALID_LEX(lex)); 271258945Sroberto 272258945Sroberto snprintf(name, sizeof(name), "buffer-%p", buffer); 273258945Sroberto 274258945Sroberto return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name)); 275258945Sroberto} 276258945Sroberto 277258945Srobertoisc_result_t 278258945Srobertoisc_lex_close(isc_lex_t *lex) { 279258945Sroberto inputsource *source; 280258945Sroberto 281258945Sroberto /* 282258945Sroberto * Close the most recently opened object (i.e. file or buffer). 283258945Sroberto */ 284258945Sroberto 285258945Sroberto REQUIRE(VALID_LEX(lex)); 286258945Sroberto 287258945Sroberto source = HEAD(lex->sources); 288258945Sroberto if (source == NULL) 289258945Sroberto return (ISC_R_NOMORE); 290258945Sroberto 291258945Sroberto ISC_LIST_UNLINK(lex->sources, source, link); 292258945Sroberto if (source->is_file) { 293258945Sroberto if (source->need_close) 294258945Sroberto (void)fclose((FILE *)(source->input)); 295258945Sroberto } 296258945Sroberto isc_mem_free(lex->mctx, source->name); 297258945Sroberto isc_buffer_free(&source->pushback); 298258945Sroberto isc_mem_put(lex->mctx, source, sizeof(*source)); 299258945Sroberto 300258945Sroberto return (ISC_R_SUCCESS); 301258945Sroberto} 302258945Sroberto 303258945Srobertotypedef enum { 304258945Sroberto lexstate_start, 305258945Sroberto lexstate_crlf, 306258945Sroberto lexstate_string, 307258945Sroberto lexstate_number, 308258945Sroberto lexstate_maybecomment, 309258945Sroberto lexstate_ccomment, 310258945Sroberto lexstate_ccommentend, 311258945Sroberto lexstate_eatline, 312258945Sroberto lexstate_qstring 313258945Sroberto} lexstate; 314258945Sroberto 315258945Sroberto#define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL) 316258945Sroberto 317258945Srobertostatic void 318258945Srobertopushback(inputsource *source, int c) { 319258945Sroberto REQUIRE(source->pushback->current > 0); 320258945Sroberto if (c == EOF) { 321258945Sroberto source->at_eof = ISC_FALSE; 322258945Sroberto return; 323258945Sroberto } 324258945Sroberto source->pushback->current--; 325258945Sroberto if (c == '\n') 326258945Sroberto source->line--; 327258945Sroberto} 328258945Sroberto 329258945Srobertostatic isc_result_t 330258945Srobertopushandgrow(isc_lex_t *lex, inputsource *source, int c) { 331258945Sroberto if (isc_buffer_availablelength(source->pushback) == 0) { 332258945Sroberto isc_buffer_t *tbuf = NULL; 333258945Sroberto unsigned int oldlen; 334258945Sroberto isc_region_t used; 335258945Sroberto isc_result_t result; 336258945Sroberto 337258945Sroberto oldlen = isc_buffer_length(source->pushback); 338258945Sroberto result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2); 339258945Sroberto if (result != ISC_R_SUCCESS) 340258945Sroberto return (result); 341258945Sroberto isc_buffer_usedregion(source->pushback, &used); 342258945Sroberto result = isc_buffer_copyregion(tbuf, &used); 343258945Sroberto INSIST(result == ISC_R_SUCCESS); 344258945Sroberto tbuf->current = source->pushback->current; 345258945Sroberto isc_buffer_free(&source->pushback); 346258945Sroberto source->pushback = tbuf; 347258945Sroberto } 348258945Sroberto isc_buffer_putuint8(source->pushback, (isc_uint8_t)c); 349258945Sroberto return (ISC_R_SUCCESS); 350258945Sroberto} 351258945Sroberto 352258945Srobertoisc_result_t 353258945Srobertoisc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { 354258945Sroberto inputsource *source; 355258945Sroberto int c; 356258945Sroberto isc_boolean_t done = ISC_FALSE; 357258945Sroberto isc_boolean_t no_comments = ISC_FALSE; 358258945Sroberto isc_boolean_t escaped = ISC_FALSE; 359258945Sroberto lexstate state = lexstate_start; 360258945Sroberto lexstate saved_state = lexstate_start; 361258945Sroberto isc_buffer_t *buffer; 362258945Sroberto FILE *stream; 363258945Sroberto char *curr, *prev; 364258945Sroberto size_t remaining; 365258945Sroberto isc_uint32_t as_ulong; 366258945Sroberto unsigned int saved_options; 367258945Sroberto isc_result_t result; 368258945Sroberto 369258945Sroberto /* 370258945Sroberto * Get the next token. 371258945Sroberto */ 372258945Sroberto 373258945Sroberto REQUIRE(VALID_LEX(lex)); 374258945Sroberto source = HEAD(lex->sources); 375258945Sroberto REQUIRE(tokenp != NULL); 376258945Sroberto 377258945Sroberto if (source == NULL) { 378258945Sroberto if ((options & ISC_LEXOPT_NOMORE) != 0) { 379258945Sroberto tokenp->type = isc_tokentype_nomore; 380258945Sroberto return (ISC_R_SUCCESS); 381258945Sroberto } 382258945Sroberto return (ISC_R_NOMORE); 383258945Sroberto } 384258945Sroberto 385258945Sroberto if (source->result != ISC_R_SUCCESS) 386258945Sroberto return (source->result); 387258945Sroberto 388258945Sroberto lex->saved_paren_count = lex->paren_count; 389258945Sroberto source->saved_line = source->line; 390258945Sroberto 391258945Sroberto if (isc_buffer_remaininglength(source->pushback) == 0 && 392258945Sroberto source->at_eof) 393258945Sroberto { 394258945Sroberto if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && 395258945Sroberto lex->paren_count != 0) { 396258945Sroberto lex->paren_count = 0; 397258945Sroberto return (ISC_R_UNBALANCED); 398258945Sroberto } 399258945Sroberto if ((options & ISC_LEXOPT_EOF) != 0) { 400258945Sroberto tokenp->type = isc_tokentype_eof; 401258945Sroberto return (ISC_R_SUCCESS); 402258945Sroberto } 403258945Sroberto return (ISC_R_EOF); 404258945Sroberto } 405258945Sroberto 406258945Sroberto isc_buffer_compact(source->pushback); 407258945Sroberto 408258945Sroberto saved_options = options; 409258945Sroberto if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0) 410258945Sroberto options &= ~IWSEOL; 411258945Sroberto 412258945Sroberto curr = lex->data; 413258945Sroberto *curr = '\0'; 414258945Sroberto 415258945Sroberto prev = NULL; 416258945Sroberto remaining = lex->max_token; 417258945Sroberto 418258945Sroberto#ifdef HAVE_FLOCKFILE 419258945Sroberto if (source->is_file) 420258945Sroberto flockfile(source->input); 421258945Sroberto#endif 422258945Sroberto 423258945Sroberto do { 424258945Sroberto if (isc_buffer_remaininglength(source->pushback) == 0) { 425258945Sroberto if (source->is_file) { 426258945Sroberto stream = source->input; 427258945Sroberto 428258945Sroberto#if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED) 429258945Sroberto c = getc_unlocked(stream); 430258945Sroberto#else 431258945Sroberto c = getc(stream); 432258945Sroberto#endif 433258945Sroberto if (c == EOF) { 434258945Sroberto if (ferror(stream)) { 435258945Sroberto source->result = ISC_R_IOERROR; 436258945Sroberto result = source->result; 437258945Sroberto goto done; 438258945Sroberto } 439258945Sroberto source->at_eof = ISC_TRUE; 440258945Sroberto } 441258945Sroberto } else { 442258945Sroberto buffer = source->input; 443258945Sroberto 444258945Sroberto if (buffer->current == buffer->used) { 445258945Sroberto c = EOF; 446258945Sroberto source->at_eof = ISC_TRUE; 447258945Sroberto } else { 448258945Sroberto c = *((char *)buffer->base + 449258945Sroberto buffer->current); 450258945Sroberto buffer->current++; 451258945Sroberto } 452258945Sroberto } 453258945Sroberto if (c != EOF) { 454258945Sroberto source->result = pushandgrow(lex, source, c); 455258945Sroberto if (source->result != ISC_R_SUCCESS) { 456258945Sroberto result = source->result; 457258945Sroberto goto done; 458258945Sroberto } 459258945Sroberto } 460258945Sroberto } 461258945Sroberto 462258945Sroberto if (!source->at_eof) { 463258945Sroberto if (state == lexstate_start) 464258945Sroberto /* Token has not started yet. */ 465258945Sroberto source->ignored = 466258945Sroberto isc_buffer_consumedlength(source->pushback); 467258945Sroberto c = isc_buffer_getuint8(source->pushback); 468258945Sroberto } else { 469258945Sroberto c = EOF; 470258945Sroberto } 471258945Sroberto 472258945Sroberto if (c == '\n') 473258945Sroberto source->line++; 474258945Sroberto 475258945Sroberto if (lex->comment_ok && !no_comments) { 476258945Sroberto if (!escaped && c == ';' && 477258945Sroberto ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE) 478258945Sroberto != 0)) { 479258945Sroberto saved_state = state; 480258945Sroberto state = lexstate_eatline; 481258945Sroberto no_comments = ISC_TRUE; 482258945Sroberto continue; 483258945Sroberto } else if (c == '/' && 484258945Sroberto (lex->comments & 485258945Sroberto (ISC_LEXCOMMENT_C| 486258945Sroberto ISC_LEXCOMMENT_CPLUSPLUS)) != 0) { 487258945Sroberto saved_state = state; 488258945Sroberto state = lexstate_maybecomment; 489258945Sroberto no_comments = ISC_TRUE; 490258945Sroberto continue; 491258945Sroberto } else if (c == '#' && 492258945Sroberto ((lex->comments & ISC_LEXCOMMENT_SHELL) 493258945Sroberto != 0)) { 494258945Sroberto saved_state = state; 495258945Sroberto state = lexstate_eatline; 496258945Sroberto no_comments = ISC_TRUE; 497258945Sroberto continue; 498258945Sroberto } 499258945Sroberto } 500258945Sroberto 501258945Sroberto no_read: 502258945Sroberto /* INSIST(c == EOF || (c >= 0 && c <= 255)); */ 503258945Sroberto switch (state) { 504258945Sroberto case lexstate_start: 505258945Sroberto if (c == EOF) { 506258945Sroberto lex->last_was_eol = ISC_FALSE; 507258945Sroberto if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && 508258945Sroberto lex->paren_count != 0) { 509258945Sroberto lex->paren_count = 0; 510258945Sroberto result = ISC_R_UNBALANCED; 511258945Sroberto goto done; 512258945Sroberto } 513258945Sroberto if ((options & ISC_LEXOPT_EOF) == 0) { 514258945Sroberto result = ISC_R_EOF; 515258945Sroberto goto done; 516258945Sroberto } 517258945Sroberto tokenp->type = isc_tokentype_eof; 518258945Sroberto done = ISC_TRUE; 519258945Sroberto } else if (c == ' ' || c == '\t') { 520258945Sroberto if (lex->last_was_eol && 521258945Sroberto (options & ISC_LEXOPT_INITIALWS) 522258945Sroberto != 0) { 523258945Sroberto lex->last_was_eol = ISC_FALSE; 524258945Sroberto tokenp->type = isc_tokentype_initialws; 525258945Sroberto tokenp->value.as_char = c; 526258945Sroberto done = ISC_TRUE; 527258945Sroberto } 528258945Sroberto } else if (c == '\n') { 529258945Sroberto if ((options & ISC_LEXOPT_EOL) != 0) { 530258945Sroberto tokenp->type = isc_tokentype_eol; 531258945Sroberto done = ISC_TRUE; 532258945Sroberto } 533258945Sroberto lex->last_was_eol = ISC_TRUE; 534258945Sroberto } else if (c == '\r') { 535258945Sroberto if ((options & ISC_LEXOPT_EOL) != 0) 536258945Sroberto state = lexstate_crlf; 537258945Sroberto } else if (c == '"' && 538258945Sroberto (options & ISC_LEXOPT_QSTRING) != 0) { 539258945Sroberto lex->last_was_eol = ISC_FALSE; 540258945Sroberto no_comments = ISC_TRUE; 541258945Sroberto state = lexstate_qstring; 542258945Sroberto } else if (lex->specials[c]) { 543258945Sroberto lex->last_was_eol = ISC_FALSE; 544258945Sroberto if ((c == '(' || c == ')') && 545258945Sroberto (options & ISC_LEXOPT_DNSMULTILINE) != 0) { 546258945Sroberto if (c == '(') { 547258945Sroberto if (lex->paren_count == 0) 548258945Sroberto options &= ~IWSEOL; 549258945Sroberto lex->paren_count++; 550258945Sroberto } else { 551258945Sroberto if (lex->paren_count == 0) { 552258945Sroberto result = ISC_R_UNBALANCED; 553258945Sroberto goto done; 554258945Sroberto } 555258945Sroberto lex->paren_count--; 556258945Sroberto if (lex->paren_count == 0) 557258945Sroberto options = 558258945Sroberto saved_options; 559258945Sroberto } 560258945Sroberto continue; 561258945Sroberto } 562258945Sroberto tokenp->type = isc_tokentype_special; 563258945Sroberto tokenp->value.as_char = c; 564258945Sroberto done = ISC_TRUE; 565258945Sroberto } else if (isdigit((unsigned char)c) && 566258945Sroberto (options & ISC_LEXOPT_NUMBER) != 0) { 567258945Sroberto lex->last_was_eol = ISC_FALSE; 568258945Sroberto if ((options & ISC_LEXOPT_OCTAL) != 0 && 569258945Sroberto (c == '8' || c == '9')) 570258945Sroberto state = lexstate_string; 571258945Sroberto else 572258945Sroberto state = lexstate_number; 573258945Sroberto goto no_read; 574258945Sroberto } else { 575258945Sroberto lex->last_was_eol = ISC_FALSE; 576258945Sroberto state = lexstate_string; 577258945Sroberto goto no_read; 578258945Sroberto } 579258945Sroberto break; 580258945Sroberto case lexstate_crlf: 581258945Sroberto if (c != '\n') 582258945Sroberto pushback(source, c); 583258945Sroberto tokenp->type = isc_tokentype_eol; 584258945Sroberto done = ISC_TRUE; 585258945Sroberto lex->last_was_eol = ISC_TRUE; 586258945Sroberto break; 587258945Sroberto case lexstate_number: 588258945Sroberto if (c == EOF || !isdigit((unsigned char)c)) { 589258945Sroberto if (c == ' ' || c == '\t' || c == '\r' || 590258945Sroberto c == '\n' || c == EOF || 591258945Sroberto lex->specials[c]) { 592258945Sroberto int base; 593258945Sroberto if ((options & ISC_LEXOPT_OCTAL) != 0) 594258945Sroberto base = 8; 595258945Sroberto else if ((options & ISC_LEXOPT_CNUMBER) != 0) 596258945Sroberto base = 0; 597258945Sroberto else 598258945Sroberto base = 10; 599258945Sroberto pushback(source, c); 600258945Sroberto 601258945Sroberto result = isc_parse_uint32(&as_ulong, 602258945Sroberto lex->data, 603258945Sroberto base); 604258945Sroberto if (result == ISC_R_SUCCESS) { 605258945Sroberto tokenp->type = 606258945Sroberto isc_tokentype_number; 607258945Sroberto tokenp->value.as_ulong = 608258945Sroberto as_ulong; 609258945Sroberto } else if (result == ISC_R_BADNUMBER) { 610258945Sroberto isc_tokenvalue_t *v; 611258945Sroberto 612258945Sroberto tokenp->type = 613258945Sroberto isc_tokentype_string; 614258945Sroberto v = &(tokenp->value); 615258945Sroberto v->as_textregion.base = 616258945Sroberto lex->data; 617258945Sroberto v->as_textregion.length = 618258945Sroberto lex->max_token - 619258945Sroberto remaining; 620258945Sroberto } else 621258945Sroberto goto done; 622258945Sroberto done = ISC_TRUE; 623258945Sroberto continue; 624258945Sroberto } else if (!(options & ISC_LEXOPT_CNUMBER) || 625258945Sroberto ((c != 'x' && c != 'X') || 626258945Sroberto (curr != &lex->data[1]) || 627258945Sroberto (lex->data[0] != '0'))) { 628258945Sroberto /* Above test supports hex numbers */ 629258945Sroberto state = lexstate_string; 630258945Sroberto } 631258945Sroberto } else if ((options & ISC_LEXOPT_OCTAL) != 0 && 632258945Sroberto (c == '8' || c == '9')) { 633258945Sroberto state = lexstate_string; 634258945Sroberto } 635258945Sroberto if (remaining == 0U) { 636258945Sroberto result = grow_data(lex, &remaining, 637258945Sroberto &curr, &prev); 638258945Sroberto if (result != ISC_R_SUCCESS) 639258945Sroberto goto done; 640258945Sroberto } 641258945Sroberto INSIST(remaining > 0U); 642258945Sroberto *curr++ = c; 643258945Sroberto *curr = '\0'; 644258945Sroberto remaining--; 645258945Sroberto break; 646258945Sroberto case lexstate_string: 647258945Sroberto /* 648258945Sroberto * EOF needs to be checked before lex->specials[c] 649258945Sroberto * as lex->specials[EOF] is not a good idea. 650258945Sroberto */ 651258945Sroberto if (c == '\r' || c == '\n' || c == EOF || 652258945Sroberto (!escaped && 653258945Sroberto (c == ' ' || c == '\t' || lex->specials[c]))) { 654258945Sroberto pushback(source, c); 655258945Sroberto if (source->result != ISC_R_SUCCESS) { 656258945Sroberto result = source->result; 657258945Sroberto goto done; 658258945Sroberto } 659258945Sroberto tokenp->type = isc_tokentype_string; 660258945Sroberto tokenp->value.as_textregion.base = lex->data; 661258945Sroberto tokenp->value.as_textregion.length = 662258945Sroberto lex->max_token - remaining; 663258945Sroberto done = ISC_TRUE; 664258945Sroberto continue; 665258945Sroberto } 666258945Sroberto if ((options & ISC_LEXOPT_ESCAPE) != 0) 667258945Sroberto escaped = (!escaped && c == '\\') ? 668258945Sroberto ISC_TRUE : ISC_FALSE; 669258945Sroberto if (remaining == 0U) { 670258945Sroberto result = grow_data(lex, &remaining, 671258945Sroberto &curr, &prev); 672258945Sroberto if (result != ISC_R_SUCCESS) 673258945Sroberto goto done; 674258945Sroberto } 675258945Sroberto INSIST(remaining > 0U); 676258945Sroberto *curr++ = c; 677258945Sroberto *curr = '\0'; 678258945Sroberto remaining--; 679258945Sroberto break; 680258945Sroberto case lexstate_maybecomment: 681258945Sroberto if (c == '*' && 682258945Sroberto (lex->comments & ISC_LEXCOMMENT_C) != 0) { 683258945Sroberto state = lexstate_ccomment; 684258945Sroberto continue; 685258945Sroberto } else if (c == '/' && 686258945Sroberto (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) { 687258945Sroberto state = lexstate_eatline; 688258945Sroberto continue; 689258945Sroberto } 690258945Sroberto pushback(source, c); 691258945Sroberto c = '/'; 692258945Sroberto no_comments = ISC_FALSE; 693258945Sroberto state = saved_state; 694258945Sroberto goto no_read; 695258945Sroberto case lexstate_ccomment: 696258945Sroberto if (c == EOF) { 697258945Sroberto result = ISC_R_UNEXPECTEDEND; 698258945Sroberto goto done; 699258945Sroberto } 700258945Sroberto if (c == '*') 701258945Sroberto state = lexstate_ccommentend; 702258945Sroberto break; 703258945Sroberto case lexstate_ccommentend: 704258945Sroberto if (c == EOF) { 705258945Sroberto result = ISC_R_UNEXPECTEDEND; 706258945Sroberto goto done; 707258945Sroberto } 708258945Sroberto if (c == '/') { 709258945Sroberto /* 710258945Sroberto * C-style comments become a single space. 711258945Sroberto * We do this to ensure that a comment will 712258945Sroberto * act as a delimiter for strings and 713258945Sroberto * numbers. 714258945Sroberto */ 715258945Sroberto c = ' '; 716258945Sroberto no_comments = ISC_FALSE; 717258945Sroberto state = saved_state; 718258945Sroberto goto no_read; 719258945Sroberto } else if (c != '*') 720258945Sroberto state = lexstate_ccomment; 721258945Sroberto break; 722258945Sroberto case lexstate_eatline: 723258945Sroberto if ((c == '\n') || (c == EOF)) { 724258945Sroberto no_comments = ISC_FALSE; 725258945Sroberto state = saved_state; 726258945Sroberto goto no_read; 727258945Sroberto } 728258945Sroberto break; 729258945Sroberto case lexstate_qstring: 730258945Sroberto if (c == EOF) { 731258945Sroberto result = ISC_R_UNEXPECTEDEND; 732258945Sroberto goto done; 733258945Sroberto } 734258945Sroberto if (c == '"') { 735258945Sroberto if (escaped) { 736258945Sroberto escaped = ISC_FALSE; 737258945Sroberto /* 738258945Sroberto * Overwrite the preceding backslash. 739258945Sroberto */ 740258945Sroberto INSIST(prev != NULL); 741258945Sroberto *prev = '"'; 742258945Sroberto } else { 743258945Sroberto tokenp->type = isc_tokentype_qstring; 744258945Sroberto tokenp->value.as_textregion.base = 745258945Sroberto lex->data; 746258945Sroberto tokenp->value.as_textregion.length = 747258945Sroberto lex->max_token - remaining; 748258945Sroberto no_comments = ISC_FALSE; 749258945Sroberto done = ISC_TRUE; 750258945Sroberto } 751258945Sroberto } else { 752258945Sroberto if (c == '\n' && !escaped && 753258945Sroberto (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) { 754258945Sroberto pushback(source, c); 755258945Sroberto result = ISC_R_UNBALANCEDQUOTES; 756258945Sroberto goto done; 757258945Sroberto } 758258945Sroberto if (c == '\\' && !escaped) 759258945Sroberto escaped = ISC_TRUE; 760258945Sroberto else 761258945Sroberto escaped = ISC_FALSE; 762258945Sroberto if (remaining == 0U) { 763258945Sroberto result = grow_data(lex, &remaining, 764258945Sroberto &curr, &prev); 765258945Sroberto if (result != ISC_R_SUCCESS) 766258945Sroberto goto done; 767258945Sroberto } 768258945Sroberto INSIST(remaining > 0U); 769258945Sroberto prev = curr; 770258945Sroberto *curr++ = c; 771258945Sroberto *curr = '\0'; 772258945Sroberto remaining--; 773258945Sroberto } 774258945Sroberto break; 775258945Sroberto default: 776258945Sroberto FATAL_ERROR(__FILE__, __LINE__, 777258945Sroberto isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX, 778258945Sroberto ISC_MSG_UNEXPECTEDSTATE, 779258945Sroberto "Unexpected state %d"), 780258945Sroberto state); 781258945Sroberto /* Does not return. */ 782258945Sroberto } 783258945Sroberto 784258945Sroberto } while (!done); 785258945Sroberto 786258945Sroberto result = ISC_R_SUCCESS; 787258945Sroberto done: 788258945Sroberto#ifdef HAVE_FLOCKFILE 789258945Sroberto if (source->is_file) 790258945Sroberto funlockfile(source->input); 791258945Sroberto#endif 792258945Sroberto return (result); 793258945Sroberto} 794258945Sroberto 795258945Srobertoisc_result_t 796258945Srobertoisc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token, 797258945Sroberto isc_tokentype_t expect, isc_boolean_t eol) 798258945Sroberto{ 799258945Sroberto unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | 800258945Sroberto ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE; 801258945Sroberto isc_result_t result; 802258945Sroberto 803258945Sroberto if (expect == isc_tokentype_qstring) 804258945Sroberto options |= ISC_LEXOPT_QSTRING; 805258945Sroberto else if (expect == isc_tokentype_number) 806258945Sroberto options |= ISC_LEXOPT_NUMBER; 807258945Sroberto result = isc_lex_gettoken(lex, options, token); 808258945Sroberto if (result == ISC_R_RANGE) 809258945Sroberto isc_lex_ungettoken(lex, token); 810258945Sroberto if (result != ISC_R_SUCCESS) 811258945Sroberto return (result); 812258945Sroberto 813258945Sroberto if (eol && ((token->type == isc_tokentype_eol) || 814258945Sroberto (token->type == isc_tokentype_eof))) 815258945Sroberto return (ISC_R_SUCCESS); 816258945Sroberto if (token->type == isc_tokentype_string && 817258945Sroberto expect == isc_tokentype_qstring) 818258945Sroberto return (ISC_R_SUCCESS); 819258945Sroberto if (token->type != expect) { 820258945Sroberto isc_lex_ungettoken(lex, token); 821258945Sroberto if (token->type == isc_tokentype_eol || 822258945Sroberto token->type == isc_tokentype_eof) 823258945Sroberto return (ISC_R_UNEXPECTEDEND); 824258945Sroberto if (expect == isc_tokentype_number) 825258945Sroberto return (ISC_R_BADNUMBER); 826258945Sroberto return (ISC_R_UNEXPECTEDTOKEN); 827258945Sroberto } 828258945Sroberto return (ISC_R_SUCCESS); 829258945Sroberto} 830258945Sroberto 831258945Srobertoisc_result_t 832258945Srobertoisc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol) 833258945Sroberto{ 834258945Sroberto unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | 835258945Sroberto ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE| 836258945Sroberto ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL; 837258945Sroberto isc_result_t result; 838258945Sroberto 839258945Sroberto result = isc_lex_gettoken(lex, options, token); 840258945Sroberto if (result == ISC_R_RANGE) 841258945Sroberto isc_lex_ungettoken(lex, token); 842258945Sroberto if (result != ISC_R_SUCCESS) 843258945Sroberto return (result); 844258945Sroberto 845258945Sroberto if (eol && ((token->type == isc_tokentype_eol) || 846258945Sroberto (token->type == isc_tokentype_eof))) 847258945Sroberto return (ISC_R_SUCCESS); 848258945Sroberto if (token->type != isc_tokentype_number) { 849258945Sroberto isc_lex_ungettoken(lex, token); 850258945Sroberto if (token->type == isc_tokentype_eol || 851258945Sroberto token->type == isc_tokentype_eof) 852258945Sroberto return (ISC_R_UNEXPECTEDEND); 853258945Sroberto return (ISC_R_BADNUMBER); 854258945Sroberto } 855258945Sroberto return (ISC_R_SUCCESS); 856258945Sroberto} 857258945Sroberto 858258945Srobertovoid 859258945Srobertoisc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) { 860258945Sroberto inputsource *source; 861258945Sroberto /* 862258945Sroberto * Unget the current token. 863258945Sroberto */ 864258945Sroberto 865258945Sroberto REQUIRE(VALID_LEX(lex)); 866258945Sroberto source = HEAD(lex->sources); 867258945Sroberto REQUIRE(source != NULL); 868258945Sroberto REQUIRE(tokenp != NULL); 869258945Sroberto REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 || 870258945Sroberto tokenp->type == isc_tokentype_eof); 871258945Sroberto 872258945Sroberto UNUSED(tokenp); 873258945Sroberto 874258945Sroberto isc_buffer_first(source->pushback); 875258945Sroberto lex->paren_count = lex->saved_paren_count; 876258945Sroberto source->line = source->saved_line; 877258945Sroberto source->at_eof = ISC_FALSE; 878258945Sroberto} 879258945Sroberto 880258945Srobertovoid 881258945Srobertoisc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r) 882258945Sroberto{ 883258945Sroberto inputsource *source; 884258945Sroberto 885258945Sroberto REQUIRE(VALID_LEX(lex)); 886258945Sroberto source = HEAD(lex->sources); 887258945Sroberto REQUIRE(source != NULL); 888258945Sroberto REQUIRE(tokenp != NULL); 889258945Sroberto REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 || 890258945Sroberto tokenp->type == isc_tokentype_eof); 891258945Sroberto 892258945Sroberto UNUSED(tokenp); 893258945Sroberto 894258945Sroberto INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback)); 895258945Sroberto r->base = (unsigned char *)isc_buffer_base(source->pushback) + 896258945Sroberto source->ignored; 897258945Sroberto r->length = isc_buffer_consumedlength(source->pushback) - 898258945Sroberto source->ignored; 899258945Sroberto} 900258945Sroberto 901258945Sroberto 902258945Srobertochar * 903258945Srobertoisc_lex_getsourcename(isc_lex_t *lex) { 904258945Sroberto inputsource *source; 905258945Sroberto 906258945Sroberto REQUIRE(VALID_LEX(lex)); 907258945Sroberto source = HEAD(lex->sources); 908258945Sroberto 909258945Sroberto if (source == NULL) 910258945Sroberto return (NULL); 911258945Sroberto 912258945Sroberto return (source->name); 913258945Sroberto} 914258945Sroberto 915258945Srobertounsigned long 916258945Srobertoisc_lex_getsourceline(isc_lex_t *lex) { 917258945Sroberto inputsource *source; 918258945Sroberto 919258945Sroberto REQUIRE(VALID_LEX(lex)); 920258945Sroberto source = HEAD(lex->sources); 921258945Sroberto 922258945Sroberto if (source == NULL) 923258945Sroberto return (0); 924258945Sroberto 925258945Sroberto return (source->line); 926258945Sroberto} 927258945Sroberto 928258945Sroberto 929258945Srobertoisc_result_t 930258945Srobertoisc_lex_setsourcename(isc_lex_t *lex, const char *name) { 931258945Sroberto inputsource *source; 932258945Sroberto char *newname; 933258945Sroberto 934258945Sroberto REQUIRE(VALID_LEX(lex)); 935258945Sroberto source = HEAD(lex->sources); 936258945Sroberto 937258945Sroberto if (source == NULL) 938258945Sroberto return(ISC_R_NOTFOUND); 939258945Sroberto newname = isc_mem_strdup(lex->mctx, name); 940258945Sroberto if (newname == NULL) 941258945Sroberto return (ISC_R_NOMEMORY); 942258945Sroberto isc_mem_free(lex->mctx, source->name); 943258945Sroberto source->name = newname; 944258945Sroberto return (ISC_R_SUCCESS); 945258945Sroberto} 946258945Sroberto 947258945Srobertoisc_boolean_t 948258945Srobertoisc_lex_isfile(isc_lex_t *lex) { 949258945Sroberto inputsource *source; 950258945Sroberto 951258945Sroberto REQUIRE(VALID_LEX(lex)); 952258945Sroberto 953258945Sroberto source = HEAD(lex->sources); 954258945Sroberto 955258945Sroberto if (source == NULL) 956258945Sroberto return (ISC_FALSE); 957258945Sroberto 958258945Sroberto return (source->is_file); 959258945Sroberto} 960