Home | History | Annotate | Line # | Download | only in eqn
      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 (at) 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", &sup1 },
    106   { "sup2", &sup2 },
    107   { "sup3", &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