PATCH: untaint method for IO::Handle, 5.003_06 version
[p5sagit/p5-mst-13.2.git] / util.c
diff --git a/util.c b/util.c
index 1e94798..ea6641a 100644 (file)
--- a/util.c
+++ b/util.c
 #include <signal.h>
 #endif
 
-/* Omit this -- it causes too much grief on mixed systems.
+/* XXX If this causes problems, set i_unistd=undef in the hint file.  */
 #ifdef I_UNISTD
 #  include <unistd.h>
 #endif
-*/
 
 #ifdef I_VFORK
 #  include <vfork.h>
@@ -56,9 +55,10 @@ static void xstat _((void));
 /* NOTE:  Do not call the next three routines directly.  Use the macros
  * in handy.h, so that we can easily redefine everything to do tracking of
  * allocated hunks back to the original New to track down any memory leaks.
+ * XXX This advice seems to be widely ignored :-(   --AD  August 1996.
  */
 
-char *
+Malloc_t
 safemalloc(size)
 #ifdef MSDOS
 unsigned long size;
@@ -66,7 +66,7 @@ unsigned long size;
 MEM_SIZE size;
 #endif /* MSDOS */
 {
-    char  *ptr;
+    Malloc_t ptr;
 #ifdef MSDOS
        if (size > 0xffff) {
                PerlIO_printf(PerlIO_stderr(), "Allocation too large: %lx\n", size) FLUSH;
@@ -96,18 +96,18 @@ MEM_SIZE size;
 
 /* paranoid version of realloc */
 
-char *
+Malloc_t
 saferealloc(where,size)
-char *where;
+Malloc_t where;
 #ifndef MSDOS
 MEM_SIZE size;
 #else
 unsigned long size;
 #endif /* MSDOS */
 {
-    char *ptr;
+    Malloc_t ptr;
 #if !defined(STANDARD_C) && !defined(HAS_REALLOC_PROTOTYPE)
-    char *realloc();
+    Malloc_t realloc();
 #endif /* !defined(STANDARD_C) && !defined(HAS_REALLOC_PROTOTYPE) */
 
 #ifdef MSDOS
@@ -151,7 +151,7 @@ unsigned long size;
 
 void
 safefree(where)
-char *where;
+Malloc_t where;
 {
 #if !(defined(I286) || defined(atarist))
     DEBUG_m( PerlIO_printf(Perl_debug_log, "0x%x: (%05d) free\n",where,an++));
@@ -166,12 +166,12 @@ char *where;
 
 /* safe version of calloc */
 
-char *
+Malloc_t
 safecalloc(count, size)
 MEM_SIZE count;
 MEM_SIZE size;
 {
-    char  *ptr;
+    Malloc_t ptr;
 
 #ifdef MSDOS
        if (size * count > 0xffff) {
@@ -209,12 +209,12 @@ MEM_SIZE size;
 
 #define ALIGN sizeof(long)
 
-char *
+Malloc_t
 safexmalloc(x,size)
 I32 x;
 MEM_SIZE size;
 {
-    register char *where;
+    register Malloc_t where;
 
     where = safemalloc(size + ALIGN);
     xcount[x]++;
@@ -223,18 +223,18 @@ MEM_SIZE size;
     return where + ALIGN;
 }
 
-char *
+Malloc_t
 safexrealloc(where,size)
-char *where;
+Malloc_t where;
 MEM_SIZE size;
 {
-    register char *new = saferealloc(where - ALIGN, size + ALIGN);
+    register Malloc_t new = saferealloc(where - ALIGN, size + ALIGN);
     return new + ALIGN;
 }
 
 void
 safexfree(where)
-char *where;
+Malloc_t where;
 {
     I32 x;
 
@@ -246,13 +246,13 @@ char *where;
     safefree(where);
 }
 
-char *
+Malloc_t
 safexcalloc(x,count,size)
 I32 x;
 MEM_SIZE count;
 MEM_SIZE size;
 {
-    register char *where;
+    register Malloc_t where;
 
     where = safexmalloc(x, size * count + ALIGN);
     xcount[x]++;
@@ -404,6 +404,19 @@ char *lend;
     return Nullch;
 }
 
+/* Initialize the fold[] array. */
+int
+perl_init_fold()
+{
+  int i;
+
+  for (i = 0; i < 256; i++) {
+    if (isUPPER(i)) fold[i] = toLOWER(i);
+    else if (isLOWER(i)) fold[i] = toUPPER(i);
+    else fold[i] = i;
+  }
+}
+
 /* Initialize locale (and the fold[] array).*/
 int
 perl_init_i18nl10n(printwarn)  
@@ -415,37 +428,171 @@ perl_init_i18nl10n(printwarn)
      *    0 = fallback to C locale,
      *   -1 = fallback to C locale failed
      */
-#if defined(HAS_SETLOCALE) && defined(LC_CTYPE)
-    char * lang     = getenv("LANG");
+#if defined(HAS_SETLOCALE)
     char * lc_all   = getenv("LC_ALL");
     char * lc_ctype = getenv("LC_CTYPE");
-    int i;
+    char * lc_collate = getenv("LC_COLLATE");
+    char * lang       = getenv("LANG");
+    int setlocale_failure = 0;
+
+#define SETLOCALE_LC_CTYPE   0x01
+#define SETLOCALE_LC_COLLATE 0x02
+    
+#ifdef LC_CTYPE
+    if (setlocale(LC_CTYPE, "")   == 0)
+      setlocale_failure |= SETLOCALE_LC_CTYPE;
+#endif
+
+#ifdef LC_COLLATE
+    if (setlocale(LC_COLLATE, "") == 0)
+      setlocale_failure |= SETLOCALE_LC_COLLATE;
+    else
+      lc_collate_active = 1;
+#endif
+    
+    if (setlocale_failure && (lc_all || lang)) {
+       char *perl_badlang;
+
+       if (printwarn > 1 || 
+           printwarn &&
+           (!(perl_badlang = getenv("PERL_BADLANG")) || atoi(perl_badlang))) {
+         
+         PerlIO_printf(PerlIO_stderr(),
+                       "perl: warning: Setting locale failed for the categories:\n\t");
+#ifdef LC_CTYPE
+         if (setlocale_failure & SETLOCALE_LC_CTYPE)
+           PerlIO_printf(PerlIO_stderr(),
+                         "LC_CTYPE ");
+#endif
+#ifdef LC_COLLATE
+         if (setlocale_failure & SETLOCALE_LC_COLLATE)
+           PerlIO_printf(PerlIO_stderr(),
+                         "LC_COLLATE ");
+#endif
+         PerlIO_printf(PerlIO_stderr(),
+                       "\n");
 
-    if (setlocale(LC_CTYPE, "") == NULL && (lc_all || lc_ctype || lang)) {
-       if (printwarn) {
-           PerlIO_printf(PerlIO_stderr(), "warning: setlocale(LC_CTYPE, \"\") failed.\n");
            PerlIO_printf(PerlIO_stderr(),
-             "warning: LC_ALL = \"%s\", LC_CTYPE = \"%s\", LANG = \"%s\",\n",
-             lc_all   ? lc_all   : "(null)",
-             lc_ctype ? lc_ctype : "(null)",
-             lang     ? lang     : "(null)"
+                       "perl: warning: Please check that your locale settings:\n");
+
+         PerlIO_printf(PerlIO_stderr(),
+                       "\tLC_ALL = %c%s%c,\n",
+                       lc_all ? '"' : '(',
+                       lc_all ? lc_all : "unset",
+                         lc_all ? '"' : ')'
              );
-           PerlIO_printf(PerlIO_stderr(), "warning: falling back to the \"C\" locale.\n");
-       }
+#ifdef LC_CTYPE
+         if (setlocale_failure & SETLOCALE_LC_CTYPE)
+           PerlIO_printf(PerlIO_stderr(),
+                         "\tLC_CTYPE = %c%s%c,\n",
+                         lc_ctype ? '"' : '(',
+                         lc_ctype ? lc_ctype : "unset",
+                         lc_ctype ? '"' : ')'
+                         );
+#endif
+#ifdef LC_COLLATE
+         if (setlocale_failure & SETLOCALE_LC_COLLATE)
+           PerlIO_printf(PerlIO_stderr(),
+                         "\tLC_COLLATE = %c%s%c,\n",
+                         lc_collate ? '"' : '(',
+                         lc_collate ? lc_collate : "unset",
+                         lc_collate ? '"' : ')'
+                         );
+#endif
+         PerlIO_printf(PerlIO_stderr(),
+                       "\tLANG = %c%s%c\n",
+                       lang ? '"' : ')',
+                       lang ? lang : "unset",
+                       lang ? '"' : ')'
+                       );
+
+         PerlIO_printf(PerlIO_stderr(),
+                       "    are supported and installed on your system.\n");
+
        ok = 0;
-       if (setlocale(LC_CTYPE, "C") == NULL)
+         
+       }
+#ifdef LC_ALL
+       if (setlocale_failure) {
+         PerlIO_printf(PerlIO_stderr(),
+                       "perl: warning: Falling back to the \"C\" locale.\n");
+         if (setlocale(LC_ALL, "C") == NULL) {
            ok = -1;
+           PerlIO_printf(PerlIO_stderr(),
+                         "perl: warning: Failed to fall back to the \"C\" locale.\n");
     }
-
-    for (i = 0; i < 256; i++) {
-       if (isUPPER(i)) fold[i] = toLOWER(i);
-       else if (isLOWER(i)) fold[i] = toUPPER(i);
-       else fold[i] = i;
     }
+#else
+       PerlIO_printf(PerlIO_stderr(),
+                     "perl: warning: Cannot fall back to the \"C\" locale.\n");
 #endif
+    }
+
+    if (setlocale_failure & SETLOCALE_LC_CTYPE == 0)
+      perl_init_fold();
+
+#endif /* #if defined(HAS_SETLOCALE) */
+
     return ok;
 }
 
+char *
+mem_collxfrm(m, n, nx) /* mem_collxfrm() does strxfrm() for (data,size) */
+     const char *m;    /* "strings", that is, transforms normal eight-bit */
+     const Size_t n;   /* data into a format that can be memcmp()ed to get */
+     Size_t * nx;      /* 'the right' result for each locale. */
+{                      /* Uses strxfrm() but handles embedded NULs. */
+  char * mx = 0;
+
+#ifdef HAS_STRXFRM
+  Size_t ma;
+
+  /* the expansion factor of 16 has been seen with strxfrm() */
+  ma = (lc_collate_active ? 16 : 1) * n + 1;
+
+#define RENEW_mx()                     \
+  do {                                 \
+       ma = 2 * ma + 1;                \
+       Renew(mx, ma, char);            \
+       if (mx == 0)                    \
+         goto out;                     \
+  } while (0)
+
+  New(171, mx, ma, char);
+
+  if (mx) {
+    Size_t xc, dx;
+    int xok;
+
+    for (*nx = 0, xc = 0; xc < n; ) {
+      if (m[xc] == 0)
+       do {
+         if (*nx == ma)
+           RENEW_mx();
+         mx[*nx++] = m[xc++];
+       } while (xc < n && m[xc] == 0);
+      else {
+       do {
+         dx = strxfrm(mx + *nx, m + xc, ma - *nx);
+         if (dx + *nx > ma) {
+           RENEW_mx();
+           xok = 0;
+         } else
+           xok = 1;
+       } while (!xok);
+       xc += strlen(mx + *nx);
+       *nx += dx;
+      }
+    }
+  }
+
+out:
+
+#endif /* HAS_STRXFRM */
+
+  return mx;
+}
+
 void
 fbm_compile(sv, iflag)
 SV *sv;
@@ -551,12 +698,12 @@ SV *littlestr;
        }
        else {
            s = bigend - littlelen;
-           if (*s == *little && bcmp((char*)s,(char*)little,littlelen)==0)
+           if (*s == *little && memcmp((char*)s,(char*)little,littlelen)==0)
                return (char*)s;                /* how sweet it is */
            else if (bigend[-1] == '\n' && little[littlelen-1] != '\n'
              && s > big) {
                    s--;
-               if (*s == *little && bcmp((char*)s,(char*)little,littlelen)==0)
+               if (*s == *little && memcmp((char*)s,(char*)little,littlelen)==0)
                    return (char*)s;
            }
            return Nullch;
@@ -861,14 +1008,20 @@ long a1, a2, a3, a4;
     CV *cv;
 
     message = mess(pat,a1,a2,a3,a4);
-    if (diehook && (cv = sv_2cv(diehook, &stash, &gv, 0)) && !CvDEPTH(cv)) {
-       dSP;
-
-       PUSHMARK(sp);
-       EXTEND(sp, 1);
-       PUSHs(sv_2mortal(newSVpv(message,0)));
-       PUTBACK;
-       perl_call_sv((SV*)cv, G_DISCARD);
+    if (diehook) {
+       SV *olddiehook = diehook;
+       diehook = Nullsv;                       /* sv_2cv might call croak() */
+       cv = sv_2cv(olddiehook, &stash, &gv, 0);
+       diehook = olddiehook;
+       if (cv && !CvDEPTH(cv)) {
+           dSP;
+
+           PUSHMARK(sp);
+           EXTEND(sp, 1);
+           PUSHs(sv_2mortal(newSVpv(message,0)));
+           PUTBACK;
+           perl_call_sv((SV*)cv, G_DISCARD);
+       }
     }
     if (in_eval) {
        restartop = die_where(message);
@@ -905,22 +1058,27 @@ long a1, a2, a3, a4;
     CV *cv;
 
     message = mess(pat,a1,a2,a3,a4);
-    if (warnhook && (cv = sv_2cv(warnhook, &stash, &gv, 0)) && !CvDEPTH(cv)) {
-       dSP;
-
-       PUSHMARK(sp);
-       EXTEND(sp, 1);
-       PUSHs(sv_2mortal(newSVpv(message,0)));
-       PUTBACK;
-       perl_call_sv((SV*)cv, G_DISCARD);
+    if (warnhook) {
+       SV *oldwarnhook = warnhook;
+       warnhook = Nullsv;      /* sv_2cv might end up calling warn() */
+       cv = sv_2cv(oldwarnhook, &stash, &gv, 0);
+       warnhook = oldwarnhook;
+       if (cv && !CvDEPTH(cv)) {
+           dSP;
+           
+           PUSHMARK(sp);
+           EXTEND(sp, 1);
+           PUSHs(sv_2mortal(newSVpv(message,0)));
+           PUTBACK;
+           perl_call_sv((SV*)cv, G_DISCARD);
+           return;
+       }
     }
-    else {
-       PerlIO_puts(PerlIO_stderr(),message);
+    PerlIO_puts(PerlIO_stderr(),message);
 #ifdef LEAKTEST
-       DEBUG_L(xstat());
+    DEBUG_L(xstat());
 #endif
-       (void)Fflush(PerlIO_stderr());
-    }
+    (void)PerlIO_flush(PerlIO_stderr());
 }
 
 #else /* !defined(I_STDARG) && !defined(I_VARARGS) */
@@ -1024,14 +1182,20 @@ croak(pat, va_alist)
 #endif
     message = mess(pat, &args);
     va_end(args);
-    if (diehook && (cv = sv_2cv(diehook, &stash, &gv, 0)) && !CvDEPTH(cv)) {
-       dSP;
-
-       PUSHMARK(sp);
-       EXTEND(sp, 1);
-       PUSHs(sv_2mortal(newSVpv(message,0)));
-       PUTBACK;
-       perl_call_sv((SV*)cv, G_DISCARD);
+    if (diehook) {
+       SV *olddiehook = diehook;
+       diehook = Nullsv;                 /* sv_2cv might call croak() */
+       cv = sv_2cv(olddiehook, &stash, &gv, 0);
+       diehook = olddiehook;
+       if (cv && !CvDEPTH(cv)) {
+           dSP;
+
+           PUSHMARK(sp);
+           EXTEND(sp, 1);
+           PUSHs(sv_2mortal(newSVpv(message,0)));
+           PUTBACK;
+           perl_call_sv((SV*)cv, G_DISCARD);
+       }
     }
     if (in_eval) {
        restartop = die_where(message);
@@ -1080,22 +1244,27 @@ warn(pat,va_alist)
     message = mess(pat, &args);
     va_end(args);
 
-    if (warnhook && (cv = sv_2cv(warnhook, &stash, &gv, 0)) && !CvDEPTH(cv)) {
-       dSP;
-
-       PUSHMARK(sp);
-       EXTEND(sp, 1);
-       PUSHs(sv_2mortal(newSVpv(message,0)));
-       PUTBACK;
-       perl_call_sv((SV*)cv, G_DISCARD);
+    if (warnhook) {
+       SV *oldwarnhook = warnhook;
+       warnhook = Nullsv;      /* sv_2cv might end up calling warn() */
+       cv = sv_2cv(oldwarnhook, &stash, &gv, 0);
+       warnhook = oldwarnhook;
+       if (cv && !CvDEPTH(cv)) {
+           dSP;
+
+           PUSHMARK(sp);
+           EXTEND(sp, 1);
+           PUSHs(sv_2mortal(newSVpv(message,0)));
+           PUTBACK;
+           perl_call_sv((SV*)cv, G_DISCARD);
+           return;
+       }
     }
-    else {
-       PerlIO_puts(PerlIO_stderr(),message);
+    PerlIO_puts(PerlIO_stderr(),message);
 #ifdef LEAKTEST
-       DEBUG_L(xstat());
+    DEBUG_L(xstat());
 #endif
-       (void)PerlIO_flush(PerlIO_stderr());
-    }
+    (void)PerlIO_flush(PerlIO_stderr());
 }
 #endif /* !defined(I_STDARG) && !defined(I_VARARGS) */
 
@@ -1718,18 +1887,24 @@ double f;
    ccflags.
               --Andy Dougherty      <doughera@lafcol.lafayette.edu>
 */
-#ifndef MY_ULONG_MAX
-#  define MY_ULONG_MAX ((UV)PERL_LONG_MAX * (UV)2 + (UV)1)
+
+/* Code modified to prefer proper named type ranges, I32, IV, or UV, instead
+   of LONG_(MIN/MAX).
+                           -- Kenneth Albanowski <kjahds@kjahds.com>
+*/                                      
+
+#ifndef MY_UV_MAX
+#  define MY_UV_MAX ((UV)IV_MAX * (UV)2 + (UV)1)
 #endif
 
 I32
 cast_i32(f)
 double f;
 {
-    if (f >= PERL_LONG_MAX)
-       return (I32) PERL_LONG_MAX;
-    if (f <= PERL_LONG_MIN)
-       return (I32) PERL_LONG_MIN;
+    if (f >= I32_MAX)
+       return (I32) I32_MAX;
+    if (f <= I32_MIN)
+       return (I32) I32_MIN;
     return (I32) f;
 }
 
@@ -1737,10 +1912,10 @@ IV
 cast_iv(f)
 double f;
 {
-    if (f >= PERL_LONG_MAX)
-       return (IV) PERL_LONG_MAX;
-    if (f <= PERL_LONG_MIN)
-       return (IV) PERL_LONG_MIN;
+    if (f >= IV_MAX)
+       return (IV) IV_MAX;
+    if (f <= IV_MIN)
+       return (IV) IV_MIN;
     return (IV) f;
 }
 
@@ -1748,8 +1923,8 @@ UV
 cast_uv(f)
 double f;
 {
-    if (f >= MY_ULONG_MAX)
-       return (UV) MY_ULONG_MAX;
+    if (f >= MY_UV_MAX)
+       return (UV) MY_UV_MAX;
     return (UV) f;
 }