Clean up and document API for hashes
[p5sagit/p5-mst-13.2.git] / perl.c
diff --git a/perl.c b/perl.c
index 9b9265c..9f3942e 100644 (file)
--- a/perl.c
+++ b/perl.c
@@ -68,6 +68,7 @@ static void init_perllib _((void));
 static void init_postdump_symbols _((int, char **, char **));
 static void init_predump_symbols _((void));
 static void init_stacks _((void));
+static void my_exit_jump _((void)) __attribute__((noreturn));
 static void nuke_stacks _((void));
 static void open_script _((char *, bool, SV *));
 static void usage _((char *));
@@ -139,6 +140,8 @@ register PerlInterpreter *sv_interp;
 
     init_ids();
 
+    STATUS_ALL_SUCCESS;
+
     SET_NUMERIC_STANDARD();
 #if defined(SUBVERSION) && SUBVERSION > 0
     sprintf(patchlevel, "%7.5f",   (double) 5 
@@ -195,12 +198,18 @@ register PerlInterpreter *sv_interp;
     LEAVE;
     FREETMPS;
 
-    /* We must account for everything.  First the syntax tree. */
+    /* We must account for everything.  */
+
+    /* Destroy the main CV and syntax tree */
     if (main_root) {
        curpad = AvARRAY(comppad);
        op_free(main_root);
-       main_root = 0;
+       main_root = Nullop;
     }
+    main_start = Nullop;
+    SvREFCNT_dec(main_cv);
+    main_cv = Nullcv;
+
     if (sv_objcount) {
        /*
         * Try to destruct global references.  We do this first so that the
@@ -346,13 +355,17 @@ register PerlInterpreter *sv_interp;
     FREETMPS;
     if (destruct_level >= 2) {
        if (scopestack_ix != 0)
-           warn("Unbalanced scopes: %d more ENTERs than LEAVEs\n", scopestack_ix);
+           warn("Unbalanced scopes: %ld more ENTERs than LEAVEs\n",
+                (long)scopestack_ix);
        if (savestack_ix != 0)
-           warn("Unbalanced saves: %d more saves than restores\n", savestack_ix);
+           warn("Unbalanced saves: %ld more saves than restores\n",
+                (long)savestack_ix);
        if (tmps_floor != -1)
-           warn("Unbalanced tmps: %d more allocs than frees\n", tmps_floor + 1);
+           warn("Unbalanced tmps: %ld more allocs than frees\n",
+                (long)tmps_floor + 1);
        if (cxstack_ix != -1)
-           warn("Unbalanced context: %d more PUSHes than POPs\n", cxstack_ix + 1);
+           warn("Unbalanced context: %ld more PUSHes than POPs\n",
+                (long)cxstack_ix + 1);
     }
 
     /* Now absolutely destruct everything, somehow or other, loops or no. */
@@ -396,7 +409,7 @@ register PerlInterpreter *sv_interp;
     SvREFCNT_dec(strtab);
 
     if (sv_count != 0)
-       warn("Scalars leaked: %d\n", sv_count);
+       warn("Scalars leaked: %ld\n", (long)sv_count);
 
     sv_free_arenas();
 
@@ -473,22 +486,28 @@ setuid perl scripts securely.\n");
        return 0;
     }
 
-    if (main_root)
+    if (main_root) {
+       curpad = AvARRAY(comppad);
        op_free(main_root);
-    main_root = 0;
+       main_root = Nullop;
+    }
+    main_start = Nullop;
+    SvREFCNT_dec(main_cv);
+    main_cv = Nullcv;
+
+    time(&basetime);
+    mustcatch = FALSE;
 
     switch (Sigsetjmp(top_env,1)) {
     case 1:
-#ifdef VMS
-       statusvalue = 255;
-#else
-       statusvalue = 1;
-#endif
+       STATUS_ALL_FAILURE;
+       /* FALL THROUGH */
     case 2:
+       /* my_exit() was called */
        curstash = defstash;
        if (endav)
            calllist(endav);
-       return(statusvalue);    /* my_exit() was called */
+       return STATUS_NATIVE_EXPORT;
     case 3:
        PerlIO_printf(PerlIO_stderr(), "panic: top_env\n");
        return 1;
@@ -524,7 +543,6 @@ setuid perl scripts securely.\n");
        case 'n':
        case 'p':
        case 's':
-       case 'T':
        case 'u':
        case 'U':
        case 'v':
@@ -533,6 +551,11 @@ setuid perl scripts securely.\n");
                goto reswitch;
            break;
 
+       case 'T':
+           tainting = TRUE;
+           s++;
+           goto reswitch;
+
        case 'e':
            if (euid != uid || egid != gid)
                croak("No -e allowed in setuid scripts");
@@ -680,7 +703,7 @@ setuid perl scripts securely.\n");
     if (doextract)
        find_beginning();
 
-    compcv = (CV*)NEWSV(1104,0);
+    main_cv = compcv = (CV*)NEWSV(1104,0);
     sv_upgrade((SV *)compcv, SVt_PVCV);
     CvUNIQUE_on(compcv);
 
@@ -766,6 +789,7 @@ PerlInterpreter *sv_interp;
        cxstack_ix = -1;                /* start context stack again */
        break;
     case 2:
+       /* my_exit() was called */
        curstash = defstash;
        if (endav)
            calllist(endav);
@@ -774,7 +798,7 @@ PerlInterpreter *sv_interp;
        if (getenv("PERL_DEBUG_MSTATS"))
            dump_mstats("after execution:  ");
 #endif
-       return(statusvalue);            /* my_exit() was called */
+       return STATUS_NATIVE_EXPORT;
     case 3:
        if (!restartop) {
            PerlIO_printf(PerlIO_stderr(), "panic: restartop\n");
@@ -811,6 +835,7 @@ PerlInterpreter *sv_interp;
        runops();
     }
     else if (main_start) {
+       CvDEPTH(main_cv) = 1;
        op = main_start;
        runops();
     }
@@ -819,24 +844,6 @@ PerlInterpreter *sv_interp;
     return 0;
 }
 
-void
-my_exit(status)
-U32 status;
-{
-    register CONTEXT *cx;
-    I32 gimme;
-    SV **newsp;
-
-    statusvalue = FIXSTATUS(status);
-    if (cxstack_ix >= 0) {
-       if (cxstack_ix > 0)
-           dounwind(0);
-       POPBLOCK(cx,curpm);
-       LEAVE;
-    }
-    Siglongjmp(top_env, 2);
-}
-
 SV*
 perl_get_sv(name, create)
 char* name;
@@ -942,31 +949,36 @@ I32 flags;                /* See G_* flags in cop.h */
 {
     LOGOP myop;                /* fake syntax tree node */
     SV** sp = stack_sp;
-    I32 oldmark = TOPMARK;
+    I32 oldmark;
     I32 retval;
     Sigjmp_buf oldtop;
     I32 oldscope;
     static CV *DBcv;
-    
+    bool oldmustcatch = mustcatch;
+
     if (flags & G_DISCARD) {
        ENTER;
        SAVETMPS;
     }
 
+    Zero(&myop, 1, LOGOP);
+    if (flags & G_NOARGS) {
+       PUSHMARK(sp);
+    }
+    else
+       myop.op_flags |= OPf_STACKED;
+    myop.op_next = Nullop;
+    myop.op_flags |= OPf_KNOW;
+    if (flags & G_ARRAY)
+       myop.op_flags |= OPf_LIST;
     SAVESPTR(op);
     op = (OP*)&myop;
-    Zero(op, 1, LOGOP);
+
     EXTEND(stack_sp, 1);
     *++stack_sp = sv;
+    oldmark = TOPMARK;
     oldscope = scopestack_ix;
 
-    if (!(flags & G_NOARGS))
-       myop.op_flags = OPf_STACKED;
-    myop.op_next = Nullop;
-    myop.op_flags |= OPf_KNOW;
-    if (flags & G_ARRAY)
-      myop.op_flags |= OPf_LIST;
-
     if (perldb && curstash != debstash
           /* Handle first BEGIN of -d. */
          && (DBcv || (DBcv = GvCV(DBsub)))
@@ -1006,11 +1018,7 @@ I32 flags;               /* See G_* flags in cop.h */
        case 0:
            break;
        case 1:
-#ifdef VMS
-           statusvalue = 255;  /* XXX I don't think we use 1 anymore. */
-#else
-       statusvalue = 1;
-#endif
+           STATUS_ALL_FAILURE;
            /* FALL THROUGH */
        case 2:
            /* my_exit() was called */
@@ -1019,7 +1027,7 @@ I32 flags;                /* See G_* flags in cop.h */
            Copy(oldtop, top_env, 1, Sigjmp_buf);
            if (statusvalue)
                croak("Callback called exit");
-           my_exit(statusvalue);
+           my_exit_jump();
            /* NOTREACHED */
        case 3:
            if (restartop) {
@@ -1037,6 +1045,8 @@ I32 flags;                /* See G_* flags in cop.h */
            goto cleanup;
        }
     }
+    else
+       mustcatch = TRUE;
 
     if (op == (OP*)&myop)
        op = pp_entersub();
@@ -1063,6 +1073,9 @@ I32 flags;                /* See G_* flags in cop.h */
        }
        Copy(oldtop, top_env, 1, Sigjmp_buf);
     }
+    else
+       mustcatch = oldmustcatch;
+
     if (flags & G_DISCARD) {
        stack_sp = stack_base + oldmark;
        retval = 0;
@@ -1115,11 +1128,7 @@ restart:
     case 0:
        break;
     case 1:
-#ifdef VMS
-       statusvalue = 255;      /* XXX I don't think we use 1 anymore. */
-#else
-    statusvalue = 1;
-#endif
+       STATUS_ALL_FAILURE;
        /* FALL THROUGH */
     case 2:
        /* my_exit() was called */
@@ -1128,7 +1137,7 @@ restart:
        Copy(oldtop, top_env, 1, Sigjmp_buf);
        if (statusvalue)
            croak("Callback called exit");
-       my_exit(statusvalue);
+       my_exit_jump();
        /* NOTREACHED */
     case 3:
        if (restartop) {
@@ -1386,7 +1395,8 @@ char *s;
        s++;
        return s;
     case 'T':
-       tainting = TRUE;
+       if (!tainting)
+           croak("Too late for \"-T\" option (try putting it first)");
        s++;
        return s;
     case 'u':
@@ -1436,6 +1446,10 @@ GNU General Public License, which may be found in the Perl 5.0 source kit.\n\n")
     case '\n':
     case '\t':
        break;
+#ifdef ALTERNATE_SHEBANG
+    case 'S':                  /* OS/2 needs -S on "extproc" line. */
+       break;
+#endif
     case 'P':
        if (preprocess)
            return s+1;
@@ -1468,9 +1482,9 @@ my_unexec()
 #  ifdef VMS
 #    include <lib$routines.h>
      lib$signal(SS$_DEBUG);  /* ssdef.h #included from vmsish.h */
-#else
+#  else
     ABORT();           /* for use with undump */
-#endif
+#  endif
 #endif
 }
 
@@ -1799,12 +1813,12 @@ char *scriptname;
                (void)PerlIO_close(rsfp);
                if (rsfp = my_popen("/bin/mail root","w")) {    /* heh, heh */
                    PerlIO_printf(rsfp,
-"User %d tried to run dev %d ino %d in place of dev %d ino %d!\n\
-(Filename of set-id script was %s, uid %d gid %d.)\n\nSincerely,\nperl\n",
-                       uid,tmpstatbuf.st_dev, tmpstatbuf.st_ino,
-                       statbuf.st_dev, statbuf.st_ino,
+"User %ld tried to run dev %ld ino %ld in place of dev %ld ino %ld!\n\
+(Filename of set-id script was %s, uid %ld gid %ld.)\n\nSincerely,\nperl\n",
+                       (long)uid,(long)tmpstatbuf.st_dev, (long)tmpstatbuf.st_ino,
+                       (long)statbuf.st_dev, (long)statbuf.st_ino,
                        SvPVX(GvSV(curcop->cop_filegv)),
-                       statbuf.st_uid, statbuf.st_gid);
+                       (long)statbuf.st_uid, (long)statbuf.st_gid);
                    (void)my_pclose(rsfp);
                }
                croak("Permission denied\n");
@@ -2201,8 +2215,6 @@ register char **env;
        sv_setpv(GvSV(tmpgv),origfilename);
        magicname("0", "0", 1);
     }
-    if (tmpgv = gv_fetchpv("\024",TRUE, SVt_PV))
-       time(&basetime);
     if (tmpgv = gv_fetchpv("\030",TRUE, SVt_PV))
        sv_setpv(GvSV(tmpgv),origargv[0]);
     if (argvgv = gv_fetchpv("ARGV",TRUE, SVt_PVAV)) {
@@ -2335,6 +2347,11 @@ int addsubdirs;
                          + sizeof("//auto"));
            New(55, archpat_auto, len, char);
            sprintf(archpat_auto, "/%s/%s/auto", ARCHNAME, patchlevel);
+#ifdef VMS
+       for (len = sizeof(ARCHNAME) + 2;
+            archpat_auto[len] != '\0' && archpat_auto[len] != '/'; len++)
+               if (archpat_auto[len] == '.') archpat_auto[len] = '_';
+#endif
        }
     }
 
@@ -2366,8 +2383,21 @@ int addsubdirs;
         */
        if (addsubdirs) {
            struct stat tmpstatbuf;
+#ifdef VMS
+           char *unix;
+           STRLEN len;
 
-           /* .../archname/version if -d .../archname/auto */
+           if ((unix = tounixspec_ts(SvPV(libdir,na),Nullch)) != Nullch) {
+               len = strlen(unix);
+               while (unix[len-1] == '/') len--;  /* Cosmetic */
+               sv_usepvn(libdir,unix,len);
+           }
+           else
+               PerlIO_printf(PerlIO_stderr(),
+                             "Failed to unixify @INC element \"%s\"\n",
+                             SvPV(libdir,na));
+#endif
+           /* .../archname/version if -d .../archname/version/auto */
            sv_setsv(subdir, libdir);
            sv_catpv(subdir, archpat_auto);
            if (Stat(SvPVX(subdir), &tmpstatbuf) >= 0 &&
@@ -2375,7 +2405,7 @@ int addsubdirs;
                av_push(GvAVn(incgv),
                        newSVpv(SvPVX(subdir), SvCUR(subdir) - sizeof "auto"));
 
-           /* .../archname/version if -d .../archname/version/auto */
+           /* .../archname if -d .../archname/auto */
            sv_insert(subdir, SvCUR(libdir) + sizeof(ARCHNAME),
                      strlen(patchlevel) + 1, "", 0);
            if (Stat(SvPVX(subdir), &tmpstatbuf) >= 0 &&
@@ -2425,11 +2455,7 @@ AV* list;
            }
            break;
        case 1:
-#ifdef VMS
-           statusvalue = 255;  /* XXX I don't think we use 1 anymore. */
-#else
-       statusvalue = 1;
-#endif
+           STATUS_ALL_FAILURE;
            /* FALL THROUGH */
        case 2:
            /* my_exit() was called */
@@ -2446,9 +2472,8 @@ AV* list;
                else
                    croak("END failed--cleanup aborted");
            }
-           my_exit(statusvalue);
+           my_exit_jump();
            /* NOTREACHED */
-           return;
        case 3:
            if (!restartop) {
                PerlIO_printf(PerlIO_stderr(), "panic: restartop\n");
@@ -2465,3 +2490,70 @@ AV* list;
     Copy(oldtop, top_env, 1, Sigjmp_buf);
 }
 
+void
+my_exit(status)
+U32 status;
+{
+    switch (status) {
+    case 0:
+       STATUS_ALL_SUCCESS;
+       break;
+    case 1:
+       STATUS_ALL_FAILURE;
+       break;
+    default:
+       STATUS_NATIVE_SET(status);
+       break;
+    }
+    my_exit_jump();
+}
+
+void
+my_failure_exit()
+{
+#ifdef VMS
+    if (vaxc$errno & 1) {
+       if (STATUS_NATIVE & 1)          /* fortuitiously includes "-1" */
+           STATUS_NATIVE_SET(44);
+    }
+    else {
+       if (!vaxc$errno && errno)       /* unlikely */
+           STATUS_NATIVE_SET(44);
+       else
+           STATUS_NATIVE_SET(vaxc$errno);
+    }
+#else
+    if (errno & 255)
+       STATUS_POSIX_SET(errno);
+    else if (STATUS_POSIX == 0)
+       STATUS_POSIX_SET(255);
+#endif
+    my_exit_jump();
+}
+
+static void
+my_exit_jump()
+{
+    register CONTEXT *cx;
+    I32 gimme;
+    SV **newsp;
+
+    if (e_tmpname) {
+       if (e_fp) {
+           PerlIO_close(e_fp);
+           e_fp = Nullfp;
+       }
+       (void)UNLINK(e_tmpname);
+       Safefree(e_tmpname);
+       e_tmpname = Nullch;
+    }
+
+    if (cxstack_ix >= 0) {
+       if (cxstack_ix > 0)
+           dounwind(0);
+       POPBLOCK(cx,curpm);
+       LEAVE;
+    }
+
+    Siglongjmp(top_env, 2);
+}