1 /*
2 * my_getopt.c - my re-implementation of getopt.
3 * Copyright 1997, 2000, 2001, 2002, Benjamin Sittler
4 *
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use, copy,
9 * modify, merge, publish, distribute, sublicense, and/or sell copies
10 * of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26 #if HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #if ! ( defined(HAVE_GETOPT_H) && defined(HAVE_GETOPT_LONG) && defined(HAVE_GETOPT_LONG_ONLY) )
31
32 #include <sys/types.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36
37 #include "compat_getopt.h"
38
39 int my_optind=1, my_opterr=1, my_optopt=0;
40 char *my_optarg=0;
41
42 /* this is the plain old UNIX getopt, with GNU-style extensions. */
43 /* if you're porting some piece of UNIX software, this is all you need. */
44 /* this supports GNU-style permutation and optional arguments */
45
my_getopt(int argc,char * argv[],const char * opts)46 int my_getopt(int argc, char * argv[], const char *opts)
47 {
48 static int charind=0;
49 const char *s;
50 char mode, colon_mode;
51 int off = 0, opt = -1;
52
53 if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+';
54 else {
55 if((colon_mode = *opts) == ':') off ++;
56 if(((mode = opts[off]) == '+') || (mode == '-')) {
57 off++;
58 if((colon_mode != ':') && ((colon_mode = opts[off]) == ':'))
59 off ++;
60 }
61 }
62 my_optarg = 0;
63 if(charind) {
64 my_optopt = argv[my_optind][charind];
65 for(s=opts+off; *s; s++) if(my_optopt == *s) {
66 charind++;
67 if((*(++s) == ':') || ((my_optopt == 'W') && (*s == ';'))) {
68 if(argv[my_optind][charind]) {
69 my_optarg = &(argv[my_optind++][charind]);
70 charind = 0;
71 } else if(*(++s) != ':') {
72 charind = 0;
73 if(++my_optind >= argc) {
74 if(my_opterr) fprintf(stderr,
75 "%s: option requires an argument -- %c\n",
76 argv[0], my_optopt);
77 opt = (colon_mode == ':') ? ':' : '?';
78 goto my_getopt_ok;
79 }
80 my_optarg = argv[my_optind++];
81 }
82 }
83 opt = my_optopt;
84 goto my_getopt_ok;
85 }
86 if(my_opterr) fprintf(stderr,
87 "%s: illegal option -- %c\n",
88 argv[0], my_optopt);
89 opt = '?';
90 if(argv[my_optind][++charind] == '\0') {
91 my_optind++;
92 charind = 0;
93 }
94 my_getopt_ok:
95 if(charind && ! argv[my_optind][charind]) {
96 my_optind++;
97 charind = 0;
98 }
99 } else if((my_optind >= argc) ||
100 ((argv[my_optind][0] == '-') &&
101 (argv[my_optind][1] == '-') &&
102 (argv[my_optind][2] == '\0'))) {
103 my_optind++;
104 opt = -1;
105 } else if((argv[my_optind][0] != '-') ||
106 (argv[my_optind][1] == '\0')) {
107 char *tmp;
108 int i, j, k;
109
110 if(mode == '+') opt = -1;
111 else if(mode == '-') {
112 my_optarg = argv[my_optind++];
113 charind = 0;
114 opt = 1;
115 } else {
116 for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') &&
117 (argv[i][1] != '\0')) {
118 my_optind=i;
119 opt=my_getopt(argc, argv, opts);
120 while(i > j) {
121 tmp=argv[--i];
122 for(k=i; k+1<my_optind; k++) argv[k]=argv[k+1];
123 argv[--my_optind]=tmp;
124 }
125 break;
126 }
127 if(i == argc) opt = -1;
128 }
129 } else {
130 charind++;
131 opt = my_getopt(argc, argv, opts);
132 }
133 if (my_optind > argc) my_optind = argc;
134 return opt;
135 }
136
137 /* this is the extended getopt_long{,_only}, with some GNU-like
138 * extensions. Implements _getopt_internal in case any programs
139 * expecting GNU libc getopt call it.
140 */
141
_my_getopt_internal(int argc,char * argv[],const char * shortopts,const struct option * longopts,int * longind,int long_only)142 int _my_getopt_internal(int argc, char * argv[], const char *shortopts,
143 const struct option *longopts, int *longind,
144 int long_only)
145 {
146 char mode, colon_mode;
147 int shortoff = 0, opt = -1;
148
149 if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+';
150 else {
151 if((colon_mode = *shortopts) == ':') shortoff ++;
152 if(((mode = shortopts[shortoff]) == '+') || (mode == '-')) {
153 shortoff++;
154 if((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':'))
155 shortoff ++;
156 }
157 }
158 my_optarg = 0;
159 if((my_optind >= argc) ||
160 ((argv[my_optind][0] == '-') &&
161 (argv[my_optind][1] == '-') &&
162 (argv[my_optind][2] == '\0'))) {
163 my_optind++;
164 opt = -1;
165 } else if((argv[my_optind][0] != '-') ||
166 (argv[my_optind][1] == '\0')) {
167 char *tmp;
168 int i, j, k;
169
170 opt = -1;
171 if(mode == '+') return -1;
172 else if(mode == '-') {
173 my_optarg = argv[my_optind++];
174 return 1;
175 }
176 for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') &&
177 (argv[i][1] != '\0')) {
178 my_optind=i;
179 opt=_my_getopt_internal(argc, argv, shortopts,
180 longopts, longind,
181 long_only);
182 while(i > j) {
183 tmp=argv[--i];
184 for(k=i; k+1<my_optind; k++)
185 argv[k]=argv[k+1];
186 argv[--my_optind]=tmp;
187 }
188 break;
189 }
190 } else if((!long_only) && (argv[my_optind][1] != '-'))
191 opt = my_getopt(argc, argv, shortopts);
192 else {
193 int charind, offset;
194 int found = 0, ind, hits = 0;
195
196 if(((my_optopt = argv[my_optind][1]) != '-') && ! argv[my_optind][2]) {
197 int c;
198
199 ind = shortoff;
200 while((c = shortopts[ind++])) {
201 if(((shortopts[ind] == ':') ||
202 ((c == 'W') && (shortopts[ind] == ';'))) &&
203 (shortopts[++ind] == ':'))
204 ind ++;
205 if(my_optopt == c) return my_getopt(argc, argv, shortopts);
206 }
207 }
208 offset = 2 - (argv[my_optind][1] != '-');
209 for(charind = offset;
210 (argv[my_optind][charind] != '\0') &&
211 (argv[my_optind][charind] != '=');
212 charind++);
213 for(ind = 0; longopts[ind].name && !hits; ind++)
214 if((strlen(longopts[ind].name) == (size_t) (charind - offset)) &&
215 (strncmp(longopts[ind].name,
216 argv[my_optind] + offset, charind - offset) == 0))
217 found = ind, hits++;
218 if(!hits) for(ind = 0; longopts[ind].name; ind++)
219 if(strncmp(longopts[ind].name,
220 argv[my_optind] + offset, charind - offset) == 0)
221 found = ind, hits++;
222 if(hits == 1) {
223 opt = 0;
224
225 if(argv[my_optind][charind] == '=') {
226 if(longopts[found].has_arg == 0) {
227 opt = '?';
228 if(my_opterr) fprintf(stderr,
229 "%s: option `--%s' doesn't allow an argument\n",
230 argv[0], longopts[found].name);
231 } else {
232 my_optarg = argv[my_optind] + ++charind;
233 /* charind not read again
234 * charind = 0;*/
235 }
236 } else if(longopts[found].has_arg == 1) {
237 if(++my_optind >= argc) {
238 opt = (colon_mode == ':') ? ':' : '?';
239 if(my_opterr) fprintf(stderr,
240 "%s: option `--%s' requires an argument\n",
241 argv[0], longopts[found].name);
242 } else my_optarg = argv[my_optind];
243 }
244 if(!opt) {
245 if (longind) *longind = found;
246 if(!longopts[found].flag) opt = longopts[found].val;
247 else *(longopts[found].flag) = longopts[found].val;
248 }
249 my_optind++;
250 } else if(!hits) {
251 if(offset == 1) opt = my_getopt(argc, argv, shortopts);
252 else {
253 opt = '?';
254 if(my_opterr) fprintf(stderr,
255 "%s: unrecognized option `%s'\n",
256 argv[0], argv[my_optind++]);
257 }
258 } else {
259 opt = '?';
260 if(my_opterr) fprintf(stderr,
261 "%s: option `%s' is ambiguous\n",
262 argv[0], argv[my_optind++]);
263 }
264 }
265 if (my_optind > argc) my_optind = argc;
266 return opt;
267 }
268
my_getopt_long(int argc,char * argv[],const char * shortopts,const struct option * longopts,int * longind)269 int my_getopt_long(int argc, char * argv[], const char *shortopts,
270 const struct option *longopts, int *longind)
271 {
272 return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 0);
273 }
274
my_getopt_long_only(int argc,char * argv[],const char * shortopts,const struct option * longopts,int * longind)275 int my_getopt_long_only(int argc, char * argv[], const char *shortopts,
276 const struct option *longopts, int *longind)
277 {
278 return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 1);
279 }
280
281 #endif
282
283