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

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 237 lines · 200 code · 13 blank · 24 comment · 99 complexity · 41d1a4f1e9f3749d73f5fe7c31897ab6 MD5 · raw file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992 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. list_box *box::to_list_box()
  19. {
  20. return 0;
  21. }
  22. list_box *list_box::to_list_box()
  23. {
  24. return this;
  25. }
  26. void list_box::append(box *pp)
  27. {
  28. list_box *q = pp->to_list_box();
  29. if (q == 0)
  30. list.append(pp);
  31. else {
  32. for (int i = 0; i < q->list.len; i++) {
  33. list.append(q->list.p[i]);
  34. q->list.p[i] = 0;
  35. }
  36. q->list.len = 0;
  37. delete q;
  38. }
  39. }
  40. list_box::list_box(box *pp) : list(pp), sty(-1)
  41. {
  42. list_box *q = pp->to_list_box();
  43. if (q != 0) {
  44. // flatten it
  45. list.p[0] = q->list.p[0];
  46. for (int i = 1; i < q->list.len; i++) {
  47. list.append(q->list.p[i]);
  48. q->list.p[i] = 0;
  49. }
  50. q->list.len = 0;
  51. delete q;
  52. }
  53. }
  54. static int compute_spacing(int is_script, int left, int right)
  55. {
  56. if (left == SUPPRESS_TYPE || right == SUPPRESS_TYPE)
  57. return 0;
  58. if (left == PUNCTUATION_TYPE)
  59. return is_script ? 0 : thin_space;
  60. if (left == OPENING_TYPE || right == CLOSING_TYPE)
  61. return 0;
  62. if (right == BINARY_TYPE || left == BINARY_TYPE)
  63. return is_script ? 0 : medium_space;
  64. if (right == RELATION_TYPE) {
  65. if (left == RELATION_TYPE)
  66. return 0;
  67. else
  68. return is_script ? 0 : thick_space;
  69. }
  70. if (left == RELATION_TYPE)
  71. return is_script ? 0 : thick_space;
  72. if (right == OPERATOR_TYPE)
  73. return thin_space;
  74. if (left == INNER_TYPE || right == INNER_TYPE)
  75. return is_script ? 0 : thin_space;
  76. if (left == OPERATOR_TYPE && right == ORDINARY_TYPE)
  77. return thin_space;
  78. return 0;
  79. }
  80. int list_box::compute_metrics(int style)
  81. {
  82. sty = style;
  83. int i;
  84. for (i = 0; i < list.len; i++) {
  85. int t = list.p[i]->spacing_type;
  86. // 5
  87. if (t == BINARY_TYPE) {
  88. int prevt;
  89. if (i == 0
  90. || (prevt = list.p[i-1]->spacing_type) == BINARY_TYPE
  91. || prevt == OPERATOR_TYPE
  92. || prevt == RELATION_TYPE
  93. || prevt == OPENING_TYPE
  94. || prevt == PUNCTUATION_TYPE)
  95. list.p[i]->spacing_type = ORDINARY_TYPE;
  96. }
  97. // 7
  98. else if ((t == RELATION_TYPE || t == CLOSING_TYPE
  99. || t == PUNCTUATION_TYPE)
  100. && i > 0 && list.p[i-1]->spacing_type == BINARY_TYPE)
  101. list.p[i-1]->spacing_type = ORDINARY_TYPE;
  102. }
  103. for (i = 0; i < list.len; i++) {
  104. unsigned flags = 0;
  105. if (i - 1 >= 0 && list.p[i - 1]->right_is_italic())
  106. flags |= HINT_PREV_IS_ITALIC;
  107. if (i + 1 < list.len && list.p[i + 1]->left_is_italic())
  108. flags |= HINT_NEXT_IS_ITALIC;
  109. if (flags)
  110. list.p[i]->hint(flags);
  111. }
  112. is_script = (style <= SCRIPT_STYLE);
  113. int total_spacing = 0;
  114. for (i = 1; i < list.len; i++)
  115. total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
  116. list.p[i]->spacing_type);
  117. int res = 0;
  118. for (i = 0; i < list.len; i++)
  119. if (!list.p[i]->is_simple()) {
  120. int r = list.p[i]->compute_metrics(style);
  121. if (r) {
  122. if (res)
  123. error("multiple marks and lineups");
  124. else {
  125. compute_sublist_width(i);
  126. printf(".nr " MARK_REG " +\\n[" TEMP_REG"]\n");
  127. res = r;
  128. }
  129. }
  130. }
  131. printf(".nr " WIDTH_FORMAT " %dM", uid, total_spacing);
  132. for (i = 0; i < list.len; i++)
  133. if (!list.p[i]->is_simple())
  134. printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
  135. printf("\n");
  136. printf(".nr " HEIGHT_FORMAT " 0", uid);
  137. for (i = 0; i < list.len; i++)
  138. if (!list.p[i]->is_simple())
  139. printf(">?\\n[" HEIGHT_FORMAT "]", list.p[i]->uid);
  140. printf("\n");
  141. printf(".nr " DEPTH_FORMAT " 0", uid);
  142. for (i = 0; i < list.len; i++)
  143. if (!list.p[i]->is_simple())
  144. printf(">?\\n[" DEPTH_FORMAT "]", list.p[i]->uid);
  145. printf("\n");
  146. int have_simple = 0;
  147. for (i = 0; i < list.len && !have_simple; i++)
  148. have_simple = list.p[i]->is_simple();
  149. if (have_simple) {
  150. printf(".nr " WIDTH_FORMAT " +\\w" DELIMITER_CHAR, uid);
  151. for (i = 0; i < list.len; i++)
  152. if (list.p[i]->is_simple())
  153. list.p[i]->output();
  154. printf(DELIMITER_CHAR "\n");
  155. printf(".nr " HEIGHT_FORMAT " \\n[rst]>?\\n[" HEIGHT_FORMAT "]\n",
  156. uid, uid);
  157. printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?\\n[" DEPTH_FORMAT "]\n",
  158. uid, uid);
  159. }
  160. return res;
  161. }
  162. void list_box::compute_sublist_width(int n)
  163. {
  164. int total_spacing = 0;
  165. int i;
  166. for (i = 1; i < n + 1 && i < list.len; i++)
  167. total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
  168. list.p[i]->spacing_type);
  169. printf(".nr " TEMP_REG " %dM", total_spacing);
  170. for (i = 0; i < n; i++)
  171. if (!list.p[i]->is_simple())
  172. printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
  173. int have_simple = 0;
  174. for (i = 0; i < n && !have_simple; i++)
  175. have_simple = list.p[i]->is_simple();
  176. if (have_simple) {
  177. printf("+\\w" DELIMITER_CHAR);
  178. for (i = 0; i < n; i++)
  179. if (list.p[i]->is_simple())
  180. list.p[i]->output();
  181. printf(DELIMITER_CHAR);
  182. }
  183. printf("\n");
  184. }
  185. void list_box::compute_subscript_kern()
  186. {
  187. // We can only call compute_subscript_kern if we have called
  188. // compute_metrics first.
  189. if (list.p[list.len-1]->is_simple())
  190. list.p[list.len-1]->compute_metrics(sty);
  191. list.p[list.len-1]->compute_subscript_kern();
  192. printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n",
  193. uid, list.p[list.len-1]->uid);
  194. }
  195. void list_box::output()
  196. {
  197. for (int i = 0; i < list.len; i++) {
  198. if (i > 0) {
  199. int n = compute_spacing(is_script,
  200. list.p[i-1]->spacing_type,
  201. list.p[i]->spacing_type);
  202. if (n > 0)
  203. printf("\\h'%dM'", n);
  204. }
  205. list.p[i]->output();
  206. }
  207. }
  208. void list_box::handle_char_type(int st, int ft)
  209. {
  210. for (int i = 0; i < list.len; i++)
  211. list.p[i]->handle_char_type(st, ft);
  212. }
  213. void list_box::debug_print()
  214. {
  215. list.list_debug_print(" ");
  216. }
  217. void list_box::check_tabs(int level)
  218. {
  219. list.list_check_tabs(level);
  220. }