Adapt src/pre-eqn (src/preproc/eqn)
[s-roff.git] / src / pre-eqn / delim.cpp
blob4a56ecc97fa70ba2d120f728ca52e751c310aa66
1 /*@
2 * Copyright (c) 2014 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 1989 - 1992, 2003, 2007
5 * Free Software Foundation, Inc.
6 * Written by James Clark (jjc@jclark.com)
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 2, or (at your option) any later
11 * version.
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.
18 * You should have received a copy of the GNU General Public License along
19 * with groff; see the file COPYING. If not, write to the Free Software
20 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
23 #include "config.h"
24 #include "eqn-config.h"
26 #include "eqn.h"
27 #include "pbox.h"
29 enum left_or_right_t { LEFT_DELIM = 01, RIGHT_DELIM = 02 };
31 // Small must be none-zero and must exist in each device.
32 // Small will be put in the roman font, others are assumed to be
33 // on the special font (so no font change will be necessary.)
35 struct delimiter { /* FIXME const? */
36 const char *name;
37 int flags;
38 const char *small;
39 const char *chain_format;
40 const char *ext;
41 const char *top;
42 const char *mid;
43 const char *bot;
44 } delim_table[] = {
46 "(", LEFT_DELIM|RIGHT_DELIM, "(", "\\[parenleft%s]",
47 "\\[parenleftex]",
48 "\\[parenlefttp]",
50 "\\[parenleftbt]",
53 ")", LEFT_DELIM|RIGHT_DELIM, ")", "\\[parenright%s]",
54 "\\[parenrightex]",
55 "\\[parenrighttp]",
57 "\\[parenrightbt]",
60 "[", LEFT_DELIM|RIGHT_DELIM, "[", "\\[bracketleft%s]",
61 "\\[bracketleftex]",
62 "\\[bracketlefttp]",
64 "\\[bracketleftbt]",
67 "]", LEFT_DELIM|RIGHT_DELIM, "]", "\\[bracketright%s]",
68 "\\[bracketrightex]",
69 "\\[bracketrighttp]",
71 "\\[bracketrightbt]",
74 "{", LEFT_DELIM|RIGHT_DELIM, "{", "\\[braceleft%s]",
75 "\\[braceleftex]",
76 "\\[bracelefttp]",
77 "\\[braceleftmid]",
78 "\\[braceleftbt]",
81 "}", LEFT_DELIM|RIGHT_DELIM, "}", "\\[braceright%s]",
82 "\\[bracerightex]",
83 "\\[bracerighttp]",
84 "\\[bracerightmid]",
85 "\\[bracerightbt]",
88 "|", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
89 "\\[barex]",
95 "floor", LEFT_DELIM, "\\(lf", "\\[floorleft%s]",
96 "\\[bracketleftex]",
99 "\\[bracketleftbt]",
102 "floor", RIGHT_DELIM, "\\(rf", "\\[floorright%s]",
103 "\\[bracketrightex]",
106 "\\[bracketrightbt]",
109 "ceiling", LEFT_DELIM, "\\(lc", "\\[ceilingleft%s]",
110 "\\[bracketleftex]",
111 "\\[bracketlefttp]",
116 "ceiling", RIGHT_DELIM, "\\(rc", "\\[ceilingright%s]",
117 "\\[bracketrightex]",
118 "\\[bracketrighttp]",
123 "||", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
124 "\\[bardblex]",
130 "<", LEFT_DELIM|RIGHT_DELIM, "\\(la", "\\[angleleft%s]",
137 ">", LEFT_DELIM|RIGHT_DELIM, "\\(ra", "\\[angleright%s]",
144 "uparrow", LEFT_DELIM|RIGHT_DELIM, "\\(ua", "\\[arrowup%s]",
145 "\\[arrowvertex]",
146 "\\[arrowverttp]",
151 "downarrow", LEFT_DELIM|RIGHT_DELIM, "\\(da", "\\[arrowdown%s]",
152 "\\[arrowvertex]",
155 "\\[arrowvertbt]",
158 "updownarrow", LEFT_DELIM|RIGHT_DELIM, "\\(va", "\\[arrowupdown%s]",
159 "\\[arrowvertex]",
160 "\\[arrowverttp]",
162 "\\[arrowvertbt]",
166 const int DELIM_TABLE_SIZE = int(NELEM(delim_table));
168 class delim_box
169 : public box
171 char *left;
172 char *right;
173 box *p;
175 public:
176 delim_box(char *, box *, char *);
177 ~delim_box();
178 int compute_metrics(int);
179 void output();
180 void check_tabs(int);
181 void debug_print();
184 box *make_delim_box(char *l, box *pp, char *r)
186 if (l != 0 && *l == '\0') {
187 a_delete l;
188 l = 0;
190 if (r != 0 && *r == '\0') {
191 a_delete r;
192 r = 0;
194 return new delim_box(l, pp, r);
197 delim_box::delim_box(char *l, box *pp, char *r)
198 : left(l), right(r), p(pp)
202 delim_box::~delim_box()
204 a_delete left;
205 a_delete right;
206 delete p;
209 static void build_extensible(const char *ext, const char *top, const char *mid,
210 const char *bot)
212 assert(ext != 0);
213 printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
214 ext);
215 printf(".nr " EXT_HEIGHT_REG " 0\\n[rst]\n");
216 printf(".nr " EXT_DEPTH_REG " 0-\\n[rsb]\n");
217 if (top) {
218 printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
219 ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
220 top);
221 printf(".nr " TOP_HEIGHT_REG " 0\\n[rst]\n");
222 printf(".nr " TOP_DEPTH_REG " 0-\\n[rsb]\n");
224 if (mid) {
225 printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
226 ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
227 mid);
228 printf(".nr " MID_HEIGHT_REG " 0\\n[rst]\n");
229 printf(".nr " MID_DEPTH_REG " 0-\\n[rsb]\n");
231 if (bot) {
232 printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
233 ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
234 bot);
235 printf(".nr " BOT_HEIGHT_REG " 0\\n[rst]\n");
236 printf(".nr " BOT_DEPTH_REG " 0-\\n[rsb]\n");
238 printf(".nr " TOTAL_HEIGHT_REG " 0");
239 if (top)
240 printf("+\\n[" TOP_HEIGHT_REG "]+\\n[" TOP_DEPTH_REG "]");
241 if (bot)
242 printf("+\\n[" BOT_HEIGHT_REG "]+\\n[" BOT_DEPTH_REG "]");
243 if (mid)
244 printf("+\\n[" MID_HEIGHT_REG "]+\\n[" MID_DEPTH_REG "]");
245 printf("\n");
246 // determine how many extensible characters we need
247 printf(".nr " TEMP_REG " \\n[" DELTA_REG "]-\\n[" TOTAL_HEIGHT_REG "]");
248 if (mid)
249 printf("/2");
250 printf(">?0+\\n[" EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "]-1/(\\n["
251 EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "])\n");
253 printf(".nr " TOTAL_HEIGHT_REG " +(\\n[" EXT_HEIGHT_REG "]+\\n["
254 EXT_DEPTH_REG "]*\\n[" TEMP_REG "]");
255 if (mid)
256 printf("*2");
257 printf(")\n");
258 printf(".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
259 "\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG "]u/2u)'\n",
260 axis_height);
261 if (top)
262 printf(".as " DELIM_STRING " \\v'\\n[" TOP_HEIGHT_REG "]u'"
263 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
264 "\\v'\\n[" TOP_DEPTH_REG "]u'\n",
265 top);
267 // this macro appends $2 copies of $3 to string $1
268 printf(".de " REPEAT_APPEND_STRING_MACRO "\n"
269 ".if \\\\$2 \\{.as \\\\$1 \"\\\\$3\n"
270 "." REPEAT_APPEND_STRING_MACRO " \\\\$1 \\\\$2-1 \"\\\\$3\"\n"
271 ".\\}\n"
272 "..\n");
274 printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING " \\n[" TEMP_REG "] "
275 "\\v'\\n[" EXT_HEIGHT_REG "]u'"
276 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
277 "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
278 ext);
280 if (mid) {
281 printf(".as " DELIM_STRING " \\v'\\n[" MID_HEIGHT_REG "]u'"
282 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
283 "\\v'\\n[" MID_DEPTH_REG "]u'\n",
284 mid);
285 printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING
286 " \\n[" TEMP_REG "] "
287 "\\v'\\n[" EXT_HEIGHT_REG "]u'"
288 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
289 "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
290 ext);
292 if (bot)
293 printf(".as " DELIM_STRING " \\v'\\n[" BOT_HEIGHT_REG "]u'"
294 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
295 "\\v'\\n[" BOT_DEPTH_REG "]u'\n",
296 bot);
297 printf(".as " DELIM_STRING " " DELIMITER_CHAR "\n");
300 static void define_extensible_string(char *delim, int uid,
301 left_or_right_t left_or_right)
303 printf(".ds " DELIM_STRING "\n");
304 delimiter *d = delim_table;
305 int delim_len = strlen(delim);
306 int i;
307 for (i = 0; i < DELIM_TABLE_SIZE; i++, d++)
308 if (strncmp(delim, d->name, delim_len) == 0
309 && (left_or_right & d->flags) != 0)
310 break;
311 if (i >= DELIM_TABLE_SIZE) {
312 error("there is no `%1' delimiter", delim);
313 printf(".nr " DELIM_WIDTH_REG " 0\n");
314 return;
317 printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
318 ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
319 "\\v'\\n[rsb]u+\\n[rst]u/2u-%dM'\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
320 ".nr " TOTAL_HEIGHT_REG " \\n[rst]-\\n[rsb]\n"
321 ".if \\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
322 "\\{",
323 current_roman_font, d->small, axis_height,
324 current_roman_font, d->small);
326 char buf[256];
327 sprintf(buf, d->chain_format, "\\\\n[" INDEX_REG "]");
328 printf(".nr " INDEX_REG " 0\n"
329 ".de " TEMP_MACRO "\n"
330 ".ie c%s \\{\\\n"
331 ".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n"
332 ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
333 "\\v'\\\\n[rsb]u+\\\\n[rst]u/2u-%dM'%s" DELIMITER_CHAR "\n"
334 ".nr " TOTAL_HEIGHT_REG " \\\\n[rst]-\\\\n[rsb]\n"
335 ".if \\\\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
336 "\\{.nr " INDEX_REG " +1\n"
337 "." TEMP_MACRO "\n"
338 ".\\}\\}\n"
339 ".el .nr " INDEX_REG " 0-1\n"
340 "..\n"
341 "." TEMP_MACRO "\n",
342 buf, buf, axis_height, buf);
343 if (d->ext) {
344 printf(".if \\n[" INDEX_REG "]<0 \\{.if c%s \\{\\\n", d->ext);
345 build_extensible(d->ext, d->top, d->mid, d->bot);
346 printf(".\\}\\}\n");
348 printf(".\\}\n");
349 printf(".as " DELIM_STRING " \\h'\\n[" DELIM_WIDTH_REG "]u'\n");
350 printf(".nr " WIDTH_FORMAT " +\\n[" DELIM_WIDTH_REG "]\n", uid);
351 printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
352 ">?(\\n[" TOTAL_HEIGHT_REG "]/2+%dM)\n",
353 uid, uid, axis_height);
354 printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
355 ">?(\\n[" TOTAL_HEIGHT_REG "]/2-%dM)\n",
356 uid, uid, axis_height);
359 int delim_box::compute_metrics(int style)
361 int r = p->compute_metrics(style);
362 printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
363 printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
364 printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
365 printf(".nr " DELTA_REG " \\n[" HEIGHT_FORMAT "]-%dM"
366 ">?(\\n[" DEPTH_FORMAT "]+%dM)\n",
367 p->uid, axis_height, p->uid, axis_height);
368 printf(".nr " DELTA_REG " 0\\n[" DELTA_REG "]*%d/500"
369 ">?(\\n[" DELTA_REG "]*2-%dM)\n",
370 delimiter_factor, delimiter_shortfall);
371 if (left) {
372 define_extensible_string(left, uid, LEFT_DELIM);
373 printf(".rn " DELIM_STRING " " LEFT_DELIM_STRING_FORMAT "\n",
374 uid);
375 if (r)
376 printf(".nr " MARK_REG " +\\n[" DELIM_WIDTH_REG "]\n");
378 if (right) {
379 define_extensible_string(right, uid, RIGHT_DELIM);
380 printf(".rn " DELIM_STRING " " RIGHT_DELIM_STRING_FORMAT "\n",
381 uid);
383 return r;
386 void delim_box::output()
388 if (output_format == troff) {
389 if (left)
390 printf("\\*[" LEFT_DELIM_STRING_FORMAT "]", uid);
391 p->output();
392 if (right)
393 printf("\\*[" RIGHT_DELIM_STRING_FORMAT "]", uid);
395 else if (output_format == mathml) {
396 printf("<mrow><mo>%s</mo>", left);
397 p->output();
398 printf("<mo>%s</mo></mrow>", right);
402 void delim_box::check_tabs(int level)
404 p->check_tabs(level);
407 void delim_box::debug_print()
409 fprintf(stderr, "left \"%s\" { ", left ? left : "");
410 p->debug_print();
411 fprintf(stderr, " }");
412 if (right)
413 fprintf(stderr, " right \"%s\"", right);
416 // s-it2-mode