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
);