2 * musl as a whole is licensed under the following standard MIT license:
4 * ----------------------------------------------------------------------
5 * Copyright © 2005-2020 Rich Felker, et al.
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 * ----------------------------------------------------------------------
28 #include <wsutil/ws_getopt.h>
37 #include <ws_codepoints.h>
40 int ws_optind
=1, ws_opterr
=1, ws_optopt
, ws_optpos
, ws_optreset
=0;
42 static void __getopt_msg(const char *prog
, const char *errstr
,
43 const char *optbuf
, size_t optsize
)
46 if ((fputs(prog
, f
) < 0) ||
47 (fputs(errstr
, f
) < 0) ||
48 (fwrite(optbuf
, sizeof(char), optsize
, f
) != optsize
)) {
54 static void permute(char *const *argv
, int dest
, int src
)
56 char **av
= (char **)argv
;
59 for (i
=src
; i
>dest
; i
--)
64 int ws_getopt(int argc
, char * const argv
[], const char *optstring
)
71 if (!ws_optind
|| ws_optreset
) {
77 if (ws_optind
>= argc
|| !argv
[ws_optind
])
80 if (argv
[ws_optind
][0] != '-') {
81 if (optstring
[0] == '-') {
82 ws_optarg
= argv
[ws_optind
++];
88 if (!argv
[ws_optind
][1])
91 if (argv
[ws_optind
][1] == '-' && !argv
[ws_optind
][2]) {
96 if (!ws_optpos
) ws_optpos
++;
97 if ((k
= mbtowc(&c
, argv
[ws_optind
]+ws_optpos
, MB_LEN_MAX
)) < 0) {
99 c
= UNICODE_REPLACEMENT_CHARACTER
; /* replacement char */
101 optchar
= argv
[ws_optind
]+ws_optpos
;
104 if (!argv
[ws_optind
][ws_optpos
]) {
109 if (optstring
[0] == '-' || optstring
[0] == '+')
115 l
= mbtowc(&d
, optstring
+i
, MB_LEN_MAX
);
116 if (l
>0) i
+=l
; else i
++;
117 } while (l
&& d
!= c
);
119 if (d
!= c
|| c
== ':') {
121 if (optstring
[0] != ':' && ws_opterr
)
122 __getopt_msg(argv
[0], ": unrecognized option: ", optchar
, k
);
125 if (optstring
[i
] == ':') {
127 if (optstring
[i
+1] != ':' || ws_optpos
) {
128 ws_optarg
= argv
[ws_optind
++] + ws_optpos
;
131 if (ws_optind
> argc
) {
133 if (optstring
[0] == ':') return ':';
134 if (ws_opterr
) __getopt_msg(argv
[0],
135 ": option requires an argument: ",
143 static int __getopt_long_core(int argc
, char *const *argv
, const char *optstring
, const struct ws_option
*longopts
, int *idx
, int longonly
);
145 static int __getopt_long(int argc
, char *const *argv
, const char *optstring
, const struct ws_option
*longopts
, int *idx
, int longonly
)
147 int ret
, skipped
, resumed
;
148 if (!ws_optind
|| ws_optreset
) {
153 if (ws_optind
>= argc
|| !argv
[ws_optind
]) return -1;
155 if (optstring
[0] != '+' && optstring
[0] != '-') {
157 for (i
=ws_optind
; ; i
++) {
158 if (i
>= argc
|| !argv
[i
]) return -1;
159 if (argv
[i
][0] == '-' && argv
[i
][1]) break;
164 ret
= __getopt_long_core(argc
, argv
, optstring
, longopts
, idx
, longonly
);
165 if (resumed
> skipped
) {
166 int i
, cnt
= ws_optind
-resumed
;
167 for (i
=0; i
<cnt
; i
++)
168 permute(argv
, skipped
, ws_optind
-1);
169 ws_optind
= skipped
+ cnt
;
174 static int __getopt_long_core(int argc
, char *const *argv
, const char *optstring
, const struct ws_option
*longopts
, int *idx
, int longonly
)
177 if (longopts
&& argv
[ws_optind
][0] == '-' &&
178 ((longonly
&& argv
[ws_optind
][1] && argv
[ws_optind
][1] != '-') ||
179 (argv
[ws_optind
][1] == '-' && argv
[ws_optind
][2])))
181 int colon
= optstring
[optstring
[0]=='+'||optstring
[0]=='-']==':';
182 int i
, cnt
, match
= -1;
183 char *arg
= NULL
, *opt
, *start
= argv
[ws_optind
]+1;
184 for (cnt
=i
=0; longopts
[i
].name
; i
++) {
185 const char *name
= longopts
[i
].name
;
187 if (*opt
== '-') opt
++;
188 while (*opt
&& *opt
!= '=' && *opt
== *name
) {
192 if (*opt
&& *opt
!= '=') continue;
201 if (cnt
==1 && longonly
&& arg
-start
== mblen(start
, MB_LEN_MAX
)) {
202 ptrdiff_t l
= arg
- start
;
203 for (i
=0; optstring
[i
]; i
++) {
205 for (j
=0; j
<l
&& start
[j
]==optstring
[i
+j
]; j
++);
217 if (!longopts
[i
].has_arg
) {
218 ws_optopt
= longopts
[i
].val
;
219 if (colon
|| !ws_opterr
)
221 __getopt_msg(argv
[0],
222 ": option does not take an argument: ",
224 strlen(longopts
[i
].name
));
228 } else if (longopts
[i
].has_arg
== ws_required_argument
) {
229 if (!(ws_optarg
= argv
[ws_optind
])) {
230 ws_optopt
= longopts
[i
].val
;
231 if (colon
) return ':';
232 if (!ws_opterr
) return '?';
233 __getopt_msg(argv
[0],
234 ": option requires an argument: ",
236 strlen(longopts
[i
].name
));
242 if (longopts
[i
].flag
) {
243 *longopts
[i
].flag
= longopts
[i
].val
;
246 return longopts
[i
].val
;
248 if (argv
[ws_optind
][1] == '-') {
250 if (!colon
&& ws_opterr
)
251 __getopt_msg(argv
[0], cnt
?
252 ": option is ambiguous: " :
253 ": unrecognized option: ",
255 strlen(argv
[ws_optind
]+2));
260 return ws_getopt(argc
, argv
, optstring
);
263 int ws_getopt_long(int argc
, char *const *argv
, const char *optstring
, const struct ws_option
*longopts
, int *idx
)
265 return __getopt_long(argc
, argv
, optstring
, longopts
, idx
, 0);
268 int ws_getopt_long_only(int argc
, char *const *argv
, const char *optstring
, const struct ws_option
*longopts
, int *idx
)
270 return __getopt_long(argc
, argv
, optstring
, longopts
, idx
, 1);