Update to groff 1.19.2.
[dragonfly.git] / contrib / groff-1.19 / src / preproc / eqn / list.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3      Written by James Clark (jjc@jclark.com)
4
5 This file is part of groff.
6
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING.  If not, write to the Free Software
19 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
20
21 #include "eqn.h"
22 #include "pbox.h"
23
24 list_box *box::to_list_box()
25 {
26   return 0;
27 }
28
29 list_box *list_box::to_list_box()
30 {
31   return this;
32 }
33
34 void list_box::append(box *pp)
35 {
36   list_box *q = pp->to_list_box();
37   if (q == 0)
38     list.append(pp);
39   else {
40     for (int i = 0; i < q->list.len; i++) {
41       list.append(q->list.p[i]);
42       q->list.p[i] = 0;
43     }
44     q->list.len = 0;
45     delete q;
46   }
47 }
48
49 list_box::list_box(box *pp) : list(pp), sty(-1)
50 {
51   list_box *q = pp->to_list_box();
52   if (q != 0) {
53     // flatten it
54     list.p[0] = q->list.p[0];
55     for (int i = 1; i < q->list.len; i++) {
56       list.append(q->list.p[i]);
57       q->list.p[i] = 0;
58     }
59     q->list.len = 0;
60     delete q;
61   }
62 }
63
64 static int compute_spacing(int is_script, int left, int right)
65 {
66   if (left == SUPPRESS_TYPE || right == SUPPRESS_TYPE)
67     return 0;
68   if (left == PUNCTUATION_TYPE)
69     return is_script ? 0 : thin_space;
70   if (left == OPENING_TYPE || right == CLOSING_TYPE)
71     return 0;
72   if (right == BINARY_TYPE || left == BINARY_TYPE)
73     return is_script ? 0 : medium_space;
74   if (right == RELATION_TYPE) {
75     if (left == RELATION_TYPE)
76       return 0;
77     else
78       return is_script ? 0 : thick_space;
79   }
80   if (left == RELATION_TYPE)
81     return is_script ? 0 : thick_space;
82   if (right == OPERATOR_TYPE)
83     return thin_space;
84   if (left == INNER_TYPE || right == INNER_TYPE)
85     return is_script ? 0 : thin_space;
86   if (left == OPERATOR_TYPE && right == ORDINARY_TYPE)
87     return thin_space;
88   return 0;
89 }
90
91 int list_box::compute_metrics(int style)
92 {
93   sty = style;
94   int i;
95   for (i = 0; i < list.len; i++) {
96     int t = list.p[i]->spacing_type; 
97     // 5
98     if (t == BINARY_TYPE) {
99       int prevt;
100       if (i == 0
101           || (prevt = list.p[i-1]->spacing_type) == BINARY_TYPE
102           || prevt == OPERATOR_TYPE
103           || prevt == RELATION_TYPE
104           || prevt == OPENING_TYPE
105           || prevt == PUNCTUATION_TYPE)
106         list.p[i]->spacing_type = ORDINARY_TYPE;
107     }
108     // 7
109     else if ((t == RELATION_TYPE || t == CLOSING_TYPE 
110               || t == PUNCTUATION_TYPE)
111              && i > 0 && list.p[i-1]->spacing_type == BINARY_TYPE)
112       list.p[i-1]->spacing_type = ORDINARY_TYPE;
113   }
114   for (i = 0; i < list.len; i++) {
115     unsigned flags = 0;
116     if (i - 1 >= 0 && list.p[i - 1]->right_is_italic())
117       flags |= HINT_PREV_IS_ITALIC;
118     if (i + 1 < list.len && list.p[i + 1]->left_is_italic())
119       flags |= HINT_NEXT_IS_ITALIC;
120     if (flags)
121       list.p[i]->hint(flags);
122   }
123   is_script = (style <= SCRIPT_STYLE);
124   int total_spacing = 0;
125   for (i = 1; i < list.len; i++)
126     total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
127                                      list.p[i]->spacing_type);
128   int res = 0;
129   for (i = 0; i < list.len; i++)
130     if (!list.p[i]->is_simple()) {
131       int r = list.p[i]->compute_metrics(style);
132       if (r) {
133         if (res)
134           error("multiple marks and lineups");
135         else {
136           compute_sublist_width(i);
137           printf(".nr " MARK_REG " +\\n[" TEMP_REG"]\n");
138           res = r;
139         }
140       }
141     }
142   printf(".nr " WIDTH_FORMAT " %dM", uid, total_spacing);
143   for (i = 0; i < list.len; i++)
144     if (!list.p[i]->is_simple())
145       printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
146   printf("\n");
147   printf(".nr " HEIGHT_FORMAT " 0", uid);
148   for (i = 0; i < list.len; i++)
149     if (!list.p[i]->is_simple())
150       printf(">?\\n[" HEIGHT_FORMAT "]", list.p[i]->uid);
151   printf("\n");
152   printf(".nr " DEPTH_FORMAT " 0", uid);
153   for (i = 0; i < list.len; i++)
154     if (!list.p[i]->is_simple())
155       printf(">?\\n[" DEPTH_FORMAT "]", list.p[i]->uid);
156   printf("\n");
157   int have_simple = 0;
158   for (i = 0; i < list.len && !have_simple; i++)
159     have_simple = list.p[i]->is_simple();
160   if (have_simple) {
161     printf(".nr " WIDTH_FORMAT " +\\w" DELIMITER_CHAR, uid);
162     for (i = 0; i < list.len; i++)
163       if (list.p[i]->is_simple())
164         list.p[i]->output();
165     printf(DELIMITER_CHAR "\n");
166     printf(".nr " HEIGHT_FORMAT " \\n[rst]>?\\n[" HEIGHT_FORMAT "]\n",
167            uid, uid);
168     printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?\\n[" DEPTH_FORMAT "]\n",
169            uid, uid);
170   }
171   return res;
172 }
173
174 void list_box::compute_sublist_width(int n)
175 {
176   int total_spacing = 0;
177   int i;
178   for (i = 1; i < n + 1 && i < list.len; i++)
179     total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
180                                      list.p[i]->spacing_type);
181   printf(".nr " TEMP_REG " %dM", total_spacing);
182   for (i = 0; i < n; i++)
183     if (!list.p[i]->is_simple())
184       printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
185   int have_simple = 0;
186   for (i = 0; i < n && !have_simple; i++)
187     have_simple = list.p[i]->is_simple();
188   if (have_simple) {
189     printf("+\\w" DELIMITER_CHAR);
190     for (i = 0; i < n; i++)
191       if (list.p[i]->is_simple())
192         list.p[i]->output();
193     printf(DELIMITER_CHAR);
194   }
195   printf("\n");
196 }
197
198 void list_box::compute_subscript_kern()
199 {
200   // We can only call compute_subscript_kern if we have called
201   // compute_metrics first.
202   if (list.p[list.len-1]->is_simple())
203     list.p[list.len-1]->compute_metrics(sty);
204   list.p[list.len-1]->compute_subscript_kern();
205   printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n",
206          uid, list.p[list.len-1]->uid);
207 }
208
209 void list_box::output()
210 {
211   for (int i = 0; i < list.len; i++) {
212     if (i > 0) {
213       int n = compute_spacing(is_script,
214                               list.p[i-1]->spacing_type,
215                               list.p[i]->spacing_type);
216       if (n > 0)
217         printf("\\h'%dM'", n);
218     }
219     list.p[i]->output();
220   }
221 }
222
223 void list_box::handle_char_type(int st, int ft)
224 {
225   for (int i = 0; i < list.len; i++)
226     list.p[i]->handle_char_type(st, ft);
227 }
228
229 void list_box::debug_print()
230 {
231   list.list_debug_print(" ");
232 }
233
234 void list_box::check_tabs(int level)
235 {
236   list.list_check_tabs(level);
237 }