source: libcfa/src/parseargs.cfa@ 38cc59f

ADT ast-experimental
Last change on this file since 38cc59f was 481f882, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Added some missing headers and cleaned up some of the fork+exec stuff.

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