rcx

miscellaneous C library
git clone git://git.rr3.xyz/rcx
Log | Files | Refs | README | LICENSE

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 }