]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/esi/Expression.cc
2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 86 ESI processing */
13 #include "esi/Expression.h"
14 #include "profiler/Profiler.h"
19 /* stack precedence rules:
20 * before pushing an operator onto the stack, the
21 * top 2 elements are checked. if either has a higher
22 * or equal precedence than the current operator, they
24 * Start of expression has 5 precedence,
25 * end of expression has 0 precedence
26 * literal has 1 as does expression results
30 * == != < > <= >= has 5
35 typedef struct _stackmember stackmember
;
37 typedef int evaluate(stackmember
* stack
, int *depth
, int whereAmI
,
38 stackmember
* candidate
);
54 ESI_EXPR_EXPR
/* the result of an expr PRI 1 */
72 literalhint valuestored
;
77 static void cleanmember(stackmember
*);
78 static void stackpop(stackmember
* s
, int *depth
);
81 cleanmember(stackmember
* s
)
83 if (s
->valuetype
== ESI_EXPR_LITERAL
84 && s
->valuestored
== ESI_LITERAL_STRING
) {
85 safe_free(s
->value
.string
);
86 s
->value
.string
= NULL
;
92 stackpop(stackmember
* s
, int *depth
)
97 cleanmember(&s
[*depth
]);
100 static evaluate evalnegate
;
101 static evaluate evalliteral
;
102 static evaluate evalor
;
103 static evaluate evaland
;
104 static evaluate evallesseq
;
105 static evaluate evallessthan
;
106 static evaluate evalmoreeq
;
107 static evaluate evalmorethan
;
108 static evaluate evalequals
;
109 static evaluate evalnotequals
;
110 static evaluate evalstartexpr
;
111 static evaluate evalendexpr
;
112 static evaluate evalexpr
;
113 static void dumpstack(stackmember
* stack
, int depth
);
114 static int addmember(stackmember
* stack
, int *stackdepth
,
115 stackmember
* candidate
);
116 static int membercompare(stackmember a
, stackmember b
);
117 static char const *trim(char const *s
);
118 static stackmember
getsymbol(const char *s
, char const **endptr
);
119 static void printliteral(stackmember s
);
120 static void printmember(stackmember s
);
122 /* -2 = failed to compate
128 membercompare(stackmember a
, stackmember b
)
130 /* we can compare: sub expressions to sub expressions ,
131 * literals to literals
134 if (!((a
.valuetype
== ESI_EXPR_LITERAL
&& b
.valuetype
== ESI_EXPR_LITERAL
&&
135 a
.valuestored
!= ESI_LITERAL_INVALID
&& b
.valuestored
!= ESI_LITERAL_INVALID
) ||
136 (a
.valuetype
== ESI_EXPR_EXPR
&& b
.valuetype
== ESI_EXPR_EXPR
)))
139 if (a
.valuetype
== ESI_EXPR_EXPR
) {
140 if (a
.value
.integral
== b
.value
.integral
)
144 } else if (a
.valuestored
== ESI_LITERAL_STRING
) {
145 if (b
.valuestored
== ESI_LITERAL_STRING
) {
146 int i
=strcmp(a
.value
.string
, b
.value
.string
);
156 /* TODO: numeric to string conversion ? */
157 debugs(86, DBG_IMPORTANT
, "strcmp with non-string");
160 } else if (a
.valuestored
== ESI_LITERAL_FLOAT
) {
161 if (b
.valuestored
== ESI_LITERAL_INT
) {
162 if (fabs(a
.value
.floating
- b
.value
.integral
) < 0.00001)
164 else if (a
.value
.floating
< b
.value
.integral
)
168 } else if (b
.valuestored
== ESI_LITERAL_FLOAT
) {
169 if (a
.value
.floating
== b
.value
.floating
)
171 else if (a
.value
.floating
< b
.value
.floating
)
176 /* TODO: attempt numeric converson again? */
177 debugs(86, DBG_IMPORTANT
, "floatcomp with non float or int");
180 } else if (a
.valuestored
== ESI_LITERAL_INT
) {
181 if (b
.valuestored
== ESI_LITERAL_INT
) {
182 if (a
.value
.integral
== b
.value
.integral
)
184 else if (a
.value
.integral
< b
.value
.integral
)
188 } else if (b
.valuestored
== ESI_LITERAL_FLOAT
) {
189 if (fabs(a
.value
.integral
- b
.value
.floating
) < 0.00001)
191 else if (a
.value
.integral
< b
.value
.floating
)
196 /* TODO: attempt numeric converson again? */
197 debugs(86, DBG_IMPORTANT
, "intcomp vs non float non int");
205 /* return 0 on success, 1 on failure */
207 evalnegate(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
209 if (whereAmI
!= *depth
- 2)
213 if (stack
[whereAmI
+ 1].valuetype
!= ESI_EXPR_EXPR
)
214 /* invalid operand */
220 stack
[whereAmI
] = stack
[(*depth
)];
222 cleanmember(candidate
);
224 if (stack
[whereAmI
].value
.integral
== 1)
225 stack
[whereAmI
].value
.integral
= 0;
227 stack
[whereAmI
].value
.integral
= 1;
233 evalliteral(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
235 debugs(86, DBG_IMPORTANT
, "attempt to evaluate a literal");
236 /* literals can't be evaluated */
241 evalexpr(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
243 debugs(86, DBG_IMPORTANT
, "attempt to evaluate a sub-expression result");
244 /* sub-scpr's can't be evaluated */
249 evalor(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
255 /* Not enough operands */
258 if (whereAmI
!= *depth
- 2)
262 if (stack
[whereAmI
+ 1].valuetype
!= ESI_EXPR_EXPR
||
263 stack
[whereAmI
- 1].valuetype
!= ESI_EXPR_EXPR
)
264 /* invalid operand */
267 rv
= stack
[whereAmI
- 1].value
.integral
|| stack
[whereAmI
+ 1].value
.integral
;
269 stackpop(stack
, depth
); /* arg rhs */
271 stackpop(stack
, depth
); /* me */
273 stackpop(stack
, depth
); /* arg lhs */
275 srv
.valuetype
= ESI_EXPR_EXPR
;
277 srv
.eval
= evalliteral
;
279 srv
.valuestored
= ESI_LITERAL_BOOL
;
281 srv
.value
.integral
= rv
? 1 : 0;
285 stack
[(*depth
)++] = srv
;
287 /* we're out of way, try adding now */
288 if (!addmember(stack
, depth
, candidate
))
289 /* Something wrong upstream */
296 evaland(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
302 /* Not enough operands */
305 if (whereAmI
!= *depth
- 2)
309 if (stack
[whereAmI
+ 1].valuetype
!= ESI_EXPR_EXPR
||
310 stack
[whereAmI
- 1].valuetype
!= ESI_EXPR_EXPR
)
311 /* invalid operand */
314 rv
= stack
[whereAmI
- 1].value
.integral
&& stack
[whereAmI
+ 1].value
.integral
;
316 stackpop(stack
, depth
); /* arg rhs */
318 stackpop(stack
, depth
); /* me */
320 stackpop(stack
, depth
); /* arg lhs */
322 srv
.valuetype
= ESI_EXPR_EXPR
;
326 srv
.valuestored
= ESI_LITERAL_BOOL
;
328 srv
.value
.integral
= rv
? 1 : 0;
332 stack
[(*depth
)++] = srv
;
334 /* we're out of way, try adding now */
335 if (!addmember(stack
, depth
, candidate
))
336 /* Something wrong upstream */
343 evallesseq(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
349 /* Not enough operands */
352 if (whereAmI
!= *depth
- 2)
356 rv
= membercompare(stack
[whereAmI
- 1], stack
[whereAmI
+ 1]);
359 /* invalid comparison */
362 stackpop(stack
, depth
); /* arg rhs */
364 stackpop(stack
, depth
); /* me */
366 stackpop(stack
, depth
); /* arg lhs */
368 srv
.valuetype
= ESI_EXPR_EXPR
;
372 srv
.valuestored
= ESI_LITERAL_BOOL
;
374 srv
.value
.integral
= rv
<= 0 ? 1 : 0;
378 stack
[(*depth
)++] = srv
;
380 /* we're out of way, try adding now */
381 if (!addmember(stack
, depth
, candidate
))
382 /* Something wrong upstream */
385 /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
391 evallessthan(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
397 /* Not enough operands */
400 if (whereAmI
!= *depth
- 2)
404 rv
= membercompare(stack
[whereAmI
- 1], stack
[whereAmI
+ 1]);
407 /* invalid comparison */
410 stackpop(stack
, depth
); /* arg rhs */
412 stackpop(stack
, depth
); /* me */
414 stackpop(stack
, depth
); /* arg lhs */
416 srv
.valuetype
= ESI_EXPR_EXPR
;
420 srv
.valuestored
= ESI_LITERAL_BOOL
;
422 srv
.value
.integral
= rv
< 0 ? 1 : 0;
426 stack
[(*depth
)++] = srv
;
428 /* we're out of way, try adding now */
429 if (!addmember(stack
, depth
, candidate
))
430 /* Something wrong upstream */
433 /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
439 evalmoreeq(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
445 /* Not enough operands */
448 if (whereAmI
!= *depth
- 2)
452 rv
= membercompare(stack
[whereAmI
- 1], stack
[whereAmI
+ 1]);
455 /* invalid comparison */
458 stackpop(stack
, depth
); /* arg rhs */
460 stackpop(stack
, depth
); /* me */
462 stackpop(stack
, depth
); /* arg lhs */
464 srv
.valuetype
= ESI_EXPR_EXPR
;
468 srv
.valuestored
= ESI_LITERAL_BOOL
;
470 srv
.value
.integral
= rv
>= 0 ? 1 : 0;
474 stack
[(*depth
)++] = srv
;
476 /* we're out of way, try adding now */
477 if (!addmember(stack
, depth
, candidate
))
478 /* Something wrong upstream */
481 /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
487 evalmorethan(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
493 /* Not enough operands */
496 if (whereAmI
!= *depth
- 2)
500 rv
= membercompare(stack
[whereAmI
- 1], stack
[whereAmI
+ 1]);
503 /* invalid comparison */
506 stackpop(stack
, depth
); /* arg rhs */
508 stackpop(stack
, depth
); /* me */
510 stackpop(stack
, depth
); /* arg lhs */
512 srv
.valuetype
= ESI_EXPR_EXPR
;
516 srv
.valuestored
= ESI_LITERAL_BOOL
;
518 srv
.value
.integral
= rv
> 0 ? 1 : 0;
522 stack
[(*depth
)++] = srv
;
524 /* we're out of way, try adding now */
525 if (!addmember(stack
, depth
, candidate
))
526 /* Something wrong upstream */
529 /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
535 evalequals(stackmember
* stack
, int *depth
, int whereAmI
,
536 stackmember
* candidate
)
542 /* Not enough operands */
545 if (whereAmI
!= *depth
- 2)
549 rv
= membercompare(stack
[whereAmI
- 1], stack
[whereAmI
+ 1]);
552 /* invalid comparison */
555 stackpop(stack
, depth
); /* arg rhs */
557 stackpop(stack
, depth
); /* me */
559 stackpop(stack
, depth
); /* arg lhs */
561 srv
.valuetype
= ESI_EXPR_EXPR
;
565 srv
.valuestored
= ESI_LITERAL_BOOL
;
567 srv
.value
.integral
= rv
? 0 : 1;
571 stack
[(*depth
)++] = srv
;
573 /* we're out of way, try adding now */
574 if (!addmember(stack
, depth
, candidate
))
575 /* Something wrong upstream */
578 /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
583 evalnotequals(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
589 /* Not enough operands */
592 if (whereAmI
!= *depth
- 2)
596 rv
= membercompare(stack
[whereAmI
- 1], stack
[whereAmI
+ 1]);
599 /* invalid comparison */
602 stackpop(stack
, depth
); /* arg rhs */
604 stackpop(stack
, depth
); /* me */
606 stackpop(stack
, depth
); /* arg lhs */
608 srv
.valuetype
= ESI_EXPR_EXPR
;
612 srv
.valuestored
= ESI_LITERAL_BOOL
;
614 srv
.value
.integral
= rv
? 1 : 0;
618 stack
[(*depth
)++] = srv
;
620 /* we're out of way, try adding now */
621 if (!addmember(stack
, depth
, candidate
))
622 /* Something wrong upstream */
625 /* debugs(86, DBG_IMPORTANT, "?= " << srv.value.integral << " "); */
630 evalstartexpr(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
632 /* debugs(86, DBG_IMPORTANT, "?("); */
634 if (whereAmI
!= *depth
- 2)
638 /* Only valid when RHS is an end bracket */
639 if (candidate
->valuetype
!= ESI_EXPR_END
)
644 stack
[whereAmI
] = stack
[(*depth
)];
646 cleanmember(candidate
);
652 evalendexpr(stackmember
* stack
, int *depth
, int whereAmI
, stackmember
* candidate
)
654 /* Can't evaluate ) brackets */
668 getsymbol(const char *s
, char const **endptr
)
672 char const *origs
= s
;
673 /* trim whitespace */
675 rv
.eval
= NULL
; /* A literal */
676 rv
.valuetype
= ESI_EXPR_INVALID
;
677 rv
.valuestored
= ESI_LITERAL_INVALID
;
678 rv
.precedence
= 1; /* A literal */
680 if (('0' <= *s
&& *s
<= '9') || *s
== '-') {
681 size_t length
= strspn(s
, "0123456789.");
684 if ((point
= strchr(s
, '.')) && point
- s
< (ssize_t
)length
) {
686 errno
=0; /* reset errno */
687 rv
.value
.floating
= strtod(s
, &end
);
689 if (s
== end
|| errno
) {
690 /* Couldn't convert to float */
691 debugs(86, DBG_IMPORTANT
, "failed to convert '" << s
<< "' to float ");
694 debugs(86,6, "found " << rv
.value
.floating
<< " of length " << end
- s
);
696 rv
.eval
= evalliteral
;
697 rv
.valuestored
= ESI_LITERAL_FLOAT
;
698 rv
.valuetype
= ESI_EXPR_LITERAL
;
703 errno
=0; /* reset errno */
704 rv
.value
.integral
= strtol(s
, &end
, 0);
706 if (s
== end
|| errno
) {
707 /* Couldn't convert to int */
708 debugs(86, DBG_IMPORTANT
, "failed to convert '" << s
<< "' to int ");
711 debugs(86,6, "found " << rv
.value
.integral
<< " of length " << end
- s
);
713 rv
.eval
= evalliteral
;
714 rv
.valuestored
= ESI_LITERAL_INT
;
715 rv
.valuetype
= ESI_EXPR_LITERAL
;
719 } else if ('!' == *s
) {
720 if ('=' == *(s
+ 1)) {
721 debugs(86, 6, "found !=");
723 rv
.eval
= evalnotequals
;
724 rv
.valuetype
= ESI_EXPR_NOTEQ
;
727 debugs(86, 6, "found !");
729 rv
.valuetype
= ESI_EXPR_NOT
;
731 rv
.eval
= evalnegate
;
733 } else if ('\'' == *s
) {
734 char const *t
= s
+ 1;
735 debugs(86, 6, "found \'");
737 while (*t
!= '\'' && *t
)
741 debugs(86, DBG_IMPORTANT
, "missing end \' in '" << s
<< "'");
745 /* Special case for zero length strings */
748 rv
.value
.string
= xstrndup(s
+ 1, t
- s
- 1);
750 rv
.value
.string
= static_cast<char *>(xcalloc(1,1));
752 rv
.eval
= evalliteral
;
754 rv
.valuestored
= ESI_LITERAL_STRING
;
756 rv
.valuetype
= ESI_EXPR_LITERAL
;
760 debugs(86, 6, "found string '" << rv
.value
.string
<< "'");
762 } else if ('(' == *s
) {
763 debugs(86, 6, "found subexpr start");
765 rv
.valuetype
= ESI_EXPR_START
;
767 rv
.eval
= evalstartexpr
;
768 } else if (')' == *s
) {
769 debugs(86, 6, "found subexpr end");
771 rv
.valuetype
= ESI_EXPR_END
;
773 rv
.eval
= evalendexpr
;
774 } else if ('&' == *s
) {
775 debugs(86, 6, "found AND");
777 rv
.valuetype
= ESI_EXPR_AND
;
780 } else if ('|' == *s
) {
781 debugs(86, 6, "found OR");
783 rv
.valuetype
= ESI_EXPR_OR
;
786 } else if ('=' == *s
) {
787 if ('=' == *(s
+ 1)) {
788 debugs(86, 6, "found equals");
790 rv
.valuetype
= ESI_EXPR_EQ
;
792 rv
.eval
= evalequals
;
794 debugs(86, DBG_IMPORTANT
, "invalid expr '" << s
<< "'");
797 } else if ('<' == *s
) {
798 if ('=' == *(s
+ 1)) {
799 debugs(86, 6, "found less-equals");
801 rv
.valuetype
= ESI_EXPR_LESSEQ
;
803 rv
.eval
= evallesseq
;
805 debugs(86, 6, "found less than");
807 rv
.valuetype
= ESI_EXPR_LESS
;
809 rv
.eval
= evallessthan
;
811 } else if ('>' == *s
) {
812 if ('=' == *(s
+ 1)) {
813 debugs(86, 6, "found more-equals");
815 rv
.valuetype
= ESI_EXPR_MOREEQ
;
817 rv
.eval
= evalmoreeq
;
819 debugs(86, 6, "found more than");
821 rv
.valuetype
= ESI_EXPR_MORE
;
823 rv
.eval
= evalmorethan
;
825 } else if (!strncmp(s
, "false", 5)) {
826 debugs(86, 5, "getsymbol: found variable result 'false'");
828 rv
.valuetype
= ESI_EXPR_EXPR
;
829 rv
.valuestored
= ESI_LITERAL_BOOL
;
830 rv
.value
.integral
= 0;
833 } else if (!strncmp(s
, "true", 4)) {
834 debugs(86, 5, "getsymbol: found variable result 'true'");
836 rv
.valuetype
= ESI_EXPR_EXPR
;
837 rv
.valuestored
= ESI_LITERAL_BOOL
;
838 rv
.value
.integral
= 1;
842 debugs(86, DBG_IMPORTANT
, "invalid expr '" << s
<< "'");
850 printliteral(stackmember s
)
852 switch (s
.valuestored
) {
854 case ESI_LITERAL_INVALID
:
855 old_debug(86, 1)( " Invalid " );
858 case ESI_LITERAL_FLOAT
:
859 old_debug(86,1)("%f", s
.value
.floating
);
862 case ESI_LITERAL_STRING
:
863 old_debug(86,1)("'%s'", s
.value
.string
);
866 case ESI_LITERAL_INT
:
867 old_debug(86,1)("%d", s
.value
.integral
);
870 case ESI_LITERAL_BOOL
:
871 old_debug(86,1)("%s",s
.value
.integral
? "true" : "false");
876 printmember(stackmember s
)
878 switch (s
.valuetype
) {
880 case ESI_EXPR_INVALID
:
881 old_debug(86,1)(" Invalid ");
884 case ESI_EXPR_LITERAL
:
889 old_debug(86,1)("%s", s
.value
.integral
? "true" : "false");
893 old_debug(86,1)("|");
897 old_debug(86,1)("&");
901 old_debug(86,1)("!");
905 old_debug(86,1)("(");
909 old_debug(86,1)(")");
913 old_debug(86,1)("==");
917 old_debug(86,1)("!=");
921 old_debug(86,1)("<");
924 case ESI_EXPR_LESSEQ
:
925 old_debug(86,1)("<=");
929 old_debug(86,1)(">");
932 case ESI_EXPR_MOREEQ
:
933 old_debug(86,1)(">=");
939 dumpstack(stackmember
* stack
, int depth
)
943 for (i
= 0; i
< depth
; ++i
)
944 printmember(stack
[i
]);
947 old_debug(86,1)("\n");
951 addmember(stackmember
* stack
, int *stackdepth
, stackmember
* candidate
)
953 if (candidate
->valuetype
!= ESI_EXPR_LITERAL
&& *stackdepth
> 1) {
954 /* !(!(a==b))) is why thats safe */
955 /* strictly less than until we unwind */
957 if (candidate
->precedence
< stack
[*stackdepth
- 1].precedence
||
958 candidate
->precedence
< stack
[*stackdepth
- 2].precedence
) {
959 /* must be an operator */
961 if (stack
[*stackdepth
- 2].valuetype
== ESI_EXPR_LITERAL
||
962 stack
[*stackdepth
- 2].valuetype
== ESI_EXPR_INVALID
||
963 stack
[*stackdepth
- 2].eval(stack
, stackdepth
,
964 *stackdepth
- 2, candidate
)) {
965 /* cleanup candidate and stack */
966 dumpstack(stack
, *stackdepth
);
967 cleanmember(candidate
);
968 debugs(86, DBG_IMPORTANT
, "invalid expression");
972 stack
[(*stackdepth
)++] = *candidate
;
974 } else if (candidate
->valuetype
!= ESI_EXPR_INVALID
)
975 stack
[(*stackdepth
)++] = *candidate
;
981 ESIExpression::Evaluate(char const *s
)
983 stackmember stack
[20];
986 PROF_start(esiExpressionEval
);
989 stackmember candidate
= getsymbol(s
, &end
);
991 if (candidate
.valuetype
!= ESI_EXPR_INVALID
) {
994 if (!addmember(stack
, &stackdepth
, &candidate
)) {
995 PROF_stop(esiExpressionEval
);
1002 debugs(86, DBG_IMPORTANT
, "failed parsing expression");
1003 PROF_stop(esiExpressionEval
);
1008 if (stackdepth
> 1) {
1010 rv
.valuetype
= ESI_EXPR_INVALID
;
1013 if (stack
[stackdepth
- 2].
1014 eval(stack
, &stackdepth
, stackdepth
- 2, &rv
)) {
1015 /* special case - leading operator failed */
1016 debugs(86, DBG_IMPORTANT
, "invalid expression");
1017 PROF_stop(esiExpressionEval
);
1022 if (stackdepth
== 0) {
1023 /* Empty expression - evaluate to false */
1024 PROF_stop(esiExpressionEval
);
1028 /* if we hit here, we think we have a valid result */
1029 assert(stackdepth
== 1);
1031 assert(stack
[0].valuetype
== ESI_EXPR_EXPR
);
1033 PROF_stop(esiExpressionEval
);
1035 return stack
[0].value
.integral
? 1 : 0;