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