source: libcfa/src/parseargs.cfa@ 4f102fa

ADT ast-experimental
Last change on this file since 4f102fa was affb51b, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

A few small fix to parseargs

  • Property mode set to 100644
File size: 8.2 KB
Line 
1#include "parseargs.hfa"
2
3#include <ctype.h>
4#include <stdint.h>
5#include <string.h>
6#include <errno.h>
7#include <unistd.h>
8
9extern "C" {
10 #include <getopt.h>
11 #include <sys/ioctl.h>
12
13 struct FILE;
14 extern FILE * stderr;
15 extern FILE * stdout;
16
17 extern int fileno(FILE *stream);
18
19 extern int fprintf ( FILE * stream, const char * format, ... );
20
21 extern long long int strtoll (const char* str, char** endptr, int base);
22 extern unsigned long long int strtoull(const char* str, char** endptr, int base);
23 extern double strtod (const char* str, char** endptr);
24}
25
26#include "common.hfa"
27#include "limits.hfa"
28
29#pragma GCC visibility push(default)
30
31extern int cfa_args_argc __attribute__((weak));
32extern char ** cfa_args_argv __attribute__((weak));
33extern char ** cfa_args_envp __attribute__((weak));
34
35static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * usage, FILE * out) __attribute__ ((noreturn));
36//-----------------------------------------------------------------------------
37// checking
38static void check_args(cfa_option options[], size_t opt_count) {
39 for(i; opt_count) {
40 for(j; opt_count) {
41 if(i == j) continue;
42
43 if( options[i].short_name != '\0'
44 && options[i].short_name == options[j].short_name)
45 abort("Parse Args error: two options have short name '%c' (%zu & %zu)", options[i].short_name, i, j);
46
47 if(0 == strcmp(options[i].long_name, options[j].long_name)) abort("Parse Args error: two options have long name '%s' (%zu & %zu)", options[i].long_name, i, j);
48 }
49 }
50}
51
52
53//-----------------------------------------------------------------------------
54// Parsing args
55void parse_args( cfa_option options[], size_t opt_count, const char * usage, char ** & left ) {
56 if( 0p != &cfa_args_argc ) {
57 parse_args(cfa_args_argc, cfa_args_argv, options, opt_count, usage, left );
58 }
59 else {
60 char * temp = "";
61 parse_args(0, &temp, options, opt_count, usage, left );
62 }
63}
64
65void parse_args(
66 int argc,
67 char * argv[],
68 cfa_option options[],
69 size_t opt_count,
70 const char * usage,
71 char ** & left
72) {
73 check_args(options, opt_count);
74
75 int maxv = 'h';
76 char optstring[(opt_count * 3) + 2] = { '\0' };
77 {
78 int idx = 0;
79 for(i; opt_count) {
80 if (options[i].short_name) {
81 maxv = max(options[i].short_name, maxv);
82 optstring[idx] = options[i].short_name;
83 idx++;
84 if( ((intptr_t)options[i].parse) != ((intptr_t)parse_settrue)
85 && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) {
86 optstring[idx] = ':';
87 idx++;
88 }
89 }
90 }
91 optstring[idx+0] = 'h';
92 optstring[idx+1] = '\0';
93 }
94
95 struct option optarr[opt_count + 2];
96 {
97 int idx = 0;
98 for(i; opt_count) {
99 if(options[i].long_name) {
100 options[i].val = (options[i].short_name != '\0') ? ((int)options[i].short_name) : ++maxv;
101 optarr[idx].name = options[i].long_name;
102 optarr[idx].flag = 0p;
103 optarr[idx].val = options[i].val;
104 if( ((intptr_t)options[i].parse) == ((intptr_t)parse_settrue)
105 || ((intptr_t)options[i].parse) == ((intptr_t)parse_setfalse) ) {
106 optarr[idx].has_arg = no_argument;
107 } else {
108 optarr[idx].has_arg = required_argument;
109 }
110 idx++;
111 }
112 }
113 optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0, 'h'];
114 optarr[idx+1].[name, has_arg, flag, val] = [0, no_argument, 0, 0];
115 }
116
117 FILE * out = stderr;
118 NEXT_ARG:
119 for() {
120 int idx = 0;
121 int opt = getopt_long(argc, argv, optstring, optarr, &idx);
122 switch(opt) {
123 case -1:
124 if(&left != 0p) left = argv + optind;
125 return;
126 case 'h':
127 out = stdout;
128 case '?':
129 usage(argv[0], options, opt_count, usage, out);
130 default:
131 for(i; opt_count) {
132 if(opt == options[i].val) {
133 const char * arg = optarg ? optarg : "";
134 if( arg[0] == '=' ) { arg++; }
135 bool success = options[i].parse( arg, options[i].variable );
136 if(success) continue NEXT_ARG;
137
138 fprintf(out, "Argument '%s' for option %c could not be parsed\n\n", arg, (char)opt);
139 usage(argv[0], options, opt_count, usage, out);
140 }
141 }
142 abort("Internal parse arg error\n");
143 }
144
145 }
146}
147
148//-----------------------------------------------------------------------------
149// Print usage
150static void printopt(FILE * out, int width, int max, char sn, const char * ln, const char * help) {
151 int hwidth = max - (11 + width);
152 if(hwidth <= 0) hwidth = max;
153
154 char sname[4] = { ' ', ' ', ' ', '\0' };
155 if(sn != '\0') {
156 sname[0] = '-';
157 sname[1] = sn;
158 sname[2] = ',';
159 }
160
161 fprintf(out, " %s --%-*s %.*s\n", sname, width, ln, hwidth, help);
162 for() {
163 help += min(strlen(help), hwidth);
164 if('\0' == *help) break;
165 fprintf(out, "%*s%.*s\n", width + 11, "", hwidth, help);
166 }
167}
168
169void print_args_usage(cfa_option options[], size_t opt_count, const char * usage, bool error) __attribute__ ((noreturn)) {
170 usage(cfa_args_argv[0], options, opt_count, usage, error ? stderr : stdout);
171}
172
173void print_args_usage(int , char * argv[], cfa_option options[], size_t opt_count, const char * usage, bool error) __attribute__ ((noreturn)) {
174 usage(argv[0], options, opt_count, usage, error ? stderr : stdout);
175}
176
177static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * help, FILE * out) __attribute__((noreturn)) {
178 int width = 0;
179 {
180 for(i; opt_count) {
181 if(options[i].long_name) {
182 int w = strlen(options[i].long_name);
183 if(w > width) width = w;
184 }
185 }
186 }
187
188 int max_width = 1_000_000;
189 int outfd = fileno(out);
190 if(isatty(outfd)) {
191 struct winsize size;
192 int ret = ioctl(outfd, TIOCGWINSZ, &size);
193 if(ret < 0) abort( "ioctl error: (%d) %s\n", (int)errno, strerror(errno) );
194 max_width = size.ws_col;
195 }
196
197 fprintf(out, "Usage:\n %s %s\n", cmd, help);
198
199 for(i; opt_count) {
200 printopt(out, width, max_width, options[i].short_name, options[i].long_name, options[i].help);
201 }
202 fprintf(out, " -%c, --%-*s %s\n", 'h', width, "help", "print this help message");
203 exit(out == stdout ? 0 : 1);
204}
205
206//-----------------------------------------------------------------------------
207// Typed argument parsing
208bool parse_yesno(const char * arg, bool & value ) {
209 if(strcmp(arg, "yes") == 0) {
210 value = true;
211 return true;
212 }
213
214 if(strcmp(arg, "Y") == 0) {
215 value = true;
216 return true;
217 }
218
219 if(strcmp(arg, "y") == 0) {
220 value = true;
221 return true;
222 }
223
224 if(strcmp(arg, "no") == 0) {
225 value = false;
226 return true;
227 }
228
229 if(strcmp(arg, "N") == 0) {
230 value = false;
231 return true;
232 }
233
234 if(strcmp(arg, "n") == 0) {
235 value = false;
236 return true;
237 }
238
239 return false;
240}
241
242bool parse_truefalse(const char * arg, bool & value) {
243 if(strcmp(arg, "true") == 0) {
244 value = true;
245 return true;
246 }
247
248 if(strcmp(arg, "false") == 0) {
249 value = false;
250 return true;
251 }
252
253 return false;
254}
255
256bool parse_settrue (const char *, bool & value ) {
257 value = true;
258 return true;
259}
260
261bool parse_setfalse(const char *, bool & value ) {
262 value = false;
263 return true;
264}
265
266bool parse(const char * arg, const char * & value ) {
267 value = arg;
268 return true;
269}
270
271bool parse(const char * arg, int & value) {
272 char * end;
273
274 errno = 0;
275 long long int r = strtoll(arg, &end, 0);
276 if(errno) return false;
277 if(*end != '\0') return false;
278 if(r > (int)MAX) return false;
279 if(r < (int)MIN) return false;
280
281 value = r;
282 return true;
283}
284
285static unsigned long long int strict_strtoull( const char * arg, int base) {
286 errno = 0;
287 {
288 const char * in = arg;
289 for() {
290 if('\0' == *in) {
291 errno = EINVAL;
292 return 0;
293 }
294 if(!isspace(*in)) break;
295 in++;
296 }
297 if(!isdigit(*in)) {
298 errno = EINVAL;
299 return 0;
300 }
301 }
302
303 *char end;
304 unsigned long long int r = strtoull(arg, &end, base);
305 if(*end != '\0') errno = EINVAL;
306 if(errno) return 0;
307 return r;
308}
309
310bool parse(const char * arg, unsigned & value) {
311 unsigned long long int r = strict_strtoull(arg, 0);
312 if(errno) return false;
313 if(r > (unsigned)MAX) return false;
314
315 value = r;
316 return true;
317}
318
319bool parse(const char * arg, unsigned long & value) {
320 unsigned long long int r = strict_strtoull(arg, 0);
321 if(errno) return false;
322 if(r > (unsigned long)MAX) return false;
323
324 value = r;
325 return true;
326}
327
328bool parse(const char * arg, unsigned long long & value) {
329 unsigned long long int r = strict_strtoull(arg, 0);
330 if(errno) return false;
331 if(r > (unsigned long long)MAX) return false;
332
333 value = r;
334 return true;
335}
336
337bool parse(const char * arg, double & value) {
338 char * end;
339 double r = strtod(arg, &end);
340 if(*end != '\0') return false;
341
342 value = r;
343 return true;
344}
Note: See TracBrowser for help on using the repository browser.