source: libcfa/src/parseargs.cfa @ b7664a0

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since b7664a0 was b7664a0, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Removed some warnings and allowed io calls to compile without io_uring.

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