1114402Sru// -*- C++ -*- 2151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2004 3114402Sru Free Software Foundation, Inc. 4114402Sru Written by James Clark (jjc@jclark.com) 5114402Sru 6114402SruThis file is part of groff. 7114402Sru 8114402Srugroff is free software; you can redistribute it and/or modify it under 9114402Sruthe terms of the GNU General Public License as published by the Free 10114402SruSoftware Foundation; either version 2, or (at your option) any later 11114402Sruversion. 12114402Sru 13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 15114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16114402Srufor more details. 17114402Sru 18114402SruYou should have received a copy of the GNU General Public License along 19114402Sruwith groff; see the file COPYING. If not, write to the Free Software 20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 21114402Sru 22114402Sru 23114402Sru#include "troff.h" 24114402Sru#include "hvunits.h" 25151497Sru#include "stringclass.h" 26151497Sru#include "mtsm.h" 27114402Sru#include "env.h" 28114402Sru#include "token.h" 29114402Sru#include "div.h" 30114402Sru 31114402Sruvunits V0; 32114402Sruhunits H0; 33114402Sru 34114402Sruint hresolution = 1; 35114402Sruint vresolution = 1; 36114402Sruint units_per_inch; 37114402Sruint sizescale; 38114402Sru 39114402Srustatic int parse_expr(units *v, int scale_indicator, 40114402Sru int parenthesised, int rigid = 0); 41114402Srustatic int start_number(); 42114402Sru 43114402Sruint get_vunits(vunits *res, unsigned char si) 44114402Sru{ 45114402Sru if (!start_number()) 46114402Sru return 0; 47114402Sru units x; 48114402Sru if (parse_expr(&x, si, 0)) { 49114402Sru *res = vunits(x); 50114402Sru return 1; 51114402Sru } 52114402Sru else 53114402Sru return 0; 54114402Sru} 55114402Sru 56114402Sruint get_hunits(hunits *res, unsigned char si) 57114402Sru{ 58114402Sru if (!start_number()) 59114402Sru return 0; 60114402Sru units x; 61114402Sru if (parse_expr(&x, si, 0)) { 62114402Sru *res = hunits(x); 63114402Sru return 1; 64114402Sru } 65114402Sru else 66114402Sru return 0; 67114402Sru} 68114402Sru 69114402Sru// for \B 70114402Sru 71114402Sruint get_number_rigidly(units *res, unsigned char si) 72114402Sru{ 73114402Sru if (!start_number()) 74114402Sru return 0; 75114402Sru units x; 76114402Sru if (parse_expr(&x, si, 0, 1)) { 77114402Sru *res = x; 78114402Sru return 1; 79114402Sru } 80114402Sru else 81114402Sru return 0; 82114402Sru} 83114402Sru 84114402Sruint get_number(units *res, unsigned char si) 85114402Sru{ 86114402Sru if (!start_number()) 87114402Sru return 0; 88114402Sru units x; 89114402Sru if (parse_expr(&x, si, 0)) { 90114402Sru *res = x; 91114402Sru return 1; 92114402Sru } 93114402Sru else 94114402Sru return 0; 95114402Sru} 96114402Sru 97114402Sruint get_integer(int *res) 98114402Sru{ 99114402Sru if (!start_number()) 100114402Sru return 0; 101114402Sru units x; 102114402Sru if (parse_expr(&x, 0, 0)) { 103114402Sru *res = x; 104114402Sru return 1; 105114402Sru } 106114402Sru else 107114402Sru return 0; 108114402Sru} 109114402Sru 110114402Sruenum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT }; 111114402Sru 112114402Srustatic incr_number_result get_incr_number(units *res, unsigned char); 113114402Sru 114114402Sruint get_vunits(vunits *res, unsigned char si, vunits prev_value) 115114402Sru{ 116114402Sru units v; 117114402Sru switch (get_incr_number(&v, si)) { 118114402Sru case BAD: 119114402Sru return 0; 120114402Sru case ABSOLUTE: 121114402Sru *res = v; 122114402Sru break; 123114402Sru case INCREMENT: 124114402Sru *res = prev_value + v; 125114402Sru break; 126114402Sru case DECREMENT: 127114402Sru *res = prev_value - v; 128114402Sru break; 129114402Sru default: 130114402Sru assert(0); 131114402Sru } 132114402Sru return 1; 133114402Sru} 134114402Sru 135114402Sruint get_hunits(hunits *res, unsigned char si, hunits prev_value) 136114402Sru{ 137114402Sru units v; 138114402Sru switch (get_incr_number(&v, si)) { 139114402Sru case BAD: 140114402Sru return 0; 141114402Sru case ABSOLUTE: 142114402Sru *res = v; 143114402Sru break; 144114402Sru case INCREMENT: 145114402Sru *res = prev_value + v; 146114402Sru break; 147114402Sru case DECREMENT: 148114402Sru *res = prev_value - v; 149114402Sru break; 150114402Sru default: 151114402Sru assert(0); 152114402Sru } 153114402Sru return 1; 154114402Sru} 155114402Sru 156114402Sruint get_number(units *res, unsigned char si, units prev_value) 157114402Sru{ 158114402Sru units v; 159114402Sru switch (get_incr_number(&v, si)) { 160114402Sru case BAD: 161114402Sru return 0; 162114402Sru case ABSOLUTE: 163114402Sru *res = v; 164114402Sru break; 165114402Sru case INCREMENT: 166114402Sru *res = prev_value + v; 167114402Sru break; 168114402Sru case DECREMENT: 169114402Sru *res = prev_value - v; 170114402Sru break; 171114402Sru default: 172114402Sru assert(0); 173114402Sru } 174114402Sru return 1; 175114402Sru} 176114402Sru 177114402Sruint get_integer(int *res, int prev_value) 178114402Sru{ 179114402Sru units v; 180114402Sru switch (get_incr_number(&v, 0)) { 181114402Sru case BAD: 182114402Sru return 0; 183114402Sru case ABSOLUTE: 184114402Sru *res = v; 185114402Sru break; 186114402Sru case INCREMENT: 187114402Sru *res = prev_value + int(v); 188114402Sru break; 189114402Sru case DECREMENT: 190114402Sru *res = prev_value - int(v); 191114402Sru break; 192114402Sru default: 193114402Sru assert(0); 194114402Sru } 195114402Sru return 1; 196114402Sru} 197114402Sru 198114402Sru 199114402Srustatic incr_number_result get_incr_number(units *res, unsigned char si) 200114402Sru{ 201114402Sru if (!start_number()) 202114402Sru return BAD; 203114402Sru incr_number_result result = ABSOLUTE; 204114402Sru if (tok.ch() == '+') { 205114402Sru tok.next(); 206114402Sru result = INCREMENT; 207114402Sru } 208114402Sru else if (tok.ch() == '-') { 209114402Sru tok.next(); 210114402Sru result = DECREMENT; 211114402Sru } 212114402Sru if (parse_expr(res, si, 0)) 213114402Sru return result; 214114402Sru else 215114402Sru return BAD; 216114402Sru} 217114402Sru 218114402Srustatic int start_number() 219114402Sru{ 220114402Sru while (tok.space()) 221114402Sru tok.next(); 222114402Sru if (tok.newline()) { 223114402Sru warning(WARN_MISSING, "missing number"); 224114402Sru return 0; 225114402Sru } 226114402Sru if (tok.tab()) { 227114402Sru warning(WARN_TAB, "tab character where number expected"); 228114402Sru return 0; 229114402Sru } 230114402Sru if (tok.right_brace()) { 231114402Sru warning(WARN_RIGHT_BRACE, "`\\}' where number expected"); 232114402Sru return 0; 233114402Sru } 234114402Sru return 1; 235114402Sru} 236114402Sru 237114402Sruenum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' }; 238114402Sru 239114402Sru#define SCALE_INDICATOR_CHARS "icfPmnpuvMsz" 240114402Sru 241114402Srustatic int parse_term(units *v, int scale_indicator, 242114402Sru int parenthesised, int rigid); 243114402Sru 244114402Srustatic int parse_expr(units *v, int scale_indicator, 245114402Sru int parenthesised, int rigid) 246114402Sru{ 247114402Sru int result = parse_term(v, scale_indicator, parenthesised, rigid); 248114402Sru while (result) { 249114402Sru if (parenthesised) 250114402Sru tok.skip(); 251114402Sru int op = tok.ch(); 252114402Sru switch (op) { 253114402Sru case '+': 254114402Sru case '-': 255114402Sru case '/': 256114402Sru case '*': 257114402Sru case '%': 258114402Sru case ':': 259114402Sru case '&': 260114402Sru tok.next(); 261114402Sru break; 262114402Sru case '>': 263114402Sru tok.next(); 264114402Sru if (tok.ch() == '=') { 265114402Sru tok.next(); 266114402Sru op = OP_GEQ; 267114402Sru } 268114402Sru else if (tok.ch() == '?') { 269114402Sru tok.next(); 270114402Sru op = OP_MAX; 271114402Sru } 272114402Sru break; 273114402Sru case '<': 274114402Sru tok.next(); 275114402Sru if (tok.ch() == '=') { 276114402Sru tok.next(); 277114402Sru op = OP_LEQ; 278114402Sru } 279114402Sru else if (tok.ch() == '?') { 280114402Sru tok.next(); 281114402Sru op = OP_MIN; 282114402Sru } 283114402Sru break; 284114402Sru case '=': 285114402Sru tok.next(); 286114402Sru if (tok.ch() == '=') 287114402Sru tok.next(); 288114402Sru break; 289114402Sru default: 290114402Sru return result; 291114402Sru } 292114402Sru units v2; 293114402Sru if (!parse_term(&v2, scale_indicator, parenthesised, rigid)) 294114402Sru return 0; 295114402Sru int overflow = 0; 296114402Sru switch (op) { 297114402Sru case '<': 298114402Sru *v = *v < v2; 299114402Sru break; 300114402Sru case '>': 301114402Sru *v = *v > v2; 302114402Sru break; 303114402Sru case OP_LEQ: 304114402Sru *v = *v <= v2; 305114402Sru break; 306114402Sru case OP_GEQ: 307114402Sru *v = *v >= v2; 308114402Sru break; 309114402Sru case OP_MIN: 310114402Sru if (*v > v2) 311114402Sru *v = v2; 312114402Sru break; 313114402Sru case OP_MAX: 314114402Sru if (*v < v2) 315114402Sru *v = v2; 316114402Sru break; 317114402Sru case '=': 318114402Sru *v = *v == v2; 319114402Sru break; 320114402Sru case '&': 321114402Sru *v = *v > 0 && v2 > 0; 322114402Sru break; 323114402Sru case ':': 324114402Sru *v = *v > 0 || v2 > 0; 325114402Sru break; 326114402Sru case '+': 327114402Sru if (v2 < 0) { 328114402Sru if (*v < INT_MIN - v2) 329114402Sru overflow = 1; 330114402Sru } 331114402Sru else if (v2 > 0) { 332114402Sru if (*v > INT_MAX - v2) 333114402Sru overflow = 1; 334114402Sru } 335114402Sru if (overflow) { 336114402Sru error("addition overflow"); 337114402Sru return 0; 338114402Sru } 339114402Sru *v += v2; 340114402Sru break; 341114402Sru case '-': 342114402Sru if (v2 < 0) { 343114402Sru if (*v > INT_MAX + v2) 344114402Sru overflow = 1; 345114402Sru } 346114402Sru else if (v2 > 0) { 347114402Sru if (*v < INT_MIN + v2) 348114402Sru overflow = 1; 349114402Sru } 350114402Sru if (overflow) { 351114402Sru error("subtraction overflow"); 352114402Sru return 0; 353114402Sru } 354114402Sru *v -= v2; 355114402Sru break; 356114402Sru case '*': 357114402Sru if (v2 < 0) { 358114402Sru if (*v > 0) { 359114402Sru if (*v > -(unsigned)INT_MIN / -(unsigned)v2) 360114402Sru overflow = 1; 361114402Sru } 362114402Sru else if (-(unsigned)*v > INT_MAX / -(unsigned)v2) 363114402Sru overflow = 1; 364114402Sru } 365114402Sru else if (v2 > 0) { 366114402Sru if (*v > 0) { 367114402Sru if (*v > INT_MAX / v2) 368114402Sru overflow = 1; 369114402Sru } 370114402Sru else if (-(unsigned)*v > -(unsigned)INT_MIN / v2) 371114402Sru overflow = 1; 372114402Sru } 373114402Sru if (overflow) { 374114402Sru error("multiplication overflow"); 375114402Sru return 0; 376114402Sru } 377114402Sru *v *= v2; 378114402Sru break; 379114402Sru case '/': 380114402Sru if (v2 == 0) { 381114402Sru error("division by zero"); 382114402Sru return 0; 383114402Sru } 384114402Sru *v /= v2; 385114402Sru break; 386114402Sru case '%': 387114402Sru if (v2 == 0) { 388114402Sru error("modulus by zero"); 389114402Sru return 0; 390114402Sru } 391114402Sru *v %= v2; 392114402Sru break; 393114402Sru default: 394114402Sru assert(0); 395114402Sru } 396114402Sru } 397114402Sru return result; 398114402Sru} 399114402Sru 400114402Srustatic int parse_term(units *v, int scale_indicator, 401114402Sru int parenthesised, int rigid) 402114402Sru{ 403114402Sru int negative = 0; 404114402Sru for (;;) 405114402Sru if (parenthesised && tok.space()) 406114402Sru tok.next(); 407114402Sru else if (tok.ch() == '+') 408114402Sru tok.next(); 409114402Sru else if (tok.ch() == '-') { 410114402Sru tok.next(); 411114402Sru negative = !negative; 412114402Sru } 413114402Sru else 414114402Sru break; 415114402Sru unsigned char c = tok.ch(); 416114402Sru switch (c) { 417114402Sru case '|': 418114402Sru // | is not restricted to the outermost level 419114402Sru // tbl uses this 420114402Sru tok.next(); 421114402Sru if (!parse_term(v, scale_indicator, parenthesised, rigid)) 422114402Sru return 0; 423114402Sru int tem; 424114402Sru tem = (scale_indicator == 'v' 425114402Sru ? curdiv->get_vertical_position().to_units() 426114402Sru : curenv->get_input_line_position().to_units()); 427114402Sru if (tem >= 0) { 428114402Sru if (*v < INT_MIN + tem) { 429114402Sru error("numeric overflow"); 430114402Sru return 0; 431114402Sru } 432114402Sru } 433114402Sru else { 434114402Sru if (*v > INT_MAX + tem) { 435114402Sru error("numeric overflow"); 436114402Sru return 0; 437114402Sru } 438114402Sru } 439114402Sru *v -= tem; 440114402Sru if (negative) { 441114402Sru if (*v == INT_MIN) { 442114402Sru error("numeric overflow"); 443114402Sru return 0; 444114402Sru } 445114402Sru *v = -*v; 446114402Sru } 447114402Sru return 1; 448114402Sru case '(': 449114402Sru tok.next(); 450114402Sru c = tok.ch(); 451114402Sru if (c == ')') { 452114402Sru if (rigid) 453114402Sru return 0; 454114402Sru warning(WARN_SYNTAX, "empty parentheses"); 455114402Sru tok.next(); 456114402Sru *v = 0; 457114402Sru return 1; 458114402Sru } 459114402Sru else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) { 460114402Sru tok.next(); 461114402Sru if (tok.ch() == ';') { 462114402Sru tok.next(); 463114402Sru scale_indicator = c; 464114402Sru } 465114402Sru else { 466114402Sru error("expected `;' after scale-indicator (got %1)", 467114402Sru tok.description()); 468114402Sru return 0; 469114402Sru } 470114402Sru } 471114402Sru else if (c == ';') { 472114402Sru scale_indicator = 0; 473114402Sru tok.next(); 474114402Sru } 475114402Sru if (!parse_expr(v, scale_indicator, 1, rigid)) 476114402Sru return 0; 477114402Sru tok.skip(); 478114402Sru if (tok.ch() != ')') { 479114402Sru if (rigid) 480114402Sru return 0; 481114402Sru warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description()); 482114402Sru } 483114402Sru else 484114402Sru tok.next(); 485114402Sru if (negative) { 486114402Sru if (*v == INT_MIN) { 487114402Sru error("numeric overflow"); 488114402Sru return 0; 489114402Sru } 490114402Sru *v = -*v; 491114402Sru } 492114402Sru return 1; 493114402Sru case '.': 494114402Sru *v = 0; 495114402Sru break; 496114402Sru case '0': 497114402Sru case '1': 498114402Sru case '2': 499114402Sru case '3': 500114402Sru case '4': 501114402Sru case '5': 502114402Sru case '6': 503114402Sru case '7': 504114402Sru case '8': 505114402Sru case '9': 506114402Sru *v = 0; 507114402Sru do { 508114402Sru if (*v > INT_MAX/10) { 509114402Sru error("numeric overflow"); 510114402Sru return 0; 511114402Sru } 512114402Sru *v *= 10; 513114402Sru if (*v > INT_MAX - (int(c) - '0')) { 514114402Sru error("numeric overflow"); 515114402Sru return 0; 516114402Sru } 517114402Sru *v += c - '0'; 518114402Sru tok.next(); 519114402Sru c = tok.ch(); 520114402Sru } while (csdigit(c)); 521114402Sru break; 522114402Sru case '/': 523114402Sru case '*': 524114402Sru case '%': 525114402Sru case ':': 526114402Sru case '&': 527114402Sru case '>': 528114402Sru case '<': 529114402Sru case '=': 530114402Sru warning(WARN_SYNTAX, "empty left operand"); 531114402Sru *v = 0; 532114402Sru return rigid ? 0 : 1; 533114402Sru default: 534114402Sru warning(WARN_NUMBER, "numeric expression expected (got %1)", 535114402Sru tok.description()); 536114402Sru return 0; 537114402Sru } 538114402Sru int divisor = 1; 539114402Sru if (tok.ch() == '.') { 540114402Sru tok.next(); 541114402Sru for (;;) { 542114402Sru c = tok.ch(); 543114402Sru if (!csdigit(c)) 544114402Sru break; 545114402Sru // we may multiply the divisor by 254 later on 546114402Sru if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) { 547114402Sru *v *= 10; 548114402Sru *v += c - '0'; 549114402Sru divisor *= 10; 550114402Sru } 551114402Sru tok.next(); 552114402Sru } 553114402Sru } 554114402Sru int si = scale_indicator; 555114402Sru int do_next = 0; 556114402Sru if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) { 557114402Sru switch (scale_indicator) { 558114402Sru case 'z': 559114402Sru if (c != 'u' && c != 'z') { 560114402Sru warning(WARN_SCALE, 561114402Sru "only `z' and `u' scale indicators valid in this context"); 562114402Sru break; 563114402Sru } 564114402Sru si = c; 565114402Sru break; 566114402Sru case 0: 567114402Sru warning(WARN_SCALE, "scale indicator invalid in this context"); 568114402Sru break; 569114402Sru case 'u': 570114402Sru si = c; 571114402Sru break; 572114402Sru default: 573114402Sru if (c == 'z') { 574114402Sru warning(WARN_SCALE, "`z' scale indicator invalid in this context"); 575114402Sru break; 576114402Sru } 577114402Sru si = c; 578114402Sru break; 579114402Sru } 580114402Sru // Don't do tok.next() here because the next token might be \s, which 581114402Sru // would affect the interpretation of m. 582114402Sru do_next = 1; 583114402Sru } 584114402Sru switch (si) { 585114402Sru case 'i': 586114402Sru *v = scale(*v, units_per_inch, divisor); 587114402Sru break; 588114402Sru case 'c': 589114402Sru *v = scale(*v, units_per_inch*100, divisor*254); 590114402Sru break; 591114402Sru case 0: 592114402Sru case 'u': 593114402Sru if (divisor != 1) 594114402Sru *v /= divisor; 595114402Sru break; 596114402Sru case 'f': 597114402Sru *v = scale(*v, 65536, divisor); 598114402Sru break; 599114402Sru case 'p': 600114402Sru *v = scale(*v, units_per_inch, divisor*72); 601114402Sru break; 602114402Sru case 'P': 603114402Sru *v = scale(*v, units_per_inch, divisor*6); 604114402Sru break; 605114402Sru case 'm': 606114402Sru { 607114402Sru // Convert to hunits so that with -Tascii `m' behaves as in nroff. 608114402Sru hunits em = curenv->get_size(); 609114402Sru *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor); 610114402Sru } 611114402Sru break; 612114402Sru case 'M': 613114402Sru { 614114402Sru hunits em = curenv->get_size(); 615114402Sru *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100); 616114402Sru } 617114402Sru break; 618114402Sru case 'n': 619114402Sru { 620114402Sru // Convert to hunits so that with -Tascii `n' behaves as in nroff. 621114402Sru hunits en = curenv->get_size()/2; 622114402Sru *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor); 623114402Sru } 624114402Sru break; 625114402Sru case 'v': 626114402Sru *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor); 627114402Sru break; 628114402Sru case 's': 629114402Sru while (divisor > INT_MAX/(sizescale*72)) { 630114402Sru divisor /= 10; 631114402Sru *v /= 10; 632114402Sru } 633114402Sru *v = scale(*v, units_per_inch, divisor*sizescale*72); 634114402Sru break; 635114402Sru case 'z': 636114402Sru *v = scale(*v, sizescale, divisor); 637114402Sru break; 638114402Sru default: 639114402Sru assert(0); 640114402Sru } 641114402Sru if (do_next) 642114402Sru tok.next(); 643114402Sru if (negative) { 644114402Sru if (*v == INT_MIN) { 645114402Sru error("numeric overflow"); 646114402Sru return 0; 647114402Sru } 648114402Sru *v = -*v; 649114402Sru } 650114402Sru return 1; 651114402Sru} 652114402Sru 653114402Sruunits scale(units n, units x, units y) 654114402Sru{ 655114402Sru assert(x >= 0 && y > 0); 656114402Sru if (x == 0) 657114402Sru return 0; 658114402Sru if (n >= 0) { 659114402Sru if (n <= INT_MAX/x) 660114402Sru return (n*x)/y; 661114402Sru } 662114402Sru else { 663114402Sru if (-(unsigned)n <= -(unsigned)INT_MIN/x) 664114402Sru return (n*x)/y; 665114402Sru } 666114402Sru double res = n*double(x)/double(y); 667114402Sru if (res > INT_MAX) { 668114402Sru error("numeric overflow"); 669114402Sru return INT_MAX; 670114402Sru } 671114402Sru else if (res < INT_MIN) { 672114402Sru error("numeric overflow"); 673114402Sru return INT_MIN; 674114402Sru } 675114402Sru return int(res); 676114402Sru} 677114402Sru 678114402Sruvunits::vunits(units x) 679114402Sru{ 680114402Sru // don't depend on the rounding direction for division of negative integers 681114402Sru if (vresolution == 1) 682114402Sru n = x; 683114402Sru else 684114402Sru n = (x < 0 685114402Sru ? -((-x + vresolution/2 - 1)/vresolution) 686114402Sru : (x + vresolution/2 - 1)/vresolution); 687114402Sru} 688114402Sru 689114402Sruhunits::hunits(units x) 690114402Sru{ 691114402Sru // don't depend on the rounding direction for division of negative integers 692114402Sru if (hresolution == 1) 693114402Sru n = x; 694114402Sru else 695114402Sru n = (x < 0 696114402Sru ? -((-x + hresolution/2 - 1)/hresolution) 697114402Sru : (x + hresolution/2 - 1)/hresolution); 698114402Sru} 699