diff options
Diffstat (limited to 'src/cmd/ksh93/sh/args.c')
-rw-r--r-- | src/cmd/ksh93/sh/args.c | 892 |
1 files changed, 892 insertions, 0 deletions
diff --git a/src/cmd/ksh93/sh/args.c b/src/cmd/ksh93/sh/args.c new file mode 100644 index 0000000..4d27580 --- /dev/null +++ b/src/cmd/ksh93/sh/args.c @@ -0,0 +1,892 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1982-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* David Korn <dgk@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * UNIX shell + * + * S. R. Bourne + * Rewritten by David Korn + * AT&T Labs + * + */ + +#include "defs.h" +#include "path.h" +#include "builtins.h" +#include "terminal.h" +#include "edit.h" +#include "FEATURE/poll" +#if SHOPT_KIA +# include "shlex.h" +# include "io.h" +#endif /* SHOPT_KIA */ +#if SHOPT_PFSH +# define PFSHOPT "P" +#else +# define PFSHOPT +#endif +#if SHOPT_BASH +# define BASHOPT "\374" +#else +# define BASHOPT +#endif +#if SHOPT_HISTEXPAND +# define HFLAG "H" +#else +# define HFLAG "" +#endif + +#define SORT 1 +#define PRINT 2 + +static char *null; + +/* The following order is determined by sh_optset */ +static const char optksh[] = PFSHOPT BASHOPT "DircabefhkmnpstuvxBCGEl" HFLAG; +static const int flagval[] = +{ +#if SHOPT_PFSH + SH_PFSH, +#endif +#if SHOPT_BASH + SH_POSIX, +#endif + SH_DICTIONARY, SH_INTERACTIVE, SH_RESTRICTED, SH_CFLAG, + SH_ALLEXPORT, SH_NOTIFY, SH_ERREXIT, SH_NOGLOB, SH_TRACKALL, + SH_KEYWORD, SH_MONITOR, SH_NOEXEC, SH_PRIVILEGED, SH_SFLAG, SH_TFLAG, + SH_NOUNSET, SH_VERBOSE, SH_XTRACE, SH_BRACEEXPAND, SH_NOCLOBBER, + SH_GLOBSTARS, SH_RC, SH_LOGIN_SHELL, +#if SHOPT_HISTEXPAND + SH_HISTEXPAND, +#endif + 0 +}; + +#define NUM_OPTS (sizeof(flagval)/sizeof(*flagval)) + +typedef struct _arg_ +{ + Shell_t *sh; + struct dolnod *argfor; /* linked list of blocks to be cleaned up */ + struct dolnod *dolh; + char flagadr[NUM_OPTS+1]; +#if SHOPT_KIA + char *kiafile; +#endif /* SHOPT_KIA */ +} Arg_t; + +static int arg_expand(Shell_t*,struct argnod*,struct argnod**,int); +static void sh_argset(Arg_t*, char *[]); + + +/* ======== option handling ======== */ + +void *sh_argopen(Shell_t *shp) +{ + void *addr = newof(0,Arg_t,1,0); + Arg_t *ap = (Arg_t*)addr; + ap->sh = shp; + return(addr); +} + +static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp) +{ +#if SHOPT_BASH + extern const char sh_bash1[], sh_bash2[]; + if(strcmp(s,"bash1")==0) + { + if(sh_isoption(SH_BASH)) + sfputr(sp,sh_bash1,-1); + } + else if(strcmp(s,"bash2")==0) + { + if(sh_isoption(SH_BASH)) + sfputr(sp,sh_bash2,-1); + } + else if(*s==':' && sh_isoption(SH_BASH)) + sfputr(sp,s,-1); + else +#endif + if(*s!=':') + sfputr(sp,sh_set,-1); + return(1); +} + +/* + * This routine turns options on and off + * The options "PDicr" are illegal from set command. + * The -o option is used to set option by name + * This routine returns the number of non-option arguments + */ +int sh_argopts(int argc,register char *argv[], void *context) +{ + Shell_t *shp = (Shell_t*)context; + register int n,o; + register Arg_t *ap = (Arg_t*)(shp->arg_context); + Lex_t *lp = (Lex_t*)(shp->lex_context); + Shopt_t newflags; + int setflag=0, action=0, trace=(int)sh_isoption(SH_XTRACE); + Namval_t *np = NIL(Namval_t*); + const char *cp; + int verbose,f; + Optdisc_t disc; + newflags=ap->sh->options; + memset(&disc, 0, sizeof(disc)); + disc.version = OPT_VERSION; + disc.infof = infof; + opt_info.disc = &disc; + + if(argc>0) + setflag = 4; + else + argc = -argc; + while((n = optget(argv,setflag?sh_optset:sh_optksh))) + { + o=0; + f=*opt_info.option=='-' && (opt_info.num || opt_info.arg); + switch(n) + { + case 'A': + np = nv_open(opt_info.arg,ap->sh->var_tree,NV_NOASSIGN|NV_ARRAY|NV_VARNAME); + if(f) + nv_unset(np); + continue; +#if SHOPT_BASH + case 'O': /* shopt options, only in bash mode */ + if(!sh_isoption(SH_BASH)) + errormsg(SH_DICT,ERROR_exit(1), e_option, opt_info.name); +#endif + case 'o': /* set options */ + byname: + if(!opt_info.arg||!*opt_info.arg||*opt_info.arg=='-') + { + action = PRINT; + /* print style: -O => shopt options + * bash => print unset options also, no heading + */ + verbose = (f?PRINT_VERBOSE:PRINT_NO_HEADER)| + (n=='O'?PRINT_SHOPT:0)| + (sh_isoption(SH_BASH)?PRINT_ALL|PRINT_NO_HEADER:0)| + ((opt_info.arg&&(!*opt_info.arg||*opt_info.arg=='-'))?(PRINT_TABLE|PRINT_NO_HEADER):0); + continue; + } + o = sh_lookopt(opt_info.arg,&f); + if(o<=0 + || (!sh_isoption(SH_BASH) && (o&SH_BASHEXTRA)) + || ((!sh_isoption(SH_BASH) || n=='o') && (o&SH_BASHOPT)) + + || (setflag && (o&SH_COMMANDLINE))) + { + errormsg(SH_DICT,2, e_option, opt_info.arg); + error_info.errors++; + } + o &= 0xff; + if(sh_isoption(SH_RESTRICTED) && !f && o==SH_RESTRICTED) + errormsg(SH_DICT,ERROR_exit(1), e_restricted, opt_info.arg); + break; +#if SHOPT_BASH + case -1: /* --rcfile */ + ap->sh->gd->rcfile = opt_info.arg; + continue; + case -2: /* --noediting */ + if (!f) + { + off_option(&newflags,SH_VI); + off_option(&newflags,SH_EMACS); + off_option(&newflags,SH_GMACS); + } + continue; + case -3: /* --profile */ + n = 'l'; + goto skip; + case -4: /* --posix */ + /* mask lower 8 bits to find char in optksh string */ + n&=0xff; + goto skip; + case -5: /* --version */ + sfputr(sfstdout, "ksh bash emulation, version ",-1); + np = nv_open("BASH_VERSION",ap->sh->var_tree,0); + sfputr(sfstdout, nv_getval(np),-1); + np = nv_open("MACHTYPE",ap->sh->var_tree,0); + sfprintf(sfstdout, " (%s)\n", nv_getval(np)); + sh_exit(0); +#endif + case -6: /* --default */ + { + register const Shtable_t *tp; + for(tp=shtab_options; o = tp->sh_number; tp++) + if(!(o&SH_COMMANDLINE) && is_option(&newflags,o&0xff)) + off_option(&newflags,o&0xff); + } + continue; + case -7: + f = 0; + goto byname; + case 'D': + on_option(&newflags,SH_NOEXEC); + goto skip; + case 'T': + if (opt_info.num) + ap->sh->test |= opt_info.num; + else + ap->sh->test = 0; + continue; + case 's': + if(setflag) + { + action = SORT; + continue; + } +#if SHOPT_KIA + goto skip; + case 'R': + if(setflag) + n = ':'; + else + { + ap->kiafile = opt_info.arg; + n = 'n'; + } + /*FALLTHROUGH*/ +#endif /* SHOPT_KIA */ +#if SHOPT_REGRESS + goto skip; + case 'I': + continue; +#endif /* SHOPT_REGRESS */ + skip: + default: + if(cp=strchr(optksh,n)) + o = flagval[cp-optksh]; + break; + case ':': + if(opt_info.name[0]=='-'&&opt_info.name[1]=='-') + { + opt_info.arg = argv[opt_info.index-1] + 2; + f = 1; + goto byname; + } + errormsg(SH_DICT,2, "%s", opt_info.arg); + continue; + case '?': + errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg); + return(-1); + } + if(f) + { + if(o==SH_VI || o==SH_EMACS || o==SH_GMACS) + { + off_option(&newflags,SH_VI); + off_option(&newflags,SH_EMACS); + off_option(&newflags,SH_GMACS); + } + on_option(&newflags,o); + off_option(&ap->sh->offoptions,o); + } + else + { + if(o==SH_XTRACE) + trace = 0; + off_option(&newflags,o); + if(setflag==0) + on_option(&ap->sh->offoptions,o); + } + } + if(error_info.errors) + errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); + /* check for '-' or '+' argument */ + if((cp=argv[opt_info.index]) && cp[1]==0 && (*cp=='+' || *cp=='-') && + strcmp(argv[opt_info.index-1],"--")) + { + opt_info.index++; + off_option(&newflags,SH_XTRACE); + off_option(&newflags,SH_VERBOSE); + trace = 0; + } + if(trace) + sh_trace(shp,argv,1); + argc -= opt_info.index; + argv += opt_info.index; + if(action==PRINT) + sh_printopts(newflags,verbose,0); + if(setflag) + { + if(action==SORT) + { + if(argc>0) + strsort(argv,argc,strcoll); + else + strsort(ap->sh->st.dolv+1,ap->sh->st.dolc,strcoll); + } + if(np) + { + nv_setvec(np,0,argc,argv); + nv_close(np); + } + else if(argc>0 || ((cp=argv[-1]) && strcmp(cp,"--")==0)) + sh_argset(ap,argv-1); + } + else if(is_option(&newflags,SH_CFLAG)) + { + if(!(ap->sh->comdiv = *argv++)) + { + errormsg(SH_DICT,2,e_cneedsarg); + errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*))); + } + argc--; + } + /* handling SH_INTERACTIVE and SH_PRIVILEGED has been moved to + * sh_applyopts(), so that the code can be reused from b_shopt(), too + */ + sh_applyopts(ap->sh,newflags); +#if SHOPT_KIA + if(ap->kiafile) + { + if(!argv[0]) + errormsg(SH_DICT,ERROR_usage(2),"-R requires scriptname"); + if(!(lp->kiafile=sfopen(NIL(Sfio_t*),ap->kiafile,"w+"))) + errormsg(SH_DICT,ERROR_system(3),e_create,ap->kiafile); + if(!(lp->kiatmp=sftmp(2*SF_BUFSIZE))) + errormsg(SH_DICT,ERROR_system(3),e_tmpcreate); + sfputr(lp->kiafile,";vdb;CIAO/ksh",'\n'); + lp->kiabegin = sftell(lp->kiafile); + lp->entity_tree = dtopen(&_Nvdisc,Dtbag); + lp->scriptname = strdup(sh_fmtq(argv[0])); + lp->script=kiaentity(lp,lp->scriptname,-1,'p',-1,0,0,'s',0,""); + lp->fscript=kiaentity(lp,lp->scriptname,-1,'f',-1,0,0,'s',0,""); + lp->unknown=kiaentity(lp,"<unknown>",-1,'p',-1,0,0,'0',0,""); + kiaentity(lp,"<unknown>",-1,'p',0,0,lp->unknown,'0',0,""); + lp->current = lp->script; + ap->kiafile = 0; + } +#endif /* SHOPT_KIA */ + return(argc); +} + +/* apply new options */ + +void sh_applyopts(Shell_t* shp,Shopt_t newflags) +{ + /* cannot set -n for interactive shells since there is no way out */ + if(sh_isoption(SH_INTERACTIVE)) + off_option(&newflags,SH_NOEXEC); + if(is_option(&newflags,SH_PRIVILEGED)) + on_option(&newflags,SH_NOUSRPROFILE); + if(!sh_isstate(SH_INIT) && is_option(&newflags,SH_PRIVILEGED) != sh_isoption(SH_PRIVILEGED) || sh_isstate(SH_INIT) && is_option(&((Arg_t*)shp->arg_context)->sh->offoptions,SH_PRIVILEGED) && shp->gd->userid!=shp->gd->euserid) + { + if(!is_option(&newflags,SH_PRIVILEGED)) + { + setuid(shp->gd->userid); + setgid(shp->gd->groupid); + if(shp->gd->euserid==0) + { + shp->gd->euserid = shp->gd->userid; + shp->gd->egroupid = shp->gd->groupid; + } + } + else if((shp->gd->userid!=shp->gd->euserid && setuid(shp->gd->euserid)<0) || + (shp->gd->groupid!=shp->gd->egroupid && setgid(shp->gd->egroupid)<0) || + (shp->gd->userid==shp->gd->euserid && shp->gd->groupid==shp->gd->egroupid)) + off_option(&newflags,SH_PRIVILEGED); + } +#if SHOPT_BASH + on_option(&newflags,SH_CMDHIST); + on_option(&newflags,SH_CHECKHASH); + on_option(&newflags,SH_EXECFAIL); + on_option(&newflags,SH_EXPAND_ALIASES); + on_option(&newflags,SH_HISTAPPEND); + on_option(&newflags,SH_INTERACTIVE_COMM); + on_option(&newflags,SH_LITHIST); + on_option(&newflags,SH_NOEMPTYCMDCOMPL); + + if(!is_option(&newflags,SH_XPG_ECHO) && sh_isoption(SH_XPG_ECHO)) + astconf("UNIVERSE", 0, "ucb"); + if(is_option(&newflags,SH_XPG_ECHO) && !sh_isoption(SH_XPG_ECHO)) + astconf("UNIVERSE", 0, "att"); + if(!is_option(&newflags,SH_PHYSICAL) && sh_isoption(SH_PHYSICAL)) + astconf("PATH_RESOLVE", 0, "metaphysical"); + if(is_option(&newflags,SH_PHYSICAL) && !sh_isoption(SH_PHYSICAL)) + astconf("PATH_RESOLVE", 0, "physical"); + if(is_option(&newflags,SH_HISTORY2) && !sh_isoption(SH_HISTORY2)) + { + sh_onstate(SH_HISTORY); + sh_onoption(SH_HISTORY); + } + if(!is_option(&newflags,SH_HISTORY2) && sh_isoption(SH_HISTORY2)) + { + sh_offstate(SH_HISTORY); + sh_offoption(SH_HISTORY); + } +#endif + shp->options = newflags; +} + +/* + * returns the value of $- + */ +char *sh_argdolminus(void* context) +{ + register Arg_t *ap = (Arg_t*)context; + register const char *cp=optksh; + register char *flagp=ap->flagadr; + while(cp< &optksh[NUM_OPTS]) + { + int n = flagval[cp-optksh]; + if(sh_isoption(n)) + *flagp++ = *cp; + cp++; + } + *flagp = 0; + return(ap->flagadr); +} + +/* + * set up positional parameters + */ +static void sh_argset(Arg_t *ap,char *argv[]) +{ + sh_argfree(ap->sh,ap->dolh,0); + ap->dolh = sh_argcreate(argv); + /* link into chain */ + ap->dolh->dolnxt = ap->argfor; + ap->argfor = ap->dolh; + ap->sh->st.dolc = ap->dolh->dolnum-1; + ap->sh->st.dolv = ap->dolh->dolval; +} + +/* + * free the argument list if the use count is 1 + * If count is greater than 1 decrement count and return same blk + * Free the argument list if the use count is 1 and return next blk + * Delete the blk from the argfor chain + * If flag is set, then the block dolh is not freed + */ +struct dolnod *sh_argfree(Shell_t *shp, struct dolnod *blk,int flag) +{ + register struct dolnod* argr=blk; + register struct dolnod* argblk; + register Arg_t *ap = (Arg_t*)shp->arg_context; + if(argblk=argr) + { + if((--argblk->dolrefcnt)==0) + { + argr = argblk->dolnxt; + if(flag && argblk==ap->dolh) + ap->dolh->dolrefcnt = 1; + else + { + /* delete from chain */ + if(ap->argfor == argblk) + ap->argfor = argblk->dolnxt; + else + { + for(argr=ap->argfor;argr;argr=argr->dolnxt) + if(argr->dolnxt==argblk) + break; + if(!argr) + return(NIL(struct dolnod*)); + argr->dolnxt = argblk->dolnxt; + argr = argblk->dolnxt; + } + free((void*)argblk); + } + } + } + return(argr); +} + +/* + * grab space for arglist and copy args + * The strings are copied after the argment vector + */ +struct dolnod *sh_argcreate(register char *argv[]) +{ + register struct dolnod *dp; + register char **pp=argv, *sp; + register int size=0,n; + /* count args and number of bytes of arglist */ + while(sp= *pp++) + size += strlen(sp); + n = (pp - argv)-1; + dp=new_of(struct dolnod,n*sizeof(char*)+size+n); + dp->dolrefcnt=1; /* use count */ + dp->dolnum = n; + dp->dolnxt = 0; + pp = dp->dolval; + sp = (char*)dp + sizeof(struct dolnod) + n*sizeof(char*); + while(n--) + { + *pp++ = sp; + sp = strcopy(sp, *argv++) + 1; + } + *pp = NIL(char*); + return(dp); +} + +/* + * used to set new arguments for functions + */ +struct dolnod *sh_argnew(Shell_t *shp,char *argi[], struct dolnod **savargfor) +{ + register Arg_t *ap = (Arg_t*)shp->arg_context; + register struct dolnod *olddolh = ap->dolh; + *savargfor = ap->argfor; + ap->dolh = 0; + ap->argfor = 0; + sh_argset(ap,argi); + return(olddolh); +} + +/* + * reset arguments as they were before function + */ +void sh_argreset(Shell_t *shp,struct dolnod *blk, struct dolnod *afor) +{ + register Arg_t *ap = (Arg_t*)shp->arg_context; + while(ap->argfor=sh_argfree(shp,ap->argfor,0)); + ap->argfor = afor; + if(ap->dolh = blk) + { + shp->st.dolc = ap->dolh->dolnum-1; + shp->st.dolv = ap->dolh->dolval; + } +} + +/* + * increase the use count so that an sh_argset will not make it go away + */ +struct dolnod *sh_arguse(Shell_t* shp) +{ + register struct dolnod *dh; + register Arg_t *ap = (Arg_t*)shp->arg_context; + if(dh=ap->dolh) + dh->dolrefcnt++; + return(dh); +} + +/* + * Print option settings on standard output + * if mode is inclusive or of PRINT_* + * if <mask> is set, only options with this mask value are displayed + */ +void sh_printopts(Shopt_t oflags,register int mode, Shopt_t *mask) +{ + register const Shtable_t *tp; + const char *name; + int on; + int value; + if(!(mode&PRINT_NO_HEADER)) + sfputr(sfstdout,sh_translate(e_heading),'\n'); + if(mode&PRINT_TABLE) + { + int w; + int c; + int r; + int i; + + c = 0; + for(tp=shtab_options; value=tp->sh_number; tp++) + { + if(mask && !is_option(mask,value&0xff)) + continue; + name = tp->sh_name; + if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') + name += 2; + if(c<(w=strlen(name))) + c = w; + } + c += 4; + if((w = ed_window()) < (2*c)) + w = 2*c; + r = w / c; + i = 0; + for(tp=shtab_options; value=tp->sh_number; tp++) + { + if(mask && !is_option(mask,value&0xff)) + continue; + on = !!is_option(&oflags,value); + value &= 0xff; + name = tp->sh_name; + if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') + { + name += 2; + on = !on; + } + if(++i>=r) + { + i = 0; + sfprintf(sfstdout, "%s%s\n", on ? "" : "no", name); + } + else + sfprintf(sfstdout, "%s%-*s", on ? "" : "no", on ? c : (c-2), name); + } + if(i) + sfputc(sfstdout,'\n'); + return; + } +#if SHOPT_RAWONLY + on_option(&oflags,SH_VIRAW); +#endif + if(!(mode&(PRINT_ALL|PRINT_VERBOSE))) /* only print set options */ + { + if(mode&PRINT_SHOPT) + sfwrite(sfstdout,"shopt -s",3); + else + sfwrite(sfstdout,"set --default",13); + } + for(tp=shtab_options; value=tp->sh_number; tp++) + { + if(mask && !is_option(mask,value&0xff)) + continue; + if(sh_isoption(SH_BASH)) + { + if (!(mode&PRINT_SHOPT) != !(value&SH_BASHOPT)) + continue; + } + else if (value&(SH_BASHEXTRA|SH_BASHOPT)) + continue; + on = !!is_option(&oflags,value); + name = tp->sh_name; + if(name[0] == 'n' && name[1] == 'o' && name[2] != 't') + { + name += 2; + on = !on; + } + if(mode&PRINT_VERBOSE) + { + sfputr(sfstdout,name,' '); + sfnputc(sfstdout,' ',24-strlen(name)); + sfputr(sfstdout,on ? sh_translate(e_on) : sh_translate(e_off),'\n'); + } + else if(mode&PRINT_ALL) /* print unset options also */ + { + if(mode&PRINT_SHOPT) + sfprintf(sfstdout, "shopt -%c %s\n", + on?'s':'u', + name); + else + sfprintf(sfstdout, "set %co %s\n", + on?'-':'+', + name); + } + else if(!(value&SH_COMMANDLINE) && is_option(&oflags,value&0xff)) + sfprintf(sfstdout," %s%s%s",(mode&PRINT_SHOPT)?"":"--",on?"":"no",name); + } + if(!(mode&(PRINT_VERBOSE|PRINT_ALL))) + sfputc(sfstdout,'\n'); +} + +/* + * build an argument list + */ +char **sh_argbuild(Shell_t *shp,int *nargs, const struct comnod *comptr,int flag) +{ + register struct argnod *argp; + struct argnod *arghead=0; + shp->xargmin = 0; + { + register const struct comnod *ac = comptr; + register int n; + /* see if the arguments have already been expanded */ + if(!ac->comarg) + { + *nargs = 0; + return(&null); + } + else if(!(ac->comtyp&COMSCAN)) + { + register struct dolnod *ap = (struct dolnod*)ac->comarg; + *nargs = ap->dolnum; + return(ap->dolval+ap->dolbot); + } + shp->lastpath = 0; + *nargs = 0; + if(ac) + { + if(ac->comnamp == SYSLET) + flag |= ARG_LET; + argp = ac->comarg; + while(argp) + { + n = arg_expand(shp,argp,&arghead,flag); + if(n>1) + { + if(shp->xargmin==0) + shp->xargmin = *nargs; + shp->xargmax = *nargs+n; + } + *nargs += n; + argp = argp->argnxt.ap; + } + argp = arghead; + } + } + { + register char **comargn; + register int argn; + register char **comargm; + argn = *nargs; + /* allow room to prepend args */ + argn += 1; + + comargn=(char**)stkalloc(shp->stk,(unsigned)(argn+1)*sizeof(char*)); + comargm = comargn += argn; + *comargn = NIL(char*); + if(!argp) + { + /* reserve an extra null pointer */ + *--comargn = 0; + return(comargn); + } + while(argp) + { + struct argnod *nextarg = argp->argchn.ap; + argp->argchn.ap = 0; + *--comargn = argp->argval; + if(!(argp->argflag&ARG_RAW)) + sh_trim(*comargn); + if(!(argp=nextarg) || (argp->argflag&ARG_MAKE)) + { + if((argn=comargm-comargn)>1) + strsort(comargn,argn,strcoll); + comargm = comargn; + } + } + shp->last_table = 0; + return(comargn); + } +} + +#if _pipe_socketpair && !_socketpair_devfd +# define sh_pipe arg_pipe +/* + * create a real pipe (not a socket) and print message on failure + */ +static int arg_pipe(register int pv[]) +{ + Shell_t *shp = sh_getinterp(); + int fd[2]; + if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0) + errormsg(SH_DICT,ERROR_system(1),e_pipe); + pv[0] = sh_iomovefd(pv[0]); + pv[1] = sh_iomovefd(pv[1]); + shp->fdstatus[pv[0]] = IONOSEEK|IOREAD; + shp->fdstatus[pv[1]] = IONOSEEK|IOWRITE; + sh_subsavefd(pv[0]); + sh_subsavefd(pv[1]); + return(0); +} +#endif + +struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp) +{ + /* argument of the form <(cmd) or >(cmd) */ + register struct argnod *ap; + int monitor, fd, pv[3]; + int subshell = shp->subshell; + ap = (struct argnod*)stkseek(shp->stk,ARGVAL); + ap->argflag |= ARG_MAKE; + ap->argflag &= ~ARG_RAW; + fd = argp->argflag&ARG_RAW; + if(fd==0 && shp->subshell) + sh_subtmpfile(shp); +#if SHOPT_DEVFD + sfwrite(shp->stk,e_devfdNN,8); + pv[2] = 0; + sh_pipe(pv); +#else + pv[0] = -1; + shp->fifo = pathtemp(0,0,0,"ksh.fifo",0); + mkfifo(shp->fifo,S_IRUSR|S_IWUSR); + sfputr(shp->stk,shp->fifo,0); +#endif /* SHOPT_DEVFD */ + sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0); + ap = (struct argnod*)stkfreeze(shp->stk,0); + shp->inpipe = shp->outpipe = 0; + if(monitor = (sh_isstate(SH_MONITOR)!=0)) + sh_offstate(SH_MONITOR); + shp->subshell = 0; + if(fd) + { + shp->inpipe = pv; + sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); + } + else + { + shp->outpipe = pv; + sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT)); + } + shp->subshell = subshell; + if(monitor) + sh_onstate(SH_MONITOR); +#if SHOPT_DEVFD + close(pv[1-fd]); + sh_iosave(shp,-pv[fd], shp->topfd, (char*)0); +#else + free(shp->fifo); + shp->fifo = 0; +#endif /* SHOPT_DEVFD */ + return(ap); +} + +/* Argument expansion */ +static int arg_expand(Shell_t *shp,register struct argnod *argp, struct argnod **argchain,int flag) +{ + register int count = 0; + argp->argflag &= ~ARG_MAKE; + if(*argp->argval==0 && (argp->argflag&ARG_EXP)) + { + struct argnod *ap; + ap = sh_argprocsub(shp,argp); + ap->argchn.ap = *argchain; + *argchain = ap; + count++; + } + else + if(!(argp->argflag&ARG_RAW)) + { +#if SHOPT_OPTIMIZE + struct argnod *ap; + sh_stats(STAT_ARGEXPAND); + if(flag&ARG_OPTIMIZE) + argp->argchn.ap=0; + if(ap=argp->argchn.ap) + { + sh_stats(STAT_ARGHITS); + count = 1; + ap->argchn.ap = *argchain; + ap->argflag |= ARG_RAW; + ap->argflag &= ~ARG_EXP; + *argchain = ap; + } + else +#endif /* SHOPT_OPTIMIZE */ + count = sh_macexpand(shp,argp,argchain,flag); + } + else + { + argp->argchn.ap = *argchain; + *argchain = argp; + argp->argflag |= ARG_MAKE; + count++; + } + return(count); +} + |