Files
cdesktop/cde/programs/dtksh/ksh93/src/cmd/ksh93/sh/args.c

561 lines
14 KiB
C

/* $XConsortium: args.c /main/3 1995/11/01 16:45:22 rswiston $ */
/***************************************************************
* *
* AT&T - PROPRIETARY *
* *
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF *
* AT&T BELL LABORATORIES *
* AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN *
* ACCORDANCE WITH APPLICABLE AGREEMENTS *
* *
* Copyright (c) 1995 AT&T Corp. *
* Unpublished & Not for Publication *
* All Rights Reserved *
* *
* The copyright notice above does not evidence any *
* actual or intended publication of such source code *
* *
* This software was created by the *
* Advanced Software Technology Department *
* AT&T Bell Laboratories *
* *
* For further information contact *
* {research,attmail}!dgk *
* *
***************************************************************/
/* : : generated by proto : : */
#if !defined(__PROTO__)
#if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
#if defined(__cplusplus)
#define __MANGLE__ "C"
#else
#define __MANGLE__
#endif
#define __STDARG__
#define __PROTO__(x) x
#define __OTORP__(x)
#define __PARAM__(n,o) n
#if !defined(__STDC__) && !defined(__cplusplus)
#if !defined(c_plusplus)
#define const
#endif
#define signed
#define void int
#define volatile
#define __V_ char
#else
#define __V_ void
#endif
#else
#define __PROTO__(x) ()
#define __OTORP__(x) x
#define __PARAM__(n,o) o
#define __MANGLE__
#define __V_ char
#define const
#define signed
#define void int
#define volatile
#endif
#if defined(__cplusplus) || defined(c_plusplus)
#define __VARARG__ ...
#else
#define __VARARG__
#endif
#if defined(__STDARG__)
#define __VA_START__(p,a) va_start(p,a)
#else
#define __VA_START__(p,a) va_start(p)
#endif
#endif
#include "defs.h"
#include "path.h"
#include "builtins.h"
#include "terminal.h"
#ifdef SHOPT_KIA
# include "shlex.h"
# include "io.h"
#endif /* SHOPT_KIA */
#define NUM_OPTS 20
#define SORT 1
#define PRINT 2
static int arg_expand __PROTO__((struct argnod*,struct argnod**));
static void print_opts __PROTO__((Shopt_t,int));
#ifdef SHOPT_KIA
static char *kiafile;
#endif /* SHOPT_KIA */
static char *null;
static struct dolnod *argfor; /* linked list of blocks to be cleaned up */
static struct dolnod *dolh;
/* The following order is determined by sh_optset */
static const Shopt_t flagval[] =
{
0, SH_DICTIONARY|SH_NOEXEC, 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_NOCLOBBER, 0
};
static char flagadr[NUM_OPTS+1];
/* ======== option handling ======== */
/*
* This routine turns options on and off
* The options "Micr" 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 __PARAM__((int argc,register char *argv[]), (argc, argv)) __OTORP__(int argc;register char *argv[];){
register int n;
register Shopt_t newflags=sh.options, opt;
int setflag=0, action=0, trace=(int)sh_isoption(SH_XTRACE);
Namval_t *np = NIL(Namval_t*);
const char *cp;
int verbose;
if(argc>0)
setflag = 4;
else
argc = -argc;
while((n = optget(argv,setflag?sh_optset:sh_optksh)))
{
switch(n)
{
case 'A':
np = nv_open(opt_arg,sh.var_tree,NV_NOASSIGN|NV_ARRAY|NV_VARNAME);
if(*opt_option=='-')
nv_unset(np);
continue;
case 'o':
if(!opt_arg)
{
action = PRINT;
verbose = (*opt_option=='-');
continue;
}
n = sh_lookup(opt_arg,shtab_options);
opt = 1L<<n;
if(setflag && (opt&(1|SH_INTERACTIVE|SH_RESTRICTED)))
{
error(2, e_option, opt_arg);
error_info.errors++;
}
break;
case 's':
if(setflag)
{
action = SORT;
continue;
}
#ifdef SHOPT_KIA
goto skip;
case 'R':
if(setflag)
n = ':';
else
{
kiafile = opt_arg;
n = 'n';
}
/* FALL THRU */
skip:
#endif /* SHOPT_KIA */
default:
if(cp=strchr(sh_optksh,n))
opt = flagval[cp-sh_optksh];
break;
case ':':
error(2, opt_arg);
continue;
case '?':
error(ERROR_usage(2), opt_arg);
return(-1);
}
if(*opt_option=='-')
{
if(opt&(SH_VI|SH_EMACS|SH_GMACS))
newflags &= ~(SH_VI|SH_EMACS|SH_GMACS);
newflags |= opt;
}
else
{
if(opt==SH_XTRACE)
trace = 0;
newflags &= ~opt;
}
}
if(error_info.errors)
error(ERROR_usage(2),optusage(NIL(char*)));
/* check for '-' or '+' argument */
if((cp=argv[opt_index]) && cp[1]==0 && (*cp=='+' || *cp=='-') &&
strcmp(argv[opt_index-1],"--"))
{
opt_index++;
newflags &= ~(SH_XTRACE|SH_VERBOSE);
trace = 0;
}
if(trace)
sh_trace(argv,1);
argc -= opt_index;
argv += opt_index;
/* cannot set -n for interactive shells since there is no way out */
if(sh_isoption(SH_INTERACTIVE))
newflags &= ~SH_NOEXEC;
if(action==PRINT)
print_opts(newflags,verbose);
if(setflag)
{
if(action==SORT)
{
if(argc>0)
strsort(argv,argc,strcoll);
else
strsort(sh.st.dolv+1,sh.st.dolc,strcoll);
}
if((newflags&SH_PRIVILEGED) && !sh_isoption(SH_PRIVILEGED))
{
if((sh.userid!=sh.euserid && setuid(sh.euserid)<0) ||
(sh.groupid!=sh.egroupid && setgid(sh.egroupid)<0) ||
(sh.userid==sh.euserid && sh.groupid==sh.egroupid))
newflags &= ~SH_PRIVILEGED;
}
else if(!(newflags&SH_PRIVILEGED) && sh_isoption(SH_PRIVILEGED))
{
setuid(sh.userid);
setgid(sh.groupid);
if(sh.euserid==0)
{
sh.euserid = sh.userid;
sh.egroupid = sh.groupid;
}
}
if(np)
{
nv_setvec(np,argc,argv);
nv_close(np);
}
else if(argc>0 || ((cp=argv[-1]) && strcmp(cp,"--")==0))
sh_argset(argv-1);
}
else if(newflags&SH_CFLAG)
{
if(!(sh.comdiv = *argv++))
{
error(2,e_cneedsarg);
error(ERROR_usage(2),optusage(NIL(char*)));
}
argc--;
}
sh.options = newflags;
#ifdef SHOPT_KIA
if(kiafile)
{
if(!(shlex.kiafile=sfopen(NIL(Sfio_t*),kiafile,"w+")))
error(ERROR_system(3),e_create,kiafile);
if(!(shlex.kiatmp=sftmp(2*SF_BUFSIZE)))
error(ERROR_system(3),e_tmpcreate);
sfprintf(shlex.kiafile,"0;s;%s;1;%6d;;;;\n",sh_fmtq(argv[0]),1);
shlex.kiabegin = sftell(shlex.kiafile)-11;
shlex.parent = "0";
shlex.file_tree = hashalloc(sh.var_tree,HASH_set,HASH_ALLOCATE,0);
kiafile = 0;
}
#endif /* SHOPT_KIA */
return(argc);
}
/*
* returns the value of $-
*/
char *sh_argdolminus __PARAM__((void), ()){
register const char *cp=sh_optksh;
register char *flagp=flagadr;
while(cp< &sh_optksh[NUM_OPTS])
{
if(sh.options&flagval[cp-sh_optksh])
*flagp++ = *cp;
cp++;
}
*flagp = 0;
return(flagadr);
}
/*
* set up positional parameters
*/
void sh_argset __PARAM__((char *argv[]), (argv)) __OTORP__(char *argv[];){
sh_argfree(dolh,0);
dolh = sh_argcreate(argv);
/* link into chain */
dolh->dolnxt = argfor;
argfor = dolh;
sh.st.dolc = dolh->dolnum-1;
sh.st.dolv = 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 __PARAM__((struct dolnod *blk,int flag), (blk, flag)) __OTORP__(struct dolnod *blk;int flag;){
register struct dolnod* argr=blk;
register struct dolnod* argblk;
if(argblk=argr)
{
if((--argblk->dolrefcnt)==0)
{
argr = argblk->dolnxt;
if(flag && argblk==dolh)
dolh->dolrefcnt = 1;
else
{
/* delete from chain */
if(argfor == argblk)
argfor = argblk->dolnxt;
else
{
for(argr=argfor;argr;argr=argr->dolnxt)
if(argr->dolnxt==argblk)
break;
if(!argr)
return(NIL(struct dolnod*));
argr->dolnxt = argblk->dolnxt;
argr = argblk->dolnxt;
}
free((__V_*)argblk);
}
}
}
return(argr);
}
/*
* grab space for arglist and copy args
* The strings are copied after the argment vector
*/
struct dolnod *sh_argcreate __PARAM__((register char *argv[]), (argv)) __OTORP__(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 __PARAM__((char *argi[], struct dolnod **savargfor), (argi, savargfor)) __OTORP__(char *argi[]; struct dolnod **savargfor;){
register struct dolnod *olddolh = dolh;
*savargfor = argfor;
dolh = 0;
argfor = 0;
sh_argset(argi);
return(olddolh);
}
/*
* reset arguments as they were before function
*/
void sh_argreset __PARAM__((struct dolnod *blk, struct dolnod *afor), (blk, afor)) __OTORP__(struct dolnod *blk; struct dolnod *afor;){
while(argfor=sh_argfree(argfor,0));
argfor = afor;
if(dolh = blk)
{
sh.st.dolc = dolh->dolnum-1;
sh.st.dolv = dolh->dolval;
}
}
/*
* increase the use count so that an sh_argset will not make it go away
*/
struct dolnod *sh_arguse __PARAM__((void), ()){
register struct dolnod *dh;
if(dh=dolh)
dh->dolrefcnt++;
return(dh);
}
/*
* Print option settings on standard output
* if mode==1 for -o format, otherwise +o format
*/
static void print_opts __PARAM__((Shopt_t oflags,register int mode), (oflags, mode)) __OTORP__(Shopt_t oflags;register int mode;){
register const Shtable_t *tp = shtab_options;
Shopt_t value;
if(mode)
sfputr(sfstdout,ERROR_translate(e_heading,1),'\n');
else
sfwrite(sfstdout,"set",3);
while(value=tp->sh_number)
{
value = 1L<<value;
if(mode)
{
char const *msg;
sfputr(sfstdout,tp->sh_name,' ');
sfnputc(sfstdout,' ',16-strlen(tp->sh_name));
if(oflags&value)
msg = e_on;
else
msg = e_off;
sfputr(sfstdout,ERROR_translate(msg,1),'\n');
}
else if(oflags&value)
sfprintf(sfstdout," -o %s",tp->sh_name);
tp++;
}
if(!mode)
sfputc(sfstdout,'\n');
}
/*
* build an argument list
*/
char **sh_argbuild __PARAM__((int *nargs, const struct comnod *comptr), (nargs, comptr)) __OTORP__(int *nargs; const struct comnod *comptr;){
register struct argnod *argp;
struct argnod *arghead=0;
{
register const struct comnod *ac = comptr;
/* 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);
}
sh.lastpath = 0;
*nargs = 0;
if(ac)
{
argp = ac->comarg;
while(argp)
{
*nargs += arg_expand(argp,&arghead);
argp = argp->argnxt.ap;
}
argp = arghead;
}
}
{
register char **comargn;
register int argn;
register char **comargm;
argn = *nargs;
/* allow room to prepend args */
#ifdef SHOPT_VPIX
argn += 2;
#else
argn += 1;
#endif /* SHOPT_VPIX */
comargn=(char**)stakalloc((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;
}
}
return(comargn);
}
}
/* Argument expansion */
static int arg_expand __PARAM__((register struct argnod *argp, struct argnod **argchain), (argp, argchain)) __OTORP__(register struct argnod *argp; struct argnod **argchain;){
register int count = 0;
argp->argflag &= ~ARG_MAKE;
#ifdef SHOPT_DEVFD
if(*argp->argval==0 && (argp->argflag&ARG_EXP))
{
/* argument of the form (cmd) */
register struct argnod *ap;
int monitor, fd, pv[2];
ap = (struct argnod*)stakseek(ARGVAL);
ap->argflag |= ARG_MAKE;
ap->argflag &= ~ARG_RAW;
ap->argchn.ap = *argchain;
*argchain = ap;
count++;
stakwrite(e_devfdNN,8);
sh_pipe(pv);
fd = argp->argflag&ARG_RAW;
stakputs(fmtbase((long)pv[fd],10,0));
ap = (struct argnod*)stakfreeze(1);
sh.inpipe = sh.outpipe = 0;
if(monitor = (sh_isstate(SH_MONITOR)!=0))
sh_offstate(SH_MONITOR);
if(fd)
{
sh.inpipe = pv;
sh_exec((union anynode*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
}
else
{
sh.outpipe = pv;
sh_exec((union anynode*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
}
if(monitor)
sh_onstate(SH_MONITOR);
close(pv[1-fd]);
sh_iosave(-pv[fd], sh.topfd);
}
else
#endif /* SHOPT_DEVFD */
if(!(argp->argflag&ARG_RAW))
count = sh_macexpand(argp,argchain);
else
{
argp->argchn.ap = *argchain;
*argchain = argp;
argp->argflag |= ARG_MAKE;
count++;
}
return(count);
}