source: trunk/src/kmk/expreval.c@ 3399

Last change on this file since 3399 was 3399, checked in by bird, 5 years ago

kmk/expreval.c: Don't pick up version compare operators in the middle of unquoted strings. Baked isspace into expr_map_get.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.8 KB
Line 
1#ifdef CONFIG_WITH_IF_CONDITIONALS
2/* $Id: expreval.c 3399 2020-07-02 11:35:23Z bird $ */
3/** @file
4 * expreval - Expressions evaluator, C / BSD make / nmake style.
5 */
6
7/*
8 * Copyright (c) 2008-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
9 *
10 * This file is part of kBuild.
11 *
12 * kBuild is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * kBuild is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
24 *
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#include "makeint.h"
31#include <assert.h>
32
33#include <glob.h>
34
35#include "filedef.h"
36#include "dep.h"
37#include "job.h"
38#include "commands.h"
39#include "variable.h"
40#include "rule.h"
41#include "debug.h"
42#include "hash.h"
43#include "version_compare.h"
44#include <ctype.h>
45#ifndef _MSC_VER
46# include <stdint.h>
47#endif
48#include <stdarg.h>
49
50
51/*******************************************************************************
52* Defined Constants And Macros *
53*******************************************************************************/
54/** The max length of a string representation of a number. */
55#define EXPR_NUM_LEN ((sizeof("-9223372036854775802") + 4) & ~3)
56
57/** The max operator stack depth. */
58#define EXPR_MAX_OPERATORS 72
59/** The max operand depth. */
60#define EXPR_MAX_OPERANDS 128
61
62/** Check if @a a_ch is a valid separator for a alphabetical binary
63 * operator, omitting isspace. */
64#define EXPR_IS_OP_SEPARATOR_NO_SPACE(a_ch) \
65 (ispunct((a_ch)) && (a_ch) != '@' && (a_ch) != '_'))
66
67/** Check if @a a_ch is a valid separator for a alphabetical binary operator. */
68#define EXPR_IS_OP_SEPARATOR(a_ch) \
69 (isspace((a_ch)) || EXPR_IS_OP_SEPARATOR_NO_SPACE(a_ch))
70
71
72/*******************************************************************************
73* Structures and Typedefs *
74*******************************************************************************/
75/** The 64-bit signed integer type we're using. */
76#ifdef _MSC_VER
77typedef __int64 EXPRINT64;
78#else
79# include <stdint.h>
80typedef int64_t EXPRINT64;
81#endif
82
83/** Pointer to a evaluator instance. */
84typedef struct EXPR *PEXPR;
85
86
87/**
88 * Operand variable type.
89 */
90typedef enum
91{
92 /** Invalid zero entry. */
93 kExprVar_Invalid = 0,
94 /** A number. */
95 kExprVar_Num,
96 /** A string in need of expanding (perhaps). */
97 kExprVar_String,
98 /** A simple string that doesn't need expanding. */
99 kExprVar_SimpleString,
100 /** A quoted string in need of expanding (perhaps). */
101 kExprVar_QuotedString,
102 /** A simple quoted string that doesn't need expanding. */
103 kExprVar_QuotedSimpleString,
104 /** The end of the valid variable types. */
105 kExprVar_End
106} EXPRVARTYPE;
107
108/**
109 * Operand variable.
110 */
111typedef struct
112{
113 /** The variable type. */
114 EXPRVARTYPE enmType;
115 /** The variable. */
116 union
117 {
118 /** Pointer to the string. */
119 char *psz;
120 /** The variable. */
121 EXPRINT64 i;
122 } uVal;
123} EXPRVAR;
124/** Pointer to a operand variable. */
125typedef EXPRVAR *PEXPRVAR;
126/** Pointer to a const operand variable. */
127typedef EXPRVAR const *PCEXPRVAR;
128
129/**
130 * Operator return statuses.
131 */
132typedef enum
133{
134 kExprRet_Error = -1,
135 kExprRet_Ok = 0,
136 kExprRet_Operator,
137 kExprRet_Operand,
138 kExprRet_EndOfExpr,
139 kExprRet_End
140} EXPRRET;
141
142/**
143 * Operator.
144 */
145typedef struct
146{
147 /** The operator. */
148 char szOp[11];
149 /** The length of the operator string. */
150 char cchOp;
151 /** The pair operator.
152 * This is used with '(' and '?'. */
153 char chPair;
154 /** The precedence. Higher means higher. */
155 char iPrecedence;
156 /** The number of arguments it takes. */
157 signed char cArgs;
158 /** Pointer to the method implementing the operator. */
159 EXPRRET (*pfn)(PEXPR pThis);
160} EXPROP;
161/** Pointer to a const operator. */
162typedef EXPROP const *PCEXPROP;
163
164/**
165 * Expression evaluator instance.
166 */
167typedef struct EXPR
168{
169 /** The full expression. */
170 const char *pszExpr;
171 /** The current location. */
172 const char *psz;
173 /** The current file location, used for errors. */
174 const floc *pFileLoc;
175 /** Pending binary operator. */
176 PCEXPROP pPending;
177 /** Top of the operator stack. */
178 int iOp;
179 /** Top of the operand stack. */
180 int iVar;
181 /** The operator stack. */
182 PCEXPROP apOps[EXPR_MAX_OPERATORS];
183 /** The operand stack. */
184 EXPRVAR aVars[EXPR_MAX_OPERANDS];
185} EXPR;
186
187
188/*******************************************************************************
189* Global Variables *
190*******************************************************************************/
191/** Operator start character map.
192 * This indicates which characters that are starting operators and which aren't.
193 *
194 * Bit 0: Indicates that this char is used in operators.
195 * Bit 1: When bit 0 is clear, this indicates whitespace.
196 * When bit 1 is set, this indicates whether the operator can be used
197 * immediately next to an operand without any clear separation.
198 * Bits 2 thru 7: Index into g_aExprOps of the first operator starting with
199 * this character.
200 */
201static unsigned char g_auchOpStartCharMap[256];
202/** Whether we've initialized the map. */
203static int g_fExprInitializedMap = 0;
204
205
206/*******************************************************************************
207* Internal Functions *
208*******************************************************************************/
209static void expr_unget_op(PEXPR pThis);
210static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis);
211
212
213
214
215/**
216 * Displays an error message.
217 *
218 * The total string length must not exceed 256 bytes.
219 *
220 * @param pThis The evaluator instance.
221 * @param pszError The message format string.
222 * @param ... The message format args.
223 */
224static void expr_error(PEXPR pThis, const char *pszError, ...)
225{
226 char szTmp[256];
227 va_list va;
228
229 va_start(va, pszError);
230 vsprintf(szTmp, pszError, va);
231 va_end(va);
232
233 OS(fatal,pThis->pFileLoc, "%s", szTmp);
234}
235
236
237/**
238 * Converts a number to a string.
239 *
240 * @returns pszDst.
241 * @param pszDst The string buffer to write into. Assumes length of EXPR_NUM_LEN.
242 * @param iSrc The number to convert.
243 */
244static char *expr_num_to_string(char *pszDst, EXPRINT64 iSrc)
245{
246 static const char s_szDigits[17] = "0123456789abcdef";
247 char szTmp[EXPR_NUM_LEN];
248 char *psz = &szTmp[EXPR_NUM_LEN - 1];
249 int fNegative;
250
251 fNegative = iSrc < 0;
252 if (fNegative)
253 {
254 /** @todo this isn't right for INT64_MIN. */
255 iSrc = -iSrc;
256 }
257
258 *psz = '\0';
259 do
260 {
261#if 0
262 *--psz = s_szDigits[iSrc & 0xf];
263 iSrc >>= 4;
264#else
265 *--psz = s_szDigits[iSrc % 10];
266 iSrc /= 10;
267#endif
268 } while (iSrc);
269
270#if 0
271 *--psz = 'x';
272 *--psz = '0';
273#endif
274
275 if (fNegative)
276 *--psz = '-';
277
278 /* copy it into the output buffer. */
279 return (char *)memcpy(pszDst, psz, &szTmp[EXPR_NUM_LEN] - psz);
280}
281
282
283/**
284 * Attempts to convert a (simple) string into a number.
285 *
286 * @returns status code.
287 * @param pThis The evaluator instance. This is optional when fQuiet is true.
288 * @param piSrc Where to store the numeric value on success.
289 * @param pszSrc The string to try convert.
290 * @param fQuiet Whether we should be quiet or grumpy on failure.
291 */
292static EXPRRET expr_string_to_num(PEXPR pThis, EXPRINT64 *piDst, const char *pszSrc, int fQuiet)
293{
294 EXPRRET rc = kExprRet_Ok;
295 char const *psz = pszSrc;
296 EXPRINT64 i;
297 unsigned uBase;
298 int fNegative;
299
300
301 /*
302 * Skip blanks.
303 */
304 while (ISBLANK(*psz))
305 psz++;
306
307 /*
308 * Check for '-'.
309 *
310 * At this point we will not need to deal with operators, this is
311 * just an indicator of negative numbers. If some operator ends up
312 * here it's because it came from a string expansion and thus shall
313 * not be interpreted. If this turns out to be an stupid restriction
314 * it can be fixed, but for now it stays like this.
315 */
316 fNegative = *psz == '-';
317 if (fNegative)
318 psz++;
319
320 /*
321 * Determin base .
322 * .
323 * Recognize some exsotic prefixes here in addition to the two standard ones.
324 */
325 if (*psz != '0' || psz[1] == '\0' || ISBLANK(psz[1]))
326 uBase = 10;
327 else if (psz[1] == 'x' || psz[1] == 'X')
328 {
329 uBase = 16;
330 psz += 2;
331 }
332 else if (psz[1] == 'b' || psz[1] == 'B')
333 {
334 uBase = 2;
335 psz += 2;
336 }
337 else if (psz[1] == 'd' || psz[1] == 'D')
338 {
339 uBase = 10;
340 psz += 2;
341 }
342 else if (psz[1] == 'o' || psz[1] == 'O')
343 {
344 uBase = 8;
345 psz += 2;
346 }
347 else if (isdigit(psz[1]) && psz[1] != '9' && psz[1] != '8')
348 {
349 uBase = 8;
350 psz++;
351 }
352 else
353 uBase = 10;
354
355 /*
356 * Convert until we hit a non-digit.
357 */
358 i = 0;
359 for (;;)
360 {
361 unsigned iDigit;
362 int ch = *psz;
363 switch (ch)
364 {
365 case '0': iDigit = 0; break;
366 case '1': iDigit = 1; break;
367 case '2': iDigit = 2; break;
368 case '3': iDigit = 3; break;
369 case '4': iDigit = 4; break;
370 case '5': iDigit = 5; break;
371 case '6': iDigit = 6; break;
372 case '7': iDigit = 7; break;
373 case '8': iDigit = 8; break;
374 case '9': iDigit = 9; break;
375 case 'a':
376 case 'A': iDigit = 10; break;
377 case 'b':
378 case 'B': iDigit = 11; break;
379 case 'c':
380 case 'C': iDigit = 12; break;
381 case 'd':
382 case 'D': iDigit = 13; break;
383 case 'e':
384 case 'E': iDigit = 14; break;
385 case 'f':
386 case 'F': iDigit = 15; break;
387
388 default:
389 /* is the rest white space? */
390 while (ISSPACE(*psz))
391 psz++;
392 if (*psz != '\0')
393 {
394 iDigit = uBase;
395 break;
396 }
397 /* fall thru */
398
399 case '\0':
400 if (fNegative)
401 i = -i;
402 *piDst = i;
403 return rc;
404 }
405 if (iDigit >= uBase)
406 {
407 if (fNegative)
408 i = -i;
409 *piDst = i;
410 if (!fQuiet)
411 expr_error(pThis, "Invalid number \"%.80s\"", pszSrc);
412 return kExprRet_Error;
413 }
414
415 /* add the digit and advance */
416 i *= uBase;
417 i += iDigit;
418 psz++;
419 }
420 /* not reached */
421}
422
423
424/**
425 * Checks if the variable is a string or not.
426 *
427 * @returns 1 if it's a string, 0 otherwise.
428 * @param pVar The variable.
429 */
430static int expr_var_is_string(PCEXPRVAR pVar)
431{
432 return pVar->enmType >= kExprVar_String;
433}
434
435
436/**
437 * Checks if the variable contains a string that was quoted
438 * in the expression.
439 *
440 * @returns 1 if if was a quoted string, otherwise 0.
441 * @param pVar The variable.
442 */
443static int expr_var_was_quoted(PCEXPRVAR pVar)
444{
445 return pVar->enmType >= kExprVar_QuotedString;
446}
447
448
449/**
450 * Deletes a variable.
451 *
452 * @param pVar The variable.
453 */
454static void expr_var_delete(PEXPRVAR pVar)
455{
456 if (expr_var_is_string(pVar))
457 {
458 free(pVar->uVal.psz);
459 pVar->uVal.psz = NULL;
460 }
461 pVar->enmType = kExprVar_Invalid;
462}
463
464
465/**
466 * Initializes a new variables with a sub-string value.
467 *
468 * @param pVar The new variable.
469 * @param psz The start of the string value.
470 * @param cch The number of chars to copy.
471 * @param enmType The string type.
472 */
473static void expr_var_init_substring(PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType)
474{
475 /* convert string needing expanding into simple ones if possible. */
476 if ( enmType == kExprVar_String
477 && !memchr(psz, '$', cch))
478 enmType = kExprVar_SimpleString;
479 else if ( enmType == kExprVar_QuotedString
480 && !memchr(psz, '$', cch))
481 enmType = kExprVar_QuotedSimpleString;
482
483 pVar->enmType = enmType;
484 pVar->uVal.psz = xmalloc(cch + 1);
485 memcpy(pVar->uVal.psz, psz, cch);
486 pVar->uVal.psz[cch] = '\0';
487}
488
489
490#if 0 /* unused */
491/**
492 * Initializes a new variables with a string value.
493 *
494 * @param pVar The new variable.
495 * @param psz The string value.
496 * @param enmType The string type.
497 */
498static void expr_var_init_string(PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType)
499{
500 expr_var_init_substring(pVar, psz, strlen(psz), enmType);
501}
502
503
504/**
505 * Assigns a sub-string value to a variable.
506 *
507 * @param pVar The new variable.
508 * @param psz The start of the string value.
509 * @param cch The number of chars to copy.
510 * @param enmType The string type.
511 */
512static void expr_var_assign_substring(PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType)
513{
514 expr_var_delete(pVar);
515 expr_var_init_substring(pVar, psz, cch, enmType);
516}
517
518
519/**
520 * Assignes a string value to a variable.
521 *
522 * @param pVar The variable.
523 * @param psz The string value.
524 * @param enmType The string type.
525 */
526static void expr_var_assign_string(PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType)
527{
528 expr_var_delete(pVar);
529 expr_var_init_string(pVar, psz, enmType);
530}
531#endif /* unused */
532
533
534/**
535 * Simplifies a string variable.
536 *
537 * @param pVar The variable.
538 */
539static void expr_var_make_simple_string(PEXPRVAR pVar)
540{
541 switch (pVar->enmType)
542 {
543 case kExprVar_Num:
544 {
545 char *psz = (char *)xmalloc(EXPR_NUM_LEN);
546 expr_num_to_string(psz, pVar->uVal.i);
547 pVar->uVal.psz = psz;
548 pVar->enmType = kExprVar_SimpleString;
549 break;
550 }
551
552 case kExprVar_String:
553 case kExprVar_QuotedString:
554 {
555 char *psz;
556 assert(strchr(pVar->uVal.psz, '$'));
557
558 psz = allocated_variable_expand(pVar->uVal.psz);
559 free(pVar->uVal.psz);
560 pVar->uVal.psz = psz;
561
562 pVar->enmType = pVar->enmType == kExprVar_String
563 ? kExprVar_SimpleString
564 : kExprVar_QuotedSimpleString;
565 break;
566 }
567
568 case kExprVar_SimpleString:
569 case kExprVar_QuotedSimpleString:
570 /* nothing to do. */
571 break;
572
573 default:
574 assert(0);
575 }
576}
577
578
579#if 0 /* unused */
580/**
581 * Turns a variable into a string value.
582 *
583 * @param pVar The variable.
584 */
585static void expr_var_make_string(PEXPRVAR pVar)
586{
587 switch (pVar->enmType)
588 {
589 case kExprVar_Num:
590 expr_var_make_simple_string(pVar);
591 break;
592
593 case kExprVar_String:
594 case kExprVar_SimpleString:
595 case kExprVar_QuotedString:
596 case kExprVar_QuotedSimpleString:
597 /* nothing to do. */
598 break;
599
600 default:
601 assert(0);
602 }
603}
604#endif /* unused */
605
606
607/**
608 * Initializes a new variables with a integer value.
609 *
610 * @param pVar The new variable.
611 * @param i The integer value.
612 */
613static void expr_var_init_num(PEXPRVAR pVar, EXPRINT64 i)
614{
615 pVar->enmType = kExprVar_Num;
616 pVar->uVal.i = i;
617}
618
619
620/**
621 * Assigns a integer value to a variable.
622 *
623 * @param pVar The variable.
624 * @param i The integer value.
625 */
626static void expr_var_assign_num(PEXPRVAR pVar, EXPRINT64 i)
627{
628 expr_var_delete(pVar);
629 expr_var_init_num(pVar, i);
630}
631
632
633/**
634 * Turns the variable into a number.
635 *
636 * @returns status code.
637 * @param pThis The evaluator instance.
638 * @param pVar The variable.
639 */
640static EXPRRET expr_var_make_num(PEXPR pThis, PEXPRVAR pVar)
641{
642 switch (pVar->enmType)
643 {
644 case kExprVar_Num:
645 /* nothing to do. */
646 break;
647
648 case kExprVar_String:
649 expr_var_make_simple_string(pVar);
650 /* fall thru */
651 case kExprVar_SimpleString:
652 {
653 EXPRINT64 i;
654 EXPRRET rc = expr_string_to_num(pThis, &i, pVar->uVal.psz, 0 /* fQuiet */);
655 if (rc < kExprRet_Ok)
656 return rc;
657 expr_var_assign_num(pVar, i);
658 break;
659 }
660
661 case kExprVar_QuotedString:
662 case kExprVar_QuotedSimpleString:
663 expr_error(pThis, "Cannot convert a quoted string to a number");
664 return kExprRet_Error;
665
666 default:
667 assert(0);
668 return kExprRet_Error;
669 }
670
671 return kExprRet_Ok;
672}
673
674
675/**
676 * Try to turn the variable into a number.
677 *
678 * @returns status code.
679 * @param pVar The variable.
680 */
681static EXPRRET expr_var_try_make_num(PEXPRVAR pVar)
682{
683 switch (pVar->enmType)
684 {
685 case kExprVar_Num:
686 /* nothing to do. */
687 break;
688
689 case kExprVar_String:
690 expr_var_make_simple_string(pVar);
691 /* fall thru */
692 case kExprVar_SimpleString:
693 {
694 EXPRINT64 i;
695 EXPRRET rc = expr_string_to_num(NULL, &i, pVar->uVal.psz, 1 /* fQuiet */);
696 if (rc < kExprRet_Ok)
697 return rc;
698 expr_var_assign_num(pVar, i);
699 break;
700 }
701
702 default:
703 assert(0);
704 case kExprVar_QuotedString:
705 case kExprVar_QuotedSimpleString:
706 /* can't do this */
707 return kExprRet_Error;
708 }
709
710 return kExprRet_Ok;
711}
712
713
714/**
715 * Initializes a new variables with a boolean value.
716 *
717 * @param pVar The new variable.
718 * @param f The boolean value.
719 */
720static void expr_var_init_bool(PEXPRVAR pVar, int f)
721{
722 pVar->enmType = kExprVar_Num;
723 pVar->uVal.i = !!f;
724}
725
726
727/**
728 * Assigns a boolean value to a variable.
729 *
730 * @param pVar The variable.
731 * @param f The boolean value.
732 */
733static void expr_var_assign_bool(PEXPRVAR pVar, int f)
734{
735 expr_var_delete(pVar);
736 expr_var_init_bool(pVar, f);
737}
738
739
740/**
741 * Turns the variable into an boolean.
742 *
743 * @returns the boolean interpretation.
744 * @param pVar The variable.
745 */
746static int expr_var_make_bool(PEXPRVAR pVar)
747{
748 switch (pVar->enmType)
749 {
750 case kExprVar_Num:
751 pVar->uVal.i = !!pVar->uVal.i;
752 break;
753
754 case kExprVar_String:
755 expr_var_make_simple_string(pVar);
756 /* fall thru */
757 case kExprVar_SimpleString:
758 {
759 /*
760 * Try convert it to a number. If that fails, use the
761 * GNU make boolean logic - not empty string means true.
762 */
763 EXPRINT64 iVal;
764 char const *psz = pVar->uVal.psz;
765 while (ISBLANK(*psz))
766 psz++;
767 if ( *psz
768 && expr_string_to_num(NULL, &iVal, psz, 1 /* fQuiet */) >= kExprRet_Ok)
769 expr_var_assign_bool(pVar, iVal != 0);
770 else
771 expr_var_assign_bool(pVar, *psz != '\0');
772 break;
773 }
774
775 case kExprVar_QuotedString:
776 expr_var_make_simple_string(pVar);
777 /* fall thru */
778 case kExprVar_QuotedSimpleString:
779 /*
780 * Use GNU make boolean logic (not empty string means true).
781 * No stripping here, the string is quoted.
782 */
783 expr_var_assign_bool(pVar, *pVar->uVal.psz != '\0');
784 break;
785
786 default:
787 assert(0);
788 break;
789 }
790
791 return pVar->uVal.i;
792}
793
794
795/**
796 * Pops a varable off the stack and deletes it.
797 * @param pThis The evaluator instance.
798 */
799static void expr_pop_and_delete_var(PEXPR pThis)
800{
801 expr_var_delete(&pThis->aVars[pThis->iVar]);
802 pThis->iVar--;
803}
804
805
806
807/**
808 * Tries to make the variables the same type.
809 *
810 * This will not convert numbers to strings, unless one of them
811 * is a quoted string.
812 *
813 * this will try convert both to numbers if neither is quoted. Both
814 * conversions will have to suceed for this to be commited.
815 *
816 * All strings will be simplified.
817 *
818 * @returns status code. Done complaining on failure.
819 *
820 * @param pThis The evaluator instance.
821 * @param pVar1 The first variable.
822 * @param pVar2 The second variable.
823 */
824static EXPRRET expr_var_unify_types(PEXPR pThis, PEXPRVAR pVar1, PEXPRVAR pVar2, const char *pszOp)
825{
826 /*
827 * Try make the variables the same type before comparing.
828 */
829 if ( !expr_var_was_quoted(pVar1)
830 && !expr_var_was_quoted(pVar2))
831 {
832 if ( expr_var_is_string(pVar1)
833 || expr_var_is_string(pVar2))
834 {
835 if (!expr_var_is_string(pVar1))
836 expr_var_try_make_num(pVar2);
837 else if (!expr_var_is_string(pVar2))
838 expr_var_try_make_num(pVar1);
839 else
840 {
841 /*
842 * Both are strings, simplify them then see if both can be made into numbers.
843 */
844 EXPRINT64 iVar1;
845 EXPRINT64 iVar2;
846
847 expr_var_make_simple_string(pVar1);
848 expr_var_make_simple_string(pVar2);
849
850 if ( expr_string_to_num(NULL, &iVar1, pVar1->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok
851 && expr_string_to_num(NULL, &iVar2, pVar2->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok)
852 {
853 expr_var_assign_num(pVar1, iVar1);
854 expr_var_assign_num(pVar2, iVar2);
855 }
856 }
857 }
858 }
859 else
860 {
861 expr_var_make_simple_string(pVar1);
862 expr_var_make_simple_string(pVar2);
863 }
864
865 /*
866 * Complain if they aren't the same type now.
867 */
868 if (expr_var_is_string(pVar1) != expr_var_is_string(pVar2))
869 {
870 expr_error(pThis, "Unable to unify types for \"%s\"", pszOp);
871 return kExprRet_Error;
872 }
873 return kExprRet_Ok;
874}
875
876
877/**
878 * Is variable defined, unary.
879 *
880 * @returns Status code.
881 * @param pThis The instance.
882 */
883static EXPRRET expr_op_defined(PEXPR pThis)
884{
885 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
886 struct variable *pMakeVar;
887
888 expr_var_make_simple_string(pVar);
889 pMakeVar = lookup_variable(pVar->uVal.psz, strlen(pVar->uVal.psz));
890 expr_var_assign_bool(pVar, pMakeVar && *pMakeVar->value != '\0');
891
892 return kExprRet_Ok;
893}
894
895
896/**
897 * Does file(/dir/whatever) exist, unary.
898 *
899 * @returns Status code.
900 * @param pThis The instance.
901 */
902static EXPRRET expr_op_exists(PEXPR pThis)
903{
904 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
905 struct stat st;
906
907 expr_var_make_simple_string(pVar);
908 expr_var_assign_bool(pVar, stat(pVar->uVal.psz, &st) == 0);
909
910 return kExprRet_Ok;
911}
912
913
914/**
915 * Is target defined, unary.
916 *
917 * @returns Status code.
918 * @param pThis The instance.
919 */
920static EXPRRET expr_op_target(PEXPR pThis)
921{
922 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
923 struct file *pFile = NULL;
924
925 /*
926 * Because of secondary target expansion, lookup the unexpanded
927 * name first.
928 */
929#ifdef CONFIG_WITH_2ND_TARGET_EXPANSION
930 if ( pVar->enmType == kExprVar_String
931 || pVar->enmType == kExprVar_QuotedString)
932 {
933 pFile = lookup_file(pVar->uVal.psz);
934 if ( pFile
935 && !pFile->need_2nd_target_expansion)
936 pFile = NULL;
937 }
938 if (!pFile)
939#endif
940 {
941 expr_var_make_simple_string(pVar);
942 pFile = lookup_file(pVar->uVal.psz);
943 }
944
945 /*
946 * Always inspect the head of a multiple target rule
947 * and look for a file with commands.
948 */
949#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET
950 if (pFile && pFile->multi_head)
951 pFile = pFile->multi_head;
952#endif
953
954 while (pFile && !pFile->cmds)
955 pFile = pFile->prev;
956
957 expr_var_assign_bool(pVar, pFile != NULL && pFile->is_target);
958
959 return kExprRet_Ok;
960}
961
962
963/**
964 * Convert to boolean.
965 *
966 * @returns Status code.
967 * @param pThis The instance.
968 */
969static EXPRRET expr_op_bool(PEXPR pThis)
970{
971 expr_var_make_bool(&pThis->aVars[pThis->iVar]);
972 return kExprRet_Ok;
973}
974
975
976/**
977 * Convert to number, works on quoted strings too.
978 *
979 * @returns Status code.
980 * @param pThis The instance.
981 */
982static EXPRRET expr_op_num(PEXPR pThis)
983{
984 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
985
986 /* unquote the string */
987 if (pVar->enmType == kExprVar_QuotedSimpleString)
988 pVar->enmType = kExprVar_SimpleString;
989 else if (pVar->enmType == kExprVar_QuotedString)
990 pVar->enmType = kExprVar_String;
991
992 return expr_var_make_num(pThis, pVar);
993}
994
995
996/**
997 * Convert to string (simplified and quoted)
998 *
999 * @returns Status code.
1000 * @param pThis The instance.
1001 */
1002static EXPRRET expr_op_str(PEXPR pThis)
1003{
1004 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1005
1006 expr_var_make_simple_string(pVar);
1007 pVar->enmType = kExprVar_QuotedSimpleString;
1008
1009 return kExprRet_Ok;
1010}
1011
1012
1013/**
1014 * Pluss (dummy / make_integer)
1015 *
1016 * @returns Status code.
1017 * @param pThis The instance.
1018 */
1019static EXPRRET expr_op_pluss(PEXPR pThis)
1020{
1021 return expr_var_make_num(pThis, &pThis->aVars[pThis->iVar]);
1022}
1023
1024
1025/**
1026 * Minus (negate)
1027 *
1028 * @returns Status code.
1029 * @param pThis The instance.
1030 */
1031static EXPRRET expr_op_minus(PEXPR pThis)
1032{
1033 EXPRRET rc;
1034 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1035
1036 rc = expr_var_make_num(pThis, pVar);
1037 if (rc >= kExprRet_Ok)
1038 pVar->uVal.i = -pVar->uVal.i;
1039
1040 return rc;
1041}
1042
1043
1044
1045/**
1046 * Bitwise NOT.
1047 *
1048 * @returns Status code.
1049 * @param pThis The instance.
1050 */
1051static EXPRRET expr_op_bitwise_not(PEXPR pThis)
1052{
1053 EXPRRET rc;
1054 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1055
1056 rc = expr_var_make_num(pThis, pVar);
1057 if (rc >= kExprRet_Ok)
1058 pVar->uVal.i = ~pVar->uVal.i;
1059
1060 return rc;
1061}
1062
1063
1064/**
1065 * Logical NOT.
1066 *
1067 * @returns Status code.
1068 * @param pThis The instance.
1069 */
1070static EXPRRET expr_op_logical_not(PEXPR pThis)
1071{
1072 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1073
1074 expr_var_make_bool(pVar);
1075 pVar->uVal.i = !pVar->uVal.i;
1076
1077 return kExprRet_Ok;
1078}
1079
1080
1081/**
1082 * Multiplication.
1083 *
1084 * @returns Status code.
1085 * @param pThis The instance.
1086 */
1087static EXPRRET expr_op_multiply(PEXPR pThis)
1088{
1089 EXPRRET rc = kExprRet_Ok;
1090 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1091 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1092
1093 rc = expr_var_make_num(pThis, pVar1);
1094 if (rc >= kExprRet_Ok)
1095 {
1096 rc = expr_var_make_num(pThis, pVar2);
1097 if (rc >= kExprRet_Ok)
1098 pVar1->uVal.i *= pVar2->uVal.i;
1099 }
1100
1101 expr_pop_and_delete_var(pThis);
1102 return rc;
1103}
1104
1105
1106
1107/**
1108 * Division.
1109 *
1110 * @returns Status code.
1111 * @param pThis The instance.
1112 */
1113static EXPRRET expr_op_divide(PEXPR pThis)
1114{
1115 EXPRRET rc = kExprRet_Ok;
1116 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1117 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1118
1119 rc = expr_var_make_num(pThis, pVar1);
1120 if (rc >= kExprRet_Ok)
1121 {
1122 rc = expr_var_make_num(pThis, pVar2);
1123 if (rc >= kExprRet_Ok)
1124 pVar1->uVal.i /= pVar2->uVal.i;
1125 }
1126
1127 expr_pop_and_delete_var(pThis);
1128 return rc;
1129}
1130
1131
1132
1133/**
1134 * Modulus.
1135 *
1136 * @returns Status code.
1137 * @param pThis The instance.
1138 */
1139static EXPRRET expr_op_modulus(PEXPR pThis)
1140{
1141 EXPRRET rc = kExprRet_Ok;
1142 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1143 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1144
1145 rc = expr_var_make_num(pThis, pVar1);
1146 if (rc >= kExprRet_Ok)
1147 {
1148 rc = expr_var_make_num(pThis, pVar2);
1149 if (rc >= kExprRet_Ok)
1150 pVar1->uVal.i %= pVar2->uVal.i;
1151 }
1152
1153 expr_pop_and_delete_var(pThis);
1154 return rc;
1155}
1156
1157
1158
1159/**
1160 * Addition (numeric).
1161 *
1162 * @returns Status code.
1163 * @param pThis The instance.
1164 */
1165static EXPRRET expr_op_add(PEXPR pThis)
1166{
1167 EXPRRET rc = kExprRet_Ok;
1168 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1169 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1170
1171 rc = expr_var_make_num(pThis, pVar1);
1172 if (rc >= kExprRet_Ok)
1173 {
1174 rc = expr_var_make_num(pThis, pVar2);
1175 if (rc >= kExprRet_Ok)
1176 pVar1->uVal.i += pVar2->uVal.i;
1177 }
1178
1179 expr_pop_and_delete_var(pThis);
1180 return rc;
1181}
1182
1183
1184/**
1185 * Subtract (numeric).
1186 *
1187 * @returns Status code.
1188 * @param pThis The instance.
1189 */
1190static EXPRRET expr_op_sub(PEXPR pThis)
1191{
1192 EXPRRET rc = kExprRet_Ok;
1193 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1194 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1195
1196 rc = expr_var_make_num(pThis, pVar1);
1197 if (rc >= kExprRet_Ok)
1198 {
1199 rc = expr_var_make_num(pThis, pVar2);
1200 if (rc >= kExprRet_Ok)
1201 pVar1->uVal.i -= pVar2->uVal.i;
1202 }
1203
1204 expr_pop_and_delete_var(pThis);
1205 return rc;
1206}
1207
1208/**
1209 * Bitwise left shift.
1210 *
1211 * @returns Status code.
1212 * @param pThis The instance.
1213 */
1214static EXPRRET expr_op_shift_left(PEXPR pThis)
1215{
1216 EXPRRET rc = kExprRet_Ok;
1217 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1218 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1219
1220 rc = expr_var_make_num(pThis, pVar1);
1221 if (rc >= kExprRet_Ok)
1222 {
1223 rc = expr_var_make_num(pThis, pVar2);
1224 if (rc >= kExprRet_Ok)
1225 pVar1->uVal.i <<= pVar2->uVal.i;
1226 }
1227
1228 expr_pop_and_delete_var(pThis);
1229 return rc;
1230}
1231
1232
1233/**
1234 * Bitwise right shift.
1235 *
1236 * @returns Status code.
1237 * @param pThis The instance.
1238 */
1239static EXPRRET expr_op_shift_right(PEXPR pThis)
1240{
1241 EXPRRET rc = kExprRet_Ok;
1242 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1243 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1244
1245 rc = expr_var_make_num(pThis, pVar1);
1246 if (rc >= kExprRet_Ok)
1247 {
1248 rc = expr_var_make_num(pThis, pVar2);
1249 if (rc >= kExprRet_Ok)
1250 pVar1->uVal.i >>= pVar2->uVal.i;
1251 }
1252
1253 expr_pop_and_delete_var(pThis);
1254 return rc;
1255}
1256
1257
1258/**
1259 * Less than or equal, version string.
1260 *
1261 * @returns Status code.
1262 * @param pThis The instance.
1263 */
1264static EXPRRET expr_op_ver_less_or_equal_than(PEXPR pThis)
1265{
1266 EXPRRET rc = kExprRet_Ok;
1267 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1268 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1269
1270 rc = expr_var_unify_types(pThis, pVar1, pVar2, "vle");
1271 if (rc >= kExprRet_Ok)
1272 {
1273 if (!expr_var_is_string(pVar1))
1274 expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i);
1275 else
1276 expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) <= 0);
1277 }
1278
1279 expr_pop_and_delete_var(pThis);
1280 return rc;
1281}
1282
1283
1284/**
1285 * Less than or equal.
1286 *
1287 * @returns Status code.
1288 * @param pThis The instance.
1289 */
1290static EXPRRET expr_op_less_or_equal_than(PEXPR pThis)
1291{
1292 EXPRRET rc = kExprRet_Ok;
1293 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1294 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1295
1296 rc = expr_var_unify_types(pThis, pVar1, pVar2, "<=");
1297 if (rc >= kExprRet_Ok)
1298 {
1299 if (!expr_var_is_string(pVar1))
1300 expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i);
1301 else
1302 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) <= 0);
1303 }
1304
1305 expr_pop_and_delete_var(pThis);
1306 return rc;
1307}
1308
1309
1310/**
1311 * Less than, version string.
1312 *
1313 * @returns Status code.
1314 * @param pThis The instance.
1315 */
1316static EXPRRET expr_op_ver_less_than(PEXPR pThis)
1317{
1318 EXPRRET rc = kExprRet_Ok;
1319 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1320 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1321
1322 rc = expr_var_unify_types(pThis, pVar1, pVar2, "vlt");
1323 if (rc >= kExprRet_Ok)
1324 {
1325 if (!expr_var_is_string(pVar1))
1326 expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i);
1327 else
1328 expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) < 0);
1329 }
1330
1331 expr_pop_and_delete_var(pThis);
1332 return rc;
1333}
1334
1335
1336/**
1337 * Less than.
1338 *
1339 * @returns Status code.
1340 * @param pThis The instance.
1341 */
1342static EXPRRET expr_op_less_than(PEXPR pThis)
1343{
1344 EXPRRET rc = kExprRet_Ok;
1345 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1346 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1347
1348 rc = expr_var_unify_types(pThis, pVar1, pVar2, "<");
1349 if (rc >= kExprRet_Ok)
1350 {
1351 if (!expr_var_is_string(pVar1))
1352 expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i);
1353 else
1354 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) < 0);
1355 }
1356
1357 expr_pop_and_delete_var(pThis);
1358 return rc;
1359}
1360
1361
1362/**
1363 * Greater or equal than, version string.
1364 *
1365 * @returns Status code.
1366 * @param pThis The instance.
1367 */
1368static EXPRRET expr_op_ver_greater_or_equal_than(PEXPR pThis)
1369{
1370 EXPRRET rc = kExprRet_Ok;
1371 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1372 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1373
1374 rc = expr_var_unify_types(pThis, pVar1, pVar2, "vge");
1375 if (rc >= kExprRet_Ok)
1376 {
1377 if (!expr_var_is_string(pVar1))
1378 expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i);
1379 else
1380 expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) >= 0);
1381 }
1382
1383 expr_pop_and_delete_var(pThis);
1384 return rc;
1385}
1386
1387
1388/**
1389 * Greater or equal than.
1390 *
1391 * @returns Status code.
1392 * @param pThis The instance.
1393 */
1394static EXPRRET expr_op_greater_or_equal_than(PEXPR pThis)
1395{
1396 EXPRRET rc = kExprRet_Ok;
1397 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1398 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1399
1400 rc = expr_var_unify_types(pThis, pVar1, pVar2, ">=");
1401 if (rc >= kExprRet_Ok)
1402 {
1403 if (!expr_var_is_string(pVar1))
1404 expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i);
1405 else
1406 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) >= 0);
1407 }
1408
1409 expr_pop_and_delete_var(pThis);
1410 return rc;
1411}
1412
1413
1414/**
1415 * Greater than, version string.
1416 *
1417 * @returns Status code.
1418 * @param pThis The instance.
1419 */
1420static EXPRRET expr_op_ver_greater_than(PEXPR pThis)
1421{
1422 EXPRRET rc = kExprRet_Ok;
1423 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1424 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1425
1426 rc = expr_var_unify_types(pThis, pVar1, pVar2, "vgt");
1427 if (rc >= kExprRet_Ok)
1428 {
1429 if (!expr_var_is_string(pVar1))
1430 expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i);
1431 else
1432 expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) > 0);
1433 }
1434
1435 expr_pop_and_delete_var(pThis);
1436 return rc;
1437}
1438
1439
1440/**
1441 * Greater than.
1442 *
1443 * @returns Status code.
1444 * @param pThis The instance.
1445 */
1446static EXPRRET expr_op_greater_than(PEXPR pThis)
1447{
1448 EXPRRET rc = kExprRet_Ok;
1449 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1450 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1451
1452 rc = expr_var_unify_types(pThis, pVar1, pVar2, ">");
1453 if (rc >= kExprRet_Ok)
1454 {
1455 if (!expr_var_is_string(pVar1))
1456 expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i);
1457 else
1458 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) > 0);
1459 }
1460
1461 expr_pop_and_delete_var(pThis);
1462 return rc;
1463}
1464
1465
1466/**
1467 * Equal, version strings.
1468 *
1469 * @returns Status code.
1470 * @param pThis The instance.
1471 */
1472static EXPRRET expr_op_ver_equal(PEXPR pThis)
1473{
1474 EXPRRET rc = kExprRet_Ok;
1475 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1476 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1477 int const fIsString1 = expr_var_is_string(pVar1);
1478
1479 /*
1480 * The same type?
1481 */
1482 if (fIsString1 == expr_var_is_string(pVar2))
1483 {
1484 if (!fIsString1)
1485 /* numbers are simple */
1486 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1487 else
1488 {
1489 /* try a normal string compare. */
1490 expr_var_make_simple_string(pVar1);
1491 expr_var_make_simple_string(pVar2);
1492 if (!version_compare(pVar1->uVal.psz, pVar2->uVal.psz))
1493 expr_var_assign_bool(pVar1, 1);
1494 /* try convert and compare as number instead. */
1495 else if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok
1496 && expr_var_try_make_num(pVar2) >= kExprRet_Ok)
1497 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1498 /* ok, they really aren't equal. */
1499 else
1500 expr_var_assign_bool(pVar1, 0);
1501 }
1502 }
1503 else
1504 {
1505 /*
1506 * If the type differs, there are now two options:
1507 * 1. Try convert the string to a valid number and compare the numbers.
1508 * 2. Convert the non-string to a number and compare the strings.
1509 */
1510 if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok
1511 && expr_var_try_make_num(pVar2) >= kExprRet_Ok)
1512 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1513 else
1514 {
1515 expr_var_make_simple_string(pVar1);
1516 expr_var_make_simple_string(pVar2);
1517 expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) == 0);
1518 }
1519 }
1520
1521 expr_pop_and_delete_var(pThis);
1522 return rc;
1523}
1524
1525
1526/**
1527 * Not equal, version string.
1528 *
1529 * @returns Status code.
1530 * @param pThis The instance.
1531 */
1532static EXPRRET expr_op_ver_not_equal(PEXPR pThis)
1533{
1534 EXPRRET rc = expr_op_ver_equal(pThis);
1535 if (rc >= kExprRet_Ok)
1536 rc = expr_op_logical_not(pThis);
1537 return rc;
1538}
1539
1540
1541/**
1542 * Equal.
1543 *
1544 * @returns Status code.
1545 * @param pThis The instance.
1546 */
1547static EXPRRET expr_op_equal(PEXPR pThis)
1548{
1549 EXPRRET rc = kExprRet_Ok;
1550 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1551 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1552 int const fIsString1 = expr_var_is_string(pVar1);
1553
1554 /*
1555 * The same type?
1556 */
1557 if (fIsString1 == expr_var_is_string(pVar2))
1558 {
1559 if (!fIsString1)
1560 /* numbers are simple */
1561 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1562 else
1563 {
1564 /* try a normal string compare. */
1565 expr_var_make_simple_string(pVar1);
1566 expr_var_make_simple_string(pVar2);
1567 if (!strcmp(pVar1->uVal.psz, pVar2->uVal.psz))
1568 expr_var_assign_bool(pVar1, 1);
1569 /* try convert and compare as number instead. */
1570 else if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok
1571 && expr_var_try_make_num(pVar2) >= kExprRet_Ok)
1572 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1573 /* ok, they really aren't equal. */
1574 else
1575 expr_var_assign_bool(pVar1, 0);
1576 }
1577 }
1578 else
1579 {
1580 /*
1581 * If the type differs, there are now two options:
1582 * 1. Convert the string to a valid number and compare the numbers.
1583 * 2. Convert an empty string to a 'false' boolean value and compare
1584 * numerically. This one is a bit questionable, so we don't try this.
1585 */
1586 if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok
1587 && expr_var_try_make_num(pVar2) >= kExprRet_Ok)
1588 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1589 else
1590 {
1591 expr_error(pThis, "Cannot compare strings and numbers");
1592 rc = kExprRet_Error;
1593 }
1594 }
1595
1596 expr_pop_and_delete_var(pThis);
1597 return rc;
1598}
1599
1600
1601/**
1602 * Not equal.
1603 *
1604 * @returns Status code.
1605 * @param pThis The instance.
1606 */
1607static EXPRRET expr_op_not_equal(PEXPR pThis)
1608{
1609 EXPRRET rc = expr_op_equal(pThis);
1610 if (rc >= kExprRet_Ok)
1611 rc = expr_op_logical_not(pThis);
1612 return rc;
1613}
1614
1615
1616/**
1617 * Bitwise AND.
1618 *
1619 * @returns Status code.
1620 * @param pThis The instance.
1621 */
1622static EXPRRET expr_op_bitwise_and(PEXPR pThis)
1623{
1624 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1625 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1626 EXPRRET rc;
1627
1628 rc = expr_var_make_num(pThis, pVar1);
1629 if (rc >= kExprRet_Ok)
1630 {
1631 rc = expr_var_make_num(pThis, pVar2);
1632 if (rc >= kExprRet_Ok)
1633 pVar1->uVal.i &= pVar2->uVal.i;
1634 }
1635
1636 expr_pop_and_delete_var(pThis);
1637 return kExprRet_Ok;
1638}
1639
1640
1641/**
1642 * Bitwise XOR.
1643 *
1644 * @returns Status code.
1645 * @param pThis The instance.
1646 */
1647static EXPRRET expr_op_bitwise_xor(PEXPR pThis)
1648{
1649 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1650 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1651 EXPRRET rc;
1652
1653 rc = expr_var_make_num(pThis, pVar1);
1654 if (rc >= kExprRet_Ok)
1655 {
1656 rc = expr_var_make_num(pThis, pVar2);
1657 if (rc >= kExprRet_Ok)
1658 pVar1->uVal.i ^= pVar2->uVal.i;
1659 }
1660
1661 expr_pop_and_delete_var(pThis);
1662 return kExprRet_Ok;
1663}
1664
1665
1666/**
1667 * Bitwise OR.
1668 *
1669 * @returns Status code.
1670 * @param pThis The instance.
1671 */
1672static EXPRRET expr_op_bitwise_or(PEXPR pThis)
1673{
1674 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1675 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1676 EXPRRET rc;
1677
1678 rc = expr_var_make_num(pThis, pVar1);
1679 if (rc >= kExprRet_Ok)
1680 {
1681 rc = expr_var_make_num(pThis, pVar2);
1682 if (rc >= kExprRet_Ok)
1683 pVar1->uVal.i |= pVar2->uVal.i;
1684 }
1685
1686 expr_pop_and_delete_var(pThis);
1687 return kExprRet_Ok;
1688}
1689
1690
1691/**
1692 * Logical AND.
1693 *
1694 * @returns Status code.
1695 * @param pThis The instance.
1696 */
1697static EXPRRET expr_op_logical_and(PEXPR pThis)
1698{
1699 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1700 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1701
1702 if ( expr_var_make_bool(pVar1)
1703 && expr_var_make_bool(pVar2))
1704 expr_var_assign_bool(pVar1, 1);
1705 else
1706 expr_var_assign_bool(pVar1, 0);
1707
1708 expr_pop_and_delete_var(pThis);
1709 return kExprRet_Ok;
1710}
1711
1712
1713/**
1714 * Logical OR.
1715 *
1716 * @returns Status code.
1717 * @param pThis The instance.
1718 */
1719static EXPRRET expr_op_logical_or(PEXPR pThis)
1720{
1721 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1722 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1723
1724 if ( expr_var_make_bool(pVar1)
1725 || expr_var_make_bool(pVar2))
1726 expr_var_assign_bool(pVar1, 1);
1727 else
1728 expr_var_assign_bool(pVar1, 0);
1729
1730 expr_pop_and_delete_var(pThis);
1731 return kExprRet_Ok;
1732}
1733
1734
1735/**
1736 * Left parenthesis.
1737 *
1738 * @returns Status code.
1739 * @param pThis The instance.
1740 */
1741static EXPRRET expr_op_left_parenthesis(PEXPR pThis)
1742{
1743 /*
1744 * There should be a right parenthesis operator lined up for us now,
1745 * eat it. If not found there is an inbalance.
1746 */
1747 EXPRRET rc = expr_get_binary_or_eoe_or_rparen(pThis);
1748 if ( rc == kExprRet_Operator
1749 && pThis->apOps[pThis->iOp]->szOp[0] == ')')
1750 {
1751 /* pop it and get another one which we can leave pending. */
1752 pThis->iOp--;
1753 rc = expr_get_binary_or_eoe_or_rparen(pThis);
1754 if (rc >= kExprRet_Ok)
1755 expr_unget_op(pThis);
1756 }
1757 else
1758 {
1759 expr_error(pThis, "Missing ')'");
1760 rc = kExprRet_Error;
1761 }
1762
1763 return rc;
1764}
1765
1766
1767/**
1768 * Right parenthesis, dummy that's never actually called.
1769 *
1770 * @returns Status code.
1771 * @param pThis The instance.
1772 */
1773static EXPRRET expr_op_right_parenthesis(PEXPR pThis)
1774{
1775 assert(0);
1776 (void)pThis;
1777 return kExprRet_Ok;
1778}
1779
1780
1781
1782
1783
1784/**
1785 * The operator table.
1786 *
1787 * This table is NOT ordered by precedence, but for linear search
1788 * allowing for first match to return the correct operator. This
1789 * means that || must come before |, or else | will match all.
1790 */
1791static const EXPROP g_aExprOps[] =
1792{
1793#define EXPR_OP(szOp, iPrecedence, cArgs, pfn) { szOp, sizeof(szOp) - 1, '\0', iPrecedence, cArgs, pfn }
1794 /* Name, iPrecedence, cArgs, pfn */
1795 EXPR_OP("defined", 90, 1, expr_op_defined),
1796 EXPR_OP("exists", 90, 1, expr_op_exists),
1797 EXPR_OP("target", 90, 1, expr_op_target),
1798 EXPR_OP("bool", 90, 1, expr_op_bool),
1799 EXPR_OP("num", 90, 1, expr_op_num),
1800 EXPR_OP("str", 90, 1, expr_op_str),
1801 EXPR_OP("+", 80, 1, expr_op_pluss),
1802 EXPR_OP("-", 80, 1, expr_op_minus),
1803 EXPR_OP("~", 80, 1, expr_op_bitwise_not),
1804 EXPR_OP("*", 75, 2, expr_op_multiply),
1805 EXPR_OP("/", 75, 2, expr_op_divide),
1806 EXPR_OP("%", 75, 2, expr_op_modulus),
1807 EXPR_OP("+", 70, 2, expr_op_add),
1808 EXPR_OP("-", 70, 2, expr_op_sub),
1809 EXPR_OP("<<", 65, 2, expr_op_shift_left),
1810 EXPR_OP(">>", 65, 2, expr_op_shift_right),
1811 EXPR_OP("<=", 60, 2, expr_op_less_or_equal_than),
1812 EXPR_OP("<", 60, 2, expr_op_less_than),
1813 EXPR_OP(">=", 60, 2, expr_op_greater_or_equal_than),
1814 EXPR_OP(">", 60, 2, expr_op_greater_than),
1815 EXPR_OP("vle", 60, 2, expr_op_ver_less_or_equal_than),
1816 EXPR_OP("vlt", 60, 2, expr_op_ver_less_than),
1817 EXPR_OP("vge", 60, 2, expr_op_ver_greater_or_equal_than),
1818 EXPR_OP("vgt", 60, 2, expr_op_ver_greater_than),
1819 EXPR_OP("==", 55, 2, expr_op_equal),
1820 EXPR_OP("veq", 55, 2, expr_op_ver_equal),
1821 EXPR_OP("!=", 55, 2, expr_op_not_equal),
1822 EXPR_OP("vne", 55, 2, expr_op_ver_not_equal),
1823 EXPR_OP("!", 80, 1, expr_op_logical_not),
1824 EXPR_OP("^", 45, 2, expr_op_bitwise_xor),
1825 EXPR_OP("&&", 35, 2, expr_op_logical_and),
1826 EXPR_OP("&", 50, 2, expr_op_bitwise_and),
1827 EXPR_OP("||", 30, 2, expr_op_logical_or),
1828 EXPR_OP("|", 40, 2, expr_op_bitwise_or),
1829 { "(", 1, ')', 10, 1, expr_op_left_parenthesis },
1830 { ")", 1, '(', 10, 0, expr_op_right_parenthesis },
1831 /* { "?", 1, ':', 5, 2, expr_op_question },
1832 { ":", 1, '?', 5, 2, expr_op_colon }, -- too weird for now. */
1833#undef EXPR_OP
1834};
1835
1836/** Dummy end of expression fake. */
1837static const EXPROP g_ExprEndOfExpOp =
1838{
1839 "", 0, '\0', 0, 0, NULL
1840};
1841
1842
1843/**
1844 * Initializes the opcode character map if necessary.
1845 */
1846static void expr_map_init(void)
1847{
1848 unsigned i;
1849 if (g_fExprInitializedMap)
1850 return;
1851
1852 /*
1853 * Initialize it.
1854 */
1855 memset(&g_auchOpStartCharMap, 0, sizeof(g_auchOpStartCharMap));
1856 for (i = 0; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++)
1857 {
1858 unsigned int ch = (unsigned int)g_aExprOps[i].szOp[0];
1859 if (!g_auchOpStartCharMap[ch])
1860 {
1861 g_auchOpStartCharMap[ch] = (i << 2) | 1;
1862 if (!isalpha(ch))
1863 g_auchOpStartCharMap[ch] |= 2; /* Need no clear separation from operands. */
1864 }
1865 }
1866
1867 /* whitespace (assumes C-like locale because I'm lazy): */
1868#define SET_WHITESPACE(a_ch) do { \
1869 assert(g_auchOpStartCharMap[(unsigned char)(a_ch)] == 0); \
1870 g_auchOpStartCharMap[(unsigned char)(a_ch)] |= 2; \
1871 } while (0)
1872 SET_WHITESPACE(' ');
1873 SET_WHITESPACE('\t');
1874 SET_WHITESPACE('\n');
1875 SET_WHITESPACE('\r');
1876 SET_WHITESPACE('\v');
1877 SET_WHITESPACE('\f');
1878
1879 g_fExprInitializedMap = 1;
1880}
1881
1882
1883/**
1884 * Looks up a character in the map.
1885 *
1886 * @returns the value for that char, see g_auchOpStartCharMap for details.
1887 * @param ch The character.
1888 */
1889static unsigned char expr_map_get(char ch)
1890{
1891 return g_auchOpStartCharMap[(unsigned int)ch];
1892}
1893
1894
1895/**
1896 * Searches the operator table given a potential operator start char.
1897 *
1898 * @returns Pointer to the matching operator. NULL if not found.
1899 * @param psz Pointer to what can be an operator.
1900 * @param uchVal The expr_map_get value.
1901 * @param fUnary Whether it must be an unary operator or not.
1902 */
1903static PCEXPROP expr_lookup_op(char const *psz, unsigned char uchVal, int fUnary)
1904{
1905 char ch = *psz;
1906 unsigned i;
1907 assert((uchVal & 2) == (isalpha(ch) ? 0 : 2));
1908
1909 for (i = uchVal >> 2; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++)
1910 {
1911 /* compare the string... */
1912 if (g_aExprOps[i].szOp[0] != ch)
1913 continue;
1914 switch (g_aExprOps[i].cchOp)
1915 {
1916 case 1:
1917 break;
1918 case 2:
1919 if (g_aExprOps[i].szOp[1] != psz[1])
1920 continue;
1921 break;
1922 default:
1923 if (strncmp(&g_aExprOps[i].szOp[1], psz + 1, g_aExprOps[i].cchOp - 1))
1924 continue;
1925 break;
1926 }
1927
1928 /* ... and the operator type. */
1929 if (fUnary == (g_aExprOps[i].cArgs == 1))
1930 {
1931 /* Check if we've got the needed operand separation: */
1932 if ( (uchVal & 2)
1933 || EXPR_IS_OP_SEPARATOR(psz[g_aExprOps[i].cchOp]))
1934 {
1935 /* got a match! */
1936 return &g_aExprOps[i];
1937 }
1938 }
1939 }
1940
1941 return NULL;
1942}
1943
1944
1945/**
1946 * Ungets a binary operator.
1947 *
1948 * The operator is poped from the stack and put in the pending position.
1949 *
1950 * @param pThis The evaluator instance.
1951 */
1952static void expr_unget_op(PEXPR pThis)
1953{
1954 assert(pThis->pPending == NULL);
1955 assert(pThis->iOp >= 0);
1956
1957 pThis->pPending = pThis->apOps[pThis->iOp];
1958 pThis->apOps[pThis->iOp] = NULL;
1959 pThis->iOp--;
1960}
1961
1962
1963
1964/**
1965 * Get the next token, it should be a binary operator, or the end of
1966 * the expression, or a right parenthesis.
1967 *
1968 * The operator is pushed onto the stack and the status code indicates
1969 * which of the two we found.
1970 *
1971 * @returns status code. Will grumble on failure.
1972 * @retval kExprRet_EndOfExpr if we encountered the end of the expression.
1973 * @retval kExprRet_Operator if we encountered a binary operator or right
1974 * parenthesis. It's on the operator stack.
1975 *
1976 * @param pThis The evaluator instance.
1977 */
1978static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis)
1979{
1980 /*
1981 * See if there is anything pending first.
1982 */
1983 PCEXPROP pOp = pThis->pPending;
1984 if (pOp)
1985 pThis->pPending = NULL;
1986 else
1987 {
1988 /*
1989 * Eat more of the expression.
1990 */
1991 char const *psz = pThis->psz;
1992
1993 /* spaces */
1994 unsigned char uchVal;
1995 char ch;
1996 while (((uchVal = expr_map_get((ch = *psz))) & 3) == 2)
1997 psz++;
1998
1999 /* see what we've got. */
2000 if (ch)
2001 {
2002 if (uchVal & 1)
2003 pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */);
2004 if (!pOp)
2005 {
2006 expr_error(pThis, "Expected binary operator, found \"%.42s\"...", psz);
2007 return kExprRet_Error;
2008 }
2009 psz += pOp->cchOp;
2010 }
2011 else
2012 pOp = &g_ExprEndOfExpOp;
2013 pThis->psz = psz;
2014 }
2015
2016 /*
2017 * Push it.
2018 */
2019 if (pThis->iOp >= EXPR_MAX_OPERATORS - 1)
2020 {
2021 expr_error(pThis, "Operator stack overflow");
2022 return kExprRet_Error;
2023 }
2024 pThis->apOps[++pThis->iOp] = pOp;
2025
2026 return pOp->iPrecedence
2027 ? kExprRet_Operator
2028 : kExprRet_EndOfExpr;
2029}
2030
2031
2032
2033/**
2034 * Get the next token, it should be an unary operator or an operand.
2035 *
2036 * This will fail if encountering the end of the expression since
2037 * it is implied that there should be something more.
2038 *
2039 * The token is pushed onto the respective stack and the status code
2040 * indicates which it is.
2041 *
2042 * @returns status code. On failure we'll be done bitching already.
2043 * @retval kExprRet_Operator if we encountered an unary operator.
2044 * It's on the operator stack.
2045 * @retval kExprRet_Operand if we encountered an operand operator.
2046 * It's on the operand stack.
2047 *
2048 * @param This The evaluator instance.
2049 */
2050static EXPRRET expr_get_unary_or_operand(PEXPR pThis)
2051{
2052 EXPRRET rc;
2053 unsigned char uchVal;
2054 PCEXPROP pOp;
2055 char const *psz = pThis->psz;
2056 char ch;
2057
2058 /*
2059 * Eat white space and make sure there is something after it.
2060 */
2061 while (((uchVal = expr_map_get((ch = *psz))) & 3) == 2)
2062 psz++;
2063 if (ch == '\0')
2064 {
2065 expr_error(pThis, "Unexpected end of expression");
2066 return kExprRet_Error;
2067 }
2068
2069 /*
2070 * Is it an operator?
2071 */
2072 pOp = NULL;
2073 if (uchVal & 1)
2074 pOp = expr_lookup_op(psz, uchVal, 1 /* fUnary */);
2075 if (pOp)
2076 {
2077 /*
2078 * Push the operator onto the stack.
2079 */
2080 if (pThis->iVar < EXPR_MAX_OPERANDS - 1)
2081 {
2082 pThis->apOps[++pThis->iOp] = pOp;
2083 rc = kExprRet_Operator;
2084 }
2085 else
2086 {
2087 expr_error(pThis, "Operator stack overflow");
2088 rc = kExprRet_Error;
2089 }
2090 psz += pOp->cchOp;
2091 }
2092 else if (pThis->iVar < EXPR_MAX_OPERANDS - 1)
2093 {
2094 /*
2095 * It's an operand. Figure out where it ends and
2096 * push it onto the stack.
2097 */
2098 const char *pszStart;
2099
2100 rc = kExprRet_Ok;
2101 if (ch == '"')
2102 {
2103 pszStart = ++psz;
2104 while ((ch = *psz) != '\0' && ch != '"')
2105 psz++;
2106 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedString);
2107 if (ch != '\0')
2108 psz++;
2109 }
2110 else if (ch == '\'')
2111 {
2112 pszStart = ++psz;
2113 while ((ch = *psz) != '\0' && ch != '\'')
2114 psz++;
2115 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedSimpleString);
2116 if (ch != '\0')
2117 psz++;
2118 }
2119 else
2120 {
2121 char achPars[20];
2122 int iPar = -1;
2123 char chEndPar = '\0';
2124
2125 pszStart = psz;
2126 while ((ch = *psz) != '\0')
2127 {
2128 char ch2;
2129
2130 /* $(adsf) or ${asdf} needs special handling. */
2131 if ( ch == '$'
2132 && ( (ch2 = psz[1]) == '('
2133 || ch2 == '{'))
2134 {
2135 psz++;
2136 if (iPar > (int)(sizeof(achPars) / sizeof(achPars[0])))
2137 {
2138 expr_error(pThis, "Too deep nesting of variable expansions");
2139 rc = kExprRet_Error;
2140 break;
2141 }
2142 achPars[++iPar] = chEndPar = ch2 == '(' ? ')' : '}';
2143 }
2144 else if (ch == chEndPar)
2145 {
2146 iPar--;
2147 chEndPar = iPar >= 0 ? achPars[iPar] : '\0';
2148 }
2149 else if (!chEndPar)
2150 {
2151 uchVal = expr_map_get(ch);
2152 if (uchVal == 0)
2153 { /*likely*/ }
2154 else if ((uchVal & 3) == 2 /*isspace*/)
2155 break;
2156 else if ( (uchVal & 1)
2157 && psz != pszStart /* not at the start */
2158 && ( (uchVal & 2) /* operator without separator needs */
2159 || EXPR_IS_OP_SEPARATOR_NO_SPACE(psz[-1])))
2160 {
2161 pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */);
2162 if (pOp)
2163 break;
2164 }
2165 }
2166
2167 /* next */
2168 psz++;
2169 }
2170
2171 if (rc == kExprRet_Ok)
2172 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_String);
2173 }
2174 }
2175 else
2176 {
2177 expr_error(pThis, "Operand stack overflow");
2178 rc = kExprRet_Error;
2179 }
2180 pThis->psz = psz;
2181
2182 return rc;
2183}
2184
2185
2186/**
2187 * Evaluates the current expression.
2188 *
2189 * @returns status code.
2190 *
2191 * @param pThis The instance.
2192 */
2193static EXPRRET expr_eval(PEXPR pThis)
2194{
2195 EXPRRET rc;
2196 PCEXPROP pOp;
2197
2198 /*
2199 * The main loop.
2200 */
2201 for (;;)
2202 {
2203 /*
2204 * Eat unary operators until we hit an operand.
2205 */
2206 do rc = expr_get_unary_or_operand(pThis);
2207 while (rc == kExprRet_Operator);
2208 if (rc < kExprRet_Ok)
2209 break;
2210
2211 /*
2212 * Look for a binary operator, right parenthesis or end of expression.
2213 */
2214 rc = expr_get_binary_or_eoe_or_rparen(pThis);
2215 if (rc < kExprRet_Ok)
2216 break;
2217 expr_unget_op(pThis);
2218
2219 /*
2220 * Pop operators and apply them.
2221 *
2222 * Parenthesis will be handed via precedence, where the left parenthesis
2223 * will go pop the right one and make another operator pending.
2224 */
2225 while ( pThis->iOp >= 0
2226 && pThis->apOps[pThis->iOp]->iPrecedence >= pThis->pPending->iPrecedence)
2227 {
2228 pOp = pThis->apOps[pThis->iOp--];
2229 assert(pThis->iVar + 1 >= pOp->cArgs);
2230 rc = pOp->pfn(pThis);
2231 if (rc < kExprRet_Ok)
2232 break;
2233 }
2234 if (rc < kExprRet_Ok)
2235 break;
2236
2237 /*
2238 * Get the next binary operator or end of expression.
2239 * There should be no right parenthesis here.
2240 */
2241 rc = expr_get_binary_or_eoe_or_rparen(pThis);
2242 if (rc < kExprRet_Ok)
2243 break;
2244 pOp = pThis->apOps[pThis->iOp];
2245 if (!pOp->iPrecedence)
2246 break; /* end of expression */
2247 if (!pOp->cArgs)
2248 {
2249 expr_error(pThis, "Unexpected \"%s\"", pOp->szOp);
2250 rc = kExprRet_Error;
2251 break;
2252 }
2253 }
2254
2255 return rc;
2256}
2257
2258
2259/**
2260 * Destroys the given instance.
2261 *
2262 * @param pThis The instance to destroy.
2263 */
2264static void expr_destroy(PEXPR pThis)
2265{
2266 while (pThis->iVar >= 0)
2267 {
2268 expr_var_delete(pThis->aVars);
2269 pThis->iVar--;
2270 }
2271 free(pThis);
2272}
2273
2274
2275/**
2276 * Instantiates an expression evaluator.
2277 *
2278 * @returns The instance.
2279 *
2280 * @param pszExpr What to parse.
2281 * This must stick around until expr_destroy.
2282 */
2283static PEXPR expr_create(char const *pszExpr)
2284{
2285 PEXPR pThis = (PEXPR)xmalloc(sizeof(*pThis));
2286 pThis->pszExpr = pszExpr;
2287 pThis->psz = pszExpr;
2288 pThis->pFileLoc = NULL;
2289 pThis->pPending = NULL;
2290 pThis->iVar = -1;
2291 pThis->iOp = -1;
2292
2293 expr_map_init();
2294 return pThis;
2295}
2296
2297
2298/**
2299 * Evaluates the given if expression.
2300 *
2301 * @returns -1, 0 or 1. (GNU make conditional check convention, see read.c.)
2302 * @retval -1 if the expression is invalid.
2303 * @retval 0 if the expression is true
2304 * @retval 1 if the expression is false.
2305 *
2306 * @param line The expression.
2307 * @param flocp The file location, used for errors.
2308 */
2309int expr_eval_if_conditionals(const char *line, const floc *flocp)
2310{
2311 /*
2312 * Instantiate the expression evaluator and let
2313 * it have a go at it.
2314 */
2315 int rc = -1;
2316 PEXPR pExpr = expr_create(line);
2317 pExpr->pFileLoc = flocp;
2318 if (expr_eval(pExpr) >= kExprRet_Ok)
2319 {
2320 /*
2321 * Convert the result (on top of the stack) to boolean and
2322 * set our return value accordingly.
2323 */
2324 if (expr_var_make_bool(&pExpr->aVars[0]))
2325 rc = 0;
2326 else
2327 rc = 1;
2328 }
2329 expr_destroy(pExpr);
2330
2331 return rc;
2332}
2333
2334
2335/**
2336 * Evaluates the given expression and returns the result as a string.
2337 *
2338 * @returns variable buffer position.
2339 *
2340 * @param o The current variable buffer position.
2341 * @param expr The expression.
2342 */
2343char *expr_eval_to_string(char *o, const char *expr)
2344{
2345 /*
2346 * Instantiate the expression evaluator and let
2347 * it have a go at it.
2348 */
2349 PEXPR pExpr = expr_create(expr);
2350 if (expr_eval(pExpr) >= kExprRet_Ok)
2351 {
2352 /*
2353 * Convert the result (on top of the stack) to a string
2354 * and copy it out the variable buffer.
2355 */
2356 PEXPRVAR pVar = &pExpr->aVars[0];
2357 expr_var_make_simple_string(pVar);
2358 o = variable_buffer_output(o, pVar->uVal.psz, strlen(pVar->uVal.psz));
2359 }
2360 else
2361 o = variable_buffer_output(o, "<expression evaluation failed>", sizeof("<expression evaluation failed>") - 1);
2362 expr_destroy(pExpr);
2363
2364 return o;
2365}
2366
2367
2368#endif /* CONFIG_WITH_IF_CONDITIONALS */
2369
Note: See TracBrowser for help on using the repository browser.