conv.c (1615B)
1 #include <errno.h> 2 3 #include "conv.h" 4 #include "debug.h" 5 #include "rcx.h" 6 7 #define IMPL(max) \ 8 u64 n; \ 9 if (r_conv_zstr_to_u64(&n, s, opts) < 0) return -1; \ 10 if (n >= (max)) { \ 11 errno = ERANGE; \ 12 return -1; \ 13 } \ 14 *i = n; \ 15 return 0; 16 17 int r_conv_zstr_to_u8 (u8 *i, char *s, RConvOpts opts) { IMPL(U8_MAX) } 18 int r_conv_zstr_to_u16(u16 *i, char *s, RConvOpts opts) { IMPL(U16_MAX) } 19 int r_conv_zstr_to_u32(u32 *i, char *s, RConvOpts opts) { IMPL(U32_MAX) } 20 21 int 22 r_conv_zstr_to_u64(u64 *i, char *s, RConvOpts opts) { 23 if (opts == 0) 24 opts = 10 | R_CONV_0B | R_CONV_0Q | R_CONV_0O | R_CONV_0X; 25 26 int base = opts & R_CONV_BASE_MASK; 27 REQUIRE(1 <= base && base <= 36); 28 29 if (s[0] == '0') { 30 int forced_base = 0; 31 32 switch (s[1]) { 33 case 'b': case 'B': if (opts & R_CONV_0B) forced_base = 2; break; 34 case 'q': case 'Q': if (opts & R_CONV_0Q) forced_base = 4; break; 35 case 'o': case 'O': if (opts & R_CONV_0O) forced_base = 8; break; 36 case 'x': case 'X': if (opts & R_CONV_0X) forced_base = 16; break; 37 } 38 39 if (forced_base) { 40 base = forced_base; 41 s += 2; 42 } 43 } 44 45 u64 n = 0; 46 47 char *t = s; 48 for (; *t; t++) { 49 uint k; 50 char c = *t; 51 if ('0' <= c && c <= '9') { 52 k = c - '0'; 53 } else if ('A' <= c && c <= 'Z') { 54 k = 10u + (c - 'A'); 55 } else if ('a' <= c && c <= 'z') { 56 k = 10u + (c - 'a'); 57 } else { 58 errno = EINVAL; 59 return -1; 60 } 61 62 if (k >= base) { 63 errno = EINVAL; 64 return -1; 65 } 66 67 if (n > U64_MAX / base || base * n > U64_MAX - k) { 68 errno = ERANGE; 69 return -1; 70 } 71 72 n = base * n + k; 73 } 74 75 if (s == t) { 76 errno = EINVAL; 77 return -1; 78 } 79 80 *i = n; 81 return 0; 82 }