source: trunk/src/kmk/expreval.c

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

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

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