Adapt src/lib-snprintf (src/libs/snprintf)
[s-roff.git] / src / preproc / eqn / delim.cpp
blob83de720263a4f21cb0fe16a62a7e5e6687bc9410
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2003, 2007
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
6 This file is part of groff.
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. */
22 #include "eqn.h"
23 #include "pbox.h"
25 enum left_or_right_t { LEFT_DELIM = 01, RIGHT_DELIM = 02 };
27 // Small must be none-zero and must exist in each device.
28 // Small will be put in the roman font, others are assumed to be
29 // on the special font (so no font change will be necessary.)
31 struct delimiter {
32 const char *name;
33 int flags;
34 const char *small;
35 const char *chain_format;
36 const char *ext;
37 const char *top;
38 const char *mid;
39 const char *bot;
40 } delim_table[] = {
42 "(", LEFT_DELIM|RIGHT_DELIM, "(", "\\[parenleft%s]",
43 "\\[parenleftex]",
44 "\\[parenlefttp]",
46 "\\[parenleftbt]",
49 ")", LEFT_DELIM|RIGHT_DELIM, ")", "\\[parenright%s]",
50 "\\[parenrightex]",
51 "\\[parenrighttp]",
53 "\\[parenrightbt]",
56 "[", LEFT_DELIM|RIGHT_DELIM, "[", "\\[bracketleft%s]",
57 "\\[bracketleftex]",
58 "\\[bracketlefttp]",
60 "\\[bracketleftbt]",
63 "]", LEFT_DELIM|RIGHT_DELIM, "]", "\\[bracketright%s]",
64 "\\[bracketrightex]",
65 "\\[bracketrighttp]",
67 "\\[bracketrightbt]",
70 "{", LEFT_DELIM|RIGHT_DELIM, "{", "\\[braceleft%s]",
71 "\\[braceleftex]",
72 "\\[bracelefttp]",
73 "\\[braceleftmid]",
74 "\\[braceleftbt]",
77 "}", LEFT_DELIM|RIGHT_DELIM, "}", "\\[braceright%s]",
78 "\\[bracerightex]",
79 "\\[bracerighttp]",
80 "\\[bracerightmid]",
81 "\\[bracerightbt]",
84 "|", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
85 "\\[barex]",
91 "floor", LEFT_DELIM, "\\(lf", "\\[floorleft%s]",
92 "\\[bracketleftex]",
95 "\\[bracketleftbt]",
98 "floor", RIGHT_DELIM, "\\(rf", "\\[floorright%s]",
99 "\\[bracketrightex]",
102 "\\[bracketrightbt]",
105 "ceiling", LEFT_DELIM, "\\(lc", "\\[ceilingleft%s]",
106 "\\[bracketleftex]",
107 "\\[bracketlefttp]",
112 "ceiling", RIGHT_DELIM, "\\(rc", "\\[ceilingright%s]",
113 "\\[bracketrightex]",
114 "\\[bracketrighttp]",
119 "||", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
120 "\\[bardblex]",
126 "<", LEFT_DELIM|RIGHT_DELIM, "\\(la", "\\[angleleft%s]",
133 ">", LEFT_DELIM|RIGHT_DELIM, "\\(ra", "\\[angleright%s]",
140 "uparrow", LEFT_DELIM|RIGHT_DELIM, "\\(ua", "\\[arrowup%s]",
141 "\\[arrowvertex]",
142 "\\[arrowverttp]",
147 "downarrow", LEFT_DELIM|RIGHT_DELIM, "\\(da", "\\[arrowdown%s]",
148 "\\[arrowvertex]",
151 "\\[arrowvertbt]",
154 "updownarrow", LEFT_DELIM|RIGHT_DELIM, "\\(va", "\\[arrowupdown%s]",
155 "\\[arrowvertex]",
156 "\\[arrowverttp]",
158 "\\[arrowvertbt]",
162 const int DELIM_TABLE_SIZE = int(sizeof(delim_table)/sizeof(delim_table[0]));
164 class delim_box : public box {
165 private:
166 char *left;
167 char *right;
168 box *p;
169 public:
170 delim_box(char *, box *, char *);
171 ~delim_box();
172 int compute_metrics(int);
173 void output();
174 void check_tabs(int);
175 void debug_print();
178 box *make_delim_box(char *l, box *pp, char *r)
180 if (l != 0 && *l == '\0') {
181 a_delete l;
182 l = 0;
184 if (r != 0 && *r == '\0') {
185 a_delete r;
186 r = 0;
188 return new delim_box(l, pp, r);
191 delim_box::delim_box(char *l, box *pp, char *r)
192 : left(l), right(r), p(pp)
196 delim_box::~delim_box()
198 a_delete left;
199 a_delete right;
200 delete p;
203 static void build_extensible(const char *ext, const char *top, const char *mid,
204 const char *bot)
206 assert(ext != 0);
207 printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
208 ext);
209 printf(".nr " EXT_HEIGHT_REG " 0\\n[rst]\n");
210 printf(".nr " EXT_DEPTH_REG " 0-\\n[rsb]\n");
211 if (top) {
212 printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
213 ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
214 top);
215 printf(".nr " TOP_HEIGHT_REG " 0\\n[rst]\n");
216 printf(".nr " TOP_DEPTH_REG " 0-\\n[rsb]\n");
218 if (mid) {
219 printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
220 ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
221 mid);
222 printf(".nr " MID_HEIGHT_REG " 0\\n[rst]\n");
223 printf(".nr " MID_DEPTH_REG " 0-\\n[rsb]\n");
225 if (bot) {
226 printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
227 ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
228 bot);
229 printf(".nr " BOT_HEIGHT_REG " 0\\n[rst]\n");
230 printf(".nr " BOT_DEPTH_REG " 0-\\n[rsb]\n");
232 printf(".nr " TOTAL_HEIGHT_REG " 0");
233 if (top)
234 printf("+\\n[" TOP_HEIGHT_REG "]+\\n[" TOP_DEPTH_REG "]");
235 if (bot)
236 printf("+\\n[" BOT_HEIGHT_REG "]+\\n[" BOT_DEPTH_REG "]");
237 if (mid)
238 printf("+\\n[" MID_HEIGHT_REG "]+\\n[" MID_DEPTH_REG "]");
239 printf("\n");
240 // determine how many extensible characters we need
241 printf(".nr " TEMP_REG " \\n[" DELTA_REG "]-\\n[" TOTAL_HEIGHT_REG "]");
242 if (mid)
243 printf("/2");
244 printf(">?0+\\n[" EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "]-1/(\\n["
245 EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "])\n");
247 printf(".nr " TOTAL_HEIGHT_REG " +(\\n[" EXT_HEIGHT_REG "]+\\n["
248 EXT_DEPTH_REG "]*\\n[" TEMP_REG "]");
249 if (mid)
250 printf("*2");
251 printf(")\n");
252 printf(".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
253 "\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG "]u/2u)'\n",
254 axis_height);
255 if (top)
256 printf(".as " DELIM_STRING " \\v'\\n[" TOP_HEIGHT_REG "]u'"
257 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
258 "\\v'\\n[" TOP_DEPTH_REG "]u'\n",
259 top);
261 // this macro appends $2 copies of $3 to string $1
262 printf(".de " REPEAT_APPEND_STRING_MACRO "\n"
263 ".if \\\\$2 \\{.as \\\\$1 \"\\\\$3\n"
264 "." REPEAT_APPEND_STRING_MACRO " \\\\$1 \\\\$2-1 \"\\\\$3\"\n"
265 ".\\}\n"
266 "..\n");
268 printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING " \\n[" TEMP_REG "] "
269 "\\v'\\n[" EXT_HEIGHT_REG "]u'"
270 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
271 "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
272 ext);
274 if (mid) {
275 printf(".as " DELIM_STRING " \\v'\\n[" MID_HEIGHT_REG "]u'"
276 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
277 "\\v'\\n[" MID_DEPTH_REG "]u'\n",
278 mid);
279 printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING
280 " \\n[" TEMP_REG "] "
281 "\\v'\\n[" EXT_HEIGHT_REG "]u'"
282 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
283 "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
284 ext);
286 if (bot)
287 printf(".as " DELIM_STRING " \\v'\\n[" BOT_HEIGHT_REG "]u'"
288 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
289 "\\v'\\n[" BOT_DEPTH_REG "]u'\n",
290 bot);
291 printf(".as " DELIM_STRING " " DELIMITER_CHAR "\n");
294 static void define_extensible_string(char *delim, int uid,
295 left_or_right_t left_or_right)
297 printf(".ds " DELIM_STRING "\n");
298 delimiter *d = delim_table;
299 int delim_len = strlen(delim);
300 int i;
301 for (i = 0; i < DELIM_TABLE_SIZE; i++, d++)
302 if (strncmp(delim, d->name, delim_len) == 0
303 && (left_or_right & d->flags) != 0)
304 break;
305 if (i >= DELIM_TABLE_SIZE) {
306 error("there is no `%1' delimiter", delim);
307 printf(".nr " DELIM_WIDTH_REG " 0\n");
308 return;
311 printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
312 ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
313 "\\v'\\n[rsb]u+\\n[rst]u/2u-%dM'\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
314 ".nr " TOTAL_HEIGHT_REG " \\n[rst]-\\n[rsb]\n"
315 ".if \\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
316 "\\{",
317 current_roman_font, d->small, axis_height,
318 current_roman_font, d->small);
320 char buf[256];
321 sprintf(buf, d->chain_format, "\\\\n[" INDEX_REG "]");
322 printf(".nr " INDEX_REG " 0\n"
323 ".de " TEMP_MACRO "\n"
324 ".ie c%s \\{\\\n"
325 ".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n"
326 ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
327 "\\v'\\\\n[rsb]u+\\\\n[rst]u/2u-%dM'%s" DELIMITER_CHAR "\n"
328 ".nr " TOTAL_HEIGHT_REG " \\\\n[rst]-\\\\n[rsb]\n"
329 ".if \\\\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
330 "\\{.nr " INDEX_REG " +1\n"
331 "." TEMP_MACRO "\n"
332 ".\\}\\}\n"
333 ".el .nr " INDEX_REG " 0-1\n"
334 "..\n"
335 "." TEMP_MACRO "\n",
336 buf, buf, axis_height, buf);
337 if (d->ext) {
338 printf(".if \\n[" INDEX_REG "]<0 \\{.if c%s \\{\\\n", d->ext);
339 build_extensible(d->ext, d->top, d->mid, d->bot);
340 printf(".\\}\\}\n");
342 printf(".\\}\n");
343 printf(".as " DELIM_STRING " \\h'\\n[" DELIM_WIDTH_REG "]u'\n");
344 printf(".nr " WIDTH_FORMAT " +\\n[" DELIM_WIDTH_REG "]\n", uid);
345 printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
346 ">?(\\n[" TOTAL_HEIGHT_REG "]/2+%dM)\n",
347 uid, uid, axis_height);
348 printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
349 ">?(\\n[" TOTAL_HEIGHT_REG "]/2-%dM)\n",
350 uid, uid, axis_height);
353 int delim_box::compute_metrics(int style)
355 int r = p->compute_metrics(style);
356 printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
357 printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
358 printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
359 printf(".nr " DELTA_REG " \\n[" HEIGHT_FORMAT "]-%dM"
360 ">?(\\n[" DEPTH_FORMAT "]+%dM)\n",
361 p->uid, axis_height, p->uid, axis_height);
362 printf(".nr " DELTA_REG " 0\\n[" DELTA_REG "]*%d/500"
363 ">?(\\n[" DELTA_REG "]*2-%dM)\n",
364 delimiter_factor, delimiter_shortfall);
365 if (left) {
366 define_extensible_string(left, uid, LEFT_DELIM);
367 printf(".rn " DELIM_STRING " " LEFT_DELIM_STRING_FORMAT "\n",
368 uid);
369 if (r)
370 printf(".nr " MARK_REG " +\\n[" DELIM_WIDTH_REG "]\n");
372 if (right) {
373 define_extensible_string(right, uid, RIGHT_DELIM);
374 printf(".rn " DELIM_STRING " " RIGHT_DELIM_STRING_FORMAT "\n",
375 uid);
377 return r;
380 void delim_box::output()
382 if (output_format == troff) {
383 if (left)
384 printf("\\*[" LEFT_DELIM_STRING_FORMAT "]", uid);
385 p->output();
386 if (right)
387 printf("\\*[" RIGHT_DELIM_STRING_FORMAT "]", uid);
389 else if (output_format == mathml) {
390 printf("<mrow><mo>%s</mo>", left);
391 p->output();
392 printf("<mo>%s</mo></mrow>", right);
396 void delim_box::check_tabs(int level)
398 p->check_tabs(level);
401 void delim_box::debug_print()
403 fprintf(stderr, "left \"%s\" { ", left ? left : "");
404 p->debug_print();
405 fprintf(stderr, " }");
406 if (right)
407 fprintf(stderr, " right \"%s\"", right);