sh.dol.c revision 65b0c20e9bbaf87a200ce20a4decf18585e61a25
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley Software License Agreement
* specifies the terms and conditions for redistribution.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <unistd.h> /* for lseek prototype */
#include "sh.h"
#include "sh.tconst.h"
/*
* C shell
*/
/*
* These routines perform variable substitution and quoting via ' and ".
* To this point these constructs have been preserved in the divided
* input words. Here we expand variables and turn quoting via ' and " into
* QUOTE bits on characters (which prevent further interpretation).
* If the `:q' modifier was applied during history expansion, then
* some QUOTEing may have occurred already, so we dont "trim()" here.
*/
#define DEOF -1
/*
* The following variables give the information about the current
* $ expansion, recording the current word position, the remaining
* words within this expansion, the count of remaining words, and the
* information about any : modifier which is being applied.
*/
int dolcnt; /* Count of further words */
int dolmcnt; /* :gx -> 10000, else 1 */
void Dgetdol(void);
void unDredc(int);
/*
* Fix up the $ expansions and quotations in the
* argument list to command t.
*/
void
{
tchar *p;
#ifdef TRACE
tprintf("TRACE- Dfix()\n");
#endif
if (noexec)
return;
/* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
while (*p)
gargv = 0;
return;
}
}
/*
* $ substitute one word, for i/o redirection
*/
tchar *
{
#ifdef TRACE
tprintf("TRACE- Dfix1()\n");
#endif
if (noexec)
return (0);
if (gargc != 1) {
bferr("Ambiguous");
}
return (cp);
}
/*
* Subroutine to do actual fixing after state initialization.
*/
void
{
#ifdef TRACE
tprintf("TRACE- Dfix2()\n");
#endif
while (Dword())
continue;
}
/*
* 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;
int wp = 0;
bool dolflg;
bool sofar = 0;
#define DYNAMICBUFFER() \
do { \
} \
} while (0)
#ifdef TRACE
tprintf("TRACE- Dword()\n");
#endif
loop:
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':
goto ret;
case ' ':
case '\t':
goto loop;
case '`':
/* We preserve ` quotations which are done yet later */
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;
for (;;) {
if (c == c1)
break;
if (c == '\n' || c == DEOF)
--wp;
switch (c1) {
case '"':
/*
* Leave any `s alone for later.
* Other chars are all quoted, thus `...`
* can tell it was within "...".
*/
break;
case '\'':
/* Prevent all further interpretation */
break;
case '`':
/* Leave all text alone for later */
break;
}
}
if (c1 == '`') {
}
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:
#endif /* MBCHAR */
}
unDgetC(c);
pack:
sofar = 1;
/* pack up more characters in this word */
for (;;) {
if (c == '\\') {
c = DgetC(0);
if (c == DEOF)
goto deof;
if (c == '\n')
c = ' ';
else
c |= QUOTE;
}
if (c == DEOF)
goto deof;
isauxsp(c)) { /* sp \t\n'"` or aux. sp */
unDgetC(c);
goto loop;
goto ret;
}
}
ret:
return (1);
}
/*
* Get a character, performing $ substitution unless flag is 0.
* Any QUOTES character which is returned from a $ expansion is
* QUOTEd so that it will not be recognized above.
*/
int
{
int c;
top:
if (c = Dpeekc) {
Dpeekc = 0;
return (c);
}
if (lap) {
if (c == 0) {
lap = 0;
goto top;
}
/*
* don't quote things if there was an error (err!=0)
* the input is original, not from a substitution and
* therefore should not be quoted
*/
return (c | QUOTE);
return (c);
}
if (dolp) {
goto quotspec;
if (dolcnt > 0) {
--dolcnt;
return (' ');
}
dolp = 0;
}
if (dolcnt > 0) {
--dolcnt;
goto top;
}
c = Dredc();
if (c == '$' && flag) {
Dgetdol();
goto top;
}
return (c);
}
/*
* Handle the multitudinous $ expansion forms.
* Ugh.
*/
void
Dgetdol(void)
{
int c, sc;
#ifdef TRACE
tprintf("TRACE- Dgetdol()\n");
#endif
if (c == '{')
c = DgetC(0); /* sc is { to take } later */
if ((c & TRIM) == '#')
else if (c == '?')
switch (c) {
case '$':
goto eatbrac;
case '<'|QUOTE:
goto syntax; /* No $?<, $#< */
error("$< line too long");
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;
goto eatbrac;
case DEOF:
case '\n':
goto syntax;
case '*':
break;
default:
if (digit(c)) {
if (dimen)
goto syntax; /* No $#1, e.g. */
subscr = 0;
do {
c = DgetC(0);
} while (digit(c));
unDredc(c);
if (subscr < 0)
error("Subscript out of range");
if (subscr == 0) {
if (bitset) {
goto eatbrac;
}
if (file == 0)
error("No file for $0");
goto eatbrac;
}
if (bitset)
goto syntax;
if (vp == 0) {
goto eatmod;
}
break;
}
if (!alnum(c))
goto syntax;
for (;;) {
*np++ = c;
c = DgetC(0);
if (!alnum(c))
break;
/* if variable name is > 20, complain */
error("Variable name too long");
}
*np++ = 0;
unDredc(c);
}
if (bitset) {
/*
* getenv() to getenv_(), because 'name''s type is now tchar *
* no need to xalloc
*/
goto eatbrac;
}
if (vp == 0) {
/*
* getenv() to getenv_(), because 'name''s type is now tchar *
* no need to xalloc
*/
if (np) {
goto eatbrac;
}
/*NOTREACHED*/
}
c = DgetC(0);
for (;;) {
if (c == ']')
break;
if (c == '\n' || c == DEOF)
goto syntax;
error("Variable reference too long");
*np++ = c;
}
goto syntax;
if (!*np)
goto syntax;
int i = 0;
/* if ((i < 0 || i > upb) && !any(*np, "-*")) { */
oob:
error("Subscript out of range");
}
lwb = i;
if (!*np)
}
if (*np == '*')
np++;
else if (*np != '-')
goto syntax;
else {
int i = upb;
np++;
i = 0;
if (i < 0 || i > upb)
goto oob;
}
if (i < lwb)
else
upb = i;
}
if (lwb == 0) {
if (upb != 0)
goto oob;
upb = -1;
}
if (*np)
goto syntax;
} else {
if (subscr > 0)
else
unDredc(c);
}
if (dimen) {
} else {
c = DgetC(0);
if (c == ':') {
if (c == 'g')
error("Bad : mod in $");
dolmod = c;
if (c == 'q')
dolmcnt = 10000;
} else
unDredc(c);
}
if (sc == '{') {
c = Dredc();
if (c != '}')
goto syntax;
}
}
void
{
#ifdef TRACE
tprintf("TRACE- setDolp()\n");
#endif
return;
}
if (dp) {
dolmcnt--;
} else
}
void
unDredc(int c)
{
Dpeekrd = c;
}
int
Dredc()
{
int c;
if (c = Dpeekrd) {
Dpeekrd = 0;
return (c);
}
if (*Dvp == 0) {
Dcp = 0;
return (DEOF);
}
return (' ');
}
void
Dtestq(int c)
{
gflag = 1;
}
/*
* 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
{
int c;
bool quoted;
'X', 'X', 'X', 0};
int fd1;
#ifdef TRACE
tprintf("TRACE- heredoc()\n");
#endif
for (;;) {
/*
* Read up a line
*/
for (;;) {
if (c < 0) {
bferr("<< terminator not found");
}
if (c == '\n')
break;
if (c &= TRIM) {
*lbp++ = c;
if (--lcnt < 0) {
error("Line overflow");
}
}
}
*lbp = 0;
/*
* Compare to terminator -- before expansion
*/
return;
}
/*
* If term was quoted or -n just pass it on
*/
*obp++ = c;
if (--ocnt == 0) {
}
}
continue;
}
/*
* Term wasn't quoted so variable and then command
* expand the input line
*/
for (;;) {
if (c == DEOF)
break;
if ((c &= TRIM) == 0)
continue;
/* \ quotes \ $ ` here */
if (c == '\\') {
c = DgetC(0);
/* if (!any(c, "$\\`")) */
if ((c != '$') && (c != '\\') && (c != '`'))
else
c |= QUOTE;
}
*mbp++ = c;
if (--mcnt == 0) {
bferr("Line overflow");
}
}
*mbp++ = 0;
/*
* If any ` in line do command substitution
*/
/*
* 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.
*/
} else
/* Setup trivial vector similar to return of dobackp */
/*
* 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!
*/
if (--ocnt == 0) {
}
}
*obp++ = '\n';
if (--ocnt == 0) {
}
}
if (pargv)
}
}