diff --git a/libc3/buf_parse.c b/libc3/buf_parse.c
index b834e7e..cfa0f08 100644
--- a/libc3/buf_parse.c
+++ b/libc3/buf_parse.c
@@ -1574,13 +1574,14 @@ sw buf_parse_s8_base (s_buf *buf, const s_str *base, bool negative,
sw radix;
sw result = 0;
s_buf_save save;
- s8 tmp = 0;
+ u8 u = 0;
assert(buf);
assert(base);
assert(dest);
buf_save_init(buf, &save);
radix = str_length_utf8(base);
if (radix < 2 || radix > S8_MAX) {
+ buf_save_clean(buf, &save);
assert(! "buf_parse_s8_base: invalid radix");
errx(1, "buf_parse_s8_base: invalid radix: %ld", radix);
return -1;
@@ -1588,24 +1589,26 @@ sw buf_parse_s8_base (s_buf *buf, const s_str *base, bool negative,
while ((r = buf_parse_digit(buf, base, &digit)) > 0) {
result += r;
if (digit >= radix) {
+ buf_save_clean(buf, &save);
assert(! "buf_parse_s8_base: digit not in radix");
errx(1, "buf_parse_s8_base: digit not in radix: %u", digit);
return -1;
}
- if (tmp > ceiling_s8(S8_MAX, radix)) {
- warnx("buf_parse_s8_base: integer overflow");
+ if (u > ceiling_s8(S8_MAX, radix)) {
+ warnx("buf_parse_s8_base: *: integer overflow");
+ r = -1;
goto restore;
}
- tmp *= radix;
- if (tmp > (s8) (S8_MAX - digit)) {
- warnx("buf_parse_s8_base: integer overflow");
+ u *= radix;
+ if (negative ? u > (u8) -S8_MIN - digit :
+ u > (s8) (S8_MAX - digit)) {
+ warnx("buf_parse_s8_base: +: integer overflow");
+ r = -1;
goto restore;
}
- tmp += digit;
+ u += digit;
}
- if (negative)
- tmp = -tmp;
- *dest = tmp;
+ *dest = negative ? -u : u;
r = result;
goto clean;
restore:
@@ -2184,49 +2187,65 @@ sw buf_parse_tuple (s_buf *buf, s_tuple *tuple)
return r;
}
-#define DEF_BUF_PARSE_U(TYPE, type) \
- sw buf_parse_ ## type (s_buf *buf, type *dest) \
+#define DEF_BUF_PARSE_U(bits) \
+ sw buf_parse_u ## bits (s_buf *buf, u ## bits *dest) \
{ \
sw r; \
+ sw r1; \
sw result = 0; \
s_buf_save save; \
+ u ## bits tmp; \
+ u ## bits tmp1; \
buf_save_init(buf, &save); \
if ((r = buf_read_1(buf, "0b")) < 0) \
goto restore; \
- result += r; \
if (r > 0) { \
- if ((r = buf_parse_ ## type ## _base(buf, &g_c3_base_bin, \
- dest)) <= 0) \
+ result += r; \
+ if ((r = buf_parse_u ## bits ## _base(buf, &g_c3_base_bin, \
+ dest)) <= 0) \
goto restore; \
result += r; \
goto ok; \
} \
if ((r = buf_read_1(buf, "0o")) < 0) \
goto restore; \
- result += r; \
if (r > 0) { \
- if ((r = buf_parse_ ## type ## _base(buf, &g_c3_base_oct, \
- dest)) <= 0) \
+ result += r; \
+ if ((r = buf_parse_u ## bits ## _base(buf, &g_c3_base_oct, \
+ dest)) <= 0) \
goto restore; \
result += r; \
goto ok; \
} \
if ((r = buf_read_1(buf, "0x")) < 0) \
goto restore; \
- result += r; \
if (r > 0) { \
- if ((r = buf_parse_## type ##_base(buf, g_c3_bases_hex, \
- dest)) < 0) \
+ result += r; \
+ if ((r = buf_parse_u ## bits ## _base(buf, g_c3_bases_hex, \
+ &tmp)) < 0) \
goto restore; \
- if (! r && (r = buf_parse_ ## type ## _base(buf, \
- g_c3_bases_hex + 1, \
- dest)) <= 0) \
+ if ((r1 = buf_parse_u ## bits ## _base(buf, \
+ g_c3_bases_hex + 1, \
+ &tmp1)) < 0) { \
+ r = r1; \
goto restore; \
- result += r; \
+ } \
+ if (r == 0 && r1 == 0) { \
+ warnx("invalid number: 0x"); \
+ goto restore; \
+ } \
+ if (r > r1) { \
+ result += r; \
+ *dest = tmp; \
+ } \
+ else { \
+ result += r1; \
+ *dest = tmp1; \
+ } \
goto ok; \
} \
- if ((r = buf_parse_ ## type ## _base(buf, &g_c3_base_dec, \
- dest)) <= 0) \
+ if ((r = buf_parse_u ## bits ## _base(buf, &g_c3_base_dec, \
+ dest)) <= 0) \
goto restore; \
result += r; \
ok: \
@@ -2239,40 +2258,45 @@ sw buf_parse_tuple (s_buf *buf, s_tuple *tuple)
return r; \
} \
\
- sw buf_parse_ ## type ## _base (s_buf *buf, const s_str *base, \
- type *dest) \
+ sw buf_parse_u ## bits ## _base (s_buf *buf, const s_str *base, \
+ u ## bits *dest) \
{ \
u8 digit; \
sw r; \
sw radix; \
sw result = 0; \
s_buf_save save; \
- type tmp = 0; \
+ u ## bits tmp = 0; \
assert(buf); \
assert(base); \
assert(dest); \
buf_save_init(buf, &save); \
radix = str_length_utf8(base); \
- if (radix < 2 || (uw) radix > TYPE ## _MAX) { \
- assert(! "buf_parse_" # type "_base: invalid radix"); \
- errx(1, "buf_parse_" # type "_base: invalid radix: %ld", radix); \
+ if (radix < 2 || (uw) radix > U ## bits ## _MAX) { \
+ assert(! "buf_parse_u" # bits "_base: invalid radix"); \
+ errx(1, "buf_parse_u" # bits "_base: invalid radix: %ld", \
+ radix); \
return -1; \
} \
while ((r = buf_parse_digit(buf, base, &digit)) > 0) { \
result += r; \
if (digit >= radix) { \
- assert(! "buf_parse_" # type "_base: digit not in radix"); \
- errx(1, "buf_parse_" # type "_base: digit not in radix: %u", \
+ assert(! "buf_parse_u" # bits \
+ "_base: digit greater than or equal to radix"); \
+ errx(1, "buf_parse_u" # bits \
+ "_base: digit greater than or equal to radix: %u", \
digit); \
return -1; \
} \
- if (tmp > ceiling_ ## type (TYPE ## _MAX, radix)) { \
- warnx("buf_parse_" # type "_base: integer overflow"); \
+ if (tmp > ceiling_u ## bits (U ## bits ## _MAX, radix)) { \
+ warnx("buf_parse_u" # bits "_base: *: integer overflow"); \
+ r = -1; \
goto restore; \
} \
tmp *= radix; \
- if (tmp > (type) (TYPE ## _MAX - digit)) { \
- warnx("buf_parse_" # type "_base: integer overflow"); \
+ if (tmp > (u ## bits) (U ## bits ## _MAX - digit)) { \
+ warnx("buf_parse_u" # bits "_base: +: integer overflow"); \
+ r = -1; \
goto restore; \
} \
tmp += digit; \
@@ -2287,11 +2311,114 @@ sw buf_parse_tuple (s_buf *buf, s_tuple *tuple)
return r; \
}
-DEF_BUF_PARSE_U(U8, u8)
-DEF_BUF_PARSE_U(U16, u16)
-DEF_BUF_PARSE_U(U32, u32)
-DEF_BUF_PARSE_U(U64, u64)
-DEF_BUF_PARSE_U(UW, uw)
+DEF_BUF_PARSE_U(8)
+DEF_BUF_PARSE_U(16)
+DEF_BUF_PARSE_U(32)
+DEF_BUF_PARSE_U(64)
+
+sw buf_parse_uw (s_buf *buf, uw *dest)
+{
+ sw r;
+ sw result = 0;
+ s_buf_save save;
+ buf_save_init(buf, &save);
+ if ((r = buf_read_1(buf, "0b")) < 0)
+ goto restore;
+ result += r;
+ if (r > 0) {
+ if ((r = buf_parse_uw_base(buf, &g_c3_base_bin,
+ dest)) <= 0)
+ goto restore;
+ result += r;
+ goto ok;
+ }
+ if ((r = buf_read_1(buf, "0o")) < 0)
+ goto restore;
+ result += r;
+ if (r > 0) {
+ if ((r = buf_parse_uw_base(buf, &g_c3_base_oct,
+ dest)) <= 0)
+ goto restore;
+ result += r;
+ goto ok;
+ }
+ if ((r = buf_read_1(buf, "0x")) < 0)
+ goto restore;
+ result += r;
+ if (r > 0) {
+ if ((r = buf_parse_uw_base(buf, g_c3_bases_hex,
+ dest)) < 0)
+ goto restore;
+ if (! r && (r = buf_parse_uw_base(buf,
+ g_c3_bases_hex + 1,
+ dest)) <= 0)
+ goto restore;
+ result += r;
+ goto ok;
+ }
+ if ((r = buf_parse_uw_base(buf, &g_c3_base_dec,
+ dest)) <= 0)
+ goto restore;
+ result += r;
+ ok:
+ r = result;
+ goto clean;
+ restore:
+ buf_save_restore_rpos(buf, &save);
+ clean:
+ buf_save_clean(buf, &save);
+ return r;
+}
+
+sw buf_parse_uw_base (s_buf *buf, const s_str *base,
+ uw *dest)
+{
+ u8 digit;
+ sw r;
+ sw radix;
+ sw result = 0;
+ s_buf_save save;
+ uw tmp = 0;
+ assert(buf);
+ assert(base);
+ assert(dest);
+ buf_save_init(buf, &save);
+ radix = str_length_utf8(base);
+ if (radix < 2 || (uw) radix > UW_MAX) {
+ assert(! "buf_parse_uw_base: invalid radix");
+ errx(1, "buf_parse_uw_base: invalid radix: %ld",
+ radix);
+ return -1;
+ }
+ while ((r = buf_parse_digit(buf, base, &digit)) > 0) {
+ result += r;
+ if (digit >= radix) {
+ assert(! "buf_parse_uw_base: digit greater than or equal to "
+ "radix");
+ errx(1, "buf_parse_uw_base: digit greater than or equal to "
+ "radix: %u", digit);
+ return -1;
+ }
+ if (tmp > ceiling_uw(UW_MAX, radix)) {
+ warnx("buf_parse_uw_base: integer overflow");
+ goto restore;
+ }
+ tmp *= radix;
+ if (tmp > (uw) (UW_MAX - digit)) {
+ warnx("buf_parse_uw_base: integer overflow");
+ goto restore;
+ }
+ tmp += digit;
+ }
+ *dest = tmp;
+ r = result;
+ goto clean;
+ restore:
+ buf_save_restore_rpos(buf, &save);
+ clean:
+ buf_save_clean(buf, &save);
+ return r;
+}
sw buf_parse_u64_dec (s_buf *buf, u64 *dest)
{
diff --git a/libc3/types.h b/libc3/types.h
index 041f2bc..0264a5c 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -35,23 +35,23 @@ typedef uint32_t u32;
typedef unsigned long uw;
typedef uint64_t u64;
-#define S8_MAX ((s8) ((1 << (8 * sizeof(s8) - 1)) - 1))
-#define S16_MAX ((s16) ((1 << (8 * sizeof(s16) - 1)) - 1))
-#define S32_MAX ((s32) ((1 << (8 * sizeof(s32) - 1)) - 1))
-#define S64_MAX ((s64) ((1 << (8 * sizeof(s64) - 1)) - 1))
-#define SW_MAX ((sw) ((1 << (8 * sizeof(sw) - 1)) - 1))
-
-#define S8_MIN ((s8) (1 << (8 * sizeof(s8))))
-#define S16_MIN ((s16) (1 << (8 * sizeof(s16))))
-#define S32_MIN ((s32) (1 << (8 * sizeof(s32))))
-#define S64_MIN ((s64) (1 << (8 * sizeof(s64))))
-#define SW_MIN ((sw) (1 << (8 * sizeof(sw))))
-
-#define U8_MAX ((u8) -1)
-#define U16_MAX ((u16) -1)
-#define U32_MAX ((u32) -1)
-#define U64_MAX ((u64) -1)
-#define UW_MAX ((uw) -1)
+#define S8_MAX ((s8) ((u8) (1 << (8 * sizeof(s8) - 1)) - 1))
+#define S16_MAX ((s16) ((u16) (1 << (8 * sizeof(s16) - 1)) - 1))
+#define S32_MAX ((s32) ((u32) (1 << (8 * sizeof(s32) - 1)) - 1))
+#define S64_MAX ((s64) ((u64) (1 << (8 * sizeof(s64) - 1)) - 1))
+#define SW_MAX ((sw) ((uw) (1 << (8 * sizeof(sw) - 1)) - 1))
+
+#define S8_MIN ((s8) (1 << (8 * sizeof(s8) - 1)))
+#define S16_MIN ((s16) (1 << (8 * sizeof(s16) - 1)))
+#define S32_MIN ((s32) (1 << (8 * sizeof(s32) - 1)))
+#define S64_MIN ((s64) (1 << (8 * sizeof(s64) - 1)))
+#define SW_MIN ((sw) (1 << (8 * sizeof(sw) - 1)))
+
+#define U8_MAX ((u8) ~ 0)
+#define U16_MAX ((u16) ~ 0)
+#define U32_MAX ((u32) ~ 0)
+#define U64_MAX ((u64) ~ 0)
+#define UW_MAX ((uw) ~ 0)
/* IEEE 754 floating point numbers. */
typedef float f32;
diff --git a/test/buf_parse_test.c b/test/buf_parse_test.c
index 2b3b489..4a1af65 100644
--- a/test/buf_parse_test.c
+++ b/test/buf_parse_test.c
@@ -651,7 +651,7 @@
#define BUF_PARSE_TEST_U(bits, test, expected) \
do { \
s_buf buf; \
- u ## bits u; \
+ u ## bits u = 0; \
test_context("buf_parse_u" # bits "(" # test ")"); \
buf_init_1(&buf, (test)); \
TEST_EQ(buf_parse_u ## bits(&buf, &u), strlen(test)); \
@@ -707,14 +707,14 @@ void buf_parse_test ()
buf_parse_test_integer_hex();
buf_parse_test_integer_oct();
buf_parse_test_integer();
- buf_parse_test_s8();
buf_parse_test_str();
buf_parse_test_sym();
+ buf_parse_test_ident();
buf_parse_test_list();
buf_parse_test_tag();
buf_parse_test_tuple();
buf_parse_test_u8();
- buf_parse_test_ident();
+ buf_parse_test_s8();
buf_parse_test_cfn();
}
@@ -1189,8 +1189,8 @@ void buf_parse_test_s8 ()
BUF_PARSE_TEST_S(8, "-020", -20);
BUF_PARSE_TEST_S(8, "-021", -21);
BUF_PARSE_TEST_S(8, "-022", -22);
- BUF_PARSE_TEST_S(8, "-128", 128);
- BUF_PARSE_TEST_S(8, "-0128", 128);
+ BUF_PARSE_TEST_S(8, "-128", -128);
+ BUF_PARSE_TEST_S(8, "-0128", -128);
BUF_PARSE_TEST_S(8, "0b0", 0);
BUF_PARSE_TEST_S(8, "0b1", 1);
BUF_PARSE_TEST_S(8, "0b00", 0);
@@ -1450,6 +1450,8 @@ void buf_parse_test_u8 ()
BUF_PARSE_TEST_U(8, "0b111", 7);
BUF_PARSE_TEST_U(8, "0b1111111", 127);
BUF_PARSE_TEST_U(8, "0b01111111", 127);
+ BUF_PARSE_TEST_U(8, "0b11111111", 255);
+ BUF_PARSE_TEST_U(8, "0b011111111", 255);
BUF_PARSE_TEST_U(8, "0o0", 0);
BUF_PARSE_TEST_U(8, "0o1", 1);
BUF_PARSE_TEST_U(8, "0o2", 2);
@@ -1465,6 +1467,8 @@ void buf_parse_test_u8 ()
BUF_PARSE_TEST_U(8, "0o000", 0);
BUF_PARSE_TEST_U(8, "0o177", 127);
BUF_PARSE_TEST_U(8, "0o0177", 127);
+ BUF_PARSE_TEST_U(8, "0o377", 255);
+ BUF_PARSE_TEST_U(8, "0o0377", 255);
BUF_PARSE_TEST_U(8, "0x0", 0);
BUF_PARSE_TEST_U(8, "0x1", 1);
BUF_PARSE_TEST_U(8, "0x2", 2);
@@ -1488,6 +1492,8 @@ void buf_parse_test_u8 ()
BUF_PARSE_TEST_U(8, "0x000", 0);
BUF_PARSE_TEST_U(8, "0x7F", 127);
BUF_PARSE_TEST_U(8, "0x07F", 127);
+ BUF_PARSE_TEST_U(8, "0xFF", 255);
+ BUF_PARSE_TEST_U(8, "0x0FF", 255);
BUF_PARSE_TEST_U(8, "0", 0);
BUF_PARSE_TEST_U(8, "1", 1);
BUF_PARSE_TEST_U(8, "2", 2);