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 
infof(Opt_t * op,Sfio_t * sp,const char * s,Optdisc_t * dp)36 static 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 
b_getopts(int argc,char * argv[],Shbltin_t * context)57 int	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