diff perl-5.22.2/perl.c @ 8045:a16537d2fe07

<xfix> tar xf perl-5.22.2.tar.gz # Ah, whatever, I\'m doing it anyway
author HackBot
date Sat, 14 May 2016 14:54:38 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/perl-5.22.2/perl.c	Sat May 14 14:54:38 2016 +0000
@@ -0,0 +1,5139 @@
+#line 2 "perl.c"
+/*    perl.c
+ *
+ *    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ *    2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+ *     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.
+ *
+ */
+
+/*
+ *      A ship then new they built for him
+ *      of mithril and of elven-glass
+ *              --from Bilbo's song of EƤrendil
+ *
+ *     [p.236 of _The Lord of the Rings_, II/i: "Many Meetings"]
+ */
+
+/* This file contains the top-level functions that are used to create, use
+ * and destroy a perl interpreter, plus the functions used by XS code to
+ * call back into perl. Note that it does not contain the actual main()
+ * function of the interpreter; that can be found in perlmain.c
+ */
+
+#if defined(PERL_IS_MINIPERL) && !defined(USE_SITECUSTOMIZE)
+#  define USE_SITECUSTOMIZE
+#endif
+
+#include "EXTERN.h"
+#define PERL_IN_PERL_C
+#include "perl.h"
+#include "patchlevel.h"			/* for local_patches */
+#include "XSUB.h"
+
+#ifdef NETWARE
+#include "nwutil.h"	
+#endif
+
+#ifdef DEBUG_LEAKING_SCALARS_FORK_DUMP
+#  ifdef I_SYSUIO
+#    include <sys/uio.h>
+#  endif
+
+union control_un {
+  struct cmsghdr cm;
+  char control[CMSG_SPACE(sizeof(int))];
+};
+
+#endif
+
+#ifndef HZ
+#  ifdef CLK_TCK
+#    define HZ CLK_TCK
+#  else
+#    define HZ 60
+#  endif
+#endif
+
+#if !defined(STANDARD_C) && !defined(HAS_GETENV_PROTOTYPE) && !defined(PERL_MICRO)
+char *getenv (char *); /* Usually in <stdlib.h> */
+#endif
+
+static I32 read_e_script(pTHX_ int idx, SV *buf_sv, int maxlen);
+
+#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
+#  define validate_suid(rsfp) NOOP
+#else
+#  define validate_suid(rsfp) S_validate_suid(aTHX_ rsfp)
+#endif
+
+#define CALL_BODY_SUB(myop) \
+    if (PL_op == (myop)) \
+	PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); \
+    if (PL_op) \
+	CALLRUNOPS(aTHX);
+
+#define CALL_LIST_BODY(cv) \
+    PUSHMARK(PL_stack_sp); \
+    call_sv(MUTABLE_SV((cv)), G_EVAL|G_DISCARD|G_VOID);
+
+static void
+S_init_tls_and_interp(PerlInterpreter *my_perl)
+{
+    dVAR;
+    if (!PL_curinterp) {			
+	PERL_SET_INTERP(my_perl);
+#if defined(USE_ITHREADS)
+	INIT_THREADS;
+	ALLOC_THREAD_KEY;
+	PERL_SET_THX(my_perl);
+	OP_REFCNT_INIT;
+	OP_CHECK_MUTEX_INIT;
+	HINTS_REFCNT_INIT;
+	MUTEX_INIT(&PL_dollarzero_mutex);
+	MUTEX_INIT(&PL_my_ctx_mutex);
+#  endif
+    }
+#if defined(USE_ITHREADS)
+    else
+#else
+    /* This always happens for non-ithreads  */
+#endif
+    {
+	PERL_SET_THX(my_perl);
+    }
+}
+
+
+/* these implement the PERL_SYS_INIT, PERL_SYS_INIT3, PERL_SYS_TERM macros */
+
+void
+Perl_sys_init(int* argc, char*** argv)
+{
+    dVAR;
+
+    PERL_ARGS_ASSERT_SYS_INIT;
+
+    PERL_UNUSED_ARG(argc); /* may not be used depending on _BODY macro */
+    PERL_UNUSED_ARG(argv);
+    PERL_SYS_INIT_BODY(argc, argv);
+}
+
+void
+Perl_sys_init3(int* argc, char*** argv, char*** env)
+{
+    dVAR;
+
+    PERL_ARGS_ASSERT_SYS_INIT3;
+
+    PERL_UNUSED_ARG(argc); /* may not be used depending on _BODY macro */
+    PERL_UNUSED_ARG(argv);
+    PERL_UNUSED_ARG(env);
+    PERL_SYS_INIT3_BODY(argc, argv, env);
+}
+
+void
+Perl_sys_term(void)
+{
+    dVAR;
+    if (!PL_veto_cleanup) {
+	PERL_SYS_TERM_BODY();
+    }
+}
+
+
+#ifdef PERL_IMPLICIT_SYS
+PerlInterpreter *
+perl_alloc_using(struct IPerlMem* ipM, struct IPerlMem* ipMS,
+		 struct IPerlMem* ipMP, struct IPerlEnv* ipE,
+		 struct IPerlStdIO* ipStd, struct IPerlLIO* ipLIO,
+		 struct IPerlDir* ipD, struct IPerlSock* ipS,
+		 struct IPerlProc* ipP)
+{
+    PerlInterpreter *my_perl;
+
+    PERL_ARGS_ASSERT_PERL_ALLOC_USING;
+
+    /* Newx() needs interpreter, so call malloc() instead */
+    my_perl = (PerlInterpreter*)(*ipM->pMalloc)(ipM, sizeof(PerlInterpreter));
+    S_init_tls_and_interp(my_perl);
+    Zero(my_perl, 1, PerlInterpreter);
+    PL_Mem = ipM;
+    PL_MemShared = ipMS;
+    PL_MemParse = ipMP;
+    PL_Env = ipE;
+    PL_StdIO = ipStd;
+    PL_LIO = ipLIO;
+    PL_Dir = ipD;
+    PL_Sock = ipS;
+    PL_Proc = ipP;
+    INIT_TRACK_MEMPOOL(PL_memory_debug_header, my_perl);
+
+    return my_perl;
+}
+#else
+
+/*
+=head1 Embedding Functions
+
+=for apidoc perl_alloc
+
+Allocates a new Perl interpreter.  See L<perlembed>.
+
+=cut
+*/
+
+PerlInterpreter *
+perl_alloc(void)
+{
+    PerlInterpreter *my_perl;
+
+    /* Newx() needs interpreter, so call malloc() instead */
+    my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
+
+    S_init_tls_and_interp(my_perl);
+#ifndef PERL_TRACK_MEMPOOL
+    return (PerlInterpreter *) ZeroD(my_perl, 1, PerlInterpreter);
+#else
+    Zero(my_perl, 1, PerlInterpreter);
+    INIT_TRACK_MEMPOOL(PL_memory_debug_header, my_perl);
+    return my_perl;
+#endif
+}
+#endif /* PERL_IMPLICIT_SYS */
+
+/*
+=for apidoc perl_construct
+
+Initializes a new Perl interpreter.  See L<perlembed>.
+
+=cut
+*/
+
+void
+perl_construct(pTHXx)
+{
+    dVAR;
+
+    PERL_ARGS_ASSERT_PERL_CONSTRUCT;
+
+#ifdef MULTIPLICITY
+    init_interp();
+    PL_perl_destruct_level = 1;
+#else
+    PERL_UNUSED_ARG(my_perl);
+   if (PL_perl_destruct_level > 0)
+       init_interp();
+#endif
+    PL_curcop = &PL_compiling;	/* needed by ckWARN, right away */
+
+#ifdef PERL_TRACE_OPS
+    Zero(PL_op_exec_cnt, OP_max+2, UV);
+#endif
+
+    init_constants();
+
+    SvREADONLY_on(&PL_sv_placeholder);
+    SvREFCNT(&PL_sv_placeholder) = SvREFCNT_IMMORTAL;
+
+    PL_sighandlerp = (Sighandler_t) Perl_sighandler;
+#ifdef PERL_USES_PL_PIDSTATUS
+    PL_pidstatus = newHV();
+#endif
+
+    PL_rs = newSVpvs("\n");
+
+    init_stacks();
+
+    init_ids();
+
+    JMPENV_BOOTSTRAP;
+    STATUS_ALL_SUCCESS;
+
+    init_i18nl10n(1);
+
+#if defined(LOCAL_PATCH_COUNT)
+    PL_localpatches = local_patches;	/* For possible -v */
+#endif
+
+#ifdef HAVE_INTERP_INTERN
+    sys_intern_init();
+#endif
+
+    PerlIO_init(aTHX);			/* Hook to IO system */
+
+    PL_fdpid = newAV();			/* for remembering popen pids by fd */
+    PL_modglobal = newHV();		/* pointers to per-interpreter module globals */
+    PL_errors = newSVpvs("");
+    sv_setpvs(PERL_DEBUG_PAD(0), "");	/* For regex debugging. */
+    sv_setpvs(PERL_DEBUG_PAD(1), "");	/* ext/re needs these */
+    sv_setpvs(PERL_DEBUG_PAD(2), "");	/* even without DEBUGGING. */
+#ifdef USE_ITHREADS
+    /* First entry is a list of empty elements. It needs to be initialised
+       else all hell breaks loose in S_find_uninit_var().  */
+    Perl_av_create_and_push(aTHX_ &PL_regex_padav, newSVpvs(""));
+    PL_regex_pad = AvARRAY(PL_regex_padav);
+    Newxz(PL_stashpad, PL_stashpadmax, HV *);
+#endif
+#ifdef USE_REENTRANT_API
+    Perl_reentrant_init(aTHX);
+#endif
+#if defined(USE_HASH_SEED) || defined(USE_HASH_SEED_EXPLICIT)
+        /* [perl #22371] Algorimic Complexity Attack on Perl 5.6.1, 5.8.0
+         * This MUST be done before any hash stores or fetches take place.
+         * If you set PL_hash_seed (and presumably also PL_hash_seed_set)
+         * yourself, it is your responsibility to provide a good random seed!
+         * You can also define PERL_HASH_SEED in compile time, see hv.h.
+         *
+         * XXX: fix this comment */
+    if (PL_hash_seed_set == FALSE) {
+        Perl_get_hash_seed(aTHX_ PL_hash_seed);
+        PL_hash_seed_set= TRUE;
+    }
+#endif /* #if defined(USE_HASH_SEED) || defined(USE_HASH_SEED_EXPLICIT) */
+
+    /* Note that strtab is a rather special HV.  Assumptions are made
+       about not iterating on it, and not adding tie magic to it.
+       It is properly deallocated in perl_destruct() */
+    PL_strtab = newHV();
+
+    HvSHAREKEYS_off(PL_strtab);			/* mandatory */
+    hv_ksplit(PL_strtab, 512);
+
+    Zero(PL_sv_consts, SV_CONSTS_COUNT, SV*);
+
+#ifndef PERL_MICRO
+#   ifdef  USE_ENVIRON_ARRAY
+    PL_origenviron = environ;
+#   endif
+#endif
+
+    /* Use sysconf(_SC_CLK_TCK) if available, if not
+     * available or if the sysconf() fails, use the HZ.
+     * The HZ if not originally defined has been by now
+     * been defined as CLK_TCK, if available. */
+#if defined(HAS_SYSCONF) && defined(_SC_CLK_TCK)
+    PL_clocktick = sysconf(_SC_CLK_TCK);
+    if (PL_clocktick <= 0)
+#endif
+	 PL_clocktick = HZ;
+
+    PL_stashcache = newHV();
+
+    PL_patchlevel = newSVpvs("v" PERL_VERSION_STRING);
+
+#ifdef HAS_MMAP
+    if (!PL_mmap_page_size) {
+#if defined(HAS_SYSCONF) && (defined(_SC_PAGESIZE) || defined(_SC_MMAP_PAGE_SIZE))
+      {
+	SETERRNO(0, SS_NORMAL);
+#   ifdef _SC_PAGESIZE
+	PL_mmap_page_size = sysconf(_SC_PAGESIZE);
+#   else
+	PL_mmap_page_size = sysconf(_SC_MMAP_PAGE_SIZE);
+#   endif
+	if ((long) PL_mmap_page_size < 0) {
+	  if (errno) {
+	    SV * const error = ERRSV;
+	    SvUPGRADE(error, SVt_PV);
+	    Perl_croak(aTHX_ "panic: sysconf: %s", SvPV_nolen_const(error));
+	  }
+	  else
+	    Perl_croak(aTHX_ "panic: sysconf: pagesize unknown");
+	}
+      }
+#else
+#   ifdef HAS_GETPAGESIZE
+      PL_mmap_page_size = getpagesize();
+#   else
+#       if defined(I_SYS_PARAM) && defined(PAGESIZE)
+      PL_mmap_page_size = PAGESIZE;       /* compiletime, bad */
+#       endif
+#   endif
+#endif
+      if (PL_mmap_page_size <= 0)
+	Perl_croak(aTHX_ "panic: bad pagesize %" IVdf,
+		   (IV) PL_mmap_page_size);
+    }
+#endif /* HAS_MMAP */
+
+#if defined(HAS_TIMES) && defined(PERL_NEED_TIMESBASE)
+    PL_timesbase.tms_utime  = 0;
+    PL_timesbase.tms_stime  = 0;
+    PL_timesbase.tms_cutime = 0;
+    PL_timesbase.tms_cstime = 0;
+#endif
+
+    PL_osname = Perl_savepvn(aTHX_ STR_WITH_LEN(OSNAME));
+
+    PL_registered_mros = newHV();
+    /* Start with 1 bucket, for DFS.  It's unlikely we'll need more.  */
+    HvMAX(PL_registered_mros) = 0;
+
+    PL_XPosix_ptrs[_CC_ASCII] = _new_invlist_C_array(ASCII_invlist);
+    PL_XPosix_ptrs[_CC_ALPHANUMERIC] = _new_invlist_C_array(XPosixAlnum_invlist);
+    PL_XPosix_ptrs[_CC_ALPHA] = _new_invlist_C_array(XPosixAlpha_invlist);
+    PL_XPosix_ptrs[_CC_BLANK] = _new_invlist_C_array(XPosixBlank_invlist);
+    PL_XPosix_ptrs[_CC_CASED] =  _new_invlist_C_array(Cased_invlist);
+    PL_XPosix_ptrs[_CC_CNTRL] = _new_invlist_C_array(XPosixCntrl_invlist);
+    PL_XPosix_ptrs[_CC_DIGIT] = _new_invlist_C_array(XPosixDigit_invlist);
+    PL_XPosix_ptrs[_CC_GRAPH] = _new_invlist_C_array(XPosixGraph_invlist);
+    PL_XPosix_ptrs[_CC_LOWER] = _new_invlist_C_array(XPosixLower_invlist);
+    PL_XPosix_ptrs[_CC_PRINT] = _new_invlist_C_array(XPosixPrint_invlist);
+    PL_XPosix_ptrs[_CC_PUNCT] = _new_invlist_C_array(XPosixPunct_invlist);
+    PL_XPosix_ptrs[_CC_SPACE] = _new_invlist_C_array(XPerlSpace_invlist);
+    PL_XPosix_ptrs[_CC_UPPER] = _new_invlist_C_array(XPosixUpper_invlist);
+    PL_XPosix_ptrs[_CC_VERTSPACE] = _new_invlist_C_array(VertSpace_invlist);
+    PL_XPosix_ptrs[_CC_WORDCHAR] = _new_invlist_C_array(XPosixWord_invlist);
+    PL_XPosix_ptrs[_CC_XDIGIT] = _new_invlist_C_array(XPosixXDigit_invlist);
+    PL_GCB_invlist = _new_invlist_C_array(Grapheme_Cluster_Break_invlist);
+    PL_SB_invlist = _new_invlist_C_array(Sentence_Break_invlist);
+    PL_WB_invlist = _new_invlist_C_array(Word_Break_invlist);
+
+    ENTER;
+}
+
+/*
+=for apidoc nothreadhook
+
+Stub that provides thread hook for perl_destruct when there are
+no threads.
+
+=cut
+*/
+
+int
+Perl_nothreadhook(pTHX)
+{
+    PERL_UNUSED_CONTEXT;
+    return 0;
+}
+
+#ifdef DEBUG_LEAKING_SCALARS_FORK_DUMP
+void
+Perl_dump_sv_child(pTHX_ SV *sv)
+{
+    ssize_t got;
+    const int sock = PL_dumper_fd;
+    const int debug_fd = PerlIO_fileno(Perl_debug_log);
+    union control_un control;
+    struct msghdr msg;
+    struct iovec vec[2];
+    struct cmsghdr *cmptr;
+    int returned_errno;
+    unsigned char buffer[256];
+
+    PERL_ARGS_ASSERT_DUMP_SV_CHILD;
+
+    if(sock == -1 || debug_fd == -1)
+	return;
+
+    PerlIO_flush(Perl_debug_log);
+
+    /* All these shenanigans are to pass a file descriptor over to our child for
+       it to dump out to.  We can't let it hold open the file descriptor when it
+       forks, as the file descriptor it will dump to can turn out to be one end
+       of pipe that some other process will wait on for EOF. (So as it would
+       be open, the wait would be forever.)  */
+
+    msg.msg_control = control.control;
+    msg.msg_controllen = sizeof(control.control);
+    /* We're a connected socket so we don't need a destination  */
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+    msg.msg_iov = vec;
+    msg.msg_iovlen = 1;
+
+    cmptr = CMSG_FIRSTHDR(&msg);
+    cmptr->cmsg_len = CMSG_LEN(sizeof(int));
+    cmptr->cmsg_level = SOL_SOCKET;
+    cmptr->cmsg_type = SCM_RIGHTS;
+    *((int *)CMSG_DATA(cmptr)) = 1;
+
+    vec[0].iov_base = (void*)&sv;
+    vec[0].iov_len = sizeof(sv);
+    got = sendmsg(sock, &msg, 0);
+
+    if(got < 0) {
+	perror("Debug leaking scalars parent sendmsg failed");
+	abort();
+    }
+    if(got < sizeof(sv)) {
+	perror("Debug leaking scalars parent short sendmsg");
+	abort();
+    }
+
+    /* Return protocol is
+       int:		errno value
+       unsigned char:	length of location string (0 for empty)
+       unsigned char*:	string (not terminated)
+    */
+    vec[0].iov_base = (void*)&returned_errno;
+    vec[0].iov_len = sizeof(returned_errno);
+    vec[1].iov_base = buffer;
+    vec[1].iov_len = 1;
+
+    got = readv(sock, vec, 2);
+
+    if(got < 0) {
+	perror("Debug leaking scalars parent read failed");
+	PerlIO_flush(PerlIO_stderr());
+	abort();
+    }
+    if(got < sizeof(returned_errno) + 1) {
+	perror("Debug leaking scalars parent short read");
+	PerlIO_flush(PerlIO_stderr());
+	abort();
+    }
+
+    if (*buffer) {
+	got = read(sock, buffer + 1, *buffer);
+	if(got < 0) {
+	    perror("Debug leaking scalars parent read 2 failed");
+	    PerlIO_flush(PerlIO_stderr());
+	    abort();
+	}
+
+	if(got < *buffer) {
+	    perror("Debug leaking scalars parent short read 2");
+	    PerlIO_flush(PerlIO_stderr());
+	    abort();
+	}
+    }
+
+    if (returned_errno || *buffer) {
+	Perl_warn(aTHX_ "Debug leaking scalars child failed%s%.*s with errno"
+		  " %d: %s", (*buffer ? " at " : ""), (int) *buffer, buffer + 1,
+		  returned_errno, Strerror(returned_errno));
+    }
+}
+#endif
+
+/*
+=for apidoc perl_destruct
+
+Shuts down a Perl interpreter.  See L<perlembed>.
+
+=cut
+*/
+
+int
+perl_destruct(pTHXx)
+{
+    dVAR;
+    VOL signed char destruct_level;  /* see possible values in intrpvar.h */
+    HV *hv;
+#ifdef DEBUG_LEAKING_SCALARS_FORK_DUMP
+    pid_t child;
+#endif
+    int i;
+
+    PERL_ARGS_ASSERT_PERL_DESTRUCT;
+#ifndef MULTIPLICITY
+    PERL_UNUSED_ARG(my_perl);
+#endif
+
+    assert(PL_scopestack_ix == 1);
+
+    /* wait for all pseudo-forked children to finish */
+    PERL_WAIT_FOR_CHILDREN;
+
+    destruct_level = PL_perl_destruct_level;
+#if defined(DEBUGGING) || defined(PERL_TRACK_MEMPOOL)
+    {
+	const char * const s = PerlEnv_getenv("PERL_DESTRUCT_LEVEL");
+	if (s) {
+            int i;
+            if (strEQ(s, "-1")) { /* Special case: modperl folklore. */
+                i = -1;
+            } else {
+                UV uv;
+                if (grok_atoUV(s, &uv, NULL) && uv <= INT_MAX)
+                    i = (int)uv;
+                else
+                    i = 0;
+            }
+#ifdef DEBUGGING
+	    if (destruct_level < i) destruct_level = i;
+#endif
+#ifdef PERL_TRACK_MEMPOOL
+            /* RT #114496, for perl_free */
+            PL_perl_destruct_level = i;
+#endif
+	}
+    }
+#endif
+
+    if (PL_exit_flags & PERL_EXIT_DESTRUCT_END) {
+        dJMPENV;
+        int x = 0;
+
+        JMPENV_PUSH(x);
+	PERL_UNUSED_VAR(x);
+        if (PL_endav && !PL_minus_c) {
+	    PERL_SET_PHASE(PERL_PHASE_END);
+            call_list(PL_scopestack_ix, PL_endav);
+	}
+        JMPENV_POP;
+    }
+    LEAVE;
+    FREETMPS;
+    assert(PL_scopestack_ix == 0);
+
+    /* Need to flush since END blocks can produce output */
+    my_fflush_all();
+
+#ifdef PERL_TRACE_OPS
+    /* If we traced all Perl OP usage, report and clean up */
+    PerlIO_printf(Perl_debug_log, "Trace of all OPs executed:\n");
+    for (i = 0; i <= OP_max; ++i) {
+        PerlIO_printf(Perl_debug_log, "  %s: %"UVuf"\n", PL_op_name[i], PL_op_exec_cnt[i]);
+        PL_op_exec_cnt[i] = 0;
+    }
+    /* Utility slot for easily doing little tracing experiments in the runloop: */
+    if (PL_op_exec_cnt[OP_max+1] != 0)
+        PerlIO_printf(Perl_debug_log, "  SPECIAL: %"UVuf"\n", PL_op_exec_cnt[OP_max+1]);
+    PerlIO_printf(Perl_debug_log, "\n");
+#endif
+
+
+    if (PL_threadhook(aTHX)) {
+        /* Threads hook has vetoed further cleanup */
+	PL_veto_cleanup = TRUE;
+        return STATUS_EXIT;
+    }
+
+#ifdef DEBUG_LEAKING_SCALARS_FORK_DUMP
+    if (destruct_level != 0) {
+	/* Fork here to create a child. Our child's job is to preserve the
+	   state of scalars prior to destruction, so that we can instruct it
+	   to dump any scalars that we later find have leaked.
+	   There's no subtlety in this code - it assumes POSIX, and it doesn't
+	   fail gracefully  */
+	int fd[2];
+
+	if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
+	    perror("Debug leaking scalars socketpair failed");
+	    abort();
+	}
+
+	child = fork();
+	if(child == -1) {
+	    perror("Debug leaking scalars fork failed");
+	    abort();
+	}
+	if (!child) {
+	    /* We are the child */
+	    const int sock = fd[1];
+	    const int debug_fd = PerlIO_fileno(Perl_debug_log);
+	    int f;
+	    const char *where;
+	    /* Our success message is an integer 0, and a char 0  */
+	    static const char success[sizeof(int) + 1] = {0};
+
+	    close(fd[0]);
+
+	    /* We need to close all other file descriptors otherwise we end up
+	       with interesting hangs, where the parent closes its end of a
+	       pipe, and sits waiting for (another) child to terminate. Only
+	       that child never terminates, because it never gets EOF, because
+	       we also have the far end of the pipe open.  We even need to
+	       close the debugging fd, because sometimes it happens to be one
+	       end of a pipe, and a process is waiting on the other end for
+	       EOF. Normally it would be closed at some point earlier in
+	       destruction, but if we happen to cause the pipe to remain open,
+	       EOF never occurs, and we get an infinite hang. Hence all the
+	       games to pass in a file descriptor if it's actually needed.  */
+
+	    f = sysconf(_SC_OPEN_MAX);
+	    if(f < 0) {
+		where = "sysconf failed";
+		goto abort;
+	    }
+	    while (f--) {
+		if (f == sock)
+		    continue;
+		close(f);
+	    }
+
+	    while (1) {
+		SV *target;
+		union control_un control;
+		struct msghdr msg;
+		struct iovec vec[1];
+		struct cmsghdr *cmptr;
+		ssize_t got;
+		int got_fd;
+
+		msg.msg_control = control.control;
+		msg.msg_controllen = sizeof(control.control);
+		/* We're a connected socket so we don't need a source  */
+		msg.msg_name = NULL;
+		msg.msg_namelen = 0;
+		msg.msg_iov = vec;
+		msg.msg_iovlen = C_ARRAY_LENGTH(vec);
+
+		vec[0].iov_base = (void*)&target;
+		vec[0].iov_len = sizeof(target);
+      
+		got = recvmsg(sock, &msg, 0);
+
+		if(got == 0)
+		    break;
+		if(got < 0) {
+		    where = "recv failed";
+		    goto abort;
+		}
+		if(got < sizeof(target)) {
+		    where = "short recv";
+		    goto abort;
+		}
+
+		if(!(cmptr = CMSG_FIRSTHDR(&msg))) {
+		    where = "no cmsg";
+		    goto abort;
+		}
+		if(cmptr->cmsg_len != CMSG_LEN(sizeof(int))) {
+		    where = "wrong cmsg_len";
+		    goto abort;
+		}
+		if(cmptr->cmsg_level != SOL_SOCKET) {
+		    where = "wrong cmsg_level";
+		    goto abort;
+		}
+		if(cmptr->cmsg_type != SCM_RIGHTS) {
+		    where = "wrong cmsg_type";
+		    goto abort;
+		}
+
+		got_fd = *(int*)CMSG_DATA(cmptr);
+		/* For our last little bit of trickery, put the file descriptor
+		   back into Perl_debug_log, as if we never actually closed it
+		*/
+		if(got_fd != debug_fd) {
+		    if (dup2(got_fd, debug_fd) == -1) {
+			where = "dup2";
+			goto abort;
+		    }
+		}
+		sv_dump(target);
+
+		PerlIO_flush(Perl_debug_log);
+
+		got = write(sock, &success, sizeof(success));
+
+		if(got < 0) {
+		    where = "write failed";
+		    goto abort;
+		}
+		if(got < sizeof(success)) {
+		    where = "short write";
+		    goto abort;
+		}
+	    }
+	    _exit(0);
+	abort:
+	    {
+		int send_errno = errno;
+		unsigned char length = (unsigned char) strlen(where);
+		struct iovec failure[3] = {
+		    {(void*)&send_errno, sizeof(send_errno)},
+		    {&length, 1},
+		    {(void*)where, length}
+		};
+		int got = writev(sock, failure, 3);
+		/* Bad news travels fast. Faster than data. We'll get a SIGPIPE
+		   in the parent if we try to read from the socketpair after the
+		   child has exited, even if there was data to read.
+		   So sleep a bit to give the parent a fighting chance of
+		   reading the data.  */
+		sleep(2);
+		_exit((got == -1) ? errno : 0);
+	    }
+	    /* End of child.  */
+	}
+	PL_dumper_fd = fd[0];
+	close(fd[1]);
+    }
+#endif
+    
+    /* We must account for everything.  */
+
+    /* Destroy the main CV and syntax tree */
+    /* Set PL_curcop now, because destroying ops can cause new SVs
+       to be generated in Perl_pad_swipe, and when running with
+      -DDEBUG_LEAKING_SCALARS they expect PL_curcop to point to a valid
+       op from which the filename structure member is copied.  */
+    PL_curcop = &PL_compiling;
+    if (PL_main_root) {
+	/* ensure comppad/curpad to refer to main's pad */
+	if (CvPADLIST(PL_main_cv)) {
+	    PAD_SET_CUR_NOSAVE(CvPADLIST(PL_main_cv), 1);
+	    PL_comppad_name = PadlistNAMES(CvPADLIST(PL_main_cv));
+	}
+	op_free(PL_main_root);
+	PL_main_root = NULL;
+    }
+    PL_main_start = NULL;
+    /* note that  PL_main_cv isn't usually actually freed at this point,
+     * due to the CvOUTSIDE refs from subs compiled within it. It will
+     * get freed once all the subs are freed in sv_clean_all(), for
+     * destruct_level > 0 */
+    SvREFCNT_dec(PL_main_cv);
+    PL_main_cv = NULL;
+    PERL_SET_PHASE(PERL_PHASE_DESTRUCT);
+
+    /* Tell PerlIO we are about to tear things apart in case
+       we have layers which are using resources that should
+       be cleaned up now.
+     */
+
+    PerlIO_destruct(aTHX);
+
+    /*
+     * Try to destruct global references.  We do this first so that the
+     * destructors and destructees still exist.  Some sv's might remain.
+     * Non-referenced objects are on their own.
+     */
+    sv_clean_objs();
+
+    /* unhook hooks which will soon be, or use, destroyed data */
+    SvREFCNT_dec(PL_warnhook);
+    PL_warnhook = NULL;
+    SvREFCNT_dec(PL_diehook);
+    PL_diehook = NULL;
+
+    /* call exit list functions */
+    while (PL_exitlistlen-- > 0)
+	PL_exitlist[PL_exitlistlen].fn(aTHX_ PL_exitlist[PL_exitlistlen].ptr);
+
+    Safefree(PL_exitlist);
+
+    PL_exitlist = NULL;
+    PL_exitlistlen = 0;
+
+    SvREFCNT_dec(PL_registered_mros);
+
+    /* jettison our possibly duplicated environment */
+    /* if PERL_USE_SAFE_PUTENV is defined environ will not have been copied
+     * so we certainly shouldn't free it here
+     */
+#ifndef PERL_MICRO
+#if defined(USE_ENVIRON_ARRAY) && !defined(PERL_USE_SAFE_PUTENV)
+    if (environ != PL_origenviron && !PL_use_safe_putenv
+#ifdef USE_ITHREADS
+	/* only main thread can free environ[0] contents */
+	&& PL_curinterp == aTHX
+#endif
+	)
+    {
+	I32 i;
+
+	for (i = 0; environ[i]; i++)
+	    safesysfree(environ[i]);
+
+	/* Must use safesysfree() when working with environ. */
+	safesysfree(environ);		
+
+	environ = PL_origenviron;
+    }
+#endif
+#endif /* !PERL_MICRO */
+
+    if (destruct_level == 0) {
+
+	DEBUG_P(debprofdump());
+
+#if defined(PERLIO_LAYERS)
+	/* No more IO - including error messages ! */
+	PerlIO_cleanup(aTHX);
+#endif
+
+	CopFILE_free(&PL_compiling);
+
+	/* The exit() function will do everything that needs doing. */
+        return STATUS_EXIT;
+    }
+
+    /* Below, do clean up for when PERL_DESTRUCT_LEVEL is not 0 */
+
+#ifdef USE_ITHREADS
+    /* the syntax tree is shared between clones
+     * so op_free(PL_main_root) only ReREFCNT_dec's
+     * REGEXPs in the parent interpreter
+     * we need to manually ReREFCNT_dec for the clones
+     */
+    {
+	I32 i = AvFILLp(PL_regex_padav);
+	SV **ary = AvARRAY(PL_regex_padav);
+
+	for (; i; i--) {
+	    SvREFCNT_dec(ary[i]);
+	    ary[i] = &PL_sv_undef;
+	}
+    }
+#endif
+
+
+    SvREFCNT_dec(MUTABLE_SV(PL_stashcache));
+    PL_stashcache = NULL;
+
+    /* loosen bonds of global variables */
+
+    /* XXX can PL_parser still be non-null here? */
+    if(PL_parser && PL_parser->rsfp) {
+	(void)PerlIO_close(PL_parser->rsfp);
+	PL_parser->rsfp = NULL;
+    }
+
+    if (PL_minus_F) {
+	Safefree(PL_splitstr);
+	PL_splitstr = NULL;
+    }
+
+    /* switches */
+    PL_minus_n      = FALSE;
+    PL_minus_p      = FALSE;
+    PL_minus_l      = FALSE;
+    PL_minus_a      = FALSE;
+    PL_minus_F      = FALSE;
+    PL_doswitches   = FALSE;
+    PL_dowarn       = G_WARN_OFF;
+#ifdef PERL_SAWAMPERSAND
+    PL_sawampersand = 0;	/* must save all match strings */
+#endif
+    PL_unsafe       = FALSE;
+
+    Safefree(PL_inplace);
+    PL_inplace = NULL;
+    SvREFCNT_dec(PL_patchlevel);
+
+    if (PL_e_script) {
+	SvREFCNT_dec(PL_e_script);
+	PL_e_script = NULL;
+    }
+
+    PL_perldb = 0;
+
+    /* magical thingies */
+
+    SvREFCNT_dec(PL_ofsgv);	/* *, */
+    PL_ofsgv = NULL;
+
+    SvREFCNT_dec(PL_ors_sv);	/* $\ */
+    PL_ors_sv = NULL;
+
+    SvREFCNT_dec(PL_rs);	/* $/ */
+    PL_rs = NULL;
+
+    Safefree(PL_osname);	/* $^O */
+    PL_osname = NULL;
+
+    SvREFCNT_dec(PL_statname);
+    PL_statname = NULL;
+    PL_statgv = NULL;
+
+    /* defgv, aka *_ should be taken care of elsewhere */
+
+    /* float buffer */
+    Safefree(PL_efloatbuf);
+    PL_efloatbuf = NULL;
+    PL_efloatsize = 0;
+
+    /* startup and shutdown function lists */
+    SvREFCNT_dec(PL_beginav);
+    SvREFCNT_dec(PL_beginav_save);
+    SvREFCNT_dec(PL_endav);
+    SvREFCNT_dec(PL_checkav);
+    SvREFCNT_dec(PL_checkav_save);
+    SvREFCNT_dec(PL_unitcheckav);
+    SvREFCNT_dec(PL_unitcheckav_save);
+    SvREFCNT_dec(PL_initav);
+    PL_beginav = NULL;
+    PL_beginav_save = NULL;
+    PL_endav = NULL;
+    PL_checkav = NULL;
+    PL_checkav_save = NULL;
+    PL_unitcheckav = NULL;
+    PL_unitcheckav_save = NULL;
+    PL_initav = NULL;
+
+    /* shortcuts just get cleared */
+    PL_hintgv = NULL;
+    PL_errgv = NULL;
+    PL_argvoutgv = NULL;
+    PL_stdingv = NULL;
+    PL_stderrgv = NULL;
+    PL_last_in_gv = NULL;
+    PL_DBsingle = NULL;
+    PL_DBtrace = NULL;
+    PL_DBsignal = NULL;
+    PL_DBsingle_iv = 0;
+    PL_DBtrace_iv = 0;
+    PL_DBsignal_iv = 0;
+    PL_DBcv = NULL;
+    PL_dbargs = NULL;
+    PL_debstash = NULL;
+
+    SvREFCNT_dec(PL_envgv);
+    SvREFCNT_dec(PL_incgv);
+    SvREFCNT_dec(PL_argvgv);
+    SvREFCNT_dec(PL_replgv);
+    SvREFCNT_dec(PL_DBgv);
+    SvREFCNT_dec(PL_DBline);
+    SvREFCNT_dec(PL_DBsub);
+    PL_envgv = NULL;
+    PL_incgv = NULL;
+    PL_argvgv = NULL;
+    PL_replgv = NULL;
+    PL_DBgv = NULL;
+    PL_DBline = NULL;
+    PL_DBsub = NULL;
+
+    SvREFCNT_dec(PL_argvout_stack);
+    PL_argvout_stack = NULL;
+
+    SvREFCNT_dec(PL_modglobal);
+    PL_modglobal = NULL;
+    SvREFCNT_dec(PL_preambleav);
+    PL_preambleav = NULL;
+    SvREFCNT_dec(PL_subname);
+    PL_subname = NULL;
+#ifdef PERL_USES_PL_PIDSTATUS
+    SvREFCNT_dec(PL_pidstatus);
+    PL_pidstatus = NULL;
+#endif
+    SvREFCNT_dec(PL_toptarget);
+    PL_toptarget = NULL;
+    SvREFCNT_dec(PL_bodytarget);
+    PL_bodytarget = NULL;
+    PL_formtarget = NULL;
+
+    /* free locale stuff */
+#ifdef USE_LOCALE_COLLATE
+    Safefree(PL_collation_name);
+    PL_collation_name = NULL;
+#endif
+
+#ifdef USE_LOCALE_NUMERIC
+    Safefree(PL_numeric_name);
+    PL_numeric_name = NULL;
+    SvREFCNT_dec(PL_numeric_radix_sv);
+    PL_numeric_radix_sv = NULL;
+#endif
+
+    /* clear character classes  */
+    for (i = 0; i < POSIX_SWASH_COUNT; i++) {
+        SvREFCNT_dec(PL_utf8_swash_ptrs[i]);
+        PL_utf8_swash_ptrs[i] = NULL;
+    }
+    SvREFCNT_dec(PL_utf8_mark);
+    SvREFCNT_dec(PL_utf8_toupper);
+    SvREFCNT_dec(PL_utf8_totitle);
+    SvREFCNT_dec(PL_utf8_tolower);
+    SvREFCNT_dec(PL_utf8_tofold);
+    SvREFCNT_dec(PL_utf8_idstart);
+    SvREFCNT_dec(PL_utf8_idcont);
+    SvREFCNT_dec(PL_utf8_foldable);
+    SvREFCNT_dec(PL_utf8_foldclosures);
+    SvREFCNT_dec(PL_AboveLatin1);
+    SvREFCNT_dec(PL_InBitmap);
+    SvREFCNT_dec(PL_UpperLatin1);
+    SvREFCNT_dec(PL_Latin1);
+    SvREFCNT_dec(PL_NonL1NonFinalFold);
+    SvREFCNT_dec(PL_HasMultiCharFold);
+#ifdef USE_LOCALE_CTYPE
+    SvREFCNT_dec(PL_warn_locale);
+#endif
+    PL_utf8_mark	= NULL;
+    PL_utf8_toupper	= NULL;
+    PL_utf8_totitle	= NULL;
+    PL_utf8_tolower	= NULL;
+    PL_utf8_tofold	= NULL;
+    PL_utf8_idstart	= NULL;
+    PL_utf8_idcont	= NULL;
+    PL_utf8_foldclosures = NULL;
+    PL_AboveLatin1       = NULL;
+    PL_InBitmap          = NULL;
+    PL_HasMultiCharFold  = NULL;
+#ifdef USE_LOCALE_CTYPE
+    PL_warn_locale       = NULL;
+#endif
+    PL_Latin1            = NULL;
+    PL_NonL1NonFinalFold = NULL;
+    PL_UpperLatin1       = NULL;
+    for (i = 0; i < POSIX_CC_COUNT; i++) {
+        SvREFCNT_dec(PL_XPosix_ptrs[i]);
+        PL_XPosix_ptrs[i] = NULL;
+    }
+    PL_GCB_invlist = NULL;
+    PL_SB_invlist = NULL;
+    PL_WB_invlist = NULL;
+
+    if (!specialWARN(PL_compiling.cop_warnings))
+	PerlMemShared_free(PL_compiling.cop_warnings);
+    PL_compiling.cop_warnings = NULL;
+    cophh_free(CopHINTHASH_get(&PL_compiling));
+    CopHINTHASH_set(&PL_compiling, cophh_new_empty());
+    CopFILE_free(&PL_compiling);
+
+    /* Prepare to destruct main symbol table.  */
+
+    hv = PL_defstash;
+    /* break ref loop  *:: <=> %:: */
+    (void)hv_delete(hv, "main::", 6, G_DISCARD);
+    PL_defstash = 0;
+    SvREFCNT_dec(hv);
+    SvREFCNT_dec(PL_curstname);
+    PL_curstname = NULL;
+
+    /* clear queued errors */
+    SvREFCNT_dec(PL_errors);
+    PL_errors = NULL;
+
+    SvREFCNT_dec(PL_isarev);
+
+    FREETMPS;
+    if (destruct_level >= 2) {
+	if (PL_scopestack_ix != 0)
+	    Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
+			     "Unbalanced scopes: %ld more ENTERs than LEAVEs\n",
+			     (long)PL_scopestack_ix);
+	if (PL_savestack_ix != 0)
+	    Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
+			     "Unbalanced saves: %ld more saves than restores\n",
+			     (long)PL_savestack_ix);
+	if (PL_tmps_floor != -1)
+	    Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),"Unbalanced tmps: %ld more allocs than frees\n",
+			     (long)PL_tmps_floor + 1);
+	if (cxstack_ix != -1)
+	    Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),"Unbalanced context: %ld more PUSHes than POPs\n",
+			     (long)cxstack_ix + 1);
+    }
+
+#ifdef USE_ITHREADS
+    SvREFCNT_dec(PL_regex_padav);
+    PL_regex_padav = NULL;
+    PL_regex_pad = NULL;
+#endif
+
+#ifdef PERL_IMPLICIT_CONTEXT
+    /* the entries in this list are allocated via SV PVX's, so get freed
+     * in sv_clean_all */
+    Safefree(PL_my_cxt_list);
+#endif
+
+    /* Now absolutely destruct everything, somehow or other, loops or no. */
+
+    /* the 2 is for PL_fdpid and PL_strtab */
+    while (sv_clean_all() > 2)
+	;
+
+#ifdef USE_ITHREADS
+    Safefree(PL_stashpad); /* must come after sv_clean_all */
+#endif
+
+    AvREAL_off(PL_fdpid);		/* no surviving entries */
+    SvREFCNT_dec(PL_fdpid);		/* needed in io_close() */
+    PL_fdpid = NULL;
+
+#ifdef HAVE_INTERP_INTERN
+    sys_intern_clear();
+#endif
+
+    /* constant strings */
+    for (i = 0; i < SV_CONSTS_COUNT; i++) {
+        SvREFCNT_dec(PL_sv_consts[i]);
+        PL_sv_consts[i] = NULL;
+    }
+
+    /* Destruct the global string table. */
+    {
+	/* Yell and reset the HeVAL() slots that are still holding refcounts,
+	 * so that sv_free() won't fail on them.
+	 * Now that the global string table is using a single hunk of memory
+	 * for both HE and HEK, we either need to explicitly unshare it the
+	 * correct way, or actually free things here.
+	 */
+	I32 riter = 0;
+	const I32 max = HvMAX(PL_strtab);
+	HE * const * const array = HvARRAY(PL_strtab);
+	HE *hent = array[0];
+
+	for (;;) {
+	    if (hent && ckWARN_d(WARN_INTERNAL)) {
+		HE * const next = HeNEXT(hent);
+		Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
+		     "Unbalanced string table refcount: (%ld) for \"%s\"",
+		     (long)hent->he_valu.hent_refcount, HeKEY(hent));
+		Safefree(hent);
+		hent = next;
+	    }
+	    if (!hent) {
+		if (++riter > max)
+		    break;
+		hent = array[riter];
+	    }
+	}
+
+	Safefree(array);
+	HvARRAY(PL_strtab) = 0;
+	HvTOTALKEYS(PL_strtab) = 0;
+    }
+    SvREFCNT_dec(PL_strtab);
+
+#ifdef USE_ITHREADS
+    /* free the pointer tables used for cloning */
+    ptr_table_free(PL_ptr_table);
+    PL_ptr_table = (PTR_TBL_t*)NULL;
+#endif
+
+    /* free special SVs */
+
+    SvREFCNT(&PL_sv_yes) = 0;
+    sv_clear(&PL_sv_yes);
+    SvANY(&PL_sv_yes) = NULL;
+    SvFLAGS(&PL_sv_yes) = 0;
+
+    SvREFCNT(&PL_sv_no) = 0;
+    sv_clear(&PL_sv_no);
+    SvANY(&PL_sv_no) = NULL;
+    SvFLAGS(&PL_sv_no) = 0;
+
+    {
+        int i;
+        for (i=0; i<=2; i++) {
+            SvREFCNT(PERL_DEBUG_PAD(i)) = 0;
+            sv_clear(PERL_DEBUG_PAD(i));
+            SvANY(PERL_DEBUG_PAD(i)) = NULL;
+            SvFLAGS(PERL_DEBUG_PAD(i)) = 0;
+        }
+    }
+
+    if (PL_sv_count != 0 && ckWARN_d(WARN_INTERNAL))
+	Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Scalars leaked: %ld\n", (long)PL_sv_count);
+
+#ifdef DEBUG_LEAKING_SCALARS
+    if (PL_sv_count != 0) {
+	SV* sva;
+	SV* sv;
+	SV* svend;
+
+	for (sva = PL_sv_arenaroot; sva; sva = MUTABLE_SV(SvANY(sva))) {
+	    svend = &sva[SvREFCNT(sva)];
+	    for (sv = sva + 1; sv < svend; ++sv) {
+		if (SvTYPE(sv) != (svtype)SVTYPEMASK) {
+		    PerlIO_printf(Perl_debug_log, "leaked: sv=0x%p"
+			" flags=0x%"UVxf
+			" refcnt=%"UVuf pTHX__FORMAT "\n"
+			"\tallocated at %s:%d %s %s (parent 0x%"UVxf");"
+			"serial %"UVuf"\n",
+			(void*)sv, (UV)sv->sv_flags, (UV)sv->sv_refcnt
+			pTHX__VALUE,
+			sv->sv_debug_file ? sv->sv_debug_file : "(unknown)",
+			sv->sv_debug_line,
+			sv->sv_debug_inpad ? "for" : "by",
+			sv->sv_debug_optype ?
+			    PL_op_name[sv->sv_debug_optype]: "(none)",
+			PTR2UV(sv->sv_debug_parent),
+			sv->sv_debug_serial
+		    );
+#ifdef DEBUG_LEAKING_SCALARS_FORK_DUMP
+		    Perl_dump_sv_child(aTHX_ sv);
+#endif
+		}
+	    }
+	}
+    }
+#ifdef DEBUG_LEAKING_SCALARS_FORK_DUMP
+    {
+	int status;
+	fd_set rset;
+	/* Wait for up to 4 seconds for child to terminate.
+	   This seems to be the least effort way of timing out on reaping
+	   its exit status.  */
+	struct timeval waitfor = {4, 0};
+	int sock = PL_dumper_fd;
+
+	shutdown(sock, 1);
+	FD_ZERO(&rset);
+	FD_SET(sock, &rset);
+	select(sock + 1, &rset, NULL, NULL, &waitfor);
+	waitpid(child, &status, WNOHANG);
+	close(sock);
+    }
+#endif
+#endif
+#ifdef DEBUG_LEAKING_SCALARS_ABORT
+    if (PL_sv_count)
+	abort();
+#endif
+    PL_sv_count = 0;
+
+#if defined(PERLIO_LAYERS)
+    /* No more IO - including error messages ! */
+    PerlIO_cleanup(aTHX);
+#endif
+
+    /* sv_undef needs to stay immortal until after PerlIO_cleanup
+       as currently layers use it rather than NULL as a marker
+       for no arg - and will try and SvREFCNT_dec it.
+     */
+    SvREFCNT(&PL_sv_undef) = 0;
+    SvREADONLY_off(&PL_sv_undef);
+
+    Safefree(PL_origfilename);
+    PL_origfilename = NULL;
+    Safefree(PL_reg_curpm);
+    free_tied_hv_pool();
+    Safefree(PL_op_mask);
+    Safefree(PL_psig_name);
+    PL_psig_name = (SV**)NULL;
+    PL_psig_ptr = (SV**)NULL;
+    {
+	/* We need to NULL PL_psig_pend first, so that
+	   signal handlers know not to use it */
+	int *psig_save = PL_psig_pend;
+	PL_psig_pend = (int*)NULL;
+	Safefree(psig_save);
+    }
+    nuke_stacks();
+    TAINTING_set(FALSE);
+    TAINT_WARN_set(FALSE);
+    PL_hints = 0;		/* Reset hints. Should hints be per-interpreter ? */
+
+    DEBUG_P(debprofdump());
+
+    PL_debug = 0;
+
+#ifdef USE_REENTRANT_API
+    Perl_reentrant_free(aTHX);
+#endif
+
+    /* These all point to HVs that are about to be blown away.
+       Code in core and on CPAN assumes that if the interpreter is re-started
+       that they will be cleanly NULL or pointing to a valid HV.  */
+    PL_custom_op_names = NULL;
+    PL_custom_op_descs = NULL;
+    PL_custom_ops = NULL;
+
+    sv_free_arenas();
+
+    while (PL_regmatch_slab) {
+	regmatch_slab  *s = PL_regmatch_slab;
+	PL_regmatch_slab = PL_regmatch_slab->next;
+	Safefree(s);
+    }
+
+    /* As the absolutely last thing, free the non-arena SV for mess() */
+
+    if (PL_mess_sv) {
+	/* we know that type == SVt_PVMG */
+
+	/* it could have accumulated taint magic */
+	MAGIC* mg;
+	MAGIC* moremagic;
+	for (mg = SvMAGIC(PL_mess_sv); mg; mg = moremagic) {
+	    moremagic = mg->mg_moremagic;
+	    if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global
+		&& mg->mg_len >= 0)
+		Safefree(mg->mg_ptr);
+	    Safefree(mg);
+	}
+
+	/* we know that type >= SVt_PV */
+	SvPV_free(PL_mess_sv);
+	Safefree(SvANY(PL_mess_sv));
+	Safefree(PL_mess_sv);
+	PL_mess_sv = NULL;
+    }
+    return STATUS_EXIT;
+}
+
+/*
+=for apidoc perl_free
+
+Releases a Perl interpreter.  See L<perlembed>.
+
+=cut
+*/
+
+void
+perl_free(pTHXx)
+{
+    dVAR;
+
+    PERL_ARGS_ASSERT_PERL_FREE;
+
+    if (PL_veto_cleanup)
+	return;
+
+#ifdef PERL_TRACK_MEMPOOL
+    {
+	/*
+	 * Don't free thread memory if PERL_DESTRUCT_LEVEL is set to a non-zero
+	 * value as we're probably hunting memory leaks then
+	 */
+	if (PL_perl_destruct_level == 0) {
+	    const U32 old_debug = PL_debug;
+	    /* Emulate the PerlHost behaviour of free()ing all memory allocated in this
+	       thread at thread exit.  */
+	    if (DEBUG_m_TEST) {
+		PerlIO_puts(Perl_debug_log, "Disabling memory debugging as we "
+			    "free this thread's memory\n");
+		PL_debug &= ~ DEBUG_m_FLAG;
+	    }
+	    while(aTHXx->Imemory_debug_header.next != &(aTHXx->Imemory_debug_header)){
+		char * next = (char *)(aTHXx->Imemory_debug_header.next);
+		Malloc_t ptr = PERL_MEMORY_DEBUG_HEADER_SIZE + next;
+		safesysfree(ptr);
+	    }
+	    PL_debug = old_debug;
+	}
+    }
+#endif
+
+#if defined(WIN32) || defined(NETWARE)
+#  if defined(PERL_IMPLICIT_SYS)
+    {
+#    ifdef NETWARE
+	void *host = nw_internal_host;
+	PerlMem_free(aTHXx);
+	nw_delete_internal_host(host);
+#    else
+	void *host = w32_internal_host;
+	PerlMem_free(aTHXx);
+	win32_delete_internal_host(host);
+#    endif
+    }
+#  else
+    PerlMem_free(aTHXx);
+#  endif
+#else
+    PerlMem_free(aTHXx);
+#endif
+}
+
+#if defined(USE_ITHREADS)
+/* provide destructors to clean up the thread key when libperl is unloaded */
+#ifndef WIN32 /* handled during DLL_PROCESS_DETACH in win32/perllib.c */
+
+#if defined(__hpux) && !(defined(__ux_version) && __ux_version <= 1020) && !defined(__GNUC__)
+#pragma fini "perl_fini"
+#elif defined(__sun) && !defined(__GNUC__)
+#pragma fini (perl_fini)
+#endif
+
+static void
+#if defined(__GNUC__)
+__attribute__((destructor))
+#endif
+perl_fini(void)
+{
+    dVAR;
+    if (
+#ifdef PERL_GLOBAL_STRUCT_PRIVATE
+        my_vars &&
+#endif
+        PL_curinterp && !PL_veto_cleanup)
+	FREE_THREAD_KEY;
+}
+
+#endif /* WIN32 */
+#endif /* THREADS */
+
+void
+Perl_call_atexit(pTHX_ ATEXIT_t fn, void *ptr)
+{
+    Renew(PL_exitlist, PL_exitlistlen+1, PerlExitListEntry);
+    PL_exitlist[PL_exitlistlen].fn = fn;
+    PL_exitlist[PL_exitlistlen].ptr = ptr;
+    ++PL_exitlistlen;
+}
+
+/*
+=for apidoc perl_parse
+
+Tells a Perl interpreter to parse a Perl script.  See L<perlembed>.
+
+=cut
+*/
+
+#define SET_CURSTASH(newstash)                       \
+	if (PL_curstash != newstash) {                \
+	    SvREFCNT_dec(PL_curstash);                 \
+	    PL_curstash = (HV *)SvREFCNT_inc(newstash); \
+	}
+
+int
+perl_parse(pTHXx_ XSINIT_t xsinit, int argc, char **argv, char **env)
+{
+    dVAR;
+    I32 oldscope;
+    int ret;
+    dJMPENV;
+
+    PERL_ARGS_ASSERT_PERL_PARSE;
+#ifndef MULTIPLICITY
+    PERL_UNUSED_ARG(my_perl);
+#endif
+#if defined(USE_HASH_SEED) || defined(USE_HASH_SEED_EXPLICIT) || defined(USE_HASH_SEED_DEBUG)
+    {
+        const char * const s = PerlEnv_getenv("PERL_HASH_SEED_DEBUG");
+
+        if (s && strEQ(s, "1")) {
+            const unsigned char *seed= PERL_HASH_SEED;
+            const unsigned char *seed_end= PERL_HASH_SEED + PERL_HASH_SEED_BYTES;
+            PerlIO_printf(Perl_debug_log, "HASH_FUNCTION = %s HASH_SEED = 0x", PERL_HASH_FUNC);
+            while (seed < seed_end) {
+                PerlIO_printf(Perl_debug_log, "%02x", *seed++);
+            }
+#ifdef PERL_HASH_RANDOMIZE_KEYS
+            PerlIO_printf(Perl_debug_log, " PERTURB_KEYS = %d (%s)",
+                    PL_HASH_RAND_BITS_ENABLED,
+                    PL_HASH_RAND_BITS_ENABLED == 0 ? "NO" : PL_HASH_RAND_BITS_ENABLED == 1 ? "RANDOM" : "DETERMINISTIC");
+#endif
+            PerlIO_printf(Perl_debug_log, "\n");
+        }
+    }
+#endif /* #if defined(USE_HASH_SEED) || defined(USE_HASH_SEED_EXPLICIT) */
+    PL_origargc = argc;
+    PL_origargv = argv;
+
+    if (PL_origalen != 0) {
+	PL_origalen = 1; /* don't use old PL_origalen if perl_parse() is called again */
+    }
+    else {
+	/* Set PL_origalen be the sum of the contiguous argv[]
+	 * elements plus the size of the env in case that it is
+	 * contiguous with the argv[].  This is used in mg.c:Perl_magic_set()
+	 * as the maximum modifiable length of $0.  In the worst case
+	 * the area we are able to modify is limited to the size of
+	 * the original argv[0].  (See below for 'contiguous', though.)
+	 * --jhi */
+	 const char *s = NULL;
+	 int i;
+	 const UV mask = ~(UV)(PTRSIZE-1);
+         /* Do the mask check only if the args seem like aligned. */
+	 const UV aligned =
+	   (mask < ~(UV)0) && ((PTR2UV(argv[0]) & mask) == PTR2UV(argv[0]));
+
+	 /* See if all the arguments are contiguous in memory.  Note
+	  * that 'contiguous' is a loose term because some platforms
+	  * align the argv[] and the envp[].  If the arguments look
+	  * like non-aligned, assume that they are 'strictly' or
+	  * 'traditionally' contiguous.  If the arguments look like
+	  * aligned, we just check that they are within aligned
+	  * PTRSIZE bytes.  As long as no system has something bizarre
+	  * like the argv[] interleaved with some other data, we are
+	  * fine.  (Did I just evoke Murphy's Law?)  --jhi */
+	 if (PL_origargv && PL_origargc >= 1 && (s = PL_origargv[0])) {
+	      while (*s) s++;
+	      for (i = 1; i < PL_origargc; i++) {
+		   if ((PL_origargv[i] == s + 1
+#ifdef OS2
+			|| PL_origargv[i] == s + 2
+#endif 
+			    )
+		       ||
+		       (aligned &&
+			(PL_origargv[i] >  s &&
+			 PL_origargv[i] <=
+			 INT2PTR(char *, PTR2UV(s + PTRSIZE) & mask)))
+			)
+		   {
+			s = PL_origargv[i];
+			while (*s) s++;
+		   }
+		   else
+			break;
+	      }
+	 }
+
+#ifndef PERL_USE_SAFE_PUTENV
+	 /* Can we grab env area too to be used as the area for $0? */
+	 if (s && PL_origenviron && !PL_use_safe_putenv) {
+	      if ((PL_origenviron[0] == s + 1)
+		  ||
+		  (aligned &&
+		   (PL_origenviron[0] >  s &&
+		    PL_origenviron[0] <=
+		    INT2PTR(char *, PTR2UV(s + PTRSIZE) & mask)))
+		 )
+	      {
+#ifndef OS2		/* ENVIRON is read by the kernel too. */
+		   s = PL_origenviron[0];
+		   while (*s) s++;
+#endif
+		   my_setenv("NoNe  SuCh", NULL);
+		   /* Force copy of environment. */
+		   for (i = 1; PL_origenviron[i]; i++) {
+			if (PL_origenviron[i] == s + 1
+			    ||
+			    (aligned &&
+			     (PL_origenviron[i] >  s &&
+			      PL_origenviron[i] <=
+			      INT2PTR(char *, PTR2UV(s + PTRSIZE) & mask)))
+			   )
+			{
+			     s = PL_origenviron[i];
+			     while (*s) s++;
+			}
+			else
+			     break;
+		   }
+	      }
+	 }
+#endif /* !defined(PERL_USE_SAFE_PUTENV) */
+
+	 PL_origalen = s ? s - PL_origargv[0] + 1 : 0;
+    }
+
+    if (PL_do_undump) {
+
+	/* Come here if running an undumped a.out. */
+
+	PL_origfilename = savepv(argv[0]);
+	PL_do_undump = FALSE;
+	cxstack_ix = -1;		/* start label stack again */
+	init_ids();
+	assert (!TAINT_get);
+	TAINT;
+	set_caret_X();
+	TAINT_NOT;
+	init_postdump_symbols(argc,argv,env);
+	return 0;
+    }
+
+    if (PL_main_root) {
+	op_free(PL_main_root);
+	PL_main_root = NULL;
+    }
+    PL_main_start = NULL;
+    SvREFCNT_dec(PL_main_cv);
+    PL_main_cv = NULL;
+
+    time(&PL_basetime);
+    oldscope = PL_scopestack_ix;
+    PL_dowarn = G_WARN_OFF;
+
+    JMPENV_PUSH(ret);
+    switch (ret) {
+    case 0:
+	parse_body(env,xsinit);
+	if (PL_unitcheckav) {
+	    call_list(oldscope, PL_unitcheckav);
+	}
+	if (PL_checkav) {
+	    PERL_SET_PHASE(PERL_PHASE_CHECK);
+	    call_list(oldscope, PL_checkav);
+	}
+	ret = 0;
+	break;
+    case 1:
+	STATUS_ALL_FAILURE;
+	/* FALLTHROUGH */
+    case 2:
+	/* my_exit() was called */
+	while (PL_scopestack_ix > oldscope)
+	    LEAVE;
+	FREETMPS;
+	SET_CURSTASH(PL_defstash);
+	if (PL_unitcheckav) {
+	    call_list(oldscope, PL_unitcheckav);
+	}
+	if (PL_checkav) {
+	    PERL_SET_PHASE(PERL_PHASE_CHECK);
+	    call_list(oldscope, PL_checkav);
+	}
+	ret = STATUS_EXIT;
+	break;
+    case 3:
+	PerlIO_printf(Perl_error_log, "panic: top_env\n");
+	ret = 1;
+	break;
+    }
+    JMPENV_POP;
+    return ret;
+}
+
+/* This needs to stay in perl.c, as perl.c is compiled with different flags for
+   miniperl, and we need to see those flags reflected in the values here.  */
+
+/* What this returns is subject to change.  Use the public interface in Config.
+ */
+static void
+S_Internals_V(pTHX_ CV *cv)
+{
+    dXSARGS;
+#ifdef LOCAL_PATCH_COUNT
+    const int local_patch_count = LOCAL_PATCH_COUNT;
+#else
+    const int local_patch_count = 0;
+#endif
+    const int entries = 3 + local_patch_count;
+    int i;
+    static const char non_bincompat_options[] = 
+#  ifdef DEBUGGING
+			     " DEBUGGING"
+#  endif
+#  ifdef NO_MATHOMS
+			     " NO_MATHOMS"
+#  endif
+#  ifdef NO_HASH_SEED
+			     " NO_HASH_SEED"
+#  endif
+#  ifdef NO_TAINT_SUPPORT
+			     " NO_TAINT_SUPPORT"
+#  endif
+#  ifdef PERL_BOOL_AS_CHAR
+			     " PERL_BOOL_AS_CHAR"
+#  endif
+#  ifdef PERL_DISABLE_PMC
+			     " PERL_DISABLE_PMC"
+#  endif
+#  ifdef PERL_DONT_CREATE_GVSV
+			     " PERL_DONT_CREATE_GVSV"
+#  endif
+#  ifdef PERL_EXTERNAL_GLOB
+			     " PERL_EXTERNAL_GLOB"
+#  endif
+#  ifdef PERL_HASH_FUNC_SIPHASH
+			     " PERL_HASH_FUNC_SIPHASH"
+#  endif
+#  ifdef PERL_HASH_FUNC_SDBM
+			     " PERL_HASH_FUNC_SDBM"
+#  endif
+#  ifdef PERL_HASH_FUNC_DJB2
+			     " PERL_HASH_FUNC_DJB2"
+#  endif
+#  ifdef PERL_HASH_FUNC_SUPERFAST
+			     " PERL_HASH_FUNC_SUPERFAST"
+#  endif
+#  ifdef PERL_HASH_FUNC_MURMUR3
+			     " PERL_HASH_FUNC_MURMUR3"
+#  endif
+#  ifdef PERL_HASH_FUNC_ONE_AT_A_TIME
+			     " PERL_HASH_FUNC_ONE_AT_A_TIME"
+#  endif
+#  ifdef PERL_HASH_FUNC_ONE_AT_A_TIME_HARD
+			     " PERL_HASH_FUNC_ONE_AT_A_TIME_HARD"
+#  endif
+#  ifdef PERL_HASH_FUNC_ONE_AT_A_TIME_OLD
+			     " PERL_HASH_FUNC_ONE_AT_A_TIME_OLD"
+#  endif
+#  ifdef PERL_IS_MINIPERL
+			     " PERL_IS_MINIPERL"
+#  endif
+#  ifdef PERL_MALLOC_WRAP
+			     " PERL_MALLOC_WRAP"
+#  endif
+#  ifdef PERL_MEM_LOG
+			     " PERL_MEM_LOG"
+#  endif
+#  ifdef PERL_MEM_LOG_NOIMPL
+			     " PERL_MEM_LOG_NOIMPL"
+#  endif
+#  ifdef PERL_NEW_COPY_ON_WRITE
+			     " PERL_NEW_COPY_ON_WRITE"
+#  endif
+#  ifdef PERL_PERTURB_KEYS_DETERMINISTIC
+			     " PERL_PERTURB_KEYS_DETERMINISTIC"
+#  endif
+#  ifdef PERL_PERTURB_KEYS_DISABLED
+			     " PERL_PERTURB_KEYS_DISABLED"
+#  endif
+#  ifdef PERL_PERTURB_KEYS_RANDOM
+			     " PERL_PERTURB_KEYS_RANDOM"
+#  endif
+#  ifdef PERL_PRESERVE_IVUV
+			     " PERL_PRESERVE_IVUV"
+#  endif
+#  ifdef PERL_RELOCATABLE_INCPUSH
+			     " PERL_RELOCATABLE_INCPUSH"
+#  endif
+#  ifdef PERL_USE_DEVEL
+			     " PERL_USE_DEVEL"
+#  endif
+#  ifdef PERL_USE_SAFE_PUTENV
+			     " PERL_USE_SAFE_PUTENV"
+#  endif
+#  ifdef UNLINK_ALL_VERSIONS
+			     " UNLINK_ALL_VERSIONS"
+#  endif
+#  ifdef USE_ATTRIBUTES_FOR_PERLIO
+			     " USE_ATTRIBUTES_FOR_PERLIO"
+#  endif
+#  ifdef USE_FAST_STDIO
+			     " USE_FAST_STDIO"
+#  endif	       
+#  ifdef USE_HASH_SEED_EXPLICIT
+			     " USE_HASH_SEED_EXPLICIT"
+#  endif
+#  ifdef USE_LOCALE
+			     " USE_LOCALE"
+#  endif
+#  ifdef USE_LOCALE_CTYPE
+			     " USE_LOCALE_CTYPE"
+#  endif
+#  ifdef USE_PERL_ATOF
+			     " USE_PERL_ATOF"
+#  endif	       
+#  ifdef USE_SITECUSTOMIZE
+			     " USE_SITECUSTOMIZE"
+#  endif	       
+	;
+    PERL_UNUSED_ARG(cv);
+    PERL_UNUSED_VAR(items);
+
+    EXTEND(SP, entries);
+
+    PUSHs(sv_2mortal(newSVpv(PL_bincompat_options, 0)));
+    PUSHs(Perl_newSVpvn_flags(aTHX_ non_bincompat_options,
+			      sizeof(non_bincompat_options) - 1, SVs_TEMP));
+
+#ifdef __DATE__
+#  ifdef __TIME__
+    PUSHs(Perl_newSVpvn_flags(aTHX_
+			      STR_WITH_LEN("Compiled at " __DATE__ " " __TIME__),
+			      SVs_TEMP));
+#  else
+    PUSHs(Perl_newSVpvn_flags(aTHX_ STR_WITH_LEN("Compiled on " __DATE__),
+			      SVs_TEMP));
+#  endif
+#else
+    PUSHs(&PL_sv_undef);
+#endif
+
+    for (i = 1; i <= local_patch_count; i++) {
+	/* This will be an undef, if PL_localpatches[i] is NULL.  */
+	PUSHs(sv_2mortal(newSVpv(PL_localpatches[i], 0)));
+    }
+
+    XSRETURN(entries);
+}
+
+#define INCPUSH_UNSHIFT			0x01
+#define INCPUSH_ADD_OLD_VERS		0x02
+#define INCPUSH_ADD_VERSIONED_SUB_DIRS	0x04
+#define INCPUSH_ADD_ARCHONLY_SUB_DIRS	0x08
+#define INCPUSH_NOT_BASEDIR		0x10
+#define INCPUSH_CAN_RELOCATE		0x20
+#define INCPUSH_ADD_SUB_DIRS	\
+    (INCPUSH_ADD_VERSIONED_SUB_DIRS|INCPUSH_ADD_ARCHONLY_SUB_DIRS)
+
+STATIC void *
+S_parse_body(pTHX_ char **env, XSINIT_t xsinit)
+{
+    dVAR;
+    PerlIO *rsfp;
+    int argc = PL_origargc;
+    char **argv = PL_origargv;
+    const char *scriptname = NULL;
+    VOL bool dosearch = FALSE;
+    char c;
+    bool doextract = FALSE;
+    const char *cddir = NULL;
+#ifdef USE_SITECUSTOMIZE
+    bool minus_f = FALSE;
+#endif
+    SV *linestr_sv = NULL;
+    bool add_read_e_script = FALSE;
+    U32 lex_start_flags = 0;
+
+    PERL_SET_PHASE(PERL_PHASE_START);
+
+    init_main_stash();
+
+    {
+	const char *s;
+    for (argc--,argv++; argc > 0; argc--,argv++) {
+	if (argv[0][0] != '-' || !argv[0][1])
+	    break;
+	s = argv[0]+1;
+      reswitch:
+	switch ((c = *s)) {
+	case 'C':
+#ifndef PERL_STRICT_CR
+	case '\r':
+#endif
+	case ' ':
+	case '0':
+	case 'F':
+	case 'a':
+	case 'c':
+	case 'd':
+	case 'D':
+	case 'h':
+	case 'i':
+	case 'l':
+	case 'M':
+	case 'm':
+	case 'n':
+	case 'p':
+	case 's':
+	case 'u':
+	case 'U':
+	case 'v':
+	case 'W':
+	case 'X':
+	case 'w':
+	    if ((s = moreswitches(s)))
+		goto reswitch;
+	    break;
+
+	case 't':
+#if defined(SILENT_NO_TAINT_SUPPORT)
+            /* silently ignore */
+#elif defined(NO_TAINT_SUPPORT)
+            Perl_croak_nocontext("This perl was compiled without taint support. "
+                       "Cowardly refusing to run with -t or -T flags");
+#else
+	    CHECK_MALLOC_TOO_LATE_FOR('t');
+	    if( !TAINTING_get ) {
+	         TAINT_WARN_set(TRUE);
+	         TAINTING_set(TRUE);
+	    }
+#endif
+	    s++;
+	    goto reswitch;
+	case 'T':
+#if defined(SILENT_NO_TAINT_SUPPORT)
+            /* silently ignore */
+#elif defined(NO_TAINT_SUPPORT)
+            Perl_croak_nocontext("This perl was compiled without taint support. "
+                       "Cowardly refusing to run with -t or -T flags");
+#else
+	    CHECK_MALLOC_TOO_LATE_FOR('T');
+	    TAINTING_set(TRUE);
+	    TAINT_WARN_set(FALSE);
+#endif
+	    s++;
+	    goto reswitch;
+
+	case 'E':
+	    PL_minus_E = TRUE;
+	    /* FALLTHROUGH */
+	case 'e':
+	    forbid_setid('e', FALSE);
+	    if (!PL_e_script) {
+		PL_e_script = newSVpvs("");
+		add_read_e_script = TRUE;
+	    }
+	    if (*++s)
+		sv_catpv(PL_e_script, s);
+	    else if (argv[1]) {
+		sv_catpv(PL_e_script, argv[1]);
+		argc--,argv++;
+	    }
+	    else
+		Perl_croak(aTHX_ "No code specified for -%c", c);
+	    sv_catpvs(PL_e_script, "\n");
+	    break;
+
+	case 'f':
+#ifdef USE_SITECUSTOMIZE
+	    minus_f = TRUE;
+#endif
+	    s++;
+	    goto reswitch;
+
+	case 'I':	/* -I handled both here and in moreswitches() */
+	    forbid_setid('I', FALSE);
+	    if (!*++s && (s=argv[1]) != NULL) {
+		argc--,argv++;
+	    }
+	    if (s && *s) {
+		STRLEN len = strlen(s);
+		incpush(s, len, INCPUSH_ADD_SUB_DIRS|INCPUSH_ADD_OLD_VERS);
+	    }
+	    else
+		Perl_croak(aTHX_ "No directory specified for -I");
+	    break;
+	case 'S':
+	    forbid_setid('S', FALSE);
+	    dosearch = TRUE;
+	    s++;
+	    goto reswitch;
+	case 'V':
+	    {
+		SV *opts_prog;
+
+		if (*++s != ':')  {
+		    opts_prog = newSVpvs("use Config; Config::_V()");
+		}
+		else {
+		    ++s;
+		    opts_prog = Perl_newSVpvf(aTHX_
+					      "use Config; Config::config_vars(qw%c%s%c)",
+					      0, s, 0);
+		    s += strlen(s);
+		}
+		Perl_av_create_and_push(aTHX_ &PL_preambleav, opts_prog);
+		/* don't look for script or read stdin */
+		scriptname = BIT_BUCKET;
+		goto reswitch;
+	    }
+	case 'x':
+	    doextract = TRUE;
+	    s++;
+	    if (*s)
+		cddir = s;
+	    break;
+	case 0:
+	    break;
+	case '-':
+	    if (!*++s || isSPACE(*s)) {
+		argc--,argv++;
+		goto switch_end;
+	    }
+	    /* catch use of gnu style long options.
+	       Both of these exit immediately.  */
+	    if (strEQ(s, "version"))
+		minus_v();
+	    if (strEQ(s, "help"))
+		usage();
+	    s--;
+	    /* FALLTHROUGH */
+	default:
+	    Perl_croak(aTHX_ "Unrecognized switch: -%s  (-h will show valid options)",s);
+	}
+    }
+    }
+
+  switch_end:
+
+    {
+	char *s;
+
+    if (
+#ifndef SECURE_INTERNAL_GETENV
+        !TAINTING_get &&
+#endif
+	(s = PerlEnv_getenv("PERL5OPT")))
+    {
+        /* s points to static memory in getenv(), which may be overwritten at
+         * any time; use a mortal copy instead */
+	s = SvPVX(sv_2mortal(newSVpv(s, 0)));
+
+	while (isSPACE(*s))
+	    s++;
+	if (*s == '-' && *(s+1) == 'T') {
+#if defined(SILENT_NO_TAINT_SUPPORT)
+            /* silently ignore */
+#elif defined(NO_TAINT_SUPPORT)
+            Perl_croak_nocontext("This perl was compiled without taint support. "
+                       "Cowardly refusing to run with -t or -T flags");
+#else
+	    CHECK_MALLOC_TOO_LATE_FOR('T');
+	    TAINTING_set(TRUE);
+            TAINT_WARN_set(FALSE);
+#endif
+	}
+	else {
+	    char *popt_copy = NULL;
+	    while (s && *s) {
+	        const char *d;
+		while (isSPACE(*s))
+		    s++;
+		if (*s == '-') {
+		    s++;
+		    if (isSPACE(*s))
+			continue;
+		}
+		d = s;
+		if (!*s)
+		    break;
+		if (!strchr("CDIMUdmtwW", *s))
+		    Perl_croak(aTHX_ "Illegal switch in PERL5OPT: -%c", *s);
+		while (++s && *s) {
+		    if (isSPACE(*s)) {
+			if (!popt_copy) {
+			    popt_copy = SvPVX(sv_2mortal(newSVpv(d,0)));
+			    s = popt_copy + (s - d);
+			    d = popt_copy;
+			}
+		        *s++ = '\0';
+			break;
+		    }
+		}
+		if (*d == 't') {
+#if defined(SILENT_NO_TAINT_SUPPORT)
+            /* silently ignore */
+#elif defined(NO_TAINT_SUPPORT)
+                    Perl_croak_nocontext("This perl was compiled without taint support. "
+                               "Cowardly refusing to run with -t or -T flags");
+#else
+		    if( !TAINTING_get) {
+		        TAINT_WARN_set(TRUE);
+		        TAINTING_set(TRUE);
+		    }
+#endif
+		} else {
+		    moreswitches(d);
+		}
+	    }
+	}
+    }
+    }
+
+    /* Set $^X early so that it can be used for relocatable paths in @INC  */
+    /* and for SITELIB_EXP in USE_SITECUSTOMIZE                            */
+    assert (!TAINT_get);
+    TAINT;
+    set_caret_X();
+    TAINT_NOT;
+
+#if defined(USE_SITECUSTOMIZE)
+    if (!minus_f) {
+	/* The games with local $! are to avoid setting errno if there is no
+	   sitecustomize script.  "q%c...%c", 0, ..., 0 becomes "q\0...\0",
+	   ie a q() operator with a NUL byte as a the delimiter. This avoids
+	   problems with pathnames containing (say) '  */
+#  ifdef PERL_IS_MINIPERL
+	AV *const inc = GvAV(PL_incgv);
+	SV **const inc0 = inc ? av_fetch(inc, 0, FALSE) : NULL;
+
+	if (inc0) {
+            /* if lib/buildcustomize.pl exists, it should not fail. If it does,
+               it should be reported immediately as a build failure.  */
+	    (void)Perl_av_create_and_unshift_one(aTHX_ &PL_preambleav,
+						 Perl_newSVpvf(aTHX_
+		"BEGIN { my $f = q%c%s%"SVf"/buildcustomize.pl%c; "
+			"do {local $!; -f $f }"
+			" and do $f || die $@ || qq '$f: $!' }",
+                                0, (TAINTING_get ? "./" : ""), SVfARG(*inc0), 0));
+	}
+#  else
+	/* SITELIB_EXP is a function call on Win32.  */
+	const char *const raw_sitelib = SITELIB_EXP;
+	if (raw_sitelib) {
+	    /* process .../.. if PERL_RELOCATABLE_INC is defined */
+	    SV *sitelib_sv = mayberelocate(raw_sitelib, strlen(raw_sitelib),
+					   INCPUSH_CAN_RELOCATE);
+	    const char *const sitelib = SvPVX(sitelib_sv);
+	    (void)Perl_av_create_and_unshift_one(aTHX_ &PL_preambleav,
+						 Perl_newSVpvf(aTHX_
+							       "BEGIN { do {local $!; -f q%c%s/sitecustomize.pl%c} && do q%c%s/sitecustomize.pl%c }",
+							       0, SVfARG(sitelib), 0,
+							       0, SVfARG(sitelib), 0));
+	    assert (SvREFCNT(sitelib_sv) == 1);
+	    SvREFCNT_dec(sitelib_sv);
+	}
+#  endif
+    }
+#endif
+
+    if (!scriptname)
+	scriptname = argv[0];
+    if (PL_e_script) {
+	argc++,argv--;
+	scriptname = BIT_BUCKET;	/* don't look for script or read stdin */
+    }
+    else if (scriptname == NULL) {
+#ifdef MSDOS
+	if ( PerlLIO_isatty(PerlIO_fileno(PerlIO_stdin())) )
+	    moreswitches("h");
+#endif
+	scriptname = "-";
+    }
+
+    assert (!TAINT_get);
+    init_perllib();
+
+    {
+	bool suidscript = FALSE;
+
+	rsfp = open_script(scriptname, dosearch, &suidscript);
+	if (!rsfp) {
+	    rsfp = PerlIO_stdin();
+	    lex_start_flags = LEX_DONT_CLOSE_RSFP;
+	}
+
+	validate_suid(rsfp);
+
+#ifndef PERL_MICRO
+#  if defined(SIGCHLD) || defined(SIGCLD)
+	{
+#  ifndef SIGCHLD
+#    define SIGCHLD SIGCLD
+#  endif
+	    Sighandler_t sigstate = rsignal_state(SIGCHLD);
+	    if (sigstate == (Sighandler_t) SIG_IGN) {
+		Perl_ck_warner(aTHX_ packWARN(WARN_SIGNAL),
+			       "Can't ignore signal CHLD, forcing to default");
+		(void)rsignal(SIGCHLD, (Sighandler_t)SIG_DFL);
+	    }
+	}
+#  endif
+#endif
+
+	if (doextract) {
+
+	    /* This will croak if suidscript is true, as -x cannot be used with
+	       setuid scripts.  */
+	    forbid_setid('x', suidscript);
+	    /* Hence you can't get here if suidscript is true */
+
+	    linestr_sv = newSV_type(SVt_PV);
+	    lex_start_flags |= LEX_START_COPIED;
+	    find_beginning(linestr_sv, rsfp);
+	    if (cddir && PerlDir_chdir( (char *)cddir ) < 0)
+		Perl_croak(aTHX_ "Can't chdir to %s",cddir);
+	}
+    }
+
+    PL_main_cv = PL_compcv = MUTABLE_CV(newSV_type(SVt_PVCV));
+    CvUNIQUE_on(PL_compcv);
+
+    CvPADLIST_set(PL_compcv, pad_new(0));
+
+    PL_isarev = newHV();
+
+    boot_core_PerlIO();
+    boot_core_UNIVERSAL();
+    boot_core_mro();
+    newXS("Internals::V", S_Internals_V, __FILE__);
+
+    if (xsinit)
+	(*xsinit)(aTHX);	/* in case linked C routines want magical variables */
+#ifndef PERL_MICRO
+#if defined(VMS) || defined(WIN32) || defined(DJGPP) || defined(__CYGWIN__) || defined(SYMBIAN)
+    init_os_extras();
+#endif
+#endif
+
+#ifdef USE_SOCKS
+#   ifdef HAS_SOCKS5_INIT
+    socks5_init(argv[0]);
+#   else
+    SOCKSinit(argv[0]);
+#   endif
+#endif
+
+    init_predump_symbols();
+    /* init_postdump_symbols not currently designed to be called */
+    /* more than once (ENV isn't cleared first, for example)	 */
+    /* But running with -u leaves %ENV & @ARGV undefined!    XXX */
+    if (!PL_do_undump)
+	init_postdump_symbols(argc,argv,env);
+
+    /* PL_unicode is turned on by -C, or by $ENV{PERL_UNICODE},
+     * or explicitly in some platforms.
+     * locale.c:Perl_init_i18nl10n() if the environment
+     * look like the user wants to use UTF-8. */
+#if defined(__SYMBIAN32__)
+    PL_unicode = PERL_UNICODE_STD_FLAG; /* See PERL_SYMBIAN_CONSOLE_UTF8. */
+#endif
+#  ifndef PERL_IS_MINIPERL
+    if (PL_unicode) {
+	 /* Requires init_predump_symbols(). */
+	 if (!(PL_unicode & PERL_UNICODE_LOCALE_FLAG) || PL_utf8locale) {
+	      IO* io;
+	      PerlIO* fp;
+	      SV* sv;
+
+	      /* Turn on UTF-8-ness on STDIN, STDOUT, STDERR
+	       * and the default open disciplines. */
+	      if ((PL_unicode & PERL_UNICODE_STDIN_FLAG) &&
+		  PL_stdingv  && (io = GvIO(PL_stdingv)) &&
+		  (fp = IoIFP(io)))
+		   PerlIO_binmode(aTHX_ fp, IoTYPE(io), 0, ":utf8");
+	      if ((PL_unicode & PERL_UNICODE_STDOUT_FLAG) &&
+		  PL_defoutgv && (io = GvIO(PL_defoutgv)) &&
+		  (fp = IoOFP(io)))
+		   PerlIO_binmode(aTHX_ fp, IoTYPE(io), 0, ":utf8");
+	      if ((PL_unicode & PERL_UNICODE_STDERR_FLAG) &&
+		  PL_stderrgv && (io = GvIO(PL_stderrgv)) &&
+		  (fp = IoOFP(io)))
+		   PerlIO_binmode(aTHX_ fp, IoTYPE(io), 0, ":utf8");
+	      if ((PL_unicode & PERL_UNICODE_INOUT_FLAG) &&
+		  (sv = GvSV(gv_fetchpvs("\017PEN", GV_ADD|GV_NOTQUAL,
+					 SVt_PV)))) {
+		   U32 in  = PL_unicode & PERL_UNICODE_IN_FLAG;
+		   U32 out = PL_unicode & PERL_UNICODE_OUT_FLAG;
+		   if (in) {
+			if (out)
+			     sv_setpvs(sv, ":utf8\0:utf8");
+			else
+			     sv_setpvs(sv, ":utf8\0");
+		   }
+		   else if (out)
+			sv_setpvs(sv, "\0:utf8");
+		   SvSETMAGIC(sv);
+	      }
+	 }
+    }
+#endif
+
+    {
+	const char *s;
+    if ((s = PerlEnv_getenv("PERL_SIGNALS"))) {
+	 if (strEQ(s, "unsafe"))
+	      PL_signals |=  PERL_SIGNALS_UNSAFE_FLAG;
+	 else if (strEQ(s, "safe"))
+	      PL_signals &= ~PERL_SIGNALS_UNSAFE_FLAG;
+	 else
+	      Perl_croak(aTHX_ "PERL_SIGNALS illegal: \"%s\"", s);
+    }
+    }
+
+
+    lex_start(linestr_sv, rsfp, lex_start_flags);
+    SvREFCNT_dec(linestr_sv);
+
+    PL_subname = newSVpvs("main");
+
+    if (add_read_e_script)
+	filter_add(read_e_script, NULL);
+
+    /* now parse the script */
+
+    SETERRNO(0,SS_NORMAL);
+    if (yyparse(GRAMPROG) || PL_parser->error_count) {
+	if (PL_minus_c)
+	    Perl_croak(aTHX_ "%s had compilation errors.\n", PL_origfilename);
+	else {
+	    Perl_croak(aTHX_ "Execution of %s aborted due to compilation errors.\n",
+		       PL_origfilename);
+	}
+    }
+    CopLINE_set(PL_curcop, 0);
+    SET_CURSTASH(PL_defstash);
+    if (PL_e_script) {
+	SvREFCNT_dec(PL_e_script);
+	PL_e_script = NULL;
+    }
+
+    if (PL_do_undump)
+	my_unexec();
+
+    if (isWARN_ONCE) {
+	SAVECOPFILE(PL_curcop);
+	SAVECOPLINE(PL_curcop);
+	gv_check(PL_defstash);
+    }
+
+    LEAVE;
+    FREETMPS;
+
+#ifdef MYMALLOC
+    {
+	const char *s;
+        UV uv;
+        s = PerlEnv_getenv("PERL_DEBUG_MSTATS");
+        if (s && grok_atoUV(s, &uv, NULL) && uv >= 2)
+            dump_mstats("after compilation:");
+    }
+#endif
+
+    ENTER;
+    PL_restartjmpenv = NULL;
+    PL_restartop = 0;
+    return NULL;
+}
+
+/*
+=for apidoc perl_run
+
+Tells a Perl interpreter to run.  See L<perlembed>.
+
+=cut
+*/
+
+int
+perl_run(pTHXx)
+{
+    I32 oldscope;
+    int ret = 0;
+    dJMPENV;
+
+    PERL_ARGS_ASSERT_PERL_RUN;
+#ifndef MULTIPLICITY
+    PERL_UNUSED_ARG(my_perl);
+#endif
+
+    oldscope = PL_scopestack_ix;
+#ifdef VMS
+    VMSISH_HUSHED = 0;
+#endif
+
+    JMPENV_PUSH(ret);
+    switch (ret) {
+    case 1:
+	cxstack_ix = -1;		/* start context stack again */
+	goto redo_body;
+    case 0:				/* normal completion */
+ redo_body:
+	run_body(oldscope);
+	/* FALLTHROUGH */
+    case 2:				/* my_exit() */
+	while (PL_scopestack_ix > oldscope)
+	    LEAVE;
+	FREETMPS;
+	SET_CURSTASH(PL_defstash);
+	if (!(PL_exit_flags & PERL_EXIT_DESTRUCT_END) &&
+	    PL_endav && !PL_minus_c) {
+	    PERL_SET_PHASE(PERL_PHASE_END);
+	    call_list(oldscope, PL_endav);
+	}
+#ifdef MYMALLOC
+	if (PerlEnv_getenv("PERL_DEBUG_MSTATS"))
+	    dump_mstats("after execution:  ");
+#endif
+	ret = STATUS_EXIT;
+	break;
+    case 3:
+	if (PL_restartop) {
+	    POPSTACK_TO(PL_mainstack);
+	    goto redo_body;
+	}
+	PerlIO_printf(Perl_error_log, "panic: restartop in perl_run\n");
+	FREETMPS;
+	ret = 1;
+	break;
+    }
+
+    JMPENV_POP;
+    return ret;
+}
+
+STATIC void
+S_run_body(pTHX_ I32 oldscope)
+{
+    DEBUG_r(PerlIO_printf(Perl_debug_log, "%s $` $& $' support (0x%x).\n",
+                    PL_sawampersand ? "Enabling" : "Omitting",
+                    (unsigned int)(PL_sawampersand)));
+
+    if (!PL_restartop) {
+#ifdef DEBUGGING
+	if (DEBUG_x_TEST || DEBUG_B_TEST)
+	    dump_all_perl(!DEBUG_B_TEST);
+	if (!DEBUG_q_TEST)
+	  PERL_DEBUG(PerlIO_printf(Perl_debug_log, "\nEXECUTING...\n\n"));
+#endif
+
+	if (PL_minus_c) {
+	    PerlIO_printf(Perl_error_log, "%s syntax OK\n", PL_origfilename);
+	    my_exit(0);
+	}
+	if (PERLDB_SINGLE && PL_DBsingle)
+            PL_DBsingle_iv = 1;
+	if (PL_initav) {
+	    PERL_SET_PHASE(PERL_PHASE_INIT);
+	    call_list(oldscope, PL_initav);
+	}
+#ifdef PERL_DEBUG_READONLY_OPS
+	if (PL_main_root && PL_main_root->op_slabbed)
+	    Slab_to_ro(OpSLAB(PL_main_root));
+#endif
+    }
+
+    /* do it */
+
+    PERL_SET_PHASE(PERL_PHASE_RUN);
+
+    if (PL_restartop) {
+	PL_restartjmpenv = NULL;
+	PL_op = PL_restartop;
+	PL_restartop = 0;
+	CALLRUNOPS(aTHX);
+    }
+    else if (PL_main_start) {
+	CvDEPTH(PL_main_cv) = 1;
+	PL_op = PL_main_start;
+	CALLRUNOPS(aTHX);
+    }
+    my_exit(0);
+    NOT_REACHED; /* NOTREACHED */
+}
+
+/*
+=head1 SV Manipulation Functions
+
+=for apidoc p||get_sv
+
+Returns the SV of the specified Perl scalar.  C<flags> are passed to
+C<gv_fetchpv>.  If C<GV_ADD> is set and the
+Perl variable does not exist then it will be created.  If C<flags> is zero
+and the variable does not exist then NULL is returned.
+
+=cut
+*/
+
+SV*
+Perl_get_sv(pTHX_ const char *name, I32 flags)
+{
+    GV *gv;
+
+    PERL_ARGS_ASSERT_GET_SV;
+
+    gv = gv_fetchpv(name, flags, SVt_PV);
+    if (gv)
+	return GvSV(gv);
+    return NULL;
+}
+
+/*
+=head1 Array Manipulation Functions
+
+=for apidoc p||get_av
+
+Returns the AV of the specified Perl global or package array with the given
+name (so it won't work on lexical variables).  C<flags> are passed 
+to C<gv_fetchpv>.  If C<GV_ADD> is set and the
+Perl variable does not exist then it will be created.  If C<flags> is zero
+and the variable does not exist then NULL is returned.
+
+Perl equivalent: C<@{"$name"}>.
+
+=cut
+*/
+
+AV*
+Perl_get_av(pTHX_ const char *name, I32 flags)
+{
+    GV* const gv = gv_fetchpv(name, flags, SVt_PVAV);
+
+    PERL_ARGS_ASSERT_GET_AV;
+
+    if (flags)
+    	return GvAVn(gv);
+    if (gv)
+	return GvAV(gv);
+    return NULL;
+}
+
+/*
+=head1 Hash Manipulation Functions
+
+=for apidoc p||get_hv
+
+Returns the HV of the specified Perl hash.  C<flags> are passed to
+C<gv_fetchpv>.  If C<GV_ADD> is set and the
+Perl variable does not exist then it will be created.  If C<flags> is zero
+and the variable does not exist then NULL is returned.
+
+=cut
+*/
+
+HV*
+Perl_get_hv(pTHX_ const char *name, I32 flags)
+{
+    GV* const gv = gv_fetchpv(name, flags, SVt_PVHV);
+
+    PERL_ARGS_ASSERT_GET_HV;
+
+    if (flags)
+    	return GvHVn(gv);
+    if (gv)
+	return GvHV(gv);
+    return NULL;
+}
+
+/*
+=head1 CV Manipulation Functions
+
+=for apidoc p||get_cvn_flags
+
+Returns the CV of the specified Perl subroutine.  C<flags> are passed to
+C<gv_fetchpvn_flags>.  If C<GV_ADD> is set and the Perl subroutine does not
+exist then it will be declared (which has the same effect as saying
+C<sub name;>).  If C<GV_ADD> is not set and the subroutine does not exist
+then NULL is returned.
+
+=for apidoc p||get_cv
+
+Uses C<strlen> to get the length of C<name>, then calls C<get_cvn_flags>.
+
+=cut
+*/
+
+CV*
+Perl_get_cvn_flags(pTHX_ const char *name, STRLEN len, I32 flags)
+{
+    GV* const gv = gv_fetchpvn_flags(name, len, flags, SVt_PVCV);
+
+    PERL_ARGS_ASSERT_GET_CVN_FLAGS;
+
+    /* XXX this is probably not what they think they're getting.
+     * It has the same effect as "sub name;", i.e. just a forward
+     * declaration! */
+    if ((flags & ~GV_NOADD_MASK) && !GvCVu(gv)) {
+    	return newSTUB(gv,0);
+    }
+    if (gv)
+	return GvCVu(gv);
+    return NULL;
+}
+
+/* Nothing in core calls this now, but we can't replace it with a macro and
+   move it to mathoms.c as a macro would evaluate name twice.  */
+CV*
+Perl_get_cv(pTHX_ const char *name, I32 flags)
+{
+    PERL_ARGS_ASSERT_GET_CV;
+
+    return get_cvn_flags(name, strlen(name), flags);
+}
+
+/* Be sure to refetch the stack pointer after calling these routines. */
+
+/*
+
+=head1 Callback Functions
+
+=for apidoc p||call_argv
+
+Performs a callback to the specified named and package-scoped Perl subroutine 
+with C<argv> (a NULL-terminated array of strings) as arguments.  See
+L<perlcall>.
+
+Approximate Perl equivalent: C<&{"$sub_name"}(@$argv)>.
+
+=cut
+*/
+
+I32
+Perl_call_argv(pTHX_ const char *sub_name, I32 flags, char **argv)
+
+          		/* See G_* flags in cop.h */
+                     	/* null terminated arg list */
+{
+    dSP;
+
+    PERL_ARGS_ASSERT_CALL_ARGV;
+
+    PUSHMARK(SP);
+    while (*argv) {
+        mXPUSHs(newSVpv(*argv,0));
+        argv++;
+    }
+    PUTBACK;
+    return call_pv(sub_name, flags);
+}
+
+/*
+=for apidoc p||call_pv
+
+Performs a callback to the specified Perl sub.  See L<perlcall>.
+
+=cut
+*/
+
+I32
+Perl_call_pv(pTHX_ const char *sub_name, I32 flags)
+              		/* name of the subroutine */
+          		/* See G_* flags in cop.h */
+{
+    PERL_ARGS_ASSERT_CALL_PV;
+
+    return call_sv(MUTABLE_SV(get_cv(sub_name, GV_ADD)), flags);
+}
+
+/*
+=for apidoc p||call_method
+
+Performs a callback to the specified Perl method.  The blessed object must
+be on the stack.  See L<perlcall>.
+
+=cut
+*/
+
+I32
+Perl_call_method(pTHX_ const char *methname, I32 flags)
+               		/* name of the subroutine */
+          		/* See G_* flags in cop.h */
+{
+    STRLEN len;
+    SV* sv;
+    PERL_ARGS_ASSERT_CALL_METHOD;
+
+    len = strlen(methname);
+    sv = flags & G_METHOD_NAMED
+        ? sv_2mortal(newSVpvn_share(methname, len,0))
+        : newSVpvn_flags(methname, len, SVs_TEMP);
+
+    return call_sv(sv, flags | G_METHOD);
+}
+
+/* May be called with any of a CV, a GV, or an SV containing the name. */
+/*
+=for apidoc p||call_sv
+
+Performs a callback to the Perl sub specified by the SV.
+
+If neither the C<G_METHOD> or C<G_METHOD_NAMED> flag is supplied, the
+SV may be any of a CV, a GV, a reference to a CV, a reference to a GV
+or C<SvPV(sv)> will be used as the name of the sub to call.
+
+If the C<G_METHOD> flag is supplied, the SV may be a reference to a CV or
+C<SvPV(sv)> will be used as the name of the method to call.
+
+If the C<G_METHOD_NAMED> flag is supplied, C<SvPV(sv)> will be used as
+the name of the method to call.
+
+Some other values are treated specially for internal use and should
+not be depended on.
+
+See L<perlcall>.
+
+=cut
+*/
+
+I32
+Perl_call_sv(pTHX_ SV *sv, VOL I32 flags)
+          		/* See G_* flags in cop.h */
+{
+    dVAR; dSP;
+    LOGOP myop;		/* fake syntax tree node */
+    METHOP method_op;
+    I32 oldmark;
+    VOL I32 retval = 0;
+    I32 oldscope;
+    bool oldcatch = CATCH_GET;
+    int ret;
+    OP* const oldop = PL_op;
+    dJMPENV;
+
+    PERL_ARGS_ASSERT_CALL_SV;
+
+    if (flags & G_DISCARD) {
+	ENTER;
+	SAVETMPS;
+    }
+    if (!(flags & G_WANT)) {
+	/* Backwards compatibility - as G_SCALAR was 0, it could be omitted.
+	 */
+	flags |= G_SCALAR;
+    }
+
+    Zero(&myop, 1, LOGOP);
+    if (!(flags & G_NOARGS))
+	myop.op_flags |= OPf_STACKED;
+    myop.op_flags |= OP_GIMME_REVERSE(flags);
+    SAVEOP();
+    PL_op = (OP*)&myop;
+
+    EXTEND(PL_stack_sp, 1);
+    if (!(flags & G_METHOD_NAMED))
+        *++PL_stack_sp = sv;
+    oldmark = TOPMARK;
+    oldscope = PL_scopestack_ix;
+
+    if (PERLDB_SUB && PL_curstash != PL_debstash
+	   /* Handle first BEGIN of -d. */
+	  && (PL_DBcv || (PL_DBcv = GvCV(PL_DBsub)))
+	   /* Try harder, since this may have been a sighandler, thus
+	    * curstash may be meaningless. */
+	  && (SvTYPE(sv) != SVt_PVCV || CvSTASH((const CV *)sv) != PL_debstash)
+	  && !(flags & G_NODEBUG))
+	myop.op_private |= OPpENTERSUB_DB;
+
+    if (flags & (G_METHOD|G_METHOD_NAMED)) {
+        Zero(&method_op, 1, METHOP);
+        method_op.op_next = (OP*)&myop;
+        PL_op = (OP*)&method_op;
+        if ( flags & G_METHOD_NAMED ) {
+            method_op.op_ppaddr = PL_ppaddr[OP_METHOD_NAMED];
+            method_op.op_type = OP_METHOD_NAMED;
+            method_op.op_u.op_meth_sv = sv;
+        } else {
+            method_op.op_ppaddr = PL_ppaddr[OP_METHOD];
+            method_op.op_type = OP_METHOD;
+        }
+        myop.op_ppaddr = PL_ppaddr[OP_ENTERSUB];
+        myop.op_type = OP_ENTERSUB;
+    }
+
+    if (!(flags & G_EVAL)) {
+	CATCH_SET(TRUE);
+	CALL_BODY_SUB((OP*)&myop);
+	retval = PL_stack_sp - (PL_stack_base + oldmark);
+	CATCH_SET(oldcatch);
+    }
+    else {
+	myop.op_other = (OP*)&myop;
+	PL_markstack_ptr--;
+	create_eval_scope(flags|G_FAKINGEVAL);
+	PL_markstack_ptr++;
+
+	JMPENV_PUSH(ret);
+
+	switch (ret) {
+	case 0:
+ redo_body:
+	    CALL_BODY_SUB((OP*)&myop);
+	    retval = PL_stack_sp - (PL_stack_base + oldmark);
+	    if (!(flags & G_KEEPERR)) {
+		CLEAR_ERRSV();
+	    }
+	    break;
+	case 1:
+	    STATUS_ALL_FAILURE;
+	    /* FALLTHROUGH */
+	case 2:
+	    /* my_exit() was called */
+	    SET_CURSTASH(PL_defstash);
+	    FREETMPS;
+	    JMPENV_POP;
+	    my_exit_jump();
+	    NOT_REACHED; /* NOTREACHED */
+	case 3:
+	    if (PL_restartop) {
+		PL_restartjmpenv = NULL;
+		PL_op = PL_restartop;
+		PL_restartop = 0;
+		goto redo_body;
+	    }
+	    PL_stack_sp = PL_stack_base + oldmark;
+	    if ((flags & G_WANT) == G_ARRAY)
+		retval = 0;
+	    else {
+		retval = 1;
+		*++PL_stack_sp = &PL_sv_undef;
+	    }
+	    break;
+	}
+
+	if (PL_scopestack_ix > oldscope)
+	    delete_eval_scope();
+	JMPENV_POP;
+    }
+
+    if (flags & G_DISCARD) {
+	PL_stack_sp = PL_stack_base + oldmark;
+	retval = 0;
+	FREETMPS;
+	LEAVE;
+    }
+    PL_op = oldop;
+    return retval;
+}
+
+/* Eval a string. The G_EVAL flag is always assumed. */
+
+/*
+=for apidoc p||eval_sv
+
+Tells Perl to C<eval> the string in the SV.  It supports the same flags
+as C<call_sv>, with the obvious exception of G_EVAL.  See L<perlcall>.
+
+=cut
+*/
+
+I32
+Perl_eval_sv(pTHX_ SV *sv, I32 flags)
+
+          		/* See G_* flags in cop.h */
+{
+    dVAR;
+    dSP;
+    UNOP myop;		/* fake syntax tree node */
+    VOL I32 oldmark = SP - PL_stack_base;
+    VOL I32 retval = 0;
+    int ret;
+    OP* const oldop = PL_op;
+    dJMPENV;
+
+    PERL_ARGS_ASSERT_EVAL_SV;
+
+    if (flags & G_DISCARD) {
+	ENTER;
+	SAVETMPS;
+    }
+
+    SAVEOP();
+    PL_op = (OP*)&myop;
+    Zero(&myop, 1, UNOP);
+    EXTEND(PL_stack_sp, 1);
+    *++PL_stack_sp = sv;
+
+    if (!(flags & G_NOARGS))
+	myop.op_flags = OPf_STACKED;
+    myop.op_type = OP_ENTEREVAL;
+    myop.op_flags |= OP_GIMME_REVERSE(flags);
+    if (flags & G_KEEPERR)
+	myop.op_flags |= OPf_SPECIAL;
+
+    if (flags & G_RE_REPARSING)
+	myop.op_private = (OPpEVAL_COPHH | OPpEVAL_RE_REPARSING);
+
+    /* fail now; otherwise we could fail after the JMPENV_PUSH but
+     * before a PUSHEVAL, which corrupts the stack after a croak */
+    TAINT_PROPER("eval_sv()");
+
+    JMPENV_PUSH(ret);
+    switch (ret) {
+    case 0:
+ redo_body:
+	if (PL_op == (OP*)(&myop)) {
+	    PL_op = PL_ppaddr[OP_ENTEREVAL](aTHX);
+	    if (!PL_op)
+		goto fail; /* failed in compilation */
+	}
+	CALLRUNOPS(aTHX);
+	retval = PL_stack_sp - (PL_stack_base + oldmark);
+	if (!(flags & G_KEEPERR)) {
+	    CLEAR_ERRSV();
+	}
+	break;
+    case 1:
+	STATUS_ALL_FAILURE;
+	/* FALLTHROUGH */
+    case 2:
+	/* my_exit() was called */
+	SET_CURSTASH(PL_defstash);
+	FREETMPS;
+	JMPENV_POP;
+	my_exit_jump();
+	NOT_REACHED; /* NOTREACHED */
+    case 3:
+	if (PL_restartop) {
+	    PL_restartjmpenv = NULL;
+	    PL_op = PL_restartop;
+	    PL_restartop = 0;
+	    goto redo_body;
+	}
+      fail:
+	PL_stack_sp = PL_stack_base + oldmark;
+	if ((flags & G_WANT) == G_ARRAY)
+	    retval = 0;
+	else {
+	    retval = 1;
+	    *++PL_stack_sp = &PL_sv_undef;
+	}
+	break;
+    }
+
+    JMPENV_POP;
+    if (flags & G_DISCARD) {
+	PL_stack_sp = PL_stack_base + oldmark;
+	retval = 0;
+	FREETMPS;
+	LEAVE;
+    }
+    PL_op = oldop;
+    return retval;
+}
+
+/*
+=for apidoc p||eval_pv
+
+Tells Perl to C<eval> the given string in scalar context and return an SV* result.
+
+=cut
+*/
+
+SV*
+Perl_eval_pv(pTHX_ const char *p, I32 croak_on_error)
+{
+    SV* sv = newSVpv(p, 0);
+
+    PERL_ARGS_ASSERT_EVAL_PV;
+
+    eval_sv(sv, G_SCALAR);
+    SvREFCNT_dec(sv);
+
+    {
+        dSP;
+        sv = POPs;
+        PUTBACK;
+    }
+
+    /* just check empty string or undef? */
+    if (croak_on_error) {
+	SV * const errsv = ERRSV;
+	if(SvTRUE_NN(errsv))
+	    /* replace with croak_sv? */
+	    Perl_croak_nocontext("%s", SvPV_nolen_const(errsv));
+    }
+
+    return sv;
+}
+
+/* Require a module. */
+
+/*
+=head1 Embedding Functions
+
+=for apidoc p||require_pv
+
+Tells Perl to C<require> the file named by the string argument.  It is
+analogous to the Perl code C<eval "require '$file'">.  It's even
+implemented that way; consider using load_module instead.
+
+=cut */
+
+void
+Perl_require_pv(pTHX_ const char *pv)
+{
+    dSP;
+    SV* sv;
+
+    PERL_ARGS_ASSERT_REQUIRE_PV;
+
+    PUSHSTACKi(PERLSI_REQUIRE);
+    sv = Perl_newSVpvf(aTHX_ "require q%c%s%c", 0, pv, 0);
+    eval_sv(sv_2mortal(sv), G_DISCARD);
+    POPSTACK;
+}
+
+STATIC void
+S_usage(pTHX)		/* XXX move this out into a module ? */
+{
+    /* This message really ought to be max 23 lines.
+     * Removed -h because the user already knows that option. Others? */
+
+    /* Grouped as 6 lines per C string literal, to keep under the ANSI C 89
+       minimum of 509 character string literals.  */
+    static const char * const usage_msg[] = {
+"  -0[octal]         specify record separator (\\0, if no argument)\n"
+"  -a                autosplit mode with -n or -p (splits $_ into @F)\n"
+"  -C[number/list]   enables the listed Unicode features\n"
+"  -c                check syntax only (runs BEGIN and CHECK blocks)\n"
+"  -d[:debugger]     run program under debugger\n"
+"  -D[number/list]   set debugging flags (argument is a bit mask or alphabets)\n",
+"  -e program        one line of program (several -e's allowed, omit programfile)\n"
+"  -E program        like -e, but enables all optional features\n"
+"  -f                don't do $sitelib/sitecustomize.pl at startup\n"
+"  -F/pattern/       split() pattern for -a switch (//'s are optional)\n"
+"  -i[extension]     edit <> files in place (makes backup if extension supplied)\n"
+"  -Idirectory       specify @INC/#include directory (several -I's allowed)\n",
+"  -l[octal]         enable line ending processing, specifies line terminator\n"
+"  -[mM][-]module    execute \"use/no module...\" before executing program\n"
+"  -n                assume \"while (<>) { ... }\" loop around program\n"
+"  -p                assume loop like -n but print line also, like sed\n"
+"  -s                enable rudimentary parsing for switches after programfile\n"
+"  -S                look for programfile using PATH environment variable\n",
+"  -t                enable tainting warnings\n"
+"  -T                enable tainting checks\n"
+"  -u                dump core after parsing program\n"
+"  -U                allow unsafe operations\n"
+"  -v                print version, patchlevel and license\n"
+"  -V[:variable]     print configuration summary (or a single Config.pm variable)\n",
+"  -w                enable many useful warnings\n"
+"  -W                enable all warnings\n"
+"  -x[directory]     ignore text before #!perl line (optionally cd to directory)\n"
+"  -X                disable all warnings\n"
+"  \n"
+"Run 'perldoc perl' for more help with Perl.\n\n",
+NULL
+};
+    const char * const *p = usage_msg;
+    PerlIO *out = PerlIO_stdout();
+
+    PerlIO_printf(out,
+		  "\nUsage: %s [switches] [--] [programfile] [arguments]\n",
+		  PL_origargv[0]);
+    while (*p)
+	PerlIO_puts(out, *p++);
+    my_exit(0);
+}
+
+/* convert a string of -D options (or digits) into an int.
+ * sets *s to point to the char after the options */
+
+#ifdef DEBUGGING
+int
+Perl_get_debug_opts(pTHX_ const char **s, bool givehelp)
+{
+    static const char * const usage_msgd[] = {
+      " Debugging flag values: (see also -d)\n"
+      "  p  Tokenizing and parsing (with v, displays parse stack)\n"
+      "  s  Stack snapshots (with v, displays all stacks)\n"
+      "  l  Context (loop) stack processing\n"
+      "  t  Trace execution\n"
+      "  o  Method and overloading resolution\n",
+      "  c  String/numeric conversions\n"
+      "  P  Print profiling info, source file input state\n"
+      "  m  Memory and SV allocation\n"
+      "  f  Format processing\n"
+      "  r  Regular expression parsing and execution\n"
+      "  x  Syntax tree dump\n",
+      "  u  Tainting checks\n"
+      "  H  Hash dump -- usurps values()\n"
+      "  X  Scratchpad allocation\n"
+      "  D  Cleaning up\n"
+      "  S  Op slab allocation\n"
+      "  T  Tokenising\n"
+      "  R  Include reference counts of dumped variables (eg when using -Ds)\n",
+      "  J  Do not s,t,P-debug (Jump over) opcodes within package DB\n"
+      "  v  Verbose: use in conjunction with other flags\n"
+      "  C  Copy On Write\n"
+      "  A  Consistency checks on internal structures\n"
+      "  q  quiet - currently only suppresses the 'EXECUTING' message\n"
+      "  M  trace smart match resolution\n"
+      "  B  dump suBroutine definitions, including special Blocks like BEGIN\n",
+      "  L  trace some locale setting information--for Perl core development\n",
+      NULL
+    };
+    UV uv = 0;
+
+    PERL_ARGS_ASSERT_GET_DEBUG_OPTS;
+
+    if (isALPHA(**s)) {
+	/* if adding extra options, remember to update DEBUG_MASK */
+	static const char debopts[] = "psltocPmfrxuUHXDSTRJvCAqMBL";
+
+	for (; isWORDCHAR(**s); (*s)++) {
+	    const char * const d = strchr(debopts,**s);
+	    if (d)
+		uv |= 1 << (d - debopts);
+	    else if (ckWARN_d(WARN_DEBUGGING))
+	        Perl_warner(aTHX_ packWARN(WARN_DEBUGGING),
+		    "invalid option -D%c, use -D'' to see choices\n", **s);
+	}
+    }
+    else if (isDIGIT(**s)) {
+        const char* e;
+	if (grok_atoUV(*s, &uv, &e))
+            *s = e;
+	for (; isWORDCHAR(**s); (*s)++) ;
+    }
+    else if (givehelp) {
+      const char *const *p = usage_msgd;
+      while (*p) PerlIO_puts(PerlIO_stdout(), *p++);
+    }
+    return (int)uv; /* ignore any UV->int conversion loss */
+}
+#endif
+
+/* This routine handles any switches that can be given during run */
+
+const char *
+Perl_moreswitches(pTHX_ const char *s)
+{
+    dVAR;
+    UV rschar;
+    const char option = *s; /* used to remember option in -m/-M code */
+
+    PERL_ARGS_ASSERT_MORESWITCHES;
+
+    switch (*s) {
+    case '0':
+    {
+	 I32 flags = 0;
+	 STRLEN numlen;
+
+	 SvREFCNT_dec(PL_rs);
+	 if (s[1] == 'x' && s[2]) {
+	      const char *e = s+=2;
+	      U8 *tmps;
+
+	      while (*e)
+		e++;
+	      numlen = e - s;
+	      flags = PERL_SCAN_SILENT_ILLDIGIT;
+	      rschar = (U32)grok_hex(s, &numlen, &flags, NULL);
+	      if (s + numlen < e) {
+		   rschar = 0; /* Grandfather -0xFOO as -0 -xFOO. */
+		   numlen = 0;
+		   s--;
+	      }
+	      PL_rs = newSVpvs("");
+	      SvGROW(PL_rs, (STRLEN)(UNISKIP(rschar) + 1));
+	      tmps = (U8*)SvPVX(PL_rs);
+	      uvchr_to_utf8(tmps, rschar);
+	      SvCUR_set(PL_rs, UNISKIP(rschar));
+	      SvUTF8_on(PL_rs);
+	 }
+	 else {
+	      numlen = 4;
+	      rschar = (U32)grok_oct(s, &numlen, &flags, NULL);
+	      if (rschar & ~((U8)~0))
+		   PL_rs = &PL_sv_undef;
+	      else if (!rschar && numlen >= 2)
+		   PL_rs = newSVpvs("");
+	      else {
+		   char ch = (char)rschar;
+		   PL_rs = newSVpvn(&ch, 1);
+	      }
+	 }
+	 sv_setsv(get_sv("/", GV_ADD), PL_rs);
+	 return s + numlen;
+    }
+    case 'C':
+        s++;
+        PL_unicode = parse_unicode_opts( (const char **)&s );
+	if (PL_unicode & PERL_UNICODE_UTF8CACHEASSERT_FLAG)
+	    PL_utf8cache = -1;
+	return s;
+    case 'F':
+	PL_minus_a = TRUE;
+	PL_minus_F = TRUE;
+        PL_minus_n = TRUE;
+	PL_splitstr = ++s;
+	while (*s && !isSPACE(*s)) ++s;
+	PL_splitstr = savepvn(PL_splitstr, s - PL_splitstr);
+	return s;
+    case 'a':
+	PL_minus_a = TRUE;
+        PL_minus_n = TRUE;
+	s++;
+	return s;
+    case 'c':
+	PL_minus_c = TRUE;
+	s++;
+	return s;
+    case 'd':
+	forbid_setid('d', FALSE);
+	s++;
+
+        /* -dt indicates to the debugger that threads will be used */
+	if (*s == 't' && !isWORDCHAR(s[1])) {
+	    ++s;
+	    my_setenv("PERL5DB_THREADED", "1");
+	}
+
+	/* The following permits -d:Mod to accepts arguments following an =
+	   in the fashion that -MSome::Mod does. */
+	if (*s == ':' || *s == '=') {
+	    const char *start;
+	    const char *end;
+	    SV *sv;
+
+	    if (*++s == '-') {
+		++s;
+		sv = newSVpvs("no Devel::");
+	    } else {
+		sv = newSVpvs("use Devel::");
+	    }
+
+	    start = s;
+	    end = s + strlen(s);
+
+	    /* We now allow -d:Module=Foo,Bar and -d:-Module */
+	    while(isWORDCHAR(*s) || *s==':') ++s;
+	    if (*s != '=')
+		sv_catpvn(sv, start, end - start);
+	    else {
+		sv_catpvn(sv, start, s-start);
+		/* Don't use NUL as q// delimiter here, this string goes in the
+		 * environment. */
+		Perl_sv_catpvf(aTHX_ sv, " split(/,/,q{%s});", ++s);
+	    }
+	    s = end;
+	    my_setenv("PERL5DB", SvPV_nolen_const(sv));
+	    SvREFCNT_dec(sv);
+	}
+	if (!PL_perldb) {
+	    PL_perldb = PERLDB_ALL;
+	    init_debugger();
+	}
+	return s;
+    case 'D':
+    {	
+#ifdef DEBUGGING
+	forbid_setid('D', FALSE);
+	s++;
+	PL_debug = get_debug_opts( (const char **)&s, 1) | DEBUG_TOP_FLAG;
+#else /* !DEBUGGING */
+	if (ckWARN_d(WARN_DEBUGGING))
+	    Perl_warner(aTHX_ packWARN(WARN_DEBUGGING),
+	           "Recompile perl with -DDEBUGGING to use -D switch (did you mean -d ?)\n");
+	for (s++; isWORDCHAR(*s); s++) ;
+#endif
+	return s;
+        NOT_REACHED; /* NOTREACHED */
+    }	
+    case 'h':
+	usage();
+        NOT_REACHED; /* NOTREACHED */
+
+    case 'i':
+	Safefree(PL_inplace);
+#if defined(__CYGWIN__) /* do backup extension automagically */
+	if (*(s+1) == '\0') {
+	PL_inplace = savepvs(".bak");
+	return s+1;
+	}
+#endif /* __CYGWIN__ */
+	{
+	    const char * const start = ++s;
+	    while (*s && !isSPACE(*s))
+		++s;
+
+	    PL_inplace = savepvn(start, s - start);
+	}
+	if (*s) {
+	    ++s;
+	    if (*s == '-')	/* Additional switches on #! line. */
+		s++;
+	}
+	return s;
+    case 'I':	/* -I handled both here and in parse_body() */
+	forbid_setid('I', FALSE);
+	++s;
+	while (*s && isSPACE(*s))
+	    ++s;
+	if (*s) {
+	    const char *e, *p;
+	    p = s;
+	    /* ignore trailing spaces (possibly followed by other switches) */
+	    do {
+		for (e = p; *e && !isSPACE(*e); e++) ;
+		p = e;
+		while (isSPACE(*p))
+		    p++;
+	    } while (*p && *p != '-');
+	    incpush(s, e-s,
+		    INCPUSH_ADD_SUB_DIRS|INCPUSH_ADD_OLD_VERS|INCPUSH_UNSHIFT);
+	    s = p;
+	    if (*s == '-')
+		s++;
+	}
+	else
+	    Perl_croak(aTHX_ "No directory specified for -I");
+	return s;
+    case 'l':
+	PL_minus_l = TRUE;
+	s++;
+	if (PL_ors_sv) {
+	    SvREFCNT_dec(PL_ors_sv);
+	    PL_ors_sv = NULL;
+	}
+	if (isDIGIT(*s)) {
+            I32 flags = 0;
+	    STRLEN numlen;
+	    PL_ors_sv = newSVpvs("\n");
+	    numlen = 3 + (*s == '0');
+	    *SvPVX(PL_ors_sv) = (char)grok_oct(s, &numlen, &flags, NULL);
+	    s += numlen;
+	}
+	else {
+	    if (RsPARA(PL_rs)) {
+		PL_ors_sv = newSVpvs("\n\n");
+	    }
+	    else {
+		PL_ors_sv = newSVsv(PL_rs);
+	    }
+	}
+	return s;
+    case 'M':
+	forbid_setid('M', FALSE);	/* XXX ? */
+	/* FALLTHROUGH */
+    case 'm':
+	forbid_setid('m', FALSE);	/* XXX ? */
+	if (*++s) {
+	    const char *start;
+	    const char *end;
+	    SV *sv;
+	    const char *use = "use ";
+	    bool colon = FALSE;
+	    /* -M-foo == 'no foo'	*/
+	    /* Leading space on " no " is deliberate, to make both
+	       possibilities the same length.  */
+	    if (*s == '-') { use = " no "; ++s; }
+	    sv = newSVpvn(use,4);
+	    start = s;
+	    /* We allow -M'Module qw(Foo Bar)'	*/
+	    while(isWORDCHAR(*s) || *s==':') {
+		if( *s++ == ':' ) {
+		    if( *s == ':' ) 
+			s++;
+		    else
+			colon = TRUE;
+		}
+	    }
+	    if (s == start)
+		Perl_croak(aTHX_ "Module name required with -%c option",
+				    option);
+	    if (colon) 
+		Perl_croak(aTHX_ "Invalid module name %.*s with -%c option: "
+				    "contains single ':'",
+				    (int)(s - start), start, option);
+	    end = s + strlen(s);
+	    if (*s != '=') {
+		sv_catpvn(sv, start, end - start);
+		if (option == 'm') {
+		    if (*s != '\0')
+			Perl_croak(aTHX_ "Can't use '%c' after -mname", *s);
+		    sv_catpvs( sv, " ()");
+		}
+	    } else {
+		sv_catpvn(sv, start, s-start);
+		/* Use NUL as q''-delimiter.  */
+		sv_catpvs(sv, " split(/,/,q\0");
+		++s;
+		sv_catpvn(sv, s, end - s);
+		sv_catpvs(sv,  "\0)");
+	    }
+	    s = end;
+	    Perl_av_create_and_push(aTHX_ &PL_preambleav, sv);
+	}
+	else
+	    Perl_croak(aTHX_ "Missing argument to -%c", option);
+	return s;
+    case 'n':
+	PL_minus_n = TRUE;
+	s++;
+	return s;
+    case 'p':
+	PL_minus_p = TRUE;
+	s++;
+	return s;
+    case 's':
+	forbid_setid('s', FALSE);
+	PL_doswitches = TRUE;
+	s++;
+	return s;
+    case 't':
+    case 'T':
+#if defined(SILENT_NO_TAINT_SUPPORT)
+            /* silently ignore */
+#elif defined(NO_TAINT_SUPPORT)
+        Perl_croak_nocontext("This perl was compiled without taint support. "
+                   "Cowardly refusing to run with -t or -T flags");
+#else
+        if (!TAINTING_get)
+	    TOO_LATE_FOR(*s);
+#endif
+        s++;
+	return s;
+    case 'u':
+	PL_do_undump = TRUE;
+	s++;
+	return s;
+    case 'U':
+	PL_unsafe = TRUE;
+	s++;
+	return s;
+    case 'v':
+	minus_v();
+    case 'w':
+	if (! (PL_dowarn & G_WARN_ALL_MASK)) {
+	    PL_dowarn |= G_WARN_ON;
+	}
+	s++;
+	return s;
+    case 'W':
+	PL_dowarn = G_WARN_ALL_ON|G_WARN_ON;
+        if (!specialWARN(PL_compiling.cop_warnings))
+            PerlMemShared_free(PL_compiling.cop_warnings);
+	PL_compiling.cop_warnings = pWARN_ALL ;
+	s++;
+	return s;
+    case 'X':
+	PL_dowarn = G_WARN_ALL_OFF;
+        if (!specialWARN(PL_compiling.cop_warnings))
+            PerlMemShared_free(PL_compiling.cop_warnings);
+	PL_compiling.cop_warnings = pWARN_NONE ;
+	s++;
+	return s;
+    case '*':
+    case ' ':
+        while( *s == ' ' )
+          ++s;
+	if (s[0] == '-')	/* Additional switches on #! line. */
+	    return s+1;
+	break;
+    case '-':
+    case 0:
+#if defined(WIN32) || !defined(PERL_STRICT_CR)
+    case '\r':
+#endif
+    case '\n':
+    case '\t':
+	break;
+#ifdef ALTERNATE_SHEBANG
+    case 'S':			/* OS/2 needs -S on "extproc" line. */
+	break;
+#endif
+    case 'e': case 'f': case 'x': case 'E':
+#ifndef ALTERNATE_SHEBANG
+    case 'S':
+#endif
+    case 'V':
+	Perl_croak(aTHX_ "Can't emulate -%.1s on #! line",s);
+    default:
+	Perl_croak(aTHX_
+	    "Unrecognized switch: -%.1s  (-h will show valid options)",s
+	);
+    }
+    return NULL;
+}
+
+
+STATIC void
+S_minus_v(pTHX)
+{
+	PerlIO * PIO_stdout;
+	{
+	    const char * const level_str = "v" PERL_VERSION_STRING;
+	    const STRLEN level_len = sizeof("v" PERL_VERSION_STRING)-1;
+#ifdef PERL_PATCHNUM
+	    SV* level;
+#  ifdef PERL_GIT_UNCOMMITTED_CHANGES
+	    static const char num [] = PERL_PATCHNUM "*";
+#  else
+	    static const char num [] = PERL_PATCHNUM;
+#  endif
+	    {
+		const STRLEN num_len = sizeof(num)-1;
+		/* A very advanced compiler would fold away the strnEQ
+		   and this whole conditional, but most (all?) won't do it.
+		   SV level could also be replaced by with preprocessor
+		   catenation.
+		*/
+		if (num_len >= level_len && strnEQ(num,level_str,level_len)) {
+		    /* per 46807d8e80, PERL_PATCHNUM is outside of the control
+		       of the interp so it might contain format characters
+		    */
+		    level = newSVpvn(num, num_len);
+		} else {
+		    level = Perl_newSVpvf_nocontext("%s (%s)", level_str, num);
+		}
+	    }
+#else
+	SV* level = newSVpvn(level_str, level_len);
+#endif /* #ifdef PERL_PATCHNUM */
+	PIO_stdout =  PerlIO_stdout();
+	    PerlIO_printf(PIO_stdout,
+		"\nThis is perl "	STRINGIFY(PERL_REVISION)
+		", version "		STRINGIFY(PERL_VERSION)
+		", subversion "		STRINGIFY(PERL_SUBVERSION)
+		" (%"SVf") built for "	ARCHNAME, SVfARG(level)
+		);
+	    SvREFCNT_dec_NN(level);
+	}
+#if defined(LOCAL_PATCH_COUNT)
+	if (LOCAL_PATCH_COUNT > 0)
+	    PerlIO_printf(PIO_stdout,
+			  "\n(with %d registered patch%s, "
+			  "see perl -V for more detail)",
+			  LOCAL_PATCH_COUNT,
+			  (LOCAL_PATCH_COUNT!=1) ? "es" : "");
+#endif
+
+	PerlIO_printf(PIO_stdout,
+		      "\n\nCopyright 1987-2015, Larry Wall\n");
+#ifdef MSDOS
+	PerlIO_printf(PIO_stdout,
+		      "\nMS-DOS port Copyright (c) 1989, 1990, Diomidis Spinellis\n");
+#endif
+#ifdef DJGPP
+	PerlIO_printf(PIO_stdout,
+		      "djgpp v2 port (jpl5003c) by Hirofumi Watanabe, 1996\n"
+		      "djgpp v2 port (perl5004+) by Laszlo Molnar, 1997-1999\n");
+#endif
+#ifdef OS2
+	PerlIO_printf(PIO_stdout,
+		      "\n\nOS/2 port Copyright (c) 1990, 1991, Raymond Chen, Kai Uwe Rommel\n"
+		      "Version 5 port Copyright (c) 1994-2002, Andreas Kaiser, Ilya Zakharevich\n");
+#endif
+#ifdef OEMVS
+	PerlIO_printf(PIO_stdout,
+		      "MVS (OS390) port by Mortice Kern Systems, 1997-1999\n");
+#endif
+#ifdef __VOS__
+	PerlIO_printf(PIO_stdout,
+		      "Stratus OpenVOS port by Paul.Green@stratus.com, 1997-2013\n");
+#endif
+#ifdef POSIX_BC
+	PerlIO_printf(PIO_stdout,
+		      "BS2000 (POSIX) port by Start Amadeus GmbH, 1998-1999\n");
+#endif
+#ifdef UNDER_CE
+	PerlIO_printf(PIO_stdout,
+			"WINCE port by Rainer Keuchel, 2001-2002\n"
+			"Built on " __DATE__ " " __TIME__ "\n\n");
+	wce_hitreturn();
+#endif
+#ifdef __SYMBIAN32__
+	PerlIO_printf(PIO_stdout,
+		      "Symbian port by Nokia, 2004-2005\n");
+#endif
+#ifdef BINARY_BUILD_NOTICE
+	BINARY_BUILD_NOTICE;
+#endif
+	PerlIO_printf(PIO_stdout,
+		      "\n\
+Perl may be copied only under the terms of either the Artistic License or the\n\
+GNU General Public License, which may be found in the Perl 5 source kit.\n\n\
+Complete documentation for Perl, including FAQ lists, should be found on\n\
+this system using \"man perl\" or \"perldoc perl\".  If you have access to the\n\
+Internet, point your browser at http://www.perl.org/, the Perl Home Page.\n\n");
+	my_exit(0);
+}
+
+/* compliments of Tom Christiansen */
+
+/* unexec() can be found in the Gnu emacs distribution */
+/* Known to work with -DUNEXEC and using unexelf.c from GNU emacs-20.2 */
+
+#ifdef VMS
+#include <lib$routines.h>
+#endif
+
+void
+Perl_my_unexec(pTHX)
+{
+#ifdef UNEXEC
+    SV *    prog = newSVpv(BIN_EXP, 0);
+    SV *    file = newSVpv(PL_origfilename, 0);
+    int    status = 1;
+    extern int etext;
+
+    sv_catpvs(prog, "/perl");
+    sv_catpvs(file, ".perldump");
+
+    unexec(SvPVX(file), SvPVX(prog), &etext, sbrk(0), 0);
+    /* unexec prints msg to stderr in case of failure */
+    PerlProc_exit(status);
+#else
+    PERL_UNUSED_CONTEXT;
+#  ifdef VMS
+     lib$signal(SS$_DEBUG);  /* ssdef.h #included from vmsish.h */
+#  elif defined(WIN32) || defined(__CYGWIN__)
+    Perl_croak_nocontext("dump is not supported");
+#  else
+    ABORT();		/* for use with undump */
+#  endif
+#endif
+}
+
+/* initialize curinterp */
+STATIC void
+S_init_interp(pTHX)
+{
+#ifdef MULTIPLICITY
+#  define PERLVAR(prefix,var,type)
+#  define PERLVARA(prefix,var,n,type)
+#  if defined(PERL_IMPLICIT_CONTEXT)
+#    define PERLVARI(prefix,var,type,init)	aTHX->prefix##var = init;
+#    define PERLVARIC(prefix,var,type,init)	aTHX->prefix##var = init;
+#  else
+#    define PERLVARI(prefix,var,type,init)	PERL_GET_INTERP->var = init;
+#    define PERLVARIC(prefix,var,type,init)	PERL_GET_INTERP->var = init;
+#  endif
+#  include "intrpvar.h"
+#  undef PERLVAR
+#  undef PERLVARA
+#  undef PERLVARI
+#  undef PERLVARIC
+#else
+#  define PERLVAR(prefix,var,type)
+#  define PERLVARA(prefix,var,n,type)
+#  define PERLVARI(prefix,var,type,init)	PL_##var = init;
+#  define PERLVARIC(prefix,var,type,init)	PL_##var = init;
+#  include "intrpvar.h"
+#  undef PERLVAR
+#  undef PERLVARA
+#  undef PERLVARI
+#  undef PERLVARIC
+#endif
+
+}
+
+STATIC void
+S_init_main_stash(pTHX)
+{
+    GV *gv;
+
+    PL_curstash = PL_defstash = (HV *)SvREFCNT_inc_simple_NN(newHV());
+    /* We know that the string "main" will be in the global shared string
+       table, so it's a small saving to use it rather than allocate another
+       8 bytes.  */
+    PL_curstname = newSVpvs_share("main");
+    gv = gv_fetchpvs("main::", GV_ADD|GV_NOTQUAL, SVt_PVHV);
+    /* If we hadn't caused another reference to "main" to be in the shared
+       string table above, then it would be worth reordering these two,
+       because otherwise all we do is delete "main" from it as a consequence
+       of the SvREFCNT_dec, only to add it again with hv_name_set */
+    SvREFCNT_dec(GvHV(gv));
+    hv_name_set(PL_defstash, "main", 4, 0);
+    GvHV(gv) = MUTABLE_HV(SvREFCNT_inc_simple(PL_defstash));
+    SvREADONLY_on(gv);
+    PL_incgv = gv_HVadd(gv_AVadd(gv_fetchpvs("INC", GV_ADD|GV_NOTQUAL,
+					     SVt_PVAV)));
+    SvREFCNT_inc_simple_void(PL_incgv); /* Don't allow it to be freed */
+    GvMULTI_on(PL_incgv);
+    PL_hintgv = gv_fetchpvs("\010", GV_ADD|GV_NOTQUAL, SVt_PV); /* ^H */
+    SvREFCNT_inc_simple_void(PL_hintgv);
+    GvMULTI_on(PL_hintgv);
+    PL_defgv = gv_fetchpvs("_", GV_ADD|GV_NOTQUAL, SVt_PVAV);
+    SvREFCNT_inc_simple_void(PL_defgv);
+    PL_errgv = gv_fetchpvs("@", GV_ADD|GV_NOTQUAL, SVt_PV);
+    SvREFCNT_inc_simple_void(PL_errgv);
+    GvMULTI_on(PL_errgv);
+    PL_replgv = gv_fetchpvs("\022", GV_ADD|GV_NOTQUAL, SVt_PV); /* ^R */
+    SvREFCNT_inc_simple_void(PL_replgv);
+    GvMULTI_on(PL_replgv);
+    (void)Perl_form(aTHX_ "%240s","");	/* Preallocate temp - for immediate signals. */
+#ifdef PERL_DONT_CREATE_GVSV
+    (void)gv_SVadd(PL_errgv);
+#endif
+    sv_grow(ERRSV, 240);	/* Preallocate - for immediate signals. */
+    CLEAR_ERRSV();
+    SET_CURSTASH(PL_defstash);
+    CopSTASH_set(&PL_compiling, PL_defstash);
+    PL_debstash = GvHV(gv_fetchpvs("DB::", GV_ADDMULTI, SVt_PVHV));
+    PL_globalstash = GvHV(gv_fetchpvs("CORE::GLOBAL::", GV_ADDMULTI,
+				      SVt_PVHV));
+    /* We must init $/ before switches are processed. */
+    sv_setpvs(get_sv("/", GV_ADD), "\n");
+}
+
+STATIC PerlIO *
+S_open_script(pTHX_ const char *scriptname, bool dosearch, bool *suidscript)
+{
+    int fdscript = -1;
+    PerlIO *rsfp = NULL;
+    Stat_t tmpstatbuf;
+    int fd;
+
+    PERL_ARGS_ASSERT_OPEN_SCRIPT;
+
+    if (PL_e_script) {
+	PL_origfilename = savepvs("-e");
+    }
+    else {
+        const char *s;
+        UV uv;
+	/* if find_script() returns, it returns a malloc()-ed value */
+	scriptname = PL_origfilename = find_script(scriptname, dosearch, NULL, 1);
+
+	if (strnEQ(scriptname, "/dev/fd/", 8)
+            && isDIGIT(scriptname[8])
+            && grok_atoUV(scriptname + 8, &uv, &s)
+            && uv <= PERL_INT_MAX
+        ) {
+            fdscript = (int)uv;
+	    if (*s) {
+		/* PSz 18 Feb 04
+		 * Tell apart "normal" usage of fdscript, e.g.
+		 * with bash on FreeBSD:
+		 *   perl <( echo '#!perl -DA'; echo 'print "$0\n"')
+		 * from usage in suidperl.
+		 * Does any "normal" usage leave garbage after the number???
+		 * Is it a mistake to use a similar /dev/fd/ construct for
+		 * suidperl?
+		 */
+		*suidscript = TRUE;
+		/* PSz 20 Feb 04  
+		 * Be supersafe and do some sanity-checks.
+		 * Still, can we be sure we got the right thing?
+		 */
+		if (*s != '/') {
+		    Perl_croak(aTHX_ "Wrong syntax (suid) fd script name \"%s\"\n", s);
+		}
+		if (! *(s+1)) {
+		    Perl_croak(aTHX_ "Missing (suid) fd script name\n");
+		}
+		scriptname = savepv(s + 1);
+		Safefree(PL_origfilename);
+		PL_origfilename = (char *)scriptname;
+	    }
+	}
+    }
+
+    CopFILE_free(PL_curcop);
+    CopFILE_set(PL_curcop, PL_origfilename);
+    if (*PL_origfilename == '-' && PL_origfilename[1] == '\0')
+	scriptname = (char *)"";
+    if (fdscript >= 0) {
+	rsfp = PerlIO_fdopen(fdscript,PERL_SCRIPT_MODE);
+    }
+    else if (!*scriptname) {
+	forbid_setid(0, *suidscript);
+	return NULL;
+    }
+    else {
+#ifdef FAKE_BIT_BUCKET
+	/* This hack allows one not to have /dev/null (or BIT_BUCKET as it
+	 * is called) and still have the "-e" work.  (Believe it or not,
+	 * a /dev/null is required for the "-e" to work because source
+	 * filter magic is used to implement it. ) This is *not* a general
+	 * replacement for a /dev/null.  What we do here is create a temp
+	 * file (an empty file), open up that as the script, and then
+	 * immediately close and unlink it.  Close enough for jazz. */ 
+#define FAKE_BIT_BUCKET_PREFIX "/tmp/perlnull-"
+#define FAKE_BIT_BUCKET_SUFFIX "XXXXXXXX"
+#define FAKE_BIT_BUCKET_TEMPLATE FAKE_BIT_BUCKET_PREFIX FAKE_BIT_BUCKET_SUFFIX
+	char tmpname[sizeof(FAKE_BIT_BUCKET_TEMPLATE)] = {
+	    FAKE_BIT_BUCKET_TEMPLATE
+	};
+	const char * const err = "Failed to create a fake bit bucket";
+	if (strEQ(scriptname, BIT_BUCKET)) {
+#ifdef HAS_MKSTEMP /* Hopefully mkstemp() is safe here. */
+            int old_umask = umask(0177);
+	    int tmpfd = mkstemp(tmpname);
+            umask(old_umask);
+	    if (tmpfd > -1) {
+		scriptname = tmpname;
+		close(tmpfd);
+	    } else
+		Perl_croak(aTHX_ err);
+#else
+#  ifdef HAS_MKTEMP
+	    scriptname = mktemp(tmpname);
+	    if (!scriptname)
+		Perl_croak(aTHX_ err);
+#  endif
+#endif
+	}
+#endif
+	rsfp = PerlIO_open(scriptname,PERL_SCRIPT_MODE);
+#ifdef FAKE_BIT_BUCKET
+	if (memEQ(scriptname, FAKE_BIT_BUCKET_PREFIX,
+		  sizeof(FAKE_BIT_BUCKET_PREFIX) - 1)
+	    && strlen(scriptname) == sizeof(tmpname) - 1) {
+	    unlink(scriptname);
+	}
+	scriptname = BIT_BUCKET;
+#endif
+    }
+    if (!rsfp) {
+	/* PSz 16 Sep 03  Keep neat error message */
+	if (PL_e_script)
+	    Perl_croak(aTHX_ "Can't open "BIT_BUCKET": %s\n", Strerror(errno));
+	else
+	    Perl_croak(aTHX_ "Can't open perl script \"%s\": %s\n",
+		    CopFILE(PL_curcop), Strerror(errno));
+    }
+    fd = PerlIO_fileno(rsfp);
+#if defined(HAS_FCNTL) && defined(F_SETFD)
+    if (fd >= 0) {
+        /* ensure close-on-exec */
+        if (fcntl(fd, F_SETFD, 1) < 0) {
+            Perl_croak(aTHX_ "Can't open perl script \"%s\": %s\n",
+                       CopFILE(PL_curcop), Strerror(errno));
+        }
+    }
+#endif
+
+    if (fd < 0 ||
+        (PerlLIO_fstat(fd, &tmpstatbuf) >= 0
+         && S_ISDIR(tmpstatbuf.st_mode)))
+        Perl_croak(aTHX_ "Can't open perl script \"%s\": %s\n",
+            CopFILE(PL_curcop),
+            Strerror(EISDIR));
+
+    return rsfp;
+}
+
+/* Mention
+ * I_SYSSTATVFS	HAS_FSTATVFS
+ * I_SYSMOUNT
+ * I_STATFS	HAS_FSTATFS	HAS_GETFSSTAT
+ * I_MNTENT	HAS_GETMNTENT	HAS_HASMNTOPT
+ * here so that metaconfig picks them up. */
+
+
+#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
+/* Don't even need this function.  */
+#else
+STATIC void
+S_validate_suid(pTHX_ PerlIO *rsfp)
+{
+    const Uid_t  my_uid = PerlProc_getuid();
+    const Uid_t my_euid = PerlProc_geteuid();
+    const Gid_t  my_gid = PerlProc_getgid();
+    const Gid_t my_egid = PerlProc_getegid();
+
+    PERL_ARGS_ASSERT_VALIDATE_SUID;
+
+    if (my_euid != my_uid || my_egid != my_gid) {	/* (suidperl doesn't exist, in fact) */
+	dVAR;
+        int fd = PerlIO_fileno(rsfp);
+        if (fd < 0) {
+            Perl_croak(aTHX_ "Illegal suidscript");
+        } else {
+            if (PerlLIO_fstat(fd, &PL_statbuf) < 0) {	/* may be either wrapped or real suid */
+                Perl_croak(aTHX_ "Illegal suidscript");
+            }
+        }
+        if ((my_euid != my_uid && my_euid == PL_statbuf.st_uid && PL_statbuf.st_mode & S_ISUID)
+            ||
+            (my_egid != my_gid && my_egid == PL_statbuf.st_gid && PL_statbuf.st_mode & S_ISGID)
+            )
+	    if (!PL_do_undump)
+		Perl_croak(aTHX_ "YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\
+FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
+	/* not set-id, must be wrapped */
+    }
+}
+#endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */
+
+STATIC void
+S_find_beginning(pTHX_ SV* linestr_sv, PerlIO *rsfp)
+{
+    const char *s;
+    const char *s2;
+
+    PERL_ARGS_ASSERT_FIND_BEGINNING;
+
+    /* skip forward in input to the real script? */
+
+    do {
+	if ((s = sv_gets(linestr_sv, rsfp, 0)) == NULL)
+	    Perl_croak(aTHX_ "No Perl script found in input\n");
+	s2 = s;
+    } while (!(*s == '#' && s[1] == '!' && ((s = instr(s,"perl")) || (s = instr(s2,"PERL")))));
+    PerlIO_ungetc(rsfp, '\n');		/* to keep line count right */
+    while (*s && !(isSPACE (*s) || *s == '#')) s++;
+    s2 = s;
+    while (*s == ' ' || *s == '\t') s++;
+    if (*s++ == '-') {
+	while (isDIGIT(s2[-1]) || s2[-1] == '-' || s2[-1] == '.'
+	       || s2[-1] == '_') s2--;
+	if (strnEQ(s2-4,"perl",4))
+	    while ((s = moreswitches(s)))
+		;
+    }
+}
+
+
+STATIC void
+S_init_ids(pTHX)
+{
+    /* no need to do anything here any more if we don't
+     * do tainting. */
+#ifndef NO_TAINT_SUPPORT
+    const Uid_t my_uid = PerlProc_getuid();
+    const Uid_t my_euid = PerlProc_geteuid();
+    const Gid_t my_gid = PerlProc_getgid();
+    const Gid_t my_egid = PerlProc_getegid();
+
+    PERL_UNUSED_CONTEXT;
+
+    /* Should not happen: */
+    CHECK_MALLOC_TAINT(my_uid && (my_euid != my_uid || my_egid != my_gid));
+    TAINTING_set( TAINTING_get | (my_uid && (my_euid != my_uid || my_egid != my_gid)) );
+#endif
+    /* BUG */
+    /* PSz 27 Feb 04
+     * Should go by suidscript, not uid!=euid: why disallow
+     * system("ls") in scripts run from setuid things?
+     * Or, is this run before we check arguments and set suidscript?
+     * What about SETUID_SCRIPTS_ARE_SECURE_NOW: could we use fdscript then?
+     * (We never have suidscript, can we be sure to have fdscript?)
+     * Or must then go by UID checks? See comments in forbid_setid also.
+     */
+}
+
+/* This is used very early in the lifetime of the program,
+ * before even the options are parsed, so PL_tainting has
+ * not been initialized properly.  */
+bool
+Perl_doing_taint(int argc, char *argv[], char *envp[])
+{
+#ifndef PERL_IMPLICIT_SYS
+    /* If we have PERL_IMPLICIT_SYS we can't call getuid() et alia
+     * before we have an interpreter-- and the whole point of this
+     * function is to be called at such an early stage.  If you are on
+     * a system with PERL_IMPLICIT_SYS but you do have a concept of
+     * "tainted because running with altered effective ids', you'll
+     * have to add your own checks somewhere in here.  The two most
+     * known samples of 'implicitness' are Win32 and NetWare, neither
+     * of which has much of concept of 'uids'. */
+    Uid_t uid  = PerlProc_getuid();
+    Uid_t euid = PerlProc_geteuid();
+    Gid_t gid  = PerlProc_getgid();
+    Gid_t egid = PerlProc_getegid();
+    (void)envp;
+
+#ifdef VMS
+    uid  |=  gid << 16;
+    euid |= egid << 16;
+#endif
+    if (uid && (euid != uid || egid != gid))
+	return 1;
+#endif /* !PERL_IMPLICIT_SYS */
+    /* This is a really primitive check; environment gets ignored only
+     * if -T are the first chars together; otherwise one gets
+     *  "Too late" message. */
+    if ( argc > 1 && argv[1][0] == '-'
+         && isALPHA_FOLD_EQ(argv[1][1], 't'))
+	return 1;
+    return 0;
+}
+
+/* Passing the flag as a single char rather than a string is a slight space
+   optimisation.  The only message that isn't /^-.$/ is
+   "program input from stdin", which is substituted in place of '\0', which
+   could never be a command line flag.  */
+STATIC void
+S_forbid_setid(pTHX_ const char flag, const bool suidscript) /* g */
+{
+    char string[3] = "-x";
+    const char *message = "program input from stdin";
+
+    PERL_UNUSED_CONTEXT;
+    if (flag) {
+	string[1] = flag;
+	message = string;
+    }
+
+#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
+    if (PerlProc_getuid() != PerlProc_geteuid())
+        Perl_croak(aTHX_ "No %s allowed while running setuid", message);
+    if (PerlProc_getgid() != PerlProc_getegid())
+        Perl_croak(aTHX_ "No %s allowed while running setgid", message);
+#endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */
+    if (suidscript)
+        Perl_croak(aTHX_ "No %s allowed with (suid) fdscript", message);
+}
+
+void
+Perl_init_dbargs(pTHX)
+{
+    AV *const args = PL_dbargs = GvAV(gv_AVadd((gv_fetchpvs("DB::args",
+							    GV_ADDMULTI,
+							    SVt_PVAV))));
+
+    if (AvREAL(args)) {
+	/* Someone has already created it.
+	   It might have entries, and if we just turn off AvREAL(), they will
+	   "leak" until global destruction.  */
+	av_clear(args);
+	if (SvTIED_mg((const SV *)args, PERL_MAGIC_tied))
+	    Perl_croak(aTHX_ "Cannot set tied @DB::args");
+    }
+    AvREIFY_only(PL_dbargs);
+}
+
+void
+Perl_init_debugger(pTHX)
+{
+    HV * const ostash = PL_curstash;
+    MAGIC *mg;
+
+    PL_curstash = (HV *)SvREFCNT_inc_simple(PL_debstash);
+
+    Perl_init_dbargs(aTHX);
+    PL_DBgv = MUTABLE_GV(
+	SvREFCNT_inc(gv_fetchpvs("DB::DB", GV_ADDMULTI, SVt_PVGV))
+    );
+    PL_DBline = MUTABLE_GV(
+	SvREFCNT_inc(gv_fetchpvs("DB::dbline", GV_ADDMULTI, SVt_PVAV))
+    );
+    PL_DBsub = MUTABLE_GV(SvREFCNT_inc(
+	gv_HVadd(gv_fetchpvs("DB::sub", GV_ADDMULTI, SVt_PVHV))
+    ));
+    PL_DBsingle = GvSV((gv_fetchpvs("DB::single", GV_ADDMULTI, SVt_PV)));
+    if (!SvIOK(PL_DBsingle))
+	sv_setiv(PL_DBsingle, 0);
+    mg = sv_magicext(PL_DBsingle, NULL, PERL_MAGIC_debugvar, &PL_vtbl_debugvar, 0, 0);
+    mg->mg_private = DBVARMG_SINGLE;
+    SvSETMAGIC(PL_DBsingle);
+
+    PL_DBtrace = GvSV((gv_fetchpvs("DB::trace", GV_ADDMULTI, SVt_PV)));
+    if (!SvIOK(PL_DBtrace))
+	sv_setiv(PL_DBtrace, 0);
+    mg = sv_magicext(PL_DBtrace, NULL, PERL_MAGIC_debugvar, &PL_vtbl_debugvar, 0, 0);
+    mg->mg_private = DBVARMG_TRACE;
+    SvSETMAGIC(PL_DBtrace);
+
+    PL_DBsignal = GvSV((gv_fetchpvs("DB::signal", GV_ADDMULTI, SVt_PV)));
+    if (!SvIOK(PL_DBsignal))
+	sv_setiv(PL_DBsignal, 0);
+    mg = sv_magicext(PL_DBsignal, NULL, PERL_MAGIC_debugvar, &PL_vtbl_debugvar, 0, 0);
+    mg->mg_private = DBVARMG_SIGNAL;
+    SvSETMAGIC(PL_DBsignal);
+
+    SvREFCNT_dec(PL_curstash);
+    PL_curstash = ostash;
+}
+
+#ifndef STRESS_REALLOC
+#define REASONABLE(size) (size)
+#define REASONABLE_but_at_least(size,min) (size)
+#else
+#define REASONABLE(size) (1) /* unreasonable */
+#define REASONABLE_but_at_least(size,min) (min)
+#endif
+
+void
+Perl_init_stacks(pTHX)
+{
+    /* start with 128-item stack and 8K cxstack */
+    PL_curstackinfo = new_stackinfo(REASONABLE(128),
+				 REASONABLE(8192/sizeof(PERL_CONTEXT) - 1));
+    PL_curstackinfo->si_type = PERLSI_MAIN;
+    PL_curstack = PL_curstackinfo->si_stack;
+    PL_mainstack = PL_curstack;		/* remember in case we switch stacks */
+
+    PL_stack_base = AvARRAY(PL_curstack);
+    PL_stack_sp = PL_stack_base;
+    PL_stack_max = PL_stack_base + AvMAX(PL_curstack);
+
+    Newx(PL_tmps_stack,REASONABLE(128),SV*);
+    PL_tmps_floor = -1;
+    PL_tmps_ix = -1;
+    PL_tmps_max = REASONABLE(128);
+
+    Newx(PL_markstack,REASONABLE(32),I32);
+    PL_markstack_ptr = PL_markstack;
+    PL_markstack_max = PL_markstack + REASONABLE(32);
+
+    SET_MARK_OFFSET;
+
+    Newx(PL_scopestack,REASONABLE(32),I32);
+#ifdef DEBUGGING
+    Newx(PL_scopestack_name,REASONABLE(32),const char*);
+#endif
+    PL_scopestack_ix = 0;
+    PL_scopestack_max = REASONABLE(32);
+
+    Newx(PL_savestack,REASONABLE_but_at_least(128,SS_MAXPUSH),ANY);
+    PL_savestack_ix = 0;
+    PL_savestack_max = REASONABLE_but_at_least(128,SS_MAXPUSH);
+}
+
+#undef REASONABLE
+
+STATIC void
+S_nuke_stacks(pTHX)
+{
+    while (PL_curstackinfo->si_next)
+	PL_curstackinfo = PL_curstackinfo->si_next;
+    while (PL_curstackinfo) {
+	PERL_SI *p = PL_curstackinfo->si_prev;
+	/* curstackinfo->si_stack got nuked by sv_free_arenas() */
+	Safefree(PL_curstackinfo->si_cxstack);
+	Safefree(PL_curstackinfo);
+	PL_curstackinfo = p;
+    }
+    Safefree(PL_tmps_stack);
+    Safefree(PL_markstack);
+    Safefree(PL_scopestack);
+#ifdef DEBUGGING
+    Safefree(PL_scopestack_name);
+#endif
+    Safefree(PL_savestack);
+}
+
+void
+Perl_populate_isa(pTHX_ const char *name, STRLEN len, ...)
+{
+    GV *const gv = gv_fetchpvn(name, len, GV_ADD | GV_ADDMULTI, SVt_PVAV);
+    AV *const isa = GvAVn(gv);
+    va_list args;
+
+    PERL_ARGS_ASSERT_POPULATE_ISA;
+
+    if(AvFILLp(isa) != -1)
+	return;
+
+    /* NOTE: No support for tied ISA */
+
+    va_start(args, len);
+    do {
+	const char *const parent = va_arg(args, const char*);
+	size_t parent_len;
+
+	if (!parent)
+	    break;
+	parent_len = va_arg(args, size_t);
+
+	/* Arguments are supplied with a trailing ::  */
+	assert(parent_len > 2);
+	assert(parent[parent_len - 1] == ':');
+	assert(parent[parent_len - 2] == ':');
+	av_push(isa, newSVpvn(parent, parent_len - 2));
+	(void) gv_fetchpvn(parent, parent_len, GV_ADD, SVt_PVGV);
+    } while (1);
+    va_end(args);
+}
+
+
+STATIC void
+S_init_predump_symbols(pTHX)
+{
+    GV *tmpgv;
+    IO *io;
+
+    sv_setpvs(get_sv("\"", GV_ADD), " ");
+    PL_ofsgv = (GV*)SvREFCNT_inc(gv_fetchpvs(",", GV_ADD|GV_NOTQUAL, SVt_PV));
+
+
+    /* Historically, PVIOs were blessed into IO::Handle, unless
+       FileHandle was loaded, in which case they were blessed into
+       that. Action at a distance.
+       However, if we simply bless into IO::Handle, we break code
+       that assumes that PVIOs will have (among others) a seek
+       method. IO::File inherits from IO::Handle and IO::Seekable,
+       and provides the needed methods. But if we simply bless into
+       it, then we break code that assumed that by loading
+       IO::Handle, *it* would work.
+       So a compromise is to set up the correct @IO::File::ISA,
+       so that code that does C<use IO::Handle>; will still work.
+    */
+		   
+    Perl_populate_isa(aTHX_ STR_WITH_LEN("IO::File::ISA"),
+		      STR_WITH_LEN("IO::Handle::"),
+		      STR_WITH_LEN("IO::Seekable::"),
+		      STR_WITH_LEN("Exporter::"),
+		      NULL);
+
+    PL_stdingv = gv_fetchpvs("STDIN", GV_ADD|GV_NOTQUAL, SVt_PVIO);
+    GvMULTI_on(PL_stdingv);
+    io = GvIOp(PL_stdingv);
+    IoTYPE(io) = IoTYPE_RDONLY;
+    IoIFP(io) = PerlIO_stdin();
+    tmpgv = gv_fetchpvs("stdin", GV_ADD|GV_NOTQUAL, SVt_PV);
+    GvMULTI_on(tmpgv);
+    GvIOp(tmpgv) = MUTABLE_IO(SvREFCNT_inc_simple(io));
+
+    tmpgv = gv_fetchpvs("STDOUT", GV_ADD|GV_NOTQUAL, SVt_PVIO);
+    GvMULTI_on(tmpgv);
+    io = GvIOp(tmpgv);
+    IoTYPE(io) = IoTYPE_WRONLY;
+    IoOFP(io) = IoIFP(io) = PerlIO_stdout();
+    setdefout(tmpgv);
+    tmpgv = gv_fetchpvs("stdout", GV_ADD|GV_NOTQUAL, SVt_PV);
+    GvMULTI_on(tmpgv);
+    GvIOp(tmpgv) = MUTABLE_IO(SvREFCNT_inc_simple(io));
+
+    PL_stderrgv = gv_fetchpvs("STDERR", GV_ADD|GV_NOTQUAL, SVt_PVIO);
+    GvMULTI_on(PL_stderrgv);
+    io = GvIOp(PL_stderrgv);
+    IoTYPE(io) = IoTYPE_WRONLY;
+    IoOFP(io) = IoIFP(io) = PerlIO_stderr();
+    tmpgv = gv_fetchpvs("stderr", GV_ADD|GV_NOTQUAL, SVt_PV);
+    GvMULTI_on(tmpgv);
+    GvIOp(tmpgv) = MUTABLE_IO(SvREFCNT_inc_simple(io));
+
+    PL_statname = newSVpvs("");		/* last filename we did stat on */
+}
+
+void
+Perl_init_argv_symbols(pTHX_ int argc, char **argv)
+{
+    PERL_ARGS_ASSERT_INIT_ARGV_SYMBOLS;
+
+    argc--,argv++;	/* skip name of script */
+    if (PL_doswitches) {
+	for (; argc > 0 && **argv == '-'; argc--,argv++) {
+	    char *s;
+	    if (!argv[0][1])
+		break;
+	    if (argv[0][1] == '-' && !argv[0][2]) {
+		argc--,argv++;
+		break;
+	    }
+	    if ((s = strchr(argv[0], '='))) {
+		const char *const start_name = argv[0] + 1;
+		sv_setpv(GvSV(gv_fetchpvn_flags(start_name, s - start_name,
+						TRUE, SVt_PV)), s + 1);
+	    }
+	    else
+		sv_setiv(GvSV(gv_fetchpv(argv[0]+1, GV_ADD, SVt_PV)),1);
+	}
+    }
+    if ((PL_argvgv = gv_fetchpvs("ARGV", GV_ADD|GV_NOTQUAL, SVt_PVAV))) {
+	SvREFCNT_inc_simple_void_NN(PL_argvgv);
+	GvMULTI_on(PL_argvgv);
+	av_clear(GvAVn(PL_argvgv));
+	for (; argc > 0; argc--,argv++) {
+	    SV * const sv = newSVpv(argv[0],0);
+	    av_push(GvAV(PL_argvgv),sv);
+	    if (!(PL_unicode & PERL_UNICODE_LOCALE_FLAG) || PL_utf8locale) {
+		 if (PL_unicode & PERL_UNICODE_ARGV_FLAG)
+		      SvUTF8_on(sv);
+	    }
+	    if (PL_unicode & PERL_UNICODE_WIDESYSCALLS_FLAG) /* Sarathy? */
+		 (void)sv_utf8_decode(sv);
+	}
+    }
+
+    if (PL_inplace && (!PL_argvgv || AvFILL(GvAV(PL_argvgv)) == -1))
+        Perl_ck_warner_d(aTHX_ packWARN(WARN_INPLACE),
+                         "-i used with no filenames on the command line, "
+                         "reading from STDIN");
+}
+
+STATIC void
+S_init_postdump_symbols(pTHX_ int argc, char **argv, char **env)
+{
+#ifdef USE_ITHREADS
+    dVAR;
+#endif
+    GV* tmpgv;
+
+    PERL_ARGS_ASSERT_INIT_POSTDUMP_SYMBOLS;
+
+    PL_toptarget = newSV_type(SVt_PVIV);
+    sv_setpvs(PL_toptarget, "");
+    PL_bodytarget = newSV_type(SVt_PVIV);
+    sv_setpvs(PL_bodytarget, "");
+    PL_formtarget = PL_bodytarget;
+
+    TAINT;
+
+    init_argv_symbols(argc,argv);
+
+    if ((tmpgv = gv_fetchpvs("0", GV_ADD|GV_NOTQUAL, SVt_PV))) {
+	sv_setpv(GvSV(tmpgv),PL_origfilename);
+    }
+    if ((PL_envgv = gv_fetchpvs("ENV", GV_ADD|GV_NOTQUAL, SVt_PVHV))) {
+	HV *hv;
+	bool env_is_not_environ;
+	SvREFCNT_inc_simple_void_NN(PL_envgv);
+	GvMULTI_on(PL_envgv);
+	hv = GvHVn(PL_envgv);
+	hv_magic(hv, NULL, PERL_MAGIC_env);
+#ifndef PERL_MICRO
+#ifdef USE_ENVIRON_ARRAY
+	/* Note that if the supplied env parameter is actually a copy
+	   of the global environ then it may now point to free'd memory
+	   if the environment has been modified since. To avoid this
+	   problem we treat env==NULL as meaning 'use the default'
+	*/
+	if (!env)
+	    env = environ;
+	env_is_not_environ = env != environ;
+	if (env_is_not_environ
+#  ifdef USE_ITHREADS
+	    && PL_curinterp == aTHX
+#  endif
+	   )
+	{
+	    environ[0] = NULL;
+	}
+	if (env) {
+	  char *s, *old_var;
+          STRLEN nlen;
+	  SV *sv;
+          HV *dups = newHV();
+
+	  for (; *env; env++) {
+	    old_var = *env;
+
+	    if (!(s = strchr(old_var,'=')) || s == old_var)
+		continue;
+            nlen = s - old_var;
+
+#if defined(MSDOS) && !defined(DJGPP)
+	    *s = '\0';
+	    (void)strupr(old_var);
+	    *s = '=';
+#endif
+            if (hv_exists(hv, old_var, nlen)) {
+                const char *name = savepvn(old_var, nlen);
+
+                /* make sure we use the same value as getenv(), otherwise code that
+                   uses getenv() (like setlocale()) might see a different value to %ENV
+                 */
+                sv = newSVpv(PerlEnv_getenv(name), 0);
+
+                /* keep a count of the dups of this name so we can de-dup environ later */
+                if (hv_exists(dups, name, nlen))
+                    ++SvIVX(*hv_fetch(dups, name, nlen, 0));
+                else
+                    (void)hv_store(dups, name, nlen, newSViv(1), 0);
+
+                Safefree(name);
+            }
+            else {
+                sv = newSVpv(s+1, 0);
+            }
+	    (void)hv_store(hv, old_var, nlen, sv, 0);
+	    if (env_is_not_environ)
+	        mg_set(sv);
+	  }
+          if (HvKEYS(dups)) {
+              /* environ has some duplicate definitions, remove them */
+              HE *entry;
+              hv_iterinit(dups);
+              while ((entry = hv_iternext_flags(dups, 0))) {
+                  STRLEN nlen;
+                  const char *name = HePV(entry, nlen);
+                  IV count = SvIV(HeVAL(entry));
+                  IV i;
+                  SV **valp = hv_fetch(hv, name, nlen, 0);
+
+                  assert(valp);
+
+                  /* try to remove any duplicate names, depending on the
+                   * implementation used in my_setenv() the iteration might
+                   * not be necessary, but let's be safe.
+                   */
+                  for (i = 0; i < count; ++i)
+                      my_setenv(name, 0);
+
+                  /* and set it back to the value we set $ENV{name} to */
+                  my_setenv(name, SvPV_nolen(*valp));
+              }
+          }
+          SvREFCNT_dec_NN(dups);
+      }
+#endif /* USE_ENVIRON_ARRAY */
+#endif /* !PERL_MICRO */
+    }
+    TAINT_NOT;
+
+    /* touch @F array to prevent spurious warnings 20020415 MJD */
+    if (PL_minus_a) {
+      (void) get_av("main::F", GV_ADD | GV_ADDMULTI);
+    }
+}
+
+STATIC void
+S_init_perllib(pTHX)
+{
+#ifndef VMS
+    const char *perl5lib = NULL;
+#endif
+    const char *s;
+#if defined(WIN32) && !defined(PERL_IS_MINIPERL)
+    STRLEN len;
+#endif
+
+    if (!TAINTING_get) {
+#ifndef VMS
+	perl5lib = PerlEnv_getenv("PERL5LIB");
+/*
+ * It isn't possible to delete an environment variable with
+ * PERL_USE_SAFE_PUTENV set unless unsetenv() is also available, so in that
+ * case we treat PERL5LIB as undefined if it has a zero-length value.
+ */
+#if defined(PERL_USE_SAFE_PUTENV) && ! defined(HAS_UNSETENV)
+	if (perl5lib && *perl5lib != '\0')
+#else
+	if (perl5lib)
+#endif
+	    incpush_use_sep(perl5lib, 0, INCPUSH_ADD_SUB_DIRS);
+	else {
+	    s = PerlEnv_getenv("PERLLIB");
+	    if (s)
+		incpush_use_sep(s, 0, 0);
+	}
+#else /* VMS */
+	/* Treat PERL5?LIB as a possible search list logical name -- the
+	 * "natural" VMS idiom for a Unix path string.  We allow each
+	 * element to be a set of |-separated directories for compatibility.
+	 */
+	char buf[256];
+	int idx = 0;
+	if (my_trnlnm("PERL5LIB",buf,0))
+	    do {
+		incpush_use_sep(buf, 0, INCPUSH_ADD_SUB_DIRS);
+	    } while (my_trnlnm("PERL5LIB",buf,++idx));
+	else {
+	    while (my_trnlnm("PERLLIB",buf,idx++))
+		incpush_use_sep(buf, 0, 0);
+	}
+#endif /* VMS */
+    }
+
+#ifndef PERL_IS_MINIPERL
+    /* miniperl gets just -I..., the split of $ENV{PERL5LIB}, and "." in @INC
+       (and not the architecture specific directories from $ENV{PERL5LIB}) */
+
+/* Use the ~-expanded versions of APPLLIB (undocumented),
+    SITEARCH, SITELIB, VENDORARCH, VENDORLIB, ARCHLIB and PRIVLIB
+*/
+#ifdef APPLLIB_EXP
+    S_incpush_use_sep(aTHX_ STR_WITH_LEN(APPLLIB_EXP),
+		      INCPUSH_ADD_SUB_DIRS|INCPUSH_CAN_RELOCATE);
+#endif
+
+#ifdef SITEARCH_EXP
+    /* sitearch is always relative to sitelib on Windows for
+     * DLL-based path intuition to work correctly */
+#  if !defined(WIN32)
+	S_incpush_use_sep(aTHX_ STR_WITH_LEN(SITEARCH_EXP),
+			  INCPUSH_CAN_RELOCATE);
+#  endif
+#endif
+
+#ifdef SITELIB_EXP
+#  if defined(WIN32)
+    /* this picks up sitearch as well */
+	s = win32_get_sitelib(PERL_FS_VERSION, &len);
+	if (s)
+	    incpush_use_sep(s, len, INCPUSH_ADD_SUB_DIRS|INCPUSH_CAN_RELOCATE);
+#  else
+	S_incpush_use_sep(aTHX_ STR_WITH_LEN(SITELIB_EXP), INCPUSH_CAN_RELOCATE);
+#  endif
+#endif
+
+#ifdef PERL_VENDORARCH_EXP
+    /* vendorarch is always relative to vendorlib on Windows for
+     * DLL-based path intuition to work correctly */
+#  if !defined(WIN32)
+    S_incpush_use_sep(aTHX_ STR_WITH_LEN(PERL_VENDORARCH_EXP),
+		      INCPUSH_CAN_RELOCATE);
+#  endif
+#endif
+
+#ifdef PERL_VENDORLIB_EXP
+#  if defined(WIN32)
+    /* this picks up vendorarch as well */
+	s = win32_get_vendorlib(PERL_FS_VERSION, &len);
+	if (s)
+	    incpush_use_sep(s, len, INCPUSH_ADD_SUB_DIRS|INCPUSH_CAN_RELOCATE);
+#  else
+	S_incpush_use_sep(aTHX_ STR_WITH_LEN(PERL_VENDORLIB_EXP),
+			  INCPUSH_CAN_RELOCATE);
+#  endif
+#endif
+
+#ifdef ARCHLIB_EXP
+    S_incpush_use_sep(aTHX_ STR_WITH_LEN(ARCHLIB_EXP), INCPUSH_CAN_RELOCATE);
+#endif
+
+#ifndef PRIVLIB_EXP
+#  define PRIVLIB_EXP "/usr/local/lib/perl5:/usr/local/lib/perl"
+#endif
+
+#if defined(WIN32)
+    s = win32_get_privlib(PERL_FS_VERSION, &len);
+    if (s)
+	incpush_use_sep(s, len, INCPUSH_ADD_SUB_DIRS|INCPUSH_CAN_RELOCATE);
+#else
+#  ifdef NETWARE
+    S_incpush_use_sep(aTHX_ PRIVLIB_EXP, 0, INCPUSH_CAN_RELOCATE);
+#  else
+    S_incpush_use_sep(aTHX_ STR_WITH_LEN(PRIVLIB_EXP), INCPUSH_CAN_RELOCATE);
+#  endif
+#endif
+
+#ifdef PERL_OTHERLIBDIRS
+    S_incpush_use_sep(aTHX_ STR_WITH_LEN(PERL_OTHERLIBDIRS),
+		      INCPUSH_ADD_VERSIONED_SUB_DIRS|INCPUSH_NOT_BASEDIR
+		      |INCPUSH_CAN_RELOCATE);
+#endif
+
+    if (!TAINTING_get) {
+#ifndef VMS
+/*
+ * It isn't possible to delete an environment variable with
+ * PERL_USE_SAFE_PUTENV set unless unsetenv() is also available, so in that
+ * case we treat PERL5LIB as undefined if it has a zero-length value.
+ */
+#if defined(PERL_USE_SAFE_PUTENV) && ! defined(HAS_UNSETENV)
+	if (perl5lib && *perl5lib != '\0')
+#else
+	if (perl5lib)
+#endif
+	    incpush_use_sep(perl5lib, 0,
+			    INCPUSH_ADD_OLD_VERS|INCPUSH_NOT_BASEDIR);
+#else /* VMS */
+	/* Treat PERL5?LIB as a possible search list logical name -- the
+	 * "natural" VMS idiom for a Unix path string.  We allow each
+	 * element to be a set of |-separated directories for compatibility.
+	 */
+	char buf[256];
+	int idx = 0;
+	if (my_trnlnm("PERL5LIB",buf,0))
+	    do {
+		incpush_use_sep(buf, 0,
+				INCPUSH_ADD_OLD_VERS|INCPUSH_NOT_BASEDIR);
+	    } while (my_trnlnm("PERL5LIB",buf,++idx));
+#endif /* VMS */
+    }
+
+/* Use the ~-expanded versions of APPLLIB (undocumented),
+    SITELIB and VENDORLIB for older versions
+*/
+#ifdef APPLLIB_EXP
+    S_incpush_use_sep(aTHX_ STR_WITH_LEN(APPLLIB_EXP), INCPUSH_ADD_OLD_VERS
+		      |INCPUSH_NOT_BASEDIR|INCPUSH_CAN_RELOCATE);
+#endif
+
+#if defined(SITELIB_STEM) && defined(PERL_INC_VERSION_LIST)
+    /* Search for version-specific dirs below here */
+    S_incpush_use_sep(aTHX_ STR_WITH_LEN(SITELIB_STEM),
+		      INCPUSH_ADD_OLD_VERS|INCPUSH_CAN_RELOCATE);
+#endif
+
+
+#if defined(PERL_VENDORLIB_STEM) && defined(PERL_INC_VERSION_LIST)
+    /* Search for version-specific dirs below here */
+    S_incpush_use_sep(aTHX_ STR_WITH_LEN(PERL_VENDORLIB_STEM),
+		      INCPUSH_ADD_OLD_VERS|INCPUSH_CAN_RELOCATE);
+#endif
+
+#ifdef PERL_OTHERLIBDIRS
+    S_incpush_use_sep(aTHX_ STR_WITH_LEN(PERL_OTHERLIBDIRS),
+		      INCPUSH_ADD_OLD_VERS|INCPUSH_ADD_ARCHONLY_SUB_DIRS
+		      |INCPUSH_CAN_RELOCATE);
+#endif
+#endif /* !PERL_IS_MINIPERL */
+
+    if (!TAINTING_get)
+	S_incpush(aTHX_ STR_WITH_LEN("."), 0);
+}
+
+#if defined(DOSISH) || defined(__SYMBIAN32__)
+#    define PERLLIB_SEP ';'
+#else
+#  if defined(VMS)
+#    define PERLLIB_SEP '|'
+#  else
+#    define PERLLIB_SEP ':'
+#  endif
+#endif
+#ifndef PERLLIB_MANGLE
+#  define PERLLIB_MANGLE(s,n) (s)
+#endif
+
+#ifndef PERL_IS_MINIPERL
+/* Push a directory onto @INC if it exists.
+   Generate a new SV if we do this, to save needing to copy the SV we push
+   onto @INC  */
+STATIC SV *
+S_incpush_if_exists(pTHX_ AV *const av, SV *dir, SV *const stem)
+{
+    Stat_t tmpstatbuf;
+
+    PERL_ARGS_ASSERT_INCPUSH_IF_EXISTS;
+
+    if (PerlLIO_stat(SvPVX_const(dir), &tmpstatbuf) >= 0 &&
+	S_ISDIR(tmpstatbuf.st_mode)) {
+	av_push(av, dir);
+	dir = newSVsv(stem);
+    } else {
+	/* Truncate dir back to stem.  */
+	SvCUR_set(dir, SvCUR(stem));
+    }
+    return dir;
+}
+#endif
+
+STATIC SV *
+S_mayberelocate(pTHX_ const char *const dir, STRLEN len, U32 flags)
+{
+    const U8 canrelocate = (U8)flags & INCPUSH_CAN_RELOCATE;
+    SV *libdir;
+
+    PERL_ARGS_ASSERT_MAYBERELOCATE;
+    assert(len > 0);
+
+    /* I am not convinced that this is valid when PERLLIB_MANGLE is
+       defined to so something (in os2/os2.c), but the code has been
+       this way, ignoring any possible changed of length, since
+       760ac839baf413929cd31cc32ffd6dba6b781a81 (5.003_02) so I'll leave
+       it be.  */
+    libdir = newSVpvn(PERLLIB_MANGLE(dir, len), len);
+
+#ifdef VMS
+    {
+	char *unix;
+
+	if ((unix = tounixspec_ts(SvPV(libdir,len),NULL)) != NULL) {
+	    len = strlen(unix);
+	    while (len > 1 && unix[len-1] == '/') len--;  /* Cosmetic */
+	    sv_usepvn(libdir,unix,len);
+	}
+	else
+	    PerlIO_printf(Perl_error_log,
+		          "Failed to unixify @INC element \"%s\"\n",
+			  SvPV_nolen_const(libdir));
+    }
+#endif
+
+	/* Do the if() outside the #ifdef to avoid warnings about an unused
+	   parameter.  */
+	if (canrelocate) {
+#ifdef PERL_RELOCATABLE_INC
+	/*
+	 * Relocatable include entries are marked with a leading .../
+	 *
+	 * The algorithm is
+	 * 0: Remove that leading ".../"
+	 * 1: Remove trailing executable name (anything after the last '/')
+	 *    from the perl path to give a perl prefix
+	 * Then
+	 * While the @INC element starts "../" and the prefix ends with a real
+	 * directory (ie not . or ..) chop that real directory off the prefix
+	 * and the leading "../" from the @INC element. ie a logical "../"
+	 * cleanup
+	 * Finally concatenate the prefix and the remainder of the @INC element
+	 * The intent is that /usr/local/bin/perl and .../../lib/perl5
+	 * generates /usr/local/lib/perl5
+	 */
+	    const char *libpath = SvPVX(libdir);
+	    STRLEN libpath_len = SvCUR(libdir);
+	    if (libpath_len >= 4 && memEQ (libpath, ".../", 4)) {
+		/* Game on!  */
+		SV * const caret_X = get_sv("\030", 0);
+		/* Going to use the SV just as a scratch buffer holding a C
+		   string:  */
+		SV *prefix_sv;
+		char *prefix;
+		char *lastslash;
+
+		/* $^X is *the* source of taint if tainting is on, hence
+		   SvPOK() won't be true.  */
+		assert(caret_X);
+		assert(SvPOKp(caret_X));
+		prefix_sv = newSVpvn_flags(SvPVX(caret_X), SvCUR(caret_X),
+					   SvUTF8(caret_X));
+		/* Firstly take off the leading .../
+		   If all else fail we'll do the paths relative to the current
+		   directory.  */
+		sv_chop(libdir, libpath + 4);
+		/* Don't use SvPV as we're intentionally bypassing taining,
+		   mortal copies that the mg_get of tainting creates, and
+		   corruption that seems to come via the save stack.
+		   I guess that the save stack isn't correctly set up yet.  */
+		libpath = SvPVX(libdir);
+		libpath_len = SvCUR(libdir);
+
+		/* This would work more efficiently with memrchr, but as it's
+		   only a GNU extension we'd need to probe for it and
+		   implement our own. Not hard, but maybe not worth it?  */
+
+		prefix = SvPVX(prefix_sv);
+		lastslash = strrchr(prefix, '/');
+
+		/* First time in with the *lastslash = '\0' we just wipe off
+		   the trailing /perl from (say) /usr/foo/bin/perl
+		*/
+		if (lastslash) {
+		    SV *tempsv;
+		    while ((*lastslash = '\0'), /* Do that, come what may.  */
+			   (libpath_len >= 3 && memEQ(libpath, "../", 3)
+			    && (lastslash = strrchr(prefix, '/')))) {
+			if (lastslash[1] == '\0'
+			    || (lastslash[1] == '.'
+				&& (lastslash[2] == '/' /* ends "/."  */
+				    || (lastslash[2] == '/'
+					&& lastslash[3] == '/' /* or "/.."  */
+					)))) {
+			    /* Prefix ends "/" or "/." or "/..", any of which
+			       are fishy, so don't do any more logical cleanup.
+			    */
+			    break;
+			}
+			/* Remove leading "../" from path  */
+			libpath += 3;
+			libpath_len -= 3;
+			/* Next iteration round the loop removes the last
+			   directory name from prefix by writing a '\0' in
+			   the while clause.  */
+		    }
+		    /* prefix has been terminated with a '\0' to the correct
+		       length. libpath points somewhere into the libdir SV.
+		       We need to join the 2 with '/' and drop the result into
+		       libdir.  */
+		    tempsv = Perl_newSVpvf(aTHX_ "%s/%s", prefix, libpath);
+		    SvREFCNT_dec(libdir);
+		    /* And this is the new libdir.  */
+		    libdir = tempsv;
+		    if (TAINTING_get &&
+			(PerlProc_getuid() != PerlProc_geteuid() ||
+			 PerlProc_getgid() != PerlProc_getegid())) {
+			/* Need to taint relocated paths if running set ID  */
+			SvTAINTED_on(libdir);
+		    }
+		}
+		SvREFCNT_dec(prefix_sv);
+	    }
+#endif
+	}
+    return libdir;
+}
+
+STATIC void
+S_incpush(pTHX_ const char *const dir, STRLEN len, U32 flags)
+{
+#ifndef PERL_IS_MINIPERL
+    const U8 using_sub_dirs
+	= (U8)flags & (INCPUSH_ADD_VERSIONED_SUB_DIRS
+		       |INCPUSH_ADD_ARCHONLY_SUB_DIRS|INCPUSH_ADD_OLD_VERS);
+    const U8 add_versioned_sub_dirs
+	= (U8)flags & INCPUSH_ADD_VERSIONED_SUB_DIRS;
+    const U8 add_archonly_sub_dirs
+	= (U8)flags & INCPUSH_ADD_ARCHONLY_SUB_DIRS;
+#ifdef PERL_INC_VERSION_LIST
+    const U8 addoldvers  = (U8)flags & INCPUSH_ADD_OLD_VERS;
+#endif
+#endif
+    const U8 unshift     = (U8)flags & INCPUSH_UNSHIFT;
+    const U8 push_basedir = (flags & INCPUSH_NOT_BASEDIR) ? 0 : 1;
+    AV *const inc = GvAVn(PL_incgv);
+
+    PERL_ARGS_ASSERT_INCPUSH;
+    assert(len > 0);
+
+    /* Could remove this vestigial extra block, if we don't mind a lot of
+       re-indenting diff noise.  */
+    {
+	SV *const libdir = mayberelocate(dir, len, flags);
+	/* Change 20189146be79a0596543441fa369c6bf7f85103f, to fix RT#6665,
+	   arranged to unshift #! line -I onto the front of @INC. However,
+	   -I can add version and architecture specific libraries, and they
+	   need to go first. The old code assumed that it was always
+	   pushing. Hence to make it work, need to push the architecture
+	   (etc) libraries onto a temporary array, then "unshift" that onto
+	   the front of @INC.  */
+#ifndef PERL_IS_MINIPERL
+	AV *const av = (using_sub_dirs) ? (unshift ? newAV() : inc) : NULL;
+
+	/*
+	 * BEFORE pushing libdir onto @INC we may first push version- and
+	 * archname-specific sub-directories.
+	 */
+	if (using_sub_dirs) {
+	    SV *subdir = newSVsv(libdir);
+#ifdef PERL_INC_VERSION_LIST
+	    /* Configure terminates PERL_INC_VERSION_LIST with a NULL */
+	    const char * const incverlist[] = { PERL_INC_VERSION_LIST };
+	    const char * const *incver;
+#endif
+
+	    if (add_versioned_sub_dirs) {
+		/* .../version/archname if -d .../version/archname */
+		sv_catpvs(subdir, "/" PERL_FS_VERSION "/" ARCHNAME);
+		subdir = S_incpush_if_exists(aTHX_ av, subdir, libdir);
+
+		/* .../version if -d .../version */
+		sv_catpvs(subdir, "/" PERL_FS_VERSION);
+		subdir = S_incpush_if_exists(aTHX_ av, subdir, libdir);
+	    }
+
+#ifdef PERL_INC_VERSION_LIST
+	    if (addoldvers) {
+		for (incver = incverlist; *incver; incver++) {
+		    /* .../xxx if -d .../xxx */
+		    Perl_sv_catpvf(aTHX_ subdir, "/%s", *incver);
+		    subdir = S_incpush_if_exists(aTHX_ av, subdir, libdir);
+		}
+	    }
+#endif
+
+	    if (add_archonly_sub_dirs) {
+		/* .../archname if -d .../archname */
+		sv_catpvs(subdir, "/" ARCHNAME);
+		subdir = S_incpush_if_exists(aTHX_ av, subdir, libdir);
+
+	    }
+
+	    assert (SvREFCNT(subdir) == 1);
+	    SvREFCNT_dec(subdir);
+	}
+#endif /* !PERL_IS_MINIPERL */
+	/* finally add this lib directory at the end of @INC */
+	if (unshift) {
+#ifdef PERL_IS_MINIPERL
+	    const Size_t extra = 0;
+#else
+	    Size_t extra = av_tindex(av) + 1;
+#endif
+	    av_unshift(inc, extra + push_basedir);
+	    if (push_basedir)
+		av_store(inc, extra, libdir);
+#ifndef PERL_IS_MINIPERL
+	    while (extra--) {
+		/* av owns a reference, av_store() expects to be donated a
+		   reference, and av expects to be sane when it's cleared.
+		   If I wanted to be naughty and wrong, I could peek inside the
+		   implementation of av_clear(), realise that it uses
+		   SvREFCNT_dec() too, so av's array could be a run of NULLs,
+		   and so directly steal from it (with a memcpy() to inc, and
+		   then memset() to NULL them out. But people copy code from the
+		   core expecting it to be best practise, so let's use the API.
+		   Although studious readers will note that I'm not checking any
+		   return codes.  */
+		av_store(inc, extra, SvREFCNT_inc(*av_fetch(av, extra, FALSE)));
+	    }
+	    SvREFCNT_dec(av);
+#endif
+	}
+	else if (push_basedir) {
+	    av_push(inc, libdir);
+	}
+
+	if (!push_basedir) {
+	    assert (SvREFCNT(libdir) == 1);
+	    SvREFCNT_dec(libdir);
+	}
+    }
+}
+
+STATIC void
+S_incpush_use_sep(pTHX_ const char *p, STRLEN len, U32 flags)
+{
+    const char *s;
+    const char *end;
+    /* This logic has been broken out from S_incpush(). It may be possible to
+       simplify it.  */
+
+    PERL_ARGS_ASSERT_INCPUSH_USE_SEP;
+
+    /* perl compiled with -DPERL_RELOCATABLE_INCPUSH will ignore the len
+     * argument to incpush_use_sep.  This allows creation of relocatable
+     * Perl distributions that patch the binary at install time.  Those
+     * distributions will have to provide their own relocation tools; this
+     * is not a feature otherwise supported by core Perl.
+     */
+#ifndef PERL_RELOCATABLE_INCPUSH
+    if (!len)
+#endif
+	len = strlen(p);
+
+    end = p + len;
+
+    /* Break at all separators */
+    while ((s = (const char*)memchr(p, PERLLIB_SEP, end - p))) {
+	if (s == p) {
+	    /* skip any consecutive separators */
+
+	    /* Uncomment the next line for PATH semantics */
+	    /* But you'll need to write tests */
+	    /* av_push(GvAVn(PL_incgv), newSVpvs(".")); */
+	} else {
+	    incpush(p, (STRLEN)(s - p), flags);
+	}
+	p = s + 1;
+    }
+    if (p != end)
+	incpush(p, (STRLEN)(end - p), flags);
+
+}
+
+void
+Perl_call_list(pTHX_ I32 oldscope, AV *paramList)
+{
+    SV *atsv;
+    volatile const line_t oldline = PL_curcop ? CopLINE(PL_curcop) : 0;
+    CV *cv;
+    STRLEN len;
+    int ret;
+    dJMPENV;
+
+    PERL_ARGS_ASSERT_CALL_LIST;
+
+    while (av_tindex(paramList) >= 0) {
+	cv = MUTABLE_CV(av_shift(paramList));
+	if (PL_savebegin) {
+	    if (paramList == PL_beginav) {
+		/* save PL_beginav for compiler */
+		Perl_av_create_and_push(aTHX_ &PL_beginav_save, MUTABLE_SV(cv));
+	    }
+	    else if (paramList == PL_checkav) {
+		/* save PL_checkav for compiler */
+		Perl_av_create_and_push(aTHX_ &PL_checkav_save, MUTABLE_SV(cv));
+	    }
+	    else if (paramList == PL_unitcheckav) {
+		/* save PL_unitcheckav for compiler */
+		Perl_av_create_and_push(aTHX_ &PL_unitcheckav_save, MUTABLE_SV(cv));
+	    }
+	} else {
+            SAVEFREESV(cv);
+	}
+	JMPENV_PUSH(ret);
+	switch (ret) {
+	case 0:
+	    CALL_LIST_BODY(cv);
+	    atsv = ERRSV;
+	    (void)SvPV_const(atsv, len);
+	    if (len) {
+		PL_curcop = &PL_compiling;
+		CopLINE_set(PL_curcop, oldline);
+		if (paramList == PL_beginav)
+		    sv_catpvs(atsv, "BEGIN failed--compilation aborted");
+		else
+		    Perl_sv_catpvf(aTHX_ atsv,
+				   "%s failed--call queue aborted",
+				   paramList == PL_checkav ? "CHECK"
+				   : paramList == PL_initav ? "INIT"
+				   : paramList == PL_unitcheckav ? "UNITCHECK"
+				   : "END");
+		while (PL_scopestack_ix > oldscope)
+		    LEAVE;
+		JMPENV_POP;
+		Perl_croak(aTHX_ "%"SVf"", SVfARG(atsv));
+	    }
+	    break;
+	case 1:
+	    STATUS_ALL_FAILURE;
+	    /* FALLTHROUGH */
+	case 2:
+	    /* my_exit() was called */
+	    while (PL_scopestack_ix > oldscope)
+		LEAVE;
+	    FREETMPS;
+	    SET_CURSTASH(PL_defstash);
+	    PL_curcop = &PL_compiling;
+	    CopLINE_set(PL_curcop, oldline);
+	    JMPENV_POP;
+	    my_exit_jump();
+	    NOT_REACHED; /* NOTREACHED */
+	case 3:
+	    if (PL_restartop) {
+		PL_curcop = &PL_compiling;
+		CopLINE_set(PL_curcop, oldline);
+		JMPENV_JUMP(3);
+	    }
+	    PerlIO_printf(Perl_error_log, "panic: restartop in call_list\n");
+	    FREETMPS;
+	    break;
+	}
+	JMPENV_POP;
+    }
+}
+
+void
+Perl_my_exit(pTHX_ U32 status)
+{
+    if (PL_exit_flags & PERL_EXIT_ABORT) {
+	abort();
+    }
+    if (PL_exit_flags & PERL_EXIT_WARN) {
+	PL_exit_flags |= PERL_EXIT_ABORT; /* Protect against reentrant calls */
+	Perl_warn(aTHX_ "Unexpected exit %lu", (unsigned long)status);
+	PL_exit_flags &= ~PERL_EXIT_ABORT;
+    }
+    switch (status) {
+    case 0:
+	STATUS_ALL_SUCCESS;
+	break;
+    case 1:
+	STATUS_ALL_FAILURE;
+	break;
+    default:
+	STATUS_EXIT_SET(status);
+	break;
+    }
+    my_exit_jump();
+}
+
+void
+Perl_my_failure_exit(pTHX)
+{
+#ifdef VMS
+     /* We have been called to fall on our sword.  The desired exit code
+      * should be already set in STATUS_UNIX, but could be shifted over
+      * by 8 bits.  STATUS_UNIX_EXIT_SET will handle the cases where a
+      * that code is set.
+      *
+      * If an error code has not been set, then force the issue.
+      */
+    if (MY_POSIX_EXIT) {
+
+        /* According to the die_exit.t tests, if errno is non-zero */
+        /* It should be used for the error status. */
+
+	if (errno == EVMSERR) {
+	    STATUS_NATIVE = vaxc$errno;
+	} else {
+
+            /* According to die_exit.t tests, if the child_exit code is */
+            /* also zero, then we need to exit with a code of 255 */
+            if ((errno != 0) && (errno < 256))
+		STATUS_UNIX_EXIT_SET(errno);
+            else if (STATUS_UNIX < 255) {
+		STATUS_UNIX_EXIT_SET(255);
+            }
+
+	}
+
+	/* The exit code could have been set by $? or vmsish which
+	 * means that it may not have fatal set.  So convert
+	 * success/warning codes to fatal with out changing
+	 * the POSIX status code.  The severity makes VMS native
+	 * status handling work, while UNIX mode programs use the
+	 * the POSIX exit codes.
+	 */
+	 if ((STATUS_NATIVE & (STS$K_SEVERE|STS$K_ERROR)) == 0) {
+	    STATUS_NATIVE &= STS$M_COND_ID;
+	    STATUS_NATIVE |= STS$K_ERROR | STS$M_INHIB_MSG;
+         }
+    }
+    else {
+	/* Traditionally Perl on VMS always expects a Fatal Error. */
+	if (vaxc$errno & 1) {
+
+	    /* So force success status to failure */
+	    if (STATUS_NATIVE & 1)
+		STATUS_ALL_FAILURE;
+	}
+	else {
+	    if (!vaxc$errno) {
+		STATUS_UNIX = EINTR; /* In case something cares */
+		STATUS_ALL_FAILURE;
+	    }
+	    else {
+		int severity;
+		STATUS_NATIVE = vaxc$errno; /* Should already be this */
+
+		/* Encode the severity code */
+		severity = STATUS_NATIVE & STS$M_SEVERITY;
+		STATUS_UNIX = (severity ? severity : 1) << 8;
+
+		/* Perl expects this to be a fatal error */
+		if (severity != STS$K_SEVERE)
+		    STATUS_ALL_FAILURE;
+	    }
+	}
+    }
+
+#else
+    int exitstatus;
+    if (errno & 255)
+	STATUS_UNIX_SET(errno);
+    else {
+	exitstatus = STATUS_UNIX >> 8;
+	if (exitstatus & 255)
+	    STATUS_UNIX_SET(exitstatus);
+	else
+	    STATUS_UNIX_SET(255);
+    }
+#endif
+    if (PL_exit_flags & PERL_EXIT_ABORT) {
+	abort();
+    }
+    if (PL_exit_flags & PERL_EXIT_WARN) {
+	PL_exit_flags |= PERL_EXIT_ABORT; /* Protect against reentrant calls */
+	Perl_warn(aTHX_ "Unexpected exit failure %ld", (long)PL_statusvalue);
+	PL_exit_flags &= ~PERL_EXIT_ABORT;
+    }
+    my_exit_jump();
+}
+
+STATIC void
+S_my_exit_jump(pTHX)
+{
+    if (PL_e_script) {
+	SvREFCNT_dec(PL_e_script);
+	PL_e_script = NULL;
+    }
+
+    POPSTACK_TO(PL_mainstack);
+    dounwind(-1);
+    LEAVE_SCOPE(0);
+
+    JMPENV_JUMP(2);
+}
+
+static I32
+read_e_script(pTHX_ int idx, SV *buf_sv, int maxlen)
+{
+    const char * const p  = SvPVX_const(PL_e_script);
+    const char *nl = strchr(p, '\n');
+
+    PERL_UNUSED_ARG(idx);
+    PERL_UNUSED_ARG(maxlen);
+
+    nl = (nl) ? nl+1 : SvEND(PL_e_script);
+    if (nl-p == 0) {
+	filter_del(read_e_script);
+	return 0;
+    }
+    sv_catpvn(buf_sv, p, nl-p);
+    sv_chop(PL_e_script, nl);
+    return 1;
+}
+
+/* removes boilerplate code at the end of each boot_Module xsub */
+void
+Perl_xs_boot_epilog(pTHX_ const U32 ax)
+{
+  if (PL_unitcheckav)
+	call_list(PL_scopestack_ix, PL_unitcheckav);
+    XSRETURN_YES;
+}
+
+/*
+ * ex: set ts=8 sts=4 sw=4 et:
+ */