Ignore:
Timestamp:
Oct 19, 2022, 4:43:26 PM (3 years ago)
Author:
Thierry Delisle <tdelisle@…>
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.
Message:

Merge branch 'master' into pthread-emulation

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
    117#include "parseargs.hfa"
    218
     19#include <assert.h>
     20#include <ctype.h>
    321#include <stdint.h>
    422#include <string.h>
    523#include <errno.h>
    624#include <unistd.h>
    7 #include <assert.h>
    825
    926extern "C" {
     
    3350extern char ** cfa_args_envp __attribute__((weak));
    3451
    35 static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * usage, FILE * out)  __attribute__ ((noreturn));
     52forall([N])
     53static void usage(char * cmd, const array( cfa_option, N ) & options, const char * usage, FILE * out)  __attribute__ ((noreturn));
    3654//-----------------------------------------------------------------------------
    3755// checking
    38 static void check_args(cfa_option options[], size_t opt_count) {
    39         for(i; opt_count) {
    40                 for(j; opt_count) {
     56forall([N])
     57static void check_args( const array( cfa_option, N ) & options ) {
     58        for(i; N) {
     59                for(j; N) {
    4160                        if(i == j) continue;
    4261
     
    5372//-----------------------------------------------------------------------------
    5473// 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] = ':';
     74forall([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                                        }
    88132                                        idx++;
    89133                                }
    90134                        }
    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");
    112168                        }
    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
     174static 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;
    147185}
    148186
     
    150188// Print usage
    151189static 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
    152192        int hwidth = max - (11 + width);
    153193        if(hwidth <= 0) hwidth = max;
    154194
    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");
    168230}
    169231
    170232void 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);
    172235}
    173236
    174237void 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
     242forall( [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
     252forall([N])
     253static void usage(char * cmd, const array( cfa_option, N ) & options, const char * help, FILE * out) __attribute__((noreturn)) {
    179254        int width = 0;
    180255        {
    181                 for(i; opt_count) {
     256                for(i; N) {
    182257                        if(options[i].long_name) {
    183258                                int w = strlen(options[i].long_name);
     
    198273        fprintf(out, "Usage:\n  %s %s\n", cmd, help);
    199274
    200         for(i; opt_count) {
     275        for(i; N) {
    201276                printopt(out, width, max_width, options[i].short_name, options[i].long_name, options[i].help);
    202277        }
     
    272347bool parse(const char * arg, int & value) {
    273348        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;
    275353        if(*end != '\0') return false;
     354        if(r > (int)MAX) return false;
     355        if(r < (int)MIN) return false;
    276356
    277357        value = r;
     
    279359}
    280360
     361static 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
    281386bool 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;
    285389        if(r > (unsigned)MAX) return false;
    286390
     
    290394
    291395bool 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;
    295398        if(r > (unsigned long)MAX) return false;
    296399
     
    300403
    301404bool 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;
    309411}
    310412
Note: See TracChangeset for help on using the changeset viewer.