]> git.ozlabs.org Git - ccan/blob - ccan/opt/helpers.c
opt/helpers: fix out-of-range check in opt_set_floatval()
[ccan] / ccan / opt / helpers.c
1 /* Licensed under GPLv2+ - see LICENSE file for details */
2 #include <ccan/opt/opt.h>
3 #include <ccan/cast/cast.h>
4 #include <inttypes.h>
5 #include <string.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <errno.h>
9 #include <stdio.h>
10 #include <limits.h>
11 #include "private.h"
12 #include <float.h>
13
14 /* Upper bound to sprintf this simple type?  Each 3 bits < 1 digit. */
15 #define CHAR_SIZE(type) (((sizeof(type)*CHAR_BIT + 2) / 3) + 1)
16
17 /* FIXME: asprintf module? */
18 static char *arg_bad(const char *fmt, const char *arg)
19 {
20         char *str = malloc(strlen(fmt) + strlen(arg));
21         sprintf(str, fmt, arg);
22         return str;
23 }
24
25 char *opt_set_bool(bool *b)
26 {
27         *b = true;
28         return NULL;
29 }
30
31 char *opt_set_invbool(bool *b)
32 {
33         *b = false;
34         return NULL;
35 }
36
37 char *opt_set_bool_arg(const char *arg, bool *b)
38 {
39         if (!strcasecmp(arg, "yes") || !strcasecmp(arg, "true"))
40                 return opt_set_bool(b);
41         if (!strcasecmp(arg, "no") || !strcasecmp(arg, "false"))
42                 return opt_set_invbool(b);
43
44         return opt_invalid_argument(arg);
45 }
46
47 char *opt_set_invbool_arg(const char *arg, bool *b)
48 {
49         char *err = opt_set_bool_arg(arg, b);
50
51         if (!err)
52                 *b = !*b;
53         return err;
54 }
55
56 /* Set a char *. */
57 char *opt_set_charp(const char *arg, char **p)
58 {
59         *p = cast_const(char *, arg);
60         return NULL;
61 }
62
63 /* Set an integer value, various forms.
64    FIXME: set to 1 on arg == NULL ? */
65 char *opt_set_intval(const char *arg, int *i)
66 {
67         long l;
68         char *err = opt_set_longval(arg, &l);
69
70         if (err)
71                 return err;
72         *i = l;
73         /* Beware truncation, but don't generate untestable code. */
74         if (sizeof(*i) != sizeof(l) && *i != l)
75                 return arg_bad("value '%s' does not fit into an integer", arg);
76         return err;
77 }
78
79 char *opt_set_uintval(const char *arg, unsigned int *ui)
80 {
81         int i;
82         char *err = opt_set_intval(arg, &i);
83
84         if (err)
85                 return err;
86         if (i < 0)
87                 return arg_bad("'%s' is negative but destination is unsigned", arg);
88         *ui = i;
89         return NULL;
90 }
91
92 char *opt_set_longval(const char *arg, long *l)
93 {
94         char *endp;
95
96         /* This is how the manpage says to do it.  Yech. */
97         errno = 0;
98         *l = strtol(arg, &endp, 0);
99         if (*endp || !arg[0])
100                 return arg_bad("'%s' is not a number", arg);
101         if (errno)
102                 return arg_bad("'%s' is out of range", arg);
103         return NULL;
104 }
105
106 char *opt_set_ulongval(const char *arg, unsigned long *ul)
107 {
108         long int l;
109         char *err;
110
111         err = opt_set_longval(arg, &l);
112         if (err)
113                 return err;
114         *ul = l;
115         if (l < 0)
116                 return arg_bad("'%s' is negative but destination is unsigned", arg);
117         return NULL;
118 }
119
120 char *opt_set_floatval(const char *arg, float *f)
121 {
122         double d;
123         char *err;
124
125         err = opt_set_doubleval(arg, &d);
126         if (err)
127                 return err;
128
129         *f = d;
130
131         /*allow true infinity via --foo=INF, while avoiding isinf() from math.h
132           because it wasn't standard 25 years ago.*/
133         double inf = 1e300 * 1e300; /*direct 1e600 annoys -Woverflow*/
134         if ((d > FLT_MAX || d < -FLT_MAX) && d != inf && d != -inf)
135                 return arg_bad("'%s' is out of range for a 32 bit float", arg);
136         if (d != 0 && *f == 0)
137                 return arg_bad("'%s' is out of range (truncated to zero)", arg);
138
139         return NULL;
140 }
141
142 void opt_show_floatval(char buf[OPT_SHOW_LEN], const float *f)
143 {
144         double d = *f;
145         opt_show_doubleval(buf, &d);
146 }
147
148 char *opt_set_doubleval(const char *arg, double *d)
149 {
150         char *endp;
151
152         /* This is how the manpage says to do it.  Yech. */
153         errno = 0;
154         /* Don't assume strtof */
155         *d = strtod(arg, &endp);
156         if (*endp || !arg[0])
157                 return arg_bad("'%s' is not a number", arg);
158         if (errno)
159                 return arg_bad("'%s' is out of range", arg);
160
161         return NULL;
162 }
163
164 void opt_show_doubleval(char buf[OPT_SHOW_LEN], const double *d)
165 {
166         snprintf(buf, OPT_SHOW_LEN, "%f", *d);
167 }
168
169 char *opt_inc_intval(int *i)
170 {
171         (*i)++;
172         return NULL;
173 }
174
175 char *opt_dec_intval(int *i)
176 {
177         (*i)--;
178         return NULL;
179 }
180
181 /* Display version string. */
182 char *opt_version_and_exit(const char *version)
183 {
184         printf("%s\n", version);
185         /* Don't have valgrind complain! */
186         opt_free_table();
187         exit(0);
188 }
189
190 char *opt_usage_and_exit(const char *extra)
191 {
192         char *usage = opt_usage(opt_argv0, extra);
193         printf("%s", usage);
194         /* Don't have valgrind complain! */
195         opt_alloc.free(usage);
196         opt_free_table();
197         exit(0);
198 }
199
200 void opt_show_bool(char buf[OPT_SHOW_LEN], const bool *b)
201 {
202         strncpy(buf, *b ? "true" : "false", OPT_SHOW_LEN);
203 }
204
205 void opt_show_invbool(char buf[OPT_SHOW_LEN], const bool *b)
206 {
207         strncpy(buf, *b ? "false" : "true", OPT_SHOW_LEN);
208 }
209
210 void opt_show_charp(char buf[OPT_SHOW_LEN], char *const *p)
211 {
212         if (*p){
213                 size_t len = strlen(*p);
214                 buf[0] = '"';
215                 if (len > OPT_SHOW_LEN - 2)
216                         len = OPT_SHOW_LEN - 2;
217                 strncpy(buf+1, *p, len);
218                 buf[1+len] = '"';
219                 if (len < OPT_SHOW_LEN - 2)
220                         buf[2+len] = '\0';
221         }
222         else {
223                 strncpy(buf, "(nil)", OPT_SHOW_LEN);
224         }
225 }
226
227 /* Show an integer value, various forms. */
228 void opt_show_intval(char buf[OPT_SHOW_LEN], const int *i)
229 {
230         snprintf(buf, OPT_SHOW_LEN, "%i", *i);
231 }
232
233 void opt_show_uintval(char buf[OPT_SHOW_LEN], const unsigned int *ui)
234 {
235         snprintf(buf, OPT_SHOW_LEN, "%u", *ui);
236 }
237
238 void opt_show_longval(char buf[OPT_SHOW_LEN], const long *l)
239 {
240         snprintf(buf, OPT_SHOW_LEN, "%li", *l);
241 }
242
243 void opt_show_ulongval(char buf[OPT_SHOW_LEN], const unsigned long *ul)
244 {
245         snprintf(buf, OPT_SHOW_LEN, "%lu", *ul);
246 }
247
248 /* a helper function that multiplies out an argument's kMGTPE suffix in the
249  * long long int range, and perform checks common to all integer destinations.
250  *
251  * The base will be either 1000 or 1024, corresponding with the '_si' and
252  * '_bi' functions.
253  */
254
255 static char *set_llong_with_suffix(const char *arg, long long *ll,
256                                    const long long base)
257 {
258         char *endp;
259         if (!arg[0]){
260                 *ll = 0;
261                 return arg_bad("'%s' (an empty string) is not a number", arg);
262         }
263         errno = 0;
264         *ll = strtoll(arg, &endp, 0);
265         if (errno)
266                 return arg_bad("'%s' is out of range", arg);
267         if (*endp){
268                 /*The string continues with non-digits.  If there is just one
269                   letter and it is a known multiplier suffix, use it.*/
270                 if (endp[1])
271                         return arg_bad("'%s' is not a number (suffix too long)", arg);
272                 long long mul;
273                 switch(*endp){
274                 case 'K':
275                 case 'k':
276                         mul = base;
277                         break;
278                 case 'M':
279                 case 'm':
280                         mul = base * base;
281                         break;
282                 case 'G':
283                 case 'g':
284                         mul = base * base * base;
285                         break;
286                 case 'T':
287                 case 't':
288                         mul = base * base * base * base;
289                         break;
290                 case 'P':
291                         mul = base * base * base * base * base;
292                         break;
293                 case 'E':
294                         mul = base * base * base * base * base * base;
295                         break;
296                 /* This is as far as we can go in 64 bits ('E' is 2 ^ 60) */
297                 default:
298                         return arg_bad("'%s' is not a number (unknown suffix)",
299                                        arg);
300                 }
301                 if (*ll > LLONG_MAX / mul || *ll < LLONG_MIN / mul)
302                         return arg_bad("'%s' is out of range", arg);
303                 *ll *= mul;
304         }
305         return NULL;
306 }
307
308 /* Middle layer helpers that perform bounds checks for specific target sizes
309  * and signednesses.
310  */
311 static char * set_ulonglong_with_suffix(const char *arg, unsigned long long *ull,
312                                         const long base)
313 {
314         long long ll;
315         char *err = set_llong_with_suffix(arg, &ll, base);
316         if (err != NULL)
317                 return err;
318         if (ll < 0)
319                 return arg_bad("'%s' is negative but destination is unsigned", arg);
320         *ull = ll;
321         return NULL;
322 }
323
324 static char * set_long_with_suffix(const char *arg, long *l, const long base)
325 {
326         long long ll;
327         char *err = set_llong_with_suffix(arg, &ll, base);
328         if (err != NULL) /*an error*/
329                 return err;
330
331         *l = ll;
332         /* Beware truncation, but don't generate untestable code. */
333         if (sizeof(*l) != sizeof(ll) && *l != ll)
334                 return arg_bad("value '%s' does not fit into a long", arg);
335         return NULL;
336 }
337
338 static char * set_ulong_with_suffix(const char *arg, unsigned long *ul, const long base)
339 {
340         long long ll;
341         char *err = set_llong_with_suffix(arg, &ll, base);
342         if (err != NULL)
343                 return err;
344         if (ll < 0)
345                 return arg_bad("'%s' is negative but destination is unsigned", arg);
346         *ul = ll;
347         /* Beware truncation, but don't generate untestable code. */
348         if (sizeof(*ul) != sizeof(ll) && *ul != ll)
349                 return arg_bad("value '%s' does not fit into an unsigned long", arg);
350         return NULL;
351 }
352
353 static char * set_int_with_suffix(const char *arg, int *i, const long base)
354 {
355         long long ll;
356         char *err = set_llong_with_suffix(arg, &ll, base);
357         if (err != NULL) /*an error*/
358                 return err;
359
360         *i = ll;
361         if (*i != ll)
362                 return arg_bad("value '%s' does not fit into an int", arg);
363         return NULL;
364 }
365
366 static char * set_uint_with_suffix(const char *arg, unsigned int *u, const long base)
367 {
368         long long ll;
369         char *err = set_llong_with_suffix(arg, &ll, base);
370         if (err != NULL)
371                 return err;
372         if (ll < 0)
373                 return arg_bad("'%s' is negative but destination is unsigned", arg);
374         *u = ll;
375         if (*u != ll)
376                 return arg_bad("value '%s' does not fit into an unsigned int", arg);
377         return NULL;
378 }
379
380 /*Set an integer, with decimal or binary suffixes.
381   The accepted suffixes are k/K, M/m, G/g, T, P, E.
382
383   The *_bi functions multiply the numeric value by a power of 1024, while the
384   *_si functions multiply by a power of 1000.
385  */
386
387 char * opt_set_ulonglongval_bi(const char *arg, unsigned long long *ll)
388 {
389         return set_ulonglong_with_suffix(arg, ll, 1024);
390 }
391
392 char * opt_set_ulonglongval_si(const char *arg, unsigned long long *ll)
393 {
394         return set_ulonglong_with_suffix(arg, ll, 1000);
395 }
396
397 char * opt_set_longlongval_bi(const char *arg, long long *ll)
398 {
399         return set_llong_with_suffix(arg, ll, 1024);
400 }
401
402 char * opt_set_longlongval_si(const char *arg, long long *ll)
403 {
404         return set_llong_with_suffix(arg, ll, 1000);
405 }
406
407 char * opt_set_longval_bi(const char *arg, long *l)
408 {
409         return set_long_with_suffix(arg, l, 1024);
410 }
411
412 char * opt_set_longval_si(const char *arg, long *l)
413 {
414         return set_long_with_suffix(arg, l, 1000);
415 }
416
417 char * opt_set_ulongval_bi(const char *arg, unsigned long *ul)
418 {
419         return set_ulong_with_suffix(arg, ul, 1024);
420 }
421
422 char * opt_set_ulongval_si(const char *arg, unsigned long *ul)
423 {
424         return set_ulong_with_suffix(arg, ul, 1000);
425 }
426
427 char * opt_set_intval_bi(const char *arg, int *i)
428 {
429         return set_int_with_suffix(arg, i, 1024);
430 }
431
432 char * opt_set_intval_si(const char *arg, int *i)
433 {
434         return set_int_with_suffix(arg, i, 1000);
435 }
436
437 char * opt_set_uintval_bi(const char *arg, unsigned int *u)
438 {
439         return set_uint_with_suffix(arg, u, 1024);
440 }
441
442 char * opt_set_uintval_si(const char *arg, unsigned int *u)
443 {
444         return set_uint_with_suffix(arg, u, 1000);
445 }
446
447 /*static helpers for showing values with kMGTPE suffixes.  In this case there
448   are separate but essentially identical functions for signed and unsigned
449   values, so that unsigned values greater than LLONG_MAX get suffixes.
450  */
451 static void show_llong_with_suffix(char buf[OPT_SHOW_LEN], long long ll,
452                                     const long long base)
453 {
454         const char *suffixes = "kMGTPE";
455         int i;
456         if (ll == 0){
457                 /*zero is special because everything divides it (you'd get "0E")*/
458                 snprintf(buf, OPT_SHOW_LEN, "0");
459                 return;
460         }
461         for (i = 0; i < strlen(suffixes); i++){
462                 long long tmp = ll / base;
463                 if (tmp * base != ll)
464                         break;
465                 ll = tmp;
466         }
467         if (i == 0)
468                 snprintf(buf, OPT_SHOW_LEN, "%"PRId64, (int64_t)ll);
469         else
470                 snprintf(buf, OPT_SHOW_LEN, "%"PRId64"%c", (int64_t)ll, suffixes[i - 1]);
471 }
472
473 static void show_ullong_with_suffix(char buf[OPT_SHOW_LEN], unsigned long long ull,
474                                     const unsigned base)
475 {
476         const char *suffixes = "kMGTPE";
477         int i;
478         if (ull == 0){
479                 /*zero is special because everything divides it (you'd get "0E")*/
480                 snprintf(buf, OPT_SHOW_LEN, "0");
481                 return;
482         }
483         for (i = 0; i < strlen(suffixes); i++){
484                 unsigned long long tmp = ull / base;
485                 if (tmp * base != ull)
486                         break;
487                 ull = tmp;
488         }
489         if (i == 0)
490                 snprintf(buf, OPT_SHOW_LEN, "%"PRIu64, (uint64_t)ull);
491         else
492                 snprintf(buf, OPT_SHOW_LEN, "%"PRIu64"%c", (uint64_t)ull, suffixes[i - 1]);
493 }
494
495 /* _bi, signed */
496 void opt_show_intval_bi(char buf[OPT_SHOW_LEN], const int *x)
497 {
498         show_llong_with_suffix(buf, *x, 1024);
499 }
500
501 void opt_show_longval_bi(char buf[OPT_SHOW_LEN], const long *x)
502 {
503         show_llong_with_suffix(buf, *x, 1024);
504 }
505
506 void opt_show_longlongval_bi(char buf[OPT_SHOW_LEN], const long long *x)
507 {
508         show_llong_with_suffix(buf, *x, 1024);
509 }
510
511 /* _bi, unsigned */
512 void opt_show_uintval_bi(char buf[OPT_SHOW_LEN], const unsigned int *x)
513 {
514         show_ullong_with_suffix(buf, (unsigned long long) *x, 1024);
515 }
516
517 void opt_show_ulongval_bi(char buf[OPT_SHOW_LEN], const unsigned long *x)
518 {
519         show_ullong_with_suffix(buf, (unsigned long long) *x, 1024);
520 }
521
522 void opt_show_ulonglongval_bi(char buf[OPT_SHOW_LEN], const unsigned long long *x)
523 {
524         show_ullong_with_suffix(buf, (unsigned long long) *x, 1024);
525 }
526
527 /* _si, signed */
528 void opt_show_intval_si(char buf[OPT_SHOW_LEN], const int *x)
529 {
530         show_llong_with_suffix(buf, (long long) *x, 1000);
531 }
532
533 void opt_show_longval_si(char buf[OPT_SHOW_LEN], const long *x)
534 {
535         show_llong_with_suffix(buf, (long long) *x, 1000);
536 }
537
538 void opt_show_longlongval_si(char buf[OPT_SHOW_LEN], const long long *x)
539 {
540         show_llong_with_suffix(buf, *x, 1000);
541 }
542
543 /* _si, unsigned */
544 void opt_show_uintval_si(char buf[OPT_SHOW_LEN], const unsigned int *x)
545 {
546         show_ullong_with_suffix(buf, (unsigned long long) *x, 1000);
547 }
548
549 void opt_show_ulongval_si(char buf[OPT_SHOW_LEN], const unsigned long *x)
550 {
551         show_ullong_with_suffix(buf, (unsigned long long) *x, 1000);
552 }
553
554 void opt_show_ulonglongval_si(char buf[OPT_SHOW_LEN], const unsigned long long *x)
555 {
556         show_ullong_with_suffix(buf, (unsigned long long) *x, 1000);
557 }
558