Update copyright notices
[p5sagit/p5-mst-13.2.git] / util.c
diff --git a/util.c b/util.c
index 48f9058..6df76a6 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1,7 +1,7 @@
 /*    util.c
  *
  *    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
 #include "perl.h"
 
 #ifndef PERL_MICRO
-#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
 #include <signal.h>
-#endif
-
 #ifndef SIG_ERR
 # define SIG_ERR ((Sighandler_t) -1)
 #endif
@@ -75,7 +72,9 @@ Perl_safesysmalloc(MEM_SIZE size)
     else if (PL_nomemok)
        return Nullch;
     else {
-       PerlIO_puts(Perl_error_log,PL_no_mem) FLUSH;
+       /* Can't use PerlIO to write as it allocates memory */
+       PerlLIO_write(PerlIO_fileno(Perl_error_log),
+                     PL_no_mem, strlen(PL_no_mem));
        my_exit(1);
        return Nullch;
     }
@@ -122,7 +121,9 @@ Perl_safesysrealloc(Malloc_t where,MEM_SIZE size)
     else if (PL_nomemok)
        return Nullch;
     else {
-       PerlIO_puts(Perl_error_log,PL_no_mem) FLUSH;
+       /* Can't use PerlIO to write as it allocates memory */
+       PerlLIO_write(PerlIO_fileno(Perl_error_log),
+                     PL_no_mem, strlen(PL_no_mem));
        my_exit(1);
        return Nullch;
     }
@@ -174,7 +175,9 @@ Perl_safesyscalloc(MEM_SIZE count, MEM_SIZE size)
     else if (PL_nomemok)
        return Nullch;
     else {
-       PerlIO_puts(Perl_error_log,PL_no_mem) FLUSH;
+       /* Can't use PerlIO to write as it allocates memory */
+       PerlLIO_write(PerlIO_fileno(Perl_error_log),
+                     PL_no_mem, strlen(PL_no_mem));
        my_exit(1);
        return Nullch;
     }
@@ -1033,6 +1036,7 @@ Perl_vdie(pTHX_ const char* pat, va_list *args)
     CV *cv;
     SV *msv;
     STRLEN msglen;
+    I32 utf8 = 0;
 
     DEBUG_S(PerlIO_printf(Perl_debug_log,
                          "%p: die: curstack = %p, mainstack = %p\n",
@@ -1047,6 +1051,7 @@ Perl_vdie(pTHX_ const char* pat, va_list *args)
        }
        else
            message = SvPV(msv,msglen);
+       utf8 = SvUTF8(msv);
     }
     else {
        message = Nullch;
@@ -1072,6 +1077,7 @@ Perl_vdie(pTHX_ const char* pat, va_list *args)
            save_re_context();
            if (message) {
                msg = newSVpvn(message, msglen);
+               SvFLAGS(msg) |= utf8;
                SvREADONLY_on(msg);
                SAVEFREESV(msg);
            }
@@ -1090,6 +1096,7 @@ Perl_vdie(pTHX_ const char* pat, va_list *args)
     }
 
     PL_restartop = die_where(message, msglen);
+    SvFLAGS(ERRSV) |= utf8;
     DEBUG_S(PerlIO_printf(Perl_debug_log,
          "%p: die: restartop = %p, was_in_eval = %d, top_env = %p\n",
          thr, PL_restartop, was_in_eval, PL_top_env));
@@ -1132,6 +1139,7 @@ Perl_vcroak(pTHX_ const char* pat, va_list *args)
     CV *cv;
     SV *msv;
     STRLEN msglen;
+    I32 utf8 = 0;
 
     if (pat) {
        msv = vmess(pat, args);
@@ -1142,6 +1150,7 @@ Perl_vcroak(pTHX_ const char* pat, va_list *args)
        }
        else
            message = SvPV(msv,msglen);
+       utf8 = SvUTF8(msv);
     }
     else {
        message = Nullch;
@@ -1167,6 +1176,7 @@ Perl_vcroak(pTHX_ const char* pat, va_list *args)
            save_re_context();
            if (message) {
                msg = newSVpvn(message, msglen);
+               SvFLAGS(msg) |= utf8;
                SvREADONLY_on(msg);
                SAVEFREESV(msg);
            }
@@ -1185,6 +1195,7 @@ Perl_vcroak(pTHX_ const char* pat, va_list *args)
     }
     if (PL_in_eval) {
        PL_restartop = die_where(message, msglen);
+       SvFLAGS(ERRSV) |= utf8;
        JMPENV_JUMP(3);
     }
     else if (!message)
@@ -1213,8 +1224,9 @@ Perl_croak_nocontext(const char *pat, ...)
 =for apidoc croak
 
 This is the XSUB-writer's interface to Perl's C<die> function.
-Normally use this function the same way you use the C C<printf>
-function.  See C<warn>.
+Normally call this function the same way you call the C C<printf>
+function.  Calling C<croak> returns control directly to Perl,
+sidestepping the normal C order of execution. See C<warn>.
 
 If you want to throw an exception object, assign the object to
 C<$@> and then pass C<Nullch> to croak():
@@ -1245,8 +1257,10 @@ Perl_vwarn(pTHX_ const char* pat, va_list *args)
     CV *cv;
     SV *msv;
     STRLEN msglen;
+    I32 utf8 = 0;
 
     msv = vmess(pat, args);
+    utf8 = SvUTF8(msv);
     message = SvPV(msv, msglen);
 
     if (PL_warnhook) {
@@ -1264,6 +1278,7 @@ Perl_vwarn(pTHX_ const char* pat, va_list *args)
            ENTER;
            save_re_context();
            msg = newSVpvn(message, msglen);
+           SvFLAGS(msg) |= utf8;
            SvREADONLY_on(msg);
            SAVEFREESV(msg);
 
@@ -1296,9 +1311,8 @@ Perl_warn_nocontext(const char *pat, ...)
 /*
 =for apidoc warn
 
-This is the XSUB-writer's interface to Perl's C<warn> function.  Use this
-function the same way you use the C C<printf> function.  See
-C<croak>.
+This is the XSUB-writer's interface to Perl's C<warn> function.  Call this
+function the same way you call the C C<printf> function.  See C<croak>.
 
 =cut
 */
@@ -1342,9 +1356,11 @@ Perl_vwarner(pTHX_ U32  err, const char* pat, va_list* args)
     CV *cv;
     SV *msv;
     STRLEN msglen;
+    I32 utf8 = 0;
 
     msv = vmess(pat, args);
     message = SvPV(msv, msglen);
+    utf8 = SvUTF8(msv);
 
     if (ckDEAD(err)) {
        if (PL_diehook) {
@@ -1362,6 +1378,7 @@ Perl_vwarner(pTHX_ U32  err, const char* pat, va_list* args)
                ENTER;
                save_re_context();
                msg = newSVpvn(message, msglen);
+               SvFLAGS(msg) |= utf8;
                SvREADONLY_on(msg);
                SAVEFREESV(msg);
 
@@ -1376,6 +1393,7 @@ Perl_vwarner(pTHX_ U32  err, const char* pat, va_list* args)
        }
        if (PL_in_eval) {
            PL_restartop = die_where(message, msglen);
+           SvFLAGS(ERRSV) |= utf8;
            JMPENV_JUMP(3);
        }
        write_to_stderr(message, msglen);
@@ -1397,6 +1415,7 @@ Perl_vwarner(pTHX_ U32  err, const char* pat, va_list* args)
                ENTER;
                save_re_context();
                msg = newSVpvn(message, msglen);
+               SvFLAGS(msg) |= utf8;
                SvREADONLY_on(msg);
                SAVEFREESV(msg);
 
@@ -1516,6 +1535,7 @@ Perl_my_setenv(pTHX_ char *nam,char *val)
 
 #endif /* WIN32 || NETWARE */
 
+#ifndef PERL_MICRO
 I32
 Perl_setenv_getix(pTHX_ char *nam)
 {
@@ -1533,6 +1553,7 @@ Perl_setenv_getix(pTHX_ char *nam)
     }                                  /* potential SEGV's */
     return i;
 }
+#endif /* !PERL_MICRO */
 
 #endif /* !VMS && !EPOC*/
 
@@ -3634,85 +3655,6 @@ Perl_getcwd_sv(pTHX_ register SV *sv)
 }
 
 /*
-=head1 SV Manipulation Functions
-
-=for apidoc scan_vstring
-
-Returns a pointer to the next character after the parsed
-vstring, as well as updating the passed in sv.
-
-Function must be called like
-
-       sv = NEWSV(92,5);
-       s = scan_vstring(s,sv);
-
-The sv should already be large enough to store the vstring
-passed in, for performance reasons.
-
-=cut
-*/
-
-char *
-Perl_scan_vstring(pTHX_ char *s, SV *sv)
-{
-    char *pos = s;
-    char *start = s;
-    if (*pos == 'v') pos++;  /* get past 'v' */
-    while (isDIGIT(*pos) || *pos == '_')
-    pos++;
-    if (!isALPHA(*pos)) {
-       UV rev;
-       U8 tmpbuf[UTF8_MAXLEN+1];
-       U8 *tmpend;
-
-       if (*s == 'v') s++;  /* get past 'v' */
-
-       sv_setpvn(sv, "", 0);
-
-       for (;;) {
-           rev = 0;
-           {
-               /* this is atoi() that tolerates underscores */
-               char *end = pos;
-               UV mult = 1;
-               while (--end >= s) {
-                   UV orev;
-                   if (*end == '_')
-                       continue;
-                   orev = rev;
-                   rev += (*end - '0') * mult;
-                   mult *= 10;
-                   if (orev > rev && ckWARN_d(WARN_OVERFLOW))
-                       Perl_warner(aTHX_ packWARN(WARN_OVERFLOW),
-                                   "Integer overflow in decimal number");
-               }
-           }
-#ifdef EBCDIC
-           if (rev > 0x7FFFFFFF)
-                Perl_croak(aTHX_ "In EBCDIC the v-string components cannot exceed 2147483647");
-#endif
-           /* Append native character for the rev point */
-           tmpend = uvchr_to_utf8(tmpbuf, rev);
-           sv_catpvn(sv, (const char*)tmpbuf, tmpend - tmpbuf);
-           if (!UNI_IS_INVARIANT(NATIVE_TO_UNI(rev)))
-                SvUTF8_on(sv);
-           if (*pos == '.' && isDIGIT(pos[1]))
-                s = ++pos;
-           else {
-                s = pos;
-                break;
-           }
-           while (isDIGIT(*pos) || *pos == '_')
-                pos++;
-       }
-       SvPOK_on(sv);
-       sv_magic(sv,NULL,PERL_MAGIC_vstring,(const char*)start, pos-start);
-       SvRMAGICAL_on(sv);
-    }
-    return s;
-}
-
-/*
 =for apidoc scan_version
 
 Returns a pointer to the next character after the parsed
@@ -3721,19 +3663,21 @@ an RV.
 
 Function must be called with an already existing SV like
 
-    sv = NEWSV(92,0);
-    s = scan_version(s,sv);
+    sv = newSV(0);
+    s = scan_version(s,SV *sv, bool qv);
 
 Performs some preprocessing to the string to ensure that
 it has the correct characteristics of a version.  Flags the
 object if it contains an underscore (which denotes this
-is a beta version).
+is a alpha version).  The boolean qv denotes that the version
+should be interpreted as if it had multiple decimals, even if
+it doesn't.
 
 =cut
 */
 
 char *
-Perl_scan_version(pTHX_ char *s, SV *rv)
+Perl_scan_version(pTHX_ char *s, SV *rv, bool qv)
 {
     const char *start = s;
     char *pos = s;
@@ -3761,7 +3705,10 @@ Perl_scan_version(pTHX_ char *s, SV *rv)
     }
     pos = s;
 
-    if (*pos == 'v') pos++;  /* get past 'v' */
+    if (*pos == 'v') {
+       pos++;  /* get past 'v' */
+       qv = 1; /* force quoted version processing */
+    }
     while (isDIGIT(*pos))
        pos++;
     if (!isALPHA(*pos)) {
@@ -3777,13 +3724,13 @@ Perl_scan_version(pTHX_ char *s, SV *rv)
                I32 mult = 1;
                I32 orev;
                if ( s < pos && s > start && *(s-1) == '_' ) {
-                       mult *= -1;     /* beta version */
+                       mult *= -1;     /* alpha version */
                }
                /* the following if() will only be true after the decimal
                 * point of a version originally created with a bare
                 * floating point number, i.e. not quoted in any way
                 */
-               if ( s > start+1 && saw_period == 1 && !saw_under ) {
+               if ( !qv && s > start+1 && saw_period == 1 && !saw_under ) {
                    mult = 100;
                    while ( s < end ) {
                        orev = rev;
@@ -3842,24 +3789,21 @@ SV *
 Perl_new_version(pTHX_ SV *ver)
 {
     SV *rv = newSV(0);
-    char *version;
-    if ( SvNOK(ver) ) /* may get too much accuracy */ 
-    {
-       char tbuf[64];
-       sprintf(tbuf,"%.9"NVgf, SvNVX(ver));
-       version = savepv(tbuf);
-    }
 #ifdef SvVOK
-    else if ( SvVOK(ver) ) { /* already a v-string */
+    if ( SvVOK(ver) ) { /* already a v-string */
+       char *version;
        MAGIC* mg = mg_find(ver,PERL_MAGIC_vstring);
        version = savepvn( (const char*)mg->mg_ptr,mg->mg_len );
+       sv_setpv(rv,version);
+       Safefree(version);
     }
+    else {
 #endif
-    else /* must be a string or something like a string */
-    {
-       version = (char *)SvPV(ver,PL_na);
+    sv_setsv(rv,ver); /* make a duplicate */
+#ifdef SvVOK
     }
-    version = scan_version(version,rv);
+#endif
+    upg_version(rv);
     return rv;
 }
 
@@ -3878,14 +3822,29 @@ Returns a pointer to the upgraded SV.
 SV *
 Perl_upg_version(pTHX_ SV *ver)
 {
-    char *version = savepvn(SvPVX(ver),SvCUR(ver));
+    char *version;
+    bool qv = 0;
+
+    if ( SvNOK(ver) ) /* may get too much accuracy */ 
+    {
+       char tbuf[64];
+       sprintf(tbuf,"%.9"NVgf, SvNVX(ver));
+       version = savepv(tbuf);
+    }
 #ifdef SvVOK
-    if ( SvVOK(ver) ) { /* already a v-string */
+    else if ( SvVOK(ver) ) { /* already a v-string */
        MAGIC* mg = mg_find(ver,PERL_MAGIC_vstring);
        version = savepvn( (const char*)mg->mg_ptr,mg->mg_len );
+       qv = 1;
     }
 #endif
-    version = scan_version(version,ver);
+    else /* must be a string or something like a string */
+    {
+       STRLEN n_a;
+       version = savepv(SvPV(ver,n_a));
+    }
+    (void)scan_version(version, ver, qv);
+    Safefree(version);
     return ver;
 }
 
@@ -3908,7 +3867,7 @@ SV *
 Perl_vnumify(pTHX_ SV *vs)
 {
     I32 i, len, digit;
-    SV *sv = NEWSV(92,0);
+    SV *sv = newSV(0);
     if ( SvROK(vs) )
        vs = SvRV(vs);
     len = av_len((AV *)vs);
@@ -3948,7 +3907,7 @@ SV *
 Perl_vstringify(pTHX_ SV *vs)
 {
     I32 i, len, digit;
-    SV *sv = NEWSV(92,0);
+    SV *sv = newSV(0);
     if ( SvROK(vs) )
        vs = SvRV(vs);
     len = av_len((AV *)vs);
@@ -3967,8 +3926,12 @@ Perl_vstringify(pTHX_ SV *vs)
        else
            Perl_sv_catpvf(aTHX_ sv,".%"IVdf,(IV)digit);
     }
-    if ( len == 0 )
-        Perl_sv_catpv(aTHX_ sv,".0");
+    
+    if ( len <= 2 ) { /* short version, must be at least three */
+       for ( len = 2 - len; len != 0; len-- )
+           Perl_sv_catpv(aTHX_ sv,".0");
+    }
+
     return sv;
 } 
 
@@ -3998,23 +3961,36 @@ Perl_vcmp(pTHX_ SV *lsv, SV *rsv)
     {
        I32 left  = SvIV(*av_fetch((AV *)lsv,i,0));
        I32 right = SvIV(*av_fetch((AV *)rsv,i,0));
-       bool lbeta = left  < 0 ? 1 : 0;
-       bool rbeta = right < 0 ? 1 : 0;
-       left  = PERL_ABS(left);
-       right = PERL_ABS(right);
-       if ( left < right || (left == right && lbeta && !rbeta) )
+       bool lalpha = left  < 0 ? 1 : 0;
+       bool ralpha = right < 0 ? 1 : 0;
+       left  = abs(left);
+       right = abs(right);
+       if ( left < right || (left == right && lalpha && !ralpha) )
            retval = -1;
-       if ( left > right || (left == right && rbeta && !lbeta) )
+       if ( left > right || (left == right && ralpha && !lalpha) )
            retval = +1;
        i++;
     }
 
-    if ( l != r && retval == 0 ) /* possible match except for trailing 0 */
+    if ( l != r && retval == 0 ) /* possible match except for trailing 0's */
     {
-       if ( !( l < r && r-l == 1 && SvIV(*av_fetch((AV *)rsv,r,0)) == 0 ) &&
-            !( l-r == 1 && SvIV(*av_fetch((AV *)lsv,l,0)) == 0 ) )
+       if ( l < r )
        {
-           retval = l < r ? -1 : +1; /* not a match after all */
+           while ( i <= r && retval == 0 )
+           {
+               if ( SvIV(*av_fetch((AV *)rsv,i,0)) != 0 )
+                   retval = -1; /* not a match after all */
+               i++;
+           }
+       }
+       else
+       {
+           while ( i <= l && retval == 0 )
+           {
+               if ( SvIV(*av_fetch((AV *)lsv,i,0)) != 0 )
+                   retval = +1; /* not a match after all */
+               i++;
+           }
        }
     }
     return retval;
@@ -4456,3 +4432,39 @@ Perl_seed(pTHX)
     return u;
 }
 
+UV
+Perl_get_hash_seed(pTHX)
+{
+     char *s = PerlEnv_getenv("PERL_HASH_SEED");
+     UV myseed = 0;
+
+     if (s)
+         while (isSPACE(*s)) s++;
+     if (s && isDIGIT(*s))
+         myseed = (UV)Atoul(s);
+     else
+#ifdef USE_HASH_SEED_EXPLICIT
+     if (s)
+#endif
+     {
+         /* Compute a random seed */
+         (void)seedDrand01((Rand_seed_t)seed());
+         myseed = (UV)(Drand01() * (NV)UV_MAX);
+#if RANDBITS < (UVSIZE * 8)
+         /* Since there are not enough randbits to to reach all
+          * the bits of a UV, the low bits might need extra
+          * help.  Sum in another random number that will
+          * fill in the low bits. */
+         myseed +=
+              (UV)(Drand01() * (NV)((1 << ((UVSIZE * 8 - RANDBITS))) - 1));
+#endif /* RANDBITS < (UVSIZE * 8) */
+         if (myseed == 0) { /* Superparanoia. */
+             myseed = (UV)(Drand01() * (NV)UV_MAX); /* One more chance. */
+             if (myseed == 0)
+                 Perl_croak(aTHX_ "Your random numbers are not that random");
+         }
+     }
+     PL_rehash_seed_set = TRUE;
+
+     return myseed;
+}