VirtualBox

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use