/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
You should have received a copy of the GNU General Public License along
with groff; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
static int parse_expr(units
*v
, int scale_indicator
, int parenthesised
);
static int start_number();
int get_vunits(vunits
*res
, unsigned char si
)
if (parse_expr(&x
, si
, 0)) {
int get_hunits(hunits
*res
, unsigned char si
)
if (parse_expr(&x
, si
, 0)) {
int get_number(units
*res
, unsigned char si
)
if (parse_expr(&x
, si
, 0)) {
int get_integer(int *res
)
if (parse_expr(&x
, 0, 0)) {
enum incr_number_result
{ BAD
, ABSOLUTE
, INCREMENT
, DECREMENT
};
static incr_number_result
get_incr_number(units
*res
, unsigned char);
int get_vunits(vunits
*res
, unsigned char si
, vunits prev_value
)
switch (get_incr_number(&v
, si
)) {
int get_hunits(hunits
*res
, unsigned char si
, hunits prev_value
)
switch (get_incr_number(&v
, si
)) {
int get_number(units
*res
, unsigned char si
, units prev_value
)
switch (get_incr_number(&v
, si
)) {
int get_integer(int *res
, int prev_value
)
switch (get_incr_number(&v
, 0)) {
*res
= prev_value
+ int(v
);
*res
= prev_value
- int(v
);
static incr_number_result
get_incr_number(units
*res
, unsigned char si
)
incr_number_result result
= ABSOLUTE
;
else if (tok
.ch() == '-') {
if (parse_expr(res
, si
, 0))
static int start_number()
warning(WARN_MISSING
, "missing number");
warning(WARN_TAB
, "tab character where number expected");
warning(WARN_RIGHT_BRACE
, "`\\}' where number expected");
enum { OP_LEQ
= 'L', OP_GEQ
= 'G', OP_MAX
= 'X', OP_MIN
= 'N' };
#define SCALE_INDICATOR_CHARS "icPmnpuvMsz"
static int parse_term(units
*v
, int scale_indicator
, int parenthesised
);
static int parse_expr(units
*v
, int scale_indicator
, int parenthesised
)
int result
= parse_term(v
, scale_indicator
, parenthesised
);
else if (tok
.ch() == '?') {
else if (tok
.ch() == '?') {
if (!parse_term(&v2
, scale_indicator
, parenthesised
))
error("addition overflow");
error("subtraction overflow");
if (*v
> -(unsigned)INT_MIN
/ -(unsigned)v2
)
else if (-(unsigned)*v
> INT_MAX
/ -(unsigned)v2
)
else if (-(unsigned)*v
> -(unsigned)INT_MIN
/ v2
)
error("multiplication overflow");
error("division by zero");
error("modulus by zero");
static int parse_term(units
*v
, int scale_indicator
, int parenthesised
)
if (parenthesised
&& tok
.space())
else if (tok
.ch() == '+')
else if (tok
.ch() == '-') {
unsigned char c
= tok
.ch();
// | is not restricted to the outermost level
if (!parse_term(v
, scale_indicator
, parenthesised
))
tem
= (scale_indicator
== 'v'
? curdiv
->get_vertical_position().to_units()
: curenv
->get_input_line_position().to_units());
if (*v
< INT_MIN
+ tem
) {
error("numeric overflow");
if (*v
> INT_MAX
+ tem
) {
error("numeric overflow");
error("numeric overflow");
warning(WARN_SYNTAX
, "empty parentheses");
else if (c
!= 0 && strchr(SCALE_INDICATOR_CHARS
, c
) != 0) {
error("expected `;' after scale-indicator (got %1)",
if (!parse_expr(v
, scale_indicator
, 1))
warning(WARN_SYNTAX
, "missing `)' (got %1)", tok
.description());
error("numeric overflow");
error("numeric overflow");
if (*v
> INT_MAX
- (int(c
) - '0')) {
error("numeric overflow");
warning(WARN_SYNTAX
, "empty left operand");
warning(WARN_NUMBER
, "numeric expression expected (got %1)",
// we may multiply the divisor by 254 later on
if (divisor
<= INT_MAX
/2540 && *v
<= (INT_MAX
- 9)/10) {
int si
= scale_indicator
;
if ((c
= tok
.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS
, c
) != 0) {
switch (scale_indicator
) {
if (c
!= 'u' && c
!= 'z') {
"only `z' and `u' scale indicators valid in this context");
warning(WARN_SCALE
, "scale indicator invalid in this context");
warning(WARN_SCALE
, "`z' scale indicator invalid in this context");
// Don't do tok.next() here because the next token might be \s, which
// would affect the interpretation of m.
*v
= scale(*v
, units_per_inch
, divisor
);
*v
= scale(*v
, units_per_inch
*100, divisor
*254);
*v
= scale(*v
, units_per_inch
, divisor
*72);
*v
= scale(*v
, units_per_inch
, divisor
*6);
// Convert to hunits so that with -Tascii `m' behaves as in nroff.
hunits em
= curenv
->get_size();
*v
= scale(*v
, em
.is_zero() ? hresolution
: em
.to_units(), divisor
);
hunits em
= curenv
->get_size();
*v
= scale(*v
, em
.is_zero() ? hresolution
: em
.to_units(), divisor
*100);
// Convert to hunits so that with -Tascii `n' behaves as in nroff.
hunits en
= curenv
->get_size()/2;
*v
= scale(*v
, en
.is_zero() ? hresolution
: en
.to_units(), divisor
);
*v
= scale(*v
, curenv
->get_vertical_spacing().to_units(), divisor
);
while (divisor
> INT_MAX
/(sizescale
*72)) {
*v
= scale(*v
, units_per_inch
, divisor
*sizescale
*72);
*v
= scale(*v
, sizescale
, divisor
);
error("numeric overflow");
units
scale(units n
, units x
, units y
)
if (-(unsigned)n
<= -(unsigned)INT_MIN
/x
)
double res
= n
*double(x
)/double(y
);
error("numeric overflow");
else if (res
< INT_MIN
) {
error("numeric overflow");
// don't depend on the rounding direction for division of negative integers
? -((-x
+ vresolution
/2 - 1)/vresolution
)
: (x
+ vresolution
/2 - 1)/vresolution
);
// don't depend on the rounding direction for division of negative integers
? -((-x
+ hresolution
/2 - 1)/hresolution
)
: (x
+ hresolution
/2 - 1)/hresolution
);