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