]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/esi/Expression.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 "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
;
710 rv
..precedence
= 1; /* A literal */
712 if (('0' <= *s
&& *s
<= '9') || *s
== '-') {
713 size_t length
= strspn (s
, "0123456789.");
716 if ((point
= strchr (s
, '.')) && point
- s
< (ssize_t
)length
) {
718 errno
=0; /* reset errno */
719 rv
.value
.floating
= strtod (s
, &end
);
721 if (s
== end
|| errno
) {
722 /* Couldn't convert to float */
723 debugs(86, 1, "failed to convert '" << s
<< "' to float ");
726 debugs (86,6, "found " << rv
.value
.floating
<< " of length " << end
- s
);
728 rv
.eval
= evalliteral
;
729 rv
.valuestored
= ESI_LITERAL_FLOAT
;
730 rv
.valuetype
= ESI_EXPR_LITERAL
;
735 errno
=0; /* reset errno */
736 rv
.value
.integral
= strtol (s
, &end
, 0);
738 if (s
== end
|| errno
) {
739 /* Couldn't convert to int */
740 debugs(86, 1, "failed to convert '" << s
<< "' to int ");
743 debugs (86,6, "found " << rv
.value
.integral
<< " of length " << end
- s
);
745 rv
.eval
= evalliteral
;
746 rv
.valuestored
= ESI_LITERAL_INT
;
747 rv
.valuetype
= ESI_EXPR_LITERAL
;
751 } else if ('!' == *s
) {
752 if ('=' == *(s
+ 1)) {
753 debugs(86, 6, "found !=");
755 rv
.eval
= evalnotequals
;
756 rv
.valuetype
= ESI_EXPR_NOTEQ
;
759 debugs(86, 6, "found !");
761 rv
.valuetype
= ESI_EXPR_NOT
;
763 rv
.eval
= evalnegate
;
765 } else if ('\'' == *s
) {
766 char const *t
= s
+ 1;
767 debugs(86, 6, "found \'");
769 while (*t
!= '\'' && *t
)
773 debugs(86, 1, "missing end \' in '" << s
<< "'");
777 /* Special case for zero length strings */
780 rv
.value
.string
= xstrndup (s
+ 1, t
- s
- 1);
782 rv
.value
.string
= static_cast<char *>(xcalloc (1,1));
784 rv
.eval
= evalliteral
;
786 rv
.valuestored
= ESI_LITERAL_STRING
;
788 rv
.valuetype
= ESI_EXPR_LITERAL
;
792 debugs(86, 6, "found string '" << rv
.value
.string
<< "'");
794 } else if ('(' == *s
) {
795 debugs(86, 6, "found subexpr start");
797 rv
.valuetype
= ESI_EXPR_START
;
799 rv
.eval
= evalstartexpr
;
800 } else if (')' == *s
) {
801 debugs(86, 6, "found subexpr end");
803 rv
.valuetype
= ESI_EXPR_END
;
805 rv
.eval
= evalendexpr
;
806 } else if ('&' == *s
) {
807 debugs(86, 6, "found AND");
809 rv
.valuetype
= ESI_EXPR_AND
;
812 } else if ('|' == *s
) {
813 debugs(86, 6, "found OR");
815 rv
.valuetype
= ESI_EXPR_OR
;
818 } else if ('=' == *s
) {
819 if ('=' == *(s
+ 1)) {
820 debugs(86, 6, "found equals");
822 rv
.valuetype
= ESI_EXPR_EQ
;
824 rv
.eval
= evalequals
;
826 debugs(86, 1, "invalid expr '" << s
<< "'");
829 } else if ('<' == *s
) {
830 if ('=' == *(s
+ 1)) {
831 debugs(86, 6, "found less-equals");
833 rv
.valuetype
= ESI_EXPR_LESSEQ
;
835 rv
.eval
= evallesseq
;
837 debugs(86, 6, "found less than");
839 rv
.valuetype
= ESI_EXPR_LESS
;
841 rv
.eval
= evallessthan
;
843 } else if ('>' == *s
) {
844 if ('=' == *(s
+ 1)) {
845 debugs(86, 6, "found more-equals");
847 rv
.valuetype
= ESI_EXPR_MOREEQ
;
849 rv
.eval
= evalmoreeq
;
851 debugs(86, 6, "found more than");
853 rv
.valuetype
= ESI_EXPR_MORE
;
855 rv
.eval
= evalmorethan
;
857 } else if (!strncmp (s
, "false", 5)) {
858 debugs(86, 5, "getsymbol: found variable result 'false'");
860 rv
.valuetype
= ESI_EXPR_EXPR
;
861 rv
.valuestored
= ESI_LITERAL_BOOL
;
862 rv
.value
.integral
= 0;
865 } else if (!strncmp (s
, "true", 4)) {
866 debugs(86, 5, "getsymbol: found variable result 'true'");
868 rv
.valuetype
= ESI_EXPR_EXPR
;
869 rv
.valuestored
= ESI_LITERAL_BOOL
;
870 rv
.value
.integral
= 1;
874 debugs(86, 1, "invalid expr '" << s
<< "'");
882 printliteral (stackmember s
)
884 switch (s
.valuestored
) {
886 case ESI_LITERAL_INVALID
:
887 old_debug(86, 1) ( " Invalid " );
890 case ESI_LITERAL_FLOAT
:
891 old_debug(86,1) ("%f", s
.value
.floating
);
894 case ESI_LITERAL_STRING
:
895 old_debug(86,1) ("'%s'", s
.value
.string
);
898 case ESI_LITERAL_INT
:
899 old_debug(86,1) ("%d", s
.value
.integral
);
902 case ESI_LITERAL_BOOL
:
903 old_debug(86,1)("%s",s
.value
.integral
? "true" : "false");
908 printmember (stackmember s
)
910 switch (s
.valuetype
) {
912 case ESI_EXPR_INVALID
:
913 old_debug(86,1) (" Invalid ");
916 case ESI_EXPR_LITERAL
:
921 old_debug(86,1) ("%s", s
.value
.integral
? "true" : "false");
925 old_debug(86,1) ("|");
929 old_debug(86,1) ("&");
933 old_debug(86,1) ("!");
937 old_debug(86,1) ("(");
941 old_debug(86,1) (")");
945 old_debug(86,1) ("==");
949 old_debug(86,1) ("!=");
953 old_debug(86,1) ("<");
956 case ESI_EXPR_LESSEQ
:
957 old_debug(86,1) ("<=");
961 old_debug(86,1) (">");
964 case ESI_EXPR_MOREEQ
:
965 old_debug(86,1) (">=");
971 dumpstack (stackmember
* stack
, int depth
)
975 for (i
= 0; i
< depth
; ++i
)
976 printmember (stack
[i
]);
979 old_debug(86,1) ("\n");
983 addmember (stackmember
* stack
, int *stackdepth
, stackmember
* candidate
)
985 if (candidate
->valuetype
!= ESI_EXPR_LITERAL
&& *stackdepth
> 1) {
986 /* !(!(a==b))) is why thats safe */
987 /* strictly less than until we unwind */
989 if (candidate
->precedence
< stack
[*stackdepth
- 1].precedence
||
990 candidate
->precedence
< stack
[*stackdepth
- 2].precedence
) {
991 /* must be an operator */
993 if (stack
[*stackdepth
- 2].valuetype
== ESI_EXPR_LITERAL
||
994 stack
[*stackdepth
- 2].valuetype
== ESI_EXPR_INVALID
||
995 stack
[*stackdepth
- 2].eval (stack
, stackdepth
,
996 *stackdepth
- 2, candidate
)) {
997 /* cleanup candidate and stack */
998 dumpstack (stack
, *stackdepth
);
999 cleanmember (candidate
);
1000 debugs(86, 1, "invalid expression");
1004 stack
[(*stackdepth
)++] = *candidate
;
1006 } else if (candidate
->valuetype
!= ESI_EXPR_INVALID
)
1007 stack
[(*stackdepth
)++] = *candidate
;
1013 ESIExpression::Evaluate (char const *s
)
1015 stackmember stack
[20];
1018 PROF_start(esiExpressionEval
);
1021 stackmember candidate
= getsymbol (s
, &end
);
1023 if (candidate
.valuetype
!= ESI_EXPR_INVALID
) {
1026 if (!addmember (stack
, &stackdepth
, &candidate
)) {
1027 PROF_stop(esiExpressionEval
);
1034 debugs(86, 1, "failed parsing expression");
1035 PROF_stop(esiExpressionEval
);
1040 if (stackdepth
> 1) {
1042 rv
.valuetype
= ESI_EXPR_INVALID
;
1045 if (stack
[stackdepth
- 2].
1046 eval (stack
, &stackdepth
, stackdepth
- 2, &rv
)) {
1047 /* special case - leading operator failed */
1048 debugs(86, 1, "invalid expression");
1049 PROF_stop(esiExpressionEval
);
1054 if (stackdepth
== 0) {
1055 /* Empty expression - evaluate to false */
1056 PROF_stop(esiExpressionEval
);
1060 /* if we hit here, we think we have a valid result */
1061 assert (stackdepth
== 1);
1063 assert (stack
[0].valuetype
== ESI_EXPR_EXPR
);
1065 PROF_stop(esiExpressionEval
);
1067 return stack
[0].value
.integral
? 1 : 0;