annotate extern/libketopt/ketopt.h @ 975:5ffc8350e84b

irccdctl: add support for rule editing
author David Demelier <markand@malikania.fr>
date Tue, 09 Feb 2021 13:00:32 +0100
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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