2 /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
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 3 of the License, or
10 (at your option) any later version.
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
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 const char *current_roman_font;
30 int script_size_reduction = -1; // negative means reduce by a percentage
32 int positive_space = -1;
33 int negative_space = -1;
42 int accent_width = 31;
43 int delimiter_factor = 900;
44 int delimiter_shortfall = 50;
46 int null_delimiter_space = 12;
49 int medium_space = 22;
54 // we don't use num3, because we don't have \atop
57 int axis_height = 26; // in 100ths of an em
61 int default_rule_thickness = 4;
67 int big_op_spacing1 = 11;
68 int big_op_spacing2 = 17;
69 int big_op_spacing3 = 20;
70 int big_op_spacing4 = 60;
71 int big_op_spacing5 = 10;
73 // These are for piles and matrices.
75 int baseline_sep = 140; // = num1 + denom1
76 int shift_down = 26; // = axis_height
77 int column_sep = 100; // = em space
78 int matrix_side_sep = 17; // = thin space
80 int nroff = 0; // should we grok ndefine or tdefine?
86 { "fat_offset", &fat_offset },
87 { "over_hang", &over_hang },
88 { "accent_width", &accent_width },
89 { "delimiter_factor", &delimiter_factor },
90 { "delimiter_shortfall", &delimiter_shortfall },
91 { "null_delimiter_space", &null_delimiter_space },
92 { "script_space", &script_space },
93 { "thin_space", &thin_space },
94 { "medium_space", &medium_space },
95 { "thick_space", &thick_space },
98 { "denom1", &denom1 },
99 { "denom2", &denom2 },
100 { "axis_height", &axis_height },
104 { "default_rule_thickness", &default_rule_thickness },
107 { "sup_drop", &sup_drop },
108 { "sub_drop", &sub_drop },
109 { "x_height", &x_height },
110 { "big_op_spacing1", &big_op_spacing1 },
111 { "big_op_spacing2", &big_op_spacing2 },
112 { "big_op_spacing3", &big_op_spacing3 },
113 { "big_op_spacing4", &big_op_spacing4 },
114 { "big_op_spacing5", &big_op_spacing5 },
115 { "minimum_size", &minimum_size },
116 { "baseline_sep", &baseline_sep },
117 { "shift_down", &shift_down },
118 { "column_sep", &column_sep },
119 { "matrix_side_sep", &matrix_side_sep },
120 { "draw_lines", &draw_flag },
121 { "body_height", &body_height },
122 { "body_depth", &body_depth },
127 void set_param(const char *name, int value)
129 for (int i = 0; param_table[i].name != 0; i++)
130 if (strcmp(param_table[i].name, name) == 0) {
131 *param_table[i].ptr = value;
134 error("unrecognised parameter '%1'", name);
137 int script_style(int style)
139 return style > SCRIPT_STYLE ? style - 2 : style;
142 int cramped_style(int style)
144 return (style & 1) ? style - 1 : style;
147 void set_space(int n)
155 // Return 0 if the specified size is bad.
156 // The caller is responsible for giving the error message.
158 int set_gsize(const char *s)
160 const char *p = (*s == '+' || *s == '-') ? s + 1 : s;
162 long n = strtol(p, &end, 10);
163 if (n <= 0 || *end != '\0' || n > INT_MAX)
169 if (gsize > INT_MAX - n)
184 void set_script_reduction(int n)
186 script_size_reduction = n;
189 const char *get_gfont()
191 return gfont ? gfont : "I";
194 const char *get_grfont()
196 return grfont ? grfont : "R";
199 const char *get_gbfont()
201 return gbfont ? gbfont : "B";
204 void set_gfont(const char *s)
210 void set_grfont(const char *s)
216 void set_gbfont(const char *s)
222 // this must be precisely 2 characters in length
223 #define COMPATIBLE_REG "0C"
227 if (output_format == troff) {
228 printf(".nr " COMPATIBLE_REG " \\n(.C\n");
230 printf(".ds " LINE_STRING "\n");
236 if (output_format == troff)
237 printf("\\*(" LINE_STRING "\n");
238 else if (output_format == mathml && !xhtml)
242 void restore_compatibility()
244 if (output_format == troff)
245 printf(".cp \\n(" COMPATIBLE_REG "\n");
248 void do_text(const char *s)
250 if (output_format == troff) {
252 printf(".as " LINE_STRING " \"%s\n", s);
255 else if (output_format == mathml) {
257 if (xhtml && strlen(s) > 0)
262 void set_minimum_size(int n)
267 void set_script_size()
269 if (minimum_size < 0)
271 if (script_size_reduction >= 0)
272 printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size);
274 printf(".ps (u;\\n[.ps]*7+5/10>?%dz)\n", minimum_size);
277 int box::next_uid = 0;
279 box::box() : spacing_type(ORDINARY_TYPE), uid(next_uid++)
287 void box::top_level()
290 if (output_format == troff) {
292 // putc('\n', stderr);
293 printf(".nr " SAVED_FONT_REG " \\n[.f]\n");
295 printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n");
296 printf(".ft %s\n", get_gfont());
297 printf(".nr " SAVED_SIZE_REG " \\n[.ps]\n");
299 char buf[INT_DIGITS + 1];
300 sprintf(buf, "%d", gsize);
301 b = new size_box(strsave(buf), b);
303 current_roman_font = get_grfont();
304 // This catches tabs used within \Z (which aren't allowed).
306 int r = b->compute_metrics(DISPLAY_STYLE);
307 printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n");
308 printf(".ft \\n[" SAVED_FONT_REG "]\n");
309 printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r);
310 if (r == FOUND_MARK) {
311 printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n");
312 printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid);
314 else if (r == FOUND_LINEUP)
315 printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
316 SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n");
318 assert(r == FOUND_NOTHING);
319 // If we use \R directly, the space will prevent it working in a
320 // macro argument; so we hide it in a string instead.
321 printf(".ds " SAVE_FONT_STRING " "
322 "\\R'" SAVED_INLINE_FONT_REG " \\En[.f]'"
324 "\\R'" SAVED_INLINE_PREV_FONT_REG " \\En[.f]'"
325 "\\R'" SAVED_INLINE_SIZE_REG " \\En[.ps]'"
327 "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\En[.ps]'"
329 ".ds " RESTORE_FONT_STRING " "
330 "\\f[\\En[" SAVED_INLINE_PREV_FONT_REG "]]"
331 "\\f[\\En[" SAVED_INLINE_FONT_REG "]]"
332 "\\s'\\En[" SAVED_INLINE_PREV_SIZE_REG "]u'"
333 "\\s'\\En[" SAVED_INLINE_SIZE_REG "]u'"
335 printf(".as1 " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]");
336 printf("\\f[%s]", get_gfont());
337 printf("\\s'\\En[" SAVED_SIZE_REG "]u'");
338 current_roman_font = get_grfont();
340 printf("\\E*[" RESTORE_FONT_STRING "]\n");
341 if (r == FOUND_LINEUP)
342 printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
343 MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n["
344 WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n",
348 printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n["
349 DEPTH_FORMAT "]u-%dM>?0)\n",
350 b->uid, body_height, b->uid, body_depth);
352 else if (output_format == mathml) {
363 // gpic defines this register so as to make geqn not produce '\x's
364 #define EQN_NO_EXTRA_SPACE_REG "0x"
366 void box::extra_space()
368 printf(".if !r" EQN_NO_EXTRA_SPACE_REG " "
369 ".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
370 if (positive_space >= 0 || negative_space >= 0) {
371 if (positive_space > 0)
372 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
373 ".as1 " LINE_STRING " \\x'-%dM'\n", positive_space);
374 if (negative_space > 0)
375 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
376 ".as1 " LINE_STRING " \\x'%dM'\n", negative_space);
377 positive_space = negative_space = -1;
380 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
381 ".if \\n[" HEIGHT_FORMAT "]>%dM .as1 " LINE_STRING
382 " \\x'-(\\n[" HEIGHT_FORMAT
384 uid, body_height, uid, body_height);
385 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
386 ".if \\n[" DEPTH_FORMAT "]>%dM .as1 " LINE_STRING
387 " \\x'\\n[" DEPTH_FORMAT
389 uid, body_depth, uid, body_depth);
393 int box::compute_metrics(int)
395 printf(".nr " WIDTH_FORMAT " 0\n", uid);
396 printf(".nr " HEIGHT_FORMAT " 0\n", uid);
397 printf(".nr " DEPTH_FORMAT " 0\n", uid);
398 return FOUND_NOTHING;
401 void box::compute_subscript_kern()
403 printf(".nr " SUB_KERN_FORMAT " 0\n", uid);
406 void box::compute_skew()
408 printf(".nr " SKEW_FORMAT " 0\n", uid);
415 void box::check_tabs(int)
424 int box::left_is_italic()
429 int box::right_is_italic()
434 void box::hint(unsigned)
438 void box::handle_char_type(int, int)
443 box_list::box_list(box *pp)
446 for (int i = 0; i < 10; i++)
453 void box_list::append(box *pp)
455 if (len + 1 > maxlen) {
458 p = new box*[maxlen];
459 memcpy(p, oldp, sizeof(box*)*len);
465 box_list::~box_list()
467 for (int i = 0; i < len; i++)
472 void box_list::list_check_tabs(int level)
474 for (int i = 0; i < len; i++)
475 p[i]->check_tabs(level);
479 pointer_box::pointer_box(box *pp) : p(pp)
481 spacing_type = p->spacing_type;
484 pointer_box::~pointer_box()
489 int pointer_box::compute_metrics(int style)
491 int r = p->compute_metrics(style);
492 printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
493 printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
494 printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
498 void pointer_box::compute_subscript_kern()
500 p->compute_subscript_kern();
501 printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid);
504 void pointer_box::compute_skew()
507 printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n",
511 void pointer_box::check_tabs(int level)
513 p->check_tabs(level);
516 int simple_box::compute_metrics(int)
518 printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid);
520 printf(DELIMITER_CHAR "\n");
521 printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid);
522 printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid);
523 printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid);
524 printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid);
525 return FOUND_NOTHING;
528 void simple_box::compute_subscript_kern()
530 // do nothing, we already computed it in do_metrics
533 void simple_box::compute_skew()
535 // do nothing, we already computed it in do_metrics
543 int simple_box::is_simple()
548 quoted_text_box::quoted_text_box(char *s) : text(s)
552 quoted_text_box::~quoted_text_box()
557 void quoted_text_box::output()
560 if (output_format == troff)
562 else if (output_format == mathml) {
563 fputs("<mtext>", stdout);
565 fputs("</mtext>", stdout);
570 tab_box::tab_box() : disabled(0)
574 // We treat a tab_box as having width 0 for width computations.
576 void tab_box::output()
582 void tab_box::check_tabs(int level)
585 error("tabs allowed only at outermost level");
590 space_box::space_box()
592 spacing_type = SUPPRESS_TYPE;
595 void space_box::output()
597 if (output_format == troff)
598 printf("\\h'%dM'", thick_space);
599 else if (output_format == mathml)
600 //    doesn't display right under Firefox 1.5.
601 printf("<mtext> </mtext>");
604 half_space_box::half_space_box()
606 spacing_type = SUPPRESS_TYPE;
609 void half_space_box::output()
611 if (output_format == troff)
612 printf("\\h'%dM'", thin_space);
613 else if (output_format == mathml)
614 printf("<mtext> </mtext>");
617 void box_list::list_debug_print(const char *sep)
620 for (int i = 1; i < len; i++) {
621 fprintf(stderr, "%s", sep);
626 void quoted_text_box::debug_print()
628 fprintf(stderr, "\"%s\"", (text ? text : ""));
631 void half_space_box::debug_print()
633 fprintf(stderr, "^");
636 void space_box::debug_print()
638 fprintf(stderr, "~");
641 void tab_box::debug_print()
643 fprintf(stderr, "<tab>");