1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                  David Korn <dgk@research.att.com>                   *
18*                                                                      *
19***********************************************************************/
20#pragma prototyped
21/*
22 * getopts  optstring name [arg...]
23 *
24 *   David Korn
25 *   AT&T Labs
26 *   research!dgk
27 *
28 */
29
30#include	"defs.h"
31#include	"variables.h"
32#include	<error.h>
33#include	<nval.h>
34#include	"builtins.h"
35
36static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
37{
38	Shell_t	*shp = *(Shell_t**)(dp+1);
39	Stk_t	*stkp = shp->stk;
40#if SHOPT_NAMESPACE
41	if((shp->namespace && sh_fsearch(shp,s,0)) || nv_search(s,shp->fun_tree,0))
42#else
43	if(nv_search(s,shp->fun_tree,0))
44#endif /* SHOPT_NAMESPACE */
45	{
46		int savtop = stktell(stkp);
47		char *savptr = stkfreeze(stkp,0);
48		sfputc(stkp,'$');
49		sfputc(stkp,'(');
50		sfputr(stkp,s,')');
51		sfputr(sp,sh_mactry(shp,stkfreeze(stkp,1)),-1);
52		stkset(stkp,savptr,savtop);
53	}
54        return(1);
55}
56
57int	b_getopts(int argc,char *argv[],Shbltin_t *context)
58{
59	register char *options=error_info.context->id;
60	register Namval_t *np;
61	register int flag, mode;
62	register Shell_t *shp = context->shp;
63	char value[2], key[2];
64	int jmpval;
65	volatile int extended, r= -1;
66	struct checkpt buff, *pp;
67	struct {
68	        Optdisc_t	hdr;
69		Shell_t		*sh;
70	} disc;
71        memset(&disc, 0, sizeof(disc));
72        disc.hdr.version = OPT_VERSION;
73        disc.hdr.infof = infof;
74	disc.sh = shp;
75	value[1] = 0;
76	key[1] = 0;
77	while((flag = optget(argv,sh_optgetopts))) switch(flag)
78	{
79	    case 'a':
80		options = opt_info.arg;
81		break;
82	    case ':':
83		errormsg(SH_DICT,2, "%s", opt_info.arg);
84		break;
85	    case '?':
86		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
87		break;
88	}
89	argv += opt_info.index;
90	argc -= opt_info.index;
91	if(error_info.errors || argc<2)
92		errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0));
93	error_info.context->flags |= ERROR_SILENT;
94	error_info.id = options;
95	options = argv[0];
96	np = nv_open(argv[1],shp->var_tree,NV_NOASSIGN|NV_VARNAME);
97	if(argc>2)
98	{
99		argv +=1;
100		argc -=1;
101	}
102	else
103	{
104		argv = shp->st.dolv;
105		argc = shp->st.dolc;
106	}
107	opt_info.index = shp->st.optindex;
108	opt_info.offset = shp->st.optchar;
109	if(mode= (*options==':'))
110		options++;
111	extended = *options=='\n' && *(options+1)=='[' || *options=='[' && *(options+1)=='-';
112	sh_pushcontext(shp,&buff,1);
113	jmpval = sigsetjmp(buff.buff,0);
114	if(jmpval)
115	{
116		sh_popcontext(shp,&buff);
117		shp->st.opterror = 1;
118		if(r==0)
119			return(2);
120		pp = (struct checkpt*)shp->jmplist;
121		pp->mode = SH_JMPERREXIT;
122		sh_exit(2);
123	}
124        opt_info.disc = &disc.hdr;
125	switch(opt_info.index>=0 && opt_info.index<=argc?(opt_info.num= LONG_MIN,flag=optget(argv,options)):0)
126	{
127	    case '?':
128		if(mode==0)
129			errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
130		opt_info.option[1] = '?';
131		/* FALL THRU */
132	    case ':':
133		key[0] = opt_info.option[1];
134		if(strmatch(opt_info.arg,"*unknown*"))
135			flag = '?';
136		if(mode)
137			opt_info.arg = key;
138		else
139		{
140			errormsg(SH_DICT,2, "%s", opt_info.arg);
141			opt_info.arg = 0;
142			flag = '?';
143		}
144		*(options = value) = flag;
145		shp->st.opterror = 1;
146		if (opt_info.offset != 0 && !argv[opt_info.index][opt_info.offset])
147		{
148			opt_info.offset = 0;
149			opt_info.index++;
150		}
151		break;
152	    case 0:
153		if(shp->st.opterror)
154		{
155			char *com[2];
156			com[0] = "-?";
157			com[1] = 0;
158			flag = opt_info.index;
159			opt_info.index = 0;
160			optget(com,options);
161			opt_info.index = flag;
162			if(!mode && strchr(options,' '))
163				errormsg(SH_DICT,ERROR_usage(2), "%s", optusage((char*)0));
164		}
165		opt_info.arg = 0;
166		options = value;
167		*options = '?';
168		r=1;
169		opt_info.offset = 0;
170		break;
171	    default:
172		options = opt_info.option + (*opt_info.option!='+');
173	}
174	if(r<0)
175		r = 0;
176	error_info.context->flags &= ~ERROR_SILENT;
177	shp->st.optindex = opt_info.index;
178	shp->st.optchar = opt_info.offset;
179	nv_putval(np, options, 0);
180	nv_close(np);
181	np = nv_open(nv_name(OPTARGNOD),shp->var_tree,0);
182	if(opt_info.num == LONG_MIN)
183		nv_putval(np, opt_info.arg, NV_RDONLY);
184	else if (opt_info.arg && opt_info.num > 0 && isalpha((char)opt_info.num) && !isdigit(opt_info.arg[0]) && opt_info.arg[0] != '-' && opt_info.arg[0] != '+')
185	{
186		key[0] = (char)opt_info.num;
187		key[1] = 0;
188		nv_putval(np, key, NV_RDONLY);
189	}
190	else if(extended)
191	{
192		Sfdouble_t d;
193		d = opt_info.number;
194		nv_putval(np, (char*)&d, NV_LDOUBLE|NV_RDONLY);
195	}
196	else
197		nv_putval(np, opt_info.arg, NV_RDONLY);
198	nv_close(np);
199	sh_popcontext(shp,&buff);
200        opt_info.disc = 0;
201	return(r);
202}
203
204