VirtualBox

source: kBuild/trunk/src/kmk/expreval.c

Last change on this file was 3544, checked in by bird, 3 years ago

kmk/expreval: Corrected expr_map_get cast. Corrected base determination in expr_string_to_num.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.0 KB
Line 
1#ifdef CONFIG_WITH_IF_CONDITIONALS
2/* $Id: expreval.c 3544 2022-01-29 02:22:03Z bird $ */
3/** @file
4 * expreval - Expressions evaluator, C / BSD make / nmake style.
5 */
6
7/*
8 * Copyright (c) 2008-2010 knut st. osmundsen <[email protected]>
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')
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 * Performs a strlen() on the simplified/converted string argument.
998 *
999 * @returns Status code.
1000 * @param pThis The instance.
1001 */
1002static EXPRRET expr_op_strlen(PEXPR pThis)
1003{
1004 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1005
1006 expr_var_make_simple_string(pVar);
1007 expr_var_assign_num(pVar, strlen(pVar->uVal.psz));
1008
1009 return kExprRet_Ok;
1010}
1011
1012
1013/**
1014 * Convert to string (simplified and quoted)
1015 *
1016 * @returns Status code.
1017 * @param pThis The instance.
1018 */
1019static EXPRRET expr_op_str(PEXPR pThis)
1020{
1021 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1022
1023 expr_var_make_simple_string(pVar);
1024 pVar->enmType = kExprVar_QuotedSimpleString;
1025
1026 return kExprRet_Ok;
1027}
1028
1029
1030/**
1031 * Pluss (dummy / make_integer)
1032 *
1033 * @returns Status code.
1034 * @param pThis The instance.
1035 */
1036static EXPRRET expr_op_pluss(PEXPR pThis)
1037{
1038 return expr_var_make_num(pThis, &pThis->aVars[pThis->iVar]);
1039}
1040
1041
1042/**
1043 * Minus (negate)
1044 *
1045 * @returns Status code.
1046 * @param pThis The instance.
1047 */
1048static EXPRRET expr_op_minus(PEXPR pThis)
1049{
1050 EXPRRET rc;
1051 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1052
1053 rc = expr_var_make_num(pThis, pVar);
1054 if (rc >= kExprRet_Ok)
1055 pVar->uVal.i = -pVar->uVal.i;
1056
1057 return rc;
1058}
1059
1060
1061
1062/**
1063 * Bitwise NOT.
1064 *
1065 * @returns Status code.
1066 * @param pThis The instance.
1067 */
1068static EXPRRET expr_op_bitwise_not(PEXPR pThis)
1069{
1070 EXPRRET rc;
1071 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1072
1073 rc = expr_var_make_num(pThis, pVar);
1074 if (rc >= kExprRet_Ok)
1075 pVar->uVal.i = ~pVar->uVal.i;
1076
1077 return rc;
1078}
1079
1080
1081/**
1082 * Logical NOT.
1083 *
1084 * @returns Status code.
1085 * @param pThis The instance.
1086 */
1087static EXPRRET expr_op_logical_not(PEXPR pThis)
1088{
1089 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1090
1091 expr_var_make_bool(pVar);
1092 pVar->uVal.i = !pVar->uVal.i;
1093
1094 return kExprRet_Ok;
1095}
1096
1097
1098/**
1099 * Multiplication.
1100 *
1101 * @returns Status code.
1102 * @param pThis The instance.
1103 */
1104static EXPRRET expr_op_multiply(PEXPR pThis)
1105{
1106 EXPRRET rc = kExprRet_Ok;
1107 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1108 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1109
1110 rc = expr_var_make_num(pThis, pVar1);
1111 if (rc >= kExprRet_Ok)
1112 {
1113 rc = expr_var_make_num(pThis, pVar2);
1114 if (rc >= kExprRet_Ok)
1115 pVar1->uVal.i *= pVar2->uVal.i;
1116 }
1117
1118 expr_pop_and_delete_var(pThis);
1119 return rc;
1120}
1121
1122
1123
1124/**
1125 * Division.
1126 *
1127 * @returns Status code.
1128 * @param pThis The instance.
1129 */
1130static EXPRRET expr_op_divide(PEXPR pThis)
1131{
1132 EXPRRET rc = kExprRet_Ok;
1133 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1134 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1135
1136 rc = expr_var_make_num(pThis, pVar1);
1137 if (rc >= kExprRet_Ok)
1138 {
1139 rc = expr_var_make_num(pThis, pVar2);
1140 if (rc >= kExprRet_Ok)
1141 pVar1->uVal.i /= pVar2->uVal.i;
1142 }
1143
1144 expr_pop_and_delete_var(pThis);
1145 return rc;
1146}
1147
1148
1149
1150/**
1151 * Modulus.
1152 *
1153 * @returns Status code.
1154 * @param pThis The instance.
1155 */
1156static EXPRRET expr_op_modulus(PEXPR pThis)
1157{
1158 EXPRRET rc = kExprRet_Ok;
1159 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1160 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1161
1162 rc = expr_var_make_num(pThis, pVar1);
1163 if (rc >= kExprRet_Ok)
1164 {
1165 rc = expr_var_make_num(pThis, pVar2);
1166 if (rc >= kExprRet_Ok)
1167 pVar1->uVal.i %= pVar2->uVal.i;
1168 }
1169
1170 expr_pop_and_delete_var(pThis);
1171 return rc;
1172}
1173
1174
1175
1176/**
1177 * Addition (numeric).
1178 *
1179 * @returns Status code.
1180 * @param pThis The instance.
1181 */
1182static EXPRRET expr_op_add(PEXPR pThis)
1183{
1184 EXPRRET rc = kExprRet_Ok;
1185 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1186 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1187
1188 rc = expr_var_make_num(pThis, pVar1);
1189 if (rc >= kExprRet_Ok)
1190 {
1191 rc = expr_var_make_num(pThis, pVar2);
1192 if (rc >= kExprRet_Ok)
1193 pVar1->uVal.i += pVar2->uVal.i;
1194 }
1195
1196 expr_pop_and_delete_var(pThis);
1197 return rc;
1198}
1199
1200
1201/**
1202 * Subtract (numeric).
1203 *
1204 * @returns Status code.
1205 * @param pThis The instance.
1206 */
1207static EXPRRET expr_op_sub(PEXPR pThis)
1208{
1209 EXPRRET rc = kExprRet_Ok;
1210 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1211 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1212
1213 rc = expr_var_make_num(pThis, pVar1);
1214 if (rc >= kExprRet_Ok)
1215 {
1216 rc = expr_var_make_num(pThis, pVar2);
1217 if (rc >= kExprRet_Ok)
1218 pVar1->uVal.i -= pVar2->uVal.i;
1219 }
1220
1221 expr_pop_and_delete_var(pThis);
1222 return rc;
1223}
1224
1225/**
1226 * Bitwise left shift.
1227 *
1228 * @returns Status code.
1229 * @param pThis The instance.
1230 */
1231static EXPRRET expr_op_shift_left(PEXPR pThis)
1232{
1233 EXPRRET rc = kExprRet_Ok;
1234 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1235 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1236
1237 rc = expr_var_make_num(pThis, pVar1);
1238 if (rc >= kExprRet_Ok)
1239 {
1240 rc = expr_var_make_num(pThis, pVar2);
1241 if (rc >= kExprRet_Ok)
1242 pVar1->uVal.i <<= pVar2->uVal.i;
1243 }
1244
1245 expr_pop_and_delete_var(pThis);
1246 return rc;
1247}
1248
1249
1250/**
1251 * Bitwise right shift.
1252 *
1253 * @returns Status code.
1254 * @param pThis The instance.
1255 */
1256static EXPRRET expr_op_shift_right(PEXPR pThis)
1257{
1258 EXPRRET rc = kExprRet_Ok;
1259 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1260 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1261
1262 rc = expr_var_make_num(pThis, pVar1);
1263 if (rc >= kExprRet_Ok)
1264 {
1265 rc = expr_var_make_num(pThis, pVar2);
1266 if (rc >= kExprRet_Ok)
1267 pVar1->uVal.i >>= pVar2->uVal.i;
1268 }
1269
1270 expr_pop_and_delete_var(pThis);
1271 return rc;
1272}
1273
1274
1275/**
1276 * Less than or equal, version string.
1277 *
1278 * @returns Status code.
1279 * @param pThis The instance.
1280 */
1281static EXPRRET expr_op_ver_less_or_equal_than(PEXPR pThis)
1282{
1283 EXPRRET rc = kExprRet_Ok;
1284 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1285 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1286
1287 rc = expr_var_unify_types(pThis, pVar1, pVar2, "vle");
1288 if (rc >= kExprRet_Ok)
1289 {
1290 if (!expr_var_is_string(pVar1))
1291 expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i);
1292 else
1293 expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) <= 0);
1294 }
1295
1296 expr_pop_and_delete_var(pThis);
1297 return rc;
1298}
1299
1300
1301/**
1302 * Less than or equal.
1303 *
1304 * @returns Status code.
1305 * @param pThis The instance.
1306 */
1307static EXPRRET expr_op_less_or_equal_than(PEXPR pThis)
1308{
1309 EXPRRET rc = kExprRet_Ok;
1310 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1311 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1312
1313 rc = expr_var_unify_types(pThis, pVar1, pVar2, "<=");
1314 if (rc >= kExprRet_Ok)
1315 {
1316 if (!expr_var_is_string(pVar1))
1317 expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i);
1318 else
1319 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) <= 0);
1320 }
1321
1322 expr_pop_and_delete_var(pThis);
1323 return rc;
1324}
1325
1326
1327/**
1328 * Less than, version string.
1329 *
1330 * @returns Status code.
1331 * @param pThis The instance.
1332 */
1333static EXPRRET expr_op_ver_less_than(PEXPR pThis)
1334{
1335 EXPRRET rc = kExprRet_Ok;
1336 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1337 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1338
1339 rc = expr_var_unify_types(pThis, pVar1, pVar2, "vlt");
1340 if (rc >= kExprRet_Ok)
1341 {
1342 if (!expr_var_is_string(pVar1))
1343 expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i);
1344 else
1345 expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) < 0);
1346 }
1347
1348 expr_pop_and_delete_var(pThis);
1349 return rc;
1350}
1351
1352
1353/**
1354 * Less than.
1355 *
1356 * @returns Status code.
1357 * @param pThis The instance.
1358 */
1359static EXPRRET expr_op_less_than(PEXPR pThis)
1360{
1361 EXPRRET rc = kExprRet_Ok;
1362 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1363 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1364
1365 rc = expr_var_unify_types(pThis, pVar1, pVar2, "<");
1366 if (rc >= kExprRet_Ok)
1367 {
1368 if (!expr_var_is_string(pVar1))
1369 expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i);
1370 else
1371 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) < 0);
1372 }
1373
1374 expr_pop_and_delete_var(pThis);
1375 return rc;
1376}
1377
1378
1379/**
1380 * Greater or equal than, version string.
1381 *
1382 * @returns Status code.
1383 * @param pThis The instance.
1384 */
1385static EXPRRET expr_op_ver_greater_or_equal_than(PEXPR pThis)
1386{
1387 EXPRRET rc = kExprRet_Ok;
1388 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1389 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1390
1391 rc = expr_var_unify_types(pThis, pVar1, pVar2, "vge");
1392 if (rc >= kExprRet_Ok)
1393 {
1394 if (!expr_var_is_string(pVar1))
1395 expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i);
1396 else
1397 expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) >= 0);
1398 }
1399
1400 expr_pop_and_delete_var(pThis);
1401 return rc;
1402}
1403
1404
1405/**
1406 * Greater or equal than.
1407 *
1408 * @returns Status code.
1409 * @param pThis The instance.
1410 */
1411static EXPRRET expr_op_greater_or_equal_than(PEXPR pThis)
1412{
1413 EXPRRET rc = kExprRet_Ok;
1414 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1415 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1416
1417 rc = expr_var_unify_types(pThis, pVar1, pVar2, ">=");
1418 if (rc >= kExprRet_Ok)
1419 {
1420 if (!expr_var_is_string(pVar1))
1421 expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i);
1422 else
1423 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) >= 0);
1424 }
1425
1426 expr_pop_and_delete_var(pThis);
1427 return rc;
1428}
1429
1430
1431/**
1432 * Greater than, version string.
1433 *
1434 * @returns Status code.
1435 * @param pThis The instance.
1436 */
1437static EXPRRET expr_op_ver_greater_than(PEXPR pThis)
1438{
1439 EXPRRET rc = kExprRet_Ok;
1440 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1441 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1442
1443 rc = expr_var_unify_types(pThis, pVar1, pVar2, "vgt");
1444 if (rc >= kExprRet_Ok)
1445 {
1446 if (!expr_var_is_string(pVar1))
1447 expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i);
1448 else
1449 expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) > 0);
1450 }
1451
1452 expr_pop_and_delete_var(pThis);
1453 return rc;
1454}
1455
1456
1457/**
1458 * Greater than.
1459 *
1460 * @returns Status code.
1461 * @param pThis The instance.
1462 */
1463static EXPRRET expr_op_greater_than(PEXPR pThis)
1464{
1465 EXPRRET rc = kExprRet_Ok;
1466 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1467 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1468
1469 rc = expr_var_unify_types(pThis, pVar1, pVar2, ">");
1470 if (rc >= kExprRet_Ok)
1471 {
1472 if (!expr_var_is_string(pVar1))
1473 expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i);
1474 else
1475 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) > 0);
1476 }
1477
1478 expr_pop_and_delete_var(pThis);
1479 return rc;
1480}
1481
1482
1483/**
1484 * Equal, version strings.
1485 *
1486 * @returns Status code.
1487 * @param pThis The instance.
1488 */
1489static EXPRRET expr_op_ver_equal(PEXPR pThis)
1490{
1491 EXPRRET rc = kExprRet_Ok;
1492 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1493 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1494 int const fIsString1 = expr_var_is_string(pVar1);
1495
1496 /*
1497 * The same type?
1498 */
1499 if (fIsString1 == expr_var_is_string(pVar2))
1500 {
1501 if (!fIsString1)
1502 /* numbers are simple */
1503 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1504 else
1505 {
1506 /* try a normal string compare. */
1507 expr_var_make_simple_string(pVar1);
1508 expr_var_make_simple_string(pVar2);
1509 if (!version_compare(pVar1->uVal.psz, pVar2->uVal.psz))
1510 expr_var_assign_bool(pVar1, 1);
1511 /* try convert and compare as number instead. */
1512 else if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok
1513 && expr_var_try_make_num(pVar2) >= kExprRet_Ok)
1514 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1515 /* ok, they really aren't equal. */
1516 else
1517 expr_var_assign_bool(pVar1, 0);
1518 }
1519 }
1520 else
1521 {
1522 /*
1523 * If the type differs, there are now two options:
1524 * 1. Try convert the string to a valid number and compare the numbers.
1525 * 2. Convert the non-string to a number and compare the strings.
1526 */
1527 if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok
1528 && expr_var_try_make_num(pVar2) >= kExprRet_Ok)
1529 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1530 else
1531 {
1532 expr_var_make_simple_string(pVar1);
1533 expr_var_make_simple_string(pVar2);
1534 expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) == 0);
1535 }
1536 }
1537
1538 expr_pop_and_delete_var(pThis);
1539 return rc;
1540}
1541
1542
1543/**
1544 * Not equal, version string.
1545 *
1546 * @returns Status code.
1547 * @param pThis The instance.
1548 */
1549static EXPRRET expr_op_ver_not_equal(PEXPR pThis)
1550{
1551 EXPRRET rc = expr_op_ver_equal(pThis);
1552 if (rc >= kExprRet_Ok)
1553 rc = expr_op_logical_not(pThis);
1554 return rc;
1555}
1556
1557
1558/**
1559 * Equal.
1560 *
1561 * @returns Status code.
1562 * @param pThis The instance.
1563 */
1564static EXPRRET expr_op_equal(PEXPR pThis)
1565{
1566 EXPRRET rc = kExprRet_Ok;
1567 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1568 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1569 int const fIsString1 = expr_var_is_string(pVar1);
1570
1571 /*
1572 * The same type?
1573 */
1574 if (fIsString1 == expr_var_is_string(pVar2))
1575 {
1576 if (!fIsString1)
1577 /* numbers are simple */
1578 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1579 else
1580 {
1581 /* try a normal string compare. */
1582 expr_var_make_simple_string(pVar1);
1583 expr_var_make_simple_string(pVar2);
1584 if (!strcmp(pVar1->uVal.psz, pVar2->uVal.psz))
1585 expr_var_assign_bool(pVar1, 1);
1586 /* try convert and compare as number instead. */
1587 else if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok
1588 && expr_var_try_make_num(pVar2) >= kExprRet_Ok)
1589 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1590 /* ok, they really aren't equal. */
1591 else
1592 expr_var_assign_bool(pVar1, 0);
1593 }
1594 }
1595 else
1596 {
1597 /*
1598 * If the type differs, there are now two options:
1599 * 1. Convert the string to a valid number and compare the numbers.
1600 * 2. Convert an empty string to a 'false' boolean value and compare
1601 * numerically. This one is a bit questionable, so we don't try this.
1602 */
1603 if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok
1604 && expr_var_try_make_num(pVar2) >= kExprRet_Ok)
1605 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1606 else
1607 {
1608 expr_error(pThis, "Cannot compare strings and numbers");
1609 rc = kExprRet_Error;
1610 }
1611 }
1612
1613 expr_pop_and_delete_var(pThis);
1614 return rc;
1615}
1616
1617
1618/**
1619 * Not equal.
1620 *
1621 * @returns Status code.
1622 * @param pThis The instance.
1623 */
1624static EXPRRET expr_op_not_equal(PEXPR pThis)
1625{
1626 EXPRRET rc = expr_op_equal(pThis);
1627 if (rc >= kExprRet_Ok)
1628 rc = expr_op_logical_not(pThis);
1629 return rc;
1630}
1631
1632
1633/**
1634 * Bitwise AND.
1635 *
1636 * @returns Status code.
1637 * @param pThis The instance.
1638 */
1639static EXPRRET expr_op_bitwise_and(PEXPR pThis)
1640{
1641 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1642 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1643 EXPRRET rc;
1644
1645 rc = expr_var_make_num(pThis, pVar1);
1646 if (rc >= kExprRet_Ok)
1647 {
1648 rc = expr_var_make_num(pThis, pVar2);
1649 if (rc >= kExprRet_Ok)
1650 pVar1->uVal.i &= pVar2->uVal.i;
1651 }
1652
1653 expr_pop_and_delete_var(pThis);
1654 return kExprRet_Ok;
1655}
1656
1657
1658/**
1659 * Bitwise XOR.
1660 *
1661 * @returns Status code.
1662 * @param pThis The instance.
1663 */
1664static EXPRRET expr_op_bitwise_xor(PEXPR pThis)
1665{
1666 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1667 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1668 EXPRRET rc;
1669
1670 rc = expr_var_make_num(pThis, pVar1);
1671 if (rc >= kExprRet_Ok)
1672 {
1673 rc = expr_var_make_num(pThis, pVar2);
1674 if (rc >= kExprRet_Ok)
1675 pVar1->uVal.i ^= pVar2->uVal.i;
1676 }
1677
1678 expr_pop_and_delete_var(pThis);
1679 return kExprRet_Ok;
1680}
1681
1682
1683/**
1684 * Bitwise OR.
1685 *
1686 * @returns Status code.
1687 * @param pThis The instance.
1688 */
1689static EXPRRET expr_op_bitwise_or(PEXPR pThis)
1690{
1691 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1692 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1693 EXPRRET rc;
1694
1695 rc = expr_var_make_num(pThis, pVar1);
1696 if (rc >= kExprRet_Ok)
1697 {
1698 rc = expr_var_make_num(pThis, pVar2);
1699 if (rc >= kExprRet_Ok)
1700 pVar1->uVal.i |= pVar2->uVal.i;
1701 }
1702
1703 expr_pop_and_delete_var(pThis);
1704 return kExprRet_Ok;
1705}
1706
1707
1708/**
1709 * Logical AND.
1710 *
1711 * @returns Status code.
1712 * @param pThis The instance.
1713 */
1714static EXPRRET expr_op_logical_and(PEXPR pThis)
1715{
1716 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1717 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1718
1719 if ( expr_var_make_bool(pVar1)
1720 && expr_var_make_bool(pVar2))
1721 expr_var_assign_bool(pVar1, 1);
1722 else
1723 expr_var_assign_bool(pVar1, 0);
1724
1725 expr_pop_and_delete_var(pThis);
1726 return kExprRet_Ok;
1727}
1728
1729
1730/**
1731 * Logical OR.
1732 *
1733 * @returns Status code.
1734 * @param pThis The instance.
1735 */
1736static EXPRRET expr_op_logical_or(PEXPR pThis)
1737{
1738 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1739 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1740
1741 if ( expr_var_make_bool(pVar1)
1742 || expr_var_make_bool(pVar2))
1743 expr_var_assign_bool(pVar1, 1);
1744 else
1745 expr_var_assign_bool(pVar1, 0);
1746
1747 expr_pop_and_delete_var(pThis);
1748 return kExprRet_Ok;
1749}
1750
1751
1752/**
1753 * Left parenthesis.
1754 *
1755 * @returns Status code.
1756 * @param pThis The instance.
1757 */
1758static EXPRRET expr_op_left_parenthesis(PEXPR pThis)
1759{
1760 /*
1761 * There should be a right parenthesis operator lined up for us now,
1762 * eat it. If not found there is an inbalance.
1763 */
1764 EXPRRET rc = expr_get_binary_or_eoe_or_rparen(pThis);
1765 if ( rc == kExprRet_Operator
1766 && pThis->apOps[pThis->iOp]->szOp[0] == ')')
1767 {
1768 /* pop it and get another one which we can leave pending. */
1769 pThis->iOp--;
1770 rc = expr_get_binary_or_eoe_or_rparen(pThis);
1771 if (rc >= kExprRet_Ok)
1772 expr_unget_op(pThis);
1773 }
1774 else
1775 {
1776 expr_error(pThis, "Missing ')'");
1777 rc = kExprRet_Error;
1778 }
1779
1780 return rc;
1781}
1782
1783
1784/**
1785 * Right parenthesis, dummy that's never actually called.
1786 *
1787 * @returns Status code.
1788 * @param pThis The instance.
1789 */
1790static EXPRRET expr_op_right_parenthesis(PEXPR pThis)
1791{
1792 assert(0);
1793 (void)pThis;
1794 return kExprRet_Ok;
1795}
1796
1797
1798
1799
1800
1801/**
1802 * The operator table.
1803 *
1804 * This table is NOT ordered by precedence, but for linear search
1805 * allowing for first match to return the correct operator. This
1806 * means that || must come before |, or else | will match all.
1807 */
1808static const EXPROP g_aExprOps[] =
1809{
1810#define EXPR_OP(szOp, iPrecedence, cArgs, pfn) { szOp, sizeof(szOp) - 1, '\0', iPrecedence, cArgs, pfn }
1811 /* Name, iPrecedence, cArgs, pfn */
1812 EXPR_OP("defined", 90, 1, expr_op_defined),
1813 EXPR_OP("exists", 90, 1, expr_op_exists),
1814 EXPR_OP("target", 90, 1, expr_op_target),
1815 EXPR_OP("bool", 90, 1, expr_op_bool),
1816 EXPR_OP("num", 90, 1, expr_op_num),
1817 EXPR_OP("strlen", 90, 1, expr_op_strlen),
1818 EXPR_OP("str", 90, 1, expr_op_str),
1819 EXPR_OP("+", 80, 1, expr_op_pluss),
1820 EXPR_OP("-", 80, 1, expr_op_minus),
1821 EXPR_OP("~", 80, 1, expr_op_bitwise_not),
1822 EXPR_OP("*", 75, 2, expr_op_multiply),
1823 EXPR_OP("/", 75, 2, expr_op_divide),
1824 EXPR_OP("%", 75, 2, expr_op_modulus),
1825 EXPR_OP("+", 70, 2, expr_op_add),
1826 EXPR_OP("-", 70, 2, expr_op_sub),
1827 EXPR_OP("<<", 65, 2, expr_op_shift_left),
1828 EXPR_OP(">>", 65, 2, expr_op_shift_right),
1829 EXPR_OP("<=", 60, 2, expr_op_less_or_equal_than),
1830 EXPR_OP("<", 60, 2, expr_op_less_than),
1831 EXPR_OP(">=", 60, 2, expr_op_greater_or_equal_than),
1832 EXPR_OP(">", 60, 2, expr_op_greater_than),
1833 EXPR_OP("vle", 60, 2, expr_op_ver_less_or_equal_than),
1834 EXPR_OP("vlt", 60, 2, expr_op_ver_less_than),
1835 EXPR_OP("vge", 60, 2, expr_op_ver_greater_or_equal_than),
1836 EXPR_OP("vgt", 60, 2, expr_op_ver_greater_than),
1837 EXPR_OP("==", 55, 2, expr_op_equal),
1838 EXPR_OP("veq", 55, 2, expr_op_ver_equal),
1839 EXPR_OP("!=", 55, 2, expr_op_not_equal),
1840 EXPR_OP("vne", 55, 2, expr_op_ver_not_equal),
1841 EXPR_OP("!", 80, 1, expr_op_logical_not),
1842 EXPR_OP("^", 45, 2, expr_op_bitwise_xor),
1843 EXPR_OP("&&", 35, 2, expr_op_logical_and),
1844 EXPR_OP("&", 50, 2, expr_op_bitwise_and),
1845 EXPR_OP("||", 30, 2, expr_op_logical_or),
1846 EXPR_OP("|", 40, 2, expr_op_bitwise_or),
1847 { "(", 1, ')', 10, 1, expr_op_left_parenthesis },
1848 { ")", 1, '(', 10, 0, expr_op_right_parenthesis },
1849 /* { "?", 1, ':', 5, 2, expr_op_question },
1850 { ":", 1, '?', 5, 2, expr_op_colon }, -- too weird for now. */
1851#undef EXPR_OP
1852};
1853
1854/** Dummy end of expression fake. */
1855static const EXPROP g_ExprEndOfExpOp =
1856{
1857 "", 0, '\0', 0, 0, NULL
1858};
1859
1860
1861/**
1862 * Initializes the opcode character map if necessary.
1863 */
1864static void expr_map_init(void)
1865{
1866 unsigned i;
1867 if (g_fExprInitializedMap)
1868 return;
1869
1870 /*
1871 * Initialize it.
1872 */
1873 memset(&g_auchOpStartCharMap, 0, sizeof(g_auchOpStartCharMap));
1874 for (i = 0; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++)
1875 {
1876 unsigned int ch = (unsigned int)g_aExprOps[i].szOp[0];
1877 if (!g_auchOpStartCharMap[ch])
1878 {
1879 g_auchOpStartCharMap[ch] = (i << 2) | 1;
1880 if (!isalpha(ch))
1881 g_auchOpStartCharMap[ch] |= 2; /* Need no clear separation from operands. */
1882 }
1883 }
1884
1885 /* whitespace (assumes C-like locale because I'm lazy): */
1886#define SET_WHITESPACE(a_ch) do { \
1887 assert(g_auchOpStartCharMap[(unsigned char)(a_ch)] == 0); \
1888 g_auchOpStartCharMap[(unsigned char)(a_ch)] |= 2; \
1889 } while (0)
1890 SET_WHITESPACE(' ');
1891 SET_WHITESPACE('\t');
1892 SET_WHITESPACE('\n');
1893 SET_WHITESPACE('\r');
1894 SET_WHITESPACE('\v');
1895 SET_WHITESPACE('\f');
1896
1897 g_fExprInitializedMap = 1;
1898}
1899
1900
1901/**
1902 * Looks up a character in the map.
1903 *
1904 * @returns the value for that char, see g_auchOpStartCharMap for details.
1905 * @param ch The character.
1906 */
1907static unsigned char expr_map_get(char ch)
1908{
1909 return g_auchOpStartCharMap[(unsigned char)ch];
1910}
1911
1912
1913/**
1914 * Searches the operator table given a potential operator start char.
1915 *
1916 * @returns Pointer to the matching operator. NULL if not found.
1917 * @param psz Pointer to what can be an operator.
1918 * @param uchVal The expr_map_get value.
1919 * @param fUnary Whether it must be an unary operator or not.
1920 */
1921static PCEXPROP expr_lookup_op(char const *psz, unsigned char uchVal, int fUnary)
1922{
1923 char ch = *psz;
1924 unsigned i;
1925 assert((uchVal & 2) == (isalpha(ch) ? 0 : 2));
1926
1927 for (i = uchVal >> 2; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++)
1928 {
1929 /* compare the string... */
1930 if (g_aExprOps[i].szOp[0] != ch)
1931 continue;
1932 switch (g_aExprOps[i].cchOp)
1933 {
1934 case 1:
1935 break;
1936 case 2:
1937 if (g_aExprOps[i].szOp[1] != psz[1])
1938 continue;
1939 break;
1940 default:
1941 if (strncmp(&g_aExprOps[i].szOp[1], psz + 1, g_aExprOps[i].cchOp - 1))
1942 continue;
1943 break;
1944 }
1945
1946 /* ... and the operator type. */
1947 if (fUnary == (g_aExprOps[i].cArgs == 1))
1948 {
1949 /* Check if we've got the needed operand separation: */
1950 if ( (uchVal & 2)
1951 || EXPR_IS_OP_SEPARATOR(psz[g_aExprOps[i].cchOp]))
1952 {
1953 /* got a match! */
1954 return &g_aExprOps[i];
1955 }
1956 }
1957 }
1958
1959 return NULL;
1960}
1961
1962
1963/**
1964 * Ungets a binary operator.
1965 *
1966 * The operator is poped from the stack and put in the pending position.
1967 *
1968 * @param pThis The evaluator instance.
1969 */
1970static void expr_unget_op(PEXPR pThis)
1971{
1972 assert(pThis->pPending == NULL);
1973 assert(pThis->iOp >= 0);
1974
1975 pThis->pPending = pThis->apOps[pThis->iOp];
1976 pThis->apOps[pThis->iOp] = NULL;
1977 pThis->iOp--;
1978}
1979
1980
1981
1982/**
1983 * Get the next token, it should be a binary operator, or the end of
1984 * the expression, or a right parenthesis.
1985 *
1986 * The operator is pushed onto the stack and the status code indicates
1987 * which of the two we found.
1988 *
1989 * @returns status code. Will grumble on failure.
1990 * @retval kExprRet_EndOfExpr if we encountered the end of the expression.
1991 * @retval kExprRet_Operator if we encountered a binary operator or right
1992 * parenthesis. It's on the operator stack.
1993 *
1994 * @param pThis The evaluator instance.
1995 */
1996static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis)
1997{
1998 /*
1999 * See if there is anything pending first.
2000 */
2001 PCEXPROP pOp = pThis->pPending;
2002 if (pOp)
2003 pThis->pPending = NULL;
2004 else
2005 {
2006 /*
2007 * Eat more of the expression.
2008 */
2009 char const *psz = pThis->psz;
2010
2011 /* spaces */
2012 unsigned char uchVal;
2013 char ch;
2014 while (((uchVal = expr_map_get((ch = *psz))) & 3) == 2)
2015 psz++;
2016
2017 /* see what we've got. */
2018 if (ch)
2019 {
2020 if (uchVal & 1)
2021 pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */);
2022 if (!pOp)
2023 {
2024 expr_error(pThis, "Expected binary operator, found \"%.42s\"...", psz);
2025 return kExprRet_Error;
2026 }
2027 psz += pOp->cchOp;
2028 }
2029 else
2030 pOp = &g_ExprEndOfExpOp;
2031 pThis->psz = psz;
2032 }
2033
2034 /*
2035 * Push it.
2036 */
2037 if (pThis->iOp >= EXPR_MAX_OPERATORS - 1)
2038 {
2039 expr_error(pThis, "Operator stack overflow");
2040 return kExprRet_Error;
2041 }
2042 pThis->apOps[++pThis->iOp] = pOp;
2043
2044 return pOp->iPrecedence
2045 ? kExprRet_Operator
2046 : kExprRet_EndOfExpr;
2047}
2048
2049
2050
2051/**
2052 * Get the next token, it should be an unary operator or an operand.
2053 *
2054 * This will fail if encountering the end of the expression since
2055 * it is implied that there should be something more.
2056 *
2057 * The token is pushed onto the respective stack and the status code
2058 * indicates which it is.
2059 *
2060 * @returns status code. On failure we'll be done bitching already.
2061 * @retval kExprRet_Operator if we encountered an unary operator.
2062 * It's on the operator stack.
2063 * @retval kExprRet_Operand if we encountered an operand operator.
2064 * It's on the operand stack.
2065 *
2066 * @param This The evaluator instance.
2067 */
2068static EXPRRET expr_get_unary_or_operand(PEXPR pThis)
2069{
2070 EXPRRET rc;
2071 unsigned char uchVal;
2072 PCEXPROP pOp;
2073 char const *psz = pThis->psz;
2074 char ch;
2075
2076 /*
2077 * Eat white space and make sure there is something after it.
2078 */
2079 while (((uchVal = expr_map_get((ch = *psz))) & 3) == 2)
2080 psz++;
2081 if (ch == '\0')
2082 {
2083 expr_error(pThis, "Unexpected end of expression");
2084 return kExprRet_Error;
2085 }
2086
2087 /*
2088 * Is it an operator?
2089 */
2090 pOp = NULL;
2091 if (uchVal & 1)
2092 pOp = expr_lookup_op(psz, uchVal, 1 /* fUnary */);
2093 if (pOp)
2094 {
2095 /*
2096 * Push the operator onto the stack.
2097 */
2098 if (pThis->iVar < EXPR_MAX_OPERANDS - 1)
2099 {
2100 pThis->apOps[++pThis->iOp] = pOp;
2101 rc = kExprRet_Operator;
2102 }
2103 else
2104 {
2105 expr_error(pThis, "Operator stack overflow");
2106 rc = kExprRet_Error;
2107 }
2108 psz += pOp->cchOp;
2109 }
2110 else if (pThis->iVar < EXPR_MAX_OPERANDS - 1)
2111 {
2112 /*
2113 * It's an operand. Figure out where it ends and
2114 * push it onto the stack.
2115 */
2116 const char *pszStart;
2117
2118 rc = kExprRet_Ok;
2119 if (ch == '"')
2120 {
2121 pszStart = ++psz;
2122 while ((ch = *psz) != '\0' && ch != '"')
2123 psz++;
2124 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedString);
2125 if (ch != '\0')
2126 psz++;
2127 }
2128 else if (ch == '\'')
2129 {
2130 pszStart = ++psz;
2131 while ((ch = *psz) != '\0' && ch != '\'')
2132 psz++;
2133 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedSimpleString);
2134 if (ch != '\0')
2135 psz++;
2136 }
2137 else
2138 {
2139 char achPars[20];
2140 int iPar = -1;
2141 char chEndPar = '\0';
2142
2143 pszStart = psz;
2144 while ((ch = *psz) != '\0')
2145 {
2146 char ch2;
2147
2148 /* $(adsf) or ${asdf} needs special handling. */
2149 if ( ch == '$'
2150 && ( (ch2 = psz[1]) == '('
2151 || ch2 == '{'))
2152 {
2153 psz++;
2154 if (iPar > (int)(sizeof(achPars) / sizeof(achPars[0])))
2155 {
2156 expr_error(pThis, "Too deep nesting of variable expansions");
2157 rc = kExprRet_Error;
2158 break;
2159 }
2160 achPars[++iPar] = chEndPar = ch2 == '(' ? ')' : '}';
2161 }
2162 else if (ch == chEndPar)
2163 {
2164 iPar--;
2165 chEndPar = iPar >= 0 ? achPars[iPar] : '\0';
2166 }
2167 else if (!chEndPar)
2168 {
2169 uchVal = expr_map_get(ch);
2170 if (uchVal == 0)
2171 { /*likely*/ }
2172 else if ((uchVal & 3) == 2 /*isspace*/)
2173 break;
2174 else if ( (uchVal & 1)
2175 && psz != pszStart /* not at the start */
2176 && ( (uchVal & 2) /* operator without separator needs */
2177 || EXPR_IS_OP_SEPARATOR_NO_SPACE(psz[-1])))
2178 {
2179 pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */);
2180 if (pOp)
2181 break;
2182 }
2183 }
2184
2185 /* next */
2186 psz++;
2187 }
2188
2189 if (rc == kExprRet_Ok)
2190 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_String);
2191 }
2192 }
2193 else
2194 {
2195 expr_error(pThis, "Operand stack overflow");
2196 rc = kExprRet_Error;
2197 }
2198 pThis->psz = psz;
2199
2200 return rc;
2201}
2202
2203
2204/**
2205 * Evaluates the current expression.
2206 *
2207 * @returns status code.
2208 *
2209 * @param pThis The instance.
2210 */
2211static EXPRRET expr_eval(PEXPR pThis)
2212{
2213 EXPRRET rc;
2214 PCEXPROP pOp;
2215
2216 /*
2217 * The main loop.
2218 */
2219 for (;;)
2220 {
2221 /*
2222 * Eat unary operators until we hit an operand.
2223 */
2224 do rc = expr_get_unary_or_operand(pThis);
2225 while (rc == kExprRet_Operator);
2226 if (rc < kExprRet_Ok)
2227 break;
2228
2229 /*
2230 * Look for a binary operator, right parenthesis or end of expression.
2231 */
2232 rc = expr_get_binary_or_eoe_or_rparen(pThis);
2233 if (rc < kExprRet_Ok)
2234 break;
2235 expr_unget_op(pThis);
2236
2237 /*
2238 * Pop operators and apply them.
2239 *
2240 * Parenthesis will be handed via precedence, where the left parenthesis
2241 * will go pop the right one and make another operator pending.
2242 */
2243 while ( pThis->iOp >= 0
2244 && pThis->apOps[pThis->iOp]->iPrecedence >= pThis->pPending->iPrecedence)
2245 {
2246 pOp = pThis->apOps[pThis->iOp--];
2247 assert(pThis->iVar + 1 >= pOp->cArgs);
2248 rc = pOp->pfn(pThis);
2249 if (rc < kExprRet_Ok)
2250 break;
2251 }
2252 if (rc < kExprRet_Ok)
2253 break;
2254
2255 /*
2256 * Get the next binary operator or end of expression.
2257 * There should be no right parenthesis here.
2258 */
2259 rc = expr_get_binary_or_eoe_or_rparen(pThis);
2260 if (rc < kExprRet_Ok)
2261 break;
2262 pOp = pThis->apOps[pThis->iOp];
2263 if (!pOp->iPrecedence)
2264 break; /* end of expression */
2265 if (!pOp->cArgs)
2266 {
2267 expr_error(pThis, "Unexpected \"%s\"", pOp->szOp);
2268 rc = kExprRet_Error;
2269 break;
2270 }
2271 }
2272
2273 return rc;
2274}
2275
2276
2277/**
2278 * Destroys the given instance.
2279 *
2280 * @param pThis The instance to destroy.
2281 */
2282static void expr_destroy(PEXPR pThis)
2283{
2284 while (pThis->iVar >= 0)
2285 {
2286 expr_var_delete(pThis->aVars);
2287 pThis->iVar--;
2288 }
2289 free(pThis);
2290}
2291
2292
2293/**
2294 * Instantiates an expression evaluator.
2295 *
2296 * @returns The instance.
2297 *
2298 * @param pszExpr What to parse.
2299 * This must stick around until expr_destroy.
2300 */
2301static PEXPR expr_create(char const *pszExpr)
2302{
2303 PEXPR pThis = (PEXPR)xmalloc(sizeof(*pThis));
2304 pThis->pszExpr = pszExpr;
2305 pThis->psz = pszExpr;
2306 pThis->pFileLoc = NULL;
2307 pThis->pPending = NULL;
2308 pThis->iVar = -1;
2309 pThis->iOp = -1;
2310
2311 expr_map_init();
2312 return pThis;
2313}
2314
2315
2316/**
2317 * Evaluates the given if expression.
2318 *
2319 * @returns -1, 0 or 1. (GNU make conditional check convention, see read.c.)
2320 * @retval -1 if the expression is invalid.
2321 * @retval 0 if the expression is true
2322 * @retval 1 if the expression is false.
2323 *
2324 * @param line The expression.
2325 * @param flocp The file location, used for errors.
2326 */
2327int expr_eval_if_conditionals(const char *line, const floc *flocp)
2328{
2329 /*
2330 * Instantiate the expression evaluator and let
2331 * it have a go at it.
2332 */
2333 int rc = -1;
2334 PEXPR pExpr = expr_create(line);
2335 pExpr->pFileLoc = flocp;
2336 if (expr_eval(pExpr) >= kExprRet_Ok)
2337 {
2338 /*
2339 * Convert the result (on top of the stack) to boolean and
2340 * set our return value accordingly.
2341 */
2342 if (expr_var_make_bool(&pExpr->aVars[0]))
2343 rc = 0;
2344 else
2345 rc = 1;
2346 }
2347 expr_destroy(pExpr);
2348
2349 return rc;
2350}
2351
2352
2353/**
2354 * Evaluates the given expression and returns the result as a string.
2355 *
2356 * @returns variable buffer position.
2357 *
2358 * @param o The current variable buffer position.
2359 * @param expr The expression.
2360 */
2361char *expr_eval_to_string(char *o, const char *expr)
2362{
2363 /*
2364 * Instantiate the expression evaluator and let
2365 * it have a go at it.
2366 */
2367 PEXPR pExpr = expr_create(expr);
2368 if (expr_eval(pExpr) >= kExprRet_Ok)
2369 {
2370 /*
2371 * Convert the result (on top of the stack) to a string
2372 * and copy it out the variable buffer.
2373 */
2374 PEXPRVAR pVar = &pExpr->aVars[0];
2375 expr_var_make_simple_string(pVar);
2376 o = variable_buffer_output(o, pVar->uVal.psz, strlen(pVar->uVal.psz));
2377 }
2378 else
2379 o = variable_buffer_output(o, "<expression evaluation failed>", sizeof("<expression evaluation failed>") - 1);
2380 expr_destroy(pExpr);
2381
2382 return o;
2383}
2384
2385
2386#endif /* CONFIG_WITH_IF_CONDITIONALS */
2387
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette