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@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