diff options
author | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2001-07-30 21:41:37 +0000 |
---|---|---|
committer | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2001-07-30 21:41:37 +0000 |
commit | c6312c270adf0ecceac516c1a3b647eb79229a73 (patch) | |
tree | f54a28df9cd460c1da85e13e6fe1b387199f92df /libbb | |
parent | 792fe8e7657642423a55f937d53b190e54d553a5 (diff) | |
download | busybox-w32-c6312c270adf0ecceac516c1a3b647eb79229a73.tar.gz busybox-w32-c6312c270adf0ecceac516c1a3b647eb79229a73.tar.bz2 busybox-w32-c6312c270adf0ecceac516c1a3b647eb79229a73.zip |
This incorporates Posix math support into ash. The Posix math support
was written by Aaron Lehmann <aaronl@vitelus.com> for busybox. This
patch makes a few trivial changes to Aaron's code so that it can be
used (in theory) by the other shells as well...
-Erik
git-svn-id: svn://busybox.net/trunk/busybox@3165 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/arith.c | 250 | ||||
-rw-r--r-- | libbb/libbb.h | 2 |
2 files changed, 252 insertions, 0 deletions
diff --git a/libbb/arith.c b/libbb/arith.c new file mode 100644 index 000000000..c7a3cf98b --- /dev/null +++ b/libbb/arith.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> | ||
2 | |||
3 | Permission is hereby granted, free of charge, to any person obtaining | ||
4 | a copy of this software and associated documentation files (the | ||
5 | "Software"), to deal in the Software without restriction, including | ||
6 | without limitation the rights to use, copy, modify, merge, publish, | ||
7 | distribute, sublicense, and/or sell copies of the Software, and to | ||
8 | permit persons to whom the Software is furnished to do so, subject to | ||
9 | the following conditions: | ||
10 | |||
11 | The above copyright notice and this permission notice shall be | ||
12 | included in all copies or substantial portions of the Software. | ||
13 | |||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | /* This is my infix parser/evaluator. It is optimized for size, intended | ||
24 | * as a replacement for yacc-based parsers. However, it may well be faster | ||
25 | * than a comparable parser writen in yacc. The supported operators are | ||
26 | * listed in #defines below. Parens, order of operations, and error handling | ||
27 | * are supported. This code is threadsafe. */ | ||
28 | |||
29 | /* To use the routine, call it with an expression string. It returns an | ||
30 | * integer result. You will also need to define an "error" function | ||
31 | * that takes printf arguments and _does not return_, or modify the code | ||
32 | * to use another error mechanism. */ | ||
33 | |||
34 | #include <stdlib.h> | ||
35 | #include <string.h> | ||
36 | #include "libbb.h" | ||
37 | |||
38 | typedef char operator; | ||
39 | |||
40 | #define tok_decl(prec,id) (((id)<<5)|(prec)) | ||
41 | #define PREC(op) ((op)&0x1F) | ||
42 | |||
43 | #define TOK_LPAREN tok_decl(0,0) | ||
44 | |||
45 | #define TOK_OR tok_decl(1,0) | ||
46 | |||
47 | #define TOK_AND tok_decl(2,0) | ||
48 | |||
49 | #define TOK_BOR tok_decl(3,0) | ||
50 | |||
51 | #define TOK_BXOR tok_decl(4,0) | ||
52 | |||
53 | #define TOK_BAND tok_decl(5,0) | ||
54 | |||
55 | #define TOK_EQ tok_decl(6,0) | ||
56 | #define TOK_NE tok_decl(6,1) | ||
57 | |||
58 | #define TOK_LT tok_decl(7,0) | ||
59 | #define TOK_GT tok_decl(7,1) | ||
60 | #define TOK_GE tok_decl(7,2) | ||
61 | #define TOK_LE tok_decl(7,3) | ||
62 | |||
63 | #define TOK_LSHIFT tok_decl(8,0) | ||
64 | #define TOK_RSHIFT tok_decl(8,1) | ||
65 | |||
66 | #define TOK_ADD tok_decl(9,0) | ||
67 | #define TOK_SUB tok_decl(9,1) | ||
68 | |||
69 | #define TOK_MUL tok_decl(10,0) | ||
70 | #define TOK_DIV tok_decl(10,1) | ||
71 | #define TOK_REM tok_decl(10,2) | ||
72 | |||
73 | #define UNARYPREC 14 | ||
74 | #define TOK_BNOT tok_decl(UNARYPREC,0) | ||
75 | #define TOK_NOT tok_decl(UNARYPREC,1) | ||
76 | #define TOK_UMINUS tok_decl(UNARYPREC,2) | ||
77 | |||
78 | #define TOK_NUM tok_decl(15,0) | ||
79 | |||
80 | #define ARITH_APPLY(op) arith_apply(op, numstack, &numstackptr) | ||
81 | #define NUMPTR (*numstackptr) | ||
82 | static short arith_apply(operator op, long *numstack, long **numstackptr) | ||
83 | { | ||
84 | if (NUMPTR == numstack) goto err; | ||
85 | if (op == TOK_UMINUS) | ||
86 | NUMPTR[-1] *= -1; | ||
87 | else if (op == TOK_NOT) | ||
88 | NUMPTR[-1] = !(NUMPTR[-1]); | ||
89 | else if (op == TOK_BNOT) | ||
90 | NUMPTR[-1] = ~(NUMPTR[-1]); | ||
91 | |||
92 | /* Binary operators */ | ||
93 | else { | ||
94 | if (NUMPTR-1 == numstack) goto err; | ||
95 | --NUMPTR; | ||
96 | if (op == TOK_BOR) | ||
97 | NUMPTR[-1] |= *NUMPTR; | ||
98 | else if (op == TOK_OR) | ||
99 | NUMPTR[-1] = *NUMPTR || NUMPTR[-1]; | ||
100 | else if (op == TOK_BAND) | ||
101 | NUMPTR[-1] &= *NUMPTR; | ||
102 | else if (op == TOK_AND) | ||
103 | NUMPTR[-1] = NUMPTR[-1] && *NUMPTR; | ||
104 | else if (op == TOK_EQ) | ||
105 | NUMPTR[-1] = (NUMPTR[-1] == *NUMPTR); | ||
106 | else if (op == TOK_NE) | ||
107 | NUMPTR[-1] = (NUMPTR[-1] != *NUMPTR); | ||
108 | else if (op == TOK_GE) | ||
109 | NUMPTR[-1] = (NUMPTR[-1] >= *NUMPTR); | ||
110 | else if (op == TOK_RSHIFT) | ||
111 | NUMPTR[-1] >>= *NUMPTR; | ||
112 | else if (op == TOK_LSHIFT) | ||
113 | NUMPTR[-1] <<= *NUMPTR; | ||
114 | else if (op == TOK_GT) | ||
115 | NUMPTR[-1] = (NUMPTR[-1] > *NUMPTR); | ||
116 | else if (op == TOK_LT) | ||
117 | NUMPTR[-1] = (NUMPTR[-1] < *NUMPTR); | ||
118 | else if (op == TOK_LE) | ||
119 | NUMPTR[-1] = (NUMPTR[-1] <= *NUMPTR); | ||
120 | else if (op == TOK_MUL) | ||
121 | NUMPTR[-1] *= *NUMPTR; | ||
122 | else if (op == TOK_DIV) | ||
123 | NUMPTR[-1] /= *NUMPTR; | ||
124 | else if (op == TOK_REM) | ||
125 | NUMPTR[-1] %= *NUMPTR; | ||
126 | else if (op == TOK_ADD) | ||
127 | NUMPTR[-1] += *NUMPTR; | ||
128 | else if (op == TOK_SUB) | ||
129 | NUMPTR[-1] -= *NUMPTR; | ||
130 | } | ||
131 | return 0; | ||
132 | err: return(1); | ||
133 | } | ||
134 | |||
135 | extern long arith (const char *startbuf) | ||
136 | { | ||
137 | register char arithval; | ||
138 | const char *expr = startbuf; | ||
139 | |||
140 | operator lasttok = TOK_MUL, op; | ||
141 | size_t datasizes = strlen(startbuf); | ||
142 | unsigned char prec; | ||
143 | |||
144 | long *numstack, *numstackptr; | ||
145 | |||
146 | operator *stack = alloca(datasizes * sizeof(operator)), *stackptr = stack; | ||
147 | numstack = alloca((datasizes/2+1)*sizeof(long)), numstackptr = numstack; | ||
148 | |||
149 | while ((arithval = *expr)) { | ||
150 | if (arithval == ' ' || arithval == '\n' || arithval == '\t') | ||
151 | goto prologue; | ||
152 | if ((unsigned)arithval-'0' <= 9) /* isdigit */ { | ||
153 | *numstackptr++ = strtol(expr, (char **) &expr, 10); | ||
154 | lasttok = TOK_NUM; | ||
155 | continue; | ||
156 | } if (arithval == '(') { | ||
157 | *stackptr++ = TOK_LPAREN; | ||
158 | lasttok = TOK_LPAREN; | ||
159 | goto prologue; | ||
160 | } if (arithval == ')') { | ||
161 | lasttok = TOK_NUM; | ||
162 | while (stackptr != stack) { | ||
163 | op = *--stackptr; | ||
164 | if (op == TOK_LPAREN) | ||
165 | goto prologue; | ||
166 | if(ARITH_APPLY(op)) goto err; | ||
167 | } | ||
168 | goto err; /* Mismatched parens */ | ||
169 | } if (arithval == '|') { | ||
170 | if (*++expr == '|') | ||
171 | op = TOK_OR; | ||
172 | else { | ||
173 | --expr; | ||
174 | op = TOK_BOR; | ||
175 | } | ||
176 | } else if (arithval == '&') { | ||
177 | if (*++expr == '&') | ||
178 | op = TOK_AND; | ||
179 | else { | ||
180 | --expr; | ||
181 | op = TOK_BAND; | ||
182 | } | ||
183 | } else if (arithval == '=') { | ||
184 | if (*++expr != '=') goto err; /* Unknown token */ | ||
185 | op = TOK_EQ; | ||
186 | } else if (arithval == '!') { | ||
187 | if (*++expr == '=') | ||
188 | op = TOK_NE; | ||
189 | else { | ||
190 | --expr; | ||
191 | op = TOK_NOT; | ||
192 | } | ||
193 | } else if (arithval == '>') { | ||
194 | switch (*++expr) { | ||
195 | case '=': | ||
196 | op = TOK_GE; | ||
197 | break; | ||
198 | case '>': | ||
199 | op = TOK_RSHIFT; | ||
200 | break; | ||
201 | default: | ||
202 | --expr; | ||
203 | op = TOK_GT; | ||
204 | } | ||
205 | } else if (arithval == '<') { | ||
206 | switch (*++expr) { | ||
207 | case '=': | ||
208 | op = TOK_LE; | ||
209 | break; | ||
210 | case '<': | ||
211 | op = TOK_LSHIFT; | ||
212 | break; | ||
213 | default: | ||
214 | --expr; | ||
215 | op = TOK_LT; | ||
216 | } | ||
217 | } else if (arithval == '*') | ||
218 | op = TOK_MUL; | ||
219 | else if (arithval == '/') | ||
220 | op = TOK_DIV; | ||
221 | else if (arithval == '%') | ||
222 | op = TOK_REM; | ||
223 | else if (arithval == '+') { | ||
224 | if (lasttok != TOK_NUM) goto prologue; /* Unary plus */ | ||
225 | op = TOK_ADD; | ||
226 | } else if (arithval == '-') | ||
227 | op = (lasttok == TOK_NUM) ? TOK_SUB : TOK_UMINUS; | ||
228 | else if (arithval == '~') | ||
229 | op = TOK_BNOT; | ||
230 | else goto err; /* Unknown token */ | ||
231 | |||
232 | prec = PREC(op); | ||
233 | if (prec != UNARYPREC) | ||
234 | while (stackptr != stack && PREC(stackptr[-1]) >= prec) | ||
235 | if(ARITH_APPLY(*--stackptr)) goto err; | ||
236 | *stackptr++ = op; | ||
237 | lasttok = op; | ||
238 | prologue: ++expr; | ||
239 | } /* yay */ | ||
240 | |||
241 | while (stackptr != stack) | ||
242 | if(ARITH_APPLY(*--stackptr)) goto err; | ||
243 | if (numstackptr != numstack+1) { | ||
244 | err: | ||
245 | return -1; | ||
246 | /* NOTREACHED */ | ||
247 | } | ||
248 | |||
249 | return *numstack; | ||
250 | } | ||
diff --git a/libbb/libbb.h b/libbb/libbb.h index 3cf932dc4..66acc2278 100644 --- a/libbb/libbb.h +++ b/libbb/libbb.h | |||
@@ -212,6 +212,8 @@ char *xreadlink(const char *path); | |||
212 | char *concat_path_file(const char *path, const char *filename); | 212 | char *concat_path_file(const char *path, const char *filename); |
213 | char *last_char_is(const char *s, int c); | 213 | char *last_char_is(const char *s, int c); |
214 | 214 | ||
215 | extern long arith (const char *startbuf); | ||
216 | |||
215 | typedef struct file_headers_s { | 217 | typedef struct file_headers_s { |
216 | char *name; | 218 | char *name; |
217 | char *link_name; | 219 | char *link_name; |