Fix a syntax error in test
[p5sagit/p5-mst-13.2.git] / util.c
diff --git a/util.c b/util.c
index abd0db9..407d86f 100644 (file)
--- a/util.c
+++ b/util.c
@@ -895,8 +895,8 @@ Perl_savepv(pTHX_ const char *pv)
 
 Perl's version of what C<strndup()> would be if it existed. Returns a
 pointer to a newly allocated string which is a duplicate of the first
-C<len> bytes from C<pv>. The memory allocated for the new string can be
-freed with the C<Safefree()> function.
+C<len> bytes from C<pv>, plus a trailing NUL byte. The memory allocated for
+the new string can be freed with the C<Safefree()> function.
 
 =cut
 */
@@ -1456,7 +1456,7 @@ void
 Perl_vwarner(pTHX_ U32  err, const char* pat, va_list* args)
 {
     dVAR;
-    if (ckDEAD(err)) {
+    if (PL_warnhook == PERL_WARNHOOK_FATAL || ckDEAD(err)) {
        SV * const msv = vmess(pat, args);
        STRLEN msglen;
        const char * const message = SvPV_const(msv, msglen);
@@ -1533,7 +1533,7 @@ Perl_ckwarn_d(pTHX_ U32 w)
 
 /* Set buffer=NULL to get a new one.  */
 STRLEN *
-Perl_new_warnings_bitfield(STRLEN *buffer, const char *const bits,
+Perl_new_warnings_bitfield(pTHX_ STRLEN *buffer, const char *const bits,
                           STRLEN size) {
     const MEM_SIZE len_wanted = sizeof(STRLEN) + size;
 
@@ -1601,15 +1601,15 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
     }
     else
        safesysfree(environ[i]);
-    nlen = strlen(nam);
-    vlen = strlen(val);
+       nlen = strlen(nam);
+       vlen = strlen(val);
 
-    environ[i] = (char*)safesysmalloc((nlen+vlen+2) * sizeof(char));
-    /* all that work just for this */
-    my_setenv_format(environ[i], nam, nlen, val, vlen);
+       environ[i] = (char*)safesysmalloc((nlen+vlen+2) * sizeof(char));
+       /* all that work just for this */
+       my_setenv_format(environ[i], nam, nlen, val, vlen);
     } else {
 # endif
-#   if defined(__CYGWIN__) || defined(EPOC) || defined(__SYMBIAN32__)
+#   if defined(__CYGWIN__) || defined(EPOC) || defined(__SYMBIAN32__) || defined(__riscos__)
 #       if defined(HAS_UNSETENV)
         if (val == NULL) {
             (void)unsetenv(nam);
@@ -1894,8 +1894,8 @@ Perl_my_ntohl(pTHX_ long l)
                type value;                                     \
                char c[sizeof(type)];                           \
            } u;                                                \
-           register I32 i;                                     \
-           register I32 s = 0;                                 \
+           register U32 i;                                     \
+           register U32 s = 0;                                 \
            for (i = 0; i < sizeof(u.c); i++, s += 8) {         \
                u.c[i] = (n >> s) & 0xFF;                       \
            }                                                   \
@@ -1910,8 +1910,8 @@ Perl_my_ntohl(pTHX_ long l)
                type value;                                     \
                char c[sizeof(type)];                           \
            } u;                                                \
-           register I32 i;                                     \
-           register I32 s = 0;                                 \
+           register U32 i;                                     \
+           register U32 s = 0;                                 \
            u.value = n;                                        \
            n = 0;                                              \
            for (i = 0; i < sizeof(u.c); i++, s += 8) {         \
@@ -1932,8 +1932,8 @@ Perl_my_ntohl(pTHX_ long l)
                type value;                                     \
                char c[sizeof(type)];                           \
            } u;                                                \
-           register I32 i;                                     \
-           register I32 s = 8*(sizeof(u.c)-1);                 \
+           register U32 i;                                     \
+           register U32 s = 8*(sizeof(u.c)-1);                 \
            for (i = 0; i < sizeof(u.c); i++, s -= 8) {         \
                u.c[i] = (n >> s) & 0xFF;                       \
            }                                                   \
@@ -1948,8 +1948,8 @@ Perl_my_ntohl(pTHX_ long l)
                type value;                                     \
                char c[sizeof(type)];                           \
            } u;                                                \
-           register I32 i;                                     \
-           register I32 s = 8*(sizeof(u.c)-1);                 \
+           register U32 i;                                     \
+           register U32 s = 8*(sizeof(u.c)-1);                 \
            u.value = n;                                        \
            n = 0;                                              \
            for (i = 0; i < sizeof(u.c); i++, s -= 8) {         \
@@ -2224,7 +2224,8 @@ Perl_my_popen_list(pTHX_ char *mode, int n, SV **args)
     /* If we managed to get status pipe check for exec fail */
     if (did_pipes && pid > 0) {
        int errkid;
-       int n = 0, n1;
+       unsigned n = 0;
+       SSize_t n1;
 
        while (n < sizeof(int)) {
            n1 = PerlLIO_read(pp[0],
@@ -2376,7 +2377,8 @@ Perl_my_popen(pTHX_ const char *cmd, const char *mode)
     PL_forkprocess = pid;
     if (did_pipes && pid > 0) {
        int errkid;
-       int n = 0, n1;
+       unsigned n = 0;
+       SSize_t n1;
 
        while (n < sizeof(int)) {
            n1 = PerlLIO_read(pp[0],
@@ -3113,9 +3115,13 @@ Perl_find_script(pTHX_ const char *scriptname, bool dosearch,
            if (len == 2 && tmpbuf[0] == '.')
                seen_dot = 1;
 #endif
+#ifdef HAS_STRLCAT
+           (void)strlcpy(tmpbuf + len, scriptname, sizeof(tmpbuf) - len);
+#else
            /* FIXME? Convert to memcpy by storing previous strlen(scriptname)
             */
            (void)strcpy(tmpbuf + len, scriptname);
+#endif /* #ifdef HAS_STRLCAT */
 #endif  /* !VMS */
 
 #ifdef SEARCH_EXTS
@@ -3427,15 +3433,6 @@ Perl_my_fflush_all(pTHX)
 void
 Perl_report_evil_fh(pTHX_ const GV *gv, const IO *io, I32 op)
 {
-    const char * const func =
-       op == OP_READLINE   ? "readline"  :     /* "<HANDLE>" not nice */
-       op == OP_LEAVEWRITE ? "write" :         /* "write exit" not nice */
-       op < 0              ? "" :              /* handle phoney cases */
-       PL_op_desc[op];
-    const char * const pars = OP_IS_FILETEST(op) ? "" : "()";
-    const char * const type = OP_IS_SOCKET(op)
-           || (gv && io && IoTYPE(io) == IoTYPE_SOCKET)
-               ?  "socket" : "filehandle";
     const char * const name = gv && isGV(gv) ? GvENAME(gv) : NULL;
 
     if (op == OP_phoney_OUTPUT_ONLY || op == OP_phoney_INPUT_ONLY) {
@@ -3464,6 +3461,15 @@ Perl_report_evil_fh(pTHX_ const GV *gv, const IO *io, I32 op)
        }
 
        if (ckWARN(warn_type)) {
+           const char * const pars = OP_IS_FILETEST(op) ? "" : "()";
+           const char * const func =
+               op == OP_READLINE   ? "readline"  :     /* "<HANDLE>" not nice */
+               op == OP_LEAVEWRITE ? "write" :         /* "write exit" not nice */
+               op < 0              ? "" :              /* handle phoney cases */
+               PL_op_desc[op];
+           const char * const type = OP_IS_SOCKET(op)
+                   || (gv && io && IoTYPE(io) == IoTYPE_SOCKET)
+                       ?  "socket" : "filehandle";
            if (name && *name) {
                Perl_warner(aTHX_ packWARN(warn_type),
                            "%s%s on %s %s %s", func, pars, vile, type, name);
@@ -4142,7 +4148,7 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv)
 
            /* Append revision */
            av_push(av, newSViv(rev));
-           if ( *pos == '.' && isDIGIT(pos[1]) )
+           if ( *pos == '.' )
                s = ++pos;
            else if ( *pos == '_' && isDIGIT(pos[1]) )
                s = ++pos;
@@ -4247,7 +4253,7 @@ Perl_new_version(pTHX_ SV *ver)
     }
 #ifdef SvVOK
     {
-       const MAGIC* const mg = SvVOK(ver);
+       const MAGIC* const mg = SvVSTRING_mg(ver);
        if ( mg ) { /* already a v-string */
            const STRLEN len = mg->mg_len;
            char * const version = savepvn( (const char*)mg->mg_ptr, len);
@@ -4288,11 +4294,12 @@ Perl_upg_version(pTHX_ SV *ver)
     if ( SvNOK(ver) ) /* may get too much accuracy */ 
     {
        char tbuf[64];
-       const STRLEN len = my_sprintf(tbuf,"%.9"NVgf, SvNVX(ver));
+       STRLEN len = my_snprintf(tbuf, sizeof(tbuf), "%.9"NVff, SvNVX(ver));
+       while (tbuf[len-1] == '0' && len > 0) len--;
        version = savepvn(tbuf, len);
     }
 #ifdef SvVOK
-    else if ( (mg = SvVOK(ver)) ) { /* already a v-string */
+    else if ( (mg = SvVSTRING_mg(ver)) ) { /* already a v-string */
        version = savepvn( (const char*)mg->mg_ptr,mg->mg_len );
        qv = 1;
     }
@@ -4924,6 +4931,8 @@ Perl_parse_unicode_opts(pTHX_ const char **popt)
                      opt |= PERL_UNICODE_LOCALE_FLAG;  break;
                 case PERL_UNICODE_ARGV:
                      opt |= PERL_UNICODE_ARGV_FLAG;    break;
+                case PERL_UNICODE_UTF8CACHEASSERT:
+                     opt |= PERL_UNICODE_UTF8CACHEASSERT_FLAG; break;
                 default:
                      if (*p != '\n' && *p != '\r')
                          Perl_croak(aTHX_
@@ -5158,20 +5167,78 @@ Perl_free_global_struct(pTHX_ struct perl_vars *plvarsp)
 
 #ifdef PERL_MEM_LOG
 
+/*
+ * PERL_MEM_LOG: the Perl_mem_log_..() will be compiled.
+ *
+ * PERL_MEM_LOG_ENV: if defined, during run time the environment
+ * variable PERL_MEM_LOG will be consulted, and if the integer value
+ * of that is true, the logging will happen.  (The default is to
+ * always log if the PERL_MEM_LOG define was in effect.)
+ */
+
+/*
+ * PERL_MEM_LOG_SPRINTF_BUF_SIZE: size of a (stack-allocated) buffer
+ * the Perl_mem_log_...() will use (either via sprintf or snprintf).
+ */
 #define PERL_MEM_LOG_SPRINTF_BUF_SIZE 128
 
+/*
+ * PERL_MEM_LOG_FD: the file descriptor the Perl_mem_log_...() will
+ * log to.  You can also define in compile time PERL_MEM_LOG_ENV_FD,
+ * in which case the environment variable PERL_MEM_LOG_FD will be
+ * consulted for the file descriptor number to use.
+ */
+#ifndef PERL_MEM_LOG_FD
+#  define PERL_MEM_LOG_FD 2 /* If STDERR is too boring for you. */
+#endif
+
 Malloc_t
 Perl_mem_log_alloc(const UV n, const UV typesize, const char *typename, Malloc_t newalloc, const char *filename, const int linenumber, const char *funcname)
 {
 #ifdef PERL_MEM_LOG_STDERR
-    /* We can't use PerlIO for obvious reasons. */
-    char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE];
-    const STRLEN len = my_sprintf(buf,
-                                 "alloc: %s:%d:%s: %"IVdf" %"UVuf
-                                 " %s = %"IVdf": %"UVxf"\n",
-                                 filename, linenumber, funcname, n, typesize,
-                                 typename, n * typesize, PTR2UV(newalloc));
-    PerlLIO_write(2,  buf, len);
+# if defined(PERL_MEM_LOG_ENV) || defined(PERL_MEM_LOG_ENV_FD)
+    char *s;
+# endif
+# ifdef PERL_MEM_LOG_ENV
+    s = getenv("PERL_MEM_LOG");
+    if (s ? atoi(s) : 0)
+# endif
+    {
+       /* We can't use SVs or PerlIO for obvious reasons,
+        * so we'll use stdio and low-level IO instead. */
+       char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE];
+# ifdef PERL_MEM_LOG_TIMESTAMP
+       struct timeval tv;
+#   ifdef HAS_GETTIMEOFDAY
+       gettimeofday(&tv, 0);
+#   endif
+       /* If there are other OS specific ways of hires time than
+        * gettimeofday() (see ext/Time/HiRes), the easiest way is
+        * probably that they would be used to fill in the struct
+        * timeval. */
+# endif
+       {
+           const STRLEN len =
+               my_snprintf(buf,
+                           PERL_MEM_LOG_SPRINTF_BUF_SIZE,
+#  ifdef PERL_MEM_LOG_TIMESTAMP
+                           "%10d.%06d: "
+# endif
+                           "alloc: %s:%d:%s: %"IVdf" %"UVuf
+                           " %s = %"IVdf": %"UVxf"\n",
+#  ifdef PERL_MEM_LOG_TIMESTAMP
+                           (int)tv.tv_sec, (int)tv.tv_usec,
+# endif
+                           filename, linenumber, funcname, n, typesize,
+                           typename, n * typesize, PTR2UV(newalloc));
+# ifdef PERL_MEM_LOG_ENV_FD
+           s = PerlEnv_getenv("PERL_MEM_LOG_FD");
+           PerlLIO_write(s ? atoi(s) : PERL_MEM_LOG_FD, buf, len);
+# else
+           PerlLIO_write(PERL_MEM_LOG_FD, buf, len);
+#endif
+       }
+    }
 #endif
     return newalloc;
 }
@@ -5180,14 +5247,44 @@ Malloc_t
 Perl_mem_log_realloc(const UV n, const UV typesize, const char *typename, Malloc_t oldalloc, Malloc_t newalloc, const char *filename, const int linenumber, const char *funcname)
 {
 #ifdef PERL_MEM_LOG_STDERR
-    /* We can't use PerlIO for obvious reasons. */
-    char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE];
-    const STRLEN len = my_sprintf(buf, "realloc: %s:%d:%s: %"IVdf" %"UVuf
-                                 " %s = %"IVdf": %"UVxf" -> %"UVxf"\n",
-                                 filename, linenumber, funcname, n, typesize,
-                                 typename, n * typesize, PTR2UV(oldalloc),
-                                 PTR2UV(newalloc));
-    PerlLIO_write(2,  buf, len);
+# if defined(PERL_MEM_LOG_ENV) || defined(PERL_MEM_LOG_ENV_FD)
+    char *s;
+# endif
+# ifdef PERL_MEM_LOG_ENV
+    s = PerlEnv_getenv("PERL_MEM_LOG");
+    if (s ? atoi(s) : 0)
+# endif
+    {
+       /* We can't use SVs or PerlIO for obvious reasons,
+        * so we'll use stdio and low-level IO instead. */
+       char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE];
+#  ifdef PERL_MEM_LOG_TIMESTAMP
+       struct timeval tv;
+       gettimeofday(&tv, 0);
+# endif
+       {
+           const STRLEN len =
+               my_snprintf(buf,
+                           PERL_MEM_LOG_SPRINTF_BUF_SIZE,
+#  ifdef PERL_MEM_LOG_TIMESTAMP
+                           "%10d.%06d: "
+# endif
+                           "realloc: %s:%d:%s: %"IVdf" %"UVuf
+                           " %s = %"IVdf": %"UVxf" -> %"UVxf"\n",
+#  ifdef PERL_MEM_LOG_TIMESTAMP
+                           (int)tv.tv_sec, (int)tv.tv_usec,
+# endif
+                           filename, linenumber, funcname, n, typesize,
+                           typename, n * typesize, PTR2UV(oldalloc),
+                           PTR2UV(newalloc));
+# ifdef PERL_MEM_LOG_ENV_FD
+           s = PerlEnv_getenv("PERL_MEM_LOG_FD");
+           PerlLIO_write(s ? atoi(s) : PERL_MEM_LOG_FD, buf, len);
+# else
+           PerlLIO_write(PERL_MEM_LOG_FD, buf, len);
+# endif
+       }
+    }
 #endif
     return newalloc;
 }
@@ -5196,12 +5293,42 @@ Malloc_t
 Perl_mem_log_free(Malloc_t oldalloc, const char *filename, const int linenumber, const char *funcname)
 {
 #ifdef PERL_MEM_LOG_STDERR
-    /* We can't use PerlIO for obvious reasons. */
-    char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE];
-    const STRLEN len = my_sprintf(buf, "free: %s:%d:%s: %"UVxf"\n",
-                                 filename, linenumber, funcname,
-                                 PTR2UV(oldalloc));
-    PerlLIO_write(2,  buf, len);
+# if defined(PERL_MEM_LOG_ENV) || defined(PERL_MEM_LOG_ENV_FD)
+    char *s;
+# endif
+# ifdef PERL_MEM_LOG_ENV
+    s = PerlEnv_getenv("PERL_MEM_LOG");
+    if (s ? atoi(s) : 0)
+# endif
+    {
+       /* We can't use SVs or PerlIO for obvious reasons,
+        * so we'll use stdio and low-level IO instead. */
+       char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE];
+#  ifdef PERL_MEM_LOG_TIMESTAMP
+       struct timeval tv;
+       gettimeofday(&tv, 0);
+# endif
+       {
+           const STRLEN len =
+               my_snprintf(buf,
+                           PERL_MEM_LOG_SPRINTF_BUF_SIZE,
+#  ifdef PERL_MEM_LOG_TIMESTAMP
+                           "%10d.%06d: "
+# endif
+                           "free: %s:%d:%s: %"UVxf"\n",
+#  ifdef PERL_MEM_LOG_TIMESTAMP
+                           (int)tv.tv_sec, (int)tv.tv_usec,
+# endif
+                           filename, linenumber, funcname,
+                           PTR2UV(oldalloc));
+# ifdef PERL_MEM_LOG_ENV_FD
+           s = PerlEnv_getenv("PERL_MEM_LOG_FD");
+           PerlLIO_write(s ? atoi(s) : PERL_MEM_LOG_FD, buf, len);
+# else
+           PerlLIO_write(PERL_MEM_LOG_FD, buf, len);
+# endif
+       }
+    }
 #endif
     return oldalloc;
 }
@@ -5229,6 +5356,74 @@ Perl_my_sprintf(char *buffer, const char* pat, ...)
 }
 #endif
 
+/*
+=for apidoc my_snprintf
+
+The C library C<snprintf> functionality, if available and
+standards-compliant (uses C<vsnprintf>, actually).  However, if the
+C<vsnprintf> is not available, will unfortunately use the unsafe
+C<vsprintf> which can overrun the buffer (there is an overrun check,
+but that may be too late).  Consider using C<sv_vcatpvf> instead, or
+getting C<vsnprintf>.
+
+=cut
+*/
+int
+Perl_my_snprintf(char *buffer, const Size_t len, const char *format, ...)
+{
+    dTHX;
+    int retval;
+    va_list ap;
+    va_start(ap, format);
+#ifdef HAS_VSNPRINTF
+    retval = vsnprintf(buffer, len, format, ap);
+#else
+    retval = vsprintf(buffer, format, ap);
+#endif
+    va_end(ap);
+    /* vsnprintf() shows failure with >= len, vsprintf() with < 0 */
+    if (retval < 0 || (len > 0 && retval >= len))
+       Perl_croak(aTHX_ "panic: my_snprintf buffer overflow");
+    return retval;
+}
+
+/*
+=for apidoc my_vsnprintf
+
+The C library C<vsnprintf> if available and standards-compliant.
+However, if if the C<vsnprintf> is not available, will unfortunately
+use the unsafe C<vsprintf> which can overrun the buffer (there is an
+overrun check, but that may be too late).  Consider using
+C<sv_vcatpvf> instead, or getting C<vsnprintf>.
+
+=cut
+*/
+int
+Perl_my_vsnprintf(char *buffer, const Size_t len, const char *format, va_list ap)
+{
+    dTHX;
+    int retval;
+#ifdef NEED_VA_COPY
+    va_list apc;
+    Perl_va_copy(ap, apc);
+# ifdef HAS_VSNPRINTF
+    retval = vsnprintf(buffer, len, format, apc);
+# else
+    retval = vsprintf(buffer, format, apc);
+# endif
+#else
+# ifdef HAS_VSNPRINTF
+    retval = vsnprintf(buffer, len, format, ap);
+# else
+    retval = vsprintf(buffer, format, ap);
+# endif
+#endif /* #ifdef NEED_VA_COPY */
+    /* vsnprintf() shows failure with >= len, vsprintf() with < 0 */
+    if (retval < 0 || (len > 0 && retval >= len))
+       Perl_croak(aTHX_ "panic: my_vsnprintf buffer overflow");
+    return retval;
+}
+
 void
 Perl_my_clearenv(pTHX)
 {