home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / eqn / delim.cc < prev    next >
C/C++ Source or Header  |  1995-06-22  |  11KB  |  382 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. enum left_or_right_t { LEFT_DELIM = 01, RIGHT_DELIM = 02 };
  25.  
  26. // Small must be none-zero and must exist in each device.
  27. // Small will be put in the roman font, others are assumed to be
  28. // on the special font (so no font change will be necessary.)
  29.  
  30. struct delimiter {
  31.   const char *name;
  32.   int flags;
  33.   const char *small;
  34.   const char *chain_format;
  35.   const char *ext;
  36.   const char *top;
  37.   const char *mid;
  38.   const char *bot;
  39. } delim_table[] = {
  40.   {
  41.     "(", LEFT_DELIM|RIGHT_DELIM, "(", "\\[parenleft%s]",
  42.     "\\[parenleftex]",
  43.     "\\[parenlefttp]",
  44.     0,
  45.     "\\[parenleftbt]",
  46.   },
  47.   {
  48.     ")", LEFT_DELIM|RIGHT_DELIM, ")", "\\[parenright%s]",
  49.     "\\[parenrightex]",
  50.     "\\[parenrighttp]",
  51.     0,
  52.     "\\[parenrightbt]",
  53.   },
  54.   {
  55.     "[", LEFT_DELIM|RIGHT_DELIM, "[", "\\[bracketleft%s]",
  56.     "\\[bracketleftex]",
  57.     "\\[bracketlefttp]",
  58.     0,
  59.     "\\[bracketleftbt]",
  60.   },
  61.   {
  62.     "]", LEFT_DELIM|RIGHT_DELIM, "]", "\\[bracketright%s]",
  63.     "\\[bracketrightex]",
  64.     "\\[bracketrighttp]",
  65.     0,
  66.     "\\[bracketrightbt]",
  67.   },
  68.   {
  69.     "{", LEFT_DELIM|RIGHT_DELIM, "{", "\\[braceleft%s]",
  70.     "\\[braceleftex]",
  71.     "\\[bracelefttp]",
  72.     "\\[braceleftmid]",
  73.     "\\[braceleftbt]",
  74.   },
  75.   {
  76.     "}", LEFT_DELIM|RIGHT_DELIM, "}", "\\[braceright%s]",
  77.     "\\[bracerightex]",
  78.     "\\[bracerighttp]",
  79.     "\\[bracerightmid]",
  80.     "\\[bracerightbt]",
  81.   },
  82.   {
  83.     "|", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
  84.     "\\[barex]",
  85.   },
  86.   {
  87.     "floor", LEFT_DELIM, "\\(lf", "\\[floorleft%s]",
  88.     "\\[bracketleftex]",
  89.     0,
  90.     0,
  91.     "\\[bracketleftbt]",
  92.   },
  93.   {
  94.     "floor", RIGHT_DELIM, "\\(rf", "\\[floorright%s]",
  95.     "\\[bracketrightex]",
  96.     0,
  97.     0,
  98.     "\\[bracketrightbt]",
  99.   },
  100.   {
  101.     "ceiling", LEFT_DELIM, "\\(lc", "\\[ceilingleft%s]",
  102.     "\\[bracketleftex]",
  103.     "\\[bracketlefttp]",
  104.   },
  105.   {
  106.     "ceiling", RIGHT_DELIM, "\\(rc", "\\[ceilingright%s]",
  107.     "\\[bracketrightex]",
  108.     "\\[bracketrighttp]",
  109.   },
  110.   {
  111.     "||", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
  112.     "\\[bardblex]",
  113.   },
  114.   {
  115.     "<", LEFT_DELIM|RIGHT_DELIM, "\\(la", "\\[angleleft%s]",
  116.   },
  117.   {
  118.     ">", LEFT_DELIM|RIGHT_DELIM, "\\(ra", "\\[angleright%s]",
  119.   },
  120.   {
  121.     "uparrow", LEFT_DELIM|RIGHT_DELIM, "\\(ua", "\\[arrowup%s]",
  122.     "\\[arrowvertex]",
  123.     "\\[arrowverttp]",
  124.   },
  125.   {
  126.     "downarrow", LEFT_DELIM|RIGHT_DELIM, "\\(da", "\\[arrowdown%s]",
  127.     "\\[arrowvertex]",
  128.     0,
  129.     0,
  130.     "\\[arrowvertbt]",
  131.   },
  132.   {
  133.     "updownarrow", LEFT_DELIM|RIGHT_DELIM, "\\(va", "\\[arrowupdown%s]",
  134.     "\\[arrowvertex]",
  135.     "\\[arrowverttp]",
  136.     0,
  137.     "\\[arrowvertbt]",
  138.   },
  139. };
  140.  
  141. const int DELIM_TABLE_SIZE = int(sizeof(delim_table)/sizeof(delim_table[0]));
  142.  
  143. class delim_box : public box {
  144. private:
  145.   char *left;
  146.   char *right;
  147.   box *p;
  148. public:
  149.   delim_box(char *, box *, char *);
  150.   ~delim_box();
  151.   int compute_metrics(int);
  152.   void output();
  153.   void check_tabs(int);
  154.   void debug_print();
  155. };
  156.  
  157. box *make_delim_box(char *l, box *pp, char *r)
  158. {
  159.   if (l != 0 && *l == '\0') {
  160.     a_delete l;
  161.     l = 0;
  162.   }
  163.   if (r != 0 && *r == '\0') {
  164.     a_delete r;
  165.     r = 0;
  166.   }
  167.   return new delim_box(l, pp, r);
  168. }
  169.  
  170. delim_box::delim_box(char *l, box *pp, char *r)
  171. : left(l), right(r), p(pp)
  172. {
  173. }
  174.  
  175. delim_box::~delim_box()
  176. {
  177.   a_delete left;
  178.   a_delete right;
  179.   delete p;
  180. }
  181.  
  182. static void build_extensible(const char *ext, const char *top, const char *mid,
  183.                  const char *bot)
  184. {
  185.   assert(ext != 0);
  186.   printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
  187.      ext);
  188.   printf(".nr " EXT_HEIGHT_REG " 0\\n[rst]\n");
  189.   printf(".nr " EXT_DEPTH_REG " 0-\\n[rsb]\n");
  190.   if (top) {
  191.     printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
  192.        ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
  193.        top);
  194.     printf(".nr " TOP_HEIGHT_REG " 0\\n[rst]\n");
  195.     printf(".nr " TOP_DEPTH_REG " 0-\\n[rsb]\n");
  196.   }
  197.   if (mid) {
  198.     printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
  199.        ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
  200.        mid);
  201.     printf(".nr " MID_HEIGHT_REG " 0\\n[rst]\n");
  202.     printf(".nr " MID_DEPTH_REG " 0-\\n[rsb]\n");
  203.   }
  204.   if (bot) {
  205.     printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
  206.        ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
  207.        bot);
  208.     printf(".nr " BOT_HEIGHT_REG " 0\\n[rst]\n");
  209.     printf(".nr " BOT_DEPTH_REG " 0-\\n[rsb]\n");
  210.   }
  211.   printf(".nr " TOTAL_HEIGHT_REG " 0");
  212.   if (top)
  213.     printf("+\\n[" TOP_HEIGHT_REG "]+\\n[" TOP_DEPTH_REG "]");
  214.   if (bot)
  215.     printf("+\\n[" BOT_HEIGHT_REG "]+\\n[" BOT_DEPTH_REG "]");
  216.   if (mid)
  217.     printf("+\\n[" MID_HEIGHT_REG "]+\\n[" MID_DEPTH_REG "]");
  218.   printf("\n");
  219.   // determine how many extensible characters we need
  220.   printf(".nr " TEMP_REG " \\n[" DELTA_REG "]-\\n[" TOTAL_HEIGHT_REG "]");
  221.   if (mid)
  222.     printf("/2");
  223.   printf(">?0+\\n[" EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "]-1/(\\n["
  224.      EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "])\n");
  225.   
  226.   printf(".nr " TOTAL_HEIGHT_REG " +(\\n[" EXT_HEIGHT_REG "]+\\n["
  227.      EXT_DEPTH_REG "]*\\n[" TEMP_REG "]");
  228.   if (mid)
  229.     printf("*2");
  230.   printf(")\n");
  231.   printf(".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
  232.      "\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG "]u/2u)'\n",
  233.      axis_height);
  234.   if (top)
  235.     printf(".as " DELIM_STRING " \\v'\\n[" TOP_HEIGHT_REG "]u'"
  236.        "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
  237.        "\\v'\\n[" TOP_DEPTH_REG "]u'\n",
  238.        top);
  239.  
  240.   // this macro appends $2 copies of $3 to string $1
  241.   printf(".de " REPEAT_APPEND_STRING_MACRO "\n"
  242.      ".if \\\\$2 \\{.as \\\\$1 \"\\\\$3\n"
  243.      "." REPEAT_APPEND_STRING_MACRO " \\\\$1 \\\\$2-1 \"\\\\$3\"\n"
  244.      ".\\}\n"
  245.      "..\n");
  246.  
  247.   printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING " \\n[" TEMP_REG "] "
  248.      "\\v'\\n[" EXT_HEIGHT_REG "]u'"
  249.      "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR 
  250.      "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
  251.      ext);
  252.  
  253.   if (mid) {
  254.     printf(".as " DELIM_STRING " \\v'\\n[" MID_HEIGHT_REG "]u'"
  255.        "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
  256.        "\\v'\\n[" MID_DEPTH_REG "]u'\n",
  257.        mid);
  258.     printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING 
  259.        " \\n[" TEMP_REG "] "
  260.        "\\v'\\n[" EXT_HEIGHT_REG "]u'"
  261.        "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
  262.        "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
  263.        ext);
  264.   }
  265.   if (bot)
  266.     printf(".as " DELIM_STRING " \\v'\\n[" BOT_HEIGHT_REG "]u'"
  267.        "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
  268.        "\\v'\\n[" BOT_DEPTH_REG "]u'\n",
  269.        bot);
  270.   printf(".as " DELIM_STRING " " DELIMITER_CHAR "\n");
  271. }
  272.  
  273. static void define_extensible_string(char *delim, int uid,
  274.                      left_or_right_t left_or_right)
  275. {
  276.   printf(".ds " DELIM_STRING "\n");
  277.   delimiter *d = delim_table;
  278.   int delim_len = strlen(delim);
  279.   int i;
  280.   for (i = 0; i < DELIM_TABLE_SIZE; i++, d++)
  281.     if (strncmp(delim, d->name, delim_len) == 0 
  282.     && (left_or_right & d->flags) != 0)
  283.       break;
  284.   if (i >= DELIM_TABLE_SIZE) {
  285.     error("there is no `%1' delimiter", delim);
  286.     printf(".nr " DELIM_WIDTH_REG " 0\n");
  287.     return;
  288.   }
  289.  
  290.   printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
  291.      ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
  292.        "\\v'\\n[rsb]u+\\n[rst]u/2u-%dM'\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
  293.      ".nr " TOTAL_HEIGHT_REG " \\n[rst]-\\n[rsb]\n"
  294.      ".if \\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
  295.      "\\{",
  296.      current_roman_font, d->small, axis_height,
  297.      current_roman_font, d->small);
  298.      
  299.   char buf[256];
  300.   sprintf(buf, d->chain_format, "\\\\n[" INDEX_REG "]");
  301.   printf(".nr " INDEX_REG " 0\n"
  302.      ".de " TEMP_MACRO "\n"
  303.      ".ie c%s \\{\\\n"
  304.      ".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n"
  305.      ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
  306.        "\\v'\\\\n[rsb]u+\\\\n[rst]u/2u-%dM'%s" DELIMITER_CHAR "\n"
  307.      ".nr " TOTAL_HEIGHT_REG " \\\\n[rst]-\\\\n[rsb]\n"
  308.      ".if \\\\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
  309.      "\\{.nr " INDEX_REG " +1\n"
  310.      "." TEMP_MACRO "\n"
  311.      ".\\}\\}\n"
  312.      ".el .nr " INDEX_REG " 0-1\n"
  313.      "..\n"
  314.      "." TEMP_MACRO "\n",
  315.      buf, buf, axis_height, buf);
  316.   if (d->ext) {
  317.     printf(".if \\n[" INDEX_REG "]<0 \\{.if c%s \\{\\\n", d->ext);
  318.     build_extensible(d->ext, d->top, d->mid, d->bot);
  319.     printf(".\\}\\}\n");
  320.   }
  321.   printf(".\\}\n");
  322.   printf(".as " DELIM_STRING " \\h'\\n[" DELIM_WIDTH_REG "]u'\n");
  323.   printf(".nr " WIDTH_FORMAT " +\\n[" DELIM_WIDTH_REG "]\n", uid);
  324.   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
  325.      ">?(\\n[" TOTAL_HEIGHT_REG "]/2+%dM)\n",
  326.      uid, uid, axis_height);
  327.   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
  328.      ">?(\\n[" TOTAL_HEIGHT_REG "]/2-%dM)\n",
  329.      uid, uid, axis_height);
  330. }
  331.  
  332. int delim_box::compute_metrics(int style)
  333. {
  334.   int r = p->compute_metrics(style);
  335.   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
  336.   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
  337.   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
  338.   printf(".nr " DELTA_REG " \\n[" HEIGHT_FORMAT "]-%dM"
  339.      ">?(\\n[" DEPTH_FORMAT "]+%dM)\n",
  340.      p->uid, axis_height, p->uid, axis_height);
  341.   printf(".nr " DELTA_REG " 0\\n[" DELTA_REG "]*%d/500"
  342.      ">?(\\n[" DELTA_REG "]*2-%dM)\n",
  343.      delimiter_factor, delimiter_shortfall);
  344.   if (left) {
  345.     define_extensible_string(left, uid, LEFT_DELIM);
  346.     printf(".rn " DELIM_STRING " " LEFT_DELIM_STRING_FORMAT "\n",
  347.        uid);
  348.     if (r)
  349.       printf(".nr " MARK_REG " +\\n[" DELIM_WIDTH_REG "]\n");
  350.   }
  351.   if (right) {
  352.     define_extensible_string(right, uid, RIGHT_DELIM);
  353.     printf(".rn " DELIM_STRING " " RIGHT_DELIM_STRING_FORMAT "\n",
  354.        uid);
  355.   }
  356.   return r;
  357. }
  358.  
  359. void delim_box::output()
  360. {
  361.   if (left)
  362.     printf("\\*[" LEFT_DELIM_STRING_FORMAT "]", uid);
  363.   p->output();
  364.   if (right)
  365.     printf("\\*[" RIGHT_DELIM_STRING_FORMAT "]", uid);
  366. }
  367.  
  368. void delim_box::check_tabs(int level)
  369. {
  370.   p->check_tabs(level);
  371. }
  372.  
  373. void delim_box::debug_print()
  374. {
  375.   fprintf(stderr, "left \"%s\" { ", left ? left : "");
  376.   p->debug_print();
  377.   fprintf(stderr, " }");
  378.   if (right)
  379.     fprintf(stderr, " right \"%s\"", right);
  380. }
  381.  
  382.