Mercurial > irccd
annotate extern/libketopt/ketopt.h @ 1004:3ea3361f0fc7
irccd: now track modes
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 16 Feb 2021 18:37:22 +0100 |
parents | 5ffc8350e84b |
children |
rev | line source |
---|---|
975
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
1 #ifndef KETOPT_H |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
2 #define KETOPT_H |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
3 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
4 #include <string.h> /* for strchr() and strncmp() */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
5 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
6 #define ko_no_argument 0 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
7 #define ko_required_argument 1 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
8 #define ko_optional_argument 2 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
9 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
10 typedef struct { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
11 int ind; /* equivalent to optind */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
12 int opt; /* equivalent to optopt */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
13 char *arg; /* equivalent to optarg */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
14 int longidx; /* index of a long option; or -1 if short */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
15 /* private variables not intended for external uses */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
16 int i, pos, n_args; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
17 } ketopt_t; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
18 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
19 typedef struct { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
20 char *name; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
21 int has_arg; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
22 int val; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
23 } ko_longopt_t; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
24 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
25 static ketopt_t KETOPT_INIT = { 0, 0, 0, -1, 0, 0, 0 }; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
26 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
27 static void ketopt_permute(char *argv[], int j, int n) /* move argv[j] over n elements to the left */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
28 { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
29 int k; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
30 char *p = argv[j]; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
31 for (k = 0; k < n; ++k) |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
32 argv[j - k] = argv[j - k - 1]; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
33 argv[j - k] = p; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
34 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
35 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
36 /** |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
37 * Parse command-line options and arguments |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
38 * |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
39 * This fuction has a similar interface to GNU's getopt_long(). Each call |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
40 * parses one option and returns the option name. s->arg points to the option |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
41 * argument if present. The function returns -1 when all command-line arguments |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
42 * are parsed. In this case, s->ind is the index of the first non-option |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
43 * argument. |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
44 * |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
45 * @param s status; shall be initialized to KETOPT_INIT on the first call |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
46 * @param argc length of argv[] |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
47 * @param argv list of command-line arguments; argv[0] is ignored |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
48 * @param permute non-zero to move options ahead of non-option arguments |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
49 * @param ostr option string |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
50 * @param longopts long options |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
51 * |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
52 * @return ASCII for a short option; ko_longopt_t::val for a long option; -1 if |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
53 * argv[] is fully processed; '?' for an unknown option or an ambiguous |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
54 * long option; ':' if an option argument is missing |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
55 */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
56 static int ketopt(ketopt_t *s, int argc, char *argv[], int permute, const char *ostr, const ko_longopt_t *longopts) |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
57 { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
58 int opt = -1, i0, j; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
59 if (permute) { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
60 while (s->i < argc && (argv[s->i][0] != '-' || argv[s->i][1] == '\0')) |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
61 ++s->i, ++s->n_args; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
62 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
63 s->arg = 0, s->longidx = -1, i0 = s->i; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
64 if (s->i >= argc || argv[s->i][0] != '-' || argv[s->i][1] == '\0') { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
65 s->ind = s->i - s->n_args; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
66 return -1; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
67 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
68 if (argv[s->i][0] == '-' && argv[s->i][1] == '-') { /* "--" or a long option */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
69 if (argv[s->i][2] == '\0') { /* a bare "--" */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
70 ketopt_permute(argv, s->i, s->n_args); |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
71 ++s->i, s->ind = s->i - s->n_args; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
72 return -1; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
73 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
74 s->opt = 0, opt = '?', s->pos = -1; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
75 if (longopts) { /* parse long options */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
76 int k, n_exact = 0, n_partial = 0; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
77 const ko_longopt_t *o = 0, *o_exact = 0, *o_partial = 0; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
78 for (j = 2; argv[s->i][j] != '\0' && argv[s->i][j] != '='; ++j) {} /* find the end of the option name */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
79 for (k = 0; longopts[k].name != 0; ++k) |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
80 if (strncmp(&argv[s->i][2], longopts[k].name, j - 2) == 0) { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
81 if (longopts[k].name[j - 2] == 0) ++n_exact, o_exact = &longopts[k]; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
82 else ++n_partial, o_partial = &longopts[k]; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
83 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
84 if (n_exact > 1 || (n_exact == 0 && n_partial > 1)) return '?'; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
85 o = n_exact == 1? o_exact : n_partial == 1? o_partial : 0; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
86 if (o) { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
87 s->opt = opt = o->val, s->longidx = o - longopts; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
88 if (argv[s->i][j] == '=') s->arg = &argv[s->i][j + 1]; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
89 if (o->has_arg == 1 && argv[s->i][j] == '\0') { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
90 if (s->i < argc - 1) s->arg = argv[++s->i]; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
91 else opt = ':'; /* missing option argument */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
92 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
93 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
94 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
95 } else { /* a short option */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
96 const char *p; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
97 if (s->pos == 0) s->pos = 1; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
98 opt = s->opt = argv[s->i][s->pos++]; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
99 p = strchr((char*)ostr, opt); |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
100 if (p == 0) { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
101 opt = '?'; /* unknown option */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
102 } else if (p[1] == ':') { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
103 if (argv[s->i][s->pos] == 0) { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
104 if (s->i < argc - 1) s->arg = argv[++s->i]; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
105 else opt = ':'; /* missing option argument */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
106 } else s->arg = &argv[s->i][s->pos]; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
107 s->pos = -1; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
108 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
109 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
110 if (s->pos < 0 || argv[s->i][s->pos] == 0) { |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
111 ++s->i, s->pos = 0; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
112 if (s->n_args > 0) /* permute */ |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
113 for (j = i0; j < s->i; ++j) |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
114 ketopt_permute(argv, j, s->n_args); |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
115 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
116 s->ind = s->i - s->n_args; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
117 return opt; |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
118 } |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
119 |
5ffc8350e84b
irccdctl: add support for rule editing
David Demelier <markand@malikania.fr>
parents:
diff
changeset
|
120 #endif |