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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
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 (*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
);