2 /* Copyright (C) 1989-2014 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 #include "stringclass.h"
37 static int parse_expr(units *v, int scale_indicator,
38 int parenthesised, int rigid = 0);
39 static int start_number();
41 int get_vunits(vunits *res, unsigned char si)
46 if (parse_expr(&x, si, 0)) {
54 int get_hunits(hunits *res, unsigned char si)
59 if (parse_expr(&x, si, 0)) {
69 int get_number_rigidly(units *res, unsigned char si)
74 if (parse_expr(&x, si, 0, 1)) {
82 int get_number(units *res, unsigned char si)
87 if (parse_expr(&x, si, 0)) {
95 int get_integer(int *res)
100 if (parse_expr(&x, 0, 0)) {
108 enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT };
110 static incr_number_result get_incr_number(units *res, unsigned char);
112 int get_vunits(vunits *res, unsigned char si, vunits prev_value)
115 switch (get_incr_number(&v, si)) {
122 *res = prev_value + v;
125 *res = prev_value - v;
133 int get_hunits(hunits *res, unsigned char si, hunits prev_value)
136 switch (get_incr_number(&v, si)) {
143 *res = prev_value + v;
146 *res = prev_value - v;
154 int get_number(units *res, unsigned char si, units prev_value)
157 switch (get_incr_number(&v, si)) {
164 *res = prev_value + v;
167 *res = prev_value - v;
175 int get_integer(int *res, int prev_value)
178 switch (get_incr_number(&v, 0)) {
185 *res = prev_value + int(v);
188 *res = prev_value - int(v);
197 static incr_number_result get_incr_number(units *res, unsigned char si)
201 incr_number_result result = ABSOLUTE;
202 if (tok.ch() == '+') {
206 else if (tok.ch() == '-') {
210 if (parse_expr(res, si, 0))
216 static int start_number()
221 warning(WARN_MISSING, "missing number");
225 warning(WARN_TAB, "tab character where number expected");
228 if (tok.right_brace()) {
229 warning(WARN_RIGHT_BRACE, "`\\}' where number expected");
235 enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
237 #define SCALE_INDICATOR_CHARS "icfPmnpuvMsz"
239 static int parse_term(units *v, int scale_indicator,
240 int parenthesised, int rigid);
242 static int parse_expr(units *v, int scale_indicator,
243 int parenthesised, int rigid)
245 int result = parse_term(v, scale_indicator, parenthesised, rigid);
262 if (tok.ch() == '=') {
266 else if (tok.ch() == '?') {
273 if (tok.ch() == '=') {
277 else if (tok.ch() == '?') {
291 if (!parse_term(&v2, scale_indicator, parenthesised, rigid))
319 *v = *v > 0 && v2 > 0;
322 *v = *v > 0 || v2 > 0;
326 if (*v < INT_MIN - v2)
330 if (*v > INT_MAX - v2)
334 error("addition overflow");
341 if (*v > INT_MAX + v2)
345 if (*v < INT_MIN + v2)
349 error("subtraction overflow");
357 if ((unsigned)*v > -(unsigned)INT_MIN / -(unsigned)v2)
360 else if (-(unsigned)*v > INT_MAX / -(unsigned)v2)
365 if (*v > INT_MAX / v2)
368 else if (-(unsigned)*v > -(unsigned)INT_MIN / v2)
372 error("multiplication overflow");
379 error("division by zero");
386 error("modulus by zero");
398 static int parse_term(units *v, int scale_indicator,
399 int parenthesised, int rigid)
403 if (parenthesised && tok.space())
405 else if (tok.ch() == '+')
407 else if (tok.ch() == '-') {
409 negative = !negative;
413 unsigned char c = tok.ch();
416 // | is not restricted to the outermost level
419 if (!parse_term(v, scale_indicator, parenthesised, rigid))
422 tem = (scale_indicator == 'v'
423 ? curdiv->get_vertical_position().to_units()
424 : curenv->get_input_line_position().to_units());
426 if (*v < INT_MIN + tem) {
427 error("numeric overflow");
432 if (*v > INT_MAX + tem) {
433 error("numeric overflow");
440 error("numeric overflow");
452 warning(WARN_SYNTAX, "empty parentheses");
457 else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
459 if (tok.ch() == ';') {
464 error("expected `;' after scale-indicator (got %1)",
473 if (!parse_expr(v, scale_indicator, 1, rigid))
476 if (tok.ch() != ')') {
479 warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description());
485 error("numeric overflow");
506 if (*v > INT_MAX/10) {
507 error("numeric overflow");
511 if (*v > INT_MAX - (int(c) - '0')) {
512 error("numeric overflow");
518 } while (csdigit(c));
528 warning(WARN_SYNTAX, "empty left operand");
530 return rigid ? 0 : 1;
532 warning(WARN_NUMBER, "numeric expression expected (got %1)",
537 if (tok.ch() == '.') {
543 // we may multiply the divisor by 254 later on
544 if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) {
552 int si = scale_indicator;
554 if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
555 switch (scale_indicator) {
557 if (c != 'u' && c != 'z') {
559 "only `z' and `u' scale indicators valid in this context");
565 warning(WARN_SCALE, "scale indicator invalid in this context");
572 warning(WARN_SCALE, "`z' scale indicator invalid in this context");
578 // Don't do tok.next() here because the next token might be \s, which
579 // would affect the interpretation of m.
584 *v = scale(*v, units_per_inch, divisor);
587 *v = scale(*v, units_per_inch*100, divisor*254);
595 *v = scale(*v, 65536, divisor);
598 *v = scale(*v, units_per_inch, divisor*72);
601 *v = scale(*v, units_per_inch, divisor*6);
605 // Convert to hunits so that with -Tascii `m' behaves as in nroff.
606 hunits em = curenv->get_size();
607 *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor);
612 hunits em = curenv->get_size();
613 *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100);
618 // Convert to hunits so that with -Tascii `n' behaves as in nroff.
619 hunits en = curenv->get_size()/2;
620 *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor);
624 *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor);
627 while (divisor > INT_MAX/(sizescale*72)) {
631 *v = scale(*v, units_per_inch, divisor*sizescale*72);
634 *v = scale(*v, sizescale, divisor);
643 error("numeric overflow");
651 units scale(units n, units x, units y)
653 assert(x >= 0 && y > 0);
661 if (-(unsigned)n <= -(unsigned)INT_MIN/x)
664 double res = n*double(x)/double(y);
666 error("numeric overflow");
669 else if (res < INT_MIN) {
670 error("numeric overflow");
676 vunits::vunits(units x)
678 // don't depend on the rounding direction for division of negative integers
679 if (vresolution == 1)
683 ? -((-x + vresolution/2 - 1)/vresolution)
684 : (x + vresolution/2 - 1)/vresolution);
687 hunits::hunits(units x)
689 // don't depend on the rounding direction for division of negative integers
690 if (hresolution == 1)
694 ? -((-x + hresolution/2 - 1)/hresolution)
695 : (x + hresolution/2 - 1)/hresolution);