box.cpp revision 114402
1114402Sru// -*- C++ -*-
2114402Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2002 Free Software Foundation, Inc.
3114402Sru     Written by James Clark (jjc@jclark.com)
4114402Sru
5114402SruThis file is part of groff.
6114402Sru
7114402Srugroff is free software; you can redistribute it and/or modify it under
8114402Sruthe terms of the GNU General Public License as published by the Free
9114402SruSoftware Foundation; either version 2, or (at your option) any later
10114402Sruversion.
11114402Sru
12114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
13114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
14114402SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15114402Srufor more details.
16114402Sru
17114402SruYou should have received a copy of the GNU General Public License along
18114402Sruwith groff; see the file COPYING.  If not, write to the Free Software
19114402SruFoundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20114402Sru
21114402Sru#include "eqn.h"
22114402Sru#include "pbox.h"
23114402Sru
24114402Sruconst char *current_roman_font;
25114402Sru
26114402Sruchar *gfont = 0;
27114402Sruchar *grfont = 0;
28114402Sruchar *gbfont = 0;
29114402Sruint gsize = 0;
30114402Sru
31114402Sruint script_size_reduction = -1;	// negative means reduce by a percentage
32114402Sru
33114402Sruint positive_space = -1;
34114402Sruint negative_space = -1;
35114402Sru
36114402Sruint minimum_size = 5;
37114402Sru
38114402Sruint fat_offset = 4;
39114402Sruint body_height = 85;
40114402Sruint body_depth = 35;
41114402Sru
42114402Sruint over_hang = 0;
43114402Sruint accent_width = 31;
44114402Sruint delimiter_factor = 900;
45114402Sruint delimiter_shortfall = 50;
46114402Sru
47114402Sruint null_delimiter_space = 12;
48114402Sruint script_space = 5;
49114402Sruint thin_space = 17;
50114402Sruint medium_space = 22;
51114402Sruint thick_space = 28;
52114402Sru
53114402Sruint num1 = 70;
54114402Sruint num2 = 40;
55114402Sru// we don't use num3, because we don't have \atop
56114402Sruint denom1 = 70;
57114402Sruint denom2 = 36;
58114402Sruint axis_height = 26;		// in 100ths of an em
59114402Sruint sup1 = 42;
60114402Sruint sup2 = 37;
61114402Sruint sup3 = 28;
62114402Sruint default_rule_thickness = 4;
63114402Sruint sub1 = 20;
64114402Sruint sub2 = 23;
65114402Sruint sup_drop = 38;
66114402Sruint sub_drop = 5;
67114402Sruint x_height = 45;
68114402Sruint big_op_spacing1 = 11;
69114402Sruint big_op_spacing2 = 17;
70114402Sruint big_op_spacing3 = 20;
71114402Sruint big_op_spacing4 = 60;
72114402Sruint big_op_spacing5 = 10;
73114402Sru
74114402Sru// These are for piles and matrices.
75114402Sru
76114402Sruint baseline_sep = 140;		// = num1 + denom1
77114402Sruint shift_down = 26;		// = axis_height
78114402Sruint column_sep = 100;		// = em space
79114402Sruint matrix_side_sep = 17;	// = thin space
80114402Sru
81114402Sruint nroff = 0;			// should we grok ndefine or tdefine?
82114402Sru
83114402Srustruct {
84114402Sru  const char *name;
85114402Sru  int *ptr;
86114402Sru} param_table[] = {
87114402Sru  { "fat_offset", &fat_offset },
88114402Sru  { "over_hang", &over_hang },
89114402Sru  { "accent_width", &accent_width },
90114402Sru  { "delimiter_factor", &delimiter_factor },
91114402Sru  { "delimiter_shortfall", &delimiter_shortfall },
92114402Sru  { "null_delimiter_space", &null_delimiter_space },
93114402Sru  { "script_space", &script_space },
94114402Sru  { "thin_space", &thin_space },
95114402Sru  { "medium_space", &medium_space },
96114402Sru  { "thick_space", &thick_space },
97114402Sru  { "num1", &num1 },
98114402Sru  { "num2", &num2 },
99114402Sru  { "denom1", &denom1 },
100114402Sru  { "denom2", &denom2 },
101114402Sru  { "axis_height", &axis_height },
102114402Sru  { "sup1", &sup1 },
103114402Sru  { "sup2", &sup2 },
104114402Sru  { "sup3", &sup3 },
105114402Sru  { "default_rule_thickness", &default_rule_thickness },
106114402Sru  { "sub1", &sub1 },
107114402Sru  { "sub2", &sub2 },
108114402Sru  { "sup_drop", &sup_drop },
109114402Sru  { "sub_drop", &sub_drop },
110114402Sru  { "x_height", &x_height },
111114402Sru  { "big_op_spacing1", &big_op_spacing1 },
112114402Sru  { "big_op_spacing2", &big_op_spacing2 },
113114402Sru  { "big_op_spacing3", &big_op_spacing3 },
114114402Sru  { "big_op_spacing4", &big_op_spacing4 },
115114402Sru  { "big_op_spacing5", &big_op_spacing5 },
116114402Sru  { "minimum_size", &minimum_size },
117114402Sru  { "baseline_sep", &baseline_sep },
118114402Sru  { "shift_down", &shift_down },
119114402Sru  { "column_sep", &column_sep },
120114402Sru  { "matrix_side_sep", &matrix_side_sep },
121114402Sru  { "draw_lines", &draw_flag },
122114402Sru  { "body_height", &body_height },
123114402Sru  { "body_depth", &body_depth },
124114402Sru  { "nroff", &nroff },
125114402Sru  { 0, 0 }
126114402Sru};
127114402Sru
128114402Sruvoid set_param(const char *name, int value)
129114402Sru{
130114402Sru  for (int i = 0; param_table[i].name != 0; i++)
131114402Sru    if (strcmp(param_table[i].name, name) == 0) {
132114402Sru      *param_table[i].ptr = value;
133114402Sru      return;
134114402Sru    }
135114402Sru  error("unrecognised parameter `%1'", name);
136114402Sru}
137114402Sru
138114402Sruint script_style(int style)
139114402Sru{
140114402Sru  return style > SCRIPT_STYLE ? style - 2 : style;
141114402Sru}
142114402Sru
143114402Sruint cramped_style(int style)
144114402Sru{
145114402Sru  return (style & 1) ? style - 1 : style;
146114402Sru}
147114402Sru
148114402Sruvoid set_space(int n)
149114402Sru{
150114402Sru  if (n < 0)
151114402Sru    negative_space = -n;
152114402Sru  else
153114402Sru    positive_space = n;
154114402Sru}
155114402Sru
156114402Sru// Return 0 if the specified size is bad.
157114402Sru// The caller is responsible for giving the error message.
158114402Sru
159114402Sruint set_gsize(const char *s)
160114402Sru{
161114402Sru  const char *p = (*s == '+' || *s == '-') ? s + 1 : s;
162114402Sru  char *end;
163114402Sru  long n = strtol(p, &end, 10);
164114402Sru  if (n <= 0 || *end != '\0' || n > INT_MAX)
165114402Sru    return 0;
166114402Sru  if (p > s) {
167114402Sru    if (!gsize)
168114402Sru      gsize = 10;
169114402Sru    if (*s == '+') {
170114402Sru      if (gsize > INT_MAX - n)
171114402Sru	return 0;
172114402Sru      gsize += int(n);
173114402Sru    }
174114402Sru    else {
175114402Sru      if (gsize - n <= 0)
176114402Sru	return 0;
177114402Sru      gsize -= int(n);
178114402Sru    }
179114402Sru  }
180114402Sru  else
181114402Sru    gsize = int(n);
182114402Sru  return 1;
183114402Sru}
184114402Sru
185114402Sruvoid set_script_reduction(int n)
186114402Sru{
187114402Sru  script_size_reduction = n;
188114402Sru}
189114402Sru
190114402Sruconst char *get_gfont()
191114402Sru{
192114402Sru  return gfont ? gfont : "I";
193114402Sru}
194114402Sru
195114402Sruconst char *get_grfont()
196114402Sru{
197114402Sru  return grfont ? grfont : "R";
198114402Sru}
199114402Sru
200114402Sruconst char *get_gbfont()
201114402Sru{
202114402Sru  return gbfont ? gbfont : "B";
203114402Sru}
204114402Sru
205114402Sruvoid set_gfont(const char *s)
206114402Sru{
207114402Sru  a_delete gfont;
208114402Sru  gfont = strsave(s);
209114402Sru}
210114402Sru
211114402Sruvoid set_grfont(const char *s)
212114402Sru{
213114402Sru  a_delete grfont;
214114402Sru  grfont = strsave(s);
215114402Sru}
216114402Sru
217114402Sruvoid set_gbfont(const char *s)
218114402Sru{
219114402Sru  a_delete gbfont;
220114402Sru  gbfont = strsave(s);
221114402Sru}
222114402Sru
223114402Sru// this must be precisely 2 characters in length
224114402Sru#define COMPATIBLE_REG "0C"
225114402Sru
226114402Sruvoid start_string()
227114402Sru{
228114402Sru  printf(".nr " COMPATIBLE_REG " \\n(.C\n");
229114402Sru  printf(".cp 0\n");
230114402Sru  printf(".ds " LINE_STRING "\n");
231114402Sru}
232114402Sru
233114402Sruvoid output_string()
234114402Sru{
235114402Sru  printf("\\*(" LINE_STRING "\n");
236114402Sru}
237114402Sru
238114402Sruvoid restore_compatibility()
239114402Sru{
240114402Sru  printf(".cp \\n(" COMPATIBLE_REG "\n");
241114402Sru}
242114402Sru
243114402Sruvoid do_text(const char *s)
244114402Sru{
245114402Sru  printf(".eo\n");
246114402Sru  printf(".as " LINE_STRING " \"%s\n", s);
247114402Sru  printf(".ec\n");
248114402Sru}
249114402Sru
250114402Sruvoid set_minimum_size(int n)
251114402Sru{
252114402Sru  minimum_size = n;
253114402Sru}
254114402Sru
255114402Sruvoid set_script_size()
256114402Sru{
257114402Sru  if (minimum_size < 0)
258114402Sru    minimum_size = 0;
259114402Sru  if (script_size_reduction >= 0)
260114402Sru    printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size);
261114402Sru  else
262114402Sru    printf(".ps (u;\\n[.ps]*7+5/10>?%d)\n", minimum_size);
263114402Sru}
264114402Sru
265114402Sruint box::next_uid = 0;
266114402Sru
267114402Srubox::box() : spacing_type(ORDINARY_TYPE), uid(next_uid++)
268114402Sru{
269114402Sru}
270114402Sru
271114402Srubox::~box()
272114402Sru{
273114402Sru}
274114402Sru
275114402Sruvoid box::top_level()
276114402Sru{
277114402Sru  // debug_print();
278114402Sru  // putc('\n', stderr);
279114402Sru  box *b = this;
280114402Sru  printf(".nr " SAVED_FONT_REG " \\n[.f]\n");
281114402Sru  printf(".ft\n");
282114402Sru  printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n");
283114402Sru  printf(".ft %s\n", get_gfont());
284114402Sru  printf(".nr " SAVED_SIZE_REG " \\n[.ps]\n");
285114402Sru  if (gsize > 0) {
286114402Sru    char buf[INT_DIGITS + 1];
287114402Sru    sprintf(buf, "%d", gsize);
288114402Sru    b = new size_box(strsave(buf), b);
289114402Sru  }
290114402Sru  current_roman_font = get_grfont();
291114402Sru  // This catches tabs used within \Z (which aren't allowed).
292114402Sru  b->check_tabs(0);
293114402Sru  int r = b->compute_metrics(DISPLAY_STYLE);
294114402Sru  printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n");
295114402Sru  printf(".ft \\n[" SAVED_FONT_REG "]\n");
296114402Sru  printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r);
297114402Sru  if (r == FOUND_MARK) {
298114402Sru    printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n");
299114402Sru    printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid);
300114402Sru  }
301114402Sru  else if (r == FOUND_LINEUP)
302114402Sru    printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
303114402Sru	   SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n");
304114402Sru  else
305114402Sru    assert(r == FOUND_NOTHING);
306114402Sru  // The problem here is that the argument to \f is read in copy mode,
307114402Sru  // so we cannot use \E there; so we hide it in a string instead.
308114402Sru  // Another problem is that if we use \R directly, then the space will
309114402Sru  // prevent it working in a macro argument.
310114402Sru  printf(".ds " SAVE_FONT_STRING " "
311114402Sru	 "\\R'" SAVED_INLINE_FONT_REG " \\\\n[.f]'"
312114402Sru	 "\\fP"
313114402Sru	 "\\R'" SAVED_INLINE_PREV_FONT_REG " \\\\n[.f]'"
314114402Sru	 "\\R'" SAVED_INLINE_SIZE_REG " \\\\n[.ps]'"
315114402Sru	 "\\s0"
316114402Sru	 "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\\\n[.ps]'"
317114402Sru	 "\n"
318114402Sru	 ".ds " RESTORE_FONT_STRING " "
319114402Sru	 "\\f[\\\\n[" SAVED_INLINE_PREV_FONT_REG "]]"
320114402Sru	 "\\f[\\\\n[" SAVED_INLINE_FONT_REG "]]"
321114402Sru	 "\\s'\\\\n[" SAVED_INLINE_PREV_SIZE_REG "]u'"
322114402Sru	 "\\s'\\\\n[" SAVED_INLINE_SIZE_REG "]u'"
323114402Sru	 "\n");
324114402Sru  printf(".as1 " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]");
325114402Sru  printf("\\f[%s]", get_gfont());
326114402Sru  printf("\\s'\\En[" SAVED_SIZE_REG "]u'");
327114402Sru  current_roman_font = get_grfont();
328114402Sru  b->output();
329114402Sru  printf("\\E*[" RESTORE_FONT_STRING "]\n");
330114402Sru  if (r == FOUND_LINEUP)
331114402Sru    printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
332114402Sru	   MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n["
333114402Sru	   WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n",
334114402Sru	   b->uid);
335114402Sru  b->extra_space();
336114402Sru  if (!inline_flag)
337114402Sru    printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n["
338114402Sru	   DEPTH_FORMAT "]u-%dM>?0)\n",
339114402Sru	   b->uid, body_height, b->uid, body_depth);
340114402Sru  delete b;
341114402Sru  next_uid = 0;
342114402Sru}
343114402Sru
344114402Sru// gpic defines this register so as to make geqn not produce `\x's
345114402Sru#define EQN_NO_EXTRA_SPACE_REG "0x"
346114402Sru
347114402Sruvoid box::extra_space()
348114402Sru{
349114402Sru  printf(".if !r" EQN_NO_EXTRA_SPACE_REG " "
350114402Sru	 ".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
351114402Sru  if (positive_space >= 0 || negative_space >= 0) {
352114402Sru    if (positive_space > 0)
353114402Sru      printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
354114402Sru	     ".as1 " LINE_STRING " \\x'-%dM'\n", positive_space);
355114402Sru    if (negative_space > 0)
356114402Sru      printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
357114402Sru	     ".as1 " LINE_STRING " \\x'%dM'\n", negative_space);
358114402Sru    positive_space = negative_space = -1;
359114402Sru  }
360114402Sru  else {
361114402Sru    printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
362114402Sru	   ".if \\n[" HEIGHT_FORMAT "]>%dM .as1 " LINE_STRING
363114402Sru	   " \\x'-(\\n[" HEIGHT_FORMAT
364114402Sru	   "]u-%dM)'\n",
365114402Sru	   uid, body_height, uid, body_height);
366114402Sru    printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
367114402Sru	   ".if \\n[" DEPTH_FORMAT "]>%dM .as1 " LINE_STRING
368114402Sru	   " \\x'\\n[" DEPTH_FORMAT
369114402Sru	   "]u-%dM'\n",
370114402Sru	   uid, body_depth, uid, body_depth);
371114402Sru  }
372114402Sru}
373114402Sru
374114402Sruint box::compute_metrics(int)
375114402Sru{
376114402Sru  printf(".nr " WIDTH_FORMAT " 0\n", uid);
377114402Sru  printf(".nr " HEIGHT_FORMAT " 0\n", uid);
378114402Sru  printf(".nr " DEPTH_FORMAT " 0\n", uid);
379114402Sru  return FOUND_NOTHING;
380114402Sru}
381114402Sru
382114402Sruvoid box::compute_subscript_kern()
383114402Sru{
384114402Sru  printf(".nr " SUB_KERN_FORMAT " 0\n", uid);
385114402Sru}
386114402Sru
387114402Sruvoid box::compute_skew()
388114402Sru{
389114402Sru  printf(".nr " SKEW_FORMAT " 0\n", uid);
390114402Sru}
391114402Sru
392114402Sruvoid box::output()
393114402Sru{
394114402Sru}
395114402Sru
396114402Sruvoid box::check_tabs(int)
397114402Sru{
398114402Sru}
399114402Sru
400114402Sruint box::is_char()
401114402Sru{
402114402Sru  return 0;
403114402Sru}
404114402Sru
405114402Sruint box::left_is_italic()
406114402Sru{
407114402Sru  return 0;
408114402Sru}
409114402Sru
410114402Sruint box::right_is_italic()
411114402Sru{
412114402Sru  return 0;
413114402Sru}
414114402Sru
415114402Sruvoid box::hint(unsigned)
416114402Sru{
417114402Sru}
418114402Sru
419114402Sruvoid box::handle_char_type(int, int)
420114402Sru{
421114402Sru}
422114402Sru
423114402Sru
424114402Srubox_list::box_list(box *pp)
425114402Sru{
426114402Sru  p = new box*[10];
427114402Sru  for (int i = 0; i < 10; i++)
428114402Sru    p[i] = 0;
429114402Sru  maxlen = 10;
430114402Sru  len = 1;
431114402Sru  p[0] = pp;
432114402Sru}
433114402Sru
434114402Sruvoid box_list::append(box *pp)
435114402Sru{
436114402Sru  if (len + 1 > maxlen) {
437114402Sru    box **oldp = p;
438114402Sru    maxlen *= 2;
439114402Sru    p = new box*[maxlen];
440114402Sru    memcpy(p, oldp, sizeof(box*)*len);
441114402Sru    a_delete oldp;
442114402Sru  }
443114402Sru  p[len++] = pp;
444114402Sru}
445114402Sru
446114402Srubox_list::~box_list()
447114402Sru{
448114402Sru  for (int i = 0; i < len; i++)
449114402Sru    delete p[i];
450114402Sru  a_delete p;
451114402Sru}
452114402Sru
453114402Sruvoid box_list::list_check_tabs(int level)
454114402Sru{
455114402Sru  for (int i = 0; i < len; i++)
456114402Sru    p[i]->check_tabs(level);
457114402Sru}
458114402Sru
459114402Sru
460114402Srupointer_box::pointer_box(box *pp) : p(pp)
461114402Sru{
462114402Sru  spacing_type = p->spacing_type;
463114402Sru}
464114402Sru
465114402Srupointer_box::~pointer_box()
466114402Sru{
467114402Sru  delete p;
468114402Sru}
469114402Sru
470114402Sruint pointer_box::compute_metrics(int style)
471114402Sru{
472114402Sru  int r = p->compute_metrics(style);
473114402Sru  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
474114402Sru  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
475114402Sru  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
476114402Sru  return r;
477114402Sru}
478114402Sru
479114402Sruvoid pointer_box::compute_subscript_kern()
480114402Sru{
481114402Sru  p->compute_subscript_kern();
482114402Sru  printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid);
483114402Sru}
484114402Sru
485114402Sruvoid pointer_box::compute_skew()
486114402Sru{
487114402Sru  p->compute_skew();
488114402Sru  printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n",
489114402Sru	 uid, p->uid);
490114402Sru}
491114402Sru
492114402Sruvoid pointer_box::check_tabs(int level)
493114402Sru{
494114402Sru  p->check_tabs(level);
495114402Sru}
496114402Sru
497114402Sruint simple_box::compute_metrics(int)
498114402Sru{
499114402Sru  printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid);
500114402Sru  output();
501114402Sru  printf(DELIMITER_CHAR "\n");
502114402Sru  printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid);
503114402Sru  printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid);
504114402Sru  printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid);
505114402Sru  printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid);
506114402Sru  return FOUND_NOTHING;
507114402Sru}
508114402Sru
509114402Sruvoid simple_box::compute_subscript_kern()
510114402Sru{
511114402Sru  // do nothing, we already computed it in do_metrics
512114402Sru}
513114402Sru
514114402Sruvoid simple_box::compute_skew()
515114402Sru{
516114402Sru  // do nothing, we already computed it in do_metrics
517114402Sru}
518114402Sru
519114402Sruint box::is_simple()
520114402Sru{
521114402Sru  return 0;
522114402Sru}
523114402Sru
524114402Sruint simple_box::is_simple()
525114402Sru{
526114402Sru  return 1;
527114402Sru}
528114402Sru
529114402Sruquoted_text_box::quoted_text_box(char *s) : text(s)
530114402Sru{
531114402Sru}
532114402Sru
533114402Sruquoted_text_box::~quoted_text_box()
534114402Sru{
535114402Sru  a_delete text;
536114402Sru}
537114402Sru
538114402Sruvoid quoted_text_box::output()
539114402Sru{
540114402Sru  if (text)
541114402Sru    fputs(text, stdout);
542114402Sru}
543114402Sru
544114402Srutab_box::tab_box() : disabled(0)
545114402Sru{
546114402Sru}
547114402Sru
548114402Sru// We treat a tab_box as having width 0 for width computations.
549114402Sru
550114402Sruvoid tab_box::output()
551114402Sru{
552114402Sru  if (!disabled)
553114402Sru    printf("\\t");
554114402Sru}
555114402Sru
556114402Sruvoid tab_box::check_tabs(int level)
557114402Sru{
558114402Sru  if (level > 0) {
559114402Sru    error("tabs allowed only at outermost level");
560114402Sru    disabled = 1;
561114402Sru  }
562114402Sru}
563114402Sru
564114402Sruspace_box::space_box()
565114402Sru{
566114402Sru  spacing_type = SUPPRESS_TYPE;
567114402Sru}
568114402Sru
569114402Sruvoid space_box::output()
570114402Sru{
571114402Sru  printf("\\h'%dM'", thick_space);
572114402Sru}
573114402Sru
574114402Sruhalf_space_box::half_space_box()
575114402Sru{
576114402Sru  spacing_type = SUPPRESS_TYPE;
577114402Sru}
578114402Sru
579114402Sruvoid half_space_box::output()
580114402Sru{
581114402Sru  printf("\\h'%dM'", thin_space);
582114402Sru}
583114402Sru
584114402Sruvoid box_list::list_debug_print(const char *sep)
585114402Sru{
586114402Sru  p[0]->debug_print();
587114402Sru  for (int i = 1; i < len; i++) {
588114402Sru    fprintf(stderr, "%s", sep);
589114402Sru    p[i]->debug_print();
590114402Sru  }
591114402Sru}
592114402Sru
593114402Sruvoid quoted_text_box::debug_print()
594114402Sru{
595114402Sru  fprintf(stderr, "\"%s\"", (text ? text : ""));
596114402Sru}
597114402Sru
598114402Sruvoid half_space_box::debug_print()
599114402Sru{
600114402Sru  fprintf(stderr, "^");
601114402Sru}
602114402Sru
603114402Sruvoid space_box::debug_print()
604114402Sru{
605114402Sru  fprintf(stderr, "~");
606114402Sru}
607114402Sru
608114402Sruvoid tab_box::debug_print()
609114402Sru{
610114402Sru  fprintf(stderr, "<tab>");
611114402Sru}
612