fmt: shrink word spaces with .ssh request
[neatroff.git] / eval.c
blobcb71890fb8371fbb2fb8d6f62eff5ba43ded26c4
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 evalexpr(char **s)
96 int ret = evalatom(s);
97 while (**s) {
98 if (!evaljmp(s, '+'))
99 ret += evalatom(s);
100 else if (!evaljmp(s, '-'))
101 ret -= evalatom(s);
102 else if (!evaljmp(s, '/'))
103 ret /= evalatom(s);
104 else if (!evaljmp(s, '*'))
105 ret *= evalatom(s);
106 else if (!evaljmp(s, '%'))
107 ret %= evalatom(s);
108 else if (!evaljmp(s, '<'))
109 ret = !evaljmp(s, '=') ? ret <= evalatom(s) : ret < evalatom(s);
110 else if (!evaljmp(s, '>'))
111 ret = !evaljmp(s, '=') ? ret >= evalatom(s) : ret > evalatom(s);
112 else if (!evaljmp(s, '=') + !evaljmp(s, '='))
113 ret = ret == evalatom(s);
114 else if (!evaljmp(s, '&'))
115 ret = ret && evalatom(s);
116 else if (!evaljmp(s, ':'))
117 ret = ret || evalatom(s);
118 else
119 break;
121 return ret;
124 /* evaluate *s and update s to point to the last character read */
125 int eval_up(char **s, int unit)
127 defunit = unit;
128 if (unit == 'v')
129 abspos = -n_d;
130 if (unit == 'm')
131 abspos = n_lb - f_hpos();
132 return evalexpr(s);
135 /* evaluate s relative to its previous value */
136 int eval_re(char *s, int orig, int unit)
138 int n;
139 int rel = 0; /* n should be added to orig */
140 if (*s == '+' || *s == '-') {
141 rel = *s == '+' ? 1 : -1;
142 s++;
144 n = eval_up(&s, unit);
145 if (rel)
146 return rel > 0 ? orig + n : orig - n;
147 return n;
150 /* evaluate s */
151 int eval(char *s, int unit)
153 return eval_up(&s, unit);