Example #1
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);
		}
	}
}
Example #2
0
/*
 * Perform command substitution.
 */
static void
expbackq(union node *cmd, int quoted, int flag, struct worddest *dst)
{
	struct backcmd in;
	int i;
	char buf[128];
	char *p;
	char *dest = expdest;
	struct nodelist *saveargbackq;
	char lastc;
	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
	int quotes = flag & (EXP_GLOB | EXP_CASE);
	size_t nnl;
	const char *ifs;

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

	p = in.buf;
	nnl = 0;
	if (!quoted && flag & EXP_SPLIT)
		ifs = ifsset() ? ifsval() : " \t\n";
	else
		ifs = "";
	/* 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')
			continue;
		if (lastc == '\n') {
			nnl++;
		} else {
			if (nnl > 0) {
				if (strchr(ifs, '\n') != NULL) {
					NEXTWORD('\n', flag, dest, dst);
					nnl = 0;
				} else {
					CHECKSTRSPACE(nnl + 2, dest);
					while (nnl > 0) {
						nnl--;
						USTPUTC('\n', dest);
					}
				}
			}
			if (strchr(ifs, lastc) != NULL)
				NEXTWORD(lastc, flag, dest, dst);
			else {
				CHECKSTRSPACE(2, 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);
	TRACE(("expbackq: size=%td: \"%.*s\"\n",
		((dest - stackblock()) - startloc),
		(int)((dest - stackblock()) - startloc),
		stackblock() + startloc));
	expdest = dest;
	INTON;
}
Example #3
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;
}
Example #4
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_GLOB or EXP_CASE are set, keep and/or generate CTLESC
 * characters to allow for further processing.
 *
 * If EXP_SPLIT is set, dst receives any complete words produced.
 */
static const char *
argstr(const char *p, int flag, struct worddest *dst)
{
	char c;
	int quotes = flag & (EXP_GLOB | 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[1] & VSQUOTE) != 0 &&
			    p[2] == '@' && p[3] == '=')
				break;
			if ((flag & EXP_SPLIT) != 0 && expdest == stackblock())
				dst->state = WORD_QUOTEMARK;
			break;
		case CTLQUOTEEND:
			lit_quoted = 0;
			break;
		case CTLESC:
			c = *p++;
			if (split_lit && !lit_quoted &&
			    strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
				NEXTWORD(c, flag, expdest, dst);
				break;
			}
			if (quotes)
				USTPUTC(CTLESC, expdest);
			USTPUTC(c, expdest);
			break;
		case CTLVAR:
			p = evalvar(p, flag, dst);
			break;
		case CTLBACKQ:
		case CTLBACKQ|CTLQUOTE:
			expbackq(argbackq->n, c & CTLQUOTE, flag, dst);
			argbackq = argbackq->next;
			break;
		case CTLARI:
			p = expari(p, flag, dst);
			break;
		case ':':
		case '=':
			/*
			 * sort of a hack - expand tildes in variable
			 * assignments (after the first '=' and after ':'s).
			 */
			if (split_lit && !lit_quoted &&
			    strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
				NEXTWORD(c, flag, expdest, dst);
				break;
			}
			USTPUTC(c, expdest);
			if (flag & EXP_VARTILDE && *p == '~' &&
			    (c != '=' || firsteq)) {
				if (c == '=')
					firsteq = 0;
				p = exptilde(p, flag);
			}
			break;
		default:
			if (split_lit && !lit_quoted &&
			    strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
				NEXTWORD(c, flag, expdest, dst);
				break;
			}
			USTPUTC(c, expdest);
		}
	}
}