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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors