2 /* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2004
3 Free Software Foundation, Inc.
4 Written by James Clark (jjc@jclark.com)
6 This file is part of groff.
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with groff; see the file COPYING. If not, write to the Free Software
20 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
25 #include "stringclass.h"
39 static int parse_expr(units *v, int scale_indicator,
40 int parenthesised, int rigid = 0);
41 static int start_number();
43 int get_vunits(vunits *res, unsigned char si)
48 if (parse_expr(&x, si, 0)) {
56 int get_hunits(hunits *res, unsigned char si)
61 if (parse_expr(&x, si, 0)) {
71 int get_number_rigidly(units *res, unsigned char si)
76 if (parse_expr(&x, si, 0, 1)) {
84 int get_number(units *res, unsigned char si)
89 if (parse_expr(&x, si, 0)) {
97 int get_integer(int *res)
102 if (parse_expr(&x, 0, 0)) {
110 enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT };
112 static incr_number_result get_incr_number(units *res, unsigned char);
114 int get_vunits(vunits *res, unsigned char si, vunits prev_value)
117 switch (get_incr_number(&v, si)) {
124 *res = prev_value + v;
127 *res = prev_value - v;
135 int get_hunits(hunits *res, unsigned char si, hunits prev_value)
138 switch (get_incr_number(&v, si)) {
145 *res = prev_value + v;
148 *res = prev_value - v;
156 int get_number(units *res, unsigned char si, units prev_value)
159 switch (get_incr_number(&v, si)) {
166 *res = prev_value + v;
169 *res = prev_value - v;
177 int get_integer(int *res, int prev_value)
180 switch (get_incr_number(&v, 0)) {
187 *res = prev_value + int(v);
190 *res = prev_value - int(v);
199 static incr_number_result get_incr_number(units *res, unsigned char si)
203 incr_number_result result = ABSOLUTE;
204 if (tok.ch() == '+') {
208 else if (tok.ch() == '-') {
212 if (parse_expr(res, si, 0))
218 static int start_number()
223 warning(WARN_MISSING, "missing number");
227 warning(WARN_TAB, "tab character where number expected");
230 if (tok.right_brace()) {
231 warning(WARN_RIGHT_BRACE, "`\\}' where number expected");
237 enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
239 #define SCALE_INDICATOR_CHARS "icfPmnpuvMsz"
241 static int parse_term(units *v, int scale_indicator,
242 int parenthesised, int rigid);
244 static int parse_expr(units *v, int scale_indicator,
245 int parenthesised, int rigid)
247 int result = parse_term(v, scale_indicator, parenthesised, rigid);
264 if (tok.ch() == '=') {
268 else if (tok.ch() == '?') {
275 if (tok.ch() == '=') {
279 else if (tok.ch() == '?') {
293 if (!parse_term(&v2, scale_indicator, parenthesised, rigid))
321 *v = *v > 0 && v2 > 0;
324 *v = *v > 0 || v2 > 0;
328 if (*v < INT_MIN - v2)
332 if (*v > INT_MAX - v2)
336 error("addition overflow");
343 if (*v > INT_MAX + v2)
347 if (*v < INT_MIN + v2)
351 error("subtraction overflow");
359 if (*v > -(unsigned)INT_MIN / -(unsigned)v2)
362 else if (-(unsigned)*v > INT_MAX / -(unsigned)v2)
367 if (*v > INT_MAX / v2)
370 else if (-(unsigned)*v > -(unsigned)INT_MIN / v2)
374 error("multiplication overflow");
381 error("division by zero");
388 error("modulus by zero");
400 static int parse_term(units *v, int scale_indicator,
401 int parenthesised, int rigid)
405 if (parenthesised && tok.space())
407 else if (tok.ch() == '+')
409 else if (tok.ch() == '-') {
411 negative = !negative;
415 unsigned char c = tok.ch();
418 // | is not restricted to the outermost level
421 if (!parse_term(v, scale_indicator, parenthesised, rigid))
424 tem = (scale_indicator == 'v'
425 ? curdiv->get_vertical_position().to_units()
426 : curenv->get_input_line_position().to_units());
428 if (*v < INT_MIN + tem) {
429 error("numeric overflow");
434 if (*v > INT_MAX + tem) {
435 error("numeric overflow");
442 error("numeric overflow");
454 warning(WARN_SYNTAX, "empty parentheses");
459 else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
461 if (tok.ch() == ';') {
466 error("expected `;' after scale-indicator (got %1)",
475 if (!parse_expr(v, scale_indicator, 1, rigid))
478 if (tok.ch() != ')') {
481 warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description());
487 error("numeric overflow");
508 if (*v > INT_MAX/10) {
509 error("numeric overflow");
513 if (*v > INT_MAX - (int(c) - '0')) {
514 error("numeric overflow");
520 } while (csdigit(c));
530 warning(WARN_SYNTAX, "empty left operand");
532 return rigid ? 0 : 1;
534 warning(WARN_NUMBER, "numeric expression expected (got %1)",
539 if (tok.ch() == '.') {
545 // we may multiply the divisor by 254 later on
546 if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) {
554 int si = scale_indicator;
556 if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
557 switch (scale_indicator) {
559 if (c != 'u' && c != 'z') {
561 "only `z' and `u' scale indicators valid in this context");
567 warning(WARN_SCALE, "scale indicator invalid in this context");
574 warning(WARN_SCALE, "`z' scale indicator invalid in this context");
580 // Don't do tok.next() here because the next token might be \s, which
581 // would affect the interpretation of m.
586 *v = scale(*v, units_per_inch, divisor);
589 *v = scale(*v, units_per_inch*100, divisor*254);
597 *v = scale(*v, 65536, divisor);
600 *v = scale(*v, units_per_inch, divisor*72);
603 *v = scale(*v, units_per_inch, divisor*6);
607 // Convert to hunits so that with -Tascii `m' behaves as in nroff.
608 hunits em = curenv->get_size();
609 *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor);
614 hunits em = curenv->get_size();
615 *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100);
620 // Convert to hunits so that with -Tascii `n' behaves as in nroff.
621 hunits en = curenv->get_size()/2;
622 *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor);
626 *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor);
629 while (divisor > INT_MAX/(sizescale*72)) {
633 *v = scale(*v, units_per_inch, divisor*sizescale*72);
636 *v = scale(*v, sizescale, divisor);
645 error("numeric overflow");
653 units scale(units n, units x, units y)
655 assert(x >= 0 && y > 0);
663 if (-(unsigned)n <= -(unsigned)INT_MIN/x)
666 double res = n*double(x)/double(y);
668 error("numeric overflow");
671 else if (res < INT_MIN) {
672 error("numeric overflow");
678 vunits::vunits(units x)
680 // don't depend on the rounding direction for division of negative integers
681 if (vresolution == 1)
685 ? -((-x + vresolution/2 - 1)/vresolution)
686 : (x + vresolution/2 - 1)/vresolution);
689 hunits::hunits(units x)
691 // don't depend on the rounding direction for division of negative integers
692 if (hresolution == 1)
696 ? -((-x + hresolution/2 - 1)/hresolution)
697 : (x + hresolution/2 - 1)/hresolution);