/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* UNIX shell
*/
#include "defs.h"
#include "sym.h"
#include <wait.h>
static unsigned char quote; /* used locally */
static unsigned char quoted; /* used locally */
static int getch();
static void comsubst(int);
static void flush(int);
static void
copyto(unsigned char endch, int trimflag)
/* trimflag - flag to check if argument will be trimmed */
{
unsigned int c;
unsigned int d;
unsigned char *pc;
while ((c = getch(endch, trimflag)) != endch && c)
if (quote) {
if(c == '\\') { /* don't interpret next character */
if (staktop >= brkend)
growstak(staktop);
pushstak(c);
d = readwc();
if(!escchar(d)) { /* both \ and following
character are quoted if next
character is not $, `, ", or \*/
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
pc = readw(d);
/* push entire multibyte char */
while(*pc) {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc++);
}
} else {
pc = readw(d);
/* d might be NULL */
/* Evenif d is NULL, we have to save it */
if (*pc) {
while (*pc) {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc++);
}
} else {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc);
}
}
} else { /* push escapes onto stack to quote characters */
pc = readw(c);
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
while(*pc) {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc++);
}
}
} else if(c == '\\') {
c = readwc(); /* get character to be escaped */
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
pc = readw(c);
/* c might be NULL */
/* Evenif c is NULL, we have to save it */
if (*pc) {
while (*pc) {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc++);
}
} else {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc);
}
} else {
pc = readw(c);
while (*pc) {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc++);
}
}
if (staktop >= brkend)
growstak(staktop);
zerostak();
if (c != endch)
error(badsub);
}
static void
skipto(unsigned char endch)
{
/*
* skip chars up to }
*/
unsigned int c;
while ((c = readwc()) && c != endch)
{
switch (c)
{
case SQUOTE:
skipto(SQUOTE);
break;
case DQUOTE:
skipto(DQUOTE);
break;
case DOLLAR:
if (readwc() == BRACE)
skipto('}');
}
}
if (c != endch)
error(badsub);
}
static
int getch(endch, trimflag)
unsigned char endch;
int trimflag; /* flag to check if an argument is going to be trimmed, here document
output is never trimmed
*/
{
unsigned int d;
int atflag; /* flag to check if $@ has already been seen within double
quotes */
retry:
d = readwc();
if (!subchar(d))
return(d);
if (d == DOLLAR)
{
unsigned int c;
if ((c = readwc(), dolchar(c)))
{
struct namnod *n = (struct namnod *)NIL;
int dolg = 0;
BOOL bra;
BOOL nulflg;
unsigned char *argp, *v;
unsigned char idb[2];
unsigned char *id = idb;
if (bra = (c == BRACE))
c = readwc();
if (letter(c))
{
argp = (unsigned char *)relstak();
while (alphanum(c))
{
if (staktop >= brkend)
growstak(staktop);
pushstak(c);
c = readwc();
}
if (staktop >= brkend)
growstak(staktop);
zerostak();
n = lookup(absstak(argp));
setstak(argp);
if (n->namflg & N_FUNCTN)
error(badsub);
v = n->namval;
id = (unsigned char *)n->namid;
peekc = c | MARK;
}
else if (digchar(c))
{
*id = c;
idb[1] = 0;
if (astchar(c))
{
if(c == '@' && !atflag && quote) {
quoted--;
atflag = 1;
}
dolg = 1;
c = '1';
}
c -= '0';
v = ((c == 0) ? cmdadr : ((int)c <= dolc) ? dolv[c] : (unsigned char *)(dolg = 0));
}
else if (c == '$')
v = pidadr;
else if (c == '!')
v = pcsadr;
else if (c == '#')
{
itos(dolc);
v = numbuf;
}
else if (c == '?')
{
itos(retval);
v = numbuf;
}
else if (c == '-')
v = flagadr;
else if (bra)
error(badsub);
else
goto retry;
c = readwc();
if (c == ':' && bra) /* null and unset fix */
{
nulflg = 1;
c = readwc();
}
else
nulflg = 0;
if (!defchar(c) && bra)
error(badsub);
argp = 0;
if (bra)
{
if (c != '}')
{
argp = (unsigned char *)relstak();
if ((v == 0 || (nulflg && *v == 0)) ^ (setchar(c)))
copyto('}', trimflag);
else
skipto('}');
argp = absstak(argp);
}
}
else
{
peekc = c | MARK;
c = 0;
}
if (v && (!nulflg || *v))
{
if (c != '+')
{
for (;;)
{
if (*v == 0 && quote) {
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
if (staktop >= brkend)
growstak(staktop);
pushstak('\0');
} else {
while (c = *v) {
wchar_t wc;
int length;
if ((length = mbtowc(&wc, (char *)v, MB_LEN_MAX)) <= 0)
length = 1;
if(quote || (c == '\\' && trimflag)) {
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
}
while(length-- > 0) {
if (staktop >= brkend)
growstak(staktop);
pushstak(*v++);
}
}
}
if (dolg == 0 || (++dolg > dolc))
break;
else /* $* and $@ expansion */
{
v = dolv[dolg];
if(*id == '*' && quote) {
/* push quoted space so that " $* " will not be broken into separate arguments */
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
}
if (staktop >= brkend)
growstak(staktop);
pushstak(' ');
}
}
}
}
else if (argp)
{
if (c == '?') {
if(trimflag)
trim(argp);
failed(id, *argp ? (const char *)argp :
badparam);
}
else if (c == '=')
{
if (n)
{
int strlngth = staktop - stakbot;
unsigned char *savptr = fixstak();
unsigned char *newargp;
/*
* copy word onto stack, trim it, and then
* do assignment
*/
usestak();
while(c = *argp) {
wchar_t wc;
int len;
if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0)
len = 1;
if(c == '\\' && trimflag) {
argp++;
if (*argp == 0) {
argp++;
continue;
}
if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0)
len = 1;
}
while(len-- > 0) {
if (staktop >= brkend)
growstak(staktop);
pushstak(*argp++);
}
}
newargp = fixstak();
assign(n, newargp);
tdystak(savptr);
(void) memcpystak(stakbot, savptr, strlngth);
staktop = stakbot + strlngth;
}
else
error(badsub);
}
}
else if (flags & setflg)
failed(id, unset);
goto retry;
}
else
peekc = c | MARK;
}
else if (d == endch)
return(d);
else if (d == SQUOTE)
{
comsubst(trimflag);
goto retry;
}
else if (d == DQUOTE && trimflag)
{
if(!quote) {
atflag = 0;
quoted++;
}
quote ^= QUOTE;
goto retry;
}
return(d);
}
unsigned char *
macro(as)
unsigned char *as;
{
/*
* Strip "" and do $ substitution
* Leaves result on top of stack
*/
BOOL savqu = quoted;
unsigned char savq = quote;
struct filehdr fb;
push(&fb);
estabf(as);
usestak();
quote = 0;
quoted = 0;
copyto(0, 1);
pop();
if (quoted && (stakbot == staktop)) {
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
if (staktop >= brkend)
growstak(staktop);
pushstak('\0');
/*
* above is the fix for *'.c' bug
*/
}
quote = savq;
quoted = savqu;
return(fixstak());
}
/* Save file descriptor for command substitution */
int savpipe = -1;
static void
comsubst(int trimflag)
/* trimflag - used to determine if argument will later be trimmed */
{
/*
* command substn
*/
struct fileblk cb;
unsigned int d;
int strlngth = staktop - stakbot;
unsigned char *oldstaktop;
unsigned char *savptr = fixstak();
unsigned char *pc;
usestak();
while ((d = readwc()) != SQUOTE && d) {
if(d == '\\') {
d = readwc();
if(!escchar(d) || (d == '"' && !quote)) {
/* trim quotes for `, \, or " if command substitution is within
double quotes */
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
}
}
pc = readw(d);
/* d might be NULL */
if (*pc) {
while (*pc) {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc++);
}
} else {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc);
}
}
{
unsigned char *argc;
argc = fixstak();
push(&cb);
estabf(argc); /* read from string */
}
{
struct trenod *t;
int pv[2];
/*
* this is done like this so that the pipe
* is open only when needed
*/
t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG ));
chkpipe(pv);
savpipe = pv[OTPIPE];
initf(pv[INPIPE]); /* read from pipe */
execute(t, XEC_NOSTOP, (int)(flags & errflg), 0, pv);
close(pv[OTPIPE]);
savpipe = -1;
}
tdystak(savptr);
(void) memcpystak(stakbot, savptr, strlngth);
oldstaktop = staktop = stakbot + strlngth;
while (d = readwc()) {
if(quote || (d == '\\' && trimflag)) {
unsigned char *rest;
/* quote output from command subst. if within double
quotes or backslash part of output */
rest = readw(d);
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
while(d = *rest++) {
/* Pick up all of multibyte character */
if (staktop >= brkend)
growstak(staktop);
pushstak(d);
}
}
else {
pc = readw(d);
while (*pc) {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc++);
}
}
}
{
extern pid_t parent;
int stat;
int rc;
int ret = 0;
while ((ret = waitpid(parent,&stat,0)) != parent) {
/* break out if waitpid(2) has failed */
if (ret == -1)
break;
}
if (WIFEXITED(stat))
rc = WEXITSTATUS(stat);
else
rc = (WTERMSIG(stat) | SIGFLG);
if (rc && (flags & errflg))
exitsh(rc);
exitval = rc;
flags |= eflag;
exitset();
}
while (oldstaktop != staktop)
{ /* strip off trailing newlines from command substitution only */
if ((*--staktop) != NL)
{
++staktop;
break;
} else if(quote)
staktop--; /* skip past backslashes if quoting */
}
pop();
}
#define CPYSIZ 512
void
subst(int in, int ot)
{
unsigned int c;
struct fileblk fb;
int count = CPYSIZ;
unsigned char *pc;
push(&fb);
initf(in);
/*
* DQUOTE used to stop it from quoting
*/
while (c = (getch(DQUOTE, 0))) /* read characters from here document
and interpret them */
{
if(c == '\\') {
c = readwc(); /* check if character in here document is
escaped */
if(!escchar(c) || c == '"') {
if (staktop >= brkend)
growstak(staktop);
pushstak('\\');
}
}
pc = readw(c);
/* c might be NULL */
if (*pc) {
while (*pc) {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc++);
}
} else {
if (staktop >= brkend)
growstak(staktop);
pushstak(*pc);
}
if (--count == 0)
{
flush(ot);
count = CPYSIZ;
}
}
flush(ot);
pop();
}
static void
flush(int ot)
{
write(ot, stakbot, staktop - stakbot);
if (flags & execpr)
write(output, stakbot, staktop - stakbot);
staktop = stakbot;
}