home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 4
/
FreshFish_May-June1994.bin
/
bsd
/
src
/
make
/
make-amiga
/
cond.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-23
|
29KB
|
1,209 lines
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
* Copyright (c) 1988, 1989 by Adam de Boor
* Copyright (c) 1989 by Berkeley Softworks
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Adam de Boor.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)cond.c 5.6 (Berkeley) 6/1/90";
#endif /* not lint */
/*-
* cond.c --
* Functions to handle conditionals in a makefile.
*
* Interface:
* Cond_Eval Evaluate the conditional in the passed line.
*
*/
#include "make.h"
#include <buf.h>
#include <ctype.h>
/*
* The parsing of conditional expressions is based on this grammar:
* E -> F || E
* E -> F
* F -> T && F
* F -> T
* T -> defined(variable)
* T -> make(target)
* T -> exists(file)
* T -> empty(varspec)
* T -> target(name)
* T -> symbol
* T -> $(varspec) op value
* T -> $(varspec) == "string"
* T -> $(varspec) != "string"
* T -> ( E )
* T -> ! T
* op -> == | != | > | < | >= | <=
*
* 'symbol' is some other symbol to which the default function (condDefProc)
* is applied.
*
* Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
* will return And for '&' and '&&', Or for '|' and '||', Not for '!',
* LParen for '(', RParen for ')' and will evaluate the other terminal
* symbols, using either the default function or the function given in the
* terminal, and return the result as either True or False.
*
* All Non-Terminal functions (CondE, CondF and CondT) return Err on error.
*/
typedef enum {
And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err
} Token;
/*-
* Structures to handle elegantly the different forms of #if's. The
* last two fields are stored in condInvert and condDefProc, respectively.
*/
static Boolean CondDoDefined(),
CondDoMake();
static struct If {
char *form; /* Form of if */
int formlen; /* Length of form */
Boolean doNot; /* TRUE if default function should be negated */
Boolean (*defProc)(); /* Default function to apply */
} ifs[] = {
"ifdef", 5, FALSE, CondDoDefined,
"ifndef", 6, TRUE, CondDoDefined,
"ifmake", 6, FALSE, CondDoMake,
"ifnmake", 7, TRUE, CondDoMake,
"if", 2, FALSE, CondDoDefined,
(char *)0, 0, FALSE, (Boolean (*)())0,
};
static Boolean condInvert; /* Invert the default function */
static Boolean (*condDefProc)(); /* Default function to apply */
static char *condExpr; /* The expression to parse */
static Token condPushBack=None; /* Single push-back token used in
* parsing */
#define MAXIF 30 /* greatest depth of #if'ing */
static Boolean condStack[MAXIF]; /* Stack of conditionals's values */
static int condTop = MAXIF; /* Top-most conditional */
static int skipIfLevel=0; /* Depth of skipped conditionals */
static Boolean skipLine = FALSE; /* Whether the parse module is skipping
* lines */
static Token CondT(), CondF(), CondE();
/*-
*-----------------------------------------------------------------------
* CondPushBack --
* Push back the most recent token read. We only need one level of
* this, so the thing is just stored in 'condPushback'.
*
* Results:
* None.
*
* Side Effects:
* condPushback is overwritten.
*
*-----------------------------------------------------------------------
*/
static void
CondPushBack (t)
Token t; /* Token to push back into the "stream" */
{
condPushBack = t;
}
/*-
*-----------------------------------------------------------------------
* CondGetArg --
* Find the argument of a built-in function.
*
* Results:
* The length of the argument and the address of the argument.
*
* Side Effects:
* The pointer is set to point to the closing parenthesis of the
* function call.
*
*-----------------------------------------------------------------------
*/
static int
CondGetArg (linePtr, argPtr, func, parens)
char **linePtr;
char **argPtr;
char *func;
Boolean parens; /* TRUE if arg should be bounded by parens */
{
register char *cp;
int argLen;
register Buffer buf;
cp = *linePtr;
if (parens) {
while (*cp != '(' && *cp != '\0') {
cp++;
}
if (*cp == '(') {
cp++;
}
}
if (*cp == '\0') {
/*
* No arguments whatsoever. Because 'make' and 'defined' aren't really
* "reserved words", we don't print a message. I think this is better
* than hitting the user with a warning message every time s/he uses
* the word 'make' or 'defined' at the beginning of a symbol...
*/
*argPtr = cp;
return (0);
}
while (*cp == ' ' || *cp == '\t') {
cp++;
}
/*
* Create a buffer for the argument and start it out at 16 characters
* long. Why 16? Why not?
*/
buf = Buf_Init(16);
while ((index(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) {
if (*cp == '$') {
/*
* Parse the variable spec and install it as part of the argument
* if it's valid. We tell Var_Parse to complain on an undefined
* variable, so we don't do it too. Nor do we return an error,
* though perhaps we should...
*/
char *cp2;
int len;
Boolean doFree;
cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree);
Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
if (doFree) {
free(cp2);
}
cp += len;
} else {
Buf_AddByte(buf, (Byte)*cp);
cp++;
}
}
Buf_AddByte(buf, (Byte)'\0');
*argPtr = (char *)Buf_GetAll(buf, &argLen);
Buf_Destroy(buf, FALSE);
while (*cp == ' ' || *cp == '\t') {
cp++;
}
if (parens && *cp != ')') {
Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()",
func);
return (0);
} else if (parens) {
/*
* Advance pointer past close parenthesis.
*/
cp++;
}
*linePtr = cp;
return (argLen);
}
/*-
*-----------------------------------------------------------------------
* CondDoDefined --
* Handle the 'defined' function for conditionals.
*
* Results:
* TRUE if the given variable is defined.
*
* Side Effects:
* None.
*
*-----------------------------------------------------------------------
*/
static Boolean
CondDoDefined (argLen, arg)
int argLen;
char *arg;
{
char savec = arg[argLen];
Boolean result;
arg[argLen] = '\0';
if (Var_Value (arg, VAR_CMD) != (char *)NULL) {
result = TRUE;