1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
4
5 This file is part of groff.
6
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 2, or (at your option) any later
10 version.
11
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
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21
22 #include "troff.h"
23 #include "symbol.h"
24 #include "hvunits.h"
25 #include "env.h"
26 #include "token.h"
27 #include "div.h"
28
29 vunits V0;
30 hunits H0;
31
32 int hresolution = 1;
33 int vresolution = 1;
34 int units_per_inch;
35 int sizescale;
36
37 static int parse_expr(units *v, int scale_indicator, int parenthesised);
38 static int start_number();
39
get_vunits(vunits * res,unsigned char si)40 int get_vunits(vunits *res, unsigned char si)
41 {
42 if (!start_number())
43 return 0;
44 units x;
45 if (parse_expr(&x, si, 0)) {
46 *res = vunits(x);
47 return 1;
48 }
49 else
50 return 0;
51 }
52
get_hunits(hunits * res,unsigned char si)53 int get_hunits(hunits *res, unsigned char si)
54 {
55 if (!start_number())
56 return 0;
57 units x;
58 if (parse_expr(&x, si, 0)) {
59 *res = hunits(x);
60 return 1;
61 }
62 else
63 return 0;
64 }
65
get_number(units * res,unsigned char si)66 int get_number(units *res, unsigned char si)
67 {
68 if (!start_number())
69 return 0;
70 units x;
71 if (parse_expr(&x, si, 0)) {
72 *res = x;
73 return 1;
74 }
75 else
76 return 0;
77 }
78
get_integer(int * res)79 int get_integer(int *res)
80 {
81 if (!start_number())
82 return 0;
83 units x;
84 if (parse_expr(&x, 0, 0)) {
85 *res = x;
86 return 1;
87 }
88 else
89 return 0;
90 }
91
92 enum incr_number_result { BAD, ABSOLUTE, INCREMENT, DECREMENT };
93
94 static incr_number_result get_incr_number(units *res, unsigned char);
95
get_vunits(vunits * res,unsigned char si,vunits prev_value)96 int get_vunits(vunits *res, unsigned char si, vunits prev_value)
97 {
98 units v;
99 switch (get_incr_number(&v, si)) {
100 case BAD:
101 return 0;
102 case ABSOLUTE:
103 *res = v;
104 break;
105 case INCREMENT:
106 *res = prev_value + v;
107 break;
108 case DECREMENT:
109 *res = prev_value - v;
110 break;
111 default:
112 assert(0);
113 }
114 return 1;
115 }
116
get_hunits(hunits * res,unsigned char si,hunits prev_value)117 int get_hunits(hunits *res, unsigned char si, hunits prev_value)
118 {
119 units v;
120 switch (get_incr_number(&v, si)) {
121 case BAD:
122 return 0;
123 case ABSOLUTE:
124 *res = v;
125 break;
126 case INCREMENT:
127 *res = prev_value + v;
128 break;
129 case DECREMENT:
130 *res = prev_value - v;
131 break;
132 default:
133 assert(0);
134 }
135 return 1;
136 }
137
get_number(units * res,unsigned char si,units prev_value)138 int get_number(units *res, unsigned char si, units prev_value)
139 {
140 units v;
141 switch (get_incr_number(&v, si)) {
142 case BAD:
143 return 0;
144 case ABSOLUTE:
145 *res = v;
146 break;
147 case INCREMENT:
148 *res = prev_value + v;
149 break;
150 case DECREMENT:
151 *res = prev_value - v;
152 break;
153 default:
154 assert(0);
155 }
156 return 1;
157 }
158
get_integer(int * res,int prev_value)159 int get_integer(int *res, int prev_value)
160 {
161 units v;
162 switch (get_incr_number(&v, 0)) {
163 case BAD:
164 return 0;
165 case ABSOLUTE:
166 *res = v;
167 break;
168 case INCREMENT:
169 *res = prev_value + int(v);
170 break;
171 case DECREMENT:
172 *res = prev_value - int(v);
173 break;
174 default:
175 assert(0);
176 }
177 return 1;
178 }
179
180
get_incr_number(units * res,unsigned char si)181 static incr_number_result get_incr_number(units *res, unsigned char si)
182 {
183 if (!start_number())
184 return BAD;
185 incr_number_result result = ABSOLUTE;
186 if (tok.ch() == '+') {
187 tok.next();
188 result = INCREMENT;
189 }
190 else if (tok.ch() == '-') {
191 tok.next();
192 result = DECREMENT;
193 }
194 if (parse_expr(res, si, 0))
195 return result;
196 else
197 return BAD;
198 }
199
start_number()200 static int start_number()
201 {
202 while (tok.space())
203 tok.next();
204 if (tok.newline()) {
205 warning(WARN_MISSING, "missing number");
206 return 0;
207 }
208 if (tok.tab()) {
209 warning(WARN_TAB, "tab character where number expected");
210 return 0;
211 }
212 if (tok.right_brace()) {
213 warning(WARN_RIGHT_BRACE, "`\\}' where number expected");
214 return 0;
215 }
216 return 1;
217 }
218
219 enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
220
221 #define SCALE_INDICATOR_CHARS "icPmnpuvMsz"
222
223 static int parse_term(units *v, int scale_indicator, int parenthesised);
224
parse_expr(units * v,int scale_indicator,int parenthesised)225 static int parse_expr(units *v, int scale_indicator, int parenthesised)
226 {
227 int result = parse_term(v, scale_indicator, parenthesised);
228 while (result) {
229 if (parenthesised)
230 tok.skip();
231 int op = tok.ch();
232 switch (op) {
233 case '+':
234 case '-':
235 case '/':
236 case '*':
237 case '%':
238 case ':':
239 case '&':
240 tok.next();
241 break;
242 case '>':
243 tok.next();
244 if (tok.ch() == '=') {
245 tok.next();
246 op = OP_GEQ;
247 }
248 else if (tok.ch() == '?') {
249 tok.next();
250 op = OP_MAX;
251 }
252 break;
253 case '<':
254 tok.next();
255 if (tok.ch() == '=') {
256 tok.next();
257 op = OP_LEQ;
258 }
259 else if (tok.ch() == '?') {
260 tok.next();
261 op = OP_MIN;
262 }
263 break;
264 case '=':
265 tok.next();
266 if (tok.ch() == '=')
267 tok.next();
268 break;
269 default:
270 return result;
271 }
272 units v2;
273 if (!parse_term(&v2, scale_indicator, parenthesised))
274 return 0;
275 int overflow = 0;
276 switch (op) {
277 case '<':
278 *v = *v < v2;
279 break;
280 case '>':
281 *v = *v > v2;
282 break;
283 case OP_LEQ:
284 *v = *v <= v2;
285 break;
286 case OP_GEQ:
287 *v = *v >= v2;
288 break;
289 case OP_MIN:
290 if (*v > v2)
291 *v = v2;
292 break;
293 case OP_MAX:
294 if (*v < v2)
295 *v = v2;
296 break;
297 case '=':
298 *v = *v == v2;
299 break;
300 case '&':
301 *v = *v > 0 && v2 > 0;
302 break;
303 case ':':
304 *v = *v > 0 || v2 > 0;
305 case '+':
306 if (v2 < 0) {
307 if (*v < INT_MIN - v2)
308 overflow = 1;
309 }
310 else if (v2 > 0) {
311 if (*v > INT_MAX - v2)
312 overflow = 1;
313 }
314 if (overflow) {
315 error("addition overflow");
316 return 0;
317 }
318 *v += v2;
319 break;
320 case '-':
321 if (v2 < 0) {
322 if (*v > INT_MAX + v2)
323 overflow = 1;
324 }
325 else if (v2 > 0) {
326 if (*v < INT_MIN + v2)
327 overflow = 1;
328 }
329 if (overflow) {
330 error("subtraction overflow");
331 return 0;
332 }
333 *v -= v2;
334 break;
335 case '*':
336 if (v2 < 0) {
337 if (*v > 0) {
338 if (*v > -(unsigned)INT_MIN / -(unsigned)v2)
339 overflow = 1;
340 }
341 else if (-(unsigned)*v > INT_MAX / -(unsigned)v2)
342 overflow = 1;
343 }
344 else if (v2 > 0) {
345 if (*v > 0) {
346 if (*v > INT_MAX / v2)
347 overflow = 1;
348 }
349 else if (-(unsigned)*v > -(unsigned)INT_MIN / v2)
350 overflow = 1;
351 }
352 if (overflow) {
353 error("multiplication overflow");
354 return 0;
355 }
356 *v *= v2;
357 break;
358 case '/':
359 if (v2 == 0) {
360 error("division by zero");
361 return 0;
362 }
363 *v /= v2;
364 break;
365 case '%':
366 if (v2 == 0) {
367 error("modulus by zero");
368 return 0;
369 }
370 *v %= v2;
371 break;
372 default:
373 assert(0);
374 }
375 }
376 return result;
377 }
378
parse_term(units * v,int scale_indicator,int parenthesised)379 static int parse_term(units *v, int scale_indicator, int parenthesised)
380 {
381 int negative = 0;
382 for (;;)
383 if (parenthesised && tok.space())
384 tok.next();
385 else if (tok.ch() == '+')
386 tok.next();
387 else if (tok.ch() == '-') {
388 tok.next();
389 negative = !negative;
390 }
391 else
392 break;
393 unsigned char c = tok.ch();
394 switch (c) {
395 case '|':
396 // | is not restricted to the outermost level
397 // tbl uses this
398 tok.next();
399 if (!parse_term(v, scale_indicator, parenthesised))
400 return 0;
401 int tem;
402 tem = (scale_indicator == 'v'
403 ? curdiv->get_vertical_position().to_units()
404 : curenv->get_input_line_position().to_units());
405 if (tem >= 0) {
406 if (*v < INT_MIN + tem) {
407 error("numeric overflow");
408 return 0;
409 }
410 }
411 else {
412 if (*v > INT_MAX + tem) {
413 error("numeric overflow");
414 return 0;
415 }
416 }
417 *v -= tem;
418 if (negative) {
419 if (*v == INT_MIN) {
420 error("numeric overflow");
421 return 0;
422 }
423 *v = -*v;
424 }
425 return 1;
426 case '(':
427 tok.next();
428 c = tok.ch();
429 if (c == ')') {
430 warning(WARN_SYNTAX, "empty parentheses");
431 tok.next();
432 *v = 0;
433 return 1;
434 }
435 else if (c != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
436 tok.next();
437 if (tok.ch() == ';') {
438 tok.next();
439 scale_indicator = c;
440 }
441 else {
442 error("expected `;' after scale-indicator (got %1)",
443 tok.description());
444 return 0;
445 }
446 }
447 else if (c == ';') {
448 scale_indicator = 0;
449 tok.next();
450 }
451 if (!parse_expr(v, scale_indicator, 1))
452 return 0;
453 tok.skip();
454 if (tok.ch() != ')') {
455 warning(WARN_SYNTAX, "missing `)' (got %1)", tok.description());
456 }
457 else
458 tok.next();
459 if (negative) {
460 if (*v == INT_MIN) {
461 error("numeric overflow");
462 return 0;
463 }
464 *v = -*v;
465 }
466 return 1;
467 case '.':
468 *v = 0;
469 break;
470 case '0':
471 case '1':
472 case '2':
473 case '3':
474 case '4':
475 case '5':
476 case '6':
477 case '7':
478 case '8':
479 case '9':
480 *v = 0;
481 do {
482 if (*v > INT_MAX/10) {
483 error("numeric overflow");
484 return 0;
485 }
486 *v *= 10;
487 if (*v > INT_MAX - (int(c) - '0')) {
488 error("numeric overflow");
489 return 0;
490 }
491 *v += c - '0';
492 tok.next();
493 c = tok.ch();
494 } while (csdigit(c));
495 break;
496 case '/':
497 case '*':
498 case '%':
499 case ':':
500 case '&':
501 case '>':
502 case '<':
503 case '=':
504 warning(WARN_SYNTAX, "empty left operand");
505 *v = 0;
506 return 1;
507 default:
508 warning(WARN_NUMBER, "numeric expression expected (got %1)",
509 tok.description());
510 return 0;
511 }
512 int divisor = 1;
513 if (tok.ch() == '.') {
514 tok.next();
515 for (;;) {
516 c = tok.ch();
517 if (!csdigit(c))
518 break;
519 // we may multiply the divisor by 254 later on
520 if (divisor <= INT_MAX/2540 && *v <= (INT_MAX - 9)/10) {
521 *v *= 10;
522 *v += c - '0';
523 divisor *= 10;
524 }
525 tok.next();
526 }
527 }
528 int si = scale_indicator;
529 int do_next = 0;
530 if ((c = tok.ch()) != 0 && strchr(SCALE_INDICATOR_CHARS, c) != 0) {
531 switch (scale_indicator) {
532 case 'z':
533 if (c != 'u' && c != 'z') {
534 warning(WARN_SCALE,
535 "only `z' and `u' scale indicators valid in this context");
536 break;
537 }
538 si = c;
539 break;
540 case 0:
541 warning(WARN_SCALE, "scale indicator invalid in this context");
542 break;
543 case 'u':
544 si = c;
545 break;
546 default:
547 if (c == 'z') {
548 warning(WARN_SCALE, "`z' scale indicator invalid in this context");
549 break;
550 }
551 si = c;
552 break;
553 }
554 // Don't do tok.next() here because the next token might be \s, which
555 // would affect the interpretation of m.
556 do_next = 1;
557 }
558 switch (si) {
559 case 'i':
560 *v = scale(*v, units_per_inch, divisor);
561 break;
562 case 'c':
563 *v = scale(*v, units_per_inch*100, divisor*254);
564 break;
565 case 0:
566 case 'u':
567 if (divisor != 1)
568 *v /= divisor;
569 break;
570 case 'p':
571 *v = scale(*v, units_per_inch, divisor*72);
572 break;
573 case 'P':
574 *v = scale(*v, units_per_inch, divisor*6);
575 break;
576 case 'm':
577 {
578 // Convert to hunits so that with -Tascii `m' behaves as in nroff.
579 hunits em = curenv->get_size();
580 *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor);
581 }
582 break;
583 case 'M':
584 {
585 hunits em = curenv->get_size();
586 *v = scale(*v, em.is_zero() ? hresolution : em.to_units(), divisor*100);
587 }
588 break;
589 case 'n':
590 {
591 // Convert to hunits so that with -Tascii `n' behaves as in nroff.
592 hunits en = curenv->get_size()/2;
593 *v = scale(*v, en.is_zero() ? hresolution : en.to_units(), divisor);
594 }
595 break;
596 case 'v':
597 *v = scale(*v, curenv->get_vertical_spacing().to_units(), divisor);
598 break;
599 case 's':
600 while (divisor > INT_MAX/(sizescale*72)) {
601 divisor /= 10;
602 *v /= 10;
603 }
604 *v = scale(*v, units_per_inch, divisor*sizescale*72);
605 break;
606 case 'z':
607 *v = scale(*v, sizescale, divisor);
608 break;
609 default:
610 assert(0);
611 }
612 if (do_next)
613 tok.next();
614 if (negative) {
615 if (*v == INT_MIN) {
616 error("numeric overflow");
617 return 0;
618 }
619 *v = -*v;
620 }
621 return 1;
622 }
623
scale(units n,units x,units y)624 units scale(units n, units x, units y)
625 {
626 assert(x >= 0 && y > 0);
627 if (x == 0)
628 return 0;
629 if (n >= 0) {
630 if (n <= INT_MAX/x)
631 return (n*x)/y;
632 }
633 else {
634 if (-(unsigned)n <= -(unsigned)INT_MIN/x)
635 return (n*x)/y;
636 }
637 double res = n*double(x)/double(y);
638 if (res > INT_MAX) {
639 error("numeric overflow");
640 return INT_MAX;
641 }
642 else if (res < INT_MIN) {
643 error("numeric overflow");
644 return INT_MIN;
645 }
646 return int(res);
647 }
648
vunits(units x)649 vunits::vunits(units x)
650 {
651 // don't depend on the rounding direction for division of negative integers
652 if (vresolution == 1)
653 n = x;
654 else
655 n = (x < 0
656 ? -((-x + vresolution/2 - 1)/vresolution)
657 : (x + vresolution/2 - 1)/vresolution);
658 }
659
hunits(units x)660 hunits::hunits(units x)
661 {
662 // don't depend on the rounding direction for division of negative integers
663 if (hresolution == 1)
664 n = x;
665 else
666 n = (x < 0
667 ? -((-x + hresolution/2 - 1)/hresolution)
668 : (x + hresolution/2 - 1)/hresolution);
669 }
670