- Timestamp:
- Jul 8, 2024, 8:35:08 PM (5 months ago)
- Branches:
- master
- Children:
- c015e2d
- Parents:
- 061b001
- Location:
- libcfa/src
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/parseargs.cfa
r061b001 ra4e1b09 10 10 // Author : Thierry Delisle 11 11 // Created On : Wed Oct 12 15:28:01 2022 12 // Last Modified By : 13 // Last Modified On : 14 // Update Count : 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Mon Jul 8 18:18:23 2024 14 // Update Count : 7 15 15 // 16 16 … … 32 32 extern FILE * stdout; 33 33 34 extern int fileno( FILE *stream);34 extern int fileno( FILE *stream ); 35 35 36 36 extern int fprintf ( FILE * stream, const char * format, ... ); 37 37 38 extern long long int strtoll ( const char* str, char** endptr, int base);39 extern unsigned long long int strtoull( const char* str, char** endptr, int base);40 extern double strtod ( const char* str, char** endptr);38 extern long long int strtoll ( const char* str, char** endptr, int base ); 39 extern unsigned long long int strtoull( const char* str, char** endptr, int base ); 40 extern double strtod ( const char* str, char** endptr ); 41 41 } 42 42 … … 44 44 #include "limits.hfa" 45 45 46 #pragma GCC visibility push( default)47 48 extern int cfa_args_argc __attribute__(( weak));49 extern char ** cfa_args_argv __attribute__(( weak));50 extern char ** cfa_args_envp __attribute__(( weak));46 #pragma GCC visibility push( default ) 47 48 extern int cfa_args_argc __attribute__(( weak )); 49 extern char ** cfa_args_argv __attribute__(( weak )); 50 extern char ** cfa_args_envp __attribute__(( weak )); 51 51 52 52 forall([N]) 53 static void usage( char * cmd, const array( cfa_option, N ) & options, const char * usage, FILE * out) __attribute__ ((noreturn));53 static void usage( char * cmd, const array( cfa_option, N ) & options, const char * usage, FILE * out ) __attribute__ (( noreturn )); 54 54 //----------------------------------------------------------------------------- 55 55 // checking 56 56 forall([N]) 57 57 static void check_args( const array( cfa_option, N ) & options ) { 58 for(i; N) { 59 for(j; N) { 60 if(i == j) continue; 61 62 if( options[i].short_name != '\0' 63 && options[i].short_name == options[j].short_name) 64 abort("Parse Args error: two options have short name '%c' (%zu & %zu)", options[i].short_name, i, j); 65 66 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); 58 for ( i; N ) { 59 for ( j; N ) { 60 if ( i == j ) continue; 61 62 if ( options[i].short_name != '\0' 63 && options[i].short_name == options[j].short_name ) 64 abort( "Parse Args error: two options have short name '%c' (%zu & %zu)", options[i].short_name, i, j ); 65 66 if (0 == strcmp( options[i].long_name, options[j].long_name )) 67 abort( "Parse Args error: two options have long name '%s' (%zu & %zu)", options[i].long_name, i, j ); 67 68 } 68 69 } … … 74 75 forall([opt_count]) { 75 76 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 { 77 if ( 0p != &cfa_args_argc ) { 78 parse_args( cfa_args_argc, cfa_args_argv, options, usage, left ); 79 } else { 80 80 char * temp[1] = { 0p }; 81 81 parse_args(0, temp, options, usage, left ); … … 90 90 char ** & left 91 91 ) { 92 check_args( options);92 check_args( options ); 93 93 94 94 int maxv = 'h'; … … 96 96 { 97 97 int idx = 0; 98 for (i; opt_count) {99 if ( options[i].short_name) {100 maxv = max( options[i].short_name, maxv);98 for ( i; opt_count ) { 99 if ( options[i].short_name ) { 100 maxv = max( options[i].short_name, maxv ); 101 101 optstring[idx] = options[i].short_name; 102 102 idx++; 103 if ( ((intptr_t)options[i].parse) != ((intptr_t)parse_settrue)104 && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) {103 if ( (intptr_t)options[i].parse != (intptr_t)parse_settrue 104 && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) { 105 105 optstring[idx] = ':'; 106 106 idx++; … … 115 115 { 116 116 int idx = 0; 117 for (i; opt_count) {118 if (options[i].long_name) {117 for ( i; opt_count ) { 118 if ( options[i].long_name ) { 119 119 // we don't have the mutable keyword here, which is really what we would want 120 120 int & val_ref = (int &)(const int &)options[i].val; … … 124 124 optarr[idx].flag = 0p; 125 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) ) {126 if ( ((intptr_t)options[i].parse) == ((intptr_t)parse_settrue) 127 || ((intptr_t)options[i].parse) == ((intptr_t)parse_setfalse) ) { 128 128 optarr[idx].has_arg = no_argument; 129 129 } else { … … 139 139 FILE * out = stderr; 140 140 NEXT_ARG: 141 for () {141 for () { 142 142 int idx = 0; 143 int opt = getopt_long( argc, argv, optstring, optarr, &idx);144 switch( opt) {143 int opt = getopt_long( argc, argv, optstring, optarr, &idx ); 144 switch( opt ) { 145 145 case -1: 146 if (&left != 0p) left = argv + optind;146 if ( &left != 0p ) left = argv + optind; 147 147 return; 148 148 case 'h': 149 149 out = stdout; 150 150 case '?': 151 usage( argv[0], options, usage, out);151 usage( argv[0], options, usage, out ); 152 152 default: 153 for (i; opt_count) {154 if (opt == options[i].val) {153 for ( i; opt_count ) { 154 if ( opt == options[i].val ) { 155 155 const char * arg = optarg ? optarg : ""; 156 if ( arg[0] == '=' ) { arg++; }156 if ( arg[0] == '=' ) { arg++; } 157 157 // work around for some weird bug 158 158 void * variable = options[i].variable; 159 159 bool (*parse_func)(const char *, void * ) = options[i].parse; 160 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);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 165 } 166 166 } 167 abort( "Internal parse arg error\n");167 abort( "Internal parse arg error\n" ); 168 168 } 169 169 … … 172 172 } 173 173 174 static inline int next_newline( const char * str) {174 static inline int next_newline( const char * str ) { 175 175 int ret; 176 const char * ptr = strstr( str, "\n");177 if (!ptr) return MAX;178 179 /* paranoid */ verify( str <= ptr );176 const char * ptr = strstr( str, "\n" ); 177 if ( ! ptr ) return MAX; 178 179 /* paranoid */ verify( str <= ptr ); 180 180 intptr_t low = (intptr_t)str; 181 181 intptr_t hi = (intptr_t)ptr; … … 187 187 //----------------------------------------------------------------------------- 188 188 // Print usage 189 static void printopt( FILE * out, int width, int max, char sn, const char * ln, const char * help) {189 static void printopt( FILE * out, int width, int max, char sn, const char * ln, const char * help ) { 190 190 // check how wide we should be printing 191 191 // this includes all options and the help message 192 192 int hwidth = max - (11 + width); 193 if (hwidth <= 0) hwidth = max;193 if ( hwidth <= 0 ) hwidth = max; 194 194 195 195 // check which pieces we have 196 bool has_ln = ln && strcmp( "", ln);197 bool has_help = help && strcmp( "", help);196 bool has_ln = ln && strcmp( "", ln ); 197 bool has_help = help && strcmp( "", help ); 198 198 199 199 // print the small name if present 200 if (sn != '\0') fprintf(out, " -%c", sn);201 else fprintf( out, " ");200 if ( sn != '\0') fprintf( out, " -%c", sn ); 201 else fprintf( out, " " ); 202 202 203 203 // print a comma if we have both short and long names 204 if (sn != '\0' && has_ln) fprintf(out, ", ");205 else fprintf( out, " ");204 if ( sn != '\0' && has_ln ) fprintf( out, ", " ); 205 else fprintf( out, " " ); 206 206 207 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) {208 if ( has_ln ) fprintf( out, "--%-*s", width, ln ); 209 else if ( has_help ) fprintf( out, " %-*s", width, "" ); 210 211 if ( has_help ) { 212 212 // print the help 213 213 // We need to wrap at the max width, and also indent newlines so everything is nice and pretty 214 214 215 215 // for each line to print 216 for () {216 for () { 217 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);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 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");230 } 231 232 void print_args_usage( cfa_option options[], const size_t opt_count, const char * usage, bool error) __attribute__ ((noreturn)) {224 if ( nextnl == real ) help++; 225 if ('\0' == *help ) break; 226 fprintf( out, "\n%*s", width + 8, "" ); 227 } 228 } 229 fprintf( out, "\n" ); 230 } 231 232 void print_args_usage( cfa_option options[], const size_t opt_count, const char * usage, bool error ) __attribute__ ((noreturn )) { 233 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);235 } 236 237 void print_args_usage( int , char * argv[], cfa_option options[], const size_t opt_count, const char * usage, bool error) __attribute__ ((noreturn)) {234 usage( cfa_args_argv[0], arr, usage, error ? stderr : stdout ); 235 } 236 237 void print_args_usage( int , char * argv[], cfa_option options[], const size_t opt_count, const char * usage, bool error ) __attribute__ (( noreturn )) { 238 238 const array( cfa_option, opt_count ) & arr = (const array( cfa_option, opt_count ) &) *options; 239 usage( argv[0], arr, usage, error ? stderr : stdout);239 usage( argv[0], arr, usage, error ? stderr : stdout ); 240 240 } 241 241 242 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);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 249 } 250 250 } 251 251 252 252 forall([N]) 253 static void usage( char * cmd, const array( cfa_option, N ) & options, const char * help, FILE * out) __attribute__((noreturn)) {253 static void usage( char * cmd, const array( cfa_option, N ) & options, const char * help, FILE * out ) __attribute__(( noreturn )) { 254 254 int width = 0; 255 255 { 256 for (i; N) {257 if (options[i].long_name) {258 int w = strlen( options[i].long_name);259 if (w > width) width = w;256 for ( i; N ) { 257 if ( options[i].long_name ) { 258 int w = strlen( options[i].long_name ); 259 if ( w > width ) width = w; 260 260 } 261 261 } … … 263 263 264 264 int max_width = 1_000_000; 265 int outfd = fileno( out);266 if (isatty(outfd)) {265 int outfd = fileno( out ); 266 if ( isatty( outfd ) ) { 267 267 struct winsize size; 268 int ret = ioctl( outfd, TIOCGWINSZ, &size);269 if (ret < 0) abort( "ioctl error: (%d) %s\n", (int)errno, strerror(errno) );268 int ret = ioctl( outfd, TIOCGWINSZ, &size ); 269 if ( ret < 0 ) abort( "ioctl error: (%d) %s\n", (int)errno, strerror( errno) ); 270 270 max_width = size.ws_col; 271 271 } 272 272 273 fprintf( out, "Usage:\n %s %s\n", cmd, help);274 275 for (i; N) {276 printopt( out, width, max_width, options[i].short_name, options[i].long_name, options[i].help);277 } 278 fprintf( out, " -%c, --%-*s %s\n", 'h', width, "help", "print this help message");279 exit( out == stdout ? 0 : 1);273 fprintf( out, "Usage:\n %s %s\n", cmd, help ); 274 275 for ( i; N ) { 276 printopt( out, width, max_width, options[i].short_name, options[i].long_name, options[i].help ); 277 } 278 fprintf( out, " -%c, --%-*s %s\n", 'h', width, "help", "print this help message" ); 279 exit( out == stdout ? 0 : 1 ); 280 280 } 281 281 282 282 //----------------------------------------------------------------------------- 283 283 // Typed argument parsing 284 bool parse_yesno( const char * arg, bool & value ) {285 if (strcmp(arg, "yes") == 0) {284 bool parse_yesno( const char * arg, bool & value ) { 285 if ( strcmp( arg, "yes" ) == 0 ) { 286 286 value = true; 287 287 return true; 288 288 } 289 290 if(strcmp(arg, "Y") == 0) { 289 if ( strcmp( arg, "Y" ) == 0 ) { 291 290 value = true; 292 291 return true; 293 292 } 294 295 if(strcmp(arg, "y") == 0) { 293 if ( strcmp( arg, "y" ) == 0 ) { 296 294 value = true; 297 295 return true; 298 296 } 299 300 if(strcmp(arg, "no") == 0) { 297 if ( strcmp( arg, "no" ) == 0 ) { 301 298 value = false; 302 299 return true; 303 300 } 304 305 if(strcmp(arg, "N") == 0) { 301 if ( strcmp( arg, "N" ) == 0 ) { 306 302 value = false; 307 303 return true; 308 304 } 309 310 if(strcmp(arg, "n") == 0) { 305 if ( strcmp( arg, "n" ) == 0 ) { 311 306 value = false; 312 307 return true; 313 308 } 314 315 309 return false; 316 310 } 317 311 318 bool parse_truefalse( const char * arg, bool & value) {319 if (strcmp(arg, "true") == 0) {312 bool parse_truefalse( const char * arg, bool & value ) { 313 if ( strcmp( arg, "true" ) == 0 ) { 320 314 value = true; 321 315 return true; 322 316 } 323 324 if(strcmp(arg, "false") == 0) { 317 if ( strcmp( arg, "false" ) == 0 ) { 325 318 value = false; 326 319 return true; 327 320 } 328 329 321 return false; 330 322 } 331 323 332 bool parse_settrue ( const char *, bool & value ) {324 bool parse_settrue ( const char *, bool & value ) { 333 325 value = true; 334 326 return true; 335 327 } 336 328 337 bool parse_setfalse( const char *, bool & value ) {329 bool parse_setfalse( const char *, bool & value ) { 338 330 value = false; 339 331 return true; 340 332 } 341 333 342 bool parse( const char * arg, const char * & value ) {334 bool parse( const char * arg, const char * & value ) { 343 335 value = arg; 344 336 return true; 345 337 } 346 338 347 bool parse( const char * arg, int & value) {339 bool parse( const char * arg, int & value ) { 348 340 char * end; 349 341 350 342 errno = 0; 351 long long int r = strtoll(arg, &end, 0); 352 if(errno) return false; 353 if(*end != '\0') return false; 354 if(r > (int)MAX) return false; 355 if(r < (int)MIN) return false; 356 343 long long int r = strtoll( arg, &end, 0 ); 344 if ( errno ) return false; 345 if (*end != '\0') return false; 346 if ( r > (int)MAX ) return false; 347 if ( r < (int)MIN ) return false; 357 348 value = r; 358 349 return true; 359 350 } 360 351 361 static unsigned long long int strict_strtoull( const char * arg, int base ) {352 static unsigned long long int strict_strtoull( const char * arg, int base ) { 362 353 errno = 0; 363 354 { 364 355 const char * in = arg; 365 for () {366 if ('\0' == *in) {356 for () { 357 if ( '\0' == *in ) { 367 358 errno = EINVAL; 368 359 return 0; 369 360 } 370 if (!isspace(*in)) break;361 if ( ! isspace(*in )) break; 371 362 in++; 372 363 } 373 if (!isdigit(*in)) {364 if ( ! isdigit(*in )) { 374 365 errno = EINVAL; 375 366 return 0; 376 367 } 377 368 } 378 379 369 *char end; 380 unsigned long long int r = strtoull( arg, &end, base);381 if (*end != '\0') errno = EINVAL;382 if (errno) return 0;370 unsigned long long int r = strtoull( arg, &end, base ); 371 if (*end != '\0') errno = EINVAL; 372 if ( errno ) return 0; 383 373 return r; 384 374 } 385 375 386 bool parse(const char * arg, unsigned & value) { 387 unsigned long long int r = strict_strtoull(arg, 0); 388 if(errno) return false; 389 if(r > (unsigned)MAX) return false; 390 376 bool parse( const char * arg, unsigned & value ) { 377 unsigned long long int r = strict_strtoull( arg, 0 ); 378 if ( errno ) return false; 379 if ( r > (unsigned)MAX ) return false; 391 380 value = r; 392 381 return true; 393 382 } 394 383 395 bool parse(const char * arg, unsigned long & value) { 396 unsigned long long int r = strict_strtoull(arg, 0); 397 if(errno) return false; 398 if(r > (unsigned long)MAX) return false; 399 384 bool parse( const char * arg, unsigned long & value ) { 385 unsigned long long int r = strict_strtoull( arg, 0 ); 386 if ( errno ) return false; 387 if ( r > (unsigned long)MAX ) return false; 400 388 value = r; 401 389 return true; 402 390 } 403 391 404 bool parse(const char * arg, unsigned long long & value) { 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 392 bool parse( const char * arg, unsigned long long & value ) { 393 unsigned long long int r = strict_strtoull( arg, 0 ); 394 if ( errno ) return false; 395 if ( r > (unsigned long long)MAX ) return false; 409 396 value = r; 410 397 return true; 411 398 } 412 399 413 bool parse( const char * arg, double & value) {400 bool parse( const char * arg, double & value ) { 414 401 char * end; 415 double r = strtod(arg, &end); 416 if(*end != '\0') return false; 417 402 double r = strtod( arg, &end ); 403 if ( *end != '\0') return false; 418 404 value = r; 419 405 return true; -
libcfa/src/parseargs.hfa
r061b001 ra4e1b09 10 10 // Author : Thierry Delisle 11 11 // Created On : Wed Oct 12 15:28:01 2022 12 // Last Modified By : 13 // Last Modified On : 14 // Update Count : 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Mon Jul 8 18:18:14 2024 14 // Update Count : 2 15 15 // 16 16 #pragma once … … 31 31 static inline void ?{}( cfa_option & this ) {} 32 32 33 forall(T & | { bool parse( const char *, T & ); })33 forall(T & | { bool parse( const char *, T & ); }) 34 34 static inline void ?{}( cfa_option & this, char short_name, const char * long_name, const char * help, T & variable ) { 35 35 this.val = 0;
Note: See TracChangeset
for help on using the changeset viewer.