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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors