Beispiel #1
0
bool
Var_ParseSkip(const char **pstr, SymTable *ctxt)
{
	const char *str = *pstr;
	struct Name name;
	bool result;
	bool has_modifier;
	const char *tstr = str;

	if (str[1] == 0) {
		*pstr = str+1;
		return false;
	}
	has_modifier = parse_base_variable_name(&tstr, &name, ctxt);
	VarName_Free(&name);
	result = true;
	if (has_modifier) {
		bool freePtr = false;
		char *s = VarModifiers_Apply(NULL, NULL, ctxt, true, &freePtr, 
		    &tstr, str[1]);
		if (s == var_Error)
			result = false;
		if (freePtr)
			free(s);
	}
	*pstr = tstr;
	return result;
}
Beispiel #2
0
char *
Var_Parse(const char *str,	/* The string to parse */
    SymTable *ctxt,		/* The context for the variable */
    bool err,			/* true if undefined variables are an error */
    size_t *lengthPtr,		/* OUT: The length of the specification */
    bool *freePtr)		/* OUT: true if caller should free result */
{
	const char *tstr;
	struct Name name;
	char *val;
	uint32_t k;
	int idx;
	bool has_modifier;

	*freePtr = false;

	tstr = str;

	if (str[1] == 0) {
		*lengthPtr = 1;
		*freePtr = false;
		return err ? var_Error : varNoError;
	}

	has_modifier = parse_base_variable_name(&tstr, &name, ctxt);

	idx = classify_var(name.s, &name.e, &k);
	val = get_expanded_value(name.s, name.e, idx, k, ctxt, err, freePtr);
	if (has_modifier) {
		val = VarModifiers_Apply(val, &name, ctxt, err, freePtr,
		    &tstr, str[1]);
	}
	if (val == NULL) {
		val = err ? var_Error : varNoError;
		/* If it comes from a dynamic source, and it doesn't have
		 * a context, copy the spec instead.
		 * Specifically, this make allows constructs like:
		 * 	target.o: $*.c
		 * Absence of a context means "parsing". But these can't
		 * be expanded during parsing, to be consistent with the
		 * way .SUFFIXES work.
		 * .SUFFIXES may be added/reset/removed during parsing,
		 * but in the end, the final list is what's considered for
		 * handling targets.  So those dynamic variables must be
		 * handled lazily too.
		 */
		if (idx != GLOBAL_INDEX) {
			if (ctxt == NULL) {
				*freePtr = true;
				val = Str_dupi(str, tstr);
			} else {
				bad_dynamic_variable(idx);
			}
		}
	}
	VarName_Free(&name);
	*lengthPtr = tstr - str;
	return val;
}
Beispiel #3
0
/* Very quick version of the variable scanner that just looks for target
 * variables, and never ever errors out
 */
bool
Var_Check_for_target(const char *str)
{
	bool seen_target = false;

	for (;;) {
		const char *tstr;
		uint32_t k;
		int idx;
		bool has_modifier;
		struct Name name;

		/* skip over uninteresting stuff */
		for (; *str != '\0' && *str != '$'; str++)
			;
		if (*str == '\0')
			break;
		if (str[1] == '$') {
			/* A $ may be escaped with another $. */
			str += 2;
			continue;
		}

		tstr = str;

		has_modifier = parse_base_variable_name(&tstr, &name, NULL);
		idx = classify_var(name.s, &name.e, &k);
		if (has_modifier) {
			bool doFree = false;
			char *val = VarModifiers_Apply(NULL, NULL, NULL, false, 
			    &doFree, &tstr, str[1]);
			if (doFree)
				free(val);
		}
		if (tlist[idx])
			seen_target = true;
		VarName_Free(&name);
		str = tstr;
	}
	return seen_target;
}
Beispiel #4
0
Datei: var.c Projekt: aharri/base
char *
Var_Parse(const char *str,	/* The string to parse */
    SymTable *ctxt,		/* The context for the variable */
    bool err,			/* true if undefined variables are an error */
    size_t *lengthPtr,		/* OUT: The length of the specification */
    bool *freePtr)		/* OUT: true if caller should free result */
{
	const char *tstr;
	struct Name name;
	char *val;
	uint32_t k;
	int idx;
	bool has_modifier;

	*freePtr = false;

	tstr = str;

	has_modifier = parse_base_variable_name(&tstr, &name, ctxt);

	idx = classify_var(name.s, &name.e, &k);
	val = get_expanded_value(name.s, name.e, idx, k, ctxt, err, freePtr);
	if (has_modifier) {
		val = VarModifiers_Apply(val, &name, ctxt, err, freePtr,
		    &tstr, str[1]);
	}
	if (val == NULL) {
		val = err ? var_Error : varNoError;
		/* Dynamic source */
		if (idx != GLOBAL_INDEX) {
			/* can't be expanded for now: copy the spec instead. */
			if (ctxt == NULL) {
				*freePtr = true;
				val = Str_dupi(str, tstr);
			} else {
			/* somehow, this should have been expanded already. */
				GNode *n;

				/* XXX */
				n = (GNode *)(((char *)ctxt) -
				    offsetof(GNode, context));
				if (idx >= LOCAL_SIZE)
					idx = EXTENDED2SIMPLE(idx);
				switch(idx) {
				case IMPSRC_INDEX:
					Fatal(
"Using $< in a non-suffix rule context is a GNUmake idiom (line %lu of %s)",
					    n->origin.lineno, n->origin.fname);
					break;
				default:
					Error(
"Using undefined dynamic variable $%s (line %lu of %s)",
					    varnames[idx], n->origin.lineno, 
					    n->origin.fname);
					break;
				}
			}
		}
	}
	VarName_Free(&name);
	*lengthPtr = tstr - str;
	return val;
}
Beispiel #5
0
static bool
parse_variable_assignment(const char *line, int ctxt)
{
	const char *arg;
	char *res1 = NULL, *res2 = NULL;
#define VAR_INVALID	-1
#define VAR_NORMAL	0
#define VAR_SUBST	1
#define VAR_APPEND	2
#define VAR_SHELL	4
#define VAR_OPT		8
	int type;
	struct Name name;

	arg = VarName_Get(line, &name, NULL, true,
	    FEATURES(FEATURE_SUNSHCMD) ? find_op1 : find_op2);

	while (isspace(*arg))
		arg++;

	type = VAR_NORMAL;

	while (*arg != '=') {
		/* Check operator type.  */
		switch (*arg++) {
		case '+':
			if (type & (VAR_OPT|VAR_APPEND))
				type = VAR_INVALID;
			else
				type |= VAR_APPEND;
			break;

		case '?':
			if (type & (VAR_OPT|VAR_APPEND))
				type = VAR_INVALID;
			else
				type |= VAR_OPT;
			break;

		case ':':
			if (FEATURES(FEATURE_SUNSHCMD) &&
			    strncmp(arg, "sh", 2) == 0) {
				type = VAR_SHELL;
				arg += 2;
				while (*arg != '=' && *arg != '\0')
					arg++;
			} else {
				if (type & VAR_SUBST)
					type = VAR_INVALID;
				else
					type |= VAR_SUBST;
			}
			break;

		case '!':
			if (type & VAR_SHELL)
				type = VAR_INVALID;
			else
				type |= VAR_SHELL;
			break;

		default:
			type = VAR_INVALID;
			break;
		}
		if (type == VAR_INVALID) {
			VarName_Free(&name);
			return false;
		}
	}

	arg++;
	while (isspace(*arg))
		arg++;
	/* If the variable already has a value, we don't do anything.  */
	if ((type & VAR_OPT) && Var_Definedi(name.s, name.e)) {
		VarName_Free(&name);
		return true;
	}
	if (type & VAR_SHELL) {
		char *err;

		if (strchr(arg, '$') != NULL) {
			char *sub;
			/* There's a dollar sign in the command, so perform
			 * variable expansion on the whole thing. */
			sub = Var_Subst(arg, NULL, true);
			res1 = Cmd_Exec(sub, &err);
			free(sub);
		} else
			res1 = Cmd_Exec(arg, &err);

		if (err)
			Parse_Error(PARSE_WARNING, err, arg);
		arg = res1;
	}
	if (type & VAR_SUBST) {
		/*
		 * Allow variables in the old value to be undefined, but leave
		 * their invocation alone -- this is done by forcing
		 * errorIsOkay to be false.
		 * XXX: This can cause recursive variables, but that's not
		 * hard to do, and this allows someone to do something like
		 *
		 *  CFLAGS = $(.INCLUDES)
		 *  CFLAGS := -I.. $(CFLAGS)
		 *
		 * And not get an error.
		 */
		bool   saved = errorIsOkay;

		errorIsOkay = false;
		/* ensure the variable is set to something to avoid `variable
		 * is recursive' errors.  */
		if (!Var_Definedi(name.s, name.e))
			Var_Seti_with_ctxt(name.s, name.e, "", ctxt);

		res2 = Var_Subst(arg, NULL, false);
		errorIsOkay = saved;

		arg = res2;
	}

	if (type & VAR_APPEND)
		Var_Appendi_with_ctxt(name.s, name.e, arg, ctxt);
	else
		Var_Seti_with_ctxt(name.s, name.e, arg, ctxt);

	VarName_Free(&name);
	free(res2);
	free(res1);
	return true;
}
Beispiel #6
0
static Token
CondHandleDefault(bool doEval)
{
	bool t;
	bool (*evalProc)(struct Name *);
	bool invert = false;
	struct Name arg;
	size_t arglen;

	evalProc = NULL;
	if (strncmp(condExpr, "empty", 5) == 0) {
		/* Use Var_Parse to parse the spec in parens and return
		 * True if the resulting string is empty.  */
		size_t length;
		bool doFree;
		char *val;

		condExpr += 5;

		for (arglen = 0; condExpr[arglen] != '(' &&
		    condExpr[arglen] != '\0';)
			arglen++;

		if (condExpr[arglen] != '\0') {
			val = Var_Parse(&condExpr[arglen - 1], NULL,
			    doEval, &length, &doFree);
			if (val == var_Error)
				t = Err;
			else {
				/* A variable is empty when it just contains
				 * spaces... 4/15/92, christos */
				char *p;
				for (p = val; isspace(*p); p++)
					continue;
				t = *p == '\0' ? True : False;
			}
			if (doFree)
				free(val);
			/* Advance condExpr to beyond the closing ). Note that
			 * we subtract one from arglen + length b/c length
			 * is calculated from condExpr[arglen - 1].  */
			condExpr += arglen + length - 1;
			return t;
		} else
			condExpr -= 5;
	} else {
		struct operator *op;

		for (op = ops; op != NULL; op++)
			if (strncmp(condExpr, op->s, op->len) == 0) {
				condExpr += op->len;
				if (CondGetArg(&condExpr, &arg, op->s, true))
					evalProc = op->proc;
				else
					condExpr -= op->len;
				break;
			}
	}
	if (evalProc == NULL) {
		/* The symbol is itself the argument to the default
		 * function. We advance condExpr to the end of the symbol
		 * by hand (the next whitespace, closing paren or
		 * binary operator) and set to invert the evaluation
		 * function if condInvert is true.  */
		invert = condInvert;
		evalProc = condDefProc;
		/* XXX should we ignore problems now ? */
		CondGetArg(&condExpr, &arg, "", false);
	}

	/* Evaluate the argument using the set function. If invert
	 * is true, we invert the sense of the function.  */
	t = (!doEval || (*evalProc)(&arg) ?
	     (invert ? False : True) :
	     (invert ? True : False));
	VarName_Free(&arg);
	return t;
}