getopt_long.c 2.7 KB
Newer Older
R
Rich Felker 已提交
1 2 3 4 5
#define _GNU_SOURCE
#include <stddef.h>
#include <getopt.h>
#include <stdio.h>

R
Rich Felker 已提交
6 7
extern int __optpos, __optreset;

8 9 10 11 12 13 14 15 16 17 18 19
static void permute(char *const *argv, int dest, int src)
{
	char **av = (char **)argv;
	char *tmp = av[src];
	int i;
	for (i=src; i>dest; i--)
		av[i] = av[i-1];
	av[dest] = tmp;
}

static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly);

R
Rich Felker 已提交
20 21
static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
{
22
	int ret, skipped, resumed;
R
Rich Felker 已提交
23 24 25 26 27
	if (!optind || __optreset) {
		__optreset = 0;
		__optpos = 0;
		optind = 1;
	}
28
	if (optind >= argc || !argv[optind]) return -1;
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
	skipped = optind;
	if (optstring[0] != '+' && optstring[0] != '-') {
		int i;
		for (i=optind; ; i++) {
			if (i >= argc || !argv[i]) return -1;
			if (argv[i][0] != '-') continue;
			if (!argv[i][1]) continue;
			break;
		}
		optind = i;
	}
	resumed = optind;
	ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
	if (resumed > skipped) {
		int i, cnt = optind-resumed;
		for (i=0; i<cnt; i++)
			permute(argv, skipped, optind-1);
		optind = skipped + cnt;
	}
	return ret;
}

static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
{

54
	if (longopts && argv[optind][0] == '-' &&
55 56
		((longonly && argv[optind][1]) ||
		 (argv[optind][1] == '-' && argv[optind][2])))
R
Rich Felker 已提交
57
	{
58 59 60
		int i, cnt, match;
		char *opt;
		for (cnt=i=0; longopts[i].name; i++) {
R
Rich Felker 已提交
61
			const char *name = longopts[i].name;
62
			opt = argv[optind]+1;
R
Rich Felker 已提交
63
			if (*opt == '-') opt++;
64
			for (; *name && *name == *opt; name++, opt++);
65 66 67 68 69 70 71 72 73 74 75
			if (*opt && *opt != '=') continue;
			match = i;
			if (!*name) {
				cnt = 1;
				break;
			}
			cnt++;
		}
		if (cnt==1) {
			i = match;
			optind++;
R
Rich Felker 已提交
76
			if (*opt == '=') {
77
				if (!longopts[i].has_arg) return '?';
R
Rich Felker 已提交
78 79 80
				optarg = opt+1;
			} else {
				if (longopts[i].has_arg == required_argument) {
81
					if (!(optarg = argv[optind]))
R
Rich Felker 已提交
82
						return ':';
83
					optind++;
R
Rich Felker 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
				} else optarg = NULL;
			}
			if (idx) *idx = i;
			if (longopts[i].flag) {
				*longopts[i].flag = longopts[i].val;
				return 0;
			}
			return longopts[i].val;
		}
		if (argv[optind][1] == '-') {
			optind++;
			return '?';
		}
	}
	return getopt(argc, argv, optstring);
}

int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
	return __getopt_long(argc, argv, optstring, longopts, idx, 0);
}

int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
	return __getopt_long(argc, argv, optstring, longopts, idx, 1);
}