2 /* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2004, 2009
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 3 of the License, or
11 (at your option) any later version.
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
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
24 #include "stringclass.h"
38 static int parse_expr(units *v, int scale_indicator,
39 int parenthesised, int rigid = 0);
40 static int start_number();
42 int get_vunits(vunits *res, unsigned char si)
47 if (parse_expr(&x, si, 0)) {
55 int get_hunits(hunits *res, unsigned char si)
60 if (parse_expr(&x, si, 0)) {
70 int get_number_rigidly(units *res, unsigned char si)
75 if (parse_expr(&x, si, 0, 1)) {
83 int get_number(units *res, unsigned char si)
88 if (parse_expr(&x, si, 0)) {
96 int get_integer(int *res)
101 if (parse_expr(&x, 0, 0)) {
109 enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT };
111 static incr_number_result get_incr_number(units *res, unsigned char);
113 int get_vunits(vunits *res, unsigned char si, vunits prev_value)
116 switch (get_incr_number(&v, si)) {
123 *res = prev_value + v;
126 *res = prev_value - v;
134 int get_hunits(hunits *res, unsigned char si, hunits prev_value)
137 switch (get_incr_number(&v, si)) {
144 *res = prev_value + v;
147 *res = prev_value - v;
155 int get_number(units *res, unsigned char si, units prev_value)
158 switch (get_incr_number(&v, si)) {
165 *res = prev_value + v;
168 *res = prev_value - v;
176 int get_integer(int *res, int prev_value)
179 switch (get_incr_number(&v, 0)) {
186 *res = prev_value + int(v);
189 *res = prev_value - int(v);
198 static incr_number_result get_incr_number(units *res, unsigned char si)
202 incr_number_result result = ABSOLUTE;
203 if (tok.ch() == '+') {
207 else if (tok.ch() == '-') {
211 if (parse_expr(res, si, 0))
217 static int start_number()
222 warning(WARN_MISSING, "missing number");
226 warning(WARN_TAB, "tab character where number expected");
229 if (tok.right_brace()) {
230 warning(WARN_RIGHT_BRACE, "`\\}' where number expected");
236 enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
238 #define SCALE_INDICATOR_CHARS "icfPmnpuvMsz"
240 static int parse_term(units *v, int scale_indicator,
241 int parenthesised, int rigid);
243 static int parse_expr(units *v, int scale_indicator,
244 int parenthesised, int rigid)
246 int result = parse_term(v, scale_indicator, parenthesised, rigid);
263 if (tok.ch() == '=') {
267 else if (tok.ch() == '?') {
274 if (tok.ch() == '=') {
278 else if (tok.ch() == '?') {
292 if (!parse_term(&v2, scale_indicator, parenthesised, rigid))
320 *v = *v > 0 && v2 > 0;
323 *v = *v > 0 || v2 > 0;
327 if (*v < INT_MIN - v2)
331 if (*v > INT_MAX - v2)
335 error("addition overflow");
342 if (*v > INT_MAX + v2)
346 if (*v < INT_MIN + v2)
350 error("subtraction overflow");
358 if (*v > -(unsigned)INT_MIN / -(unsigned)v2)
361 else if (-(unsigned)*v > INT_MAX / -(unsigned)v2)
366 if (*v > INT_MAX / v2)
369 else if (-(unsigned)*v > -(unsigned)INT_MIN / v2)
373 error("multiplication overflow");
380 error("division by zero");
387 error("modulus by zero");
399 static int parse_term(units *v, int scale_indicator,
400 int parenthesised, int rigid)
404 if (parenthesised && tok.space())
406 else if (tok.ch() == '+')
408 else if (tok.ch() == '-') {
410 negative = !negative;
414 unsigned char c = tok.ch();
417 // | is not restricted to the outermost level
420 if (!parse_term(v, scale_indicator, parenthesised, rigid))
423 tem = (scale_indicator == 'v'
424 ? curdiv->get_vertical_position().to_units()
425 : curenv->get_input_line_position().to_units());
427 if (*v < INT_MIN + tem) {
428 error("numeric overflow");
433 if (*v > INT_MAX + tem) {
434 error("numeric overflow");
441 error("numeric overflow");
453 warning(WARN_SYNTAX, "empty parentheses");
458 else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
460 if (tok.ch() == ';') {
465 error("expected `;' after scale-indicator (got %1)",
474 if (!parse_expr(v, scale_indicator, 1, rigid))
477 if (tok.ch() != ')') {
480 warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description());
486 error("numeric overflow");
507 if (*v > INT_MAX/10) {
508 error("numeric overflow");
512 if (*v > INT_MAX - (int(c) - '0')) {
513 error("numeric overflow");
519 } while (csdigit(c));
529 warning(WARN_SYNTAX, "empty left operand");
531 return rigid ? 0 : 1;
533 warning(WARN_NUMBER, "numeric expression expected (got %1)",
538 if (tok.ch() == '.') {
544 // we may multiply the divisor by 254 later on
545 if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) {
553 int si = scale_indicator;
555 if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
556 switch (scale_indicator) {
558 if (c != 'u' && c != 'z') {
560 "only `z' and `u' scale indicators valid in this context");
566 warning(WARN_SCALE, "scale indicator invalid in this context");
573 warning(WARN_SCALE, "`z' scale indicator invalid in this context");
579 // Don't do tok.next() here because the next token might be \s, which
580 // would affect the interpretation of m.
585 *v = scale(*v, units_per_inch, divisor);
588 *v = scale(*v, units_per_inch*100, divisor*254);
596 *v = scale(*v, 65536, divisor);
599 *v = scale(*v, units_per_inch, divisor*72);
602 *v = scale(*v, units_per_inch, divisor*6);
606 // Convert to hunits so that with -Tascii `m' behaves as in nroff.
607 hunits em = curenv->get_size();
608 *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor);
613 hunits em = curenv->get_size();
614 *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100);
619 // Convert to hunits so that with -Tascii `n' behaves as in nroff.
620 hunits en = curenv->get_size()/2;
621 *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor);
625 *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor);
628 while (divisor > INT_MAX/(sizescale*72)) {
632 *v = scale(*v, units_per_inch, divisor*sizescale*72);
635 *v = scale(*v, sizescale, divisor);
644 error("numeric overflow");
652 units scale(units n, units x, units y)
654 assert(x >= 0 && y > 0);
662 if (-(unsigned)n <= -(unsigned)INT_MIN/x)
665 double res = n*double(x)/double(y);
667 error("numeric overflow");
670 else if (res < INT_MIN) {
671 error("numeric overflow");
677 vunits::vunits(units x)
679 // don't depend on the rounding direction for division of negative integers
680 if (vresolution == 1)
684 ? -((-x + vresolution/2 - 1)/vresolution)
685 : (x + vresolution/2 - 1)/vresolution);
688 hunits::hunits(units x)
690 // don't depend on the rounding direction for division of negative integers
691 if (hresolution == 1)
695 ? -((-x + hresolution/2 - 1)/hresolution)
696 : (x + hresolution/2 - 1)/hresolution);