GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/make/cond.c Lines: 270 398 67.8 %
Date: 2016-12-06 Branches: 190 352 54.0 %

Line Branch Exec Source
1
/*	$OpenBSD: cond.c,v 1.50 2013/11/22 15:47:35 espie Exp $	*/
2
/*	$NetBSD: cond.c,v 1.7 1996/11/06 17:59:02 christos Exp $	*/
3
4
/*
5
 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
6
 * Copyright (c) 1988, 1989 by Adam de Boor
7
 * Copyright (c) 1989 by Berkeley Softworks
8
 * All rights reserved.
9
 *
10
 * This code is derived from software contributed to Berkeley by
11
 * Adam de Boor.
12
 *
13
 * Redistribution and use in source and binary forms, with or without
14
 * modification, are permitted provided that the following conditions
15
 * are met:
16
 * 1. Redistributions of source code must retain the above copyright
17
 *    notice, this list of conditions and the following disclaimer.
18
 * 2. Redistributions in binary form must reproduce the above copyright
19
 *    notice, this list of conditions and the following disclaimer in the
20
 *    documentation and/or other materials provided with the distribution.
21
 * 3. Neither the name of the University nor the names of its contributors
22
 *    may be used to endorse or promote products derived from this software
23
 *    without specific prior written permission.
24
 *
25
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35
 * SUCH DAMAGE.
36
 */
37
38
#include <ctype.h>
39
#include <stddef.h>
40
#include <stdint.h>
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <ohash.h>
45
#include "config.h"
46
#include "defines.h"
47
#include "dir.h"
48
#include "buf.h"
49
#include "cond.h"
50
#include "cond_int.h"
51
#include "condhashconsts.h"
52
#include "error.h"
53
#include "var.h"
54
#include "varname.h"
55
#include "targ.h"
56
#include "lowparse.h"
57
#include "str.h"
58
#include "main.h"
59
#include "gnode.h"
60
#include "lst.h"
61
62
63
/* The parsing of conditional expressions is based on this grammar:
64
 *	E -> F || E
65
 *	E -> F
66
 *	F -> T && F
67
 *	F -> T
68
 *	T -> defined(variable)
69
 *	T -> make(target)
70
 *	T -> exists(file)
71
 *	T -> empty(varspec)
72
 *	T -> target(name)
73
 *	T -> commands(name)
74
 *	T -> symbol
75
 *	T -> $(varspec) op value
76
 *	T -> $(varspec) == "string"
77
 *	T -> $(varspec) != "string"
78
 *	T -> "string" == "string"
79
 *	T -> "string" != "string"
80
 *	T -> number op number
81
 *	T -> ( E )
82
 *	T -> ! T
83
 *	op -> == | != | > | < | >= | <=
84
 *
85
 * 'symbol' is some other symbol to which the default function (condDefProc)
86
 * is applied.
87
 *
88
 * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
89
 * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
90
 * LParen for '(', RParen for ')' and will evaluate the other terminal
91
 * symbols, using either the default function or the function given in the
92
 * terminal, and return the result as either true or False.
93
 *
94
 * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.  */
95
typedef enum {
96
	False = 0, True = 1, And, Or, Not, LParen, RParen, EndOfFile, None, Err
97
} Token;
98
99
/*-
100
 * Structures to handle elegantly the different forms of #if's. The
101
 * last two fields are stored in condInvert and condDefProc, respectively.
102
 */
103
static bool CondGetArg(const char **, struct Name *,
104
    const char *, bool);
105
static bool CondDoDefined(struct Name *);
106
static bool CondDoMake(struct Name *);
107
static bool CondDoExists(struct Name *);
108
static bool CondDoTarget(struct Name *);
109
static bool CondDoTargetWithCommands(struct Name *);
110
static bool CondCvtArg(const char *, double *);
111
static Token CondToken(bool);
112
static Token CondT(bool);
113
static Token CondF(bool);
114
static Token CondE(bool);
115
static Token CondHandleVarSpec(bool);
116
static Token CondHandleDefault(bool);
117
static Token CondHandleComparison(char *, bool, bool);
118
static Token CondHandleString(bool);
119
static Token CondHandleNumber(bool);
120
static const char *find_cond(const char *);
121
122
123
struct If {
124
	bool isElse;			/* true for else forms */
125
	bool doNot;			/* true for embedded negation */
126
	bool (*defProc)(struct Name *); /* function to apply */
127
};
128
129
static struct If ifs[] = {
130
	{ false,false,	CondDoDefined },	/* if, ifdef */
131
	{ false,true,	CondDoDefined },	/* ifndef */
132
	{ false,false,	CondDoMake },		/* ifmake */
133
	{ false,true,	CondDoMake },		/* ifnmake */
134
	{ true,	false,	CondDoDefined },	/* elif, elifdef */
135
	{ true,	true,	CondDoDefined },	/* elifndef */
136
	{ true,	false,	CondDoMake },		/* elifmake */
137
	{ true,	true,	CondDoMake },		/* elifnmake */
138
	{ true,	false,	NULL }
139
};
140
141
#define COND_IF_INDEX		0
142
#define COND_IFDEF_INDEX	0
143
#define COND_IFNDEF_INDEX	1
144
#define COND_IFMAKE_INDEX	2
145
#define COND_IFNMAKE_INDEX	3
146
#define COND_ELIF_INDEX		4
147
#define COND_ELIFDEF_INDEX	4
148
#define COND_ELIFNDEF_INDEX	5
149
#define COND_ELIFMAKE_INDEX	6
150
#define COND_ELIFNMAKE_INDEX	7
151
#define COND_ELSE_INDEX		8
152
153
static bool condInvert;		/* Invert the default function */
154
static bool (*condDefProc)(struct Name *);
155
				/* Default function to apply */
156
static const char *condExpr;	/* The expression to parse */
157
static Token condPushBack=None;	/* Single push-back token used in parsing */
158
159
#define MAXIF 30		/* greatest depth of #if'ing */
160
161
static struct {
162
	bool 	value;
163
	Location origin;
164
} condStack[MAXIF];		/* Stack of conditionals */
165
166
static int condTop = MAXIF;	/* Top-most conditional */
167
static int skipIfLevel=0;	/* Depth of skipped conditionals */
168
static bool skipLine = false;	/* Whether the parse module is skipping lines */
169
170
static const char *
171
find_cond(const char *p)
172
332393
{
173
289932
	for (;;p++) {
174
		/* XXX: when *p == '\0', strchr() returns !NULL */
175
332393
		if (strchr(" \t)&|$", *p) != NULL)
176
42461
			return p;
177
289932
	}
178
}
179
180
181
/*-
182
 *-----------------------------------------------------------------------
183
 * CondGetArg --
184
 *	Find the argument of a built-in function.
185
 *
186
 * Results:
187
 *	true if evaluation went okay
188
 *
189
 * Side Effects:
190
 *	The line pointer is set to point to the closing parenthesis of the
191
 *	function call. The argument is filled.
192
 *-----------------------------------------------------------------------
193
 */
194
static bool
195
CondGetArg(const char **linePtr, struct Name *arg, const char *func,
196
    bool parens) /* true if arg should be bounded by parens */
197
39154
{
198
	const char *cp;
199
200
39154
	cp = *linePtr;
201
	/* Set things up to return faster in case of problem */
202
39154
	arg->s = cp;
203
39154
	arg->e = cp;
204
39154
	arg->tofree = false;
205
206
	/* make and defined are not really keywords, so if CondGetArg doesn't
207
	 * work...
208
	 */
209
39154
	if (parens) {
210
76842
		while (ISSPACE(*cp))
211
			cp++;
212
38421
		if (*cp == '(')
213
37688
			cp++;
214
		else
215
733
			return false;
216
	}
217
218
38421
	if (*cp == '\0')
219
		return false;
220
221
76842
	while (ISSPACE(*cp))
222
		cp++;
223
224
38421
	cp = VarName_Get(cp, arg, NULL, true, find_cond);
225
226
115263
	while (ISSPACE(*cp))
227
		cp++;
228
38421
	if (parens) {
229
37688
		if (*cp == ')')
230
37688
			cp++;
231
		else {
232
			Parse_Error(PARSE_WARNING,
233
			    "Missing closing parenthesis for %s()", func);
234
			return false;
235
	    	}
236
	}
237
238
38421
	*linePtr = cp;
239
38421
	return true;
240
}
241
242
/*-
243
 *-----------------------------------------------------------------------
244
 * CondDoDefined --
245
 *	Handle the 'defined' function for conditionals.
246
 *
247
 * Results:
248
 *	true if the given variable is defined.
249
 *-----------------------------------------------------------------------
250
 */
251
static bool
252
CondDoDefined(struct Name *arg)
253
22691
{
254
22691
	return Var_Definedi(arg->s, arg->e);
255
}
256
257
/*-
258
 *-----------------------------------------------------------------------
259
 * CondDoMake --
260
 *	Handle the 'make' function for conditionals.
261
 *
262
 * Results:
263
 *	true if the given target is being made.
264
 *-----------------------------------------------------------------------
265
 */
266
static bool
267
CondDoMake(struct Name *arg)
268
15
{
269
	LstNode ln;
270
271
21
	for (ln = Lst_First(create); ln != NULL; ln = Lst_Adv(ln)) {
272
6
		char *s = (char *)Lst_Datum(ln);
273
6
		if (Str_Matchi(s, strchr(s, '\0'), arg->s, arg->e))
274
			return true;
275
	}
276
277
15
	return false;
278
}
279
280
/*-
281
 *-----------------------------------------------------------------------
282
 * CondDoExists --
283
 *	See if the given file exists.
284
 *
285
 * Results:
286
 *	true if the file exists and false if it does not.
287
 *-----------------------------------------------------------------------
288
 */
289
static bool
290
CondDoExists(struct Name *arg)
291
1319
{
292
	bool result;
293
	char *path;
294
295
1319
	path = Dir_FindFilei(arg->s, arg->e, defaultPath);
296
1319
	if (path != NULL) {
297
900
		result = true;
298
900
		free(path);
299
	} else {
300
419
		result = false;
301
	}
302
1319
	return result;
303
}
304
305
/*-
306
 *-----------------------------------------------------------------------
307
 * CondDoTarget --
308
 *	See if the given node exists and is an actual target.
309
 *
310
 * Results:
311
 *	true if the node exists as a target and false if it does not.
312
 *-----------------------------------------------------------------------
313
 */
314
static bool
315
CondDoTarget(struct Name *arg)
316
12788
{
317
	GNode *gn;
318
319
12788
	gn = Targ_FindNodei(arg->s, arg->e, TARG_NOCREATE);
320

12788
	if (gn != NULL && !OP_NOP(gn->type))
321
6018
		return true;
322
	else
323
6770
		return false;
324
}
325
326
/*-
327
 *-----------------------------------------------------------------------
328
 * CondDoTargetWithCommands --
329
 *	See if the given node exists and has commands.
330
 *
331
 * Results:
332
 *	true if the node is complete and false if it does not.
333
 *-----------------------------------------------------------------------
334
 */
335
static bool
336
CondDoTargetWithCommands(struct Name *arg)
337
{
338
	GNode *gn;
339
340
	gn = Targ_FindNodei(arg->s, arg->e, TARG_NOCREATE);
341
	if (gn != NULL && !OP_NOP(gn->type) && (gn->type & OP_HAS_COMMANDS))
342
		return true;
343
	else
344
		return false;
345
}
346
347
348
/*-
349
 *-----------------------------------------------------------------------
350
 * CondCvtArg --
351
 *	Convert the given number into a double. If the number begins
352
 *	with 0x, it is interpreted as a hexadecimal integer
353
 *	and converted to a double from there. All other strings just have
354
 *	strtod called on them.
355
 *
356
 * Results:
357
 *	Sets 'value' to double value of string.
358
 *	Returns true if the string was a valid number, false o.w.
359
 *
360
 * Side Effects:
361
 *	Can change 'value' even if string is not a valid number.
362
 *-----------------------------------------------------------------------
363
 */
364
static bool
365
CondCvtArg(const char *str, double *value)
366
9168
{
367

9168
	if (*str == '0' && str[1] == 'x') {
368
		long i;
369
370
		for (str += 2, i = 0; *str; str++) {
371
			int x;
372
			if (ISDIGIT(*str))
373
				x  = *str - '0';
374
			else if (ISXDIGIT(*str))
375
				x = 10 + *str - (ISUPPER(*str) ? 'A' : 'a');
376
			else
377
				return false;
378
			i = (i << 4) + x;
379
		}
380
		*value = (double) i;
381
		return true;
382
	}
383
	else {
384
		char *eptr;
385
9168
		*value = strtod(str, &eptr);
386
9168
		return *eptr == '\0';
387
	}
388
}
389
390
391
static Token
392
CondHandleNumber(bool doEval)
393
679
{
394
	const char *end;
395
	char *lhs;
396
397
679
	end = condExpr;
398

3395
	while (!ISSPACE(*end) && strchr("!=><", *end) == NULL)
399
679
		end++;
400
679
	lhs = Str_dupi(condExpr, end);
401
679
	condExpr = end;
402
679
	return CondHandleComparison(lhs, true, doEval);
403
}
404
405
static Token
406
CondHandleVarSpec(bool doEval)
407
13767
{
408
	char *lhs;
409
	size_t varSpecLen;
410
	bool doFree;
411
412
	/* Parse the variable spec and skip over it, saving its
413
	 * value in lhs.  */
414
13767
	lhs = Var_Parse(condExpr, NULL, doEval,&varSpecLen,&doFree);
415
13767
	if (lhs == var_Error)
416
		/* Even if !doEval, we still report syntax errors, which
417
		 * is what getting var_Error back with !doEval means.  */
418
		return Err;
419
13767
	condExpr += varSpecLen;
420
421

27534
	if (!ISSPACE(*condExpr) &&
422
		strchr("!=><", *condExpr) == NULL) {
423
		BUFFER buf;
424
425
		Buf_Init(&buf, 0);
426
427
		Buf_AddString(&buf, lhs);
428
429
		if (doFree)
430
			free(lhs);
431
432
		for (;*condExpr && !ISSPACE(*condExpr); condExpr++)
433
			Buf_AddChar(&buf, *condExpr);
434
435
		lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval);
436
		Buf_Destroy(&buf);
437
		doFree = true;
438
	}
439
440
13767
	return CondHandleComparison(lhs, doFree, doEval);
441
}
442
443
static Token
444
CondHandleString(bool doEval)
445
{
446
	char *lhs;
447
	const char *begin;
448
	BUFFER buf;
449
450
	/* find the extent of the string */
451
	begin = ++condExpr;
452
	while (*condExpr && *condExpr != '"') {
453
		condExpr++;
454
	}
455
456
	Buf_Init(&buf, 0);
457
	Buf_Addi(&buf, begin, condExpr);
458
	if (*condExpr == '"')
459
		condExpr++;
460
	lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval);
461
	Buf_Destroy(&buf);
462
	return CondHandleComparison(lhs, true, doEval);
463
}
464
465
static Token
466
CondHandleComparison(char *lhs, bool doFree, bool doEval)
467
14446
{
468
	Token t;
469
	const char *rhs;
470
	const char *op;
471
472
14446
	t = Err;
473
	/* Skip whitespace to get to the operator.	*/
474
63454
	while (ISSPACE(*condExpr))
475
10058
		condExpr++;
476
477
	/* Make sure the operator is a valid one. If it isn't a
478
	 * known relational operator, pretend we got a
479
	 * != 0 comparison.  */
480
14446
	op = condExpr;
481
14446
	switch (*condExpr) {
482
	case '!':
483
	case '=':
484
	case '<':
485
	case '>':
486
10056
		if (condExpr[1] == '=')
487
10056
			condExpr += 2;
488
		else
489
			condExpr += 1;
490
		break;
491
	default:
492
4390
		op = "!=";
493
4390
		rhs = "0";
494
495
4390
		goto do_compare;
496
	}
497
40224
	while (ISSPACE(*condExpr))
498
10056
		condExpr++;
499
10056
	if (*condExpr == '\0') {
500
		Parse_Error(PARSE_WARNING,
501
		    "Missing right-hand-side of operator");
502
		goto error;
503
	}
504
10056
	rhs = condExpr;
505
14446
do_compare:
506
14446
	if (*rhs == '"') {
507
		/* Doing a string comparison. Only allow == and != for
508
		 * operators.  */
509
		char *string;
510
		const char *cp;
511
		int qt;
512
		BUFFER buf;
513
514
10442
do_string_compare:
515

10442
		if ((*op != '!' && *op != '=') || op[1] != '=') {
516
			Parse_Error(PARSE_WARNING,
517
			    "String comparison operator should be either == or !=");
518
			goto error;
519
		}
520
521
10442
		Buf_Init(&buf, 0);
522
10442
		qt = *rhs == '"' ? 1 : 0;
523
524


70850
		for (cp = &rhs[qt]; ((qt && *cp != '"') ||
525
		    (!qt && strchr(" \t)", *cp) == NULL)) && *cp != '\0';) {
526
49966
			if (*cp == '$') {
527
				size_t len;
528
529
2
				if (Var_ParseBuffer(&buf, cp, NULL, doEval,
530
				    &len)) {
531
2
					cp += len;
532
2
					continue;
533
				}
534

49964
			} else if (*cp == '\\' && cp[1] != '\0')
535
				/* Backslash escapes things -- skip over next
536
				 * character, if it exists.  */
537
				cp++;
538
49964
			Buf_AddChar(&buf, *cp++);
539
		}
540
541
10442
		string = Buf_Retrieve(&buf);
542
543
10442
		if (DEBUG(COND))
544
			printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
545
			    lhs, string, op);
546
		/* Null-terminate rhs and perform the comparison.
547
		 * t is set to the result.  */
548
10442
		if (*op == '=')
549
9279
			t = strcmp(lhs, string) ? False : True;
550
		else
551
1163
			t = strcmp(lhs, string) ? True : False;
552
10442
		free(string);
553
10442
		if (rhs == condExpr) {
554

10056
			if (!qt && *cp == ')')
555
				condExpr = cp;
556
10056
			else if (*cp == '\0')
557
774
				condExpr = cp;
558
			else
559
9282
				condExpr = cp + 1;
560
		}
561
	} else {
562
		/* rhs is either a float or an integer. Convert both the
563
		 * lhs and the rhs to a double and compare the two.  */
564
		double left, right;
565
		char *string;
566
567
5164
		if (!CondCvtArg(lhs, &left))
568
1160
			goto do_string_compare;
569
4004
		if (*rhs == '$') {
570
			size_t len;
571
			bool freeIt;
572
573
			string = Var_Parse(rhs, NULL, doEval,&len,&freeIt);
574
			if (string == var_Error)
575
				right = 0.0;
576
			else {
577
				if (!CondCvtArg(string, &right)) {
578
					if (freeIt)
579
						free(string);
580
					goto do_string_compare;
581
				}
582
				if (freeIt)
583
					free(string);
584
				if (rhs == condExpr)
585
					condExpr += len;
586
			}
587
		} else {
588
4004
			if (!CondCvtArg(rhs, &right))
589
				goto do_string_compare;
590
4004
			if (rhs == condExpr) {
591
				/* Skip over the right-hand side.  */
592
				while (!ISSPACE(*condExpr) && *condExpr != '\0')
593
					condExpr++;
594
			}
595
		}
596
597
4004
		if (DEBUG(COND))
598
			printf("left = %f, right = %f, op = %.2s\n", left,
599
			    right, op);
600

4004
		switch (op[0]) {
601
		case '!':
602
4004
			if (op[1] != '=') {
603
				Parse_Error(PARSE_WARNING, "Unknown operator");
604
				goto error;
605
			}
606
4004
			t = left != right ? True : False;
607
4004
			break;
608
		case '=':
609
			if (op[1] != '=') {
610
				Parse_Error(PARSE_WARNING, "Unknown operator");
611
				goto error;
612
			}
613
			t = left == right ? True : False;
614
			break;
615
		case '<':
616
			if (op[1] == '=')
617
				t = left <= right ? True : False;
618
			else
619
				t = left < right ? True : False;
620
			break;
621
		case '>':
622
			if (op[1] == '=')
623
				t = left >= right ? True : False;
624
			else
625
				t = left > right ? True : False;
626
			break;
627
		}
628
	}
629
14446
error:
630
14446
	if (doFree)
631
5053
		free(lhs);
632
14446
	return t;
633
}
634
635
#define S(s)	s, sizeof(s)-1
636
static struct operator {
637
	const char *s;
638
	size_t len;
639
	bool (*proc)(struct Name *);
640
} ops[] = {
641
	{S("defined"), CondDoDefined},
642
	{S("make"), CondDoMake},
643
	{S("exists"), CondDoExists},
644
	{S("target"), CondDoTarget},
645
	{S("commands"), CondDoTargetWithCommands},
646
	{NULL, 0, NULL}
647
};
648
649
static Token
650
CondHandleDefault(bool doEval)
651
45137
{
652
	bool t;
653
	bool (*evalProc)(struct Name *);
654
45137
	bool invert = false;
655
	struct Name arg;
656
	size_t arglen;
657
658
45137
	evalProc = NULL;
659
45137
	if (strncmp(condExpr, "empty", 5) == 0) {
660
		/* Use Var_Parse to parse the spec in parens and return
661
		 * True if the resulting string is empty.  */
662
		size_t length;
663
		bool doFree;
664
		char *val;
665
666
6716
		condExpr += 5;
667
668
13432
		for (arglen = 0; condExpr[arglen] != '(' &&
669
		    condExpr[arglen] != '\0';)
670
			arglen++;
671
672
6716
		if (condExpr[arglen] != '\0') {
673
6716
			val = Var_Parse(&condExpr[arglen - 1], NULL,
674
			    doEval, &length, &doFree);
675
6716
			if (val == var_Error)
676
				t = Err;
677
			else {
678
				/* A variable is empty when it just contains
679
				 * spaces... 4/15/92, christos */
680
				char *p;
681
13434
				for (p = val; ISSPACE(*p); p++)
682
					continue;
683
6716
				t = *p == '\0' ? True : False;
684
			}
685
6716
			if (doFree)
686
5186
				free(val);
687
			/* Advance condExpr to beyond the closing ). Note that
688
			 * we subtract one from arglen + length b/c length
689
			 * is calculated from condExpr[arglen - 1].  */
690
6716
			condExpr += arglen + length - 1;
691
6716
			return t;
692
		} else
693
			condExpr -= 5;
694
	} else {
695
		struct operator *op;
696
697
84461
		for (op = ops; op != NULL; op++)
698
84461
			if (strncmp(condExpr, op->s, op->len) == 0) {
699
38421
				condExpr += op->len;
700
38421
				if (CondGetArg(&condExpr, &arg, op->s, true))
701
37688
					evalProc = op->proc;
702
				else
703
733
					condExpr -= op->len;
704
				break;
705
			}
706
	}
707
38421
	if (evalProc == NULL) {
708
		/* The symbol is itself the argument to the default
709
		 * function. We advance condExpr to the end of the symbol
710
		 * by hand (the next whitespace, closing paren or
711
		 * binary operator) and set to invert the evaluation
712
		 * function if condInvert is true.  */
713
733
		invert = condInvert;
714
733
		evalProc = condDefProc;
715
		/* XXX should we ignore problems now ? */
716
733
		CondGetArg(&condExpr, &arg, "", false);
717
	}
718
719
	/* Evaluate the argument using the set function. If invert
720
	 * is true, we invert the sense of the function.  */
721

38421
	t = (!doEval || (*evalProc)(&arg) ?
722
	     (invert ? False : True) :
723
	     (invert ? True : False));
724
38421
	VarName_Free(&arg);
725
38421
	return t;
726
}
727
728
/*-
729
 *-----------------------------------------------------------------------
730
 * CondToken --
731
 *	Return the next token from the input.
732
 *
733
 * Results:
734
 *	A Token for the next lexical token in the stream.
735
 *
736
 * Side Effects:
737
 *	condPushback will be set back to None if it is used.
738
 *-----------------------------------------------------------------------
739
 */
740
static Token
741
CondToken(bool doEval)
742
256192
{
743
744
256192
	if (condPushBack != None) {
745
		Token t;
746
747
106260
		t = condPushBack;
748
106260
		condPushBack = None;
749
106260
		return t;
750
	}
751
752
352710
	while (ISSPACE(*condExpr))
753
26423
		condExpr++;
754


149932
	switch (*condExpr) {
755
	case '(':
756
2036
		condExpr++;
757
2036
		return LParen;
758
	case ')':
759
2036
		condExpr++;
760
2036
		return RParen;
761
	case '|':
762
7288
		if (condExpr[1] == '|')
763
7288
			condExpr++;
764
7288
		condExpr++;
765
7288
		return Or;
766
	case '&':
767
4845
		if (condExpr[1] == '&')
768
4845
			condExpr++;
769
4845
		condExpr++;
770
4845
		return And;
771
	case '!':
772
26694
		condExpr++;
773
26694
		return Not;
774
	case '\n':
775
	case '\0':
776
47450
		return EndOfFile;
777
	case '"':
778
		return CondHandleString(doEval);
779
	case '$':
780
13767
		return CondHandleVarSpec(doEval);
781
	case '0': case '1': case '2': case '3': case '4':
782
	case '5': case '6': case '7': case '8': case '9':
783
679
		return CondHandleNumber(doEval);
784
	default:
785
45137
		return CondHandleDefault(doEval);
786
	}
787
}
788
789
/*-
790
 *-----------------------------------------------------------------------
791
 * CondT --
792
 *	Parse a single term in the expression. This consists of a terminal
793
 *	symbol or Not and a terminal symbol (not including the binary
794
 *	operators):
795
 *	    T -> defined(variable) | make(target) | exists(file) | symbol
796
 *	    T -> ! T | ( E )
797
 *
798
 * Results:
799
 *	True, False or Err.
800
 *
801
 * Side Effects:
802
 *	Tokens are consumed.
803
 *-----------------------------------------------------------------------
804
 */
805
static Token
806
CondT(bool doEval)
807
88313
{
808
	Token t;
809
810
88313
	t = CondToken(doEval);
811
812
88313
	if (t == EndOfFile)
813
		/* If we reached the end of the expression, the expression
814
		 * is malformed...  */
815
		t = Err;
816
88313
	else if (t == LParen) {
817
		/* T -> ( E ).	*/
818
2036
		t = CondE(doEval);
819
2036
		if (t != Err)
820
2036
			if (CondToken(doEval) != RParen)
821
				t = Err;
822
86277
	} else if (t == Not) {
823
26694
		t = CondT(doEval);
824
26694
		if (t == True)
825
12102
			t = False;
826
14592
		else if (t == False)
827
14592
			t = True;
828
	}
829
88313
	return t;
830
}
831
832
/*-
833
 *-----------------------------------------------------------------------
834
 * CondF --
835
 *	Parse a conjunctive factor (nice name, wot?)
836
 *	    F -> T && F | T
837
 *
838
 * Results:
839
 *	True, False or Err
840
 *
841
 * Side Effects:
842
 *	Tokens are consumed.
843
 *-----------------------------------------------------------------------
844
 */
845
static Token
846
CondF(bool doEval)
847
61619
{
848
	Token l, o;
849
850
61619
	l = CondT(doEval);
851
61619
	if (l != Err) {
852
61619
		o = CondToken(doEval);
853
854
61619
		if (o == And) {
855
		    /* F -> T && F
856
		     *
857
		     * If T is False, the whole thing will be False, but we
858
		     * have to parse the r.h.s. anyway (to throw it away).  If
859
		     * T is True, the result is the r.h.s., be it an Err or no.
860
		     * */
861
4845
		    if (l == True)
862
1895
			    l = CondF(doEval);
863
		    else
864
2950
			    (void)CondF(false);
865
		} else
866
			/* F -> T.	*/
867
56774
			condPushBack = o;
868
	}
869
61619
	return l;
870
}
871
872
/*-
873
 *-----------------------------------------------------------------------
874
 * CondE --
875
 *	Main expression production.
876
 *	    E -> F || E | F
877
 *
878
 * Results:
879
 *	True, False or Err.
880
 *
881
 * Side Effects:
882
 *	Tokens are, of course, consumed.
883
 *-----------------------------------------------------------------------
884
 */
885
static Token
886
CondE(bool doEval)
887
56774
{
888
	Token l, o;
889
890
56774
	l = CondF(doEval);
891
56774
	if (l != Err) {
892
56774
		o = CondToken(doEval);
893
894
56774
		if (o == Or) {
895
			/* E -> F || E
896
			 *
897
			 * A similar thing occurs for ||, except that here we
898
			 * make sure the l.h.s. is False before we bother to
899
			 * evaluate the r.h.s.  Once again, if l is False, the
900
			 * result is the r.h.s. and once again if l is True, we
901
			 * parse the r.h.s. to throw it away.  */
902
7288
			if (l == False)
903
6663
				l = CondE(doEval);
904
			else
905
625
				(void)CondE(false);
906
		} else
907
			/* E -> F.	*/
908
49486
			condPushBack = o;
909
	}
910
56774
	return l;
911
}
912
913
/* Evaluate conditional in line.
914
 * returns COND_SKIP, COND_PARSE, COND_INVALID, COND_ISFOR, COND_ISINCLUDE,
915
 * COND_ISUNDEF.
916
 * A conditional line looks like this:
917
 *	<cond-type> <expr>
918
 *	where <cond-type> is any of if, ifmake, ifnmake, ifdef,
919
 *	ifndef, elif, elifmake, elifnmake, elifdef, elifndef
920
 *	and <expr> consists of &&, ||, !, make(target), defined(variable)
921
 *	and parenthetical groupings thereof.
922
 */
923
int
924
Cond_Eval(const char *line)
925
181733
{
926
	/* find end of keyword */
927
	const char *end;
928
	uint32_t k;
929
	size_t len;
930
	struct If *ifp;
931
181733
	bool value = false;
932
	int level;	/* Level at which to report errors. */
933
934
181733
	level = PARSE_FATAL;
935
936
181733
	for (end = line; ISLOWER(*end); end++)
937
		;
938
	/* quick path: recognize special targets early on */
939
181733
	if (*end == '.' || *end == ':')
940
28410
		return COND_INVALID;
941
153323
	len = end - line;
942
153323
	k = ohash_interval(line, &end);
943




153323
	switch(k % MAGICSLOTS2) {
944
	case K_COND_IF % MAGICSLOTS2:
945

107804
		if (k == K_COND_IF && len == strlen(COND_IF) &&
946
		    strncmp(line, COND_IF, len) == 0) {
947
53902
			ifp = ifs + COND_IF_INDEX;
948
		} else
949
			return COND_INVALID;
950
		break;
951
	case K_COND_IFDEF % MAGICSLOTS2:
952

12
		if (k == K_COND_IFDEF && len == strlen(COND_IFDEF) &&
953
		    strncmp(line, COND_IFDEF, len) == 0) {
954
6
			ifp = ifs + COND_IFDEF_INDEX;
955
		} else
956
			return COND_INVALID;
957
		break;
958
	case K_COND_IFNDEF % MAGICSLOTS2:
959

1454
		if (k == K_COND_IFNDEF && len == strlen(COND_IFNDEF) &&
960
		    strncmp(line, COND_IFNDEF, len) == 0) {
961
727
			ifp = ifs + COND_IFNDEF_INDEX;
962
		} else
963
			return COND_INVALID;
964
		break;
965
	case K_COND_IFMAKE % MAGICSLOTS2:
966
		if (k == K_COND_IFMAKE && len == strlen(COND_IFMAKE) &&
967
		    strncmp(line, COND_IFMAKE, len) == 0) {
968
			ifp = ifs + COND_IFMAKE_INDEX;
969
		} else
970
			return COND_INVALID;
971
		break;
972
	case K_COND_IFNMAKE % MAGICSLOTS2:
973
		if (k == K_COND_IFNMAKE && len == strlen(COND_IFNMAKE) &&
974
		    strncmp(line, COND_IFNMAKE, len) == 0) {
975
			ifp = ifs + COND_IFNMAKE_INDEX;
976
		} else
977
			return COND_INVALID;
978
		break;
979
	case K_COND_ELIF % MAGICSLOTS2:
980

1368
		if (k == K_COND_ELIF && len == strlen(COND_ELIF) &&
981
		    strncmp(line, COND_ELIF, len) == 0) {
982
684
			ifp = ifs + COND_ELIF_INDEX;
983
		} else
984
			return COND_INVALID;
985
		break;
986
	case K_COND_ELIFDEF % MAGICSLOTS2:
987
		if (k == K_COND_ELIFDEF && len == strlen(COND_ELIFDEF) &&
988
		    strncmp(line, COND_ELIFDEF, len) == 0) {
989
			ifp = ifs + COND_ELIFDEF_INDEX;
990
		} else
991
			return COND_INVALID;
992
		break;
993
	case K_COND_ELIFNDEF % MAGICSLOTS2:
994
		if (k == K_COND_ELIFNDEF && len == strlen(COND_ELIFNDEF) &&
995
		    strncmp(line, COND_ELIFNDEF, len) == 0) {
996
			ifp = ifs + COND_ELIFNDEF_INDEX;
997
		} else
998
			return COND_INVALID;
999
		break;
1000
	case K_COND_ELIFMAKE % MAGICSLOTS2:
1001
		if (k == K_COND_ELIFMAKE && len == strlen(COND_ELIFMAKE) &&
1002
		    strncmp(line, COND_ELIFMAKE, len) == 0) {
1003
			ifp = ifs + COND_ELIFMAKE_INDEX;
1004
		} else
1005
			return COND_INVALID;
1006
		break;
1007
	case K_COND_ELIFNMAKE % MAGICSLOTS2:
1008
		if (k == K_COND_ELIFNMAKE && len == strlen(COND_ELIFNMAKE) &&
1009
		    strncmp(line, COND_ELIFNMAKE, len) == 0) {
1010
			ifp = ifs + COND_ELIFNMAKE_INDEX;
1011
		} else
1012
			return COND_INVALID;
1013
		break;
1014
	case K_COND_ELSE % MAGICSLOTS2:
1015
		/* valid conditional whose value is the inverse
1016
		 * of the previous if we parsed.  */
1017

13827
		if (k == K_COND_ELSE && len == strlen(COND_ELSE) &&
1018
		    strncmp(line, COND_ELSE, len) == 0) {
1019
13827
			if (condTop == MAXIF) {
1020
				Parse_Error(level, "if-less else");
1021
				return COND_INVALID;
1022
13827
			} else if (skipIfLevel == 0) {
1023
13626
				value = !condStack[condTop].value;
1024
13626
				ifp = ifs + COND_ELSE_INDEX;
1025
			} else
1026
201
				return COND_SKIP;
1027
		} else
1028
			return COND_INVALID;
1029
		break;
1030
	case K_COND_ENDIF % MAGICSLOTS2:
1031

54635
		if (k == K_COND_ENDIF && len == strlen(COND_ENDIF) &&
1032
		    strncmp(line, COND_ENDIF, len) == 0) {
1033
			/* End of a conditional section. If skipIfLevel is
1034
			 * non-zero, that conditional was skipped, so lines
1035
			 * following it should also be skipped. Hence, we
1036
			 * return COND_SKIP. Otherwise, the conditional was
1037
			 * read so succeeding lines should be parsed (think
1038
			 * about it...) so we return COND_PARSE, unless this
1039
			 * endif isn't paired with a decent if.  */
1040
54635
			if (skipIfLevel != 0) {
1041
7864
				skipIfLevel--;
1042
7864
				return COND_SKIP;
1043
			} else {
1044
46771
				if (condTop == MAXIF) {
1045
					Parse_Error(level, "if-less endif");
1046
					return COND_INVALID;
1047
				} else {
1048
46771
					skipLine = false;
1049
46771
					condTop++;
1050
46771
					return COND_PARSE;
1051
				}
1052
			}
1053
		} else
1054
			return COND_INVALID;
1055
		break;
1056
1057
	/* Recognize other keywords there, to simplify parser's task */
1058
	case K_COND_FOR % MAGICSLOTS2:
1059

5117
		if (k == K_COND_FOR && len == strlen(COND_FOR) &&
1060
		    strncmp(line, COND_FOR, len) == 0)
1061
5117
			return COND_ISFOR;
1062
		else
1063
			return COND_INVALID;
1064
	case K_COND_UNDEF % MAGICSLOTS2:
1065
		if (k == K_COND_UNDEF && len == strlen(COND_UNDEF) &&
1066
		    strncmp(line, COND_UNDEF, len) == 0)
1067
			return COND_ISUNDEF;
1068
		else
1069
			return COND_INVALID;
1070
	case K_COND_POISON % MAGICSLOTS2:
1071
		if (k == K_COND_POISON && len == strlen(COND_POISON) &&
1072
		    strncmp(line, COND_POISON, len) == 0)
1073
			return COND_ISPOISON;
1074
		else
1075
			return COND_INVALID;
1076
	case K_COND_INCLUDE % MAGICSLOTS2:
1077

8417
		if (k == K_COND_INCLUDE && len == strlen(COND_INCLUDE) &&
1078
		    strncmp(line, COND_INCLUDE, len) == 0)
1079
8417
			return COND_ISINCLUDE;
1080
		else
1081
			return COND_INVALID;
1082
	default:
1083
		/* Not a valid conditional type. No error...  */
1084
16008
		return COND_INVALID;
1085
	}
1086
1087
68945
	if (ifp->isElse) {
1088
14310
		if (condTop == MAXIF) {
1089
			Parse_Error(level, "if-less elif");
1090
			return COND_INVALID;
1091

14310
		} else if (skipIfLevel != 0 || condStack[condTop].value) {
1092
			/*
1093
			 * Skip if we're meant to or is an else-type
1094
			 * conditional and previous corresponding one was
1095
			 * evaluated to true.
1096
			 */
1097
5623
			skipLine = true;
1098
5623
			return COND_SKIP;
1099
		}
1100
54635
	} else if (skipLine) {
1101
		/* Don't even try to evaluate a conditional that's not an else
1102
		 * if we're skipping things...  */
1103
7864
		skipIfLevel++;
1104
7864
		return COND_SKIP;
1105
	} else
1106
46771
		condTop--;
1107
1108
55458
	if (condTop < 0) {
1109
		/* This is the one case where we can definitely proclaim a fatal
1110
		 * error. If we don't, we're hosed.  */
1111
		Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.",
1112
		    MAXIF);
1113
		condTop = 0;
1114
		return COND_INVALID;
1115
	}
1116
1117
55458
	if (ifp->defProc) {
1118
		/* Initialize file-global variables for parsing.  */
1119
47450
		condDefProc = ifp->defProc;
1120
47450
		condInvert = ifp->doNot;
1121
1122
47450
		line += len;
1123
1124
142350
		while (*line == ' ' || *line == '\t')
1125
47450
			line++;
1126
1127
47450
		condExpr = line;
1128
47450
		condPushBack = None;
1129
1130

47450
		switch (CondE(true)) {
1131
		case True:
1132
19420
			if (CondToken(true) == EndOfFile) {
1133
19420
				value = true;
1134
19420
				break;
1135
			}
1136
			goto err;
1137
			/* FALLTHROUGH */
1138
		case False:
1139
28030
			if (CondToken(true) == EndOfFile) {
1140
28030
				value = false;
1141
28030
				break;
1142
			}
1143
			/* FALLTHROUGH */
1144
		case Err:
1145
err:
1146
			Parse_Error(level, "Malformed conditional (%s)", line);
1147
			return COND_INVALID;
1148
		default:
1149
			break;
1150
		}
1151
	}
1152
1153
55458
	condStack[condTop].value = value;
1154
55458
	Parse_FillLocation(&condStack[condTop].origin);
1155
55458
	skipLine = !value;
1156
55458
	return value ? COND_PARSE : COND_SKIP;
1157
}
1158
1159
void
1160
Cond_End(void)
1161
1458
{
1162
	int i;
1163
1164
1458
	if (condTop != MAXIF) {
1165
		Parse_Error(PARSE_FATAL, "%s%d open conditional%s",
1166
		    condTop == 0 ? "at least ": "", MAXIF-condTop,
1167
		    MAXIF-condTop == 1 ? "" : "s");
1168
		for (i = MAXIF-1; i >= condTop; i--) {
1169
			fprintf(stderr, "\t(%s:%lu)\n",
1170
			    condStack[i].origin.fname,
1171
			    condStack[i].origin.lineno);
1172
		}
1173
	}
1174
1458
	condTop = MAXIF;
1175
1458
}