2 /* Copyright (C) 1989, 1990, 1991, 1992 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 2, or (at your option) any later
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 along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
24 const char *current_roman_font;
31 int script_size_reduction = -1; // negative means reduce by a percentage
33 int positive_space = -1;
34 int negative_space = -1;
43 int accent_width = 31;
44 int delimiter_factor = 900;
45 int delimiter_shortfall = 50;
47 int null_delimiter_space = 12;
50 int medium_space = 22;
55 // we don't use num3, because we don't have \atop
58 int axis_height = 26; // in 100ths of an em
62 int default_rule_thickness = 4;
68 int big_op_spacing1 = 11;
69 int big_op_spacing2 = 17;
70 int big_op_spacing3 = 20;
71 int big_op_spacing4 = 60;
72 int big_op_spacing5 = 10;
74 // These are for piles and matrices.
76 int baseline_sep = 140; // = num1 + denom1
77 int shift_down = 26; // = axis_height
78 int column_sep = 100; // = em space
79 int matrix_side_sep = 17; // = thin space
81 int nroff = 0; // should we grok ndefine or tdefine?
87 { "fat_offset", &fat_offset },
88 { "over_hang", &over_hang },
89 { "accent_width", &accent_width },
90 { "delimiter_factor", &delimiter_factor },
91 { "delimiter_shortfall", &delimiter_shortfall },
92 { "null_delimiter_space", &null_delimiter_space },
93 { "script_space", &script_space },
94 { "thin_space", &thin_space },
95 { "medium_space", &medium_space },
96 { "thick_space", &thick_space },
99 { "denom1", &denom1 },
100 { "denom2", &denom2 },
101 { "axis_height", &axis_height },
105 { "default_rule_thickness", &default_rule_thickness },
108 { "sup_drop", &sup_drop },
109 { "sub_drop", &sub_drop },
110 { "x_height", &x_height },
111 { "big_op_spacing1", &big_op_spacing1 },
112 { "big_op_spacing2", &big_op_spacing2 },
113 { "big_op_spacing3", &big_op_spacing3 },
114 { "big_op_spacing4", &big_op_spacing4 },
115 { "big_op_spacing5", &big_op_spacing5 },
116 { "minimum_size", &minimum_size },
117 { "baseline_sep", &baseline_sep },
118 { "shift_down", &shift_down },
119 { "column_sep", &column_sep },
120 { "matrix_side_sep", &matrix_side_sep },
121 { "draw_lines", &draw_flag },
122 { "body_height", &body_height },
123 { "body_depth", &body_depth },
128 void set_param(const char *name, int value)
130 for (int i = 0; param_table[i].name != 0; i++)
131 if (strcmp(param_table[i].name, name) == 0) {
132 *param_table[i].ptr = value;
135 error("unrecognised parameter `%1'", name);
138 int script_style(int style)
140 return style > SCRIPT_STYLE ? style - 2 : style;
143 int cramped_style(int style)
145 return (style & 1) ? style - 1 : style;
148 void set_space(int n)
156 // Return 0 if the specified size is bad.
157 // The caller is responsible for giving the error message.
159 int set_gsize(const char *s)
161 const char *p = (*s == '+' || *s == '-') ? s + 1 : s;
163 long n = strtol(p, &end, 10);
164 if (n <= 0 || *end != '\0' || n > INT_MAX)
170 if (gsize > INT_MAX - n)
185 void set_script_reduction(int n)
187 script_size_reduction = n;
190 const char *get_gfont()
192 return gfont ? gfont : "I";
195 const char *get_grfont()
197 return grfont ? grfont : "R";
200 const char *get_gbfont()
202 return gbfont ? gbfont : "B";
205 void set_gfont(const char *s)
211 void set_grfont(const char *s)
217 void set_gbfont(const char *s)
223 // this must be precisely 2 characters in length
224 #define COMPATIBLE_REG "0C"
228 printf(".nr " COMPATIBLE_REG " \\n(.C\n");
230 printf(".ds " LINE_STRING "\n");
235 printf("\\*[" LINE_STRING "]\n");
238 void restore_compatibility()
240 printf(".cp \\n(" COMPATIBLE_REG "\n");
243 void do_text(const char *s)
246 printf(".as " LINE_STRING " \"%s\n", s);
250 void set_minimum_size(int n)
255 void set_script_size()
257 if (minimum_size < 0)
259 if (script_size_reduction >= 0)
260 printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size);
262 printf(".ps (u;\\n[.s]*7+5/10>?%d)*1z\n", minimum_size);
265 int box::next_uid = 0;
267 box::box() : uid(next_uid++), spacing_type(ORDINARY_TYPE)
275 void box::top_level()
278 // putc('\n', stderr);
280 printf(".nr " SAVED_FONT_REG " \\n[.f]\n");
282 printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n");
283 printf(".ft %s\n", get_gfont());
284 printf(".nr " SAVED_SIZE_REG " \\n[.s]z\n");
286 char buf[INT_DIGITS + 1];
287 sprintf(buf, "%d", gsize);
288 b = new size_box(strsave(buf), b);
290 current_roman_font = get_grfont();
291 // This catches tabs used within \Z (which aren't allowed).
293 int r = b->compute_metrics(DISPLAY_STYLE);
294 printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n");
295 printf(".ft \\n[" SAVED_FONT_REG "]\n");
296 printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r);
297 if (r == FOUND_MARK) {
298 printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n");
299 printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid);
301 else if (r == FOUND_LINEUP)
302 printf(".if r" SAVED_MARK_REG " .as " LINE_STRING " \\h'\\n["
303 SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n");
305 assert(r == FOUND_NOTHING);
306 // The problem here is that the argument to \f is read in copy mode,
307 // so we cannot use \E there; so we hide it in a string instead.
308 // Another problem is that if we use \R directly, then the space will
309 // prevent it working in a macro argument.
310 printf(".ds " SAVE_FONT_STRING " "
311 "\\R'" SAVED_INLINE_FONT_REG " \\\\n[.f]'"
313 "\\R'" SAVED_INLINE_PREV_FONT_REG " \\\\n[.f]'"
314 "\\R'" SAVED_INLINE_SIZE_REG " \\\\n[.s]z'"
316 "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\\\n[.s]z'"
318 ".ds " RESTORE_FONT_STRING " "
319 "\\f[\\\\n[" SAVED_INLINE_PREV_FONT_REG "]]"
320 "\\f[\\\\n[" SAVED_INLINE_FONT_REG "]]"
321 "\\s'\\\\n[" SAVED_INLINE_PREV_SIZE_REG "]u'"
322 "\\s'\\\\n[" SAVED_INLINE_SIZE_REG "]u'"
324 printf(".as " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]");
325 printf("\\f[%s]", get_gfont());
326 printf("\\s'\\En[" SAVED_SIZE_REG "]u'");
327 current_roman_font = get_grfont();
329 printf("\\E*[" RESTORE_FONT_STRING "]\n");
330 if (r == FOUND_LINEUP)
331 printf(".if r" SAVED_MARK_REG " .as " LINE_STRING " \\h'\\n["
332 MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n["
333 WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n",
337 printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n["
338 DEPTH_FORMAT "]u-%dM>?0)\n",
339 b->uid, body_height, b->uid, body_depth);
344 // gpic defines this register so as to make geqn not produce `\x's
345 #define EQN_NO_EXTRA_SPACE_REG "0x"
347 void box::extra_space()
349 printf(".if !r" EQN_NO_EXTRA_SPACE_REG " "
350 ".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
351 if (positive_space >= 0 || negative_space >= 0) {
352 if (positive_space > 0)
353 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
354 ".as " LINE_STRING " \\x'-%dM'\n", positive_space);
355 if (negative_space > 0)
356 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
357 ".as " LINE_STRING " \\x'%dM'\n", negative_space);
358 positive_space = negative_space = -1;
361 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
362 ".if \\n[" HEIGHT_FORMAT "]>%dM .as " LINE_STRING
363 " \\x'-(\\n[" HEIGHT_FORMAT
365 uid, body_height, uid, body_height);
366 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
367 ".if \\n[" DEPTH_FORMAT "]>%dM .as " LINE_STRING
368 " \\x'\\n[" DEPTH_FORMAT
370 uid, body_depth, uid, body_depth);
374 int box::compute_metrics(int)
376 printf(".nr " WIDTH_FORMAT " 0\n", uid);
377 printf(".nr " HEIGHT_FORMAT " 0\n", uid);
378 printf(".nr " DEPTH_FORMAT " 0\n", uid);
379 return FOUND_NOTHING;
382 void box::compute_subscript_kern()
384 printf(".nr " SUB_KERN_FORMAT " 0\n", uid);
387 void box::compute_skew()
389 printf(".nr " SKEW_FORMAT " 0\n", uid);
396 void box::check_tabs(int)
405 int box::left_is_italic()
410 int box::right_is_italic()
415 void box::hint(unsigned)
419 void box::handle_char_type(int, int)
424 box_list::box_list(box *pp)
427 for (int i = 0; i < 10; i++)
434 void box_list::append(box *pp)
436 if (len + 1 > maxlen) {
439 p = new box*[maxlen];
440 memcpy(p, oldp, sizeof(box*)*len);
446 box_list::~box_list()
448 for (int i = 0; i < len; i++)
453 void box_list::list_check_tabs(int level)
455 for (int i = 0; i < len; i++)
456 p[i]->check_tabs(level);
460 pointer_box::pointer_box(box *pp) : p(pp)
462 spacing_type = p->spacing_type;
465 pointer_box::~pointer_box()
470 int pointer_box::compute_metrics(int style)
472 int r = p->compute_metrics(style);
473 printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
474 printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
475 printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
479 void pointer_box::compute_subscript_kern()
481 p->compute_subscript_kern();
482 printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid);
485 void pointer_box::compute_skew()
488 printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n",
492 void pointer_box::check_tabs(int level)
494 p->check_tabs(level);
497 int simple_box::compute_metrics(int)
499 printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid);
501 printf(DELIMITER_CHAR "\n");
502 printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid);
503 printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid);
504 printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid);
505 printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid);
506 return FOUND_NOTHING;
509 void simple_box::compute_subscript_kern()
511 // do nothing, we already computed it in do_metrics
514 void simple_box::compute_skew()
516 // do nothing, we already computed it in do_metrics
524 int simple_box::is_simple()
529 quoted_text_box::quoted_text_box(char *s) : text(s)
533 quoted_text_box::~quoted_text_box()
538 void quoted_text_box::output()
544 tab_box::tab_box() : disabled(0)
548 // We treat a tab_box as having width 0 for width computations.
550 void tab_box::output()
556 void tab_box::check_tabs(int level)
559 error("tabs allowed only at outermost level");
564 space_box::space_box()
566 spacing_type = SUPPRESS_TYPE;
569 void space_box::output()
571 printf("\\h'%dM'", thick_space);
574 half_space_box::half_space_box()
576 spacing_type = SUPPRESS_TYPE;
579 void half_space_box::output()
581 printf("\\h'%dM'", thin_space);
584 void box_list::list_debug_print(const char *sep)
587 for (int i = 1; i < len; i++) {
588 fprintf(stderr, "%s", sep);
593 void quoted_text_box::debug_print()
595 fprintf(stderr, "\"%s\"", (text ? text : ""));
598 void half_space_box::debug_print()
600 fprintf(stderr, "^");
603 void space_box::debug_print()
605 fprintf(stderr, "~");
608 void tab_box::debug_print()
610 fprintf(stderr, "<tab>");