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", ¹ }, 106 { "sup2", ² }, 107 { "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 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 141 int script_style(int style) 142 { 143 return style > SCRIPT_STYLE ? style - 2 : style; 144 } 145 146 int cramped_style(int style) 147 { 148 return (style & 1) ? style - 1 : style; 149 } 150 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 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 188 void set_script_reduction(int n) 189 { 190 script_size_reduction = n; 191 } 192 193 const char *get_gfont() 194 { 195 return gfont ? gfont : "I"; 196 } 197 198 const char *get_grfont() 199 { 200 return grfont ? grfont : "R"; 201 } 202 203 const char *get_gbfont() 204 { 205 return gbfont ? gbfont : "B"; 206 } 207 208 void set_gfont(const char *s) 209 { 210 a_delete gfont; 211 gfont = strsave(s); 212 } 213 214 void set_grfont(const char *s) 215 { 216 a_delete grfont; 217 grfont = strsave(s); 218 } 219 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 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 236 void output_string() 237 { 238 printf("\\*(" LINE_STRING "\n"); 239 } 240 241 void restore_compatibility() 242 { 243 printf(".cp \\n(" COMPATIBLE_REG "\n"); 244 } 245 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 253 void set_minimum_size(int n) 254 { 255 minimum_size = n; 256 } 257 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 270 box::box() : spacing_type(ORDINARY_TYPE), uid(next_uid++) 271 { 272 } 273 274 box::~box() 275 { 276 } 277 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 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 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 385 void box::compute_subscript_kern() 386 { 387 printf(".nr " SUB_KERN_FORMAT " 0\n", uid); 388 } 389 390 void box::compute_skew() 391 { 392 printf(".nr " SKEW_FORMAT " 0\n", uid); 393 } 394 395 void box::output() 396 { 397 } 398 399 void box::check_tabs(int) 400 { 401 } 402 403 int box::is_char() 404 { 405 return 0; 406 } 407 408 int box::left_is_italic() 409 { 410 return 0; 411 } 412 413 int box::right_is_italic() 414 { 415 return 0; 416 } 417 418 void box::hint(unsigned) 419 { 420 } 421 422 void box::handle_char_type(int, int) 423 { 424 } 425 426 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 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 449 box_list::~box_list() 450 { 451 for (int i = 0; i < len; i++) 452 delete p[i]; 453 a_delete p; 454 } 455 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 463 pointer_box::pointer_box(box *pp) : p(pp) 464 { 465 spacing_type = p->spacing_type; 466 } 467 468 pointer_box::~pointer_box() 469 { 470 delete p; 471 } 472 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 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 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 495 void pointer_box::check_tabs(int level) 496 { 497 p->check_tabs(level); 498 } 499 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 512 void simple_box::compute_subscript_kern() 513 { 514 // do nothing, we already computed it in do_metrics 515 } 516 517 void simple_box::compute_skew() 518 { 519 // do nothing, we already computed it in do_metrics 520 } 521 522 int box::is_simple() 523 { 524 return 0; 525 } 526 527 int simple_box::is_simple() 528 { 529 return 1; 530 } 531 532 quoted_text_box::quoted_text_box(char *s) : text(s) 533 { 534 } 535 536 quoted_text_box::~quoted_text_box() 537 { 538 a_delete text; 539 } 540 541 void quoted_text_box::output() 542 { 543 if (text) 544 fputs(text, stdout); 545 } 546 547 tab_box::tab_box() : disabled(0) 548 { 549 } 550 551 // We treat a tab_box as having width 0 for width computations. 552 553 void tab_box::output() 554 { 555 if (!disabled) 556 printf("\\t"); 557 } 558 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 567 space_box::space_box() 568 { 569 spacing_type = SUPPRESS_TYPE; 570 } 571 572 void space_box::output() 573 { 574 printf("\\h'%dM'", thick_space); 575 } 576 577 half_space_box::half_space_box() 578 { 579 spacing_type = SUPPRESS_TYPE; 580 } 581 582 void half_space_box::output() 583 { 584 printf("\\h'%dM'", thin_space); 585 } 586 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 596 void quoted_text_box::debug_print() 597 { 598 fprintf(stderr, "\"%s\"", (text ? text : "")); 599 } 600 601 void half_space_box::debug_print() 602 { 603 fprintf(stderr, "^"); 604 } 605 606 void space_box::debug_print() 607 { 608 fprintf(stderr, "~"); 609 } 610 611 void tab_box::debug_print() 612 { 613 fprintf(stderr, "<tab>"); 614 } 615