Example #1
0
static char *
stputs_split(const char *data, const char *syntax, int flag, char *p,
    struct worddest *dst)
{
	const char *ifs;
	char c;

	ifs = ifsset() ? ifsval() : " \t\n";
	while (*data) {
		CHECKSTRSPACE(2, p);
		c = *data++;
		if (strchr(ifs, c) != NULL) {
			NEXTWORD(c, flag, p, dst);
			continue;
		}
		if (flag & EXP_GLOB && syntax[(int)c] == CCTL)
			USTPUTC(CTLESC, p);
		USTPUTC(c, p);
	}
	return (p);
}
Example #2
0
/*
 * Break the argument string into pieces based upon IFS and add the
 * strings to the argument list.  The regions of the string to be
 * searched for IFS characters have been stored by recordregion.
 * CTLESC characters are preserved but have little effect in this pass
 * other than escaping CTL* characters.  In particular, they do not escape
 * IFS characters: that should be done with the ifsregion mechanism.
 * CTLQUOTEMARK characters are used to preserve empty quoted strings.
 * This pass treats them as a regular character, making the string non-empty.
 * Later, they are removed along with the other CTL* characters.
 */
static void
ifsbreakup(char *string, struct arglist *arglist)
{
	struct ifsregion *ifsp;
	struct strlist *sp;
	char *start;
	char *p;
	char *q;
	const char *ifs;
	const char *ifsspc;
	int had_param_ch = 0;

	start = string;

	if (ifslastp == NULL) {
		/* Return entire argument, IFS doesn't apply to any of it */
		sp = (struct strlist *)stalloc(sizeof *sp);
		sp->text = start;
		*arglist->lastp = sp;
		arglist->lastp = &sp->next;
		return;
	}

	ifs = ifsset() ? ifsval() : " \t\n";

	for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
		p = string + ifsp->begoff;
		while (p < string + ifsp->endoff) {
			q = p;
			if (*p == CTLESC)
				p++;
			if (ifsp->inquotes) {
				/* Only NULs (should be from "$@") end args */
				had_param_ch = 1;
				if (*p != 0) {
					p++;
					continue;
				}
				ifsspc = NULL;
			} else {
				if (!strchr(ifs, *p)) {
					had_param_ch = 1;
					p++;
					continue;
				}
				ifsspc = strchr(" \t\n", *p);

				/* Ignore IFS whitespace at start */
				if (q == start && ifsspc != NULL) {
					p++;
					start = p;
					continue;
				}
				had_param_ch = 0;
			}

			/* Save this argument... */
			*q = '\0';
			sp = (struct strlist *)stalloc(sizeof *sp);
			sp->text = start;
			*arglist->lastp = sp;
			arglist->lastp = &sp->next;
			p++;

			if (ifsspc != NULL) {
				/* Ignore further trailing IFS whitespace */
				for (; p < string + ifsp->endoff; p++) {
					q = p;
					if (*p == CTLESC)
						p++;
					if (strchr(ifs, *p) == NULL) {
						p = q;
						break;
					}
					if (strchr(" \t\n", *p) == NULL) {
						p++;
						break;
					}
				}
			}
			start = p;
		}
	}

	/*
	 * Save anything left as an argument.
	 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
	 * generating 2 arguments, the second of which is empty.
	 * Some recent clarification of the Posix spec say that it
	 * should only generate one....
	 */
	if (had_param_ch || *start != 0) {
		sp = (struct strlist *)stalloc(sizeof *sp);
		sp->text = start;
		*arglist->lastp = sp;
		arglist->lastp = &sp->next;
	}
}
Example #3
0
static void
varvalue(const char *name, int quoted, int subtype, int flag)
{
	int num;
	char *p;
	int i;
	char sep[2];
	char **ap;

	switch (*name) {
	case '$':
		num = rootpid;
		break;
	case '?':
		num = oexitstatus;
		break;
	case '#':
		num = shellparam.nparam;
		break;
	case '!':
		num = backgndpidval();
		break;
	case '-':
		for (i = 0 ; i < NOPTS ; i++) {
			if (optlist[i].val)
				STPUTC(optlist[i].letter, expdest);
		}
		return;
	case '@':
		if (flag & EXP_FULL && quoted) {
			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
				strtodest(p, flag, subtype, quoted);
				if (*ap)
					STPUTC('\0', expdest);
			}
			return;
		}
		/* FALLTHROUGH */
	case '*':
		if (ifsset())
			sep[0] = ifsval()[0];
		else
			sep[0] = ' ';
		sep[1] = '\0';
		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
			strtodest(p, flag, subtype, quoted);
			if (!*ap)
				break;
			if (sep[0])
				strtodest(sep, flag, subtype, quoted);
			else if (flag & EXP_FULL && !quoted && **ap != '\0')
				STPUTC('\0', expdest);
		}
		return;
	default:
		if (is_digit(*name)) {
			num = atoi(name);
			if (num == 0)
				p = arg0;
			else if (num > 0 && num <= shellparam.nparam)
				p = shellparam.p[num - 1];
			else
				return;
			strtodest(p, flag, subtype, quoted);
			}
		return;
		}
	expdest = cvtnum(num, expdest);
}
Example #4
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;
}
Example #5
0
STATIC void
varvalue(shinstance *psh, char *name, int quoted, int subtype, int flag)
{
	int num;
	char *p;
	int i;
	char sep;
	char **ap;
	char const *syntax;

#define STRTODEST(p) \
	do {\
	if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \
		syntax = quoted? DQSYNTAX : BASESYNTAX; \
		while (*p) { \
			if (syntax[(int)*p] == CCTL) \
				STPUTC(psh, CTLESC, psh->expdest); \
			STPUTC(psh, *p++, psh->expdest); \
		} \
	} else \
		while (*p) \
			STPUTC(psh, *p++, psh->expdest); \
	} while (0)


	switch (*name) {
	case '$':
		num = psh->rootpid;
		goto numvar;
	case '?':
		num = psh->exitstatus;
		goto numvar;
	case '#':
		num = psh->shellparam.nparam;
		goto numvar;
	case '!':
		num = psh->backgndpid;
numvar:
		psh->expdest = cvtnum(psh, num, psh->expdest);
		break;
	case '-':
		for (i = 0; psh->optlist[i].name; i++) {
			if (psh->optlist[i].val)
				STPUTC(psh, psh->optlist[i].letter, psh->expdest);
		}
		break;
	case '@':
		if (flag & EXP_FULL && quoted) {
			for (ap = psh->shellparam.p ; (p = *ap++) != NULL ; ) {
				STRTODEST(p);
				if (*ap)
					STPUTC(psh, '\0', psh->expdest);
			}
			break;
		}
		/* fall through */
	case '*':
		if (ifsset(psh) != 0)
			sep = ifsval(psh)[0];
		else
			sep = ' ';
		for (ap = psh->shellparam.p ; (p = *ap++) != NULL ; ) {
			STRTODEST(p);
			if (*ap && sep)
				STPUTC(psh, sep, psh->expdest);
		}
		break;
	case '0':
		p = psh->arg0;
		STRTODEST(p);
		break;
	default:
		if (is_digit(*name)) {
			num = atoi(name);
			if (num > 0 && num <= psh->shellparam.nparam) {
				p = psh->shellparam.p[num - 1];
				STRTODEST(p);
			}
		}
		break;
	}
}
Example #6
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;
		}
	}
}
Example #7
0
STATIC void
varvalue(char *name, int quoted, int subtype, int flag)
{
	int num;
	char *p;
	int i;
	char sep;
	char **ap;
	char const *syntax;

#define STRTODEST(p) \
	do {\
	if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \
		syntax = quoted? DQSYNTAX : BASESYNTAX; \
		while (*p) { \
			if (syntax[(int)*p] == CCTL) \
				STPUTC(CTLESC, expdest); \
			STPUTC(*p++, expdest); \
		} \
	} else \
		while (*p) \
			STPUTC(*p++, expdest); \
	} while (0)


	switch (*name) {
	case '$':
		num = rootpid;
		goto numvar;
	case '?':
		num = exitstatus;
		goto numvar;
	case '#':
		num = shellparam.nparam;
		goto numvar;
	case '!':
		num = backgndpid;
numvar:
		expdest = cvtnum(num, expdest);
		break;
	case '-':
		for (i = 0; optlist[i].name; i++) {
			if (optlist[i].val && optlist[i].letter)
				STPUTC(optlist[i].letter, expdest);
		}
		break;
	case '@':
		if (flag & EXP_FULL && quoted) {
			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
				STRTODEST(p);
				if (*ap)
					/* A NUL separates args inside "" */
					STPUTC('\0', expdest);
			}
			break;
		}
		/* fall through */
	case '*':
		if (ifsset() != 0)
			sep = ifsval()[0];
		else
			sep = ' ';
		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
			STRTODEST(p);
			if (*ap && sep)
				STPUTC(sep, expdest);
		}
		break;
	case '0':
		p = arg0;
		STRTODEST(p);
		break;
	default:
		if (is_digit(*name)) {
			num = atoi(name);
			if (num > 0 && num <= shellparam.nparam) {
				p = shellparam.p[num - 1];
				STRTODEST(p);
			}
		}
		break;
	}
}
Example #8
0
static void
varvalue(const_cstring_t name, int32_t quoted, int32_t subtype, int32_t flag)
{
    int32_t num;
    cstring_t p;
    int32_t i;
    char sep;
    cstring_t* ap;
    switch (*name)
    {
    case '$':
        num = rootpid;
        goto numvar;
    case '?':
        num = oexitstatus;
        goto numvar;
    case '#':
        num = shellparam.nparam;
        goto numvar;
    case '!':
        num = backgndpidval();
numvar:
        expdest = cvtnum(num, expdest);
        break;
    case '-':
        for (i = 0 ; i < NOPTS ; i++)
        {
            if (optlist[i].val)
                STPUTC(optlist[i].letter, expdest);
        }
        break;
    case '@':
        if (flag & EXP_FULL && quoted)
        {
            for (ap = shellparam.p ; (p = *ap++) != NULL ;)
            {
                strtodest(p, flag, subtype, quoted);
                if (*ap)
                    STPUTC('\0', expdest);
            }
            break;
        }
    /* FALLTHROUGH */
    case '*':
        if (ifsset())
            sep = ifsval()[0];
        else
            sep = ' ';
        for (ap = shellparam.p ; (p = *ap++) != NULL ;)
        {
            strtodest(p, flag, subtype, quoted);
            if (!*ap)
                break;
            if (sep || (flag & EXP_FULL && !quoted &&** ap != '\0'))
                STPUTC(sep, expdest);
        }
        break;
    default:
        if (is_digit(*name))
        {
            num = atoi(name);
            if (num == 0)
                p = arg0;
            else if (num > 0 && num <= shellparam.nparam)
                p = shellparam.p[num - 1];
            else
                break;
            strtodest(p, flag, subtype, quoted);
        }
        break;
    }
}
Example #9
0
static void
varvalue(const char *name, int quoted, int subtype, int flag,
    struct worddest *dst)
{
	int num;
	char *p;
	int i;
	int splitlater;
	char sep[2];
	char **ap;
	char buf[(NSHORTOPTS > 10 ? NSHORTOPTS : 10) + 1];

	if (subtype == VSLENGTH)
		flag &= ~EXP_FULL;
	splitlater = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
		subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX;

	switch (*name) {
	case '$':
		num = rootpid;
		break;
	case '?':
		num = oexitstatus;
		break;
	case '#':
		num = shellparam.nparam;
		break;
	case '!':
		num = backgndpidval();
		break;
	case '-':
		p = buf;
		for (i = 0 ; i < NSHORTOPTS ; i++) {
			if (optlist[i].val)
				*p++ = optlist[i].letter;
		}
		*p = '\0';
		strtodest(buf, flag, subtype, quoted, dst);
		return;
	case '@':
		if (flag & EXP_SPLIT && quoted) {
			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
				strtodest(p, flag, subtype, quoted, dst);
				if (*ap) {
					if (splitlater)
						STPUTC('\0', expdest);
					else
						NEXTWORD('\0', flag, expdest,
						    dst);
				}
			}
			if (shellparam.nparam > 0)
				dst->state = WORD_QUOTEMARK;
			return;
		}
		/* FALLTHROUGH */
	case '*':
		if (ifsset())
			sep[0] = ifsval()[0];
		else
			sep[0] = ' ';
		sep[1] = '\0';
		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
			strtodest(p, flag, subtype, quoted, dst);
			if (!*ap)
				break;
			if (sep[0])
				strtodest(sep, flag, subtype, quoted, dst);
			else if (flag & EXP_SPLIT && !quoted && **ap != '\0') {
				if (splitlater)
					STPUTC('\0', expdest);
				else
					NEXTWORD('\0', flag, expdest, dst);
			}
		}
		return;
	default:
		if (is_digit(*name)) {
			num = atoi(name);
			if (num == 0)
				p = arg0;
			else if (num > 0 && num <= shellparam.nparam)
				p = shellparam.p[num - 1];
			else
				return;
			strtodest(p, flag, subtype, quoted, dst);
		}
		return;
	}
	cvtnum(num, buf);
	strtodest(buf, flag, subtype, quoted, dst);
}
Example #10
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;
	lastc = '\0';
	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 #11
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 char *
argstr(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);
		}
	}
}
Example #12
0
/*
 * Break the argument string into pieces based upon IFS and add the
 * strings to the argument list.  The regions of the string to be
 * searched for IFS characters have been stored by recordregion.
 */
STATIC void
ifsbreakup(char *string, struct arglist *arglist)
{
	struct ifsregion *ifsp;
	struct strlist *sp;
	char *start;
	char *p;
	char *q;
	char *ifs;
	int ifsspc;
	int nulonly;


	start = string;
	ifsspc = 0;
	nulonly = 0;
	if (ifslastp != NULL) {
		ifsp = &ifsfirst;
		do {
			p = string + ifsp->begoff;
			nulonly = ifsp->nulonly;
			ifs = nulonly ? nullstr :
				( ifsset() ? ifsval() : " \t\n" );
			ifsspc = 0;
			while (p < string + ifsp->endoff) {
				q = p;
				if (*p == CTLESC)
					p++;
				if (strchr(ifs, *p)) {
					if (!nulonly)
						ifsspc = (strchr(" \t\n", *p) != NULL);
					/* Ignore IFS whitespace at start */
					if (q == start && ifsspc) {
						p++;
						start = p;
						continue;
					}
					*q = '\0';
					sp = (struct strlist *)stalloc(sizeof *sp);
					sp->text = start;
					*arglist->lastp = sp;
					arglist->lastp = &sp->next;
					p++;
					if (!nulonly) {
						for (;;) {
							if (p >= string + ifsp->endoff) {
								break;
							}
							q = p;
							if (*p == CTLESC)
								p++;
							if (strchr(ifs, *p) == NULL ) {
								p = q;
								break;
							} else if (strchr(" \t\n",*p) == NULL) {
								if (ifsspc) {
									p++;
									ifsspc = 0;
								} else {
									p = q;
									break;
								}
							} else
								p++;
						}
					}
					start = p;
				} else
					p++;
			}
		} while ((ifsp = ifsp->next) != NULL);
		if (*start || (!ifsspc && start > string)) {
			sp = (struct strlist *)stalloc(sizeof *sp);
			sp->text = start;
			*arglist->lastp = sp;
			arglist->lastp = &sp->next;
		}
	} else {
		sp = (struct strlist *)stalloc(sizeof *sp);
		sp->text = start;
		*arglist->lastp = sp;
		arglist->lastp = &sp->next;
	}
}