]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ESIExpression.cc
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 "ESIExpression.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 rv
.value
.floating
= strtod (s
, &end
);
719 if (s
== end
|| errno
) {
720 /* Couldn't convert to float */
721 debugs(86, 1, "failed to convert '" << s
<< "' to float ");
724 debugs (86,6, "found " << rv
.value
.floating
<< " of length " << end
- s
);
726 rv
.eval
= evalliteral
;
727 rv
.valuestored
= ESI_LITERAL_FLOAT
;
728 rv
.valuetype
= ESI_EXPR_LITERAL
;
733 rv
.value
.integral
= strtol (s
, &end
, 0);
735 if (s
== end
|| errno
) {
736 /* Couldn't convert to int */
737 debugs(86, 1, "failed to convert '" << s
<< "' to int ");
740 debugs (86,6, "found " << rv
.value
.integral
<< " of length " << end
- s
);
742 rv
.eval
= evalliteral
;
743 rv
.valuestored
= ESI_LITERAL_INT
;
744 rv
.valuetype
= ESI_EXPR_LITERAL
;
748 } else if ('!' == *s
) {
749 if ('=' == *(s
+ 1)) {
750 debugs(86, 6, "found !=");
752 rv
.eval
= evalnotequals
;
753 rv
.valuetype
= ESI_EXPR_NOTEQ
;
756 debugs(86, 6, "found !");
758 rv
.valuetype
= ESI_EXPR_NOT
;
760 rv
.eval
= evalnegate
;
762 } else if ('\'' == *s
) {
763 char const *t
= s
+ 1;
764 debugs(86, 6, "found \'");
766 while (*t
!= '\'' && *t
)
770 debugs(86, 1, "missing end \' in '" << s
<< "'");
774 /* Special case for zero length strings */
777 rv
.value
.string
= xstrndup (s
+ 1, t
- s
- 1);
779 rv
.value
.string
= static_cast<char *>(xcalloc (1,1));
781 rv
.eval
= evalliteral
;
783 rv
.valuestored
= ESI_LITERAL_STRING
;
785 rv
.valuetype
= ESI_EXPR_LITERAL
;
789 debugs(86, 6, "found string '" << rv
.value
.string
<< "'");
791 } else if ('(' == *s
) {
792 debugs(86, 6, "found subexpr start");
794 rv
.valuetype
= ESI_EXPR_START
;
796 rv
.eval
= evalstartexpr
;
797 } else if (')' == *s
) {
798 debugs(86, 6, "found subexpr end");
800 rv
.valuetype
= ESI_EXPR_END
;
802 rv
.eval
= evalendexpr
;
803 } else if ('&' == *s
) {
804 debugs(86, 6, "found AND");
806 rv
.valuetype
= ESI_EXPR_AND
;
809 } else if ('|' == *s
) {
810 debugs(86, 6, "found OR");
812 rv
.valuetype
= ESI_EXPR_OR
;
815 } else if ('=' == *s
) {
816 if ('=' == *(s
+ 1)) {
817 debugs(86, 6, "found equals");
819 rv
.valuetype
= ESI_EXPR_EQ
;
821 rv
.eval
= evalequals
;
823 debugs(86, 1, "invalid expr '" << s
<< "'");
826 } else if ('<' == *s
) {
827 if ('=' == *(s
+ 1)) {
828 debugs(86, 6, "found less-equals");
830 rv
.valuetype
= ESI_EXPR_LESSEQ
;
832 rv
.eval
= evallesseq
;
834 debugs(86, 6, "found less than");
836 rv
.valuetype
= ESI_EXPR_LESS
;
838 rv
.eval
= evallessthan
;
840 } else if ('>' == *s
) {
841 if ('=' == *(s
+ 1)) {
842 debugs(86, 6, "found more-equals");
844 rv
.valuetype
= ESI_EXPR_MOREEQ
;
846 rv
.eval
= evalmoreeq
;
848 debugs(86, 6, "found more than");
850 rv
.valuetype
= ESI_EXPR_MORE
;
852 rv
.eval
= evalmorethan
;
854 } else if (!strncmp (s
, "false", 5)) {
855 debugs(86, 5, "getsymbol: found variable result 'false'");
857 rv
.valuetype
= ESI_EXPR_EXPR
;
858 rv
.valuestored
= ESI_LITERAL_BOOL
;
859 rv
.value
.integral
= 0;
862 } else if (!strncmp (s
, "true", 4)) {
863 debugs(86, 5, "getsymbol: found variable result 'true'");
865 rv
.valuetype
= ESI_EXPR_EXPR
;
866 rv
.valuestored
= ESI_LITERAL_BOOL
;
867 rv
.value
.integral
= 1;
871 debugs(86, 1, "invalid expr '" << s
<< "'");
879 printliteral (stackmember s
)
881 switch (s
.valuestored
) {
883 case ESI_LITERAL_INVALID
:
884 debug(86, 1) ( " Invalid " );
887 case ESI_LITERAL_FLOAT
:
888 debug (86,1) ("%f", s
.value
.floating
);
891 case ESI_LITERAL_STRING
:
892 debug (86,1) ("'%s'", s
.value
.string
);
895 case ESI_LITERAL_INT
:
896 debug (86,1) ("%d", s
.value
.integral
);
899 case ESI_LITERAL_BOOL
:
900 debug (86,1)("%s",s
.value
.integral
? "true" : "false");
905 printmember (stackmember s
)
907 switch (s
.valuetype
) {
909 case ESI_EXPR_INVALID
:
910 debug (86,1) (" Invalid ");
913 case ESI_EXPR_LITERAL
:
918 debug (86,1) ("%s", s
.value
.integral
? "true" : "false");
953 case ESI_EXPR_LESSEQ
:
961 case ESI_EXPR_MOREEQ
:
968 dumpstack (stackmember
* stack
, int depth
)
972 for (i
= 0; i
< depth
; ++i
)
973 printmember (stack
[i
]);
980 addmember (stackmember
* stack
, int *stackdepth
, stackmember
* candidate
)
982 if (candidate
->valuetype
!= ESI_EXPR_LITERAL
&& *stackdepth
> 1) {
983 /* !(!(a==b))) is why thats safe */
984 /* strictly less than until we unwind */
986 if (candidate
->precedence
< stack
[*stackdepth
- 1].precedence
||
987 candidate
->precedence
< stack
[*stackdepth
- 2].precedence
) {
988 /* must be an operator */
990 if (stack
[*stackdepth
- 2].valuetype
== ESI_EXPR_LITERAL
||
991 stack
[*stackdepth
- 2].valuetype
== ESI_EXPR_INVALID
||
992 stack
[*stackdepth
- 2].eval (stack
, stackdepth
,
993 *stackdepth
- 2, candidate
)) {
994 /* cleanup candidate and stack */
995 dumpstack (stack
, *stackdepth
);
996 cleanmember (candidate
);
997 debugs(86, 1, "invalid expression");
1001 stack
[(*stackdepth
)++] = *candidate
;
1003 } else if (candidate
->valuetype
!= ESI_EXPR_INVALID
)
1004 stack
[(*stackdepth
)++] = *candidate
;
1010 ESIExpression::Evaluate (char const *s
)
1012 stackmember stack
[20];
1015 PROF_start(esiExpressionEval
);
1018 stackmember candidate
= getsymbol (s
, &end
);
1020 if (candidate
.valuetype
!= ESI_EXPR_INVALID
) {
1023 if (!addmember (stack
, &stackdepth
, &candidate
)) {
1024 PROF_stop(esiExpressionEval
);
1031 debugs(86, 1, "failed parsing expression");
1032 PROF_stop(esiExpressionEval
);
1037 if (stackdepth
> 1) {
1039 rv
.valuetype
= ESI_EXPR_INVALID
;
1042 if (stack
[stackdepth
- 2].
1043 eval (stack
, &stackdepth
, stackdepth
- 2, &rv
)) {
1044 /* special case - leading operator failed */
1045 debugs(86, 1, "invalid expression");
1046 PROF_stop(esiExpressionEval
);
1051 if (stackdepth
== 0) {
1052 /* Empty expression - evaluate to false */
1053 PROF_stop(esiExpressionEval
);
1057 /* if we hit here, we think we have a valid result */
1058 assert (stackdepth
== 1);
1060 assert (stack
[0].valuetype
== ESI_EXPR_EXPR
);
1062 PROF_stop(esiExpressionEval
);
1064 return stack
[0].value
.integral
? 1 : 0;