2
* Copyright (c) 1987, 1993, 1994
3
* The Regents of the University of California. All rights reserved.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. All advertising materials mentioning features or use of this software
14
* must display the following acknowledgement:
15
* This product includes software developed by the University of
16
* California, Berkeley and its contributors.
17
* 4. Neither the name of the University nor the names of its contributors
18
* may be used to endorse or promote products derived from this software
19
* without specific prior written permission.
21
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34
#include "apr_arch_misc.h"
35
#include "apr_strings.h"
40
APR_DECLARE(apr_status_t) apr_getopt_init(apr_getopt_t **os, apr_pool_t *cont,
41
int argc, const char *const *argv)
45
*os = apr_palloc(cont, sizeof(apr_getopt_t));
48
(*os)->errfn = (apr_getopt_err_fn_t*)(fprintf);
49
(*os)->errarg = (void*)(stderr);
54
/* The argv parameter must be compatible with main()'s argv, since
55
that's the primary purpose of this function. But people might
56
want to use this function with arrays other than the main argv,
57
and we shouldn't touch the caller's data. So we copy. */
58
argv_buff = apr_palloc(cont, (argc + 1) * sizeof(const char *));
59
memcpy(argv_buff, argv, argc * sizeof(const char *));
60
(*os)->argv = argv_buff;
61
(*os)->argv[argc] = NULL;
63
(*os)->interleave = 0;
65
(*os)->skip_start = 1;
71
APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts,
72
char *optch, const char **optarg)
74
const char *oli; /* option letter list index */
76
if (os->reset || !*os->place) { /* update scanning pointer */
78
if (os->ind >= os->argc || *(os->place = os->argv[os->ind]) != '-') {
83
if (os->place[1] && *++os->place == '-') { /* found "--" */
89
} /* option letter okay? */
90
if ((os->opt = (int) *os->place++) == (int) ':' ||
91
!(oli = strchr(opts, os->opt))) {
93
* if the user didn't specify '-' as an option,
96
if (os->opt == (int) '-') {
102
if (os->errfn && *opts != ':') {
103
(os->errfn)(os->errarg, "%s: illegal option -- %c\n",
104
apr_filepath_name_get(*os->argv), os->opt);
109
if (*++oli != ':') { /* don't need argument */
114
else { /* need an argument */
115
if (*os->place) /* no white space */
117
else if (os->argc <= ++os->ind) { /* no arg */
124
(os->errfn)(os->errarg,
125
"%s: option requires an argument -- %c\n",
126
apr_filepath_name_get(*os->argv), os->opt);
131
else /* white space */
132
*optarg = os->argv[os->ind];
140
/* Reverse the sequence argv[start..start+len-1]. */
141
static void reverse(const char **argv, int start, int len)
145
for (; len >= 2; start++, len -= 2) {
147
argv[start] = argv[start + len - 1];
148
argv[start + len - 1] = temp;
153
* Permute os->argv with the goal that non-option arguments will all
154
* appear at the end. os->skip_start is where we started skipping
155
* non-option arguments, os->skip_end is where we stopped, and os->ind
156
* is where we are now.
158
static void permute(apr_getopt_t *os)
160
int len1 = os->skip_end - os->skip_start;
161
int len2 = os->ind - os->skip_end;
163
if (os->interleave) {
165
* Exchange the sequences argv[os->skip_start..os->skip_end-1] and
166
* argv[os->skip_end..os->ind-1]. The easiest way to do that is
167
* to reverse the entire range and then reverse the two
170
reverse(os->argv, os->skip_start, len1 + len2);
171
reverse(os->argv, os->skip_start, len2);
172
reverse(os->argv, os->skip_start + len2, len1);
175
/* Reset skip range to the new location of the non-option sequence. */
176
os->skip_start += len2;
177
os->skip_end += len2;
180
/* Helper function to print out an error involving a long option */
181
static apr_status_t serr(apr_getopt_t *os, const char *err, const char *str,
185
(os->errfn)(os->errarg, "%s: %s: %s\n",
186
apr_filepath_name_get(*os->argv), err, str);
190
/* Helper function to print out an error involving a short option */
191
static apr_status_t cerr(apr_getopt_t *os, const char *err, int ch,
195
(os->errfn)(os->errarg, "%s: %s: %c\n",
196
apr_filepath_name_get(*os->argv), err, ch);
200
APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os,
201
const apr_getopt_option_t *opts,
202
int *optch, const char **optarg)
207
/* Let the calling program reset option processing. */
215
* We can be in one of two states: in the middle of processing a
216
* run of short options, or about to process a new argument.
217
* Since the second case can lead to the first one, handle that
221
/* If we are interleaving, skip non-option arguments. */
222
if (os->interleave) {
223
while (os->ind < os->argc && *os->argv[os->ind] != '-')
225
os->skip_end = os->ind;
227
if (os->ind >= os->argc || *os->argv[os->ind] != '-') {
228
os->ind = os->skip_start;
232
p = os->argv[os->ind++] + 1;
233
if (*p == '-' && p[1] != '\0') { /* Long option */
234
/* Search for the long option name in the caller's table. */
239
if (opts[i].optch == 0) /* No match */
240
return serr(os, "invalid option", p - 2, APR_BADCH);
243
len = strlen(opts[i].name);
244
if (strncmp(p, opts[i].name, len) == 0
245
&& (p[len] == '\0' || p[len] == '='))
249
*optch = opts[i].optch;
251
if (opts[i].has_arg) {
252
if (p[len] == '=') /* Argument inline */
253
*optarg = p + len + 1;
255
if (os->ind >= os->argc) /* Argument missing */
256
return serr(os, "missing argument", p - 2, APR_BADARG);
257
else /* Argument in next arg */
258
*optarg = os->argv[os->ind++];
263
return serr(os, "erroneous argument", p - 2, APR_BADARG);
268
if (*p == '-') { /* Bare "--"; we're done */
270
os->ind = os->skip_start;
274
if (*p == '\0') /* Bare "-" is illegal */
275
return serr(os, "invalid option", p, APR_BADCH);
280
* Now we're in a run of short options, and *p is the next one.
281
* Look for it in the caller's table.
284
if (opts[i].optch == 0) /* No match */
285
return cerr(os, "invalid option character", *p, APR_BADCH);
287
if (*p == opts[i].optch)
292
if (opts[i].has_arg) {
293
if (*p != '\0') /* Argument inline */
296
if (os->ind >= os->argc) /* Argument missing */
297
return cerr(os, "missing argument", *optch, APR_BADARG);
298
else /* Argument in next arg */
299
*optarg = os->argv[os->ind++];