One fix for strtoul not setting errno
Hal Morris [Sat, 2 Jun 2001 09:23:11 +0000 (02:23 -0700)]
Message-Id: <200106021623.JAA06906@cepheus.utsglobal.com>

p4raw-id: //depot/perl@10436

MANIFEST
hints/uts.sh
uts/strtol_wrap.c [new file with mode: 0644]

index 1701463..0e672a1 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -1919,6 +1919,7 @@ utils/perlcc.PL           Front-end for compiler
 utils/perldoc.PL       A simple tool to find & display perl's documentation
 utils/pl2pm.PL         A pl to pm translator
 utils/splain.PL                Stand-alone version of diagnostics.pm
+uts/strtol_wrap.c      strtol wrapper for UTS
 vmesa/Makefile         VM/ESA Makefile
 vmesa/vmesa.c          VM/ESA-specific C code for Perl core
 vmesa/vmesaish.h       VM/ESA-specific C header for Perl core
index 06a0fda..592bc3e 100644 (file)
@@ -1,7 +1,8 @@
 archname='s390'
+archobjs='uts/strtol_wrap.o'
 cc='cc'
 cccdlflags='-pic'
-ccflags='-Xa -XTSTRINGS=1500000'
+ccflags='-Xa -XTSTRINGS=1500000 -DStrtol=strtol_wrap32 -DStrtoul=strtoul_wrap32'
 d_bincompat3='undef'
 d_csh='undef' 
 d_lstat='define'
@@ -14,6 +15,17 @@ libperl='libperl.so'
 libpth='/lib /usr/lib /usr/ccs/lib'
 libs='-lsocket -lnsl -ldl -lm'  
 libswanted='m'
-prefix='psf_prefix'
+prefix='/usr/local'
 toke_cflags='optimize=""' 
 useshrplib='define'
+
+#################################
+# Some less routine stuff:
+#################################
+cc -g -Xa -c -pic -O uts/strtol_wrap.c -o uts/strtol_wrap.o
+# Make POSIX a static extension.
+cat <<'EOSH' > config.over
+static_ext='POSIX B'
+dynamic_ext=`echo " $dynamic_ext " |
+  sed -e 's/ POSIX / /' -e 's/ B / /'`
+EOSH
diff --git a/uts/strtol_wrap.c b/uts/strtol_wrap.c
new file mode 100644 (file)
index 0000000..24bb055
--- /dev/null
@@ -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);
+}