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
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
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.
24 #include "eqn-config.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? */
39 const char *chain_format
;
46 "(", LEFT_DELIM
|RIGHT_DELIM
, "(", "\\[parenleft%s]",
53 ")", LEFT_DELIM
|RIGHT_DELIM
, ")", "\\[parenright%s]",
60 "[", LEFT_DELIM
|RIGHT_DELIM
, "[", "\\[bracketleft%s]",
67 "]", LEFT_DELIM
|RIGHT_DELIM
, "]", "\\[bracketright%s]",
74 "{", LEFT_DELIM
|RIGHT_DELIM
, "{", "\\[braceleft%s]",
81 "}", LEFT_DELIM
|RIGHT_DELIM
, "}", "\\[braceright%s]",
88 "|", LEFT_DELIM
|RIGHT_DELIM
, "|", "\\[bar%s]",
95 "floor", LEFT_DELIM
, "\\(lf", "\\[floorleft%s]",
102 "floor", RIGHT_DELIM
, "\\(rf", "\\[floorright%s]",
103 "\\[bracketrightex]",
106 "\\[bracketrightbt]",
109 "ceiling", LEFT_DELIM
, "\\(lc", "\\[ceilingleft%s]",
116 "ceiling", RIGHT_DELIM
, "\\(rc", "\\[ceilingright%s]",
117 "\\[bracketrightex]",
118 "\\[bracketrighttp]",
123 "||", LEFT_DELIM
|RIGHT_DELIM
, "|", "\\[bar%s]",
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]",
151 "downarrow", LEFT_DELIM
|RIGHT_DELIM
, "\\(da", "\\[arrowdown%s]",
158 "updownarrow", LEFT_DELIM
|RIGHT_DELIM
, "\\(va", "\\[arrowupdown%s]",
166 const int DELIM_TABLE_SIZE
= int(NELEM(delim_table
));
176 delim_box(char *, box
*, char *);
178 int compute_metrics(int);
180 void check_tabs(int);
184 box
*make_delim_box(char *l
, box
*pp
, char *r
)
186 if (l
!= 0 && *l
== '\0') {
190 if (r
!= 0 && *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()
209 static void build_extensible(const char *ext
, const char *top
, const char *mid
,
213 printf(".nr " DELIM_WIDTH_REG
" 0\\w" DELIMITER_CHAR
"%s" DELIMITER_CHAR
"\n",
215 printf(".nr " EXT_HEIGHT_REG
" 0\\n[rst]\n");
216 printf(".nr " EXT_DEPTH_REG
" 0-\\n[rsb]\n");
218 printf(".nr " DELIM_WIDTH_REG
" 0\\n[" DELIM_WIDTH_REG
"]"
219 ">?\\w" DELIMITER_CHAR
"%s" DELIMITER_CHAR
"\n",
221 printf(".nr " TOP_HEIGHT_REG
" 0\\n[rst]\n");
222 printf(".nr " TOP_DEPTH_REG
" 0-\\n[rsb]\n");
225 printf(".nr " DELIM_WIDTH_REG
" 0\\n[" DELIM_WIDTH_REG
"]"
226 ">?\\w" DELIMITER_CHAR
"%s" DELIMITER_CHAR
"\n",
228 printf(".nr " MID_HEIGHT_REG
" 0\\n[rst]\n");
229 printf(".nr " MID_DEPTH_REG
" 0-\\n[rsb]\n");
232 printf(".nr " DELIM_WIDTH_REG
" 0\\n[" DELIM_WIDTH_REG
"]"
233 ">?\\w" DELIMITER_CHAR
"%s" DELIMITER_CHAR
"\n",
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");
240 printf("+\\n[" TOP_HEIGHT_REG
"]+\\n[" TOP_DEPTH_REG
"]");
242 printf("+\\n[" BOT_HEIGHT_REG
"]+\\n[" BOT_DEPTH_REG
"]");
244 printf("+\\n[" MID_HEIGHT_REG
"]+\\n[" MID_DEPTH_REG
"]");
246 // determine how many extensible characters we need
247 printf(".nr " TEMP_REG
" \\n[" DELTA_REG
"]-\\n[" TOTAL_HEIGHT_REG
"]");
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
"]");
258 printf(".ds " DELIM_STRING
" \\Z" DELIMITER_CHAR
259 "\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG
"]u/2u)'\n",
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",
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"
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",
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",
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",
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",
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
);
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)
311 if (i
>= DELIM_TABLE_SIZE
) {
312 error("there is no `%1' delimiter", delim
);
313 printf(".nr " DELIM_WIDTH_REG
" 0\n");
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
"] "
323 current_roman_font
, d
->small
, axis_height
,
324 current_roman_font
, d
->small
);
327 sprintf(buf
, d
->chain_format
, "\\\\n[" INDEX_REG
"]");
328 printf(".nr " INDEX_REG
" 0\n"
329 ".de " TEMP_MACRO
"\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"
339 ".el .nr " INDEX_REG
" 0-1\n"
342 buf
, buf
, axis_height
, buf
);
344 printf(".if \\n[" INDEX_REG
"]<0 \\{.if c%s \\{\\\n", d
->ext
);
345 build_extensible(d
->ext
, d
->top
, d
->mid
, d
->bot
);
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
);
372 define_extensible_string(left
, uid
, LEFT_DELIM
);
373 printf(".rn " DELIM_STRING
" " LEFT_DELIM_STRING_FORMAT
"\n",
376 printf(".nr " MARK_REG
" +\\n[" DELIM_WIDTH_REG
"]\n");
379 define_extensible_string(right
, uid
, RIGHT_DELIM
);
380 printf(".rn " DELIM_STRING
" " RIGHT_DELIM_STRING_FORMAT
"\n",
386 void delim_box::output()
388 if (output_format
== troff
) {
390 printf("\\*[" LEFT_DELIM_STRING_FORMAT
"]", uid
);
393 printf("\\*[" RIGHT_DELIM_STRING_FORMAT
"]", uid
);
395 else if (output_format
== mathml
) {
396 printf("<mrow><mo>%s</mo>", left
);
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
: "");
411 fprintf(stderr
, " }");
413 fprintf(stderr
, " right \"%s\"", right
);