source: libcfa/src/parseargs.cfa@ a51b8f6

ADT ast-experimental
Last change on this file since a51b8f6 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
RevLine 
[7f389a5c]1#include "parseargs.hfa"
2
[affb51b]3#include <ctype.h>
[e699eb6]4#include <stdint.h>
[7f389a5c]5#include <string.h>
[e699eb6]6#include <errno.h>
[3f1d9b5]7#include <unistd.h>
[1c893ae]8
[7f389a5c]9extern "C" {
10 #include <getopt.h>
[3f1d9b5]11 #include <sys/ioctl.h>
[7f389a5c]12
13 struct FILE;
14 extern FILE * stderr;
15 extern FILE * stdout;
16
[3f1d9b5]17 extern int fileno(FILE *stream);
18
[7f389a5c]19 extern int fprintf ( FILE * stream, const char * format, ... );
[53e4562]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);
[7f6e9eb]23 extern double strtod (const char* str, char** endptr);
[7f389a5c]24}
25
[e699eb6]26#include "common.hfa"
27#include "limits.hfa"
[3f1d9b5]28
[789f279]29#pragma GCC visibility push(default)
30
[433d352]31extern int cfa_args_argc __attribute__((weak));
32extern char ** cfa_args_argv __attribute__((weak));
33extern char ** cfa_args_envp __attribute__((weak));
[7874d77]34
[419c434]35static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * usage, FILE * out) __attribute__ ((noreturn));
[80d3b1b]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)
[b7664a03]45 abort("Parse Args error: two options have short name '%c' (%zu & %zu)", options[i].short_name, i, j);
[3f1d9b5]46
[b7664a03]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);
[80d3b1b]48 }
49 }
50}
51
52
53//-----------------------------------------------------------------------------
54// Parsing args
[7874d77]55void parse_args( cfa_option options[], size_t opt_count, const char * usage, char ** & left ) {
[433d352]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 }
[7874d77]63}
64
[7f389a5c]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) {
[80d3b1b]73 check_args(options, opt_count);
74
75 int maxv = 'h';
[affb51b]76 char optstring[(opt_count * 3) + 2] = { '\0' };
[80d3b1b]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
[7f389a5c]95 struct option optarr[opt_count + 2];
96 {
97 int idx = 0;
98 for(i; opt_count) {
99 if(options[i].long_name) {
[80d3b1b]100 options[i].val = (options[i].short_name != '\0') ? ((int)options[i].short_name) : ++maxv;
[7f389a5c]101 optarr[idx].name = options[i].long_name;
102 optarr[idx].flag = 0p;
[80d3b1b]103 optarr[idx].val = options[i].val;
[7f389a5c]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 }
[e699eb6]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];
[7f389a5c]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 '?':
[419c434]129 usage(argv[0], options, opt_count, usage, out);
[7f389a5c]130 default:
131 for(i; opt_count) {
[80d3b1b]132 if(opt == options[i].val) {
[7f389a5c]133 const char * arg = optarg ? optarg : "";
[772b300]134 if( arg[0] == '=' ) { arg++; }
[7f389a5c]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);
[419c434]139 usage(argv[0], options, opt_count, usage, out);
[7f389a5c]140 }
141 }
142 abort("Internal parse arg error\n");
143 }
144
145 }
[419c434]146}
[7f389a5c]147
[419c434]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
[6f94958]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);
[419c434]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;
[3f1d9b5]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
[419c434]197 fprintf(out, "Usage:\n %s %s\n", cmd, help);
[7f389a5c]198
199 for(i; opt_count) {
[3f1d9b5]200 printopt(out, width, max_width, options[i].short_name, options[i].long_name, options[i].help);
[7f389a5c]201 }
202 fprintf(out, " -%c, --%-*s %s\n", 'h', width, "help", "print this help message");
203 exit(out == stdout ? 0 : 1);
204}
205
[419c434]206//-----------------------------------------------------------------------------
207// Typed argument parsing
[7f389a5c]208bool parse_yesno(const char * arg, bool & value ) {
209 if(strcmp(arg, "yes") == 0) {
210 value = true;
211 return true;
212 }
213
[e07187d]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
[7f389a5c]224 if(strcmp(arg, "no") == 0) {
225 value = false;
226 return true;
227 }
228
[e07187d]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
[7f389a5c]239 return false;
240}
241
[7efb322]242bool parse_truefalse(const char * arg, bool & value) {
[d411769c]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
[7f389a5c]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
[7f6e9eb]271bool parse(const char * arg, int & value) {
272 char * end;
[affb51b]273
274 errno = 0;
275 long long int r = strtoll(arg, &end, 0);
276 if(errno) return false;
[7f6e9eb]277 if(*end != '\0') return false;
[affb51b]278 if(r > (int)MAX) return false;
279 if(r < (int)MIN) return false;
[7f6e9eb]280
281 value = r;
282 return true;
283}
284
[affb51b]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
[53e4562]310bool parse(const char * arg, unsigned & value) {
[affb51b]311 unsigned long long int r = strict_strtoull(arg, 0);
312 if(errno) return false;
[3f1d9b5]313 if(r > (unsigned)MAX) return false;
[53e4562]314
315 value = r;
316 return true;
317}
318
[56e8cb3]319bool parse(const char * arg, unsigned long & value) {
[affb51b]320 unsigned long long int r = strict_strtoull(arg, 0);
321 if(errno) return false;
[56e8cb3]322 if(r > (unsigned long)MAX) return false;
[53e4562]323
324 value = r;
325 return true;
326}
327
[56e8cb3]328bool parse(const char * arg, unsigned long long & value) {
[affb51b]329 unsigned long long int r = strict_strtoull(arg, 0);
330 if(errno) return false;
331 if(r > (unsigned long long)MAX) return false;
[56e8cb3]332
[affb51b]333 value = r;
334 return true;
[56e8cb3]335}
336
[7f6e9eb]337bool parse(const char * arg, double & value) {
[7f389a5c]338 char * end;
[7f6e9eb]339 double r = strtod(arg, &end);
[7f389a5c]340 if(*end != '\0') return false;
341
342 value = r;
343 return true;
[56e8cb3]344}
Note: See TracBrowser for help on using the repository browser.