Exemplo n.º 1
0
/*
 * Expand arithmetic expression.
 * Note that flag is not required as digits never require CTLESC characters.
 */
static char *
expari(char *p)
{
	char *q, *start;
	arith_t result;
	int begoff;
	int quoted;
	int adj;

	quoted = *p++ == '"';
	begoff = expdest - stackblock();
	p = argstr(p, 0);
	removerecordregions(begoff);
	STPUTC('\0', expdest);
	start = stackblock() + begoff;

	q = grabstackstr(expdest);
	result = arith(start);
	ungrabstackstr(q, expdest);

	start = stackblock() + begoff;
	adj = start - expdest;
	STADJUST(adj, expdest);

	CHECKSTRSPACE((int)(DIGITS(result) + 1), expdest);
	fmtstr(expdest, DIGITS(result), ARITH_FORMAT_STR, result);
	adj = strlen(expdest);
	STADJUST(adj, expdest);
	if (!quoted)
		recordregion(begoff, expdest - stackblock(), 0);
	return p;
}
Exemplo n.º 2
0
/*
 * Expand arithmetic expression.  Backup to start of expression,
 * evaluate, place result in (backed up) result, adjust string position.
 */
void
expari(shinstance *psh, int flag)
{
	char *p, *start;
	int result;
	int begoff;
	int quotes = flag & (EXP_FULL | EXP_CASE);
	int quoted;

	/*	ifsfree(); */

	/*
	 * This routine is slightly over-complicated for
	 * efficiency.  First we make sure there is
	 * enough space for the result, which may be bigger
	 * than the expression if we add exponentation.  Next we
	 * scan backwards looking for the start of arithmetic.  If the
	 * next previous character is a CTLESC character, then we
	 * have to rescan starting from the beginning since CTLESC
	 * characters have to be processed left to right.
	 */
#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10
#error "integers with more than 10 digits are not supported"
#endif
	CHECKSTRSPACE(psh, 12 - 2, psh->expdest);
	USTPUTC(psh, '\0', psh->expdest);
	start = stackblock(psh);
	p = psh->expdest - 1;
	while (*p != CTLARI && p >= start)
		--p;
	if (*p != CTLARI)
		error(psh, "missing CTLARI (shouldn't happen)");
	if (p > start && *(p-1) == CTLESC)
		for (p = start; *p != CTLARI; p++)
			if (*p == CTLESC)
				p++;

	if (p[1] == '"')
		quoted=1;
	else
		quoted=0;
	begoff = (int)(p - start);
	removerecordregions(psh, begoff);
	if (quotes)
		rmescapes(psh, p+2);
	result = arith(psh, p+2);
	fmtstr(p, 12, "%d", result);

	while (*p++)
		;

	if (quoted == 0)
		recordregion(psh, begoff, (int)(p - 1 - start), 0);
	result = (int)(psh->expdest - p + 1);
	STADJUST(psh, -result, psh->expdest);
}
Exemplo n.º 3
0
/*
 * Expand arithmetic expression.  Backup to start of expression,
 * evaluate, place result in (backed up) result, adjust string position.
 */
void
expari(int flag)
{
	char *p, *start;
	intmax_t result;
	int adjustment;
	int begoff;
	int quotes = flag & (EXP_FULL | EXP_CASE);
	int quoted;

	/*	ifsfree(); */

	/*
	 * This routine is slightly over-complicated for
	 * efficiency.  First we make sure there is
	 * enough space for the result, which may be bigger
	 * than the expression if we add exponentation.  Next we
	 * scan backwards looking for the start of arithmetic.  If the
	 * next previous character is a CTLESC character, then we
	 * have to rescan starting from the beginning since CTLESC
	 * characters have to be processed left to right.
	 */
/* SPACE_NEEDED is enough for all digits, plus possible "-", plus 2 (why?) */
#define SPACE_NEEDED ((sizeof(intmax_t) * CHAR_BIT + 2) / 3 + 1 + 2)
	CHECKSTRSPACE((int)(SPACE_NEEDED - 2), expdest);
	USTPUTC('\0', expdest);
	start = stackblock();
	p = expdest - 1;
	while (*p != CTLARI && p >= start)
		--p;
	if (*p != CTLARI)
		error("missing CTLARI (shouldn't happen)");
	if (p > start && *(p-1) == CTLESC)
		for (p = start; *p != CTLARI; p++)
			if (*p == CTLESC)
				p++;

	if (p[1] == '"')
		quoted=1;
	else
		quoted=0;
	begoff = p - start;
	removerecordregions(begoff);
	if (quotes)
		rmescapes(p+2);
	result = arith(p+2);
	fmtstr(p, SPACE_NEEDED, "%"PRIdMAX, result);

	while (*p++)
		;

	if (quoted == 0)
		recordregion(begoff, p - 1 - start, 0);
	adjustment = expdest - p + 1;
	STADJUST(-adjustment, expdest);
}
Exemplo n.º 4
0
/*
 * Expand arithmetic expression.  Backup to start of expression,
 * evaluate, place result in (backed up) result, adjust string position.
 */
void
expari(int flag)
{
	char *p, *q, *start;
	arith_t result;
	int begoff;
	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
	int quoted;

	/*
	 * This routine is slightly over-complicated for
	 * efficiency.  First we make sure there is
	 * enough space for the result, which may be bigger
	 * than the expression.  Next we
	 * scan backwards looking for the start of arithmetic.  If the
	 * next previous character is a CTLESC character, then we
	 * have to rescan starting from the beginning since CTLESC
	 * characters have to be processed left to right.
	 */
	CHECKSTRSPACE(DIGITS(result) - 2, expdest);
	USTPUTC('\0', expdest);
	start = stackblock();
	p = expdest - 2;
	while (p >= start && *p != CTLARI)
		--p;
	if (p < start || *p != CTLARI)
		error("missing CTLARI (shouldn't happen)");
	if (p > start && *(p - 1) == CTLESC)
		for (p = start; *p != CTLARI; p++)
			if (*p == CTLESC)
				p++;

	if (p[1] == '"')
		quoted=1;
	else
		quoted=0;
	begoff = p - start;
	removerecordregions(begoff);
	if (quotes)
		rmescapes(p+2);
	q = grabstackstr(expdest);
	result = arith(p+2);
	ungrabstackstr(q, expdest);
	fmtstr(p, DIGITS(result), ARITH_FORMAT_STR, result);
	while (*p++)
		;
	if (quoted == 0)
		recordregion(begoff, p - 1 - start, 0);
	result = expdest - p + 1;
	STADJUST(-result, expdest);
}
Exemplo n.º 5
0
/*
 * Expand arithmetic expression.
 * Note that flag is not required as digits never require CTLESC characters.
 */
static char *
expari(char *p)
{
    char *q, *start;
    arith_t result;
    int begoff;
    int quoted;
    int c;
    int nesting;
    int adj;

    quoted = *p++ == '"';
    begoff = expdest - stackblock();
    argstr(p, 0);
    removerecordregions(begoff);
    STPUTC('\0', expdest);
    start = stackblock() + begoff;

    q = grabstackstr(expdest);
    result = arith(start);
    ungrabstackstr(q, expdest);

    start = stackblock() + begoff;
    adj = start - expdest;
    STADJUST(adj, expdest);

    CHECKSTRSPACE((int)(DIGITS(result) + 1), expdest);
    fmtstr(expdest, DIGITS(result), ARITH_FORMAT_STR, result);
    adj = strlen(expdest);
    STADJUST(adj, expdest);
    if (!quoted)
        recordregion(begoff, expdest - stackblock(), 0);
    nesting = 1;
    while (nesting > 0) {
        c = *p++;
        if (c == CTLESC)
            p++;
        else if (c == CTLARI)
            nesting++;
        else if (c == CTLENDARI)
            nesting--;
        else if (c == CTLVAR)
            p++; /* ignore variable substitution byte */
        else if (c == '\0')
            return p - 1;
    }
    return p;
}
Exemplo n.º 6
0
/** handle one line of the read command.
 *  more fields than variables -> remainder shall be part of last variable.
 *  less fields than variables -> remaining variables unset.
 *
 *  @param line complete line of input
 *  @param ap argument (variable) list
 *  @param len length of line including trailing '\0'
 */
static void
readcmd_handle_line(char *line, char **ap, size_t len)
{
	struct arglist arglist;
	struct strlist *sl;
	char *s, *backup;

	/* ifsbreakup will fiddle with stack region... */
	s = grabstackstr(line + len);

	/* need a copy, so that delimiters aren't lost
	 * in case there are more fields than variables */
	backup = sstrdup(line);

	arglist.lastp = &arglist.list;
	recordregion(0, len - 1, 0);
	
	ifsbreakup(s, &arglist);
	*arglist.lastp = NULL;
	removerecordregions(0);

	for (sl = arglist.list; sl; sl = sl->next) {
		/* remaining fields present, but no variables left. */
		if (!ap[1]) {
			size_t offset;
			char *remainder;

			/* FIXME little bit hacky, assuming that ifsbreakup 
			 * will not modify the length of the string */
			offset = sl->text - s;
			remainder = backup + offset;
			rmescapes(remainder);
			setvar(*ap, remainder, 0);

			return;
		}
		
		/* set variable to field */
		rmescapes(sl->text);
		setvar(*ap, sl->text, 0);
		ap++;
	}

	/* nullify remaining arguments */
	do {
		setvar(*ap, nullstr, 0);
	} while (*++ap);
}
Exemplo n.º 7
0
static char *
evalvar(char *p, int flag)
{
	int subtype;
	int varflags;
	char *var;
	const char *val;
	int patloc;
	int c;
	int set;
	int special;
	int startloc;
	int varlen;
	int varlenb;
	int easy;
	int quotes = flag & (EXP_FULL | EXP_CASE);
	int record = 0;

	varflags = (unsigned char)*p++;
	subtype = varflags & VSTYPE;
	var = p;
	special = 0;
	if (! is_name(*p))
		special = 1;
	p = strchr(p, '=') + 1;
again: /* jump here after setting a variable with ${var=text} */
	if (varflags & VSLINENO) {
		set = 1;
		special = 1;
		val = NULL;
	} else if (special) {
		set = varisset(var, varflags & VSNUL);
		val = NULL;
	} else {
		val = bltinlookup(var, 1);
		if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
			val = NULL;
			set = 0;
		} else
			set = 1;
	}
	varlen = 0;
	startloc = expdest - stackblock();
	if (!set && uflag && *var != '@' && *var != '*') {
		switch (subtype) {
		case VSNORMAL:
		case VSTRIMLEFT:
		case VSTRIMLEFTMAX:
		case VSTRIMRIGHT:
		case VSTRIMRIGHTMAX:
		case VSLENGTH:
			error("%.*s: parameter not set", (int)(p - var - 1),
			    var);
		}
	}
	if (set && subtype != VSPLUS) {
		/* insert the value of the variable */
		if (special) {
			if (varflags & VSLINENO)
				STPUTBIN(var, p - var - 1, expdest);
			else
			varvalue(var, varflags & VSQUOTE, subtype, flag);
			if (subtype == VSLENGTH) {
				varlenb = expdest - stackblock() - startloc;
				varlen = varlenb;
				if (localeisutf8) {
					val = stackblock() + startloc;
					for (;val != expdest; val++)
						if ((*val & 0xC0) == 0x80)
							varlen--;
				}
				STADJUST(-varlenb, expdest);
			}
		} else {
			if (subtype == VSLENGTH) {
				for (;*val; val++)
					if (!localeisutf8 ||
					    (*val & 0xC0) != 0x80)
						varlen++;
			}
				else
				strtodest(val, flag, subtype,
				    varflags & VSQUOTE);
		}
	}

	if (subtype == VSPLUS)
		set = ! set;

	easy = ((varflags & VSQUOTE) == 0 ||
		(*var == '@' && shellparam.nparam != 1));


	switch (subtype) {
	case VSLENGTH:
		expdest = cvtnum(varlen, expdest);
		record = 1;
		break;

	case VSNORMAL:
		record = easy;
		break;

	case VSPLUS:
	case VSMINUS:
		if (!set) {
			argstr(p, flag | (flag & EXP_FULL ? EXP_SPLIT_LIT : 0) |
			    (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0));
			break;
		}
		record = easy;
		break;

	case VSTRIMLEFT:
	case VSTRIMLEFTMAX:
	case VSTRIMRIGHT:
	case VSTRIMRIGHTMAX:
		if (!set)
			break;
		/*
		 * Terminate the string and start recording the pattern
		 * right after it
		 */
		STPUTC('\0', expdest);
		patloc = expdest - stackblock();
		if (subevalvar(p, NULL, patloc, subtype,
		    startloc, varflags, quotes) == 0) {
			int amount = (expdest - stackblock() - patloc) + 1;
			STADJUST(-amount, expdest);
		}
		/* Remove any recorded regions beyond start of variable */
		removerecordregions(startloc);
		record = 1;
		break;

	case VSASSIGN:
	case VSQUESTION:
		if (!set) {
			if (subevalvar(p, var, 0, subtype, startloc, varflags,
			    quotes)) {
				varflags &= ~VSNUL;
				/*
				 * Remove any recorded regions beyond
				 * start of variable
				 */
				removerecordregions(startloc);
				goto again;
			}
			break;
		}
		record = easy;
		break;

	case VSERROR:
		c = p - var - 1;
		error("${%.*s%s}: Bad substitution", c, var,
		    (c > 0 && *p != CTLENDVAR) ? "..." : "");

	default:
		abort();
	}

	if (record)
		recordregion(startloc, expdest - stackblock(),
		    varflags & VSQUOTE || (ifsset() && ifsval()[0] == '\0' &&
		    (*var == '@' || *var == '*')));

	if (subtype != VSNORMAL) {	/* skip to end of alternative */
		int nesting = 1;
		for (;;) {
			if ((c = *p++) == CTLESC)
				p++;
			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
				if (set)
					argbackq = argbackq->next;
			} else if (c == CTLVAR) {
				if ((*p++ & VSTYPE) != VSNORMAL)
					nesting++;
			} else if (c == CTLENDVAR) {
				if (--nesting == 0)
					break;
			}
		}
	}
	return p;
}
Exemplo n.º 8
0
STATIC char *
evalvar(shinstance *psh, char *p, int flag)
{
	int subtype;
	int varflags;
	char *var;
	char *val;
	int patloc;
	int c;
	int set;
	int special;
	int startloc;
	int varlen;
	int apply_ifs;
	int quotes = flag & (EXP_FULL | EXP_CASE);

	varflags = (unsigned char)*p++;
	subtype = varflags & VSTYPE;
	var = p;
	special = !is_name(*p);
	p = strchr(p, '=') + 1;

again: /* jump here after setting a variable with ${var=text} */
	if (special) {
		set = varisset(psh, var, varflags & VSNUL);
		val = NULL;
	} else {
		val = lookupvar(psh, var);
		if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
			val = NULL;
			set = 0;
		} else
			set = 1;
	}

	varlen = 0;
	startloc = (int)(psh->expdest - stackblock(psh));

	if (!set && uflag(psh)) {
		switch (subtype) {
		case VSNORMAL:
		case VSTRIMLEFT:
		case VSTRIMLEFTMAX:
		case VSTRIMRIGHT:
		case VSTRIMRIGHTMAX:
		case VSLENGTH:
			error(psh, "%.*s: parameter not set", p - var - 1, var);
			/* NOTREACHED */
		}
	}

	if (set && subtype != VSPLUS) {
		/* insert the value of the variable */
		if (special) {
			varvalue(psh, var, varflags & VSQUOTE, subtype, flag);
			if (subtype == VSLENGTH) {
				varlen = (int)(psh->expdest - stackblock(psh) - startloc);
				STADJUST(psh, -varlen, psh->expdest);
			}
		} else {
			char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
								  : BASESYNTAX;

			if (subtype == VSLENGTH) {
				for (;*val; val++)
					varlen++;
			} else {
				while (*val) {
					if (quotes && syntax[(int)*val] == CCTL)
						STPUTC(psh, CTLESC, psh->expdest);
					STPUTC(psh, *val++, psh->expdest);
				}

			}
		}
	}


	apply_ifs = ((varflags & VSQUOTE) == 0 ||
		(*var == '@' && psh->shellparam.nparam != 1));

	switch (subtype) {
	case VSLENGTH:
		psh->expdest = cvtnum(psh, varlen, psh->expdest);
		break;

	case VSNORMAL:
		break;

	case VSPLUS:
		set = !set;
		/* FALLTHROUGH */
	case VSMINUS:
		if (!set) {
		        argstr(psh, p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0));
			/*
			 * ${x-a b c} doesn't get split, but removing the
			 * 'apply_ifs = 0' apparantly breaks ${1+"$@"}..
			 * ${x-'a b' c} should generate 2 args.
			 */
			/* We should have marked stuff already */
			apply_ifs = 0;
		}
		break;

	case VSTRIMLEFT:
	case VSTRIMLEFTMAX:
	case VSTRIMRIGHT:
	case VSTRIMRIGHTMAX:
		if (!set)
			break;
		/*
		 * Terminate the string and start recording the pattern
		 * right after it
		 */
		STPUTC(psh, '\0', psh->expdest);
		patloc = (int)(psh->expdest - stackblock(psh));
		if (subevalvar(psh, p, NULL, patloc, subtype,
			       startloc, varflags) == 0) {
			int amount = (int)(psh->expdest - stackblock(psh) - patloc) + 1;
			STADJUST(psh, -amount, psh->expdest);
		}
		/* Remove any recorded regions beyond start of variable */
		removerecordregions(psh, startloc);
		apply_ifs = 1;
		break;

	case VSASSIGN:
	case VSQUESTION:
		if (set)
			break;
		if (subevalvar(psh, p, var, 0, subtype, startloc, varflags)) {
			varflags &= ~VSNUL;
			/*
			 * Remove any recorded regions beyond
			 * start of variable
			 */
			removerecordregions(psh, startloc);
			goto again;
		}
		apply_ifs = 0;
		break;

	default:
		sh_abort(psh);
	}

	if (apply_ifs)
		recordregion(psh, startloc, (int)(psh->expdest - stackblock(psh)),
			     varflags & VSQUOTE);

	if (subtype != VSNORMAL) {	/* skip to end of alternative */
		int nesting = 1;
		for (;;) {
			if ((c = *p++) == CTLESC)
				p++;
			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
				if (set)
					psh->argbackq = psh->argbackq->next;
			} else if (c == CTLVAR) {
				if ((*p++ & VSTYPE) != VSNORMAL)
					nesting++;
			} else if (c == CTLENDVAR) {
				if (--nesting == 0)
					break;
			}
		}
	}
	return p;
}
Exemplo n.º 9
0
STATIC char *
evalvar(char *p, int flag)
{
	int subtype;
	int varflags;
	char *var;
	char *val;
	int patloc;
	int c;
	int set;
	int special;
	int startloc;
	int varlen;
	int easy;
	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);

	varflags = (unsigned char)*p++;
	subtype = varflags & VSTYPE;
	var = p;
	special = 0;
	if (! is_name(*p))
		special = 1;
	p = strchr(p, '=') + 1;
again: /* jump here after setting a variable with ${var=text} */
	if (varflags & VSLINENO) {
		set = 1;
		special = 0;
		val = var;
		p[-1] = '\0';	/* temporarily overwrite '=' to have \0
				   terminated string */
	} else if (special) {
		set = varisset(var, varflags & VSNUL);
		val = NULL;
	} else {
		val = bltinlookup(var, 1);
		if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
			val = NULL;
			set = 0;
		} else
			set = 1;
	}
	varlen = 0;
	startloc = expdest - stackblock();
	if (!set && uflag) {
		switch (subtype) {
		case VSNORMAL:
		case VSTRIMLEFT:
		case VSTRIMLEFTMAX:
		case VSTRIMRIGHT:
		case VSTRIMRIGHTMAX:
		case VSLENGTH:
			error("%.*s: parameter not set", (int)(p - var - 1),
			    var);
		}
	}
	if (set && subtype != VSPLUS) {
		/* insert the value of the variable */
		if (special) {
			varvalue(var, varflags & VSQUOTE, subtype, flag);
			if (subtype == VSLENGTH) {
				varlen = expdest - stackblock() - startloc;
				STADJUST(-varlen, expdest);
			}
		} else {
			char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
								  : BASESYNTAX;

			if (subtype == VSLENGTH) {
				for (;*val; val++)
					varlen++;
			}
			else {
				while (*val) {
					if (quotes &&
					    syntax[(int)*val] == CCTL)
						STPUTC(CTLESC, expdest);
					STPUTC(*val++, expdest);
				}

			}
		}
	}

	if (subtype == VSPLUS)
		set = ! set;

	easy = ((varflags & VSQUOTE) == 0 ||
		(*var == '@' && shellparam.nparam != 1));


	switch (subtype) {
	case VSLENGTH:
		expdest = cvtnum(varlen, expdest);
		goto record;

	case VSNORMAL:
		if (!easy)
			break;
record:
		recordregion(startloc, expdest - stackblock(),
			     varflags & VSQUOTE);
		break;

	case VSPLUS:
	case VSMINUS:
		if (!set) {
			argstr(p, flag);
			break;
		}
		if (easy)
			goto record;
		break;

	case VSTRIMLEFT:
	case VSTRIMLEFTMAX:
	case VSTRIMRIGHT:
	case VSTRIMRIGHTMAX:
		if (!set)
			break;
		/*
		 * Terminate the string and start recording the pattern
		 * right after it
		 */
		STPUTC('\0', expdest);
		patloc = expdest - stackblock();
		if (subevalvar(p, NULL, patloc, subtype,
			       startloc, varflags) == 0) {
			int amount = (expdest - stackblock() - patloc) + 1;
			STADJUST(-amount, expdest);
		}
		/* Remove any recorded regions beyond start of variable */
		removerecordregions(startloc);
		goto record;

	case VSASSIGN:
	case VSQUESTION:
		if (!set) {
			if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
				varflags &= ~VSNUL;
				/*
				 * Remove any recorded regions beyond
				 * start of variable
				 */
				removerecordregions(startloc);
				goto again;
			}
			break;
		}
		if (easy)
			goto record;
		break;

	case VSERROR:
		c = p - var - 1;
		error("${%.*s%s}: Bad substitution", c, var,
		    (c > 0 && *p != CTLENDVAR) ? "..." : "");

	default:
		abort();
	}
	p[-1] = '=';	/* recover overwritten '=' */

	if (subtype != VSNORMAL) {	/* skip to end of alternative */
		int nesting = 1;
		for (;;) {
			if ((c = *p++) == CTLESC)
				p++;
			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
				if (set)
					argbackq = argbackq->next;
			} else if (c == CTLVAR) {
				if ((*p++ & VSTYPE) != VSNORMAL)
					nesting++;
			} else if (c == CTLENDVAR) {
				if (--nesting == 0)
					break;
			}
		}
	}
	return p;
}