xref: /netbsd-src/external/gpl2/groff/dist/src/preproc/eqn/box.cpp (revision 89a07cf815a29524268025a1139fac4c5190f765)
1 /*	$NetBSD: box.cpp,v 1.1.1.1 2016/01/13 18:41:49 christos Exp $	*/
2 
3 // -*- C++ -*-
4 /* Copyright (C) 1989, 1990, 1991, 1992, 2002, 2004
5    Free Software Foundation, Inc.
6      Written by James Clark (jjc@jclark.com)
7 
8 This file is part of groff.
9 
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.
14 
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.
19 
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. */
23 
24 #include "eqn.h"
25 #include "pbox.h"
26 
27 const char *current_roman_font;
28 
29 char *gfont = 0;
30 char *grfont = 0;
31 char *gbfont = 0;
32 int gsize = 0;
33 
34 int script_size_reduction = -1;	// negative means reduce by a percentage
35 
36 int positive_space = -1;
37 int negative_space = -1;
38 
39 int minimum_size = 5;
40 
41 int fat_offset = 4;
42 int body_height = 85;
43 int body_depth = 35;
44 
45 int over_hang = 0;
46 int accent_width = 31;
47 int delimiter_factor = 900;
48 int delimiter_shortfall = 50;
49 
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;
55 
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;
76 
77 // These are for piles and matrices.
78 
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
83 
84 int nroff = 0;			// should we grok ndefine or tdefine?
85 
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 }
129 };
130 
set_param(const char * name,int value)131 void set_param(const char *name, int value)
132 {
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;
137     }
138   error("unrecognised parameter `%1'", name);
139 }
140 
script_style(int style)141 int script_style(int style)
142 {
143   return style > SCRIPT_STYLE ? style - 2 : style;
144 }
145 
cramped_style(int style)146 int cramped_style(int style)
147 {
148   return (style & 1) ? style - 1 : style;
149 }
150 
set_space(int n)151 void set_space(int n)
152 {
153   if (n < 0)
154     negative_space = -n;
155   else
156     positive_space = n;
157 }
158 
159 // Return 0 if the specified size is bad.
160 // The caller is responsible for giving the error message.
161 
set_gsize(const char * s)162 int set_gsize(const char *s)
163 {
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);
176     }
177     else {
178       if (gsize - n <= 0)
179 	return 0;
180       gsize -= int(n);
181     }
182   }
183   else
184     gsize = int(n);
185   return 1;
186 }
187 
set_script_reduction(int n)188 void set_script_reduction(int n)
189 {
190   script_size_reduction = n;
191 }
192 
get_gfont()193 const char *get_gfont()
194 {
195   return gfont ? gfont : "I";
196 }
197 
get_grfont()198 const char *get_grfont()
199 {
200   return grfont ? grfont : "R";
201 }
202 
get_gbfont()203 const char *get_gbfont()
204 {
205   return gbfont ? gbfont : "B";
206 }
207 
set_gfont(const char * s)208 void set_gfont(const char *s)
209 {
210   a_delete gfont;
211   gfont = strsave(s);
212 }
213 
set_grfont(const char * s)214 void set_grfont(const char *s)
215 {
216   a_delete grfont;
217   grfont = strsave(s);
218 }
219 
set_gbfont(const char * s)220 void set_gbfont(const char *s)
221 {
222   a_delete gbfont;
223   gbfont = strsave(s);
224 }
225 
226 // this must be precisely 2 characters in length
227 #define COMPATIBLE_REG "0C"
228 
start_string()229 void start_string()
230 {
231   printf(".nr " COMPATIBLE_REG " \\n(.C\n");
232   printf(".cp 0\n");
233   printf(".ds " LINE_STRING "\n");
234 }
235 
output_string()236 void output_string()
237 {
238   printf("\\*(" LINE_STRING "\n");
239 }
240 
restore_compatibility()241 void restore_compatibility()
242 {
243   printf(".cp \\n(" COMPATIBLE_REG "\n");
244 }
245 
do_text(const char * s)246 void do_text(const char *s)
247 {
248   printf(".eo\n");
249   printf(".as " LINE_STRING " \"%s\n", s);
250   printf(".ec\n");
251 }
252 
set_minimum_size(int n)253 void set_minimum_size(int n)
254 {
255   minimum_size = n;
256 }
257 
set_script_size()258 void set_script_size()
259 {
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);
266 }
267 
268 int box::next_uid = 0;
269 
box()270 box::box() : spacing_type(ORDINARY_TYPE), uid(next_uid++)
271 {
272 }
273 
~box()274 box::~box()
275 {
276 }
277 
top_level()278 void box::top_level()
279 {
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);
292   }
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);
303   }
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;
345 }
346 
347 // gpic defines this register so as to make geqn not produce `\x's
348 #define EQN_NO_EXTRA_SPACE_REG "0x"
349 
extra_space()350 void box::extra_space()
351 {
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;
362   }
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);
374   }
375 }
376 
compute_metrics(int)377 int box::compute_metrics(int)
378 {
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;
383 }
384 
compute_subscript_kern()385 void box::compute_subscript_kern()
386 {
387   printf(".nr " SUB_KERN_FORMAT " 0\n", uid);
388 }
389 
compute_skew()390 void box::compute_skew()
391 {
392   printf(".nr " SKEW_FORMAT " 0\n", uid);
393 }
394 
output()395 void box::output()
396 {
397 }
398 
check_tabs(int)399 void box::check_tabs(int)
400 {
401 }
402 
is_char()403 int box::is_char()
404 {
405   return 0;
406 }
407 
left_is_italic()408 int box::left_is_italic()
409 {
410   return 0;
411 }
412 
right_is_italic()413 int box::right_is_italic()
414 {
415   return 0;
416 }
417 
hint(unsigned)418 void box::hint(unsigned)
419 {
420 }
421 
handle_char_type(int,int)422 void box::handle_char_type(int, int)
423 {
424 }
425 
426 
box_list(box * pp)427 box_list::box_list(box *pp)
428 {
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;
435 }
436 
append(box * pp)437 void box_list::append(box *pp)
438 {
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;
445   }
446   p[len++] = pp;
447 }
448 
~box_list()449 box_list::~box_list()
450 {
451   for (int i = 0; i < len; i++)
452     delete p[i];
453   a_delete p;
454 }
455 
list_check_tabs(int level)456 void box_list::list_check_tabs(int level)
457 {
458   for (int i = 0; i < len; i++)
459     p[i]->check_tabs(level);
460 }
461 
462 
pointer_box(box * pp)463 pointer_box::pointer_box(box *pp) : p(pp)
464 {
465   spacing_type = p->spacing_type;
466 }
467 
~pointer_box()468 pointer_box::~pointer_box()
469 {
470   delete p;
471 }
472 
compute_metrics(int style)473 int pointer_box::compute_metrics(int style)
474 {
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;
480 }
481 
compute_subscript_kern()482 void pointer_box::compute_subscript_kern()
483 {
484   p->compute_subscript_kern();
485   printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid);
486 }
487 
compute_skew()488 void pointer_box::compute_skew()
489 {
490   p->compute_skew();
491   printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n",
492 	 uid, p->uid);
493 }
494 
check_tabs(int level)495 void pointer_box::check_tabs(int level)
496 {
497   p->check_tabs(level);
498 }
499 
compute_metrics(int)500 int simple_box::compute_metrics(int)
501 {
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;
510 }
511 
compute_subscript_kern()512 void simple_box::compute_subscript_kern()
513 {
514   // do nothing, we already computed it in do_metrics
515 }
516 
compute_skew()517 void simple_box::compute_skew()
518 {
519   // do nothing, we already computed it in do_metrics
520 }
521 
is_simple()522 int box::is_simple()
523 {
524   return 0;
525 }
526 
is_simple()527 int simple_box::is_simple()
528 {
529   return 1;
530 }
531 
quoted_text_box(char * s)532 quoted_text_box::quoted_text_box(char *s) : text(s)
533 {
534 }
535 
~quoted_text_box()536 quoted_text_box::~quoted_text_box()
537 {
538   a_delete text;
539 }
540 
output()541 void quoted_text_box::output()
542 {
543   if (text)
544     fputs(text, stdout);
545 }
546 
tab_box()547 tab_box::tab_box() : disabled(0)
548 {
549 }
550 
551 // We treat a tab_box as having width 0 for width computations.
552 
output()553 void tab_box::output()
554 {
555   if (!disabled)
556     printf("\\t");
557 }
558 
check_tabs(int level)559 void tab_box::check_tabs(int level)
560 {
561   if (level > 0) {
562     error("tabs allowed only at outermost level");
563     disabled = 1;
564   }
565 }
566 
space_box()567 space_box::space_box()
568 {
569   spacing_type = SUPPRESS_TYPE;
570 }
571 
output()572 void space_box::output()
573 {
574   printf("\\h'%dM'", thick_space);
575 }
576 
half_space_box()577 half_space_box::half_space_box()
578 {
579   spacing_type = SUPPRESS_TYPE;
580 }
581 
output()582 void half_space_box::output()
583 {
584   printf("\\h'%dM'", thin_space);
585 }
586 
list_debug_print(const char * sep)587 void box_list::list_debug_print(const char *sep)
588 {
589   p[0]->debug_print();
590   for (int i = 1; i < len; i++) {
591     fprintf(stderr, "%s", sep);
592     p[i]->debug_print();
593   }
594 }
595 
debug_print()596 void quoted_text_box::debug_print()
597 {
598   fprintf(stderr, "\"%s\"", (text ? text : ""));
599 }
600 
debug_print()601 void half_space_box::debug_print()
602 {
603   fprintf(stderr, "^");
604 }
605 
debug_print()606 void space_box::debug_print()
607 {
608   fprintf(stderr, "~");
609 }
610 
debug_print()611 void tab_box::debug_print()
612 {
613   fprintf(stderr, "<tab>");
614 }
615