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