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(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.º 3
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.º 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
/*
 * Perform command substitution.
 */
static void
expbackq(union node *cmd, int quoted, int flag)
{
	struct backcmd in;
	int i;
	char buf[128];
	char *p;
	char *dest = expdest;
	struct ifsregion saveifs, *savelastp;
	struct nodelist *saveargbackq;
	char lastc;
	int startloc = dest - stackblock();
	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
	int quotes = flag & (EXP_FULL | EXP_CASE);
	size_t nnl;

	INTOFF;
	saveifs = ifsfirst;
	savelastp = ifslastp;
	saveargbackq = argbackq;
	p = grabstackstr(dest);
	evalbackcmd(cmd, &in);
	ungrabstackstr(p, dest);
	ifsfirst = saveifs;
	ifslastp = savelastp;
	argbackq = saveargbackq;

	p = in.buf;
	lastc = '\0';
	nnl = 0;
	/* Don't copy trailing newlines */
	for (;;) {
		if (--in.nleft < 0) {
			if (in.fd < 0)
				break;
			while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
			TRACE(("expbackq: read returns %d\n", i));
			if (i <= 0)
				break;
			p = buf;
			in.nleft = i - 1;
		}
		lastc = *p++;
		if (lastc != '\0') {
			if (lastc == '\n') {
				nnl++;
			} else {
				CHECKSTRSPACE(nnl + 2, dest);
				while (nnl > 0) {
					nnl--;
					USTPUTC('\n', dest);
				}
				if (quotes && syntax[(int)lastc] == CCTL)
					USTPUTC(CTLESC, dest);
				USTPUTC(lastc, dest);
			}
		}
	}

	if (in.fd >= 0)
		close(in.fd);
	if (in.buf)
		ckfree(in.buf);
	if (in.jp)
		exitstatus = waitforjob(in.jp, (int *)NULL);
	if (quoted == 0)
		recordregion(startloc, dest - stackblock(), 0);
	TRACE(("expbackq: size=%td: \"%.*s\"\n",
		((dest - stackblock()) - startloc),
		(int)((dest - stackblock()) - startloc),
		stackblock() + startloc));
	expdest = dest;
	INTON;
}
Exemplo n.º 9
0
/*
 * Perform parameter expansion, command substitution and arithmetic
 * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
 * Processing ends at a CTLENDVAR or CTLENDARI character as well as '\0'.
 * This is used to expand word in ${var+word} etc.
 * If EXP_FULL or EXP_CASE are set, keep and/or generate CTLESC
 * characters to allow for further processing.
 * If EXP_FULL is set, also preserve CTLQUOTEMARK characters.
 */
static char *
argstr(char *p, int flag)
{
	char c;
	int quotes = flag & (EXP_FULL | EXP_CASE);	/* do CTLESC */
	int firsteq = 1;
	int split_lit;
	int lit_quoted;

	split_lit = flag & EXP_SPLIT_LIT;
	lit_quoted = flag & EXP_LIT_QUOTED;
	flag &= ~(EXP_SPLIT_LIT | EXP_LIT_QUOTED);
	if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
		p = exptilde(p, flag);
	for (;;) {
		CHECKSTRSPACE(2, expdest);
		switch (c = *p++) {
		case '\0':
			return (p - 1);
		case CTLENDVAR:
		case CTLENDARI:
			return (p);
		case CTLQUOTEMARK:
			lit_quoted = 1;
			/* "$@" syntax adherence hack */
			if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
				break;
			if ((flag & EXP_FULL) != 0)
				USTPUTC(c, expdest);
			break;
		case CTLQUOTEEND:
			lit_quoted = 0;
			break;
		case CTLESC:
			if (quotes)
				USTPUTC(c, expdest);
			c = *p++;
			USTPUTC(c, expdest);
			if (split_lit && !lit_quoted)
				recordregion(expdest - stackblock() -
				    (quotes ? 2 : 1),
				    expdest - stackblock(), 0);
			break;
		case CTLVAR:
			p = evalvar(p, flag);
			break;
		case CTLBACKQ:
		case CTLBACKQ|CTLQUOTE:
			expbackq(argbackq->n, c & CTLQUOTE, flag);
			argbackq = argbackq->next;
			break;
		case CTLARI:
			p = expari(p);
			break;
		case ':':
		case '=':
			/*
			 * sort of a hack - expand tildes in variable
			 * assignments (after the first '=' and after ':'s).
			 */
			USTPUTC(c, expdest);
			if (split_lit && !lit_quoted)
				recordregion(expdest - stackblock() - 1,
				    expdest - stackblock(), 0);
			if (flag & EXP_VARTILDE && *p == '~' &&
			    (c != '=' || firsteq)) {
				if (c == '=')
					firsteq = 0;
				p = exptilde(p, flag);
			}
			break;
		default:
			USTPUTC(c, expdest);
			if (split_lit && !lit_quoted)
				recordregion(expdest - stackblock() - 1,
				    expdest - stackblock(), 0);
		}
	}
}
Exemplo n.º 10
0
int
readcmd(int argc, char **argv)
{
	char **ap;
	char c;
	int rflag;
	char *prompt;
	char *p;
	int startloc;
	int newloc;
	int status;
	int i;

	rflag = 0;
	prompt = NULL;
	while ((i = nextopt("p:r")) != '\0') {
		if (i == 'p')
			prompt = optionarg;
		else
			rflag = 1;
	}
	if (prompt && isatty(0)) {
		out2str(prompt);
#ifdef FLUSHERR
		flushall();
#endif
	}
	if (*(ap = argptr) == NULL)
		sh_error("arg count");

	status = 0;
	STARTSTACKSTR(p);

	goto start;

	for (;;) {
		switch (read(0, &c, 1)) {
		case 1:
			break;
		default:
			if (errno == EINTR && !pendingsigs)
				continue;
				/* fall through */
		case 0:
			status = 1;
			goto out;
		}
		if (c == '\0')
			continue;
		if (newloc >= startloc) {
			if (c == '\n')
				goto resetbs;
			goto put;
		}
		if (!rflag && c == '\\') {
			newloc = p - (char *)stackblock();
			continue;
		}
		if (c == '\n')
			break;
put:
		CHECKSTRSPACE(2, p);
		if (strchr(qchars, c))
			USTPUTC(CTLESC, p);
		USTPUTC(c, p);

		if (newloc >= startloc) {
resetbs:
			recordregion(startloc, newloc, 0);
start:
			startloc = p - (char *)stackblock();
			newloc = startloc - 1;
		}
	}
out:
	recordregion(startloc, p - (char *)stackblock(), 0);
	STACKSTRNUL(p);
	readcmd_handle_line(p + 1, ap);
	return status;
}
Exemplo n.º 11
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.º 12
0
STATIC void
expbackq(shinstance *psh, union node *cmd, int quoted, int flag)
{
	struct backcmd in;
	int i;
	char buf[128];
	char *p;
	char *dest = psh->expdest;
	struct ifsregion saveifs, *savelastp;
	struct nodelist *saveargbackq;
	char lastc;
	int startloc = (int)(dest - stackblock(psh));
	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
	int saveherefd;
	int quotes = flag & (EXP_FULL | EXP_CASE);
#ifdef SH_DEAL_WITH_CRLF
	int pending_cr = 0;
#endif

	INTOFF;
	saveifs = psh->ifsfirst;
	savelastp = psh->ifslastp;
	saveargbackq = psh->argbackq;
	saveherefd = psh->herefd;
	psh->herefd = -1;
	p = grabstackstr(psh, dest);
	evalbackcmd(psh, cmd, &in);
	ungrabstackstr(psh, p, dest);
	psh->ifsfirst = saveifs;
	psh->ifslastp = savelastp;
	psh->argbackq = saveargbackq;
	psh->herefd = saveherefd;

	p = in.buf;
	lastc = '\0';
	for (;;) {
		if (--in.nleft < 0) {
			if (in.fd < 0)
				break;
			while ((i = shfile_read(&psh->fdtab, in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
			TRACE((psh, "expbackq: read returns %d\n", i));
			if (i <= 0)
				break;
			p = buf;
			in.nleft = i - 1;
		}
		lastc = *p++;
#ifdef SH_DEAL_WITH_CRLF
		if (pending_cr) {
			pending_cr = 0;
			if (lastc != '\n') {
				if (quotes && syntax[(int)'\r'] == CCTL)
					STPUTC(psh, CTLESC, dest);
				STPUTC(psh, '\r', dest);
			}
		}
		if (lastc == '\r')
			pending_cr = '\r';
		else
#endif
		if (lastc != '\0') {
			if (quotes && syntax[(int)lastc] == CCTL)
				STPUTC(psh, CTLESC, dest);
			STPUTC(psh, lastc, dest);
		}
	}
#ifdef SH_DEAL_WITH_CRLF
	if (pending_cr) {
		if (quotes && syntax[(int)'\r'] == CCTL)
			STPUTC(psh, CTLESC, dest);
		STPUTC(psh, '\r', dest);
	}
#endif

	/* Eat all trailing newlines */
	p = stackblock(psh) + startloc;
	while (dest > p && dest[-1] == '\n')
		STUNPUTC(psh, dest);

	if (in.fd >= 0)
		shfile_close(&psh->fdtab, in.fd);
	if (in.buf)
		ckfree(psh, in.buf);
	if (in.jp)
		psh->back_exitstatus = waitforjob(psh, in.jp);
	if (quoted == 0)
		recordregion(psh, startloc, (int)(dest - stackblock(psh)), 0);
	TRACE((psh, "evalbackq: size=%d: \"%.*s\"\n",
		(dest - stackblock(psh)) - startloc,
		(dest - stackblock(psh)) - startloc,
		stackblock(psh) + startloc));
	psh->expdest = dest;
	INTON;
}
Exemplo n.º 13
0
STATIC void
argstr(shinstance *psh, char *p, int flag)
{
	char c;
	int quotes = flag & (EXP_FULL | EXP_CASE);	/* do CTLESC */
	int firsteq = 1;
	const char *ifs = NULL;
	int ifs_split = EXP_IFS_SPLIT;

	if (flag & EXP_IFS_SPLIT)
		ifs = ifsset(psh) ? ifsval(psh) : " \t\n";

	if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
		p = exptilde(psh, p, flag);
	for (;;) {
		switch (c = *p++) {
		case '\0':
		case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */
			return;
		case CTLQUOTEMARK:
			/* "$@" syntax adherence hack */
			if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
				break;
			if ((flag & EXP_FULL) != 0)
				STPUTC(psh, c, psh->expdest);
			ifs_split = 0;
			break;
		case CTLQUOTEEND:
			ifs_split = EXP_IFS_SPLIT;
			break;
		case CTLESC:
			if (quotes)
				STPUTC(psh, c, psh->expdest);
			c = *p++;
			STPUTC(psh, c, psh->expdest);
			break;
		case CTLVAR:
			p = evalvar(psh, p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split));
			break;
		case CTLBACKQ:
		case CTLBACKQ|CTLQUOTE:
			expbackq(psh, psh->argbackq->n, c & CTLQUOTE, flag);
			psh->argbackq = psh->argbackq->next;
			break;
		case CTLENDARI:
			expari(psh, flag);
			break;
		case ':':
		case '=':
			/*
			 * sort of a hack - expand tildes in variable
			 * assignments (after the first '=' and after ':'s).
			 */
			STPUTC(psh, c, psh->expdest);
			if (flag & EXP_VARTILDE && *p == '~') {
				if (c == '=') {
					if (firsteq)
						firsteq = 0;
					else
						break;
				}
				p = exptilde(psh, p, flag);
			}
			break;
		default:
			STPUTC(psh, c, psh->expdest);
			if (flag & EXP_IFS_SPLIT & ifs_split && strchr(ifs, c) != NULL) {
				/* We need to get the output split here... */
				recordregion(psh, (int)(psh->expdest - stackblock(psh) - 1),
						(int)(psh->expdest - stackblock(psh)), 0);
			}
			break;
		}
	}
}
Exemplo n.º 14
0
STATIC void
expbackq(union node *cmd, int quoted, int flag)
{
	struct backcmd in;
	int i;
	char buf[128];
	char *p;
	char *dest = expdest;
	struct ifsregion saveifs, *savelastp;
	struct nodelist *saveargbackq;
	char lastc;
	int startloc = dest - stackblock();
	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
	int saveherefd;
	int quotes = flag & (EXP_FULL | EXP_CASE);

	INTOFF;
	saveifs = ifsfirst;
	savelastp = ifslastp;
	saveargbackq = argbackq;
	saveherefd = herefd;
	herefd = -1;
	p = grabstackstr(dest);
	evalbackcmd(cmd, &in);
	ungrabstackstr(p, dest);
	ifsfirst = saveifs;
	ifslastp = savelastp;
	argbackq = saveargbackq;
	herefd = saveherefd;

	p = in.buf;
	lastc = '\0';
	for (;;) {
		if (--in.nleft < 0) {
			if (in.fd < 0)
				break;
			while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
			TRACE(("expbackq: read returns %d\n", i));
			if (i <= 0)
				break;
			p = buf;
			in.nleft = i - 1;
		}
		lastc = *p++;
		if (lastc != '\0') {
			if (quotes && syntax[(int)lastc] == CCTL)
				STPUTC(CTLESC, dest);
			STPUTC(lastc, dest);
		}
	}

	/* Eat all trailing newlines */
	p = stackblock() + startloc;
	while (dest > p && dest[-1] == '\n')
		STUNPUTC(dest);

	if (in.fd >= 0)
		close(in.fd);
	if (in.buf)
		ckfree(in.buf);
	if (in.jp)
		back_exitstatus = waitforjob(in.jp);
	if (quoted == 0)
		recordregion(startloc, dest - stackblock(), 0);
	TRACE(("evalbackq: size=%d: \"%.*s\"\n",
		(dest - stackblock()) - startloc,
		(dest - stackblock()) - startloc,
		stackblock() + startloc));
	expdest = dest;
	INTON;
}
Exemplo n.º 15
0
int
readcmd(int argc, char **argv)
{
	char **ap;
	char c;
	int rflag;
	char *prompt;
	char *p;
	int startloc;
	int newloc;
	int status;
	int timeout;
	int i;
	fd_set set;
	struct timeval ts, t0, t1, to;

	ts.tv_sec = ts.tv_usec = 0;

	rflag = 0;
	timeout = 0;
	prompt = NULL;
	while ((i = nextopt("p:rt:")) != '\0') {
		switch(i) {
		case 'p':
			prompt = optionarg;
			break;
		case 't':
			p = strtotimeval(optionarg, &ts);
			if (*p || (!ts.tv_sec && !ts.tv_usec))
				sh_error("invalid timeout");
			timeout = 1;
			break;
		case 'r':
			rflag = 1;
			break;
		default:
			break;
		}
	}
	if (prompt && isatty(0)) {
		out2str(prompt);
#ifdef FLUSHERR
		flushall();
#endif
	}
	if (*(ap = argptr) == NULL)
		sh_error("arg count");

	status = 0;
	if (timeout) {
		gettimeofday(&t0, NULL);

		/* ts += t0; */
		ts.tv_usec += t0.tv_usec;
		while (ts.tv_usec >= 1000000) {
			ts.tv_sec++;
			ts.tv_usec -= 1000000;
		}
		ts.tv_sec += t0.tv_sec;
	}
	STARTSTACKSTR(p);

	goto start;

	for (;;) {
		if (timeout) {
			gettimeofday(&t1, NULL);
			if (t1.tv_sec > ts.tv_sec ||
			    (t1.tv_sec == ts.tv_sec &&
			     t1.tv_usec >= ts.tv_usec)) {
				status = 1;
				break;	/* Timeout! */
			}

			/* to = ts - t1; */
			if (ts.tv_usec >= t1.tv_usec) {
				to.tv_usec = ts.tv_usec - t1.tv_usec;
				to.tv_sec  = ts.tv_sec - t1.tv_sec;
			} else {
				to.tv_usec = ts.tv_usec - t1.tv_usec + 1000000;
				to.tv_sec  = ts.tv_sec - t1.tv_sec - 1;
			}

			FD_ZERO(&set);
			FD_SET(0, &set);
			if (select(1, &set, NULL, NULL, &to) != 1) {
				status = 1;
				break; /* Timeout! */
			}
		}
		switch (read(0, &c, 1)) {
		case 1:
			break;
		default:
			if (errno == EINTR && !pendingsigs)
				continue;
				/* fall through */
		case 0:
			status = 1;
			goto out;
		}
		if (c == '\0')
			continue;
		if (newloc >= startloc) {
			if (c == '\n')
				goto resetbs;
			goto put;
		}
		if (!rflag && c == '\\') {
			newloc = p - (char *)stackblock();
			continue;
		}
		if (c == '\n')
			break;
put:
		CHECKSTRSPACE(2, p);
		if (strchr(qchars, c))
			USTPUTC(CTLESC, p);
		USTPUTC(c, p);

		if (newloc >= startloc) {
resetbs:
			recordregion(startloc, newloc, 0);
start:
			startloc = p - (char *)stackblock();
			newloc = startloc - 1;
		}
	}
out:
	recordregion(startloc, p - (char *)stackblock(), 0);
	STACKSTRNUL(p);
	readcmd_handle_line(p + 1, ap);
	return status;
}
Exemplo n.º 16
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;
}