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