5
* DEBUG: section 86 ESI processing
6
* AUTHOR: Robert Collins
8
* SQUID Web Proxy Cache http://www.squid-cache.org/
9
* ----------------------------------------------------------
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.
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.
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.
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.
37
#include "esi/Expression.h"
39
/* stack precedence rules:
40
* before pushing an operator onto the stack, the
41
* top 2 elements are checked. if either has a higher
42
* or equal precedence than the current operator, they
44
* Start of expression has 5 precedence,
45
* end of expression has 0 precedence
46
* literal has 1 as does expression results
50
* == != < > <= >= has 5
55
typedef struct _stackmember stackmember;
57
typedef int evaluate (stackmember * stack, int *depth, int whereAmI,
58
stackmember * candidate);
74
ESI_EXPR_EXPR /* the result of an expr PRI 1 */
92
literalhint valuestored;
97
static void cleanmember (stackmember *);
98
static void stackpop (stackmember * s, int *depth);
101
cleanmember (stackmember * s)
103
if (s->valuetype == ESI_EXPR_LITERAL
104
&& s->valuestored == ESI_LITERAL_STRING) {
105
safe_free (s->value.string);
106
s->value.string = NULL;
112
stackpop (stackmember * s, int *depth)
117
cleanmember (&s[*depth]);
120
static evaluate evalnegate;
121
static evaluate evalliteral;
122
static evaluate evalor;
123
static evaluate evaland;
124
static evaluate evallesseq;
125
static evaluate evallessthan;
126
static evaluate evalmoreeq;
127
static evaluate evalmorethan;
128
static evaluate evalequals;
129
static evaluate evalnotequals;
130
static evaluate evalstartexpr;
131
static evaluate evalendexpr;
132
static evaluate evalexpr;
133
static void dumpstack (stackmember * stack, int depth);
134
static int addmember (stackmember * stack, int *stackdepth,
135
stackmember * candidate);
136
static int membercompare (stackmember a, stackmember b);
137
static char const *trim (char const *s);
138
static stackmember getsymbol (const char *s, char const **endptr);
139
static void printliteral (stackmember s);
140
static void printmember (stackmember s);
142
/* -2 = failed to compate
148
membercompare (stackmember a, stackmember b)
150
/* we can compare: sub expressions to sub expressions ,
151
* literals to literals
154
if (!((a.valuetype == ESI_EXPR_LITERAL && b.valuetype == ESI_EXPR_LITERAL &&
155
a.valuestored != ESI_LITERAL_INVALID && b.valuestored != ESI_LITERAL_INVALID) ||
156
(a.valuetype == ESI_EXPR_EXPR && b.valuetype == ESI_EXPR_EXPR)))
159
if (a.valuetype == ESI_EXPR_EXPR) {
160
if (a.value.integral == b.value.integral)
164
} else if (a.valuestored == ESI_LITERAL_STRING) {
165
if (b.valuestored == ESI_LITERAL_STRING) {
166
int i =strcmp (a.value.string, b.value.string);
176
/* TODO: numeric to string conversion ? */
177
debugs(86, 1, "strcmp with non-string");
180
} else if (a.valuestored == ESI_LITERAL_FLOAT) {
181
if (b.valuestored == ESI_LITERAL_INT) {
182
if (fabs(a.value.floating - b.value.integral) < 0.00001)
184
else if (a.value.floating < b.value.integral)
188
} else if (b.valuestored == ESI_LITERAL_FLOAT) {
189
if (a.value.floating == b.value.floating)
191
else if (a.value.floating < b.value.floating)
196
/* TODO: attempt numeric converson again? */
197
debugs(86, 1, "floatcomp with non float or int");
200
} else if (a.valuestored == ESI_LITERAL_INT) {
201
if (b.valuestored == ESI_LITERAL_INT) {
202
if (a.value.integral == b.value.integral)
204
else if (a.value.integral < b.value.integral)
208
} else if (b.valuestored == ESI_LITERAL_FLOAT) {
209
if (fabs(a.value.integral - b.value.floating) < 0.00001)
211
else if (a.value.integral < b.value.floating)
216
/* TODO: attempt numeric converson again? */
217
debugs(86, 1, "intcomp vs non float non int");
225
/* return 0 on success, 1 on failure */
227
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
229
if (whereAmI != *depth - 2)
233
if (stack[whereAmI + 1].valuetype != ESI_EXPR_EXPR)
234
/* invalid operand */
240
stack[whereAmI] = stack[(*depth)];
242
cleanmember (candidate);
244
if (stack[whereAmI].value.integral == 1)
245
stack[whereAmI].value.integral = 0;
247
stack[whereAmI].value.integral = 1;
253
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
255
debugs(86, 1, "attempt to evaluate a literal");
256
/* literals can't be evaluated */
261
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
263
debugs(86, 1, "attempt to evaluate a sub-expression result");
264
/* sub-scpr's can't be evaluated */
270
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
276
/* Not enough operands */
279
if (whereAmI != *depth - 2)
283
if (stack[whereAmI + 1].valuetype != ESI_EXPR_EXPR ||
284
stack[whereAmI - 1].valuetype != ESI_EXPR_EXPR)
285
/* invalid operand */
288
rv = stack[whereAmI - 1].value.integral || stack[whereAmI + 1].value.integral;
291
/* invalid comparison */
294
stackpop (stack, depth); /* arg rhs */
296
stackpop (stack, depth); /* me */
298
stackpop (stack, depth); /* arg lhs */
300
srv.valuetype = ESI_EXPR_EXPR;
302
srv.eval = evalliteral;
304
srv.valuestored = ESI_LITERAL_BOOL;
306
srv.value.integral = rv ? 1 : 0;
310
stack[(*depth)++] = srv;
312
/* we're out of way, try adding now */
313
if (!addmember (stack, depth, candidate))
314
/* Something wrong upstream */
321
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
327
/* Not enough operands */
330
if (whereAmI != *depth - 2)
334
if (stack[whereAmI + 1].valuetype != ESI_EXPR_EXPR ||
335
stack[whereAmI - 1].valuetype != ESI_EXPR_EXPR)
336
/* invalid operand */
339
rv = stack[whereAmI - 1].value.integral && stack[whereAmI + 1].value.integral;
342
/* invalid comparison */
345
stackpop (stack, depth); /* arg rhs */
347
stackpop (stack, depth); /* me */
349
stackpop (stack, depth); /* arg lhs */
351
srv.valuetype = ESI_EXPR_EXPR;
355
srv.valuestored = ESI_LITERAL_BOOL;
357
srv.value.integral = rv ? 1 : 0;
361
stack[(*depth)++] = srv;
363
/* we're out of way, try adding now */
364
if (!addmember (stack, depth, candidate))
365
/* Something wrong upstream */
372
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
378
/* Not enough operands */
381
if (whereAmI != *depth - 2)
385
rv = membercompare (stack[whereAmI - 1], stack[whereAmI + 1]);
388
/* invalid comparison */
391
stackpop (stack, depth); /* arg rhs */
393
stackpop (stack, depth); /* me */
395
stackpop (stack, depth); /* arg lhs */
397
srv.valuetype = ESI_EXPR_EXPR;
401
srv.valuestored = ESI_LITERAL_BOOL;
403
srv.value.integral = rv <= 0 ? 1 : 0;
407
stack[(*depth)++] = srv;
409
/* we're out of way, try adding now */
410
if (!addmember (stack, depth, candidate))
411
/* Something wrong upstream */
414
/* debugs(86, 1, "?= " << srv.value.integral << " "); */
421
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
427
/* Not enough operands */
430
if (whereAmI != *depth - 2)
434
rv = membercompare (stack[whereAmI - 1], stack[whereAmI + 1]);
437
/* invalid comparison */
440
stackpop (stack, depth); /* arg rhs */
442
stackpop (stack, depth); /* me */
444
stackpop (stack, depth); /* arg lhs */
446
srv.valuetype = ESI_EXPR_EXPR;
450
srv.valuestored = ESI_LITERAL_BOOL;
452
srv.value.integral = rv < 0 ? 1 : 0;
456
stack[(*depth)++] = srv;
458
/* we're out of way, try adding now */
459
if (!addmember (stack, depth, candidate))
460
/* Something wrong upstream */
463
/* debugs(86, 1, "?= " << srv.value.integral << " "); */
470
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
476
/* Not enough operands */
479
if (whereAmI != *depth - 2)
483
rv = membercompare (stack[whereAmI - 1], stack[whereAmI + 1]);
486
/* invalid comparison */
489
stackpop (stack, depth); /* arg rhs */
491
stackpop (stack, depth); /* me */
493
stackpop (stack, depth); /* arg lhs */
495
srv.valuetype = ESI_EXPR_EXPR;
499
srv.valuestored = ESI_LITERAL_BOOL;
501
srv.value.integral = rv >= 0 ? 1 : 0;
505
stack[(*depth)++] = srv;
507
/* we're out of way, try adding now */
508
if (!addmember (stack, depth, candidate))
509
/* Something wrong upstream */
512
/* debugs(86, 1, "?= " << srv.value.integral << " "); */
519
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
525
/* Not enough operands */
528
if (whereAmI != *depth - 2)
532
rv = membercompare (stack[whereAmI - 1], stack[whereAmI + 1]);
535
/* invalid comparison */
538
stackpop (stack, depth); /* arg rhs */
540
stackpop (stack, depth); /* me */
542
stackpop (stack, depth); /* arg lhs */
544
srv.valuetype = ESI_EXPR_EXPR;
548
srv.valuestored = ESI_LITERAL_BOOL;
550
srv.value.integral = rv > 0 ? 1 : 0;
554
stack[(*depth)++] = srv;
556
/* we're out of way, try adding now */
557
if (!addmember (stack, depth, candidate))
558
/* Something wrong upstream */
561
/* debugs(86, 1, "?= " << srv.value.integral << " "); */
567
evalequals (stackmember * stack, int *depth, int whereAmI,
568
stackmember * candidate)
574
/* Not enough operands */
577
if (whereAmI != *depth - 2)
581
rv = membercompare (stack[whereAmI - 1], stack[whereAmI + 1]);
584
/* invalid comparison */
587
stackpop (stack, depth); /* arg rhs */
589
stackpop (stack, depth); /* me */
591
stackpop (stack, depth); /* arg lhs */
593
srv.valuetype = ESI_EXPR_EXPR;
597
srv.valuestored = ESI_LITERAL_BOOL;
599
srv.value.integral = rv ? 0 : 1;
603
stack[(*depth)++] = srv;
605
/* we're out of way, try adding now */
606
if (!addmember (stack, depth, candidate))
607
/* Something wrong upstream */
610
/* debugs(86, 1, "?= " << srv.value.integral << " "); */
615
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
621
/* Not enough operands */
624
if (whereAmI != *depth - 2)
628
rv = membercompare (stack[whereAmI - 1], stack[whereAmI + 1]);
631
/* invalid comparison */
634
stackpop (stack, depth); /* arg rhs */
636
stackpop (stack, depth); /* me */
638
stackpop (stack, depth); /* arg lhs */
640
srv.valuetype = ESI_EXPR_EXPR;
644
srv.valuestored = ESI_LITERAL_BOOL;
646
srv.value.integral = rv ? 1 : 0;
650
stack[(*depth)++] = srv;
652
/* we're out of way, try adding now */
653
if (!addmember (stack, depth, candidate))
654
/* Something wrong upstream */
657
/* debugs(86, 1, "?= " << srv.value.integral << " "); */
662
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
664
/* debugs(86, 1, "?("); */
666
if (whereAmI != *depth - 2)
670
/* Only valid when RHS is an end bracket */
671
if (candidate->valuetype != ESI_EXPR_END)
676
stack[whereAmI] = stack[(*depth)];
678
cleanmember (candidate);
684
(stackmember * stack, int *depth, int whereAmI, stackmember * candidate)
686
/* Can't evaluate ) brackets */
700
getsymbol (const char *s, char const **endptr)
704
char const *origs = s;
705
/* trim whitespace */
707
rv.eval = NULL; /* A literal */
708
rv.valuetype = ESI_EXPR_INVALID;
709
rv.valuestored = ESI_LITERAL_INVALID;
711
if (('0' <= *s && *s <= '9') || *s == '-') {
712
size_t length = strspn (s, "0123456789.");
715
if ((point = strchr (s, '.')) && point - s < (ssize_t)length) {
717
errno=0; /* reset errno */
718
rv.value.floating = strtod (s, &end);
720
if (s == end || errno) {
721
/* Couldn't convert to float */
722
debugs(86, 1, "failed to convert '" << s << "' to float ");
725
debugs (86,6, "found " << rv.value.floating << " of length " << end - s);
727
rv.eval = evalliteral;
728
rv.valuestored = ESI_LITERAL_FLOAT;
729
rv.valuetype = ESI_EXPR_LITERAL;
734
errno=0; /* reset errno */
735
rv.value.integral = strtol (s, &end, 0);
737
if (s == end || errno) {
738
/* Couldn't convert to int */
739
debugs(86, 1, "failed to convert '" << s << "' to int ");
742
debugs (86,6, "found " << rv.value.integral << " of length " << end - s);
744
rv.eval = evalliteral;
745
rv.valuestored = ESI_LITERAL_INT;
746
rv.valuetype = ESI_EXPR_LITERAL;
750
} else if ('!' == *s) {
751
if ('=' == *(s + 1)) {
752
debugs(86, 6, "found !=");
754
rv.eval = evalnotequals;
755
rv.valuetype = ESI_EXPR_NOTEQ;
758
debugs(86, 6, "found !");
760
rv.valuetype = ESI_EXPR_NOT;
762
rv.eval = evalnegate;
764
} else if ('\'' == *s) {
765
char const *t = s + 1;
766
debugs(86, 6, "found \'");
768
while (*t != '\'' && *t)
772
debugs(86, 1, "missing end \' in '" << s << "'");
776
/* Special case for zero length strings */
779
rv.value.string = xstrndup (s + 1, t - s - 1);
781
rv.value.string = static_cast<char *>(xcalloc (1,1));
783
rv.eval = evalliteral;
785
rv.valuestored = ESI_LITERAL_STRING;
787
rv.valuetype = ESI_EXPR_LITERAL;
791
debugs(86, 6, "found string '" << rv.value.string << "'");
793
} else if ('(' == *s) {
794
debugs(86, 6, "found subexpr start");
796
rv.valuetype = ESI_EXPR_START;
798
rv.eval = evalstartexpr;
799
} else if (')' == *s) {
800
debugs(86, 6, "found subexpr end");
802
rv.valuetype = ESI_EXPR_END;
804
rv.eval = evalendexpr;
805
} else if ('&' == *s) {
806
debugs(86, 6, "found AND");
808
rv.valuetype = ESI_EXPR_AND;
811
} else if ('|' == *s) {
812
debugs(86, 6, "found OR");
814
rv.valuetype = ESI_EXPR_OR;
817
} else if ('=' == *s) {
818
if ('=' == *(s + 1)) {
819
debugs(86, 6, "found equals");
821
rv.valuetype = ESI_EXPR_EQ;
823
rv.eval = evalequals;
825
debugs(86, 1, "invalid expr '" << s << "'");
828
} else if ('<' == *s) {
829
if ('=' == *(s + 1)) {
830
debugs(86, 6, "found less-equals");
832
rv.valuetype = ESI_EXPR_LESSEQ;
834
rv.eval = evallesseq;
836
debugs(86, 6, "found less than");
838
rv.valuetype = ESI_EXPR_LESS;
840
rv.eval = evallessthan;
842
} else if ('>' == *s) {
843
if ('=' == *(s + 1)) {
844
debugs(86, 6, "found more-equals");
846
rv.valuetype = ESI_EXPR_MOREEQ;
848
rv.eval = evalmoreeq;
850
debugs(86, 6, "found more than");
852
rv.valuetype = ESI_EXPR_MORE;
854
rv.eval = evalmorethan;
856
} else if (!strncmp (s, "false", 5)) {
857
debugs(86, 5, "getsymbol: found variable result 'false'");
859
rv.valuetype = ESI_EXPR_EXPR;
860
rv.valuestored = ESI_LITERAL_BOOL;
861
rv.value.integral = 0;
864
} else if (!strncmp (s, "true", 4)) {
865
debugs(86, 5, "getsymbol: found variable result 'true'");
867
rv.valuetype = ESI_EXPR_EXPR;
868
rv.valuestored = ESI_LITERAL_BOOL;
869
rv.value.integral = 1;
873
debugs(86, 1, "invalid expr '" << s << "'");
881
printliteral (stackmember s)
883
switch (s.valuestored) {
885
case ESI_LITERAL_INVALID:
886
debug(86, 1) ( " Invalid " );
889
case ESI_LITERAL_FLOAT:
890
debug (86,1) ("%f", s.value.floating);
893
case ESI_LITERAL_STRING:
894
debug (86,1) ("'%s'", s.value.string);
897
case ESI_LITERAL_INT:
898
debug (86,1) ("%d", s.value.integral);
901
case ESI_LITERAL_BOOL:
902
debug (86,1)("%s",s.value.integral ? "true" : "false");
907
printmember (stackmember s)
909
switch (s.valuetype) {
911
case ESI_EXPR_INVALID:
912
debug (86,1) (" Invalid ");
915
case ESI_EXPR_LITERAL:
920
debug (86,1) ("%s", s.value.integral ? "true" : "false");
955
case ESI_EXPR_LESSEQ:
963
case ESI_EXPR_MOREEQ:
970
dumpstack (stackmember * stack, int depth)
974
for (i = 0; i < depth; ++i)
975
printmember (stack[i]);
982
addmember (stackmember * stack, int *stackdepth, stackmember * candidate)
984
if (candidate->valuetype != ESI_EXPR_LITERAL && *stackdepth > 1) {
985
/* !(!(a==b))) is why thats safe */
986
/* strictly less than until we unwind */
988
if (candidate->precedence < stack[*stackdepth - 1].precedence ||
989
candidate->precedence < stack[*stackdepth - 2].precedence) {
990
/* must be an operator */
992
if (stack[*stackdepth - 2].valuetype == ESI_EXPR_LITERAL ||
993
stack[*stackdepth - 2].valuetype == ESI_EXPR_INVALID ||
994
stack[*stackdepth - 2].eval (stack, stackdepth,
995
*stackdepth - 2, candidate)) {
996
/* cleanup candidate and stack */
997
dumpstack (stack, *stackdepth);
998
cleanmember (candidate);
999
debugs(86, 1, "invalid expression");
1003
stack[(*stackdepth)++] = *candidate;
1005
} else if (candidate->valuetype != ESI_EXPR_INVALID)
1006
stack[(*stackdepth)++] = *candidate;
1012
ESIExpression::Evaluate (char const *s)
1014
stackmember stack[20];
1017
PROF_start(esiExpressionEval);
1020
stackmember candidate = getsymbol (s, &end);
1022
if (candidate.valuetype != ESI_EXPR_INVALID) {
1025
if (!addmember (stack, &stackdepth, &candidate)) {
1026
PROF_stop(esiExpressionEval);
1033
debugs(86, 1, "failed parsing expression");
1034
PROF_stop(esiExpressionEval);
1039
if (stackdepth > 1) {
1041
rv.valuetype = ESI_EXPR_INVALID;
1044
if (stack[stackdepth - 2].
1045
eval (stack, &stackdepth, stackdepth - 2, &rv)) {
1046
/* special case - leading operator failed */
1047
debugs(86, 1, "invalid expression");
1048
PROF_stop(esiExpressionEval);
1053
if (stackdepth == 0) {
1054
/* Empty expression - evaluate to false */
1055
PROF_stop(esiExpressionEval);
1059
/* if we hit here, we think we have a valid result */
1060
assert (stackdepth == 1);
1062
assert (stack[0].valuetype == ESI_EXPR_EXPR);
1064
PROF_stop(esiExpressionEval);
1066
return stack[0].value.integral ? 1 : 0;