| [481f882] | 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 | 
|---|
| [a4e1b09] | 12 | // Last Modified By : Peter A. Buhr | 
|---|
|  | 13 | // Last Modified On : Mon Jul  8 18:18:23 2024 | 
|---|
|  | 14 | // Update Count     : 7 | 
|---|
| [481f882] | 15 | // | 
|---|
|  | 16 |  | 
|---|
| [7f389a5c] | 17 | #include "parseargs.hfa" | 
|---|
|  | 18 |  | 
|---|
| [f82f07e] | 19 | #include <assert.h> | 
|---|
| [affb51b] | 20 | #include <ctype.h> | 
|---|
| [e699eb6] | 21 | #include <stdint.h> | 
|---|
| [7f389a5c] | 22 | #include <string.h> | 
|---|
| [e699eb6] | 23 | #include <errno.h> | 
|---|
| [3f1d9b5] | 24 | #include <unistd.h> | 
|---|
| [1c893ae] | 25 |  | 
|---|
| [7f389a5c] | 26 | extern "C" { | 
|---|
|  | 27 | #include <getopt.h> | 
|---|
| [3f1d9b5] | 28 | #include <sys/ioctl.h> | 
|---|
| [7f389a5c] | 29 |  | 
|---|
|  | 30 | struct FILE; | 
|---|
|  | 31 | extern FILE * stderr; | 
|---|
|  | 32 | extern FILE * stdout; | 
|---|
|  | 33 |  | 
|---|
| [a4e1b09] | 34 | extern int fileno( FILE *stream ); | 
|---|
| [3f1d9b5] | 35 |  | 
|---|
| [7f389a5c] | 36 | extern int fprintf ( FILE * stream, const char * format, ... ); | 
|---|
| [53e4562] | 37 |  | 
|---|
| [a4e1b09] | 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 ); | 
|---|
| [7f389a5c] | 41 | } | 
|---|
|  | 42 |  | 
|---|
| [e699eb6] | 43 | #include "common.hfa" | 
|---|
|  | 44 | #include "limits.hfa" | 
|---|
| [3f1d9b5] | 45 |  | 
|---|
| [a4e1b09] | 46 | #pragma GCC visibility push( default ) | 
|---|
| [789f279] | 47 |  | 
|---|
| [a4e1b09] | 48 | extern int cfa_args_argc __attribute__(( weak )); | 
|---|
|  | 49 | extern char ** cfa_args_argv __attribute__(( weak )); | 
|---|
|  | 50 | extern char ** cfa_args_envp __attribute__(( weak )); | 
|---|
| [7874d77] | 51 |  | 
|---|
| [d1abc63c] | 52 | forall([N]) | 
|---|
| [a4e1b09] | 53 | static void usage( char * cmd, const array( cfa_option, N ) & options, const char * usage, FILE * out )  __attribute__ (( noreturn )); | 
|---|
| [80d3b1b] | 54 | //----------------------------------------------------------------------------- | 
|---|
|  | 55 | // checking | 
|---|
| [d1abc63c] | 56 | forall([N]) | 
|---|
|  | 57 | static void check_args( const array( cfa_option, N ) & options ) { | 
|---|
| [a4e1b09] | 58 | for ( i; N ) { | 
|---|
|  | 59 | for ( j; N ) { | 
|---|
|  | 60 | if ( i == j ) continue; | 
|---|
| [80d3b1b] | 61 |  | 
|---|
| [a4e1b09] | 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 ); | 
|---|
| [3f1d9b5] | 65 |  | 
|---|
| [a4e1b09] | 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 ); | 
|---|
| [80d3b1b] | 68 | } | 
|---|
|  | 69 | } | 
|---|
|  | 70 | } | 
|---|
|  | 71 |  | 
|---|
|  | 72 |  | 
|---|
|  | 73 | //----------------------------------------------------------------------------- | 
|---|
|  | 74 | // Parsing args | 
|---|
| [54f70c6] | 75 | forall([opt_count]) | 
|---|
|  | 76 | void parse_args( const array( cfa_option, opt_count ) & options, const char * usage, char ** & left ) { | 
|---|
|  | 77 | if ( 0p != &cfa_args_argc ) { | 
|---|
|  | 78 | parse_args( cfa_args_argc, cfa_args_argv, options, usage, left ); | 
|---|
|  | 79 | } else { | 
|---|
|  | 80 | char * temp[1] = { 0p }; | 
|---|
|  | 81 | parse_args(0, temp, options, usage, left ); | 
|---|
| [433d352] | 82 | } | 
|---|
| [54f70c6] | 83 | } | 
|---|
| [7874d77] | 84 |  | 
|---|
| [54f70c6] | 85 | forall([opt_count]) | 
|---|
|  | 86 | void parse_args( | 
|---|
|  | 87 | int argc, | 
|---|
|  | 88 | char * argv[], | 
|---|
|  | 89 | const array( cfa_option, opt_count ) & options, | 
|---|
|  | 90 | const char * usage, | 
|---|
|  | 91 | char ** & left | 
|---|
|  | 92 | ) { | 
|---|
|  | 93 | check_args( options ); | 
|---|
|  | 94 |  | 
|---|
|  | 95 | int maxv = 'h'; | 
|---|
|  | 96 | char optstring[(opt_count * 3) + 2] = { '\0' }; | 
|---|
|  | 97 | { | 
|---|
|  | 98 | int idx = 0; | 
|---|
|  | 99 | for ( i; opt_count ) { | 
|---|
|  | 100 | if ( options[i].short_name ) { | 
|---|
|  | 101 | maxv = max( options[i].short_name, maxv ); | 
|---|
|  | 102 | optstring[idx] = options[i].short_name; | 
|---|
|  | 103 | idx++; | 
|---|
|  | 104 | if ( (intptr_t)options[i].parse != (intptr_t)parse_settrue | 
|---|
|  | 105 | && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) { | 
|---|
|  | 106 | optstring[idx] = ':'; | 
|---|
| [80d3b1b] | 107 | idx++; | 
|---|
|  | 108 | } | 
|---|
|  | 109 | } | 
|---|
|  | 110 | } | 
|---|
| [54f70c6] | 111 | optstring[idx+0] = 'h'; | 
|---|
|  | 112 | optstring[idx+1] = '\0'; | 
|---|
|  | 113 | } | 
|---|
| [80d3b1b] | 114 |  | 
|---|
| [54f70c6] | 115 | struct option optarr[opt_count + 2]; | 
|---|
|  | 116 | { | 
|---|
|  | 117 | int idx = 0; | 
|---|
|  | 118 | for ( i; opt_count ) { | 
|---|
|  | 119 | if ( options[i].long_name ) { | 
|---|
|  | 120 | // we don't have the mutable keyword here, which is really what we would want | 
|---|
|  | 121 | int & val_ref = (int &)(const int &)options[i].val; | 
|---|
|  | 122 | val_ref = (options[i].short_name != '\0') ? ((int)options[i].short_name) : ++maxv; | 
|---|
|  | 123 |  | 
|---|
|  | 124 | optarr[idx].name = options[i].long_name; | 
|---|
|  | 125 | optarr[idx].flag = 0p; | 
|---|
|  | 126 | optarr[idx].val  = options[i].val; | 
|---|
|  | 127 | if ( ((intptr_t)options[i].parse) == ((intptr_t)parse_settrue) | 
|---|
|  | 128 | || ((intptr_t)options[i].parse) == ((intptr_t)parse_setfalse) ) { | 
|---|
|  | 129 | optarr[idx].has_arg = no_argument; | 
|---|
|  | 130 | } else { | 
|---|
|  | 131 | optarr[idx].has_arg = required_argument; | 
|---|
| [7f389a5c] | 132 | } | 
|---|
| [54f70c6] | 133 | idx++; | 
|---|
| [7f389a5c] | 134 | } | 
|---|
|  | 135 | } | 
|---|
| [54f70c6] | 136 | optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0, 'h']; | 
|---|
|  | 137 | optarr[idx+1].[name, has_arg, flag, val] = [0, no_argument, 0, 0]; | 
|---|
|  | 138 | } | 
|---|
| [7f389a5c] | 139 |  | 
|---|
| [54f70c6] | 140 | FILE * out = stderr; | 
|---|
|  | 141 | NEXT_ARG: | 
|---|
|  | 142 | for () { | 
|---|
|  | 143 | int idx = 0; | 
|---|
|  | 144 | int opt = getopt_long( argc, argv, optstring, optarr, &idx ); | 
|---|
|  | 145 | switch( opt ) { | 
|---|
|  | 146 | case -1: | 
|---|
|  | 147 | if ( &left != 0p ) left = argv + optind; | 
|---|
|  | 148 | return; | 
|---|
|  | 149 | case 'h': | 
|---|
|  | 150 | out = stdout; | 
|---|
|  | 151 | case '?': | 
|---|
|  | 152 | usage( argv[0], options, usage, out ); | 
|---|
|  | 153 | default: | 
|---|
|  | 154 | for ( i; opt_count ) { | 
|---|
|  | 155 | if ( opt == options[i].val ) { | 
|---|
|  | 156 | const char * arg = optarg ? optarg : ""; | 
|---|
|  | 157 | if ( arg[0] == '=' ) { arg++; } | 
|---|
|  | 158 | // work around for some weird bug | 
|---|
|  | 159 | void * variable = options[i].variable; | 
|---|
|  | 160 | bool (*parse_func)(const char *, void * ) = options[i].parse; | 
|---|
|  | 161 | bool success = parse_func( arg, variable ); | 
|---|
|  | 162 | if ( success ) continue NEXT_ARG; | 
|---|
|  | 163 |  | 
|---|
|  | 164 | fprintf( out, "Argument '%s' for option %c could not be parsed\n\n", arg, (char)opt ); | 
|---|
| [a4e1b09] | 165 | usage( argv[0], options, usage, out ); | 
|---|
| [54f70c6] | 166 | } | 
|---|
| [d1abc63c] | 167 | } | 
|---|
| [54f70c6] | 168 | abort( "Internal parse arg error\n" ); | 
|---|
| [d1abc63c] | 169 | } | 
|---|
| [7f389a5c] | 170 | } | 
|---|
| [419c434] | 171 | } | 
|---|
| [7f389a5c] | 172 |  | 
|---|
| [a4e1b09] | 173 | static inline int next_newline( const char * str ) { | 
|---|
| [f82f07e] | 174 | int ret; | 
|---|
| [a4e1b09] | 175 | const char * ptr = strstr( str, "\n" ); | 
|---|
|  | 176 | if ( ! ptr ) return MAX; | 
|---|
| [f82f07e] | 177 |  | 
|---|
| [a4e1b09] | 178 | /* paranoid */ verify( str <= ptr ); | 
|---|
| [f82f07e] | 179 | intptr_t low = (intptr_t)str; | 
|---|
|  | 180 | intptr_t hi  = (intptr_t)ptr; | 
|---|
|  | 181 | ret = hi - low; | 
|---|
|  | 182 |  | 
|---|
|  | 183 | return ret; | 
|---|
|  | 184 | } | 
|---|
|  | 185 |  | 
|---|
| [419c434] | 186 | //----------------------------------------------------------------------------- | 
|---|
|  | 187 | // Print usage | 
|---|
| [a4e1b09] | 188 | static void printopt( FILE * out, int width, int max, char sn, const char * ln, const char * help ) { | 
|---|
| [f82f07e] | 189 | // check how wide we should be printing | 
|---|
|  | 190 | // this includes all options and the help message | 
|---|
| [419c434] | 191 | int hwidth = max - (11 + width); | 
|---|
| [a4e1b09] | 192 | if ( hwidth <= 0 ) hwidth = max; | 
|---|
| [419c434] | 193 |  | 
|---|
| [f82f07e] | 194 | // check which pieces we have | 
|---|
| [a4e1b09] | 195 | bool has_ln = ln && strcmp( "", ln ); | 
|---|
|  | 196 | bool has_help = help && strcmp( "", help ); | 
|---|
| [f82f07e] | 197 |  | 
|---|
|  | 198 | // print the small name if present | 
|---|
| [a4e1b09] | 199 | if ( sn != '\0') fprintf( out, "  -%c", sn ); | 
|---|
|  | 200 | else fprintf( out, "    " ); | 
|---|
| [f82f07e] | 201 |  | 
|---|
|  | 202 | // print a comma if we have both short and long names | 
|---|
| [a4e1b09] | 203 | if ( sn != '\0' && has_ln ) fprintf( out, ", " ); | 
|---|
|  | 204 | else fprintf( out, "  " ); | 
|---|
| [f82f07e] | 205 |  | 
|---|
|  | 206 | // print the long name if present | 
|---|
| [a4e1b09] | 207 | if ( has_ln ) fprintf( out, "--%-*s", width, ln ); | 
|---|
|  | 208 | else if ( has_help ) fprintf( out, "  %-*s", width, "" ); | 
|---|
| [f82f07e] | 209 |  | 
|---|
| [a4e1b09] | 210 | if ( has_help ) { | 
|---|
| [f82f07e] | 211 | // print the help | 
|---|
|  | 212 | // We need to wrap at the max width, and also indent newlines so everything is nice and pretty | 
|---|
|  | 213 |  | 
|---|
|  | 214 | // for each line to print | 
|---|
| [a4e1b09] | 215 | for () { | 
|---|
| [f82f07e] | 216 | //find out if there is a newline | 
|---|
| [a4e1b09] | 217 | int nextnl = next_newline( help ); | 
|---|
|  | 218 | int real = min( min( strlen( help ), hwidth ), nextnl ); | 
|---|
| [f82f07e] | 219 |  | 
|---|
| [a4e1b09] | 220 | fprintf( out, "   %.*s", real, help ); | 
|---|
|  | 221 | // printf( "%d %d\n", real, nextnl ); | 
|---|
| [f82f07e] | 222 | help += real; | 
|---|
| [a4e1b09] | 223 | if ( nextnl == real ) help++; | 
|---|
|  | 224 | if ('\0' == *help ) break; | 
|---|
|  | 225 | fprintf( out, "\n%*s", width + 8, "" ); | 
|---|
| [f82f07e] | 226 | } | 
|---|
| [419c434] | 227 | } | 
|---|
| [a4e1b09] | 228 | fprintf( out, "\n" ); | 
|---|
| [419c434] | 229 | } | 
|---|
|  | 230 |  | 
|---|
| [a4e1b09] | 231 | void print_args_usage( cfa_option options[], const size_t opt_count, const char * usage, bool error )  __attribute__ ((noreturn )) { | 
|---|
| [d1abc63c] | 232 | const array( cfa_option, opt_count ) & arr = (const array( cfa_option, opt_count ) &) *options; | 
|---|
| [a4e1b09] | 233 | usage( cfa_args_argv[0], arr, usage, error ? stderr : stdout ); | 
|---|
| [419c434] | 234 | } | 
|---|
|  | 235 |  | 
|---|
| [a4e1b09] | 236 | void print_args_usage( int , char * argv[], cfa_option options[], const size_t opt_count, const char * usage, bool error )  __attribute__ (( noreturn )) { | 
|---|
| [d1abc63c] | 237 | const array( cfa_option, opt_count ) & arr = (const array( cfa_option, opt_count ) &) *options; | 
|---|
| [a4e1b09] | 238 | usage( argv[0], arr, usage, error ? stderr : stdout ); | 
|---|
| [d1abc63c] | 239 | } | 
|---|
|  | 240 |  | 
|---|
| [54f70c6] | 241 | forall([N]) | 
|---|
|  | 242 | void print_args_usage( const array(cfa_option, N ) & options, const char * usage, bool error ) { | 
|---|
|  | 243 | usage( cfa_args_argv[0], options, usage, error ? stderr : stdout ); | 
|---|
|  | 244 | } | 
|---|
| [d1abc63c] | 245 |  | 
|---|
| [54f70c6] | 246 | forall([N]) | 
|---|
|  | 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 ); | 
|---|
| [419c434] | 249 | } | 
|---|
|  | 250 |  | 
|---|
| [d1abc63c] | 251 | forall([N]) | 
|---|
| [a4e1b09] | 252 | static void usage( char * cmd, const array( cfa_option, N ) & options, const char * help, FILE * out ) __attribute__(( noreturn )) { | 
|---|
| [419c434] | 253 | int width = 0; | 
|---|
|  | 254 | { | 
|---|
| [a4e1b09] | 255 | for ( i; N ) { | 
|---|
|  | 256 | if ( options[i].long_name ) { | 
|---|
|  | 257 | int w = strlen( options[i].long_name ); | 
|---|
|  | 258 | if ( w > width ) width = w; | 
|---|
| [419c434] | 259 | } | 
|---|
|  | 260 | } | 
|---|
|  | 261 | } | 
|---|
|  | 262 |  | 
|---|
|  | 263 | int max_width = 1_000_000; | 
|---|
| [a4e1b09] | 264 | int outfd = fileno( out ); | 
|---|
|  | 265 | if ( isatty( outfd ) ) { | 
|---|
| [3f1d9b5] | 266 | struct winsize size; | 
|---|
| [a4e1b09] | 267 | int ret = ioctl( outfd, TIOCGWINSZ, &size ); | 
|---|
|  | 268 | if ( ret < 0 ) abort( "ioctl error: (%d) %s\n", (int)errno, strerror( errno) ); | 
|---|
| [3f1d9b5] | 269 | max_width = size.ws_col; | 
|---|
|  | 270 | } | 
|---|
|  | 271 |  | 
|---|
| [a4e1b09] | 272 | fprintf( out, "Usage:\n  %s %s\n", cmd, help ); | 
|---|
| [7f389a5c] | 273 |  | 
|---|
| [a4e1b09] | 274 | for ( i; N ) { | 
|---|
|  | 275 | printopt( out, width, max_width, options[i].short_name, options[i].long_name, options[i].help ); | 
|---|
| [7f389a5c] | 276 | } | 
|---|
| [a4e1b09] | 277 | fprintf( out, "  -%c, --%-*s   %s\n", 'h', width, "help", "print this help message" ); | 
|---|
|  | 278 | exit( out == stdout ? 0 : 1 ); | 
|---|
| [7f389a5c] | 279 | } | 
|---|
|  | 280 |  | 
|---|
| [419c434] | 281 | //----------------------------------------------------------------------------- | 
|---|
|  | 282 | // Typed argument parsing | 
|---|
| [a4e1b09] | 283 | bool parse_yesno( const char * arg, bool & value ) { | 
|---|
|  | 284 | if ( strcmp( arg, "yes" ) == 0 ) { | 
|---|
| [7f389a5c] | 285 | value = true; | 
|---|
|  | 286 | return true; | 
|---|
|  | 287 | } | 
|---|
| [a4e1b09] | 288 | if ( strcmp( arg, "Y" ) == 0 ) { | 
|---|
| [e07187d] | 289 | value = true; | 
|---|
|  | 290 | return true; | 
|---|
|  | 291 | } | 
|---|
| [a4e1b09] | 292 | if ( strcmp( arg, "y" ) == 0 ) { | 
|---|
| [e07187d] | 293 | value = true; | 
|---|
|  | 294 | return true; | 
|---|
|  | 295 | } | 
|---|
| [a4e1b09] | 296 | if ( strcmp( arg, "no" ) == 0 ) { | 
|---|
| [7f389a5c] | 297 | value = false; | 
|---|
|  | 298 | return true; | 
|---|
|  | 299 | } | 
|---|
| [a4e1b09] | 300 | if ( strcmp( arg, "N" ) == 0 ) { | 
|---|
| [e07187d] | 301 | value = false; | 
|---|
|  | 302 | return true; | 
|---|
|  | 303 | } | 
|---|
| [a4e1b09] | 304 | if ( strcmp( arg, "n" ) == 0 ) { | 
|---|
| [e07187d] | 305 | value = false; | 
|---|
|  | 306 | return true; | 
|---|
|  | 307 | } | 
|---|
| [7f389a5c] | 308 | return false; | 
|---|
|  | 309 | } | 
|---|
|  | 310 |  | 
|---|
| [a4e1b09] | 311 | bool parse_truefalse( const char * arg, bool & value ) { | 
|---|
|  | 312 | if ( strcmp( arg, "true" ) == 0 ) { | 
|---|
| [d411769c] | 313 | value = true; | 
|---|
|  | 314 | return true; | 
|---|
|  | 315 | } | 
|---|
| [a4e1b09] | 316 | if ( strcmp( arg, "false" )  == 0 ) { | 
|---|
| [d411769c] | 317 | value = false; | 
|---|
|  | 318 | return true; | 
|---|
|  | 319 | } | 
|---|
|  | 320 | return false; | 
|---|
|  | 321 | } | 
|---|
|  | 322 |  | 
|---|
| [a4e1b09] | 323 | bool parse_settrue ( const char *, bool & value ) { | 
|---|
| [7f389a5c] | 324 | value = true; | 
|---|
|  | 325 | return true; | 
|---|
|  | 326 | } | 
|---|
|  | 327 |  | 
|---|
| [a4e1b09] | 328 | bool parse_setfalse( const char *, bool & value )  { | 
|---|
| [7f389a5c] | 329 | value = false; | 
|---|
|  | 330 | return true; | 
|---|
|  | 331 | } | 
|---|
|  | 332 |  | 
|---|
| [a4e1b09] | 333 | bool parse( const char * arg, const char * & value ) { | 
|---|
| [7f389a5c] | 334 | value = arg; | 
|---|
|  | 335 | return true; | 
|---|
|  | 336 | } | 
|---|
|  | 337 |  | 
|---|
| [a4e1b09] | 338 | bool parse( const char * arg, int & value ) { | 
|---|
| [7f6e9eb] | 339 | char * end; | 
|---|
| [affb51b] | 340 |  | 
|---|
|  | 341 | errno = 0; | 
|---|
| [a4e1b09] | 342 | long long int r = strtoll( arg, &end, 0 ); | 
|---|
|  | 343 | if ( errno ) return false; | 
|---|
|  | 344 | if (*end != '\0') return false; | 
|---|
|  | 345 | if ( r > (int)MAX ) return false; | 
|---|
|  | 346 | if ( r < (int)MIN ) return false; | 
|---|
| [7f6e9eb] | 347 | value = r; | 
|---|
|  | 348 | return true; | 
|---|
|  | 349 | } | 
|---|
|  | 350 |  | 
|---|
| [a4e1b09] | 351 | static unsigned long long int strict_strtoull( const char * arg, int base ) { | 
|---|
| [affb51b] | 352 | errno = 0; | 
|---|
|  | 353 | { | 
|---|
|  | 354 | const char * in = arg; | 
|---|
| [a4e1b09] | 355 | for () { | 
|---|
|  | 356 | if ( '\0' == *in ) { | 
|---|
| [affb51b] | 357 | errno = EINVAL; | 
|---|
|  | 358 | return 0; | 
|---|
|  | 359 | } | 
|---|
| [a4e1b09] | 360 | if ( ! isspace(*in )) break; | 
|---|
| [affb51b] | 361 | in++; | 
|---|
|  | 362 | } | 
|---|
| [a4e1b09] | 363 | if ( ! isdigit(*in )) { | 
|---|
| [affb51b] | 364 | errno = EINVAL; | 
|---|
|  | 365 | return 0; | 
|---|
|  | 366 | } | 
|---|
|  | 367 | } | 
|---|
|  | 368 | *char end; | 
|---|
| [a4e1b09] | 369 | unsigned long long int r = strtoull( arg, &end, base ); | 
|---|
|  | 370 | if (*end != '\0') errno = EINVAL; | 
|---|
|  | 371 | if ( errno ) return 0; | 
|---|
| [affb51b] | 372 | return r; | 
|---|
|  | 373 | } | 
|---|
|  | 374 |  | 
|---|
| [a4e1b09] | 375 | bool parse( const char * arg, unsigned & value ) { | 
|---|
|  | 376 | unsigned long long int r = strict_strtoull( arg, 0 ); | 
|---|
|  | 377 | if ( errno ) return false; | 
|---|
|  | 378 | if ( r > (unsigned)MAX ) return false; | 
|---|
| [53e4562] | 379 | value = r; | 
|---|
|  | 380 | return true; | 
|---|
|  | 381 | } | 
|---|
|  | 382 |  | 
|---|
| [a4e1b09] | 383 | bool parse( const char * arg, unsigned long & value ) { | 
|---|
|  | 384 | unsigned long long int r = strict_strtoull( arg, 0 ); | 
|---|
|  | 385 | if ( errno ) return false; | 
|---|
|  | 386 | if ( r > (unsigned long)MAX ) return false; | 
|---|
| [53e4562] | 387 | value = r; | 
|---|
|  | 388 | return true; | 
|---|
|  | 389 | } | 
|---|
|  | 390 |  | 
|---|
| [a4e1b09] | 391 | bool parse( const char * arg, unsigned long long & value ) { | 
|---|
|  | 392 | unsigned long long int r = strict_strtoull( arg, 0 ); | 
|---|
|  | 393 | if ( errno ) return false; | 
|---|
|  | 394 | if ( r > (unsigned long long)MAX ) return false; | 
|---|
| [affb51b] | 395 | value = r; | 
|---|
|  | 396 | return true; | 
|---|
| [56e8cb3] | 397 | } | 
|---|
|  | 398 |  | 
|---|
| [a4e1b09] | 399 | bool parse( const char * arg, double & value ) { | 
|---|
| [7f389a5c] | 400 | char * end; | 
|---|
| [a4e1b09] | 401 | double r = strtod( arg, &end ); | 
|---|
|  | 402 | if ( *end != '\0') return false; | 
|---|
| [7f389a5c] | 403 | value = r; | 
|---|
|  | 404 | return true; | 
|---|
| [56e8cb3] | 405 | } | 
|---|