Changeset df6cc9d for libcfa/src/parseargs.cfa
- Timestamp:
- Oct 19, 2022, 4:43:26 PM (3 years ago)
- Branches:
- ADT, ast-experimental, master
- Children:
- 1a45263
- Parents:
- 9cd5bd2 (diff), 135143ba (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/parseargs.cfa
r9cd5bd2 rdf6cc9d 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 1 17 #include "parseargs.hfa" 2 18 19 #include <assert.h> 20 #include <ctype.h> 3 21 #include <stdint.h> 4 22 #include <string.h> 5 23 #include <errno.h> 6 24 #include <unistd.h> 7 #include <assert.h>8 25 9 26 extern "C" { … … 33 50 extern char ** cfa_args_envp __attribute__((weak)); 34 51 35 static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * usage, FILE * out) __attribute__ ((noreturn)); 52 forall([N]) 53 static void usage(char * cmd, const array( cfa_option, N ) & options, const char * usage, FILE * out) __attribute__ ((noreturn)); 36 54 //----------------------------------------------------------------------------- 37 55 // checking 38 static void check_args(cfa_option options[], size_t opt_count) { 39 for(i; opt_count) { 40 for(j; opt_count) { 56 forall([N]) 57 static void check_args( const array( cfa_option, N ) & options ) { 58 for(i; N) { 59 for(j; N) { 41 60 if(i == j) continue; 42 61 … … 53 72 //----------------------------------------------------------------------------- 54 73 // Parsing args 55 void 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 65 void 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 assert( opt_count > 0 ); 77 char optstring[opt_count * 3] = { '\0' }; 78 { 79 int idx = 0; 80 for(i; opt_count) { 81 if (options[i].short_name) { 82 maxv = max(options[i].short_name, maxv); 83 optstring[idx] = options[i].short_name; 84 idx++; 85 if( ((intptr_t)options[i].parse) != ((intptr_t)parse_settrue) 86 && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) { 87 optstring[idx] = ':'; 74 forall([opt_count]) { 75 void parse_args( const array( cfa_option, opt_count ) & options, const char * usage, char ** & left ) { 76 if( 0p != &cfa_args_argc ) { 77 parse_args(cfa_args_argc, cfa_args_argv, options, usage, left ); 78 } 79 else { 80 char * temp = ""; 81 parse_args(0, &temp, options, usage, left ); 82 } 83 } 84 85 void parse_args( 86 int argc, 87 char * argv[], 88 const array( cfa_option, opt_count ) & options, 89 const char * usage, 90 char ** & left 91 ) { 92 check_args(options); 93 94 int maxv = 'h'; 95 char optstring[(opt_count * 3) + 2] = { '\0' }; 96 { 97 int idx = 0; 98 for(i; opt_count) { 99 if (options[i].short_name) { 100 maxv = max(options[i].short_name, maxv); 101 optstring[idx] = options[i].short_name; 102 idx++; 103 if( ((intptr_t)options[i].parse) != ((intptr_t)parse_settrue) 104 && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) { 105 optstring[idx] = ':'; 106 idx++; 107 } 108 } 109 } 110 optstring[idx+0] = 'h'; 111 optstring[idx+1] = '\0'; 112 } 113 114 struct option optarr[opt_count + 2]; 115 { 116 int idx = 0; 117 for(i; opt_count) { 118 if(options[i].long_name) { 119 // we don't have the mutable keyword here, which is really what we would want 120 int & val_ref = (int &)(const int &)options[i].val; 121 val_ref = (options[i].short_name != '\0') ? ((int)options[i].short_name) : ++maxv; 122 123 optarr[idx].name = options[i].long_name; 124 optarr[idx].flag = 0p; 125 optarr[idx].val = options[i].val; 126 if( ((intptr_t)options[i].parse) == ((intptr_t)parse_settrue) 127 || ((intptr_t)options[i].parse) == ((intptr_t)parse_setfalse) ) { 128 optarr[idx].has_arg = no_argument; 129 } else { 130 optarr[idx].has_arg = required_argument; 131 } 88 132 idx++; 89 133 } 90 134 } 91 } 92 optstring[idx+0] = 'h'; 93 optstring[idx+1] = '\0'; 94 } 95 96 struct option optarr[opt_count + 2]; 97 { 98 int idx = 0; 99 for(i; opt_count) { 100 if(options[i].long_name) { 101 options[i].val = (options[i].short_name != '\0') ? ((int)options[i].short_name) : ++maxv; 102 optarr[idx].name = options[i].long_name; 103 optarr[idx].flag = 0p; 104 optarr[idx].val = options[i].val; 105 if( ((intptr_t)options[i].parse) == ((intptr_t)parse_settrue) 106 || ((intptr_t)options[i].parse) == ((intptr_t)parse_setfalse) ) { 107 optarr[idx].has_arg = no_argument; 108 } else { 109 optarr[idx].has_arg = required_argument; 110 } 111 idx++; 135 optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0, 'h']; 136 optarr[idx+1].[name, has_arg, flag, val] = [0, no_argument, 0, 0]; 137 } 138 139 FILE * out = stderr; 140 NEXT_ARG: 141 for() { 142 int idx = 0; 143 int opt = getopt_long(argc, argv, optstring, optarr, &idx); 144 switch(opt) { 145 case -1: 146 if(&left != 0p) left = argv + optind; 147 return; 148 case 'h': 149 out = stdout; 150 case '?': 151 usage(argv[0], options, usage, out); 152 default: 153 for(i; opt_count) { 154 if(opt == options[i].val) { 155 const char * arg = optarg ? optarg : ""; 156 if( arg[0] == '=' ) { arg++; } 157 // work around for some weird bug 158 void * variable = options[i].variable; 159 bool (*parse_func)(const char *, void * ) = options[i].parse; 160 bool success = parse_func( arg, variable ); 161 if(success) continue NEXT_ARG; 162 163 fprintf(out, "Argument '%s' for option %c could not be parsed\n\n", arg, (char)opt); 164 usage(argv[0], options, usage, out); 165 } 166 } 167 abort("Internal parse arg error\n"); 112 168 } 113 } 114 optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0, 'h']; 115 optarr[idx+1].[name, has_arg, flag, val] = [0, no_argument, 0, 0]; 116 } 117 118 FILE * out = stderr; 119 NEXT_ARG: 120 for() { 121 int idx = 0; 122 int opt = getopt_long(argc, argv, optstring, optarr, &idx); 123 switch(opt) { 124 case -1: 125 if(&left != 0p) left = argv + optind; 126 return; 127 case 'h': 128 out = stdout; 129 case '?': 130 usage(argv[0], options, opt_count, usage, out); 131 default: 132 for(i; opt_count) { 133 if(opt == options[i].val) { 134 const char * arg = optarg ? optarg : ""; 135 if( arg[0] == '=' ) { arg++; } 136 bool success = options[i].parse( arg, options[i].variable ); 137 if(success) continue NEXT_ARG; 138 139 fprintf(out, "Argument '%s' for option %c could not be parsed\n\n", arg, (char)opt); 140 usage(argv[0], options, opt_count, usage, out); 141 } 142 } 143 abort("Internal parse arg error\n"); 144 } 145 146 } 169 170 } 171 } 172 } 173 174 static inline int next_newline(const char * str) { 175 int ret; 176 const char * ptr = strstr(str, "\n"); 177 if(!ptr) return MAX; 178 179 /* paranoid */ verify( str <= ptr); 180 intptr_t low = (intptr_t)str; 181 intptr_t hi = (intptr_t)ptr; 182 ret = hi - low; 183 184 return ret; 147 185 } 148 186 … … 150 188 // Print usage 151 189 static void printopt(FILE * out, int width, int max, char sn, const char * ln, const char * help) { 190 // check how wide we should be printing 191 // this includes all options and the help message 152 192 int hwidth = max - (11 + width); 153 193 if(hwidth <= 0) hwidth = max; 154 194 155 char sname[4] = { ' ', ' ', ' ', '\0' }; 156 if(sn != '\0') { 157 sname[0] = '-'; 158 sname[1] = sn; 159 sname[2] = ','; 160 } 161 162 fprintf(out, " %s --%-*s %.*s\n", sname, width, ln, hwidth, help); 163 for() { 164 help += min(strlen(help), hwidth); 165 if('\0' == *help) break; 166 fprintf(out, "%*s%.*s\n", width + 11, "", hwidth, help); 167 } 195 // check which pieces we have 196 bool has_ln = ln && strcmp("", ln); 197 bool has_help = help && strcmp("", help); 198 199 // print the small name if present 200 if(sn != '\0') fprintf(out, " -%c", sn); 201 else fprintf(out, " "); 202 203 // print a comma if we have both short and long names 204 if(sn != '\0' && has_ln) fprintf(out, ", "); 205 else fprintf(out, " "); 206 207 // print the long name if present 208 if(has_ln) fprintf(out, "--%-*s", width, ln); 209 else if(has_help) fprintf(out, " %-*s", width, ""); 210 211 if(has_help) { 212 // print the help 213 // We need to wrap at the max width, and also indent newlines so everything is nice and pretty 214 215 // for each line to print 216 for() { 217 //find out if there is a newline 218 int nextnl = next_newline(help); 219 int real = min(min(strlen(help), hwidth), nextnl); 220 221 fprintf(out, " %.*s", real, help); 222 // printf("%d %d\n", real, nextnl); 223 help += real; 224 if( nextnl == real ) help++; 225 if('\0' == *help) break; 226 fprintf(out, "\n%*s", width + 8, ""); 227 } 228 } 229 fprintf(out, "\n"); 168 230 } 169 231 170 232 void print_args_usage(cfa_option options[], size_t opt_count, const char * usage, bool error) __attribute__ ((noreturn)) { 171 usage(cfa_args_argv[0], options, opt_count, usage, error ? stderr : stdout); 233 const array( cfa_option, opt_count ) & arr = (const array( cfa_option, opt_count ) &) *options; 234 usage(cfa_args_argv[0], arr, usage, error ? stderr : stdout); 172 235 } 173 236 174 237 void print_args_usage(int , char * argv[], cfa_option options[], size_t opt_count, const char * usage, bool error) __attribute__ ((noreturn)) { 175 usage(argv[0], options, opt_count, usage, error ? stderr : stdout); 176 } 177 178 static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * help, FILE * out) __attribute__((noreturn)) { 238 const array( cfa_option, opt_count ) & arr = (const array( cfa_option, opt_count ) &) *options; 239 usage(argv[0], arr, usage, error ? stderr : stdout); 240 } 241 242 forall( [N] ) { 243 void print_args_usage( const array(cfa_option, N ) & options, const char * usage, bool error) { 244 usage(cfa_args_argv[0], options, usage, error ? stderr : stdout); 245 } 246 247 void print_args_usage(int argc, char * argv[], const array( cfa_option, N ) & options, const char * usage, bool error) { 248 usage(argv[0], options, usage, error ? stderr : stdout); 249 } 250 } 251 252 forall([N]) 253 static void usage(char * cmd, const array( cfa_option, N ) & options, const char * help, FILE * out) __attribute__((noreturn)) { 179 254 int width = 0; 180 255 { 181 for(i; opt_count) {256 for(i; N) { 182 257 if(options[i].long_name) { 183 258 int w = strlen(options[i].long_name); … … 198 273 fprintf(out, "Usage:\n %s %s\n", cmd, help); 199 274 200 for(i; opt_count) {275 for(i; N) { 201 276 printopt(out, width, max_width, options[i].short_name, options[i].long_name, options[i].help); 202 277 } … … 272 347 bool parse(const char * arg, int & value) { 273 348 char * end; 274 int r = strtoll(arg, &end, 10); 349 350 errno = 0; 351 long long int r = strtoll(arg, &end, 0); 352 if(errno) return false; 275 353 if(*end != '\0') return false; 354 if(r > (int)MAX) return false; 355 if(r < (int)MIN) return false; 276 356 277 357 value = r; … … 279 359 } 280 360 361 static unsigned long long int strict_strtoull( const char * arg, int base) { 362 errno = 0; 363 { 364 const char * in = arg; 365 for() { 366 if('\0' == *in) { 367 errno = EINVAL; 368 return 0; 369 } 370 if(!isspace(*in)) break; 371 in++; 372 } 373 if(!isdigit(*in)) { 374 errno = EINVAL; 375 return 0; 376 } 377 } 378 379 *char end; 380 unsigned long long int r = strtoull(arg, &end, base); 381 if(*end != '\0') errno = EINVAL; 382 if(errno) return 0; 383 return r; 384 } 385 281 386 bool parse(const char * arg, unsigned & value) { 282 char * end; 283 unsigned long long int r = strtoull(arg, &end, 10); 284 if(*end != '\0') return false; 387 unsigned long long int r = strict_strtoull(arg, 0); 388 if(errno) return false; 285 389 if(r > (unsigned)MAX) return false; 286 390 … … 290 394 291 395 bool parse(const char * arg, unsigned long & value) { 292 char * end; 293 unsigned long long int r = strtoull(arg, &end, 10); 294 if(*end != '\0') return false; 396 unsigned long long int r = strict_strtoull(arg, 0); 397 if(errno) return false; 295 398 if(r > (unsigned long)MAX) return false; 296 399 … … 300 403 301 404 bool parse(const char * arg, unsigned long long & value) { 302 char * end; 303 unsigned long long int r = strtoull(arg, &end, 10); 304 if(*end != '\0') return false; 305 if(r > (unsigned long long)MAX) return false; 306 307 value = r; 308 return true; 405 unsigned long long int r = strict_strtoull(arg, 0); 406 if(errno) return false; 407 if(r > (unsigned long long)MAX) return false; 408 409 value = r; 410 return true; 309 411 } 310 412
Note:
See TracChangeset
for help on using the changeset viewer.