font: unmap glyphs with .fmap
[neatroff.git] / eval.c
blob3cc4b141a4bf67db610db46428f85878af6aeb45
1 /* evaluation of integer expressions */
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "roff.h"
7 #define SCHAR "icpPvmnu" /* scale indicators */
9 static int defunit = 0; /* default scale indicator */
10 static int abspos = 0; /* absolute position like |1i */
12 static int readunit(int c, int n)
14 switch (c) {
15 case 'i':
16 return n * SC_IN;
17 case 'c':
18 return n * SC_IN * 50 / 127;
19 case 'p':
20 return n * SC_IN / 72;
21 case 'P':
22 return n * SC_IN / 6;
23 case 'v':
24 return n * n_v;
25 case 'm':
26 return n * n_s * SC_IN / 72;
27 case 'n':
28 return n * n_s * SC_IN / 144;
29 case 'u':
30 return n;
32 return n;
35 static int evalnum(char **_s)
37 char *s = *_s;
38 int n = 0; /* the result */
39 int mag = 0; /* n should be divided by mag */
40 while (isdigit(*s) || *s == '.') {
41 if (*s == '.') {
42 mag = 1;
43 s++;
44 continue;
46 mag *= 10;
47 n = n * 10 + *s++ - '0';
49 if (mag > MAXFRAC) {
50 n /= mag / MAXFRAC;
51 mag /= mag / MAXFRAC;
53 n = readunit(*s && strchr(SCHAR, *s) ? *s++ : defunit, n);
54 *_s = s;
55 return n / (mag > 0 ? mag : 1);
58 static int evaljmp(char **s, int c)
60 if (**s == c) {
61 (*s)++;
62 return 0;
64 return 1;
67 static int evalisnum(char **s)
69 return **s == '.' || isdigit(**s);
72 static int evalexpr(char **s);
73 static int evalatom(char **s);
75 static int evalatom(char **s)
77 int ret;
78 if (evalisnum(s))
79 return evalnum(s);
80 if (!evaljmp(s, '-'))
81 return -evalatom(s);
82 if (!evaljmp(s, '+'))
83 return evalatom(s);
84 if (!evaljmp(s, '|'))
85 return abspos + evalatom(s);
86 if (!evaljmp(s, '(')) {
87 ret = evalexpr(s);
88 evaljmp(s, ')');
89 return ret;
91 return 0;
94 static int nonzero(int n)
96 if (!n)
97 errdie("neatroff: divide by zero\n");
98 return n;
101 static int evalexpr(char **s)
103 int ret = evalatom(s);
104 while (**s) {
105 if (!evaljmp(s, '+'))
106 ret += evalatom(s);
107 else if (!evaljmp(s, '-'))
108 ret -= evalatom(s);
109 else if (!evaljmp(s, '/'))
110 ret /= nonzero(evalatom(s));
111 else if (!evaljmp(s, '*'))
112 ret *= evalatom(s);
113 else if (!evaljmp(s, '%'))
114 ret %= nonzero(evalatom(s));
115 else if (!evaljmp(s, '<'))
116 ret = !evaljmp(s, '=') ? ret <= evalatom(s) : ret < evalatom(s);
117 else if (!evaljmp(s, '>'))
118 ret = !evaljmp(s, '=') ? ret >= evalatom(s) : ret > evalatom(s);
119 else if (!evaljmp(s, '=') + !evaljmp(s, '='))
120 ret = ret == evalatom(s);
121 else if (!evaljmp(s, '&'))
122 ret = ret > 0 && evalatom(s) > 0;
123 else if (!evaljmp(s, ':'))
124 ret = ret > 0 || evalatom(s) > 0;
125 else
126 break;
128 return ret;
131 /* evaluate *s and update s to point to the last character read */
132 int eval_up(char **s, int unit)
134 defunit = unit;
135 if (unit == 'v')
136 abspos = -n_d;
137 if (unit == 'm')
138 abspos = n_lb - f_hpos();
139 return evalexpr(s);
142 /* evaluate s relative to its previous value */
143 int eval_re(char *s, int orig, int unit)
145 int n;
146 int rel = 0; /* n should be added to orig */
147 if (*s == '+' || *s == '-') {
148 rel = *s == '+' ? 1 : -1;
149 s++;
151 n = eval_up(&s, unit);
152 if (rel)
153 return rel > 0 ? orig + n : orig - n;
154 return n;
157 /* evaluate s */
158 int eval(char *s, int unit)
160 return eval_up(&s, unit);