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