ref: df83e0fd31da4af191a662e4f54df71c905d2f34
parent: b98c14dc639f4da1a80606224ff526731f46905a
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Mon Mar 13 20:08:49 EDT 2023
read: plan9-specific strtoll/strtoull with underflow/overflow control
--- a/read.c
+++ b/read.c
@@ -5,6 +5,56 @@
TOK_OPENB, TOK_CLOSEB, TOK_SHARPSYM, TOK_GENSYM, TOK_DOUBLEQUOTE
};
+#if defined(__plan9__)
+// FIXME remove all this after adding mp entirely
+#include <mp.h>
+#define ERANGE 34
+#define VLONG_MAX ~(1LL<<63)
+#define VLONG_MIN (1LL<<63)
+#define UVLONG_MAX (1LL<<63)
+static int errno;
+static mpint *mp_vlong_min, *mp_vlong_max, *mp_uvlong_max;
+
+static vlong strtoll_(char *nptr, char **rptr, int base)
+{
+ vlong x;
+ mpint *m, *c;
+
+ x = strtoll(nptr, rptr, base);
+ if((x != VLONG_MAX && x != VLONG_MIN) || *rptr == nptr)
+ return x;
+ m = strtomp(nptr, rptr, base, nil);
+ if(x == VLONG_MAX){
+ if(mp_vlong_max == nil) mp_vlong_max = vtomp(VLONG_MAX, nil);
+ c = mp_vlong_max;
+ }else{
+ if(mp_vlong_min == nil) mp_vlong_min = vtomp(VLONG_MIN, nil);
+ c = mp_vlong_min;
+ }
+ errno = mpcmp(c, m) == 0 ? 0 : ERANGE;
+ mpfree(m);
+ return x;
+}
+
+static uvlong strtoull_(char *nptr, char **rptr, int base)
+{
+ uvlong x;
+ mpint *m;
+
+ x = strtoull(nptr, rptr, base);
+ if(x != UVLONG_MAX || *rptr == nptr)
+ return x;
+ m = strtomp(nptr, rptr, base, nil);
+ if(mp_uvlong_max == nil)
+ mp_uvlong_max = uvtomp(UVLONG_MAX, nil);
+ errno = mpcmp(mp_uvlong_max, m) == 0 ? 0 : ERANGE;
+ mpfree(m);
+ return x;
+}
+#define strtoll strtoll_
+#define strtoull strtoull_
+#endif
+
#define F value2c(ios_t*,readstate->source)
// defines which characters are ordinary symbol characters.
@@ -60,27 +110,17 @@
if (pval) *pval = mk_double(D_NINF);
return 1;
}
-#if defined(__plan9__)
- // FIXME use libmp?
- i64 = strtoll(tok, &end, base);
-#else
errno = 0;
i64 = strtoll(tok, &end, base);
if (errno)
return 0;
-#endif
if (pval) *pval = return_from_int64(i64);
return (*end == '\0');
}
-#if defined(__plan9__)
- // FIXME use libmp?
- ui64 = strtoull(tok, &end, base);
-#else
errno = 0;
ui64 = strtoull(tok, &end, base);
if (errno)
return 0;
-#endif
if (pval) *pval = return_from_uint64(ui64);
return (*end == '\0');
}
@@ -93,15 +133,10 @@
static int read_numtok(char *tok, value_t *pval, int base)
{
int result;
-#if defined(__plan9__)
- // FIXME figure out what to do here
- result = isnumtok_base(tok, pval, base);
-#else
errno = 0;
result = isnumtok_base(tok, pval, base);
if (errno == ERANGE)
lerrorf(ParseError, "read: overflow in numeric constant %s", tok);
-#endif
return result;
}
@@ -281,17 +316,10 @@
toktype = TOK_LABEL;
else
lerror(ParseError, "read: invalid label");
-#if defined(__plan9__)
- // FIXME :(
- x = strtoll(buf, &end, 10);
- if (*end != '\0')
- lerror(ParseError, "read: invalid label");
-#else
errno = 0;
x = strtoll(buf, &end, 10);
if (*end != '\0' || errno)
lerror(ParseError, "read: invalid label");
-#endif
tokval = fixnum(x);
}
else if (c == '!') {
@@ -342,17 +370,10 @@
if ((char)ch == 'g')
ch = ios_getc(F);
read_token((char)ch, 0);
-#if defined(__plan9__)
- // FIXME :(
- x = strtol(buf, &end, 10);
- if (*end != '\0' || buf[0] == '\0')
- lerror(ParseError, "read: invalid gensym label");
-#else
errno = 0;
x = strtol(buf, &end, 10);
if (*end != '\0' || buf[0] == '\0' || errno)
lerror(ParseError, "read: invalid gensym label");
-#endif
toktype = TOK_GENSYM;
tokval = fixnum(x);
}