cp: allow \$[] and more than 9 arguments
[neatroff.git] / eval.c
bloba1f18faff82d2bd76f65027350490384419e401f
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include "roff.h"
6 #define SCHAR "icpPvmnu" /* scale indicators */
8 static int defunit = 0; /* default scale indicator */
9 static int abspos = 0; /* absolute position like |1i */
11 static int readunit(int c, int n)
13 switch (c) {
14 case 'i':
15 return n * SC_IN;
16 case 'c':
17 return n * SC_IN * 50 / 127;
18 case 'p':
19 return n * SC_IN / 72;
20 case 'P':
21 return n * SC_IN / 6;
22 case 'v':
23 return n * n_v;
24 case 'm':
25 return n * n_s * SC_IN / 72;
26 case 'n':
27 return n * n_s * SC_IN / 144;
28 case 'u':
29 return n;
31 return n;
34 static int evalnum(char **_s)
36 char *s = *_s;
37 int n = 0; /* the result */
38 int mag = 0; /* n should be divided by mag */
39 while (isdigit(*s) || *s == '.') {
40 if (*s == '.') {
41 mag = 1;
42 s++;
43 continue;
45 mag *= 10;
46 n = n * 10 + *s++ - '0';
48 if (mag > MAXFRAC) {
49 n /= mag / MAXFRAC;
50 mag /= mag / MAXFRAC;
52 n = readunit(*s && strchr(SCHAR, *s) ? *s++ : defunit, n);
53 *_s = s;
54 return n / (mag > 0 ? mag : 1);
57 static int evaljmp(char **s, int c)
59 if (**s == c) {
60 (*s)++;
61 return 0;
63 return 1;
66 static int evalisnum(char **s)
68 return **s == '.' || isdigit(**s);
71 static int evalexpr(char **s);
72 static int evalatom(char **s);
74 static int evalatom(char **s)
76 int ret;
77 if (evalisnum(s))
78 return evalnum(s);
79 if (!evaljmp(s, '-'))
80 return -evalatom(s);
81 if (!evaljmp(s, '+'))
82 return evalatom(s);
83 if (!evaljmp(s, '|'))
84 return abspos + evalatom(s);
85 if (!evaljmp(s, '(')) {
86 ret = evalexpr(s);
87 evaljmp(s, ')');
88 return ret;
90 return 0;
93 static int evalexpr(char **s)
95 int ret = evalatom(s);
96 while (**s) {
97 if (!evaljmp(s, '+'))
98 ret += evalatom(s);
99 else if (!evaljmp(s, '-'))
100 ret -= evalatom(s);
101 else if (!evaljmp(s, '/'))
102 ret /= evalatom(s);
103 else if (!evaljmp(s, '*'))
104 ret *= evalatom(s);
105 else if (!evaljmp(s, '%'))
106 ret %= evalatom(s);
107 else if (!evaljmp(s, '<'))
108 ret = !evaljmp(s, '=') ? ret <= evalatom(s) : ret < evalatom(s);
109 else if (!evaljmp(s, '>'))
110 ret = !evaljmp(s, '=') ? ret >= evalatom(s) : ret > evalatom(s);
111 else if (!evaljmp(s, '=') + !evaljmp(s, '='))
112 ret = ret == evalatom(s);
113 else if (!evaljmp(s, '&'))
114 ret = ret && evalatom(s);
115 else if (!evaljmp(s, ':'))
116 ret = ret || evalatom(s);
117 else
118 break;
120 return ret;
123 /* evaluate *s and update s to point to the last character read */
124 int eval_up(char **s, int unit)
126 defunit = unit;
127 if (unit == 'v')
128 abspos = -n_d;
129 if (unit == 'm')
130 abspos = n_lb - f_hpos();
131 return evalexpr(s);
134 /* evaluate s relative to its previous value */
135 int eval_re(char *s, int orig, int unit)
137 int n;
138 int rel = 0; /* n should be added to orig */
139 if (*s == '+' || *s == '-') {
140 rel = *s == '+' ? 1 : -1;
141 s++;
143 n = eval_up(&s, unit);
144 if (rel)
145 return rel > 0 ? orig + n : orig - n;
146 return n;
149 /* evaluate s */
150 int eval(char *s, int unit)
152 return eval_up(&s, unit);