net-snmp 5.7
|
00001 /* 00002 * An implementation of strtoull() for compilers that do not have this 00003 * function, e.g. MSVC. 00004 * See also http://www.opengroup.org/onlinepubs/000095399/functions/strtoul.html 00005 * for more information about strtoull(). 00006 */ 00007 00008 00009 /* 00010 * For MSVC, disable the warning "unary minus operator applied to unsigned 00011 * type, result still unsigned" 00012 */ 00013 #ifdef _MSC_VER 00014 #pragma warning (disable: 4146) 00015 #endif 00016 00017 00018 #define __STDC_CONSTANT_MACROS /* Enable UINT64_C in <stdint.h> */ 00019 #define __STDC_FORMAT_MACROS /* Enable PRIu64 in <inttypes.h> */ 00020 00021 #include <net-snmp/net-snmp-config.h> 00022 00023 #include <errno.h> 00024 #include <ctype.h> 00025 #include <limits.h> 00026 #ifdef HAVE_INTTYPES_H 00027 #include <inttypes.h> 00028 #endif 00029 00030 #include <net-snmp/types.h> 00031 #include <net-snmp/library/system.h> 00032 00033 /* 00034 * UINT64_C: C99 macro for the suffix for uint64_t constants. 00035 */ 00036 #ifndef UINT64_C 00037 #ifdef _MSC_VER 00038 #define UINT64_C(c) c##ui64 00039 #else 00040 #define UINT64_C(c) c##ULL 00041 #endif 00042 #endif 00043 00044 /* 00045 * According to the C99 standard, the constant ULLONG_MAX must be defined in 00046 * <limits.h>. Define it here for pre-C99 compilers. 00047 */ 00048 #ifndef ULLONG_MAX 00049 #define ULLONG_MAX UINT64_C(0xffffffffffffffff) 00050 #endif 00051 00052 #ifdef STRTOULL_UNIT_TEST 00053 uint64_t 00054 my_strtoull(const char *nptr, char **endptr, int base) 00055 #else 00056 uint64_t 00057 strtoull(const char *nptr, char **endptr, int base) 00058 #endif 00059 { 00060 uint64_t result = 0; 00061 const char *p; 00062 const char *first_nonspace; 00063 const char *digits_start; 00064 int sign = 1; 00065 int out_of_range = 0; 00066 00067 if (base != 0 && (base < 2 || base > 36)) 00068 goto invalid_input; 00069 00070 p = nptr; 00071 00072 /* 00073 * Process the initial, possibly empty, sequence of white-space characters. 00074 */ 00075 while (isspace((unsigned char) (*p))) 00076 p++; 00077 00078 first_nonspace = p; 00079 00080 /* 00081 * Determine sign. 00082 */ 00083 if (*p == '+') 00084 p++; 00085 else if (*p == '-') { 00086 p++; 00087 sign = -1; 00088 } 00089 00090 if (base == 0) { 00091 /* 00092 * Determine base. 00093 */ 00094 if (*p == '0') { 00095 if ((p[1] == 'x' || p[1] == 'X')) { 00096 if (isxdigit((unsigned char)(p[2]))) { 00097 base = 16; 00098 p += 2; 00099 } else { 00100 /* 00101 * Special case: treat the string "0x" without any further 00102 * hex digits as a decimal number. 00103 */ 00104 base = 10; 00105 } 00106 } else { 00107 base = 8; 00108 p++; 00109 } 00110 } else { 00111 base = 10; 00112 } 00113 } else if (base == 16) { 00114 /* 00115 * For base 16, skip the optional "0x" / "0X" prefix. 00116 */ 00117 if (*p == '0' && (p[1] == 'x' || p[1] == 'X') 00118 && isxdigit((unsigned char)(p[2]))) { 00119 p += 2; 00120 } 00121 } 00122 00123 digits_start = p; 00124 00125 for (; *p; p++) { 00126 int digit; 00127 digit = ('0' <= *p && *p <= '9') ? *p - '0' 00128 : ('a' <= *p && *p <= 'z') ? (*p - 'a' + 10) 00129 : ('A' <= *p && *p <= 'Z') ? (*p - 'A' + 10) : 36; 00130 if (digit < base) { 00131 if (! out_of_range) { 00132 if (result > ULLONG_MAX / base 00133 || result * base > ULLONG_MAX - digit) { 00134 out_of_range = 1; 00135 } 00136 result = result * base + digit; 00137 } 00138 } else 00139 break; 00140 } 00141 00142 if (p > first_nonspace && p == digits_start) 00143 goto invalid_input; 00144 00145 if (p == first_nonspace) 00146 p = nptr; 00147 00148 if (endptr) 00149 *endptr = (char *) p; 00150 00151 if (out_of_range) { 00152 errno = ERANGE; 00153 return ULLONG_MAX; 00154 } 00155 00156 return sign > 0 ? result : -result; 00157 00158 invalid_input: 00159 errno = EINVAL; 00160 if (endptr) 00161 *endptr = (char *) nptr; 00162 return 0; 00163 } 00164 00165 #if defined(STRTOULL_UNIT_TEST) 00166 00167 #include <stdio.h> 00168 #include <stdlib.h> 00169 00170 #ifndef PRIu64 00171 #ifdef _MSC_VER 00172 #define PRIu64 "I64u" 00173 #else 00174 #define PRIu64 "llu" 00175 #endif 00176 #endif 00177 00178 struct strtoull_testcase { 00179 /* 00180 * inputs 00181 */ 00182 const char *nptr; 00183 int base; 00184 /* 00185 * expected outputs 00186 */ 00187 int expected_errno; 00188 int expected_end; 00189 uint64_t expected_result; 00190 }; 00191 00192 static const struct strtoull_testcase test_input[] = { 00193 {"0x0", 0, 0, 3, 0}, 00194 {"1", 0, 0, 1, 1}, 00195 {"0x1", 0, 0, 3, 1}, 00196 {" -0666", 0, 0, 7, -0666}, 00197 {" -0x666", 0, 0, 8, -0x666}, 00198 {"18446744073709551614", 0, 0, 20, UINT64_C(0xfffffffffffffffe)}, 00199 {"0xfffffffffffffffe", 0, 0, 18, UINT64_C(0xfffffffffffffffe)}, 00200 {"18446744073709551615", 0, 0, 20, UINT64_C(0xffffffffffffffff)}, 00201 {"0xffffffffffffffff", 0, 0, 18, UINT64_C(0xffffffffffffffff)}, 00202 {"18446744073709551616", 0, ERANGE, 20, UINT64_C(0xffffffffffffffff)}, 00203 {"0x10000000000000000", 0, ERANGE, 19, UINT64_C(0xffffffffffffffff)}, 00204 {"ff", 16, 0, 2, 255}, 00205 {"0xff", 16, 0, 4, 255}, 00206 {" ", 0, 0, 0, 0}, 00207 {"0x", 0, 0, 1, 0}, 00208 {"0x", 8, 0, 1, 0}, 00209 {"0x", 16, 0, 1, 0}, 00210 {"zyyy", 0, 0, 0, 0}, 00211 {"0xfffffffffffffffff", 0, ERANGE, 19, ULLONG_MAX}, 00212 {"0xfffffffffffffffffz", 0, ERANGE, 19, ULLONG_MAX} 00213 }; 00214 00215 int 00216 main(void) 00217 { 00218 int failure_count = 0; 00219 unsigned int i; 00220 00221 for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) { 00222 const struct strtoull_testcase *const p = &test_input[i]; 00223 char *endptr; 00224 uint64_t result; 00225 00226 errno = 0; 00227 result = my_strtoull(p->nptr, &endptr, p->base); 00228 if (errno != p->expected_errno) { 00229 failure_count++; 00230 printf("test %d failed (input \"%s\"): expected errno %d" 00231 ", got errno %d\n", 00232 i, p->nptr, p->expected_errno, errno); 00233 } 00234 if (result != p->expected_result) { 00235 failure_count++; 00236 printf("test %d failed (input \"%s\"): expected result %" PRIu64 00237 ", got result %" PRIu64 "\n", 00238 i, p->nptr, p->expected_result, result); 00239 } 00240 if (endptr - p->nptr != p->expected_end) { 00241 failure_count++; 00242 printf("test %d failed (input \"%s\"): expected end %d," 00243 " got end %d\n", 00244 i, p->nptr, p->expected_end, (int) (endptr - p->nptr)); 00245 } 00246 00247 #if HAVE_STRTOULL 00248 errno = 0; 00249 result = strtoull(p->nptr, &endptr, p->base); 00250 if (errno != p->expected_errno) { 00251 failure_count++; 00252 printf("test %d (input \"%s\"): expected errno %d" 00253 ", libc strtoull() returned errno %d\n", 00254 i, p->nptr, p->expected_errno, errno); 00255 } 00256 if (result != p->expected_result) { 00257 failure_count++; 00258 printf("test %d (input \"%s\"): expected result %" PRIu64 00259 ", libc strtoull() returned result %" PRIu64 "\n", 00260 i, p->nptr, p->expected_result, result); 00261 } 00262 if (endptr - p->nptr != p->expected_end) { 00263 failure_count++; 00264 printf("test %d (input \"%s\"): expected end %d," 00265 " libc strtoull() returned end %d\n", 00266 i, p->nptr, p->expected_end, (int) (endptr - p->nptr)); 00267 } 00268 #endif 00269 } 00270 if (failure_count == 0) 00271 printf("All %d tests passed.\n", i); 00272 return 0; 00273 } 00274 00275 #endif /* defined(STRTOULL_UNIT_TEST) */ 00276 00277 /* 00278 * Local variables: 00279 * c-basic-offset: 4 00280 * indent-tabs-mode: nil 00281 * compile-command: "gcc -Wall -Werror -DSTRTOULL_UNIT_TEST=1 -I../include -g -o strtoull-unit-test strtoull.c && ./strtoull-unit-test" 00282 * End: 00283 */