1/* vi: set sw=4 ts=4: */ 2/* 3 * Utility routines. 4 * 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 * 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8 */ 9 10#include "libbb.h" 11 12/* On exit: errno = 0 only if there was non-empty, '\0' terminated value 13 * errno = EINVAL if value was not '\0' terminated, but othervise ok 14 * Return value is still valid, caller should just check whether end[0] 15 * is a valid terminating char for particular case. OTOH, if caller 16 * requires '\0' terminated input, [s]he can just check errno == 0. 17 * errno = ERANGE if value had alphanumeric terminating char ("1234abcg"). 18 * errno = ERANGE if value is out of range, missing, etc. 19 * errno = ERANGE if value had minus sign for strtouXX (even "-0" is not ok ) 20 * return value is all-ones in this case. 21 */ 22 23static unsigned long long ret_ERANGE(void) 24{ 25 errno = ERANGE; /* this ain't as small as it looks (on glibc) */ 26 return ULLONG_MAX; 27} 28 29static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr) 30{ 31 if (endp) *endp = endptr; 32 33 /* Check for the weird "feature": 34 * a "-" string is apparently a valid "number" for strto[u]l[l]! 35 * It returns zero and errno is 0! :( */ 36 if (endptr[-1] == '-') 37 return ret_ERANGE(); 38 39 /* errno is already set to ERANGE by strtoXXX if value overflowed */ 40 if (endptr[0]) { 41 /* "1234abcg" or out-of-range? */ 42 if (isalnum(endptr[0]) || errno) 43 return ret_ERANGE(); 44 /* good number, just suspicious terminator */ 45 errno = EINVAL; 46 } 47 return v; 48} 49 50 51unsigned long long bb_strtoull(const char *arg, char **endp, int base) 52{ 53 unsigned long long v; 54 char *endptr; 55 56 /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */ 57 /* I don't think that this is right. Preventing this... */ 58 if (!isalnum(arg[0])) return ret_ERANGE(); 59 60 /* not 100% correct for lib func, but convenient for the caller */ 61 errno = 0; 62 v = strtoull(arg, &endptr, base); 63 return handle_errors(v, endp, endptr); 64} 65 66long long bb_strtoll(const char *arg, char **endp, int base) 67{ 68 unsigned long long v; 69 char *endptr; 70 71 if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE(); 72 errno = 0; 73 v = strtoll(arg, &endptr, base); 74 return handle_errors(v, endp, endptr); 75} 76 77#if ULONG_MAX != ULLONG_MAX 78unsigned long bb_strtoul(const char *arg, char **endp, int base) 79{ 80 unsigned long v; 81 char *endptr; 82 83 if (!isalnum(arg[0])) return ret_ERANGE(); 84 errno = 0; 85 v = strtoul(arg, &endptr, base); 86 return handle_errors(v, endp, endptr); 87} 88 89long bb_strtol(const char *arg, char **endp, int base) 90{ 91 long v; 92 char *endptr; 93 94 if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE(); 95 errno = 0; 96 v = strtol(arg, &endptr, base); 97 return handle_errors(v, endp, endptr); 98} 99#endif 100 101#if UINT_MAX != ULONG_MAX 102unsigned bb_strtou(const char *arg, char **endp, int base) 103{ 104 unsigned long v; 105 char *endptr; 106 107 if (!isalnum(arg[0])) return ret_ERANGE(); 108 errno = 0; 109 v = strtoul(arg, &endptr, base); 110 if (v > UINT_MAX) return ret_ERANGE(); 111 return handle_errors(v, endp, endptr); 112} 113 114int bb_strtoi(const char *arg, char **endp, int base) 115{ 116 long v; 117 char *endptr; 118 119 if (arg[0] != '-' && !isalnum(arg[0])) return ret_ERANGE(); 120 errno = 0; 121 v = strtol(arg, &endptr, base); 122 if (v > INT_MAX) return ret_ERANGE(); 123 if (v < INT_MIN) return ret_ERANGE(); 124 return handle_errors(v, endp, endptr); 125} 126#endif 127 128/* Floating point */ 129