GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/make/cond.c Lines: 297 420 70.7 %
Date: 2017-11-07 Branches: 218 377 57.8 %

Line Branch Exec Source
1
/*	$OpenBSD: cond.c,v 1.52 2017/06/21 00:11:36 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
{
173
110906854
	for (;;p++) {
174
		/* XXX: when *p == '\0', strchr() returns !NULL */
175
103028823
		if (strchr(" \t)&|$", *p) != NULL)
176
7878031
			return p;
177
	}
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
{
198
	const char *cp;
199
200
7652914
	cp = *linePtr;
201
	/* Set things up to return faster in case of problem */
202
7652914
	arg->s = cp;
203
7652914
	arg->e = cp;
204
7652914
	arg->tofree = false;
205
206
	/* make and defined are not really keywords, so if CondGetArg doesn't
207
	 * work...
208
	 */
209
7652914
	if (parens) {
210
7585956
		while (ISSPACE(*cp))
211
5023
			cp++;
212
7575910
		if (*cp == '(')
213
7498906
			cp++;
214
		else
215
77004
			return false;
216
7498906
	}
217
218
7575910
	if (*cp == '\0')
219
		return false;
220
221
7575910
	while (ISSPACE(*cp))
222
		cp++;
223
224
7575910
	cp = VarName_Get(cp, arg, NULL, true, find_cond);
225
226
15154154
	while (ISSPACE(*cp))
227
1167
		cp++;
228
7575910
	if (parens) {
229
7498906
		if (*cp == ')')
230
7498906
			cp++;
231
		else {
232
			Parse_Error(PARSE_WARNING,
233
			    "Missing closing parenthesis for %s()", func);
234
			return false;
235
	    	}
236
7498906
	}
237
238
7575910
	*linePtr = cp;
239
7575910
	return true;
240
7652914
}
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
{
254
13399436
	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
{
269
	LstNode ln;
270
271
187120
	for (ln = Lst_First(create); ln != NULL; ln = Lst_Adv(ln)) {
272
37971
		char *s = Lst_Datum(ln);
273
37971
		if (Str_Matchi(s, strchr(s, '\0'), arg->s, arg->e))
274
1420
			return true;
275
36551
	}
276
277
36586
	return false;
278
38006
}
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
{
292
	bool result;
293
	char *path;
294
295
216656
	if (arg->s == arg->e)
296
		Parse_Error(PARSE_FATAL, "Empty file name in .if exists()");
297
298
108328
	path = Dir_FindFilei(arg->s, arg->e, defaultPath);
299
108328
	if (path != NULL) {
300
		result = true;
301
84978
		free(path);
302
84978
	} else {
303
		result = false;
304
	}
305
108328
	return result;
306
}
307
308
/*-
309
 *-----------------------------------------------------------------------
310
 * CondDoTarget --
311
 *	See if the given node exists and is an actual target.
312
 *
313
 * Results:
314
 *	true if the node exists as a target and false if it does not.
315
 *-----------------------------------------------------------------------
316
 */
317
static bool
318
CondDoTarget(struct Name *arg)
319
{
320
	GNode *gn;
321
322
1182862
	gn = Targ_FindNodei(arg->s, arg->e, TARG_NOCREATE);
323

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

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

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

11797201
	if (!ISSPACE(*condExpr) &&
425
5453226
		strchr("!=><", *condExpr) == NULL) {
426
		BUFFER buf;
427
428
		Buf_Init(&buf, 0);
429
430
		Buf_AddString(&buf, lhs);
431
432
		if (doFree)
433
			free(lhs);
434
435
		for (;*condExpr && !ISSPACE(*condExpr); condExpr++)
436
			Buf_AddChar(&buf, *condExpr);
437
438
		lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval);
439
		Buf_Destroy(&buf);
440
		doFree = true;
441
	}
442
443
6343975
	return CondHandleComparison(lhs, doFree, doEval);
444
6343975
}
445
446
static Token
447
CondHandleString(bool doEval)
448
{
449
	char *lhs;
450
	const char *begin;
451
68
	BUFFER buf;
452
453
	/* find the extent of the string */
454
68
	begin = ++condExpr;
455

2673
	while (*condExpr && *condExpr != '"') {
456
823
		condExpr++;
457
	}
458
459
68
	Buf_Init(&buf, 0);
460
68
	Buf_Addi(&buf, begin, condExpr);
461
68
	if (*condExpr == '"')
462
68
		condExpr++;
463
68
	lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval);
464
68
	Buf_Destroy(&buf);
465
136
	return CondHandleComparison(lhs, true, doEval);
466
68
}
467
468
static Token
469
CondHandleComparison(char *lhs, bool doFree, bool doEval)
470
{
471
	Token t;
472
	const char *rhs;
473
	const char *op;
474
475
	t = Err;
476
	/* Skip whitespace to get to the operator.	*/
477
14606808
	while (ISSPACE(*condExpr))
478
890817
		condExpr++;
479
480
	/* Make sure the operator is a valid one. If it isn't a
481
	 * known relational operator, pretend we got a
482
	 * != 0 comparison.  */
483
	op = condExpr;
484

6412587
	switch (*condExpr) {
485
	case '!':
486
	case '=':
487
	case '<':
488
	case '>':
489
890763
		if (condExpr[1] == '=')
490
			condExpr += 2;
491
		else
492
			condExpr += 1;
493
		break;
494
	default:
495
		op = "!=";
496
		rhs = "0";
497
498
5521824
		goto do_compare;
499
	}
500
3563002
	while (ISSPACE(*condExpr))
501
890738
		condExpr++;
502
890763
	if (*condExpr == '\0') {
503
		Parse_Error(PARSE_WARNING,
504
		    "Missing right-hand-side of operator");
505
		goto error;
506
	}
507
890763
	rhs = condExpr;
508
do_compare:
509
6412587
	if (*rhs == '"') {
510
		/* Doing a string comparison. Only allow == and != for
511
		 * operators.  */
512
		char *string;
513
		const char *cp;
514
		int qt;
515
		BUFFER buf;
516
517
do_string_compare:
518

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

32093628
		for (cp = &rhs[qt]; ((qt && *cp != '"') ||
528

8807090
		    (!qt && strchr(" \t)", *cp) == NULL)) && *cp != '\0';) {
529
7384389
			if (*cp == '$') {
530
2027
				size_t len;
531
532
2027
				if (Var_ParseBuffer(&buf, cp, NULL, doEval,
533
				    &len)) {
534
2027
					cp += len;
535
2027
					continue;
536
				}
537

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

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

10922868
		switch (op[0]) {
604
		case '!':
605
5461434
			if (op[1] != '=') {
606
				Parse_Error(PARSE_WARNING, "Unknown operator");
607
				goto error;
608
			}
609
5461434
			t = left != right ? True : False;
610
5461434
			break;
611
		case '=':
612
			if (op[1] != '=') {
613
				Parse_Error(PARSE_WARNING, "Unknown operator");
614
				goto error;
615
			}
616
			t = left == right ? True : False;
617
			break;
618
		case '<':
619
			if (op[1] == '=')
620
				t = left <= right ? True : False;
621
			else
622
				t = left < right ? True : False;
623
			break;
624
		case '>':
625
			if (op[1] == '=')
626
				t = left >= right ? True : False;
627
			else
628
				t = left > right ? True : False;
629
			break;
630
		}
631

16741860
	}
632
error:
633
6412587
	if (doFree)
634
5556671
		free(lhs);
635
6412587
	return t;
636
6412587
}
637
638
#define S(s)	s, sizeof(s)-1
639
static struct operator {
640
	const char *s;
641
	size_t len;
642
	bool (*proc)(struct Name *);
643
} ops[] = {
644
	{S("defined"), CondDoDefined},
645
	{S("make"), CondDoMake},
646
	{S("exists"), CondDoExists},
647
	{S("target"), CondDoTarget},
648
	{S("commands"), CondDoTargetWithCommands},
649
	{NULL, 0, NULL}
650
};
651
652
static Token
653
CondHandleDefault(bool doEval)
654
{
655
	bool t;
656
	bool (*evalProc)(struct Name *);
657
	bool invert = false;
658
9426427
	struct Name arg;
659
	size_t arglen;
660
661
	evalProc = NULL;
662
9426427
	if (strncmp(condExpr, "empty", 5) == 0) {
663
		/* Use Var_Parse to parse the spec in parens and return
664
		 * True if the resulting string is empty.  */
665
1850517
		size_t length;
666
1850517
		bool doFree;
667
		char *val;
668
669
1850517
		condExpr += 5;
670
671

3816102
		for (arglen = 0; condExpr[arglen] != '(' &&
672
38356
		    condExpr[arglen] != '\0';)
673
38356
			arglen++;
674
675
1850517
		if (condExpr[arglen] != '\0') {
676
1850517
			val = Var_Parse(&condExpr[arglen - 1], NULL,
677
			    doEval, &length, &doFree);
678
1850517
			if (val == var_Error)
679
3344
				t = Err;
680
			else {
681
				/* A variable is empty when it just contains
682
				 * spaces... 4/15/92, christos */
683
				char *p;
684
3843278
				for (p = val; ISSPACE(*p); p++)
685
					continue;
686
1847173
				t = *p == '\0' ? True : False;
687
			}
688
1850517
			if (doFree)
689
1692837
				free(val);
690
			/* Advance condExpr to beyond the closing ). Note that
691
			 * we subtract one from arglen + length b/c length
692
			 * is calculated from condExpr[arglen - 1].  */
693
1850517
			condExpr += arglen + length - 1;
694
1850517
			return t;
695
		} else
696
			condExpr -= 5;
697
1850517
	} else {
698
		struct operator *op;
699
700
20256390
		for (op = ops; op != NULL; op++)
701
10128195
			if (strncmp(condExpr, op->s, op->len) == 0) {
702
7575910
				condExpr += op->len;
703
7575910
				if (CondGetArg(&condExpr, &arg, op->s, true))
704
7498906
					evalProc = op->proc;
705
				else
706
77004
					condExpr -= op->len;
707
				break;
708
			}
709
	}
710
7575910
	if (evalProc == NULL) {
711
		/* The symbol is itself the argument to the default
712
		 * function. We advance condExpr to the end of the symbol
713
		 * by hand (the next whitespace, closing paren or
714
		 * binary operator) and set to invert the evaluation
715
		 * function if condInvert is true.  */
716
77004
		invert = condInvert;
717
77004
		evalProc = condDefProc;
718
		/* XXX should we ignore problems now ? */
719
77004
		CondGetArg(&condExpr, &arg, "", false);
720
77004
	}
721
722
	/* Evaluate the argument using the set function. If invert
723
	 * is true, we invert the sense of the function.  */
724

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





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

89498886
	if (*end == '.' || *end == ':')
943
1171928
		return COND_INVALID;
944
43975303
	len = end - line;
945
43975303
	k = ohash_interval(line, &end);
946




43975303
	switch(k % MAGICSLOTS2) {
947
	case K_COND_IF % MAGICSLOTS2:
948

29707490
		if (k == K_COND_IF && len == strlen(COND_IF) &&
949
14853745
		    strncmp(line, COND_IF, len) == 0) {
950
			ifp = ifs + COND_IF_INDEX;
951
		} else
952
			return COND_INVALID;
953
14853745
		break;
954
	case K_COND_IFDEF % MAGICSLOTS2:
955

12990
		if (k == K_COND_IFDEF && len == strlen(COND_IFDEF) &&
956
6495
		    strncmp(line, COND_IFDEF, len) == 0) {
957
			ifp = ifs + COND_IFDEF_INDEX;
958
		} else
959
			return COND_INVALID;
960
6495
		break;
961
	case K_COND_IFNDEF % MAGICSLOTS2:
962

169811
		if (k == K_COND_IFNDEF && len == strlen(COND_IFNDEF) &&
963
68953
		    strncmp(line, COND_IFNDEF, len) == 0) {
964
			ifp = ifs + COND_IFNDEF_INDEX;
965
		} else
966
31905
			return COND_INVALID;
967
68953
		break;
968
	case K_COND_IFMAKE % MAGICSLOTS2:
969

778
		if (k == K_COND_IFMAKE && len == strlen(COND_IFMAKE) &&
970
389
		    strncmp(line, COND_IFMAKE, len) == 0) {
971
			ifp = ifs + COND_IFMAKE_INDEX;
972
		} else
973
			return COND_INVALID;
974
389
		break;
975
	case K_COND_IFNMAKE % MAGICSLOTS2:
976
		if (k == K_COND_IFNMAKE && len == strlen(COND_IFNMAKE) &&
977
		    strncmp(line, COND_IFNMAKE, len) == 0) {
978
			ifp = ifs + COND_IFNMAKE_INDEX;
979
		} else
980
			return COND_INVALID;
981
		break;
982
	case K_COND_ELIF % MAGICSLOTS2:
983

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

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

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

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

1105964
		if (k == K_COND_INCLUDE && len == strlen(COND_INCLUDE) &&
1081
552982
		    strncmp(line, COND_INCLUDE, len) == 0)
1082
552982
			return COND_ISINCLUDE;
1083
		else
1084
			return COND_INVALID;
1085
	default:
1086
		/* Not a valid conditional type. No error...  */
1087
1011930
		return COND_INVALID;
1088
	}
1089
1090
26757461
	if (ifp->isElse) {
1091
11827879
		if (condTop == MAXIF) {
1092
			Parse_Error(level, "if-less elif");
1093
			return COND_INVALID;
1094

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

100730177
		while (*line == ' ' || *line == '\t')
1128
14390040
			line++;
1129
1130
28780020
		condExpr = line;
1131
28780020
		condPushBack = None;
1132
1133

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