/contrib/groff/src/preproc/eqn/text.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 528 lines · 461 code · 46 blank · 21 comment · 86 complexity · 14e4a7e6b92a8fde86ee57fcbf436354 MD5 · raw file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc.
  3. Written by James Clark (jjc@jclark.com)
  4. This file is part of groff.
  5. groff is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free
  7. Software Foundation; either version 2, or (at your option) any later
  8. version.
  9. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. for more details.
  13. You should have received a copy of the GNU General Public License along
  14. with groff; see the file COPYING. If not, write to the Free Software
  15. Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
  16. #include "eqn.h"
  17. #include "pbox.h"
  18. #include "ptable.h"
  19. class char_box : public simple_box {
  20. unsigned char c;
  21. char next_is_italic;
  22. char prev_is_italic;
  23. public:
  24. char_box(unsigned char);
  25. void debug_print();
  26. void output();
  27. int is_char();
  28. int left_is_italic();
  29. int right_is_italic();
  30. void hint(unsigned);
  31. void handle_char_type(int, int);
  32. };
  33. class special_char_box : public simple_box {
  34. char *s;
  35. public:
  36. special_char_box(const char *);
  37. ~special_char_box();
  38. void output();
  39. void debug_print();
  40. int is_char();
  41. void handle_char_type(int, int);
  42. };
  43. const char *spacing_type_table[] = {
  44. "ordinary",
  45. "operator",
  46. "binary",
  47. "relation",
  48. "opening",
  49. "closing",
  50. "punctuation",
  51. "inner",
  52. "suppress",
  53. 0,
  54. };
  55. const int DIGIT_TYPE = 0;
  56. const int LETTER_TYPE = 1;
  57. const char *font_type_table[] = {
  58. "digit",
  59. "letter",
  60. 0,
  61. };
  62. struct char_info {
  63. int spacing_type;
  64. int font_type;
  65. char_info();
  66. };
  67. char_info::char_info()
  68. : spacing_type(ORDINARY_TYPE), font_type(DIGIT_TYPE)
  69. {
  70. }
  71. static char_info char_table[256];
  72. declare_ptable(char_info)
  73. implement_ptable(char_info)
  74. PTABLE(char_info) special_char_table;
  75. static int get_special_char_spacing_type(const char *ch)
  76. {
  77. char_info *p = special_char_table.lookup(ch);
  78. return p ? p->spacing_type : ORDINARY_TYPE;
  79. }
  80. static int get_special_char_font_type(const char *ch)
  81. {
  82. char_info *p = special_char_table.lookup(ch);
  83. return p ? p->font_type : DIGIT_TYPE;
  84. }
  85. static void set_special_char_type(const char *ch, int st, int ft)
  86. {
  87. char_info *p = special_char_table.lookup(ch);
  88. if (!p) {
  89. p = new char_info[1];
  90. special_char_table.define(ch, p);
  91. }
  92. if (st >= 0)
  93. p->spacing_type = st;
  94. if (ft >= 0)
  95. p->font_type = ft;
  96. }
  97. void init_char_table()
  98. {
  99. set_special_char_type("pl", 2, -1); // binary
  100. set_special_char_type("mi", 2, -1);
  101. set_special_char_type("eq", 3, -1); // relation
  102. set_special_char_type("<=", 3, -1);
  103. set_special_char_type(">=", 3, -1);
  104. char_table['}'].spacing_type = 5; // closing
  105. char_table[')'].spacing_type = 5;
  106. char_table[']'].spacing_type = 5;
  107. char_table['{'].spacing_type = 4; // opening
  108. char_table['('].spacing_type = 4;
  109. char_table['['].spacing_type = 4;
  110. char_table[','].spacing_type = 6; // punctuation
  111. char_table[';'].spacing_type = 6;
  112. char_table[':'].spacing_type = 6;
  113. char_table['.'].spacing_type = 6;
  114. char_table['>'].spacing_type = 3;
  115. char_table['<'].spacing_type = 3;
  116. char_table['*'].spacing_type = 2; // binary
  117. for (int i = 0; i < 256; i++)
  118. if (csalpha(i))
  119. char_table[i].font_type = LETTER_TYPE;
  120. }
  121. static int lookup_spacing_type(const char *type)
  122. {
  123. for (int i = 0; spacing_type_table[i] != 0; i++)
  124. if (strcmp(spacing_type_table[i], type) == 0)
  125. return i;
  126. return -1;
  127. }
  128. static int lookup_font_type(const char *type)
  129. {
  130. for (int i = 0; font_type_table[i] != 0; i++)
  131. if (strcmp(font_type_table[i], type) == 0)
  132. return i;
  133. return -1;
  134. }
  135. void box::set_spacing_type(char *type)
  136. {
  137. int t = lookup_spacing_type(type);
  138. if (t < 0)
  139. error("unrecognised type `%1'", type);
  140. else
  141. spacing_type = t;
  142. a_delete type;
  143. }
  144. char_box::char_box(unsigned char cc)
  145. : c(cc), next_is_italic(0), prev_is_italic(0)
  146. {
  147. spacing_type = char_table[c].spacing_type;
  148. }
  149. void char_box::hint(unsigned flags)
  150. {
  151. if (flags & HINT_PREV_IS_ITALIC)
  152. prev_is_italic = 1;
  153. if (flags & HINT_NEXT_IS_ITALIC)
  154. next_is_italic = 1;
  155. }
  156. void char_box::output()
  157. {
  158. int font_type = char_table[c].font_type;
  159. if (font_type != LETTER_TYPE)
  160. printf("\\f[%s]", current_roman_font);
  161. if (!prev_is_italic)
  162. fputs("\\,", stdout);
  163. if (c == '\\')
  164. fputs("\\e", stdout);
  165. else
  166. putchar(c);
  167. if (!next_is_italic)
  168. fputs("\\/", stdout);
  169. else
  170. fputs("\\&", stdout); // suppress ligaturing and kerning
  171. if (font_type != LETTER_TYPE)
  172. fputs("\\fP", stdout);
  173. }
  174. int char_box::left_is_italic()
  175. {
  176. int font_type = char_table[c].font_type;
  177. return font_type == LETTER_TYPE;
  178. }
  179. int char_box::right_is_italic()
  180. {
  181. int font_type = char_table[c].font_type;
  182. return font_type == LETTER_TYPE;
  183. }
  184. int char_box::is_char()
  185. {
  186. return 1;
  187. }
  188. void char_box::debug_print()
  189. {
  190. if (c == '\\') {
  191. putc('\\', stderr);
  192. putc('\\', stderr);
  193. }
  194. else
  195. putc(c, stderr);
  196. }
  197. special_char_box::special_char_box(const char *t)
  198. {
  199. s = strsave(t);
  200. spacing_type = get_special_char_spacing_type(s);
  201. }
  202. special_char_box::~special_char_box()
  203. {
  204. a_delete s;
  205. }
  206. void special_char_box::output()
  207. {
  208. int font_type = get_special_char_font_type(s);
  209. if (font_type != LETTER_TYPE)
  210. printf("\\f[%s]", current_roman_font);
  211. printf("\\,\\[%s]\\/", s);
  212. if (font_type != LETTER_TYPE)
  213. printf("\\fP");
  214. }
  215. int special_char_box::is_char()
  216. {
  217. return 1;
  218. }
  219. void special_char_box::debug_print()
  220. {
  221. fprintf(stderr, "\\[%s]", s);
  222. }
  223. void char_box::handle_char_type(int st, int ft)
  224. {
  225. if (st >= 0)
  226. char_table[c].spacing_type = st;
  227. if (ft >= 0)
  228. char_table[c].font_type = ft;
  229. }
  230. void special_char_box::handle_char_type(int st, int ft)
  231. {
  232. set_special_char_type(s, st, ft);
  233. }
  234. void set_char_type(const char *type, char *ch)
  235. {
  236. assert(ch != 0);
  237. int st = lookup_spacing_type(type);
  238. int ft = lookup_font_type(type);
  239. if (st < 0 && ft < 0) {
  240. error("bad character type `%1'", type);
  241. a_delete ch;
  242. return;
  243. }
  244. box *b = split_text(ch);
  245. b->handle_char_type(st, ft);
  246. delete b;
  247. }
  248. /* We give primes special treatment so that in ``x' sub 2'', the ``2''
  249. will be tucked under the prime */
  250. class prime_box : public pointer_box {
  251. box *pb;
  252. public:
  253. prime_box(box *);
  254. ~prime_box();
  255. int compute_metrics(int style);
  256. void output();
  257. void compute_subscript_kern();
  258. void debug_print();
  259. void handle_char_type(int, int);
  260. };
  261. box *make_prime_box(box *pp)
  262. {
  263. return new prime_box(pp);
  264. }
  265. prime_box::prime_box(box *pp) : pointer_box(pp)
  266. {
  267. pb = new special_char_box("fm");
  268. }
  269. prime_box::~prime_box()
  270. {
  271. delete pb;
  272. }
  273. int prime_box::compute_metrics(int style)
  274. {
  275. int res = p->compute_metrics(style);
  276. pb->compute_metrics(style);
  277. printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]"
  278. "+\\n[" WIDTH_FORMAT "]\n",
  279. uid, p->uid, pb->uid);
  280. printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
  281. ">?\\n[" HEIGHT_FORMAT "]\n",
  282. uid, p->uid, pb->uid);
  283. printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
  284. ">?\\n[" DEPTH_FORMAT "]\n",
  285. uid, p->uid, pb->uid);
  286. return res;
  287. }
  288. void prime_box::compute_subscript_kern()
  289. {
  290. p->compute_subscript_kern();
  291. printf(".nr " SUB_KERN_FORMAT " 0\\n[" WIDTH_FORMAT "]"
  292. "+\\n[" SUB_KERN_FORMAT "]>?0\n",
  293. uid, pb->uid, p->uid);
  294. }
  295. void prime_box::output()
  296. {
  297. p->output();
  298. pb->output();
  299. }
  300. void prime_box::handle_char_type(int st, int ft)
  301. {
  302. p->handle_char_type(st, ft);
  303. pb->handle_char_type(st, ft);
  304. }
  305. void prime_box::debug_print()
  306. {
  307. p->debug_print();
  308. putc('\'', stderr);
  309. }
  310. box *split_text(char *text)
  311. {
  312. list_box *lb = 0;
  313. box *fb = 0;
  314. char *s = text;
  315. while (*s != '\0') {
  316. char c = *s++;
  317. box *b = 0;
  318. switch (c) {
  319. case '+':
  320. b = new special_char_box("pl");
  321. break;
  322. case '-':
  323. b = new special_char_box("mi");
  324. break;
  325. case '=':
  326. b = new special_char_box("eq");
  327. break;
  328. case '\'':
  329. b = new special_char_box("fm");
  330. break;
  331. case '<':
  332. if (*s == '=') {
  333. b = new special_char_box("<=");
  334. s++;
  335. break;
  336. }
  337. goto normal_char;
  338. case '>':
  339. if (*s == '=') {
  340. b = new special_char_box(">=");
  341. s++;
  342. break;
  343. }
  344. goto normal_char;
  345. case '\\':
  346. if (*s == '\0') {
  347. lex_error("bad escape");
  348. break;
  349. }
  350. c = *s++;
  351. switch (c) {
  352. case '(':
  353. {
  354. char buf[3];
  355. if (*s != '\0') {
  356. buf[0] = *s++;
  357. if (*s != '\0') {
  358. buf[1] = *s++;
  359. buf[2] = '\0';
  360. b = new special_char_box(buf);
  361. }
  362. else {
  363. lex_error("bad escape");
  364. }
  365. }
  366. else {
  367. lex_error("bad escape");
  368. }
  369. }
  370. break;
  371. case '[':
  372. {
  373. char *ch = s;
  374. while (*s != ']' && *s != '\0')
  375. s++;
  376. if (*s == '\0')
  377. lex_error("bad escape");
  378. else {
  379. *s++ = '\0';
  380. b = new special_char_box(ch);
  381. }
  382. }
  383. break;
  384. case 'f':
  385. case 'g':
  386. case 'k':
  387. case 'n':
  388. case '*':
  389. {
  390. char *escape_start = s - 2;
  391. switch (*s) {
  392. case '(':
  393. if (*++s != '\0')
  394. ++s;
  395. break;
  396. case '[':
  397. for (++s; *s != '\0' && *s != ']'; s++)
  398. ;
  399. break;
  400. }
  401. if (*s == '\0')
  402. lex_error("bad escape");
  403. else {
  404. ++s;
  405. char *buf = new char[s - escape_start + 1];
  406. memcpy(buf, escape_start, s - escape_start);
  407. buf[s - escape_start] = '\0';
  408. b = new quoted_text_box(buf);
  409. }
  410. }
  411. break;
  412. case '-':
  413. case '_':
  414. {
  415. char buf[2];
  416. buf[0] = c;
  417. buf[1] = '\0';
  418. b = new special_char_box(buf);
  419. }
  420. break;
  421. case '`':
  422. b = new special_char_box("ga");
  423. break;
  424. case '\'':
  425. b = new special_char_box("aa");
  426. break;
  427. case 'e':
  428. case '\\':
  429. b = new char_box('\\');
  430. break;
  431. case '^':
  432. case '|':
  433. case '0':
  434. {
  435. char buf[3];
  436. buf[0] = '\\';
  437. buf[1] = c;
  438. buf[2] = '\0';
  439. b = new quoted_text_box(strsave(buf));
  440. break;
  441. }
  442. default:
  443. lex_error("unquoted escape");
  444. b = new quoted_text_box(strsave(s - 2));
  445. s = strchr(s, '\0');
  446. break;
  447. }
  448. break;
  449. default:
  450. normal_char:
  451. b = new char_box(c);
  452. break;
  453. }
  454. while (*s == '\'') {
  455. if (b == 0)
  456. b = new quoted_text_box(0);
  457. b = new prime_box(b);
  458. s++;
  459. }
  460. if (b != 0) {
  461. if (lb != 0)
  462. lb->append(b);
  463. else if (fb != 0) {
  464. lb = new list_box(fb);
  465. lb->append(b);
  466. }
  467. else
  468. fb = b;
  469. }
  470. }
  471. a_delete text;
  472. if (lb != 0)
  473. return lb;
  474. else if (fb != 0)
  475. return fb;
  476. else
  477. return new quoted_text_box(0);
  478. }