summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/perl/uts/strtol_wrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/perl/uts/strtol_wrap.c')
-rw-r--r--gnu/usr.bin/perl/uts/strtol_wrap.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/gnu/usr.bin/perl/uts/strtol_wrap.c b/gnu/usr.bin/perl/uts/strtol_wrap.c
new file mode 100644
index 00000000000..24bb05542f5
--- /dev/null
+++ b/gnu/usr.bin/perl/uts/strtol_wrap.c
@@ -0,0 +1,174 @@
+/* A wrapper around strtol() and strtoul() to correct some
+ * "out of bounds" cases that don't work well on at least UTS.
+ * If a value is Larger than the max, strto[u]l should return
+ * the max value, and set errno to ERANGE
+ * The same if a value is smaller than the min value (only
+ * relevant for strtol(); not strtoul()), except the minimum
+ * value is returned (and errno == ERANGE).
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <stdlib.h>
+
+extern int errno;
+
+#undef I32
+#undef U32
+
+#define I32 int
+#define U32 unsigned int
+
+struct base_info {
+ char *ValidChars;
+
+ char *Ulong_max_str;
+ char *Long_max_str;
+ char *Long_min_str; /* Absolute value */
+
+ int Ulong_max_str_len;
+ int Long_max_str_len;
+ int Long_min_str_len; /* Absolute value */
+
+ U32 Ulong_max;
+ I32 Long_max;
+ I32 Long_min; /* NOT Absolute value */
+};
+static struct base_info Base_info[37];
+
+static struct base_info Base_info_16 = {
+ "0123456789abcdefABCDEF",
+ "4294967295", "2147483648" /* <== ABS VAL */ , "2147483647",
+ 10, 10, 10,
+ 4294967295, 2147483647, - 2147483648,
+};
+
+static struct base_info Base_info_10 = {
+ "0123456789",
+ "4294967295", "2147483648" /* <== ABS VAL */ , "2147483647",
+ 10, 10, 10,
+ 4294967295, 2147483647, - 2147483648,
+};
+
+ /* Used eventually (if this is fully developed) to hold info
+ * for processing bases 2-36. So that we can just plug the
+ * base in as a selector for its info, we sacrifice
+ * Base_info[0] and Base_info[1] (unless they are used
+ * at some point for special information).
+ */
+
+/* This may be replaced later by something more universal */
+static void
+init_Base_info()
+{
+ if(Base_info[10].ValidChars) return;
+ Base_info[10] = Base_info_10;
+ Base_info[16] = Base_info_16;
+}
+
+unsigned int
+strtoul_wrap32(char *s, char **pEnd, int base)
+{
+ int Len;
+ int isNegated = 0;
+ char *sOrig = s;
+
+ init_Base_info();
+
+ while(*s && isspace(*s)) ++s;
+
+ if(*s == '-') {
+ ++isNegated;
+ ++s;
+ while(*s && isspace(*s)) ++s;
+ }
+ if(base == 0) {
+ if(*s == '0') {
+ if(s[1] == 'x' || s[1] == 'X') {
+ s += 2;
+ base = 16;
+ } else {
+ ++s;
+ base = 8;
+ }
+ } else if(isdigit(*s)) {
+ base = 10;
+ }
+ }
+ if(base != 10) {
+ return strtoul(sOrig, pEnd, base);
+ }
+
+ Len = strspn(s, Base_info[base].ValidChars);
+
+ if(Len > Base_info[base].Ulong_max_str_len
+ ||
+ (Len == Base_info[base].Ulong_max_str_len
+ &&
+ strncmp(Base_info[base].Ulong_max_str, s, Len) < 0)
+ ) {
+ /* In case isNegated is set - what to do?? */
+ /* Mightn't we say a negative number is ERANGE for strtoul? */
+ errno = ERANGE;
+ return Base_info[base].Ulong_max;
+ }
+
+ return strtoul(sOrig, pEnd, base);
+}
+
+int
+strtol_wrap32(char *s, char **pEnd, int base)
+{
+ int Len;
+ int isNegated = 0;
+ char *sOrig = s;
+
+ init_Base_info();
+
+ while(*s && isspace(*s)) ++s;
+
+ if(*s == '-') {
+ ++isNegated;
+ ++s;
+ while(*s && isspace(*s)) ++s;
+ }
+ if(base == 0) {
+ if(*s == '0') {
+ if(s[1] == 'x' || s[1] == 'X') {
+ s += 2;
+ base = 16;
+ } else {
+ ++s;
+ base = 8;
+ }
+ } else if(isdigit(*s)) {
+ base = 10;
+ }
+ }
+ if(base != 10) {
+ return strtol(sOrig, pEnd, base);
+ }
+
+ Len = strspn(s, Base_info[base].ValidChars);
+
+ if(Len > Base_info[base].Long_max_str_len
+ ||
+ (!isNegated && Len == Base_info[base].Long_max_str_len
+ &&
+ strncmp(Base_info[base].Long_max_str, s, Len) < 0)
+ ||
+ (isNegated && Len == Base_info[base].Long_min_str_len
+ &&
+ strncmp(Base_info[base].Long_min_str, s, Len) < 0)
+ ) {
+ /* In case isNegated is set - what to do?? */
+ /* Mightn't we say a negative number is ERANGE for strtol? */
+ errno = ERANGE;
+ return(isNegated ? Base_info[base].Long_min
+ :
+ Base_info[base].Long_min);
+ }
+
+ return strtol(sOrig, pEnd, base);
+}