PageRenderTime 39ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/ncurses/ncurses/tinfo/comp_scan.c

https://github.com/okuoku/freebsd-head
C | 948 lines | 632 code | 106 blank | 210 comment | 265 complexity | d65ecc2fdce3a74be76f1481a900b660 MD5 | raw file
  1. /****************************************************************************
  2. * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc. *
  3. * *
  4. * Permission is hereby granted, free of charge, to any person obtaining a *
  5. * copy of this software and associated documentation files (the *
  6. * "Software"), to deal in the Software without restriction, including *
  7. * without limitation the rights to use, copy, modify, merge, publish, *
  8. * distribute, distribute with modifications, sublicense, and/or sell *
  9. * copies of the Software, and to permit persons to whom the Software is *
  10. * furnished to do so, subject to the following conditions: *
  11. * *
  12. * The above copyright notice and this permission notice shall be included *
  13. * in all copies or substantial portions of the Software. *
  14. * *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
  16. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
  18. * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
  19. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
  20. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
  21. * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
  22. * *
  23. * Except as contained in this notice, the name(s) of the above copyright *
  24. * holders shall not be used in advertising or otherwise to promote the *
  25. * sale, use or other dealings in this Software without prior written *
  26. * authorization. *
  27. ****************************************************************************/
  28. /****************************************************************************
  29. * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
  30. * and: Eric S. Raymond <esr@snark.thyrsus.com> *
  31. * and: Thomas E. Dickey 1996 on *
  32. ****************************************************************************/
  33. /* $FreeBSD$ */
  34. /*
  35. * comp_scan.c --- Lexical scanner for terminfo compiler.
  36. *
  37. * _nc_reset_input()
  38. * _nc_get_token()
  39. * _nc_panic_mode()
  40. * int _nc_syntax;
  41. * int _nc_curr_line;
  42. * long _nc_curr_file_pos;
  43. * long _nc_comment_start;
  44. * long _nc_comment_end;
  45. */
  46. #include <curses.priv.h>
  47. #include <ctype.h>
  48. #include <term_entry.h>
  49. #include <tic.h>
  50. MODULE_ID("$Id: comp_scan.c,v 1.83 2008/08/16 19:22:55 tom Exp $")
  51. /*
  52. * Maximum length of string capability we'll accept before raising an error.
  53. * Yes, there is a real capability in /etc/termcap this long, an "is".
  54. */
  55. #define MAXCAPLEN 600
  56. #define iswhite(ch) (ch == ' ' || ch == '\t')
  57. NCURSES_EXPORT_VAR(int)
  58. _nc_syntax = 0; /* termcap or terminfo? */
  59. NCURSES_EXPORT_VAR(long)
  60. _nc_curr_file_pos = 0; /* file offset of current line */
  61. NCURSES_EXPORT_VAR(long)
  62. _nc_comment_start = 0; /* start of comment range before name */
  63. NCURSES_EXPORT_VAR(long)
  64. _nc_comment_end = 0; /* end of comment range before name */
  65. NCURSES_EXPORT_VAR(long)
  66. _nc_start_line = 0; /* start line of current entry */
  67. NCURSES_EXPORT_VAR(struct token)
  68. _nc_curr_token =
  69. {
  70. 0, 0, 0
  71. };
  72. /*****************************************************************************
  73. *
  74. * Token-grabbing machinery
  75. *
  76. *****************************************************************************/
  77. static bool first_column; /* See 'next_char()' below */
  78. static bool had_newline;
  79. static char separator; /* capability separator */
  80. static int pushtype; /* type of pushback token */
  81. static char *pushname;
  82. #if NCURSES_EXT_FUNCS
  83. NCURSES_EXPORT_VAR(bool)
  84. _nc_disable_period = FALSE; /* used by tic -a option */
  85. #endif
  86. /*****************************************************************************
  87. *
  88. * Character-stream handling
  89. *
  90. *****************************************************************************/
  91. #define LEXBUFSIZ 1024
  92. static char *bufptr; /* otherwise, the input buffer pointer */
  93. static char *bufstart; /* start of buffer so we can compute offsets */
  94. static FILE *yyin; /* scanner's input file descriptor */
  95. /*
  96. * _nc_reset_input()
  97. *
  98. * Resets the input-reading routines. Used on initialization,
  99. * or after a seek has been done. Exactly one argument must be
  100. * non-null.
  101. */
  102. NCURSES_EXPORT(void)
  103. _nc_reset_input(FILE *fp, char *buf)
  104. {
  105. pushtype = NO_PUSHBACK;
  106. if (pushname != 0)
  107. pushname[0] = '\0';
  108. yyin = fp;
  109. bufstart = bufptr = buf;
  110. _nc_curr_file_pos = 0L;
  111. if (fp != 0)
  112. _nc_curr_line = 0;
  113. _nc_curr_col = 0;
  114. }
  115. /*
  116. * int last_char()
  117. *
  118. * Returns the final nonblank character on the current input buffer
  119. */
  120. static int
  121. last_char(void)
  122. {
  123. size_t len = strlen(bufptr);
  124. while (len--) {
  125. if (!isspace(UChar(bufptr[len])))
  126. return bufptr[len];
  127. }
  128. return 0;
  129. }
  130. /*
  131. * int next_char()
  132. *
  133. * Returns the next character in the input stream. Comments and leading
  134. * white space are stripped.
  135. *
  136. * The global state variable 'firstcolumn' is set TRUE if the character
  137. * returned is from the first column of the input line.
  138. *
  139. * The global variable _nc_curr_line is incremented for each new line.
  140. * The global variable _nc_curr_file_pos is set to the file offset of the
  141. * beginning of each line.
  142. */
  143. static int
  144. next_char(void)
  145. {
  146. static char *result;
  147. static size_t allocated;
  148. int the_char;
  149. if (!yyin) {
  150. if (result != 0) {
  151. FreeAndNull(result);
  152. FreeAndNull(pushname);
  153. allocated = 0;
  154. }
  155. /*
  156. * An string with an embedded null will truncate the input. This is
  157. * intentional (we don't read binary files here).
  158. */
  159. if (bufptr == 0 || *bufptr == '\0')
  160. return (EOF);
  161. if (*bufptr == '\n') {
  162. _nc_curr_line++;
  163. _nc_curr_col = 0;
  164. } else if (*bufptr == '\t') {
  165. _nc_curr_col = (_nc_curr_col | 7);
  166. }
  167. } else if (!bufptr || !*bufptr) {
  168. /*
  169. * In theory this could be recoded to do its I/O one character at a
  170. * time, saving the buffer space. In practice, this turns out to be
  171. * quite hard to get completely right. Try it and see. If you
  172. * succeed, don't forget to hack push_back() correspondingly.
  173. */
  174. size_t used;
  175. size_t len;
  176. do {
  177. bufstart = 0;
  178. used = 0;
  179. do {
  180. if (used + (LEXBUFSIZ / 4) >= allocated) {
  181. allocated += (allocated + LEXBUFSIZ);
  182. result = typeRealloc(char, allocated, result);
  183. if (result == 0)
  184. return (EOF);
  185. bufstart = result;
  186. }
  187. if (used == 0)
  188. _nc_curr_file_pos = ftell(yyin);
  189. if (fgets(result + used, (int) (allocated - used), yyin) != 0) {
  190. bufstart = result;
  191. if (used == 0) {
  192. _nc_curr_line++;
  193. _nc_curr_col = 0;
  194. }
  195. } else {
  196. if (used != 0)
  197. strcat(result, "\n");
  198. }
  199. if ((bufptr = bufstart) != 0) {
  200. used = strlen(bufptr);
  201. while (iswhite(*bufptr)) {
  202. if (*bufptr == '\t') {
  203. _nc_curr_col = (_nc_curr_col | 7) + 1;
  204. } else {
  205. _nc_curr_col++;
  206. }
  207. bufptr++;
  208. }
  209. /*
  210. * Treat a trailing <cr><lf> the same as a <newline> so we
  211. * can read files on OS/2, etc.
  212. */
  213. if ((len = strlen(bufptr)) > 1) {
  214. if (bufptr[len - 1] == '\n'
  215. && bufptr[len - 2] == '\r') {
  216. len--;
  217. bufptr[len - 1] = '\n';
  218. bufptr[len] = '\0';
  219. }
  220. }
  221. } else {
  222. return (EOF);
  223. }
  224. } while (bufptr[len - 1] != '\n'); /* complete a line */
  225. } while (result[0] == '#'); /* ignore comments */
  226. } else if (*bufptr == '\t') {
  227. _nc_curr_col = (_nc_curr_col | 7);
  228. }
  229. first_column = (bufptr == bufstart);
  230. if (first_column)
  231. had_newline = FALSE;
  232. _nc_curr_col++;
  233. the_char = *bufptr++;
  234. return UChar(the_char);
  235. }
  236. static void
  237. push_back(char c)
  238. /* push a character back onto the input stream */
  239. {
  240. if (bufptr == bufstart)
  241. _nc_syserr_abort("Can't backspace off beginning of line");
  242. *--bufptr = c;
  243. _nc_curr_col--;
  244. }
  245. static long
  246. stream_pos(void)
  247. /* return our current character position in the input stream */
  248. {
  249. return (yyin ? ftell(yyin) : (bufptr ? bufptr - bufstart : 0));
  250. }
  251. static bool
  252. end_of_stream(void)
  253. /* are we at end of input? */
  254. {
  255. return ((yyin ? feof(yyin) : (bufptr && *bufptr == '\0'))
  256. ? TRUE : FALSE);
  257. }
  258. /* Assume we may be looking at a termcap-style continuation */
  259. static NCURSES_INLINE int
  260. eat_escaped_newline(int ch)
  261. {
  262. if (ch == '\\')
  263. while ((ch = next_char()) == '\n' || iswhite(ch))
  264. continue;
  265. return ch;
  266. }
  267. #define TOK_BUF_SIZE MAX_ENTRY_SIZE
  268. #define OkToAdd() \
  269. ((tok_ptr - tok_buf) < (TOK_BUF_SIZE - 2))
  270. #define AddCh(ch) \
  271. *tok_ptr++ = (char) ch; \
  272. *tok_ptr = '\0'
  273. /*
  274. * int
  275. * get_token()
  276. *
  277. * Scans the input for the next token, storing the specifics in the
  278. * global structure 'curr_token' and returning one of the following:
  279. *
  280. * NAMES A line beginning in column 1. 'name'
  281. * will be set to point to everything up to but
  282. * not including the first separator on the line.
  283. * BOOLEAN An entry consisting of a name followed by
  284. * a separator. 'name' will be set to point to
  285. * the name of the capability.
  286. * NUMBER An entry of the form
  287. * name#digits,
  288. * 'name' will be set to point to the capability
  289. * name and 'valnumber' to the number given.
  290. * STRING An entry of the form
  291. * name=characters,
  292. * 'name' is set to the capability name and
  293. * 'valstring' to the string of characters, with
  294. * input translations done.
  295. * CANCEL An entry of the form
  296. * name@,
  297. * 'name' is set to the capability name and
  298. * 'valnumber' to -1.
  299. * EOF The end of the file has been reached.
  300. *
  301. * A `separator' is either a comma or a semicolon, depending on whether
  302. * we are in termcap or terminfo mode.
  303. *
  304. */
  305. NCURSES_EXPORT(int)
  306. _nc_get_token(bool silent)
  307. {
  308. static const char terminfo_punct[] = "@%&*!#";
  309. static char *tok_buf;
  310. char *after_list;
  311. char *after_name;
  312. char *numchk;
  313. char *tok_ptr;
  314. char *s;
  315. char numbuf[80];
  316. int ch;
  317. int dot_flag = FALSE;
  318. int type;
  319. long number;
  320. long token_start;
  321. unsigned found;
  322. #ifdef TRACE
  323. int old_line;
  324. int old_col;
  325. #endif
  326. if (pushtype != NO_PUSHBACK) {
  327. int retval = pushtype;
  328. _nc_set_type(pushname != 0 ? pushname : "");
  329. DEBUG(3, ("pushed-back token: `%s', class %d",
  330. _nc_curr_token.tk_name, pushtype));
  331. pushtype = NO_PUSHBACK;
  332. if (pushname != 0)
  333. pushname[0] = '\0';
  334. /* currtok wasn't altered by _nc_push_token() */
  335. return (retval);
  336. }
  337. if (end_of_stream()) {
  338. yyin = 0;
  339. next_char(); /* frees its allocated memory */
  340. if (tok_buf != 0) {
  341. if (_nc_curr_token.tk_name == tok_buf)
  342. _nc_curr_token.tk_name = 0;
  343. FreeAndNull(tok_buf);
  344. }
  345. return (EOF);
  346. }
  347. start_token:
  348. token_start = stream_pos();
  349. while ((ch = next_char()) == '\n' || iswhite(ch)) {
  350. if (ch == '\n')
  351. had_newline = TRUE;
  352. continue;
  353. }
  354. ch = eat_escaped_newline(ch);
  355. #ifdef TRACE
  356. old_line = _nc_curr_line;
  357. old_col = _nc_curr_col;
  358. #endif
  359. if (ch == EOF)
  360. type = EOF;
  361. else {
  362. /* if this is a termcap entry, skip a leading separator */
  363. if (separator == ':' && ch == ':')
  364. ch = next_char();
  365. if (ch == '.'
  366. #if NCURSES_EXT_FUNCS
  367. && !_nc_disable_period
  368. #endif
  369. ) {
  370. dot_flag = TRUE;
  371. DEBUG(8, ("dot-flag set"));
  372. while ((ch = next_char()) == '.' || iswhite(ch))
  373. continue;
  374. }
  375. if (ch == EOF) {
  376. type = EOF;
  377. goto end_of_token;
  378. }
  379. /* have to make some punctuation chars legal for terminfo */
  380. if (!isalnum(UChar(ch))
  381. #if NCURSES_EXT_FUNCS
  382. && !(ch == '.' && _nc_disable_period)
  383. #endif
  384. && !strchr(terminfo_punct, (char) ch)) {
  385. if (!silent)
  386. _nc_warning("Illegal character (expected alphanumeric or %s) - '%s'",
  387. terminfo_punct, unctrl((chtype) ch));
  388. _nc_panic_mode(separator);
  389. goto start_token;
  390. }
  391. if (tok_buf == 0)
  392. tok_buf = typeMalloc(char, TOK_BUF_SIZE);
  393. #ifdef TRACE
  394. old_line = _nc_curr_line;
  395. old_col = _nc_curr_col;
  396. #endif
  397. tok_ptr = tok_buf;
  398. AddCh(ch);
  399. if (first_column) {
  400. _nc_comment_start = token_start;
  401. _nc_comment_end = _nc_curr_file_pos;
  402. _nc_start_line = _nc_curr_line;
  403. _nc_syntax = ERR;
  404. after_name = 0;
  405. after_list = 0;
  406. while ((ch = next_char()) != '\n') {
  407. if (ch == EOF) {
  408. _nc_err_abort(MSG_NO_INPUTS);
  409. } else if (ch == '|') {
  410. after_list = tok_ptr;
  411. if (after_name == 0)
  412. after_name = tok_ptr;
  413. } else if (ch == ':' && last_char() != ',') {
  414. _nc_syntax = SYN_TERMCAP;
  415. separator = ':';
  416. break;
  417. } else if (ch == ',') {
  418. _nc_syntax = SYN_TERMINFO;
  419. separator = ',';
  420. /*
  421. * If we did not see a '|', then we found a name with no
  422. * aliases or description.
  423. */
  424. if (after_name == 0)
  425. break;
  426. /*
  427. * If we see a comma, we assume this is terminfo unless we
  428. * subsequently run into a colon. But we don't stop
  429. * looking for a colon until hitting a newline. This
  430. * allows commas to be embedded in description fields of
  431. * either syntax.
  432. */
  433. } else
  434. ch = eat_escaped_newline(ch);
  435. if (OkToAdd()) {
  436. AddCh(ch);
  437. } else {
  438. ch = EOF;
  439. break;
  440. }
  441. }
  442. *tok_ptr = '\0';
  443. if (_nc_syntax == ERR) {
  444. /*
  445. * Grrr...what we ought to do here is barf, complaining that
  446. * the entry is malformed. But because a couple of name fields
  447. * in the 8.2 termcap file end with |\, we just have to assume
  448. * it's termcap syntax.
  449. */
  450. _nc_syntax = SYN_TERMCAP;
  451. separator = ':';
  452. } else if (_nc_syntax == SYN_TERMINFO) {
  453. /* throw away trailing /, *$/ */
  454. for (--tok_ptr;
  455. iswhite(*tok_ptr) || *tok_ptr == ',';
  456. tok_ptr--)
  457. continue;
  458. tok_ptr[1] = '\0';
  459. }
  460. /*
  461. * This is the soonest we have the terminal name fetched. Set up
  462. * for following warning messages. If there's no '|', then there
  463. * is no description.
  464. */
  465. if (after_name != 0) {
  466. ch = *after_name;
  467. *after_name = '\0';
  468. _nc_set_type(tok_buf);
  469. *after_name = (char) ch;
  470. }
  471. /*
  472. * Compute the boundary between the aliases and the description
  473. * field for syntax-checking purposes.
  474. */
  475. if (after_list != 0) {
  476. if (!silent) {
  477. if (*after_list == '\0')
  478. _nc_warning("empty longname field");
  479. #ifndef FREEBSD_NATIVE
  480. else if (strchr(after_list, ' ') == 0)
  481. _nc_warning("older tic versions may treat the description field as an alias");
  482. #endif
  483. }
  484. } else {
  485. after_list = tok_buf + strlen(tok_buf);
  486. DEBUG(1, ("missing description"));
  487. }
  488. /*
  489. * Whitespace in a name field other than the long name can confuse
  490. * rdist and some termcap tools. Slashes are a no-no. Other
  491. * special characters can be dangerous due to shell expansion.
  492. */
  493. for (s = tok_buf; s < after_list; ++s) {
  494. if (isspace(UChar(*s))) {
  495. if (!silent)
  496. _nc_warning("whitespace in name or alias field");
  497. break;
  498. } else if (*s == '/') {
  499. if (!silent)
  500. _nc_warning("slashes aren't allowed in names or aliases");
  501. break;
  502. } else if (strchr("$[]!*?", *s)) {
  503. if (!silent)
  504. _nc_warning("dubious character `%c' in name or alias field", *s);
  505. break;
  506. }
  507. }
  508. _nc_curr_token.tk_name = tok_buf;
  509. type = NAMES;
  510. } else {
  511. if (had_newline && _nc_syntax == SYN_TERMCAP) {
  512. _nc_warning("Missing backslash before newline");
  513. had_newline = FALSE;
  514. }
  515. while ((ch = next_char()) != EOF) {
  516. if (!isalnum(UChar(ch))) {
  517. if (_nc_syntax == SYN_TERMINFO) {
  518. if (ch != '_')
  519. break;
  520. } else { /* allow ';' for "k;" */
  521. if (ch != ';')
  522. break;
  523. }
  524. }
  525. if (OkToAdd()) {
  526. AddCh(ch);
  527. } else {
  528. ch = EOF;
  529. break;
  530. }
  531. }
  532. *tok_ptr++ = '\0'; /* separate name/value in buffer */
  533. switch (ch) {
  534. case ',':
  535. case ':':
  536. if (ch != separator)
  537. _nc_err_abort("Separator inconsistent with syntax");
  538. _nc_curr_token.tk_name = tok_buf;
  539. type = BOOLEAN;
  540. break;
  541. case '@':
  542. if ((ch = next_char()) != separator && !silent)
  543. _nc_warning("Missing separator after `%s', have %s",
  544. tok_buf, unctrl((chtype) ch));
  545. _nc_curr_token.tk_name = tok_buf;
  546. type = CANCEL;
  547. break;
  548. case '#':
  549. found = 0;
  550. while (isalnum(ch = next_char())) {
  551. numbuf[found++] = (char) ch;
  552. if (found >= sizeof(numbuf) - 1)
  553. break;
  554. }
  555. numbuf[found] = '\0';
  556. number = strtol(numbuf, &numchk, 0);
  557. if (!silent) {
  558. if (numchk == numbuf)
  559. _nc_warning("no value given for `%s'", tok_buf);
  560. if ((*numchk != '\0') || (ch != separator))
  561. _nc_warning("Missing separator");
  562. }
  563. _nc_curr_token.tk_name = tok_buf;
  564. _nc_curr_token.tk_valnumber = number;
  565. type = NUMBER;
  566. break;
  567. case '=':
  568. ch = _nc_trans_string(tok_ptr, tok_buf + TOK_BUF_SIZE);
  569. if (!silent && ch != separator)
  570. _nc_warning("Missing separator");
  571. _nc_curr_token.tk_name = tok_buf;
  572. _nc_curr_token.tk_valstring = tok_ptr;
  573. type = STRING;
  574. break;
  575. case EOF:
  576. type = EOF;
  577. break;
  578. default:
  579. /* just to get rid of the compiler warning */
  580. type = UNDEF;
  581. if (!silent)
  582. _nc_warning("Illegal character - '%s'", unctrl((chtype) ch));
  583. }
  584. } /* end else (first_column == FALSE) */
  585. } /* end else (ch != EOF) */
  586. end_of_token:
  587. #ifdef TRACE
  588. if (dot_flag == TRUE)
  589. DEBUG(8, ("Commented out "));
  590. if (_nc_tracing >= DEBUG_LEVEL(8)) {
  591. _tracef("parsed %d.%d to %d.%d",
  592. old_line, old_col,
  593. _nc_curr_line, _nc_curr_col);
  594. }
  595. if (_nc_tracing >= DEBUG_LEVEL(7)) {
  596. switch (type) {
  597. case BOOLEAN:
  598. _tracef("Token: Boolean; name='%s'",
  599. _nc_curr_token.tk_name);
  600. break;
  601. case NUMBER:
  602. _tracef("Token: Number; name='%s', value=%d",
  603. _nc_curr_token.tk_name,
  604. _nc_curr_token.tk_valnumber);
  605. break;
  606. case STRING:
  607. _tracef("Token: String; name='%s', value=%s",
  608. _nc_curr_token.tk_name,
  609. _nc_visbuf(_nc_curr_token.tk_valstring));
  610. break;
  611. case CANCEL:
  612. _tracef("Token: Cancel; name='%s'",
  613. _nc_curr_token.tk_name);
  614. break;
  615. case NAMES:
  616. _tracef("Token: Names; value='%s'",
  617. _nc_curr_token.tk_name);
  618. break;
  619. case EOF:
  620. _tracef("Token: End of file");
  621. break;
  622. default:
  623. _nc_warning("Bad token type");
  624. }
  625. }
  626. #endif
  627. if (dot_flag == TRUE) /* if commented out, use the next one */
  628. type = _nc_get_token(silent);
  629. DEBUG(3, ("token: `%s', class %d",
  630. ((_nc_curr_token.tk_name != 0)
  631. ? _nc_curr_token.tk_name
  632. : "<null>"),
  633. type));
  634. return (type);
  635. }
  636. /*
  637. * char
  638. * trans_string(ptr)
  639. *
  640. * Reads characters using next_char() until encountering a separator, nl,
  641. * or end-of-file. The returned value is the character which caused
  642. * reading to stop. The following translations are done on the input:
  643. *
  644. * ^X goes to ctrl-X (i.e. X & 037)
  645. * {\E,\n,\r,\b,\t,\f} go to
  646. * {ESCAPE,newline,carriage-return,backspace,tab,formfeed}
  647. * {\^,\\} go to {carat,backslash}
  648. * \ddd (for ddd = up to three octal digits) goes to the character ddd
  649. *
  650. * \e == \E
  651. * \0 == \200
  652. *
  653. */
  654. NCURSES_EXPORT(int)
  655. _nc_trans_string(char *ptr, char *last)
  656. {
  657. int count = 0;
  658. int number = 0;
  659. int i, c;
  660. chtype ch, last_ch = '\0';
  661. bool ignored = FALSE;
  662. bool long_warning = FALSE;
  663. while ((ch = c = next_char()) != (chtype) separator && c != EOF) {
  664. if (ptr >= (last - 1)) {
  665. if (c != EOF) {
  666. while ((c = next_char()) != separator && c != EOF) {
  667. ;
  668. }
  669. ch = c;
  670. }
  671. break;
  672. }
  673. if ((_nc_syntax == SYN_TERMCAP) && c == '\n')
  674. break;
  675. if (ch == '^' && last_ch != '%') {
  676. ch = c = next_char();
  677. if (c == EOF)
  678. _nc_err_abort(MSG_NO_INPUTS);
  679. if (!(is7bits(ch) && isprint(ch))) {
  680. _nc_warning("Illegal ^ character - '%s'", unctrl(ch));
  681. }
  682. if (ch == '?') {
  683. *(ptr++) = '\177';
  684. if (_nc_tracing)
  685. _nc_warning("Allow ^? as synonym for \\177");
  686. } else {
  687. if ((ch &= 037) == 0)
  688. ch = 128;
  689. *(ptr++) = (char) (ch);
  690. }
  691. } else if (ch == '\\') {
  692. ch = c = next_char();
  693. if (c == EOF)
  694. _nc_err_abort(MSG_NO_INPUTS);
  695. if (ch >= '0' && ch <= '7') {
  696. number = ch - '0';
  697. for (i = 0; i < 2; i++) {
  698. ch = c = next_char();
  699. if (c == EOF)
  700. _nc_err_abort(MSG_NO_INPUTS);
  701. if (c < '0' || c > '7') {
  702. if (isdigit(c)) {
  703. _nc_warning("Non-octal digit `%c' in \\ sequence", c);
  704. /* allow the digit; it'll do less harm */
  705. } else {
  706. push_back((char) c);
  707. break;
  708. }
  709. }
  710. number = number * 8 + c - '0';
  711. }
  712. if (number == 0)
  713. number = 0200;
  714. *(ptr++) = (char) number;
  715. } else {
  716. switch (c) {
  717. case 'E':
  718. case 'e':
  719. *(ptr++) = '\033';
  720. break;
  721. case 'a':
  722. *(ptr++) = '\007';
  723. break;
  724. case 'l':
  725. case 'n':
  726. *(ptr++) = '\n';
  727. break;
  728. case 'r':
  729. *(ptr++) = '\r';
  730. break;
  731. case 'b':
  732. *(ptr++) = '\010';
  733. break;
  734. case 's':
  735. *(ptr++) = ' ';
  736. break;
  737. case 'f':
  738. *(ptr++) = '\014';
  739. break;
  740. case 't':
  741. *(ptr++) = '\t';
  742. break;
  743. case '\\':
  744. *(ptr++) = '\\';
  745. break;
  746. case '^':
  747. *(ptr++) = '^';
  748. break;
  749. case ',':
  750. *(ptr++) = ',';
  751. break;
  752. case ':':
  753. *(ptr++) = ':';
  754. break;
  755. case '\n':
  756. continue;
  757. default:
  758. _nc_warning("Illegal character '%s' in \\ sequence",
  759. unctrl(ch));
  760. /* FALLTHRU */
  761. case '|':
  762. *(ptr++) = (char) ch;
  763. } /* endswitch (ch) */
  764. } /* endelse (ch < '0' || ch > '7') */
  765. }
  766. /* end else if (ch == '\\') */
  767. else if (ch == '\n' && (_nc_syntax == SYN_TERMINFO)) {
  768. /*
  769. * Newlines embedded in a terminfo string are ignored, provided
  770. * that the next line begins with whitespace.
  771. */
  772. ignored = TRUE;
  773. } else {
  774. *(ptr++) = (char) ch;
  775. }
  776. if (!ignored) {
  777. if (_nc_curr_col <= 1) {
  778. push_back((char) ch);
  779. ch = '\n';
  780. break;
  781. }
  782. last_ch = ch;
  783. count++;
  784. }
  785. ignored = FALSE;
  786. if (count > MAXCAPLEN && !long_warning) {
  787. _nc_warning("Very long string found. Missing separator?");
  788. long_warning = TRUE;
  789. }
  790. } /* end while */
  791. *ptr = '\0';
  792. return (ch);
  793. }
  794. /*
  795. * _nc_push_token()
  796. *
  797. * Push a token of given type so that it will be reread by the next
  798. * get_token() call.
  799. */
  800. NCURSES_EXPORT(void)
  801. _nc_push_token(int tokclass)
  802. {
  803. /*
  804. * This implementation is kind of bogus, it will fail if we ever do more
  805. * than one pushback at a time between get_token() calls. It relies on the
  806. * fact that _nc_curr_token is static storage that nothing but
  807. * _nc_get_token() touches.
  808. */
  809. pushtype = tokclass;
  810. if (pushname == 0)
  811. pushname = typeMalloc(char, MAX_NAME_SIZE + 1);
  812. _nc_get_type(pushname);
  813. DEBUG(3, ("pushing token: `%s', class %d",
  814. ((_nc_curr_token.tk_name != 0)
  815. ? _nc_curr_token.tk_name
  816. : "<null>"),
  817. pushtype));
  818. }
  819. /*
  820. * Panic mode error recovery - skip everything until a "ch" is found.
  821. */
  822. NCURSES_EXPORT(void)
  823. _nc_panic_mode(char ch)
  824. {
  825. int c;
  826. for (;;) {
  827. c = next_char();
  828. if (c == ch)
  829. return;
  830. if (c == EOF)
  831. return;
  832. }
  833. }
  834. #if NO_LEAKS
  835. NCURSES_EXPORT(void)
  836. _nc_comp_scan_leaks(void)
  837. {
  838. if (pushname != 0) {
  839. FreeAndNull(pushname);
  840. }
  841. }
  842. #endif