don't crash if an extrn symbol isn't referenced
[xorcyst.git] / my_getopt.c
blob512b0ae29930d7ea2738d9f9127ccec9f4eaf117
1 /*
2 * my_getopt.c - my re-implementation of getopt.
3 * Copyright 1997, 2000, 2001, 2002, Benjamin Sittler
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:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
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.
26 #include <sys/types.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include "my_getopt.h"
32 int my_optind=1, my_opterr=1, my_optopt=0;
33 char *my_optarg=0;
35 /* this is the plain old UNIX getopt, with GNU-style extensions. */
36 /* if you're porting some piece of UNIX software, this is all you need. */
37 /* this supports GNU-style permution and optional arguments */
39 int my_getopt(int argc, char * argv[], const char *opts)
41 static int charind=0;
42 const char *s;
43 char mode, colon_mode;
44 int off = 0, opt = -1;
46 if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+';
47 else {
48 if((colon_mode = *opts) == ':') off ++;
49 if(((mode = opts[off]) == '+') || (mode == '-')) {
50 off++;
51 if((colon_mode != ':') && ((colon_mode = opts[off]) == ':'))
52 off ++;
55 my_optarg = 0;
56 if(charind) {
57 my_optopt = argv[my_optind][charind];
58 for(s=opts+off; *s; s++) if(my_optopt == *s) {
59 charind++;
60 if((*(++s) == ':') || ((my_optopt == 'W') && (*s == ';'))) {
61 if(argv[my_optind][charind]) {
62 my_optarg = &(argv[my_optind++][charind]);
63 charind = 0;
64 } else if(*(++s) != ':') {
65 charind = 0;
66 if(++my_optind >= argc) {
67 if(my_opterr) fprintf(stderr,
68 "%s: option requires an argument -- %c\n",
69 argv[0], my_optopt);
70 opt = (colon_mode == ':') ? ':' : '?';
71 goto my_getopt_ok;
73 my_optarg = argv[my_optind++];
76 opt = my_optopt;
77 goto my_getopt_ok;
79 if(my_opterr) fprintf(stderr,
80 "%s: illegal option -- %c\n",
81 argv[0], my_optopt);
82 opt = '?';
83 if(argv[my_optind][++charind] == '\0') {
84 my_optind++;
85 charind = 0;
87 my_getopt_ok:
88 if(charind && ! argv[my_optind][charind]) {
89 my_optind++;
90 charind = 0;
92 } else if((my_optind >= argc) ||
93 ((argv[my_optind][0] == '-') &&
94 (argv[my_optind][1] == '-') &&
95 (argv[my_optind][2] == '\0'))) {
96 my_optind++;
97 opt = -1;
98 } else if((argv[my_optind][0] != '-') ||
99 (argv[my_optind][1] == '\0')) {
100 char *tmp;
101 int i, j, k;
103 if(mode == '+') opt = -1;
104 else if(mode == '-') {
105 my_optarg = argv[my_optind++];
106 charind = 0;
107 opt = 1;
108 } else {
109 for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') &&
110 (argv[i][1] != '\0')) {
111 my_optind=i;
112 opt=my_getopt(argc, argv, opts);
113 while(i > j) {
114 tmp=argv[--i];
115 for(k=i; k+1<my_optind; k++) argv[k]=argv[k+1];
116 argv[--my_optind]=tmp;
118 break;
120 if(i == argc) opt = -1;
122 } else {
123 charind++;
124 opt = my_getopt(argc, argv, opts);
126 if (my_optind > argc) my_optind = argc;
127 return opt;
130 /* this is the extended getopt_long{,_only}, with some GNU-like
131 * extensions. Implements _getopt_internal in case any programs
132 * expecting GNU libc getopt call it.
135 int _my_getopt_internal(int argc, char * argv[], const char *shortopts,
136 const struct option *longopts, int *longind,
137 int long_only)
139 char mode, colon_mode = *shortopts;
140 int shortoff = 0, opt = -1;
142 if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+';
143 else {
144 if((colon_mode = *shortopts) == ':') shortoff ++;
145 if(((mode = shortopts[shortoff]) == '+') || (mode == '-')) {
146 shortoff++;
147 if((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':'))
148 shortoff ++;
151 my_optarg = 0;
152 if((my_optind >= argc) ||
153 ((argv[my_optind][0] == '-') &&
154 (argv[my_optind][1] == '-') &&
155 (argv[my_optind][2] == '\0'))) {
156 my_optind++;
157 opt = -1;
158 } else if((argv[my_optind][0] != '-') ||
159 (argv[my_optind][1] == '\0')) {
160 char *tmp;
161 int i, j, k;
163 opt = -1;
164 if(mode == '+') return -1;
165 else if(mode == '-') {
166 my_optarg = argv[my_optind++];
167 return 1;
169 for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') &&
170 (argv[i][1] != '\0')) {
171 my_optind=i;
172 opt=_my_getopt_internal(argc, argv, shortopts,
173 longopts, longind,
174 long_only);
175 while(i > j) {
176 tmp=argv[--i];
177 for(k=i; k+1<my_optind; k++)
178 argv[k]=argv[k+1];
179 argv[--my_optind]=tmp;
181 break;
183 } else if((!long_only) && (argv[my_optind][1] != '-'))
184 opt = my_getopt(argc, argv, shortopts);
185 else {
186 int charind, offset;
187 int found = 0, ind, hits = 0;
189 if(((my_optopt = argv[my_optind][1]) != '-') && ! argv[my_optind][2]) {
190 int c;
192 ind = shortoff;
193 while((c = shortopts[ind++])) {
194 if(((shortopts[ind] == ':') ||
195 ((c == 'W') && (shortopts[ind] == ';'))) &&
196 (shortopts[++ind] == ':'))
197 ind ++;
198 if(my_optopt == c) return my_getopt(argc, argv, shortopts);
201 offset = 2 - (argv[my_optind][1] != '-');
202 for(charind = offset;
203 (argv[my_optind][charind] != '\0') &&
204 (argv[my_optind][charind] != '=');
205 charind++);
206 for(ind = 0; longopts[ind].name && !hits; ind++)
207 if((strlen(longopts[ind].name) == (size_t) (charind - offset)) &&
208 (strncmp(longopts[ind].name,
209 argv[my_optind] + offset, charind - offset) == 0))
210 found = ind, hits++;
211 if(!hits) for(ind = 0; longopts[ind].name; ind++)
212 if(strncmp(longopts[ind].name,
213 argv[my_optind] + offset, charind - offset) == 0)
214 found = ind, hits++;
215 if(hits == 1) {
216 opt = 0;
218 if(argv[my_optind][charind] == '=') {
219 if(longopts[found].has_arg == 0) {
220 opt = '?';
221 if(my_opterr) fprintf(stderr,
222 "%s: option `--%s' doesn't allow an argument\n",
223 argv[0], longopts[found].name);
224 } else {
225 my_optarg = argv[my_optind] + ++charind;
226 charind = 0;
228 } else if(longopts[found].has_arg == 1) {
229 if(++my_optind >= argc) {
230 opt = (colon_mode == ':') ? ':' : '?';
231 if(my_opterr) fprintf(stderr,
232 "%s: option `--%s' requires an argument\n",
233 argv[0], longopts[found].name);
234 } else my_optarg = argv[my_optind];
236 if(!opt) {
237 if (longind) *longind = found;
238 if(!longopts[found].flag) opt = longopts[found].val;
239 else *(longopts[found].flag) = longopts[found].val;
241 my_optind++;
242 } else if(!hits) {
243 if(offset == 1) opt = my_getopt(argc, argv, shortopts);
244 else {
245 opt = '?';
246 if(my_opterr) fprintf(stderr,
247 "%s: unrecognized option `%s'\n",
248 argv[0], argv[my_optind++]);
250 } else {
251 opt = '?';
252 if(my_opterr) fprintf(stderr,
253 "%s: option `%s' is ambiguous\n",
254 argv[0], argv[my_optind++]);
257 if (my_optind > argc) my_optind = argc;
258 return opt;
261 int my_getopt_long(int argc, char * argv[], const char *shortopts,
262 const struct option *longopts, int *longind)
264 return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 0);
267 int my_getopt_long_only(int argc, char * argv[], const char *shortopts,
268 const struct option *longopts, int *longind)
270 return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 1);