1114402Sru// -*- C++ -*- 2114402Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc. 3114402Sru Written by James Clark (jjc@jclark.com) 4114402Sru 5114402SruThis file is part of groff. 6114402Sru 7114402Srugroff is free software; you can redistribute it and/or modify it under 8114402Sruthe terms of the GNU General Public License as published by the Free 9114402SruSoftware Foundation; either version 2, or (at your option) any later 10114402Sruversion. 11114402Sru 12114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 13114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 14114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15114402Srufor more details. 16114402Sru 17114402SruYou should have received a copy of the GNU General Public License along 18114402Sruwith groff; see the file COPYING. If not, write to the Free Software 19151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 20114402Sru 21114402Sru#include "eqn.h" 22114402Sru#include "pbox.h" 23114402Sru 24114402Sruenum left_or_right_t { LEFT_DELIM = 01, RIGHT_DELIM = 02 }; 25114402Sru 26114402Sru// Small must be none-zero and must exist in each device. 27114402Sru// Small will be put in the roman font, others are assumed to be 28114402Sru// on the special font (so no font change will be necessary.) 29114402Sru 30114402Srustruct delimiter { 31114402Sru const char *name; 32114402Sru int flags; 33114402Sru const char *small; 34114402Sru const char *chain_format; 35114402Sru const char *ext; 36114402Sru const char *top; 37114402Sru const char *mid; 38114402Sru const char *bot; 39114402Sru} delim_table[] = { 40114402Sru { 41114402Sru "(", LEFT_DELIM|RIGHT_DELIM, "(", "\\[parenleft%s]", 42114402Sru "\\[parenleftex]", 43114402Sru "\\[parenlefttp]", 44114402Sru 0, 45114402Sru "\\[parenleftbt]", 46114402Sru }, 47114402Sru { 48114402Sru ")", LEFT_DELIM|RIGHT_DELIM, ")", "\\[parenright%s]", 49114402Sru "\\[parenrightex]", 50114402Sru "\\[parenrighttp]", 51114402Sru 0, 52114402Sru "\\[parenrightbt]", 53114402Sru }, 54114402Sru { 55114402Sru "[", LEFT_DELIM|RIGHT_DELIM, "[", "\\[bracketleft%s]", 56114402Sru "\\[bracketleftex]", 57114402Sru "\\[bracketlefttp]", 58114402Sru 0, 59114402Sru "\\[bracketleftbt]", 60114402Sru }, 61114402Sru { 62114402Sru "]", LEFT_DELIM|RIGHT_DELIM, "]", "\\[bracketright%s]", 63114402Sru "\\[bracketrightex]", 64114402Sru "\\[bracketrighttp]", 65114402Sru 0, 66114402Sru "\\[bracketrightbt]", 67114402Sru }, 68114402Sru { 69114402Sru "{", LEFT_DELIM|RIGHT_DELIM, "{", "\\[braceleft%s]", 70114402Sru "\\[braceleftex]", 71114402Sru "\\[bracelefttp]", 72114402Sru "\\[braceleftmid]", 73114402Sru "\\[braceleftbt]", 74114402Sru }, 75114402Sru { 76114402Sru "}", LEFT_DELIM|RIGHT_DELIM, "}", "\\[braceright%s]", 77114402Sru "\\[bracerightex]", 78114402Sru "\\[bracerighttp]", 79114402Sru "\\[bracerightmid]", 80114402Sru "\\[bracerightbt]", 81114402Sru }, 82114402Sru { 83114402Sru "|", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]", 84114402Sru "\\[barex]", 85114402Sru 0, 86114402Sru 0, 87114402Sru 0, 88114402Sru }, 89114402Sru { 90114402Sru "floor", LEFT_DELIM, "\\(lf", "\\[floorleft%s]", 91114402Sru "\\[bracketleftex]", 92114402Sru 0, 93114402Sru 0, 94114402Sru "\\[bracketleftbt]", 95114402Sru }, 96114402Sru { 97114402Sru "floor", RIGHT_DELIM, "\\(rf", "\\[floorright%s]", 98114402Sru "\\[bracketrightex]", 99114402Sru 0, 100114402Sru 0, 101114402Sru "\\[bracketrightbt]", 102114402Sru }, 103114402Sru { 104114402Sru "ceiling", LEFT_DELIM, "\\(lc", "\\[ceilingleft%s]", 105114402Sru "\\[bracketleftex]", 106114402Sru "\\[bracketlefttp]", 107114402Sru 0, 108114402Sru 0, 109114402Sru }, 110114402Sru { 111114402Sru "ceiling", RIGHT_DELIM, "\\(rc", "\\[ceilingright%s]", 112114402Sru "\\[bracketrightex]", 113114402Sru "\\[bracketrighttp]", 114114402Sru 0, 115114402Sru 0, 116114402Sru }, 117114402Sru { 118114402Sru "||", LEFT_DELIM|RIGHT_DELIM, "|", "\\[bar%s]", 119114402Sru "\\[bardblex]", 120114402Sru 0, 121114402Sru 0, 122114402Sru 0, 123114402Sru }, 124114402Sru { 125114402Sru "<", LEFT_DELIM|RIGHT_DELIM, "\\(la", "\\[angleleft%s]", 126114402Sru 0, 127114402Sru 0, 128114402Sru 0, 129114402Sru 0, 130114402Sru }, 131114402Sru { 132114402Sru ">", LEFT_DELIM|RIGHT_DELIM, "\\(ra", "\\[angleright%s]", 133114402Sru 0, 134114402Sru 0, 135114402Sru 0, 136114402Sru 0, 137114402Sru }, 138114402Sru { 139114402Sru "uparrow", LEFT_DELIM|RIGHT_DELIM, "\\(ua", "\\[arrowup%s]", 140114402Sru "\\[arrowvertex]", 141114402Sru "\\[arrowverttp]", 142114402Sru 0, 143114402Sru 0, 144114402Sru }, 145114402Sru { 146114402Sru "downarrow", LEFT_DELIM|RIGHT_DELIM, "\\(da", "\\[arrowdown%s]", 147114402Sru "\\[arrowvertex]", 148114402Sru 0, 149114402Sru 0, 150114402Sru "\\[arrowvertbt]", 151114402Sru }, 152114402Sru { 153114402Sru "updownarrow", LEFT_DELIM|RIGHT_DELIM, "\\(va", "\\[arrowupdown%s]", 154114402Sru "\\[arrowvertex]", 155114402Sru "\\[arrowverttp]", 156114402Sru 0, 157114402Sru "\\[arrowvertbt]", 158114402Sru }, 159114402Sru}; 160114402Sru 161114402Sruconst int DELIM_TABLE_SIZE = int(sizeof(delim_table)/sizeof(delim_table[0])); 162114402Sru 163114402Sruclass delim_box : public box { 164114402Sruprivate: 165114402Sru char *left; 166114402Sru char *right; 167114402Sru box *p; 168114402Srupublic: 169114402Sru delim_box(char *, box *, char *); 170114402Sru ~delim_box(); 171114402Sru int compute_metrics(int); 172114402Sru void output(); 173114402Sru void check_tabs(int); 174114402Sru void debug_print(); 175114402Sru}; 176114402Sru 177114402Srubox *make_delim_box(char *l, box *pp, char *r) 178114402Sru{ 179114402Sru if (l != 0 && *l == '\0') { 180114402Sru a_delete l; 181114402Sru l = 0; 182114402Sru } 183114402Sru if (r != 0 && *r == '\0') { 184114402Sru a_delete r; 185114402Sru r = 0; 186114402Sru } 187114402Sru return new delim_box(l, pp, r); 188114402Sru} 189114402Sru 190114402Srudelim_box::delim_box(char *l, box *pp, char *r) 191114402Sru: left(l), right(r), p(pp) 192114402Sru{ 193114402Sru} 194114402Sru 195114402Srudelim_box::~delim_box() 196114402Sru{ 197114402Sru a_delete left; 198114402Sru a_delete right; 199114402Sru delete p; 200114402Sru} 201114402Sru 202114402Srustatic void build_extensible(const char *ext, const char *top, const char *mid, 203114402Sru const char *bot) 204114402Sru{ 205114402Sru assert(ext != 0); 206114402Sru printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", 207114402Sru ext); 208114402Sru printf(".nr " EXT_HEIGHT_REG " 0\\n[rst]\n"); 209114402Sru printf(".nr " EXT_DEPTH_REG " 0-\\n[rsb]\n"); 210114402Sru if (top) { 211114402Sru printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]" 212114402Sru ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", 213114402Sru top); 214114402Sru printf(".nr " TOP_HEIGHT_REG " 0\\n[rst]\n"); 215114402Sru printf(".nr " TOP_DEPTH_REG " 0-\\n[rsb]\n"); 216114402Sru } 217114402Sru if (mid) { 218114402Sru printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]" 219114402Sru ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", 220114402Sru mid); 221114402Sru printf(".nr " MID_HEIGHT_REG " 0\\n[rst]\n"); 222114402Sru printf(".nr " MID_DEPTH_REG " 0-\\n[rsb]\n"); 223114402Sru } 224114402Sru if (bot) { 225114402Sru printf(".nr " DELIM_WIDTH_REG " 0\\n[" DELIM_WIDTH_REG "]" 226114402Sru ">?\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n", 227114402Sru bot); 228114402Sru printf(".nr " BOT_HEIGHT_REG " 0\\n[rst]\n"); 229114402Sru printf(".nr " BOT_DEPTH_REG " 0-\\n[rsb]\n"); 230114402Sru } 231114402Sru printf(".nr " TOTAL_HEIGHT_REG " 0"); 232114402Sru if (top) 233114402Sru printf("+\\n[" TOP_HEIGHT_REG "]+\\n[" TOP_DEPTH_REG "]"); 234114402Sru if (bot) 235114402Sru printf("+\\n[" BOT_HEIGHT_REG "]+\\n[" BOT_DEPTH_REG "]"); 236114402Sru if (mid) 237114402Sru printf("+\\n[" MID_HEIGHT_REG "]+\\n[" MID_DEPTH_REG "]"); 238114402Sru printf("\n"); 239114402Sru // determine how many extensible characters we need 240114402Sru printf(".nr " TEMP_REG " \\n[" DELTA_REG "]-\\n[" TOTAL_HEIGHT_REG "]"); 241114402Sru if (mid) 242114402Sru printf("/2"); 243114402Sru printf(">?0+\\n[" EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "]-1/(\\n[" 244114402Sru EXT_HEIGHT_REG "]+\\n[" EXT_DEPTH_REG "])\n"); 245114402Sru 246114402Sru printf(".nr " TOTAL_HEIGHT_REG " +(\\n[" EXT_HEIGHT_REG "]+\\n[" 247114402Sru EXT_DEPTH_REG "]*\\n[" TEMP_REG "]"); 248114402Sru if (mid) 249114402Sru printf("*2"); 250114402Sru printf(")\n"); 251114402Sru printf(".ds " DELIM_STRING " \\Z" DELIMITER_CHAR 252114402Sru "\\v'-%dM-(\\n[" TOTAL_HEIGHT_REG "]u/2u)'\n", 253114402Sru axis_height); 254114402Sru if (top) 255114402Sru printf(".as " DELIM_STRING " \\v'\\n[" TOP_HEIGHT_REG "]u'" 256114402Sru "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR 257114402Sru "\\v'\\n[" TOP_DEPTH_REG "]u'\n", 258114402Sru top); 259114402Sru 260114402Sru // this macro appends $2 copies of $3 to string $1 261114402Sru printf(".de " REPEAT_APPEND_STRING_MACRO "\n" 262114402Sru ".if \\\\$2 \\{.as \\\\$1 \"\\\\$3\n" 263114402Sru "." REPEAT_APPEND_STRING_MACRO " \\\\$1 \\\\$2-1 \"\\\\$3\"\n" 264114402Sru ".\\}\n" 265114402Sru "..\n"); 266114402Sru 267114402Sru printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING " \\n[" TEMP_REG "] " 268114402Sru "\\v'\\n[" EXT_HEIGHT_REG "]u'" 269114402Sru "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR 270114402Sru "\\v'\\n[" EXT_DEPTH_REG "]u'\n", 271114402Sru ext); 272114402Sru 273114402Sru if (mid) { 274114402Sru printf(".as " DELIM_STRING " \\v'\\n[" MID_HEIGHT_REG "]u'" 275114402Sru "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR 276114402Sru "\\v'\\n[" MID_DEPTH_REG "]u'\n", 277114402Sru mid); 278114402Sru printf("." REPEAT_APPEND_STRING_MACRO " " DELIM_STRING 279114402Sru " \\n[" TEMP_REG "] " 280114402Sru "\\v'\\n[" EXT_HEIGHT_REG "]u'" 281114402Sru "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR 282114402Sru "\\v'\\n[" EXT_DEPTH_REG "]u'\n", 283114402Sru ext); 284114402Sru } 285114402Sru if (bot) 286114402Sru printf(".as " DELIM_STRING " \\v'\\n[" BOT_HEIGHT_REG "]u'" 287114402Sru "\\Z" DELIMITER_CHAR "%s" DELIMITER_CHAR 288114402Sru "\\v'\\n[" BOT_DEPTH_REG "]u'\n", 289114402Sru bot); 290114402Sru printf(".as " DELIM_STRING " " DELIMITER_CHAR "\n"); 291114402Sru} 292114402Sru 293114402Srustatic void define_extensible_string(char *delim, int uid, 294114402Sru left_or_right_t left_or_right) 295114402Sru{ 296114402Sru printf(".ds " DELIM_STRING "\n"); 297114402Sru delimiter *d = delim_table; 298114402Sru int delim_len = strlen(delim); 299114402Sru int i; 300114402Sru for (i = 0; i < DELIM_TABLE_SIZE; i++, d++) 301114402Sru if (strncmp(delim, d->name, delim_len) == 0 302114402Sru && (left_or_right & d->flags) != 0) 303114402Sru break; 304114402Sru if (i >= DELIM_TABLE_SIZE) { 305114402Sru error("there is no `%1' delimiter", delim); 306114402Sru printf(".nr " DELIM_WIDTH_REG " 0\n"); 307114402Sru return; 308114402Sru } 309114402Sru 310114402Sru printf(".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "\\f[%s]%s\\fP" DELIMITER_CHAR "\n" 311114402Sru ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR 312114402Sru "\\v'\\n[rsb]u+\\n[rst]u/2u-%dM'\\f[%s]%s\\fP" DELIMITER_CHAR "\n" 313114402Sru ".nr " TOTAL_HEIGHT_REG " \\n[rst]-\\n[rsb]\n" 314114402Sru ".if \\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] " 315114402Sru "\\{", 316114402Sru current_roman_font, d->small, axis_height, 317114402Sru current_roman_font, d->small); 318114402Sru 319114402Sru char buf[256]; 320114402Sru sprintf(buf, d->chain_format, "\\\\n[" INDEX_REG "]"); 321114402Sru printf(".nr " INDEX_REG " 0\n" 322114402Sru ".de " TEMP_MACRO "\n" 323114402Sru ".ie c%s \\{\\\n" 324114402Sru ".nr " DELIM_WIDTH_REG " 0\\w" DELIMITER_CHAR "%s" DELIMITER_CHAR "\n" 325114402Sru ".ds " DELIM_STRING " \\Z" DELIMITER_CHAR 326114402Sru "\\v'\\\\n[rsb]u+\\\\n[rst]u/2u-%dM'%s" DELIMITER_CHAR "\n" 327114402Sru ".nr " TOTAL_HEIGHT_REG " \\\\n[rst]-\\\\n[rsb]\n" 328114402Sru ".if \\\\n[" TOTAL_HEIGHT_REG "]<\\n[" DELTA_REG "] " 329114402Sru "\\{.nr " INDEX_REG " +1\n" 330114402Sru "." TEMP_MACRO "\n" 331114402Sru ".\\}\\}\n" 332114402Sru ".el .nr " INDEX_REG " 0-1\n" 333114402Sru "..\n" 334114402Sru "." TEMP_MACRO "\n", 335114402Sru buf, buf, axis_height, buf); 336114402Sru if (d->ext) { 337114402Sru printf(".if \\n[" INDEX_REG "]<0 \\{.if c%s \\{\\\n", d->ext); 338114402Sru build_extensible(d->ext, d->top, d->mid, d->bot); 339114402Sru printf(".\\}\\}\n"); 340114402Sru } 341114402Sru printf(".\\}\n"); 342114402Sru printf(".as " DELIM_STRING " \\h'\\n[" DELIM_WIDTH_REG "]u'\n"); 343114402Sru printf(".nr " WIDTH_FORMAT " +\\n[" DELIM_WIDTH_REG "]\n", uid); 344114402Sru printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]" 345114402Sru ">?(\\n[" TOTAL_HEIGHT_REG "]/2+%dM)\n", 346114402Sru uid, uid, axis_height); 347114402Sru printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]" 348114402Sru ">?(\\n[" TOTAL_HEIGHT_REG "]/2-%dM)\n", 349114402Sru uid, uid, axis_height); 350114402Sru} 351114402Sru 352114402Sruint delim_box::compute_metrics(int style) 353114402Sru{ 354114402Sru int r = p->compute_metrics(style); 355114402Sru printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid); 356114402Sru printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid); 357114402Sru printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid); 358114402Sru printf(".nr " DELTA_REG " \\n[" HEIGHT_FORMAT "]-%dM" 359114402Sru ">?(\\n[" DEPTH_FORMAT "]+%dM)\n", 360114402Sru p->uid, axis_height, p->uid, axis_height); 361114402Sru printf(".nr " DELTA_REG " 0\\n[" DELTA_REG "]*%d/500" 362114402Sru ">?(\\n[" DELTA_REG "]*2-%dM)\n", 363114402Sru delimiter_factor, delimiter_shortfall); 364114402Sru if (left) { 365114402Sru define_extensible_string(left, uid, LEFT_DELIM); 366114402Sru printf(".rn " DELIM_STRING " " LEFT_DELIM_STRING_FORMAT "\n", 367114402Sru uid); 368114402Sru if (r) 369114402Sru printf(".nr " MARK_REG " +\\n[" DELIM_WIDTH_REG "]\n"); 370114402Sru } 371114402Sru if (right) { 372114402Sru define_extensible_string(right, uid, RIGHT_DELIM); 373114402Sru printf(".rn " DELIM_STRING " " RIGHT_DELIM_STRING_FORMAT "\n", 374114402Sru uid); 375114402Sru } 376114402Sru return r; 377114402Sru} 378114402Sru 379114402Sruvoid delim_box::output() 380114402Sru{ 381114402Sru if (left) 382114402Sru printf("\\*[" LEFT_DELIM_STRING_FORMAT "]", uid); 383114402Sru p->output(); 384114402Sru if (right) 385114402Sru printf("\\*[" RIGHT_DELIM_STRING_FORMAT "]", uid); 386114402Sru} 387114402Sru 388114402Sruvoid delim_box::check_tabs(int level) 389114402Sru{ 390114402Sru p->check_tabs(level); 391114402Sru} 392114402Sru 393114402Sruvoid delim_box::debug_print() 394114402Sru{ 395114402Sru fprintf(stderr, "left \"%s\" { ", left ? left : ""); 396114402Sru p->debug_print(); 397114402Sru fprintf(stderr, " }"); 398114402Sru if (right) 399114402Sru fprintf(stderr, " right \"%s\"", right); 400114402Sru} 401114402Sru 402