View | Details | Raw Unified | Return to bug 56030
Collapse All | Expand All

(-)include/apr_getopt.h (+40 lines)
Lines 92-97 Link Here
92
};
92
};
93
93
94
/**
94
/**
95
 * Error codes returned from apr_getopt_errcode().
96
 * 
97
 * The associated values returned from apr_getopt_errparam() are given
98
 * below for each error code.
99
 */
100
typedef enum {
101
    APR_GETOPT_INVALID_OPTION,    /**< Invalid option; error parameter
102
                                       is the option. */
103
    APR_GETOPT_MISSING_ARGUMENT,  /**< Missing argument; error parameter is
104
                                       the option whose argument is
105
                                       missing. */
106
    APR_GETOPT_INVALID_ARGUMENT   /**< Invalid or malformed argument; error
107
                                       parameter is the invalid argument. */
108
} apr_getopt_error_e;
109
110
/**
95
 * Initialize the arguments for parsing by apr_getopt().
111
 * Initialize the arguments for parsing by apr_getopt().
96
 * @param os   The options structure created for apr_getopt()
112
 * @param os   The options structure created for apr_getopt()
97
 * @param cont The pool to operate on
113
 * @param cont The pool to operate on
Lines 151-156 Link Here
151
					  const apr_getopt_option_t *opts,
167
					  const apr_getopt_option_t *opts,
152
					  int *option_ch,
168
					  int *option_ch,
153
                                          const char **option_arg);
169
                                          const char **option_arg);
170
171
/**
172
 * Retrieve a code describing the current getopt error. This function
173
 * may only be called from the getopt error function, @c errfn
174
 * in @c apr_getopt_t.
175
 * @param os  The apr_getopt_t structure created by apr_getopt_init().
176
 * @return    The error code.
177
 * Error codes may have an associated string parameter;
178
 * use apr_getopt_errparam() to retrieve it.
179
 */
180
APR_DECLARE(apr_getopt_error_e) apr_getopt_errcode(apr_getopt_t *os);
181
182
/**
183
 * Retrieve a string parameter pertaining to the current getopt error.
184
 * This function may only be called from the getopt error function, @c errfn
185
 * in @c apr_getopt_t.
186
 * @param os  The apr_getopt_t structure created by apr_getopt_init().
187
 * @return    The error parameter string. It is only valid during the error 
188
 *            function call.
189
 * The meaning of the returned string depends on the current getopt error code;
190
 * use apr_getopt_errcode() to retrieve it.
191
 */
192
APR_DECLARE(const char *) apr_getopt_errparam(apr_getopt_t *os);
193
154
/** @} */
194
/** @} */
155
195
156
#ifdef __cplusplus
196
#ifdef __cplusplus
(-)misc/unix/getopt.c (-42 / +80 lines)
Lines 68-73 Link Here
68
    return APR_SUCCESS;
68
    return APR_SUCCESS;
69
}
69
}
70
70
71
struct error_info_t {
72
    apr_getopt_error_e code;
73
    const char *param;
74
};
75
76
APR_DECLARE(apr_getopt_error_e) apr_getopt_errcode(apr_getopt_t *os)
77
{
78
    struct error_info_t *e = os->errarg;
79
    return e->code;
80
}
81
82
APR_DECLARE(const char *) apr_getopt_errparam(apr_getopt_t *os)
83
{
84
    struct error_info_t *e = os->errarg;
85
    return e->param;
86
}
87
88
/* Print out an error by calling the user-defined error callback, if any. */
89
static void perr(apr_getopt_t *os, apr_getopt_error_e err,
90
                 const char *msg, const char *par)
91
{
92
    if (os->errfn) {
93
        /* Hack: we temporarily re-purpose the errarg member for
94
           holding a reference to the error code and string parameter
95
           during the call to the error function. */
96
        void *errarg = os->errarg;
97
        struct error_info_t e;
98
        e.code = err;
99
        e.param = par;
100
        os->errarg = &e;
101
        (os->errfn)(errarg, "%s: %s: %s\n",
102
                    apr_filepath_name_get(*os->argv), msg, par);
103
        if (os->errarg == &e)
104
            os->errarg = errarg;
105
    }
106
}
107
71
APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts, 
108
APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts, 
72
                                     char *optch, const char **optarg)
109
                                     char *optch, const char **optarg)
73
{
110
{
Lines 99-107 Link Here
99
        }
136
        }
100
        if (!*os->place)
137
        if (!*os->place)
101
            ++os->ind;
138
            ++os->ind;
102
        if (os->errfn && *opts != ':') {
139
        if (*opts != ':') {
103
            (os->errfn)(os->errarg, "%s: illegal option -- %c\n",
140
            char par[2] = "x";
104
                        apr_filepath_name_get(*os->argv), os->opt);
141
            par[0] = os->opt;
142
            perr(os, APR_GETOPT_INVALID_OPTION,
143
                 "illegal option", par);
105
        }
144
        }
106
        *optch = os->opt;
145
        *optch = os->opt;
107
        return (APR_BADCH);
146
        return (APR_BADCH);
Lines 115-130 Link Here
115
        if (*os->place)                /* no white space */
154
        if (*os->place)                /* no white space */
116
            *optarg = os->place;
155
            *optarg = os->place;
117
        else if (os->argc <= ++os->ind) {        /* no arg */
156
        else if (os->argc <= ++os->ind) {        /* no arg */
157
            char par[2] = "x";
118
            os->place = EMSG;
158
            os->place = EMSG;
119
            if (*opts == ':') {
159
            if (*opts == ':') {
120
                *optch = os->opt;
160
                *optch = os->opt;
121
                return (APR_BADARG);
161
                return (APR_BADARG);
122
            }
162
            }
123
            if (os->errfn) {
163
            par[0] = os->opt;
124
                (os->errfn)(os->errarg, 
164
            perr(os, APR_GETOPT_MISSING_ARGUMENT,
125
                            "%s: option requires an argument -- %c\n",
165
                 "option requires an argument", par);
126
                            apr_filepath_name_get(*os->argv), os->opt);
127
            }
128
            *optch = os->opt;
166
            *optch = os->opt;
129
            return (APR_BADCH);
167
            return (APR_BADCH);
130
        }
168
        }
Lines 177-202 Link Here
177
    os->skip_end += len2;
215
    os->skip_end += len2;
178
}
216
}
179
217
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,
218
APR_DECLARE(apr_status_t) apr_getopt_long(apr_getopt_t *os,
201
                                          const apr_getopt_option_t *opts,
219
                                          const apr_getopt_option_t *opts,
202
                                          int *optch, const char **optarg)
220
                                          int *optch, const char **optarg)
Lines 236-243 Link Here
236
254
237
            p++;
255
            p++;
238
            for (i = 0; ; i++) {
256
            for (i = 0; ; i++) {
239
                if (opts[i].optch == 0)             /* No match */
257
                if (opts[i].optch == 0) {            /* No match */
240
                    return serr(os, "invalid option", p - 2, APR_BADCH);
258
                    perr(os, APR_GETOPT_INVALID_OPTION,
259
                         "invalid option", p - 2);
260
                    return APR_BADCH;
261
                }
241
262
242
                if (opts[i].name) {
263
                if (opts[i].name) {
243
                    len = strlen(opts[i].name);
264
                    len = strlen(opts[i].name);
Lines 252-266 Link Here
252
                if (p[len] == '=')             /* Argument inline */
273
                if (p[len] == '=')             /* Argument inline */
253
                    *optarg = p + len + 1;
274
                    *optarg = p + len + 1;
254
                else { 
275
                else { 
255
                    if (os->ind >= os->argc)   /* Argument missing */
276
                    if (os->ind >= os->argc) {  /* Argument missing */
256
                        return serr(os, "missing argument", p - 2, APR_BADARG);
277
                        perr(os, APR_GETOPT_MISSING_ARGUMENT,
257
                    else                       /* Argument in next arg */
278
                             "missing argument", p - 2);
279
                        return APR_BADARG;
280
                    } else                      /* Argument in next arg */
258
                        *optarg = os->argv[os->ind++];
281
                        *optarg = os->argv[os->ind++];
259
                }
282
                }
260
            } else {
283
            } else {
261
                *optarg = NULL;
284
                *optarg = NULL;
262
                if (p[len] == '=')
285
                if (p[len] == '=') {
263
                    return serr(os, "erroneous argument", p - 2, APR_BADARG);
286
                    perr(os, APR_GETOPT_INVALID_ARGUMENT,
287
                         "erroneous argument", p - 2);
288
                    return APR_BADARG;
289
                }
264
            }
290
            }
265
            permute(os);
291
            permute(os);
266
            return APR_SUCCESS;
292
            return APR_SUCCESS;
Lines 271-278 Link Here
271
                return APR_EOF;
297
                return APR_EOF;
272
            }
298
            }
273
            else 
299
            else 
274
                if (*p == '\0')                    /* Bare "-" is illegal */
300
                if (*p == '\0') {                   /* Bare "-" is illegal */
275
                    return serr(os, "invalid option", p, APR_BADCH);
301
                    perr(os, APR_GETOPT_INVALID_OPTION,
302
                         "invalid option", p - 1);
303
                    return APR_BADCH;
304
                }
276
        }
305
        }
277
    }
306
    }
278
307
Lines 281-288 Link Here
281
     * Look for it in the caller's table.
310
     * Look for it in the caller's table.
282
     */
311
     */
283
    for (i = 0; ; i++) {
312
    for (i = 0; ; i++) {
284
        if (opts[i].optch == 0)                     /* No match */
313
        if (opts[i].optch == 0) {                    /* No match */
285
            return cerr(os, "invalid option character", *p, APR_BADCH);
314
            char arg[2] = "x";
315
            arg[0] = *p;
316
            perr(os, APR_GETOPT_INVALID_OPTION,
317
                 "invalid option", arg);
318
            return APR_BADCH;
319
        }
286
320
287
        if (*p == opts[i].optch)
321
        if (*p == opts[i].optch)
288
            break;
322
            break;
Lines 293-301 Link Here
293
        if (*p != '\0')                         /* Argument inline */
327
        if (*p != '\0')                         /* Argument inline */
294
            *optarg = p;
328
            *optarg = p;
295
        else { 
329
        else { 
296
            if (os->ind >= os->argc)           /* Argument missing */
330
            if (os->ind >= os->argc) {          /* Argument missing */
297
                return cerr(os, "missing argument", *optch, APR_BADARG);
331
                char arg[2] = "x";
298
            else                               /* Argument in next arg */
332
                arg[0] = *optch;
333
                perr(os, APR_GETOPT_MISSING_ARGUMENT,
334
                     "missing argument", arg);
335
                return APR_BADARG;
336
            } else                              /* Argument in next arg */
299
                *optarg = os->argv[os->ind++];
337
                *optarg = os->argv[os->ind++];
300
        }
338
        }
301
        os->place = EMSG;
339
        os->place = EMSG;
(-)test/testargs.c (-10 / +66 lines)
Lines 30-42 Link Here
30
    }
30
    }
31
}
31
}
32
32
33
static void unknown_arg(void *str, const char *err, ...)
33
typedef struct {
34
    apr_getopt_t *opt;
35
    char *formatted;
36
    char *param;
37
    int errcode;       /* Actually an apr_getopt_error_e, but declared
38
                          int so that it can contain an OOB value. */
39
} error_data_t;
40
41
static void unknown_arg(void *arg, const char *err, ...)
34
{
42
{
43
    error_data_t *ed = arg;
35
    va_list va;
44
    va_list va;
36
45
37
    va_start(va, err);
46
    va_start(va, err);
38
    apr_vsnprintf(str, 8196, err, va);
47
    apr_vsnprintf(ed->formatted, 8196, err, va);
39
    va_end(va);
48
    va_end(va);
49
50
    ed->errcode = apr_getopt_errcode(ed->opt);
51
    strncpy(ed->param, apr_getopt_errparam(ed->opt), 128);
40
}
52
}
41
53
42
static void no_options_found(abts_case *tc, void *data)
54
static void no_options_found(abts_case *tc, void *data)
Lines 78-90 Link Here
78
    char ch;
90
    char ch;
79
    const char *opt_arg;
91
    const char *opt_arg;
80
    char str[8196];
92
    char str[8196];
93
    char par[128];
94
    error_data_t ed;
81
95
82
    str[0] = '\0';
96
    str[0] = '\0';
97
    par[0] = '\0';
83
    rv = apr_getopt_init(&opt, p, largc, largv);
98
    rv = apr_getopt_init(&opt, p, largc, largv);
84
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
99
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
85
100
101
    ed.opt = opt;
102
    ed.formatted = str;
103
    ed.param = par;
104
    ed.errcode = -1;
105
86
    opt->errfn = unknown_arg;
106
    opt->errfn = unknown_arg;
87
    opt->errarg = str;
107
    opt->errarg = &ed;
88
   
108
   
89
    while (apr_getopt(opt, "efgh", &ch, &opt_arg) == APR_SUCCESS) {
109
    while (apr_getopt(opt, "efgh", &ch, &opt_arg) == APR_SUCCESS) {
90
        switch (ch) {
110
        switch (ch) {
Lines 98-104 Link Here
98
                break;
118
                break;
99
        }
119
        }
100
    }
120
    }
101
    ABTS_STR_EQUAL(tc, "testprog: illegal option -- a\n", str);
121
    ABTS_STR_EQUAL(tc, "testprog: illegal option: a\n", str);
122
    ABTS_STR_EQUAL(tc, "a", par);
123
    ABTS_INT_EQUAL(tc, APR_GETOPT_INVALID_OPTION, ed.errcode);
102
}
124
}
103
125
104
static void required_option(abts_case *tc, void *data)
126
static void required_option(abts_case *tc, void *data)
Lines 110-122 Link Here
110
    char ch;
132
    char ch;
111
    const char *opt_arg;
133
    const char *opt_arg;
112
    char str[8196];
134
    char str[8196];
135
    error_data_t ed;
113
136
114
    str[0] = '\0';
137
    str[0] = '\0';
115
    rv = apr_getopt_init(&opt, p, largc, largv);
138
    rv = apr_getopt_init(&opt, p, largc, largv);
116
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
139
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
117
140
141
    ed.opt = opt;
142
    ed.formatted = str;
143
    ed.param = NULL;
144
    ed.errcode = -1;
145
118
    opt->errfn = unknown_arg;
146
    opt->errfn = unknown_arg;
119
    opt->errarg = str;
147
    opt->errarg = &ed;
120
   
148
   
121
    while (apr_getopt(opt, "a:", &ch, &opt_arg) == APR_SUCCESS) {
149
    while (apr_getopt(opt, "a:", &ch, &opt_arg) == APR_SUCCESS) {
122
        switch (ch) {
150
        switch (ch) {
Lines 128-133 Link Here
128
        }
156
        }
129
    }
157
    }
130
    ABTS_STR_EQUAL(tc, "option: a with foo\n", str);
158
    ABTS_STR_EQUAL(tc, "option: a with foo\n", str);
159
    ABTS_INT_EQUAL(tc, -1, ed.errcode);
131
}
160
}
132
161
133
static void required_option_notgiven(abts_case *tc, void *data)
162
static void required_option_notgiven(abts_case *tc, void *data)
Lines 139-151 Link Here
139
    char ch;
168
    char ch;
140
    const char *opt_arg;
169
    const char *opt_arg;
141
    char str[8196];
170
    char str[8196];
171
    char par[128];
172
    error_data_t ed;
142
173
143
    str[0] = '\0';
174
    str[0] = '\0';
175
    par[0] = '\0';
144
    rv = apr_getopt_init(&opt, p, largc, largv);
176
    rv = apr_getopt_init(&opt, p, largc, largv);
145
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
177
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
146
178
179
    ed.opt = opt;
180
    ed.formatted = str;
181
    ed.param = par;
182
    ed.errcode = -1;
183
147
    opt->errfn = unknown_arg;
184
    opt->errfn = unknown_arg;
148
    opt->errarg = str;
185
    opt->errarg = &ed;
149
   
186
   
150
    while (apr_getopt(opt, "a:", &ch, &opt_arg) == APR_SUCCESS) {
187
    while (apr_getopt(opt, "a:", &ch, &opt_arg) == APR_SUCCESS) {
151
        switch (ch) {
188
        switch (ch) {
Lines 156-162 Link Here
156
                break;
193
                break;
157
        }
194
        }
158
    }
195
    }
159
    ABTS_STR_EQUAL(tc, "testprog: option requires an argument -- a\n", str);
196
    ABTS_STR_EQUAL(tc, "testprog: option requires an argument: a\n", str);
197
    ABTS_STR_EQUAL(tc, "a", par);
198
    ABTS_INT_EQUAL(tc, APR_GETOPT_MISSING_ARGUMENT, ed.errcode);
160
}
199
}
161
200
162
static void optional_option(abts_case *tc, void *data)
201
static void optional_option(abts_case *tc, void *data)
Lines 168-180 Link Here
168
    char ch;
207
    char ch;
169
    const char *opt_arg;
208
    const char *opt_arg;
170
    char str[8196];
209
    char str[8196];
210
    error_data_t ed;
171
211
172
    str[0] = '\0';
212
    str[0] = '\0';
173
    rv = apr_getopt_init(&opt, p, largc, largv);
213
    rv = apr_getopt_init(&opt, p, largc, largv);
174
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
214
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
175
215
216
    ed.opt = opt;
217
    ed.formatted = str;
218
    ed.param = NULL;
219
    ed.errcode = -1;
220
176
    opt->errfn = unknown_arg;
221
    opt->errfn = unknown_arg;
177
    opt->errarg = str;
222
    opt->errarg = &ed;
178
   
223
   
179
    while (apr_getopt(opt, "a::", &ch, &opt_arg) == APR_SUCCESS) {
224
    while (apr_getopt(opt, "a::", &ch, &opt_arg) == APR_SUCCESS) {
180
        switch (ch) {
225
        switch (ch) {
Lines 186-191 Link Here
186
        }
231
        }
187
    }
232
    }
188
    ABTS_STR_EQUAL(tc, "option: a with foo\n", str);
233
    ABTS_STR_EQUAL(tc, "option: a with foo\n", str);
234
    ABTS_INT_EQUAL(tc, -1, ed.errcode);
189
}
235
}
190
236
191
static void optional_option_notgiven(abts_case *tc, void *data)
237
static void optional_option_notgiven(abts_case *tc, void *data)
Lines 197-209 Link Here
197
    char ch;
243
    char ch;
198
    const char *opt_arg;
244
    const char *opt_arg;
199
    char str[8196];
245
    char str[8196];
246
    char par[128];
247
    error_data_t ed;
200
248
201
    str[0] = '\0';
249
    str[0] = '\0';
250
    par[0] = '\0';
202
    rv = apr_getopt_init(&opt, p, largc, largv);
251
    rv = apr_getopt_init(&opt, p, largc, largv);
203
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
252
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
204
253
254
    ed.opt = opt;
255
    ed.formatted = str;
256
    ed.param = par;
257
    ed.errcode = -1;
258
205
    opt->errfn = unknown_arg;
259
    opt->errfn = unknown_arg;
206
    opt->errarg = str;
260
    opt->errarg = &ed;
207
   
261
   
208
    while (apr_getopt(opt, "a::", &ch, &opt_arg) == APR_SUCCESS) {
262
    while (apr_getopt(opt, "a::", &ch, &opt_arg) == APR_SUCCESS) {
209
        switch (ch) {
263
        switch (ch) {
Lines 218-224 Link Here
218
/*  Our version of getopt doesn't allow for optional arguments.  */
272
/*  Our version of getopt doesn't allow for optional arguments.  */
219
    ABTS_STR_EQUAL(tc, "option: a\n", str);
273
    ABTS_STR_EQUAL(tc, "option: a\n", str);
220
#endif
274
#endif
221
    ABTS_STR_EQUAL(tc, "testprog: option requires an argument -- a\n", str);
275
    ABTS_STR_EQUAL(tc, "testprog: option requires an argument: a\n", str);
276
    ABTS_STR_EQUAL(tc, "a", par);
277
    ABTS_INT_EQUAL(tc, APR_GETOPT_MISSING_ARGUMENT, ed.errcode);
222
}
278
}
223
279
224
abts_suite *testgetopt(abts_suite *suite)
280
abts_suite *testgetopt(abts_suite *suite)

Return to bug 56030