[win32] merge change#985 from maintbranch
[p5sagit/p5-mst-13.2.git] / util.c
diff --git a/util.c b/util.c
index 31827b0..e4f408d 100644 (file)
--- a/util.c
+++ b/util.c
 #define FLUSH
 
 #ifdef LEAKTEST
-static void xstat _((void));
-#endif
 
-#ifdef USE_THREADS
-static U32 threadnum = 0;
-#endif /* USE_THREADS */
+static void xstat _((int));
+long xcount[MAXXCOUNT];
+long lastxcount[MAXXCOUNT];
+long xycount[MAXXCOUNT][MAXYCOUNT];
+long lastxycount[MAXXCOUNT][MAXYCOUNT];
+
+#endif
 
 #ifndef MYMALLOC
 
@@ -211,64 +213,142 @@ safecalloc(MEM_SIZE count, MEM_SIZE size)
 
 #ifdef LEAKTEST
 
-#define ALIGN sizeof(long)
+struct mem_test_strut {
+    union {
+       long type;
+       char c[2];
+    } u;
+    long size;
+};
+
+#    define ALIGN sizeof(struct mem_test_strut)
+
+#    define sizeof_chunk(ch) (((struct mem_test_strut*) (ch))->size)
+#    define typeof_chunk(ch) \
+       (((struct mem_test_strut*) (ch))->u.c[0] + ((struct mem_test_strut*) (ch))->u.c[1]*100)
+#    define set_typeof_chunk(ch,t) \
+       (((struct mem_test_strut*) (ch))->u.c[0] = t % 100, ((struct mem_test_strut*) (ch))->u.c[1] = t / 100)
+#define SIZE_TO_Y(size) ( (size) > MAXY_SIZE                           \
+                         ? MAXYCOUNT - 1                               \
+                         : ( (size) > 40                               \
+                             ? ((size) - 1)/8 + 5                      \
+                             : ((size) - 1)/4))
 
 Malloc_t
 safexmalloc(I32 x, MEM_SIZE size)
 {
-    register Malloc_t where;
+    register char* where = (char*)safemalloc(size + ALIGN);
 
-    where = safemalloc(size + ALIGN);
-    xcount[x]++;
-    where[0] = x % 100;
-    where[1] = x / 100;
-    return where + ALIGN;
+    xcount[x] += size;
+    xycount[x][SIZE_TO_Y(size)]++;
+    set_typeof_chunk(where, x);
+    sizeof_chunk(where) = size;
+    return (Malloc_t)(where + ALIGN);
 }
 
 Malloc_t
-safexrealloc(Malloc_t where, MEM_SIZE size)
+safexrealloc(Malloc_t wh, MEM_SIZE size)
 {
-    register Malloc_t new = saferealloc(where - ALIGN, size + ALIGN);
-    return new + ALIGN;
+    char *where = (char*)wh;
+
+    if (!wh)
+       return safexmalloc(0,size);
+    
+    {
+       MEM_SIZE old = sizeof_chunk(where - ALIGN);
+       int t = typeof_chunk(where - ALIGN);
+       register char* new = (char*)saferealloc(where - ALIGN, size + ALIGN);
+    
+       xycount[t][SIZE_TO_Y(old)]--;
+       xycount[t][SIZE_TO_Y(size)]++;
+       xcount[t] += size - old;
+       sizeof_chunk(new) = size;
+       return (Malloc_t)(new + ALIGN);
+    }
 }
 
 void
-safexfree(Malloc_t where)
+safexfree(Malloc_t wh)
 {
     I32 x;
-
+    char *where = (char*)wh;
+    MEM_SIZE size;
+    
     if (!where)
        return;
     where -= ALIGN;
+    size = sizeof_chunk(where);
     x = where[0] + 100 * where[1];
-    xcount[x]--;
+    xcount[x] -= size;
+    xycount[x][SIZE_TO_Y(size)]--;
     safefree(where);
 }
 
 Malloc_t
 safexcalloc(I32 x,MEM_SIZE count, MEM_SIZE size)
 {
-    register Malloc_t where;
-
-    where = safexmalloc(x, size * count + ALIGN);
-    xcount[x]++;
-    memset((void*)where + ALIGN, 0, size * count);
-    where[0] = x % 100;
-    where[1] = x / 100;
-    return where + ALIGN;
+    register char * where = (char*)safexmalloc(x, size * count + ALIGN);
+    xcount[x] += size;
+    xycount[x][SIZE_TO_Y(size)]++;
+    memset((void*)(where + ALIGN), 0, size * count);
+    set_typeof_chunk(where, x);
+    sizeof_chunk(where) = size;
+    return (Malloc_t)(where + ALIGN);
 }
 
 static void
-xstat(void)
+xstat(int flag)
 {
-    register I32 i;
+    register I32 i, j, total = 0;
+    I32 subtot[MAXYCOUNT];
 
+    for (j = 0; j < MAXYCOUNT; j++) {
+       subtot[j] = 0;
+    }
+    
+    PerlIO_printf(PerlIO_stderr(), "   Id  subtot   4   8  12  16  20  24  28  32  36  40  48  56  64  72  80 80+\n", total);
     for (i = 0; i < MAXXCOUNT; i++) {
-       if (xcount[i] > lastxcount[i]) {
-           PerlIO_printf(PerlIO_stderr(),"%2d %2d\t%ld\n", i / 100, i % 100, xcount[i]);
+       total += xcount[i];
+       for (j = 0; j < MAXYCOUNT; j++) {
+           subtot[j] += xycount[i][j];
+       }
+       if (flag == 0
+           ? xcount[i]                 /* Have something */
+           : (flag == 2 
+              ? xcount[i] != lastxcount[i] /* Changed */
+              : xcount[i] > lastxcount[i])) { /* Growed */
+           PerlIO_printf(PerlIO_stderr(),"%2d %02d %7ld ", i / 100, i % 100, 
+                         flag == 2 ? xcount[i] - lastxcount[i] : xcount[i]);
            lastxcount[i] = xcount[i];
+           for (j = 0; j < MAXYCOUNT; j++) {
+               if ( flag == 0 
+                    ? xycount[i][j]    /* Have something */
+                    : (flag == 2 
+                       ? xycount[i][j] != lastxycount[i][j] /* Changed */
+                       : xycount[i][j] > lastxycount[i][j])) { /* Growed */
+                   PerlIO_printf(PerlIO_stderr(),"%3ld ", 
+                                 flag == 2 
+                                 ? xycount[i][j] - lastxycount[i][j] 
+                                 : xycount[i][j]);
+                   lastxycount[i][j] = xycount[i][j];
+               } else {
+                   PerlIO_printf(PerlIO_stderr(), "  . ", xycount[i][j]);
+               }
+           }
+           PerlIO_printf(PerlIO_stderr(), "\n");
        }
     }
+    if (flag != 2) {
+       PerlIO_printf(PerlIO_stderr(), "Total %7ld ", total);
+       for (j = 0; j < MAXYCOUNT; j++) {
+           if (subtot[j]) {
+               PerlIO_printf(PerlIO_stderr(), "%3ld ", subtot[j]);
+           } else {
+               PerlIO_printf(PerlIO_stderr(), "  . ");
+           }
+       }
+       PerlIO_printf(PerlIO_stderr(), "\n");   
+    }
 }
 
 #endif /* LEAKTEST */
@@ -811,7 +891,7 @@ mem_collxfrm(const char *s, STRLEN len, STRLEN *xlen)
 #endif /* USE_LOCALE_COLLATE */
 
 void
-fbm_compile(SV *sv)
+fbm_compile(SV *sv, U32 flags /* not used yet */)
 {
     register unsigned char *s;
     register unsigned char *table;
@@ -1193,20 +1273,13 @@ die(pat, va_alist)
                          "%p: die: curstack = %p, mainstack = %p\n",
                          thr, curstack, mainstack));
 #endif /* USE_THREADS */
-    /* We have to switch back to mainstack or die_where may try to pop
-     * the eval block from the wrong stack if die is being called from a
-     * signal handler.  - dkindred@cs.cmu.edu */
-    if (curstack != mainstack) {
-        dSP;
-        SWITCHSTACK(curstack, mainstack);
-    }
 
 #ifdef I_STDARG
     va_start(args, pat);
 #else
     va_start(args);
 #endif
-    message = mess(pat, &args);
+    message = pat ? mess(pat, &args) : Nullch;
     va_end(args);
 
 #ifdef USE_THREADS
@@ -1227,15 +1300,21 @@ die(pat, va_alist)
            SV *msg;
 
            ENTER;
-           msg = newSVpv(message, 0);
-           SvREADONLY_on(msg);
-           SAVEFREESV(msg);
+           if(message) {
+               msg = newSVpv(message, 0);
+               SvREADONLY_on(msg);
+               SAVEFREESV(msg);
+           }
+           else {
+               msg = ERRSV;
+           }
 
-           PUSHMARK(sp);
+           PUSHSTACK(SI_DIEHOOK);
+           PUSHMARK(SP);
            XPUSHs(msg);
            PUTBACK;
            perl_call_sv((SV*)cv, G_DISCARD);
-
+           POPSTACK();
            LEAVE;
        }
     }
@@ -1296,11 +1375,12 @@ croak(pat, va_alist)
            SvREADONLY_on(msg);
            SAVEFREESV(msg);
 
-           PUSHMARK(sp);
+           PUSHSTACK(SI_DIEHOOK);
+           PUSHMARK(SP);
            XPUSHs(msg);
            PUTBACK;
            perl_call_sv((SV*)cv, G_DISCARD);
-
+           POPSTACK();
            LEAVE;
        }
     }
@@ -1355,18 +1435,24 @@ warn(pat,va_alist)
            SvREADONLY_on(msg);
            SAVEFREESV(msg);
 
-           PUSHMARK(sp);
+           PUSHSTACK(SI_WARNHOOK);
+           PUSHMARK(SP);
            XPUSHs(msg);
            PUTBACK;
            perl_call_sv((SV*)cv, G_DISCARD);
-
+           POPSTACK();
            LEAVE;
            return;
        }
     }
     PerlIO_puts(PerlIO_stderr(),message);
 #ifdef LEAKTEST
-    DEBUG_L(xstat());
+    DEBUG_L(*message == '!' 
+           ? (xstat(message[1]=='!'
+                    ? (message[2]=='!' ? 2 : 1)
+                    : 0)
+              , 0)
+           : 0);
 #endif
     (void)PerlIO_flush(PerlIO_stderr());
 }
@@ -1622,12 +1708,7 @@ char *args;
 #ifdef MYSWAP
 #if BYTEORDER != 0x4321
 short
-#ifndef CAN_PROTOTYPE
-my_swap(s)
-short s;
-#else
 my_swap(short s)
-#endif
 {
 #if (BYTEORDER & 1) == 0
     short result;
@@ -1640,12 +1721,7 @@ my_swap(short s)
 }
 
 long
-#ifndef CAN_PROTOTYPE
-my_htonl(l)
-register long l;
-#else
 my_htonl(long l)
-#endif
 {
     union {
        long result;
@@ -1674,12 +1750,7 @@ my_htonl(long l)
 }
 
 long
-#ifndef CAN_PROTOTYPE
-my_ntohl(l)
-register long l;
-#else
 my_ntohl(long l)
-#endif
 {
     union {
        long l;
@@ -1785,14 +1856,14 @@ my_popen(char *cmd, char *mode)
        return my_syspopen(cmd,mode);
     }
 #endif 
-    if (PerlProc_pipe(p) < 0)
-       return Nullfp;
     This = (*mode == 'w');
     that = !This;
     if (doexec && tainting) {
        taint_env();
        taint_proper("Insecure %s%s", "EXEC");
     }
+    if (PerlProc_pipe(p) < 0)
+       return Nullfp;
     while ((pid = (doexec?vfork():fork())) < 0) {
        if (errno != EAGAIN) {
            PerlLIO_close(p[This]);
@@ -2020,6 +2091,7 @@ my_pclose(PerlIO *ptr)
     int status;
     SV **svp;
     int pid;
+    int pid2;
     bool close_failed;
     int saved_errno;
 #ifdef VMS
@@ -2054,8 +2126,8 @@ my_pclose(PerlIO *ptr)
     rsignal_save(SIGINT, SIG_IGN, &istat);
     rsignal_save(SIGQUIT, SIG_IGN, &qstat);
     do {
-       pid = wait4pid(pid, &status, 0);
-    } while (pid == -1 && errno == EINTR);
+       pid2 = wait4pid(pid, &status, 0);
+    } while (pid2 == -1 && errno == EINTR);
     rsignal_restore(SIGHUP, &hstat);
     rsignal_restore(SIGINT, &istat);
     rsignal_restore(SIGQUIT, &qstat);
@@ -2063,7 +2135,7 @@ my_pclose(PerlIO *ptr)
        SETERRNO(saved_errno, saved_vaxc_errno);
        return -1;
     }
-    return(pid < 0 ? pid : status == 0 ? 0 : (errno = 0, status));
+    return(pid2 < 0 ? pid2 : status == 0 ? 0 : (errno = 0, status));
 }
 #endif /* !DOSISH */
 
@@ -2282,13 +2354,13 @@ char *b;
        sv_setpv(tmpsv, ".");
     else
        sv_setpvn(tmpsv, a, fa - a);
-    if (Stat(SvPVX(tmpsv), &tmpstatbuf1) < 0)
+    if (PerlLIO_stat(SvPVX(tmpsv), &tmpstatbuf1) < 0)
        return FALSE;
     if (fb == b)
        sv_setpv(tmpsv, ".");
     else
        sv_setpvn(tmpsv, b, fb - b);
-    if (Stat(SvPVX(tmpsv), &tmpstatbuf2) < 0)
+    if (PerlLIO_stat(SvPVX(tmpsv), &tmpstatbuf2) < 0)
        return FALSE;
     return tmpstatbuf1.st_dev == tmpstatbuf2.st_dev &&
           tmpstatbuf1.st_ino == tmpstatbuf2.st_ino;
@@ -2323,7 +2395,7 @@ scan_hex(char *start, I32 len, I32 *retlen)
     register char *s = start;
     register UV retval = 0;
     bool overflowed = FALSE;
-    char *tmp;
+    char *tmp = s;
 
     while (len-- && *s && (tmp = strchr((char *) hexdigit, *s))) {
        register UV n = retval << 4;
@@ -2334,10 +2406,218 @@ scan_hex(char *start, I32 len, I32 *retlen)
        retval = n | ((tmp - hexdigit) & 15);
        s++;
     }
+    if (dowarn && !tmp) {
+       warn("Illegal hex digit ignored");
+    }
     *retlen = s - start;
     return retval;
 }
 
+char*
+find_script(char *scriptname, bool dosearch, char **search_ext, I32 flags)
+{
+    dTHR;
+    char *xfound = Nullch;
+    char *xfailed = Nullch;
+    register char *s;
+    I32 len;
+    int retval;
+#if defined(DOSISH) && !defined(OS2) && !defined(atarist)
+#  define SEARCH_EXTS ".bat", ".cmd", NULL
+#  define MAX_EXT_LEN 4
+#endif
+#ifdef OS2
+#  define SEARCH_EXTS ".cmd", ".btm", ".bat", ".pl", NULL
+#  define MAX_EXT_LEN 4
+#endif
+#ifdef VMS
+#  define SEARCH_EXTS ".pl", ".com", NULL
+#  define MAX_EXT_LEN 4
+#endif
+    /* additional extensions to try in each dir if scriptname not found */
+#ifdef SEARCH_EXTS
+    char *exts[] = { SEARCH_EXTS };
+    char **ext = search_ext ? search_ext : exts;
+    int extidx = 0, i = 0;
+    char *curext = Nullch;
+#else
+#  define MAX_EXT_LEN 0
+#endif
+
+    /*
+     * If dosearch is true and if scriptname does not contain path
+     * delimiters, search the PATH for scriptname.
+     *
+     * If SEARCH_EXTS is also defined, will look for each
+     * scriptname{SEARCH_EXTS} whenever scriptname is not found
+     * while searching the PATH.
+     *
+     * Assuming SEARCH_EXTS is C<".foo",".bar",NULL>, PATH search
+     * proceeds as follows:
+     *   If DOSISH or VMSISH:
+     *     + look for ./scriptname{,.foo,.bar}
+     *     + search the PATH for scriptname{,.foo,.bar}
+     *
+     *   If !DOSISH:
+     *     + look *only* in the PATH for scriptname{,.foo,.bar} (note
+     *       this will not look in '.' if it's not in the PATH)
+     */
+
+#ifdef VMS
+#  ifdef ALWAYS_DEFTYPES
+    len = strlen(scriptname);
+    if (!(len == 1 && *scriptname == '-') && scriptname[len-1] != ':') {
+       int hasdir, idx = 0, deftypes = 1;
+       bool seen_dot = 1;
+
+       hasdir = !dosearch || (strpbrk(scriptname,":[</") != Nullch) ;
+#  else
+    if (dosearch) {
+       int hasdir, idx = 0, deftypes = 1;
+       bool seen_dot = 1;
+
+       hasdir = (strpbrk(scriptname,":[</") != Nullch) ;
+#  endif
+       /* The first time through, just add SEARCH_EXTS to whatever we
+        * already have, so we can check for default file types. */
+       while (deftypes ||
+              (!hasdir && my_trnlnm("DCL$PATH",tokenbuf,idx++)) )
+       {
+           if (deftypes) {
+               deftypes = 0;
+               *tokenbuf = '\0';
+           }
+           if ((strlen(tokenbuf) + strlen(scriptname)
+                + MAX_EXT_LEN) >= sizeof tokenbuf)
+               continue;       /* don't search dir with too-long name */
+           strcat(tokenbuf, scriptname);
+#else  /* !VMS */
+
+#ifdef DOSISH
+    if (strEQ(scriptname, "-"))
+       dosearch = 0;
+    if (dosearch) {            /* Look in '.' first. */
+       char *cur = scriptname;
+#ifdef SEARCH_EXTS
+       if ((curext = strrchr(scriptname,'.'))) /* possible current ext */
+           while (ext[i])
+               if (strEQ(ext[i++],curext)) {
+                   extidx = -1;                /* already has an ext */
+                   break;
+               }
+       do {
+#endif
+           DEBUG_p(PerlIO_printf(Perl_debug_log,
+                                 "Looking for %s\n",cur));
+           if (PerlLIO_stat(cur,&statbuf) >= 0) {
+               dosearch = 0;
+               scriptname = cur;
+#ifdef SEARCH_EXTS
+               break;
+#endif
+           }
+#ifdef SEARCH_EXTS
+           if (cur == scriptname) {
+               len = strlen(scriptname);
+               if (len+MAX_EXT_LEN+1 >= sizeof(tokenbuf))
+                   break;
+               cur = strcpy(tokenbuf, scriptname);
+           }
+       } while (extidx >= 0 && ext[extidx]     /* try an extension? */
+                && strcpy(tokenbuf+len, ext[extidx++]));
+#endif
+    }
+#endif
+
+    if (dosearch && !strchr(scriptname, '/')
+#ifdef DOSISH
+                && !strchr(scriptname, '\\')
+#endif
+                && (s = PerlEnv_getenv("PATH"))) {
+       bool seen_dot = 0;
+       
+       bufend = s + strlen(s);
+       while (s < bufend) {
+#if defined(atarist) || defined(DOSISH)
+           for (len = 0; *s
+#  ifdef atarist
+                   && *s != ','
+#  endif
+                   && *s != ';'; len++, s++) {
+               if (len < sizeof tokenbuf)
+                   tokenbuf[len] = *s;
+           }
+           if (len < sizeof tokenbuf)
+               tokenbuf[len] = '\0';
+#else  /* ! (atarist || DOSISH) */
+           s = delimcpy(tokenbuf, tokenbuf + sizeof tokenbuf, s, bufend,
+                       ':',
+                       &len);
+#endif /* ! (atarist || DOSISH) */
+           if (s < bufend)
+               s++;
+           if (len + 1 + strlen(scriptname) + MAX_EXT_LEN >= sizeof tokenbuf)
+               continue;       /* don't search dir with too-long name */
+           if (len
+#if defined(atarist) || defined(DOSISH)
+               && tokenbuf[len - 1] != '/'
+               && tokenbuf[len - 1] != '\\'
+#endif
+              )
+               tokenbuf[len++] = '/';
+           if (len == 2 && tokenbuf[0] == '.')
+               seen_dot = 1;
+           (void)strcpy(tokenbuf + len, scriptname);
+#endif  /* !VMS */
+
+#ifdef SEARCH_EXTS
+           len = strlen(tokenbuf);
+           if (extidx > 0)     /* reset after previous loop */
+               extidx = 0;
+           do {
+#endif
+               DEBUG_p(PerlIO_printf(Perl_debug_log, "Looking for %s\n",tokenbuf));
+               retval = PerlLIO_stat(tokenbuf,&statbuf);
+#ifdef SEARCH_EXTS
+           } while (  retval < 0               /* not there */
+                   && extidx>=0 && ext[extidx] /* try an extension? */
+                   && strcpy(tokenbuf+len, ext[extidx++])
+               );
+#endif
+           if (retval < 0)
+               continue;
+           if (S_ISREG(statbuf.st_mode)
+               && cando(S_IRUSR,TRUE,&statbuf)
+#ifndef DOSISH
+               && cando(S_IXUSR,TRUE,&statbuf)
+#endif
+               )
+           {
+               xfound = tokenbuf;              /* bingo! */
+               break;
+           }
+           if (!xfailed)
+               xfailed = savepv(tokenbuf);
+       }
+#ifndef DOSISH
+       if (!xfound && !seen_dot && !xfailed && (PerlLIO_stat(scriptname,&statbuf) < 0))
+#endif
+           seen_dot = 1;                       /* Disable message. */
+       if (!xfound) 
+           scriptname = NULL;
+/*         croak("Can't %s %s%s%s",
+                 (xfailed ? "execute" : "find"),
+                 (xfailed ? xfailed : scriptname),
+                 (xfailed ? "" : " on PATH"),
+                 (xfailed || seen_dot) ? "" : ", '.' not in PATH"); */
+       if (xfailed)
+           Safefree(xfailed);
+       scriptname = xfound;
+    }
+    return scriptname;
+}
+
+
 #ifdef USE_THREADS
 #ifdef FAKE_THREADS
 /* Very simplistic scheduler for now */
@@ -2444,11 +2724,11 @@ condpair_magic(SV *sv)
        COND_INIT(&cp->owner_cond);
        COND_INIT(&cp->cond);
        cp->owner = 0;
-       MUTEX_LOCK(&sv_mutex);
+       LOCK_SV_MUTEX;
        mg = mg_find(sv, 'm');
        if (mg) {
            /* someone else beat us to initialising it */
-           MUTEX_UNLOCK(&sv_mutex);
+           UNLOCK_SV_MUTEX;
            MUTEX_DESTROY(&cp->mutex);
            COND_DESTROY(&cp->owner_cond);
            COND_DESTROY(&cp->cond);
@@ -2459,7 +2739,7 @@ condpair_magic(SV *sv)
            mg = SvMAGIC(sv);
            mg->mg_ptr = (char *)cp;
            mg->mg_len = sizeof(cp);
-           MUTEX_UNLOCK(&sv_mutex);
+           UNLOCK_SV_MUTEX;
            DEBUG_L(WITH_THR(PerlIO_printf(PerlIO_stderr(),
                                           "%p: condpair_magic %p\n", thr, sv));)
        }
@@ -2553,6 +2833,7 @@ new_struct_thread(struct perl_thread *t)
                "new_struct_thread: copied threadsv %d %p->%p\n",i, t, thr));
        }
     } 
+    thr->threadsvp = AvARRAY(thr->threadsv);
 
     MUTEX_LOCK(&threads_mutex);
     nthreads++;