/contrib/groff/src/roff/troff/input.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 8214 lines · 7726 code · 378 blank · 110 comment · 1291 complexity · 62b837aa80c4497c3fc2edb1fd1e5325 MD5 · raw file

Large files are truncated click here to view the full file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
  3. Free Software Foundation, Inc.
  4. Written by James Clark (jjc@jclark.com)
  5. This file is part of groff.
  6. groff is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU General Public License as published by the Free
  8. Software Foundation; either version 2, or (at your option) any later
  9. version.
  10. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with groff; see the file COPYING. If not, write to the Free Software
  16. Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
  17. #define DEBUGGING
  18. #include "troff.h"
  19. #include "dictionary.h"
  20. #include "hvunits.h"
  21. #include "stringclass.h"
  22. #include "mtsm.h"
  23. #include "env.h"
  24. #include "request.h"
  25. #include "node.h"
  26. #include "token.h"
  27. #include "div.h"
  28. #include "reg.h"
  29. #include "charinfo.h"
  30. #include "macropath.h"
  31. #include "input.h"
  32. #include "defs.h"
  33. #include "font.h"
  34. #include "unicode.h"
  35. // Needed for getpid() and isatty()
  36. #include "posix.h"
  37. #include "nonposix.h"
  38. #ifdef NEED_DECLARATION_PUTENV
  39. extern "C" {
  40. int putenv(const char *);
  41. }
  42. #endif /* NEED_DECLARATION_PUTENV */
  43. #define MACRO_PREFIX "tmac."
  44. #define MACRO_POSTFIX ".tmac"
  45. #define INITIAL_STARTUP_FILE "troffrc"
  46. #define FINAL_STARTUP_FILE "troffrc-end"
  47. #define DEFAULT_INPUT_STACK_LIMIT 1000
  48. #ifndef DEFAULT_WARNING_MASK
  49. // warnings that are enabled by default
  50. #define DEFAULT_WARNING_MASK \
  51. (WARN_CHAR|WARN_NUMBER|WARN_BREAK|WARN_SPACE|WARN_FONT)
  52. #endif
  53. // initial size of buffer for reading names; expanded as necessary
  54. #define ABUF_SIZE 16
  55. extern "C" const char *program_name;
  56. extern "C" const char *Version_string;
  57. #ifdef COLUMN
  58. void init_column_requests();
  59. #endif /* COLUMN */
  60. static node *read_draw_node();
  61. static void read_color_draw_node(token &);
  62. static void push_token(const token &);
  63. void copy_file();
  64. #ifdef COLUMN
  65. void vjustify();
  66. #endif /* COLUMN */
  67. void transparent_file();
  68. token tok;
  69. int break_flag = 0;
  70. int color_flag = 1; // colors are on by default
  71. static int backtrace_flag = 0;
  72. #ifndef POPEN_MISSING
  73. char *pipe_command = 0;
  74. #endif
  75. charinfo *charset_table[256];
  76. unsigned char hpf_code_table[256];
  77. static int warning_mask = DEFAULT_WARNING_MASK;
  78. static int inhibit_errors = 0;
  79. static int ignoring = 0;
  80. static void enable_warning(const char *);
  81. static void disable_warning(const char *);
  82. static int escape_char = '\\';
  83. static symbol end_macro_name;
  84. static symbol blank_line_macro_name;
  85. static int compatible_flag = 0;
  86. int ascii_output_flag = 0;
  87. int suppress_output_flag = 0;
  88. int is_html = 0;
  89. int begin_level = 0; // number of nested \O escapes
  90. int have_input = 0; // whether \f, \F, \D'F...', \H, \m, \M,
  91. // \R, \s, or \S has been processed in
  92. // token::next()
  93. int old_have_input = 0; // value of have_input right before \n
  94. int tcommand_flag = 0;
  95. int safer_flag = 1; // safer by default
  96. int have_string_arg = 0; // whether we have \*[foo bar...]
  97. double spread_limit = -3.0 - 1.0; // negative means deactivated
  98. double warn_scale;
  99. char warn_scaling_indicator;
  100. int debug_state = 0; // turns on debugging of the html troff state
  101. search_path *mac_path = &safer_macro_path;
  102. // Defaults to the current directory.
  103. search_path include_search_path(0, 0, 0, 1);
  104. static int get_copy(node**, int = 0);
  105. static void copy_mode_error(const char *,
  106. const errarg & = empty_errarg,
  107. const errarg & = empty_errarg,
  108. const errarg & = empty_errarg);
  109. enum read_mode { ALLOW_EMPTY, WITH_ARGS, NO_ARGS };
  110. static symbol read_escape_name(read_mode mode = NO_ARGS);
  111. static symbol read_long_escape_name(read_mode mode = NO_ARGS);
  112. static void interpolate_string(symbol);
  113. static void interpolate_string_with_args(symbol);
  114. static void interpolate_macro(symbol);
  115. static void interpolate_number_format(symbol);
  116. static void interpolate_environment_variable(symbol);
  117. static symbol composite_glyph_name(symbol);
  118. static void interpolate_arg(symbol);
  119. static request_or_macro *lookup_request(symbol);
  120. static int get_delim_number(units *, unsigned char);
  121. static int get_delim_number(units *, unsigned char, units);
  122. static symbol do_get_long_name(int, char);
  123. static int get_line_arg(units *res, unsigned char si, charinfo **cp);
  124. static int read_size(int *);
  125. static symbol get_delim_name();
  126. static void init_registers();
  127. static void trapping_blank_line();
  128. class input_iterator;
  129. input_iterator *make_temp_iterator(const char *);
  130. const char *input_char_description(int);
  131. void process_input_stack();
  132. void chop_macro(); // declare to avoid friend name injection
  133. void set_escape_char()
  134. {
  135. if (has_arg()) {
  136. if (tok.ch() == 0) {
  137. error("bad escape character");
  138. escape_char = '\\';
  139. }
  140. else
  141. escape_char = tok.ch();
  142. }
  143. else
  144. escape_char = '\\';
  145. skip_line();
  146. }
  147. void escape_off()
  148. {
  149. escape_char = 0;
  150. skip_line();
  151. }
  152. static int saved_escape_char = '\\';
  153. void save_escape_char()
  154. {
  155. saved_escape_char = escape_char;
  156. skip_line();
  157. }
  158. void restore_escape_char()
  159. {
  160. escape_char = saved_escape_char;
  161. skip_line();
  162. }
  163. class input_iterator {
  164. public:
  165. input_iterator();
  166. input_iterator(int is_div);
  167. virtual ~input_iterator() {}
  168. int get(node **);
  169. friend class input_stack;
  170. int is_diversion;
  171. statem *diversion_state;
  172. protected:
  173. const unsigned char *ptr;
  174. const unsigned char *eptr;
  175. input_iterator *next;
  176. private:
  177. virtual int fill(node **);
  178. virtual int peek();
  179. virtual int has_args() { return 0; }
  180. virtual int nargs() { return 0; }
  181. virtual input_iterator *get_arg(int) { return 0; }
  182. virtual int get_location(int, const char **, int *) { return 0; }
  183. virtual void backtrace() {}
  184. virtual int set_location(const char *, int) { return 0; }
  185. virtual int next_file(FILE *, const char *) { return 0; }
  186. virtual void shift(int) {}
  187. virtual int is_boundary() {return 0; }
  188. virtual int is_file() { return 0; }
  189. virtual int is_macro() { return 0; }
  190. virtual void save_compatible_flag(int) {}
  191. virtual int get_compatible_flag() { return 0; }
  192. };
  193. input_iterator::input_iterator()
  194. : is_diversion(0), ptr(0), eptr(0)
  195. {
  196. }
  197. input_iterator::input_iterator(int is_div)
  198. : is_diversion(is_div), ptr(0), eptr(0)
  199. {
  200. }
  201. int input_iterator::fill(node **)
  202. {
  203. return EOF;
  204. }
  205. int input_iterator::peek()
  206. {
  207. return EOF;
  208. }
  209. inline int input_iterator::get(node **p)
  210. {
  211. return ptr < eptr ? *ptr++ : fill(p);
  212. }
  213. class input_boundary : public input_iterator {
  214. public:
  215. int is_boundary() { return 1; }
  216. };
  217. class input_return_boundary : public input_iterator {
  218. public:
  219. int is_boundary() { return 2; }
  220. };
  221. class file_iterator : public input_iterator {
  222. FILE *fp;
  223. int lineno;
  224. const char *filename;
  225. int popened;
  226. int newline_flag;
  227. int seen_escape;
  228. enum { BUF_SIZE = 512 };
  229. unsigned char buf[BUF_SIZE];
  230. void close();
  231. public:
  232. file_iterator(FILE *, const char *, int = 0);
  233. ~file_iterator();
  234. int fill(node **);
  235. int peek();
  236. int get_location(int, const char **, int *);
  237. void backtrace();
  238. int set_location(const char *, int);
  239. int next_file(FILE *, const char *);
  240. int is_file();
  241. };
  242. file_iterator::file_iterator(FILE *f, const char *fn, int po)
  243. : fp(f), lineno(1), filename(fn), popened(po),
  244. newline_flag(0), seen_escape(0)
  245. {
  246. if ((font::use_charnames_in_special) && (fn != 0)) {
  247. if (!the_output)
  248. init_output();
  249. the_output->put_filename(fn);
  250. }
  251. }
  252. file_iterator::~file_iterator()
  253. {
  254. close();
  255. }
  256. void file_iterator::close()
  257. {
  258. if (fp == stdin)
  259. clearerr(stdin);
  260. #ifndef POPEN_MISSING
  261. else if (popened)
  262. pclose(fp);
  263. #endif /* not POPEN_MISSING */
  264. else
  265. fclose(fp);
  266. }
  267. int file_iterator::is_file()
  268. {
  269. return 1;
  270. }
  271. int file_iterator::next_file(FILE *f, const char *s)
  272. {
  273. close();
  274. filename = s;
  275. fp = f;
  276. lineno = 1;
  277. newline_flag = 0;
  278. seen_escape = 0;
  279. popened = 0;
  280. ptr = 0;
  281. eptr = 0;
  282. return 1;
  283. }
  284. int file_iterator::fill(node **)
  285. {
  286. if (newline_flag)
  287. lineno++;
  288. newline_flag = 0;
  289. unsigned char *p = buf;
  290. ptr = p;
  291. unsigned char *e = p + BUF_SIZE;
  292. while (p < e) {
  293. int c = getc(fp);
  294. if (c == EOF)
  295. break;
  296. if (invalid_input_char(c))
  297. warning(WARN_INPUT, "invalid input character code %1", int(c));
  298. else {
  299. *p++ = c;
  300. if (c == '\n') {
  301. seen_escape = 0;
  302. newline_flag = 1;
  303. break;
  304. }
  305. seen_escape = (c == '\\');
  306. }
  307. }
  308. if (p > buf) {
  309. eptr = p;
  310. return *ptr++;
  311. }
  312. else {
  313. eptr = p;
  314. return EOF;
  315. }
  316. }
  317. int file_iterator::peek()
  318. {
  319. int c = getc(fp);
  320. while (invalid_input_char(c)) {
  321. warning(WARN_INPUT, "invalid input character code %1", int(c));
  322. c = getc(fp);
  323. }
  324. if (c != EOF)
  325. ungetc(c, fp);
  326. return c;
  327. }
  328. int file_iterator::get_location(int /*allow_macro*/,
  329. const char **filenamep, int *linenop)
  330. {
  331. *linenop = lineno;
  332. if (filename != 0 && strcmp(filename, "-") == 0)
  333. *filenamep = "<standard input>";
  334. else
  335. *filenamep = filename;
  336. return 1;
  337. }
  338. void file_iterator::backtrace()
  339. {
  340. errprint("%1:%2: backtrace: %3 `%1'\n", filename, lineno,
  341. popened ? "process" : "file");
  342. }
  343. int file_iterator::set_location(const char *f, int ln)
  344. {
  345. if (f) {
  346. filename = f;
  347. if (!the_output)
  348. init_output();
  349. the_output->put_filename(f);
  350. }
  351. lineno = ln;
  352. return 1;
  353. }
  354. input_iterator nil_iterator;
  355. class input_stack {
  356. public:
  357. static int get(node **);
  358. static int peek();
  359. static void push(input_iterator *);
  360. static input_iterator *get_arg(int);
  361. static int nargs();
  362. static int get_location(int, const char **, int *);
  363. static int set_location(const char *, int);
  364. static void backtrace();
  365. static void backtrace_all();
  366. static void next_file(FILE *, const char *);
  367. static void end_file();
  368. static void shift(int n);
  369. static void add_boundary();
  370. static void add_return_boundary();
  371. static int is_return_boundary();
  372. static void remove_boundary();
  373. static int get_level();
  374. static int get_div_level();
  375. static void increase_level();
  376. static void decrease_level();
  377. static void clear();
  378. static void pop_macro();
  379. static void save_compatible_flag(int);
  380. static int get_compatible_flag();
  381. static statem *get_diversion_state();
  382. static void check_end_diversion(input_iterator *t);
  383. static int limit;
  384. static int div_level;
  385. static statem *diversion_state;
  386. private:
  387. static input_iterator *top;
  388. static int level;
  389. static int finish_get(node **);
  390. static int finish_peek();
  391. };
  392. input_iterator *input_stack::top = &nil_iterator;
  393. int input_stack::level = 0;
  394. int input_stack::limit = DEFAULT_INPUT_STACK_LIMIT;
  395. int input_stack::div_level = 0;
  396. statem *input_stack::diversion_state = NULL;
  397. int suppress_push=0;
  398. inline int input_stack::get_level()
  399. {
  400. return level;
  401. }
  402. inline void input_stack::increase_level()
  403. {
  404. level++;
  405. }
  406. inline void input_stack::decrease_level()
  407. {
  408. level--;
  409. }
  410. inline int input_stack::get_div_level()
  411. {
  412. return div_level;
  413. }
  414. inline int input_stack::get(node **np)
  415. {
  416. int res = (top->ptr < top->eptr) ? *top->ptr++ : finish_get(np);
  417. if (res == '\n') {
  418. old_have_input = have_input;
  419. have_input = 0;
  420. }
  421. return res;
  422. }
  423. int input_stack::finish_get(node **np)
  424. {
  425. for (;;) {
  426. int c = top->fill(np);
  427. if (c != EOF || top->is_boundary())
  428. return c;
  429. if (top == &nil_iterator)
  430. break;
  431. input_iterator *tem = top;
  432. check_end_diversion(tem);
  433. #if defined(DEBUGGING)
  434. if (debug_state)
  435. if (tem->is_diversion)
  436. fprintf(stderr,
  437. "in diversion level = %d\n", input_stack::get_div_level());
  438. #endif
  439. top = top->next;
  440. level--;
  441. delete tem;
  442. if (top->ptr < top->eptr)
  443. return *top->ptr++;
  444. }
  445. assert(level == 0);
  446. return EOF;
  447. }
  448. inline int input_stack::peek()
  449. {
  450. return (top->ptr < top->eptr) ? *top->ptr : finish_peek();
  451. }
  452. void input_stack::check_end_diversion(input_iterator *t)
  453. {
  454. if (t->is_diversion) {
  455. div_level--;
  456. diversion_state = t->diversion_state;
  457. }
  458. }
  459. int input_stack::finish_peek()
  460. {
  461. for (;;) {
  462. int c = top->peek();
  463. if (c != EOF || top->is_boundary())
  464. return c;
  465. if (top == &nil_iterator)
  466. break;
  467. input_iterator *tem = top;
  468. check_end_diversion(tem);
  469. top = top->next;
  470. level--;
  471. delete tem;
  472. if (top->ptr < top->eptr)
  473. return *top->ptr;
  474. }
  475. assert(level == 0);
  476. return EOF;
  477. }
  478. void input_stack::add_boundary()
  479. {
  480. push(new input_boundary);
  481. }
  482. void input_stack::add_return_boundary()
  483. {
  484. push(new input_return_boundary);
  485. }
  486. int input_stack::is_return_boundary()
  487. {
  488. return top->is_boundary() == 2;
  489. }
  490. void input_stack::remove_boundary()
  491. {
  492. assert(top->is_boundary());
  493. input_iterator *temp = top->next;
  494. check_end_diversion(top);
  495. delete top;
  496. top = temp;
  497. level--;
  498. }
  499. void input_stack::push(input_iterator *in)
  500. {
  501. if (in == 0)
  502. return;
  503. if (++level > limit && limit > 0)
  504. fatal("input stack limit exceeded (probable infinite loop)");
  505. in->next = top;
  506. top = in;
  507. if (top->is_diversion) {
  508. div_level++;
  509. in->diversion_state = diversion_state;
  510. diversion_state = curenv->construct_state(0);
  511. #if defined(DEBUGGING)
  512. if (debug_state) {
  513. curenv->dump_troff_state();
  514. fflush(stderr);
  515. }
  516. #endif
  517. }
  518. #if defined(DEBUGGING)
  519. if (debug_state)
  520. if (top->is_diversion) {
  521. fprintf(stderr,
  522. "in diversion level = %d\n", input_stack::get_div_level());
  523. fflush(stderr);
  524. }
  525. #endif
  526. }
  527. statem *get_diversion_state()
  528. {
  529. return input_stack::get_diversion_state();
  530. }
  531. statem *input_stack::get_diversion_state()
  532. {
  533. if (diversion_state == NULL)
  534. return NULL;
  535. else
  536. return new statem(diversion_state);
  537. }
  538. input_iterator *input_stack::get_arg(int i)
  539. {
  540. input_iterator *p;
  541. for (p = top; p != 0; p = p->next)
  542. if (p->has_args())
  543. return p->get_arg(i);
  544. return 0;
  545. }
  546. void input_stack::shift(int n)
  547. {
  548. for (input_iterator *p = top; p; p = p->next)
  549. if (p->has_args()) {
  550. p->shift(n);
  551. return;
  552. }
  553. }
  554. int input_stack::nargs()
  555. {
  556. for (input_iterator *p =top; p != 0; p = p->next)
  557. if (p->has_args())
  558. return p->nargs();
  559. return 0;
  560. }
  561. int input_stack::get_location(int allow_macro, const char **filenamep, int *linenop)
  562. {
  563. for (input_iterator *p = top; p; p = p->next)
  564. if (p->get_location(allow_macro, filenamep, linenop))
  565. return 1;
  566. return 0;
  567. }
  568. void input_stack::backtrace()
  569. {
  570. const char *f;
  571. int n;
  572. // only backtrace down to (not including) the topmost file
  573. for (input_iterator *p = top;
  574. p && !p->get_location(0, &f, &n);
  575. p = p->next)
  576. p->backtrace();
  577. }
  578. void input_stack::backtrace_all()
  579. {
  580. for (input_iterator *p = top; p; p = p->next)
  581. p->backtrace();
  582. }
  583. int input_stack::set_location(const char *filename, int lineno)
  584. {
  585. for (input_iterator *p = top; p; p = p->next)
  586. if (p->set_location(filename, lineno))
  587. return 1;
  588. return 0;
  589. }
  590. void input_stack::next_file(FILE *fp, const char *s)
  591. {
  592. input_iterator **pp;
  593. for (pp = &top; *pp != &nil_iterator; pp = &(*pp)->next)
  594. if ((*pp)->next_file(fp, s))
  595. return;
  596. if (++level > limit && limit > 0)
  597. fatal("input stack limit exceeded");
  598. *pp = new file_iterator(fp, s);
  599. (*pp)->next = &nil_iterator;
  600. }
  601. void input_stack::end_file()
  602. {
  603. for (input_iterator **pp = &top; *pp != &nil_iterator; pp = &(*pp)->next)
  604. if ((*pp)->is_file()) {
  605. input_iterator *tem = *pp;
  606. check_end_diversion(tem);
  607. *pp = (*pp)->next;
  608. delete tem;
  609. level--;
  610. return;
  611. }
  612. }
  613. void input_stack::clear()
  614. {
  615. int nboundaries = 0;
  616. while (top != &nil_iterator) {
  617. if (top->is_boundary())
  618. nboundaries++;
  619. input_iterator *tem = top;
  620. check_end_diversion(tem);
  621. top = top->next;
  622. level--;
  623. delete tem;
  624. }
  625. // Keep while_request happy.
  626. for (; nboundaries > 0; --nboundaries)
  627. add_return_boundary();
  628. }
  629. void input_stack::pop_macro()
  630. {
  631. int nboundaries = 0;
  632. int is_macro = 0;
  633. do {
  634. if (top->next == &nil_iterator)
  635. break;
  636. if (top->is_boundary())
  637. nboundaries++;
  638. is_macro = top->is_macro();
  639. input_iterator *tem = top;
  640. check_end_diversion(tem);
  641. top = top->next;
  642. level--;
  643. delete tem;
  644. } while (!is_macro);
  645. // Keep while_request happy.
  646. for (; nboundaries > 0; --nboundaries)
  647. add_return_boundary();
  648. }
  649. inline void input_stack::save_compatible_flag(int f)
  650. {
  651. top->save_compatible_flag(f);
  652. }
  653. inline int input_stack::get_compatible_flag()
  654. {
  655. return top->get_compatible_flag();
  656. }
  657. void backtrace_request()
  658. {
  659. input_stack::backtrace_all();
  660. fflush(stderr);
  661. skip_line();
  662. }
  663. void next_file()
  664. {
  665. symbol nm = get_long_name();
  666. while (!tok.newline() && !tok.eof())
  667. tok.next();
  668. if (nm.is_null())
  669. input_stack::end_file();
  670. else {
  671. errno = 0;
  672. FILE *fp = include_search_path.open_file_cautious(nm.contents());
  673. if (!fp)
  674. error("can't open `%1': %2", nm.contents(), strerror(errno));
  675. else
  676. input_stack::next_file(fp, nm.contents());
  677. }
  678. tok.next();
  679. }
  680. void shift()
  681. {
  682. int n;
  683. if (!has_arg() || !get_integer(&n))
  684. n = 1;
  685. input_stack::shift(n);
  686. skip_line();
  687. }
  688. static char get_char_for_escape_name(int allow_space = 0)
  689. {
  690. int c = get_copy(0);
  691. switch (c) {
  692. case EOF:
  693. copy_mode_error("end of input in escape name");
  694. return '\0';
  695. default:
  696. if (!invalid_input_char(c))
  697. break;
  698. // fall through
  699. case '\n':
  700. if (c == '\n')
  701. input_stack::push(make_temp_iterator("\n"));
  702. // fall through
  703. case ' ':
  704. if (c == ' ' && allow_space)
  705. break;
  706. // fall through
  707. case '\t':
  708. case '\001':
  709. case '\b':
  710. copy_mode_error("%1 is not allowed in an escape name",
  711. input_char_description(c));
  712. return '\0';
  713. }
  714. return c;
  715. }
  716. static symbol read_two_char_escape_name()
  717. {
  718. char buf[3];
  719. buf[0] = get_char_for_escape_name();
  720. if (buf[0] != '\0') {
  721. buf[1] = get_char_for_escape_name();
  722. if (buf[1] == '\0')
  723. buf[0] = 0;
  724. else
  725. buf[2] = 0;
  726. }
  727. return symbol(buf);
  728. }
  729. static symbol read_long_escape_name(read_mode mode)
  730. {
  731. int start_level = input_stack::get_level();
  732. char abuf[ABUF_SIZE];
  733. char *buf = abuf;
  734. int buf_size = ABUF_SIZE;
  735. int i = 0;
  736. char c;
  737. int have_char = 0;
  738. for (;;) {
  739. c = get_char_for_escape_name(have_char && mode == WITH_ARGS);
  740. if (c == 0) {
  741. if (buf != abuf)
  742. a_delete buf;
  743. return NULL_SYMBOL;
  744. }
  745. have_char = 1;
  746. if (mode == WITH_ARGS && c == ' ')
  747. break;
  748. if (i + 2 > buf_size) {
  749. if (buf == abuf) {
  750. buf = new char[ABUF_SIZE*2];
  751. memcpy(buf, abuf, buf_size);
  752. buf_size = ABUF_SIZE*2;
  753. }
  754. else {
  755. char *old_buf = buf;
  756. buf = new char[buf_size*2];
  757. memcpy(buf, old_buf, buf_size);
  758. buf_size *= 2;
  759. a_delete old_buf;
  760. }
  761. }
  762. if (c == ']' && input_stack::get_level() == start_level)
  763. break;
  764. buf[i++] = c;
  765. }
  766. buf[i] = 0;
  767. if (c == ' ')
  768. have_string_arg = 1;
  769. if (buf == abuf) {
  770. if (i == 0) {
  771. if (mode != ALLOW_EMPTY)
  772. copy_mode_error("empty escape name");
  773. return EMPTY_SYMBOL;
  774. }
  775. return symbol(abuf);
  776. }
  777. else {
  778. symbol s(buf);
  779. a_delete buf;
  780. return s;
  781. }
  782. }
  783. static symbol read_escape_name(read_mode mode)
  784. {
  785. char c = get_char_for_escape_name();
  786. if (c == 0)
  787. return NULL_SYMBOL;
  788. if (c == '(')
  789. return read_two_char_escape_name();
  790. if (c == '[' && !compatible_flag)
  791. return read_long_escape_name(mode);
  792. char buf[2];
  793. buf[0] = c;
  794. buf[1] = '\0';
  795. return symbol(buf);
  796. }
  797. static symbol read_increment_and_escape_name(int *incp)
  798. {
  799. char c = get_char_for_escape_name();
  800. switch (c) {
  801. case 0:
  802. *incp = 0;
  803. return NULL_SYMBOL;
  804. case '(':
  805. *incp = 0;
  806. return read_two_char_escape_name();
  807. case '+':
  808. *incp = 1;
  809. return read_escape_name();
  810. case '-':
  811. *incp = -1;
  812. return read_escape_name();
  813. case '[':
  814. if (!compatible_flag) {
  815. *incp = 0;
  816. return read_long_escape_name();
  817. }
  818. break;
  819. }
  820. *incp = 0;
  821. char buf[2];
  822. buf[0] = c;
  823. buf[1] = '\0';
  824. return symbol(buf);
  825. }
  826. static int get_copy(node **nd, int defining)
  827. {
  828. for (;;) {
  829. int c = input_stack::get(nd);
  830. if (c == PUSH_GROFF_MODE) {
  831. input_stack::save_compatible_flag(compatible_flag);
  832. compatible_flag = 0;
  833. continue;
  834. }
  835. if (c == PUSH_COMP_MODE) {
  836. input_stack::save_compatible_flag(compatible_flag);
  837. compatible_flag = 1;
  838. continue;
  839. }
  840. if (c == POP_GROFFCOMP_MODE) {
  841. compatible_flag = input_stack::get_compatible_flag();
  842. continue;
  843. }
  844. if (c == BEGIN_QUOTE) {
  845. input_stack::increase_level();
  846. continue;
  847. }
  848. if (c == END_QUOTE) {
  849. input_stack::decrease_level();
  850. continue;
  851. }
  852. if (c == ESCAPE_NEWLINE) {
  853. if (defining)
  854. return c;
  855. do {
  856. c = input_stack::get(nd);
  857. } while (c == ESCAPE_NEWLINE);
  858. }
  859. if (c != escape_char || escape_char <= 0)
  860. return c;
  861. c = input_stack::peek();
  862. switch(c) {
  863. case 0:
  864. return escape_char;
  865. case '"':
  866. (void)input_stack::get(0);
  867. while ((c = input_stack::get(0)) != '\n' && c != EOF)
  868. ;
  869. return c;
  870. case '#': // Like \" but newline is ignored.
  871. (void)input_stack::get(0);
  872. while ((c = input_stack::get(0)) != '\n')
  873. if (c == EOF)
  874. return EOF;
  875. break;
  876. case '$':
  877. {
  878. (void)input_stack::get(0);
  879. symbol s = read_escape_name();
  880. if (!(s.is_null() || s.is_empty()))
  881. interpolate_arg(s);
  882. break;
  883. }
  884. case '*':
  885. {
  886. (void)input_stack::get(0);
  887. symbol s = read_escape_name(WITH_ARGS);
  888. if (!(s.is_null() || s.is_empty())) {
  889. if (have_string_arg) {
  890. have_string_arg = 0;
  891. interpolate_string_with_args(s);
  892. }
  893. else
  894. interpolate_string(s);
  895. }
  896. break;
  897. }
  898. case 'a':
  899. (void)input_stack::get(0);
  900. return '\001';
  901. case 'e':
  902. (void)input_stack::get(0);
  903. return ESCAPE_e;
  904. case 'E':
  905. (void)input_stack::get(0);
  906. return ESCAPE_E;
  907. case 'n':
  908. {
  909. (void)input_stack::get(0);
  910. int inc;
  911. symbol s = read_increment_and_escape_name(&inc);
  912. if (!(s.is_null() || s.is_empty()))
  913. interpolate_number_reg(s, inc);
  914. break;
  915. }
  916. case 'g':
  917. {
  918. (void)input_stack::get(0);
  919. symbol s = read_escape_name();
  920. if (!(s.is_null() || s.is_empty()))
  921. interpolate_number_format(s);
  922. break;
  923. }
  924. case 't':
  925. (void)input_stack::get(0);
  926. return '\t';
  927. case 'V':
  928. {
  929. (void)input_stack::get(0);
  930. symbol s = read_escape_name();
  931. if (!(s.is_null() || s.is_empty()))
  932. interpolate_environment_variable(s);
  933. break;
  934. }
  935. case '\n':
  936. (void)input_stack::get(0);
  937. if (defining)
  938. return ESCAPE_NEWLINE;
  939. break;
  940. case ' ':
  941. (void)input_stack::get(0);
  942. return ESCAPE_SPACE;
  943. case '~':
  944. (void)input_stack::get(0);
  945. return ESCAPE_TILDE;
  946. case ':':
  947. (void)input_stack::get(0);
  948. return ESCAPE_COLON;
  949. case '|':
  950. (void)input_stack::get(0);
  951. return ESCAPE_BAR;
  952. case '^':
  953. (void)input_stack::get(0);
  954. return ESCAPE_CIRCUMFLEX;
  955. case '{':
  956. (void)input_stack::get(0);
  957. return ESCAPE_LEFT_BRACE;
  958. case '}':
  959. (void)input_stack::get(0);
  960. return ESCAPE_RIGHT_BRACE;
  961. case '`':
  962. (void)input_stack::get(0);
  963. return ESCAPE_LEFT_QUOTE;
  964. case '\'':
  965. (void)input_stack::get(0);
  966. return ESCAPE_RIGHT_QUOTE;
  967. case '-':
  968. (void)input_stack::get(0);
  969. return ESCAPE_HYPHEN;
  970. case '_':
  971. (void)input_stack::get(0);
  972. return ESCAPE_UNDERSCORE;
  973. case 'c':
  974. (void)input_stack::get(0);
  975. return ESCAPE_c;
  976. case '!':
  977. (void)input_stack::get(0);
  978. return ESCAPE_BANG;
  979. case '?':
  980. (void)input_stack::get(0);
  981. return ESCAPE_QUESTION;
  982. case '&':
  983. (void)input_stack::get(0);
  984. return ESCAPE_AMPERSAND;
  985. case ')':
  986. (void)input_stack::get(0);
  987. return ESCAPE_RIGHT_PARENTHESIS;
  988. case '.':
  989. (void)input_stack::get(0);
  990. return c;
  991. case '%':
  992. (void)input_stack::get(0);
  993. return ESCAPE_PERCENT;
  994. default:
  995. if (c == escape_char) {
  996. (void)input_stack::get(0);
  997. return c;
  998. }
  999. else
  1000. return escape_char;
  1001. }
  1002. }
  1003. }
  1004. class non_interpreted_char_node : public node {
  1005. unsigned char c;
  1006. public:
  1007. non_interpreted_char_node(unsigned char);
  1008. node *copy();
  1009. int interpret(macro *);
  1010. int same(node *);
  1011. const char *type();
  1012. int force_tprint();
  1013. int is_tag();
  1014. };
  1015. int non_interpreted_char_node::same(node *nd)
  1016. {
  1017. return c == ((non_interpreted_char_node *)nd)->c;
  1018. }
  1019. const char *non_interpreted_char_node::type()
  1020. {
  1021. return "non_interpreted_char_node";
  1022. }
  1023. int non_interpreted_char_node::force_tprint()
  1024. {
  1025. return 0;
  1026. }
  1027. int non_interpreted_char_node::is_tag()
  1028. {
  1029. return 0;
  1030. }
  1031. non_interpreted_char_node::non_interpreted_char_node(unsigned char n) : c(n)
  1032. {
  1033. assert(n != 0);
  1034. }
  1035. node *non_interpreted_char_node::copy()
  1036. {
  1037. return new non_interpreted_char_node(c);
  1038. }
  1039. int non_interpreted_char_node::interpret(macro *mac)
  1040. {
  1041. mac->append(c);
  1042. return 1;
  1043. }
  1044. static void do_width();
  1045. static node *do_non_interpreted();
  1046. static node *do_special();
  1047. static node *do_suppress(symbol nm);
  1048. static void do_register();
  1049. dictionary color_dictionary(501);
  1050. static color *lookup_color(symbol nm)
  1051. {
  1052. assert(!nm.is_null());
  1053. if (nm == default_symbol)
  1054. return &default_color;
  1055. color *c = (color *)color_dictionary.lookup(nm);
  1056. if (c == 0)
  1057. warning(WARN_COLOR, "color `%1' not defined", nm.contents());
  1058. return c;
  1059. }
  1060. void do_glyph_color(symbol nm)
  1061. {
  1062. if (nm.is_null())
  1063. return;
  1064. if (nm.is_empty())
  1065. curenv->set_glyph_color(curenv->get_prev_glyph_color());
  1066. else {
  1067. color *tem = lookup_color(nm);
  1068. if (tem)
  1069. curenv->set_glyph_color(tem);
  1070. else
  1071. (void)color_dictionary.lookup(nm, new color(nm));
  1072. }
  1073. }
  1074. void do_fill_color(symbol nm)
  1075. {
  1076. if (nm.is_null())
  1077. return;
  1078. if (nm.is_empty())
  1079. curenv->set_fill_color(curenv->get_prev_fill_color());
  1080. else {
  1081. color *tem = lookup_color(nm);
  1082. if (tem)
  1083. curenv->set_fill_color(tem);
  1084. else
  1085. (void)color_dictionary.lookup(nm, new color(nm));
  1086. }
  1087. }
  1088. static unsigned int get_color_element(const char *scheme, const char *col)
  1089. {
  1090. units val;
  1091. if (!get_number(&val, 'f')) {
  1092. warning(WARN_COLOR, "%1 in %2 definition set to 0", col, scheme);
  1093. tok.next();
  1094. return 0;
  1095. }
  1096. if (val < 0) {
  1097. warning(WARN_RANGE, "%1 cannot be negative: set to 0", col);
  1098. return 0;
  1099. }
  1100. if (val > color::MAX_COLOR_VAL+1) {
  1101. warning(WARN_RANGE, "%1 cannot be greater than 1", col);
  1102. // we change 0x10000 to 0xffff
  1103. return color::MAX_COLOR_VAL;
  1104. }
  1105. return (unsigned int)val;
  1106. }
  1107. static color *read_rgb(char end = 0)
  1108. {
  1109. symbol component = do_get_long_name(0, end);
  1110. if (component.is_null()) {
  1111. warning(WARN_COLOR, "missing rgb color values");
  1112. return 0;
  1113. }
  1114. const char *s = component.contents();
  1115. color *col = new color;
  1116. if (*s == '#') {
  1117. if (!col->read_rgb(s)) {
  1118. warning(WARN_COLOR, "expecting rgb color definition not `%1'", s);
  1119. delete col;
  1120. return 0;
  1121. }
  1122. }
  1123. else {
  1124. if (!end)
  1125. input_stack::push(make_temp_iterator(" "));
  1126. input_stack::push(make_temp_iterator(s));
  1127. tok.next();
  1128. unsigned int r = get_color_element("rgb color", "red component");
  1129. unsigned int g = get_color_element("rgb color", "green component");
  1130. unsigned int b = get_color_element("rgb color", "blue component");
  1131. col->set_rgb(r, g, b);
  1132. }
  1133. return col;
  1134. }
  1135. static color *read_cmy(char end = 0)
  1136. {
  1137. symbol component = do_get_long_name(0, end);
  1138. if (component.is_null()) {
  1139. warning(WARN_COLOR, "missing cmy color values");
  1140. return 0;
  1141. }
  1142. const char *s = component.contents();
  1143. color *col = new color;
  1144. if (*s == '#') {
  1145. if (!col->read_cmy(s)) {
  1146. warning(WARN_COLOR, "expecting cmy color definition not `%1'", s);
  1147. delete col;
  1148. return 0;
  1149. }
  1150. }
  1151. else {
  1152. if (!end)
  1153. input_stack::push(make_temp_iterator(" "));
  1154. input_stack::push(make_temp_iterator(s));
  1155. tok.next();
  1156. unsigned int c = get_color_element("cmy color", "cyan component");
  1157. unsigned int m = get_color_element("cmy color", "magenta component");
  1158. unsigned int y = get_color_element("cmy color", "yellow component");
  1159. col->set_cmy(c, m, y);
  1160. }
  1161. return col;
  1162. }
  1163. static color *read_cmyk(char end = 0)
  1164. {
  1165. symbol component = do_get_long_name(0, end);
  1166. if (component.is_null()) {
  1167. warning(WARN_COLOR, "missing cmyk color values");
  1168. return 0;
  1169. }
  1170. const char *s = component.contents();
  1171. color *col = new color;
  1172. if (*s == '#') {
  1173. if (!col->read_cmyk(s)) {
  1174. warning(WARN_COLOR, "`expecting a cmyk color definition not `%1'", s);
  1175. delete col;
  1176. return 0;
  1177. }
  1178. }
  1179. else {
  1180. if (!end)
  1181. input_stack::push(make_temp_iterator(" "));
  1182. input_stack::push(make_temp_iterator(s));
  1183. tok.next();
  1184. unsigned int c = get_color_element("cmyk color", "cyan component");
  1185. unsigned int m = get_color_element("cmyk color", "magenta component");
  1186. unsigned int y = get_color_element("cmyk color", "yellow component");
  1187. unsigned int k = get_color_element("cmyk color", "black component");
  1188. col->set_cmyk(c, m, y, k);
  1189. }
  1190. return col;
  1191. }
  1192. static color *read_gray(char end = 0)
  1193. {
  1194. symbol component = do_get_long_name(0, end);
  1195. if (component.is_null()) {
  1196. warning(WARN_COLOR, "missing gray values");
  1197. return 0;
  1198. }
  1199. const char *s = component.contents();
  1200. color *col = new color;
  1201. if (*s == '#') {
  1202. if (!col->read_gray(s)) {
  1203. warning(WARN_COLOR, "`expecting a gray definition not `%1'", s);
  1204. delete col;
  1205. return 0;
  1206. }
  1207. }
  1208. else {
  1209. if (!end)
  1210. input_stack::push(make_temp_iterator("\n"));
  1211. input_stack::push(make_temp_iterator(s));
  1212. tok.next();
  1213. unsigned int g = get_color_element("gray", "gray value");
  1214. col->set_gray(g);
  1215. }
  1216. return col;
  1217. }
  1218. static void activate_color()
  1219. {
  1220. int n;
  1221. if (has_arg() && get_integer(&n))
  1222. color_flag = n != 0;
  1223. else
  1224. color_flag = 1;
  1225. skip_line();
  1226. }
  1227. static void define_color()
  1228. {
  1229. symbol color_name = get_long_name(1);
  1230. if (color_name.is_null()) {
  1231. skip_line();
  1232. return;
  1233. }
  1234. if (color_name == default_symbol) {
  1235. warning(WARN_COLOR, "default color can't be redefined");
  1236. skip_line();
  1237. return;
  1238. }
  1239. symbol style = get_long_name(1);
  1240. if (style.is_null()) {
  1241. skip_line();
  1242. return;
  1243. }
  1244. color *col;
  1245. if (strcmp(style.contents(), "rgb") == 0)
  1246. col = read_rgb();
  1247. else if (strcmp(style.contents(), "cmyk") == 0)
  1248. col = read_cmyk();
  1249. else if (strcmp(style.contents(), "gray") == 0)
  1250. col = read_gray();
  1251. else if (strcmp(style.contents(), "grey") == 0)
  1252. col = read_gray();
  1253. else if (strcmp(style.contents(), "cmy") == 0)
  1254. col = read_cmy();
  1255. else {
  1256. warning(WARN_COLOR,
  1257. "unknown color space `%1'; use rgb, cmyk, gray or cmy",
  1258. style.contents());
  1259. skip_line();
  1260. return;
  1261. }
  1262. if (col) {
  1263. col->nm = color_name;
  1264. (void)color_dictionary.lookup(color_name, col);
  1265. }
  1266. skip_line();
  1267. }
  1268. static node *do_overstrike()
  1269. {
  1270. token start;
  1271. overstrike_node *on = new overstrike_node;
  1272. int start_level = input_stack::get_level();
  1273. start.next();
  1274. for (;;) {
  1275. tok.next();
  1276. if (tok.newline() || tok.eof()) {
  1277. warning(WARN_DELIM, "missing closing delimiter");
  1278. input_stack::push(make_temp_iterator("\n"));
  1279. break;
  1280. }
  1281. if (tok == start
  1282. && (compatible_flag || input_stack::get_level() == start_level))
  1283. break;
  1284. charinfo *ci = tok.get_char(1);
  1285. if (ci) {
  1286. node *n = curenv->make_char_node(ci);
  1287. if (n)
  1288. on->overstrike(n);
  1289. }
  1290. }
  1291. return on;
  1292. }
  1293. static node *do_bracket()
  1294. {
  1295. token start;
  1296. bracket_node *bn = new bracket_node;
  1297. start.next();
  1298. int start_level = input_stack::get_level();
  1299. for (;;) {
  1300. tok.next();
  1301. if (tok.eof()) {
  1302. warning(WARN_DELIM, "missing closing delimiter");
  1303. break;
  1304. }
  1305. if (tok.newline()) {
  1306. warning(WARN_DELIM, "missing closing delimiter");
  1307. input_stack::push(make_temp_iterator("\n"));
  1308. break;
  1309. }
  1310. if (tok == start
  1311. && (compatible_flag || input_stack::get_level() == start_level))
  1312. break;
  1313. charinfo *ci = tok.get_char(1);
  1314. if (ci) {
  1315. node *n = curenv->make_char_node(ci);
  1316. if (n)
  1317. bn->bracket(n);
  1318. }
  1319. }
  1320. return bn;
  1321. }
  1322. static int do_name_test()
  1323. {
  1324. token start;
  1325. start.next();
  1326. int start_level = input_stack::get_level();
  1327. int bad_char = 0;
  1328. int some_char = 0;
  1329. for (;;) {
  1330. tok.next();
  1331. if (tok.newline() || tok.eof()) {
  1332. warning(WARN_DELIM, "missing closing delimiter");
  1333. input_stack::push(make_temp_iterator("\n"));
  1334. break;
  1335. }
  1336. if (tok == start
  1337. && (compatible_flag || input_stack::get_level() == start_level))
  1338. break;
  1339. if (!tok.ch())
  1340. bad_char = 1;
  1341. some_char = 1;
  1342. }
  1343. return some_char && !bad_char;
  1344. }
  1345. static int do_expr_test()
  1346. {
  1347. token start;
  1348. start.next();
  1349. int start_level = input_stack::get_level();
  1350. if (!start.delimiter(1))
  1351. return 0;
  1352. tok.next();
  1353. // disable all warning and error messages temporarily
  1354. int saved_warning_mask = warning_mask;
  1355. int saved_inhibit_errors = inhibit_errors;
  1356. warning_mask = 0;
  1357. inhibit_errors = 1;
  1358. int dummy;
  1359. int result = get_number_rigidly(&dummy, 'u');
  1360. warning_mask = saved_warning_mask;
  1361. inhibit_errors = saved_inhibit_errors;
  1362. if (tok == start && input_stack::get_level() == start_level)
  1363. return result;
  1364. // ignore everything up to the delimiter in case we aren't right there
  1365. for (;;) {
  1366. tok.next();
  1367. if (tok.newline() || tok.eof()) {
  1368. warning(WARN_DELIM, "missing closing delimiter");
  1369. input_stack::push(make_temp_iterator("\n"));
  1370. break;
  1371. }
  1372. if (tok == start && input_stack::get_level() == start_level)
  1373. break;
  1374. }
  1375. return 0;
  1376. }
  1377. #if 0
  1378. static node *do_zero_width()
  1379. {
  1380. token start;
  1381. start.next();
  1382. int start_level = input_stack::get_level();
  1383. environment env(curenv);
  1384. environment *oldenv = curenv;
  1385. curenv = &env;
  1386. for (;;) {
  1387. tok.next();
  1388. if (tok.newline() || tok.eof()) {
  1389. error("missing closing delimiter");
  1390. break;
  1391. }
  1392. if (tok == start
  1393. && (compatible_flag || input_stack::get_level() == start_level))
  1394. break;
  1395. tok.process();
  1396. }
  1397. curenv = oldenv;
  1398. node *rev = env.extract_output_line();
  1399. node *n = 0;
  1400. while (rev) {
  1401. node *tem = rev;
  1402. rev = rev->next;
  1403. tem->next = n;
  1404. n = tem;
  1405. }
  1406. return new zero_width_node(n);
  1407. }
  1408. #else
  1409. // It's undesirable for \Z to change environments, because then
  1410. // \n(.w won't work as expected.
  1411. static node *do_zero_width()
  1412. {
  1413. node *rev = new dummy_node;
  1414. token start;
  1415. start.next();
  1416. int start_level = input_stack::get_level();
  1417. for (;;) {
  1418. tok.next();
  1419. if (tok.newline() || tok.eof()) {
  1420. warning(WARN_DELIM, "missing closing delimiter");
  1421. input_stack::push(make_temp_iterator("\n"));
  1422. break;
  1423. }
  1424. if (tok == start
  1425. && (compatible_flag || input_stack::get_level() == start_level))
  1426. break;
  1427. if (!tok.add_to_node_list(&rev))
  1428. error("invalid token in argument to \\Z");
  1429. }
  1430. node *n = 0;
  1431. while (rev) {
  1432. node *tem = rev;
  1433. rev = rev->next;
  1434. tem->next = n;
  1435. n = tem;
  1436. }
  1437. return new zero_width_node(n);
  1438. }
  1439. #endif
  1440. token_node *node::get_token_node()
  1441. {
  1442. return 0;
  1443. }
  1444. class token_node : public node {
  1445. public:
  1446. token tk;
  1447. token_node(const token &t);
  1448. node *copy();
  1449. token_node *get_token_node();
  1450. int same(node *);
  1451. const char *type();
  1452. int force_tprint();
  1453. int is_tag();
  1454. };
  1455. token_node::token_node(const token &t) : tk(t)
  1456. {
  1457. }
  1458. node *token_node::copy()
  1459. {
  1460. return new token_node(tk);
  1461. }
  1462. token_node *token_node::get_token_node()
  1463. {
  1464. return this;
  1465. }
  1466. int token_node::same(node *nd)
  1467. {
  1468. return tk == ((token_node *)nd)->tk;
  1469. }
  1470. const char *token_node::type()
  1471. {
  1472. return "token_node";
  1473. }
  1474. int token_node::force_tprint()
  1475. {
  1476. return 0;
  1477. }
  1478. int token_node::is_tag()
  1479. {
  1480. return 0;
  1481. }
  1482. token::token() : nd(0), type(TOKEN_EMPTY)
  1483. {
  1484. }
  1485. token::~token()
  1486. {
  1487. delete nd;
  1488. }
  1489. token::token(const token &t)
  1490. : nm(t.nm), c(t.c), val(t.val), dim(t.dim), type(t.type)
  1491. {
  1492. // Use two statements to work around bug in SGI C++.
  1493. node *tem = t.nd;
  1494. nd = tem ? tem->copy() : 0;
  1495. }
  1496. void token::operator=(const token &t)
  1497. {
  1498. delete nd;
  1499. nm = t.nm;
  1500. // Use two statements to work around bug in SGI C++.
  1501. node *tem = t.nd;
  1502. nd = tem ? tem->copy() : 0;
  1503. c = t.c;
  1504. val = t.val;
  1505. dim = t.dim;
  1506. type = t.type;
  1507. }
  1508. void token::skip()
  1509. {
  1510. while (space())
  1511. next();
  1512. }
  1513. int has_arg()
  1514. {
  1515. while (tok.space())
  1516. tok.next();
  1517. return !tok.newline();
  1518. }
  1519. void token::make_space()
  1520. {
  1521. type = TOKEN_SPACE;
  1522. }
  1523. void token::make_newline()
  1524. {
  1525. type = TOKEN_NEWLINE;
  1526. }
  1527. void token::next()
  1528. {
  1529. if (nd) {
  1530. delete nd;
  1531. nd = 0;
  1532. }
  1533. units x;
  1534. for (;;) {
  1535. node *n = 0;
  1536. int cc = input_stack::get(&n);
  1537. if (cc != escape_char || escape_char == 0) {
  1538. handle_normal_char:
  1539. switch(cc) {
  1540. case PUSH_GROFF_MODE:
  1541. input_stack::save_compatible_flag(compatible_flag);
  1542. compatible_flag = 0;
  1543. continue;
  1544. case PUSH_COMP_MODE:
  1545. input_stack::save_compatible_flag(compatible_flag);
  1546. compatible_flag = 1;
  1547. continue;
  1548. case POP_GROFFCOMP_MODE:
  1549. compatible_flag = input_stack::get_compatible_flag();
  1550. continue;
  1551. case BEGIN_QUOTE:
  1552. input_stack::increase_level();
  1553. continue;
  1554. case END_QUOTE:
  1555. input_stack::decrease_level();
  1556. continue;
  1557. case EOF:
  1558. type = TOKEN_EOF;
  1559. return;
  1560. case TRANSPARENT_FILE_REQUEST:
  1561. case TITLE_REQUEST:
  1562. case COPY_FILE_REQUEST:
  1563. #ifdef COLUMN
  1564. case VJUSTIFY_REQUEST:
  1565. #endif /* COLUMN */
  1566. type = TOKEN_REQUEST;
  1567. c = cc;
  1568. return;
  1569. case BEGIN_TRAP:
  1570. type = TOKEN_BEGIN_TRAP;
  1571. return;
  1572. case END_TRAP:
  1573. type = TOKEN_END_TRAP;
  1574. return;
  1575. case LAST_PAGE_EJECTOR:
  1576. seen_last_page_ejector = 1;
  1577. // fall through
  1578. case PAGE_EJECTOR:
  1579. type = TOKEN_PAGE_EJECTOR;
  1580. return;
  1581. case ESCAPE_PERCENT:
  1582. ESCAPE_PERCENT:
  1583. type = TOKEN_HYPHEN_INDICATOR;
  1584. return;
  1585. case ESCAPE_SPACE:
  1586. ESCAPE_SPACE:
  1587. type = TOKEN_UNSTRETCHABLE_SPACE;
  1588. return;
  1589. case ESCAPE_TILDE:
  1590. ESCAPE_TILDE:
  1591. type = TOKEN_STRETCHABLE_SPACE;
  1592. return;
  1593. case ESCAPE_COLON:
  1594. ESCAPE_COLON:
  1595. type = TOKEN_ZERO_WIDTH_BREAK;
  1596. return;
  1597. case ESCAPE_e:
  1598. ESCAPE_e:
  1599. type = TOKEN_ESCAPE;
  1600. return;
  1601. case ESCAPE_E:
  1602. goto handle_escape_char;
  1603. case ESCAPE_BAR:
  1604. ESCAPE_BAR:
  1605. type = TOKEN_NODE;
  1606. nd = new hmotion_node(curenv->get_narrow_space_width(),
  1607. curenv->get_fill_color());
  1608. return;
  1609. case ESCAPE_CIRCUMFLEX:
  1610. ESCAPE_CIRCUMFLEX:
  1611. type = TOKEN_NODE;
  1612. nd = new hmotion_node(curenv->get_half_narrow_space_width(),
  1613. curenv->get_fill_color());
  1614. return;
  1615. case ESCAPE_NEWLINE:
  1616. have_input = 0;
  1617. break;
  1618. case ESCAPE_LEFT_BRACE:
  1619. ESCAPE_LEFT_BRACE:
  1620. type = TOKEN_LEFT_BRACE;
  1621. return;
  1622. case ESCAPE_RIGHT_BRACE:
  1623. ESCAPE_RIGHT_BRACE:
  1624. type = TOKEN_RIGHT_BRACE;
  1625. return;
  1626. case ESCAPE_LEFT_QUOTE:
  1627. ESCAPE_LEFT_QUOTE:
  1628. type = TOKEN_SPECIAL;
  1629. nm = symbol("ga");
  1630. return;
  1631. case ESCAPE_RIGHT_QUOTE:
  1632. ESCAPE_RIGHT_QUOTE:
  1633. type = TOKEN_SPECIAL;
  1634. nm = symbol("aa");
  1635. return;
  1636. case ESCAPE_HYPHEN:
  1637. ESCAPE_HYPHEN:
  1638. type = TOKEN_SPECIAL;
  1639. nm = symbol("-");
  1640. return;
  1641. case ESCAPE_UNDERSCORE:
  1642. ESCAPE_UNDERSCORE:
  1643. type = TOKEN_SPECIAL;
  1644. nm = symbol("ul");
  1645. return;
  1646. case ESCAPE_c:
  1647. ESCAPE_c:
  1648. type = TOKEN_INTERRUPT;
  1649. return;
  1650. case ESCAPE_BANG:
  1651. ESCAPE_BANG:
  1652. type = TOKEN_TRANSPARENT;
  1653. return;
  1654. case ESCAPE_QUESTION:
  1655. ESCAPE_QUESTION:
  1656. nd = do_non_interpreted();
  1657. if (nd) {
  1658. type = TOKEN_NODE;
  1659. return;
  1660. }
  1661. break;
  1662. case ESCAPE_AMPERSAND:
  1663. ESCAPE_AMPERSAND:
  1664. type = TOKEN_DUMMY;
  1665. return;
  1666. case ESCAPE_RIGHT_PARENTHESIS:
  1667. ESCAPE_RIGHT_PARENTHESIS:
  1668. type = TOKEN_TRANSPARENT_DUMMY;
  1669. return;
  1670. case '\b':
  1671. type = TOKEN_BACKSPACE;
  1672. return;
  1673. case ' ':
  1674. type = TOKEN_SPACE;
  1675. return;
  1676. case '\t':
  1677. type = TOKEN_TAB;
  1678. return;
  1679. case '\n':
  1680. type = TOKEN_NEWLINE;
  1681. return;
  1682. case '\001':
  1683. type = TOKEN_LEADER;
  1684. return;
  1685. case 0:
  1686. {
  1687. assert(n != 0);
  1688. token_node *tn = n->get_token_node();
  1689. if (tn) {
  1690. *this = tn->tk;
  1691. delete tn;
  1692. }
  1693. else {
  1694. nd = n;
  1695. type = TOKEN_NODE;
  1696. }
  1697. }
  1698. return;
  1699. default:
  1700. type = TOKEN_CHAR;
  1701. c = cc;
  1702. return;
  1703. }
  1704. }
  1705. else {
  1706. handle_escape_char:
  1707. cc = input_stack::get(&n);
  1708. switch(cc) {
  1709. case '(':
  1710. nm = read_two_char_escape_name();
  1711. type = TOKEN_SPECIAL;
  1712. return;
  1713. case EOF:
  1714. type = TOKEN_EOF;
  1715. error("end of input after escape character");
  1716. return;
  1717. case '`':
  1718. goto ESCAPE_LEFT_QUOTE;
  1719. case '\'':
  1720. goto ESCAPE_RIGHT_QUOTE;
  1721. case '-':
  1722. goto ESCAPE_HYPHEN;
  1723. case '_':
  1724. goto ESCAPE_UNDERSCORE;
  1725. case '%':
  1726. goto ESCAPE_PERCENT;
  1727. case ' ':
  1728. goto ESCAPE_SPACE;
  1729. case '0':
  1730. nd = new hmotion_node(curenv->get_digit_width(),
  1731. curenv->get_fill_color());
  1732. type = TOKEN_NODE;
  1733. return;
  1734. case '|':
  1735. goto ESCAPE_BAR;
  1736. case '^':
  1737. goto ESCAPE_CIRCUMFLEX;
  1738. case '/':
  1739. type = TOKEN_ITALIC_CORRECTION;
  1740. return;
  1741. case ',':
  1742. type = TOKEN_NODE;
  1743. nd = new left_italic_corrected_node;
  1744. return;
  1745. case '&':
  1746. goto ESCAPE_AMPERSAND;
  1747. case ')':
  1748. goto ESCAPE_RIGHT_PARENTHESIS;
  1749. case '!':
  1750. goto ESCAPE_BANG;
  1751. case '?':
  1752. goto ESCAPE_QUESTION;
  1753. case '~':
  1754. goto ESCAPE_TILDE;
  1755. case ':':
  1756. goto ESCAPE_COLON;
  1757. case '"':
  1758. while ((cc = input_stack::get(0)) != '\n' && cc != EOF)
  1759. ;
  1760. if (cc == '\n')
  1761. type = TOKEN_NEWLINE;
  1762. else
  1763. type = TOKEN_EOF;
  1764. return;
  1765. case '#': // Like \" but newline is ignored.
  1766. while ((cc = input_stack::get(0)) != '\n')
  1767. if (cc == EOF) {
  1768. type = TOKEN_EOF;
  1769. return;
  1770. }
  1771. break;
  1772. case '$':
  1773. {
  1774. symbol s = read_escape_name();
  1775. if (!(s.is_null() || s.is_empty()))
  1776. interpolate_arg(s);
  1777. break;
  1778. }
  1779. case '*':
  1780. {
  1781. symbol s = read_escape_name(WITH_ARGS);
  1782. if (!(s.is_null() || s.is_empty())) {
  1783. if (have_string_arg) {
  1784. have_string_arg = 0;
  1785. interpolate_string_with_args(s);
  1786. }
  1787. else
  1788. interpolate_string(s);
  1789. }
  1790. break;
  1791. }
  1792. case 'a':
  1793. nd = new non_interpreted_char_node('\001');
  1794. type = TOKEN_NODE;
  1795. return;
  1796. case 'A':
  1797. c = '0' + do_name_test();
  1798. type = TOKEN_CHAR;
  1799. return;
  1800. case 'b':
  1801. nd = do_bracket();
  1802. type = TOKEN_NODE;
  1803. return;
  1804. case 'B':
  1805. c = '0' + do_expr_test();
  1806. type = TOKEN_CHAR;
  1807. return;
  1808. case 'c':
  1809. goto ESCAPE_c;
  1810. case 'C':
  1811. nm = get_delim_name();
  1812. if (nm.is_null())
  1813. break;
  1814. type = TOKEN_SPECIAL;
  1815. return;
  1816. case 'd':
  1817. type = TOKEN_NODE;
  1818. nd = new vmotion_node(curenv->get_size() / 2,
  1819. curenv->get_fill_color());
  1820. return;
  1821. case 'D':
  1822. nd = read_draw_node();
  1823. if (!nd)
  1824. break;
  1825. type = TOKEN_NODE;
  1826. return;
  1827. case 'e':
  1828. goto ESCAPE_e;
  1829. case 'E':
  1830. goto handle_escape_char;
  1831. case 'f':
  1832. {
  1833. symbol s = read_escape_name(ALLOW_EMPTY);
  1834. if (s.is_null())
  1835. break;
  1836. const char *p;
  1837. for (p = s.contents(); *p != '\0'; p++)
  1838. if (!csdigit(*p))
  1839. break;
  1840. if (*p || s.is_empty())
  1841. curenv->set_font(s);
  1842. else
  1843. curenv->set_font(atoi(s.contents()));
  1844. if (!compatible_flag)
  1845. have_input = 1;
  1846. break;
  1847. }
  1848. case 'F':
  1849. {
  1850. symbol s = read_escape_name(ALLOW_EMPTY);
  1851. if (s.is_null())
  1852. break;
  1853. curenv->set_family(s);
  1854. have_input = 1;
  1855. break;
  1856. }
  1857. case 'g':
  1858. {
  1859. symbol s = read_escape_name();
  1860. if (!(s.is_null() || s.is_empty()))
  1861. interpolate_number_format(s);
  1862. break;
  1863. }
  1864. case 'h':
  1865. if (!get_delim_number(&x, 'm'))
  1866. break;
  1867. type = TOKEN_NODE;
  1868. nd = new hmotion_node(x, curenv->get_fill_color());
  1869. return;
  1870. case 'H':
  1871. // don't take height increments relative to previous height if
  1872. // in compatibility mode
  1873. if (!compatible_flag && curenv->get_char_height())
  1874. {
  1875. if (get_delim_number(&x, 'z', curenv->get_char_height()))
  1876. curenv->set_char_height(x);
  1877. }
  1878. else
  1879. {
  1880. if (get_delim_number(&x, 'z', curenv->get_requested_point_size()))
  1881. curenv->set_char_height(x);
  1882. }
  1883. if (!compatible_flag)
  1884. have_input = 1;
  1885. break;
  1886. case 'k':
  1887. nm = read_escape_name();
  1888. if (nm.is_null() || nm.is_empty())
  1889. break;
  1890. type = TOKEN_MARK_INPUT;
  1891. return;
  1892. case 'l':
  1893. case 'L':
  1894. {
  1895. charinfo *s = 0;
  1896. if (!get_line_arg(&x, (cc == 'l' ? 'm': 'v'), &s))
  1897. break;
  1898. if (s == 0)
  1899. s = get_charinfo(cc == 'l' ? "ru" : "br");
  1900. type = TOKEN_NODE;
  1901. node *char_node = curenv->make_char_node(s);
  1902. if (cc == 'l')
  1903. nd = new hline_node(x, char_node);
  1904. else
  1905. nd = new vline_node(x, char_node);
  1906. return;
  1907. }
  1908. case 'm':
  1909. do_glyph_color(read_escape_name(ALLOW_EMPTY));
  1910. if (!compatible_flag)
  1911. have_input = 1;
  1912. break;
  1913. case 'M':
  1914. do_fill_color(read_escape_name(ALLOW_EMPTY));
  1915. if (!compatible_flag)
  1916. have_input = 1;
  1917. break;
  1918. case 'n':
  1919. {
  1920. int inc;
  1921. symbol s = read_increment_and_escape_name(&inc);
  1922. if (!(s.is_null() || s.is_empty()))
  1923. interpolate_number_reg(s, inc);
  1924. break;
  1925. }
  1926. case 'N':
  1927. if (!get_delim_number(&val, 0))
  1928. break;
  1929. type = TOKEN_NUMBERED_CHAR;
  1930. return;
  1931. case 'o':
  1932. nd = do_overstrike();
  1933. type = TOKEN_NODE;
  1934. return;
  1935. case 'O':
  1936. nd = do_suppress(read_escape_name());
  1937. if (!nd)
  1938. break;
  1939. type = TOKEN_NODE;
  1940. return;
  1941. case 'p':
  1942. type = TOKEN_SPREAD;
  1943. return;
  1944. case 'r':
  1945. type = TOKEN_NODE;
  1946. nd = new vmotion_node(-curenv->get_size(), curenv->get_fill_color());
  1947. return;
  1948. case 'R':
  1949. do_register();
  1950. if (!compatible_flag)
  1951. have_input = 1;
  1952. break;
  1953. case 's':
  1954. if (read_size(&x))
  1955. curenv->set_size(x);
  1956. if (!compatible_flag)
  1957. have_input = 1;
  1958. break;
  1959. case 'S':
  1960. if (get_delim_number(&x, 0))
  1961. curenv->set_char_slant(x);
  1962. if (!compatible_flag)
  1963. have_input = 1;
  1964. break;
  1965. case 't':
  1966. type = TOKEN_NODE;
  1967. nd = new non_interpreted_char_node('\t');
  1968. return;
  1969. case 'u':
  1970. type = TOKEN_NODE;
  1971. nd = new vmotion_node(-curenv->get_size() / 2,
  1972. curenv->get_fill_color());
  1973. return;
  1974. case 'v':
  1975. if (!get_delim_number(&x, 'v'))
  1976. break;
  1977. type = TOKEN_NODE;
  1978. nd = new vmotion_node(x, curenv->get_fill_color());
  1979. return;
  1980. case 'V':
  1981. {
  1982. symbol s = read_escape_name();
  1983. if (!(s.is_null() || s.is_empty()))
  1984. interpolate_environment_variable(s);
  1985. break;
  1986. }
  1987. case 'w':
  1988. do_width();
  1989. break;
  1990. case 'x':
  1991. if (!get_delim_number(&x, 'v'))
  1992. break;
  1993. type = TOKEN_NODE;
  1994. nd = new extra_size_node(x);
  1995. return;
  1996. case 'X':
  1997. nd = do_special();
  1998. if (!nd)
  1999. break;
  2000. type = TOKEN_NODE;
  2001. return;
  2002. case 'Y':
  2003. {
  2004. symbol s = read_escape_name();
  2005. if (s.is_null() || s.is_empty())
  2006. break;
  2007. request_or_macro *p = lookup_request(s);
  2008. macro *m = p->to_macro();
  2009. if (!m) {
  2010. error("can't transparently throughput a request");
  2011. break;
  2012. }
  2013. nd = new special_node(*m);
  2014. type = TOKEN_NODE;
  2015. return;
  2016. }
  2017. case 'z':
  2018. {
  2019. next();
  2020. if (type == TOKEN_NODE)
  2021. nd = new zero_width_node(nd);
  2022. else {
  2023. charinfo *ci = get_char(1);
  2024. if (ci == 0)
  2025. break;
  2026. node *gn = curenv->make_char_node(ci);
  2027. if (gn == 0)
  2028. break;
  2029. nd = new zero_width_node(gn);
  2030. type = TOKEN_NODE;
  2031. }
  2032. return;
  2033. }
  2034. case 'Z':
  2035. nd = do_zero_width();
  2036. if (nd == 0)
  2037. break;
  2038. type = TOKEN_NODE;
  2039. return;
  2040. case '{':
  2041. goto ESCAPE_LEFT_BRACE;
  2042. case '}':
  2043. goto ESCAPE_RIGHT_BRACE;
  2044. case '\n':
  2045. break;
  2046. case '[':
  2047. if (!compatible_flag) {
  2048. symbol s = read_long_escape_name(WITH_ARGS);
  2049. if (s.is_null() || s.is_empty())
  2050. break;
  2051. if (have_string_arg) {
  2052. have_string_arg = 0;
  2053. nm = composite_glyph_name(s);
  2054. }
  2055. else {
  2056. const char *gn = check_unicode_name(s.contents());
  2057. if (gn) {
  2058. const char *gn_decomposed = decompose_unicode(gn);
  2059. if (gn_decomposed)
  2060. gn = &gn_decomposed[1];
  2061. const char *groff_gn = unicode_to_glyph_name(gn);
  2062. if (groff_gn)
  2063. nm = symbol(groff_gn);
  2064. else {
  2065. char *buf = new char[strlen(gn) + 1 + 1];
  2066. strcpy(buf, "u");
  2067. strcat(buf, gn);
  2068. nm = symbol(buf);
  2069. a_delete buf;
  2070. }
  2071. }
  2072. else
  2073. nm = symbol(s.contents());
  2074. }
  2075. type = TOKEN_SPECIAL;
  2076. return;
  2077. }
  2078. goto handle_normal_char;
  2079. default:
  2080. if (cc != escape_char && cc != '.')
  2081. warning(WARN_ESCAPE, "escape character ignored before %1",
  2082. input_char_description(cc));
  2083. goto handle_normal_char;
  2084. }
  2085. }
  2086. }
  2087. }
  2088. int token::operator==(const token &t)
  2089. {
  2090. if (type != t.type)
  2091. return 0;
  2092. switch(type) {
  2093. case TOKEN_CHAR:
  2094. return c == t.c;
  2095. case TOKEN_SPECIAL:
  2096. return nm == t.nm;
  2097. case TOKEN_NUMBERED_CHAR:
  2098. return val == t.val;
  2099. default:
  2100. return 1;
  2101. }
  2102. }
  2103. int token::operator!=(const token &t)
  2104. {
  2105. return !(*this == t);
  2106. }
  2107. // is token a suitable delimiter (like ')?
  2108. int token::delimiter(int err)
  2109. {
  2110. switch(type) {
  2111. case TOKEN_CHAR:
  2112. switch(c) {
  2113. case '0':
  2114. case '1':
  2115. case '2':
  2116. case '3':
  2117. case '4':
  2118. case '5':
  2119. case '6':
  2120. case '7':
  2121. case '8':
  2122. case '9':
  2123. case '+':
  2124. case '-':
  2125. case '/':
  2126. case '*':
  2127. case '%':
  2128. case '<':
  2129. case '>':
  2130. case '=':
  2131. case '&':
  2132. case ':':
  2133. case '(':
  2134. case ')':
  2135. case '.':
  2136. if (err)
  2137. error("cannot use character `%1' as a starting delimiter", char(c));
  2138. return 0;
  2139. default:
  2140. return 1;
  2141. }
  2142. case TOKEN_NODE:
  2143. case TOKEN_SPACE:
  2144. case TOKEN_STRETCHABLE_SPACE:
  2145. case TOKEN_UNSTRETCHABLE_SPACE:
  2146. case TOKEN_TAB:
  2147. case TOKEN_NEWLINE:
  2148. if (err)
  2149. error("cannot use %1 as a starting delimiter", description());
  2150. return 0;
  2151. default:
  2152. return 1;
  2153. }
  2154. }
  2155. const char *token::description()
  2156. {
  2157. static char buf[4];
  2158. switch (type) {
  2159. case TOKEN_BACKSPACE:
  2160. return "a backspace character";
  2161. case TOKEN_CHAR:
  2162. buf[0] = '`';
  2163. buf[1] = c;
  2164. buf[2] = '\'';
  2165. buf[3] = '\0';
  2166. return buf;
  2167. case TOKEN_DUMMY:
  2168. return "`\\&'";
  2169. case TOKEN_ESCAPE:
  2170. return "`\\e'";
  2171. case TOKEN_HYPHEN_INDICATOR:
  2172. return "`\\%'";
  2173. case TOKEN_INTERRUPT:
  2174. return "`\\c'";
  2175. case TOKEN_ITALIC_CORRECTION:
  2176. return "`\\/'";
  2177. case TOKEN_LEADER:
  2178. return "a leader character";
  2179. case TOKEN_LEFT_BRACE:
  2180. return "`\\{'";
  2181. case TOKEN_MARK_INPUT:
  2182. return "`\\k'";
  2183. case TOKEN_NEWLINE:
  2184. return "newline";
  2185. case TOKEN_NODE:
  2186. return "a node";
  2187. case TOKEN_NUMBERED_CHAR:
  2188. return "`\\N'";
  2189. case TOKEN_RIGHT_BRACE:
  2190. return "`\…