268834b28bcf34e96920caffdf66b50531226cff
[platform/upstream/groff.git] / src / roff / troff / number.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989-2014  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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }