1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                  David Korn <dgk@research.att.com>                   *
19*4887Schin *                   Phong Vo <kpv@research.att.com>                    *
20*4887Schin *                                                                      *
21*4887Schin ***********************************************************************/
22*4887Schin #pragma prototyped
23*4887Schin 
24*4887Schin #include <ast.h>
25*4887Schin 
26*4887Schin #undef	_BLD_ast	/* enable ast imports since we're user static */
27*4887Schin 
28*4887Schin #include <error.h>
29*4887Schin #include <option.h>
30*4887Schin #include <getopt.h>
31*4887Schin #include <ctype.h>
32*4887Schin 
33*4887Schin static const char*		lastoptstring;
34*4887Schin static const struct option*	lastlongopts;
35*4887Schin static char*			usage;
36*4887Schin static Sfio_t*			up;
37*4887Schin 
38*4887Schin static int			lastoptind;
39*4887Schin 
40*4887Schin static int
41*4887Schin golly(int argc, char* const* argv, const char* optstring, const struct option* longopts, int* longindex, int flags)
42*4887Schin {
43*4887Schin 	register char*			s;
44*4887Schin 	register const struct option*	o;
45*4887Schin 	register int			c;
46*4887Schin 	char*				t;
47*4887Schin 
48*4887Schin 	if (!up || optstring != lastoptstring || longopts != lastlongopts)
49*4887Schin 	{
50*4887Schin 		if (!up && !(up = sfstropen()))
51*4887Schin 			return -1;
52*4887Schin 		sfprintf(up, "[-1p%d]", flags);
53*4887Schin 		t = strdup(optstring);
54*4887Schin 		for (o = longopts; o->name; o++)
55*4887Schin 		{
56*4887Schin 			if (o->flag || o->val <= 0 || o->val > UCHAR_MAX || !isalnum(o->val))
57*4887Schin 				sfprintf(up, "\n[%d:%s]", UCHAR_MAX + 1 + (o - longopts), o->name);
58*4887Schin 			else
59*4887Schin 			{
60*4887Schin 				sfprintf(up, "\n[%c:%s]", o->val, o->name);
61*4887Schin 				if (s = strchr(t, o->val))
62*4887Schin 				{
63*4887Schin 					*s++ = ' ';
64*4887Schin 					if (*s == ':')
65*4887Schin 					{
66*4887Schin 						*s++ = ' ';
67*4887Schin 						if (*s == ':')
68*4887Schin 							*s = ' ';
69*4887Schin 					}
70*4887Schin 				}
71*4887Schin 			}
72*4887Schin 			if (o->has_arg)
73*4887Schin 			{
74*4887Schin 				sfputc(up, ':');
75*4887Schin 				if (o->has_arg == optional_argument)
76*4887Schin 					sfputc(up, '?');
77*4887Schin 				sfprintf(up, "[string]");
78*4887Schin 			}
79*4887Schin 		}
80*4887Schin 		s = t;
81*4887Schin 		while (c = *s++)
82*4887Schin 			if (c != ' ')
83*4887Schin 			{
84*4887Schin 				sfprintf(up, "\n[%c]", c);
85*4887Schin 				if (*s == ':')
86*4887Schin 				{
87*4887Schin 					sfputc(up, *s);
88*4887Schin 					if (*++s == ':')
89*4887Schin 					{
90*4887Schin 						sfputc(up, '?');
91*4887Schin 						s++;
92*4887Schin 					}
93*4887Schin 					sfputc(up, '[');
94*4887Schin 					sfputc(up, ']');
95*4887Schin 				}
96*4887Schin 			}
97*4887Schin 		sfputc(up, '\n');
98*4887Schin 		if (!(usage = sfstruse(up)))
99*4887Schin 			return -1;
100*4887Schin 		lastoptstring = optstring;
101*4887Schin 		lastlongopts = longopts;
102*4887Schin 	}
103*4887Schin 	opt_info.index = (optind > 1 || optind == lastoptind) ? optind : 0;
104*4887Schin 	if (opt_info.index >= argc || !(c = optget((char**)argv, usage)))
105*4887Schin 	{
106*4887Schin 		sfstrclose(up);
107*4887Schin 		up = 0;
108*4887Schin 		c = -1;
109*4887Schin 	}
110*4887Schin 	else
111*4887Schin 	{
112*4887Schin 		if (c == ':' || c == '?')
113*4887Schin 		{
114*4887Schin 			if (opterr && (!optstring || *optstring != ':'))
115*4887Schin 			{
116*4887Schin 				if (!error_info.id)
117*4887Schin 					error_info.id = argv[0];
118*4887Schin 				errormsg(NiL, c == '?' ? (ERROR_USAGE|4) : 2, "%s", opt_info.arg);
119*4887Schin 			}
120*4887Schin 			optopt = opt_info.option[1];
121*4887Schin 			c = '?';
122*4887Schin 		}
123*4887Schin 		optarg = opt_info.arg;
124*4887Schin 		if (c < 0)
125*4887Schin 		{
126*4887Schin 			o = longopts - c - UCHAR_MAX - 1;
127*4887Schin 			if (o->flag)
128*4887Schin 			{
129*4887Schin 				*o->flag = o->val;
130*4887Schin 				c = 0;
131*4887Schin 			}
132*4887Schin 			else
133*4887Schin 				c = o->val;
134*4887Schin 		}
135*4887Schin 	}
136*4887Schin 	lastoptind = optind = opt_info.index;
137*4887Schin 	return c;
138*4887Schin }
139*4887Schin 
140*4887Schin extern int
141*4887Schin getopt_long(int argc, char* const* argv, const char* optstring, const struct option* longopts, int* longindex)
142*4887Schin {
143*4887Schin 	return golly(argc, argv, optstring, longopts, longindex, 2);
144*4887Schin }
145*4887Schin 
146*4887Schin extern int
147*4887Schin getopt_long_only(int argc, char* const* argv, const char* optstring, const struct option* longopts, int* longindex)
148*4887Schin {
149*4887Schin 	return golly(argc, argv, optstring, longopts, longindex, 1);
150*4887Schin }
151