Exemple #1
0
/*
 * Pack up more characters in this word
 */
static int
Dpack(struct Strbuf *wbuf)
{
    eChar c;

    for (;;) {
	c = DgetC(DODOL);
	if (c == '\\') {
	    c = DgetC(0);
	    if (c == DEOF) {
		unDredc(c);
		return 1;
	    }
	    if (c == '\n')
		c = ' ';
	    else
		c |= QUOTE;
	}
	if (c == DEOF) {
	    unDredc(c);
	    return 1;
	}
	if (cmap(c, _SP | _NL | _QF | _QB)) {	/* sp \t\n'"` */
	    unDgetC(c);
	    if (cmap(c, QUOTES))
		return 0;
	    return 1;
	}
	Strbuf_append1(wbuf, (Char) c);
    }
}
Exemple #2
0
static void
fixDolMod(void)
{
    int c;

    c = DgetC(0);
    if (c == ':') {
	do {
	    c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
	    if (c == 'g' || c == 'a') {
		if (c == 'g')
		    dolmcnt = 10000;
		else
		    dolwcnt = 10000;
		c = DgetC(0);
	    }
	    if ((c == 'g' && dolmcnt != 10000) ||
		(c == 'a' && dolwcnt != 10000)) {
		if (c == 'g')
		    dolmcnt = 10000;
		else
		    dolwcnt = 10000;
		c = DgetC(0);
	    }

	    if (c == 's') {	/* [eichin:19910926.0755EST] */
		int delimcnt = 2;
		int delim = DgetC(0);
		dolmod[dolnmod++] = c;
		dolmod[dolnmod++] = delim;

		if (!delim || letter(delim)
		    || Isdigit(delim) || any(" \t\n", delim)) {
		    seterror(ERR_BADSUBST);
		    break;
		}
		while ((c = DgetC(0)) != (-1)) {
		    dolmod[dolnmod++] = c;
		    if(c == delim) delimcnt--;
		    if(!delimcnt) break;
		}
		if(delimcnt) {
		    seterror(ERR_BADSUBST);
		    break;
		}
		continue;
	    }
	    if (!any("htrqxes", c))
		stderror(ERR_BADMOD, c);
	    dolmod[dolnmod++] = c;
	    if (c == 'q')
		dolmcnt = 10000;
	}
	while ((c = DgetC(0)) == ':');
	unDredc(c);
    }
    else
	unDredc(c);
}
Exemple #3
0
static void
fixDolMod(void)
{
    eChar c;

    c = DgetC(0);
    if (c == ':') {
	do {
	    c = DgetC(0), dolmcnt = 1, dol_flag_a = 0;
	    if (c == 'g' || c == 'a') {
		if (c == 'g')
		    dolmcnt = INT_MAX;
		else
		    dol_flag_a = 1;
		c = DgetC(0);
	    }
	    if ((c == 'g' && dolmcnt != INT_MAX) || 
		(c == 'a' && dol_flag_a == 0)) {
		if (c == 'g')
		    dolmcnt = INT_MAX;
		else
		    dol_flag_a = 1;
		c = DgetC(0);
	    }

	    if (c == 's') {	/* [eichin:19910926.0755EST] */
		int delimcnt = 2;
		eChar delim = DgetC(0);
		Strbuf_append1(&dolmod, (Char) c);
		Strbuf_append1(&dolmod, (Char) delim);

		if (delim == DEOF || !delim || letter(delim)
		    || Isdigit(delim) || any(" \t\n", delim)) {
		    seterror(ERR_BADSUBST);
		    break;
		}	
		while ((c = DgetC(0)) != DEOF) {
		    Strbuf_append1(&dolmod, (Char) c);
		    if(c == delim) delimcnt--;
		    if(!delimcnt) break;
		}
		if(delimcnt) {
		    seterror(ERR_BADSUBST);
		    break;
		}
		continue;
	    }
	    if (!any("luhtrqxes", c))
		stderror(ERR_BADMOD, (int)c);
	    Strbuf_append1(&dolmod, (Char) c);
	    if (c == 'q')
		dolmcnt = INT_MAX;
	}
	while ((c = DgetC(0)) == ':');
	unDredc(c);
    }
    else
	unDredc(c);
}
Exemple #4
0
/*
 * Pack up more characters in this word
 */
static Char *
Dpack(Char *wbuf, Char *wp)
{
    int c;
    int i = MAXWLEN - (wp - wbuf);

    for (;;) {
	c = DgetC(DODOL);
	if (c == '\\') {
	    c = DgetC(0);
	    if (c == DEOF) {
		unDredc(c);
		*wp = 0;
		Gcat(STRNULL, wbuf);
		return (NULL);
	    }
	    if (c == '\n')
		c = ' ';
	    else
		c |= QUOTE;
	}
	if (c == DEOF) {
	    unDredc(c);
	    *wp = 0;
	    Gcat(STRNULL, wbuf);
	    return (NULL);
	}
	if (cmap(c, _SP | _NL | _QF | _QB)) {	/* sp \t\n'"` */
	    unDgetC(c);
	    if (cmap(c, QUOTES))
		return (wp);
	    *wp++ = 0;
	    Gcat(STRNULL, wbuf);
	    return (NULL);
	}
	if (--i <= 0)
	    stderror(ERR_WTOOLONG);
	*wp++ = c;
    }
}
Exemple #5
0
/*
 * Form a shell temporary file (in unit 0) from the words
 * of the shell input up to EOF or a line the same as "term".
 * Unit 0 should have been closed before this call.
 */
void
/*ARGSUSED*/
heredoc(Char *term)
{
    int c;
    Char   *Dv[2];
    Char    obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
    int     ocnt, lcnt, mcnt;
    Char *lbp, *obp, *mbp;
    Char  **vp;
    bool    quoted;
    char   tmp[] = "/tmp/sh.XXXXXXXX";

    if (mkstemp(tmp) < 0)
	stderror(ERR_SYSTEM, tmp, strerror(errno));
    (void) unlink(tmp);		/* 0 0 inode! */
    Dv[0] = term;
    Dv[1] = NULL;
    gflag = 0;
    trim(Dv);
    rscan(Dv, Dtestq);
    quoted = gflag;
    ocnt = BUFSIZ;
    obp = obuf;
    for (;;) {
	/*
	 * Read up a line
	 */
	lbp = lbuf;
	lcnt = BUFSIZ - 4;
	for (;;) {
	    c = readc(1);	/* 1 -> Want EOF returns */
	    if (c < 0 || c == '\n')
		break;
	    if ((c &= TRIM) != '\0') {
		*lbp++ = c;
		if (--lcnt < 0) {
		    setname("<<");
		    stderror(ERR_NAME | ERR_OVERFLOW);
		}
	    }
	}
	*lbp = 0;

	/*
	 * Check for EOF or compare to terminator -- before expansion
	 */
	if (c < 0 || eq(lbuf, term)) {
	    (void) write(STDIN_FILENO, short2str(obuf), 
	        (size_t) (BUFSIZ - ocnt));
	    (void) lseek(STDIN_FILENO, (off_t) 0, SEEK_SET);
	    return;
	}

	/*
	 * If term was quoted or -n just pass it on
	 */
	if (quoted || noexec) {
	    *lbp++ = '\n';
	    *lbp = 0;
	    for (lbp = lbuf; (c = *lbp++) != '\0';) {
		*obp++ = c;
		if (--ocnt == 0) {
		    (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ);
		    obp = obuf;
		    ocnt = BUFSIZ;
		}
	    }
	    continue;
	}

	/*
	 * Term wasn't quoted so variable and then command expand the input
	 * line
	 */
	Dcp = lbuf;
	Dvp = Dv + 1;
	mbp = mbuf;
	mcnt = BUFSIZ - 4;
	for (;;) {
	    c = DgetC(DODOL);
	    if (c == DEOF)
		break;
	    if ((c &= TRIM) == 0)
		continue;
	    /* \ quotes \ $ ` here */
	    if (c == '\\') {
		c = DgetC(0);
		if (!any("$\\`", c))
		    unDgetC(c | QUOTE), c = '\\';
		else
		    c |= QUOTE;
	    }
	    *mbp++ = c;
	    if (--mcnt == 0) {
		setname("<<");
		stderror(ERR_NAME | ERR_OVERFLOW);
	    }
	}
	*mbp++ = 0;

	/*
	 * If any ` in line do command substitution
	 */
	mbp = mbuf;
	if (any(short2str(mbp), '`')) {
	    /*
	     * 1 arg to dobackp causes substitution to be literal. Words are
	     * broken only at newlines so that all blanks and tabs are
	     * preserved.  Blank lines (null words) are not discarded.
	     */
	    vp = dobackp(mbuf, 1);
	}
	else
	    /* Setup trivial vector similar to return of dobackp */
	    Dv[0] = mbp, Dv[1] = NULL, vp = Dv;

	/*
	 * Resurrect the words from the command substitution each separated by
	 * a newline.  Note that the last newline of a command substitution
	 * will have been discarded, but we put a newline after the last word
	 * because this represents the newline after the last input line!
	 */
	for (; *vp; vp++) {
	    for (mbp = *vp; *mbp; mbp++) {
		*obp++ = *mbp & TRIM;
		if (--ocnt == 0) {
		    (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ);
		    obp = obuf;
		    ocnt = BUFSIZ;
		}
	    }
	    *obp++ = '\n';
	    if (--ocnt == 0) {
		(void) write(STDIN_FILENO, short2str(obuf), BUFSIZ);
		obp = obuf;
		ocnt = BUFSIZ;
	    }
	}
	if (pargv)
	    blkfree(pargv), pargv = 0;
    }
}
Exemple #6
0
/*
 * Handle the multitudinous $ expansion forms.
 * Ugh.
 */
static void
Dgetdol(void)
{
    Char *np;
    struct varent *vp = NULL;
    Char    name[4 * MAXVARLEN + 1];
    int     c, sc;
    int     subscr = 0, lwb = 1, upb = 0;
    bool    dimen = 0, bitset = 0;
    char    tnp;
    Char    wbuf[BUFSIZ];
    static Char *dolbang = NULL;

    dolnmod = dolmcnt = dolwcnt = 0;
    c = sc = DgetC(0);
    if (c == '{')
	c = DgetC(0);		/* sc is { to take } later */
    if ((c & TRIM) == '#')
	dimen++, c = DgetC(0);	/* $# takes dimension */
    else if (c == '?')
	bitset++, c = DgetC(0);	/* $? tests existence */
    switch (c) {

    case '!':
	if (dimen || bitset)
	    stderror(ERR_SYNTAX);
	if (backpid != 0) {
	    if (dolbang)
		xfree(dolbang);
	    setDolp(dolbang = putn(backpid));
	}
	goto eatbrac;

    case '$':
	if (dimen || bitset)
	    stderror(ERR_SYNTAX);
	setDolp(doldol);
	goto eatbrac;

    case '<' | QUOTE:
	if (bitset)
	    stderror(ERR_NOTALLOWED, "$?<");
	if (dimen)
	    stderror(ERR_NOTALLOWED, "$?#");
	for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
	    *np = (unsigned char) tnp;
	    if (np >= &wbuf[BUFSIZ - 1])
		stderror(ERR_LTOOLONG);
	    if (tnp == '\n')
		break;
	}
	*np = 0;
	/*
	 * KLUDGE: dolmod is set here because it will cause setDolp to call
	 * domod and thus to copy wbuf. Otherwise setDolp would use it
	 * directly. If we saved it ourselves, no one would know when to free
	 * it. The actual function of the 'q' causes filename expansion not to
	 * be done on the interpolated value.
	 */
	dolmod[dolnmod++] = 'q';
	dolmcnt = 10000;
	setDolp(wbuf);
	goto eatbrac;

    case DEOF:
    case '\n':
	stderror(ERR_SYNTAX);
	/* NOTREACHED */
	break;

    case '*':
	(void) Strlcpy(name, STRargv, sizeof name/sizeof(Char));
	vp = adrof(STRargv);
	subscr = -1;		/* Prevent eating [...] */
	break;

    default:
	np = name;
	if (Isdigit(c)) {
	    if (dimen)
		stderror(ERR_NOTALLOWED, "$#<num>");
	    subscr = 0;
	    do {
		subscr = subscr * 10 + c - '0';
		c = DgetC(0);
	    } while (Isdigit(c));
	    unDredc(c);
	    if (subscr < 0)
		stderror(ERR_RANGE);
	    if (subscr == 0) {
		if (bitset) {
		    dolp = ffile ? STR1 : STR0;
		    goto eatbrac;
		}
		if (ffile == 0)
		    stderror(ERR_DOLZERO);
		fixDolMod();
		setDolp(ffile);
		goto eatbrac;
	    }
	    if (bitset)
		stderror(ERR_DOLQUEST);
	    vp = adrof(STRargv);
	    if (vp == 0) {
		vp = &nulargv;
		goto eatmod;
	    }
	    break;
	}
	if (!alnum(c))
	    stderror(ERR_VARALNUM);
	for (;;) {
	    *np++ = c;
	    c = DgetC(0);
	    if (!alnum(c))
		break;
	    if (np >= &name[MAXVARLEN])
		stderror(ERR_VARTOOLONG);
	}
	*np++ = 0;
	unDredc(c);
	vp = adrof(name);
    }
    if (bitset) {
	dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
	goto eatbrac;
    }
    if (vp == 0) {
	np = str2short(getenv(short2str(name)));
	if (np) {
	    fixDolMod();
	    setDolp(np);
	    goto eatbrac;
	}
	udvar(name);
	/* NOTREACHED */
    }
    c = DgetC(0);
    upb = blklen(vp->vec);
    if (dimen == 0 && subscr == 0 && c == '[') {
	np = name;
	for (;;) {
	    c = DgetC(DODOL);	/* Allow $ expand within [ ] */
	    if (c == ']')
		break;
	    if (c == '\n' || c == DEOF)
		stderror(ERR_INCBR);
	    if (np >= &name[sizeof(name) / sizeof(Char) - 2])
		stderror(ERR_VARTOOLONG);
	    *np++ = c;
	}
	*np = 0, np = name;
	if (dolp || dolcnt)	/* $ exp must end before ] */
	    stderror(ERR_EXPORD);
	if (!*np)
	    stderror(ERR_SYNTAX);
	if (Isdigit(*np)) {
	    int     i;

	    for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
		continue;
	    if ((i < 0 || i > upb) && !any("-*", *np)) {
		dolerror(vp->v_name);
		return;
	    }
	    lwb = i;
	    if (!*np)
		upb = lwb, np = STRstar;
	}
	if (*np == '*')
	    np++;
	else if (*np != '-')
	    stderror(ERR_MISSING, '-');
	else {
	    int i = upb;

	    np++;
	    if (Isdigit(*np)) {
		i = 0;
		while (Isdigit(*np))
		    i = i * 10 + *np++ - '0';
		if (i < 0 || i > upb) {
		    dolerror(vp->v_name);
		    return;
		}
	    }
	    if (i < lwb)
		upb = lwb - 1;
	    else
		upb = i;
	}
	if (lwb == 0) {
	    if (upb != 0) {
		dolerror(vp->v_name);
		return;
	    }
	    upb = -1;
	}
	if (*np)
	    stderror(ERR_SYNTAX);
    }
    else {
	if (subscr > 0) {
	    if (subscr > upb)
		lwb = 1, upb = 0;
	    else
		lwb = upb = subscr;
	}
	unDredc(c);
    }
    if (dimen) {
	Char   *cp = putn(upb - lwb + 1);

	addla(cp);
	xfree(cp);
    }
    else {
eatmod:
	fixDolMod();
	dolnxt = &vp->vec[lwb - 1];
	dolcnt = upb - lwb + 1;
    }
eatbrac:
    if (sc == '{') {
	c = Dredc();
	if (c != '}')
	    stderror(ERR_MISSING, '}');
    }
}
Exemple #7
0
/*
 * Get a word.  This routine is analogous to the routine
 * word() in sh.lex.c for the main lexical input.  One difference
 * here is that we don't get a newline to terminate our expansion.
 * Rather, DgetC will return a DEOF when we hit the end-of-input.
 */
static int
Dword(void)
{
    int c, c1;
    Char    wbuf[BUFSIZ];
    Char *wp = wbuf;
    int i = MAXWLEN;
    bool dolflg;
    bool    sofar = 0, done = 0;

    while (!done) {
	done = 1;
	c = DgetC(DODOL);
	switch (c) {

	case DEOF:
	    if (sofar == 0)
		return (0);
	    /* finish this word and catch the code above the next time */
	    unDredc(c);
	    /* fall into ... */

	case '\n':
	    *wp = 0;
	    Gcat(STRNULL, wbuf);
	    return (1);

	case ' ':
	case '\t':
	    done = 0;
	    break;

	case '`':
	    /* We preserve ` quotations which are done yet later */
	    *wp++ = c, --i;
	case '\'':
	case '"':
	    /*
	     * Note that DgetC never returns a QUOTES character from an
	     * expansion, so only true input quotes will get us here or out.
	     */
	    c1 = c;
	    dolflg = c1 == '"' ? DODOL : 0;
	    for (;;) {
		c = DgetC(dolflg);
		if (c == c1)
		    break;
		if (c == '\n' || c == DEOF)
		    stderror(ERR_UNMATCHED, c1);
		if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE))
		    --wp, ++i;
		if (--i <= 0)
		    stderror(ERR_WTOOLONG);
		switch (c1) {

		case '"':
		    /*
		     * Leave any `s alone for later. Other chars are all
		     * quoted, thus `...` can tell it was within "...".
		     */
		    *wp++ = c == '`' ? '`' : c | QUOTE;
		    break;

		case '\'':
		    /* Prevent all further interpretation */
		    *wp++ = c | QUOTE;
		    break;

		case '`':
		    /* Leave all text alone for later */
		    *wp++ = c;
		    break;

		default:
		    break;
		}
	    }
	    if (c1 == '`')
		*wp++ = '`' /* i--; eliminated */;
	    sofar = 1;
	    if ((wp = Dpack(wbuf, wp)) == NULL)
		return (1);
	    else {
		i = MAXWLEN - (wp - wbuf);
		done = 0;
	    }
	    break;

	case '\\':
	    c = DgetC(0);	/* No $ subst! */
	    if (c == '\n' || c == DEOF) {
		done = 0;
		break;
	    }
	    c |= QUOTE;
	    break;

	default:
	    break;
	}
	if (done) {
	    unDgetC(c);
	    sofar = 1;
	    if ((wp = Dpack(wbuf, wp)) == NULL)
		return (1);
	    else {
		i = MAXWLEN - (wp - wbuf);
		done = 0;
	    }
	}
    }
    /* Really NOTREACHED */
    return (0);
}
Exemple #8
0
/*
 * Form a shell temporary file (in unit 0) from the words
 * of the shell input up to EOF or a line the same as "term".
 * Unit 0 should have been closed before this call.
 */
void
heredoc(Char *term)
{
    eChar  c;
    Char   *Dv[2];
    struct Strbuf lbuf = Strbuf_INIT, mbuf = Strbuf_INIT;
    Char    obuf[BUFSIZE + 1];
#define OBUF_END (obuf + sizeof(obuf) / sizeof (*obuf) - 1)
    Char *lbp, *obp, *mbp;
    Char  **vp;
    int    quoted;
#ifdef HAVE_MKSTEMP
    char   *tmp = short2str(shtemp);
    char   *dot = strrchr(tmp, '.');

    if (!dot)
	stderror(ERR_NAME | ERR_NOMATCH);
    strcpy(dot, TMP_TEMPLATE);

    xclose(0);
    if (mkstemp(tmp) == -1)
	stderror(ERR_SYSTEM, tmp, strerror(errno));
#else /* !HAVE_MKSTEMP */
    char   *tmp;
# ifndef WINNT_NATIVE

again:
# endif /* WINNT_NATIVE */
    tmp = short2str(shtemp);
# if O_CREAT == 0
    if (xcreat(tmp, 0600) < 0)
	stderror(ERR_SYSTEM, tmp, strerror(errno));
# endif
    xclose(0);
    if (xopen(tmp, O_RDWR|O_CREAT|O_EXCL|O_TEMPORARY|O_LARGEFILE, 0600) ==
	-1) {
	int oerrno = errno;
# ifndef WINNT_NATIVE
	if (errno == EEXIST) {
	    if (unlink(tmp) == -1) {
		xfree(shtemp);
		mbp = randsuf();
		shtemp = Strspl(STRtmpsh, mbp);
		xfree(mbp);
	    }
	    goto again;
	}
# endif /* WINNT_NATIVE */
	(void) unlink(tmp);
	errno = oerrno;
 	stderror(ERR_SYSTEM, tmp, strerror(errno));
    }
#endif /* HAVE_MKSTEMP */
    (void) unlink(tmp);		/* 0 0 inode! */
    Dv[0] = term;
    Dv[1] = NULL;
    gflag = 0;
    trim(Dv);
    rscan(Dv, Dtestq);
    quoted = gflag;
    obp = obuf;
    obuf[BUFSIZE] = 0;
    inheredoc = 1;
    cleanup_push(&inheredoc, inheredoc_cleanup);
#ifdef WINNT_NATIVE
    __dup_stdin = 1;
#endif /* WINNT_NATIVE */
    cleanup_push(&lbuf, Strbuf_cleanup);
    cleanup_push(&mbuf, Strbuf_cleanup);
    for (;;) {
	Char **words;

	/*
	 * Read up a line
	 */
	lbuf.len = 0;
	for (;;) {
	    c = readc(1);	/* 1 -> Want EOF returns */
	    if (c == CHAR_ERR || c == '\n')
		break;
	    if ((c &= TRIM) != 0)
		Strbuf_append1(&lbuf, (Char) c);
	}
	Strbuf_terminate(&lbuf);

	/* Catch EOF in the middle of a line. */
	if (c == CHAR_ERR && lbuf.len != 0)
	    c = '\n';

	/*
	 * Check for EOF or compare to terminator -- before expansion
	 */
	if (c == CHAR_ERR || eq(lbuf.s, term))
	    break;

	/*
	 * If term was quoted or -n just pass it on
	 */
	if (quoted || noexec) {
	    Strbuf_append1(&lbuf, '\n');
	    Strbuf_terminate(&lbuf);
	    for (lbp = lbuf.s; (c = *lbp++) != 0;) {
		*obp++ = (Char) c;
		if (obp == OBUF_END) {
		    tmp = short2str(obuf);
		    (void) xwrite(0, tmp, strlen (tmp));
		    obp = obuf;
		}
	    }
	    continue;
	}

	/*
	 * Term wasn't quoted so variable and then command expand the input
	 * line
	 */
	Dcp = lbuf.s;
	Dvp = Dv + 1;
	mbuf.len = 0;
	for (;;) {
	    c = DgetC(DODOL);
	    if (c == DEOF)
		break;
	    if ((c &= TRIM) == 0)
		continue;
	    /* \ quotes \ $ ` here */
	    if (c == '\\') {
		c = DgetC(0);
		if (!any("$\\`", c))
		    unDgetC(c | QUOTE), c = '\\';
		else
		    c |= QUOTE;
	    }
	    Strbuf_append1(&mbuf, (Char) c);
	}
	Strbuf_terminate(&mbuf);

	/*
	 * If any ` in line do command substitution
	 */
	mbp = mbuf.s;
	if (Strchr(mbp, '`') != NULL) {
	    /*
	     * 1 arg to dobackp causes substitution to be literal. Words are
	     * broken only at newlines so that all blanks and tabs are
	     * preserved.  Blank lines (null words) are not discarded.
	     */
	    words = dobackp(mbp, 1);
	}
	else
	    /* Setup trivial vector similar to return of dobackp */
	    Dv[0] = mbp, Dv[1] = NULL, words = Dv;

	/*
	 * Resurrect the words from the command substitution each separated by
	 * a newline.  Note that the last newline of a command substitution
	 * will have been discarded, but we put a newline after the last word
	 * because this represents the newline after the last input line!
	 */
	for (vp= words; *vp; vp++) {
	    for (mbp = *vp; *mbp; mbp++) {
		*obp++ = *mbp & TRIM;
		if (obp == OBUF_END) {
		    tmp = short2str(obuf);
		    (void) xwrite(0, tmp, strlen (tmp));
		    obp = obuf;
		}
	    }
	    *obp++ = '\n';
	    if (obp == OBUF_END) {
	        tmp = short2str(obuf);
		(void) xwrite(0, tmp, strlen (tmp));
		obp = obuf;
	    }
	}
	if (words != Dv)
	    blkfree(words);
    }
    *obp = 0;
    tmp = short2str(obuf);
    (void) xwrite(0, tmp, strlen (tmp));
    (void) lseek(0, (off_t) 0, L_SET);
    cleanup_until(&inheredoc);
}
Exemple #9
0
/*
 * Handle the multitudinous $ expansion forms.
 * Ugh.
 */
static void
Dgetdol(void)
{
    Char *np;
    struct varent *vp = NULL;
    struct Strbuf *name = Strbuf_alloc();
    eChar   c, sc;
    int     subscr = 0, lwb = 1, upb = 0;
    int    dimen = 0, bitset = 0, length = 0;
    static Char *dolbang = NULL;

    cleanup_push(name, Strbuf_free);
    dolmod.len = dolmcnt = dol_flag_a = 0;
    c = sc = DgetC(0);
    if (c == DEOF) {
      stderror(ERR_SYNTAX);
      return;
    }
    if (c == '{')
	c = DgetC(0);		/* sc is { to take } later */
    if ((c & TRIM) == '#')
	dimen++, c = DgetC(0);	/* $# takes dimension */
    else if (c == '?')
	bitset++, c = DgetC(0);	/* $? tests existence */
    else if (c == '%')
	length++, c = DgetC(0); /* $% returns length in chars */
    switch (c) {

    case '!':
	if (dimen || bitset || length)
	    stderror(ERR_SYNTAX);
	if (backpid != 0) {
	    xfree(dolbang);
	    setDolp(dolbang = putn((tcsh_number_t)backpid));
	}
	cleanup_until(name);
	goto eatbrac;

    case '$':
	if (dimen || bitset || length)
	    stderror(ERR_SYNTAX);
	setDolp(doldol);
	cleanup_until(name);
	goto eatbrac;

    case '<'|QUOTE: {
	static struct Strbuf wbuf; /* = Strbuf_INIT; */

	if (bitset)
	    stderror(ERR_NOTALLOWED, "$?<");
	if (dimen)
	    stderror(ERR_NOTALLOWED, "$#<");
	if (length)
	    stderror(ERR_NOTALLOWED, "$%<");
	wbuf.len = 0;
	{
	    char cbuf[MB_LEN_MAX];
	    size_t cbp = 0;
	    int old_pintr_disabled;

	    for (;;) {
	        int len;
		ssize_t res;
		Char wc;

		pintr_push_enable(&old_pintr_disabled);
		res = force_read(OLDSTD, cbuf + cbp, 1);
		cleanup_until(&old_pintr_disabled);
		if (res != 1)
		    break;
		cbp++;
		len = normal_mbtowc(&wc, cbuf, cbp);
		if (len == -1) {
		    reset_mbtowc();
		    if (cbp < MB_LEN_MAX)
		        continue; /* Maybe a partial character */
		    wc = (unsigned char)*cbuf | INVALID_BYTE;
		}
		if (len <= 0)
		    len = 1;
		if (cbp != (size_t)len)
		    memmove(cbuf, cbuf + len, cbp - len);
		cbp -= len;
		if (wc == '\n')
		    break;
		Strbuf_append1(&wbuf, wc);
	    }
	    while (cbp != 0) {
		int len;
		Char wc;

		len = normal_mbtowc(&wc, cbuf, cbp);
		if (len == -1) {
		    reset_mbtowc();
		    wc = (unsigned char)*cbuf | INVALID_BYTE;
		}
		if (len <= 0)
		    len = 1;
		if (cbp != (size_t)len)
		    memmove(cbuf, cbuf + len, cbp - len);
		cbp -= len;
		if (wc == '\n')
		    break;
		Strbuf_append1(&wbuf, wc);
	    }
	    Strbuf_terminate(&wbuf);
	}

	fixDolMod();
	setDolp(wbuf.s); /* Kept allocated until next $< expansion */
	cleanup_until(name);
	goto eatbrac;
    }

    case '*':
	Strbuf_append(name, STRargv);
	Strbuf_terminate(name);
	vp = adrof(STRargv);
	subscr = -1;		/* Prevent eating [...] */
	break;

    case DEOF:
    case '\n':
	np = dimen ? STRargv : (bitset ? STRstatus : NULL);
	if (np) {
	    bitset = 0;
	    Strbuf_append(name, np);
	    Strbuf_terminate(name);
	    vp = adrof(np);
	    subscr = -1;		/* Prevent eating [...] */
	    unDredc(c);
	    break;
	}
	else
	    stderror(ERR_SYNTAX);
	/*NOTREACHED*/

    default:
	if (Isdigit(c)) {
	    if (dimen)
		stderror(ERR_NOTALLOWED, "$#<num>");
	    subscr = 0;
	    do {
		subscr = subscr * 10 + c - '0';
		c = DgetC(0);
	    } while (c != DEOF && Isdigit(c));
	    unDredc(c);
	    if (subscr < 0)
		stderror(ERR_RANGE);
	    if (subscr == 0) {
		if (bitset) {
		    dolp = dolzero ? STR1 : STR0;
		    cleanup_until(name);
		    goto eatbrac;
		}
		if (ffile == 0)
		    stderror(ERR_DOLZERO);
		if (length) {
		    length = Strlen(ffile);
		    addla(putn((tcsh_number_t)length));
		}
		else {
		    fixDolMod();
		    setDolp(ffile);
		}
		cleanup_until(name);
		goto eatbrac;
	    }
#if 0
	    if (bitset)
		stderror(ERR_NOTALLOWED, "$?<num>");
	    if (length)
		stderror(ERR_NOTALLOWED, "$%<num>");
#endif
	    vp = adrof(STRargv);
	    if (vp == 0) {
		vp = &nulargv;
		cleanup_until(name);
		goto eatmod;
	    }
	    break;
	}
	if (c == DEOF || !alnum(c)) {
	    np = dimen ? STRargv : (bitset ? STRstatus : NULL);
	    if (np) {
		bitset = 0;
		Strbuf_append(name, np);
		Strbuf_terminate(name);
		vp = adrof(np);
		subscr = -1;		/* Prevent eating [...] */
		unDredc(c);
		break;
	    }
	    else
		stderror(ERR_VARALNUM);
	}
	for (;;) {
	    Strbuf_append1(name, (Char) c);
	    c = DgetC(0);
	    if (c == DEOF || !alnum(c))
		break;
	}
	Strbuf_terminate(name);
	unDredc(c);
	vp = adrof(name->s);
    }
    if (bitset) {
	dolp = (vp || getenv(short2str(name->s))) ? STR1 : STR0;
	cleanup_until(name);
	goto eatbrac;
    }
    if (vp == NULL || vp->vec == NULL) {
	np = str2short(getenv(short2str(name->s)));
	if (np) {
	    static Char *env_val; /* = NULL; */

	    cleanup_until(name);
	    fixDolMod();
	    if (length) {
		    addla(putn((tcsh_number_t)Strlen(np)));
	    } else {
		    xfree(env_val);
		    env_val = Strsave(np);
		    setDolp(env_val);
	    }
	    goto eatbrac;
	}
	udvar(name->s);
	/* NOTREACHED */
    }
    cleanup_until(name);
    c = DgetC(0);
    upb = blklen(vp->vec);
    if (dimen == 0 && subscr == 0 && c == '[') {
	name = Strbuf_alloc();
	cleanup_push(name, Strbuf_free);
	np = name->s;
	for (;;) {
	    c = DgetC(DODOL);	/* Allow $ expand within [ ] */
	    if (c == ']')
		break;
	    if (c == '\n' || c == DEOF)
		stderror(ERR_INCBR);
	    Strbuf_append1(name, (Char) c);
	}
	Strbuf_terminate(name);
	np = name->s;
	if (dolp || dolcnt)	/* $ exp must end before ] */
	    stderror(ERR_EXPORD);
	if (!*np)
	    stderror(ERR_SYNTAX);
	if (Isdigit(*np)) {
	    int     i;

	    for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
		continue;
	    if (i < 0 || (i > upb && !any("-*", *np))) {
		cleanup_until(name);
		dolerror(vp->v_name);
		return;
	    }
	    lwb = i;
	    if (!*np)
		upb = lwb, np = STRstar;
	}
	if (*np == '*')
	    np++;
	else if (*np != '-')
	    stderror(ERR_MISSING, '-');
	else {
	    int i = upb;

	    np++;
	    if (Isdigit(*np)) {
		i = 0;
		while (Isdigit(*np))
		    i = i * 10 + *np++ - '0';
		if (i < 0 || i > upb) {
		    cleanup_until(name);
		    dolerror(vp->v_name);
		    return;
		}
	    }
	    if (i < lwb)
		upb = lwb - 1;
	    else
		upb = i;
	}
	if (lwb == 0) {
	    if (upb != 0) {
		cleanup_until(name);
		dolerror(vp->v_name);
		return;
	    }
	    upb = -1;
	}
	if (*np)
	    stderror(ERR_SYNTAX);
	cleanup_until(name);
    }
    else {
	if (subscr > 0) {
	    if (subscr > upb)
		lwb = 1, upb = 0;
	    else
		lwb = upb = subscr;
	}
	unDredc(c);
    }
    if (dimen) {
	/* this is a kludge. It prevents Dgetdol() from */
	/* pushing erroneous ${#<error> values into the labuf. */
	if (sc == '{') {
	    c = Dredc();
	    if (c != '}')
		stderror(ERR_MISSING, '}');
	    unDredc(c);
	}
	addla(putn((tcsh_number_t)(upb - lwb + 1)));
    }
    else if (length) {
	int i;

	for (i = lwb - 1, length = 0; i < upb; i++)
	    length += Strlen(vp->vec[i]);
#ifdef notdef
	/* We don't want that, since we can always compute it by adding $#xxx */
	length += i - 1;	/* Add the number of spaces in */
#endif
	addla(putn((tcsh_number_t)length));
    }
    else {
eatmod:
	fixDolMod();
	dolnxt = &vp->vec[lwb - 1];
	dolcnt = upb - lwb + 1;
    }
eatbrac:
    if (sc == '{') {
	c = Dredc();
	if (c != '}')
	    stderror(ERR_MISSING, '}');
    }
}
Exemple #10
0
/*
 * Get a word.  This routine is analogous to the routine
 * word() in sh.lex.c for the main lexical input.  One difference
 * here is that we don't get a newline to terminate our expansion.
 * Rather, DgetC will return a DEOF when we hit the end-of-input.
 */
static int
Dword(struct blk_buf *bb)
{
    eChar c, c1;
    struct Strbuf *wbuf = Strbuf_alloc();
    int dolflg;
    int    sofar = 0;
    Char *str;

    cleanup_push(wbuf, Strbuf_free);
    for (;;) {
	c = DgetC(DODOL);
	switch (c) {

	case DEOF:
	    if (sofar == 0) {
		cleanup_until(wbuf);
		return (0);
	    }
	    /* finish this word and catch the code above the next time */
	    unDredc(c);
	    /*FALLTHROUGH*/

	case '\n':
	    goto end;

	case ' ':
	case '\t':
	    continue;

	case '`':
	    /* We preserve ` quotations which are done yet later */
	    Strbuf_append1(wbuf, (Char) c);
	    /*FALLTHROUGH*/
	case '\'':
	case '"':
	    /*
	     * Note that DgetC never returns a QUOTES character from an
	     * expansion, so only true input quotes will get us here or out.
	     */
	    c1 = c;
	    dolflg = c1 == '"' ? DODOL : 0;
	    for (;;) {
		c = DgetC(dolflg);
		if (c == c1)
		    break;
		if (c == '\n' || c == DEOF) {
		    cleanup_until(bb);
		    stderror(ERR_UNMATCHED, (int)c1);
		}
		if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE)) {
		    if (wbuf->len != 0 && (wbuf->s[wbuf->len - 1] & TRIM) == '\\')
			wbuf->len--;
		}
		switch (c1) {

		case '"':
		    /*
		     * Leave any `s alone for later. Other chars are all
		     * quoted, thus `...` can tell it was within "...".
		     */
		    Strbuf_append1(wbuf, c == '`' ? '`' : c | QUOTE);
		    break;

		case '\'':
		    /* Prevent all further interpretation */
		    Strbuf_append1(wbuf, c | QUOTE);
		    break;

		case '`':
		    /* Leave all text alone for later */
		    Strbuf_append1(wbuf, (Char) c);
		    break;

		default:
		    break;
		}
	    }
	    if (c1 == '`')
		Strbuf_append1(wbuf, '`');
	    sofar = 1;
	    if (Dpack(wbuf) != 0)
		goto end;
	    continue;

	case '\\':
	    c = DgetC(0);	/* No $ subst! */
	    if (c == '\n' || c == DEOF)
		continue;
	    c |= QUOTE;
	    break;

	default:
	    break;
	}
	unDgetC(c);
	sofar = 1;
	if (Dpack(wbuf) != 0)
	    goto end;
    }

 end:
    cleanup_ignore(wbuf);
    cleanup_until(wbuf);
    str = Strbuf_finish(wbuf);
    bb_append(bb, str);
    xfree(wbuf);
    return 1;
}
Exemple #11
0
/*
 * Form a shell temporary file (in unit 0) from the words
 * of the shell input up to a line the same as "term".
 * Unit 0 should have been closed before this call.
 */
void
heredoc(tchar *term)
{
	int c;
	tchar *Dv[2];
	tchar obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
	int ocnt, lcnt, mcnt;
	tchar *lbp, *obp, *mbp;
	tchar **vp;
	bool quoted;
	tchar shtemp[] = {'/', 't', 'm', 'p', '/', 's', 'h', 'X', 'X', 'X',
'X', 'X', 'X', 0};
	int fd1;

#ifdef TRACE
	tprintf("TRACE- heredoc()\n");
#endif
	if ((fd1 = mkstemp_(shtemp)) < 0)
		Perror(shtemp);
	(void) unlink_(shtemp);			/* 0 0 inode! */
	unsetfd(fd1);
	Dv[0] = term; Dv[1] = NOSTR; gflag = 0;
	trim(Dv); rscan(Dv, Dtestq); quoted = gflag;
	ocnt = BUFSIZ; obp = obuf;
	for (;;) {
		/*
		 * Read up a line
		 */
		lbp = lbuf; lcnt = BUFSIZ - 4;
		for (;;) {
			c = readc(1);		/* 1 -> Want EOF returns */
			if (c < 0) {
				setname(term);
				bferr("<< terminator not found");
			}
			if (c == '\n')
				break;
			if (c &= TRIM) {
				*lbp++ = c;
				if (--lcnt < 0) {
					setname(S_LESLES /* "<<" */);
					error("Line overflow");
				}
			}
		}
		*lbp = 0;

		/*
		 * Compare to terminator -- before expansion
		 */
		if (eq(lbuf, term)) {
			(void) write_(0, obuf, BUFSIZ - ocnt);
			(void) lseek(0, (off_t)0, 0);
			return;
		}

		/*
		 * If term was quoted or -n just pass it on
		 */
		if (quoted || noexec) {
			*lbp++ = '\n'; *lbp = 0;
			for (lbp = lbuf; c = *lbp++; ) {
				*obp++ = c;
				if (--ocnt == 0) {
					(void) write_(0, obuf, BUFSIZ);
					obp = obuf; ocnt = BUFSIZ;
				}
			}
			continue;
		}

		/*
		 * Term wasn't quoted so variable and then command
		 * expand the input line
		 */
		Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4;
		for (;;) {
			c = DgetC(DODOL);
			if (c == DEOF)
				break;
			if ((c &= TRIM) == 0)
				continue;
			/* \ quotes \ $ ` here */
			if (c == '\\') {
				c = DgetC(0);
/*				if (!any(c, "$\\`")) */
				if ((c != '$') && (c != '\\') && (c != '`'))
					unDgetC(c | QUOTE), c = '\\';
				else
					c |= QUOTE;
			}
			*mbp++ = c;
			if (--mcnt == 0) {
				setname(S_LESLES /* "<<" */);
				bferr("Line overflow");
			}
		}
		*mbp++ = 0;

		/*
		 * If any ` in line do command substitution
		 */
		mbp = mbuf;
		if (any('`', mbp)) {
			/*
			 * 1 arg to dobackp causes substitution to be literal.
			 * Words are broken only at newlines so that all blanks
			 * and tabs are preserved.  Blank lines (null words)
			 * are not discarded.
			 */
			vp = dobackp(mbuf, 1);
		} else
			/* Setup trivial vector similar to return of dobackp */
			Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv;

		/*
		 * Resurrect the words from the command substitution
		 * each separated by a newline.  Note that the last
		 * newline of a command substitution will have been
		 * discarded, but we put a newline after the last word
		 * because this represents the newline after the last
		 * input line!
		 */
		for (; *vp; vp++) {
			for (mbp = *vp; *mbp; mbp++) {
				*obp++ = *mbp & TRIM;
				if (--ocnt == 0) {
					(void) write_(0, obuf, BUFSIZ);
					obp = obuf; ocnt = BUFSIZ;
				}
			}
			*obp++ = '\n';
			if (--ocnt == 0) {
				(void) write_(0, obuf, BUFSIZ);
				obp = obuf; ocnt = BUFSIZ;
			}
		}
		if (pargv)
			blkfree(pargv), pargv = 0;
	}
}
Exemple #12
0
/*
 * Handle the multitudinous $ expansion forms.
 * Ugh.
 */
void
Dgetdol(void)
{
	tchar *np;
	struct varent *vp;
	tchar name[MAX_VREF_LEN];
	int c, sc;
	int subscr = 0, lwb = 1, upb = 0;
	bool dimen = 0, bitset = 0;
	tchar wbuf[BUFSIZ + MB_LEN_MAX]; /* read_ may return extra bytes */

#ifdef TRACE
	tprintf("TRACE- Dgetdol()\n");
#endif
	dolmod = dolmcnt = 0;
	c = sc = DgetC(0);
	if (c == '{')
		c = DgetC(0);		/* sc is { to take } later */
	if ((c & TRIM) == '#')
		dimen++, c = DgetC(0);		/* $# takes dimension */
	else if (c == '?')
		bitset++, c = DgetC(0);		/* $? tests existence */
	switch (c) {

	case '$':
		if (dimen || bitset)
syntax:
		error("Variable syntax");  /* No $?$, $#$ */
		setDolp(doldol);
		goto eatbrac;

	case '<'|QUOTE:
		if (dimen || bitset)
			goto syntax;		/* No $?<, $#< */
		for (np = wbuf; read_(OLDSTD, np, 1) == 1; np++) {
			if (np >= &wbuf[BUFSIZ-1])
				error("$< line too long");
			if (*np <= 0 || *np == '\n')
				break;
		}
		*np = 0;
		/*
		 * KLUDGE: dolmod is set here because it will
		 * cause setDolp to call domod and thus to copy wbuf.
		 * Otherwise setDolp would use it directly. If we saved
		 * it ourselves, no one would know when to free it.
		 * The actual function of the 'q' causes filename
		 * expansion not to be done on the interpolated value.
		 */
		dolmod = 'q';
		dolmcnt = 10000;
		setDolp(wbuf);
		goto eatbrac;

	case DEOF:
	case '\n':
		goto syntax;

	case '*':
		(void) strcpy_(name, S_argv);
		vp = adrof(S_argv);
		subscr = -1;			/* Prevent eating [...] */
		break;

	default:
		np = name;
		if (digit(c)) {
			if (dimen)
				goto syntax;	/* No $#1, e.g. */
			subscr = 0;
			do {
				subscr = subscr * 10 + c - '0';
				c = DgetC(0);
			} while (digit(c));
			unDredc(c);
			if (subscr < 0)
				error("Subscript out of range");
			if (subscr == 0) {
				if (bitset) {
					dolp = file ? S_1 /* "1" */ : S_0 /* "0" */;
					goto eatbrac;
				}
				if (file == 0)
					error("No file for $0");
				setDolp(file);
				goto eatbrac;
			}
			if (bitset)
				goto syntax;
			vp = adrof(S_argv);
			if (vp == 0) {
				vp = &nulargv;
				goto eatmod;
			}
			break;
		}
		if (!alnum(c))
			goto syntax;
		for (;;) {
			*np++ = c;
			c = DgetC(0);
			if (!alnum(c))
				break;
			/* if variable name is > 20, complain */
			if (np >= &name[MAX_VAR_LEN])
				error("Variable name too long");

		}
		*np++ = 0;
		unDredc(c);
		vp = adrof(name);
	}
	if (bitset) {
		/*
		 * getenv() to getenv_(), because 'name''s type is now tchar *
		 * no need to xalloc
		 */
		dolp = (vp || getenv_(name)) ? S_1 /* "1" */ : S_0 /* "0" */;
		goto eatbrac;
	}
	if (vp == 0) {
		/*
		 * getenv() to getenv_(), because 'name''s type is now tchar *
		 * no need to xalloc
		 */
		np = getenv_(name);
		if (np) {
			addla(np);
			goto eatbrac;
		}
		udvar(name);
		/*NOTREACHED*/
	}
	c = DgetC(0);
	upb = blklen(vp->vec);
	if (dimen == 0 && subscr == 0 && c == '[') {
		np = name;
		for (;;) {
			c = DgetC(DODOL);	/* Allow $ expand within [ ] */
			if (c == ']')
				break;
			if (c == '\n' || c == DEOF)
				goto syntax;
			if (np >= &name[MAX_VREF_LEN])
				error("Variable reference too long");
			*np++ = c;
		}
		*np = 0, np = name;
		if (dolp || dolcnt)		/* $ exp must end before ] */
			goto syntax;
		if (!*np)
			goto syntax;
		if (digit(*np)) {
			int i = 0;

			while (digit(*np))
				i = i * 10 + *np++ - '0';
/*			if ((i < 0 || i > upb) && !any(*np, "-*")) { */
			if ((i < 0 || i > upb) && (*np != '-') && (*np != '*')) {
oob:
				setname(vp->v_name);
				error("Subscript out of range");
			}
			lwb = i;
			if (!*np)
				upb = lwb, np = S_AST /* "*" */;
		}
		if (*np == '*')
			np++;
		else if (*np != '-')
			goto syntax;
		else {
			int i = upb;

			np++;
			if (digit(*np)) {
				i = 0;
				while (digit(*np))
					i = i * 10 + *np++ - '0';
				if (i < 0 || i > upb)
					goto oob;
			}
			if (i < lwb)
				upb = lwb - 1;
			else
				upb = i;
		}
		if (lwb == 0) {
			if (upb != 0)
				goto oob;
			upb = -1;
		}
		if (*np)
			goto syntax;
	} else {
		if (subscr > 0)
			if (subscr > upb)
				lwb = 1, upb = 0;
			else
				lwb = upb = subscr;
		unDredc(c);
	}
	if (dimen) {
		tchar *cp = putn(upb - lwb + 1);

		addla(cp);
		xfree(cp);
	} else {
eatmod:
		c = DgetC(0);
		if (c == ':') {
			c = DgetC(0), dolmcnt = 1;
			if (c == 'g')
				c = DgetC(0), dolmcnt = 10000;
			if (!any(c, S_htrqxe))
				error("Bad : mod in $");
			dolmod = c;
			if (c == 'q')
				dolmcnt = 10000;
		} else
			unDredc(c);
		dolnxt = &vp->vec[lwb - 1];
		dolcnt = upb - lwb + 1;
	}
eatbrac:
	if (sc == '{') {
		c = Dredc();
		if (c != '}')
			goto syntax;
	}
}
Exemple #13
0
/*
 * Get a word.  This routine is analogous to the routine
 * word() in sh.lex.c for the main lexical input.  One difference
 * here is that we don't get a newline to terminate our expansion.
 * Rather, DgetC will return a DEOF when we hit the end-of-input.
 */
int
Dword(void)
{
	int c, c1;
	static tchar *wbuf = NULL;
	static int wbufsiz = BUFSIZ;
	int wp = 0;
	bool dolflg;
	bool sofar = 0;
#define	DYNAMICBUFFER() \
	do { \
		if (wp >= wbufsiz) { \
			wbufsiz += BUFSIZ; \
			wbuf = xrealloc(wbuf, (wbufsiz+1) * sizeof (tchar)); \
		} \
	} while (0)

#ifdef TRACE
	tprintf("TRACE- Dword()\n");
#endif
	if (wbuf == NULL)
		wbuf = xalloc((wbufsiz+1) * sizeof (tchar));
loop:
	c = DgetC(DODOL);
	switch (c) {

	case DEOF:
deof:
		if (sofar == 0)
			return (0);
		/* finish this word and catch the code above the next time */
		unDredc(c);
		/* fall into ... */

	case '\n':
		wbuf[wp] = 0;
		goto ret;

	case ' ':
	case '\t':
		goto loop;

	case '`':
		/* We preserve ` quotations which are done yet later */
		wbuf[wp++] = c;
	case '\'':
	case '"':
		/*
		 * Note that DgetC never returns a QUOTES character
		 * from an expansion, so only true input quotes will
		 * get us here or out.
		 */
		c1 = c;
		dolflg = c1 == '"' ? DODOL : 0;
		for (;;) {
			c = DgetC(dolflg);
			if (c == c1)
				break;
			if (c == '\n' || c == DEOF)
				error("Unmatched %c", (tchar) c1);
			if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
				--wp;
			DYNAMICBUFFER();
			switch (c1) {

			case '"':
				/*
				 * Leave any `s alone for later.
				 * Other chars are all quoted, thus `...`
				 * can tell it was within "...".
				 */
				wbuf[wp++] = c == '`' ? '`' : c | QUOTE;
				break;

			case '\'':
				/* Prevent all further interpretation */
				wbuf[wp++] = c | QUOTE;
				break;

			case '`':
				/* Leave all text alone for later */
				wbuf[wp++] = c;
				break;
			}
		}
		if (c1 == '`') {
			DYNAMICBUFFER();
			wbuf[wp++] = '`';
		}
		goto pack;		/* continue the word */

	case '\\':
		c = DgetC(0);		/* No $ subst! */
		if (c == '\n' || c == DEOF)
			goto loop;
		c |= QUOTE;
		break;
#ifdef MBCHAR /* Could be a space char from aux. codeset. */
	default:
		if (isauxsp(c)) goto loop;
#endif /* MBCHAR */
	}
	unDgetC(c);
pack:
	sofar = 1;
	/* pack up more characters in this word */
	for (;;) {
		c = DgetC(DODOL);
		if (c == '\\') {
			c = DgetC(0);
			if (c == DEOF)
				goto deof;
			if (c == '\n')
				c = ' ';
			else
				c |= QUOTE;
		}
		if (c == DEOF)
			goto deof;
		if (cmap(c, _SP|_NL|_Q|_Q1) ||
		    isauxsp(c)) {		/* sp \t\n'"` or aux. sp */
			unDgetC(c);
			if (cmap(c, QUOTES))
				goto loop;
			DYNAMICBUFFER();
			wbuf[wp++] = 0;
			goto ret;
		}
		DYNAMICBUFFER();
		wbuf[wp++] = c;
	}
ret:
	Gcat(S_ /* "" */, wbuf);
	return (1);
}