Mercurial > hg > index.cgi
annotate lwlib/lw_cmdline.c @ 318:bcd1daabdb2e
Added tag lwtools-4.9 for changeset 21ecf29b568e
author | William Astle <lost@l-w.ca> |
---|---|
date | Fri, 10 Jan 2014 18:59:26 -0700 |
parents | 806e5fc6dd93 |
children | 8e25147c2aa8 |
rev | line source |
---|---|
4 | 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> | |
8
fdc11ef4115b
Switched lwlink to lw_cmdline from argp and also brought in lw_alloc and lw_string to replace util.c
lost@l-w.ca
parents:
6
diff
changeset
|
25 #include <ctype.h> |
4 | 26 |
27 #include "lw_alloc.h" | |
28 | |
29 #define ___lw_cmdline_c_seen___ | |
30 #include "lw_cmdline.h" | |
31 | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
32 #define DOCCOL 30 |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
33 #define LLEN 78 |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
34 |
4 | 35 static struct lw_cmdline_options builtin[3] = |
36 { | |
37 { "help", '?', 0, 0, "give this help list" }, | |
38 { "usage", 0, 0, 0, "give a short usage message" }, | |
39 { "version", 'V', 0, 0, "print program version" } | |
40 }; | |
41 | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
42 static int cmpr(const void *e1, const void *e2) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
43 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
44 struct lw_cmdline_options **o1, **o2; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
45 o1 = (struct lw_cmdline_options **)e1; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
46 o2 = (struct lw_cmdline_options **)e2; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
47 |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
48 return strcmp((*o1) -> name ? (*o1) -> name : "", (*o2) -> name ? (*o2) -> name : ""); |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
49 } |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
50 |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
51 static int cmpr2(const void *e1, const void *e2) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
52 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
53 struct lw_cmdline_options **o1, **o2; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
54 o1 = (struct lw_cmdline_options **)e1; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
55 o2 = (struct lw_cmdline_options **)e2; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
56 |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
57 if ((*o1) -> key < ((*o2) -> key)) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
58 return -1; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
59 if ((*o1) -> key > ((*o2) -> key)) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
60 return 1; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
61 return 0; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
62 } |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
63 |
4 | 64 static void lw_cmdline_usage(struct lw_cmdline_parser *parser, char *name) |
65 { | |
66 struct lw_cmdline_options **slist, **llist; | |
67 int nopt; | |
68 int i; | |
69 int t; | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
70 int col; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
71 |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
72 for (nopt = 0; parser -> options[nopt].name || parser -> options[nopt].key || parser -> options[nopt].doc; nopt++) |
4 | 73 /* do nothing */ ; |
74 | |
75 slist = lw_alloc(sizeof(struct lw_cmdline_options *) * (nopt + 3)); | |
76 llist = lw_alloc(sizeof(struct lw_cmdline_options *) * (nopt + 3)); | |
77 | |
78 for (i = 0; i < nopt; i++) | |
79 { | |
80 slist[i] = &(parser -> options[i]); | |
81 llist[i] = &(parser -> options[i]); | |
82 } | |
83 | |
84 /* now sort the two lists */ | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
85 qsort(slist, nopt, sizeof(struct lw_cmdline_options *), cmpr2); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
86 qsort(llist, nopt, sizeof(struct lw_cmdline_options *), cmpr); |
4 | 87 |
88 /* now append the automatic options */ | |
89 slist[nopt] = &(builtin[0]); | |
90 slist[nopt + 1] = &(builtin[1]); | |
91 slist[nopt + 2] = &(builtin[2]); | |
92 | |
93 llist[nopt] = &(builtin[0]); | |
94 llist[nopt + 1] = &(builtin[1]); | |
95 llist[nopt + 2] = &(builtin[2]); | |
96 | |
97 /* now show the usage message */ | |
98 printf("Usage: %s", name); | |
99 | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
100 col = 7 + strlen(name); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
101 |
4 | 102 /* print short options that take no args */ |
103 t = 0; | |
104 for (i = 0; i < nopt + 3; i++) | |
105 { | |
192 | 106 if (slist[i]->flags & lw_cmdline_opt_hidden) |
107 continue; | |
4 | 108 if (slist[i]->key > 0x20 && slist[i]->key < 0x7f) |
109 { | |
110 if (slist[i]->arg == NULL) | |
111 { | |
112 if (!t) | |
113 { | |
114 printf(" [-"); | |
115 t = 1; | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
116 col += 3; |
4 | 117 } |
118 printf("%c", slist[i]->key); | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
119 col++; |
4 | 120 } |
121 } | |
122 } | |
123 if (t) | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
124 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
125 col++; |
4 | 126 printf("]"); |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
127 } |
4 | 128 |
129 /* print short options that take args */ | |
130 for (i = 0; i < nopt + 3; i++) | |
131 { | |
192 | 132 if (slist[i]->flags & lw_cmdline_opt_hidden) |
133 continue; | |
4 | 134 if (slist[i]->key > 0x20 && slist[i]->key < 0x7f && slist[i] -> arg) |
135 { | |
136 if (slist[i]->flags & lw_cmdline_opt_optional) | |
137 { | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
138 t = 7 + strlen(slist[i] -> arg); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
139 if (col + t > LLEN) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
140 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
141 printf("\n "); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
142 col = 7; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
143 } |
4 | 144 printf(" [-%c[%s]]", slist[i]->key, slist[i]->arg); |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
145 col += t; |
4 | 146 } |
147 else | |
148 { | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
149 t = 6 + strlen(slist[i] -> arg); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
150 if (col + t > LLEN) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
151 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
152 printf("\n "); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
153 col = 7; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
154 } |
4 | 155 printf(" [-%c %s]", slist[i]->key, slist[i]->arg); |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
156 col += t; |
4 | 157 } |
158 } | |
159 } | |
160 | |
161 /* print long options */ | |
162 for (i = 0; i < nopt + 3; i++) | |
163 { | |
192 | 164 if (slist[i]->flags & lw_cmdline_opt_hidden) |
165 continue; | |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
166 if (!(llist[i]->name)) |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
167 continue; |
4 | 168 if (llist[i]->arg) |
169 { | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
170 t = strlen(llist[i] -> name) + 6 + strlen(llist[i] -> arg); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
171 if (llist[i] -> flags & lw_cmdline_opt_optional) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
172 t += 2; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
173 if (col + t > LLEN) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
174 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
175 printf("\n "); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
176 col = 7; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
177 } |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
178 if (llist[i] -> flags & lw_cmdline_opt_doc) |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
179 { |
198
d2bed389e94a
Fix --help and --usage to display = correctly for long option args
William Astle <lost@l-w.ca>
parents:
192
diff
changeset
|
180 printf(" [%s=%s]", llist[i] -> name, llist[i] -> arg); |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
181 t = strlen(llist[i] -> name) + strlen(llist[i] -> arg) + 3; |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
182 } |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
183 else |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
184 { |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
185 printf(" [--%s%s=%s%s]", |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
186 llist[i] -> name, |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
187 (llist[i] -> flags & lw_cmdline_opt_optional) ? "[" : "", |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
188 llist[i] -> arg, |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
189 (llist[i] -> flags & lw_cmdline_opt_optional) ? "]" : ""); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
190 } |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
191 col += t; |
4 | 192 } |
193 else | |
194 { | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
195 t = strlen(llist[i] -> name) + 5; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
196 if (col + t > LLEN) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
197 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
198 printf("\n "); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
199 col = 7; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
200 } |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
201 if (llist[i] -> flags & lw_cmdline_opt_doc) |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
202 { |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
203 t -= 2; |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
204 printf(" [%s]", llist[i] -> name); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
205 } |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
206 else |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
207 { |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
208 printf(" [--%s]", llist[i] -> name); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
209 } |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
210 col += t; |
4 | 211 } |
212 } | |
213 | |
214 /* print "non option" text */ | |
215 if (parser -> args_doc) | |
216 { | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
217 if (col + strlen(parser -> args_doc) + 1 > LLEN) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
218 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
219 printf("\n "); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
220 } |
4 | 221 printf(" %s", parser -> args_doc); |
222 } | |
223 printf("\n"); | |
224 | |
225 /* clean up scratch lists */ | |
226 lw_free(slist); | |
227 lw_free(llist); | |
228 } | |
229 | |
5 | 230 static void lw_cmdline_help(struct lw_cmdline_parser *parser, char *name) |
4 | 231 { |
5 | 232 struct lw_cmdline_options **llist; |
233 int nopt; | |
234 int i; | |
235 char *tstr; | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
236 int col = 0; |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
237 int noequ; |
5 | 238 |
239 tstr = parser -> doc; | |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
240 for (nopt = 0; parser -> options[nopt].name || parser -> options[nopt].key || parser -> options[nopt].doc; nopt++) |
5 | 241 /* do nothing */ ; |
242 | |
243 llist = lw_alloc(sizeof(struct lw_cmdline_options *) * (nopt + 3)); | |
244 | |
245 for (i = 0; i < nopt; i++) | |
246 { | |
247 llist[i] = &(parser -> options[i]); | |
248 } | |
249 | |
250 /* now sort the list */ | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
251 qsort(llist, nopt, sizeof(struct lw_cmdline_options *), cmpr); |
5 | 252 |
253 /* now append the automatic options */ | |
254 llist[nopt] = &(builtin[0]); | |
255 llist[nopt + 1] = &(builtin[1]); | |
256 llist[nopt + 2] = &(builtin[2]); | |
257 | |
258 /* print brief usage */ | |
259 printf("Usage: %s [OPTION...] %s\n", name, parser -> args_doc ? parser -> args_doc : ""); | |
260 if (tstr) | |
261 { | |
262 while (*tstr && *tstr != '\v') | |
263 fputc(*tstr++, stdout); | |
264 if (*tstr) | |
265 tstr++; | |
266 } | |
267 fputc('\n', stdout); | |
268 fputc('\n', stdout); | |
269 | |
270 /* display options - do it the naïve way for now */ | |
271 for (i = 0; i < (nopt + 3); i++) | |
272 { | |
192 | 273 if (llist[i]->flags & lw_cmdline_opt_hidden) |
274 continue; | |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
275 noequ = 0; |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
276 if (llist[i] -> flags & lw_cmdline_opt_doc) |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
277 { |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
278 col = strlen(llist[i] -> name) + 2; |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
279 printf(" %s", llist[i] -> name); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
280 noequ = 1; |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
281 } |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
282 else if (llist[i] -> key > 0x20 && llist[i] -> key < 0x7F) |
5 | 283 { |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
284 printf(" -%c", llist[i] -> key); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
285 col = 5; |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
286 if (llist[i] -> name) |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
287 { |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
288 col++; |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
289 fputc(',', stdout); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
290 } |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
291 fputc(' ', stdout); |
5 | 292 } |
293 else | |
294 { | |
295 printf(" "); | |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
296 col = 6; |
5 | 297 } |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
298 if (llist[i] -> name && !(llist[i] -> flags & lw_cmdline_opt_doc)) |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
299 { |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
300 col += 2 + strlen(llist[i] -> name); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
301 printf("--%s", llist[i] -> name); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
302 } |
5 | 303 if (llist[i] -> arg) |
304 { | |
305 if (llist[i] -> flags & lw_cmdline_opt_optional) | |
306 { | |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
307 col++; |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
308 fputc('[', stdout); |
5 | 309 } |
198
d2bed389e94a
Fix --help and --usage to display = correctly for long option args
William Astle <lost@l-w.ca>
parents:
192
diff
changeset
|
310 if (!noequ) |
5 | 311 { |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
312 fputc('=', stdout); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
313 col++; |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
314 } |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
315 printf("%s", llist[i] -> arg); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
316 col += strlen(llist[i] -> arg); |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
317 if (llist[i] -> flags & lw_cmdline_opt_optional) |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
318 { |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
319 col++; |
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
320 fputc(']', stdout); |
5 | 321 } |
322 } | |
323 if (llist[i] -> doc) | |
324 { | |
6
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
325 char *s = llist[i] -> doc; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
326 char *s2; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
327 |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
328 while (*s && isspace(*s)) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
329 s++; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
330 |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
331 if (col > DOCCOL) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
332 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
333 fputc('\n', stdout); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
334 col = 0; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
335 } |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
336 while (*s) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
337 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
338 while (col < (DOCCOL - 1)) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
339 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
340 fputc(' ', stdout); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
341 col++; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
342 } |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
343 for (s2 = s; *s2 && !isspace(*s2); s2++) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
344 /* do nothing */ ; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
345 if ((col + (s2 - s) + 1) > LLEN && col >= DOCCOL) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
346 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
347 /* next line */ |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
348 fputc('\n', stdout); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
349 col = 0; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
350 continue; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
351 } |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
352 col++; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
353 fputc(' ', stdout); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
354 while (s != s2) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
355 { |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
356 fputc(*s, stdout); |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
357 col++; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
358 s++; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
359 } |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
360 while (*s && isspace(*s)) |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
361 s++; |
1e5e8ec406fb
Various output cleanups for --help and --usage in lw_cmdline
lost@l-w.ca
parents:
5
diff
changeset
|
362 } |
5 | 363 } |
364 fputc('\n', stdout); | |
365 } | |
366 | |
367 printf("\nMandatory or optional arguments to long options are also mandatory or optional\nfor any corresponding short options.\n"); | |
368 | |
369 if (*tstr) | |
370 { | |
371 printf("\n%s\n", tstr); | |
372 } | |
373 | |
374 /* clean up scratch lists */ | |
375 lw_free(llist); | |
4 | 376 } |
377 | |
378 int lw_cmdline_parse(struct lw_cmdline_parser *parser, int argc, char **argv, unsigned flags, int *arg_index, void *input) | |
379 { | |
380 int i, j, r; | |
381 int firstarg; | |
382 int nextarg; | |
383 char *tstr; | |
384 int cch; | |
385 | |
386 /* first, permute the argv array so that all option arguments are at the start */ | |
387 for (i = 1, firstarg = 1; i < argc; i++) | |
388 { | |
389 if (argv[i][0] == '-' && argv[i][1]) | |
390 { | |
391 /* have an option arg */ | |
392 if (firstarg == i) | |
393 { | |
394 firstarg++; | |
395 continue; | |
396 } | |
397 tstr = argv[i]; | |
398 for (j = i; j > firstarg; j--) | |
399 { | |
400 argv[j] = argv[j - 1]; | |
401 } | |
402 argv[firstarg] = tstr; | |
403 firstarg++; | |
404 if (argv[firstarg - 1][1] == '-' && argv[firstarg - 1][2] == 0) | |
405 break; | |
406 } | |
407 } | |
408 | |
409 /* now start parsing options */ | |
410 nextarg = firstarg; | |
411 i = 1; | |
412 cch = 0; | |
413 while (i < firstarg) | |
414 { | |
415 if (cch > 0 && argv[i][cch] == 0) | |
416 { | |
417 i++; | |
418 cch = 0; | |
419 continue; | |
420 } | |
421 | |
422 if (cch > 0) | |
423 goto shortopt; | |
424 | |
425 /* skip the "--" option */ | |
426 if (argv[i][1] == '-' && argv[i][2] == 0) | |
427 break; | |
428 | |
429 if (argv[i][1] == '-') | |
430 { | |
431 goto longopt; | |
432 } | |
433 | |
434 cch = 1; | |
435 shortopt: | |
436 /* handle a short option here */ | |
437 | |
438 /* automatic options */ | |
439 if (argv[i][cch] == '?') | |
440 goto do_help; | |
441 if (argv[i][cch] == 'V') | |
442 goto do_version; | |
443 /* look up key */ | |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
444 for (j = 0; parser -> options[j].name || parser -> options[j].key || parser -> options[j].doc; j++) |
4 | 445 if (parser -> options[j].key == argv[i][cch]) |
446 break; | |
447 cch++; | |
448 tstr = argv[i] + cch; | |
105 | 449 if (*tstr == 0) |
450 tstr = NULL; | |
451 if (!tstr && (parser -> options[j].flags & lw_cmdline_opt_optional) == 0) | |
4 | 452 { |
103
8b0be0fc42cf
Fixed arg handling for short args in command line option parser - optional args for short opts should now work and options no longer need a space between option character and argument
lost@l-w.ca
parents:
54
diff
changeset
|
453 /* only consume the next arg if the argument is optional */ |
4 | 454 if (nextarg < argc) |
455 tstr = argv[nextarg]; | |
456 else | |
457 tstr = NULL; | |
458 } | |
459 goto common; | |
460 | |
461 longopt: | |
462 if (strcmp(argv[i], "--help") == 0) | |
463 goto do_help; | |
464 if (strcmp(argv[i], "--usage") == 0) | |
465 goto do_usage; | |
466 if (strcmp(argv[i], "--version") == 0) | |
467 goto do_version; | |
468 /* look up name */ | |
469 | |
470 for (j = 2; argv[i][j] && argv[i][j] != '='; j++) | |
471 /* do nothing */ ; | |
472 tstr = lw_alloc(j - 1); | |
473 strncpy(tstr, argv[i] + 2, j - 2); | |
52 | 474 tstr[j - 2] = 0; |
4 | 475 if (argv[i][j] == '=') |
476 j++; | |
477 cch = j; | |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
478 for (j = 0; parser -> options[j].name || parser -> options[j].key || parser -> options[j].doc; j++) |
4 | 479 { |
191
ddffceb3c331
Added "documentation only" options to lw_cmdline and also allowed options that do not have a long equivalent
lost@l-w.ca
parents:
105
diff
changeset
|
480 if (parser -> options[j].name && strcmp(parser -> options[j].name, tstr) == 0) |
4 | 481 break; |
482 } | |
483 lw_free(tstr); | |
484 tstr = argv[i] + cch; | |
105 | 485 if (*tstr == 0) |
486 tstr = NULL; | |
4 | 487 cch = 0; |
37 | 488 i++; |
4 | 489 |
490 common: | |
491 /* j will be the offset into the option table when we get here */ | |
492 /* cch will be zero and tstr will point to the arg if it's a long option */ | |
493 /* cch will be > 0 and tstr points to the theoretical option, either within */ | |
494 /* this string or "nextarg" */ | |
495 if (parser -> options[j].name == NULL) | |
496 { | |
103
8b0be0fc42cf
Fixed arg handling for short args in command line option parser - optional args for short opts should now work and options no longer need a space between option character and argument
lost@l-w.ca
parents:
54
diff
changeset
|
497 if (cch) |
8b0be0fc42cf
Fixed arg handling for short args in command line option parser - optional args for short opts should now work and options no longer need a space between option character and argument
lost@l-w.ca
parents:
54
diff
changeset
|
498 fprintf(stderr, "Unknown option '%c'. See %s --usage.\n", argv[i][cch - 1], argv[0]); |
8b0be0fc42cf
Fixed arg handling for short args in command line option parser - optional args for short opts should now work and options no longer need a space between option character and argument
lost@l-w.ca
parents:
54
diff
changeset
|
499 else |
8b0be0fc42cf
Fixed arg handling for short args in command line option parser - optional args for short opts should now work and options no longer need a space between option character and argument
lost@l-w.ca
parents:
54
diff
changeset
|
500 fprintf(stderr, "Unknown option '%s'. See %s --usage.\n", argv[i - 1], argv[0]); |
4 | 501 exit(1); |
502 } | |
503 if (parser -> options[j].arg) | |
504 { | |
505 if (tstr && cch && argv[i][cch] == 0) | |
506 nextarg++; | |
507 | |
105 | 508 //if (!*tstr) |
509 // tstr = NULL; | |
4 | 510 |
103
8b0be0fc42cf
Fixed arg handling for short args in command line option parser - optional args for short opts should now work and options no longer need a space between option character and argument
lost@l-w.ca
parents:
54
diff
changeset
|
511 /* move on to next argument if we have an arg specified */ |
8b0be0fc42cf
Fixed arg handling for short args in command line option parser - optional args for short opts should now work and options no longer need a space between option character and argument
lost@l-w.ca
parents:
54
diff
changeset
|
512 if (tstr && cch && argv[i][cch] != 0) |
104 | 513 { |
103
8b0be0fc42cf
Fixed arg handling for short args in command line option parser - optional args for short opts should now work and options no longer need a space between option character and argument
lost@l-w.ca
parents:
54
diff
changeset
|
514 i++; |
104 | 515 cch = 0; |
516 } | |
103
8b0be0fc42cf
Fixed arg handling for short args in command line option parser - optional args for short opts should now work and options no longer need a space between option character and argument
lost@l-w.ca
parents:
54
diff
changeset
|
517 |
4 | 518 if (!tstr && (parser -> options[j].flags & lw_cmdline_opt_optional) == 0) |
519 { | |
520 fprintf(stderr, "Option %s requires argument.\n", parser -> options[j].name); | |
205
806e5fc6dd93
Fix segfault during command parsing
William Astle <lost@l-w.ca>
parents:
198
diff
changeset
|
521 continue; |
4 | 522 } |
523 } | |
524 r = (*(parser -> parser))(parser -> options[j].key, tstr, input); | |
525 if (r != 0) | |
526 return r; | |
527 } | |
528 /* handle non-option args */ | |
529 if (arg_index) | |
530 *arg_index = nextarg; | |
531 for (i = nextarg; i < argc; i++) | |
532 { | |
533 r = (*(parser -> parser))(lw_cmdline_key_arg, argv[i], input); | |
534 if (r != 0) | |
535 return r; | |
536 } | |
537 r = (*(parser -> parser))(lw_cmdline_key_end, NULL, input); | |
538 return r; | |
539 | |
540 do_help: | |
5 | 541 lw_cmdline_help(parser, argv[0]); |
4 | 542 exit(0); |
543 | |
544 do_version: | |
545 printf("%s\n", parser -> program_version); | |
546 exit(0); | |
547 | |
548 do_usage: | |
549 lw_cmdline_usage(parser, argv[0]); | |
550 exit(0); | |
551 } |