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