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