This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Small documentation fix to ExtUtils::Constant
[perl5.git] / util.c
diff --git a/util.c b/util.c
index d145262..52319d3 100644 (file)
--- a/util.c
+++ b/util.c
  * not content."  --Gandalf
  */
 
+/* This file contains assorted utility routines.
+ * Which is a polite way of saying any stuff that people couldn't think of
+ * a better place for. Amongst other things, it includes the warning and
+ * dieing stuff, plus wrappers for malloc code.
+ */
+
 #include "EXTERN.h"
 #define PERL_IN_UTIL_C
 #include "perl.h"
@@ -751,12 +757,12 @@ be freed with the C<Safefree()> function.
 char *
 Perl_savepv(pTHX_ const char *pv)
 {
-    register char *newaddr = Nullch;
-    if (pv) {
-       New(902,newaddr,strlen(pv)+1,char);
-       (void)strcpy(newaddr,pv);
-    }
-    return newaddr;
+    register char *newaddr;
+    if (!pv)
+       return Nullch;
+
+    New(902,newaddr,strlen(pv)+1,char);
+    return strcpy(newaddr,pv);
 }
 
 /* same thing but with a known length */
@@ -780,13 +786,13 @@ Perl_savepvn(pTHX_ const char *pv, register I32 len)
     New(903,newaddr,len+1,char);
     /* Give a meaning to NULL pointer mainly for the use in sv_magic() */
     if (pv) {
-       Copy(pv,newaddr,len,char);      /* might not be null terminated */
-       newaddr[len] = '\0';            /* is now */
+       /* might not be null terminated */
+       newaddr[len] = '\0';
+       return CopyD(pv,newaddr,len,char);
     }
     else {
-       Zero(newaddr,len+1,char);
+       return ZeroD(newaddr,len+1,char);
     }
-    return newaddr;
 }
 
 /*
@@ -800,12 +806,17 @@ which is shared between threads.
 char *
 Perl_savesharedpv(pTHX_ const char *pv)
 {
-    register char *newaddr = Nullch;
-    if (pv) {
-       newaddr = (char*)PerlMemShared_malloc(strlen(pv)+1);
-       (void)strcpy(newaddr,pv);
+    register char *newaddr;
+    if (!pv)
+       return Nullch;
+
+    newaddr = (char*)PerlMemShared_malloc(strlen(pv)+1);
+    if (!newaddr) {
+       PerlLIO_write(PerlIO_fileno(Perl_error_log),
+                     PL_no_mem, strlen(PL_no_mem));
+       my_exit(1);
     }
-    return newaddr;
+    return strcpy(newaddr,pv);
 }
 
 
@@ -1026,74 +1037,94 @@ Perl_write_to_stderr(pTHX_ const char* message, int msglen)
     }
 }
 
-OP *
-Perl_vdie(pTHX_ const char* pat, va_list *args)
+/* Common code used by vcroak, vdie and vwarner  */
+
+void S_vdie_common(pTHX_ const char *message, STRLEN msglen, I32 utf8);
+
+char *
+S_vdie_croak_common(pTHX_ const char* pat, va_list* args, STRLEN* msglen,
+                   I32* utf8)
 {
     char *message;
-    int was_in_eval = PL_in_eval;
-    HV *stash;
-    GV *gv;
-    CV *cv;
-    SV *msv;
-    STRLEN msglen;
-    I32 utf8 = 0;
-
-    DEBUG_S(PerlIO_printf(Perl_debug_log,
-                         "%p: die: curstack = %p, mainstack = %p\n",
-                         thr, PL_curstack, PL_mainstack));
 
     if (pat) {
-       msv = vmess(pat, args);
+       SV *msv = vmess(pat, args);
        if (PL_errors && SvCUR(PL_errors)) {
            sv_catsv(PL_errors, msv);
-           message = SvPV(PL_errors, msglen);
+           message = SvPV(PL_errors, *msglen);
            SvCUR_set(PL_errors, 0);
        }
        else
-           message = SvPV(msv,msglen);
-       utf8 = SvUTF8(msv);
+           message = SvPV(msv,*msglen);
+       *utf8 = SvUTF8(msv);
     }
     else {
        message = Nullch;
-       msglen = 0;
     }
 
     DEBUG_S(PerlIO_printf(Perl_debug_log,
-                         "%p: die: message = %s\ndiehook = %p\n",
+                         "%p: die/croak: message = %s\ndiehook = %p\n",
                          thr, message, PL_diehook));
     if (PL_diehook) {
-       /* sv_2cv might call Perl_croak() */
-       SV *olddiehook = PL_diehook;
-       ENTER;
-       SAVESPTR(PL_diehook);
-       PL_diehook = Nullsv;
-       cv = sv_2cv(olddiehook, &stash, &gv, 0);
-       LEAVE;
-       if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
-           dSP;
-           SV *msg;
+       S_vdie_common(aTHX_ message, *msglen, *utf8);
+    }
+    return message;
+}
 
-           ENTER;
-           save_re_context();
-           if (message) {
-               msg = newSVpvn(message, msglen);
-               SvFLAGS(msg) |= utf8;
-               SvREADONLY_on(msg);
-               SAVEFREESV(msg);
-           }
-           else {
-               msg = ERRSV;
-           }
+void
+S_vdie_common(pTHX_ const char *message, STRLEN msglen, I32 utf8)
+{
+    HV *stash;
+    GV *gv;
+    CV *cv;
+    /* sv_2cv might call Perl_croak() */
+    SV *olddiehook = PL_diehook;
+
+    assert(PL_diehook);
+    ENTER;
+    SAVESPTR(PL_diehook);
+    PL_diehook = Nullsv;
+    cv = sv_2cv(olddiehook, &stash, &gv, 0);
+    LEAVE;
+    if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
+       dSP;
+       SV *msg;
 
-           PUSHSTACKi(PERLSI_DIEHOOK);
-           PUSHMARK(SP);
-           XPUSHs(msg);
-           PUTBACK;
-           call_sv((SV*)cv, G_DISCARD);
-           POPSTACK;
-           LEAVE;
+       ENTER;
+       save_re_context();
+       if (message) {
+           msg = newSVpvn(message, msglen);
+           SvFLAGS(msg) |= utf8;
+           SvREADONLY_on(msg);
+           SAVEFREESV(msg);
        }
+       else {
+           msg = ERRSV;
+       }
+
+       PUSHSTACKi(PERLSI_DIEHOOK);
+       PUSHMARK(SP);
+       XPUSHs(msg);
+       PUTBACK;
+       call_sv((SV*)cv, G_DISCARD);
+       POPSTACK;
+       LEAVE;
     }
+}
+
+OP *
+Perl_vdie(pTHX_ const char* pat, va_list *args)
+{
+    char *message;
+    int was_in_eval = PL_in_eval;
+    STRLEN msglen;
+    I32 utf8 = 0;
+
+    DEBUG_S(PerlIO_printf(Perl_debug_log,
+                         "%p: die: curstack = %p, mainstack = %p\n",
+                         thr, PL_curstack, PL_mainstack));
+
+    message = S_vdie_croak_common(aTHX_ pat, args, &msglen, &utf8);
 
     PL_restartop = die_where(message, msglen);
     SvFLAGS(ERRSV) |= utf8;
@@ -1134,65 +1165,11 @@ void
 Perl_vcroak(pTHX_ const char* pat, va_list *args)
 {
     char *message;
-    HV *stash;
-    GV *gv;
-    CV *cv;
-    SV *msv;
     STRLEN msglen;
     I32 utf8 = 0;
 
-    if (pat) {
-       msv = vmess(pat, args);
-       if (PL_errors && SvCUR(PL_errors)) {
-           sv_catsv(PL_errors, msv);
-           message = SvPV(PL_errors, msglen);
-           SvCUR_set(PL_errors, 0);
-       }
-       else
-           message = SvPV(msv,msglen);
-       utf8 = SvUTF8(msv);
-    }
-    else {
-       message = Nullch;
-       msglen = 0;
-    }
-
-    DEBUG_S(PerlIO_printf(Perl_debug_log, "croak: 0x%"UVxf" %s",
-                         PTR2UV(thr), message));
-
-    if (PL_diehook) {
-       /* sv_2cv might call Perl_croak() */
-       SV *olddiehook = PL_diehook;
-       ENTER;
-       SAVESPTR(PL_diehook);
-       PL_diehook = Nullsv;
-       cv = sv_2cv(olddiehook, &stash, &gv, 0);
-       LEAVE;
-       if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
-           dSP;
-           SV *msg;
-
-           ENTER;
-           save_re_context();
-           if (message) {
-               msg = newSVpvn(message, msglen);
-               SvFLAGS(msg) |= utf8;
-               SvREADONLY_on(msg);
-               SAVEFREESV(msg);
-           }
-           else {
-               msg = ERRSV;
-           }
+    message = S_vdie_croak_common(aTHX_ pat, args, &msglen, &utf8);
 
-           PUSHSTACKi(PERLSI_DIEHOOK);
-           PUSHMARK(SP);
-           XPUSHs(msg);
-           PUTBACK;
-           call_sv((SV*)cv, G_DISCARD);
-           POPSTACK;
-           LEAVE;
-       }
-    }
     if (PL_in_eval) {
        PL_restartop = die_where(message, msglen);
        SvFLAGS(ERRSV) |= utf8;
@@ -1350,46 +1327,15 @@ Perl_warner(pTHX_ U32  err, const char* pat,...)
 void
 Perl_vwarner(pTHX_ U32  err, const char* pat, va_list* args)
 {
-    char *message;
-    HV *stash;
-    GV *gv;
-    CV *cv;
-    SV *msv;
-    STRLEN msglen;
-    I32 utf8 = 0;
-
-    msv = vmess(pat, args);
-    message = SvPV(msv, msglen);
-    utf8 = SvUTF8(msv);
-
     if (ckDEAD(err)) {
+       SV *msv = vmess(pat, args);
+       STRLEN msglen;
+       char *message = SvPV(msv, msglen);
+       I32 utf8 = SvUTF8(msv);
+
        if (PL_diehook) {
-           /* sv_2cv might call Perl_croak() */
-           SV *olddiehook = PL_diehook;
-           ENTER;
-           SAVESPTR(PL_diehook);
-           PL_diehook = Nullsv;
-           cv = sv_2cv(olddiehook, &stash, &gv, 0);
-           LEAVE;
-           if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
-               dSP;
-               SV *msg;
-
-               ENTER;
-               save_re_context();
-               msg = newSVpvn(message, msglen);
-               SvFLAGS(msg) |= utf8;
-               SvREADONLY_on(msg);
-               SAVEFREESV(msg);
-
-               PUSHSTACKi(PERLSI_DIEHOOK);
-               PUSHMARK(sp);
-               XPUSHs(msg);
-               PUTBACK;
-               call_sv((SV*)cv, G_DISCARD);
-               POPSTACK;
-               LEAVE;
-           }
+           assert(message);
+           S_vdie_common(aTHX_ message, msglen, utf8);
        }
        if (PL_in_eval) {
            PL_restartop = die_where(message, msglen);
@@ -1400,36 +1346,7 @@ Perl_vwarner(pTHX_ U32  err, const char* pat, va_list* args)
        my_failure_exit();
     }
     else {
-       if (PL_warnhook) {
-           /* sv_2cv might call Perl_warn() */
-           SV *oldwarnhook = PL_warnhook;
-           ENTER;
-           SAVESPTR(PL_warnhook);
-           PL_warnhook = Nullsv;
-           cv = sv_2cv(oldwarnhook, &stash, &gv, 0);
-           LEAVE;
-           if (cv && !CvDEPTH(cv) && (CvROOT(cv) || CvXSUB(cv))) {
-               dSP;
-               SV *msg;
-
-               ENTER;
-               save_re_context();
-               msg = newSVpvn(message, msglen);
-               SvFLAGS(msg) |= utf8;
-               SvREADONLY_on(msg);
-               SAVEFREESV(msg);
-
-               PUSHSTACKi(PERLSI_WARNHOOK);
-               PUSHMARK(sp);
-               XPUSHs(msg);
-               PUTBACK;
-               call_sv((SV*)cv, G_DISCARD);
-               POPSTACK;
-               LEAVE;
-               return;
-           }
-       }
-       write_to_stderr(message, msglen);
+       Perl_vwarn(aTHX_ pat, args);
     }
 }
 
@@ -3876,6 +3793,7 @@ Perl_scan_version(pTHX_ char *s, SV *rv, bool qv)
     bool saw_under = 0;
     SV* sv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */
     (void)sv_upgrade(sv, SVt_PVAV); /* needs to be an AV type */
+    AvREAL_on((AV*)sv);
 
     /* pre-scan the imput string to check for decimals */
     while ( *pos == '.' || *pos == '_' || isDIGIT(*pos) )
@@ -3922,7 +3840,7 @@ Perl_scan_version(pTHX_ char *s, SV *rv, bool qv)
                 * floating point number, i.e. not quoted in any way
                 */
                if ( !qv && s > start+1 && saw_period == 1 ) {
-                   mult *= 100;
+                   mult *= 100;
                    while ( s < end ) {
                        orev = rev;
                        rev += (*s - '0') * mult;
@@ -3962,7 +3880,15 @@ Perl_scan_version(pTHX_ char *s, SV *rv, bool qv)
     }
     if ( qv ) { /* quoted versions always become full version objects */
        I32 len = av_len((AV *)sv);
-       for ( len = 2 - len; len != 0; len-- )
+       /* This for loop appears to trigger a compiler bug on OS X, as it
+          loops infinitely. Yes, len is negative. No, it makes no sense.
+          Compiler in question is:
+          gcc version 3.3 20030304 (Apple Computer, Inc. build 1640)
+          for ( len = 2 - len; len > 0; len-- )
+          av_push((AV *)sv, newSViv(0));
+       */
+       len = 2 - len;
+       while (len-- > 0)
            av_push((AV *)sv, newSViv(0));
     }
     return s;
@@ -3985,6 +3911,20 @@ SV *
 Perl_new_version(pTHX_ SV *ver)
 {
     SV *rv = newSV(0);
+    if ( sv_derived_from(ver,"version") ) /* can just copy directly */
+    {
+       I32 key;
+       AV *av = (AV *)SvRV(ver);
+       SV* sv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */
+       (void)sv_upgrade(sv, SVt_PVAV); /* needs to be an AV type */
+       AvREAL_on((AV*)sv);
+       for ( key = 0; key <= av_len(av); key++ )
+       {
+           I32 rev = SvIV(*av_fetch(av, key, FALSE));
+           av_push((AV *)sv, newSViv(rev));
+       }
+       return rv;
+    }
 #ifdef SvVOK
     if ( SvVOK(ver) ) { /* already a v-string */
        char *version;
@@ -4083,10 +4023,11 @@ Perl_vnumify(pTHX_ SV *vs)
     if ( len > 0 )
     {
        digit = SvIVX(*av_fetch((AV *)vs, len, 0));
-
-       /* Don't display any additional trailing zeros */
        if ( (int)PERL_ABS(digit) != 0 || len == 1 )
        {
+           if ( digit < 0 ) /* alpha version */
+               Perl_sv_catpv(aTHX_ sv,"_");
+           /* Don't display additional trailing zeros */
            Perl_sv_catpvf(aTHX_ sv,"%03d", (int)PERL_ABS(digit));
        }
     }
@@ -4157,12 +4098,13 @@ the original version contained 1 or more dots, respectively
 SV *
 Perl_vstringify(pTHX_ SV *vs)
 {
-    I32 len;
+    I32 len, digit;
     if ( SvROK(vs) )
        vs = SvRV(vs);
     len = av_len((AV *)vs);
+    digit = SvIVX(*av_fetch((AV *)vs, len, 0));
     
-    if ( len < 2 )
+    if ( len < 2 || ( len == 2 && digit < 0 ) )
        return vnumify(vs);
     else
        return vnormal(vs);