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>
39 #include <ws_codepoints.h>
42 int ws_optind
=1, ws_opterr
=1, ws_optopt
, ws_optpos
, ws_optreset
=0;
44 static void __getopt_msg(const char *prog
, const char *errstr
,
45 const char *optbuf
, size_t optsize
)
48 if ((fputs(prog
, f
) < 0) ||
49 (fputs(errstr
, f
) < 0) ||
50 (fwrite(optbuf
, sizeof(char), optsize
, f
) != optsize
)) {
56 static void permute(char *const *argv
, int dest
, int src
)
58 char **av
= (char **)argv
;
61 for (i
=src
; i
>dest
; i
--)
66 int ws_getopt(int argc
, char * const argv
[], const char *optstring
)
73 if (!ws_optind
|| ws_optreset
) {
79 if (ws_optind
>= argc
|| !argv
[ws_optind
])
82 if (argv
[ws_optind
][0] != '-') {
83 if (optstring
[0] == '-') {
84 ws_optarg
= argv
[ws_optind
++];
90 if (!argv
[ws_optind
][1])
93 if (argv
[ws_optind
][1] == '-' && !argv
[ws_optind
][2]) {
98 if (!ws_optpos
) ws_optpos
++;
99 if ((k
= mbtowc(&c
, argv
[ws_optind
]+ws_optpos
, MB_LEN_MAX
)) < 0) {
101 c
= UNICODE_REPLACEMENT_CHARACTER
; /* replacement char */
103 optchar
= argv
[ws_optind
]+ws_optpos
;
106 if (!argv
[ws_optind
][ws_optpos
]) {
111 if (optstring
[0] == '-' || optstring
[0] == '+')
117 l
= mbtowc(&d
, optstring
+i
, MB_LEN_MAX
);
118 if (l
>0) i
+=l
; else i
++;
119 } while (l
&& d
!= c
);
121 if (d
!= c
|| c
== ':') {
123 if (optstring
[0] != ':' && ws_opterr
)
124 __getopt_msg(g_get_prgname(), ": unrecognized option: ", optchar
, k
);
127 if (optstring
[i
] == ':') {
129 if (optstring
[i
+1] != ':' || ws_optpos
) {
130 ws_optarg
= argv
[ws_optind
++] + ws_optpos
;
133 if (ws_optind
> argc
) {
135 if (optstring
[0] == ':') return ':';
136 if (ws_opterr
) __getopt_msg(g_get_prgname(),
137 ": option requires an argument: ",
145 static int __getopt_long_core(int argc
, char *const *argv
, const char *optstring
, const struct ws_option
*longopts
, int *idx
, int longonly
);
147 static int __getopt_long(int argc
, char *const *argv
, const char *optstring
, const struct ws_option
*longopts
, int *idx
, int longonly
)
149 int ret
, skipped
, resumed
;
150 if (!ws_optind
|| ws_optreset
) {
155 if (ws_optind
>= argc
|| !argv
[ws_optind
]) return -1;
157 if (optstring
[0] != '+' && optstring
[0] != '-') {
159 for (i
=ws_optind
; ; i
++) {
160 if (i
>= argc
|| !argv
[i
]) return -1;
161 if (argv
[i
][0] == '-' && argv
[i
][1]) break;
166 ret
= __getopt_long_core(argc
, argv
, optstring
, longopts
, idx
, longonly
);
167 if (resumed
> skipped
) {
168 int i
, cnt
= ws_optind
-resumed
;
169 for (i
=0; i
<cnt
; i
++)
170 permute(argv
, skipped
, ws_optind
-1);
171 ws_optind
= skipped
+ cnt
;
176 static int __getopt_long_core(int argc
, char *const *argv
, const char *optstring
, const struct ws_option
*longopts
, int *idx
, int longonly
)
179 if (longopts
&& argv
[ws_optind
][0] == '-' &&
180 ((longonly
&& argv
[ws_optind
][1] && argv
[ws_optind
][1] != '-') ||
181 (argv
[ws_optind
][1] == '-' && argv
[ws_optind
][2])))
183 int colon
= optstring
[optstring
[0]=='+'||optstring
[0]=='-']==':';
184 int i
, cnt
, match
= -1;
185 char *arg
= NULL
, *opt
, *start
= argv
[ws_optind
]+1;
186 for (cnt
=i
=0; longopts
[i
].name
; i
++) {
187 const char *name
= longopts
[i
].name
;
189 if (*opt
== '-') opt
++;
190 while (*opt
&& *opt
!= '=' && *opt
== *name
) {
194 if (*opt
&& *opt
!= '=') continue;
203 if (cnt
==1 && longonly
&& arg
-start
== mblen(start
, MB_LEN_MAX
)) {
204 ptrdiff_t l
= arg
- start
;
205 for (i
=0; optstring
[i
]; i
++) {
207 for (j
=0; j
<l
&& start
[j
]==optstring
[i
+j
]; j
++);
219 if (!longopts
[i
].has_arg
) {
220 ws_optopt
= longopts
[i
].val
;
221 if (colon
|| !ws_opterr
)
223 __getopt_msg(g_get_prgname(),
224 ": option does not take an argument: ",
226 strlen(longopts
[i
].name
));
230 } else if (longopts
[i
].has_arg
== ws_required_argument
) {
231 if (!(ws_optarg
= argv
[ws_optind
])) {
232 ws_optopt
= longopts
[i
].val
;
233 if (colon
) return ':';
234 if (!ws_opterr
) return '?';
235 __getopt_msg(g_get_prgname(),
236 ": option requires an argument: ",
238 strlen(longopts
[i
].name
));
244 if (longopts
[i
].flag
) {
245 *longopts
[i
].flag
= longopts
[i
].val
;
248 return longopts
[i
].val
;
250 if (argv
[ws_optind
][1] == '-') {
252 if (!colon
&& ws_opterr
)
253 __getopt_msg(g_get_prgname(), cnt
?
254 ": option is ambiguous: " :
255 ": unrecognized option: ",
257 strlen(argv
[ws_optind
]+2));
262 return ws_getopt(argc
, argv
, optstring
);
265 int ws_getopt_long(int argc
, char *const *argv
, const char *optstring
, const struct ws_option
*longopts
, int *idx
)
267 return __getopt_long(argc
, argv
, optstring
, longopts
, idx
, 0);
270 int ws_getopt_long_only(int argc
, char *const *argv
, const char *optstring
, const struct ws_option
*longopts
, int *idx
)
272 return __getopt_long(argc
, argv
, optstring
, longopts
, idx
, 1);