Subversion Repositories Kolibri OS

Rev

Rev 9837 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
9837 turbocat 1
/* Getopt for GNU.
2
   NOTE: getopt is now part of the C library, so if you don't know what
3
   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
4
   before changing it!
5
 
6
   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
7
   	Free Software Foundation, Inc.
8
 
9
   This program is free software; you can redistribute it and/or modify it
10
   under the terms of the GNU General Public License as published by the
11
   Free Software Foundation; either version 2, or (at your option) any
12
   later version.
13
 
14
   This program is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
 
19
   You should have received a copy of the GNU General Public License
20
   along with this program; if not, write to the Free Software
21
   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
22
 
23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26
 
27
#ifndef __STDC__
28
#  ifndef const
29
#    define const
30
#  endif
31
#endif
32
 
33
/* This tells Alpha OSF/1 not to define a getopt prototype in .  */
34
#ifndef _NO_PROTO
35
#define _NO_PROTO
36
#endif
37
 
38
#include 
39
#include 
40
 
41
/* Comment out all this code if we are using the GNU C Library, and are not
42
   actually compiling the library itself.  This code is part of the GNU C
43
   Library, but also included in many other GNU distributions.  Compiling
44
   and linking in this code is a waste when using the GNU C library
45
   (especially if it is a shared library).  Rather than having every GNU
46
   program understand `configure --with-gnu-libc' and omit the object files,
47
   it is simpler to just do this in the source for each such file.  */
48
 
49
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
50
 
51
 
52
/* This needs to come after some library #include
53
   to get __GNU_LIBRARY__ defined.  */
54
#ifdef	__GNU_LIBRARY__
55
/* Don't include stdlib.h for non-GNU C libraries because some of them
56
   contain conflicting prototypes for getopt.  */
57
#include 
58
#endif				/* GNU C library.  */
59
 
60
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
61
   long-named option.  Because this is not POSIX.2 compliant, it is
62
   being phased out.  */
63
/* #define GETOPT_COMPAT */
64
 
65
/* This version of `getopt' appears to the caller like standard Unix `getopt'
66
   but it behaves differently for the user, since it allows the user
67
   to intersperse the options with the other arguments.
68
 
69
   As `getopt' works, it permutes the elements of ARGV so that,
70
   when it is done, all the options precede everything else.  Thus
71
   all application programs are extended to handle flexible argument order.
72
 
73
   Setting the environment variable POSIXLY_CORRECT disables permutation.
74
   Then the behavior is completely standard.
75
 
76
   GNU application programs can use a third alternative mode in which
77
   they can distinguish the relative order of options and other arguments.  */
78
 
79
#include "getopt.h"
80
 
81
/* For communication from `getopt' to the caller.
82
   When `getopt' finds an option that takes an argument,
83
   the argument value is returned here.
84
   Also, when `ordering' is RETURN_IN_ORDER,
85
   each non-option ARGV-element is returned here.  */
86
 
87
char *optarg = 0;
88
 
89
/* Index in ARGV of the next element to be scanned.
90
   This is used for communication to and from the caller
91
   and for communication between successive calls to `getopt'.
92
 
93
   On entry to `getopt', zero means this is the first call; initialize.
94
 
95
   When `getopt' returns EOF, this is the index of the first of the
96
   non-option elements that the caller should itself scan.
97
 
98
   Otherwise, `optind' communicates from one call to the next
99
   how much of ARGV has been scanned so far.  */
100
 
101
/* XXX 1003.2 says this must be 1 before any call.  */
102
int optind = 0;
103
 
104
/* The next char to be scanned in the option-element
105
   in which the last option character we returned was found.
106
   This allows us to pick up the scan where we left off.
107
 
108
   If this is zero, or a null string, it means resume the scan
109
   by advancing to the next ARGV-element.  */
110
 
111
static char *nextchar;
112
 
113
/* Callers store zero here to inhibit the error message
114
   for unrecognized options.  */
115
 
116
int opterr = 1;
117
 
118
/* Set to an option character which was unrecognized.
119
   This must be initialized on some systems to avoid linking in the
120
   system's own getopt implementation.  */
121
 
122
#define BAD_OPTION '\0'
123
int optopt = BAD_OPTION;
124
 
125
/* Describe how to deal with options that follow non-option ARGV-elements.
126
 
127
   If the caller did not specify anything,
128
   the default is REQUIRE_ORDER if the environment variable
129
   POSIXLY_CORRECT is defined, PERMUTE otherwise.
130
 
131
   REQUIRE_ORDER means don't recognize them as options;
132
   stop option processing when the first non-option is seen.
133
   This is what Unix does.
134
   This mode of operation is selected by either setting the environment
135
   variable POSIXLY_CORRECT, or using `+' as the first character
136
   of the list of option characters.
137
 
138
   PERMUTE is the default.  We permute the contents of ARGV as we scan,
139
   so that eventually all the non-options are at the end.  This allows options
140
   to be given in any order, even with programs that were not written to
141
   expect this.
142
 
143
   RETURN_IN_ORDER is an option available to programs that were written
144
   to expect options and other ARGV-elements in any order and that care about
145
   the ordering of the two.  We describe each non-option ARGV-element
146
   as if it were the argument of an option with character code 1.
147
   Using `-' as the first character of the list of option characters
148
   selects this mode of operation.
149
 
150
   The special argument `--' forces an end of option-scanning regardless
151
   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
152
   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
153
 
154
static enum {
155
	REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
156
} ordering;
157
 
158
#ifdef	__GNU_LIBRARY__
159
/* We want to avoid inclusion of string.h with non-GNU libraries
160
   because there are many ways it can cause trouble.
161
   On some systems, it contains special magic macros that don't work
162
   in GCC.  */
163
#include 
164
#define	my_index	strchr
165
#define	my_strlen	strlen
166
#else
167
 
168
/* Avoid depending on library functions or files
169
   whose names are inconsistent.  */
170
 
171
#if __STDC__ || defined(PROTO)
172
extern char *getenv(const char *name);
173
//extern int strcmp(const char *s1, const char *s2);
174
//extern int strncmp(const char *s1, const char *s2, int n);
175
 
176
static int my_strlen(const char *s);
177
static char *my_index(const char *str, int chr);
178
#else
179
extern char *getenv();
180
#endif
181
 
182
static int my_strlen(const char *str)
183
{
184
	int n = 0;
185
	while (*str++)
186
		n++;
187
	return n;
188
}
189
 
190
static char *my_index(const char *str, int chr)
191
{
192
	while (*str) {
193
		if (*str == chr)
194
			return (char *) str;
195
		str++;
196
	}
197
	return 0;
198
}
199
 
200
#endif				/* GNU C library.  */
201
 
202
/* Handle permutation of arguments.  */
203
 
204
/* Describe the part of ARGV that contains non-options that have
205
   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
206
   `last_nonopt' is the index after the last of them.  */
207
 
208
static int first_nonopt;
209
static int last_nonopt;
210
 
211
/* Exchange two adjacent subsequences of ARGV.
212
   One subsequence is elements [first_nonopt,last_nonopt)
213
   which contains all the non-options that have been skipped so far.
214
   The other is elements [last_nonopt,optind), which contains all
215
   the options processed since those non-options were skipped.
216
 
217
   `first_nonopt' and `last_nonopt' are relocated so that they describe
218
   the new indices of the non-options in ARGV after they are moved.
219
 
220
   To perform the swap, we first reverse the order of all elements. So
221
   all options now come before all non options, but they are in the
222
   wrong order. So we put back the options and non options in original
223
   order by reversing them again. For example:
224
       original input:      a b c -x -y
225
       reverse all:         -y -x c b a
226
       reverse options:     -x -y c b a
227
       reverse non options: -x -y a b c
228
*/
229
 
230
#if __STDC__ || defined(PROTO)
231
static void exchange(char **argv);
232
#endif
233
 
234
static void exchange(char **argv)
235
{
236
	char *temp, **first, **last;
237
 
238
	/* Reverse all the elements [first_nonopt, optind) */
239
	first = &argv[first_nonopt];
240
	last = &argv[optind - 1];
241
	while (first < last) {
242
		temp = *first;
243
		*first = *last;
244
		*last = temp;
245
		first++;
246
		last--;
247
	}
248
	/* Put back the options in order */
249
	first = &argv[first_nonopt];
250
	first_nonopt += (optind - last_nonopt);
251
	last = &argv[first_nonopt - 1];
252
	while (first < last) {
253
		temp = *first;
254
		*first = *last;
255
		*last = temp;
256
		first++;
257
		last--;
258
	}
259
 
260
	/* Put back the non options in order */
261
	first = &argv[first_nonopt];
262
	last_nonopt = optind;
263
	last = &argv[last_nonopt - 1];
264
	while (first < last) {
265
		temp = *first;
266
		*first = *last;
267
		*last = temp;
268
		first++;
269
		last--;
270
	}
271
}
272
 
273
/* Scan elements of ARGV (whose length is ARGC) for option characters
274
   given in OPTSTRING.
275
 
276
   If an element of ARGV starts with '-', and is not exactly "-" or "--",
277
   then it is an option element.  The characters of this element
278
   (aside from the initial '-') are option characters.  If `getopt'
279
   is called repeatedly, it returns successively each of the option characters
280
   from each of the option elements.
281
 
282
   If `getopt' finds another option character, it returns that character,
283
   updating `optind' and `nextchar' so that the next call to `getopt' can
284
   resume the scan with the following option character or ARGV-element.
285
 
286
   If there are no more option characters, `getopt' returns `EOF'.
287
   Then `optind' is the index in ARGV of the first ARGV-element
288
   that is not an option.  (The ARGV-elements have been permuted
289
   so that those that are not options now come last.)
290
 
291
   OPTSTRING is a string containing the legitimate option characters.
292
   If an option character is seen that is not listed in OPTSTRING,
293
   return BAD_OPTION after printing an error message.  If you set `opterr' to
294
   zero, the error message is suppressed but we still return BAD_OPTION.
295
 
296
   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
297
   so the following text in the same ARGV-element, or the text of the following
298
   ARGV-element, is returned in `optarg'.  Two colons mean an option that
299
   wants an optional arg; if there is text in the current ARGV-element,
300
   it is returned in `optarg', otherwise `optarg' is set to zero.
301
 
302
   If OPTSTRING starts with `-' or `+', it requests different methods of
303
   handling the non-option ARGV-elements.
304
   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
305
 
306
   Long-named options begin with `--' instead of `-'.
307
   Their names may be abbreviated as long as the abbreviation is unique
308
   or is an exact match for some defined option.  If they have an
309
   argument, it follows the option name in the same ARGV-element, separated
310
   from the option name by a `=', or else the in next ARGV-element.
311
   When `getopt' finds a long-named option, it returns 0 if that option's
312
   `flag' field is nonzero, the value of the option's `val' field
313
   if the `flag' field is zero.
314
 
315
   The elements of ARGV aren't really const, because we permute them.
316
   But we pretend they're const in the prototype to be compatible
317
   with other systems.
318
 
319
   LONGOPTS is a vector of `struct option' terminated by an
320
   element containing a name which is zero.
321
 
322
   LONGIND returns the index in LONGOPT of the long-named option found.
323
   It is only valid when a long-named option has been found by the most
324
   recent call.
325
 
326
   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
327
   long-named options.  */
328
 
329
int _getopt_internal(int argc, char *const *argv, const char *optstring,
330
		     const struct option *longopts, int *longind, int long_only)
331
{
332
	int option_index;
333
 
334
	optarg = 0;
335
 
336
	/* Initialize the internal data when the first call is made.
337
	   Start processing options with ARGV-element 1 (since ARGV-element 0
338
	   is the program name); the sequence of previously skipped
339
	   non-option ARGV-elements is empty.  */
340
 
341
	if (optind == 0) {
342
		first_nonopt = last_nonopt = optind = 1;
343
 
344
		nextchar = NULL;
345
 
346
		/* Determine how to handle the ordering of options and nonoptions.  */
347
 
348
		if (optstring[0] == '-') {
349
			ordering = RETURN_IN_ORDER;
350
			++optstring;
351
		} else if (optstring[0] == '+') {
352
			ordering = REQUIRE_ORDER;
353
			++optstring;
354
		} else if (getenv("POSIXLY_CORRECT") != NULL)
355
			ordering = REQUIRE_ORDER;
356
		else
357
			ordering = PERMUTE;
358
	}
359
 
360
	if (nextchar == NULL || *nextchar == '\0') {
361
		if (ordering == PERMUTE) {
362
			/* If we have just processed some options following some non-options,
363
			   exchange them so that the options come first.  */
364
 
365
			if (first_nonopt != last_nonopt && last_nonopt != optind)
366
				exchange((char **) argv);
367
			else if (last_nonopt != optind)
368
				first_nonopt = optind;
369
 
370
			/* Now skip any additional non-options
371
			   and extend the range of non-options previously skipped.  */
372
 
373
			while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0')
374
#ifdef GETOPT_COMPAT
375
			       && (longopts == NULL
376
				   || argv[optind][0] != '+' || argv[optind][1] == '\0')
377
#endif				/* GETOPT_COMPAT */
378
			    )
379
				optind++;
380
			last_nonopt = optind;
381
		}
382
 
383
		/* Special ARGV-element `--' means premature end of options.
384
		   Skip it like a null option,
385
		   then exchange with previous non-options as if it were an option,
386
		   then skip everything else like a non-option.  */
387
 
388
		if (optind != argc && !strcmp(argv[optind], "--")) {
389
			optind++;
390
 
391
			if (first_nonopt != last_nonopt && last_nonopt != optind)
392
				exchange((char **) argv);
393
			else if (first_nonopt == last_nonopt)
394
				first_nonopt = optind;
395
			last_nonopt = argc;
396
 
397
			optind = argc;
398
		}
399
 
400
		/* If we have done all the ARGV-elements, stop the scan
401
		   and back over any non-options that we skipped and permuted.  */
402
 
403
		if (optind == argc) {
404
			/* Set the next-arg-index to point at the non-options
405
			   that we previously skipped, so the caller will digest them.  */
406
			if (first_nonopt != last_nonopt)
407
				optind = first_nonopt;
408
			return EOF;
409
		}
410
 
411
		/* If we have come to a non-option and did not permute it,
412
		   either stop the scan or describe it to the caller and pass it by.  */
413
 
414
		if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
415
#ifdef GETOPT_COMPAT
416
		    && (longopts == NULL || argv[optind][0] != '+' || argv[optind][1] == '\0')
417
#endif				/* GETOPT_COMPAT */
418
		    ) {
419
			if (ordering == REQUIRE_ORDER)
420
				return EOF;
421
			optarg = argv[optind++];
422
			return 1;
423
		}
424
 
425
		/* We have found another option-ARGV-element.
426
		   Start decoding its characters.  */
427
 
428
		nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-'));
429
	}
430
 
431
	if (longopts != NULL && ((argv[optind][0] == '-' && (argv[optind][1] == '-' || long_only))
432
#ifdef GETOPT_COMPAT
433
				 || argv[optind][0] == '+'
434
#endif				/* GETOPT_COMPAT */
435
	    )) {
436
		const struct option *p;
437
		char *s = nextchar;
438
		int exact = 0;
439
		int ambig = 0;
440
		const struct option *pfound = NULL;
441
		int indfound = 0;
442
 
443
		while (*s && *s != '=')
444
			s++;
445
 
446
		/* Test all options for either exact match or abbreviated matches.  */
447
		for (p = longopts, option_index = 0; p->name; p++, option_index++)
448
			if (!strncmp(p->name, nextchar, s - nextchar)) {
449
				if (s - nextchar == my_strlen(p->name)) {
450
					/* Exact match found.  */
451
					pfound = p;
452
					indfound = option_index;
453
					exact = 1;
454
					break;
455
				} else if (pfound == NULL) {
456
					/* First nonexact match found.  */
457
					pfound = p;
458
					indfound = option_index;
459
				} else
460
					/* Second nonexact match found.  */
461
					ambig = 1;
462
			}
463
 
464
		if (ambig && !exact) {
465
			if (opterr)
466
				fprintf(stderr, "%s: option `%s' is ambiguous\n",
467
					argv[0], argv[optind]);
468
			nextchar += my_strlen(nextchar);
469
			optind++;
470
			return BAD_OPTION;
471
		}
472
 
473
		if (pfound != NULL) {
474
			option_index = indfound;
475
			optind++;
476
			if (*s) {
477
				/* Don't test has_arg with >, because some C compilers don't
478
				   allow it to be used on enums.  */
479
				if (pfound->has_arg)
480
					optarg = s + 1;
481
				else {
482
					if (opterr) {
483
						if (argv[optind - 1][1] == '-')
484
							/* --option */
485
							fprintf(stderr,
486
								"%s: option `--%s' doesn't allow an argument\n",
487
								argv[0], pfound->name);
488
						else
489
							/* +option or -option */
490
							fprintf(stderr,
491
								"%s: option `%c%s' doesn't allow an argument\n",
492
								argv[0], argv[optind - 1][0],
493
								pfound->name);
494
					}
495
					nextchar += my_strlen(nextchar);
496
					return BAD_OPTION;
497
				}
498
			} else if (pfound->has_arg == 1) {
499
				if (optind < argc)
500
					optarg = argv[optind++];
501
				else {
502
					if (opterr)
503
						fprintf(stderr,
504
							"%s: option `%s' requires an argument\n",
505
							argv[0], argv[optind - 1]);
506
					nextchar += my_strlen(nextchar);
507
					return optstring[0] == ':' ? ':' : BAD_OPTION;
508
				}
509
			}
510
			nextchar += my_strlen(nextchar);
511
			if (longind != NULL)
512
				*longind = option_index;
513
			if (pfound->flag) {
514
				*(pfound->flag) = pfound->val;
515
				return 0;
516
			}
517
			return pfound->val;
518
		}
519
		/* Can't find it as a long option.  If this is not getopt_long_only,
520
		   or the option starts with '--' or is not a valid short
521
		   option, then it's an error.
522
		   Otherwise interpret it as a short option.  */
523
		if (!long_only || argv[optind][1] == '-'
524
#ifdef GETOPT_COMPAT
525
		    || argv[optind][0] == '+'
526
#endif				/* GETOPT_COMPAT */
527
		    || my_index(optstring, *nextchar) == NULL) {
528
			if (opterr) {
529
				if (argv[optind][1] == '-')
530
					/* --option */
531
					fprintf(stderr, "%s: unrecognized option `--%s'\n",
532
						argv[0], nextchar);
533
				else
534
					/* +option or -option */
535
					fprintf(stderr, "%s: unrecognized option `%c%s'\n",
536
						argv[0], argv[optind][0], nextchar);
537
			}
538
			nextchar = (char *) "";
539
			optind++;
540
			return BAD_OPTION;
541
		}
542
	}
543
 
544
	/* Look at and handle the next option-character.  */
545
 
546
	{
547
		char c = *nextchar++;
548
		char *temp = my_index(optstring, c);
549
 
550
		/* Increment `optind' when we start to process its last character.  */
551
		if (*nextchar == '\0')
552
			++optind;
553
 
554
		if (temp == NULL || c == ':') {
555
			if (opterr) {
556
#if 0
557
				if (c < 040 || c >= 0177)
558
					fprintf(stderr,
559
						"%s: unrecognized option, character code 0%o\n",
560
						argv[0], c);
561
				else
562
					fprintf(stderr, "%s: unrecognized option `-%c'\n", argv[0],
563
						c);
564
#else
565
				/* 1003.2 specifies the format of this message.  */
566
				fprintf(stderr, "%s: illegal option -- %c\n", argv[0], c);
567
#endif
568
			}
569
			optopt = c;
570
			return BAD_OPTION;
571
		}
572
		if (temp[1] == ':') {
573
			if (temp[2] == ':') {
574
				/* This is an option that accepts an argument optionally.  */
575
				if (*nextchar != '\0') {
576
					optarg = nextchar;
577
					optind++;
578
				} else
579
					optarg = 0;
580
				nextchar = NULL;
581
			} else {
582
				/* This is an option that requires an argument.  */
583
				if (*nextchar != '\0') {
584
					optarg = nextchar;
585
					/* If we end this ARGV-element by taking the rest as an arg,
586
					   we must advance to the next element now.  */
587
					optind++;
588
				} else if (optind == argc) {
589
					if (opterr) {
590
#if 0
591
						fprintf(stderr,
592
							"%s: option `-%c' requires an argument\n",
593
							argv[0], c);
594
#else
595
						/* 1003.2 specifies the format of this message.  */
596
						fprintf(stderr,
597
							"%s: option requires an argument -- %c\n",
598
							argv[0], c);
599
#endif
600
					}
601
					optopt = c;
602
					if (optstring[0] == ':')
603
						c = ':';
604
					else
605
						c = BAD_OPTION;
606
				} else
607
					/* We already incremented `optind' once;
608
					   increment it again when taking next ARGV-elt as argument.  */
609
					optarg = argv[optind++];
610
				nextchar = NULL;
611
			}
612
		}
613
		return c;
614
	}
615
}
616
 
617
int getopt(int argc, char *const *argv, const char *optstring)
618
{
619
	return _getopt_internal(argc, argv, optstring, (const struct option *) 0, (int *) 0, 0);
620
}
621
 
622
int getopt_long(int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index)
623
{
624
	return _getopt_internal(argc, argv, options, long_options, opt_index, 0);
625
}
626
 
627
#endif				/* _LIBC or not __GNU_LIBRARY__.  */
628
 
629
#ifdef TEST
630
 
631
/* Compile with -DTEST to make an executable for use in testing
632
   the above definition of `getopt'.  */
633
 
634
int main(int argc, char **argv)
635
{
636
	int c;
637
	int digit_optind = 0;
638
 
639
	while (1) {
640
		int this_option_optind = optind ? optind : 1;
641
 
642
		c = getopt(argc, argv, "abc:d:0123456789");
643
		if (c == EOF)
644
			break;
645
 
646
		switch (c) {
647
		case '0':
648
		case '1':
649
		case '2':
650
		case '3':
651
		case '4':
652
		case '5':
653
		case '6':
654
		case '7':
655
		case '8':
656
		case '9':
657
			if (digit_optind != 0 && digit_optind != this_option_optind)
658
				printf("digits occur in two different argv-elements.\n");
659
			digit_optind = this_option_optind;
660
			printf("option %c\n", c);
661
			break;
662
 
663
		case 'a':
664
			printf("option a\n");
665
			break;
666
 
667
		case 'b':
668
			printf("option b\n");
669
			break;
670
 
671
		case 'c':
672
			printf("option c with value `%s'\n", optarg);
673
			break;
674
 
675
		case BAD_OPTION:
676
			break;
677
 
678
		default:
679
			printf("?? getopt returned character code 0%o ??\n", c);
680
		}
681
	}
682
 
683
	if (optind < argc) {
684
		printf("non-option ARGV-elements: ");
685
		while (optind < argc)
686
			printf("%s ", argv[optind++]);
687
		printf("\n");
688
	}
689
 
690
	exit(0);
691
}
692
 
693
#endif				/* TEST */