VirtualBox

source: kBuild/trunk/src/kmk/ifcond.c@ 1723

Last change on this file since 1723 was 1723, checked in by bird, 16 years ago

kmk/ifcond: windows build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.1 KB
Line 
1#ifdef CONFIG_WITH_IF_CONDITIONALS
2/* $Id: ifcond.c 1723 2008-09-04 14:10:08Z bird $ */
3/** @file
4 * ifcond - C like if expressions.
5 */
6
7/*
8 * Copyright (c) 2008 knut st. osmundsen <[email protected]>
9 *
10 * This file is part of kBuild.
11 *
12 * kBuild is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * kBuild is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with kBuild; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 *
26 */
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "make.h"
32#include <assert.h>
33
34#include <glob.h>
35
36#include "dep.h"
37#include "filedef.h"
38#include "job.h"
39#include "commands.h"
40#include "variable.h"
41#include "rule.h"
42#include "debug.h"
43#include "hash.h"
44#include <ctype.h>
45#ifndef _MSC_VER
46# include <stdint.h>
47#endif
48#include <stdarg.h>
49
50
51/*******************************************************************************
52* Defined Constants And Macros *
53*******************************************************************************/
54/** The max length of a string representation of a number. */
55#define IFCOND_NUM_LEN ((sizeof("-9223372036854775802") + 4) & ~3)
56
57/** The max operator stack depth. */
58#define IFCOND_MAX_OPERATORS 72
59/** The max operand depth. */
60#define IFCOND_MAX_OPERANDS 128
61
62
63/*******************************************************************************
64* Structures and Typedefs *
65*******************************************************************************/
66/** The 64-bit signed integer type we're using. */
67#ifdef _MSC_VER
68typedef __int64 IFCONDINT64;
69#else
70# include <stdint.h>
71typedef int64_t IFCONDINT64;
72#endif
73
74/** Pointer to a evaluator instance. */
75typedef struct IFCOND *PIFCOND;
76
77
78/**
79 * Operand variable type.
80 */
81typedef enum
82{
83 /** Invalid zero entry. */
84 kIfCondVar_Invalid = 0,
85 /** A number. */
86 kIfCondVar_Num,
87 /** A string in need of expanding (perhaps). */
88 kIfCondVar_String,
89 /** A simple string that doesn't need expanding. */
90 kIfCondVar_SimpleString,
91 /** A quoted string in need of expanding (perhaps). */
92 kIfCondVar_QuotedString,
93 /** A simple quoted string that doesn't need expanding. */
94 kIfCondVar_QuotedSimpleString,
95 /** The end of the valid variable types. */
96 kIfCondVar_End
97} IFCONDVARTYPE;
98
99/**
100 * Operand variable.
101 */
102typedef struct
103{
104 /** The variable type. */
105 IFCONDVARTYPE enmType;
106 /** The variable. */
107 union
108 {
109 /** Pointer to the string. */
110 char *psz;
111 /** The variable. */
112 IFCONDINT64 i;
113 } uVal;
114} IFCONDVAR;
115/** Pointer to a operand variable. */
116typedef IFCONDVAR *PIFCONDVAR;
117/** Pointer to a const operand variable. */
118typedef IFCONDVAR const *PCIFCONDVAR;
119
120/**
121 * Operator return statuses.
122 */
123typedef enum
124{
125 kIfCondRet_Error = -1,
126 kIfCondRet_Ok = 0,
127 kIfCondRet_Operator,
128 kIfCondRet_Operand,
129 kIfCondRet_EndOfExpr,
130 kIfCondRet_End
131} IFCONDRET;
132
133/**
134 * Operator.
135 */
136typedef struct
137{
138 /** The operator. */
139 char szOp[11];
140 /** The length of the operator string. */
141 char cchOp;
142 /** The pair operator.
143 * This is used with '(' and '?'. */
144 char chPair;
145 /** The precedence. Higher means higher. */
146 char iPrecedence;
147 /** The number of arguments it takes. */
148 signed char cArgs;
149 /** Pointer to the method implementing the operator. */
150 IFCONDRET (*pfn)(PIFCOND pThis);
151} IFCONDOP;
152/** Pointer to a const operator. */
153typedef IFCONDOP const *PCIFCONDOP;
154
155/**
156 * Expression evaluator instance.
157 */
158typedef struct IFCOND
159{
160 /** The full expression. */
161 const char *pszExpr;
162 /** The current location. */
163 const char *psz;
164 /** The current file location, used for errors. */
165 const struct floc *pFileLoc;
166 /** Pending binary operator. */
167 PCIFCONDOP pPending;
168 /** Top of the operator stack. */
169 int iOp;
170 /** Top of the operand stack. */
171 int iVar;
172 /** The operator stack. */
173 PCIFCONDOP apOps[IFCOND_MAX_OPERATORS];
174 /** The operand stack. */
175 IFCONDVAR aVars[IFCOND_MAX_OPERANDS];
176} IFCOND;
177
178
179/*******************************************************************************
180* Global Variables *
181*******************************************************************************/
182/** Operator start character map.
183 * This indicates which characters that are starting operators and which aren't. */
184static char g_auchOpStartCharMap[256];
185/** Whether we've initialized the map. */
186static int g_fIfCondInitializedMap = 0;
187
188
189/*******************************************************************************
190* Internal Functions *
191*******************************************************************************/
192static void ifcond_unget_op(PIFCOND pThis);
193static IFCONDRET ifcond_get_binary_or_eoe_or_rparen(PIFCOND pThis);
194
195
196
197
198/**
199 * Displays an error message.
200 *
201 * The total string length must not exceed 256 bytes.
202 *
203 * @param pThis The evaluator instance.
204 * @param pszError The message format string.
205 * @param ... The message format args.
206 */
207static void ifcond_error(PIFCOND pThis, const char *pszError, ...)
208{
209 char szTmp[256];
210 va_list va;
211
212 va_start(va, pszError);
213 vsprintf(szTmp, pszError, va);
214 va_end(va);
215
216 fatal(pThis->pFileLoc, "%s", szTmp);
217}
218
219
220/**
221 * Converts a number to a string.
222 *
223 * @returns pszDst.
224 * @param pszDst The string buffer to write into. Assumes length of IFCOND_NUM_LEN.
225 * @param iSrc The number to convert.
226 */
227static char *ifcond_num_to_string(char *pszDst, IFCONDINT64 iSrc)
228{
229 static const char s_szDigits[17] = "0123456789abcdef";
230 char szTmp[IFCOND_NUM_LEN];
231 char *psz = &szTmp[IFCOND_NUM_LEN - 1];
232 int fNegative;
233
234 fNegative = iSrc < 0;
235 if (fNegative)
236 {
237 /** @todo this isn't right for INT64_MIN. */
238 iSrc = -iSrc;
239 }
240
241 *psz = '\0';
242 do
243 {
244#if 0
245 *--psz = s_szDigits[iSrc & 0xf];
246 iSrc >>= 4;
247#else
248 *--psz = s_szDigits[iSrc % 10];
249 iSrc /= 10;
250#endif
251 } while (iSrc);
252
253#if 0
254 *--psz = 'x';
255 *--psz = '0';
256#endif
257
258 if (fNegative)
259 *--psz = '-';
260
261 /* copy it into the output buffer. */
262 psz++;
263 return (char *)memcpy(pszDst, psz, &szTmp[IFCOND_NUM_LEN] - psz);
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. This is optional when fQuiet is true.
272 * @param piSrc 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 IFCONDRET ifcond_string_to_num(PIFCOND pThis, IFCONDINT64 *piDst, const char *pszSrc, int fQuiet)
277{
278 IFCONDRET rc = kIfCondRet_Ok;
279 char const *psz = pszSrc;
280 IFCONDINT64 i;
281 unsigned uBase;
282 int fNegative;
283
284
285 /*
286 * Skip blanks.
287 */
288 while (isblank(*psz))
289 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 * .
307 * Recognize some exsotic prefixes here in addition to the two standard ones.
308 */
309 if (*psz != '0' || psz[1] == '\0' || isblank((unsigned int)psz[1]))
310 uBase = 10;
311 else if (psz[1] == 'x' || psz[1] == 'X')
312 {
313 uBase = 16;
314 psz += 2;
315 }
316 else if (psz[1] == 'b' || psz[1] == 'B')
317 {
318 uBase = 2;
319 psz += 2;
320 }
321 else if (psz[1] == 'd' || psz[1] == 'D')
322 {
323 uBase = 10;
324 psz += 2;
325 }
326 else if (psz[1] == 'o' || psz[1] == 'O')
327 {
328 uBase = 8;
329 psz += 2;
330 }
331 else if (isdigit(psz[1]) && psz[1] != '9' && psz[1] != '8')
332 {
333 uBase = 8;
334 psz++;
335 }
336 else
337 uBase = 10;
338
339 /*
340 * Convert until we hit a non-digit.
341 */
342 i = 0;
343 for (;;)
344 {
345 int iDigit;
346 int ch = *psz;
347 switch (ch)
348 {
349 case '0': iDigit = 0; break;
350 case '1': iDigit = 1; break;
351 case '2': iDigit = 2; break;
352 case '3': iDigit = 3; break;
353 case '4': iDigit = 4; break;
354 case '5': iDigit = 5; break;
355 case '6': iDigit = 6; break;
356 case '7': iDigit = 7; break;
357 case '8': iDigit = 8; break;
358 case '9': iDigit = 9; break;
359 case 'a':
360 case 'A': iDigit = 10; break;
361 case 'b':
362 case 'B': iDigit = 11; break;
363 case 'c':
364 case 'C': iDigit = 12; break;
365 case 'd':
366 case 'D': iDigit = 13; break;
367 case 'e':
368 case 'E': iDigit = 14; break;
369 case 'f':
370 case 'F': iDigit = 15; break;
371
372 default:
373 /* is the rest white space? */
374 while (isspace((unsigned int)*psz))
375 psz++;
376 if (*psz != '\0')
377 {
378 iDigit = uBase;
379 break;
380 }
381 /* fall thru */
382
383 case '\0':
384 if (fNegative)
385 i = -i;
386 *piDst = i;
387 return rc;
388 }
389 if (iDigit >= uBase)
390 {
391 if (fNegative)
392 i = -i;
393 *piDst = i;
394 if (!fQuiet)
395 ifcond_error(pThis, "Invalid a number \"%.80s\"", pszSrc);
396 return kIfCondRet_Error;
397 }
398
399 /* add the digit and advance */
400 i *= uBase;
401 i += iDigit;
402 psz++;
403 }
404 /* not reached */
405}
406
407
408/**
409 * Checks if the variable is a string or not.
410 *
411 * @returns 1 if it's a string, 0 otherwise.
412 * @param pVar The variable.
413 */
414static int ifcond_var_is_string(PCIFCONDVAR pVar)
415{
416 return pVar->enmType >= kIfCondVar_String;
417}
418
419
420/**
421 * Checks if the variable contains a string that was quoted
422 * in the expression.
423 *
424 * @returns 1 if if was a quoted string, otherwise 0.
425 * @param pVar The variable.
426 */
427static int ifcond_var_was_quoted(PCIFCONDVAR pVar)
428{
429 return pVar->enmType >= kIfCondVar_QuotedString;
430}
431
432
433/**
434 * Deletes a variable.
435 *
436 * @param pVar The variable.
437 */
438static void ifcond_var_delete(PIFCONDVAR pVar)
439{
440 if (ifcond_var_is_string(pVar))
441 {
442 free(pVar->uVal.psz);
443 pVar->uVal.psz = NULL;
444 }
445 pVar->enmType = kIfCondVar_Invalid;
446}
447
448
449/**
450 * Initializes a new variables with a sub-string value.
451 *
452 * @param pVar The new variable.
453 * @param psz The start of the string value.
454 * @param cch The number of chars to copy.
455 * @param enmType The string type.
456 */
457static void ifcond_var_init_substring(PIFCONDVAR pVar, const char *psz, size_t cch, IFCONDVARTYPE enmType)
458{
459 /* convert string needing expanding into simple ones if possible. */
460 if ( enmType == kIfCondVar_String
461 && !memchr(psz, '$', cch))
462 enmType = kIfCondVar_SimpleString;
463 else if ( enmType == kIfCondVar_QuotedString
464 && !memchr(psz, '$', cch))
465 enmType = kIfCondVar_QuotedSimpleString;
466
467 pVar->enmType = enmType;
468 pVar->uVal.psz = xmalloc(cch + 1);
469 memcpy(pVar->uVal.psz, psz, cch);
470 pVar->uVal.psz[cch] = '\0';
471}
472
473
474#if 0 /* unused */
475/**
476 * Initializes a new variables with a string value.
477 *
478 * @param pVar The new variable.
479 * @param psz The string value.
480 * @param enmType The string type.
481 */
482static void ifcond_var_init_string(PIFCONDVAR pVar, const char *psz, IFCONDVARTYPE enmType)
483{
484 ifcond_var_init_substring(pVar, psz, strlen(psz), enmType);
485}
486
487
488/**
489 * Assigns a sub-string value to a variable.
490 *
491 * @param pVar The new variable.
492 * @param psz The start of the string value.
493 * @param cch The number of chars to copy.
494 * @param enmType The string type.
495 */
496static void ifcond_var_assign_substring(PIFCONDVAR pVar, const char *psz, size_t cch, IFCONDVARTYPE enmType)
497{
498 ifcond_var_delete(pVar);
499 ifcond_var_init_substring(pVar, psz, cch, enmType);
500}
501
502
503/**
504 * Assignes a string value to a variable.
505 *
506 * @param pVar The variable.
507 * @param psz The string value.
508 * @param enmType The string type.
509 */
510static void ifcond_var_assign_string(PIFCONDVAR pVar, const char *psz, IFCONDVARTYPE enmType)
511{
512 ifcond_var_delete(pVar);
513 ifcond_var_init_string(pVar, psz, enmType);
514}
515#endif /* unused */
516
517
518/**
519 * Simplifies a string variable.
520 *
521 * @param pVar The variable.
522 */
523static void ifcond_var_make_simple_string(PIFCONDVAR pVar)
524{
525 switch (pVar->enmType)
526 {
527 case kIfCondVar_Num:
528 {
529 char *psz = (char *)xmalloc(IFCOND_NUM_LEN);
530 ifcond_num_to_string(psz, pVar->uVal.i);
531 pVar->uVal.psz = psz;
532 pVar->enmType = kIfCondVar_SimpleString;
533 break;
534 }
535
536 case kIfCondVar_String:
537 case kIfCondVar_QuotedString:
538 {
539 char *psz;
540 assert(strchr(pVar->uVal.psz, '$'));
541
542 psz = allocated_variable_expand(pVar->uVal.psz);
543 free(pVar->uVal.psz);
544 pVar->uVal.psz = psz;
545
546 pVar->enmType = pVar->enmType == kIfCondVar_String
547 ? kIfCondVar_SimpleString
548 : kIfCondVar_QuotedSimpleString;
549 break;
550 }
551
552 case kIfCondVar_SimpleString:
553 case kIfCondVar_QuotedSimpleString:
554 /* nothing to do. */
555 break;
556
557 default:
558 assert(0);
559 }
560}
561
562
563#if 0 /* unused */
564/**
565 * Turns a variable into a string value.
566 *
567 * @param pVar The variable.
568 */
569static void ifcond_var_make_string(PIFCONDVAR pVar)
570{
571 switch (pVar->enmType)
572 {
573 case kIfCondVar_Num:
574 ifcond_var_make_simple_string(pVar);
575 break;
576
577 case kIfCondVar_String:
578 case kIfCondVar_SimpleString:
579 case kIfCondVar_QuotedString:
580 case kIfCondVar_QuotedSimpleString:
581 /* nothing to do. */
582 break;
583
584 default:
585 assert(0);
586 }
587}
588#endif /* unused */
589
590
591/**
592 * Initializes a new variables with a integer value.
593 *
594 * @param pVar The new variable.
595 * @param i The integer value.
596 */
597static void ifcond_var_init_num(PIFCONDVAR pVar, IFCONDINT64 i)
598{
599 pVar->enmType = kIfCondVar_Num;
600 pVar->uVal.i = i;
601}
602
603
604/**
605 * Assigns a integer value to a variable.
606 *
607 * @param pVar The variable.
608 * @param i The integer value.
609 */
610static void ifcond_var_assign_num(PIFCONDVAR pVar, IFCONDINT64 i)
611{
612 ifcond_var_delete(pVar);
613 ifcond_var_init_num(pVar, i);
614}
615
616
617/**
618 * Turns the variable into a number.
619 *
620 * @returns status code.
621 * @param pThis The evaluator instance.
622 * @param pVar The variable.
623 */
624static IFCONDRET ifcond_var_make_num(PIFCOND pThis, PIFCONDVAR pVar)
625{
626 switch (pVar->enmType)
627 {
628 case kIfCondVar_Num:
629 /* nothing to do. */
630 break;
631
632 case kIfCondVar_String:
633 ifcond_var_make_simple_string(pVar);
634 /* fall thru */
635 case kIfCondVar_SimpleString:
636 {
637 IFCONDINT64 i;
638 IFCONDRET rc = ifcond_string_to_num(pThis, &i, pVar->uVal.psz, 0 /* fQuiet */);
639 if (rc < kIfCondRet_Ok)
640 return rc;
641 ifcond_var_assign_num(pVar, i);
642 break;
643 }
644
645 case kIfCondVar_QuotedString:
646 case kIfCondVar_QuotedSimpleString:
647 ifcond_error(pThis, "Cannot convert a quoted string to a number");
648 return kIfCondRet_Error;
649
650 default:
651 assert(0);
652 return kIfCondRet_Error;
653 }
654
655 return kIfCondRet_Ok;
656}
657
658
659/**
660 * Try to turn the variable into a number.
661 *
662 * @returns status code.
663 * @param pVar The variable.
664 */
665static IFCONDRET ifcond_var_try_make_num(PIFCONDVAR pVar)
666{
667 switch (pVar->enmType)
668 {
669 case kIfCondVar_Num:
670 /* nothing to do. */
671 break;
672
673 case kIfCondVar_String:
674 ifcond_var_make_simple_string(pVar);
675 /* fall thru */
676 case kIfCondVar_SimpleString:
677 {
678 IFCONDINT64 i;
679 IFCONDRET rc = ifcond_string_to_num(NULL, &i, pVar->uVal.psz, 1 /* fQuiet */);
680 if (rc < kIfCondRet_Ok)
681 return rc;
682 ifcond_var_assign_num(pVar, i);
683 break;
684 }
685
686 default:
687 assert(0);
688 case kIfCondVar_QuotedString:
689 case kIfCondVar_QuotedSimpleString:
690 /* can't do this */
691 return kIfCondRet_Error;
692 }
693
694 return kIfCondRet_Ok;
695}
696
697
698/**
699 * Initializes a new variables with a boolean value.
700 *
701 * @param pVar The new variable.
702 * @param f The boolean value.
703 */
704static void ifcond_var_init_bool(PIFCONDVAR pVar, int f)
705{
706 pVar->enmType = kIfCondVar_Num;
707 pVar->uVal.i = !!f;
708}
709
710
711/**
712 * Assigns a boolean value to a variable.
713 *
714 * @param pVar The variable.
715 * @param f The boolean value.
716 */
717static void ifcond_var_assign_bool(PIFCONDVAR pVar, int f)
718{
719 ifcond_var_delete(pVar);
720 ifcond_var_init_bool(pVar, f);
721}
722
723
724/**
725 * Turns the variable into an boolean.
726 *
727 * @returns the boolean interpretation.
728 * @param pVar The variable.
729 */
730static int ifcond_var_make_bool(PIFCONDVAR pVar)
731{
732 switch (pVar->enmType)
733 {
734 case kIfCondVar_Num:
735 pVar->uVal.i = !!pVar->uVal.i;
736 break;
737
738 case kIfCondVar_String:
739 ifcond_var_make_simple_string(pVar);
740 /* fall thru */
741 case kIfCondVar_SimpleString:
742 {
743 /*
744 * Try convert it to a number. If that fails, use the
745 * GNU make boolean logic - not empty string means true.
746 */
747 IFCONDINT64 iVal;
748 char const *psz = pVar->uVal.psz;
749 while (isblank((unsigned char)*psz))
750 psz++;
751 if ( *psz
752 && ifcond_string_to_num(NULL, &iVal, psz, 1 /* fQuiet */) >= kIfCondRet_Ok)
753 ifcond_var_assign_bool(pVar, iVal != 0);
754 else
755 ifcond_var_assign_bool(pVar, *psz != '\0');
756 break;
757 }
758
759 case kIfCondVar_QuotedString:
760 ifcond_var_make_simple_string(pVar);
761 /* fall thru */
762 case kIfCondVar_QuotedSimpleString:
763 /*
764 * Use GNU make boolean logic (not empty string means true).
765 * No stripping here, the string is quoted.
766 */
767 ifcond_var_assign_bool(pVar, *pVar->uVal.psz != '\0');
768 break;
769
770 default:
771 assert(0);
772 break;
773 }
774
775 return pVar->uVal.i;
776}
777
778
779/**
780 * Pops a varable off the stack and deletes it.
781 * @param pThis The evaluator instance.
782 */
783static void ifcond_pop_and_delete_var(PIFCOND pThis)
784{
785 ifcond_var_delete(&pThis->aVars[pThis->iVar]);
786 pThis->iVar--;
787}
788
789
790
791/**
792 * Tries to make the variables the same type.
793 *
794 * This will not convert numbers to strings, unless one of them
795 * is a quoted string.
796 *
797 * this will try convert both to numbers if neither is quoted. Both
798 * conversions will have to suceed for this to be commited.
799 *
800 * All strings will be simplified.
801 *
802 * @returns status code. Done complaining on failure.
803 *
804 * @param pThis The evaluator instance.
805 * @param pVar1 The first variable.
806 * @param pVar2 The second variable.
807 */
808static IFCONDRET ifcond_var_unify_types(PIFCOND pThis, PIFCONDVAR pVar1, PIFCONDVAR pVar2, const char *pszOp)
809{
810 /*
811 * Try make the variables the same type before comparing.
812 */
813 if ( !ifcond_var_was_quoted(pVar1)
814 && !ifcond_var_was_quoted(pVar2))
815 {
816 if ( ifcond_var_is_string(pVar1)
817 || ifcond_var_is_string(pVar2))
818 {
819 if (!ifcond_var_is_string(pVar1))
820 ifcond_var_try_make_num(pVar2);
821 else if (!ifcond_var_is_string(pVar2))
822 ifcond_var_try_make_num(pVar1);
823 else
824 {
825 /*
826 * Both are strings, simplify them then see if both can be made into numbers.
827 */
828 IFCONDINT64 iVar1;
829 IFCONDINT64 iVar2;
830
831 ifcond_var_make_simple_string(pVar1);
832 ifcond_var_make_simple_string(pVar2);
833
834 if ( ifcond_string_to_num(NULL, &iVar1, pVar1->uVal.psz, 1 /* fQuiet */) >= kIfCondRet_Ok
835 && ifcond_string_to_num(NULL, &iVar2, pVar2->uVal.psz, 1 /* fQuiet */) >= kIfCondRet_Ok)
836 {
837 ifcond_var_assign_num(pVar1, iVar1);
838 ifcond_var_assign_num(pVar2, iVar2);
839 }
840 }
841 }
842 }
843 else
844 {
845 ifcond_var_make_simple_string(pVar1);
846 ifcond_var_make_simple_string(pVar2);
847 }
848
849 /*
850 * Complain if they aren't the same type now.
851 */
852 if (ifcond_var_is_string(pVar1) != ifcond_var_is_string(pVar2))
853 {
854 ifcond_error(pThis, "Unable to unify types for \"%s\"", pszOp);
855 return kIfCondRet_Error;
856 }
857 return kIfCondRet_Ok;
858}
859
860
861/**
862 * Is variable defined, unary.
863 *
864 * @returns Status code.
865 * @param pThis The instance.
866 */
867static IFCONDRET ifcond_op_defined(PIFCOND pThis)
868{
869 PIFCONDVAR pVar = &pThis->aVars[pThis->iVar];
870 struct variable *pMakeVar;
871 assert(pThis->iVar >= 0);
872
873 ifcond_var_make_simple_string(pVar);
874 pMakeVar = lookup_variable(pVar->uVal.psz, strlen(pVar->uVal.psz));
875 ifcond_var_assign_bool(pVar, pMakeVar && *pMakeVar->value != '\0');
876
877 return kIfCondRet_Ok;
878}
879
880
881/**
882 * Is target defined, unary.
883 *
884 * @returns Status code.
885 * @param pThis The instance.
886 */
887static IFCONDRET ifcond_op_target(PIFCOND pThis)
888{
889 PIFCONDVAR pVar = &pThis->aVars[pThis->iVar];
890 struct file *pFile = NULL;
891 assert(pThis->iVar >= 0);
892
893 /*
894 * Because of secondary target expansion, lookup the unexpanded
895 * name first.
896 */
897#ifdef CONFIG_WITH_2ND_TARGET_EXPANSION
898 if ( pVar->enmType == kIfCondVar_String
899 || pVar->enmType == kIfCondVar_QuotedString)
900 {
901 pFile = lookup_file(pVar->uVal.psz);
902 if ( pFile
903 && !pFile->need_2nd_target_expansion)
904 pFile = NULL;
905 }
906 if (pFile)
907#endif
908 {
909 ifcond_var_make_simple_string(pVar);
910 pFile = lookup_file(pVar->uVal.psz);
911 }
912
913 /*
914 * Always inspect the head of a multiple target rule
915 * and look for a file with commands.
916 */
917#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET
918 if (pFile && pFile->multi_head)
919 pFile = pFile->multi_head;
920#endif
921
922 while (pFile && !pFile->cmds)
923 pFile = pFile->prev;
924
925 ifcond_var_assign_bool(pVar, pFile != NULL && pFile->is_target);
926
927 return kIfCondRet_Ok;
928}
929
930
931/**
932 * Pluss (dummy / make_integer)
933 *
934 * @returns Status code.
935 * @param pThis The instance.
936 */
937static IFCONDRET ifcond_op_pluss(PIFCOND pThis)
938{
939 PIFCONDVAR pVar = &pThis->aVars[pThis->iVar];
940 assert(pThis->iVar >= 0);
941
942 return ifcond_var_make_num(pThis, pVar);
943}
944
945
946
947/**
948 * Minus (negate)
949 *
950 * @returns Status code.
951 * @param pThis The instance.
952 */
953static IFCONDRET ifcond_op_minus(PIFCOND pThis)
954{
955 IFCONDRET rc;
956 PIFCONDVAR pVar = &pThis->aVars[pThis->iVar];
957 assert(pThis->iVar >= 0);
958
959 rc = ifcond_var_make_num(pThis, pVar);
960 if (rc >= kIfCondRet_Ok)
961 pVar->uVal.i = -pVar->uVal.i;
962
963 return rc;
964}
965
966
967
968/**
969 * Bitwise NOT.
970 *
971 * @returns Status code.
972 * @param pThis The instance.
973 */
974static IFCONDRET ifcond_op_bitwise_not(PIFCOND pThis)
975{
976 IFCONDRET rc;
977 PIFCONDVAR pVar = &pThis->aVars[pThis->iVar];
978 assert(pThis->iVar >= 0);
979
980 rc = ifcond_var_make_num(pThis, pVar);
981 if (rc >= kIfCondRet_Ok)
982 pVar->uVal.i = ~pVar->uVal.i;
983
984 return rc;
985}
986
987
988/**
989 * Logical NOT.
990 *
991 * @returns Status code.
992 * @param pThis The instance.
993 */
994static IFCONDRET ifcond_op_logical_not(PIFCOND pThis)
995{
996 PIFCONDVAR pVar = &pThis->aVars[pThis->iVar];
997 assert(pThis->iVar >= 0);
998
999 ifcond_var_assign_bool(pVar, !ifcond_var_make_bool(pVar));
1000
1001 return kIfCondRet_Ok;
1002}
1003
1004
1005/**
1006 * Multiplication.
1007 *
1008 * @returns Status code.
1009 * @param pThis The instance.
1010 */
1011static IFCONDRET ifcond_op_multiply(PIFCOND pThis)
1012{
1013 IFCONDRET rc = kIfCondRet_Ok;
1014 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1015 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1016 assert(pThis->iVar >= 1);
1017
1018 rc = ifcond_var_make_num(pThis, pVar1);
1019 if (rc >= kIfCondRet_Ok)
1020 {
1021 rc = ifcond_var_make_num(pThis, pVar2);
1022 if (rc >= kIfCondRet_Ok)
1023 pVar1->uVal.i %= pVar2->uVal.i;
1024 }
1025
1026 ifcond_pop_and_delete_var(pThis);
1027 return rc;
1028}
1029
1030
1031
1032/**
1033 * Division.
1034 *
1035 * @returns Status code.
1036 * @param pThis The instance.
1037 */
1038static IFCONDRET ifcond_op_divide(PIFCOND pThis)
1039{
1040 IFCONDRET rc = kIfCondRet_Ok;
1041 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1042 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1043 assert(pThis->iVar >= 1);
1044
1045 rc = ifcond_var_make_num(pThis, pVar1);
1046 if (rc >= kIfCondRet_Ok)
1047 {
1048 rc = ifcond_var_make_num(pThis, pVar2);
1049 if (rc >= kIfCondRet_Ok)
1050 pVar1->uVal.i /= pVar2->uVal.i;
1051 }
1052
1053 ifcond_pop_and_delete_var(pThis);
1054 return rc;
1055}
1056
1057
1058
1059/**
1060 * Modulus.
1061 *
1062 * @returns Status code.
1063 * @param pThis The instance.
1064 */
1065static IFCONDRET ifcond_op_modulus(PIFCOND pThis)
1066{
1067 IFCONDRET rc = kIfCondRet_Ok;
1068 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1069 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1070 assert(pThis->iVar >= 1);
1071
1072 rc = ifcond_var_make_num(pThis, pVar1);
1073 if (rc >= kIfCondRet_Ok)
1074 {
1075 rc = ifcond_var_make_num(pThis, pVar2);
1076 if (rc >= kIfCondRet_Ok)
1077 pVar1->uVal.i %= pVar2->uVal.i;
1078 }
1079
1080 ifcond_pop_and_delete_var(pThis);
1081 return rc;
1082}
1083
1084
1085
1086/**
1087 * Addition (numeric).
1088 *
1089 * @returns Status code.
1090 * @param pThis The instance.
1091 */
1092static IFCONDRET ifcond_op_add(PIFCOND pThis)
1093{
1094 IFCONDRET rc = kIfCondRet_Ok;
1095 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1096 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1097 assert(pThis->iVar >= 1);
1098
1099 rc = ifcond_var_make_num(pThis, pVar1);
1100 if (rc >= kIfCondRet_Ok)
1101 {
1102 rc = ifcond_var_make_num(pThis, pVar2);
1103 if (rc >= kIfCondRet_Ok)
1104 pVar1->uVal.i += pVar2->uVal.i;
1105 }
1106
1107 ifcond_pop_and_delete_var(pThis);
1108 return rc;
1109}
1110
1111
1112/**
1113 * Subtract (numeric).
1114 *
1115 * @returns Status code.
1116 * @param pThis The instance.
1117 */
1118static IFCONDRET ifcond_op_sub(PIFCOND pThis)
1119{
1120 IFCONDRET rc = kIfCondRet_Ok;
1121 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1122 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1123 assert(pThis->iVar >= 1);
1124
1125 rc = ifcond_var_make_num(pThis, pVar1);
1126 if (rc >= kIfCondRet_Ok)
1127 {
1128 rc = ifcond_var_make_num(pThis, pVar2);
1129 if (rc >= kIfCondRet_Ok)
1130 pVar1->uVal.i -= pVar2->uVal.i;
1131 }
1132
1133 ifcond_pop_and_delete_var(pThis);
1134 return rc;
1135}
1136
1137/**
1138 * Bitwise left shift.
1139 *
1140 * @returns Status code.
1141 * @param pThis The instance.
1142 */
1143static IFCONDRET ifcond_op_shift_left(PIFCOND pThis)
1144{
1145 IFCONDRET rc = kIfCondRet_Ok;
1146 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1147 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1148 assert(pThis->iVar >= 1);
1149
1150 rc = ifcond_var_make_num(pThis, pVar1);
1151 if (rc >= kIfCondRet_Ok)
1152 {
1153 rc = ifcond_var_make_num(pThis, pVar2);
1154 if (rc >= kIfCondRet_Ok)
1155 pVar1->uVal.i <<= pVar2->uVal.i;
1156 }
1157
1158 ifcond_pop_and_delete_var(pThis);
1159 return rc;
1160}
1161
1162
1163/**
1164 * Bitwise right shift.
1165 *
1166 * @returns Status code.
1167 * @param pThis The instance.
1168 */
1169static IFCONDRET ifcond_op_shift_right(PIFCOND pThis)
1170{
1171 IFCONDRET rc = kIfCondRet_Ok;
1172 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1173 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1174 assert(pThis->iVar >= 1);
1175
1176 rc = ifcond_var_make_num(pThis, pVar1);
1177 if (rc >= kIfCondRet_Ok)
1178 {
1179 rc = ifcond_var_make_num(pThis, pVar2);
1180 if (rc >= kIfCondRet_Ok)
1181 pVar1->uVal.i >>= pVar2->uVal.i;
1182 }
1183
1184 ifcond_pop_and_delete_var(pThis);
1185 return rc;
1186}
1187
1188
1189/**
1190 * Less than or equal
1191 *
1192 * @returns Status code.
1193 * @param pThis The instance.
1194 */
1195static IFCONDRET ifcond_op_less_or_equal_than(PIFCOND pThis)
1196{
1197 IFCONDRET rc = kIfCondRet_Ok;
1198 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1199 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1200 assert(pThis->iVar >= 1);
1201
1202 rc = ifcond_var_unify_types(pThis, pVar1, pVar2, "<=");
1203 if (rc >= kIfCondRet_Ok)
1204 {
1205 if (!ifcond_var_is_string(pVar1))
1206 ifcond_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i);
1207 else
1208 ifcond_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) <= 0);
1209 }
1210
1211 ifcond_pop_and_delete_var(pThis);
1212 return rc;
1213}
1214
1215
1216/**
1217 * Less than.
1218 *
1219 * @returns Status code.
1220 * @param pThis The instance.
1221 */
1222static IFCONDRET ifcond_op_less_than(PIFCOND pThis)
1223{
1224 IFCONDRET rc = kIfCondRet_Ok;
1225 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1226 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1227 assert(pThis->iVar >= 1);
1228
1229 rc = ifcond_var_unify_types(pThis, pVar1, pVar2, "<");
1230 if (rc >= kIfCondRet_Ok)
1231 {
1232 if (!ifcond_var_is_string(pVar1))
1233 ifcond_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i);
1234 else
1235 ifcond_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) < 0);
1236 }
1237
1238 ifcond_pop_and_delete_var(pThis);
1239 return rc;
1240}
1241
1242
1243/**
1244 * Greater or equal than
1245 *
1246 * @returns Status code.
1247 * @param pThis The instance.
1248 */
1249static IFCONDRET ifcond_op_greater_or_equal_than(PIFCOND pThis)
1250{
1251 IFCONDRET rc = kIfCondRet_Ok;
1252 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1253 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1254 assert(pThis->iVar >= 1);
1255
1256 rc = ifcond_var_unify_types(pThis, pVar1, pVar2, ">=");
1257 if (rc >= kIfCondRet_Ok)
1258 {
1259 if (!ifcond_var_is_string(pVar1))
1260 ifcond_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i);
1261 else
1262 ifcond_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) >= 0);
1263 }
1264
1265 ifcond_pop_and_delete_var(pThis);
1266 return rc;
1267}
1268
1269
1270/**
1271 * Greater than.
1272 *
1273 * @returns Status code.
1274 * @param pThis The instance.
1275 */
1276static IFCONDRET ifcond_op_greater_than(PIFCOND pThis)
1277{
1278 IFCONDRET rc = kIfCondRet_Ok;
1279 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1280 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1281 assert(pThis->iVar >= 1);
1282
1283 rc = ifcond_var_unify_types(pThis, pVar1, pVar2, ">");
1284 if (rc >= kIfCondRet_Ok)
1285 {
1286 if (!ifcond_var_is_string(pVar1))
1287 ifcond_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i);
1288 else
1289 ifcond_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) > 0);
1290 }
1291
1292 ifcond_pop_and_delete_var(pThis);
1293 return rc;
1294}
1295
1296
1297/**
1298 * Equal.
1299 *
1300 * @returns Status code.
1301 * @param pThis The instance.
1302 */
1303static IFCONDRET ifcond_op_equal(PIFCOND pThis)
1304{
1305 IFCONDRET rc = kIfCondRet_Ok;
1306 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1307 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1308 assert(pThis->iVar >= 1);
1309
1310 /*
1311 * The same type?
1312 */
1313 if (ifcond_var_is_string(pVar1) == ifcond_var_is_string(pVar2))
1314 {
1315 if (!ifcond_var_is_string(pVar1))
1316 /* numbers are simple */
1317 ifcond_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1318 else
1319 {
1320 /* try a normal string compare. */
1321 ifcond_var_make_simple_string(pVar1);
1322 ifcond_var_make_simple_string(pVar2);
1323 if (!strcmp(pVar1->uVal.psz, pVar2->uVal.psz))
1324 ifcond_var_assign_bool(pVar1, 1);
1325 /* try convert and compare as number instead. */
1326 else if ( ifcond_var_try_make_num(pVar1) >= kIfCondRet_Ok
1327 && ifcond_var_try_make_num(pVar2) >= kIfCondRet_Ok)
1328 ifcond_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1329 /* ok, they really aren't equal. */
1330 else
1331 ifcond_var_assign_bool(pVar1, 0);
1332 }
1333 }
1334 else
1335 {
1336 /*
1337 * If the type differs, there are now two options:
1338 * 1. Convert the string to a valid number and compare the numbers.
1339 * 2. Convert an empty string to a 'false' boolean value and compare
1340 * numerically. This one is a bit questionable, so we don't try this.
1341 */
1342 if ( ifcond_var_try_make_num(pVar1) >= kIfCondRet_Ok
1343 && ifcond_var_try_make_num(pVar2) >= kIfCondRet_Ok)
1344 ifcond_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i);
1345 else
1346 {
1347 ifcond_error(pThis, "Cannot compare strings and numbers");
1348 rc = kIfCondRet_Error;
1349 }
1350 }
1351
1352 ifcond_pop_and_delete_var(pThis);
1353 return kIfCondRet_Ok;
1354}
1355
1356
1357/**
1358 * Not equal.
1359 *
1360 * @returns Status code.
1361 * @param pThis The instance.
1362 */
1363static IFCONDRET ifcond_op_not_equal(PIFCOND pThis)
1364{
1365 IFCONDRET rc = ifcond_op_equal(pThis);
1366 if (rc >= kIfCondRet_Ok)
1367 rc = ifcond_op_logical_not(pThis);
1368 return rc;
1369}
1370
1371
1372/**
1373 * Bitwise AND.
1374 *
1375 * @returns Status code.
1376 * @param pThis The instance.
1377 */
1378static IFCONDRET ifcond_op_bitwise_and(PIFCOND pThis)
1379{
1380 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1381 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1382 IFCONDRET rc;
1383 assert(pThis->iVar >= 1);
1384
1385 rc = ifcond_var_make_num(pThis, pVar1);
1386 if (rc >= kIfCondRet_Ok)
1387 {
1388 rc = ifcond_var_make_num(pThis, pVar2);
1389 if (rc >= kIfCondRet_Ok)
1390 pVar1->uVal.i &= pVar2->uVal.i;
1391 }
1392
1393 ifcond_pop_and_delete_var(pThis);
1394 return kIfCondRet_Ok;
1395}
1396
1397
1398/**
1399 * Bitwise XOR.
1400 *
1401 * @returns Status code.
1402 * @param pThis The instance.
1403 */
1404static IFCONDRET ifcond_op_bitwise_xor(PIFCOND pThis)
1405{
1406 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1407 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1408 IFCONDRET rc;
1409 assert(pThis->iVar >= 1);
1410
1411 rc = ifcond_var_make_num(pThis, pVar1);
1412 if (rc >= kIfCondRet_Ok)
1413 {
1414 rc = ifcond_var_make_num(pThis, pVar2);
1415 if (rc >= kIfCondRet_Ok)
1416 pVar1->uVal.i ^= pVar2->uVal.i;
1417 }
1418
1419 ifcond_pop_and_delete_var(pThis);
1420 return kIfCondRet_Ok;
1421}
1422
1423
1424/**
1425 * Bitwise OR.
1426 *
1427 * @returns Status code.
1428 * @param pThis The instance.
1429 */
1430static IFCONDRET ifcond_op_bitwise_or(PIFCOND pThis)
1431{
1432 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1433 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1434 IFCONDRET rc;
1435 assert(pThis->iVar >= 1);
1436
1437 rc = ifcond_var_make_num(pThis, pVar1);
1438 if (rc >= kIfCondRet_Ok)
1439 {
1440 rc = ifcond_var_make_num(pThis, pVar2);
1441 if (rc >= kIfCondRet_Ok)
1442 pVar1->uVal.i |= pVar2->uVal.i;
1443 }
1444
1445 ifcond_pop_and_delete_var(pThis);
1446 return kIfCondRet_Ok;
1447}
1448
1449
1450/**
1451 * Logical AND.
1452 *
1453 * @returns Status code.
1454 * @param pThis The instance.
1455 */
1456static IFCONDRET ifcond_op_logical_and(PIFCOND pThis)
1457{
1458 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1459 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1460 assert(pThis->iVar >= 1);
1461
1462 if ( ifcond_var_make_bool(pVar1)
1463 && ifcond_var_make_bool(pVar2))
1464 ifcond_var_assign_bool(pVar1, 1);
1465 else
1466 ifcond_var_assign_bool(pVar1, 0);
1467
1468 ifcond_pop_and_delete_var(pThis);
1469 return kIfCondRet_Ok;
1470}
1471
1472
1473/**
1474 * Logical OR.
1475 *
1476 * @returns Status code.
1477 * @param pThis The instance.
1478 */
1479static IFCONDRET ifcond_op_logical_or(PIFCOND pThis)
1480{
1481 PIFCONDVAR pVar1 = &pThis->aVars[pThis->iVar - 1];
1482 PIFCONDVAR pVar2 = &pThis->aVars[pThis->iVar];
1483 assert(pThis->iVar >= 1);
1484
1485 if ( ifcond_var_make_bool(pVar1)
1486 || ifcond_var_make_bool(pVar2))
1487 ifcond_var_assign_bool(pVar1, 1);
1488 else
1489 ifcond_var_assign_bool(pVar1, 0);
1490
1491 ifcond_pop_and_delete_var(pThis);
1492 return kIfCondRet_Ok;
1493}
1494
1495
1496/**
1497 * Left parenthesis.
1498 *
1499 * @returns Status code.
1500 * @param pThis The instance.
1501 */
1502static IFCONDRET ifcond_op_left_parenthesis(PIFCOND pThis)
1503{
1504 /*
1505 * There should be a right parenthesis operator lined up for us now,
1506 * eat it. If not found there is an inbalance.
1507 */
1508 IFCONDRET rc = ifcond_get_binary_or_eoe_or_rparen(pThis);
1509 if ( rc == kIfCondRet_Operator
1510 && pThis->apOps[pThis->iOp]->szOp[0] == ')')
1511 {
1512 /* pop it and get another one which we can leave pending. */
1513 pThis->iOp--;
1514 rc = ifcond_get_binary_or_eoe_or_rparen(pThis);
1515 if (rc >= kIfCondRet_Ok)
1516 ifcond_unget_op(pThis);
1517 }
1518 else
1519 {
1520 ifcond_error(pThis, "Missing ')'");
1521 rc = kIfCondRet_Error;
1522 }
1523
1524 return rc;
1525}
1526
1527
1528/**
1529 * Right parenthesis, dummy that's never actually called.
1530 *
1531 * @returns Status code.
1532 * @param pThis The instance.
1533 */
1534static IFCONDRET ifcond_op_right_parenthesis(PIFCOND pThis)
1535{
1536 return kIfCondRet_Ok;
1537}
1538
1539
1540
1541
1542
1543/**
1544 * The operator table.
1545 *
1546 * This table is NOT ordered by precedence, but for linear search
1547 * allowing for first match to return the correct operator. This
1548 * means that || must come before |, or else | will match all.
1549 */
1550static const IFCONDOP g_aIfCondOps[] =
1551{
1552#define IFCOND_OP(szOp, iPrecedence, cArgs, pfn) { szOp, sizeof(szOp) - 1, '\0', iPrecedence, cArgs, pfn }
1553 /* Name, iPrecedence, cArgs, pfn */
1554 IFCOND_OP("defined", 90, 1, ifcond_op_defined),
1555 IFCOND_OP("target", 90, 1, ifcond_op_target),
1556 IFCOND_OP("+", 80, 1, ifcond_op_pluss),
1557 IFCOND_OP("-", 80, 1, ifcond_op_minus),
1558 IFCOND_OP("~", 80, 1, ifcond_op_bitwise_not),
1559 IFCOND_OP("*", 75, 2, ifcond_op_multiply),
1560 IFCOND_OP("/", 75, 2, ifcond_op_divide),
1561 IFCOND_OP("%", 75, 2, ifcond_op_modulus),
1562 IFCOND_OP("+", 70, 2, ifcond_op_add),
1563 IFCOND_OP("-", 70, 2, ifcond_op_sub),
1564 IFCOND_OP("<<", 65, 2, ifcond_op_shift_left),
1565 IFCOND_OP(">>", 65, 2, ifcond_op_shift_right),
1566 IFCOND_OP("<=", 60, 2, ifcond_op_less_or_equal_than),
1567 IFCOND_OP("<", 60, 2, ifcond_op_less_than),
1568 IFCOND_OP(">=", 60, 2, ifcond_op_greater_or_equal_than),
1569 IFCOND_OP(">", 60, 2, ifcond_op_greater_than),
1570 IFCOND_OP("==", 55, 2, ifcond_op_equal),
1571 IFCOND_OP("!=", 55, 2, ifcond_op_not_equal),
1572 IFCOND_OP("!", 80, 1, ifcond_op_logical_not),
1573 IFCOND_OP("^", 45, 2, ifcond_op_bitwise_xor),
1574 IFCOND_OP("&&", 35, 2, ifcond_op_logical_and),
1575 IFCOND_OP("&", 50, 2, ifcond_op_bitwise_and),
1576 IFCOND_OP("||", 30, 2, ifcond_op_logical_or),
1577 IFCOND_OP("|", 40, 2, ifcond_op_bitwise_or),
1578 { "(", 1, ')', 10, 1, ifcond_op_left_parenthesis },
1579 { ")", 1, '(', 10, 0, ifcond_op_right_parenthesis },
1580 /* { "?", 1, ':', 5, 2, ifcond_op_question },
1581 { ":", 1, '?', 5, 2, ifcond_op_colon }, -- too weird for now. */
1582#undef IFCOND_OP
1583};
1584
1585/** Dummy end of expression fake. */
1586static const IFCONDOP g_IfCondEndOfExpOp =
1587{
1588 "", 0, '\0', 0, 0, NULL
1589};
1590
1591
1592/**
1593 * Initializes the opcode character map if necessary.
1594 */
1595static void ifcond_map_init(void)
1596{
1597 int i;
1598 if (g_fIfCondInitializedMap)
1599 return;
1600
1601 /*
1602 * Initialize it.
1603 */
1604 memset(&g_auchOpStartCharMap, 0, sizeof(g_auchOpStartCharMap));
1605 for (i = 0; i < sizeof(g_aIfCondOps) / sizeof(g_aIfCondOps[0]); i++)
1606 {
1607 unsigned int ch = (unsigned int)g_aIfCondOps[i].szOp[0];
1608 if (!g_auchOpStartCharMap[ch])
1609 g_auchOpStartCharMap[ch] = (i << 1) | 1;
1610 }
1611
1612 g_fIfCondInitializedMap = 1;
1613}
1614
1615
1616/**
1617 * Looks up a character in the map.
1618 *
1619 * @returns the value for that char.
1620 * @retval 0 if not a potential opcode start char.
1621 * @retval non-zero if it's a potential operator. The low bit is always set
1622 * while the remaining 7 bits is the index into the operator table
1623 * of the first match.
1624 *
1625 * @param ch The character.
1626 */
1627static unsigned char ifcond_map_get(char ch)
1628{
1629 return g_auchOpStartCharMap[(unsigned int)ch];
1630}
1631
1632
1633/**
1634 * Searches the operator table given a potential operator start char.
1635 *
1636 * @returns Pointer to the matching operator. NULL if not found.
1637 * @param psz Pointer to what can be an operator.
1638 * @param uchVal The ifcond_map_get value.
1639 * @param fUnary Whether it must be an unary operator or not.
1640 */
1641static PCIFCONDOP ifcond_lookup_op(char const *psz, unsigned char uchVal, int fUnary)
1642{
1643 char ch = *psz;
1644 int i;
1645
1646 for (i = uchVal >> 1; i < sizeof(g_aIfCondOps) / sizeof(g_aIfCondOps[0]); i++)
1647 {
1648 /* compare the string... */
1649 switch (g_aIfCondOps[i].cchOp)
1650 {
1651 case 1:
1652 if (g_aIfCondOps[i].szOp[0] != ch)
1653 continue;
1654 break;
1655 case 2:
1656 if ( g_aIfCondOps[i].szOp[0] != ch
1657 || g_aIfCondOps[i].szOp[1] != psz[1])
1658 continue;
1659 break;
1660 default:
1661 if ( g_aIfCondOps[i].szOp[0] != ch
1662 || strncmp(&g_aIfCondOps[i].szOp[1], psz + 1, g_aIfCondOps[i].cchOp - 1))
1663 continue;
1664 break;
1665 }
1666
1667 /* ... and the operator type. */
1668 if (fUnary == (g_aIfCondOps[i].cArgs == 1))
1669 {
1670 /* got a match! */
1671 return &g_aIfCondOps[i];
1672 }
1673 }
1674
1675 return NULL;
1676}
1677
1678
1679/**
1680 * Ungets a binary operator.
1681 *
1682 * The operator is poped from the stack and put in the pending position.
1683 *
1684 * @param pThis The evaluator instance.
1685 */
1686static void ifcond_unget_op(PIFCOND pThis)
1687{
1688 assert(pThis->pPending == NULL);
1689 assert(pThis->iOp >= 0);
1690
1691 pThis->pPending = pThis->apOps[pThis->iOp];
1692 pThis->apOps[pThis->iOp] = NULL;
1693 pThis->iOp--;
1694}
1695
1696
1697
1698/**
1699 * Get the next token, it should be a binary operator, or the end of
1700 * the expression, or a right parenthesis.
1701 *
1702 * The operator is pushed onto the stack and the status code indicates
1703 * which of the two we found.
1704 *
1705 * @returns status code. Will grumble on failure.
1706 * @retval kIfCondRet_EndOfExpr if we encountered the end of the expression.
1707 * @retval kIfCondRet_Operator if we encountered a binary operator or right
1708 * parenthesis. It's on the operator stack.
1709 *
1710 * @param pThis The evaluator instance.
1711 */
1712static IFCONDRET ifcond_get_binary_or_eoe_or_rparen(PIFCOND pThis)
1713{
1714 /*
1715 * See if there is anything pending first.
1716 */
1717 PCIFCONDOP pOp = pThis->pPending;
1718 if (pOp)
1719 pThis->pPending = NULL;
1720 else
1721 {
1722 /*
1723 * Eat more of the expression.
1724 */
1725 char const *psz = pThis->psz;
1726
1727 /* spaces */
1728 while (isspace((unsigned int)*psz))
1729 psz++;
1730 /* see what we've got. */
1731 if (*psz)
1732 {
1733 unsigned char uchVal = ifcond_map_get(*psz);
1734 if (uchVal)
1735 pOp = ifcond_lookup_op(psz, uchVal, 0 /* fUnary */);
1736 if (!pOp)
1737 {
1738 ifcond_error(pThis, "Expected binary operator, found \"%.42s\"...", psz);
1739 return kIfCondRet_Error;
1740 }
1741 psz += pOp->cchOp;
1742 }
1743 else
1744 pOp = &g_IfCondEndOfExpOp;
1745 pThis->psz = psz;
1746 }
1747
1748 /*
1749 * Push it.
1750 */
1751 if (pThis->iOp >= IFCOND_MAX_OPERATORS - 1)
1752 {
1753 ifcond_error(pThis, "Operator stack overflow");
1754 return kIfCondRet_Error;
1755 }
1756 pThis->apOps[++pThis->iOp] = pOp;
1757
1758 return pOp->iPrecedence
1759 ? kIfCondRet_Operator
1760 : kIfCondRet_EndOfExpr;
1761}
1762
1763
1764
1765/**
1766 * Get the next token, it should be an unary operator or an operand.
1767 *
1768 * This will fail if encountering the end of the expression since
1769 * it is implied that there should be something more.
1770 *
1771 * The token is pushed onto the respective stack and the status code
1772 * indicates which it is.
1773 *
1774 * @returns status code. On failure we'll be done bitching already.
1775 * @retval kIfCondRet_Operator if we encountered an unary operator.
1776 * It's on the operator stack.
1777 * @retval kIfCondRet_Operand if we encountered an operand operator.
1778 * It's on the operand stack.
1779 *
1780 * @param This The evaluator instance.
1781 */
1782static IFCONDRET ifcond_get_unary_or_operand(PIFCOND pThis)
1783{
1784 IFCONDRET rc;
1785 unsigned char uchVal;
1786 PCIFCONDOP pOp;
1787 char const *psz = pThis->psz;
1788
1789 /*
1790 * Eat white space and make sure there is something after it.
1791 */
1792 while (isspace((unsigned int)*psz))
1793 psz++;
1794 if (!*psz)
1795 {
1796 ifcond_error(pThis, "Unexpected end of expression");
1797 return kIfCondRet_Error;
1798 }
1799
1800 /*
1801 * Is it an operator?
1802 */
1803 pOp = NULL;
1804 uchVal = ifcond_map_get(*psz);
1805 if (uchVal)
1806 pOp = ifcond_lookup_op(psz, uchVal, 1 /* fUnary */);
1807 if (pOp)
1808 {
1809 /*
1810 * Push the operator onto the stack.
1811 */
1812 if (pThis->iVar < IFCOND_MAX_OPERANDS - 1)
1813 {
1814 pThis->apOps[++pThis->iOp] = pOp;
1815 rc = kIfCondRet_Operator;
1816 }
1817 else
1818 {
1819 ifcond_error(pThis, "Operator stack overflow");
1820 rc = kIfCondRet_Error;
1821 }
1822 psz += pOp->cchOp;
1823 }
1824 else if (pThis->iVar < IFCOND_MAX_OPERANDS - 1)
1825 {
1826 /*
1827 * It's an operand. Figure out where it ends and
1828 * push it onto the stack.
1829 */
1830 const char *pszStart = psz;
1831
1832 rc = kIfCondRet_Ok;
1833 if (*psz == '"')
1834 {
1835 pszStart++;
1836 while (*psz && *psz != '"')
1837 psz++;
1838 ifcond_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kIfCondVar_QuotedString);
1839 }
1840 else if (*psz == '\'')
1841 {
1842 pszStart++;
1843 while (*psz && *psz != '\'')
1844 psz++;
1845 ifcond_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kIfCondVar_QuotedSimpleString);
1846 }
1847 else
1848 {
1849 char achPars[20];
1850 int iPar = -1;
1851 char chEndPar = '\0';
1852 char ch;
1853
1854 while ((ch = *psz) != '\0')
1855 {
1856 /* $(adsf) or ${asdf} needs special handling. */
1857 if ( ch == '$'
1858 && ( psz[1] == '('
1859 || psz[1] == '{'))
1860 {
1861 psz++;
1862 if (iPar > sizeof(achPars) / sizeof(achPars[0]))
1863 {
1864 ifcond_error(pThis, "Too deep nesting of variable expansions");
1865 rc = kIfCondRet_Error;
1866 break;
1867 }
1868 achPars[++iPar] = chEndPar = ch == '(' ? ')' : '}';
1869 }
1870 else if (ch == chEndPar)
1871 {
1872 iPar--;
1873 chEndPar = iPar >= 0 ? achPars[iPar] : '\0';
1874 }
1875 else if (!chEndPar)
1876 {
1877 /** @todo combine isspace and ifcond_map_get! */
1878 unsigned chVal = ifcond_map_get(ch);
1879 if (chVal)
1880 {
1881 PCIFCONDOP pOp = ifcond_lookup_op(psz, uchVal, 0 /* fUnary */);
1882 if (pOp)
1883 break;
1884 }
1885 if (isspace((unsigned char)ch))
1886 break;
1887 }
1888
1889 /* next */
1890 psz++;
1891 }
1892
1893 if (rc == kIfCondRet_Ok)
1894 ifcond_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kIfCondVar_String);
1895 }
1896 }
1897 else
1898 {
1899 ifcond_error(pThis, "Operand stack overflow");
1900 rc = kIfCondRet_Error;
1901 }
1902 pThis->psz = psz;
1903
1904 return rc;
1905}
1906
1907
1908/**
1909 * Evaluates the current expression.
1910 *
1911 * @returns status code.
1912 *
1913 * @param pThis The instance.
1914 */
1915static IFCONDRET ifcond_eval(PIFCOND pThis)
1916{
1917 IFCONDRET rc;
1918 PCIFCONDOP pOp;
1919
1920 /*
1921 * The main loop.
1922 */
1923 for (;;)
1924 {
1925 /*
1926 * Eat unary operators until we hit an operand.
1927 */
1928 do rc = ifcond_get_unary_or_operand(pThis);
1929 while (rc == kIfCondRet_Operator);
1930 if (rc < kIfCondRet_Error)
1931 break;
1932
1933 /*
1934 * Look for a binary operator, right parenthesis or end of expression.
1935 */
1936 rc = ifcond_get_binary_or_eoe_or_rparen(pThis);
1937 if (rc < kIfCondRet_Error)
1938 break;
1939 ifcond_unget_op(pThis);
1940
1941 /*
1942 * Pop operators and apply them.
1943 *
1944 * Parenthesis will be handed via precedence, where the left parenthesis
1945 * will go pop the right one and make another operator pending.
1946 */
1947 while ( pThis->iOp >= 0
1948 && pThis->apOps[pThis->iOp]->iPrecedence >= pThis->pPending->iPrecedence)
1949 {
1950 pOp = pThis->apOps[pThis->iOp--];
1951 rc = pOp->pfn(pThis);
1952 if (rc < kIfCondRet_Error)
1953 break;
1954 }
1955 if (rc < kIfCondRet_Error)
1956 break;
1957
1958 /*
1959 * Get the next binary operator or end of expression.
1960 * There should be no right parenthesis here.
1961 */
1962 rc = ifcond_get_binary_or_eoe_or_rparen(pThis);
1963 if (rc < kIfCondRet_Error)
1964 break;
1965 pOp = pThis->apOps[pThis->iOp];
1966 if (!pOp->iPrecedence)
1967 break; /* end of expression */
1968 if (!pOp->cArgs)
1969 {
1970 ifcond_error(pThis, "Unexpected \"%s\"", pOp->szOp);
1971 rc = kIfCondRet_Error;
1972 break;
1973 }
1974 }
1975
1976 return rc;
1977}
1978
1979
1980/**
1981 * Destroys the given instance.
1982 *
1983 * @param pThis The instance to destroy.
1984 */
1985static void ifcond_destroy(PIFCOND pThis)
1986{
1987 while (pThis->iVar >= 0)
1988 {
1989 ifcond_var_delete(pThis->aVars);
1990 pThis->iVar--;
1991 }
1992 free(pThis);
1993}
1994
1995
1996/**
1997 * Instantiates an expression evaluator.
1998 *
1999 * @returns The instance.
2000 *
2001 * @param pszExpr What to parse.
2002 * This must stick around until ifcond_destroy.
2003 */
2004static PIFCOND ifcond_create(char const *pszExpr)
2005{
2006 PIFCOND pThis = (PIFCOND)xmalloc(sizeof(*pThis));
2007 pThis->pszExpr = pszExpr;
2008 pThis->psz = pszExpr;
2009 pThis->pFileLoc = NULL;
2010 pThis->pPending = NULL;
2011 pThis->iVar = -1;
2012 pThis->iOp = -1;
2013
2014 ifcond_map_init();
2015 return pThis;
2016}
2017
2018
2019/**
2020 * Evaluates the given if expression.
2021 *
2022 * @returns -1, 0 or 1.
2023 * @retval -1 if the expression is invalid.
2024 * @retval 0 if the expression is true
2025 * @retval 1 if the expression is false.
2026 *
2027 * @param line The expression. Can modify this as we like.
2028 * @param flocp The file location, used for errors.
2029 */
2030int ifcond(char *line, const struct floc *flocp)
2031{
2032 /*
2033 * Instantiate the expression evaluator and let
2034 * it have a go at it.
2035 */
2036 int rc = -1;
2037 PIFCOND pIfCond = ifcond_create(line);
2038 pIfCond->pFileLoc = flocp;
2039 if (ifcond_eval(pIfCond) >= kIfCondRet_Ok)
2040 {
2041 /*
2042 * Convert the result (on top of the stack) to boolean and
2043 * set our return value accordingly.
2044 */
2045 if (ifcond_var_make_bool(&pIfCond->aVars[0]))
2046 rc = 0;
2047 else
2048 rc = 1;
2049 }
2050 ifcond_destroy(pIfCond);
2051
2052 return rc;
2053}
2054
2055
2056#endif /* CONFIG_WITH_IF_CONDITIONALS */
2057
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