/* * 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 */ /* * UNIX shell */ #include "defs.h" #include "sym.h" #include 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; }