GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
59968191 |
for (;;p++) { |
|
174 |
/* XXX: when *p == '\0', strchr() returns !NULL */ |
||
175 |
✓✓ | 55768179 |
if (strchr(" \t)&|$", *p) != NULL) |
176 |
4200012 |
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 |
4086181 |
cp = *linePtr; |
|
201 |
/* Set things up to return faster in case of problem */ |
||
202 |
4086181 |
arg->s = cp; |
|
203 |
4086181 |
arg->e = cp; |
|
204 |
4086181 |
arg->tofree = false; |
|
205 |
|||
206 |
/* make and defined are not really keywords, so if CondGetArg doesn't |
||
207 |
* work... |
||
208 |
*/ |
||
209 |
✓✓ | 4086181 |
if (parens) { |
210 |
✓✓ | 8101244 |
while (ISSPACE(*cp)) |
211 |
2942 |
cp++; |
|
212 |
✓✓ | 4047680 |
if (*cp == '(') |
213 |
4009179 |
cp++; |
|
214 |
else |
||
215 |
38501 |
return false; |
|
216 |
4009179 |
} |
|
217 |
|||
218 |
✗✓ | 4047680 |
if (*cp == '\0') |
219 |
return false; |
||
220 |
|||
221 |
✗✓ | 8095360 |
while (ISSPACE(*cp)) |
222 |
cp++; |
||
223 |
|||
224 |
4047680 |
cp = VarName_Get(cp, arg, NULL, true, find_cond); |
|
225 |
|||
226 |
✓✓ | 8096848 |
while (ISSPACE(*cp)) |
227 |
744 |
cp++; |
|
228 |
✓✓ | 4047680 |
if (parens) { |
229 |
✓✗ | 4009179 |
if (*cp == ')') |
230 |
4009179 |
cp++; |
|
231 |
else { |
||
232 |
Parse_Error(PARSE_WARNING, |
||
233 |
"Missing closing parenthesis for %s()", func); |
||
234 |
return false; |
||
235 |
} |
||
236 |
4009179 |
} |
|
237 |
|||
238 |
4047680 |
*linePtr = cp; |
|
239 |
4047680 |
return true; |
|
240 |
4086181 |
} |
|
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 |
7244716 |
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 |
✓✓ | 90716 |
for (ln = Lst_First(create); ln != NULL; ln = Lst_Adv(ln)) { |
272 |
18403 |
char *s = Lst_Datum(ln); |
|
273 |
✓✓ | 18403 |
if (Str_Matchi(s, strchr(s, '\0'), arg->s, arg->e)) |
274 |
663 |
return true; |
|
275 |
✓✓ | 17740 |
} |
276 |
|||
277 |
17749 |
return false; |
|
278 |
18412 |
} |
|
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 |
✗✓ | 105212 |
if (arg->s == arg->e) |
296 |
Parse_Error(PARSE_FATAL, "Empty file name in .if exists()"); |
||
297 |
|||
298 |
52606 |
path = Dir_FindFilei(arg->s, arg->e, defaultPath); |
|
299 |
✓✓ | 52606 |
if (path != NULL) { |
300 |
result = true; |
||
301 |
41479 |
free(path); |
|
302 |
41479 |
} else { |
|
303 |
result = false; |
||
304 |
} |
||
305 |
52606 |
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 |
570972 |
gn = Targ_FindNodei(arg->s, arg->e, TARG_NOCREATE); |
|
323 |
✓✓✓✓ |
508975 |
if (gn != NULL && !OP_NOP(gn->type)) |
324 |
155128 |
return true; |
|
325 |
else |
||
326 |
130358 |
return false; |
|
327 |
285486 |
} |
|
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 |
✓✓✗✓ |
15184421 |
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 |
6072302 |
char *eptr; |
|
388 |
6072302 |
*value = strtod(str, &eptr); |
|
389 |
6072302 |
return *eptr == '\0'; |
|
390 |
6072302 |
} |
|
391 |
6072302 |
} |
|
392 |
|||
393 |
|||
394 |
static Token |
||
395 |
CondHandleNumber(bool doEval) |
||
396 |
{ |
||
397 |
const char *end; |
||
398 |
char *lhs; |
||
399 |
|||
400 |
33739 |
end = condExpr; |
|
401 |
✓✗✓✓ |
202434 |
while (!ISSPACE(*end) && strchr("!=><", *end) == NULL) |
402 |
33739 |
end++; |
|
403 |
33739 |
lhs = Str_dupi(condExpr, end); |
|
404 |
33739 |
condExpr = end; |
|
405 |
33739 |
return CondHandleComparison(lhs, true, doEval); |
|
406 |
} |
||
407 |
|||
408 |
static Token |
||
409 |
CondHandleVarSpec(bool doEval) |
||
410 |
{ |
||
411 |
char *lhs; |
||
412 |
3384890 |
size_t varSpecLen; |
|
413 |
3384890 |
bool doFree; |
|
414 |
|||
415 |
/* Parse the variable spec and skip over it, saving its |
||
416 |
* value in lhs. */ |
||
417 |
3384890 |
lhs = Var_Parse(condExpr, NULL, doEval,&varSpecLen,&doFree); |
|
418 |
✗✓ | 3384890 |
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 |
3384890 |
condExpr += varSpecLen; |
|
423 |
|||
424 |
✓✓✗✓ |
6387081 |
if (!ISSPACE(*condExpr) && |
425 |
3002191 |
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 |
3384890 |
return CondHandleComparison(lhs, doFree, doEval); |
|
444 |
3384890 |
} |
|
445 |
|||
446 |
static Token |
||
447 |
CondHandleString(bool doEval) |
||
448 |
{ |
||
449 |
char *lhs; |
||
450 |
const char *begin; |
||
451 |
36 |
BUFFER buf; |
|
452 |
|||
453 |
/* find the extent of the string */ |
||
454 |
36 |
begin = ++condExpr; |
|
455 |
✓✗✓✓ |
1404 |
while (*condExpr && *condExpr != '"') { |
456 |
432 |
condExpr++; |
|
457 |
} |
||
458 |
|||
459 |
36 |
Buf_Init(&buf, 0); |
|
460 |
36 |
Buf_Addi(&buf, begin, condExpr); |
|
461 |
✓✗ | 36 |
if (*condExpr == '"') |
462 |
36 |
condExpr++; |
|
463 |
36 |
lhs = Var_Subst(Buf_Retrieve(&buf), NULL, doEval); |
|
464 |
36 |
Buf_Destroy(&buf); |
|
465 |
72 |
return CondHandleComparison(lhs, true, doEval); |
|
466 |
36 |
} |
|
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 |
✓✓ | 7602800 |
while (ISSPACE(*condExpr)) |
478 |
382735 |
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 |
✗✗✗✓ ✓ |
3418665 |
switch (*condExpr) { |
485 |
case '!': |
||
486 |
case '=': |
||
487 |
case '<': |
||
488 |
case '>': |
||
489 |
382715 |
if (condExpr[1] == '=') |
|
490 |
condExpr += 2; |
||
491 |
else |
||
492 |
condExpr += 1; |
||
493 |
break; |
||
494 |
default: |
||
495 |
op = "!="; |
||
496 |
rhs = "0"; |
||
497 |
|||
498 |
3035950 |
goto do_compare; |
|
499 |
} |
||
500 |
✓✓ | 1530836 |
while (ISSPACE(*condExpr)) |
501 |
382703 |
condExpr++; |
|
502 |
✗✓ | 382715 |
if (*condExpr == '\0') { |
503 |
Parse_Error(PARSE_WARNING, |
||
504 |
"Missing right-hand-side of operator"); |
||
505 |
goto error; |
||
506 |
} |
||
507 |
382715 |
rhs = condExpr; |
|
508 |
do_compare: |
||
509 |
✓✓ | 3418665 |
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 |
✓✓✓✗ ✗✓ |
1179179 |
if ((*op != '!' && *op != '=') || op[1] != '=') { |
519 |
Parse_Error(PARSE_WARNING, |
||
520 |
"String comparison operator should be either == or !="); |
||
521 |
goto error; |
||
522 |
} |
||
523 |
|||
524 |
413234 |
Buf_Init(&buf, 0); |
|
525 |
413234 |
qt = *rhs == '"' ? 1 : 0; |
|
526 |
|||
527 |
✓✓✓✓ ✓✗ |
8767223 |
for (cp = &rhs[qt]; ((qt && *cp != '"') || |
528 |
✓✓✓✓ |
2575846 |
(!qt && strchr(" \t)", *cp) == NULL)) && *cp != '\0';) { |
529 |
✓✓ | 1920126 |
if (*cp == '$') { |
530 |
1182 |
size_t len; |
|
531 |
|||
532 |
✓✗ | 1182 |
if (Var_ParseBuffer(&buf, cp, NULL, doEval, |
533 |
&len)) { |
||
534 |
1182 |
cp += len; |
|
535 |
1182 |
continue; |
|
536 |
} |
||
537 |
✓✗✗✓ ✗✗ |
1920126 |
} else if (*cp == '\\' && cp[1] != '\0') |
538 |
/* Backslash escapes things -- skip over next |
||
539 |
* character, if it exists. */ |
||
540 |
cp++; |
||
541 |
✗✓ | 3837888 |
Buf_AddChar(&buf, *cp++); |
542 |
} |
||
543 |
|||
544 |
413234 |
string = Buf_Retrieve(&buf); |
|
545 |
|||
546 |
✗✓ | 413234 |
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 |
✓✓ | 826468 |
if (*op == '=') |
552 |
765945 |
t = strcmp(lhs, string) ? False : True; |
|
553 |
else |
||
554 |
60523 |
t = strcmp(lhs, string) ? True : False; |
|
555 |
413234 |
free(string); |
|
556 |
✓✓ | 413234 |
if (rhs == condExpr) { |
557 |
✓✓✓✓ |
413312 |
if (!qt && *cp == ')') |
558 |
566 |
condExpr = cp; |
|
559 |
764298 |
else if (*cp == '\0') |
|
560 |
condExpr = cp; |
||
561 |
else |
||
562 |
382149 |
condExpr = cp + 1; |
|
563 |
382715 |
} |
|
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 |
3066547 |
double left, right; |
|
568 |
char *string; |
||
569 |
|||
570 |
✓✓ | 3066547 |
if (!CondCvtArg(lhs, &left)) |
571 |
60792 |
goto do_string_compare; |
|
572 |
✗✓ | 3005755 |
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 |
✓✓ | 3005755 |
if (!CondCvtArg(rhs, &right)) |
592 |
324 |
goto do_string_compare; |
|
593 |
✗✓ | 3005431 |
if (rhs == condExpr) { |
594 |
/* Skip over the right-hand side. */ |
||
595 |
while (!ISSPACE(*condExpr) && *condExpr != '\0') |
||
596 |
condExpr++; |
||
597 |
} |
||
598 |
} |
||
599 |
|||
600 |
✗✓ | 3005431 |
if (DEBUG(COND)) |
601 |
printf("left = %f, right = %f, op = %.2s\n", left, |
||
602 |
right, op); |
||
603 |
✓✗✗✗ ✓ |
6010862 |
switch (op[0]) { |
604 |
case '!': |
||
605 |
✗✓ | 3005431 |
if (op[1] != '=') { |
606 |
Parse_Error(PARSE_WARNING, "Unknown operator"); |
||
607 |
goto error; |
||
608 |
} |
||
609 |
3005431 |
t = left != right ? True : False; |
|
610 |
3005431 |
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 |
✓✗✓✓ |
9199641 |
} |
632 |
error: |
||
633 |
✓✓ | 3418665 |
if (doFree) |
634 |
3053120 |
free(lhs); |
|
635 |
3418665 |
return t; |
|
636 |
3418665 |
} |
|
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 |
5028032 |
struct Name arg; |
|
659 |
size_t arglen; |
||
660 |
|||
661 |
evalProc = NULL; |
||
662 |
✓✓ | 5028032 |
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 |
980352 |
size_t length; |
|
666 |
980352 |
bool doFree; |
|
667 |
char *val; |
||
668 |
|||
669 |
980352 |
condExpr += 5; |
|
670 |
|||
671 |
✓✓✓✗ |
2026428 |
for (arglen = 0; condExpr[arglen] != '(' && |
672 |
21908 |
condExpr[arglen] != '\0';) |
|
673 |
21908 |
arglen++; |
|
674 |
|||
675 |
✓✗ | 980352 |
if (condExpr[arglen] != '\0') { |
676 |
980352 |
val = Var_Parse(&condExpr[arglen - 1], NULL, |
|
677 |
doEval, &length, &doFree); |
||
678 |
✓✓ | 980352 |
if (val == var_Error) |
679 |
1888 |
t = Err; |
|
680 |
else { |
||
681 |
/* A variable is empty when it just contains |
||
682 |
* spaces... 4/15/92, christos */ |
||
683 |
char *p; |
||
684 |
✓✓ | 2036444 |
for (p = val; ISSPACE(*p); p++) |
685 |
continue; |
||
686 |
978464 |
t = *p == '\0' ? True : False; |
|
687 |
} |
||
688 |
✓✓ | 980352 |
if (doFree) |
689 |
896820 |
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 |
980352 |
condExpr += arglen + length - 1; |
|
694 |
980352 |
return t; |
|
695 |
} else |
||
696 |
condExpr -= 5; |
||
697 |
✗✓ | 980352 |
} else { |
698 |
struct operator *op; |
||
699 |
|||
700 |
✓✗ | 10576070 |
for (op = ops; op != NULL; op++) |
701 |
✓✓ | 5288035 |
if (strncmp(condExpr, op->s, op->len) == 0) { |
702 |
4047680 |
condExpr += op->len; |
|
703 |
✓✓ | 4047680 |
if (CondGetArg(&condExpr, &arg, op->s, true)) |
704 |
4009179 |
evalProc = op->proc; |
|
705 |
else |
||
706 |
38501 |
condExpr -= op->len; |
|
707 |
break; |
||
708 |
} |
||
709 |
} |
||
710 |
✓✓ | 4047680 |
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 |
38501 |
invert = condInvert; |
|
717 |
38501 |
evalProc = condDefProc; |
|
718 |
/* XXX should we ignore problems now ? */ |
||
719 |
38501 |
CondGetArg(&condExpr, &arg, "", false); |
|
720 |
38501 |
} |
|
721 |
|||
722 |
/* Evaluate the argument using the set function. If invert |
||
723 |
* is true, we invert the sense of the function. */ |
||
724 |
✓✓✓✓ |
16121902 |
t = (!doEval || (*evalProc)(&arg) ? |
725 |
393223 |
(invert ? False : True) : |
|
726 |
3654457 |
(invert ? True : False)); |
|
727 |
4047680 |
VarName_Free(&arg); |
|
728 |
4047680 |
return t; |
|
729 |
5028032 |
} |
|
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 |
✓✓ | 36787044 |
if (condPushBack != None) { |
748 |
Token t; |
||
749 |
|||
750 |
t = condPushBack; |
||
751 |
15922885 |
condPushBack = None; |
|
752 |
return t; |
||
753 |
} |
||
754 |
|||
755 |
✓✓ | 44839484 |
while (ISSPACE(*condExpr)) |
756 |
1555583 |
condExpr++; |
|
757 |
✓✓✓✓ ✓✗✓✓ ✓✗✗✗ ✗✗✗✗ ✗✗✓✓ |
20864159 |
switch (*condExpr) { |
758 |
case '(': |
||
759 |
90666 |
condExpr++; |
|
760 |
90666 |
return LParen; |
|
761 |
case ')': |
||
762 |
90666 |
condExpr++; |
|
763 |
90666 |
return RParen; |
|
764 |
case '|': |
||
765 |
✓✗ | 276109 |
if (condExpr[1] == '|') |
766 |
276109 |
condExpr++; |
|
767 |
276109 |
condExpr++; |
|
768 |
276109 |
return Or; |
|
769 |
case '&': |
||
770 |
✓✗ | 437866 |
if (condExpr[1] == '&') |
771 |
437866 |
condExpr++; |
|
772 |
437866 |
condExpr++; |
|
773 |
437866 |
return And; |
|
774 |
case '!': |
||
775 |
3789433 |
condExpr++; |
|
776 |
3789433 |
return Not; |
|
777 |
case '\n': |
||
778 |
case '\0': |
||
779 |
7732722 |
return EndOfFile; |
|
780 |
case '"': |
||
781 |
36 |
return CondHandleString(doEval); |
|
782 |
case '$': |
||
783 |
3384890 |
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 |
33739 |
return CondHandleNumber(doEval); |
|
787 |
default: |
||
788 |
5028032 |
return CondHandleDefault(doEval); |
|
789 |
} |
||
790 |
36787044 |
} |
|
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 |
12326796 |
t = CondToken(doEval); |
|
814 |
|||
815 |
✗✓ | 12326796 |
if (t == EndOfFile) |
816 |
/* If we reached the end of the expression, the expression |
||
817 |
* is malformed... */ |
||
818 |
t = Err; |
||
819 |
✓✓ | 12326796 |
else if (t == LParen) { |
820 |
/* T -> ( E ). */ |
||
821 |
90666 |
t = CondE(doEval); |
|
822 |
✓✗ | 90666 |
if (t != Err) |
823 |
✗✓ | 90666 |
if (CondToken(doEval) != RParen) |
824 |
t = Err; |
||
825 |
✓✓ | 12236130 |
} else if (t == Not) { |
826 |
3789433 |
t = CondT(doEval); |
|
827 |
✓✓ | 3789433 |
if (t == True) |
828 |
462206 |
t = False; |
|
829 |
✓✗ | 3327227 |
else if (t == False) |
830 |
3327227 |
t = True; |
|
831 |
} |
||
832 |
12326796 |
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 |
8537363 |
l = CondT(doEval); |
|
854 |
✓✗ | 8537363 |
if (l != Err) { |
855 |
8537363 |
o = CondToken(doEval); |
|
856 |
|||
857 |
✓✓ | 8537363 |
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 |
✓✓ | 437866 |
if (l == True) |
865 |
242087 |
l = CondF(doEval); |
|
866 |
else |
||
867 |
195779 |
(void)CondF(false); |
|
868 |
} else |
||
869 |
/* F -> T. */ |
||
870 |
8099497 |
condPushBack = o; |
|
871 |
} |
||
872 |
8537363 |
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 |
8099497 |
l = CondF(doEval); |
|
894 |
✓✗ | 8099497 |
if (l != Err) { |
895 |
8099497 |
o = CondToken(doEval); |
|
896 |
|||
897 |
✓✓ | 8099497 |
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 |
✓✓ | 276109 |
if (l == False) |
906 |
220522 |
l = CondE(doEval); |
|
907 |
else |
||
908 |
55587 |
(void)CondE(false); |
|
909 |
} else |
||
910 |
/* E -> F. */ |
||
911 |
7823388 |
condPushBack = o; |
|
912 |
} |
||
913 |
8099497 |
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 |
48440016 |
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 |
✓✓ | 221913506 |
for (end = line; ISLOWER(*end); end++) |
940 |
; |
||
941 |
/* quick path: recognize special targets early on */ |
||
942 |
✓✓✓✓ |
48045635 |
if (*end == '.' || *end == ':') |
943 |
580167 |
return COND_INVALID; |
|
944 |
23639841 |
len = end - line; |
|
945 |
23639841 |
k = ohash_interval(line, &end); |
|
946 |
✓✓✓✓ ✗✓✗✗ ✗✗✓✓ ✓✗✗✓ ✓ |
23639841 |
switch(k % MAGICSLOTS2) { |
947 |
case K_COND_IF % MAGICSLOTS2: |
||
948 |
✓✗✓✗ |
15957140 |
if (k == K_COND_IF && len == strlen(COND_IF) && |
949 |
7978570 |
strncmp(line, COND_IF, len) == 0) { |
|
950 |
ifp = ifs + COND_IF_INDEX; |
||
951 |
} else |
||
952 |
return COND_INVALID; |
||
953 |
7978570 |
break; |
|
954 |
case K_COND_IFDEF % MAGICSLOTS2: |
||
955 |
✓✗✓✗ |
7280 |
if (k == K_COND_IFDEF && len == strlen(COND_IFDEF) && |
956 |
3640 |
strncmp(line, COND_IFDEF, len) == 0) { |
|
957 |
ifp = ifs + COND_IFDEF_INDEX; |
||
958 |
} else |
||
959 |
return COND_INVALID; |
||
960 |
3640 |
break; |
|
961 |
case K_COND_IFNDEF % MAGICSLOTS2: |
||
962 |
✓✓✓✗ |
85718 |
if (k == K_COND_IFNDEF && len == strlen(COND_IFNDEF) && |
963 |
33869 |
strncmp(line, COND_IFNDEF, len) == 0) { |
|
964 |
ifp = ifs + COND_IFNDEF_INDEX; |
||
965 |
} else |
||
966 |
17980 |
return COND_INVALID; |
|
967 |
33869 |
break; |
|
968 |
case K_COND_IFMAKE % MAGICSLOTS2: |
||
969 |
✓✗✓✗ |
496 |
if (k == K_COND_IFMAKE && len == strlen(COND_IFMAKE) && |
970 |
248 |
strncmp(line, COND_IFMAKE, len) == 0) { |
|
971 |
ifp = ifs + COND_IFMAKE_INDEX; |
||
972 |
} else |
||
973 |
return COND_INVALID; |
||
974 |
248 |
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 |
✓✗✓✗ |
270076 |
if (k == K_COND_ELIF && len == strlen(COND_ELIF) && |
984 |
135038 |
strncmp(line, COND_ELIF, len) == 0) { |
|
985 |
ifp = ifs + COND_ELIF_INDEX; |
||
986 |
} else |
||
987 |
return COND_INVALID; |
||
988 |
135038 |
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 |
✓✗✓✗ |
12724418 |
if (k == K_COND_ELSE && len == strlen(COND_ELSE) && |
1021 |
6362209 |
strncmp(line, COND_ELSE, len) == 0) { |
|
1022 |
✗✓ | 6362209 |
if (condTop == MAXIF) { |
1023 |
Parse_Error(level, "if-less else"); |
||
1024 |
return COND_INVALID; |
||
1025 |
✓✓ | 6362209 |
} else if (skipIfLevel == 0) { |
1026 |
6333349 |
value = !condStack[condTop].value; |
|
1027 |
ifp = ifs + COND_ELSE_INDEX; |
||
1028 |
} else |
||
1029 |
28860 |
return COND_SKIP; |
|
1030 |
} else |
||
1031 |
return COND_INVALID; |
||
1032 |
6333349 |
break; |
|
1033 |
case K_COND_ENDIF % MAGICSLOTS2: |
||
1034 |
✓✗✓✗ |
16032654 |
if (k == K_COND_ENDIF && len == strlen(COND_ENDIF) && |
1035 |
8016327 |
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 |
✓✓ | 8016327 |
if (skipIfLevel != 0) { |
1044 |
384842 |
skipIfLevel--; |
|
1045 |
384842 |
return COND_SKIP; |
|
1046 |
} else { |
||
1047 |
✗✓ | 7631485 |
if (condTop == MAXIF) { |
1048 |
Parse_Error(level, "if-less endif"); |
||
1049 |
return COND_INVALID; |
||
1050 |
} else { |
||
1051 |
7631485 |
skipLine = false; |
|
1052 |
7631485 |
condTop++; |
|
1053 |
7631485 |
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 |
✓✗✓✗ |
633708 |
if (k == K_COND_FOR && len == strlen(COND_FOR) && |
1063 |
316854 |
strncmp(line, COND_FOR, len) == 0) |
|
1064 |
316854 |
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 |
✓✗✓✗ |
547504 |
if (k == K_COND_INCLUDE && len == strlen(COND_INCLUDE) && |
1081 |
273752 |
strncmp(line, COND_INCLUDE, len) == 0) |
|
1082 |
273752 |
return COND_ISINCLUDE; |
|
1083 |
else |
||
1084 |
return COND_INVALID; |
||
1085 |
default: |
||
1086 |
/* Not a valid conditional type. No error... */ |
||
1087 |
501354 |
return COND_INVALID; |
|
1088 |
} |
||
1089 |
|||
1090 |
✓✓ | 14484714 |
if (ifp->isElse) { |
1091 |
✗✓ | 6468387 |
if (condTop == MAXIF) { |
1092 |
Parse_Error(level, "if-less elif"); |
||
1093 |
return COND_INVALID; |
||
1094 |
✓✓✓✓ |
12920458 |
} 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 |
3204119 |
skipLine = true; |
|
1101 |
3204119 |
return COND_SKIP; |
|
1102 |
} |
||
1103 |
✓✓ | 8016327 |
} else if (skipLine) { |
1104 |
/* Don't even try to evaluate a conditional that's not an else |
||
1105 |
* if we're skipping things... */ |
||
1106 |
384842 |
skipIfLevel++; |
|
1107 |
384842 |
return COND_SKIP; |
|
1108 |
} else |
||
1109 |
7631485 |
condTop--; |
|
1110 |
|||
1111 |
✗✓ | 10895753 |
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 |
✓✓ | 10895753 |
if (ifp->defProc) { |
1121 |
/* Initialize file-global variables for parsing. */ |
||
1122 |
7732722 |
condDefProc = ifp->defProc; |
|
1123 |
7732722 |
condInvert = ifp->doNot; |
|
1124 |
|||
1125 |
line += len; |
||
1126 |
|||
1127 |
✓✓✓✓ |
54129089 |
while (*line == ' ' || *line == '\t') |
1128 |
7732732 |
line++; |
|
1129 |
|||
1130 |
15465444 |
condExpr = line; |
|
1131 |
15465444 |
condPushBack = None; |
|
1132 |
|||
1133 |
✓✓✗✓ |
15465444 |
switch (CondE(true)) { |
1134 |
case True: |
||
1135 |
✓✗ | 3731282 |
if (CondToken(true) == EndOfFile) { |
1136 |
value = true; |
||
1137 |
3731282 |
break; |
|
1138 |
} |
||
1139 |
goto err; |
||
1140 |
/* FALLTHROUGH */ |
||
1141 |
case False: |
||
1142 |
✓✗ | 4001440 |
if (CondToken(true) == EndOfFile) { |
1143 |
value = false; |
||
1144 |
4001440 |
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 |
10895753 |
condStack[condTop].value = value; |
|
1157 |
10895753 |
Parse_FillLocation(&condStack[condTop].origin); |
|
1158 |
10895753 |
skipLine = !value; |
|
1159 |
10895753 |
return value ? COND_PARSE : COND_SKIP; |
|
1160 |
24220008 |
} |
|
1161 |
|||
1162 |
void |
||
1163 |
Cond_End(void) |
||
1164 |
{ |
||
1165 |
int i; |
||
1166 |
|||
1167 |
✗✓ | 67416 |
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 |
33708 |
condTop = MAXIF; |
|
1178 |
33708 |
} |
Generated by: GCOVR (Version 3.3) |