2 * Copyright (c) 2014 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
4 * Copyright (C) 1989 - 1992, 2001, 2002, 2004
5 * Free Software Foundation, Inc.
6 * Written by James Clark (jjc@jclark.com)
8 * This 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 * This 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.
24 #include "troff-config.h"
26 #include "stringclass.h"
43 static int parse_expr(units
*v
, int scale_indicator
,
44 int parenthesised
, int rigid
= 0);
45 static int start_number();
47 int get_vunits(vunits
*res
, unsigned char si
)
52 if (parse_expr(&x
, si
, 0)) {
60 int get_hunits(hunits
*res
, unsigned char si
)
65 if (parse_expr(&x
, si
, 0)) {
75 int get_number_rigidly(units
*res
, unsigned char si
)
80 if (parse_expr(&x
, si
, 0, 1)) {
88 int get_number(units
*res
, unsigned char si
)
93 if (parse_expr(&x
, si
, 0)) {
101 int get_integer(int *res
)
106 if (parse_expr(&x
, 0, 0)) {
114 enum incr_number_result
{ BAD
, ABSOLUTE
, INCREMENT
, DECREMENT
};
116 static incr_number_result
get_incr_number(units
*res
, unsigned char);
118 int get_vunits(vunits
*res
, unsigned char si
, vunits prev_value
)
121 switch (get_incr_number(&v
, si
)) {
128 *res
= prev_value
+ v
;
131 *res
= prev_value
- v
;
139 int get_hunits(hunits
*res
, unsigned char si
, hunits prev_value
)
142 switch (get_incr_number(&v
, si
)) {
149 *res
= prev_value
+ v
;
152 *res
= prev_value
- v
;
160 int get_number(units
*res
, unsigned char si
, units prev_value
)
163 switch (get_incr_number(&v
, si
)) {
170 *res
= prev_value
+ v
;
173 *res
= prev_value
- v
;
181 int get_integer(int *res
, int prev_value
)
184 switch (get_incr_number(&v
, 0)) {
191 *res
= prev_value
+ int(v
);
194 *res
= prev_value
- int(v
);
202 static incr_number_result
get_incr_number(units
*res
, unsigned char si
)
206 incr_number_result result
= ABSOLUTE
;
207 if (tok
.ch() == '+') {
211 else if (tok
.ch() == '-') {
215 if (parse_expr(res
, si
, 0))
221 static int start_number()
226 warning(WARN_MISSING
, "missing number");
230 warning(WARN_TAB
, "tab character where number expected");
233 if (tok
.right_brace()) {
234 warning(WARN_RIGHT_BRACE
, "`\\}' where number expected");
240 enum { OP_LEQ
= 'L', OP_GEQ
= 'G', OP_MAX
= 'X', OP_MIN
= 'N' };
242 #define SCALE_INDICATOR_CHARS "icfPmnpuvMsz"
244 static int parse_term(units
*v
, int scale_indicator
,
245 int parenthesised
, int rigid
);
247 static int parse_expr(units
*v
, int scale_indicator
,
248 int parenthesised
, int rigid
)
250 int result
= parse_term(v
, scale_indicator
, parenthesised
, rigid
);
267 if (tok
.ch() == '=') {
271 else if (tok
.ch() == '?') {
278 if (tok
.ch() == '=') {
282 else if (tok
.ch() == '?') {
296 if (!parse_term(&v2
, scale_indicator
, parenthesised
, rigid
))
324 *v
= *v
> 0 && v2
> 0;
327 *v
= *v
> 0 || v2
> 0;
331 if (*v
< INT_MIN
- v2
)
335 if (*v
> INT_MAX
- v2
)
339 error("addition overflow");
346 if (*v
> INT_MAX
+ v2
)
350 if (*v
< INT_MIN
+ v2
)
354 error("subtraction overflow");
362 if ((unsigned)*v
> -(unsigned)INT_MIN
/ -(unsigned)v2
)
365 else if (-(unsigned)*v
> INT_MAX
/ -(unsigned)v2
)
370 if (*v
> INT_MAX
/ v2
)
373 else if (-(unsigned)*v
> -(unsigned)INT_MIN
/ v2
)
377 error("multiplication overflow");
384 error("division by zero");
391 error("modulus by zero");
403 static int parse_term(units
*v
, int scale_indicator
,
404 int parenthesised
, int rigid
)
408 if (parenthesised
&& tok
.space())
410 else if (tok
.ch() == '+')
412 else if (tok
.ch() == '-') {
414 negative
= !negative
;
418 unsigned char c
= tok
.ch();
421 // | is not restricted to the outermost level
424 if (!parse_term(v
, scale_indicator
, parenthesised
, rigid
))
427 tem
= (scale_indicator
== 'v'
428 ? curdiv
->get_vertical_position().to_units()
429 : curenv
->get_input_line_position().to_units());
431 if (*v
< INT_MIN
+ tem
) {
432 error("numeric overflow");
437 if (*v
> INT_MAX
+ tem
) {
438 error("numeric overflow");
445 error("numeric overflow");
457 warning(WARN_SYNTAX
, "empty parentheses");
462 else if (c
!= 0 && strchr(SCALE_INDICATOR_CHARS
, c
) != 0) {
464 if (tok
.ch() == ';') {
469 error("expected `;' after scale-indicator (got %1)",
478 if (!parse_expr(v
, scale_indicator
, 1, rigid
))
481 if (tok
.ch() != ')') {
484 warning(WARN_SYNTAX
, "missing `)' (got %1)", tok
.description());
490 error("numeric overflow");
511 if (*v
> INT_MAX
/10) {
512 error("numeric overflow");
516 if (*v
> INT_MAX
- (int(c
) - '0')) {
517 error("numeric overflow");
523 } while (csdigit(c
));
533 warning(WARN_SYNTAX
, "empty left operand");
535 return rigid
? 0 : 1;
537 warning(WARN_NUMBER
, "numeric expression expected (got %1)",
542 if (tok
.ch() == '.') {
548 // we may multiply the divisor by 254 later on
549 if (divisor
<= INT_MAX
/2540 && *v
<= (INT_MAX
- 9)/10) {
557 int si
= scale_indicator
;
559 if ((c
= tok
.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS
, c
) != 0) {
560 switch (scale_indicator
) {
562 if (c
!= 'u' && c
!= 'z') {
564 "only `z' and `u' scale indicators valid in this context");
570 warning(WARN_SCALE
, "scale indicator invalid in this context");
577 warning(WARN_SCALE
, "`z' scale indicator invalid in this context");
583 // Don't do tok.next() here because the next token might be \s, which
584 // would affect the interpretation of m.
589 *v
= scale(*v
, units_per_inch
, divisor
);
592 *v
= scale(*v
, units_per_inch
*100, divisor
*254);
600 *v
= scale(*v
, 65536, divisor
);
603 *v
= scale(*v
, units_per_inch
, divisor
*72);
606 *v
= scale(*v
, units_per_inch
, divisor
*6);
610 // Convert to hunits so that with -Tascii `m' behaves as in nroff.
611 hunits em
= curenv
->get_size();
612 *v
= scale(*v
, em
.is_zero() ? hresolution
: em
.to_units(), divisor
);
617 hunits em
= curenv
->get_size();
618 *v
= scale(*v
, em
.is_zero() ? hresolution
: em
.to_units(), divisor
*100);
623 // Convert to hunits so that with -Tascii `n' behaves as in nroff.
624 hunits en
= curenv
->get_size()/2;
625 *v
= scale(*v
, en
.is_zero() ? hresolution
: en
.to_units(), divisor
);
629 *v
= scale(*v
, curenv
->get_vertical_spacing().to_units(), divisor
);
632 while (divisor
> INT_MAX
/(sizescale
*72)) {
636 *v
= scale(*v
, units_per_inch
, divisor
*sizescale
*72);
639 *v
= scale(*v
, sizescale
, divisor
);
648 error("numeric overflow");
656 units
scale(units n
, units x
, units y
)
658 assert(x
>= 0 && y
> 0);
666 if (-(unsigned)n
<= -(unsigned)INT_MIN
/x
)
669 double res
= n
*double(x
)/double(y
);
671 error("numeric overflow");
674 else if (res
< INT_MIN
) {
675 error("numeric overflow");
681 vunits::vunits(units x
)
683 // don't depend on the rounding direction for division of negative integers
684 if (vresolution
== 1)
688 ? -((-x
+ vresolution
/2 - 1)/vresolution
)
689 : (x
+ vresolution
/2 - 1)/vresolution
);
692 hunits::hunits(units x
)
694 // don't depend on the rounding direction for division of negative integers
695 if (hresolution
== 1)
699 ? -((-x
+ hresolution
/2 - 1)/hresolution
)
700 : (x
+ hresolution
/2 - 1)/hresolution
);