]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - vendor/ya_getopt/ya_getopt.c
Only check for a join time if a user is actually in the channel.
[user/henk/code/inspircd.git] / vendor / ya_getopt / ya_getopt.c
1 /* -*- indent-tabs-mode: nil -*-
2  *
3  * ya_getopt  - Yet another getopt
4  * https://github.com/kubo/ya_getopt
5  *
6  * Copyright 2015 Kubo Takehiro <kubo@jiubao.org>
7  *
8  * Redistribution and use in source and binary forms, with or without modification, are
9  * permitted provided that the following conditions are met:
10  *
11  *    1. Redistributions of source code must retain the above copyright notice, this list of
12  *       conditions and the following disclaimer.
13  *
14  *    2. Redistributions in binary form must reproduce the above copyright notice, this list
15  *       of conditions and the following disclaimer in the documentation and/or other materials
16  *       provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED
19  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * The views and conclusions contained in the software and documentation are those of the
29  * authors and should not be interpreted as representing official policies, either expressed
30  * or implied, of the authors.
31  *
32  */
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include "ya_getopt.h"
38
39 char *ya_optarg = NULL;
40 int ya_optind = 1;
41 int ya_opterr = 1;
42 int ya_optopt = '?';
43 static char *ya_optnext = NULL;
44 static int posixly_correct = -1;
45 static int handle_nonopt_argv = 0;
46
47 static void ya_getopt_error(const char *optstring, const char *format, ...);
48 static void check_gnu_extension(const char *optstring);
49 static int ya_getopt_internal(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex, int long_only);
50 static int ya_getopt_shortopts(int argc, char * const argv[], const char *optstring, int long_only);
51 static int ya_getopt_longopts(int argc, char * const argv[], char *arg, const char *optstring, const struct option *longopts, int *longindex, int *long_only_flag);
52
53 static void ya_getopt_error(const char *optstring, const char *format, ...)
54 {
55     if (ya_opterr && optstring[0] != ':') {
56         va_list ap;
57         va_start(ap, format);
58         vfprintf(stderr, format, ap);
59         va_end(ap);
60     }
61 }
62
63 static void check_gnu_extension(const char *optstring)
64 {
65     if (optstring[0] == '+' || getenv("POSIXLY_CORRECT") != NULL) {
66         posixly_correct = 1;
67     } else {
68         posixly_correct = 0;
69     }
70     if (optstring[0] == '-') {
71         handle_nonopt_argv = 1;
72     } else {
73         handle_nonopt_argv = 0;
74     }
75 }
76
77 static int is_option(const char *arg)
78 {
79     return arg[0] == '-' && arg[1] != '\0';
80 }
81
82 int ya_getopt(int argc, char * const argv[], const char *optstring)
83 {
84     return ya_getopt_internal(argc, argv, optstring, NULL, NULL, 0);
85 }
86
87 int ya_getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex)
88 {
89     return ya_getopt_internal(argc, argv, optstring, longopts, longindex, 0);
90 }
91
92 int ya_getopt_long_only(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex)
93 {
94     return ya_getopt_internal(argc, argv, optstring, longopts, longindex, 1);
95 }
96
97 static int ya_getopt_internal(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex, int long_only)
98 {
99     static int start, end;
100
101     if (ya_optopt == '?') {
102         ya_optopt = 0;
103     }
104
105     if (posixly_correct == -1) {
106         check_gnu_extension(optstring);
107     }
108
109     if (ya_optind == 0) {
110         check_gnu_extension(optstring);
111         ya_optind = 1;
112         ya_optnext = NULL;
113     }
114
115     switch (optstring[0]) {
116     case '+':
117     case '-':
118         optstring++;
119     }
120
121     if (ya_optnext == NULL && start != 0) {
122         int last_pos = ya_optind - 1;
123
124         ya_optind -= end - start;
125         if (ya_optind <= 0) {
126             ya_optind = 1;
127         }
128         while (start < end--) {
129             int i;
130             char *arg = argv[end];
131
132             for (i = end; i < last_pos; i++) {
133                 ((char **)argv)[i] = argv[i + 1];
134             }
135             ((char const **)argv)[i] = arg;
136             last_pos--;
137         }
138         start = 0;
139     }
140
141     if (ya_optind >= argc) {
142         ya_optarg = NULL;
143         return -1;
144     }
145     if (ya_optnext == NULL) {
146         const char *arg = argv[ya_optind];
147         if (!is_option(arg)) {
148             if (handle_nonopt_argv) {
149                 ya_optarg = argv[ya_optind++];
150                 start = 0;
151                 return 1;
152             } else if (posixly_correct) {
153                 ya_optarg = NULL;
154                 return -1;
155             } else {
156                 int i;
157
158                 start = ya_optind;
159                 for (i = ya_optind + 1; i < argc; i++) {
160                     if (is_option(argv[i])) {
161                         end = i;
162                         break;
163                     }
164                 }
165                 if (i == argc) {
166                     ya_optarg = NULL;
167                     return -1;
168                 }
169                 ya_optind = i;
170                 arg = argv[ya_optind];
171             }
172         }
173         if (strcmp(arg, "--") == 0) {
174             ya_optind++;
175             return -1;
176         }
177         if (longopts != NULL && arg[1] == '-') {
178             return ya_getopt_longopts(argc, argv, argv[ya_optind] + 2, optstring, longopts, longindex, NULL);
179         }
180     }
181
182     if (ya_optnext == NULL) {
183         ya_optnext = argv[ya_optind] + 1;
184     }
185     if (long_only) {
186         int long_only_flag = 0;
187         int rv = ya_getopt_longopts(argc, argv, ya_optnext, optstring, longopts, longindex, &long_only_flag);
188         if (!long_only_flag) {
189             ya_optnext = NULL;
190             return rv;
191         }
192     }
193
194     return ya_getopt_shortopts(argc, argv, optstring, long_only);
195 }
196
197 static int ya_getopt_shortopts(int argc, char * const argv[], const char *optstring, int long_only)
198 {
199     int opt = *ya_optnext;
200     const char *os = strchr(optstring, opt);
201
202     if (os == NULL) {
203         ya_optarg = NULL;
204         if (long_only) {
205             ya_getopt_error(optstring, "%s: unrecognized option '-%s'\n", argv[0], ya_optnext);
206             ya_optind++;
207             ya_optnext = NULL;
208         } else {
209             ya_optopt = opt;
210             ya_getopt_error(optstring, "%s: invalid option -- '%c'\n", argv[0], opt);
211             if (*(++ya_optnext) == 0) {
212                 ya_optind++;
213                 ya_optnext = NULL;
214             }
215         }
216         return '?';
217     }
218     if (os[1] == ':') {
219         if (ya_optnext[1] == 0) {
220             ya_optind++;
221             ya_optnext = NULL;
222             if (os[2] == ':') {
223                 /* optional argument */
224                 ya_optarg = NULL;
225             } else {
226                 if (ya_optind == argc) {
227                     ya_optarg = NULL;
228                     ya_optopt = opt;
229                     ya_getopt_error(optstring, "%s: option requires an argument -- '%c'\n", argv[0], opt);
230                     if (optstring[0] == ':') {
231                         return ':';
232                     } else {
233                         return '?';
234                     }
235                 }
236                 ya_optarg = argv[ya_optind];
237                 ya_optind++;
238             }
239         } else {
240             ya_optarg = ya_optnext + 1;
241             ya_optind++;
242         }
243         ya_optnext = NULL;
244     } else {
245         ya_optarg = NULL;
246         if (ya_optnext[1] == 0) {
247             ya_optnext = NULL;
248             ya_optind++;
249         } else {
250             ya_optnext++;
251         }
252     }
253     return opt;
254 }
255
256 static int ya_getopt_longopts(int argc, char * const argv[], char *arg, const char *optstring, const struct option *longopts, int *longindex, int *long_only_flag)
257 {
258     char *val = NULL;
259     const struct option *opt;
260     size_t namelen;
261     int idx;
262
263     for (idx = 0; longopts[idx].name != NULL; idx++) {
264         opt = &longopts[idx];
265         namelen = strlen(opt->name);
266         if (strncmp(arg, opt->name, namelen) == 0) {
267             switch (arg[namelen]) {
268             case '\0':
269                 switch (opt->has_arg) {
270                 case ya_required_argument:
271                     ya_optind++;
272                     if (ya_optind == argc) {
273                         ya_optarg = NULL;
274                         ya_optopt = opt->val;
275                         ya_getopt_error(optstring, "%s: option '--%s' requires an argument\n", argv[0], opt->name);
276                         if (optstring[0] == ':') {
277                             return ':';
278                         } else {
279                             return '?';
280                         }
281                     }
282                     val = argv[ya_optind];
283                     break;
284                 }
285                 goto found;
286             case '=':
287                 if (opt->has_arg == ya_no_argument) {
288                     const char *hyphens = (argv[ya_optind][1] == '-') ? "--" : "-";
289
290                     ya_optind++;
291                     ya_optarg = NULL;
292                     ya_optopt = opt->val;
293                     ya_getopt_error(optstring, "%s: option '%s%s' doesn't allow an argument\n", argv[0], hyphens, opt->name);
294                     return '?';
295                 }
296                 val = arg + namelen + 1;
297                 goto found;
298             }
299         }
300     }
301     if (long_only_flag) {
302         *long_only_flag = 1;
303     } else {
304         ya_getopt_error(optstring, "%s: unrecognized option '%s'\n", argv[0], argv[ya_optind]);
305         ya_optind++;
306     }
307     return '?';
308 found:
309     ya_optarg = val;
310     ya_optind++;
311     if (opt->flag) {
312         *opt->flag = opt->val;
313     }
314     if (longindex) {
315         *longindex = idx;
316     }
317     return opt->flag ? 0 : opt->val;
318 }