Mercurial > hg > index.cgi
comparison lwlib/lw_cmdline.c @ 4:a4812d57ed13
Started implementing command line parsing in lwlib
author | lost@l-w.ca |
---|---|
date | Fri, 21 Jan 2011 22:54:48 -0700 |
parents | |
children | 0e01d1343c02 |
comparison
equal
deleted
inserted
replaced
3:d4eb3c328a47 | 4:a4812d57ed13 |
---|---|
1 /* | |
2 lw_cmdline.c | |
3 | |
4 Copyright © 2010 William Astle | |
5 | |
6 This file is part of LWTOOLS. | |
7 | |
8 LWTOOLS is free software: you can redistribute it and/or modify it under the | |
9 terms of the GNU General Public License as published by the Free Software | |
10 Foundation, either version 3 of the License, or (at your option) any later | |
11 version. | |
12 | |
13 This program is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
16 more details. | |
17 | |
18 You should have received a copy of the GNU General Public License along with | |
19 this program. If not, see <http://www.gnu.org/licenses/>. | |
20 */ | |
21 | |
22 #include <stdio.h> | |
23 #include <stdlib.h> | |
24 #include <string.h> | |
25 | |
26 #include "lw_alloc.h" | |
27 | |
28 #define ___lw_cmdline_c_seen___ | |
29 #include "lw_cmdline.h" | |
30 | |
31 static struct lw_cmdline_options builtin[3] = | |
32 { | |
33 { "help", '?', 0, 0, "give this help list" }, | |
34 { "usage", 0, 0, 0, "give a short usage message" }, | |
35 { "version", 'V', 0, 0, "print program version" } | |
36 }; | |
37 | |
38 static void lw_cmdline_usage(struct lw_cmdline_parser *parser, char *name) | |
39 { | |
40 struct lw_cmdline_options **slist, **llist; | |
41 int nopt; | |
42 int i; | |
43 int t; | |
44 | |
45 for (nopt = 0; parser -> options[nopt].name; nopt++) | |
46 /* do nothing */ ; | |
47 | |
48 slist = lw_alloc(sizeof(struct lw_cmdline_options *) * (nopt + 3)); | |
49 llist = lw_alloc(sizeof(struct lw_cmdline_options *) * (nopt + 3)); | |
50 | |
51 for (i = 0; i < nopt; i++) | |
52 { | |
53 slist[i] = &(parser -> options[i]); | |
54 llist[i] = &(parser -> options[i]); | |
55 } | |
56 | |
57 /* now sort the two lists */ | |
58 | |
59 /* now append the automatic options */ | |
60 slist[nopt] = &(builtin[0]); | |
61 slist[nopt + 1] = &(builtin[1]); | |
62 slist[nopt + 2] = &(builtin[2]); | |
63 | |
64 llist[nopt] = &(builtin[0]); | |
65 llist[nopt + 1] = &(builtin[1]); | |
66 llist[nopt + 2] = &(builtin[2]); | |
67 | |
68 /* now show the usage message */ | |
69 printf("Usage: %s", name); | |
70 | |
71 /* print short options that take no args */ | |
72 t = 0; | |
73 for (i = 0; i < nopt + 3; i++) | |
74 { | |
75 if (slist[i]->key > 0x20 && slist[i]->key < 0x7f) | |
76 { | |
77 if (slist[i]->arg == NULL) | |
78 { | |
79 if (!t) | |
80 { | |
81 printf(" [-"); | |
82 t = 1; | |
83 } | |
84 printf("%c", slist[i]->key); | |
85 } | |
86 } | |
87 } | |
88 if (t) | |
89 printf("]"); | |
90 | |
91 /* print short options that take args */ | |
92 for (i = 0; i < nopt + 3; i++) | |
93 { | |
94 if (slist[i]->key > 0x20 && slist[i]->key < 0x7f && slist[i] -> arg) | |
95 { | |
96 if (slist[i]->flags & lw_cmdline_opt_optional) | |
97 { | |
98 printf(" [-%c[%s]]", slist[i]->key, slist[i]->arg); | |
99 } | |
100 else | |
101 { | |
102 printf(" [-%c %s]", slist[i]->key, slist[i]->arg); | |
103 } | |
104 } | |
105 } | |
106 | |
107 /* print long options */ | |
108 for (i = 0; i < nopt + 3; i++) | |
109 { | |
110 if (llist[i]->arg) | |
111 { | |
112 printf(" [--%s=%s%s%s]", | |
113 llist[i] -> name, | |
114 (llist[i] -> flags & lw_cmdline_opt_optional) ? "[" : "", | |
115 llist[i] -> arg, | |
116 (llist[i] -> flags & lw_cmdline_opt_optional) ? "]" : ""); | |
117 } | |
118 else | |
119 { | |
120 printf(" [--%s]", llist[i] -> name); | |
121 } | |
122 } | |
123 | |
124 /* print "non option" text */ | |
125 if (parser -> args_doc) | |
126 { | |
127 printf(" %s", parser -> args_doc); | |
128 } | |
129 printf("\n"); | |
130 | |
131 /* clean up scratch lists */ | |
132 lw_free(slist); | |
133 lw_free(llist); | |
134 } | |
135 | |
136 static void lw_cmdline_help(struct lw_cmdline_parser *parser) | |
137 { | |
138 printf("TODO: help\n"); | |
139 } | |
140 | |
141 int lw_cmdline_parse(struct lw_cmdline_parser *parser, int argc, char **argv, unsigned flags, int *arg_index, void *input) | |
142 { | |
143 int i, j, r; | |
144 int firstarg; | |
145 int nextarg; | |
146 char *tstr; | |
147 int cch; | |
148 | |
149 /* first, permute the argv array so that all option arguments are at the start */ | |
150 for (i = 1, firstarg = 1; i < argc; i++) | |
151 { | |
152 if (argv[i][0] == '-' && argv[i][1]) | |
153 { | |
154 /* have an option arg */ | |
155 if (firstarg == i) | |
156 { | |
157 firstarg++; | |
158 continue; | |
159 } | |
160 tstr = argv[i]; | |
161 for (j = i; j > firstarg; j--) | |
162 { | |
163 argv[j] = argv[j - 1]; | |
164 } | |
165 argv[firstarg] = tstr; | |
166 firstarg++; | |
167 if (argv[firstarg - 1][1] == '-' && argv[firstarg - 1][2] == 0) | |
168 break; | |
169 } | |
170 } | |
171 | |
172 /* now start parsing options */ | |
173 nextarg = firstarg; | |
174 i = 1; | |
175 cch = 0; | |
176 while (i < firstarg) | |
177 { | |
178 if (cch > 0 && argv[i][cch] == 0) | |
179 { | |
180 i++; | |
181 cch = 0; | |
182 continue; | |
183 } | |
184 | |
185 if (cch > 0) | |
186 goto shortopt; | |
187 | |
188 /* skip the "--" option */ | |
189 if (argv[i][1] == '-' && argv[i][2] == 0) | |
190 break; | |
191 | |
192 if (argv[i][1] == '-') | |
193 { | |
194 goto longopt; | |
195 } | |
196 | |
197 cch = 1; | |
198 shortopt: | |
199 /* handle a short option here */ | |
200 | |
201 /* automatic options */ | |
202 if (argv[i][cch] == '?') | |
203 goto do_help; | |
204 if (argv[i][cch] == 'V') | |
205 goto do_version; | |
206 /* look up key */ | |
207 for (j = 0; parser -> options[j].name; j++) | |
208 if (parser -> options[j].key == argv[i][cch]) | |
209 break; | |
210 cch++; | |
211 tstr = argv[i] + cch; | |
212 if (!*tstr) | |
213 { | |
214 if (nextarg < argc) | |
215 tstr = argv[nextarg]; | |
216 else | |
217 tstr = NULL; | |
218 } | |
219 goto common; | |
220 | |
221 longopt: | |
222 if (strcmp(argv[i], "--help") == 0) | |
223 goto do_help; | |
224 if (strcmp(argv[i], "--usage") == 0) | |
225 goto do_usage; | |
226 if (strcmp(argv[i], "--version") == 0) | |
227 goto do_version; | |
228 /* look up name */ | |
229 | |
230 for (j = 2; argv[i][j] && argv[i][j] != '='; j++) | |
231 /* do nothing */ ; | |
232 tstr = lw_alloc(j - 1); | |
233 strncpy(tstr, argv[i] + 2, j - 2); | |
234 tstr[j - 1] = 0; | |
235 if (argv[i][j] == '=') | |
236 j++; | |
237 cch = j; | |
238 | |
239 for (j = 0; parser -> options[j].name; j++) | |
240 { | |
241 if (strcmp(parser -> options[j].name, tstr) == 0) | |
242 break; | |
243 } | |
244 lw_free(tstr); | |
245 tstr = argv[i] + cch; | |
246 cch = 0; | |
247 | |
248 common: | |
249 /* j will be the offset into the option table when we get here */ | |
250 /* cch will be zero and tstr will point to the arg if it's a long option */ | |
251 /* cch will be > 0 and tstr points to the theoretical option, either within */ | |
252 /* this string or "nextarg" */ | |
253 if (parser -> options[j].name == NULL) | |
254 { | |
255 fprintf(stderr, "Unknown option. See %s --usage.\n", argv[0]); | |
256 exit(1); | |
257 } | |
258 if (parser -> options[j].arg) | |
259 { | |
260 if (tstr && cch && argv[i][cch] == 0) | |
261 nextarg++; | |
262 | |
263 if (!*tstr) | |
264 tstr = NULL; | |
265 | |
266 if (!tstr && (parser -> options[j].flags & lw_cmdline_opt_optional) == 0) | |
267 { | |
268 fprintf(stderr, "Option %s requires argument.\n", parser -> options[j].name); | |
269 } | |
270 } | |
271 r = (*(parser -> parser))(parser -> options[j].key, tstr, input); | |
272 if (r != 0) | |
273 return r; | |
274 } | |
275 /* handle non-option args */ | |
276 if (arg_index) | |
277 *arg_index = nextarg; | |
278 for (i = nextarg; i < argc; i++) | |
279 { | |
280 r = (*(parser -> parser))(lw_cmdline_key_arg, argv[i], input); | |
281 if (r != 0) | |
282 return r; | |
283 } | |
284 r = (*(parser -> parser))(lw_cmdline_key_end, NULL, input); | |
285 return r; | |
286 | |
287 do_help: | |
288 lw_cmdline_help(parser); | |
289 exit(0); | |
290 | |
291 do_version: | |
292 printf("%s\n", parser -> program_version); | |
293 exit(0); | |
294 | |
295 do_usage: | |
296 lw_cmdline_usage(parser, argv[0]); | |
297 exit(0); | |
298 } |