mirror of
				git://git.code.sf.net/p/cdesktopenv/code
				synced 2025-03-09 15:50:02 +00:00 
			
		
		
		
	SHOPT_KIA enables the -R option that generates a cross-reference database from a script. However, no tool to analyse this database is shipped or seems to be available anywhere (in spite of multiple people looking for one), and the format is very opaque. No usage examples are known or findable on the internet. This seems like it should not be compiled in by default, although we'll keep the code in case some way to use it is found. src/cmd/ksh93/SHOPT.sh: - Disable SHOPT_KIA by default by removing the default 1 value. src/cmd/ksh93/sh/args.c, src/cmd/ksh93/sh/parse.c: - Fix a couple of preprocessor logic bugs that made it impossible to compile ksh without SHOPT_KIA. src/cmd/ksh93/data/builtins.c: - Fix typo in -R doc in ksh --man (in case SHOPT_KIA is enabled). src/cmd/ksh93/sh.1: - Since sh.1 is not generated dynamically, remove the -R doc.
		
			
				
	
	
		
			784 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			784 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /***********************************************************************
 | |
| *                                                                      *
 | |
| *               This software is part of the ast package               *
 | |
| *          Copyright (c) 1982-2012 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	"jobs.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_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 "DircabefhkmnpstuvxBCGEl" HFLAG;
 | |
| static const int flagval[]  =
 | |
| {
 | |
| #if SHOPT_PFSH
 | |
| 	SH_PFSH,
 | |
| #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(*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);
 | |
| #if SHOPT_KIA
 | |
| 	Lex_t		*lp = (Lex_t*)(shp->lex_context);
 | |
| #endif
 | |
| 	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;
 | |
| 		    case 'o':	/* set options */
 | |
| 		    byname:
 | |
| 			if(!opt_info.arg||!*opt_info.arg||*opt_info.arg=='-')
 | |
| 			{
 | |
| 				action = PRINT;
 | |
| 				verbose = (f?PRINT_VERBOSE:PRINT_NO_HEADER)|
 | |
| 					  ((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 || (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;
 | |
| 		    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_RESTRICTED) && sh_isoption(SH_RESTRICTED))
 | |
| 				errormsg(SH_DICT,ERROR_exit(1),e_restricted,"r"); /* set -r cannot be unset */
 | |
| 			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--;
 | |
| 	}
 | |
| 	/* SH_INTERACTIVE and SH_PRIVILEGED are handled in sh_applyopts() */
 | |
| 	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);
 | |
| 	}
 | |
| 	/* -o posix also switches -o braceexpand and -o letoctal */
 | |
| 	if(!sh_isoption(SH_POSIX) && is_option(&newflags,SH_POSIX))
 | |
| 	{
 | |
| #if SHOPT_BRACEPAT
 | |
| 		off_option(&newflags,SH_BRACEEXPAND);
 | |
| #endif
 | |
| 		on_option(&newflags,SH_LETOCTAL);
 | |
| 	}
 | |
| 	else if(sh_isoption(SH_POSIX) && !is_option(&newflags,SH_POSIX))
 | |
| 	{
 | |
| #if SHOPT_BRACEPAT
 | |
| 		on_option(&newflags,SH_BRACEEXPAND);
 | |
| #endif
 | |
| 		off_option(&newflags,SH_LETOCTAL);
 | |
| 	}
 | |
| 	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 argument 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 */
 | |
| 		sfwrite(sfstdout,"set --default",13);
 | |
| 	for(tp=shtab_options; value=tp->sh_number; tp++)
 | |
| 	{
 | |
| 		if(mask && !is_option(mask,value&0xff))
 | |
| 			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 */
 | |
| 			sfprintf(sfstdout, "set %co %s\n", on?'-':'+', name);
 | |
| 		else if(!(value&SH_COMMANDLINE) && is_option(&oflags,value&0xff))
 | |
| 			sfprintf(sfstdout, " %s%s%s","--", 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(a)	sh_rpipe(a)
 | |
| #endif
 | |
| 
 | |
| struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp)
 | |
| {
 | |
| 	/* argument of the form <(cmd) or >(cmd) */
 | |
| 	register struct argnod *ap;
 | |
| 	int fd, pv[3];
 | |
| 	int savestates = sh_getstate();
 | |
| 	char savejobcontrol = job.jobcontrol;
 | |
| 	unsigned int savesubshell = 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->comsub);
 | |
| #if SHOPT_DEVFD
 | |
| 	sfwrite(shp->stk,e_devfdNN,8);
 | |
| 	pv[2] = 0;
 | |
| 	sh_pipe(pv);
 | |
| #else
 | |
| 	pv[0] = -1;
 | |
| 	while((shp->fifo = pathtemp(0,0,0,"ksh.fifo",0), mkfifo(shp->fifo,0))<0)
 | |
| 	{
 | |
| 		if(errno==EEXIST || errno==EACCES || errno==ENOENT || errno==ENOTDIR || errno==EROFS)
 | |
| 			continue;		/* lost race (name conflict or tmp dir change); try again */
 | |
| 		errormsg(SH_DICT,ERROR_system(128),"process substitution: FIFO creation failed");
 | |
| 	}
 | |
| 	chmod(shp->fifo,S_IRUSR|S_IWUSR);	/* mkfifo + chmod works regardless of umask */
 | |
| 	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;
 | |
| 	/* turn off job control */
 | |
| 	sh_offstate(SH_INTERACTIVE);
 | |
| 	sh_offstate(SH_MONITOR);
 | |
| 	job.jobcontrol = 0;
 | |
| 	/* do the process substitution */
 | |
| 	shp->subshell = 0;
 | |
| 	if(fd)
 | |
| 		shp->inpipe = pv;
 | |
| 	else
 | |
| 		shp->outpipe = pv;
 | |
| 	sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
 | |
| 	/* restore the previous state */
 | |
| 	shp->subshell = savesubshell;
 | |
| 	job.jobcontrol = savejobcontrol;
 | |
| 	sh_setstate(savestates);
 | |
| #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);
 | |
| }
 | |
| 
 |