1/* 2You need to define the following (example): 3 4#define type long 5#define xstrtou(rest) xstrtoul##rest 6#define xstrto(rest) xstrtol##rest 7#define xatou(rest) xatoul##rest 8#define xato(rest) xatol##rest 9#define XSTR_UTYPE_MAX ULONG_MAX 10#define XSTR_TYPE_MAX LONG_MAX 11#define XSTR_TYPE_MIN LONG_MIN 12#define XSTR_STRTOU strtoul 13*/ 14 15unsigned type xstrtou(_range_sfx)(const char *numstr, int base, 16 unsigned type lower, 17 unsigned type upper, 18 const struct suffix_mult *suffixes) 19{ 20 unsigned type r; 21 int old_errno; 22 char *e; 23 24 /* Disallow '-' and any leading whitespace. Speed isn't critical here 25 * since we're parsing commandline args. So make sure we get the 26 * actual isspace function rather than a lnumstrer macro implementaion. */ 27 if (*numstr == '-' || *numstr == '+' || (isspace)(*numstr)) 28 goto inval; 29 30 /* Since this is a lib function, we're not allowed to reset errno to 0. 31 * Doing so could break an app that is deferring checking of errno. 32 * So, save the old value so that we can restore it if successful. */ 33 old_errno = errno; 34 errno = 0; 35 r = XSTR_STRTOU(numstr, &e, base); 36 /* Do the initial validity check. Note: The standards do not 37 * guarantee that errno is set if no digits were found. So we 38 * must test for this explicitly. */ 39 if (errno || numstr == e) 40 goto inval; /* error / no digits / illegal trailing chars */ 41 42 errno = old_errno; /* Ok. So restore errno. */ 43 44 /* Do optional suffix parsing. Allow 'empty' suffix tables. 45 * Note that we also allow nul suffixes with associated multipliers, 46 * to allow for scaling of the numstr by some default multiplier. */ 47 if (suffixes) { 48 while (suffixes->mult) { 49 if (strcmp(suffixes->suffix, e) == 0) { 50 if (XSTR_UTYPE_MAX / suffixes->mult < r) 51 goto range; /* overflow! */ 52 r *= suffixes->mult; 53 goto chk_range; 54 } 55 ++suffixes; 56 } 57 } 58 59 /* Note: trailing space is an error. 60 It would be easy enough to allow though if desired. */ 61 if (*e) 62 goto inval; 63 chk_range: 64 /* Finally, check for range limits. */ 65 if (r >= lower && r <= upper) 66 return r; 67 range: 68 bb_error_msg_and_die("number %s is not in %llu..%llu range", 69 numstr, (unsigned long long)lower, 70 (unsigned long long)upper); 71 inval: 72 bb_error_msg_and_die("invalid number '%s'", numstr); 73} 74 75unsigned type xstrtou(_range)(const char *numstr, int base, 76 unsigned type lower, 77 unsigned type upper) 78{ 79 return xstrtou(_range_sfx)(numstr, base, lower, upper, NULL); 80} 81 82unsigned type xstrtou(_sfx)(const char *numstr, int base, 83 const struct suffix_mult *suffixes) 84{ 85 return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, suffixes); 86} 87 88unsigned type xstrtou()(const char *numstr, int base) 89{ 90 return xstrtou(_range_sfx)(numstr, base, 0, XSTR_UTYPE_MAX, NULL); 91} 92 93unsigned type xatou(_range_sfx)(const char *numstr, 94 unsigned type lower, 95 unsigned type upper, 96 const struct suffix_mult *suffixes) 97{ 98 return xstrtou(_range_sfx)(numstr, 10, lower, upper, suffixes); 99} 100 101unsigned type xatou(_range)(const char *numstr, 102 unsigned type lower, 103 unsigned type upper) 104{ 105 return xstrtou(_range_sfx)(numstr, 10, lower, upper, NULL); 106} 107 108unsigned type xatou(_sfx)(const char *numstr, 109 const struct suffix_mult *suffixes) 110{ 111 return xstrtou(_range_sfx)(numstr, 10, 0, XSTR_UTYPE_MAX, suffixes); 112} 113 114unsigned type xatou()(const char *numstr) 115{ 116 return xatou(_sfx)(numstr, NULL); 117} 118 119/* Signed ones */ 120 121type xstrto(_range_sfx)(const char *numstr, int base, 122 type lower, 123 type upper, 124 const struct suffix_mult *suffixes) 125{ 126 unsigned type u = XSTR_TYPE_MAX; 127 type r; 128 const char *p = numstr; 129 130 if (p[0] == '-') { 131 ++p; 132 ++u; /* two's complement */ 133 } 134 135 r = xstrtou(_range_sfx)(p, base, 0, u, suffixes); 136 137 if (*numstr == '-') { 138 r = -r; 139 } 140 141 if (r < lower || r > upper) { 142 bb_error_msg_and_die("number %s is not in %lld..%lld range", 143 numstr, (long long)lower, (long long)upper); 144 } 145 146 return r; 147} 148 149type xstrto(_range)(const char *numstr, int base, type lower, type upper) 150{ 151 return xstrto(_range_sfx)(numstr, base, lower, upper, NULL); 152} 153 154type xato(_range_sfx)(const char *numstr, 155 type lower, 156 type upper, 157 const struct suffix_mult *suffixes) 158{ 159 return xstrto(_range_sfx)(numstr, 10, lower, upper, suffixes); 160} 161 162type xato(_range)(const char *numstr, type lower, type upper) 163{ 164 return xstrto(_range_sfx)(numstr, 10, lower, upper, NULL); 165} 166 167type xato(_sfx)(const char *numstr, const struct suffix_mult *suffixes) 168{ 169 return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, suffixes); 170} 171 172type xato()(const char *numstr) 173{ 174 return xstrto(_range_sfx)(numstr, 10, XSTR_TYPE_MIN, XSTR_TYPE_MAX, NULL); 175} 176 177#undef type 178#undef xstrtou 179#undef xstrto 180#undef xatou 181#undef xato 182#undef XSTR_UTYPE_MAX 183#undef XSTR_TYPE_MAX 184#undef XSTR_TYPE_MIN 185#undef XSTR_STRTOU 186