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
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
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. */
27 const char *current_roman_font
;
34 int script_size_reduction
= -1; // negative means reduce by a percentage
36 int positive_space
= -1;
37 int negative_space
= -1;
46 int accent_width
= 31;
47 int delimiter_factor
= 900;
48 int delimiter_shortfall
= 50;
50 int null_delimiter_space
= 12;
53 int medium_space
= 22;
58 // we don't use num3, because we don't have \atop
61 int axis_height
= 26; // in 100ths of an em
65 int default_rule_thickness
= 4;
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?
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
},
102 { "denom1", &denom1
},
103 { "denom2", &denom2
},
104 { "axis_height", &axis_height
},
108 { "default_rule_thickness", &default_rule_thickness
},
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
},
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
;
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
)
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
;
166 long n
= strtol(p
, &end
, 10);
167 if (n
<= 0 || *end
!= '\0' || n
> INT_MAX
)
173 if (gsize
> INT_MAX
- n
)
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
)
214 void set_grfont(const char *s
)
220 void set_gbfont(const char *s
)
226 // this must be precisely 2 characters in length
227 #define COMPATIBLE_REG "0C"
231 printf(".nr " COMPATIBLE_REG
" \\n(.C\n");
233 printf(".ds " LINE_STRING
"\n");
238 printf("\\*(" LINE_STRING
"\n");
241 void restore_compatibility()
243 printf(".cp \\n(" COMPATIBLE_REG
"\n");
246 void do_text(const char *s
)
249 printf(".as " LINE_STRING
" \"%s\n", s
);
253 void set_minimum_size(int n
)
258 void set_script_size()
260 if (minimum_size
< 0)
262 if (script_size_reduction
>= 0)
263 printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction
, minimum_size
);
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
++)
278 void box::top_level()
281 // putc('\n', stderr);
283 printf(".nr " SAVED_FONT_REG
" \\n[.f]\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");
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).
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");
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]'"
316 "\\R'" SAVED_INLINE_PREV_FONT_REG
" \\\\n[.f]'"
317 "\\R'" SAVED_INLINE_SIZE_REG
" \\\\n[.ps]'"
319 "\\R'" SAVED_INLINE_PREV_SIZE_REG
" \\\\n[.ps]'"
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'"
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();
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",
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
);
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;
364 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG
"] "
365 ".if \\n[" HEIGHT_FORMAT
"]>%dM .as1 " LINE_STRING
366 " \\x'-(\\n[" HEIGHT_FORMAT
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
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
);
399 void box::check_tabs(int)
408 int box::left_is_italic()
413 int box::right_is_italic()
418 void box::hint(unsigned)
422 void box::handle_char_type(int, int)
427 box_list::box_list(box
*pp
)
430 for (int i
= 0; i
< 10; i
++)
437 void box_list::append(box
*pp
)
439 if (len
+ 1 > maxlen
) {
442 p
= new box
*[maxlen
];
443 memcpy(p
, oldp
, sizeof(box
*)*len
);
449 box_list::~box_list()
451 for (int i
= 0; i
< len
; i
++)
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()
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
);
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()
491 printf(".nr " SKEW_FORMAT
" 0\\n[" SKEW_FORMAT
"]\n",
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
);
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
527 int simple_box::is_simple()
532 quoted_text_box::quoted_text_box(char *s
) : text(s
)
536 quoted_text_box::~quoted_text_box()
541 void quoted_text_box::output()
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()
559 void tab_box::check_tabs(int level
)
562 error("tabs allowed only at outermost level");
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
)
590 for (int i
= 1; i
< len
; i
++) {
591 fprintf(stderr
, "%s", sep
);
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>");