summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MANIFEST1
-rw-r--r--hints/uts.sh16
-rw-r--r--uts/strtol_wrap.c174
3 files changed, 189 insertions, 2 deletions
diff --git a/MANIFEST b/MANIFEST
index 1701463efe..0e672a1697 100644
--- 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
diff --git a/hints/uts.sh b/hints/uts.sh
index 06a0fdab78..592bc3e84c 100644
--- a/hints/uts.sh
+++ b/hints/uts.sh
@@ -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
index 0000000000..24bb05542f
--- /dev/null
+++ b/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);
+}