~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to srclib/apr/misc/unix/getopt.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#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
{
 
43
    void *argv_buff;
 
44
 
 
45
    *os = apr_palloc(cont, sizeof(apr_getopt_t));
 
46
    (*os)->cont = cont;
 
47
    (*os)->reset = 0;
 
48
    (*os)->errfn = (apr_getopt_err_fn_t*)(fprintf);
 
49
    (*os)->errarg = (void*)(stderr);
 
50
 
 
51
    (*os)->place = EMSG;
 
52
    (*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
    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;
 
62
 
 
63
    (*os)->interleave = 0;
 
64
    (*os)->ind = 1;
 
65
    (*os)->skip_start = 1;
 
66
    (*os)->skip_end = 1;
 
67
 
 
68
    return APR_SUCCESS;
 
69
}
 
70
 
 
71
APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts, 
 
72
                                     char *optch, const char **optarg)
 
73
{
 
74
    const char *oli;  /* option letter list index */
 
75
 
 
76
    if (os->reset || !*os->place) {   /* update scanning pointer */
 
77
        os->reset = 0;
 
78
        if (os->ind >= os->argc || *(os->place = os->argv[os->ind]) != '-') {
 
79
            os->place = EMSG;
 
80
            *optch = os->opt;
 
81
            return (APR_EOF);
 
82
        }
 
83
        if (os->place[1] && *++os->place == '-') {        /* found "--" */
 
84
            ++os->ind;
 
85
            os->place = EMSG;
 
86
            *optch = os->opt;
 
87
            return (APR_EOF);
 
88
        }
 
89
    }                                /* option letter okay? */
 
90
    if ((os->opt = (int) *os->place++) == (int) ':' ||
 
91
        !(oli = strchr(opts, os->opt))) {
 
92
        /*
 
93
         * if the user didn't specify '-' as an option,
 
94
         * assume it means -1.
 
95
         */
 
96
        if (os->opt == (int) '-') {
 
97
            *optch = os->opt;
 
98
            return (APR_EOF);
 
99
        }
 
100
        if (!*os->place)
 
101
            ++os->ind;
 
102
        if (os->errfn && *opts != ':') {
 
103
            (os->errfn)(os->errarg, "%s: illegal option -- %c\n",
 
104
                        apr_filepath_name_get(*os->argv), os->opt);
 
105
        }
 
106
        *optch = os->opt;
 
107
        return (APR_BADCH);
 
108
    }
 
109
    if (*++oli != ':') {        /* don't need argument */
 
110
        *optarg = NULL;
 
111
        if (!*os->place)
 
112
            ++os->ind;
 
113
    }
 
114
    else {                        /* need an argument */
 
115
        if (*os->place)                /* no white space */
 
116
            *optarg = os->place;
 
117
        else if (os->argc <= ++os->ind) {        /* no arg */
 
118
            os->place = EMSG;
 
119
            if (*opts == ':') {
 
120
                *optch = os->opt;
 
121
                return (APR_BADARG);
 
122
            }
 
123
            if (os->errfn) {
 
124
                (os->errfn)(os->errarg, 
 
125
                            "%s: option requires an argument -- %c\n",
 
126
                            apr_filepath_name_get(*os->argv), os->opt);
 
127
            }
 
128
            *optch = os->opt;
 
129
            return (APR_BADCH);
 
130
        }
 
131
        else                        /* white space */
 
132
            *optarg = os->argv[os->ind];
 
133
        os->place = EMSG;
 
134
        ++os->ind;
 
135
    }
 
136
    *optch = os->opt;
 
137
    return APR_SUCCESS;
 
138
}
 
139
 
 
140
/* Reverse the sequence argv[start..start+len-1]. */
 
141
static void reverse(const char **argv, int start, int len)
 
142
{
 
143
    const char *temp;
 
144
 
 
145
    for (; len >= 2; start++, len -= 2) {
 
146
        temp = argv[start];
 
147
        argv[start] = argv[start + len - 1];
 
148
        argv[start + len - 1] = temp;
 
149
    }
 
150
}
 
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
{
 
160
    int len1 = os->skip_end - os->skip_start;
 
161
    int len2 = os->ind - os->skip_end;
 
162
 
 
163
    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
        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);
 
173
    }
 
174
 
 
175
    /* Reset skip range to the new location of the non-option sequence. */
 
176
    os->skip_start += len2;
 
177
    os->skip_end += len2;
 
178
}
 
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
{
 
184
    if (os->errfn)
 
185
        (os->errfn)(os->errarg, "%s: %s: %s\n", 
 
186
                    apr_filepath_name_get(*os->argv), err, str);
 
187
    return status;
 
188
}
 
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
{
 
194
    if (os->errfn)
 
195
        (os->errfn)(os->errarg, "%s: %s: %c\n", 
 
196
                    apr_filepath_name_get(*os->argv), err, ch);
 
197
    return status;
 
198
}
 
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
{
 
204
    const char *p;
 
205
    int i;
 
206
 
 
207
    /* Let the calling program reset option processing. */
 
208
    if (os->reset) {
 
209
        os->place = EMSG;
 
210
        os->ind = 1;
 
211
        os->reset = 0;
 
212
    }
 
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
    p = os->place;
 
220
    if (*p == '\0') {
 
221
        /* If we are interleaving, skip non-option arguments. */
 
222
        if (os->interleave) {
 
223
            while (os->ind < os->argc && *os->argv[os->ind] != '-')
 
224
                os->ind++;
 
225
            os->skip_end = os->ind;
 
226
        }
 
227
        if (os->ind >= os->argc || *os->argv[os->ind] != '-') {
 
228
            os->ind = os->skip_start;
 
229
            return APR_EOF;
 
230
        }
 
231
 
 
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. */
 
235
            apr_size_t len = 0;
 
236
 
 
237
            p++;
 
238
            for (i = 0; ; i++) {
 
239
                if (opts[i].optch == 0)             /* No match */
 
240
                    return serr(os, "invalid option", p - 2, APR_BADCH);
 
241
 
 
242
                if (opts[i].name) {
 
243
                    len = strlen(opts[i].name);
 
244
                    if (strncmp(p, opts[i].name, len) == 0
 
245
                        && (p[len] == '\0' || p[len] == '='))
 
246
                        break;
 
247
                }
 
248
            }
 
249
            *optch = opts[i].optch;
 
250
 
 
251
            if (opts[i].has_arg) {
 
252
                if (p[len] == '=')             /* Argument inline */
 
253
                    *optarg = p + len + 1;
 
254
                else { 
 
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++];
 
259
                }
 
260
            } else {
 
261
                *optarg = NULL;
 
262
                if (p[len] == '=')
 
263
                    return serr(os, "erroneous argument", p - 2, APR_BADARG);
 
264
            }
 
265
            permute(os);
 
266
            return APR_SUCCESS;
 
267
        } else {
 
268
            if (*p == '-') {                 /* Bare "--"; we're done */
 
269
                permute(os);
 
270
                os->ind = os->skip_start;
 
271
                return APR_EOF;
 
272
            }
 
273
            else 
 
274
                if (*p == '\0')                    /* Bare "-" is illegal */
 
275
                    return serr(os, "invalid option", p, APR_BADCH);
 
276
        }
 
277
    }
 
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
    for (i = 0; ; i++) {
 
284
        if (opts[i].optch == 0)                     /* No match */
 
285
            return cerr(os, "invalid option character", *p, APR_BADCH);
 
286
 
 
287
        if (*p == opts[i].optch)
 
288
            break;
 
289
    }
 
290
    *optch = *p++;
 
291
 
 
292
    if (opts[i].has_arg) {
 
293
        if (*p != '\0')                         /* Argument inline */
 
294
            *optarg = p;
 
295
        else { 
 
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++];
 
300
        }
 
301
        os->place = EMSG;
 
302
    } else {
 
303
        *optarg = NULL;
 
304
        os->place = p;
 
305
    }
 
306
 
 
307
    permute(os);
 
308
    return APR_SUCCESS;
 
309
}