]>
Commit | Line | Data |
---|---|---|
43ae1d95 | 1 | /* |
4ac4a490 | 2 | * Copyright (C) 1996-2017 The Squid Software Foundation and contributors |
43ae1d95 | 3 | * |
bbc27441 AJ |
4 | * Squid software is distributed under GPLv2+ license and includes |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
43ae1d95 | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 86 ESI processing */ |
10 | ||
582c2af2 FC |
11 | #include "squid.h" |
12 | #include "Debug.h" | |
f99c2cfe | 13 | #include "esi/Expression.h" |
582c2af2 FC |
14 | #include "profiler/Profiler.h" |
15 | ||
074d6a40 AJ |
16 | #include <cerrno> |
17 | #include <cmath> | |
43ae1d95 | 18 | |
19 | /* stack precedence rules: | |
26ac0430 | 20 | * before pushing an operator onto the stack, the |
43ae1d95 | 21 | * top 2 elements are checked. if either has a higher |
22 | * or equal precedence than the current operator, they | |
26ac0430 AJ |
23 | * are evaluated. |
24 | * Start of expression has 5 precedence, | |
43ae1d95 | 25 | * end of expression has 0 precedence |
26 | * literal has 1 as does expression results | |
27 | * | has 2 | |
28 | * & has 3 | |
29 | * ! has 4 | |
30 | * == != < > <= >= has 5 | |
31 | * ( has 5 | |
32 | * ) has 0 | |
33 | */ | |
34 | ||
35 | typedef struct _stackmember stackmember; | |
36 | ||
6ca34f6f HN |
37 | typedef int evaluate(stackmember * stack, int *depth, int whereAmI, |
38 | stackmember * candidate); | |
43ae1d95 | 39 | |
26ac0430 | 40 | typedef enum { |
43ae1d95 | 41 | ESI_EXPR_INVALID, |
42 | ESI_EXPR_LITERAL, | |
43 | ESI_EXPR_OR, | |
44 | ESI_EXPR_AND, | |
45 | ESI_EXPR_NOT, | |
46 | ESI_EXPR_START, | |
47 | ESI_EXPR_END, | |
48 | ESI_EXPR_EQ, | |
49 | ESI_EXPR_NOTEQ, | |
50 | ESI_EXPR_LESS, | |
51 | ESI_EXPR_LESSEQ, | |
52 | ESI_EXPR_MORE, | |
53 | ESI_EXPR_MOREEQ, | |
f53969cc | 54 | ESI_EXPR_EXPR /* the result of an expr PRI 1 */ |
2fadd50d | 55 | } evaltype; |
43ae1d95 | 56 | |
26ac0430 | 57 | typedef enum { |
43ae1d95 | 58 | ESI_LITERAL_STRING, |
59 | ESI_LITERAL_FLOAT, | |
60 | ESI_LITERAL_INT, | |
61 | ESI_LITERAL_BOOL, | |
62 | ESI_LITERAL_INVALID | |
2fadd50d | 63 | } literalhint; |
43ae1d95 | 64 | |
26ac0430 | 65 | struct _stackmember { |
43ae1d95 | 66 | evaluate *eval; |
26ac0430 | 67 | union { |
43ae1d95 | 68 | char *string; |
69 | double floating; | |
70 | int integral; | |
2fadd50d | 71 | } value; |
43ae1d95 | 72 | literalhint valuestored; |
73 | evaltype valuetype; | |
74 | int precedence; | |
75 | }; | |
76 | ||
6ca34f6f HN |
77 | static void cleanmember(stackmember *); |
78 | static void stackpop(stackmember * s, int *depth); | |
43ae1d95 | 79 | |
80 | void | |
6ca34f6f | 81 | cleanmember(stackmember * s) |
43ae1d95 | 82 | { |
83 | if (s->valuetype == ESI_EXPR_LITERAL | |
84 | && s->valuestored == ESI_LITERAL_STRING) { | |
6ca34f6f | 85 | safe_free(s->value.string); |
43ae1d95 | 86 | s->value.string = NULL; |
87 | } | |
88 | ||
89 | } | |
90 | ||
91 | void | |
6ca34f6f | 92 | stackpop(stackmember * s, int *depth) |
43ae1d95 | 93 | { |
94 | if (!(*depth)--) | |
95 | return; | |
96 | ||
6ca34f6f | 97 | cleanmember(&s[*depth]); |
43ae1d95 | 98 | } |
99 | ||
100 | static evaluate evalnegate; | |
101 | static evaluate evalliteral; | |
102 | static evaluate evalor; | |
103 | static evaluate evaland; | |
104 | static evaluate evallesseq; | |
105 | static evaluate evallessthan; | |
106 | static evaluate evalmoreeq; | |
107 | static evaluate evalmorethan; | |
108 | static evaluate evalequals; | |
109 | static evaluate evalnotequals; | |
110 | static evaluate evalstartexpr; | |
111 | static evaluate evalendexpr; | |
112 | static evaluate evalexpr; | |
6ca34f6f HN |
113 | static void dumpstack(stackmember * stack, int depth); |
114 | static int addmember(stackmember * stack, int *stackdepth, | |
115 | stackmember * candidate); | |
116 | static int membercompare(stackmember a, stackmember b); | |
117 | static char const *trim(char const *s); | |
118 | static stackmember getsymbol(const char *s, char const **endptr); | |
43ae1d95 | 119 | |
43ae1d95 | 120 | /* -2 = failed to compate |
121 | * -1 = a less than b | |
122 | * 0 = a equal b | |
123 | * 2 - a more than b | |
124 | */ | |
125 | int | |
6ca34f6f | 126 | membercompare(stackmember a, stackmember b) |
43ae1d95 | 127 | { |
128 | /* we can compare: sub expressions to sub expressions , | |
129 | * literals to literals | |
130 | */ | |
131 | ||
132 | if (!((a.valuetype == ESI_EXPR_LITERAL && b.valuetype == ESI_EXPR_LITERAL && | |
133 | a.valuestored != ESI_LITERAL_INVALID && b.valuestored != ESI_LITERAL_INVALID) || | |
134 | (a.valuetype == ESI_EXPR_EXPR && b.valuetype == ESI_EXPR_EXPR))) | |
135 | return -2; | |
136 | ||
137 | if (a.valuetype == ESI_EXPR_EXPR) { | |
138 | if (a.value.integral == b.value.integral) | |
139 | return 0; | |
140 | else | |
141 | return 1; | |
142 | } else if (a.valuestored == ESI_LITERAL_STRING) { | |
143 | if (b.valuestored == ESI_LITERAL_STRING) { | |
6ca34f6f | 144 | int i =strcmp(a.value.string, b.value.string); |
43ae1d95 | 145 | |
146 | if (i < 0) | |
147 | return -1; | |
148 | ||
149 | if (i > 0) | |
150 | return 1; | |
151 | ||
152 | return 0; | |
153 | } else { | |
154 | /* TODO: numeric to string conversion ? */ | |
e0236918 | 155 | debugs(86, DBG_IMPORTANT, "strcmp with non-string"); |
43ae1d95 | 156 | return -2; |
157 | } | |
158 | } else if (a.valuestored == ESI_LITERAL_FLOAT) { | |
159 | if (b.valuestored == ESI_LITERAL_INT) { | |
160 | if (fabs(a.value.floating - b.value.integral) < 0.00001) | |
161 | return 0; | |
162 | else if (a.value.floating < b.value.integral) | |
163 | return -1; | |
164 | else | |
165 | return 1; | |
166 | } else if (b.valuestored == ESI_LITERAL_FLOAT) { | |
167 | if (a.value.floating == b.value.floating) | |
168 | return 0; | |
169 | else if (a.value.floating < b.value.floating) | |
170 | return -1; | |
171 | else | |
172 | return 1; | |
173 | } else { | |
174 | /* TODO: attempt numeric converson again? */ | |
e0236918 | 175 | debugs(86, DBG_IMPORTANT, "floatcomp with non float or int"); |
43ae1d95 | 176 | return -2; |
177 | } | |
178 | } else if (a.valuestored == ESI_LITERAL_INT) { | |
179 | if (b.valuestored == ESI_LITERAL_INT) { | |
180 | if (a.value.integral == b.value.integral) | |
181 | return 0; | |
182 | else if (a.value.integral < b.value.integral) | |
183 | return -1; | |
184 | else | |
185 | return 1; | |
186 | } else if (b.valuestored == ESI_LITERAL_FLOAT) { | |
187 | if (fabs(a.value.integral - b.value.floating) < 0.00001) | |
188 | return 0; | |
189 | else if (a.value.integral < b.value.floating) | |
190 | return -1; | |
191 | else | |
192 | return 1; | |
193 | } else { | |
194 | /* TODO: attempt numeric converson again? */ | |
e0236918 | 195 | debugs(86, DBG_IMPORTANT, "intcomp vs non float non int"); |
43ae1d95 | 196 | return -2; |
197 | } | |
198 | } | |
199 | ||
200 | return -2; | |
201 | } | |
202 | ||
203 | /* return 0 on success, 1 on failure */ | |
6ca34f6f HN |
204 | int |
205 | evalnegate(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 206 | { |
207 | if (whereAmI != *depth - 2) | |
208 | /* invalid stack */ | |
209 | return 1; | |
210 | ||
211 | if (stack[whereAmI + 1].valuetype != ESI_EXPR_EXPR) | |
212 | /* invalid operand */ | |
213 | return 1; | |
214 | ||
215 | /* copy down */ | |
216 | --(*depth); | |
217 | ||
218 | stack[whereAmI] = stack[(*depth)]; | |
219 | ||
6ca34f6f | 220 | cleanmember(candidate); |
43ae1d95 | 221 | |
222 | if (stack[whereAmI].value.integral == 1) | |
223 | stack[whereAmI].value.integral = 0; | |
224 | else | |
225 | stack[whereAmI].value.integral = 1; | |
226 | ||
227 | return 0; | |
228 | } | |
229 | ||
6ca34f6f HN |
230 | int |
231 | evalliteral(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 232 | { |
e0236918 | 233 | debugs(86, DBG_IMPORTANT, "attempt to evaluate a literal"); |
43ae1d95 | 234 | /* literals can't be evaluated */ |
235 | return 1; | |
236 | } | |
237 | ||
6ca34f6f HN |
238 | int |
239 | evalexpr(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 240 | { |
e0236918 | 241 | debugs(86, DBG_IMPORTANT, "attempt to evaluate a sub-expression result"); |
43ae1d95 | 242 | /* sub-scpr's can't be evaluated */ |
243 | return 1; | |
244 | } | |
245 | ||
6ca34f6f HN |
246 | int |
247 | evalor(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 248 | { |
249 | int rv; | |
250 | stackmember srv; | |
251 | ||
252 | if (*depth < 3) | |
253 | /* Not enough operands */ | |
254 | return 1; | |
255 | ||
256 | if (whereAmI != *depth - 2) | |
257 | /* invalid stack */ | |
258 | return 1; | |
259 | ||
260 | if (stack[whereAmI + 1].valuetype != ESI_EXPR_EXPR || | |
261 | stack[whereAmI - 1].valuetype != ESI_EXPR_EXPR) | |
262 | /* invalid operand */ | |
263 | return 1; | |
264 | ||
265 | rv = stack[whereAmI - 1].value.integral || stack[whereAmI + 1].value.integral; | |
266 | ||
6ca34f6f | 267 | stackpop(stack, depth); /* arg rhs */ |
43ae1d95 | 268 | |
6ca34f6f | 269 | stackpop(stack, depth); /* me */ |
43ae1d95 | 270 | |
6ca34f6f | 271 | stackpop(stack, depth); /* arg lhs */ |
43ae1d95 | 272 | |
273 | srv.valuetype = ESI_EXPR_EXPR; | |
274 | ||
275 | srv.eval = evalliteral; | |
276 | ||
277 | srv.valuestored = ESI_LITERAL_BOOL; | |
278 | ||
279 | srv.value.integral = rv ? 1 : 0; | |
280 | ||
281 | srv.precedence = 1; | |
282 | ||
283 | stack[(*depth)++] = srv; | |
284 | ||
285 | /* we're out of way, try adding now */ | |
6ca34f6f | 286 | if (!addmember(stack, depth, candidate)) |
43ae1d95 | 287 | /* Something wrong upstream */ |
288 | return 1; | |
289 | ||
290 | return 0; | |
291 | } | |
292 | ||
6ca34f6f HN |
293 | int |
294 | evaland(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 295 | { |
296 | int rv; | |
297 | stackmember srv; | |
298 | ||
299 | if (*depth < 3) | |
300 | /* Not enough operands */ | |
301 | return 1; | |
302 | ||
303 | if (whereAmI != *depth - 2) | |
304 | /* invalid stack */ | |
305 | return 1; | |
306 | ||
307 | if (stack[whereAmI + 1].valuetype != ESI_EXPR_EXPR || | |
308 | stack[whereAmI - 1].valuetype != ESI_EXPR_EXPR) | |
309 | /* invalid operand */ | |
310 | return 1; | |
311 | ||
312 | rv = stack[whereAmI - 1].value.integral && stack[whereAmI + 1].value.integral; | |
313 | ||
6ca34f6f | 314 | stackpop(stack, depth); /* arg rhs */ |
43ae1d95 | 315 | |
6ca34f6f | 316 | stackpop(stack, depth); /* me */ |
43ae1d95 | 317 | |
6ca34f6f | 318 | stackpop(stack, depth); /* arg lhs */ |
43ae1d95 | 319 | |
320 | srv.valuetype = ESI_EXPR_EXPR; | |
321 | ||
322 | srv.eval = evalexpr; | |
323 | ||
324 | srv.valuestored = ESI_LITERAL_BOOL; | |
325 | ||
326 | srv.value.integral = rv ? 1 : 0; | |
327 | ||
328 | srv.precedence = 1; | |
329 | ||
330 | stack[(*depth)++] = srv; | |
331 | ||
332 | /* we're out of way, try adding now */ | |
6ca34f6f | 333 | if (!addmember(stack, depth, candidate)) |
43ae1d95 | 334 | /* Something wrong upstream */ |
335 | return 1; | |
336 | ||
337 | return 0; | |
338 | } | |
339 | ||
6ca34f6f HN |
340 | int |
341 | evallesseq(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 342 | { |
343 | int rv; | |
344 | stackmember srv; | |
345 | ||
346 | if (*depth < 3) | |
347 | /* Not enough operands */ | |
348 | return 1; | |
349 | ||
350 | if (whereAmI != *depth - 2) | |
351 | /* invalid stack */ | |
352 | return 1; | |
353 | ||
6ca34f6f | 354 | rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]); |
43ae1d95 | 355 | |
356 | if (rv == -2) | |
357 | /* invalid comparison */ | |
358 | return 1; | |
359 | ||
6ca34f6f | 360 | stackpop(stack, depth); /* arg rhs */ |
43ae1d95 | 361 | |
6ca34f6f | 362 | stackpop(stack, depth); /* me */ |
43ae1d95 | 363 | |
6ca34f6f | 364 | stackpop(stack, depth); /* arg lhs */ |
43ae1d95 | 365 | |
366 | srv.valuetype = ESI_EXPR_EXPR; | |
367 | ||
368 | srv.eval = evalexpr; | |
369 | ||
370 | srv.valuestored = ESI_LITERAL_BOOL; | |
371 | ||
372 | srv.value.integral = rv <= 0 ? 1 : 0; | |
373 | ||
374 | srv.precedence = 1; | |
375 | ||
376 | stack[(*depth)++] = srv; | |
377 | ||
378 | /* we're out of way, try adding now */ | |
6ca34f6f | 379 | if (!addmember(stack, depth, candidate)) |
43ae1d95 | 380 | /* Something wrong upstream */ |
381 | return 1; | |
382 | ||
e0236918 | 383 | /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */ |
43ae1d95 | 384 | return 0; |
385 | ||
43ae1d95 | 386 | } |
387 | ||
6ca34f6f HN |
388 | int |
389 | evallessthan(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 390 | { |
391 | int rv; | |
392 | stackmember srv; | |
393 | ||
394 | if (*depth < 3) | |
395 | /* Not enough operands */ | |
396 | return 1; | |
397 | ||
398 | if (whereAmI != *depth - 2) | |
399 | /* invalid stack */ | |
400 | return 1; | |
401 | ||
6ca34f6f | 402 | rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]); |
43ae1d95 | 403 | |
404 | if (rv == -2) | |
405 | /* invalid comparison */ | |
406 | return 1; | |
407 | ||
6ca34f6f | 408 | stackpop(stack, depth); /* arg rhs */ |
43ae1d95 | 409 | |
6ca34f6f | 410 | stackpop(stack, depth); /* me */ |
43ae1d95 | 411 | |
6ca34f6f | 412 | stackpop(stack, depth); /* arg lhs */ |
43ae1d95 | 413 | |
414 | srv.valuetype = ESI_EXPR_EXPR; | |
415 | ||
416 | srv.eval = evalexpr; | |
417 | ||
418 | srv.valuestored = ESI_LITERAL_BOOL; | |
419 | ||
420 | srv.value.integral = rv < 0 ? 1 : 0; | |
421 | ||
422 | srv.precedence = 1; | |
423 | ||
424 | stack[(*depth)++] = srv; | |
425 | ||
426 | /* we're out of way, try adding now */ | |
6ca34f6f | 427 | if (!addmember(stack, depth, candidate)) |
43ae1d95 | 428 | /* Something wrong upstream */ |
429 | return 1; | |
430 | ||
e0236918 | 431 | /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */ |
43ae1d95 | 432 | return 0; |
433 | ||
43ae1d95 | 434 | } |
435 | ||
6ca34f6f HN |
436 | int |
437 | evalmoreeq(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 438 | { |
439 | int rv; | |
440 | stackmember srv; | |
441 | ||
442 | if (*depth < 3) | |
443 | /* Not enough operands */ | |
444 | return 1; | |
445 | ||
446 | if (whereAmI != *depth - 2) | |
447 | /* invalid stack */ | |
448 | return 1; | |
449 | ||
6ca34f6f | 450 | rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]); |
43ae1d95 | 451 | |
452 | if (rv == -2) | |
453 | /* invalid comparison */ | |
454 | return 1; | |
455 | ||
6ca34f6f | 456 | stackpop(stack, depth); /* arg rhs */ |
43ae1d95 | 457 | |
6ca34f6f | 458 | stackpop(stack, depth); /* me */ |
43ae1d95 | 459 | |
6ca34f6f | 460 | stackpop(stack, depth); /* arg lhs */ |
43ae1d95 | 461 | |
462 | srv.valuetype = ESI_EXPR_EXPR; | |
463 | ||
464 | srv.eval = evalexpr; | |
465 | ||
466 | srv.valuestored = ESI_LITERAL_BOOL; | |
467 | ||
468 | srv.value.integral = rv >= 0 ? 1 : 0; | |
469 | ||
470 | srv.precedence = 1; | |
471 | ||
472 | stack[(*depth)++] = srv; | |
473 | ||
474 | /* we're out of way, try adding now */ | |
6ca34f6f | 475 | if (!addmember(stack, depth, candidate)) |
43ae1d95 | 476 | /* Something wrong upstream */ |
477 | return 1; | |
478 | ||
e0236918 | 479 | /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */ |
43ae1d95 | 480 | return 0; |
481 | ||
43ae1d95 | 482 | } |
483 | ||
6ca34f6f HN |
484 | int |
485 | evalmorethan(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 486 | { |
487 | int rv; | |
488 | stackmember srv; | |
489 | ||
490 | if (*depth < 3) | |
491 | /* Not enough operands */ | |
492 | return 1; | |
493 | ||
494 | if (whereAmI != *depth - 2) | |
495 | /* invalid stack */ | |
496 | return 1; | |
497 | ||
6ca34f6f | 498 | rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]); |
43ae1d95 | 499 | |
500 | if (rv == -2) | |
501 | /* invalid comparison */ | |
502 | return 1; | |
503 | ||
f53969cc | 504 | stackpop(stack, depth); /* arg rhs */ |
43ae1d95 | 505 | |
f53969cc | 506 | stackpop(stack, depth); /* me */ |
43ae1d95 | 507 | |
f53969cc | 508 | stackpop(stack, depth); /* arg lhs */ |
43ae1d95 | 509 | |
510 | srv.valuetype = ESI_EXPR_EXPR; | |
511 | ||
512 | srv.eval = evalexpr; | |
513 | ||
514 | srv.valuestored = ESI_LITERAL_BOOL; | |
515 | ||
516 | srv.value.integral = rv > 0 ? 1 : 0; | |
517 | ||
518 | srv.precedence = 1; | |
519 | ||
520 | stack[(*depth)++] = srv; | |
521 | ||
522 | /* we're out of way, try adding now */ | |
6ca34f6f | 523 | if (!addmember(stack, depth, candidate)) |
43ae1d95 | 524 | /* Something wrong upstream */ |
525 | return 1; | |
526 | ||
e0236918 | 527 | /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */ |
43ae1d95 | 528 | return 0; |
529 | ||
530 | } | |
531 | ||
532 | int | |
6ca34f6f HN |
533 | evalequals(stackmember * stack, int *depth, int whereAmI, |
534 | stackmember * candidate) | |
43ae1d95 | 535 | { |
536 | int rv; | |
537 | stackmember srv; | |
538 | ||
539 | if (*depth < 3) | |
540 | /* Not enough operands */ | |
541 | return 1; | |
542 | ||
543 | if (whereAmI != *depth - 2) | |
544 | /* invalid stack */ | |
545 | return 1; | |
546 | ||
6ca34f6f | 547 | rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]); |
43ae1d95 | 548 | |
549 | if (rv == -2) | |
550 | /* invalid comparison */ | |
551 | return 1; | |
552 | ||
f53969cc | 553 | stackpop(stack, depth); /* arg rhs */ |
43ae1d95 | 554 | |
f53969cc | 555 | stackpop(stack, depth); /* me */ |
43ae1d95 | 556 | |
f53969cc | 557 | stackpop(stack, depth); /* arg lhs */ |
43ae1d95 | 558 | |
559 | srv.valuetype = ESI_EXPR_EXPR; | |
560 | ||
561 | srv.eval = evalexpr; | |
562 | ||
563 | srv.valuestored = ESI_LITERAL_BOOL; | |
564 | ||
565 | srv.value.integral = rv ? 0 : 1; | |
566 | ||
567 | srv.precedence = 1; | |
568 | ||
569 | stack[(*depth)++] = srv; | |
570 | ||
571 | /* we're out of way, try adding now */ | |
6ca34f6f | 572 | if (!addmember(stack, depth, candidate)) |
43ae1d95 | 573 | /* Something wrong upstream */ |
574 | return 1; | |
575 | ||
e0236918 | 576 | /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */ |
43ae1d95 | 577 | return 0; |
578 | } | |
579 | ||
6ca34f6f HN |
580 | int |
581 | evalnotequals(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 582 | { |
583 | int rv; | |
584 | stackmember srv; | |
585 | ||
586 | if (*depth < 3) | |
587 | /* Not enough operands */ | |
588 | return 1; | |
589 | ||
590 | if (whereAmI != *depth - 2) | |
591 | /* invalid stack */ | |
592 | return 1; | |
593 | ||
6ca34f6f | 594 | rv = membercompare(stack[whereAmI - 1], stack[whereAmI + 1]); |
43ae1d95 | 595 | |
596 | if (rv == -2) | |
597 | /* invalid comparison */ | |
598 | return 1; | |
599 | ||
f53969cc | 600 | stackpop(stack, depth); /* arg rhs */ |
43ae1d95 | 601 | |
f53969cc | 602 | stackpop(stack, depth); /* me */ |
43ae1d95 | 603 | |
f53969cc | 604 | stackpop(stack, depth); /* arg lhs */ |
43ae1d95 | 605 | |
606 | srv.valuetype = ESI_EXPR_EXPR; | |
607 | ||
608 | srv.eval = evalexpr; | |
609 | ||
610 | srv.valuestored = ESI_LITERAL_BOOL; | |
611 | ||
612 | srv.value.integral = rv ? 1 : 0; | |
613 | ||
614 | srv.precedence = 1; | |
615 | ||
616 | stack[(*depth)++] = srv; | |
617 | ||
618 | /* we're out of way, try adding now */ | |
6ca34f6f | 619 | if (!addmember(stack, depth, candidate)) |
43ae1d95 | 620 | /* Something wrong upstream */ |
621 | return 1; | |
622 | ||
e0236918 | 623 | /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */ |
43ae1d95 | 624 | return 0; |
625 | } | |
626 | ||
6ca34f6f HN |
627 | int |
628 | evalstartexpr(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 629 | { |
e0236918 | 630 | /* debugs(86, DBG_IMPORTANT, "?("); */ |
43ae1d95 | 631 | |
632 | if (whereAmI != *depth - 2) | |
633 | /* invalid stack */ | |
634 | return 1; | |
635 | ||
636 | /* Only valid when RHS is an end bracket */ | |
637 | if (candidate->valuetype != ESI_EXPR_END) | |
638 | return 1; | |
639 | ||
640 | --(*depth); | |
641 | ||
642 | stack[whereAmI] = stack[(*depth)]; | |
643 | ||
6ca34f6f | 644 | cleanmember(candidate); |
43ae1d95 | 645 | |
646 | return 0; | |
647 | } | |
648 | ||
6ca34f6f HN |
649 | int |
650 | evalendexpr(stackmember * stack, int *depth, int whereAmI, stackmember * candidate) | |
43ae1d95 | 651 | { |
652 | /* Can't evaluate ) brackets */ | |
653 | return 1; | |
654 | } | |
655 | ||
656 | char const * | |
6ca34f6f | 657 | trim(char const *s) |
43ae1d95 | 658 | { |
659 | while (*s == ' ') | |
660 | ++s; | |
661 | ||
662 | return s; | |
663 | } | |
664 | ||
665 | stackmember | |
6ca34f6f | 666 | getsymbol(const char *s, char const **endptr) |
43ae1d95 | 667 | { |
668 | stackmember rv; | |
669 | char *end; | |
670 | char const *origs = s; | |
671 | /* trim whitespace */ | |
6ca34f6f | 672 | s = trim(s); |
f53969cc | 673 | rv.eval = NULL; /* A literal */ |
43ae1d95 | 674 | rv.valuetype = ESI_EXPR_INVALID; |
675 | rv.valuestored = ESI_LITERAL_INVALID; | |
f5428b78 | 676 | rv.precedence = 1; /* A literal */ |
43ae1d95 | 677 | |
678 | if (('0' <= *s && *s <= '9') || *s == '-') { | |
6ca34f6f | 679 | size_t length = strspn(s, "0123456789."); |
49cb2642 | 680 | char const *point; |
43ae1d95 | 681 | |
6ca34f6f | 682 | if ((point = strchr(s, '.')) && point - s < (ssize_t)length) { |
43ae1d95 | 683 | /* floating point */ |
c822f9f0 | 684 | errno=0; /* reset errno */ |
6ca34f6f | 685 | rv.value.floating = strtod(s, &end); |
43ae1d95 | 686 | |
687 | if (s == end || errno) { | |
688 | /* Couldn't convert to float */ | |
e0236918 | 689 | debugs(86, DBG_IMPORTANT, "failed to convert '" << s << "' to float "); |
43ae1d95 | 690 | *endptr = origs; |
691 | } else { | |
6ca34f6f | 692 | debugs(86,6, "found " << rv.value.floating << " of length " << end - s); |
43ae1d95 | 693 | *endptr = end; |
694 | rv.eval = evalliteral; | |
695 | rv.valuestored = ESI_LITERAL_FLOAT; | |
696 | rv.valuetype = ESI_EXPR_LITERAL; | |
697 | rv.precedence = 1; | |
698 | } | |
699 | } else { | |
700 | /* INT */ | |
c822f9f0 | 701 | errno=0; /* reset errno */ |
6ca34f6f | 702 | rv.value.integral = strtol(s, &end, 0); |
43ae1d95 | 703 | |
704 | if (s == end || errno) { | |
705 | /* Couldn't convert to int */ | |
e0236918 | 706 | debugs(86, DBG_IMPORTANT, "failed to convert '" << s << "' to int "); |
43ae1d95 | 707 | *endptr = origs; |
708 | } else { | |
6ca34f6f | 709 | debugs(86,6, "found " << rv.value.integral << " of length " << end - s); |
43ae1d95 | 710 | *endptr = end; |
711 | rv.eval = evalliteral; | |
712 | rv.valuestored = ESI_LITERAL_INT; | |
713 | rv.valuetype = ESI_EXPR_LITERAL; | |
714 | rv.precedence = 1; | |
715 | } | |
716 | } | |
717 | } else if ('!' == *s) { | |
718 | if ('=' == *(s + 1)) { | |
bf8fe701 | 719 | debugs(86, 6, "found !="); |
43ae1d95 | 720 | *endptr = s + 2; |
721 | rv.eval = evalnotequals; | |
722 | rv.valuetype = ESI_EXPR_NOTEQ; | |
723 | rv.precedence = 5; | |
724 | } else { | |
bf8fe701 | 725 | debugs(86, 6, "found !"); |
43ae1d95 | 726 | *endptr = s + 1; |
727 | rv.valuetype = ESI_EXPR_NOT; | |
728 | rv.precedence = 4; | |
729 | rv.eval = evalnegate; | |
730 | } | |
731 | } else if ('\'' == *s) { | |
732 | char const *t = s + 1; | |
bf8fe701 | 733 | debugs(86, 6, "found \'"); |
43ae1d95 | 734 | |
735 | while (*t != '\'' && *t) | |
736 | ++t; | |
737 | ||
738 | if (!*t) { | |
e0236918 | 739 | debugs(86, DBG_IMPORTANT, "missing end \' in '" << s << "'"); |
43ae1d95 | 740 | *endptr = origs; |
741 | } else { | |
742 | *endptr = t + 1; | |
924f73bc | 743 | /* Special case for zero length strings */ |
744 | ||
745 | if (t - s - 1) | |
6ca34f6f | 746 | rv.value.string = xstrndup(s + 1, t - s - 1); |
924f73bc | 747 | else |
6ca34f6f | 748 | rv.value.string = static_cast<char *>(xcalloc(1,1)); |
924f73bc | 749 | |
43ae1d95 | 750 | rv.eval = evalliteral; |
924f73bc | 751 | |
43ae1d95 | 752 | rv.valuestored = ESI_LITERAL_STRING; |
924f73bc | 753 | |
43ae1d95 | 754 | rv.valuetype = ESI_EXPR_LITERAL; |
924f73bc | 755 | |
43ae1d95 | 756 | rv.precedence = 1; |
924f73bc | 757 | |
bf8fe701 | 758 | debugs(86, 6, "found string '" << rv.value.string << "'"); |
43ae1d95 | 759 | } |
760 | } else if ('(' == *s) { | |
bf8fe701 | 761 | debugs(86, 6, "found subexpr start"); |
43ae1d95 | 762 | *endptr = s + 1; |
763 | rv.valuetype = ESI_EXPR_START; | |
764 | rv.precedence = 5; | |
765 | rv.eval = evalstartexpr; | |
766 | } else if (')' == *s) { | |
bf8fe701 | 767 | debugs(86, 6, "found subexpr end"); |
43ae1d95 | 768 | *endptr = s + 1; |
769 | rv.valuetype = ESI_EXPR_END; | |
770 | rv.precedence = 0; | |
771 | rv.eval = evalendexpr; | |
772 | } else if ('&' == *s) { | |
bf8fe701 | 773 | debugs(86, 6, "found AND"); |
43ae1d95 | 774 | *endptr = s + 1; |
775 | rv.valuetype = ESI_EXPR_AND; | |
776 | rv.precedence = 3; | |
777 | rv.eval = evaland; | |
778 | } else if ('|' == *s) { | |
bf8fe701 | 779 | debugs(86, 6, "found OR"); |
43ae1d95 | 780 | *endptr = s + 1; |
781 | rv.valuetype = ESI_EXPR_OR; | |
782 | rv.precedence = 2; | |
783 | rv.eval = evalor; | |
784 | } else if ('=' == *s) { | |
785 | if ('=' == *(s + 1)) { | |
bf8fe701 | 786 | debugs(86, 6, "found equals"); |
43ae1d95 | 787 | *endptr = s + 2; |
788 | rv.valuetype = ESI_EXPR_EQ; | |
789 | rv.precedence = 5; | |
790 | rv.eval = evalequals; | |
791 | } else { | |
e0236918 | 792 | debugs(86, DBG_IMPORTANT, "invalid expr '" << s << "'"); |
43ae1d95 | 793 | *endptr = origs; |
794 | } | |
795 | } else if ('<' == *s) { | |
796 | if ('=' == *(s + 1)) { | |
bf8fe701 | 797 | debugs(86, 6, "found less-equals"); |
43ae1d95 | 798 | *endptr = s + 2; |
799 | rv.valuetype = ESI_EXPR_LESSEQ; | |
800 | rv.precedence = 5; | |
801 | rv.eval = evallesseq; | |
802 | } else { | |
bf8fe701 | 803 | debugs(86, 6, "found less than"); |
43ae1d95 | 804 | *endptr = s + 1; |
805 | rv.valuetype = ESI_EXPR_LESS; | |
806 | rv.precedence = 5; | |
807 | rv.eval = evallessthan; | |
808 | } | |
809 | } else if ('>' == *s) { | |
810 | if ('=' == *(s + 1)) { | |
bf8fe701 | 811 | debugs(86, 6, "found more-equals"); |
43ae1d95 | 812 | *endptr = s + 2; |
813 | rv.valuetype = ESI_EXPR_MOREEQ; | |
814 | rv.precedence = 5; | |
815 | rv.eval = evalmoreeq; | |
816 | } else { | |
bf8fe701 | 817 | debugs(86, 6, "found more than"); |
43ae1d95 | 818 | *endptr = s + 1; |
819 | rv.valuetype = ESI_EXPR_MORE; | |
820 | rv.precedence = 5; | |
821 | rv.eval = evalmorethan; | |
822 | } | |
6ca34f6f | 823 | } else if (!strncmp(s, "false", 5)) { |
bf8fe701 | 824 | debugs(86, 5, "getsymbol: found variable result 'false'"); |
43ae1d95 | 825 | *endptr = s + 5; |
826 | rv.valuetype = ESI_EXPR_EXPR; | |
827 | rv.valuestored = ESI_LITERAL_BOOL; | |
828 | rv.value.integral = 0; | |
829 | rv.precedence = 1; | |
830 | rv.eval = evalexpr; | |
6ca34f6f | 831 | } else if (!strncmp(s, "true", 4)) { |
bf8fe701 | 832 | debugs(86, 5, "getsymbol: found variable result 'true'"); |
43ae1d95 | 833 | *endptr = s + 4; |
834 | rv.valuetype = ESI_EXPR_EXPR; | |
835 | rv.valuestored = ESI_LITERAL_BOOL; | |
836 | rv.value.integral = 1; | |
837 | rv.precedence = 1; | |
838 | rv.eval = evalexpr; | |
839 | } else { | |
e0236918 | 840 | debugs(86, DBG_IMPORTANT, "invalid expr '" << s << "'"); |
43ae1d95 | 841 | *endptr = origs; |
842 | } | |
843 | ||
844 | return rv; | |
845 | } | |
846 | ||
014adac1 AR |
847 | static void |
848 | printLiteral(std::ostream &os, const stackmember &s) | |
43ae1d95 | 849 | { |
850 | switch (s.valuestored) { | |
851 | ||
852 | case ESI_LITERAL_INVALID: | |
014adac1 | 853 | os << " Invalid "; |
43ae1d95 | 854 | break; |
855 | ||
856 | case ESI_LITERAL_FLOAT: | |
014adac1 | 857 | os << s.value.floating; |
43ae1d95 | 858 | break; |
859 | ||
860 | case ESI_LITERAL_STRING: | |
014adac1 | 861 | os << '\'' << s.value.string << '\''; |
43ae1d95 | 862 | break; |
863 | ||
864 | case ESI_LITERAL_INT: | |
014adac1 | 865 | os << s.value.integral; |
43ae1d95 | 866 | break; |
867 | ||
868 | case ESI_LITERAL_BOOL: | |
014adac1 | 869 | os << (s.value.integral ? "true" : "false"); |
43ae1d95 | 870 | } |
871 | } | |
872 | ||
014adac1 AR |
873 | static std::ostream & |
874 | operator <<(std::ostream &os, const stackmember &s) | |
43ae1d95 | 875 | { |
876 | switch (s.valuetype) { | |
877 | ||
878 | case ESI_EXPR_INVALID: | |
014adac1 | 879 | os << " Invalid "; |
43ae1d95 | 880 | break; |
881 | ||
882 | case ESI_EXPR_LITERAL: | |
014adac1 | 883 | printLiteral(os, s); |
43ae1d95 | 884 | break; |
885 | ||
886 | case ESI_EXPR_EXPR: | |
014adac1 | 887 | os << (s.value.integral ? "true" : "false"); |
43ae1d95 | 888 | break; |
889 | ||
890 | case ESI_EXPR_OR: | |
014adac1 | 891 | os << "|"; |
43ae1d95 | 892 | break; |
893 | ||
894 | case ESI_EXPR_AND: | |
014adac1 | 895 | os << "&"; |
43ae1d95 | 896 | break; |
897 | ||
898 | case ESI_EXPR_NOT: | |
014adac1 | 899 | os << "!"; |
43ae1d95 | 900 | break; |
901 | ||
902 | case ESI_EXPR_START: | |
014adac1 | 903 | os << "("; |
43ae1d95 | 904 | break; |
905 | ||
906 | case ESI_EXPR_END: | |
014adac1 | 907 | os << ")"; |
43ae1d95 | 908 | break; |
909 | ||
910 | case ESI_EXPR_EQ: | |
014adac1 | 911 | os << "=="; |
43ae1d95 | 912 | break; |
913 | ||
914 | case ESI_EXPR_NOTEQ: | |
014adac1 | 915 | os << "!="; |
43ae1d95 | 916 | break; |
917 | ||
918 | case ESI_EXPR_LESS: | |
014adac1 | 919 | os << "<"; |
43ae1d95 | 920 | break; |
921 | ||
922 | case ESI_EXPR_LESSEQ: | |
014adac1 | 923 | os << "<="; |
43ae1d95 | 924 | break; |
925 | ||
926 | case ESI_EXPR_MORE: | |
014adac1 | 927 | os << ">"; |
43ae1d95 | 928 | break; |
929 | ||
930 | case ESI_EXPR_MOREEQ: | |
014adac1 | 931 | os << ">="; |
43ae1d95 | 932 | break; |
933 | } | |
014adac1 AR |
934 | |
935 | return os; | |
43ae1d95 | 936 | } |
937 | ||
938 | void | |
6ca34f6f | 939 | dumpstack(stackmember * stack, int depth) |
43ae1d95 | 940 | { |
014adac1 AR |
941 | if (depth) { |
942 | std::ostringstream buf; | |
943 | for (int i = 0; i < depth; ++i) | |
944 | buf << stack[i]; | |
945 | debugs(86,1, buf.str()); | |
946 | } | |
43ae1d95 | 947 | } |
948 | ||
949 | int | |
6ca34f6f | 950 | addmember(stackmember * stack, int *stackdepth, stackmember * candidate) |
43ae1d95 | 951 | { |
952 | if (candidate->valuetype != ESI_EXPR_LITERAL && *stackdepth > 1) { | |
953 | /* !(!(a==b))) is why thats safe */ | |
954 | /* strictly less than until we unwind */ | |
955 | ||
956 | if (candidate->precedence < stack[*stackdepth - 1].precedence || | |
957 | candidate->precedence < stack[*stackdepth - 2].precedence) { | |
958 | /* must be an operator */ | |
959 | ||
960 | if (stack[*stackdepth - 2].valuetype == ESI_EXPR_LITERAL || | |
961 | stack[*stackdepth - 2].valuetype == ESI_EXPR_INVALID || | |
6ca34f6f HN |
962 | stack[*stackdepth - 2].eval(stack, stackdepth, |
963 | *stackdepth - 2, candidate)) { | |
43ae1d95 | 964 | /* cleanup candidate and stack */ |
6ca34f6f HN |
965 | dumpstack(stack, *stackdepth); |
966 | cleanmember(candidate); | |
e0236918 | 967 | debugs(86, DBG_IMPORTANT, "invalid expression"); |
43ae1d95 | 968 | return 0; |
969 | } | |
970 | } else { | |
971 | stack[(*stackdepth)++] = *candidate; | |
972 | } | |
973 | } else if (candidate->valuetype != ESI_EXPR_INVALID) | |
974 | stack[(*stackdepth)++] = *candidate; | |
975 | ||
976 | return 1; | |
977 | } | |
978 | ||
979 | int | |
6ca34f6f | 980 | ESIExpression::Evaluate(char const *s) |
43ae1d95 | 981 | { |
982 | stackmember stack[20]; | |
983 | int stackdepth = 0; | |
984 | char const *end; | |
985 | PROF_start(esiExpressionEval); | |
986 | ||
987 | while (*s) { | |
6ca34f6f | 988 | stackmember candidate = getsymbol(s, &end); |
43ae1d95 | 989 | |
990 | if (candidate.valuetype != ESI_EXPR_INVALID) { | |
6ca34f6f | 991 | assert(s != end); |
43ae1d95 | 992 | |
6ca34f6f | 993 | if (!addmember(stack, &stackdepth, &candidate)) { |
43ae1d95 | 994 | PROF_stop(esiExpressionEval); |
995 | return 0; | |
996 | } | |
997 | ||
998 | s = end; | |
999 | } else { | |
1000 | assert (s == end); | |
e0236918 | 1001 | debugs(86, DBG_IMPORTANT, "failed parsing expression"); |
43ae1d95 | 1002 | PROF_stop(esiExpressionEval); |
1003 | return 0; | |
1004 | } | |
1005 | } | |
1006 | ||
1007 | if (stackdepth > 1) { | |
1008 | stackmember rv; | |
1009 | rv.valuetype = ESI_EXPR_INVALID; | |
1010 | rv.precedence = 0; | |
1011 | ||
1012 | if (stack[stackdepth - 2]. | |
6ca34f6f | 1013 | eval(stack, &stackdepth, stackdepth - 2, &rv)) { |
43ae1d95 | 1014 | /* special case - leading operator failed */ |
e0236918 | 1015 | debugs(86, DBG_IMPORTANT, "invalid expression"); |
43ae1d95 | 1016 | PROF_stop(esiExpressionEval); |
1017 | return 0; | |
1018 | } | |
1019 | } | |
1020 | ||
1021 | if (stackdepth == 0) { | |
1022 | /* Empty expression - evaluate to false */ | |
1023 | PROF_stop(esiExpressionEval); | |
1024 | return 0; | |
1025 | } | |
1026 | ||
1027 | /* if we hit here, we think we have a valid result */ | |
6ca34f6f | 1028 | assert(stackdepth == 1); |
43ae1d95 | 1029 | |
6ca34f6f | 1030 | assert(stack[0].valuetype == ESI_EXPR_EXPR); |
43ae1d95 | 1031 | |
1032 | PROF_stop(esiExpressionEval); | |
1033 | ||
1034 | return stack[0].value.integral ? 1 : 0; | |
1035 | } | |
f53969cc | 1036 |