Merge branch 'vendor/GCC50'
[dragonfly.git] / contrib / groff / src / preproc / eqn / pile.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2004, 2007, 2009
3    Free Software Foundation, Inc.
4      Written by James Clark (jjc@jclark.com)
5
6 This file is part of groff.
7
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 // piles and matrices
21
22 #include "eqn.h"
23 #include "pbox.h"
24
25 // SUP_RAISE_FORMAT gives the first baseline
26 // BASELINE_SEP_FORMAT gives the separation between baselines
27
28 int pile_box::compute_metrics(int style)
29 {
30   int i;
31   for (i = 0; i < col.len; i++)
32     col.p[i]->compute_metrics(style);
33   printf(".nr " WIDTH_FORMAT " 0", uid);
34   for (i = 0; i < col.len; i++)
35     printf(">?\\n[" WIDTH_FORMAT "]", col.p[i]->uid);
36   printf("\n");
37   printf(".nr " BASELINE_SEP_FORMAT " %dM",
38          uid, baseline_sep+col.space);
39   for (i = 1; i < col.len; i++)
40     printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)",
41            col.p[i-1]->uid, col.p[i]->uid, default_rule_thickness*5);
42   // round it so that it's a multiple of the vertical resolution
43   printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n");
44
45   printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2"
46          "+%dM\n",
47          uid, uid, col.len-1, axis_height - shift_down);
48   printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
49          HEIGHT_FORMAT "]\n",
50          uid, uid, col.p[0]->uid);
51   printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d+\\n["
52          DEPTH_FORMAT "]-\\n[" SUP_RAISE_FORMAT "]\n",
53          uid, uid, col.len-1, col.p[col.len-1]->uid, uid);
54   return FOUND_NOTHING;
55 }
56
57 void pile_box::output()
58 {
59   if (output_format == troff) {
60     int i;
61     printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
62     for (i = 0; i < col.len; i++) {
63       switch (col.align) {
64       case LEFT_ALIGN:
65         break;
66       case CENTER_ALIGN:
67         printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
68                uid, col.p[i]->uid);
69         break;
70       case RIGHT_ALIGN:
71         printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
72                uid, col.p[i]->uid);
73         break;
74       default:
75         assert(0);
76       }
77       col.p[i]->output();
78       printf("\\h'-\\n[" WIDTH_FORMAT "]u'", col.p[i]->uid);
79       switch (col.align) {
80       case LEFT_ALIGN:
81         break;
82       case CENTER_ALIGN:
83         printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
84                col.p[i]->uid, uid);
85         break;
86       case RIGHT_ALIGN:
87         printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
88                col.p[i]->uid, uid);
89         break;
90       default:
91         assert(0);
92       }
93       if (i != col.len - 1)
94         printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid);
95     }
96     printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
97     printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", col.len - 1, uid);
98     printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
99   }
100   else if (output_format == mathml) {
101     const char *av;
102     switch (col.align) {
103     case LEFT_ALIGN:
104       av = "left";
105       break;
106     case RIGHT_ALIGN:
107       av = "right";
108       break;
109     case CENTER_ALIGN:
110       av = "center";
111       break;
112     default:
113       assert(0);
114     }
115     printf("<mtable columnalign='%s'>", av);
116     for (int i = 0; i < col.len; i++) {
117       printf("<mtr><mtd>");
118       col.p[i]->output();
119       printf("</mtd></mtr>");
120     }
121     printf("</mtable>");
122   }
123 }
124
125 pile_box::pile_box(box *pp) : col(pp)
126 {
127 }
128
129 void pile_box::check_tabs(int level)
130 {
131   col.list_check_tabs(level);
132 }
133
134 void pile_box::debug_print()
135 {
136   col.debug_print("pile");
137 }
138
139 int matrix_box::compute_metrics(int style)
140 {
141   int i, j;
142   int max_len = 0;
143   int space = 0;
144   for (i = 0; i < len; i++) {
145     for (j = 0; j < p[i]->len; j++)
146       p[i]->p[j]->compute_metrics(style);
147     if (p[i]->len > max_len)
148       max_len = p[i]->len;
149     if (p[i]->space > space)
150       space = p[i]->space;
151   }
152   for (i = 0; i < len; i++) {
153     printf(".nr " COLUMN_WIDTH_FORMAT " 0", uid, i);
154     for (j = 0; j < p[i]->len; j++)
155       printf(">?\\n[" WIDTH_FORMAT "]", p[i]->p[j]->uid);
156     printf("\n");
157   }
158   printf(".nr " WIDTH_FORMAT " %dM",
159          uid, column_sep*(len-1)+2*matrix_side_sep);
160   for (i = 0; i < len; i++)
161     printf("+\\n[" COLUMN_WIDTH_FORMAT "]", uid, i);
162   printf("\n");
163   printf(".nr " BASELINE_SEP_FORMAT " %dM",
164          uid, baseline_sep+space);
165   for (i = 0; i < len; i++)
166     for (j = 1; j < p[i]->len; j++)
167       printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)",
168            p[i]->p[j-1]->uid, p[i]->p[j]->uid, default_rule_thickness*5);
169   // round it so that it's a multiple of the vertical resolution
170   printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n");
171   printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2"
172          "+%dM\n",
173          uid, uid, max_len-1, axis_height - shift_down);
174   printf(".nr " HEIGHT_FORMAT " 0\\n[" SUP_RAISE_FORMAT "]+(0",
175          uid, uid);
176   for (i = 0; i < len; i++)
177     printf(">?\\n[" HEIGHT_FORMAT "]", p[i]->p[0]->uid);
178   printf(")>?0\n");
179   printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d-\\n["
180          SUP_RAISE_FORMAT "]+(0",
181          uid, uid, max_len-1, uid);
182   for (i = 0; i < len; i++)
183     if (p[i]->len == max_len)
184       printf(">?\\n[" DEPTH_FORMAT "]", p[i]->p[max_len-1]->uid);
185   printf(")>?0\n");
186   return FOUND_NOTHING;
187 }
188
189 void matrix_box::output()
190 {
191   if (output_format == troff) {
192     printf("\\h'%dM'", matrix_side_sep);
193     for (int i = 0; i < len; i++) {
194       int j;
195       printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
196       for (j = 0; j < p[i]->len; j++) {
197         switch (p[i]->align) {
198         case LEFT_ALIGN:
199           break;
200         case CENTER_ALIGN:
201           printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
202                  uid, i, p[i]->p[j]->uid);
203           break;
204         case RIGHT_ALIGN:
205           printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
206                  uid, i, p[i]->p[j]->uid);
207           break;
208         default:
209           assert(0);
210         }
211         p[i]->p[j]->output();
212         printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p[i]->p[j]->uid);
213         switch (p[i]->align) {
214         case LEFT_ALIGN:
215           break;
216         case CENTER_ALIGN:
217           printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u/2u'",
218                  p[i]->p[j]->uid, uid, i);
219           break;
220         case RIGHT_ALIGN:
221           printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u'",
222                  p[i]->p[j]->uid, uid, i);
223           break;
224         default:
225           assert(0);
226         }
227         if (j != p[i]->len - 1)
228           printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid);
229       }
230       printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
231       printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", p[i]->len - 1, uid);
232       printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u'", uid, i);
233       if (i != len - 1)
234         printf("\\h'%dM'", column_sep);
235     }
236     printf("\\h'%dM'", matrix_side_sep);
237   }
238   else if (output_format == mathml) {
239     int n = p[0]->len;  // Each column must have the same number of rows in it
240     printf("<mtable>");
241     for (int i = 0; i < n; i++) {
242       printf("<mtr>");
243       for (int j = 0; j < len; j++) {
244         const char *av;
245         switch (p[j]->align) {
246         case LEFT_ALIGN:
247           av = "left";
248           break;
249         case RIGHT_ALIGN:
250           av = "right";
251           break;
252         case CENTER_ALIGN:
253           av = "center";
254           break;
255         default:
256           assert(0);
257         }
258         printf("<mtd columnalign='%s'>", av);
259         p[j]->p[i]->output();
260         printf("</mtd>");
261       }
262       printf("</mtr>");
263     }
264     printf("</mtable>");
265   }
266 }
267
268 matrix_box::matrix_box(column *pp)
269 {
270   p = new column*[10];
271   for (int i = 0; i < 10; i++)
272     p[i] = 0;
273   maxlen = 10;
274   len = 1;
275   p[0] = pp;
276 }
277
278 matrix_box::~matrix_box()
279 {
280   for (int i = 0; i < len; i++)
281     delete p[i];
282   a_delete p;
283 }
284
285 void matrix_box::append(column *pp)
286 {
287   if (len + 1 > maxlen) {
288     column **oldp = p;
289     maxlen *= 2;
290     p = new column*[maxlen];
291     memcpy(p, oldp, sizeof(column*)*len);
292     a_delete oldp;
293   }
294   p[len++] = pp;
295 }
296
297 void matrix_box::check_tabs(int level)
298 {
299   for (int i = 0; i < len; i++)
300     p[i]->list_check_tabs(level);
301 }
302
303 void matrix_box::debug_print()
304 {
305   fprintf(stderr, "matrix { ");
306   p[0]->debug_print("col");
307   for (int i = 1; i < len; i++) {
308     fprintf(stderr, " ");
309     p[i]->debug_print("col");
310   }
311   fprintf(stderr, " }");
312 }
313
314 column::column(box *pp) : box_list(pp), align(CENTER_ALIGN), space(0)
315 {
316 }
317
318 void column::set_alignment(alignment a)
319 {
320   align = a;
321 }
322
323 void column::set_space(int n)
324 {
325   space = n;
326 }
327
328 void column::debug_print(const char *s)
329 {
330   char c = '\0';                // shut up -Wall
331   switch (align) {
332   case LEFT_ALIGN:
333     c = 'l';
334     break;
335   case RIGHT_ALIGN:
336     c = 'r';
337     break;
338   case CENTER_ALIGN:
339     c = 'c';
340     break;
341   default:
342     assert(0);
343   }
344   fprintf(stderr, "%c%s %d { ", c, s, space);
345   list_debug_print(" above ");
346   fprintf(stderr, " }");
347 }
348