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", ¹ }, 103114402Sru { "sup2", ² }, 104114402Sru { "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