cond.c

来自「早期freebsd实现」· C语言 代码 · 共 1,248 行 · 第 1/2 页

C
1,248
字号
/* * Copyright (c) 1988, 1989, 1990, 1993 *	The Regents of the University of California.  All rights reserved. * 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 lintstatic char sccsid[] = "@(#)cond.c	8.2 (Berkeley) 1/2/94";#endif /* not lint *//*- * cond.c -- *	Functions to handle conditionals in a makefile. * * Interface: *	Cond_Eval 	Evaluate the conditional in the passed line. * */#include    <ctype.h>#include    <math.h>#include    "make.h"#include    "hash.h"#include    "dir.h"#include    "buf.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 int CondGetArg __P((char **, char **, char *, Boolean));static Boolean CondDoDefined __P((int, char *));static int CondStrMatch __P((char *, char *));static Boolean CondDoMake __P((int, char *));static Boolean CondDoExists __P((int, char *));static Boolean CondDoTarget __P((int, char *));static Boolean CondCvtArg __P((char *, double *));static Token CondToken __P((Boolean));static Token CondT __P((Boolean));static Token CondF __P((Boolean));static Token CondE __P((Boolean));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 *//*- *----------------------------------------------------------------------- * 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 voidCondPushBack (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 intCondGetArg (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 ((strchr(" \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 BooleanCondDoDefined (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;    } else {	result = FALSE;    }    arg[argLen] = savec;    return (result);}/*- *----------------------------------------------------------------------- * CondStrMatch -- *	Front-end for Str_Match so it returns 0 on match and non-zero *	on mismatch. Callback function for CondDoMake via Lst_Find * * Results: *	0 if string matches pattern * * Side Effects: *	None * *----------------------------------------------------------------------- */static intCondStrMatch(string, pattern)    char    *string;    char    *pattern;{    return(!Str_Match(string,pattern));}/*- *----------------------------------------------------------------------- * CondDoMake -- *	Handle the 'make' function for conditionals. * * Results: *	TRUE if the given target is being made. * * Side Effects: *	None. * *----------------------------------------------------------------------- */static BooleanCondDoMake (argLen, arg)    int	    argLen;    char    *arg;{    char    savec = arg[argLen];    Boolean result;    arg[argLen] = '\0';    if (Lst_Find (create, (ClientData)arg, CondStrMatch) == NILLNODE) {	result = FALSE;    } else {	result = TRUE;    }    arg[argLen] = savec;    return (result);}/*- *----------------------------------------------------------------------- * CondDoExists -- *	See if the given file exists. * * Results: *	TRUE if the file exists and FALSE if it does not. * * Side Effects: *	None. * *----------------------------------------------------------------------- */static BooleanCondDoExists (argLen, arg)    int	    argLen;    char    *arg;{    char    savec = arg[argLen];    Boolean result;    char    *path;    arg[argLen] = '\0';    path = Dir_FindFile(arg, dirSearchPath);    if (path != (char *)NULL) {	result = TRUE;	free(path);    } else {	result = FALSE;    }    arg[argLen] = savec;    return (result);}/*- *----------------------------------------------------------------------- * CondDoTarget -- *	See if the given node exists and is an actual target. * * Results: *	TRUE if the node exists as a target and FALSE if it does not. * * Side Effects: *	None. * *----------------------------------------------------------------------- */static BooleanCondDoTarget (argLen, arg)    int	    argLen;    char    *arg;{    char    savec = arg[argLen];    Boolean result;    GNode   *gn;    arg[argLen] = '\0';    gn = Targ_FindNode(arg, TARG_NOCREATE);    if ((gn != NILGNODE) && !OP_NOP(gn->type)) {	result = TRUE;    } else {	result = FALSE;    }    arg[argLen] = savec;    return (result);}/*- *----------------------------------------------------------------------- * CondCvtArg -- *	Convert the given number into a double. If the number begins *	with 0x, it is interpreted as a hexadecimal integer *	and converted to a double from there. All other strings just have *	strtod called on them. * * Results: *	Sets 'value' to double value of string. *	Returns true if the string was a valid number, false o.w. * * Side Effects: *	Can change 'value' even if string is not a valid number. *	 * *----------------------------------------------------------------------- */static BooleanCondCvtArg(str, value)    register char    	*str;    double		*value;{    if ((*str == '0') && (str[1] == 'x')) {	register long i;	for (str += 2, i = 0; *str; str++) {	    int x;	    if (isdigit((unsigned char) *str))		x  = *str - '0';	    else if (isxdigit((unsigned char) *str))		x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a';	    else		return FALSE;	    i = (i << 4) + x;	}	*value = (double) i;	return TRUE;    }    else {	char *eptr;	*value = strtod(str, &eptr);	return *eptr == '\0';    }}/*- *----------------------------------------------------------------------- * CondToken -- *	Return the next token from the input. * * Results: *	A Token for the next lexical token in the stream. * * Side Effects: *	condPushback will be set back to None if it is used. * *----------------------------------------------------------------------- */static TokenCondToken(doEval)    Boolean doEval;{    Token	  t;    if (condPushBack == None) {	while (*condExpr == ' ' || *condExpr == '\t') {	    condExpr++;	}	switch (*condExpr) {	    case '(':		t = LParen;		condExpr++;		break;	    case ')':		t = RParen;		condExpr++;		break;	    case '|':		if (condExpr[1] == '|') {		    condExpr++;		}		condExpr++;		t = Or;		break;	    case '&':		if (condExpr[1] == '&') {		    condExpr++;		}		condExpr++;		t = And;		break;	    case '!':		t = Not;		condExpr++;		break;	    case '\n':	    case '\0':		t = EndOfFile;		break;	    case '$': {		char	*lhs;		char	*rhs;		char	*op;		int	varSpecLen;		Boolean	doFree;		/*		 * Parse the variable spec and skip over it, saving its		 * value in lhs.		 */		t = Err;		lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree);		if (lhs == var_Error) {		    /*		     * Even if !doEval, we still report syntax errors, which		     * is what getting var_Error back with !doEval means.		     */		    return(Err);		}		condExpr += varSpecLen;		if (!isspace(*condExpr) && strchr("!=><", *condExpr) == NULL) {		    Buffer buf;		    char *cp;		    buf = Buf_Init(0);		    for (cp = lhs; *cp; cp++)			Buf_AddByte(buf, (Byte)*cp);		    if (doFree)			free(lhs);		    for (;*condExpr && !isspace(*condExpr); condExpr++)			Buf_AddByte(buf, (Byte)*condExpr);		    Buf_AddByte(buf, (Byte)'\0');		    lhs = (char *)Buf_GetAll(buf, &varSpecLen);		    Buf_Destroy(buf, FALSE);		    doFree = TRUE;		}		/*		 * Skip whitespace to get to the operator		 */		while (isspace(*condExpr))		    condExpr++;		/*		 * Make sure the operator is a valid one. If it isn't a		 * known relational operator, pretend we got a		 * != 0 comparison.		 */		op = condExpr;		switch (*condExpr) {		    case '!':		    case '=':		    case '<':		    case '>':			if (condExpr[1] == '=') {			    condExpr += 2;			} else {			    condExpr += 1;			}			break;		    default:			op = "!=";			rhs = "0";			goto do_compare;		}		while (isspace(*condExpr)) {		    condExpr++;		}		if (*condExpr == '\0') {		    Parse_Error(PARSE_WARNING,				"Missing right-hand-side of operator");		    goto error;		}		rhs = condExpr;do_compare:		if (*rhs == '"') {		    /*		     * Doing a string comparison. Only allow == and != for		     * operators.		     */		    char    *string;		    char    *cp, *cp2;		    int	    qt;		    Buffer  buf;do_string_compare:		    if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {			Parse_Error(PARSE_WARNING,		"String comparison operator should be either == or !=");			goto error;		    }		    buf = Buf_Init(0);		    qt = *rhs == '"' ? 1 : 0;		    		    for (cp = &rhs[qt]; 			 ((qt && (*cp != '"')) || 			  (!qt && strchr(" \t)", *cp) == NULL)) && 			 (*cp != '\0'); cp++) {			if ((*cp == '\\') && (cp[1] != '\0')) {			    /*			     * Backslash escapes things -- skip over next			     * character, if it exists.			     */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?