Subversion Repositories HelenOS

Rev

Rev 3318 | Rev 3346 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3318 Rev 3336
1
/*  $NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $    */
1
/*  $NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $    */
2
 
2
 
3
/*-
3
/*-
4
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
4
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5
 * All rights reserved.
5
 * All rights reserved.
6
 *
6
 *
7
 * This code is derived from software contributed to The NetBSD Foundation
7
 * This code is derived from software contributed to The NetBSD Foundation
8
 * by Dieter Baron and Thomas Klausner.
8
 * by Dieter Baron and Thomas Klausner.
9
 *
9
 *
10
 * Redistribution and use in source and binary forms, with or without
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
11
 * modification, are permitted provided that the following conditions
12
 * are met:
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
17
 *    documentation and/or other materials provided with the distribution.
18
 *
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
 * POSSIBILITY OF SUCH DAMAGE.
29
 * POSSIBILITY OF SUCH DAMAGE.
30
 */
30
 */
31
 
31
 
32
/* Ported to HelenOS August 2008 by Tim Post <echo@echoreply.us> */
32
/* Ported to HelenOS August 2008 by Tim Post <echo@echoreply.us> */
33
 
33
 
34
#include <assert.h>
34
#include <assert.h>
35
#include <stdarg.h>
35
#include <stdarg.h>
36
#include <err.h>
36
#include <err.h>
37
#include <errno.h>
37
#include <errno.h>
38
#include <getopt.h>
38
#include <getopt.h>
39
#include <stdlib.h>
39
#include <stdlib.h>
40
#include <string.h>
40
#include <string.h>
41
 
41
 
42
/* HelenOS Port: Something similar to warnx(), however we just print
-
 
43
 * to the console */
-
 
44
 
-
 
45
void warnx(const char *fmt, ...);
-
 
46
 
-
 
47
void warnx(const char *fmt, ...)
-
 
48
{
-
 
49
    va_list vargs;
-
 
50
    va_start(vargs, fmt);
-
 
51
    vprintf(fmt, vargs);
-
 
52
    va_end(vargs);
-
 
53
    printf("\n");
-
 
54
    return;
-
 
55
}
-
 
56
 
-
 
57
/* HelenOS Port : We're incorporating only the modern getopt_long with wrappers
42
/* HelenOS Port : We're incorporating only the modern getopt_long with wrappers
58
 * to keep legacy getopt() usage from breaking. All references to REPLACE_GETOPT
43
 * to keep legacy getopt() usage from breaking. All references to REPLACE_GETOPT
59
 * are dropped, we just include the code */
44
 * are dropped, we just include the code */
60
 
45
 
61
int opterr = 1;     /* if error message should be printed */
46
int opterr = 1;     /* if error message should be printed */
62
int optind = 1;     /* index into parent argv vector */
47
int optind = 1;     /* index into parent argv vector */
63
int optopt = '?';       /* character checked for validity */
48
int optopt = '?';       /* character checked for validity */
64
int optreset;       /* reset getopt */
49
int optreset;       /* reset getopt */
65
char *optarg;       /* argument associated with option */
50
char *optarg;       /* argument associated with option */
66
 
51
 
67
 
52
 
68
#define IGNORE_FIRST    (*options == '-' || *options == '+')
53
#define IGNORE_FIRST    (*options == '-' || *options == '+')
69
#define PRINT_ERROR ((opterr) && ((*options != ':') \
54
#define PRINT_ERROR ((opterr) && ((*options != ':') \
70
                      || (IGNORE_FIRST && options[1] != ':')))
55
                      || (IGNORE_FIRST && options[1] != ':')))
71
/*HelenOS Port - POSIXLY_CORRECT is always false */
56
/*HelenOS Port - POSIXLY_CORRECT is always false */
72
#define IS_POSIXLY_CORRECT 0
57
#define IS_POSIXLY_CORRECT 0
73
#define PERMUTE         (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
58
#define PERMUTE         (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
74
/* XXX: GNU ignores PC if *options == '-' */
59
/* XXX: GNU ignores PC if *options == '-' */
75
#define IN_ORDER        (!IS_POSIXLY_CORRECT && *options == '-')
60
#define IN_ORDER        (!IS_POSIXLY_CORRECT && *options == '-')
76
 
61
 
77
/* return values */
62
/* return values */
78
#define BADCH   (int)'?'
63
#define BADCH   (int)'?'
79
#define BADARG      ((IGNORE_FIRST && options[1] == ':') \
64
#define BADARG      ((IGNORE_FIRST && options[1] == ':') \
80
             || (*options == ':') ? (int)':' : (int)'?')
65
             || (*options == ':') ? (int)':' : (int)'?')
81
#define INORDER (int)1
66
#define INORDER (int)1
82
 
67
 
83
#define EMSG    ""
68
#define EMSG    ""
84
 
69
 
85
static int getopt_internal(int, char **, const char *);
70
static int getopt_internal(int, char **, const char *);
86
static int gcd(int, int);
71
static int gcd(int, int);
87
static void permute_args(int, int, int, char **);
72
static void permute_args(int, int, int, char **);
88
 
73
 
89
static const char *place = EMSG; /* option letter processing */
74
static const char *place = EMSG; /* option letter processing */
90
 
75
 
91
/* XXX: set optreset to 1 rather than these two */
76
/* XXX: set optreset to 1 rather than these two */
92
static int nonopt_start = -1; /* first non option argument (for permute) */
77
static int nonopt_start = -1; /* first non option argument (for permute) */
93
static int nonopt_end = -1;   /* first option after non options (for permute) */
78
static int nonopt_end = -1;   /* first option after non options (for permute) */
94
 
79
 
95
/* Error messages */
80
/* Error messages */
-
 
81
 
-
 
82
/* HelenOS Port: Calls to warnx() were eliminated (as we have no stderr that
-
 
83
 * may be redirected) and replaced with printf. As such, error messages now
-
 
84
 * end in a newline */
-
 
85
 
96
static const char recargchar[] = "option requires an argument -- %c";
86
static const char recargchar[] = "option requires an argument -- %c\n";
97
static const char recargstring[] = "option requires an argument -- %s";
87
static const char recargstring[] = "option requires an argument -- %s\n";
98
static const char ambig[] = "ambiguous option -- %.*s";
88
static const char ambig[] = "ambiguous option -- %.*s\n";
99
static const char noarg[] = "option doesn't take an argument -- %.*s";
89
static const char noarg[] = "option doesn't take an argument -- %.*s\n";
100
static const char illoptchar[] = "unknown option -- %c";
90
static const char illoptchar[] = "unknown option -- %c\n";
101
static const char illoptstring[] = "unknown option -- %s";
91
static const char illoptstring[] = "unknown option -- %s\n";
102
 
92
 
103
 
93
 
104
/*
94
/*
105
 * Compute the greatest common divisor of a and b.
95
 * Compute the greatest common divisor of a and b.
106
 */
96
 */
107
static int
97
static int
108
gcd(a, b)
98
gcd(a, b)
109
    int a;
99
    int a;
110
    int b;
100
    int b;
111
{
101
{
112
    int c;
102
    int c;
113
 
103
 
114
    c = a % b;
104
    c = a % b;
115
    while (c != 0) {
105
    while (c != 0) {
116
        a = b;
106
        a = b;
117
        b = c;
107
        b = c;
118
        c = a % b;
108
        c = a % b;
119
    }
109
    }
120
       
110
       
121
    return b;
111
    return b;
122
}
112
}
123
 
113
 
124
/*
114
/*
125
 * Exchange the block from nonopt_start to nonopt_end with the block
115
 * Exchange the block from nonopt_start to nonopt_end with the block
126
 * from nonopt_end to opt_end (keeping the same order of arguments
116
 * from nonopt_end to opt_end (keeping the same order of arguments
127
 * in each block).
117
 * in each block).
128
 */
118
 */
129
static void
119
static void
130
permute_args(panonopt_start, panonopt_end, opt_end, nargv)
120
permute_args(panonopt_start, panonopt_end, opt_end, nargv)
131
    int panonopt_start;
121
    int panonopt_start;
132
    int panonopt_end;
122
    int panonopt_end;
133
    int opt_end;
123
    int opt_end;
134
    char **nargv;
124
    char **nargv;
135
{
125
{
136
    int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
126
    int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
137
    char *swap;
127
    char *swap;
138
 
128
 
139
    assert(nargv != NULL);
129
    assert(nargv != NULL);
140
 
130
 
141
    /*
131
    /*
142
     * compute lengths of blocks and number and size of cycles
132
     * compute lengths of blocks and number and size of cycles
143
     */
133
     */
144
    nnonopts = panonopt_end - panonopt_start;
134
    nnonopts = panonopt_end - panonopt_start;
145
    nopts = opt_end - panonopt_end;
135
    nopts = opt_end - panonopt_end;
146
    ncycle = gcd(nnonopts, nopts);
136
    ncycle = gcd(nnonopts, nopts);
147
    cyclelen = (opt_end - panonopt_start) / ncycle;
137
    cyclelen = (opt_end - panonopt_start) / ncycle;
148
 
138
 
149
    for (i = 0; i < ncycle; i++) {
139
    for (i = 0; i < ncycle; i++) {
150
        cstart = panonopt_end+i;
140
        cstart = panonopt_end+i;
151
        pos = cstart;
141
        pos = cstart;
152
        for (j = 0; j < cyclelen; j++) {
142
        for (j = 0; j < cyclelen; j++) {
153
            if (pos >= panonopt_end)
143
            if (pos >= panonopt_end)
154
                pos -= nnonopts;
144
                pos -= nnonopts;
155
            else
145
            else
156
                pos += nopts;
146
                pos += nopts;
157
            swap = nargv[pos];
147
            swap = nargv[pos];
158
            nargv[pos] = nargv[cstart];
148
            nargv[pos] = nargv[cstart];
159
            nargv[cstart] = swap;
149
            nargv[cstart] = swap;
160
        }
150
        }
161
    }
151
    }
162
}
152
}
163
 
153
 
164
/*
154
/*
165
 * getopt_internal --
155
 * getopt_internal --
166
 *  Parse argc/argv argument vector.  Called by user level routines.
156
 *  Parse argc/argv argument vector.  Called by user level routines.
167
 *  Returns -2 if -- is found (can be long option or end of options marker).
157
 *  Returns -2 if -- is found (can be long option or end of options marker).
168
 */
158
 */
169
static int
159
static int
170
getopt_internal(nargc, nargv, options)
160
getopt_internal(nargc, nargv, options)
171
    int nargc;
161
    int nargc;
172
    char **nargv;
162
    char **nargv;
173
    const char *options;
163
    const char *options;
174
{
164
{
175
    char *oli;              /* option letter list index */
165
    char *oli;              /* option letter list index */
176
    int optchar;
166
    int optchar;
177
 
167
 
178
    assert(nargv != NULL);
168
    assert(nargv != NULL);
179
    assert(options != NULL);
169
    assert(options != NULL);
180
 
170
 
181
    optarg = NULL;
171
    optarg = NULL;
182
 
172
 
183
    /*
173
    /*
184
     * XXX Some programs (like rsyncd) expect to be able to
174
     * XXX Some programs (like rsyncd) expect to be able to
185
     * XXX re-initialize optind to 0 and have getopt_long(3)
175
     * XXX re-initialize optind to 0 and have getopt_long(3)
186
     * XXX properly function again.  Work around this braindamage.
176
     * XXX properly function again.  Work around this braindamage.
187
     */
177
     */
188
    if (optind == 0)
178
    if (optind == 0)
189
        optind = 1;
179
        optind = 1;
190
 
180
 
191
    if (optreset)
181
    if (optreset)
192
        nonopt_start = nonopt_end = -1;
182
        nonopt_start = nonopt_end = -1;
193
start:
183
start:
194
    if (optreset || !*place) {      /* update scanning pointer */
184
    if (optreset || !*place) {      /* update scanning pointer */
195
        optreset = 0;
185
        optreset = 0;
196
        if (optind >= nargc) {          /* end of argument vector */
186
        if (optind >= nargc) {          /* end of argument vector */
197
            place = EMSG;
187
            place = EMSG;
198
            if (nonopt_end != -1) {
188
            if (nonopt_end != -1) {
199
                /* do permutation, if we have to */
189
                /* do permutation, if we have to */
200
                permute_args(nonopt_start, nonopt_end,
190
                permute_args(nonopt_start, nonopt_end,
201
                    optind, nargv);
191
                    optind, nargv);
202
                optind -= nonopt_end - nonopt_start;
192
                optind -= nonopt_end - nonopt_start;
203
            }
193
            }
204
            else if (nonopt_start != -1) {
194
            else if (nonopt_start != -1) {
205
                /*
195
                /*
206
                 * If we skipped non-options, set optind
196
                 * If we skipped non-options, set optind
207
                 * to the first of them.
197
                 * to the first of them.
208
                 */
198
                 */
209
                optind = nonopt_start;
199
                optind = nonopt_start;
210
            }
200
            }
211
            nonopt_start = nonopt_end = -1;
201
            nonopt_start = nonopt_end = -1;
212
            return -1;
202
            return -1;
213
        }
203
        }
214
        if ((*(place = nargv[optind]) != '-')
204
        if ((*(place = nargv[optind]) != '-')
215
            || (place[1] == '\0')) {    /* found non-option */
205
            || (place[1] == '\0')) {    /* found non-option */
216
            place = EMSG;
206
            place = EMSG;
217
            if (IN_ORDER) {
207
            if (IN_ORDER) {
218
                /*
208
                /*
219
                 * GNU extension:
209
                 * GNU extension:
220
                 * return non-option as argument to option 1
210
                 * return non-option as argument to option 1
221
                 */
211
                 */
222
                optarg = nargv[optind++];
212
                optarg = nargv[optind++];
223
                return INORDER;
213
                return INORDER;
224
            }
214
            }
225
            if (!PERMUTE) {
215
            if (!PERMUTE) {
226
                /*
216
                /*
227
                 * if no permutation wanted, stop parsing
217
                 * if no permutation wanted, stop parsing
228
                 * at first non-option
218
                 * at first non-option
229
                 */
219
                 */
230
                return -1;
220
                return -1;
231
            }
221
            }
232
            /* do permutation */
222
            /* do permutation */
233
            if (nonopt_start == -1)
223
            if (nonopt_start == -1)
234
                nonopt_start = optind;
224
                nonopt_start = optind;
235
            else if (nonopt_end != -1) {
225
            else if (nonopt_end != -1) {
236
                permute_args(nonopt_start, nonopt_end,
226
                permute_args(nonopt_start, nonopt_end,
237
                    optind, nargv);
227
                    optind, nargv);
238
                nonopt_start = optind -
228
                nonopt_start = optind -
239
                    (nonopt_end - nonopt_start);
229
                    (nonopt_end - nonopt_start);
240
                nonopt_end = -1;
230
                nonopt_end = -1;
241
            }
231
            }
242
            optind++;
232
            optind++;
243
            /* process next argument */
233
            /* process next argument */
244
            goto start;
234
            goto start;
245
        }
235
        }
246
        if (nonopt_start != -1 && nonopt_end == -1)
236
        if (nonopt_start != -1 && nonopt_end == -1)
247
            nonopt_end = optind;
237
            nonopt_end = optind;
248
        if (place[1] && *++place == '-') {  /* found "--" */
238
        if (place[1] && *++place == '-') {  /* found "--" */
249
            place++;
239
            place++;
250
            return -2;
240
            return -2;
251
        }
241
        }
252
    }
242
    }
253
    if ((optchar = (int)*place++) == (int)':' ||
243
    if ((optchar = (int)*place++) == (int)':' ||
254
        (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
244
        (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
255
        /* option letter unknown or ':' */
245
        /* option letter unknown or ':' */
256
        if (!*place)
246
        if (!*place)
257
            ++optind;
247
            ++optind;
258
        if (PRINT_ERROR)
248
        if (PRINT_ERROR)
259
            warnx(illoptchar, optchar);
249
            printf(illoptchar, optchar);
260
        optopt = optchar;
250
        optopt = optchar;
261
        return BADCH;
251
        return BADCH;
262
    }
252
    }
263
    if (optchar == 'W' && oli[1] == ';') {      /* -W long-option */
253
    if (optchar == 'W' && oli[1] == ';') {      /* -W long-option */
264
        /* XXX: what if no long options provided (called by getopt)? */
254
        /* XXX: what if no long options provided (called by getopt)? */
265
        if (*place)
255
        if (*place)
266
            return -2;
256
            return -2;
267
 
257
 
268
        if (++optind >= nargc) {    /* no arg */
258
        if (++optind >= nargc) {    /* no arg */
269
            place = EMSG;
259
            place = EMSG;
270
            if (PRINT_ERROR)
260
            if (PRINT_ERROR)
271
                warnx(recargchar, optchar);
261
                printf(recargchar, optchar);
272
            optopt = optchar;
262
            optopt = optchar;
273
            return BADARG;
263
            return BADARG;
274
        } else              /* white space */
264
        } else              /* white space */
275
            place = nargv[optind];
265
            place = nargv[optind];
276
        /*
266
        /*
277
         * Handle -W arg the same as --arg (which causes getopt to
267
         * Handle -W arg the same as --arg (which causes getopt to
278
         * stop parsing).
268
         * stop parsing).
279
         */
269
         */
280
        return -2;
270
        return -2;
281
    }
271
    }
282
    if (*++oli != ':') {            /* doesn't take argument */
272
    if (*++oli != ':') {            /* doesn't take argument */
283
        if (!*place)
273
        if (!*place)
284
            ++optind;
274
            ++optind;
285
    } else {                /* takes (optional) argument */
275
    } else {                /* takes (optional) argument */
286
        optarg = NULL;
276
        optarg = NULL;
287
        if (*place)         /* no white space */
277
        if (*place)         /* no white space */
288
            optarg = *place;
278
            optarg = *place;
289
        /* XXX: disable test for :: if PC? (GNU doesn't) */
279
        /* XXX: disable test for :: if PC? (GNU doesn't) */
290
        else if (oli[1] != ':') {   /* arg not optional */
280
        else if (oli[1] != ':') {   /* arg not optional */
291
            if (++optind >= nargc) {    /* no arg */
281
            if (++optind >= nargc) {    /* no arg */
292
                place = EMSG;
282
                place = EMSG;
293
                if (PRINT_ERROR)
283
                if (PRINT_ERROR)
294
                    warnx(recargchar, optchar);
284
                    printf(recargchar, optchar);
295
                optopt = optchar;
285
                optopt = optchar;
296
                return BADARG;
286
                return BADARG;
297
            } else
287
            } else
298
                optarg = nargv[optind];
288
                optarg = nargv[optind];
299
        }
289
        }
300
        place = EMSG;
290
        place = EMSG;
301
        ++optind;
291
        ++optind;
302
    }
292
    }
303
    /* dump back option letter */
293
    /* dump back option letter */
304
    return optchar;
294
    return optchar;
305
}
295
}
306
 
296
 
307
/*
297
/*
308
 * getopt --
298
 * getopt --
309
 *  Parse argc/argv argument vector.
299
 *  Parse argc/argv argument vector.
310
 */
300
 */
311
int
301
int
312
getopt(nargc, nargv, options)
302
getopt(nargc, nargv, options)
313
    int nargc;
303
    int nargc;
314
    char * const *nargv;
304
    char * const *nargv;
315
    const char *options;
305
    const char *options;
316
{
306
{
317
    int retval;
307
    int retval;
318
 
308
 
319
    assert(nargv != NULL);
309
    assert(nargv != NULL);
320
    assert(options != NULL);
310
    assert(options != NULL);
321
 
311
 
322
    retval = getopt_internal(nargc, (char **)nargv, options);
312
    retval = getopt_internal(nargc, (char **)nargv, options);
323
    if (retval == -2) {
313
    if (retval == -2) {
324
        ++optind;
314
        ++optind;
325
        /*
315
        /*
326
         * We found an option (--), so if we skipped non-options,
316
         * We found an option (--), so if we skipped non-options,
327
         * we have to permute.
317
         * we have to permute.
328
         */
318
         */
329
        if (nonopt_end != -1) {
319
        if (nonopt_end != -1) {
330
            permute_args(nonopt_start, nonopt_end, optind,
320
            permute_args(nonopt_start, nonopt_end, optind,
331
                       (char **)nargv);
321
                       (char **)nargv);
332
            optind -= nonopt_end - nonopt_start;
322
            optind -= nonopt_end - nonopt_start;
333
        }
323
        }
334
        nonopt_start = nonopt_end = -1;
324
        nonopt_start = nonopt_end = -1;
335
        retval = -1;
325
        retval = -1;
336
    }
326
    }
337
    return retval;
327
    return retval;
338
}
328
}
339
 
329
 
340
/*
330
/*
341
 * getopt_long --
331
 * getopt_long --
342
 *  Parse argc/argv argument vector.
332
 *  Parse argc/argv argument vector.
343
 */
333
 */
344
int
334
int
345
getopt_long(nargc, nargv, options, long_options, idx)
335
getopt_long(nargc, nargv, options, long_options, idx)
346
    int nargc;
336
    int nargc;
347
    char * const *nargv;
337
    char * const *nargv;
348
    const char *options;
338
    const char *options;
349
    const struct option *long_options;
339
    const struct option *long_options;
350
    int *idx;
340
    int *idx;
351
{
341
{
352
    int retval;
342
    int retval;
353
 
343
 
354
#define IDENTICAL_INTERPRETATION(_x, _y)                \
344
#define IDENTICAL_INTERPRETATION(_x, _y)                \
355
    (long_options[(_x)].has_arg == long_options[(_y)].has_arg &&    \
345
    (long_options[(_x)].has_arg == long_options[(_y)].has_arg &&    \
356
     long_options[(_x)].flag == long_options[(_y)].flag &&      \
346
     long_options[(_x)].flag == long_options[(_y)].flag &&      \
357
     long_options[(_x)].val == long_options[(_y)].val)
347
     long_options[(_x)].val == long_options[(_y)].val)
358
 
348
 
359
    assert(nargv != NULL);
349
    assert(nargv != NULL);
360
    assert(options != NULL);
350
    assert(options != NULL);
361
    assert(long_options != NULL);
351
    assert(long_options != NULL);
362
    /* idx may be NULL */
352
    /* idx may be NULL */
363
 
353
 
364
    retval = getopt_internal(nargc, (char **)nargv, options);
354
    retval = getopt_internal(nargc, (char **)nargv, options);
365
    if (retval == -2) {
355
    if (retval == -2) {
366
        char *current_argv, *has_equal;
356
        char *current_argv, *has_equal;
367
        size_t current_argv_len;
357
        size_t current_argv_len;
368
        int i, ambiguous, match;
358
        int i, ambiguous, match;
369
 
359
 
370
        current_argv = (char *)place;
360
        current_argv = (char *)place;
371
        match = -1;
361
        match = -1;
372
        ambiguous = 0;
362
        ambiguous = 0;
373
 
363
 
374
        optind++;
364
        optind++;
375
        place = EMSG;
365
        place = EMSG;
376
 
366
 
377
        if (*current_argv == '\0') {        /* found "--" */
367
        if (*current_argv == '\0') {        /* found "--" */
378
            /*
368
            /*
379
             * We found an option (--), so if we skipped
369
             * We found an option (--), so if we skipped
380
             * non-options, we have to permute.
370
             * non-options, we have to permute.
381
             */
371
             */
382
            if (nonopt_end != -1) {
372
            if (nonopt_end != -1) {
383
                permute_args(nonopt_start, nonopt_end,
373
                permute_args(nonopt_start, nonopt_end,
384
                    optind, (char **)nargv);
374
                    optind, (char **)nargv);
385
                optind -= nonopt_end - nonopt_start;
375
                optind -= nonopt_end - nonopt_start;
386
            }
376
            }
387
            nonopt_start = nonopt_end = -1;
377
            nonopt_start = nonopt_end = -1;
388
            return -1;
378
            return -1;
389
        }
379
        }
390
        if ((has_equal = strchr(current_argv, '=')) != NULL) {
380
        if ((has_equal = strchr(current_argv, '=')) != NULL) {
391
            /* argument found (--option=arg) */
381
            /* argument found (--option=arg) */
392
            current_argv_len = has_equal - current_argv;
382
            current_argv_len = has_equal - current_argv;
393
            has_equal++;
383
            has_equal++;
394
        } else
384
        } else
395
            current_argv_len = strlen(current_argv);
385
            current_argv_len = strlen(current_argv);
396
       
386
       
397
        for (i = 0; long_options[i].name; i++) {
387
        for (i = 0; long_options[i].name; i++) {
398
            /* find matching long option */
388
            /* find matching long option */
399
            if (strncmp(current_argv, long_options[i].name,
389
            if (strncmp(current_argv, long_options[i].name,
400
                current_argv_len))
390
                current_argv_len))
401
                continue;
391
                continue;
402
 
392
 
403
            if (strlen(long_options[i].name) ==
393
            if (strlen(long_options[i].name) ==
404
                (unsigned)current_argv_len) {
394
                (unsigned)current_argv_len) {
405
                /* exact match */
395
                /* exact match */
406
                match = i;
396
                match = i;
407
                ambiguous = 0;
397
                ambiguous = 0;
408
                break;
398
                break;
409
            }
399
            }
410
            if (match == -1)        /* partial match */
400
            if (match == -1)        /* partial match */
411
                match = i;
401
                match = i;
412
            else if (!IDENTICAL_INTERPRETATION(i, match))
402
            else if (!IDENTICAL_INTERPRETATION(i, match))
413
                ambiguous = 1;
403
                ambiguous = 1;
414
        }
404
        }
415
        if (ambiguous) {
405
        if (ambiguous) {
416
            /* ambiguous abbreviation */
406
            /* ambiguous abbreviation */
417
            if (PRINT_ERROR)
407
            if (PRINT_ERROR)
418
                warnx(ambig, (int)current_argv_len,
408
                printf(ambig, (int)current_argv_len,
419
                     current_argv);
409
                     current_argv);
420
            optopt = 0;
410
            optopt = 0;
421
            return BADCH;
411
            return BADCH;
422
        }
412
        }
423
        if (match != -1) {          /* option found */
413
        if (match != -1) {          /* option found */
424
                if (long_options[match].has_arg == no_argument
414
                if (long_options[match].has_arg == no_argument
425
                && has_equal) {
415
                && has_equal) {
426
                if (PRINT_ERROR)
416
                if (PRINT_ERROR)
427
                    warnx(noarg, (int)current_argv_len,
417
                    printf(noarg, (int)current_argv_len,
428
                         current_argv);
418
                         current_argv);
429
                /*
419
                /*
430
                 * XXX: GNU sets optopt to val regardless of
420
                 * XXX: GNU sets optopt to val regardless of
431
                 * flag
421
                 * flag
432
                 */
422
                 */
433
                if (long_options[match].flag == NULL)
423
                if (long_options[match].flag == NULL)
434
                    optopt = long_options[match].val;
424
                    optopt = long_options[match].val;
435
                else
425
                else
436
                    optopt = 0;
426
                    optopt = 0;
437
                return BADARG;
427
                return BADARG;
438
            }
428
            }
439
            if (long_options[match].has_arg == required_argument ||
429
            if (long_options[match].has_arg == required_argument ||
440
                long_options[match].has_arg == optional_argument) {
430
                long_options[match].has_arg == optional_argument) {
441
                if (has_equal)
431
                if (has_equal)
442
                    optarg = has_equal;
432
                    optarg = has_equal;
443
                else if (long_options[match].has_arg ==
433
                else if (long_options[match].has_arg ==
444
                    required_argument) {
434
                    required_argument) {
445
                    /*
435
                    /*
446
                     * optional argument doesn't use
436
                     * optional argument doesn't use
447
                     * next nargv
437
                     * next nargv
448
                     */
438
                     */
449
                    optarg = nargv[optind++];
439
                    optarg = nargv[optind++];
450
                }
440
                }
451
            }
441
            }
452
            if ((long_options[match].has_arg == required_argument)
442
            if ((long_options[match].has_arg == required_argument)
453
                && (optarg == NULL)) {
443
                && (optarg == NULL)) {
454
                /*
444
                /*
455
                 * Missing argument; leading ':'
445
                 * Missing argument; leading ':'
456
                 * indicates no error should be generated
446
                 * indicates no error should be generated
457
                 */
447
                 */
458
                if (PRINT_ERROR)
448
                if (PRINT_ERROR)
459
                    warnx(recargstring, current_argv);
449
                    printf(recargstring, current_argv);
460
                /*
450
                /*
461
                 * XXX: GNU sets optopt to val regardless
451
                 * XXX: GNU sets optopt to val regardless
462
                 * of flag
452
                 * of flag
463
                 */
453
                 */
464
                if (long_options[match].flag == NULL)
454
                if (long_options[match].flag == NULL)
465
                    optopt = long_options[match].val;
455
                    optopt = long_options[match].val;
466
                else
456
                else
467
                    optopt = 0;
457
                    optopt = 0;
468
                --optind;
458
                --optind;
469
                return BADARG;
459
                return BADARG;
470
            }
460
            }
471
        } else {            /* unknown option */
461
        } else {            /* unknown option */
472
            if (PRINT_ERROR)
462
            if (PRINT_ERROR)
473
                warnx(illoptstring, current_argv);
463
                printf(illoptstring, current_argv);
474
            optopt = 0;
464
            optopt = 0;
475
            return BADCH;
465
            return BADCH;
476
        }
466
        }
477
        if (long_options[match].flag) {
467
        if (long_options[match].flag) {
478
            *long_options[match].flag = long_options[match].val;
468
            *long_options[match].flag = long_options[match].val;
479
            retval = 0;
469
            retval = 0;
480
        } else
470
        } else
481
            retval = long_options[match].val;
471
            retval = long_options[match].val;
482
        if (idx)
472
        if (idx)
483
            *idx = match;
473
            *idx = match;
484
    }
474
    }
485
    return retval;
475
    return retval;
486
#undef IDENTICAL_INTERPRETATION
476
#undef IDENTICAL_INTERPRETATION
487
}
477
}
488
 
478
 
489
 
479