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

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 612 lines · 493 code · 83 blank · 36 comment · 44 complexity · 9e7e0be193fe0c867656691b77912d71 MD5 · raw file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992, 2002, 2004
  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. #include "eqn.h"
  18. #include "pbox.h"
  19. const char *current_roman_font;
  20. char *gfont = 0;
  21. char *grfont = 0;
  22. char *gbfont = 0;
  23. int gsize = 0;
  24. int script_size_reduction = -1; // negative means reduce by a percentage
  25. int positive_space = -1;
  26. int negative_space = -1;
  27. int minimum_size = 5;
  28. int fat_offset = 4;
  29. int body_height = 85;
  30. int body_depth = 35;
  31. int over_hang = 0;
  32. int accent_width = 31;
  33. int delimiter_factor = 900;
  34. int delimiter_shortfall = 50;
  35. int null_delimiter_space = 12;
  36. int script_space = 5;
  37. int thin_space = 17;
  38. int medium_space = 22;
  39. int thick_space = 28;
  40. int num1 = 70;
  41. int num2 = 40;
  42. // we don't use num3, because we don't have \atop
  43. int denom1 = 70;
  44. int denom2 = 36;
  45. int axis_height = 26; // in 100ths of an em
  46. int sup1 = 42;
  47. int sup2 = 37;
  48. int sup3 = 28;
  49. int default_rule_thickness = 4;
  50. int sub1 = 20;
  51. int sub2 = 23;
  52. int sup_drop = 38;
  53. int sub_drop = 5;
  54. int x_height = 45;
  55. int big_op_spacing1 = 11;
  56. int big_op_spacing2 = 17;
  57. int big_op_spacing3 = 20;
  58. int big_op_spacing4 = 60;
  59. int big_op_spacing5 = 10;
  60. // These are for piles and matrices.
  61. int baseline_sep = 140; // = num1 + denom1
  62. int shift_down = 26; // = axis_height
  63. int column_sep = 100; // = em space
  64. int matrix_side_sep = 17; // = thin space
  65. int nroff = 0; // should we grok ndefine or tdefine?
  66. struct S {
  67. const char *name;
  68. int *ptr;
  69. } param_table[] = {
  70. { "fat_offset", &fat_offset },
  71. { "over_hang", &over_hang },
  72. { "accent_width", &accent_width },
  73. { "delimiter_factor", &delimiter_factor },
  74. { "delimiter_shortfall", &delimiter_shortfall },
  75. { "null_delimiter_space", &null_delimiter_space },
  76. { "script_space", &script_space },
  77. { "thin_space", &thin_space },
  78. { "medium_space", &medium_space },
  79. { "thick_space", &thick_space },
  80. { "num1", &num1 },
  81. { "num2", &num2 },
  82. { "denom1", &denom1 },
  83. { "denom2", &denom2 },
  84. { "axis_height", &axis_height },
  85. { "sup1", &sup1 },
  86. { "sup2", &sup2 },
  87. { "sup3", &sup3 },
  88. { "default_rule_thickness", &default_rule_thickness },
  89. { "sub1", &sub1 },
  90. { "sub2", &sub2 },
  91. { "sup_drop", &sup_drop },
  92. { "sub_drop", &sub_drop },
  93. { "x_height", &x_height },
  94. { "big_op_spacing1", &big_op_spacing1 },
  95. { "big_op_spacing2", &big_op_spacing2 },
  96. { "big_op_spacing3", &big_op_spacing3 },
  97. { "big_op_spacing4", &big_op_spacing4 },
  98. { "big_op_spacing5", &big_op_spacing5 },
  99. { "minimum_size", &minimum_size },
  100. { "baseline_sep", &baseline_sep },
  101. { "shift_down", &shift_down },
  102. { "column_sep", &column_sep },
  103. { "matrix_side_sep", &matrix_side_sep },
  104. { "draw_lines", &draw_flag },
  105. { "body_height", &body_height },
  106. { "body_depth", &body_depth },
  107. { "nroff", &nroff },
  108. { 0, 0 }
  109. };
  110. void set_param(const char *name, int value)
  111. {
  112. for (int i = 0; param_table[i].name != 0; i++)
  113. if (strcmp(param_table[i].name, name) == 0) {
  114. *param_table[i].ptr = value;
  115. return;
  116. }
  117. error("unrecognised parameter `%1'", name);
  118. }
  119. int script_style(int style)
  120. {
  121. return style > SCRIPT_STYLE ? style - 2 : style;
  122. }
  123. int cramped_style(int style)
  124. {
  125. return (style & 1) ? style - 1 : style;
  126. }
  127. void set_space(int n)
  128. {
  129. if (n < 0)
  130. negative_space = -n;
  131. else
  132. positive_space = n;
  133. }
  134. // Return 0 if the specified size is bad.
  135. // The caller is responsible for giving the error message.
  136. int set_gsize(const char *s)
  137. {
  138. const char *p = (*s == '+' || *s == '-') ? s + 1 : s;
  139. char *end;
  140. long n = strtol(p, &end, 10);
  141. if (n <= 0 || *end != '\0' || n > INT_MAX)
  142. return 0;
  143. if (p > s) {
  144. if (!gsize)
  145. gsize = 10;
  146. if (*s == '+') {
  147. if (gsize > INT_MAX - n)
  148. return 0;
  149. gsize += int(n);
  150. }
  151. else {
  152. if (gsize - n <= 0)
  153. return 0;
  154. gsize -= int(n);
  155. }
  156. }
  157. else
  158. gsize = int(n);
  159. return 1;
  160. }
  161. void set_script_reduction(int n)
  162. {
  163. script_size_reduction = n;
  164. }
  165. const char *get_gfont()
  166. {
  167. return gfont ? gfont : "I";
  168. }
  169. const char *get_grfont()
  170. {
  171. return grfont ? grfont : "R";
  172. }
  173. const char *get_gbfont()
  174. {
  175. return gbfont ? gbfont : "B";
  176. }
  177. void set_gfont(const char *s)
  178. {
  179. a_delete gfont;
  180. gfont = strsave(s);
  181. }
  182. void set_grfont(const char *s)
  183. {
  184. a_delete grfont;
  185. grfont = strsave(s);
  186. }
  187. void set_gbfont(const char *s)
  188. {
  189. a_delete gbfont;
  190. gbfont = strsave(s);
  191. }
  192. // this must be precisely 2 characters in length
  193. #define COMPATIBLE_REG "0C"
  194. void start_string()
  195. {
  196. printf(".nr " COMPATIBLE_REG " \\n(.C\n");
  197. printf(".cp 0\n");
  198. printf(".ds " LINE_STRING "\n");
  199. }
  200. void output_string()
  201. {
  202. printf("\\*(" LINE_STRING "\n");
  203. }
  204. void restore_compatibility()
  205. {
  206. printf(".cp \\n(" COMPATIBLE_REG "\n");
  207. }
  208. void do_text(const char *s)
  209. {
  210. printf(".eo\n");
  211. printf(".as " LINE_STRING " \"%s\n", s);
  212. printf(".ec\n");
  213. }
  214. void set_minimum_size(int n)
  215. {
  216. minimum_size = n;
  217. }
  218. void set_script_size()
  219. {
  220. if (minimum_size < 0)
  221. minimum_size = 0;
  222. if (script_size_reduction >= 0)
  223. printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size);
  224. else
  225. printf(".ps (u;\\n[.ps]*7+5/10>?%d)\n", minimum_size);
  226. }
  227. int box::next_uid = 0;
  228. box::box() : spacing_type(ORDINARY_TYPE), uid(next_uid++)
  229. {
  230. }
  231. box::~box()
  232. {
  233. }
  234. void box::top_level()
  235. {
  236. // debug_print();
  237. // putc('\n', stderr);
  238. box *b = this;
  239. printf(".nr " SAVED_FONT_REG " \\n[.f]\n");
  240. printf(".ft\n");
  241. printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n");
  242. printf(".ft %s\n", get_gfont());
  243. printf(".nr " SAVED_SIZE_REG " \\n[.ps]\n");
  244. if (gsize > 0) {
  245. char buf[INT_DIGITS + 1];
  246. sprintf(buf, "%d", gsize);
  247. b = new size_box(strsave(buf), b);
  248. }
  249. current_roman_font = get_grfont();
  250. // This catches tabs used within \Z (which aren't allowed).
  251. b->check_tabs(0);
  252. int r = b->compute_metrics(DISPLAY_STYLE);
  253. printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n");
  254. printf(".ft \\n[" SAVED_FONT_REG "]\n");
  255. printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r);
  256. if (r == FOUND_MARK) {
  257. printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n");
  258. printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid);
  259. }
  260. else if (r == FOUND_LINEUP)
  261. printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
  262. SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n");
  263. else
  264. assert(r == FOUND_NOTHING);
  265. // The problem here is that the argument to \f is read in copy mode,
  266. // so we cannot use \E there; so we hide it in a string instead.
  267. // Another problem is that if we use \R directly, then the space will
  268. // prevent it working in a macro argument.
  269. printf(".ds " SAVE_FONT_STRING " "
  270. "\\R'" SAVED_INLINE_FONT_REG " \\\\n[.f]'"
  271. "\\fP"
  272. "\\R'" SAVED_INLINE_PREV_FONT_REG " \\\\n[.f]'"
  273. "\\R'" SAVED_INLINE_SIZE_REG " \\\\n[.ps]'"
  274. "\\s0"
  275. "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\\\n[.ps]'"
  276. "\n"
  277. ".ds " RESTORE_FONT_STRING " "
  278. "\\f[\\\\n[" SAVED_INLINE_PREV_FONT_REG "]]"
  279. "\\f[\\\\n[" SAVED_INLINE_FONT_REG "]]"
  280. "\\s'\\\\n[" SAVED_INLINE_PREV_SIZE_REG "]u'"
  281. "\\s'\\\\n[" SAVED_INLINE_SIZE_REG "]u'"
  282. "\n");
  283. printf(".as1 " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]");
  284. printf("\\f[%s]", get_gfont());
  285. printf("\\s'\\En[" SAVED_SIZE_REG "]u'");
  286. current_roman_font = get_grfont();
  287. b->output();
  288. printf("\\E*[" RESTORE_FONT_STRING "]\n");
  289. if (r == FOUND_LINEUP)
  290. printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
  291. MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n["
  292. WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n",
  293. b->uid);
  294. b->extra_space();
  295. if (!inline_flag)
  296. printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n["
  297. DEPTH_FORMAT "]u-%dM>?0)\n",
  298. b->uid, body_height, b->uid, body_depth);
  299. delete b;
  300. next_uid = 0;
  301. }
  302. // gpic defines this register so as to make geqn not produce `\x's
  303. #define EQN_NO_EXTRA_SPACE_REG "0x"
  304. void box::extra_space()
  305. {
  306. printf(".if !r" EQN_NO_EXTRA_SPACE_REG " "
  307. ".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
  308. if (positive_space >= 0 || negative_space >= 0) {
  309. if (positive_space > 0)
  310. printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
  311. ".as1 " LINE_STRING " \\x'-%dM'\n", positive_space);
  312. if (negative_space > 0)
  313. printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
  314. ".as1 " LINE_STRING " \\x'%dM'\n", negative_space);
  315. positive_space = negative_space = -1;
  316. }
  317. else {
  318. printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
  319. ".if \\n[" HEIGHT_FORMAT "]>%dM .as1 " LINE_STRING
  320. " \\x'-(\\n[" HEIGHT_FORMAT
  321. "]u-%dM)'\n",
  322. uid, body_height, uid, body_height);
  323. printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
  324. ".if \\n[" DEPTH_FORMAT "]>%dM .as1 " LINE_STRING
  325. " \\x'\\n[" DEPTH_FORMAT
  326. "]u-%dM'\n",
  327. uid, body_depth, uid, body_depth);
  328. }
  329. }
  330. int box::compute_metrics(int)
  331. {
  332. printf(".nr " WIDTH_FORMAT " 0\n", uid);
  333. printf(".nr " HEIGHT_FORMAT " 0\n", uid);
  334. printf(".nr " DEPTH_FORMAT " 0\n", uid);
  335. return FOUND_NOTHING;
  336. }
  337. void box::compute_subscript_kern()
  338. {
  339. printf(".nr " SUB_KERN_FORMAT " 0\n", uid);
  340. }
  341. void box::compute_skew()
  342. {
  343. printf(".nr " SKEW_FORMAT " 0\n", uid);
  344. }
  345. void box::output()
  346. {
  347. }
  348. void box::check_tabs(int)
  349. {
  350. }
  351. int box::is_char()
  352. {
  353. return 0;
  354. }
  355. int box::left_is_italic()
  356. {
  357. return 0;
  358. }
  359. int box::right_is_italic()
  360. {
  361. return 0;
  362. }
  363. void box::hint(unsigned)
  364. {
  365. }
  366. void box::handle_char_type(int, int)
  367. {
  368. }
  369. box_list::box_list(box *pp)
  370. {
  371. p = new box*[10];
  372. for (int i = 0; i < 10; i++)
  373. p[i] = 0;
  374. maxlen = 10;
  375. len = 1;
  376. p[0] = pp;
  377. }
  378. void box_list::append(box *pp)
  379. {
  380. if (len + 1 > maxlen) {
  381. box **oldp = p;
  382. maxlen *= 2;
  383. p = new box*[maxlen];
  384. memcpy(p, oldp, sizeof(box*)*len);
  385. a_delete oldp;
  386. }
  387. p[len++] = pp;
  388. }
  389. box_list::~box_list()
  390. {
  391. for (int i = 0; i < len; i++)
  392. delete p[i];
  393. a_delete p;
  394. }
  395. void box_list::list_check_tabs(int level)
  396. {
  397. for (int i = 0; i < len; i++)
  398. p[i]->check_tabs(level);
  399. }
  400. pointer_box::pointer_box(box *pp) : p(pp)
  401. {
  402. spacing_type = p->spacing_type;
  403. }
  404. pointer_box::~pointer_box()
  405. {
  406. delete p;
  407. }
  408. int pointer_box::compute_metrics(int style)
  409. {
  410. int r = p->compute_metrics(style);
  411. printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
  412. printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
  413. printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
  414. return r;
  415. }
  416. void pointer_box::compute_subscript_kern()
  417. {
  418. p->compute_subscript_kern();
  419. printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid);
  420. }
  421. void pointer_box::compute_skew()
  422. {
  423. p->compute_skew();
  424. printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n",
  425. uid, p->uid);
  426. }
  427. void pointer_box::check_tabs(int level)
  428. {
  429. p->check_tabs(level);
  430. }
  431. int simple_box::compute_metrics(int)
  432. {
  433. printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid);
  434. output();
  435. printf(DELIMITER_CHAR "\n");
  436. printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid);
  437. printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid);
  438. printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid);
  439. printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid);
  440. return FOUND_NOTHING;
  441. }
  442. void simple_box::compute_subscript_kern()
  443. {
  444. // do nothing, we already computed it in do_metrics
  445. }
  446. void simple_box::compute_skew()
  447. {
  448. // do nothing, we already computed it in do_metrics
  449. }
  450. int box::is_simple()
  451. {
  452. return 0;
  453. }
  454. int simple_box::is_simple()
  455. {
  456. return 1;
  457. }
  458. quoted_text_box::quoted_text_box(char *s) : text(s)
  459. {
  460. }
  461. quoted_text_box::~quoted_text_box()
  462. {
  463. a_delete text;
  464. }
  465. void quoted_text_box::output()
  466. {
  467. if (text)
  468. fputs(text, stdout);
  469. }
  470. tab_box::tab_box() : disabled(0)
  471. {
  472. }
  473. // We treat a tab_box as having width 0 for width computations.
  474. void tab_box::output()
  475. {
  476. if (!disabled)
  477. printf("\\t");
  478. }
  479. void tab_box::check_tabs(int level)
  480. {
  481. if (level > 0) {
  482. error("tabs allowed only at outermost level");
  483. disabled = 1;
  484. }
  485. }
  486. space_box::space_box()
  487. {
  488. spacing_type = SUPPRESS_TYPE;
  489. }
  490. void space_box::output()
  491. {
  492. printf("\\h'%dM'", thick_space);
  493. }
  494. half_space_box::half_space_box()
  495. {
  496. spacing_type = SUPPRESS_TYPE;
  497. }
  498. void half_space_box::output()
  499. {
  500. printf("\\h'%dM'", thin_space);
  501. }
  502. void box_list::list_debug_print(const char *sep)
  503. {
  504. p[0]->debug_print();
  505. for (int i = 1; i < len; i++) {
  506. fprintf(stderr, "%s", sep);
  507. p[i]->debug_print();
  508. }
  509. }
  510. void quoted_text_box::debug_print()
  511. {
  512. fprintf(stderr, "\"%s\"", (text ? text : ""));
  513. }
  514. void half_space_box::debug_print()
  515. {
  516. fprintf(stderr, "^");
  517. }
  518. void space_box::debug_print()
  519. {
  520. fprintf(stderr, "~");
  521. }
  522. void tab_box::debug_print()
  523. {
  524. fprintf(stderr, "<tab>");
  525. }