Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tpruvot
GitHub Repository: tpruvot/cpuminer-multi
Path: blob/linux/compat/getopt/getopt_long.c
1201 views
1
/* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
2
/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
3
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
4
5
/*
6
* Copyright (c) 2002 Todd C. Miller <[email protected]>
7
*
8
* Permission to use, copy, modify, and distribute this software for any
9
* purpose with or without fee is hereby granted, provided that the above
10
* copyright notice and this permission notice appear in all copies.
11
*
12
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
*
20
* Sponsored in part by the Defense Advanced Research Projects
21
* Agency (DARPA) and Air Force Research Laboratory, Air Force
22
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
23
*/
24
25
#ifndef lint
26
static const char rcsid[]="$Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $";
27
#endif /* lint */
28
/*-
29
* Copyright (c) 2000 The NetBSD Foundation, Inc.
30
* All rights reserved.
31
*
32
* This code is derived from software contributed to The NetBSD Foundation
33
* by Dieter Baron and Thomas Klausner.
34
*
35
* Redistribution and use in source and binary forms, with or without
36
* modification, are permitted provided that the following conditions
37
* are met:
38
* 1. Redistributions of source code must retain the above copyright
39
* notice, this list of conditions and the following disclaimer.
40
* 2. Redistributions in binary form must reproduce the above copyright
41
* notice, this list of conditions and the following disclaimer in the
42
* documentation and/or other materials provided with the distribution.
43
*
44
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
45
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
46
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
48
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
54
* POSSIBILITY OF SUCH DAMAGE.
55
*/
56
57
#if 0
58
#include <err.h>
59
#endif
60
#include <errno.h>
61
#include <getopt.h>
62
#include <stdlib.h>
63
#include <string.h>
64
65
#ifdef _WIN32
66
67
/* Windows needs warnx(). We change the definition though:
68
* 1. (another) global is defined, opterrmsg, which holds the error message
69
* 2. errors are always printed out on stderr w/o the program name
70
* Note that opterrmsg always gets set no matter what opterr is set to. The
71
* error message will not be printed if opterr is 0 as usual.
72
*/
73
74
#include <stdio.h>
75
#include <stdarg.h>
76
#include <stdarg.h>
77
78
char opterrmsg[128]; /* last error message is stored here */
79
80
static void warnx(const char *fmt, ...)
81
{
82
va_list ap;
83
va_start(ap, fmt);
84
if (fmt != NULL)
85
_vsnprintf(opterrmsg, 128, fmt, ap);
86
else
87
opterrmsg[0]='\0';
88
va_end(ap);
89
fprintf(stderr, opterrmsg);
90
fprintf(stderr, "\n");
91
}
92
93
#endif /*_WIN32*/
94
95
#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
96
97
#ifdef REPLACE_GETOPT
98
int opterr = 1; /* if error message should be printed */
99
int optind = 1; /* index into parent argv vector */
100
int optopt = '?'; /* character checked for validity */
101
int optreset; /* reset getopt */
102
char *optarg; /* argument associated with option */
103
#endif
104
105
#define PRINT_ERROR ((opterr) && (*options != ':'))
106
107
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
108
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
109
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
110
111
/* return values */
112
#define BADCH (int)'?'
113
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
114
#define INORDER (int)1
115
116
#define EMSG ""
117
118
static int getopt_internal(int, char * const *, const char *,
119
const struct option *, int *, int);
120
static int parse_long_options(char * const *, const char *,
121
const struct option *, int *, int);
122
static int gcd(int, int);
123
static void permute_args(int, int, int, char * const *);
124
125
static char *place = EMSG; /* option letter processing */
126
127
/* XXX: set optreset to 1 rather than these two */
128
static int nonopt_start = -1; /* first non option argument (for permute) */
129
static int nonopt_end = -1; /* first option after non options (for permute) */
130
131
/* Error messages */
132
static const char recargchar[] = "option requires an argument -- %c";
133
static const char recargstring[] = "option requires an argument -- %s";
134
static const char ambig[] = "ambiguous option -- %.*s";
135
static const char noarg[] = "option doesn't take an argument -- %.*s";
136
static const char illoptchar[] = "unknown option -- %c";
137
static const char illoptstring[] = "unknown option -- %s";
138
139
/*
140
* Compute the greatest common divisor of a and b.
141
*/
142
static int
143
gcd(int a, int b)
144
{
145
int c;
146
147
c = a % b;
148
while (c != 0) {
149
a = b;
150
b = c;
151
c = a % b;
152
}
153
154
return (b);
155
}
156
157
/*
158
* Exchange the block from nonopt_start to nonopt_end with the block
159
* from nonopt_end to opt_end (keeping the same order of arguments
160
* in each block).
161
*/
162
static void
163
permute_args(int panonopt_start, int panonopt_end, int opt_end,
164
char * const *nargv)
165
{
166
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
167
char *swap;
168
169
/*
170
* compute lengths of blocks and number and size of cycles
171
*/
172
nnonopts = panonopt_end - panonopt_start;
173
nopts = opt_end - panonopt_end;
174
ncycle = gcd(nnonopts, nopts);
175
cyclelen = (opt_end - panonopt_start) / ncycle;
176
177
for (i = 0; i < ncycle; i++) {
178
cstart = panonopt_end+i;
179
pos = cstart;
180
for (j = 0; j < cyclelen; j++) {
181
if (pos >= panonopt_end)
182
pos -= nnonopts;
183
else
184
pos += nopts;
185
swap = nargv[pos];
186
/* LINTED const cast */
187
((char **) nargv)[pos] = nargv[cstart];
188
/* LINTED const cast */
189
((char **)nargv)[cstart] = swap;
190
}
191
}
192
}
193
194
/*
195
* parse_long_options --
196
* Parse long options in argc/argv argument vector.
197
* Returns -1 if short_too is set and the option does not match long_options.
198
*/
199
static int
200
parse_long_options(char * const *nargv, const char *options,
201
const struct option *long_options, int *idx, int short_too)
202
{
203
char *current_argv, *has_equal;
204
size_t current_argv_len;
205
int i, match;
206
207
current_argv = place;
208
match = -1;
209
210
optind++;
211
212
if ((has_equal = strchr(current_argv, '=')) != NULL) {
213
/* argument found (--option=arg) */
214
current_argv_len = has_equal - current_argv;
215
has_equal++;
216
} else
217
current_argv_len = strlen(current_argv);
218
219
for (i = 0; long_options[i].name; i++) {
220
/* find matching long option */
221
if (strncmp(current_argv, long_options[i].name,
222
current_argv_len))
223
continue;
224
225
if (strlen(long_options[i].name) == current_argv_len) {
226
/* exact match */
227
match = i;
228
break;
229
}
230
/*
231
* If this is a known short option, don't allow
232
* a partial match of a single character.
233
*/
234
if (short_too && current_argv_len == 1)
235
continue;
236
237
if (match == -1) /* partial match */
238
match = i;
239
else {
240
/* ambiguous abbreviation */
241
if (PRINT_ERROR)
242
warnx(ambig, (int)current_argv_len,
243
current_argv);
244
optopt = 0;
245
return (BADCH);
246
}
247
}
248
if (match != -1) { /* option found */
249
if (long_options[match].has_arg == no_argument
250
&& has_equal) {
251
if (PRINT_ERROR)
252
warnx(noarg, (int)current_argv_len,
253
current_argv);
254
/*
255
* XXX: GNU sets optopt to val regardless of flag
256
*/
257
if (long_options[match].flag == NULL)
258
optopt = long_options[match].val;
259
else
260
optopt = 0;
261
return (BADARG);
262
}
263
if (long_options[match].has_arg == required_argument ||
264
long_options[match].has_arg == optional_argument) {
265
if (has_equal)
266
optarg = has_equal;
267
else if (long_options[match].has_arg ==
268
required_argument) {
269
/*
270
* optional argument doesn't use next nargv
271
*/
272
optarg = nargv[optind++];
273
}
274
}
275
if ((long_options[match].has_arg == required_argument)
276
&& (optarg == NULL)) {
277
/*
278
* Missing argument; leading ':' indicates no error
279
* should be generated.
280
*/
281
if (PRINT_ERROR)
282
warnx(recargstring,
283
current_argv);
284
/*
285
* XXX: GNU sets optopt to val regardless of flag
286
*/
287
if (long_options[match].flag == NULL)
288
optopt = long_options[match].val;
289
else
290
optopt = 0;
291
--optind;
292
return (BADARG);
293
}
294
} else { /* unknown option */
295
if (short_too) {
296
--optind;
297
return (-1);
298
}
299
if (PRINT_ERROR)
300
warnx(illoptstring, current_argv);
301
optopt = 0;
302
return (BADCH);
303
}
304
if (idx)
305
*idx = match;
306
if (long_options[match].flag) {
307
*long_options[match].flag = long_options[match].val;
308
return (0);
309
} else
310
return (long_options[match].val);
311
}
312
313
/*
314
* getopt_internal --
315
* Parse argc/argv argument vector. Called by user level routines.
316
*/
317
static int
318
getopt_internal(int nargc, char * const *nargv, const char *options,
319
const struct option *long_options, int *idx, int flags)
320
{
321
char *oli; /* option letter list index */
322
int optchar, short_too;
323
static int posixly_correct = -1;
324
325
if (options == NULL)
326
return (-1);
327
328
/*
329
* Disable GNU extensions if POSIXLY_CORRECT is set or options
330
* string begins with a '+'.
331
*/
332
if (posixly_correct == -1)
333
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
334
if (posixly_correct || *options == '+')
335
flags &= ~FLAG_PERMUTE;
336
else if (*options == '-')
337
flags |= FLAG_ALLARGS;
338
if (*options == '+' || *options == '-')
339
options++;
340
341
/*
342
* XXX Some GNU programs (like cvs) set optind to 0 instead of
343
* XXX using optreset. Work around this braindamage.
344
*/
345
if (optind == 0)
346
optind = optreset = 1;
347
348
optarg = NULL;
349
if (optreset)
350
nonopt_start = nonopt_end = -1;
351
start:
352
if (optreset || !*place) { /* update scanning pointer */
353
optreset = 0;
354
if (optind >= nargc) { /* end of argument vector */
355
place = EMSG;
356
if (nonopt_end != -1) {
357
/* do permutation, if we have to */
358
permute_args(nonopt_start, nonopt_end,
359
optind, nargv);
360
optind -= nonopt_end - nonopt_start;
361
}
362
else if (nonopt_start != -1) {
363
/*
364
* If we skipped non-options, set optind
365
* to the first of them.
366
*/
367
optind = nonopt_start;
368
}
369
nonopt_start = nonopt_end = -1;
370
return (-1);
371
}
372
if (*(place = nargv[optind]) != '-' ||
373
(place[1] == '\0' && strchr(options, '-') == NULL)) {
374
place = EMSG; /* found non-option */
375
if (flags & FLAG_ALLARGS) {
376
/*
377
* GNU extension:
378
* return non-option as argument to option 1
379
*/
380
optarg = nargv[optind++];
381
return (INORDER);
382
}
383
if (!(flags & FLAG_PERMUTE)) {
384
/*
385
* If no permutation wanted, stop parsing
386
* at first non-option.
387
*/
388
return (-1);
389
}
390
/* do permutation */
391
if (nonopt_start == -1)
392
nonopt_start = optind;
393
else if (nonopt_end != -1) {
394
permute_args(nonopt_start, nonopt_end,
395
optind, nargv);
396
nonopt_start = optind -
397
(nonopt_end - nonopt_start);
398
nonopt_end = -1;
399
}
400
optind++;
401
/* process next argument */
402
goto start;
403
}
404
if (nonopt_start != -1 && nonopt_end == -1)
405
nonopt_end = optind;
406
407
/*
408
* If we have "-" do nothing, if "--" we are done.
409
*/
410
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
411
optind++;
412
place = EMSG;
413
/*
414
* We found an option (--), so if we skipped
415
* non-options, we have to permute.
416
*/
417
if (nonopt_end != -1) {
418
permute_args(nonopt_start, nonopt_end,
419
optind, nargv);
420
optind -= nonopt_end - nonopt_start;
421
}
422
nonopt_start = nonopt_end = -1;
423
return (-1);
424
}
425
}
426
427
/*
428
* Check long options if:
429
* 1) we were passed some
430
* 2) the arg is not just "-"
431
* 3) either the arg starts with -- we are getopt_long_only()
432
*/
433
if (long_options != NULL && place != nargv[optind] &&
434
(*place == '-' || (flags & FLAG_LONGONLY))) {
435
short_too = 0;
436
if (*place == '-')
437
place++; /* --foo long option */
438
else if (*place != ':' && strchr(options, *place) != NULL)
439
short_too = 1; /* could be short option too */
440
441
optchar = parse_long_options(nargv, options, long_options,
442
idx, short_too);
443
if (optchar != -1) {
444
place = EMSG;
445
return (optchar);
446
}
447
}
448
449
if ((optchar = (int)*place++) == (int)':' ||
450
(optchar == (int)'-' && *place != '\0') ||
451
(oli = strchr(options, optchar)) == NULL) {
452
/*
453
* If the user specified "-" and '-' isn't listed in
454
* options, return -1 (non-option) as per POSIX.
455
* Otherwise, it is an unknown option character (or ':').
456
*/
457
if (optchar == (int)'-' && *place == '\0')
458
return (-1);
459
if (!*place)
460
++optind;
461
if (PRINT_ERROR)
462
warnx(illoptchar, optchar);
463
optopt = optchar;
464
return (BADCH);
465
}
466
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
467
/* -W long-option */
468
if (*place) /* no space */
469
/* NOTHING */;
470
else if (++optind >= nargc) { /* no arg */
471
place = EMSG;
472
if (PRINT_ERROR)
473
warnx(recargchar, optchar);
474
optopt = optchar;
475
return (BADARG);
476
} else /* white space */
477
place = nargv[optind];
478
optchar = parse_long_options(nargv, options, long_options,
479
idx, 0);
480
place = EMSG;
481
return (optchar);
482
}
483
if (*++oli != ':') { /* doesn't take argument */
484
if (!*place)
485
++optind;
486
} else { /* takes (optional) argument */
487
optarg = NULL;
488
if (*place) /* no white space */
489
optarg = place;
490
else if (oli[1] != ':') { /* arg not optional */
491
if (++optind >= nargc) { /* no arg */
492
place = EMSG;
493
if (PRINT_ERROR)
494
warnx(recargchar, optchar);
495
optopt = optchar;
496
return (BADARG);
497
} else
498
optarg = nargv[optind];
499
}
500
place = EMSG;
501
++optind;
502
}
503
/* dump back option letter */
504
return (optchar);
505
}
506
507
#ifdef REPLACE_GETOPT
508
/*
509
* getopt --
510
* Parse argc/argv argument vector.
511
*
512
* [eventually this will replace the BSD getopt]
513
*/
514
int
515
getopt(int nargc, char * const *nargv, const char *options)
516
{
517
518
/*
519
* We don't pass FLAG_PERMUTE to getopt_internal() since
520
* the BSD getopt(3) (unlike GNU) has never done this.
521
*
522
* Furthermore, since many privileged programs call getopt()
523
* before dropping privileges it makes sense to keep things
524
* as simple (and bug-free) as possible.
525
*/
526
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
527
}
528
#endif /* REPLACE_GETOPT */
529
530
/*
531
* getopt_long --
532
* Parse argc/argv argument vector.
533
*/
534
int
535
getopt_long(int nargc, char * const *nargv, const char *options,
536
const struct option *long_options, int *idx)
537
{
538
539
return (getopt_internal(nargc, nargv, options, long_options, idx,
540
FLAG_PERMUTE));
541
}
542
543
/*
544
* getopt_long_only --
545
* Parse argc/argv argument vector.
546
*/
547
int
548
getopt_long_only(int nargc, char * const *nargv, const char *options,
549
const struct option *long_options, int *idx)
550
{
551
552
return (getopt_internal(nargc, nargv, options, long_options, idx,
553
FLAG_PERMUTE|FLAG_LONGONLY));
554
}
555
556