delim.cpp revision 151497
174822Srwatson// -*- C++ -*-
2165890Srwatson/* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc.
374822Srwatson     Written by James Clark (jjc@jclark.com)
474822Srwatson
585845SrwatsonThis file is part of groff.
685845Srwatson
774822Srwatsongroff is free software; you can redistribute it and/or modify it under
874822Srwatsonthe terms of the GNU General Public License as published by the Free
974822SrwatsonSoftware Foundation; either version 2, or (at your option) any later
1074822Srwatsonversion.
1174822Srwatson
1274822Srwatsongroff is distributed in the hope that it will be useful, but WITHOUT ANY
1374822SrwatsonWARRANTY; without even the implied warranty of MERCHANTABILITY or
1474822SrwatsonFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1574822Srwatsonfor more details.
1674822Srwatson
1774822SrwatsonYou should have received a copy of the GNU General Public License along
1874822Srwatsonwith groff; see the file COPYING.  If not, write to the Free Software
1974822SrwatsonFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
2074822Srwatson
2174822Srwatson#include "eqn.h"
2274822Srwatson#include "pbox.h"
2374822Srwatson
2474822Srwatsonenum left_or_right_t { LEFT_DELIM = 01, RIGHT_DELIM = 02 };
2574822Srwatson
2674822Srwatson// Small must be none-zero and must exist in each device.
2774822Srwatson// Small will be put in the roman font, others are assumed to be
28116192Sobrien// on the special font (so no font change will be necessary.)
2974822Srwatson
3074822Srwatsonstruct delimiter {
3174822Srwatson  const char *name;
3274822Srwatson  int flags;
33116192Sobrien  const char *small;
34116192Sobrien  const char *chain_format;
35116192Sobrien  const char *ext;
3674822Srwatson  const char *top;
3774822Srwatson  const char *mid;
3874822Srwatson  const char *bot;
3974822Srwatson} delim_table[] = {
4074822Srwatson  {
4174822Srwatson    "(", LEFT_DELIM|RIGHT_DELIM, "(", "\\[parenleft%s]",
4274822Srwatson    "\\[parenleftex]",
4374822Srwatson    "\\[parenlefttp]",
4474822Srwatson    0,
4574822Srwatson    "\\[parenleftbt]",
4674822Srwatson  },
4774822Srwatson  {
4874822Srwatson    ")", LEFT_DELIM|RIGHT_DELIM, ")", "\\[parenright%s]",
4974822Srwatson    "\\[parenrightex]",
5074822Srwatson    "\\[parenrighttp]",
5174822Srwatson    0,
5274822Srwatson    "\\[parenrightbt]",
5374822Srwatson  },
5474822Srwatson  {
5574822Srwatson    "[", LEFT_DELIM|RIGHT_DELIM, "[", "\\[bracketleft%s]",
56184629Strasz    "\\[bracketleftex]",
5774822Srwatson    "\\[bracketlefttp]",
5874822Srwatson    0,
5974822Srwatson    "\\[bracketleftbt]",
6074822Srwatson  },
6174822Srwatson  {
6274822Srwatson    "]", LEFT_DELIM|RIGHT_DELIM, "]", "\\[bracketright%s]",
6374822Srwatson    "\\[bracketrightex]",
6474822Srwatson    "\\[bracketrighttp]",
6574822Srwatson    0,
6674822Srwatson    "\\[bracketrightbt]",
6774822Srwatson  },
6874822Srwatson  {
6974822Srwatson    "{", LEFT_DELIM|RIGHT_DELIM, "{", "\\[braceleft%s]",
7074822Srwatson    "\\[braceleftex]",
7174822Srwatson    "\\[bracelefttp]",
7274822Srwatson    "\\[braceleftmid]",
7374822Srwatson    "\\[braceleftbt]",
7474822Srwatson  },
7574822Srwatson  {
7674822Srwatson    "}", LEFT_DELIM|RIGHT_DELIM, "}", "\\[braceright%s]",
7774822Srwatson    "\\[bracerightex]",
7874822Srwatson    "\\[bracerighttp]",
7974822Srwatson    "\\[bracerightmid]",
8074822Srwatson    "\\[bracerightbt]",
8174822Srwatson  },
8274822Srwatson  {
8375571Srwatson    "|", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
8474822Srwatson    "\\[barex]",
8574822Srwatson    0,
8674822Srwatson    0,
8774822Srwatson    0,
8875571Srwatson  },
8974822Srwatson  {
9074822Srwatson    "floor", LEFT_DELIM, "\\(lf", "\\[floorleft%s]",
9174822Srwatson    "\\[bracketleftex]",
9274822Srwatson    0,
9374822Srwatson    0,
9475571Srwatson    "\\[bracketleftbt]",
9574822Srwatson  },
9674822Srwatson  {
9774822Srwatson    "floor", RIGHT_DELIM, "\\(rf", "\\[floorright%s]",
9874822Srwatson    "\\[bracketrightex]",
9975571Srwatson    0,
10074822Srwatson    0,
10174822Srwatson    "\\[bracketrightbt]",
10274822Srwatson  },
10374822Srwatson  {
10474822Srwatson    "ceiling", LEFT_DELIM, "\\(lc", "\\[ceilingleft%s]",
10574822Srwatson    "\\[bracketleftex]",
10674822Srwatson    "\\[bracketlefttp]",
10774822Srwatson    0,
10874822Srwatson    0,
10974822Srwatson  },
11074822Srwatson  {
11174822Srwatson    "ceiling", RIGHT_DELIM, "\\(rc", "\\[ceilingright%s]",
11274822Srwatson    "\\[bracketrightex]",
11374822Srwatson    "\\[bracketrighttp]",
11474822Srwatson    0,
11574822Srwatson    0,
11674822Srwatson  },
11774822Srwatson  {
11874822Srwatson    "||", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]",
11974822Srwatson    "\\[bardblex]",
12074822Srwatson    0,
12174822Srwatson    0,
12274822Srwatson    0,
12374822Srwatson  },
12474822Srwatson  {
12574822Srwatson    "<", LEFT_DELIM|RIGHT_DELIM, "\\(la", "\\[angleleft%s]",
12674822Srwatson    0,
12774822Srwatson    0,
12874822Srwatson    0,
12974822Srwatson    0,
130118411Srwatson  },
131118411Srwatson  {
132118411Srwatson    ">", LEFT_DELIM|RIGHT_DELIM, "\\(ra", "\\[angleright%s]",
13374822Srwatson    0,
13474822Srwatson    0,
135118411Srwatson    0,
13674822Srwatson    0,
13774822Srwatson  },
138118411Srwatson  {
139118411Srwatson    "uparrow", LEFT_DELIM|RIGHT_DELIM, "\\(ua", "\\[arrowup%s]",
140132775Skan    "\\[arrowvertex]",
14174822Srwatson    "\\[arrowverttp]",
14274822Srwatson    0,
14374822Srwatson    0,
14474822Srwatson  },
14574822Srwatson  {
14674822Srwatson    "downarrow", LEFT_DELIM|RIGHT_DELIM, "\\(da", "\\[arrowdown%s]",
14774822Srwatson    "\\[arrowvertex]",
14874822Srwatson    0,
14974822Srwatson    0,
15074822Srwatson    "\\[arrowvertbt]",
15174822Srwatson  },
15274822Srwatson  {
15374822Srwatson    "updownarrow", LEFT_DELIM|RIGHT_DELIM, "\\(va", "\\[arrowupdown%s]",
15474822Srwatson    "\\[arrowvertex]",
15574822Srwatson    "\\[arrowverttp]",
15674822Srwatson    0,
15783366Sjulian    "\\[arrowvertbt]",
15874822Srwatson  },
15974822Srwatson};
16074822Srwatson
16174822Srwatsonconst int DELIM_TABLE_SIZE = int(sizeof(delim_table)/sizeof(delim_table[0]));
16274822Srwatson
163105179Srwatsonclass delim_box : public box {
164105179Srwatsonprivate:
165105179Srwatson  char *left;
166105179Srwatson  char *right;
167105179Srwatson  box *p;
168105179Srwatsonpublic:
16974822Srwatson  delim_box(char *, box *, char *);
17074822Srwatson  ~delim_box();
17174822Srwatson  int compute_metrics(int);
17274822Srwatson  void output();
17374822Srwatson  void check_tabs(int);
17475077Srwatson  void debug_print();
17574822Srwatson};
17674822Srwatson
17774822Srwatsonbox *make_delim_box(char *l, box *pp, char *r)
17874822Srwatson{
17974822Srwatson  if (l != 0 && *l == '\0') {
18074822Srwatson    a_delete l;
18174822Srwatson    l = 0;
18274822Srwatson  }
18374822Srwatson  if (r != 0 && *r == '\0') {
18474822Srwatson    a_delete r;
18574822Srwatson    r = 0;
18674822Srwatson  }
18783366Sjulian  return new delim_box(l, pp, r);
18874822Srwatson}
18996755Strhodes
19074822Srwatsondelim_box::delim_box(char *l, box *pp, char *r)
19191814Sgreen: left(l), right(r), p(pp)
19274822Srwatson{
19374822Srwatson}
19474822Srwatson
19574822Srwatsondelim_box::~delim_box()
19674822Srwatson{
19774822Srwatson  a_delete left;
19874822Srwatson  a_delete right;
19974822Srwatson  delete p;
20075571Srwatson}
20182770Sjedgar
20274822Srwatsonstatic void build_extensible(const char *ext, const char *top, const char *mid,
20375571Srwatson			     const char *bot)
20482770Sjedgar{
20574822Srwatson  assert(ext != 0);
20675571Srwatson  printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
20782770Sjedgar	 ext);
20874822Srwatson  printf(".nr " EXT_HEIGHT_REG " 0\\n[rst]\n");
20974822Srwatson  printf(".nr " EXT_DEPTH_REG " 0-\\n[rsb]\n");
21074822Srwatson  if (top) {
21174822Srwatson    printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
21274822Srwatson	   ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
21374822Srwatson	   top);
21474822Srwatson    printf(".nr " TOP_HEIGHT_REG " 0\\n[rst]\n");
21574822Srwatson    printf(".nr " TOP_DEPTH_REG " 0-\\n[rsb]\n");
21674822Srwatson  }
21774822Srwatson  if (mid) {
21874822Srwatson    printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
21974822Srwatson	   ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
22074822Srwatson	   mid);
221184629Strasz    printf(".nr " MID_HEIGHT_REG " 0\\n[rst]\n");
222184629Strasz    printf(".nr " MID_DEPTH_REG " 0-\\n[rsb]\n");
22374822Srwatson  }
22474822Srwatson  if (bot) {
22574822Srwatson    printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]"
22674822Srwatson	   ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n",
22774822Srwatson	   bot);
22897724Salfred    printf(".nr " BOT_HEIGHT_REG " 0\\n[rst]\n");
22997724Salfred    printf(".nr " BOT_DEPTH_REG " 0-\\n[rsb]\n");
23074822Srwatson  }
23174822Srwatson  printf(".nr " TOTAL_HEIGHT_REG " 0");
23274822Srwatson  if (top)
23374822Srwatson    printf("+\\n[" TOP_HEIGHT_REG "]+\\n[" TOP_DEPTH_REG "]");
23474822Srwatson  if (bot)
23574822Srwatson    printf("+\\n[" BOT_HEIGHT_REG "]+\\n[" BOT_DEPTH_REG "]");
23674822Srwatson  if (mid)
23774822Srwatson    printf("+\\n[" MID_HEIGHT_REG "]+\\n[" MID_DEPTH_REG "]");
23874822Srwatson  printf("\n");
23974822Srwatson  // determine how many extensible characters we need
24074822Srwatson  printf(".nr " TEMP_REG " \\n[" DELTA_REG "]-\\n[" TOTAL_HEIGHT_REG "]");
24183366Sjulian  if (mid)
24274822Srwatson    printf("/2");
24374822Srwatson  printf(">?0+\\n[" EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "]-1/(\\n["
24474822Srwatson	 EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "])\n");
24574822Srwatson
24674822Srwatson  printf(".nr " TOTAL_HEIGHT_REG " +(\\n[" EXT_HEIGHT_REG "]+\\n["
24774822Srwatson	 EXT_DEPTH_REG "]*\\n[" TEMP_REG "]");
24874822Srwatson  if (mid)
24974822Srwatson    printf("*2");
25096755Strhodes  printf(")\n");
25174822Srwatson  printf(".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
25291814Sgreen	 "\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG "]u/2u)'\n",
25374822Srwatson	 axis_height);
25474822Srwatson  if (top)
25574822Srwatson    printf(".as " DELIM_STRING " \\v'\\n[" TOP_HEIGHT_REG "]u'"
25674822Srwatson	   "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
25774822Srwatson	   "\\v'\\n[" TOP_DEPTH_REG "]u'\n",
25874822Srwatson	   top);
25975077Srwatson
26075077Srwatson  // this macro appends $2 copies of $3 to string $1
26175077Srwatson  printf(".de " REPEAT_APPEND_STRING_MACRO "\n"
26275077Srwatson	 ".if \\\\$2 \\{.as \\\\$1 \"\\\\$3\n"
26375077Srwatson	 "." REPEAT_APPEND_STRING_MACRO " \\\\$1 \\\\$2-1 \"\\\\$3\"\n"
26475077Srwatson	 ".\\}\n"
26575077Srwatson	 "..\n");
26675077Srwatson
267184629Strasz  printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING " \\n[" TEMP_REG "] "
268184629Strasz	 "\\v'\\n[" EXT_HEIGHT_REG "]u'"
26975077Srwatson	 "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
27075077Srwatson	 "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
27174822Srwatson	 ext);
27274822Srwatson
27397724Salfred  if (mid) {
27497724Salfred    printf(".as " DELIM_STRING " \\v'\\n[" MID_HEIGHT_REG "]u'"
27574822Srwatson	   "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
27674822Srwatson	   "\\v'\\n[" MID_DEPTH_REG "]u'\n",
27774822Srwatson	   mid);
27874822Srwatson    printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING
27974822Srwatson	   " \\n[" TEMP_REG "] "
28074822Srwatson	   "\\v'\\n[" EXT_HEIGHT_REG "]u'"
28174822Srwatson	   "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
28274822Srwatson	   "\\v'\\n[" EXT_DEPTH_REG "]u'\n",
28374822Srwatson	   ext);
28474822Srwatson  }
28574822Srwatson  if (bot)
28674822Srwatson    printf(".as " DELIM_STRING " \\v'\\n[" BOT_HEIGHT_REG "]u'"
28774822Srwatson	   "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR
28874822Srwatson	   "\\v'\\n[" BOT_DEPTH_REG "]u'\n",
28974822Srwatson	   bot);
29074822Srwatson  printf(".as " DELIM_STRING " " DELIMITER_CHAR "\n");
29174822Srwatson}
29274822Srwatson
29374822Srwatsonstatic void define_extensible_string(char *delim, int uid,
29474822Srwatson				     left_or_right_t left_or_right)
29574822Srwatson{
29674822Srwatson  printf(".ds " DELIM_STRING "\n");
29774822Srwatson  delimiter *d = delim_table;
29874822Srwatson  int delim_len = strlen(delim);
29974822Srwatson  int i;
30074822Srwatson  for (i = 0; i < DELIM_TABLE_SIZE; i++, d++)
30174822Srwatson    if (strncmp(delim, d->name, delim_len) == 0
30274822Srwatson	&& (left_or_right & d->flags) != 0)
30374822Srwatson      break;
30474822Srwatson  if (i >= DELIM_TABLE_SIZE) {
30575571Srwatson    error("there is no `%1' delimiter", delim);
30674822Srwatson    printf(".nr " DELIM_WIDTH_REG " 0\n");
307105179Srwatson    return;
308105179Srwatson  }
309105179Srwatson
31074822Srwatson  printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
31174822Srwatson	 ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
31274822Srwatson	   "\\v'\\n[rsb]u+\\n[rst]u/2u-%dM'\\f[%s]%s\\fP" DELIMITER_CHAR "\n"
31374822Srwatson	 ".nr " TOTAL_HEIGHT_REG " \\n[rst]-\\n[rsb]\n"
31474822Srwatson	 ".if \\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
31574822Srwatson	 "\\{",
31674822Srwatson	 current_roman_font, d->small, axis_height,
31774822Srwatson	 current_roman_font, d->small);
31874822Srwatson
31974822Srwatson  char buf[256];
32083366Sjulian  sprintf(buf, d->chain_format, "\\\\n[" INDEX_REG "]");
32174822Srwatson  printf(".nr " INDEX_REG " 0\n"
32274822Srwatson	 ".de " TEMP_MACRO "\n"
32374822Srwatson	 ".ie c%s \\{\\\n"
32474822Srwatson	 ".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n"
32574822Srwatson	 ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR
32674822Srwatson	   "\\v'\\\\n[rsb]u+\\\\n[rst]u/2u-%dM'%s" DELIMITER_CHAR "\n"
32774822Srwatson	 ".nr " TOTAL_HEIGHT_REG " \\\\n[rst]-\\\\n[rsb]\n"
32874822Srwatson	 ".if \\\\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] "
32974822Srwatson	 "\\{.nr " INDEX_REG " +1\n"
33074822Srwatson	 "." TEMP_MACRO "\n"
33174822Srwatson	 ".\\}\\}\n"
33274822Srwatson	 ".el .nr " INDEX_REG " 0-1\n"
33374822Srwatson	 "..\n"
33474822Srwatson	 "." TEMP_MACRO "\n",
33574822Srwatson	 buf, buf, axis_height, buf);
33674822Srwatson  if (d->ext) {
33774822Srwatson    printf(".if \\n[" INDEX_REG "]<0 \\{.if c%s \\{\\\n", d->ext);
33874822Srwatson    build_extensible(d->ext, d->top, d->mid, d->bot);
33974822Srwatson    printf(".\\}\\}\n");
34074822Srwatson  }
34174822Srwatson  printf(".\\}\n");
34274822Srwatson  printf(".as " DELIM_STRING " \\h'\\n[" DELIM_WIDTH_REG "]u'\n");
34374822Srwatson  printf(".nr " WIDTH_FORMAT " +\\n[" DELIM_WIDTH_REG "]\n", uid);
34474822Srwatson  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]"
34574822Srwatson	 ">?(\\n[" TOTAL_HEIGHT_REG "]/2+%dM)\n",
34674822Srwatson	 uid, uid, axis_height);
34783366Sjulian  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
34874822Srwatson	 ">?(\\n[" TOTAL_HEIGHT_REG "]/2-%dM)\n",
34974822Srwatson	 uid, uid, axis_height);
35074822Srwatson}
35174822Srwatson
35274822Srwatsonint delim_box::compute_metrics(int style)
35374822Srwatson{
35474822Srwatson  int r = p->compute_metrics(style);
35583366Sjulian  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
35674822Srwatson  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
35774822Srwatson  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
35874822Srwatson  printf(".nr " DELTA_REG " \\n[" HEIGHT_FORMAT "]-%dM"
35974822Srwatson	 ">?(\\n[" DEPTH_FORMAT "]+%dM)\n",
36074822Srwatson	 p->uid, axis_height, p->uid, axis_height);
36174822Srwatson  printf(".nr " DELTA_REG " 0\\n[" DELTA_REG "]*%d/500"
36283366Sjulian	 ">?(\\n[" DELTA_REG "]*2-%dM)\n",
36374822Srwatson	 delimiter_factor, delimiter_shortfall);
36474822Srwatson  if (left) {
36574822Srwatson    define_extensible_string(left, uid, LEFT_DELIM);
36674822Srwatson    printf(".rn " DELIM_STRING " " LEFT_DELIM_STRING_FORMAT "\n",
36785581Srwatson	   uid);
36885581Srwatson    if (r)
36985581Srwatson      printf(".nr " MARK_REG " +\\n[" DELIM_WIDTH_REG "]\n");
37085581Srwatson  }
37191814Sgreen  if (right) {
37274822Srwatson    define_extensible_string(right, uid, RIGHT_DELIM);
37391814Sgreen    printf(".rn " DELIM_STRING " " RIGHT_DELIM_STRING_FORMAT "\n",
37474822Srwatson	   uid);
37574822Srwatson  }
37674822Srwatson  return r;
37774822Srwatson}
37874822Srwatson
37983366Sjulianvoid delim_box::output()
38074822Srwatson{
38174822Srwatson  if (left)
38274822Srwatson    printf("\\*[" LEFT_DELIM_STRING_FORMAT "]", uid);
38374822Srwatson  p->output();
38474822Srwatson  if (right)
38574822Srwatson    printf("\\*[" RIGHT_DELIM_STRING_FORMAT "]", uid);
38674822Srwatson}
38796755Strhodes
38874822Srwatsonvoid delim_box::check_tabs(int level)
38991814Sgreen{
39074822Srwatson  p->check_tabs(level);
39174822Srwatson}
39274822Srwatson
39374822Srwatsonvoid delim_box::debug_print()
39474822Srwatson{
39574822Srwatson  fprintf(stderr, "left \"%s\" { ", left ? left : "");
39674822Srwatson  p->debug_print();
39774822Srwatson  fprintf(stderr, " }");
39874822Srwatson  if (right)
399118411Srwatson    fprintf(stderr, " right \"%s\"", right);
40074822Srwatson}
40174822Srwatson
40274822Srwatson