/contrib/bind9/lib/isc/lex.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 959 lines · 820 code · 81 blank · 58 comment · 122 complexity · 366f42a2570ee17fc44dce58eb54e462 MD5 · raw file

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