Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/parseargs.cfa

    r550afde2 ra4e1b09  
    1010// Author           : Thierry Delisle
    1111// 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
    1515//
    1616
     
    3232        extern FILE * stdout;
    3333
    34         extern int fileno(FILE *stream);
     34        extern int fileno( FILE *stream );
    3535
    3636        extern int fprintf ( FILE * stream, const char * format, ... );
    3737
    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 );
    4141}
    4242
     
    4444#include "limits.hfa"
    4545
    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
     48extern int cfa_args_argc __attribute__(( weak ));
     49extern char ** cfa_args_argv __attribute__(( weak ));
     50extern char ** cfa_args_envp __attribute__(( weak ));
    5151
    5252forall([N])
    53 static void usage(char * cmd, const array( cfa_option, N ) & options, const char * usage, FILE * out)  __attribute__ ((noreturn));
     53static void usage( char * cmd, const array( cfa_option, N ) & options, const char * usage, FILE * out )  __attribute__ (( noreturn ));
    5454//-----------------------------------------------------------------------------
    5555// checking
    5656forall([N])
    5757static 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 );
    6768                }
    6869        }
     
    7475forall([opt_count]) {
    7576        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 {
    8080                        char * temp[1] = { 0p };
    8181                        parse_args(0, temp, options, usage, left );
     
    9090                char ** & left
    9191        ) {
    92                 check_args(options);
     92                check_args( options );
    9393
    9494                int maxv = 'h';
     
    9696                {
    9797                        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 );
    101101                                        optstring[idx] = options[i].short_name;
    102102                                        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) ) {
    105105                                                optstring[idx] = ':';
    106106                                                idx++;
     
    115115                {
    116116                        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 ) {
    119119                                        // we don't have the mutable keyword here, which is really what we would want
    120120                                        int & val_ref = (int &)(const int &)options[i].val;
     
    124124                                        optarr[idx].flag = 0p;
    125125                                        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) ) {
    128128                                                optarr[idx].has_arg = no_argument;
    129129                                        } else {
     
    139139                FILE * out = stderr;
    140140                NEXT_ARG:
    141                 for() {
     141                for () {
    142142                        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 ) {
    145145                                case -1:
    146                                         if(&left != 0p) left = argv + optind;
     146                                        if ( &left != 0p ) left = argv + optind;
    147147                                        return;
    148148                                case 'h':
    149149                                        out = stdout;
    150150                                case '?':
    151                                         usage(argv[0], options, usage, out);
     151                                        usage( argv[0], options, usage, out );
    152152                                default:
    153                                         for(i; opt_count) {
    154                                                 if(opt == options[i].val) {
     153                                        for ( i; opt_count ) {
     154                                                if ( opt == options[i].val ) {
    155155                                                        const char * arg = optarg ? optarg : "";
    156                                                         if( arg[0] == '=' ) { arg++; }
     156                                                        if ( arg[0] == '=' ) { arg++; }
    157157                                                        // work around for some weird bug
    158158                                                        void * variable = options[i].variable;
    159159                                                        bool (*parse_func)(const char *, void * ) = options[i].parse;
    160160                                                        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 );
    165165                                                }
    166166                                        }
    167                                         abort("Internal parse arg error\n");
     167                                        abort( "Internal parse arg error\n" );
    168168                        }
    169169
     
    172172}
    173173
    174 static inline int next_newline(const char * str) {
     174static inline int next_newline( const char * str ) {
    175175        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 );
    180180        intptr_t low = (intptr_t)str;
    181181        intptr_t hi  = (intptr_t)ptr;
     
    187187//-----------------------------------------------------------------------------
    188188// Print usage
    189 static void printopt(FILE * out, int width, int max, char sn, const char * ln, const char * help) {
     189static void printopt( FILE * out, int width, int max, char sn, const char * ln, const char * help ) {
    190190        // check how wide we should be printing
    191191        // this includes all options and the help message
    192192        int hwidth = max - (11 + width);
    193         if(hwidth <= 0) hwidth = max;
     193        if ( hwidth <= 0 ) hwidth = max;
    194194
    195195        // 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 );
    198198
    199199        // 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, "    " );
    202202
    203203        // 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, "  " );
    206206
    207207        // 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 ) {
    212212                // print the help
    213213                // We need to wrap at the max width, and also indent newlines so everything is nice and pretty
    214214
    215215                // for each line to print
    216                 for() {
     216                for () {
    217217                        //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 );
    223223                        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
     232void print_args_usage( cfa_option options[], const size_t opt_count, const char * usage, bool error )  __attribute__ ((noreturn )) {
    233233        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
     237void print_args_usage( int , char * argv[], cfa_option options[], const size_t opt_count, const char * usage, bool error )  __attribute__ (( noreturn )) {
    238238        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 );
    240240}
    241241
    242242forall( [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 );
    249249        }
    250250}
    251251
    252252forall([N])
    253 static void usage(char * cmd, const array( cfa_option, N ) & options, const char * help, FILE * out) __attribute__((noreturn)) {
     253static void usage( char * cmd, const array( cfa_option, N ) & options, const char * help, FILE * out ) __attribute__(( noreturn )) {
    254254        int width = 0;
    255255        {
    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;
    260260                        }
    261261                }
     
    263263
    264264        int max_width = 1_000_000;
    265         int outfd = fileno(out);
    266         if(isatty(outfd)) {
     265        int outfd = fileno( out );
     266        if ( isatty( outfd ) ) {
    267267                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) );
    270270                max_width = size.ws_col;
    271271        }
    272272
    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 );
    280280}
    281281
    282282//-----------------------------------------------------------------------------
    283283// Typed argument parsing
    284 bool parse_yesno(const char * arg, bool & value ) {
    285         if(strcmp(arg, "yes") == 0) {
     284bool parse_yesno( const char * arg, bool & value ) {
     285        if ( strcmp( arg, "yes" ) == 0 ) {
    286286                value = true;
    287287                return true;
    288288        }
    289 
    290         if(strcmp(arg, "Y") == 0) {
     289        if ( strcmp( arg, "Y" ) == 0 ) {
    291290                value = true;
    292291                return true;
    293292        }
    294 
    295         if(strcmp(arg, "y") == 0) {
     293        if ( strcmp( arg, "y" ) == 0 ) {
    296294                value = true;
    297295                return true;
    298296        }
    299 
    300         if(strcmp(arg, "no") == 0) {
     297        if ( strcmp( arg, "no" ) == 0 ) {
    301298                value = false;
    302299                return true;
    303300        }
    304 
    305         if(strcmp(arg, "N") == 0) {
     301        if ( strcmp( arg, "N" ) == 0 ) {
    306302                value = false;
    307303                return true;
    308304        }
    309 
    310         if(strcmp(arg, "n") == 0) {
     305        if ( strcmp( arg, "n" ) == 0 ) {
    311306                value = false;
    312307                return true;
    313308        }
    314 
    315309        return false;
    316310}
    317311
    318 bool parse_truefalse(const char * arg, bool & value) {
    319         if(strcmp(arg, "true") == 0) {
     312bool parse_truefalse( const char * arg, bool & value ) {
     313        if ( strcmp( arg, "true" ) == 0 ) {
    320314                value = true;
    321315                return true;
    322316        }
    323 
    324         if(strcmp(arg, "false") == 0) {
     317        if ( strcmp( arg, "false" )  == 0 ) {
    325318                value = false;
    326319                return true;
    327320        }
    328 
    329321        return false;
    330322}
    331323
    332 bool parse_settrue (const char *, bool & value ) {
     324bool parse_settrue ( const char *, bool & value ) {
    333325        value = true;
    334326        return true;
    335327}
    336328
    337 bool parse_setfalse(const char *, bool & value )  {
     329bool parse_setfalse( const char *, bool & value )  {
    338330        value = false;
    339331        return true;
    340332}
    341333
    342 bool parse(const char * arg, const char * & value ) {
     334bool parse( const char * arg, const char * & value ) {
    343335        value = arg;
    344336        return true;
    345337}
    346338
    347 bool parse(const char * arg, int & value) {
     339bool parse( const char * arg, int & value ) {
    348340        char * end;
    349341
    350342        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;
    357348        value = r;
    358349        return true;
    359350}
    360351
    361 static unsigned long long int strict_strtoull( const char * arg, int base) {
     352static unsigned long long int strict_strtoull( const char * arg, int base ) {
    362353        errno = 0;
    363354        {
    364355                const char * in = arg;
    365                 for() {
    366                         if('\0' == *in) {
     356                for () {
     357                        if ( '\0' == *in ) {
    367358                                errno = EINVAL;
    368359                                return 0;
    369360                        }
    370                         if(!isspace(*in)) break;
     361                        if ( ! isspace(*in )) break;
    371362                        in++;
    372363                }
    373                 if(!isdigit(*in)) {
     364                if ( ! isdigit(*in )) {
    374365                        errno = EINVAL;
    375366                        return 0;
    376367                }
    377368        }
    378 
    379369        *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;
    383373        return r;
    384374}
    385375
    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 
     376bool 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;
    391380        value = r;
    392381        return true;
    393382}
    394383
    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 
     384bool 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;
    400388        value = r;
    401389        return true;
    402390}
    403391
    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 
     392bool 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;
    409396        value = r;
    410397        return true;
    411398}
    412399
    413 bool parse(const char * arg, double & value) {
     400bool parse( const char * arg, double & value ) {
    414401        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;
    418404        value = r;
    419405        return true;
Note: See TracChangeset for help on using the changeset viewer.