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