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