Coverage Report

Created: 2023-03-26 06:28

/src/httpd/srclib/apr/misc/unix/getopt.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 1987, 1993, 1994
3
 *      The Regents of the University of California.  All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
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.
20
 *
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
31
 * SUCH DAMAGE.
32
 */
33
34
#include "apr_arch_misc.h"
35
#include "apr_strings.h"
36
#include "apr_lib.h"
37
38
0
#define EMSG    ""
39
40
APR_DECLARE(apr_status_t) apr_getopt_init(apr_getopt_t **os, apr_pool_t *cont,
41
                                      int argc, const char *const *argv)
42
0
{
43
0
    void *argv_buff;
44
45
0
    *os = apr_palloc(cont, sizeof(apr_getopt_t));
46
0
    (*os)->cont = cont;
47
0
    (*os)->reset = 0;
48
0
    (*os)->errfn = (apr_getopt_err_fn_t*)(fprintf);
49
0
    (*os)->errarg = (void*)(stderr);
50
51
0
    (*os)->place = EMSG;
52
0
    (*os)->argc = argc;
53
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
0
    argv_buff = apr_palloc(cont, (argc + 1) * sizeof(const char *));
59
0
    memcpy(argv_buff, argv, argc * sizeof(const char *));
60
0
    (*os)->argv = argv_buff;
61
0
    (*os)->argv[argc] = NULL;
62
63
0
    (*os)->interleave = 0;
64
0
    (*os)->ind = 1;
65
0
    (*os)->skip_start = 1;
66
0
    (*os)->skip_end = 1;
67
68
0
    return APR_SUCCESS;
69
0
}
70
71
APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts,
72
                                     char *optch, const char **optarg)
73
0
{
74
0
    const char *oli;  /* option letter list index */
75
76
0
    if (os->reset || !*os->place) {   /* update scanning pointer */
77
0
        os->reset = 0;
78
0
        if (os->ind >= os->argc || *(os->place = os->argv[os->ind]) != '-') {
79
0
            os->place = EMSG;
80
0
            *optch = os->opt;
81
0
            return (APR_EOF);
82
0
        }
83
0
        if (os->place[1] && *++os->place == '-') {        /* found "--" */
84
0
            ++os->ind;
85
0
            os->place = EMSG;
86
0
            *optch = os->opt;
87
0
            return (APR_EOF);
88
0
        }
89
0
    }                                /* option letter okay? */
90
0
    if ((os->opt = (int) *os->place++) == (int) ':' ||
91
0
        !(oli = strchr(opts, os->opt))) {
92
        /*
93
         * if the user didn't specify '-' as an option,
94
         * assume it means -1.
95
         */
96
0
        if (os->opt == (int) '-') {
97
0
            *optch = os->opt;
98
0
            return (APR_EOF);
99
0
        }
100
0
        if (!*os->place)
101
0
            ++os->ind;
102
0
        if (os->errfn && *opts != ':') {
103
0
            (os->errfn)(os->errarg, "%s: illegal option -- %c\n",
104
0
                        apr_filepath_name_get(*os->argv), os->opt);
105
0
        }
106
0
        *optch = os->opt;
107
0
        return (APR_BADCH);
108
0
    }
109
0
    if (*++oli != ':') {        /* don't need argument */
110
0
        *optarg = NULL;
111
0
        if (!*os->place)
112
0
            ++os->ind;
113
0
    }
114
0
    else {                        /* need an argument */
115
0
        if (*os->place)                /* no white space */
116
0
            *optarg = os->place;
117
0
        else if (os->argc <= ++os->ind) {        /* no arg */
118
0
            os->place = EMSG;
119
0
            if (*opts == ':') {
120
0
                *optch = os->opt;
121
0
                return (APR_BADARG);
122
0
            }
123
0
            if (os->errfn) {
124
0
                (os->errfn)(os->errarg,
125
0
                            "%s: option requires an argument -- %c\n",
126
0
                            apr_filepath_name_get(*os->argv), os->opt);
127
0
            }
128
0
            *optch = os->opt;
129
0
            return (APR_BADCH);
130
0
        }
131
0
        else                        /* white space */
132
0
            *optarg = os->argv[os->ind];
133
0
        os->place = EMSG;
134
0
        ++os->ind;
135
0
    }
136
0
    *optch = os->opt;
137
0
    return APR_SUCCESS;
138
0
}
139
140
/* Reverse the sequence argv[start..start+len-1]. */
141
static void reverse(const char **argv, int start, int len)
142
0
{
143
0
    const char *temp;
144
145
0
    for (; len >= 2; start++, len -= 2) {
146
0
        temp = argv[start];
147
0
        argv[start] = argv[start + len - 1];
148
0
        argv[start + len - 1] = temp;
149
0
    }
150
0
}
151
152
/*
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.
157
 */
158
static void permute(apr_getopt_t *os)
159
0
{
160
0
    int len1 = os->skip_end - os->skip_start;
161
0
    int len2 = os->ind - os->skip_end;
162
163
0
    if (os->interleave) {
164
        /*
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
168
         * sub-ranges.
169
         */
170
0
        reverse(os->argv, os->skip_start, len1 + len2);
171
0
        reverse(os->argv, os->skip_start, len2);
172
0
        reverse(os->argv, os->skip_start + len2, len1);
173
0
    }
174
175
    /* Reset skip range to the new location of the non-option sequence. */
176
0
    os->skip_start += len2;
177
0
    os->skip_end += len2;
178
0
}
179
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,
182
                         apr_status_t status)
183
0
{
184
0
    if (os->errfn)
185
0
        (os->errfn)(os->errarg, "%s: %s: %s\n",
186
0
                    apr_filepath_name_get(*os->argv), err, str);
187
0
    return status;
188
0
}
189
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,
192
                         apr_status_t status)
193
0
{
194
0
    if (os->errfn)
195
0
        (os->errfn)(os->errarg, "%s: %s: %c\n",
196
0
                    apr_filepath_name_get(*os->argv), err, ch);
197
0
    return status;
198
0
}
199
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)
203
0
{
204
0
    const char *p;
205
0
    int i;
206
207
    /* Let the calling program reset option processing. */
208
0
    if (os->reset) {
209
0
        os->place = EMSG;
210
0
        os->ind = 1;
211
0
        os->reset = 0;
212
0
    }
213
214
    /*
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
218
     * one first.  */
219
0
    p = os->place;
220
0
    if (*p == '\0') {
221
        /* If we are interleaving, skip non-option arguments. */
222
0
        if (os->interleave) {
223
0
            while (os->ind < os->argc && *os->argv[os->ind] != '-')
224
0
                os->ind++;
225
0
            os->skip_end = os->ind;
226
0
        }
227
0
        if (os->ind >= os->argc || *os->argv[os->ind] != '-') {
228
0
            os->ind = os->skip_start;
229
0
            return APR_EOF;
230
0
        }
231
232
0
        p = os->argv[os->ind++] + 1;
233
0
        if (*p == '-' && p[1] != '\0') {        /* Long option */
234
            /* Search for the long option name in the caller's table. */
235
0
            apr_size_t len = 0;
236
237
0
            p++;
238
0
            for (i = 0; ; i++) {
239
0
                if (opts[i].optch == 0)             /* No match */
240
0
                    return serr(os, "invalid option", p - 2, APR_BADCH);
241
242
0
                if (opts[i].name) {
243
0
                    len = strlen(opts[i].name);
244
0
                    if (strncmp(p, opts[i].name, len) == 0
245
0
                        && (p[len] == '\0' || p[len] == '='))
246
0
                        break;
247
0
                }
248
0
            }
249
0
            *optch = opts[i].optch;
250
251
0
            if (opts[i].has_arg) {
252
0
                if (p[len] == '=')             /* Argument inline */
253
0
                    *optarg = p + len + 1;
254
0
                else {
255
0
                    if (os->ind >= os->argc)   /* Argument missing */
256
0
                        return serr(os, "missing argument", p - 2, APR_BADARG);
257
0
                    else                       /* Argument in next arg */
258
0
                        *optarg = os->argv[os->ind++];
259
0
                }
260
0
            } else {
261
0
                *optarg = NULL;
262
0
                if (p[len] == '=')
263
0
                    return serr(os, "erroneous argument", p - 2, APR_BADARG);
264
0
            }
265
0
            permute(os);
266
0
            return APR_SUCCESS;
267
0
        } else {
268
0
            if (*p == '-') {                 /* Bare "--"; we're done */
269
0
                permute(os);
270
0
                os->ind = os->skip_start;
271
0
                return APR_EOF;
272
0
            }
273
0
            else
274
0
                if (*p == '\0')                    /* Bare "-" is illegal */
275
0
                    return serr(os, "invalid option", p, APR_BADCH);
276
0
        }
277
0
    }
278
279
    /*
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.
282
     */
283
0
    for (i = 0; ; i++) {
284
0
        if (opts[i].optch == 0)                     /* No match */
285
0
            return cerr(os, "invalid option character", *p, APR_BADCH);
286
287
0
        if (*p == opts[i].optch)
288
0
            break;
289
0
    }
290
0
    *optch = *p++;
291
292
0
    if (opts[i].has_arg) {
293
0
        if (*p != '\0')                         /* Argument inline */
294
0
            *optarg = p;
295
0
        else {
296
0
            if (os->ind >= os->argc)           /* Argument missing */
297
0
                return cerr(os, "missing argument", *optch, APR_BADARG);
298
0
            else                               /* Argument in next arg */
299
0
                *optarg = os->argv[os->ind++];
300
0
        }
301
0
        os->place = EMSG;
302
0
    } else {
303
0
        *optarg = NULL;
304
0
        os->place = p;
305
0
    }
306
307
0
    permute(os);
308
0
    return APR_SUCCESS;
309
0
}