home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / eqn / box.cc next >
C/C++ Source or Header  |  1995-06-22  |  13KB  |  612 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.com)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 2, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file COPYING.  If not, write to the Free Software
  19. Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  20.  
  21. #include "eqn.h"
  22. #include "pbox.h"
  23.  
  24. const char *current_roman_font;
  25.  
  26. char *gfont = 0;
  27. char *grfont = 0;
  28. char *gbfont = 0;
  29. int gsize = 0;
  30.  
  31. int script_size_reduction = -1;    // negative means reduce by a percentage 
  32.  
  33. int positive_space = -1;
  34. int negative_space = -1;
  35.  
  36. int minimum_size = 5;
  37.  
  38. int fat_offset = 4;
  39. int body_height = 85;
  40. int body_depth = 35;
  41.  
  42. int over_hang = 0;
  43. int accent_width = 31;
  44. int delimiter_factor = 900;
  45. int delimiter_shortfall = 50;
  46.  
  47. int null_delimiter_space = 12;
  48. int script_space = 5;
  49. int thin_space = 17;
  50. int medium_space = 22;
  51. int thick_space = 28;
  52.  
  53. int num1 = 70;
  54. int num2 = 40;
  55. // we don't use num3, because we don't have \atop
  56. int denom1 = 70;
  57. int denom2 = 36;
  58. int axis_height = 26;        // in 100ths of an em
  59. int sup1 = 42;
  60. int sup2 = 37;
  61. int sup3 = 28;
  62. int default_rule_thickness = 4;
  63. int sub1 = 20;
  64. int sub2 = 23;
  65. int sup_drop = 38;
  66. int sub_drop = 5;
  67. int x_height = 45;
  68. int big_op_spacing1 = 11;
  69. int big_op_spacing2 = 17;
  70. int big_op_spacing3 = 20;
  71. int big_op_spacing4 = 60;
  72. int big_op_spacing5 = 10;
  73.  
  74. // These are for piles and matrices.
  75.  
  76. int baseline_sep = 140;        // = num1 + denom1
  77. int shift_down = 26;        // = axis_height
  78. int column_sep = 100;        // = em space
  79. int matrix_side_sep = 17;    // = thin space
  80.  
  81. int nroff = 0;            // should we grok ndefine or tdefine?
  82.  
  83. struct {
  84.   const char *name;
  85.   int *ptr;
  86. } param_table[] = {
  87.   { "fat_offset", &fat_offset },
  88.   { "over_hang", &over_hang },
  89.   { "accent_width", &accent_width },
  90.   { "delimiter_factor", &delimiter_factor },
  91.   { "delimiter_shortfall", &delimiter_shortfall },
  92.   { "null_delimiter_space", &null_delimiter_space },
  93.   { "script_space", &script_space },
  94.   { "thin_space", &thin_space },
  95.   { "medium_space", &medium_space },
  96.   { "thick_space", &thick_space },
  97.   { "num1", &num1 },
  98.   { "num2", &num2 },
  99.   { "denom1", &denom1 },
  100.   { "denom2", &denom2 },
  101.   { "axis_height", &axis_height },
  102.   { "sup1", ¹ },
  103.   { "sup2", ² },
  104.   { "sup3", ³ },
  105.   { "default_rule_thickness", &default_rule_thickness },
  106.   { "sub1", &sub1 },
  107.   { "sub2", &sub2 },
  108.   { "sup_drop", &sup_drop },
  109.   { "sub_drop", &sub_drop },
  110.   { "x_height", &x_height },
  111.   { "big_op_spacing1", &big_op_spacing1 },
  112.   { "big_op_spacing2", &big_op_spacing2 },
  113.   { "big_op_spacing3", &big_op_spacing3 },
  114.   { "big_op_spacing4", &big_op_spacing4 },
  115.   { "big_op_spacing5", &big_op_spacing5 },
  116.   { "minimum_size", &minimum_size },
  117.   { "baseline_sep", &baseline_sep },
  118.   { "shift_down", &shift_down },
  119.   { "column_sep", &column_sep },
  120.   { "matrix_side_sep", &matrix_side_sep },
  121.   { "draw_lines", &draw_flag },
  122.   { "body_height", &body_height },
  123.   { "body_depth", &body_depth },
  124.   { "nroff", &nroff },
  125.   { 0, 0 }
  126. };
  127.  
  128. void set_param(const char *name, int value)
  129. {
  130.   for (int i = 0; param_table[i].name != 0; i++)
  131.     if (strcmp(param_table[i].name, name) == 0) {
  132.       *param_table[i].ptr = value;
  133.       return;
  134.     }
  135.   error("unrecognised parameter `%1'", name);
  136. }
  137.  
  138. int script_style(int style)
  139. {
  140.   return style > SCRIPT_STYLE ? style - 2 : style;
  141. }
  142.  
  143. int cramped_style(int style)
  144. {
  145.   return (style & 1) ? style - 1 : style;
  146. }
  147.  
  148. void set_space(int n)
  149. {
  150.   if (n < 0)
  151.     negative_space = -n;
  152.   else
  153.     positive_space = n;
  154. }
  155.  
  156. // Return 0 if the specified size is bad.
  157. // The caller is responsible for giving the error message.
  158.  
  159. int set_gsize(const char *s)
  160. {
  161.   const char *p = (*s == '+' || *s == '-') ? s + 1 : s;
  162.   char *end;
  163.   long n = strtol(p, &end, 10);
  164.   if (n <= 0 || *end != '\0' || n > INT_MAX)
  165.     return 0;
  166.   if (p > s) {
  167.     if (!gsize)
  168.       gsize = 10;
  169.     if (*s == '+') {
  170.       if (gsize > INT_MAX - n)
  171.     return 0;
  172.       gsize += int(n);
  173.     }
  174.     else {
  175.       if (gsize - n <= 0)
  176.     return 0;
  177.       gsize -= int(n);
  178.     }
  179.   }
  180.   else
  181.     gsize = int(n);
  182.   return 1;
  183. }
  184.  
  185. void set_script_reduction(int n)
  186. {
  187.   script_size_reduction = n;
  188. }
  189.  
  190. const char *get_gfont()
  191. {
  192.   return gfont ? gfont : "I";
  193. }
  194.  
  195. const char *get_grfont()
  196. {
  197.   return grfont ? grfont : "R";
  198. }
  199.  
  200. const char *get_gbfont()
  201. {
  202.   return gbfont ? gbfont : "B";
  203. }
  204.  
  205. void set_gfont(const char *s)
  206. {
  207.   a_delete gfont;
  208.   gfont = strsave(s);
  209. }
  210.  
  211. void set_grfont(const char *s)
  212. {
  213.   a_delete grfont;
  214.   grfont = strsave(s);
  215. }
  216.  
  217. void set_gbfont(const char *s)
  218. {
  219.   a_delete gbfont;
  220.   gbfont = strsave(s);
  221. }
  222.  
  223. // this must be precisely 2 characters in length
  224. #define COMPATIBLE_REG "0C"
  225.  
  226. void start_string()
  227. {
  228.   printf(".nr " COMPATIBLE_REG " \\n(.C\n");
  229.   printf(".cp 0\n");
  230.   printf(".ds " LINE_STRING "\n");
  231. }
  232.  
  233. void output_string()
  234. {
  235.   printf("\\*[" LINE_STRING "]\n");
  236. }
  237.  
  238. void restore_compatibility()
  239. {
  240.   printf(".cp \\n(" COMPATIBLE_REG "\n");
  241. }
  242.  
  243. void do_text(const char *s)
  244. {
  245.   printf(".eo\n");
  246.   printf(".as " LINE_STRING " \"%s\n", s);
  247.   printf(".ec\n");
  248. }
  249.  
  250. void set_minimum_size(int n)
  251. {
  252.   minimum_size = n;
  253. }
  254.  
  255. void set_script_size()
  256. {
  257.   if (minimum_size < 0)
  258.     minimum_size = 0;
  259.   if (script_size_reduction >= 0)
  260.     printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size);
  261.   else
  262.     printf(".ps (u;\\n[.s]*7+5/10>?%d)*1z\n", minimum_size);
  263. }
  264.  
  265. int box::next_uid = 0;
  266.  
  267. box::box() : uid(next_uid++), spacing_type(ORDINARY_TYPE)
  268. {
  269. }
  270.  
  271. box::~box()
  272. {
  273. }
  274.  
  275. void box::top_level()
  276. {
  277.   // debug_print();
  278.   // putc('\n', stderr);
  279.   box *b = this;
  280.   printf(".nr " SAVED_FONT_REG " \\n[.f]\n");
  281.   printf(".ft\n");
  282.   printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n");
  283.   printf(".ft %s\n", get_gfont());
  284.   printf(".nr " SAVED_SIZE_REG " \\n[.s]z\n");
  285.   if (gsize > 0) {
  286.     char buf[INT_DIGITS + 1];
  287.     sprintf(buf, "%d", gsize);
  288.     b = new size_box(strsave(buf), b);
  289.   }
  290.   current_roman_font = get_grfont();
  291.   // This catches tabs used within \Z (which aren't allowed).
  292.   b->check_tabs(0);
  293.   int r = b->compute_metrics(DISPLAY_STYLE);
  294.   printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n");
  295.   printf(".ft \\n[" SAVED_FONT_REG "]\n");
  296.   printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r);
  297.   if (r == FOUND_MARK) {
  298.     printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n");
  299.     printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid);
  300.   }
  301.   else if (r == FOUND_LINEUP)
  302.     printf(".if r" SAVED_MARK_REG " .as " LINE_STRING " \\h'\\n["
  303.        SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n");
  304.   else
  305.     assert(r == FOUND_NOTHING);
  306.   // The problem here is that the argument to \f is read in copy mode,
  307.   // so we cannot use \E there; so we hide it in a string instead.
  308.   // Another problem is that if we use \R directly, then the space will
  309.   // prevent it working in a macro argument.
  310.   printf(".ds " SAVE_FONT_STRING " "
  311.      "\\R'" SAVED_INLINE_FONT_REG " \\\\n[.f]'"
  312.      "\\fP"
  313.      "\\R'" SAVED_INLINE_PREV_FONT_REG " \\\\n[.f]'"
  314.      "\\R'" SAVED_INLINE_SIZE_REG " \\\\n[.s]z'"
  315.      "\\s0"
  316.      "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\\\n[.s]z'"
  317.      "\n"
  318.      ".ds " RESTORE_FONT_STRING " "
  319.      "\\f[\\\\n[" SAVED_INLINE_PREV_FONT_REG "]]"
  320.      "\\f[\\\\n[" SAVED_INLINE_FONT_REG "]]"
  321.      "\\s'\\\\n[" SAVED_INLINE_PREV_SIZE_REG "]u'"
  322.      "\\s'\\\\n[" SAVED_INLINE_SIZE_REG "]u'"
  323.      "\n");
  324.   printf(".as " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]");
  325.   printf("\\f[%s]", get_gfont());
  326.   printf("\\s'\\En[" SAVED_SIZE_REG "]u'");
  327.   current_roman_font = get_grfont();
  328.   b->output();
  329.   printf("\\E*[" RESTORE_FONT_STRING "]\n");
  330.   if (r == FOUND_LINEUP)
  331.     printf(".if r" SAVED_MARK_REG " .as " LINE_STRING " \\h'\\n["
  332.        MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n["
  333.        WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n",
  334.        b->uid);
  335.   b->extra_space();
  336.   if (!inline_flag)
  337.     printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n["
  338.        DEPTH_FORMAT "]u-%dM>?0)\n",
  339.        b->uid, body_height, b->uid, body_depth);
  340.   delete b;
  341.   next_uid = 0;
  342. }
  343.  
  344. // gpic defines this register so as to make geqn not produce `\x's
  345. #define EQN_NO_EXTRA_SPACE_REG "0x"
  346.  
  347. void box::extra_space()
  348. {
  349.   printf(".if !r" EQN_NO_EXTRA_SPACE_REG " "
  350.      ".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
  351.   if (positive_space >= 0 || negative_space >= 0) {
  352.     if (positive_space > 0)
  353.       printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
  354.          ".as " LINE_STRING " \\x'-%dM'\n", positive_space);
  355.     if (negative_space > 0)
  356.       printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
  357.          ".as " LINE_STRING " \\x'%dM'\n", negative_space);
  358.     positive_space = negative_space = -1;
  359.   }
  360.   else {
  361.     printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
  362.        ".if \\n[" HEIGHT_FORMAT "]>%dM .as " LINE_STRING
  363.        " \\x'-(\\n[" HEIGHT_FORMAT
  364.        "]u-%dM)'\n",
  365.        uid, body_height, uid, body_height);
  366.     printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
  367.        ".if \\n[" DEPTH_FORMAT "]>%dM .as " LINE_STRING
  368.        " \\x'\\n[" DEPTH_FORMAT
  369.        "]u-%dM'\n",
  370.        uid, body_depth, uid, body_depth);
  371.   }
  372. }
  373.  
  374. int box::compute_metrics(int)
  375. {
  376.   printf(".nr " WIDTH_FORMAT " 0\n", uid);
  377.   printf(".nr " HEIGHT_FORMAT " 0\n", uid);
  378.   printf(".nr " DEPTH_FORMAT " 0\n", uid);
  379.   return FOUND_NOTHING;
  380. }
  381.  
  382. void box::compute_subscript_kern()
  383. {
  384.   printf(".nr " SUB_KERN_FORMAT " 0\n", uid);
  385. }
  386.  
  387. void box::compute_skew()
  388. {
  389.   printf(".nr " SKEW_FORMAT " 0\n", uid);
  390. }
  391.  
  392. void box::output()
  393. {
  394. }
  395.  
  396. void box::check_tabs(int)
  397. {
  398. }
  399.  
  400. int box::is_char()
  401. {
  402.   return 0;
  403. }
  404.  
  405. int box::left_is_italic()
  406. {
  407.   return 0;
  408. }
  409.  
  410. int box::right_is_italic()
  411. {
  412.   return 0;
  413. }
  414.  
  415. void box::hint(unsigned)
  416. {
  417. }
  418.   
  419. void box::handle_char_type(int, int)
  420. {
  421. }
  422.  
  423.  
  424. box_list::box_list(box *pp)
  425. {
  426.   p = new box*[10];
  427.   for (int i = 0; i < 10; i++)
  428.     p[i] = 0;
  429.   maxlen = 10;
  430.   len = 1;
  431.   p[0] = pp;
  432. }
  433.  
  434. void box_list::append(box *pp)
  435. {
  436.   if (len + 1 > maxlen) {
  437.     box **oldp = p;
  438.     maxlen *= 2;
  439.     p = new box*[maxlen];
  440.     memcpy(p, oldp, sizeof(box*)*len);
  441.     a_delete oldp;
  442.   }
  443.   p[len++] = pp;
  444. }
  445.  
  446. box_list::~box_list()
  447. {
  448.   for (int i = 0; i < len; i++)
  449.     delete p[i];
  450.   a_delete p;
  451. }
  452.  
  453. void box_list::list_check_tabs(int level)
  454. {
  455.   for (int i = 0; i < len; i++)
  456.     p[i]->check_tabs(level);
  457. }
  458.  
  459.  
  460. pointer_box::pointer_box(box *pp) : p(pp)
  461. {
  462.   spacing_type = p->spacing_type;
  463. }
  464.  
  465. pointer_box::~pointer_box()
  466. {
  467.   delete p;
  468. }
  469.  
  470. int pointer_box::compute_metrics(int style)
  471. {
  472.   int r = p->compute_metrics(style);
  473.   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
  474.   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
  475.   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
  476.   return r;
  477. }
  478.  
  479. void pointer_box::compute_subscript_kern()
  480. {
  481.   p->compute_subscript_kern();
  482.   printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid);
  483. }
  484.  
  485. void pointer_box::compute_skew()
  486. {
  487.   p->compute_skew();
  488.   printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n",
  489.      uid, p->uid);
  490. }
  491.  
  492. void pointer_box::check_tabs(int level)
  493. {
  494.   p->check_tabs(level);
  495. }
  496.  
  497. int simple_box::compute_metrics(int)
  498. {
  499.   printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid);
  500.   output();
  501.   printf(DELIMITER_CHAR "\n");
  502.   printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid);
  503.   printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid);
  504.   printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid);
  505.   printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid);
  506.   return FOUND_NOTHING;
  507. }
  508.  
  509. void simple_box::compute_subscript_kern()
  510. {
  511.   // do nothing, we already computed it in do_metrics
  512. }
  513.  
  514. void simple_box::compute_skew()
  515. {
  516.   // do nothing, we already computed it in do_metrics
  517. }
  518.  
  519. int box::is_simple()
  520. {
  521.   return 0;
  522. }
  523.  
  524. int simple_box::is_simple()
  525. {
  526.   return 1;
  527. }
  528.  
  529. quoted_text_box::quoted_text_box(char *s) : text(s)
  530. {
  531. }
  532.  
  533. quoted_text_box::~quoted_text_box()
  534. {
  535.   a_delete text;
  536. }
  537.  
  538. void quoted_text_box::output()
  539. {
  540.   if (text)
  541.     fputs(text, stdout);
  542. }
  543.  
  544. tab_box::tab_box() : disabled(0)
  545. {
  546. }
  547.  
  548. // We treat a tab_box as having width 0 for width computations.
  549.  
  550. void tab_box::output()
  551. {
  552.   if (!disabled)
  553.     printf("\\t");
  554. }
  555.  
  556. void tab_box::check_tabs(int level)
  557. {
  558.   if (level > 0) {
  559.     error("tabs allowed only at outermost level");
  560.     disabled = 1;
  561.   }
  562. }
  563.  
  564. space_box::space_box()
  565. {
  566.   spacing_type = SUPPRESS_TYPE;
  567. }
  568.  
  569. void space_box::output()
  570. {
  571.   printf("\\h'%dM'", thick_space);
  572. }
  573.  
  574. half_space_box::half_space_box()
  575. {
  576.   spacing_type = SUPPRESS_TYPE;
  577. }
  578.  
  579. void half_space_box::output()
  580. {
  581.   printf("\\h'%dM'", thin_space);
  582. }
  583.  
  584. void box_list::list_debug_print(const char *sep)
  585. {
  586.   p[0]->debug_print();
  587.   for (int i = 1; i < len; i++) {
  588.     fprintf(stderr, "%s", sep);
  589.     p[i]->debug_print();
  590.   }
  591. }
  592.  
  593. void quoted_text_box::debug_print()
  594. {
  595.   fprintf(stderr, "\"%s\"", (text ? text : ""));
  596. }
  597.  
  598. void half_space_box::debug_print()
  599. {
  600.   fprintf(stderr, "^");
  601. }
  602.  
  603. void space_box::debug_print()
  604. {
  605.   fprintf(stderr, "~");
  606. }
  607.  
  608. void tab_box::debug_print()
  609. {
  610.   fprintf(stderr, "<tab>");
  611. }
  612.