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++];