Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / groff / src / preproc / eqn / box.cpp
blob5e8835f4a74d174f1ea4876a5800ab4a5c1c7e03
1 /* $NetBSD$ */
3 // -*- C++ -*-
4 /* Copyright (C) 1989, 1990, 1991, 1992, 2002, 2004
5 Free Software Foundation, Inc.
6 Written by James Clark (jjc@jclark.com)
8 This file is part of groff.
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 for more details.
20 You should have received a copy of the GNU General Public License along
21 with groff; see the file COPYING. If not, write to the Free Software
22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
24 #include "eqn.h"
25 #include "pbox.h"
27 const char *current_roman_font;
29 char *gfont = 0;
30 char *grfont = 0;
31 char *gbfont = 0;
32 int gsize = 0;
34 int script_size_reduction = -1; // negative means reduce by a percentage
36 int positive_space = -1;
37 int negative_space = -1;
39 int minimum_size = 5;
41 int fat_offset = 4;
42 int body_height = 85;
43 int body_depth = 35;
45 int over_hang = 0;
46 int accent_width = 31;
47 int delimiter_factor = 900;
48 int delimiter_shortfall = 50;
50 int null_delimiter_space = 12;
51 int script_space = 5;
52 int thin_space = 17;
53 int medium_space = 22;
54 int thick_space = 28;
56 int num1 = 70;
57 int num2 = 40;
58 // we don't use num3, because we don't have \atop
59 int denom1 = 70;
60 int denom2 = 36;
61 int axis_height = 26; // in 100ths of an em
62 int sup1 = 42;
63 int sup2 = 37;
64 int sup3 = 28;
65 int default_rule_thickness = 4;
66 int sub1 = 20;
67 int sub2 = 23;
68 int sup_drop = 38;
69 int sub_drop = 5;
70 int x_height = 45;
71 int big_op_spacing1 = 11;
72 int big_op_spacing2 = 17;
73 int big_op_spacing3 = 20;
74 int big_op_spacing4 = 60;
75 int big_op_spacing5 = 10;
77 // These are for piles and matrices.
79 int baseline_sep = 140; // = num1 + denom1
80 int shift_down = 26; // = axis_height
81 int column_sep = 100; // = em space
82 int matrix_side_sep = 17; // = thin space
84 int nroff = 0; // should we grok ndefine or tdefine?
86 struct S {
87 const char *name;
88 int *ptr;
89 } param_table[] = {
90 { "fat_offset", &fat_offset },
91 { "over_hang", &over_hang },
92 { "accent_width", &accent_width },
93 { "delimiter_factor", &delimiter_factor },
94 { "delimiter_shortfall", &delimiter_shortfall },
95 { "null_delimiter_space", &null_delimiter_space },
96 { "script_space", &script_space },
97 { "thin_space", &thin_space },
98 { "medium_space", &medium_space },
99 { "thick_space", &thick_space },
100 { "num1", &num1 },
101 { "num2", &num2 },
102 { "denom1", &denom1 },
103 { "denom2", &denom2 },
104 { "axis_height", &axis_height },
105 { "sup1", &sup1 },
106 { "sup2", &sup2 },
107 { "sup3", &sup3 },
108 { "default_rule_thickness", &default_rule_thickness },
109 { "sub1", &sub1 },
110 { "sub2", &sub2 },
111 { "sup_drop", &sup_drop },
112 { "sub_drop", &sub_drop },
113 { "x_height", &x_height },
114 { "big_op_spacing1", &big_op_spacing1 },
115 { "big_op_spacing2", &big_op_spacing2 },
116 { "big_op_spacing3", &big_op_spacing3 },
117 { "big_op_spacing4", &big_op_spacing4 },
118 { "big_op_spacing5", &big_op_spacing5 },
119 { "minimum_size", &minimum_size },
120 { "baseline_sep", &baseline_sep },
121 { "shift_down", &shift_down },
122 { "column_sep", &column_sep },
123 { "matrix_side_sep", &matrix_side_sep },
124 { "draw_lines", &draw_flag },
125 { "body_height", &body_height },
126 { "body_depth", &body_depth },
127 { "nroff", &nroff },
128 { 0, 0 }
131 void set_param(const char *name, int value)
133 for (int i = 0; param_table[i].name != 0; i++)
134 if (strcmp(param_table[i].name, name) == 0) {
135 *param_table[i].ptr = value;
136 return;
138 error("unrecognised parameter `%1'", name);
141 int script_style(int style)
143 return style > SCRIPT_STYLE ? style - 2 : style;
146 int cramped_style(int style)
148 return (style & 1) ? style - 1 : style;
151 void set_space(int n)
153 if (n < 0)
154 negative_space = -n;
155 else
156 positive_space = n;
159 // Return 0 if the specified size is bad.
160 // The caller is responsible for giving the error message.
162 int set_gsize(const char *s)
164 const char *p = (*s == '+' || *s == '-') ? s + 1 : s;
165 char *end;
166 long n = strtol(p, &end, 10);
167 if (n <= 0 || *end != '\0' || n > INT_MAX)
168 return 0;
169 if (p > s) {
170 if (!gsize)
171 gsize = 10;
172 if (*s == '+') {
173 if (gsize > INT_MAX - n)
174 return 0;
175 gsize += int(n);
177 else {
178 if (gsize - n <= 0)
179 return 0;
180 gsize -= int(n);
183 else
184 gsize = int(n);
185 return 1;
188 void set_script_reduction(int n)
190 script_size_reduction = n;
193 const char *get_gfont()
195 return gfont ? gfont : "I";
198 const char *get_grfont()
200 return grfont ? grfont : "R";
203 const char *get_gbfont()
205 return gbfont ? gbfont : "B";
208 void set_gfont(const char *s)
210 a_delete gfont;
211 gfont = strsave(s);
214 void set_grfont(const char *s)
216 a_delete grfont;
217 grfont = strsave(s);
220 void set_gbfont(const char *s)
222 a_delete gbfont;
223 gbfont = strsave(s);
226 // this must be precisely 2 characters in length
227 #define COMPATIBLE_REG "0C"
229 void start_string()
231 printf(".nr " COMPATIBLE_REG " \\n(.C\n");
232 printf(".cp 0\n");
233 printf(".ds " LINE_STRING "\n");
236 void output_string()
238 printf("\\*(" LINE_STRING "\n");
241 void restore_compatibility()
243 printf(".cp \\n(" COMPATIBLE_REG "\n");
246 void do_text(const char *s)
248 printf(".eo\n");
249 printf(".as " LINE_STRING " \"%s\n", s);
250 printf(".ec\n");
253 void set_minimum_size(int n)
255 minimum_size = n;
258 void set_script_size()
260 if (minimum_size < 0)
261 minimum_size = 0;
262 if (script_size_reduction >= 0)
263 printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size);
264 else
265 printf(".ps (u;\\n[.ps]*7+5/10>?%d)\n", minimum_size);
268 int box::next_uid = 0;
270 box::box() : spacing_type(ORDINARY_TYPE), uid(next_uid++)
274 box::~box()
278 void box::top_level()
280 // debug_print();
281 // putc('\n', stderr);
282 box *b = this;
283 printf(".nr " SAVED_FONT_REG " \\n[.f]\n");
284 printf(".ft\n");
285 printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n");
286 printf(".ft %s\n", get_gfont());
287 printf(".nr " SAVED_SIZE_REG " \\n[.ps]\n");
288 if (gsize > 0) {
289 char buf[INT_DIGITS + 1];
290 sprintf(buf, "%d", gsize);
291 b = new size_box(strsave(buf), b);
293 current_roman_font = get_grfont();
294 // This catches tabs used within \Z (which aren't allowed).
295 b->check_tabs(0);
296 int r = b->compute_metrics(DISPLAY_STYLE);
297 printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n");
298 printf(".ft \\n[" SAVED_FONT_REG "]\n");
299 printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r);
300 if (r == FOUND_MARK) {
301 printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n");
302 printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid);
304 else if (r == FOUND_LINEUP)
305 printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
306 SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n");
307 else
308 assert(r == FOUND_NOTHING);
309 // The problem here is that the argument to \f is read in copy mode,
310 // so we cannot use \E there; so we hide it in a string instead.
311 // Another problem is that if we use \R directly, then the space will
312 // prevent it working in a macro argument.
313 printf(".ds " SAVE_FONT_STRING " "
314 "\\R'" SAVED_INLINE_FONT_REG " \\\\n[.f]'"
315 "\\fP"
316 "\\R'" SAVED_INLINE_PREV_FONT_REG " \\\\n[.f]'"
317 "\\R'" SAVED_INLINE_SIZE_REG " \\\\n[.ps]'"
318 "\\s0"
319 "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\\\n[.ps]'"
320 "\n"
321 ".ds " RESTORE_FONT_STRING " "
322 "\\f[\\\\n[" SAVED_INLINE_PREV_FONT_REG "]]"
323 "\\f[\\\\n[" SAVED_INLINE_FONT_REG "]]"
324 "\\s'\\\\n[" SAVED_INLINE_PREV_SIZE_REG "]u'"
325 "\\s'\\\\n[" SAVED_INLINE_SIZE_REG "]u'"
326 "\n");
327 printf(".as1 " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]");
328 printf("\\f[%s]", get_gfont());
329 printf("\\s'\\En[" SAVED_SIZE_REG "]u'");
330 current_roman_font = get_grfont();
331 b->output();
332 printf("\\E*[" RESTORE_FONT_STRING "]\n");
333 if (r == FOUND_LINEUP)
334 printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
335 MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n["
336 WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n",
337 b->uid);
338 b->extra_space();
339 if (!inline_flag)
340 printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n["
341 DEPTH_FORMAT "]u-%dM>?0)\n",
342 b->uid, body_height, b->uid, body_depth);
343 delete b;
344 next_uid = 0;
347 // gpic defines this register so as to make geqn not produce `\x's
348 #define EQN_NO_EXTRA_SPACE_REG "0x"
350 void box::extra_space()
352 printf(".if !r" EQN_NO_EXTRA_SPACE_REG " "
353 ".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
354 if (positive_space >= 0 || negative_space >= 0) {
355 if (positive_space > 0)
356 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
357 ".as1 " LINE_STRING " \\x'-%dM'\n", positive_space);
358 if (negative_space > 0)
359 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
360 ".as1 " LINE_STRING " \\x'%dM'\n", negative_space);
361 positive_space = negative_space = -1;
363 else {
364 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
365 ".if \\n[" HEIGHT_FORMAT "]>%dM .as1 " LINE_STRING
366 " \\x'-(\\n[" HEIGHT_FORMAT
367 "]u-%dM)'\n",
368 uid, body_height, uid, body_height);
369 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
370 ".if \\n[" DEPTH_FORMAT "]>%dM .as1 " LINE_STRING
371 " \\x'\\n[" DEPTH_FORMAT
372 "]u-%dM'\n",
373 uid, body_depth, uid, body_depth);
377 int box::compute_metrics(int)
379 printf(".nr " WIDTH_FORMAT " 0\n", uid);
380 printf(".nr " HEIGHT_FORMAT " 0\n", uid);
381 printf(".nr " DEPTH_FORMAT " 0\n", uid);
382 return FOUND_NOTHING;
385 void box::compute_subscript_kern()
387 printf(".nr " SUB_KERN_FORMAT " 0\n", uid);
390 void box::compute_skew()
392 printf(".nr " SKEW_FORMAT " 0\n", uid);
395 void box::output()
399 void box::check_tabs(int)
403 int box::is_char()
405 return 0;
408 int box::left_is_italic()
410 return 0;
413 int box::right_is_italic()
415 return 0;
418 void box::hint(unsigned)
422 void box::handle_char_type(int, int)
427 box_list::box_list(box *pp)
429 p = new box*[10];
430 for (int i = 0; i < 10; i++)
431 p[i] = 0;
432 maxlen = 10;
433 len = 1;
434 p[0] = pp;
437 void box_list::append(box *pp)
439 if (len + 1 > maxlen) {
440 box **oldp = p;
441 maxlen *= 2;
442 p = new box*[maxlen];
443 memcpy(p, oldp, sizeof(box*)*len);
444 a_delete oldp;
446 p[len++] = pp;
449 box_list::~box_list()
451 for (int i = 0; i < len; i++)
452 delete p[i];
453 a_delete p;
456 void box_list::list_check_tabs(int level)
458 for (int i = 0; i < len; i++)
459 p[i]->check_tabs(level);
463 pointer_box::pointer_box(box *pp) : p(pp)
465 spacing_type = p->spacing_type;
468 pointer_box::~pointer_box()
470 delete p;
473 int pointer_box::compute_metrics(int style)
475 int r = p->compute_metrics(style);
476 printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
477 printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
478 printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
479 return r;
482 void pointer_box::compute_subscript_kern()
484 p->compute_subscript_kern();
485 printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid);
488 void pointer_box::compute_skew()
490 p->compute_skew();
491 printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n",
492 uid, p->uid);
495 void pointer_box::check_tabs(int level)
497 p->check_tabs(level);
500 int simple_box::compute_metrics(int)
502 printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid);
503 output();
504 printf(DELIMITER_CHAR "\n");
505 printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid);
506 printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid);
507 printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid);
508 printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid);
509 return FOUND_NOTHING;
512 void simple_box::compute_subscript_kern()
514 // do nothing, we already computed it in do_metrics
517 void simple_box::compute_skew()
519 // do nothing, we already computed it in do_metrics
522 int box::is_simple()
524 return 0;
527 int simple_box::is_simple()
529 return 1;
532 quoted_text_box::quoted_text_box(char *s) : text(s)
536 quoted_text_box::~quoted_text_box()
538 a_delete text;
541 void quoted_text_box::output()
543 if (text)
544 fputs(text, stdout);
547 tab_box::tab_box() : disabled(0)
551 // We treat a tab_box as having width 0 for width computations.
553 void tab_box::output()
555 if (!disabled)
556 printf("\\t");
559 void tab_box::check_tabs(int level)
561 if (level > 0) {
562 error("tabs allowed only at outermost level");
563 disabled = 1;
567 space_box::space_box()
569 spacing_type = SUPPRESS_TYPE;
572 void space_box::output()
574 printf("\\h'%dM'", thick_space);
577 half_space_box::half_space_box()
579 spacing_type = SUPPRESS_TYPE;
582 void half_space_box::output()
584 printf("\\h'%dM'", thin_space);
587 void box_list::list_debug_print(const char *sep)
589 p[0]->debug_print();
590 for (int i = 1; i < len; i++) {
591 fprintf(stderr, "%s", sep);
592 p[i]->debug_print();
596 void quoted_text_box::debug_print()
598 fprintf(stderr, "\"%s\"", (text ? text : ""));
601 void half_space_box::debug_print()
603 fprintf(stderr, "^");
606 void space_box::debug_print()
608 fprintf(stderr, "~");
611 void tab_box::debug_print()
613 fprintf(stderr, "<tab>");