Пример #1
0
Файл: var.c Проект: aharri/base
/* mark variable as poisoned, in a given setup.
 */
void
Var_MarkPoisoned(const char *name, const char *ename, unsigned int type)
{
	Var   *v;
	uint32_t	k;
	int		idx;
	idx = classify_var(name, &ename, &k);

	if (idx != GLOBAL_INDEX) {
		Parse_Error(PARSE_FATAL,
		    "Trying to poison dynamic variable $%s",
		    varnames[idx]);
		return;
	}

	v = find_global_var(name, ename, k);
	v->flags |= type;
	/* POISON_NORMAL is not lazy: if the variable already exists in
	 * the Makefile, then it's a mistake.
	 */
	if (v->flags & POISON_NORMAL) {
		if (v->flags & VAR_DUMMY)
			return;
		if (v->flags & VAR_FROM_ENV)
			return;
		Parse_Error(PARSE_FATAL,
		    "Poisoned variable %s is already set\n", v->name);
	}
}
Пример #2
0
char *
Parse_ReadNextConditionalLine(Buffer linebuf)
{
	int c;

	/* If first char isn't dot, skip to end of line, handling \ */
	while ((c = read_char()) != '.') {
		for (;c != '\n'; c = read_char()) {
			if (c == '\\') {
				c = read_char();
				if (c == '\n')
					current->lineno++;
			}
			if (c == EOF) {
				Parse_Error(PARSE_FATAL,
				    "Unclosed conditional");
				return NULL;
			}
		}
		current->lineno++;
	}

	/* This is the line we need to copy */
	return Parse_ReadUnparsedLine(linebuf, "conditional");
}
Пример #3
0
char *
Parse_ReadUnparsedLine(Buffer linebuf, const char *type)
{
	int c;

	Buf_Reset(linebuf);
	c = read_char();
	if (c == EOF) {
		Parse_Error(PARSE_FATAL, "Unclosed %s", type);
		return NULL;
	}

	/* Handle '\' at beginning of line, since \\n needs special treatment */
	while (c == '\\') {
		c = read_char();
		if (c == '\n') {
			current->lineno++;
			do {
				c = read_char();
			} while (c == ' ' || c == '\t');
		} else {
			Buf_AddChar(linebuf, '\\');
			if (c == '\\') {
				Buf_AddChar(linebuf, '\\');
				c = read_char();
			}
			break;
		}
	}
	read_logical_line(linebuf, c);

	return Buf_Retrieve(linebuf);
}
Пример #4
0
static bool
parse_base_variable_name(const char **pstr, struct Name *name, SymTable *ctxt)
{
	const char *str = *pstr;
	const char *tstr;
	bool has_modifier = false;

	switch(str[1]) {
	case '(':
	case '{':
		/* Find eventual modifiers in the variable */
		tstr = VarName_Get(str+2, name, ctxt, false, find_pos(str[1]));
		if (*tstr == '\0')
			 Parse_Error(PARSE_FATAL, "Unterminated variable spec in %s", *pstr);
		else if (*tstr == ':')
			has_modifier = true;
		else
			tstr++;
		break;
	default:
		name->s = str+1;
		name->e = str+2;
		name->tofree = false;
		tstr = str + 2;
		break;
	}
	*pstr = tstr;
	return has_modifier;
}
Пример #5
0
Файл: var.c Проект: aharri/base
/* Delete global variable.
 */
void
Var_Deletei(const char *name, const char *ename)
{
	Var *v;
	uint32_t k;
	unsigned int slot;
	int idx;

	idx = classify_var(name, &ename, &k);
	if (idx != GLOBAL_INDEX) {
		Parse_Error(PARSE_FATAL,
		    "Trying to delete dynamic variable $%s", varnames[idx]);
		return;
	}
	slot = ohash_lookup_interval(&global_variables, name, ename, k);
	v = ohash_find(&global_variables, slot);

	if (v == NULL)
		return;

	if (checkEnvFirst && (v->flags & VAR_FROM_ENV))
		return;

	if (v->flags & VAR_FROM_CMD)
		return;

	ohash_remove(&global_variables, slot);
	delete_var(v);
}
Пример #6
0
/*-
 *-----------------------------------------------------------------------
 * Cond_EvalExpression --
 *	Evaluate an expression in the passed line. The expression
 *	consists of &&, ||, !, make(target), defined(variable)
 *	and parenthetical groupings thereof.
 *
 * Results:
 *	COND_PARSE	if the condition was valid grammatically
 *	COND_INVALID  	if not a valid conditional.
 *
 *	(*value) is set to the boolean value of the condition
 *
 * Side Effects:
 *	None.
 *
 *-----------------------------------------------------------------------
 */
int
Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprint)
{
    static const struct If *dflt_info;
    const struct If *sv_if_info = if_info;
    char *sv_condExpr = condExpr;
    Token sv_condPushBack = condPushBack;
    int rval;

    while (*line == ' ' || *line == '\t')
	line++;

    if (info == NULL && (info = dflt_info) == NULL) {
	/* Scan for the entry for .if - it can't be first */
	for (info = ifs; ; info++)
	    if (info->form[0] == 0)
		break;
	dflt_info = info;
    }

    if_info = info != NULL ? info : ifs + 4;
    condExpr = line;
    condPushBack = TOK_NONE;

    rval = do_Cond_EvalExpression(value);

    if (rval == COND_INVALID && eprint)
	Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line);

    if_info = sv_if_info;
    condExpr = sv_condExpr;
    condPushBack = sv_condPushBack;

    return rval;
}
Пример #7
0
      ImplementationArtifactDescription *  IAD_Handler::resolve_iad (const ACE_TCHAR *uri)
      {
        DANCE_TRACE ("IAD_Handler::resolve_iad");

        xercesc::DOMDocument *dom = XML::XML_Typedef::XML_HELPER.create_dom (uri);

        if (!dom)
          throw Parse_Error (ACE_TEXT ("Unable to create DOM for IAD"));

        try {
          return new ImplementationArtifactDescription
            (reader::implementationArtifactDescription (dom));
        }
        catch (...) {
          throw Parse_Error (ACE_TEXT ("Unable to create XSC structure for IAD"));
        }
      }
Пример #8
0
Файл: var.c Проект: aharri/base
/* Check if there's any reason not to use the variable in this context.
 */
static void
poison_check(Var *v)
{
	if (v->flags & POISON_NORMAL) {
		Parse_Error(PARSE_FATAL,
		    "Poisoned variable %s has been referenced\n", v->name);
		return;
	}
	if (v->flags & VAR_DUMMY) {
		Parse_Error(PARSE_FATAL,
		    "Poisoned variable %s is not defined\n", v->name);
		return;
	}
	if (v->flags & POISON_EMPTY)
		if (strcmp(var_get_value(v), "") == 0)
			Parse_Error(PARSE_FATAL,
			    "Poisoned variable %s is empty\n", v->name);
}
Пример #9
0
      ComponentImplementationDescription *
      CID_Handler::resolve_cid (const ACE_TCHAR *uri)
      {
        DANCE_TRACE ("CID_Handler::resolve_cid");

        xercesc::DOMDocument *dom = XML::XML_Typedef::XML_HELPER.create_dom (uri);

        if (!dom)
          throw Parse_Error (ACE_TEXT ("Unable to create DOM for CID"));

        try {
          return new ComponentImplementationDescription
            (reader::componentImplementationDescription (dom));
        }
        catch (...) {
          throw Parse_Error (
            ACE_TEXT ("Unable to create XSC structure for CID"));
        }
      }
Пример #10
0
int main() {
    double i_abc[3], i_alfabeta[2], i_dq[2];
    double i_alfabeta_prime[2], i_dq_prime[2];
    motor_err_t err;

    double theta;
    int i;


    //open loop simulation
    i_dq[ID]=0.0;
    i_dq[IQ]=1.0; //1 Amp for example

    printf("Header\n");
    printf("i, theta, id, iq, ialfa, ibeta, ia, ib, ic, ialfa_prime, ibeta_prime, id_prime, iq_prime\n");
    for (i=0; i<360; i++) {
        theta = TO_RADIANS(i);

        err = Convert_dq_to_alfabeta(i_dq, theta, i_alfabeta);
        Parse_Error(err, "Convert_dq_to_alfabeta", QUIET);

        err = Convert_alfabeta_to_abc(i_alfabeta, i_abc);
        Parse_Error(err, "Convert_dq_to_alfabeta", QUIET);

        err = Convert_abc_to_alfabeta(i_abc, i_alfabeta_prime);
        Parse_Error(err, "Convert_dq_to_alfabeta", QUIET);

        err = Convert_alfabeta_to_dq(i_alfabeta_prime, theta, i_dq_prime);
        Parse_Error(err, "Convert_dq_to_alfabeta", QUIET);

        printf("%d, %2.5f; %2.5f, %2.5f; %2.5f, %2.5f; %2.5f, %2.5f, %2.5f; %2.5f, %2.5f; %2.5f, %2.5f\n",
               i, theta,
               i_dq[ID], i_dq[IQ],
               i_alfabeta[IALFA], i_alfabeta[IBETA],
               i_abc[IA], i_abc[IB], i_abc[IC],
               i_alfabeta_prime[IALFA], i_alfabeta_prime[IBETA],
               i_dq_prime[ID], i_dq_prime[IQ]);
    }
    return 0;
}
Пример #11
0
Файл: var.c Проект: aharri/base
/* Set or add a global variable, in VAR_CMD or VAR_GLOBAL context.
 */
static void
var_set_append(const char *name, const char *ename, const char *val, int ctxt,
    bool append)
{
	Var *v;
	uint32_t k;
	int idx;

	idx = classify_var(name, &ename, &k);
	if (idx != GLOBAL_INDEX) {
		Parse_Error(PARSE_FATAL, "Trying to %s dynamic variable $%s",
		    append ? "append to" : "set", varnames[idx]);
		return;
	}

	v = find_global_var(name, ename, k);
	if (v->flags & POISON_NORMAL)
		Parse_Error(PARSE_FATAL, "Trying to %s poisoned variable %s\n",
		    append ? "append to" : "set", v->name);
	/* so can we write to it ? */
	if (ctxt == VAR_CMD) {	/* always for command line */
		(append ? var_append_value : var_set_value)(v, val);
		v->flags |= VAR_FROM_CMD;
		if ((v->flags & VAR_SHELL) == 0) {
			/* Any variables given on the command line are
			 * automatically exported to the environment,
			 * except for SHELL (as per POSIX standard).
			 */
			esetenv(v->name, val);
		}
		if (DEBUG(VAR))
			printf("command:%s = %s\n", v->name, var_get_value(v));
	} else if ((v->flags & VAR_FROM_CMD) == 0 &&
	     (!checkEnvFirst || (v->flags & VAR_FROM_ENV) == 0)) {
		(append ? var_append_value : var_set_value)(v, val);
		if (DEBUG(VAR))
			printf("global:%s = %s\n", v->name, var_get_value(v));
	} else if (DEBUG(VAR))
		printf("overridden:%s = %s\n", v->name, var_get_value(v));
}
Пример #12
0
/*-
 *-----------------------------------------------------------------------
 * Cond_End --
 *	Make sure everything's clean at the end of a makefile.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	Parse_Error will be called if open conditionals are around.
 *
 *-----------------------------------------------------------------------
 */
void
Cond_restore_depth(unsigned int saved_depth)
{
    int open_conds = cond_depth - cond_min_depth;

    if (open_conds != 0 || saved_depth > cond_depth) {
	Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds,
		    open_conds == 1 ? "" : "s");
	cond_depth = cond_min_depth;
    }

    cond_min_depth = saved_depth;
}
Пример #13
0
      ComponentPackageDescription * CPD_Handler::resolve_cpd (
        const ACE_TCHAR *uri)
      {
        DANCE_TRACE ("CPD_Handler::resolve_cpd");
        if (!XML::XML_Typedef::XML_HELPER.is_initialized ())
          return 0;

        xercesc::DOMDocument* dom =
          XML::XML_Typedef::XML_HELPER.create_dom (uri);

        if (!dom)
          throw Parse_Error ( ACE_TEXT (
            "Unable to create DOM for component package description"));

        try {
          return new ComponentPackageDescription (reader::componentPackageDescription (dom));
        }
        catch (...) {
          throw Parse_Error (ACE_TEXT (
            "Unable to create XSC structure for CID"));
        }
      }
Пример #14
0
/*-
 *---------------------------------------------------------------------
 * ParseDoOp  --
 *	Apply the parsed operator to the given target node. Used in a
 *	Array_Find call by ParseDoDependency once all targets have
 *	been found and their operator parsed. If the previous and new
 *	operators are incompatible, a major error is taken.
 *
 * Side Effects:
 *	The type field of the node is altered to reflect any new bits in
 *	the op.
 *---------------------------------------------------------------------
 */
static int
ParseDoOp(GNode **gnp, unsigned int op)
{
	GNode *gn = *gnp;
	/*
	 * If the dependency mask of the operator and the node don't match and
	 * the node has actually had an operator applied to it before, and the
	 * operator actually has some dependency information in it, complain.
	 */
	if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
	    !OP_NOP(gn->type) && !OP_NOP(op)) {
		Parse_Error(PARSE_FATAL, 
		    "Inconsistent dependency operator for target %s\n"
		    "\t(was %s%s, now %s%s)",
		    gn->name, gn->name, operator_string(gn->type), 
		    gn->name, operator_string(op));
		return 0;
	}

	if (op == OP_DOUBLEDEP && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
		/* If the node was the object of a :: operator, we need to
		 * create a new instance of it for the children and commands on
		 * this dependency line. The new instance is placed on the
		 * 'cohorts' list of the initial one (note the initial one is
		 * not on its own cohorts list) and the new instance is linked
		 * to all parents of the initial instance.  */
		GNode *cohort;
		LstNode ln;

		cohort = Targ_NewGN(gn->name);
		/* Duplicate links to parents so graph traversal is simple.
		 * Perhaps some type bits should be duplicated?
		 *
		 * Make the cohort invisible as well to avoid duplicating it
		 * into other variables. True, parents of this target won't
		 * tend to do anything with their local variables, but better
		 * safe than sorry.  */
		for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Adv(ln))
			ParseLinkSrc((GNode *)Lst_Datum(ln), cohort);
		cohort->type = OP_DOUBLEDEP|OP_INVISIBLE;
		Lst_AtEnd(&gn->cohorts, cohort);

		/* Replace the node in the targets list with the new copy */
		*gnp = cohort;
		gn = cohort;
	}
	/* We don't want to nuke any previous flags (whatever they were) so we
	 * just OR the new operator into the old.  */
	gn->type |= op;
	return 1;
}
Пример #15
0
Файл: var.c Проект: aharri/base
/* Figure out what kind of name we're looking for from a start character.
 */
static find_t
find_pos(int c)
{
	switch(c) {
	case '(':
		return find_rparen;
	case '{':
		return find_ket;
	default:
		Parse_Error(PARSE_FATAL,
		    "Wrong character in variable spec %c (can't happen)");
		return find_rparen;
	}
}
Пример #16
0
void
Cond_End(void)
{
	int i;

	if (condTop != MAXIF) {
		Parse_Error(PARSE_FATAL, "%s%d open conditional%s",
		    condTop == 0 ? "at least ": "", MAXIF-condTop,
		    MAXIF-condTop == 1 ? "" : "s");
		for (i = MAXIF-1; i >= condTop; i--) {
			fprintf(stderr, "\t at line %lu of %s\n", 
			    condStack[i].lineno, condStack[i].filename);
		}
	}
	condTop = MAXIF;
}
Пример #17
0
/*-
 *-----------------------------------------------------------------------
 * CondGetArg --
 *	Find the argument of a built-in function.
 *
 * Results:
 *	true if evaluation went okay
 *
 * Side Effects:
 *	The line pointer is set to point to the closing parenthesis of the
 *	function call. The argument is filled.
 *-----------------------------------------------------------------------
 */
static bool
CondGetArg(const char **linePtr, struct Name *arg, const char *func,
    bool parens) /* true if arg should be bounded by parens */
{
	const char *cp;

	cp = *linePtr;
	/* Set things up to return faster in case of problem */
	arg->s = cp;
	arg->e = cp;
	arg->tofree = false;

	/* make and defined are not really keywords, so if CondGetArg doesn't
	 * work...
	 */
	if (parens) {
		while (isspace(*cp))
			cp++;
		if (*cp == '(')
			cp++;
		else
			return false;
	}

	if (*cp == '\0')
		return false;

	while (isspace(*cp))
		cp++;

	cp = VarName_Get(cp, arg, NULL, true, find_cond);

	while (isspace(*cp))
		cp++;
	if (parens) {
		if (*cp == ')')
			cp++;
		else {
			Parse_Error(PARSE_WARNING,
			    "Missing closing parenthesis for %s()", func);
			return false;
	    	}
	}

	*linePtr = cp;
	return true;
}
Пример #18
0
void
Cond_End(void)
{
	int i;

	if (condTop != MAXIF) {
		Parse_Error(PARSE_FATAL, "%s%d open conditional%s",
		    condTop == 0 ? "at least ": "", MAXIF-condTop,
		    MAXIF-condTop == 1 ? "" : "s");
		for (i = MAXIF-1; i >= condTop; i--) {
			fprintf(stderr, "\t(%s:%lu)\n", 
			    condStack[i].origin.fname, 
			    condStack[i].origin.lineno);
		}
	}
	condTop = MAXIF;
}
Пример #19
0
/*-
 *-----------------------------------------------------------------------
 * CondGetArg --
 *	Find the argument of a built-in function.
 *
 * Results:
 *	true if evaluation went okay
 *
 * Side Effects:
 *	The line pointer is set to point to the closing parenthesis of the
 *	function call. The argument is filled.
 *-----------------------------------------------------------------------
 */
static bool
CondGetArg(const char **linePtr, struct Name *arg, const char *func,
    bool parens) /* true if arg should be bounded by parens */
{
	const char *cp;

	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...  */
		arg->s = cp;
		arg->e = cp;
		arg->tofree = false;
		return false;
	}

	while (*cp == ' ' || *cp == '\t')
		cp++;


	cp = VarName_Get(cp, arg, NULL, true, find_cond);

	while (*cp == ' ' || *cp == '\t')
		cp++;
	if (parens && *cp != ')') {
		Parse_Error(PARSE_WARNING, 
		    "Missing closing parenthesis for %s()", func);
	    return false;
	} else if (parens)
		/* Advance pointer past close parenthesis.  */
		cp++;

	*linePtr = cp;
	return true;
}
Пример #20
0
Файл: var.c Проект: aharri/base
/* XXX different semantics for Var_Valuei() and Var_Definedi():
 * references to poisoned value variables will error out in Var_Valuei(),
 * but not in Var_Definedi(), so the following construct works:
 *	.poison BINDIR
 *	BINDIR ?= /usr/bin
 */
char *
Var_Valuei(const char *name, const char *ename)
{
	Var *v;
	uint32_t k;
	int idx;

	idx = classify_var(name, &ename, &k);
	if (idx != GLOBAL_INDEX) {
		Parse_Error(PARSE_FATAL,
		    "Trying to get value of dynamic variable $%s",
			varnames[idx]);
		return NULL;
	}
	v = find_global_var(name, ename, k);
	if (v->flags & POISONS)
		poison_check(v);
	if ((v->flags & VAR_DUMMY) == 0)
		return var_get_value(v);
	else
		return NULL;
}
Пример #21
0
/*-
 *-----------------------------------------------------------------------
 * Cond_Eval --
 *	Evaluate the conditional in the passed line. The line
 *	looks like this:
 *	    .<cond-type> <expr>
 *	where <cond-type> is any of if, ifmake, ifnmake, ifdef,
 *	ifndef, elif, elifmake, elifnmake, elifdef, elifndef
 *	and <expr> consists of &&, ||, !, make(target), defined(variable)
 *	and parenthetical groupings thereof.
 *
 * Input:
 *	line		Line to parse
 *
 * Results:
 *	COND_PARSE	if should parse lines after the conditional
 *	COND_SKIP	if should skip lines after the conditional
 *	COND_INVALID  	if not a valid conditional.
 *
 * Side Effects:
 *	None.
 *
 * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
 * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF)
 * otherwise .else could be treated as '.elif 1'.
 *
 *-----------------------------------------------------------------------
 */
int
Cond_Eval(char *line)
{
    #define	    MAXIF	64	/* maximum depth of .if'ing */
    enum if_states {
	IF_ACTIVE,		/* .if or .elif part active */
	ELSE_ACTIVE,		/* .else part active */
	SEARCH_FOR_ELIF,	/* searching for .elif/else to execute */
	SKIP_TO_ELSE,           /* has been true, but not seen '.else' */
	SKIP_TO_ENDIF		/* nothing else to execute */
    };
    static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE };

    const struct If *ifp;
    Boolean 	    isElif;
    Boolean 	    value;
    int	    	    level;  	/* Level at which to report errors. */
    enum if_states  state;

    level = PARSE_FATAL;

    /* skip leading character (the '.') and any whitespace */
    for (line++; *line == ' ' || *line == '\t'; line++)
	continue;

    /* Find what type of if we're dealing with.  */
    if (line[0] == 'e') {
	if (line[1] != 'l') {
	    if (!istoken(line + 1, "ndif", 4))
		return COND_INVALID;
	    /* End of conditional section */
	    if (cond_depth == cond_min_depth) {
		Parse_Error(level, "if-less endif");
		return COND_PARSE;
	    }
	    /* Return state for previous conditional */
	    cond_depth--;
	    if (cond_depth > MAXIF)
		return COND_SKIP;
	    return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
	}

	/* Quite likely this is 'else' or 'elif' */
	line += 2;
	if (istoken(line, "se", 2)) {
	    /* It is else... */
	    if (cond_depth == cond_min_depth) {
		Parse_Error(level, "if-less else");
		return COND_PARSE;
	    }

	    if (cond_depth > MAXIF)
		return COND_SKIP;
	    state = cond_state[cond_depth];
	    switch (state) {
	    case SEARCH_FOR_ELIF:
		state = ELSE_ACTIVE;
		break;
	    case ELSE_ACTIVE:
	    case SKIP_TO_ENDIF:
		Parse_Error(PARSE_WARNING, "extra else");
		/* FALLTHROUGH */
	    default:
	    case IF_ACTIVE:
	    case SKIP_TO_ELSE:
		state = SKIP_TO_ENDIF;
		break;
	    }
	    cond_state[cond_depth] = state;
	    return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
	}
	/* Assume for now it is an elif */
	isElif = TRUE;
    } else
	isElif = FALSE;

    if (line[0] != 'i' || line[1] != 'f')
	/* Not an ifxxx or elifxxx line */
	return COND_INVALID;

    /*
     * Figure out what sort of conditional it is -- what its default
     * function is, etc. -- by looking in the table of valid "ifs"
     */
    line += 2;
    for (ifp = ifs; ; ifp++) {
	if (ifp->form == NULL)
	    return COND_INVALID;
	if (istoken(ifp->form, line, ifp->formlen)) {
	    line += ifp->formlen;
	    break;
	}
    }

    /* Now we know what sort of 'if' it is... */

    if (isElif) {
	if (cond_depth == cond_min_depth) {
	    Parse_Error(level, "if-less elif");
	    return COND_PARSE;
	}
	if (cond_depth > MAXIF)
	    /* Error reported when we saw the .if ... */
	    return COND_SKIP;
	state = cond_state[cond_depth];
	if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) {
	    Parse_Error(PARSE_WARNING, "extra elif");
	    cond_state[cond_depth] = SKIP_TO_ENDIF;
	    return COND_SKIP;
	}
	if (state != SEARCH_FOR_ELIF) {
	    /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
	    cond_state[cond_depth] = SKIP_TO_ELSE;
	    return COND_SKIP;
	}
    } else {
	/* Normal .if */
	if (cond_depth >= MAXIF) {
	    cond_depth++;
	    Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
	    return COND_SKIP;
	}
	state = cond_state[cond_depth];
	cond_depth++;
	if (state > ELSE_ACTIVE) {
	    /* If we aren't parsing the data, treat as always false */
	    cond_state[cond_depth] = SKIP_TO_ELSE;
	    return COND_SKIP;
	}
    }

    /* And evaluate the conditional expresssion */
    if (Cond_EvalExpression(ifp, line, &value, 1) == COND_INVALID) {
	/* Syntax error in conditional, error message already output. */
	/* Skip everything to matching .endif */
	cond_state[cond_depth] = SKIP_TO_ELSE;
	return COND_SKIP;
    }

    if (!value) {
	cond_state[cond_depth] = SEARCH_FOR_ELIF;
	return COND_SKIP;
    }
    cond_state[cond_depth] = IF_ACTIVE;
    return COND_PARSE;
}
Пример #22
0
/*-
 *-----------------------------------------------------------------------
 * CondGetArg --
 *	Find the argument of a built-in function.
 *
 * Input:
 *	parens		TRUE if arg should be bounded by parens
 *
 * 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(char **linePtr, char **argPtr, const char *func)
{
    char	  *cp;
    int	    	  argLen;
    Buffer	  buf;
    int           paren_depth;
    char          ch;

    cp = *linePtr;
    if (func != NULL)
	/* Skip opening '(' - verfied by caller */
	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 = NULL;
	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_Init(&buf, 16);

    paren_depth = 0;
    for (;;) {
	ch = *cp;
	if (ch == 0 || ch == ' ' || ch == '\t')
	    break;
	if ((ch == '&' || ch == '|') && paren_depth == 0)
	    break;
	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;
	    void	*freeIt;

	    cp2 = Var_Parse(cp, VAR_CMD, VARF_UNDEFERR|VARF_WANTRES,
			    &len, &freeIt);
	    Buf_AddBytes(&buf, strlen(cp2), cp2);
	    free(freeIt);
	    cp += len;
	    continue;
	}
	if (ch == '(')
	    paren_depth++;
	else
	    if (ch == ')' && --paren_depth < 0)
		break;
	Buf_AddByte(&buf, *cp);
	cp++;
    }

    *argPtr = Buf_GetAll(&buf, &argLen);
    Buf_Destroy(&buf, FALSE);

    while (*cp == ' ' || *cp == '\t') {
	cp++;
    }

    if (func != NULL && *cp++ != ')') {
	Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()",
		     func);
	return (0);
    }

    *linePtr = cp;
    return (argLen);
}
Пример #23
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 TOK_NONE if it is used.
 *
 *-----------------------------------------------------------------------
 */
static Token
compare_expression(Boolean doEval)
{
    Token	t;
    char	*lhs;
    char	*rhs;
    char	*op;
    void	*lhsFree;
    void	*rhsFree;
    Boolean lhsQuoted;
    Boolean rhsQuoted;
    double  	left, right;

    t = TOK_ERROR;
    rhs = NULL;
    lhsFree = rhsFree = FALSE;
    lhsQuoted = rhsQuoted = FALSE;
    
    /*
     * Parse the variable spec and skip over it, saving its
     * value in lhs.
     */
    lhs = CondGetString(doEval, &lhsQuoted, &lhsFree, lhsStrict);
    if (!lhs)
	goto done;

    /*
     * Skip whitespace to get to the operator
     */
    while (isspace((unsigned char) *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:
	    if (!doEval) {
		t = TOK_FALSE;
		goto done;
	    }
	    /* For .ifxxx "..." check for non-empty string. */
	    if (lhsQuoted) {
		t = lhs[0] != 0;
		goto done;
	    }
	    /* For .ifxxx <number> compare against zero */
	    if (CondCvtArg(lhs, &left)) { 
		t = left != 0.0;
		goto done;
	    }
	    /* For .if ${...} check for non-empty string (defProc is ifdef). */
	    if (if_info->form[0] == 0) {
		t = lhs[0] != 0;
		goto done;
	    }
	    /* Otherwise action default test ... */
	    t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot;
	    goto done;
    }

    while (isspace((unsigned char)*condExpr))
	condExpr++;

    if (*condExpr == '\0') {
	Parse_Error(PARSE_WARNING,
		    "Missing right-hand-side of operator");
	goto done;
    }

    rhs = CondGetString(doEval, &rhsQuoted, &rhsFree, FALSE);
    if (!rhs)
	goto done;

    if (rhsQuoted || lhsQuoted) {
do_string_compare:
	if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
	    Parse_Error(PARSE_WARNING,
    "String comparison operator should be either == or !=");
	    goto done;
	}

	if (DEBUG(COND)) {
	    fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
		   lhs, rhs, op);
	}
	/*
	 * Null-terminate rhs and perform the comparison.
	 * t is set to the result.
	 */
	if (*op == '=') {
	    t = strcmp(lhs, rhs) == 0;
	} else {
	    t = strcmp(lhs, rhs) != 0;
	}
    } else {
	/*
	 * rhs is either a float or an integer. Convert both the
	 * lhs and the rhs to a double and compare the two.
	 */
    
	if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right))
	    goto do_string_compare;

	if (DEBUG(COND)) {
	    fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left,
		   right, op);
	}
	switch(op[0]) {
	case '!':
	    if (op[1] != '=') {
		Parse_Error(PARSE_WARNING,
			    "Unknown operator");
		goto done;
	    }
	    t = (left != right);
	    break;
	case '=':
	    if (op[1] != '=') {
		Parse_Error(PARSE_WARNING,
			    "Unknown operator");
		goto done;
	    }
	    t = (left == right);
	    break;
	case '<':
	    if (op[1] == '=') {
		t = (left <= right);
	    } else {
		t = (left < right);
	    }
	    break;
	case '>':
	    if (op[1] == '=') {
		t = (left >= right);
	    } else {
		t = (left > right);
	    }
	    break;
	}
    }

done:
    free(lhsFree);
    free(rhsFree);
    return t;
}
Пример #24
0
/**
 * Parse a shell specification and set up commandShell appropriately.
 *
 * Results:
 *	TRUE if the specification was correct. FALSE otherwise.
 *
 * Side Effects:
 *	commandShell points to a Shell structure.
 *	created from the shell spec).
 *
 * Notes:
 *	A shell specification consists of a .SHELL target, with dependency
 *	operator, followed by a series of blank-separated words. Double
 *	quotes can be used to use blanks in words. A backslash escapes
 *	anything (most notably a double-quote and a space) and
 *	provides the functionality it does in C. Each word consists of
 *	keyword and value separated by an equal sign. There should be no
 *	unnecessary spaces in the word. The keywords are as follows:
 *	    name	    Name of shell.
 *	    path	    Location of shell. Overrides "name" if given
 *	    quiet	    Command to turn off echoing.
 *	    echo	    Command to turn echoing on
 *	    filter	    Result of turning off echoing that shouldn't be
 *			    printed.
 *	    echoFlag	    Flag to turn echoing on at the start
 *	    errFlag	    Flag to turn error checking on at the start
 *	    hasErrCtl	    True if shell has error checking control
 *	    check	    Command to turn on error checking if hasErrCtl
 *			    is TRUE or template of command to echo a command
 *			    for which error checking is off if hasErrCtl is
 *			    FALSE.
 *	    ignore	    Command to turn off error checking if hasErrCtl
 *			    is TRUE or template of command to execute a
 *			    command so as to ignore any errors it returns if
 *			    hasErrCtl is FALSE.
 *	    builtins	    A space separated list of builtins. If one
 *			    of these builtins is detected when make wants
 *			    to execute a command line, the command line is
 *			    handed to the shell. Otherwise make may try to
 *			    execute the command directly. If this list is empty
 *			    it is assumed, that the command must always be
 *			    handed over to the shell.
 *	    meta	    The shell meta characters. If this is not specified
 *			    or empty, commands are alway passed to the shell.
 *			    Otherwise they are not passed when they contain
 *			    neither a meta character nor a builtin command.
 *	    unsetenv	    Unsetenv("ENV") before executing anything.
 */
Boolean
Shell_Parse(const char line[])
{
	Boolean		fullSpec;
	struct Shell	*sh;
	struct Shell	*match;

	/* parse the specification */
	if ((sh = ShellParseSpec(line, &fullSpec)) == NULL)
		return (FALSE);

	if (sh->path == NULL) {
		/*
		 * If no path was given, the user wants one of the pre-defined
		 * shells, yes? So we find the one s/he wants with the help of
		 * JobMatchShell and set things up the right way.
		 */
		if (sh->name == NULL) {
			Parse_Error(PARSE_FATAL,
			    "Neither path nor name specified");
			ShellFree(sh);
			return (FALSE);
		}
		if (fullSpec) {
			/*
			 * XXX May want to merge sh into match. But this
			 * require ShellParseSpec to return information
			 * which attributes actuall have been specified.
			 */
			Parse_Error(PARSE_FATAL, "No path specified");
			ShellFree(sh);
			return (FALSE);
		}
		if ((match = ShellMatch(sh->name)) == NULL) {
			Parse_Error(PARSE_FATAL, "%s: no matching shell",
			    sh->name);
			ShellFree(sh);
			return (FALSE);
		}
		ShellFree(sh);
		commandShell = match;

		return (TRUE);
	}

	/*
	 * The user provided a path. If s/he gave nothing else
	 * (fullSpec is FALSE), try and find a matching shell in the
	 * ones we know of. Else we just take the specification at its
	 * word and copy it to a new location. In either case, we need
	 * to record the path the user gave for the shell.
	 */
	if (sh->name == NULL) {
		/* get the base name as the name */
		if ((sh->name = strrchr(sh->path, '/')) == NULL) {
			sh->name = estrdup(sh->path);
		} else {
			sh->name = estrdup(sh->name + 1);
		}
	}

	if (!fullSpec) {
		if ((match = ShellMatch(sh->name)) == NULL) {
			Parse_Error(PARSE_FATAL,
			    "%s: no matching shell", sh->name);
			ShellFree(sh);
			return (FALSE);
		}

		/* set the patch on the matching shell */
		free(match->path);
		match->path = sh->path;
		sh->path = NULL;

		ShellFree(sh);
		commandShell = match;
		return (TRUE);
	}

	TAILQ_INSERT_HEAD(&shells, sh, link);

	/* set the new shell */
	commandShell = sh;
	return (TRUE);
}
Пример #25
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;
}
Пример #26
0
/**
 * Given the line following a .SHELL target, parse it as a shell
 * specification.
 *
 * Results:
 *	A pointer to a Shell structure, or NULL if no the spec was invalid.
 */
Shell *
Shell_Parse(const char line[])
{
	bool	fullSpec;
	Shell	*sh;

	/* parse the specification */
	if ((sh = ShellParseSpec(line, &fullSpec)) == NULL)
		return (NULL);

	if (sh->path == NULL) {
		Shell	*match;
		/*
		 * If no path was given, the user wants one of the pre-defined
		 * shells, yes? So we find the one s/he wants with the help of
		 * ShellMatch and set things up the right way.
		 */
		if (sh->name == NULL) {
			Parse_Error(PARSE_FATAL,
			    "Neither path nor name specified");
			Shell_Destroy(sh);
			return (NULL);
		}
		if (fullSpec) {
			Parse_Error(PARSE_FATAL, "No path specified");
			Shell_Destroy(sh);
			return (NULL);
		}
		if ((match = Shell_Match(sh->name)) == NULL) {
			Parse_Error(PARSE_FATAL, "%s: no matching shell",
			    sh->name);
			Shell_Destroy(sh);
			return (NULL);
		}

		Shell_Destroy(sh);
		return (match);

	} else {
		Shell	*match;

		/*
		 * The user provided a path. If s/he gave nothing else
		 * (fullSpec is false), try and find a matching shell in the
		 * ones we know of. Else we just take the specification at its
		 * word and copy it to a new location. In either case, we need
		 * to record the path the user gave for the shell.
		 */
		if (sh->name == NULL) {
			/* get the base name as the name */
			if ((sh->name = strrchr(sh->path, '/')) == NULL) {
				sh->name = estrdup(sh->path);
			} else {
				sh->name = estrdup(sh->name + 1);
			}
		}
		if (fullSpec) {
			return (sh);
		}
		if ((match = Shell_Match(sh->name)) == NULL) {
			Parse_Error(PARSE_FATAL,
			    "%s: no matching shell", sh->name);
			Shell_Destroy(sh);
			return (NULL);
		}

		free(match->path);
		match->path = sh->path;
		sh->path = NULL;

		Shell_Destroy(sh);
		return (match);
	}
}
Пример #27
0
static Token
CondHandleComparison(char *lhs, bool doFree, bool doEval)
{
	Token t;
	const char *rhs;
	const char *op;

	t = Err;
	/* 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;
		const char *cp;
		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_Init(&buf, 0);
		qt = *rhs == '"' ? 1 : 0;

		for (cp = &rhs[qt]; ((qt && *cp != '"') ||
		    (!qt && strchr(" \t)", *cp) == NULL)) && *cp != '\0';) {
			if (*cp == '$') {
				size_t len;

				if (Var_ParseBuffer(&buf, cp, NULL, doEval,
				    &len)) {
					cp += len;
					continue;
				}
			} else if (*cp == '\\' && cp[1] != '\0')
				/* Backslash escapes things -- skip over next
				 * character, if it exists.  */
				cp++;
			Buf_AddChar(&buf, *cp++);
		}

		string = Buf_Retrieve(&buf);

		if (DEBUG(COND))
			printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
			    lhs, string, op);
		/* Null-terminate rhs and perform the comparison.
		 * t is set to the result.  */
		if (*op == '=')
			t = strcmp(lhs, string) ? False : True;
		else
			t = strcmp(lhs, string) ? True : False;
		free(string);
		if (rhs == condExpr) {
			if (!qt && *cp == ')')
				condExpr = cp;
			else if (*cp == '\0')
				condExpr = cp;
			else
				condExpr = cp + 1;
		}
	} else {
		/* rhs is either a float or an integer. Convert both the
		 * lhs and the rhs to a double and compare the two.  */
		double left, right;
		char *string;

		if (!CondCvtArg(lhs, &left))
			goto do_string_compare;
		if (*rhs == '$') {
			size_t len;
			bool freeIt;

			string = Var_Parse(rhs, NULL, doEval,&len,&freeIt);
			if (string == var_Error)
				right = 0.0;
			else {
				if (!CondCvtArg(string, &right)) {
					if (freeIt)
						free(string);
					goto do_string_compare;
				}
				if (freeIt)
					free(string);
				if (rhs == condExpr)
					condExpr += len;
			}
		} else {
			if (!CondCvtArg(rhs, &right))
				goto do_string_compare;
			if (rhs == condExpr) {
				/* Skip over the right-hand side.  */
				while (!isspace(*condExpr) && *condExpr != '\0')
					condExpr++;
			}
		}

		if (DEBUG(COND))
			printf("left = %f, right = %f, op = %.2s\n", left,
			    right, op);
		switch (op[0]) {
		case '!':
			if (op[1] != '=') {
				Parse_Error(PARSE_WARNING, "Unknown operator");
				goto error;
			}
			t = left != right ? True : False;
			break;
		case '=':
			if (op[1] != '=') {
				Parse_Error(PARSE_WARNING, "Unknown operator");
				goto error;
			}
			t = left == right ? True : False;
			break;
		case '<':
			if (op[1] == '=')
				t = left <= right ? True : False;
			else
				t = left < right ? True : False;
			break;
		case '>':
			if (op[1] == '=')
				t = left >= right ? True : False;
			else
				t = left > right ? True : False;
			break;
		}
	}
error:
	if (doFree)
		free(lhs);
	return t;
}
Пример #28
0
/* Evaluate conditional in line.
 * returns COND_SKIP, COND_PARSE, COND_INVALID, COND_ISFOR, COND_ISINCLUDE,
 * COND_ISUNDEF.
 * A conditional line looks like this:
 *	<cond-type> <expr>
 *	where <cond-type> is any of if, ifmake, ifnmake, ifdef,
 *	ifndef, elif, elifmake, elifnmake, elifdef, elifndef
 *	and <expr> consists of &&, ||, !, make(target), defined(variable)
 *	and parenthetical groupings thereof.
 */
int
Cond_Eval(const char *line)
{
	/* find end of keyword */
	const char *end;
	uint32_t k;
	size_t len;
	struct If *ifp;
	bool value = false;
	int level;	/* Level at which to report errors. */

	level = PARSE_FATAL;

	for (end = line; islower(*end); end++)
		;
	/* quick path: recognize special targets early on */
	if (*end == '.' || *end == ':')
		return COND_INVALID;
	len = end - line;
	k = ohash_interval(line, &end);
	switch(k % MAGICSLOTS2) {
	case K_COND_IF % MAGICSLOTS2:
		if (k == K_COND_IF && len == strlen(COND_IF) &&
		    strncmp(line, COND_IF, len) == 0) {
			ifp = ifs + COND_IF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_IFDEF % MAGICSLOTS2:
		if (k == K_COND_IFDEF && len == strlen(COND_IFDEF) &&
		    strncmp(line, COND_IFDEF, len) == 0) {
			ifp = ifs + COND_IFDEF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_IFNDEF % MAGICSLOTS2:
		if (k == K_COND_IFNDEF && len == strlen(COND_IFNDEF) &&
		    strncmp(line, COND_IFNDEF, len) == 0) {
			ifp = ifs + COND_IFNDEF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_IFMAKE % MAGICSLOTS2:
		if (k == K_COND_IFMAKE && len == strlen(COND_IFMAKE) &&
		    strncmp(line, COND_IFMAKE, len) == 0) {
			ifp = ifs + COND_IFMAKE_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_IFNMAKE % MAGICSLOTS2:
		if (k == K_COND_IFNMAKE && len == strlen(COND_IFNMAKE) &&
		    strncmp(line, COND_IFNMAKE, len) == 0) {
			ifp = ifs + COND_IFNMAKE_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELIF % MAGICSLOTS2:
		if (k == K_COND_ELIF && len == strlen(COND_ELIF) &&
		    strncmp(line, COND_ELIF, len) == 0) {
			ifp = ifs + COND_ELIF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELIFDEF % MAGICSLOTS2:
		if (k == K_COND_ELIFDEF && len == strlen(COND_ELIFDEF) &&
		    strncmp(line, COND_ELIFDEF, len) == 0) {
			ifp = ifs + COND_ELIFDEF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELIFNDEF % MAGICSLOTS2:
		if (k == K_COND_ELIFNDEF && len == strlen(COND_ELIFNDEF) &&
		    strncmp(line, COND_ELIFNDEF, len) == 0) {
			ifp = ifs + COND_ELIFNDEF_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELIFMAKE % MAGICSLOTS2:
		if (k == K_COND_ELIFMAKE && len == strlen(COND_ELIFMAKE) &&
		    strncmp(line, COND_ELIFMAKE, len) == 0) {
			ifp = ifs + COND_ELIFMAKE_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELIFNMAKE % MAGICSLOTS2:
		if (k == K_COND_ELIFNMAKE && len == strlen(COND_ELIFNMAKE) &&
		    strncmp(line, COND_ELIFNMAKE, len) == 0) {
			ifp = ifs + COND_ELIFNMAKE_INDEX;
		} else
			return COND_INVALID;
		break;
	case K_COND_ELSE % MAGICSLOTS2:
		/* valid conditional whose value is the inverse
		 * of the previous if we parsed.  */
		if (k == K_COND_ELSE && len == strlen(COND_ELSE) &&
		    strncmp(line, COND_ELSE, len) == 0) {
			if (condTop == MAXIF) {
				Parse_Error(level, "if-less else");
				return COND_INVALID;
			} else if (skipIfLevel == 0) {
				value = !condStack[condTop].value;
				ifp = ifs + COND_ELSE_INDEX;
			} else
				return COND_SKIP;
		} else
			return COND_INVALID;
		break;
	case K_COND_ENDIF % MAGICSLOTS2:
		if (k == K_COND_ENDIF && len == strlen(COND_ENDIF) &&
		    strncmp(line, COND_ENDIF, len) == 0) {
			/* End of a conditional section. If skipIfLevel is
			 * non-zero, that conditional was skipped, so lines
			 * following it should also be skipped. Hence, we
			 * return COND_SKIP. Otherwise, the conditional was
			 * read so succeeding lines should be parsed (think
			 * about it...) so we return COND_PARSE, unless this
			 * endif isn't paired with a decent if.  */
			if (skipIfLevel != 0) {
				skipIfLevel--;
				return COND_SKIP;
			} else {
				if (condTop == MAXIF) {
					Parse_Error(level, "if-less endif");
					return COND_INVALID;
				} else {
					skipLine = false;
					condTop++;
					return COND_PARSE;
				}
			}
		} else
			return COND_INVALID;
		break;

	/* Recognize other keywords there, to simplify parser's task */
	case K_COND_FOR % MAGICSLOTS2:
		if (k == K_COND_FOR && len == strlen(COND_FOR) &&
		    strncmp(line, COND_FOR, len) == 0)
			return COND_ISFOR;
		else
			return COND_INVALID;
	case K_COND_UNDEF % MAGICSLOTS2:
		if (k == K_COND_UNDEF && len == strlen(COND_UNDEF) &&
		    strncmp(line, COND_UNDEF, len) == 0)
			return COND_ISUNDEF;
		else
			return COND_INVALID;
	case K_COND_POISON % MAGICSLOTS2:
		if (k == K_COND_POISON && len == strlen(COND_POISON) &&
		    strncmp(line, COND_POISON, len) == 0)
			return COND_ISPOISON;
		else
			return COND_INVALID;
	case K_COND_INCLUDE % MAGICSLOTS2:
		if (k == K_COND_INCLUDE && len == strlen(COND_INCLUDE) &&
		    strncmp(line, COND_INCLUDE, len) == 0)
			return COND_ISINCLUDE;
		else
			return COND_INVALID;
	default:
		/* Not a valid conditional type. No error...  */
		return COND_INVALID;
	}

	if (ifp->isElse) {
		if (condTop == MAXIF) {
			Parse_Error(level, "if-less elif");
			return COND_INVALID;
		} else if (skipIfLevel != 0 || condStack[condTop].value) {
			/*
			 * Skip if we're meant to or is an else-type
			 * conditional and previous corresponding one was
			 * evaluated to true.
			 */
			skipLine = true;
			return COND_SKIP;
		}
	} else if (skipLine) {
		/* Don't even try to evaluate a conditional that's not an else
		 * if we're skipping things...  */
		skipIfLevel++;
		return COND_SKIP;
	} else
		condTop--;

	if (condTop < 0) {
		/* This is the one case where we can definitely proclaim a fatal
		 * error. If we don't, we're hosed.  */
		Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.",
		    MAXIF);
		condTop = 0;
		return COND_INVALID;
	}

	if (ifp->defProc) {
		/* Initialize file-global variables for parsing.  */
		condDefProc = ifp->defProc;
		condInvert = ifp->doNot;

		line += len;

		while (*line == ' ' || *line == '\t')
			line++;

		condExpr = line;
		condPushBack = None;

		switch (CondE(true)) {
		case True:
			if (CondToken(true) == EndOfFile) {
				value = true;
				break;
			}
			goto err;
			/* FALLTHROUGH */
		case False:
			if (CondToken(true) == EndOfFile) {
				value = false;
				break;
			}
			/* FALLTHROUGH */
		case Err:
err:
			Parse_Error(level, "Malformed conditional (%s)", line);
			return COND_INVALID;
		default:
			break;
		}
	}

	condStack[condTop].value = value;
	Parse_FillLocation(&condStack[condTop].origin);
	skipLine = !value;
	return value ? COND_PARSE : COND_SKIP;
}
Пример #29
0
Файл: var.c Проект: aharri/base
char *
Var_Subst(const char *str,	/* the string in which to substitute */
    SymTable *ctxt,		/* the context wherein to find variables */
    bool undefErr)		/* true if undefineds are an error */
{
	BUFFER buf;		/* Buffer for forming things */
	static bool errorReported;

	Buf_Init(&buf, MAKE_BSIZE);
	errorReported = false;

	for (;;) {
		char *val;	/* Value to substitute for a variable */
		size_t length;	/* Length of the variable invocation */
		bool doFree;	/* Set true if val should be freed */
		const char *cp;

		/* copy uninteresting stuff */
		for (cp = str; *str != '\0' && *str != '$'; str++)
			;
		Buf_Addi(&buf, cp, str);
		if (*str == '\0')
			break;
		if (str[1] == '$') {
			/* A $ may be escaped with another $. */
			Buf_AddChar(&buf, '$');
			str += 2;
			continue;
		}
		val = Var_Parse(str, ctxt, undefErr, &length, &doFree);
		/* When we come down here, val should either point to the
		 * value of this variable, suitably modified, or be NULL.
		 * Length should be the total length of the potential
		 * variable invocation (from $ to end character...) */
		if (val == var_Error || val == varNoError) {
			/* If errors are not an issue, skip over the variable
			 * and continue with the substitution. Otherwise, store
			 * the dollar sign and advance str so we continue with
			 * the string...  */
			if (errorIsOkay)
				str += length;
			else if (undefErr) {
				/* If variable is undefined, complain and
				 * skip the variable name. The complaint
				 * will stop us from doing anything when
				 * the file is parsed.  */
				if (!errorReported)
					Parse_Error(PARSE_FATAL,
					     "Undefined variable \"%.*s\"",
					     length, str);
				str += length;
				errorReported = true;
			} else {
				Buf_AddChar(&buf, *str);
				str++;
			}
		} else {
			/* We've now got a variable structure to store in.
			 * But first, advance the string pointer.  */
			str += length;

			/* Copy all the characters from the variable value
			 * straight into the new string.  */
			Buf_AddString(&buf, val);
			if (doFree)
				free(val);
		}
	}
	return  Buf_Retrieve(&buf);
}
Пример #30
0
/**
 * Parse a shell specification line and return the new Shell structure.
 * In case of an error a message is printed and NULL is returned.
 *
 * Notes:
 *	A shell specification consists of a .SHELL target, with dependency
 *	operator, followed by a series of blank-separated words. Double
 *	quotes can be used to use blanks in words. A backslash escapes
 *	anything (most notably a double-quote and a space) and
 *	provides the functionality it does in C. Each word consists of
 *	keyword and value separated by an equal sign. There should be no
 *	unnecessary spaces in the word. The keywords are as follows:
 *	    name	    Name of shell.
 *	    path	    Location of shell. Overrides "name" if given
 *	    quiet	    Command to turn off echoing.
 *	    echo	    Command to turn echoing on
 *	    filter	    Result of turning off echoing that shouldn't be
 *			    printed.
 *	    echoFlag	    Flag to turn echoing on at the start
 *	    errFlag	    Flag to turn error checking on at the start
 *	    hasErrCtl	    True if shell has error checking control
 *	    check	    Command to turn on error checking if hasErrCtl
 *			    is true or template of command to echo a command
 *			    for which error checking is off if hasErrCtl is
 *			    false.
 *	    ignore	    Command to turn off error checking if hasErrCtl
 *			    is true or template of command to execute a
 *			    command so as to ignore any errors it returns if
 *			    hasErrCtl is false.
 *	    builtins	    A space separated list of builtins. If one
 *			    of these builtins is detected when make wants
 *			    to execute a command line, the command line is
 *			    handed to the shell. Otherwise make may try to
 *			    execute the command directly. If this list is empty
 *			    it is assumed, that the command must always be
 *			    handed over to the shell.
 *	    meta	    The shell meta characters. If this is not specified
 *			    or empty, commands are alway passed to the shell.
 *			    Otherwise they are not passed when they contain
 *			    neither a meta character nor a builtin command.
 */
static Shell *
ShellParseSpec(const char spec[], bool *fullSpec)
{
	ArgArray	aa;
	Shell		*sh;
	char		*eq;
	char		*keyw;
	int		arg;

	*fullSpec = false;

	sh = emalloc(sizeof(*sh));
	memset(sh, 0, sizeof(*sh));
	ArgArray_Init(&sh->builtins);

	/*
	 * Parse the specification by keyword but skip the first word
	 */
	brk_string(&aa, spec, true);

	for (arg = 1; arg < aa.argc; arg++) {
		/*
		 * Split keyword and value
		 */
		keyw = aa.argv[arg];
		if ((eq = strchr(keyw, '=')) == NULL) {
			Parse_Error(PARSE_FATAL, "missing '=' in shell "
			    "specification keyword '%s'", keyw);
			ArgArray_Done(&aa);
			Shell_Destroy(sh);
			return (NULL);
		}
		*eq++ = '\0';

		if (strcmp(keyw, "path") == 0) {
			free(sh->path);
			sh->path = estrdup(eq);
		} else if (strcmp(keyw, "name") == 0) {
			free(sh->name);
			sh->name = estrdup(eq);
		} else if (strcmp(keyw, "quiet") == 0) {
			free(sh->echoOff);
			sh->echoOff = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "echo") == 0) {
			free(sh->echoOn);
			sh->echoOn = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "filter") == 0) {
			free(sh->noPrint);
			sh->noPrint = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "echoFlag") == 0) {
			free(sh->echo);
			sh->echo = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "errFlag") == 0) {
			free(sh->exit);
			sh->exit = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "hasErrCtl") == 0) {
			sh->hasErrCtl = (
			    *eq == 'Y' || *eq == 'y' ||
			    *eq == 'T' || *eq == 't');
			*fullSpec = true;
		} else if (strcmp(keyw, "check") == 0) {
			free(sh->errCheck);
			sh->errCheck = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "ignore") == 0) {
			free(sh->ignErr);
			sh->ignErr = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "builtins") == 0) {
			ArgArray_Done(&sh->builtins);
			brk_string(&sh->builtins, eq, true);
			qsort(sh->builtins.argv + 1, sh->builtins.argc - 1,
			    sizeof(char *), sort_builtins);
			*fullSpec = true;
		} else if (strcmp(keyw, "meta") == 0) {
			free(sh->meta);
			sh->meta = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "unsetenv") == 0) {
			sh->unsetenv = (
			    *eq == 'Y' || *eq == 'y' ||
			    *eq == 'T' || *eq == 't');
			*fullSpec = true;
		} else {
			Parse_Error(PARSE_FATAL, "unknown keyword in shell "
			    "specification '%s'", keyw);
			ArgArray_Done(&aa);
			Shell_Destroy(sh);
			return (NULL);
		}
	}
	ArgArray_Done(&aa);

	/*
	 * Some checks (could be more)
	 */
	if (*fullSpec) {
		if ((sh->echoOn != NULL) ^ (sh->echoOff != NULL)) {
			Parse_Error(PARSE_FATAL, "Shell must have either both "
			    "echoOff and echoOn or none of them");
			Shell_Destroy(sh);
			return (NULL);
		}

		if (sh->echoOn != NULL && sh->echoOff != NULL)
			sh->hasEchoCtl = true;
	}

	return (sh);
}