VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/expreval.cpp

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.6 KB
Line 
1/* $Id: expreval.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * expreval - Expressions evaluator.
4 */
5
6/*
7 * Copyright (C) 2022-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "internal/iprt.h"
42#include <iprt/expreval.h>
43
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/ctype.h>
47#include <iprt/err.h>
48#include <iprt/md5.h>
49#include <iprt/mem.h>
50#include <iprt/path.h>
51#include <iprt/sha.h>
52#include <iprt/string.h>
53
54
55/*********************************************************************************************************************************
56* Defined Constants And Macros *
57*********************************************************************************************************************************/
58/** The max length of a string representation of a number. */
59#define EXPR_NUM_LEN ((sizeof("-9223372036854775802") + 4) & ~3)
60
61/** The max operator stack depth. */
62#define EXPR_MAX_OPERATORS 72
63/** The max operand depth. */
64#define EXPR_MAX_OPERANDS 128
65/** the max variable recursion. */
66#define EXPR_MAX_VAR_RECURSION 20
67
68/** Check if @a a_ch is a valid separator for a alphabetical binary
69 * operator, omitting isspace. */
70#define EXPR_IS_OP_SEPARATOR_NO_SPACE(a_ch) \
71 (RT_C_IS_PUNCT((a_ch)) && (a_ch) != '@' && (a_ch) != '_')
72
73/** Check if @a a_ch is a valid separator for a alphabetical binary operator. */
74#define EXPR_IS_OP_SEPARATOR(a_ch) \
75 (RT_C_IS_SPACE((a_ch)) || EXPR_IS_OP_SEPARATOR_NO_SPACE(a_ch))
76
77
78/*********************************************************************************************************************************
79* Structures and Typedefs *
80*********************************************************************************************************************************/
81/** The 64-bit signed integer type we're using. */
82typedef int64_t EXPRINT64;
83
84/** Pointer to a evaluator instance. */
85typedef struct EXPR *PEXPR;
86
87
88/**
89 * Operand variable type.
90 */
91typedef enum
92{
93 /** Invalid zero entry. */
94 kExprVar_Invalid = 0,
95 /** A number. */
96 kExprVar_Num,
97 /** A string in need of expanding (perhaps). */
98 kExprVar_String,
99 /** A simple string that doesn't need expanding. */
100 kExprVar_SimpleString,
101 /** A quoted string in need of expanding (perhaps). */
102 kExprVar_QuotedString,
103 /** A simple quoted string that doesn't need expanding. */
104 kExprVar_QuotedSimpleString,
105 /** The end of the valid variable types. */
106 kExprVar_End
107} EXPRVARTYPE;
108
109/**
110 * Operand variable.
111 */
112typedef struct
113{
114 /** The variable type. */
115 EXPRVARTYPE enmType;
116 /** The variable. */
117 union
118 {
119 /** Pointer to the string. */
120 char *psz;
121 /** The variable. */
122 EXPRINT64 i;
123 } uVal;
124} EXPRVAR;
125/** Pointer to a operand variable. */
126typedef EXPRVAR *PEXPRVAR;
127/** Pointer to a const operand variable. */
128typedef EXPRVAR const *PCEXPRVAR;
129
130/**
131 * Operator return statuses.
132 */
133typedef enum
134{
135 kExprRet_Error = -1,
136 kExprRet_Ok = 0,
137 kExprRet_Operator,
138 kExprRet_Operand,
139 kExprRet_EndOfExpr,
140 kExprRet_End
141} EXPRRET;
142
143/**
144 * Operator.
145 */
146typedef struct
147{
148 /** The operator. */
149 char szOp[11];
150 /** The length of the operator string. */
151 uint8_t cchOp;
152 /** The pair operator.
153 * This is used with '(' and '?'. */
154 char chPair;
155 /** The precedence. Higher means higher. */
156 char iPrecedence;
157 /** The number of arguments it takes. */
158 signed char cArgs;
159 /** Pointer to the method implementing the operator. */
160 EXPRRET (*pfn)(PEXPR pThis);
161} EXPROP;
162/** Pointer to a const operator. */
163typedef EXPROP const *PCEXPROP;
164
165
166/** Magic value for RTEXPREVALINT::u32Magic.
167 * @todo fixme */
168#define RTEXPREVAL_MAGIC UINT32_C(0x12345678)
169
170/**
171 * Expression evaluator instance.
172 */
173typedef struct RTEXPREVALINT
174{
175 /** Magic number (RTEXPREVAL_MAGIC). */
176 uint32_t u32Magic;
177 /** Reference counter. */
178 uint32_t volatile cRefs;
179 /** RTEXPREVAL_XXX. */
180 uint64_t fFlags;
181 /** Name for logging purposes (copy) */
182 char *pszName;
183 /** User argument to callbacks. */
184 void *pvUser;
185 /** Callback for getting variables or checking if they exists. */
186 PFNRTEXPREVALQUERYVARIABLE pfnQueryVariable;
187} RTEXPREVALINT;
188
189/**
190 * An expression being evaluated.
191 */
192typedef struct EXPR
193{
194 /** The full expression. */
195 const char *pszExpr;
196 /** The current location. */
197 const char *psz;
198 /** Error info keeper. */
199 PRTERRINFO pErrInfo;
200 /** Pointer to the instance we evaluating under. */
201 RTEXPREVALINT *pEvaluator;
202 /** Pending binary operator. */
203 PCEXPROP pPending;
204 /** Top of the operator stack. */
205 int iOp;
206 /** Top of the operand stack. */
207 int iVar;
208 /** The operator stack. */
209 PCEXPROP apOps[EXPR_MAX_OPERATORS];
210 /** The operand stack. */
211 EXPRVAR aVars[EXPR_MAX_OPERANDS];
212} EXPR;
213
214
215/*********************************************************************************************************************************
216* Global Variables *
217*********************************************************************************************************************************/
218/** Operator start character map.
219 * This indicates which characters that are starting operators and which aren't.
220 *
221 * Bit 0: Indicates that this char is used in operators.
222 * Bit 1: When bit 0 is clear, this indicates whitespace.
223 * When bit 1 is set, this indicates whether the operator can be used
224 * immediately next to an operand without any clear separation.
225 * Bits 2 thru 7: Index into g_aExprOps of the first operator starting with
226 * this character.
227 */
228static uint8_t g_abOpStartCharMap[256] = {0};
229/** Whether we've initialized the map. */
230static int g_fExprInitializedMap = 0;
231
232
233/*********************************************************************************************************************************
234* Internal Functions *
235*********************************************************************************************************************************/
236static void expr_unget_op(PEXPR pThis);
237static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis);
238
239
240
241
242/**
243 * Displays an error message.
244 *
245 * The total string length must not exceed 256 bytes.
246 *
247 * @returns kExprRet_Error
248 * @param pThis The evaluator instance.
249 * @param pszError The message format string.
250 * @param ... The message format args.
251 */
252static EXPRRET expr_error(PEXPR pThis, const char *pszError, ...)
253{
254 va_list va;
255 va_start(va, pszError);
256 RTErrInfoSetV(pThis->pErrInfo, VERR_PARSE_ERROR, pszError, va);
257 va_end(va);
258 return kExprRet_Error;
259}
260
261
262/**
263 * Converts a number to a string.
264 *
265 * @returns pszDst.
266 * @param pszDst The string buffer to write into. Assumes length of EXPR_NUM_LEN.
267 * @param iSrc The number to convert.
268 */
269static char *expr_num_to_string(char *pszDst, EXPRINT64 iSrc)
270{
271 char szTmp[64]; /* RTStrFormatNumber assumes this as a minimum size. */
272 AssertCompile(EXPR_NUM_LEN < sizeof(szTmp));
273 size_t cchTmp = RTStrFormatNumber(szTmp, iSrc, 10 /*uBase*/, 0 /*cchWidth*/, 0 /*cchPrecision*/,
274 RTSTR_F_64BIT | RTSTR_F_VALSIGNED);
275 return (char *)memcpy(pszDst, szTmp, cchTmp + 1);
276}
277
278
279/**
280 * Attempts to convert a (simple) string into a number.
281 *
282 * @returns status code.
283 * @param pThis The evaluator instance.
284 * @param piDst Where to store the numeric value on success.
285 * @param pszSrc The string to try convert.
286 * @param fQuiet Whether we should be quiet or grumpy on failure.
287 */
288static EXPRRET expr_string_to_num(PEXPR pThis, EXPRINT64 *piDst, const char *pszSrc, int fQuiet)
289{
290 EXPRRET rc = kExprRet_Ok;
291 char const *psz = pszSrc;
292 EXPRINT64 i;
293 unsigned uBase;
294 int fNegative;
295
296 /*
297 * Skip blanks.
298 */
299 while (RT_C_IS_BLANK(*psz))
300 psz++;
301 const char *const pszFirst = psz;
302
303 /*
304 * Check for '-'.
305 *
306 * At this point we will not need to deal with operators, this is
307 * just an indicator of negative numbers. If some operator ends up
308 * here it's because it came from a string expansion and thus shall
309 * not be interpreted. If this turns out to be an stupid restriction
310 * it can be fixed, but for now it stays like this.
311 */
312 fNegative = *psz == '-';
313 if (fNegative)
314 psz++;
315
316 /*
317 * Determin base.
318 * Recognize some exsotic prefixes here in addition to the two standard ones.
319 */
320 uint64_t const fFlags = pThis->pEvaluator->fFlags;
321 uBase = fFlags & RTEXPREVAL_F_DEFAULT_BASE_16 ? 16 : 10;
322 char const ch0 = psz[0];
323 if (ch0 == '0')
324 {
325 char const ch1 = psz[1];
326 switch (ch1)
327 {
328 case '\0':
329 break;
330
331 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': /* C-style octal */
332 if (fFlags & RTEXPREVAL_F_C_OCTAL)
333 {
334 uBase = 8;
335 psz++;
336 }
337 break;
338
339 case '8':
340 case '9':
341 break;
342
343 case 'x':
344 case 'X':
345 uBase = 16;
346 psz += 2;
347 break;
348 case 'y': case 'Y': /* windbg, VBoxDbg */
349 case 'b': case 'B': /* python and others */
350 uBase = 2;
351 psz += 2;
352 break;
353 case 'n': case 'N': /* windbg */
354 case 'i': case 'I': /* VBoxDbg */
355 uBase = 10;
356 psz += 2;
357 break;
358 case 't': case 'T': /* windbg, VBoxDbg */
359 case 'o': case 'O': /* python and others */
360 uBase = 8;
361 psz += 2;
362 break;
363 }
364 }
365
366 /*
367 * Convert digits.
368 */
369 i = 0;
370 for (;;)
371 {
372 unsigned iDigit;
373 int ch = *psz;
374 switch (ch)
375 {
376 case '0': iDigit = 0; break;
377 case '1': iDigit = 1; break;
378 case '2': iDigit = 2; break;
379 case '3': iDigit = 3; break;
380 case '4': iDigit = 4; break;
381 case '5': iDigit = 5; break;
382 case '6': iDigit = 6; break;
383 case '7': iDigit = 7; break;
384 case '8': iDigit = 8; break;
385 case '9': iDigit = 9; break;
386 case 'a':
387 case 'A': iDigit = 10; break;
388 case 'b':
389 case 'B': iDigit = 11; break;
390 case 'c':
391 case 'C': iDigit = 12; break;
392 case 'd':
393 case 'D': iDigit = 13; break;
394 case 'e':
395 case 'E': iDigit = 14; break;
396 case 'F': iDigit = 15; break;
397 case 'f':
398 /* Make 'false' -> 0: */
399 if ( psz != pszFirst
400 || strncmp(psz + 1, RT_STR_TUPLE("alse")) != 0)
401 {
402 iDigit = 15;
403 break;
404 }
405 psz += sizeof("false") - 1;
406 RT_FALL_THROUGH();
407
408 default:
409 /* Make 'true' evaluate to 1: */
410 if (psz == pszFirst && strncmp(psz, RT_STR_TUPLE("true")) == 0)
411 {
412 psz += sizeof("true") - 1;
413 i = 1;
414 }
415
416 /*
417 * Is the rest white space?
418 */
419 while (RT_C_IS_SPACE(*psz))
420 psz++;
421 if (*psz != '\0')
422 {
423 iDigit = uBase;
424 break;
425 }
426 RT_FALL_THROUGH();
427
428 case '\0':
429 if (fNegative)
430 i = -i;
431 *piDst = i;
432 return rc;
433 }
434 if (iDigit >= uBase)
435 {
436 if (fNegative)
437 i = -i;
438 *piDst = i;
439 if (!fQuiet)
440 expr_error(pThis, "Invalid %u-base number \"%.80s\"", uBase, pszSrc);
441 return kExprRet_Error;
442 }
443
444 /* add the digit and advance */
445 /** @todo check for overflow? */
446 i *= uBase;
447 i += iDigit;
448 psz++;
449 }
450 /* not reached */
451}
452
453
454/**
455 * Checks if the variable is a string or not.
456 *
457 * @returns 1 if it's a string, 0 otherwise.
458 * @param pVar The variable.
459 */
460static int expr_var_is_string(PCEXPRVAR pVar)
461{
462 return pVar->enmType >= kExprVar_String;
463}
464
465
466/**
467 * Checks if the variable contains a string that was quoted
468 * in the expression.
469 *
470 * @returns 1 if if was a quoted string, otherwise 0.
471 * @param pVar The variable.
472 */
473static int expr_var_was_quoted(PCEXPRVAR pVar)
474{
475 return pVar->enmType >= kExprVar_QuotedString;
476}
477
478
479/**
480 * Deletes a variable.
481 *
482 * @param pVar The variable.
483 */
484static void expr_var_delete(PEXPRVAR pVar)
485{
486 if (expr_var_is_string(pVar))
487 {
488 RTMemTmpFree(pVar->uVal.psz);
489 pVar->uVal.psz = NULL;
490 }
491 pVar->enmType = kExprVar_Invalid;
492}
493
494
495/**
496 * Initializes a new variables with a sub-string value.
497 *
498 * @returns kExprRet_Ok or kExprRet_Error.
499 * @param pThis The evaluator expression instance.
500 * @param pVar The new variable.
501 * @param psz The start of the string value.
502 * @param cch The number of chars to copy.
503 * @param enmType The string type.
504 */
505static EXPRRET expr_var_init_substring(PEXPR pThis, PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType)
506{
507 /* convert string needing expanding into simple ones if possible. */
508 if ( enmType == kExprVar_String
509 && !memchr(psz, '$', cch))
510 enmType = kExprVar_SimpleString;
511 else if ( enmType == kExprVar_QuotedString
512 && !memchr(psz, '$', cch))
513 enmType = kExprVar_QuotedSimpleString;
514
515 pVar->enmType = enmType;
516 pVar->uVal.psz = (char *)RTMemTmpAlloc(cch + 1);
517 if (RT_LIKELY(pVar->uVal.psz))
518 {
519 memcpy(pVar->uVal.psz, psz, cch);
520 pVar->uVal.psz[cch] = '\0';
521 return kExprRet_Ok;
522 }
523 pVar->enmType = kExprVar_End;
524 RTErrInfoSetF(pThis->pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate %zu bytes", cch + 1);
525 return kExprRet_Error;
526}
527
528
529/**
530 * Initializes a new variables with a string value.
531 *
532 * @returns kExprRet_Ok or kExprRet_Error.
533 * @param pThis The evaluator expression instance.
534 * @param pVar The new variable.
535 * @param psz The string value.
536 * @param enmType The string type.
537 */
538static EXPRRET expr_var_init_string(PEXPR pThis, PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType)
539{
540 return expr_var_init_substring(pThis, pVar, psz, strlen(psz), enmType);
541}
542
543
544#if 0 /* unused */
545/**
546 * Assigns a sub-string value to a variable.
547 *
548 * @returns kExprRet_Ok or kExprRet_Error.
549 * @param pThis The evaluator expression instance.
550 * @param pVar The new variable.
551 * @param psz The start of the string value.
552 * @param cch The number of chars to copy.
553 * @param enmType The string type.
554 */
555static EXPRRET expr_var_assign_substring(PEXPR pThis, PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType)
556{
557 expr_var_delete(pVar);
558 return expr_var_init_substring(pThis, pVar, psz, cch, enmType);
559}
560#endif /* unused */
561
562
563/**
564 * Assignes a string value to a variable.
565 *
566 * @returns kExprRet_Ok or kExprRet_Error.
567 * @param pThis The evaluator expression instance.
568 * @param pVar The variable.
569 * @param psz The string value.
570 * @param enmType The string type.
571 */
572static EXPRRET expr_var_assign_string(PEXPR pThis, PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType)
573{
574 expr_var_delete(pVar);
575 return expr_var_init_string(pThis, pVar, psz, enmType);
576}
577
578
579/**
580 * Finds the end of the current variable expansion, taking nested expansion
581 * into account.
582 *
583 * This is somewhat similar to the code down in expr_get_unary_or_operand.
584 *
585 * @returns kExprRet_Ok or kExprRet_Error.
586 * @param pThis The evaluator expression instance.
587 * @param pchSrc Pointer to the dollar of the variable expansion.
588 * @param cchSrc The length of the variable expansion expression.
589 * @param pcchVarRef Where to return the length of the variable expansion.
590 * @param pfNested Where to return whether it's a nested (@c true) or plain
591 * one.
592 */
593static EXPRRET expr_expand_find_end(PEXPR pThis, const char *pchSrc, size_t cchSrc, size_t *pcchVarRef, bool *pfNested)
594{
595 const char * const pchStart = pchSrc;
596
597 /*
598 * Push the initial expression.
599 */
600 Assert(cchSrc >= 2);
601 Assert(pchSrc[0] == '$');
602 Assert(pchSrc[1] == '{');
603 unsigned cPars = 1;
604 pchSrc += 2;
605 cchSrc -= 2;
606
607 /*
608 * Parse the rest of the string till we've back at cPars == 0.
609 */
610 *pfNested = false;
611 while (cchSrc > 0)
612 {
613 char const ch = *pchSrc;
614 if ( ch == '$'
615 && cchSrc >= 2
616 && pchSrc[1] == '{')
617 {
618 if (cPars < EXPR_MAX_VAR_RECURSION)
619 cPars++;
620 else
621 {
622 *pcchVarRef = 0;
623 return expr_error(pThis, "Too deep nesting of variable expansions");
624 }
625 *pfNested = true;
626 pchSrc += 2;
627 cchSrc -= 2;
628 }
629 else
630 {
631 pchSrc += 1;
632 cchSrc -= 1;
633 if (ch == '}')
634 if (--cPars == 0)
635 {
636 *pcchVarRef = pchSrc - pchStart;
637 return kExprRet_Ok;
638 }
639 }
640 }
641 *pcchVarRef = 0;
642 return expr_error(pThis, "Unbalanced variable expansions: %.*s", pchStart, pchSrc - pchStart);
643}
644
645
646/**
647 * Returns the given string with all variables references replaced.
648 *
649 * @returns Pointer to expanded string on success (RTMemTmpFree), NULL on
650 * failure (error already set).
651 * @param pThis The evaluator expression instance.
652 * @param pchSrc The string to expand.
653 * @param cchSrc The length of the string to expand.
654 * @param cDepth The recursion depth, starting at zero.
655 */
656static char *expr_expand_string(PEXPR pThis, const char *pchSrc, size_t cchSrc, unsigned cDepth)
657{
658 if (cDepth < EXPR_MAX_VAR_RECURSION)
659 {
660 size_t cbRetAlloc = RT_ALIGN_Z(cchSrc + 1 + 16, 16);
661 char *pszRet = (char *)RTMemTmpAlloc(cbRetAlloc);
662 if (pszRet)
663 {
664 size_t offRet = 0;
665 while (cchSrc > 0)
666 {
667 /*
668 * Look for the next potential variable reference.
669 */
670 const char *pchDollar = (const char *)memchr(pchSrc, '$', cchSrc);
671 size_t cchPlain = pchDollar ? pchDollar - pchSrc : cchSrc;
672 size_t cchNext = cchPlain;
673
674 if (pchDollar)
675 {
676 /* Treat lone $ w/o a following { as plain text. */
677 if ( cchPlain + 1 >= cchSrc
678 && pchDollar[0] == '$'
679 && ( cchPlain + 1 == cchSrc
680 || pchDollar[1] != '{') )
681 {
682 cchPlain += 1;
683 cchNext += 1;
684 pchDollar += 1;
685 }
686 /* Eat up escaped dollars: $$ -> $ */
687 else
688 while (cchNext + 2 <= cchSrc && pchDollar[1] == '$' && pchDollar[0] == '$')
689 {
690 cchPlain += 1;
691 cchNext += 2;
692 pchDollar += 2;
693 }
694 }
695
696 /* Finally copy out plain text.*/
697 if (cchPlain > 0)
698 {
699 if (cchPlain >= cbRetAlloc - offRet)
700 {
701 size_t const cbNeeded = RT_ALIGN_Z(offRet + cchPlain + (!pchDollar ? 1 : offRet <= 64 ? 16 : 64), 16);
702 void *pvNew = RTMemTmpAlloc(cbNeeded);
703 if (pvNew)
704 memcpy(pvNew, pszRet, offRet);
705 RTMemTmpFree(pszRet);
706 pszRet = (char *)pvNew;
707 if (pvNew)
708 cbRetAlloc = cbNeeded;
709 else
710 {
711 RTErrInfoSetF(pThis->pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate %zu bytes", cbNeeded);
712 return NULL;
713 }
714 }
715
716 memcpy(&pszRet[offRet], pchSrc, cchPlain);
717 offRet += cchPlain;
718 pszRet[offRet] = '\0';
719 pchSrc += cchNext;
720 cchSrc -= cchNext;
721 if (!cchSrc)
722 break;
723
724 /* If we don't have ${, just loop. */
725 if ( cchSrc < 2
726 || pchSrc[0] != '$'
727 || pchSrc[1] != '{')
728 continue;
729 }
730
731 /*
732 * If we get down here we have a ${ or $( at pchSrc. The fun part now is
733 * finding the end of it and recursively dealing with any sub-expansions first.
734 */
735 Assert(pchSrc[0] == '$' && pchSrc[1] == '{');
736 size_t cchVarRef;
737 bool fNested;
738 if (expr_expand_find_end(pThis, pchSrc, cchSrc, &cchVarRef, &fNested) == kExprRet_Ok)
739 {
740 /* Lookup the variable. Simple when it's a plain one, for nested ones we
741 first have to expand the variable name itself before looking it up. */
742 char *pszValue;
743 int vrc;
744 if (!fNested)
745 vrc = pThis->pEvaluator->pfnQueryVariable(&pchSrc[2], cchSrc - 3, pThis->pEvaluator->pvUser, &pszValue);
746 else
747 {
748 char *pszName = expr_expand_string(pThis, &pchSrc[2], cchSrc - 3, cDepth + 1);
749 if (!pszName)
750 {
751 RTMemTmpFree(pszRet);
752 return NULL;
753 }
754 vrc = pThis->pEvaluator->pfnQueryVariable(pszName, strlen(pszName), pThis->pEvaluator->pvUser, &pszValue);
755 RTMemTmpFree(pszName);
756 }
757
758 /* Treat variables that aren't found as empty strings for now.
759 This may need to become configurable later. */
760 char *pszValueFree = pszValue;
761 static char s_szNotFound[] = "";
762 if (vrc == VERR_NOT_FOUND)
763 {
764 pszValue = s_szNotFound;
765 vrc = VINF_SUCCESS;
766 }
767
768 if (RT_SUCCESS(vrc))
769 {
770 /*
771 * Append the value to the return string.
772 */
773 size_t cchValue = strlen(pszValue);
774 if (cchValue > 0)
775 {
776 if (cchValue >= cbRetAlloc - offRet)
777 {
778 size_t const cbNeeded = RT_ALIGN_Z(offRet + cchValue + (!pchDollar ? 1 : offRet <= 64 ? 16 : 64),
779 16);
780 void *pvNew = RTMemTmpAlloc(cbNeeded);
781 if (pvNew)
782 memcpy(pvNew, pszRet, offRet);
783 RTMemTmpFree(pszRet);
784 pszRet = (char *)pvNew;
785 if (pvNew)
786 cbRetAlloc = cbNeeded;
787 else
788 {
789 RTErrInfoSetF(pThis->pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate %zu bytes", cbNeeded);
790 RTStrFree(pszValueFree);
791 return NULL;
792 }
793 }
794
795 memcpy(&pszRet[offRet], pszValue, cchValue);
796 offRet += cchValue;
797 pszRet[offRet] = '\0';
798 }
799 pchSrc += cchVarRef;
800 cchSrc -= cchVarRef;
801 RTStrFree(pszValueFree);
802 continue;
803 }
804 }
805 RTMemTmpFree(pszRet);
806 return NULL;
807 }
808 return pszRet;
809 }
810 RTErrInfoSetF(pThis->pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate %zu bytes", cbRetAlloc);
811 }
812 else
813 RTErrInfoSet(pThis->pErrInfo, VERR_TOO_MUCH_DATA, "Too deeply nested variable expression");
814 return NULL;
815}
816
817
818/**
819 * Simplifies a string variable.
820 *
821 * @returns kExprRet_Ok or kExprRet_Error.
822 * @param pThis The evaluator expression instance.
823 * @param pVar The variable.
824 */
825static EXPRRET expr_var_make_simple_string(PEXPR pThis, PEXPRVAR pVar)
826{
827 switch (pVar->enmType)
828 {
829 case kExprVar_Num:
830 {
831 char *psz = (char *)RTMemTmpAlloc(EXPR_NUM_LEN);
832 if (psz)
833 {
834 expr_num_to_string(psz, pVar->uVal.i);
835 pVar->uVal.psz = psz;
836 pVar->enmType = kExprVar_SimpleString;
837 }
838 else
839 {
840 RTErrInfoSetF(pThis->pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate %zu bytes", EXPR_NUM_LEN);
841 return kExprRet_Error;
842 }
843 break;
844 }
845
846 case kExprVar_String:
847 case kExprVar_QuotedString:
848 {
849 Assert(strchr(pVar->uVal.psz, '$'));
850 char *psz = expr_expand_string(pThis, pVar->uVal.psz, strlen(pVar->uVal.psz), 0);
851 if (psz)
852 {
853 RTMemTmpFree(pVar->uVal.psz);
854 pVar->uVal.psz = psz;
855
856 pVar->enmType = pVar->enmType == kExprVar_String
857 ? kExprVar_SimpleString
858 : kExprVar_QuotedSimpleString;
859 }
860 else
861 return kExprRet_Error;
862 break;
863 }
864
865 case kExprVar_SimpleString:
866 case kExprVar_QuotedSimpleString:
867 /* nothing to do. */
868 break;
869
870 default:
871 AssertMsgFailed(("%d\n", pVar->enmType));
872 }
873 return kExprRet_Ok;
874}
875
876
877#if 0 /* unused */
878/**
879 * Turns a variable into a string value.
880 *
881 * @param pVar The variable.
882 */
883static void expr_var_make_string(PEXPRVAR pVar)
884{
885 switch (pVar->enmType)
886 {
887 case kExprVar_Num:
888 expr_var_make_simple_string(pVar);
889 break;
890
891 case kExprVar_String:
892 case kExprVar_SimpleString:
893 case kExprVar_QuotedString:
894 case kExprVar_QuotedSimpleString:
895 /* nothing to do. */
896 break;
897
898 default:
899 AssertMsgFailed(("%d\n", pVar->enmType));
900 }
901}
902#endif /* unused */
903
904
905/**
906 * Initializes a new variables with a integer value.
907 *
908 * @param pVar The new variable.
909 * @param i The integer value.
910 */
911static void expr_var_init_num(PEXPRVAR pVar, EXPRINT64 i)
912{
913 pVar->enmType = kExprVar_Num;
914 pVar->uVal.i = i;
915}
916
917
918/**
919 * Assigns a integer value to a variable.
920 *
921 * @param pVar The variable.
922 * @param i The integer value.
923 */
924static void expr_var_assign_num(PEXPRVAR pVar, EXPRINT64 i)
925{
926 expr_var_delete(pVar);
927 expr_var_init_num(pVar, i);
928}
929
930
931/**
932 * Turns the variable into a number.
933 *
934 * @returns status code.
935 * @param pThis The evaluator instance.
936 * @param pVar The variable.
937 */
938static EXPRRET expr_var_make_num(PEXPR pThis, PEXPRVAR pVar)
939{
940 switch (pVar->enmType)
941 {
942 case kExprVar_Num:
943 /* nothing to do. */
944 break;
945
946 case kExprVar_String:
947 {
948 EXPRRET rc = expr_var_make_simple_string(pThis, pVar);
949 if (rc != kExprRet_Ok)
950 return rc;
951 RT_FALL_THROUGH();
952 }
953 case kExprVar_SimpleString:
954 {
955 EXPRINT64 i;
956 EXPRRET rc = expr_string_to_num(pThis, &i, pVar->uVal.psz, 0 /* fQuiet */);
957 if (rc < kExprRet_Ok)
958 return rc;
959 expr_var_assign_num(pVar, i);
960 break;
961 }
962
963 case kExprVar_QuotedString:
964 case kExprVar_QuotedSimpleString:
965 return expr_error(pThis, "Cannot convert a quoted string to a number");
966
967 default:
968 AssertMsgFailedReturn(("%d\n", pVar->enmType), kExprRet_Error);
969 }
970
971 return kExprRet_Ok;
972}
973
974
975/**
976 * Try to turn the variable into a number.
977 *
978 * @returns status code.
979 * @param pThis The instance.
980 * @param pVar The variable.
981 */
982static EXPRRET expr_var_try_make_num(PEXPR pThis, PEXPRVAR pVar)
983{
984 EXPRRET rc;
985 switch (pVar->enmType)
986 {
987 case kExprVar_Num:
988 /* nothing to do. */
989 break;
990
991 case kExprVar_String:
992 rc = expr_var_make_simple_string(pThis, pVar);
993 if (rc != kExprRet_Ok)
994 return rc;
995 RT_FALL_THROUGH();
996 case kExprVar_SimpleString:
997 {
998 EXPRINT64 i;
999 rc = expr_string_to_num(pThis, &i, pVar->uVal.psz, 1 /* fQuiet */);
1000 if (rc < kExprRet_Ok)
1001 return rc;
1002 expr_var_assign_num(pVar, i);
1003 break;
1004 }
1005
1006 case kExprVar_QuotedString:
1007 case kExprVar_QuotedSimpleString:
1008 /* can't do this */
1009 return kExprRet_Error;
1010
1011 default:
1012 AssertMsgFailedReturn(("%d\n", pVar->enmType), kExprRet_Error);
1013 }
1014
1015 return kExprRet_Ok;
1016}
1017
1018
1019/**
1020 * Initializes a new variables with a boolean value.
1021 *
1022 * @param pVar The new variable.
1023 * @param f The boolean value.
1024 */
1025static void expr_var_init_bool(PEXPRVAR pVar, int f)
1026{
1027 pVar->enmType = kExprVar_Num;
1028 pVar->uVal.i = !!f;
1029}
1030
1031
1032/**
1033 * Assigns a boolean value to a variable.
1034 *
1035 * @param pVar The variable.
1036 * @param f The boolean value.
1037 */
1038static void expr_var_assign_bool(PEXPRVAR pVar, int f)
1039{
1040 expr_var_delete(pVar);
1041 expr_var_init_bool(pVar, f);
1042}
1043
1044
1045/**
1046 * Turns the variable into an boolean.
1047 *
1048 * @returns the boolean interpretation.
1049 * @param pThis The instance.
1050 * @param pVar The variable.
1051 */
1052static EXPRRET expr_var_make_bool(PEXPR pThis, PEXPRVAR pVar)
1053{
1054 EXPRRET rc = kExprRet_Ok;
1055
1056 switch (pVar->enmType)
1057 {
1058 case kExprVar_Num:
1059 pVar->uVal.i = !!pVar->uVal.i;
1060 break;
1061
1062 case kExprVar_String:
1063 rc = expr_var_make_simple_string(pThis, pVar);
1064 if (rc != kExprRet_Ok)
1065 break;
1066 RT_FALL_THROUGH();
1067 case kExprVar_SimpleString:
1068 {
1069 /*
1070 * Try convert it to a number. If that fails, check for 'true' or
1071 * 'false', if neither then use python / GNU make logic wrt strings.
1072 */
1073 EXPRINT64 iVal;
1074 char const *psz = pVar->uVal.psz;
1075 while (RT_C_IS_BLANK(*psz))
1076 psz++;
1077 if ( *psz
1078 && expr_string_to_num(pThis, &iVal, psz, 1 /* fQuiet */) >= kExprRet_Ok)
1079 expr_var_assign_bool(pVar, iVal != 0);
1080 else if ( strncmp(psz, RT_STR_TUPLE("true")) == 0
1081 && *RTStrStripL(&psz[sizeof("true") - 1]) == '\0')
1082 expr_var_assign_bool(pVar, true);
1083 else if ( strncmp(psz, RT_STR_TUPLE("false")) == 0
1084 && *RTStrStripL(&psz[sizeof("false") - 1]) == '\0')
1085 expr_var_assign_bool(pVar, false);
1086 else
1087 expr_var_assign_bool(pVar, *psz != '\0');
1088 break;
1089 }
1090
1091 case kExprVar_QuotedString:
1092 rc = expr_var_make_simple_string(pThis, pVar);
1093 if (rc != kExprRet_Ok)
1094 break;
1095 RT_FALL_THROUGH();
1096 case kExprVar_QuotedSimpleString:
1097 /*
1098 * Use python / GNU make boolean logic: non-empty string means true.
1099 * No stripping here, as the string is quoted as should be taken exactly as given.
1100 */
1101 expr_var_assign_bool(pVar, *pVar->uVal.psz != '\0');
1102 break;
1103
1104 default:
1105 AssertMsgFailed(("%d\n", pVar->enmType));
1106 }
1107
1108 return rc;
1109}
1110
1111
1112/**
1113 * Pops a varable off the stack and deletes it.
1114 * @param pThis The evaluator instance.
1115 */
1116static void expr_pop_and_delete_var(PEXPR pThis)
1117{
1118 expr_var_delete(&pThis->aVars[pThis->iVar]);
1119 pThis->iVar--;
1120}
1121
1122
1123
1124/**
1125 * Tries to make the variables the same type.
1126 *
1127 * This will not convert numbers to strings, unless one of them
1128 * is a quoted string.
1129 *
1130 * this will try convert both to numbers if neither is quoted. Both
1131 * conversions will have to suceed for this to be commited.
1132 *
1133 * All strings will be simplified.
1134 *
1135 * @returns status code. Done complaining on failure.
1136 *
1137 * @param pThis The evaluator instance.
1138 * @param pVar1 The first variable.
1139 * @param pVar2 The second variable.
1140 * @param pszOp The operator requesting this (for errors).
1141 */
1142static EXPRRET expr_var_unify_types(PEXPR pThis, PEXPRVAR pVar1, PEXPRVAR pVar2, const char *pszOp)
1143{
1144/** @todo Add flag for selecting preference here when forcing types */
1145
1146
1147 /*
1148 * Try make the variables the same type before comparing.
1149 */
1150 if ( !expr_var_was_quoted(pVar1)
1151 && !expr_var_was_quoted(pVar2))
1152 {
1153 if ( expr_var_is_string(pVar1)
1154 || expr_var_is_string(pVar2))
1155 {
1156 if (!expr_var_is_string(pVar1))
1157 expr_var_try_make_num(pThis, pVar2);
1158 else if (!expr_var_is_string(pVar2))
1159 expr_var_try_make_num(pThis, pVar1);
1160 else
1161 {
1162 /*
1163 * Both are strings, simplify them then see if both can be made into numbers.
1164 */
1165 EXPRRET rc = expr_var_make_simple_string(pThis, pVar1);
1166 if (rc == kExprRet_Ok)
1167 rc = expr_var_make_simple_string(pThis, pVar2);
1168 if (rc == kExprRet_Ok)
1169 {
1170 EXPRINT64 iVar1;
1171 EXPRINT64 iVar2;
1172 if ( expr_string_to_num(pThis, &iVar1, pVar1->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok
1173 && expr_string_to_num(pThis, &iVar2, pVar2->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok)
1174 {
1175 expr_var_assign_num(pVar1, iVar1);
1176 expr_var_assign_num(pVar2, iVar2);
1177 }
1178 }
1179 else
1180 return rc;
1181 }
1182 }
1183 }
1184 else
1185 {
1186 EXPRRET rc = expr_var_make_simple_string(pThis, pVar1);
1187 if (rc == kExprRet_Ok)
1188 rc = expr_var_make_simple_string(pThis, pVar2);
1189 if (rc == kExprRet_Ok)
1190 { /* likely */ }
1191 else
1192 return rc;
1193 }
1194
1195 /*
1196 * Complain if they aren't the same type now.
1197 */
1198 if (expr_var_is_string(pVar1) != expr_var_is_string(pVar2))
1199 return expr_error(pThis, "Unable to unify types for \"%s\"", pszOp);
1200 return kExprRet_Ok;
1201}
1202
1203
1204
1205/*********************************************************************************************************************************
1206* Operators *
1207*********************************************************************************************************************************/
1208
1209/**
1210 * Is variable defined, unary.
1211 *
1212 * @returns Status code.
1213 * @param pThis The instance.
1214 */
1215static EXPRRET expr_op_defined(PEXPR pThis)
1216{
1217 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1218
1219 EXPRRET rc = expr_var_make_simple_string(pThis, pVar);
1220 if (rc == kExprRet_Ok)
1221 {
1222 int vrc = pThis->pEvaluator->pfnQueryVariable(pVar->uVal.psz, strlen(pVar->uVal.psz), pThis->pEvaluator->pvUser, NULL);
1223 expr_var_assign_bool(pVar, vrc != VERR_NOT_FOUND);
1224 }
1225
1226 return rc;
1227}
1228
1229
1230/**
1231 * Does file(/dir/whatever) exist, unary.
1232 *
1233 * @returns Status code.
1234 * @param pThis The instance.
1235 */
1236static EXPRRET expr_op_exists(PEXPR pThis)
1237{
1238 EXPRRET rc;
1239 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1240
1241 if (pThis->pEvaluator->fFlags & RTEXPREVAL_F_EXISTS_OP)
1242 {
1243 rc = expr_var_make_simple_string(pThis, pVar);
1244 if (rc == kExprRet_Ok)
1245 expr_var_assign_bool(pVar, RTPathExists(pVar->uVal.psz) == 0);
1246 }
1247 else
1248 rc = expr_error(pThis, "The 'exists' operator is not accessible");
1249
1250 return rc;
1251}
1252
1253
1254/**
1255 * Convert to boolean.
1256 *
1257 * @returns Status code.
1258 * @param pThis The instance.
1259 */
1260static EXPRRET expr_op_bool(PEXPR pThis)
1261{
1262 return expr_var_make_bool(pThis, &pThis->aVars[pThis->iVar]);
1263}
1264
1265
1266/**
1267 * Convert to number, works on quoted strings too.
1268 *
1269 * @returns Status code.
1270 * @param pThis The instance.
1271 */
1272static EXPRRET expr_op_num(PEXPR pThis)
1273{
1274 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1275
1276 /* unquote the string */
1277 if (pVar->enmType == kExprVar_QuotedSimpleString)
1278 pVar->enmType = kExprVar_SimpleString;
1279 else if (pVar->enmType == kExprVar_QuotedString)
1280 pVar->enmType = kExprVar_String;
1281
1282 return expr_var_make_num(pThis, pVar);
1283}
1284
1285
1286/**
1287 * Performs a strlen() on the simplified/converted string argument.
1288 *
1289 * @returns Status code.
1290 * @param pThis The instance.
1291 */
1292static EXPRRET expr_op_strlen(PEXPR pThis)
1293{
1294 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1295 EXPRRET rc = expr_var_make_simple_string(pThis, pVar);
1296 if (rc == kExprRet_Ok)
1297 expr_var_assign_num(pVar, strlen(pVar->uVal.psz));
1298
1299 return rc;
1300}
1301
1302
1303/**
1304 * Convert to string (simplified and quoted)
1305 *
1306 * @returns Status code.
1307 * @param pThis The instance.
1308 */
1309static EXPRRET expr_op_str(PEXPR pThis)
1310{
1311 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1312 EXPRRET rc = expr_var_make_simple_string(pThis, pVar);
1313 if (rc == kExprRet_Ok)
1314 pVar->enmType = kExprVar_QuotedSimpleString;
1315
1316 return rc;
1317}
1318
1319
1320/**
1321 * Returns the MD5 digest of the input as a string.
1322 *
1323 * @returns Status code.
1324 * @param pThis The instance.
1325 */
1326static EXPRRET expr_op_md5(PEXPR pThis)
1327{
1328 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1329 EXPRRET rc = expr_var_make_simple_string(pThis, pVar);
1330 if (rc == kExprRet_Ok)
1331 {
1332 pVar->enmType = kExprVar_QuotedSimpleString;
1333
1334 uint8_t abDigest[RTMD5_HASH_SIZE];
1335 RTMd5(pVar->uVal.psz, strlen(pVar->uVal.psz), abDigest);
1336 char szHash[RTMD5_DIGEST_LEN + 1];
1337 RTMd5ToString(abDigest, szHash, sizeof(szHash));
1338
1339 rc = expr_var_assign_string(pThis, pVar, szHash, kExprVar_QuotedSimpleString);
1340 }
1341
1342 return rc;
1343}
1344
1345
1346/**
1347 * Returns the SHA1 digest of the input as a string.
1348 *
1349 * @returns Status code.
1350 * @param pThis The instance.
1351 */
1352static EXPRRET expr_op_sha1(PEXPR pThis)
1353{
1354 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1355 EXPRRET rc = expr_var_make_simple_string(pThis, pVar);
1356 if (rc == kExprRet_Ok)
1357 {
1358 pVar->enmType = kExprVar_QuotedSimpleString;
1359
1360 uint8_t abDigest[RTSHA1_HASH_SIZE];
1361 RTSha1(pVar->uVal.psz, strlen(pVar->uVal.psz), abDigest);
1362 char szHash[RTSHA1_DIGEST_LEN + 1];
1363 RTSha1ToString(abDigest, szHash, sizeof(szHash));
1364
1365 rc = expr_var_assign_string(pThis, pVar, szHash, kExprVar_QuotedSimpleString);
1366 }
1367
1368 return rc;
1369}
1370
1371
1372/**
1373 * Returns the SHA256 digest of the input as a string.
1374 *
1375 * @returns Status code.
1376 * @param pThis The instance.
1377 */
1378static EXPRRET expr_op_sha256(PEXPR pThis)
1379{
1380 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1381 EXPRRET rc = expr_var_make_simple_string(pThis, pVar);
1382 if (rc == kExprRet_Ok)
1383 {
1384 pVar->enmType = kExprVar_QuotedSimpleString;
1385
1386 uint8_t abDigest[RTSHA256_HASH_SIZE];
1387 RTSha256(pVar->uVal.psz, strlen(pVar->uVal.psz), abDigest);
1388 char szHash[RTSHA256_DIGEST_LEN + 1];
1389 RTSha256ToString(abDigest, szHash, sizeof(szHash));
1390
1391 rc = expr_var_assign_string(pThis, pVar, szHash, kExprVar_QuotedSimpleString);
1392 }
1393
1394 return rc;
1395}
1396
1397
1398/**
1399 * Returns the SHA-512 digest of the input as a string.
1400 *
1401 * @returns Status code.
1402 * @param pThis The instance.
1403 */
1404static EXPRRET expr_op_sha512(PEXPR pThis)
1405{
1406 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1407 EXPRRET rc = expr_var_make_simple_string(pThis, pVar);
1408 if (rc == kExprRet_Ok)
1409 {
1410 pVar->enmType = kExprVar_QuotedSimpleString;
1411
1412 uint8_t abDigest[RTSHA512_HASH_SIZE];
1413 RTSha512(pVar->uVal.psz, strlen(pVar->uVal.psz), abDigest);
1414 char szHash[RTSHA512_DIGEST_LEN + 1];
1415 RTSha512ToString(abDigest, szHash, sizeof(szHash));
1416
1417 rc = expr_var_assign_string(pThis, pVar, szHash, kExprVar_QuotedSimpleString);
1418 }
1419
1420 return rc;
1421}
1422
1423
1424/**
1425 * Pluss (dummy / make_integer)
1426 *
1427 * @returns Status code.
1428 * @param pThis The instance.
1429 */
1430static EXPRRET expr_op_pluss(PEXPR pThis)
1431{
1432 return expr_var_make_num(pThis, &pThis->aVars[pThis->iVar]);
1433}
1434
1435
1436/**
1437 * Minus (negate)
1438 *
1439 * @returns Status code.
1440 * @param pThis The instance.
1441 */
1442static EXPRRET expr_op_minus(PEXPR pThis)
1443{
1444 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1445 EXPRRET rc = expr_var_make_num(pThis, pVar);
1446 if (rc >= kExprRet_Ok)
1447 pVar->uVal.i = -pVar->uVal.i;
1448
1449 return rc;
1450}
1451
1452
1453
1454/**
1455 * Bitwise NOT.
1456 *
1457 * @returns Status code.
1458 * @param pThis The instance.
1459 */
1460static EXPRRET expr_op_bitwise_not(PEXPR pThis)
1461{
1462 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1463 EXPRRET rc = expr_var_make_num(pThis, pVar);
1464 if (rc >= kExprRet_Ok)
1465 pVar->uVal.i = ~pVar->uVal.i;
1466
1467 return rc;
1468}
1469
1470
1471/**
1472 * Logical NOT.
1473 *
1474 * @returns Status code.
1475 * @param pThis The instance.
1476 */
1477static EXPRRET expr_op_logical_not(PEXPR pThis)
1478{
1479 PEXPRVAR pVar = &pThis->aVars[pThis->iVar];
1480 EXPRRET rc = expr_var_make_bool(pThis, pVar);
1481 if (rc == kExprRet_Ok)
1482 pVar->uVal.i = !pVar->uVal.i;
1483
1484 return rc;
1485}
1486
1487
1488/**
1489 * Multiplication.
1490 *
1491 * @returns Status code.
1492 * @param pThis The instance.
1493 */
1494static EXPRRET expr_op_multiply(PEXPR pThis)
1495{
1496 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1497 EXPRRET rc = expr_var_make_num(pThis, pVar1);
1498 if (rc >= kExprRet_Ok)
1499 {
1500 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1501 rc = expr_var_make_num(pThis, pVar2);
1502 if (rc >= kExprRet_Ok)
1503 pVar1->uVal.i *= pVar2->uVal.i;
1504 }
1505 expr_pop_and_delete_var(pThis);
1506 return rc;
1507}
1508
1509
1510
1511/**
1512 * Division.
1513 *
1514 * @returns Status code.
1515 * @param pThis The instance.
1516 */
1517static EXPRRET expr_op_divide(PEXPR pThis)
1518{
1519 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1520 EXPRRET rc = expr_var_make_num(pThis, pVar1);
1521 if (rc >= kExprRet_Ok)
1522 {
1523 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1524 rc = expr_var_make_num(pThis, pVar2);
1525 if (rc >= kExprRet_Ok)
1526 pVar1->uVal.i /= pVar2->uVal.i;
1527 }
1528 expr_pop_and_delete_var(pThis);
1529 return rc;
1530}
1531
1532
1533
1534/**
1535 * Modulus.
1536 *
1537 * @returns Status code.
1538 * @param pThis The instance.
1539 */
1540static EXPRRET expr_op_modulus(PEXPR pThis)
1541{
1542 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1543 EXPRRET rc = expr_var_make_num(pThis, pVar1);
1544 if (rc >= kExprRet_Ok)
1545 {
1546 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1547 rc = expr_var_make_num(pThis, pVar2);
1548 if (rc >= kExprRet_Ok)
1549 pVar1->uVal.i %= pVar2->uVal.i;
1550 }
1551 expr_pop_and_delete_var(pThis);
1552 return rc;
1553}
1554
1555
1556#if 0 /** @todo not happy with 'strcat' as an operator. Dot doesn't work, so, figure something else out... */
1557/**
1558 * Concatnation (string).
1559 *
1560 * @returns Status code.
1561 * @param pThis The instance.
1562 */
1563static EXPRRET expr_op_concat(PEXPR pThis)
1564{
1565 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1566 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1567 EXPRRET rc = kExprRet_Ok;
1568 if (!expr_var_is_string(pVar1))
1569 rc = expr_var_make_simple_string(pThis, pVar1);
1570 if (rc >= kExprRet_Ok)
1571 {
1572 if (!expr_var_is_string(pVar2))
1573 rc = expr_var_make_simple_string(pThis, pVar2);
1574 if (rc >= kExprRet_Ok)
1575 {
1576 /** @todo this may be problematic if we combine simple with quoted strings
1577 * if the simple string contains $. */
1578 if (rc >= kExprRet_Ok)
1579 {
1580 size_t cchVar1 = strlen(pVar1->uVal.psz);
1581 size_t cchVar2 = strlen(pVar2->uVal.psz);
1582 size_t cchNew = cchVar1 + cchVar2;
1583 char *pszNew = (char *)RTMemTmpAlloc(cchNew + 1);
1584 if (pszNew)
1585 {
1586 memcpy(pszNew, pVar1->uVal.psz, cchVar1);
1587 memcpy(&pszNew[cchVar1], pVar2->uVal.psz, cchVar2);
1588 pszNew[cchNew] = '\0';
1589 RTMemTmpFree(pVar1->uVal.psz);
1590 pVar1->uVal.psz = pszNew;
1591 }
1592 else
1593 {
1594 RTErrInfoSetF(pThis->pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate %zu bytes", cchNew + 1);
1595 rc = kExprRet_Error;
1596 }
1597 }
1598 }
1599 }
1600
1601 expr_pop_and_delete_var(pThis);
1602 return rc;
1603}
1604#endif
1605
1606
1607/**
1608 * Addition (numeric).
1609 *
1610 * @returns Status code.
1611 * @param pThis The instance.
1612 */
1613static EXPRRET expr_op_add(PEXPR pThis)
1614{
1615 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1616 EXPRRET rc = expr_var_make_num(pThis, pVar1);
1617 if (rc >= kExprRet_Ok)
1618 {
1619 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1620 rc = expr_var_make_num(pThis, pVar2);
1621 if (rc >= kExprRet_Ok)
1622 pVar1->uVal.i += pVar2->uVal.i;
1623 }
1624 expr_pop_and_delete_var(pThis);
1625 return rc;
1626}
1627
1628
1629/**
1630 * Subtract (numeric).
1631 *
1632 * @returns Status code.
1633 * @param pThis The instance.
1634 */
1635static EXPRRET expr_op_sub(PEXPR pThis)
1636{
1637 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1638 EXPRRET rc = expr_var_make_num(pThis, pVar1);
1639 if (rc >= kExprRet_Ok)
1640 {
1641 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1642 rc = expr_var_make_num(pThis, pVar2);
1643 if (rc >= kExprRet_Ok)
1644 pVar1->uVal.i -= pVar2->uVal.i;
1645 }
1646 expr_pop_and_delete_var(pThis);
1647 return rc;
1648}
1649
1650
1651/**
1652 * Bitwise left shift.
1653 *
1654 * @returns Status code.
1655 * @param pThis The instance.
1656 */
1657static EXPRRET expr_op_shift_left(PEXPR pThis)
1658{
1659 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1660 EXPRRET rc = expr_var_make_num(pThis, pVar1);
1661 if (rc >= kExprRet_Ok)
1662 {
1663 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1664 rc = expr_var_make_num(pThis, pVar2);
1665 if (rc >= kExprRet_Ok)
1666 pVar1->uVal.i <<= pVar2->uVal.i;
1667 }
1668 expr_pop_and_delete_var(pThis);
1669 return rc;
1670}
1671
1672
1673/**
1674 * Bitwise right shift.
1675 *
1676 * @returns Status code.
1677 * @param pThis The instance.
1678 */
1679static EXPRRET expr_op_shift_right(PEXPR pThis)
1680{
1681 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1682 EXPRRET rc = expr_var_make_num(pThis, pVar1);
1683 if (rc >= kExprRet_Ok)
1684 {
1685 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1686 rc = expr_var_make_num(pThis, pVar2);
1687 if (rc >= kExprRet_Ok)
1688 pVar1->uVal.i >>= pVar2->uVal.i;
1689 }
1690 expr_pop_and_delete_var(pThis);
1691 return rc;
1692}
1693
1694
1695/**
1696 * Less than or equal, version string.
1697 *
1698 * @returns Status code.
1699 * @param pThis The instance.
1700 */
1701static EXPRRET expr_op_ver_less_or_equal_than(PEXPR pThis)
1702{
1703 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1704 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1705 EXPRRET rc = expr_var_unify_types(pThis, pVar1, pVar2, "vle");
1706 if (rc >= kExprRet_Ok)
1707 {
1708 if (!expr_var_is_string(pVar1))
1709 expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i);
1710 else
1711 expr_var_assign_bool(pVar1, RTStrVersionCompare(pVar1->uVal.psz, pVar2->uVal.psz) <= 0);
1712 }
1713 expr_pop_and_delete_var(pThis);
1714 return rc;
1715}
1716
1717
1718/**
1719 * Less than or equal.
1720 *
1721 * @returns Status code.
1722 * @param pThis The instance.
1723 */
1724static EXPRRET expr_op_less_or_equal_than(PEXPR pThis)
1725{
1726 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1727 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1728 EXPRRET rc = expr_var_unify_types(pThis, pVar1, pVar2, "<=");
1729 if (rc >= kExprRet_Ok)
1730 {
1731 if (!expr_var_is_string(pVar1))
1732 expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i);
1733 else
1734 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) <= 0);
1735 }
1736 expr_pop_and_delete_var(pThis);
1737 return rc;
1738}
1739
1740
1741/**
1742 * Less than, version string.
1743 *
1744 * @returns Status code.
1745 * @param pThis The instance.
1746 */
1747static EXPRRET expr_op_ver_less_than(PEXPR pThis)
1748{
1749 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1750 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1751 EXPRRET rc = expr_var_unify_types(pThis, pVar1, pVar2, "vlt");
1752 if (rc >= kExprRet_Ok)
1753 {
1754 if (!expr_var_is_string(pVar1))
1755 expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i);
1756 else
1757 expr_var_assign_bool(pVar1, RTStrVersionCompare(pVar1->uVal.psz, pVar2->uVal.psz) < 0);
1758 }
1759 expr_pop_and_delete_var(pThis);
1760 return rc;
1761}
1762
1763
1764/**
1765 * Less than.
1766 *
1767 * @returns Status code.
1768 * @param pThis The instance.
1769 */
1770static EXPRRET expr_op_less_than(PEXPR pThis)
1771{
1772 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1773 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1774 EXPRRET rc = expr_var_unify_types(pThis, pVar1, pVar2, "<");
1775 if (rc >= kExprRet_Ok)
1776 {
1777 if (!expr_var_is_string(pVar1))
1778 expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i);
1779 else
1780 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) < 0);
1781 }
1782 expr_pop_and_delete_var(pThis);
1783 return rc;
1784}
1785
1786
1787/**
1788 * Greater or equal than, version string.
1789 *
1790 * @returns Status code.
1791 * @param pThis The instance.
1792 */
1793static EXPRRET expr_op_ver_greater_or_equal_than(PEXPR pThis)
1794{
1795 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1796 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1797 EXPRRET rc = expr_var_unify_types(pThis, pVar1, pVar2, "vge");
1798 if (rc >= kExprRet_Ok)
1799 {
1800 if (!expr_var_is_string(pVar1))
1801 expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i);
1802 else
1803 expr_var_assign_bool(pVar1, RTStrVersionCompare(pVar1->uVal.psz, pVar2->uVal.psz) >= 0);
1804 }
1805 expr_pop_and_delete_var(pThis);
1806 return rc;
1807}
1808
1809
1810/**
1811 * Greater or equal than.
1812 *
1813 * @returns Status code.
1814 * @param pThis The instance.
1815 */
1816static EXPRRET expr_op_greater_or_equal_than(PEXPR pThis)
1817{
1818 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1819 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1820 EXPRRET rc = expr_var_unify_types(pThis, pVar1, pVar2, ">=");
1821 if (rc >= kExprRet_Ok)
1822 {
1823 if (!expr_var_is_string(pVar1))
1824 expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i);
1825 else
1826 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) >= 0);
1827 }
1828 expr_pop_and_delete_var(pThis);
1829 return rc;
1830}
1831
1832
1833/**
1834 * Greater than, version string.
1835 *
1836 * @returns Status code.
1837 * @param pThis The instance.
1838 */
1839static EXPRRET expr_op_ver_greater_than(PEXPR pThis)
1840{
1841 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1842 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1843 EXPRRET rc = expr_var_unify_types(pThis, pVar1, pVar2, "vgt");
1844 if (rc >= kExprRet_Ok)
1845 {
1846 if (!expr_var_is_string(pVar1))
1847 expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i);
1848 else
1849 expr_var_assign_bool(pVar1, RTStrVersionCompare(pVar1->uVal.psz, pVar2->uVal.psz) > 0);
1850 }
1851 expr_pop_and_delete_var(pThis);
1852 return rc;
1853}
1854
1855
1856/**
1857 * Greater than.
1858 *
1859 * @returns Status code.
1860 * @param pThis The instance.
1861 */
1862static EXPRRET expr_op_greater_than(PEXPR pThis)
1863{
1864 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1865 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1866 EXPRRET rc = expr_var_unify_types(pThis, pVar1, pVar2, ">");
1867 if (rc >= kExprRet_Ok)
1868 {
1869 if (!expr_var_is_string(pVar1))
1870 expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i);
1871 else
1872 expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) > 0);
1873 }
1874 expr_pop_and_delete_var(pThis);
1875 return rc;
1876}
1877
1878
1879/**
1880 * Equal, version strings.
1881 *
1882 * @returns Status code.
1883 * @param pThis The instance.
1884 */
1885static EXPRRET expr_op_ver_equal(PEXPR pThis)
1886{
1887 EXPRRET rc = kExprRet_Ok;
1888 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1889 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1890 int const fIsString1 = expr_var_is_string(pVar1);
1891
1892 /*
1893 * The same type?
1894 */
1895 if (fIsString1 == expr_var_is_string(pVar2))
1896 {
1897 if (!fIsString1)
1898 /* numbers are simple */
1899 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1900 else
1901 {
1902 /* try a normal string compare. */
1903 rc = expr_var_make_simple_string(pThis, pVar1);
1904 if (rc == kExprRet_Ok)
1905 rc = expr_var_make_simple_string(pThis, pVar2);
1906 if (rc == kExprRet_Ok)
1907 {
1908 if (!RTStrVersionCompare(pVar1->uVal.psz, pVar2->uVal.psz))
1909 expr_var_assign_bool(pVar1, 1);
1910 /* try convert and compare as number instead. */
1911 else if ( expr_var_try_make_num(pThis, pVar1) >= kExprRet_Ok
1912 && expr_var_try_make_num(pThis, pVar2) >= kExprRet_Ok)
1913 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1914 /* ok, they really aren't equal. */
1915 else
1916 expr_var_assign_bool(pVar1, 0);
1917 }
1918 }
1919 }
1920 else
1921 {
1922 /*
1923 * If the type differs, there are now two options:
1924 * 1. Try convert the string to a valid number and compare the numbers.
1925 * 2. Convert the non-string to a number and compare the strings.
1926 */
1927 if ( expr_var_try_make_num(pThis, pVar1) >= kExprRet_Ok
1928 && expr_var_try_make_num(pThis, pVar2) >= kExprRet_Ok)
1929 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1930 else
1931 {
1932 rc = expr_var_make_simple_string(pThis, pVar1);
1933 if (rc == kExprRet_Ok)
1934 rc = expr_var_make_simple_string(pThis, pVar2);
1935 if (rc == kExprRet_Ok)
1936 expr_var_assign_bool(pVar1, RTStrVersionCompare(pVar1->uVal.psz, pVar2->uVal.psz) == 0);
1937 }
1938 }
1939
1940 expr_pop_and_delete_var(pThis);
1941 return rc;
1942}
1943
1944
1945/**
1946 * Not equal, version string.
1947 *
1948 * @returns Status code.
1949 * @param pThis The instance.
1950 */
1951static EXPRRET expr_op_ver_not_equal(PEXPR pThis)
1952{
1953 EXPRRET rc = expr_op_ver_equal(pThis);
1954 if (rc >= kExprRet_Ok)
1955 rc = expr_op_logical_not(pThis);
1956 return rc;
1957}
1958
1959
1960/**
1961 * Equal.
1962 *
1963 * @returns Status code.
1964 * @param pThis The instance.
1965 */
1966static EXPRRET expr_op_equal(PEXPR pThis)
1967{
1968 EXPRRET rc = kExprRet_Ok;
1969 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1970 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
1971 int const fIsString1 = expr_var_is_string(pVar1);
1972
1973 /*
1974 * The same type?
1975 */
1976 if (fIsString1 == expr_var_is_string(pVar2))
1977 {
1978 if (!fIsString1)
1979 /* numbers are simple */
1980 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1981 else
1982 {
1983 /* try a normal string compare. */
1984 rc = expr_var_make_simple_string(pThis, pVar1);
1985 if (rc == kExprRet_Ok)
1986 rc = expr_var_make_simple_string(pThis, pVar2);
1987 if (rc == kExprRet_Ok)
1988 {
1989 if (!strcmp(pVar1->uVal.psz, pVar2->uVal.psz))
1990 expr_var_assign_bool(pVar1, 1);
1991 /* try convert and compare as number instead. */
1992 else if ( expr_var_try_make_num(pThis, pVar1) >= kExprRet_Ok
1993 && expr_var_try_make_num(pThis, pVar2) >= kExprRet_Ok)
1994 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1995 /* ok, they really aren't equal. */
1996 else
1997 expr_var_assign_bool(pVar1, 0);
1998 }
1999 }
2000 }
2001 else
2002 {
2003 /*
2004 * If the type differs, there are now two options:
2005 * 1. Convert the string to a valid number and compare the numbers.
2006 * 2. Convert an empty string to a 'false' boolean value and compare
2007 * numerically. This one is a bit questionable, so we don't try this.
2008 */
2009 /** @todo this needs to be redone, both because we're hiding alloc errors
2010 * here but also because this should be controlled by a flag. */
2011 if ( expr_var_try_make_num(pThis, pVar1) >= kExprRet_Ok
2012 && expr_var_try_make_num(pThis, pVar2) >= kExprRet_Ok)
2013 expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
2014 else
2015 rc = expr_error(pThis, "Cannot compare strings and numbers");
2016 }
2017
2018 expr_pop_and_delete_var(pThis);
2019 return rc;
2020}
2021
2022
2023/**
2024 * Not equal.
2025 *
2026 * @returns Status code.
2027 * @param pThis The instance.
2028 */
2029static EXPRRET expr_op_not_equal(PEXPR pThis)
2030{
2031 EXPRRET rc = expr_op_equal(pThis);
2032 if (rc >= kExprRet_Ok)
2033 rc = expr_op_logical_not(pThis);
2034 return rc;
2035}
2036
2037
2038/**
2039 * Bitwise AND.
2040 *
2041 * @returns Status code.
2042 * @param pThis The instance.
2043 */
2044static EXPRRET expr_op_bitwise_and(PEXPR pThis)
2045{
2046 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
2047 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
2048
2049 EXPRRET rc = expr_var_make_num(pThis, pVar1);
2050 if (rc >= kExprRet_Ok)
2051 {
2052 rc = expr_var_make_num(pThis, pVar2);
2053 if (rc >= kExprRet_Ok)
2054 pVar1->uVal.i &= pVar2->uVal.i;
2055 }
2056
2057 expr_pop_and_delete_var(pThis);
2058 return rc;
2059}
2060
2061
2062/**
2063 * Bitwise XOR.
2064 *
2065 * @returns Status code.
2066 * @param pThis The instance.
2067 */
2068static EXPRRET expr_op_bitwise_xor(PEXPR pThis)
2069{
2070 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
2071 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
2072
2073 EXPRRET rc = expr_var_make_num(pThis, pVar1);
2074 if (rc >= kExprRet_Ok)
2075 {
2076 rc = expr_var_make_num(pThis, pVar2);
2077 if (rc >= kExprRet_Ok)
2078 pVar1->uVal.i ^= pVar2->uVal.i;
2079 }
2080
2081 expr_pop_and_delete_var(pThis);
2082 return rc;
2083}
2084
2085
2086/**
2087 * Bitwise OR.
2088 *
2089 * @returns Status code.
2090 * @param pThis The instance.
2091 */
2092static EXPRRET expr_op_bitwise_or(PEXPR pThis)
2093{
2094 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
2095 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
2096
2097 EXPRRET rc = expr_var_make_num(pThis, pVar1);
2098 if (rc >= kExprRet_Ok)
2099 {
2100 rc = expr_var_make_num(pThis, pVar2);
2101 if (rc >= kExprRet_Ok)
2102 pVar1->uVal.i |= pVar2->uVal.i;
2103 }
2104
2105 expr_pop_and_delete_var(pThis);
2106 return rc;
2107}
2108
2109
2110/**
2111 * Logical AND.
2112 *
2113 * @returns Status code.
2114 * @param pThis The instance.
2115 */
2116static EXPRRET expr_op_logical_and(PEXPR pThis)
2117{
2118 bool fResult = false;
2119 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
2120 EXPRRET rc = expr_var_make_bool(pThis, pVar1);
2121 if ( rc == kExprRet_Ok
2122 && pVar1->uVal.i != 0)
2123 {
2124 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
2125 rc = expr_var_make_bool(pThis, pVar2);
2126 if (rc == kExprRet_Ok && pVar2->uVal.i != 0)
2127 fResult = true;
2128 }
2129 expr_var_assign_bool(pVar1, fResult);
2130 expr_pop_and_delete_var(pThis);
2131 return rc;
2132}
2133
2134
2135/**
2136 * Logical OR.
2137 *
2138 * @returns Status code.
2139 * @param pThis The instance.
2140 */
2141static EXPRRET expr_op_logical_or(PEXPR pThis)
2142{
2143 bool fResult = false;
2144 PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
2145 EXPRRET rc = expr_var_make_bool(pThis, pVar1);
2146 if (rc == kExprRet_Ok)
2147 {
2148 if (pVar1->uVal.i)
2149 fResult = true;
2150 else
2151 {
2152 PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar];
2153 rc = expr_var_make_bool(pThis, pVar2);
2154 if (rc == kExprRet_Ok && pVar2->uVal.i != 0)
2155 fResult = true;
2156 }
2157 }
2158 expr_var_assign_bool(pVar1, fResult);
2159 expr_pop_and_delete_var(pThis);
2160 return rc;
2161}
2162
2163
2164/**
2165 * Left parenthesis.
2166 *
2167 * @returns Status code.
2168 * @param pThis The instance.
2169 */
2170static EXPRRET expr_op_left_parenthesis(PEXPR pThis)
2171{
2172 /*
2173 * There should be a right parenthesis operator lined up for us now,
2174 * eat it. If not found there is an inbalance.
2175 */
2176 EXPRRET rc = expr_get_binary_or_eoe_or_rparen(pThis);
2177 if ( rc == kExprRet_Operator
2178 && pThis->apOps[pThis->iOp]->szOp[0] == ')')
2179 {
2180 /* pop it and get another one which we can leave pending. */
2181 pThis->iOp--;
2182 rc = expr_get_binary_or_eoe_or_rparen(pThis);
2183 if (rc >= kExprRet_Ok)
2184 expr_unget_op(pThis);
2185 }
2186 else
2187 rc = expr_error(pThis, "Missing ')'");
2188
2189 return rc;
2190}
2191
2192
2193/**
2194 * Right parenthesis, dummy that's never actually called.
2195 *
2196 * @returns Status code.
2197 * @param pThis The instance.
2198 */
2199static EXPRRET expr_op_right_parenthesis(PEXPR pThis)
2200{
2201 RT_NOREF_PV(pThis);
2202 AssertFailed();
2203 return kExprRet_Ok;
2204}
2205
2206
2207
2208
2209
2210/**
2211 * The operator table.
2212 *
2213 * This table is NOT ordered by precedence, but for linear search
2214 * allowing for first match to return the correct operator. This
2215 * means that || must come before |, or else | will match all.
2216 */
2217static const EXPROP g_aExprOps[] =
2218{
2219#define EXPR_OP(szOp, iPrecedence, cArgs, pfn) { szOp, sizeof(szOp) - 1, '\0', iPrecedence, cArgs, pfn }
2220 /* Name, iPrecedence, cArgs, pfn */
2221 EXPR_OP("defined", 90, 1, expr_op_defined),
2222 EXPR_OP("exists", 90, 1, expr_op_exists),
2223 EXPR_OP("bool", 90, 1, expr_op_bool),
2224 EXPR_OP("md5", 90, 1, expr_op_md5),
2225 EXPR_OP("num", 90, 1, expr_op_num),
2226 EXPR_OP("sha1", 90, 1, expr_op_sha1),
2227 EXPR_OP("sha256", 90, 1, expr_op_sha256),
2228 EXPR_OP("sha512", 90, 1, expr_op_sha512),
2229 EXPR_OP("strlen", 90, 1, expr_op_strlen),
2230 EXPR_OP("str", 90, 1, expr_op_str),
2231 EXPR_OP("+", 80, 1, expr_op_pluss),
2232 EXPR_OP("-", 80, 1, expr_op_minus),
2233 EXPR_OP("~", 80, 1, expr_op_bitwise_not),
2234 EXPR_OP("*", 75, 2, expr_op_multiply),
2235 EXPR_OP("/", 75, 2, expr_op_divide),
2236 EXPR_OP("%", 75, 2, expr_op_modulus),
2237 EXPR_OP("+", 70, 2, expr_op_add),
2238 EXPR_OP("-", 70, 2, expr_op_sub),
2239#if 0 /** @todo not happy with 'strcat' as an operator. Dot doesn't work, so, figure something else out... */
2240 EXPR_OP("strcat", 70, 2, expr_op_concat),
2241#endif
2242 EXPR_OP("<<", 65, 2, expr_op_shift_left),
2243 EXPR_OP(">>", 65, 2, expr_op_shift_right),
2244 EXPR_OP("<=", 60, 2, expr_op_less_or_equal_than),
2245 EXPR_OP("<", 60, 2, expr_op_less_than),
2246 EXPR_OP(">=", 60, 2, expr_op_greater_or_equal_than),
2247 EXPR_OP(">", 60, 2, expr_op_greater_than),
2248 EXPR_OP("vle", 60, 2, expr_op_ver_less_or_equal_than),
2249 EXPR_OP("vlt", 60, 2, expr_op_ver_less_than),
2250 EXPR_OP("vge", 60, 2, expr_op_ver_greater_or_equal_than),
2251 EXPR_OP("vgt", 60, 2, expr_op_ver_greater_than),
2252 EXPR_OP("==", 55, 2, expr_op_equal),
2253 EXPR_OP("veq", 55, 2, expr_op_ver_equal),
2254 EXPR_OP("!=", 55, 2, expr_op_not_equal),
2255 EXPR_OP("vne", 55, 2, expr_op_ver_not_equal),
2256 EXPR_OP("!", 80, 1, expr_op_logical_not),
2257 EXPR_OP("^", 45, 2, expr_op_bitwise_xor),
2258 EXPR_OP("&&", 35, 2, expr_op_logical_and),
2259 EXPR_OP("&", 50, 2, expr_op_bitwise_and),
2260 EXPR_OP("||", 30, 2, expr_op_logical_or),
2261 EXPR_OP("|", 40, 2, expr_op_bitwise_or),
2262 { "(", 1, ')', 10, 1, expr_op_left_parenthesis },
2263 { ")", 1, '(', 10, 0, expr_op_right_parenthesis },
2264 /* { "?", 1, ':', 5, 2, expr_op_question },
2265 { ":", 1, '?', 5, 2, expr_op_colon }, -- too weird for now. */
2266#undef EXPR_OP
2267};
2268
2269/** Dummy end of expression fake. */
2270static const EXPROP g_ExprEndOfExpOp =
2271{
2272 "", 0, '\0', 0, 0, NULL
2273};
2274
2275
2276/**
2277 * Initializes the opcode character map if necessary.
2278 */
2279static void expr_map_init(void)
2280{
2281 unsigned i;
2282 if (g_fExprInitializedMap)
2283 return;
2284
2285 /*
2286 * Initialize it.
2287 */
2288 for (i = 0; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++)
2289 {
2290 unsigned int ch = (unsigned int)g_aExprOps[i].szOp[0];
2291 if (!g_abOpStartCharMap[ch])
2292 {
2293 g_abOpStartCharMap[ch] = (i << 2) | 1;
2294 if (!RT_C_IS_ALPHA(ch))
2295 g_abOpStartCharMap[ch] |= 2; /* Need no clear separation from operands. */
2296 }
2297 }
2298
2299 /* whitespace (assumes C-like locale because I'm lazy): */
2300#define SET_WHITESPACE(a_ch) do { \
2301 Assert(g_abOpStartCharMap[(unsigned char)(a_ch)] == 0); \
2302 g_abOpStartCharMap[(unsigned char)(a_ch)] |= 2; \
2303 } while (0)
2304 SET_WHITESPACE(' ');
2305 SET_WHITESPACE('\t');
2306 SET_WHITESPACE('\n');
2307 SET_WHITESPACE('\r');
2308 SET_WHITESPACE('\v');
2309 SET_WHITESPACE('\f');
2310
2311 g_fExprInitializedMap = 1;
2312}
2313
2314
2315/**
2316 * Looks up a character in the map.
2317 *
2318 * @returns the value for that char, see g_abOpStartCharMap for details.
2319 * @param ch The character.
2320 */
2321DECLINLINE(unsigned char) expr_map_get(char ch)
2322{
2323 return g_abOpStartCharMap[(unsigned char)ch];
2324}
2325
2326
2327/**
2328 * Searches the operator table given a potential operator start char.
2329 *
2330 * @returns Pointer to the matching operator. NULL if not found.
2331 * @param psz Pointer to what can be an operator.
2332 * @param uchVal The expr_map_get value.
2333 * @param fUnary Whether it must be an unary operator or not.
2334 */
2335static PCEXPROP expr_lookup_op(char const *psz, unsigned char uchVal, int fUnary)
2336{
2337 char ch = *psz;
2338 unsigned i;
2339 Assert((uchVal & 2) == (RT_C_IS_ALPHA(ch) ? 0 : 2));
2340
2341 for (i = uchVal >> 2; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++)
2342 {
2343 /* compare the string... */
2344 if (g_aExprOps[i].szOp[0] != ch)
2345 continue;
2346 switch (g_aExprOps[i].cchOp)
2347 {
2348 case 1:
2349 break;
2350 case 2:
2351 if (g_aExprOps[i].szOp[1] != psz[1])
2352 continue;
2353 break;
2354 default:
2355 if (strncmp(&g_aExprOps[i].szOp[1], psz + 1, g_aExprOps[i].cchOp - 1))
2356 continue;
2357 break;
2358 }
2359
2360 /* ... and the operator type. */
2361 if (fUnary == (g_aExprOps[i].cArgs == 1))
2362 {
2363 /* Check if we've got the needed operand separation: */
2364 if ( (uchVal & 2)
2365 || EXPR_IS_OP_SEPARATOR(psz[g_aExprOps[i].cchOp]))
2366 {
2367 /* got a match! */
2368 return &g_aExprOps[i];
2369 }
2370 }
2371 }
2372
2373 return NULL;
2374}
2375
2376
2377/**
2378 * Ungets a binary operator.
2379 *
2380 * The operator is poped from the stack and put in the pending position.
2381 *
2382 * @param pThis The evaluator instance.
2383 */
2384static void expr_unget_op(PEXPR pThis)
2385{
2386 Assert(pThis->pPending == NULL);
2387 Assert(pThis->iOp >= 0);
2388
2389 pThis->pPending = pThis->apOps[pThis->iOp];
2390 pThis->apOps[pThis->iOp] = NULL;
2391 pThis->iOp--;
2392}
2393
2394
2395
2396/**
2397 * Get the next token, it should be a binary operator, or the end of
2398 * the expression, or a right parenthesis.
2399 *
2400 * The operator is pushed onto the stack and the status code indicates
2401 * which of the two we found.
2402 *
2403 * @returns status code. Will grumble on failure.
2404 * @retval kExprRet_EndOfExpr if we encountered the end of the expression.
2405 * @retval kExprRet_Operator if we encountered a binary operator or right
2406 * parenthesis. It's on the operator stack.
2407 *
2408 * @param pThis The evaluator instance.
2409 */
2410static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis)
2411{
2412 /*
2413 * See if there is anything pending first.
2414 */
2415 PCEXPROP pOp = pThis->pPending;
2416 if (pOp)
2417 pThis->pPending = NULL;
2418 else
2419 {
2420 /*
2421 * Eat more of the expression.
2422 */
2423 char const *psz = pThis->psz;
2424
2425 /* spaces */
2426 unsigned char uchVal;
2427 char ch;
2428 while (((uchVal = expr_map_get((ch = *psz))) & 3) == 2)
2429 psz++;
2430
2431 /* see what we've got. */
2432 if (ch)
2433 {
2434 if (uchVal & 1)
2435 pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */);
2436 if (!pOp)
2437 return expr_error(pThis, "Expected binary operator, found \"%.42s\"...", psz);
2438 psz += pOp->cchOp;
2439 }
2440 else
2441 pOp = &g_ExprEndOfExpOp;
2442 pThis->psz = psz;
2443 }
2444
2445 /*
2446 * Push it.
2447 */
2448 if (pThis->iOp >= EXPR_MAX_OPERATORS - 1)
2449 return expr_error(pThis, "Operator stack overflow");
2450 pThis->apOps[++pThis->iOp] = pOp;
2451
2452 return pOp->iPrecedence
2453 ? kExprRet_Operator
2454 : kExprRet_EndOfExpr;
2455}
2456
2457
2458
2459/**
2460 * Get the next token, it should be an unary operator or an operand.
2461 *
2462 * This will fail if encountering the end of the expression since
2463 * it is implied that there should be something more.
2464 *
2465 * The token is pushed onto the respective stack and the status code
2466 * indicates which it is.
2467 *
2468 * @returns status code. On failure we'll be done bitching already.
2469 * @retval kExprRet_Operator if we encountered an unary operator.
2470 * It's on the operator stack.
2471 * @retval kExprRet_Operand if we encountered an operand operator.
2472 * It's on the operand stack.
2473 *
2474 * @param pThis The evaluator instance.
2475 */
2476static EXPRRET expr_get_unary_or_operand(PEXPR pThis)
2477{
2478 EXPRRET rc;
2479 unsigned char uchVal;
2480 PCEXPROP pOp;
2481 char const *psz = pThis->psz;
2482 char ch;
2483
2484 /*
2485 * Eat white space and make sure there is something after it.
2486 */
2487 while (((uchVal = expr_map_get((ch = *psz))) & 3) == 2)
2488 psz++;
2489 if (ch == '\0')
2490 return expr_error(pThis, "Unexpected end of expression");
2491
2492 /*
2493 * Is it an operator?
2494 */
2495 pOp = NULL;
2496 if (uchVal & 1)
2497 pOp = expr_lookup_op(psz, uchVal, 1 /* fUnary */);
2498 if (pOp)
2499 {
2500 /*
2501 * Push the operator onto the stack.
2502 */
2503 if (pThis->iVar < EXPR_MAX_OPERANDS - 1)
2504 {
2505 pThis->apOps[++pThis->iOp] = pOp;
2506 rc = kExprRet_Operator;
2507 }
2508 else
2509 rc = expr_error(pThis, "Operator stack overflow");
2510 psz += pOp->cchOp;
2511 }
2512 else if (pThis->iVar < EXPR_MAX_OPERANDS - 1)
2513 {
2514 /*
2515 * It's an operand. Figure out where it ends and
2516 * push it onto the stack.
2517 */
2518 const char *pszStart;
2519
2520 rc = kExprRet_Ok;
2521 if (ch == '"')
2522 {
2523 pszStart = ++psz;
2524 while ((ch = *psz) != '\0' && ch != '"')
2525 psz++;
2526 rc = expr_var_init_substring(pThis, &pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedString);
2527 if (ch != '\0')
2528 psz++;
2529 }
2530 else if (ch == '\'')
2531 {
2532 pszStart = ++psz;
2533 while ((ch = *psz) != '\0' && ch != '\'')
2534 psz++;
2535 rc = expr_var_init_substring(pThis, &pThis->aVars[++pThis->iVar], pszStart, psz - pszStart,
2536 kExprVar_QuotedSimpleString);
2537 if (ch != '\0')
2538 psz++;
2539 }
2540 else
2541 {
2542 unsigned cPars = 0;
2543 pszStart = psz;
2544 while ((ch = *psz) != '\0')
2545 {
2546 /* ${asdf} needs special handling. */
2547 if ( ch == '$'
2548 && psz[1] == '{')
2549 {
2550 psz++;
2551 if (cPars < EXPR_MAX_VAR_RECURSION)
2552 ++cPars;
2553 else
2554 {
2555 rc = expr_error(pThis, "Too deep nesting of variable expansions");
2556 break;
2557 }
2558 }
2559 else if (ch == '}')
2560 {
2561 if (cPars > 0)
2562 cPars--;
2563 }
2564 else if (cPars == 0)
2565 {
2566 uchVal = expr_map_get(ch);
2567 if (uchVal == 0)
2568 { /*likely*/ }
2569 else if ((uchVal & 3) == 2 /*isspace*/)
2570 break;
2571 else if ( (uchVal & 1)
2572 && psz != pszStart /* not at the start */
2573 && ( (uchVal & 2) /* operator without separator needs */
2574 || EXPR_IS_OP_SEPARATOR_NO_SPACE(psz[-1])))
2575 {
2576 pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */);
2577 if (pOp)
2578 break;
2579 }
2580 }
2581
2582 /* next */
2583 psz++;
2584 }
2585
2586 if (rc == kExprRet_Ok)
2587 rc = expr_var_init_substring(pThis, &pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_String);
2588 }
2589 }
2590 else
2591 rc = expr_error(pThis, "Operand stack overflow");
2592 pThis->psz = psz;
2593
2594 return rc;
2595}
2596
2597
2598/**
2599 * Evaluates the current expression.
2600 *
2601 * @returns status code.
2602 *
2603 * @param pThis The instance.
2604 */
2605static EXPRRET expr_eval(PEXPR pThis)
2606{
2607 EXPRRET rc;
2608 PCEXPROP pOp;
2609
2610 /*
2611 * The main loop.
2612 */
2613 for (;;)
2614 {
2615 /*
2616 * Eat unary operators until we hit an operand.
2617 */
2618 do
2619 rc = expr_get_unary_or_operand(pThis);
2620 while (rc == kExprRet_Operator);
2621 if (rc < kExprRet_Ok)
2622 break;
2623
2624 /*
2625 * Look for a binary operator, right parenthesis or end of expression.
2626 */
2627 rc = expr_get_binary_or_eoe_or_rparen(pThis);
2628 if (rc < kExprRet_Ok)
2629 break;
2630 expr_unget_op(pThis);
2631
2632 /*
2633 * Pop operators and apply them.
2634 *
2635 * Parenthesis will be handed via precedence, where the left parenthesis
2636 * will go pop the right one and make another operator pending.
2637 */
2638 while ( pThis->iOp >= 0
2639 && pThis->apOps[pThis->iOp]->iPrecedence >= pThis->pPending->iPrecedence)
2640 {
2641 pOp = pThis->apOps[pThis->iOp--];
2642 Assert(pThis->iVar + 1 >= pOp->cArgs);
2643 rc = pOp->pfn(pThis);
2644 if (rc < kExprRet_Ok)
2645 break;
2646 }
2647 if (rc < kExprRet_Ok)
2648 break;
2649
2650 /*
2651 * Get the next binary operator or end of expression.
2652 * There should be no right parenthesis here.
2653 */
2654 rc = expr_get_binary_or_eoe_or_rparen(pThis);
2655 if (rc < kExprRet_Ok)
2656 break;
2657 pOp = pThis->apOps[pThis->iOp];
2658 if (!pOp->iPrecedence)
2659 break; /* end of expression */
2660 if (!pOp->cArgs)
2661 {
2662 rc = expr_error(pThis, "Unexpected \"%s\"", pOp->szOp);
2663 break;
2664 }
2665 }
2666
2667 return rc;
2668}
2669
2670
2671/**
2672 * Destroys the given instance.
2673 *
2674 * @param pThis The instance to destroy.
2675 */
2676static void expr_destroy(PEXPR pThis)
2677{
2678 while (pThis->iVar >= 0)
2679 {
2680 expr_var_delete(pThis->aVars);
2681 pThis->iVar--;
2682 }
2683 RTMemTmpFree(pThis);
2684}
2685
2686
2687/**
2688 * Instantiates an expression evaluator.
2689 *
2690 * @returns The instance.
2691 */
2692static PEXPR expr_create(RTEXPREVALINT *pThis, const char *pch, size_t cch, PRTERRINFO pErrInfo)
2693{
2694 cch = RTStrNLen(pch, cch);
2695
2696 PEXPR pExpr = (PEXPR)RTMemTmpAllocZ(sizeof(*pExpr) + cch + 1);
2697 if (pExpr)
2698 {
2699 pExpr->psz = pExpr->pszExpr = (char *)memcpy(pExpr + 1, pch, cch);
2700 pExpr->pErrInfo = pErrInfo;
2701 pExpr->pEvaluator = pThis;
2702 pExpr->pPending = NULL;
2703 pExpr->iVar = -1;
2704 pExpr->iOp = -1;
2705
2706 expr_map_init();
2707 }
2708 return pExpr;
2709}
2710
2711
2712
2713/*********************************************************************************************************************************
2714* API *
2715*********************************************************************************************************************************/
2716
2717/** @callback_method_impl{PFNRTEXPREVALQUERYVARIABLE, Stub} */
2718static DECLCALLBACK(int) rtExprEvalDummyQueryVariable(const char *pchName, size_t cchName, void *pvUser, char **ppszValue)
2719{
2720 RT_NOREF(pchName, cchName, pvUser);
2721 if (ppszValue)
2722 *ppszValue = NULL;
2723 return VERR_NOT_FOUND;
2724}
2725
2726
2727RTDECL(int) RTExprEvalCreate(PRTEXPREVAL phEval, uint64_t fFlags, const char *pszName,
2728 void *pvUser, PFNRTEXPREVALQUERYVARIABLE pfnQueryVariable)
2729{
2730 AssertPtrReturn(phEval, VERR_INVALID_POINTER);
2731 *phEval = NULL;
2732 AssertPtrNullReturn(pfnQueryVariable, VERR_INVALID_POINTER);
2733 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
2734 AssertReturn(!(fFlags & ~0), VERR_INVALID_FLAGS);
2735
2736 char *pszNameCopy = RTStrDup(pszName);
2737 if (pszNameCopy)
2738 {
2739 RTEXPREVALINT *pThis = (RTEXPREVALINT *)RTMemAllocZ(sizeof(*pThis));
2740 if (pThis)
2741 {
2742 pThis->u32Magic = RTEXPREVAL_MAGIC;
2743 pThis->cRefs = 1;
2744 pThis->fFlags = fFlags;
2745 pThis->pszName = pszNameCopy;
2746 pThis->pvUser = pvUser;
2747 pThis->pfnQueryVariable = pfnQueryVariable ? pfnQueryVariable : rtExprEvalDummyQueryVariable;
2748 *phEval = pThis;
2749 return VINF_SUCCESS;
2750
2751 }
2752
2753 RTStrFree(pszNameCopy);
2754 return VERR_NO_MEMORY;
2755 }
2756 return VERR_NO_STR_MEMORY;
2757}
2758
2759
2760RTDECL(uint32_t) RTExprEvalRetain(RTEXPREVAL hEval)
2761{
2762 RTEXPREVALINT *pThis = hEval;
2763 AssertPtrReturn(pThis, UINT32_MAX);
2764 AssertReturn(pThis->u32Magic == RTEXPREVAL_MAGIC, UINT32_MAX);
2765 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
2766 Assert(cRefs > 1);
2767 Assert(cRefs < 512);
2768 return cRefs;
2769}
2770
2771
2772RTDECL(uint32_t) RTExprEvalRelease(RTEXPREVAL hEval)
2773{
2774 RTEXPREVALINT *pThis = hEval;
2775 AssertPtrReturn(pThis, UINT32_MAX);
2776 AssertReturn(pThis->u32Magic == RTEXPREVAL_MAGIC, UINT32_MAX);
2777 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
2778 Assert(cRefs < 512);
2779 if (cRefs == 0)
2780 {
2781 pThis->u32Magic = ~RTEXPREVAL_MAGIC;
2782 if (pThis->pszName)
2783 {
2784 RTStrFree(pThis->pszName);
2785 pThis->pszName = NULL;
2786 }
2787 RTMemFree(pThis);
2788 return 0;
2789 }
2790 return cRefs;
2791}
2792
2793
2794RTDECL(int) RTExprEvalToBool(RTEXPREVAL hEval, const char *pch, size_t cch, bool *pfResult, PRTERRINFO pErrInfo)
2795{
2796 AssertPtrReturn(pfResult, VERR_INVALID_POINTER);
2797 *pfResult = false;
2798 RTEXPREVALINT *pThis = hEval;
2799 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2800 AssertReturn(pThis->u32Magic == RTEXPREVAL_MAGIC, VERR_INVALID_HANDLE);
2801
2802 /*
2803 * Instantiate the expression evaluator and let it have a go at it.
2804 */
2805 int rc;
2806 PEXPR pExpr = expr_create(pThis, pch, cch, pErrInfo);
2807 if (pExpr)
2808 {
2809 if (expr_eval(pExpr) >= kExprRet_Ok)
2810 {
2811 /*
2812 * Convert the result (on top of the stack) to boolean and
2813 * set our return value accordingly.
2814 */
2815 if ( expr_var_make_bool(pExpr, &pExpr->aVars[0]) == kExprRet_Ok
2816 && pExpr->aVars[0].uVal.i)
2817 *pfResult = true;
2818 rc = VINF_SUCCESS;
2819 }
2820 else
2821 rc = VERR_PARSE_ERROR; /** @todo better errors? */
2822 expr_destroy(pExpr);
2823 }
2824 else
2825 rc = VERR_NO_TMP_MEMORY;
2826 return rc;
2827}
2828
2829
2830RTDECL(int) RTExprEvalToInteger(RTEXPREVAL hEval, const char *pch, size_t cch, int64_t *piResult, PRTERRINFO pErrInfo)
2831{
2832 AssertPtrReturn(piResult, VERR_INVALID_POINTER);
2833 *piResult = INT64_MAX;
2834 RTEXPREVALINT *pThis = hEval;
2835 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2836 AssertReturn(pThis->u32Magic == RTEXPREVAL_MAGIC, VERR_INVALID_HANDLE);
2837
2838 /*
2839 * Instantiate the expression evaluator and let it have a go at it.
2840 */
2841 int rc;
2842 PEXPR pExpr = expr_create(pThis, pch, cch, pErrInfo);
2843 if (pExpr)
2844 {
2845 if (expr_eval(pExpr) >= kExprRet_Ok)
2846 {
2847 /*
2848 * Convert the result (on top of the stack) to boolean and
2849 * set our return value accordingly.
2850 */
2851 PEXPRVAR pVar = &pExpr->aVars[0];
2852 EXPRRET rcExpr = expr_var_make_num(pExpr, pVar);
2853 if (rcExpr >= kExprRet_Ok)
2854 {
2855 *piResult = pVar->uVal.i;
2856 rc = VINF_SUCCESS;
2857 }
2858 else
2859 rc = VERR_PARSE_ERROR; /** @todo better error! */
2860 }
2861 else
2862 rc = VERR_PARSE_ERROR; /** @todo better errors? */
2863 expr_destroy(pExpr);
2864 }
2865 else
2866 rc = VERR_NO_TMP_MEMORY;
2867 return rc;
2868}
2869
2870
2871RTDECL(int) RTExprEvalToString(RTEXPREVAL hEval, const char *pch, size_t cch, char **ppszResult, PRTERRINFO pErrInfo)
2872{
2873 AssertPtrReturn(ppszResult, VERR_INVALID_POINTER);
2874 *ppszResult = NULL;
2875 RTEXPREVALINT *pThis = hEval;
2876 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2877 AssertReturn(pThis->u32Magic == RTEXPREVAL_MAGIC, VERR_INVALID_HANDLE);
2878
2879 /*
2880 * Instantiate the expression evaluator and let it have a go at it.
2881 */
2882 int rc;
2883 PEXPR pExpr = expr_create(pThis, pch, cch, pErrInfo);
2884 if (pExpr)
2885 {
2886 if (expr_eval(pExpr) >= kExprRet_Ok)
2887 {
2888 /*
2889 * Convert the result (on top of the stack) to a string
2890 * and copy it out the variable buffer.
2891 */
2892 PEXPRVAR pVar = &pExpr->aVars[0];
2893 if (expr_var_make_simple_string(pExpr, pVar) == kExprRet_Ok)
2894 rc = RTStrDupEx(ppszResult, pVar->uVal.psz);
2895 else
2896 rc = VERR_NO_TMP_MEMORY;
2897 }
2898 else
2899 rc = VERR_PARSE_ERROR;
2900 expr_destroy(pExpr);
2901 }
2902 else
2903 rc = VERR_NO_TMP_MEMORY;
2904
2905 return rc;
2906}
2907
Note: See TracBrowser for help on using the repository browser.

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