Home | History | Annotate | Line # | Download | only in eqn
      1 /*	$NetBSD: delim.cpp,v 1.1.1.1 2016/01/13 18:41:49 christos Exp $	*/
      2 
      3 // -*- C++ -*-
      4 /* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc.
      5      Written by James Clark (jjc (at) jclark.com)
      6 
      7 This file is part of groff.
      8 
      9 groff is free software; you can redistribute it and/or modify it under
     10 the terms of the GNU General Public License as published by the Free
     11 Software Foundation; either version 2, or (at your option) any later
     12 version.
     13 
     14 groff is distributed in the hope that it will be useful, but WITHOUT ANY
     15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
     16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     17 for more details.
     18 
     19 You should have received a copy of the GNU General Public License along
     20 with groff; see the file COPYING.  If not, write to the Free Software
     21 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
     22 
     23 #include "eqn.h"
     24 #include "pbox.h"
     25 
     26 enum left_or_right_t { LEFT_DELIM = 01, RIGHT_DELIM = 02 };
     27 
     28 // Small must be none-zero and must exist in each device.
     29 // Small will be put in the roman font, others are assumed to be
     30 // on the special font (so no font change will be necessary.)
     31 
     32 struct delimiter {
     33   const char *name;
     34   int flags;
     35   const char *small;
     36   const char *chain_format;
     37   const char *ext;
     38   const char *top;
     39   const char *mid;
     40   const char *bot;
     41 } delim_table[] = {
     42   {
     43     "(", LEFT_DELIM|RIGHT_DELIM, "(", "\\[parenleft%s]",
     44     "\\[parenleftex]",
     45     "\\[parenlefttp]",
     46     0,
     47     "\\[parenleftbt]",
     48   },
     49   {
     50     ")", LEFT_DELIM|RIGHT_DELIM, ")", "\\[parenright%s]",
     51     "\\[parenrightex]",
     52     "\\[parenrighttp]",
     53     0,
     54     "\\[parenrightbt]",
     55   },
     56   {
     57     "[", LEFT_DELIM|RIGHT_DELIM, "[", "\\[bracketleft%s]",
     58     "\\[bracketleftex]",
     59     "\\[bracketlefttp]",
     60     0,
     61     "\\[bracketleftbt]",
     62   },
     63   {
     64     "]", LEFT_DELIM|RIGHT_DELIM, "]", "\\[bracketright%s]",
     65     "\\[bracketrightex]",
     66     "\\[bracketrighttp]",
     67     0,
     68     "\\[bracketrightbt]",
     69   },
     70   {
     71     "{", LEFT_DELIM|RIGHT_DELIM, "{", "\\[braceleft%s]",
     72     "\\[braceleftex]",
     73     "\\[bracelefttp]",
     74     "\\[braceleftmid]",
     75     "\\[braceleftbt]",
     76   },
     77   {
     78     "}", LEFT_DELIM|RIGHT_DELIM, "}", "\\[braceright%s]",
     79     "\\[bracerightex]",
     80     "\\[bracerighttp]",
     81     "\\[bracerightmid]",
     82     "\\[bracerightbt]",
     83   },
     84   {
     85     "|", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
     86     "\\[barex]",
     87     0,
     88     0,
     89     0,
     90   },
     91   {
     92     "floor", LEFT_DELIM, "\\(lf", "\\[floorleft%s]",
     93     "\\[bracketleftex]",
     94     0,
     95     0,
     96     "\\[bracketleftbt]",
     97   },
     98   {
     99     "floor", RIGHT_DELIM, "\\(rf", "\\[floorright%s]",
    100     "\\[bracketrightex]",
    101     0,
    102     0,
    103     "\\[bracketrightbt]",
    104   },
    105   {
    106     "ceiling", LEFT_DELIM, "\\(lc", "\\[ceilingleft%s]",
    107     "\\[bracketleftex]",
    108     "\\[bracketlefttp]",
    109     0,
    110     0,
    111   },
    112   {
    113     "ceiling", RIGHT_DELIM, "\\(rc", "\\[ceilingright%s]",
    114     "\\[bracketrightex]",
    115     "\\[bracketrighttp]",
    116     0,
    117     0,
    118   },
    119   {
    120     "||", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
    121     "\\[bardblex]",
    122     0,
    123     0,
    124     0,
    125   },
    126   {
    127     "<", LEFT_DELIM|RIGHT_DELIM, "\\(la", "\\[angleleft%s]",
    128     0,
    129     0,
    130     0,
    131     0,
    132   },
    133   {
    134     ">", LEFT_DELIM|RIGHT_DELIM, "\\(ra", "\\[angleright%s]",
    135     0,
    136     0,
    137     0,
    138     0,
    139   },
    140   {
    141     "uparrow", LEFT_DELIM|RIGHT_DELIM, "\\(ua", "\\[arrowup%s]",
    142     "\\[arrowvertex]",
    143     "\\[arrowverttp]",
    144     0,
    145     0,
    146   },
    147   {
    148     "downarrow", LEFT_DELIM|RIGHT_DELIM, "\\(da", "\\[arrowdown%s]",
    149     "\\[arrowvertex]",
    150     0,
    151     0,
    152     "\\[arrowvertbt]",
    153   },
    154   {
    155     "updownarrow", LEFT_DELIM|RIGHT_DELIM, "\\(va", "\\[arrowupdown%s]",
    156     "\\[arrowvertex]",
    157     "\\[arrowverttp]",
    158     0,
    159     "\\[arrowvertbt]",
    160   },
    161 };
    162 
    163 const int DELIM_TABLE_SIZE = int(sizeof(delim_table)/sizeof(delim_table[0]));
    164 
    165 class delim_box : public box {
    166 private:
    167   char *left;
    168   char *right;
    169   box *p;
    170 public:
    171   delim_box(char *, box *, char *);
    172   ~delim_box();
    173   int compute_metrics(int);
    174   void output();
    175   void check_tabs(int);
    176   void debug_print();
    177 };
    178 
    179 box *make_delim_box(char *l, box *pp, char *r)
    180 {
    181   if (l != 0 && *l == '\0') {
    182     a_delete l;
    183     l = 0;
    184   }
    185   if (r != 0 && *r == '\0') {
    186     a_delete r;
    187     r = 0;
    188   }
    189   return new delim_box(l, pp, r);
    190 }
    191 
    192 delim_box::delim_box(char *l, box *pp, char *r)
    193 : left(l), right(r), p(pp)
    194 {
    195 }
    196 
    197 delim_box::~delim_box()
    198 {
    199   a_delete left;
    200   a_delete right;
    201   delete p;
    202 }
    203 
    204 static void build_extensible(const char *ext, const char *top, const char *mid,
    205 			     const char *bot)
    206 {
    207   assert(ext != 0);
    208   printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
    209 	 ext);
    210   printf(".nr " EXT_HEIGHT_REG " 0\\n[rst]\n");
    211   printf(".nr " EXT_DEPTH_REG " 0-\\n[rsb]\n");
    212   if (top) {
    213     printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
    214 	   ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
    215 	   top);
    216     printf(".nr " TOP_HEIGHT_REG " 0\\n[rst]\n");
    217     printf(".nr " TOP_DEPTH_REG " 0-\\n[rsb]\n");
    218   }
    219   if (mid) {
    220     printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
    221 	   ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
    222 	   mid);
    223     printf(".nr " MID_HEIGHT_REG " 0\\n[rst]\n");
    224     printf(".nr " MID_DEPTH_REG " 0-\\n[rsb]\n");
    225   }
    226   if (bot) {
    227     printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
    228 	   ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
    229 	   bot);
    230     printf(".nr " BOT_HEIGHT_REG " 0\\n[rst]\n");
    231     printf(".nr " BOT_DEPTH_REG " 0-\\n[rsb]\n");
    232   }
    233   printf(".nr " TOTAL_HEIGHT_REG " 0");
    234   if (top)
    235     printf("+\\n[" TOP_HEIGHT_REG "]+\\n[" TOP_DEPTH_REG "]");
    236   if (bot)
    237     printf("+\\n[" BOT_HEIGHT_REG "]+\\n[" BOT_DEPTH_REG "]");
    238   if (mid)
    239     printf("+\\n[" MID_HEIGHT_REG "]+\\n[" MID_DEPTH_REG "]");
    240   printf("\n");
    241   // determine how many extensible characters we need
    242   printf(".nr " TEMP_REG " \\n[" DELTA_REG "]-\\n[" TOTAL_HEIGHT_REG "]");
    243   if (mid)
    244     printf("/2");
    245   printf(">?0+\\n[" EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "]-1/(\\n["
    246 	 EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "])\n");
    247 
    248   printf(".nr " TOTAL_HEIGHT_REG " +(\\n[" EXT_HEIGHT_REG "]+\\n["
    249 	 EXT_DEPTH_REG "]*\\n[" TEMP_REG "]");
    250   if (mid)
    251     printf("*2");
    252   printf(")\n");
    253   printf(".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
    254 	 "\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG "]u/2u)'\n",
    255 	 axis_height);
    256   if (top)
    257     printf(".as " DELIM_STRING " \\v'\\n[" TOP_HEIGHT_REG "]u'"
    258 	   "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
    259 	   "\\v'\\n[" TOP_DEPTH_REG "]u'\n",
    260 	   top);
    261 
    262   // this macro appends $2 copies of $3 to string $1
    263   printf(".de " REPEAT_APPEND_STRING_MACRO "\n"
    264 	 ".if \\\\$2 \\{.as \\\\$1 \"\\\\$3\n"
    265 	 "." REPEAT_APPEND_STRING_MACRO " \\\\$1 \\\\$2-1 \"\\\\$3\"\n"
    266 	 ".\\}\n"
    267 	 "..\n");
    268 
    269   printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING " \\n[" TEMP_REG "] "
    270 	 "\\v'\\n[" EXT_HEIGHT_REG "]u'"
    271 	 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
    272 	 "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
    273 	 ext);
    274 
    275   if (mid) {
    276     printf(".as " DELIM_STRING " \\v'\\n[" MID_HEIGHT_REG "]u'"
    277 	   "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
    278 	   "\\v'\\n[" MID_DEPTH_REG "]u'\n",
    279 	   mid);
    280     printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING
    281 	   " \\n[" TEMP_REG "] "
    282 	   "\\v'\\n[" EXT_HEIGHT_REG "]u'"
    283 	   "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
    284 	   "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
    285 	   ext);
    286   }
    287   if (bot)
    288     printf(".as " DELIM_STRING " \\v'\\n[" BOT_HEIGHT_REG "]u'"
    289 	   "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
    290 	   "\\v'\\n[" BOT_DEPTH_REG "]u'\n",
    291 	   bot);
    292   printf(".as " DELIM_STRING " " DELIMITER_CHAR "\n");
    293 }
    294 
    295 static void define_extensible_string(char *delim, int uid,
    296 				     left_or_right_t left_or_right)
    297 {
    298   printf(".ds " DELIM_STRING "\n");
    299   delimiter *d = delim_table;
    300   int delim_len = strlen(delim);
    301   int i;
    302   for (i = 0; i < DELIM_TABLE_SIZE; i++, d++)
    303     if (strncmp(delim, d->name, delim_len) == 0
    304 	&& (left_or_right & d->flags) != 0)
    305       break;
    306   if (i >= DELIM_TABLE_SIZE) {
    307     error("there is no `%1' delimiter", delim);
    308     printf(".nr " DELIM_WIDTH_REG " 0\n");
    309     return;
    310   }
    311 
    312   printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
    313 	 ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
    314 	   "\\v'\\n[rsb]u+\\n[rst]u/2u-%dM'\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
    315 	 ".nr " TOTAL_HEIGHT_REG " \\n[rst]-\\n[rsb]\n"
    316 	 ".if \\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
    317 	 "\\{",
    318 	 current_roman_font, d->small, axis_height,
    319 	 current_roman_font, d->small);
    320 
    321   char buf[256];
    322   sprintf(buf, d->chain_format, "\\\\n[" INDEX_REG "]");
    323   printf(".nr " INDEX_REG " 0\n"
    324 	 ".de " TEMP_MACRO "\n"
    325 	 ".ie c%s \\{\\\n"
    326 	 ".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n"
    327 	 ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
    328 	   "\\v'\\\\n[rsb]u+\\\\n[rst]u/2u-%dM'%s" DELIMITER_CHAR "\n"
    329 	 ".nr " TOTAL_HEIGHT_REG " \\\\n[rst]-\\\\n[rsb]\n"
    330 	 ".if \\\\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
    331 	 "\\{.nr " INDEX_REG " +1\n"
    332 	 "." TEMP_MACRO "\n"
    333 	 ".\\}\\}\n"
    334 	 ".el .nr " INDEX_REG " 0-1\n"
    335 	 "..\n"
    336 	 "." TEMP_MACRO "\n",
    337 	 buf, buf, axis_height, buf);
    338   if (d->ext) {
    339     printf(".if \\n[" INDEX_REG "]<0 \\{.if c%s \\{\\\n", d->ext);
    340     build_extensible(d->ext, d->top, d->mid, d->bot);
    341     printf(".\\}\\}\n");
    342   }
    343   printf(".\\}\n");
    344   printf(".as " DELIM_STRING " \\h'\\n[" DELIM_WIDTH_REG "]u'\n");
    345   printf(".nr " WIDTH_FORMAT " +\\n[" DELIM_WIDTH_REG "]\n", uid);
    346   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
    347 	 ">?(\\n[" TOTAL_HEIGHT_REG "]/2+%dM)\n",
    348 	 uid, uid, axis_height);
    349   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
    350 	 ">?(\\n[" TOTAL_HEIGHT_REG "]/2-%dM)\n",
    351 	 uid, uid, axis_height);
    352 }
    353 
    354 int delim_box::compute_metrics(int style)
    355 {
    356   int r = p->compute_metrics(style);
    357   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
    358   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
    359   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
    360   printf(".nr " DELTA_REG " \\n[" HEIGHT_FORMAT "]-%dM"
    361 	 ">?(\\n[" DEPTH_FORMAT "]+%dM)\n",
    362 	 p->uid, axis_height, p->uid, axis_height);
    363   printf(".nr " DELTA_REG " 0\\n[" DELTA_REG "]*%d/500"
    364 	 ">?(\\n[" DELTA_REG "]*2-%dM)\n",
    365 	 delimiter_factor, delimiter_shortfall);
    366   if (left) {
    367     define_extensible_string(left, uid, LEFT_DELIM);
    368     printf(".rn " DELIM_STRING " " LEFT_DELIM_STRING_FORMAT "\n",
    369 	   uid);
    370     if (r)
    371       printf(".nr " MARK_REG " +\\n[" DELIM_WIDTH_REG "]\n");
    372   }
    373   if (right) {
    374     define_extensible_string(right, uid, RIGHT_DELIM);
    375     printf(".rn " DELIM_STRING " " RIGHT_DELIM_STRING_FORMAT "\n",
    376 	   uid);
    377   }
    378   return r;
    379 }
    380 
    381 void delim_box::output()
    382 {
    383   if (left)
    384     printf("\\*[" LEFT_DELIM_STRING_FORMAT "]", uid);
    385   p->output();
    386   if (right)
    387     printf("\\*[" RIGHT_DELIM_STRING_FORMAT "]", uid);
    388 }
    389 
    390 void delim_box::check_tabs(int level)
    391 {
    392   p->check_tabs(level);
    393 }
    394 
    395 void delim_box::debug_print()
    396 {
    397   fprintf(stderr, "left \"%s\" { ", left ? left : "");
    398   p->debug_print();
    399   fprintf(stderr, " }");
    400   if (right)
    401     fprintf(stderr, " right \"%s\"", right);
    402 }
    403 
    404