VirtualBox

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

Last change on this file since 96014 was 94888, checked in by vboxsync, 3 years ago

Runtime: Fix a few memory leaks in error handling paths, bugref:3409

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