/* perl.c
*
- * Copyright (c) 1987-1996 Larry Wall
+ * Copyright (c) 1987-1997 Larry Wall
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
#include <unistd.h>
#endif
+#if !defined(STANDARD_C) && !defined(HAS_GETENV_PROTOTYPE)
+char *getenv _((char *)); /* Usually in <stdlib.h> */
+#endif
+
dEXTCONST char rcsid[] = "perl.c\nPatch level: ###\n";
#ifdef IAMSUID
dlmax = 128; \
laststatval = -1; \
laststype = OP_STAT; \
+ mess_sv = Nullsv; \
} STMT_END
static void find_beginning _((void));
static void init_perllib _((void));
static void init_postdump_symbols _((int, char **, char **));
static void init_predump_symbols _((void));
-static void init_stacks _((void));
static void my_exit_jump _((void)) __attribute__((noreturn));
static void nuke_stacks _((void));
static void open_script _((char *, bool, SV *));
+#ifdef USE_THREADS
+static void thread_destruct _((void *));
+#endif /* USE_THREADS */
static void usage _((char *));
static void validate_suid _((char *, char*));
static int fdscript = -1;
+#if defined(DEBUGGING) && defined(USE_THREADS) && defined(__linux__)
+#include <asm/sigcontext.h>
+static void
+catch_sigsegv(int signo, struct sigcontext_struct sc)
+{
+ signal(SIGSEGV, SIG_DFL);
+ fprintf(stderr, "Segmentation fault dereferencing 0x%lx\n"
+ "return_address = 0x%lx, eip = 0x%lx\n",
+ sc.cr2, __builtin_return_address(0), sc.eip);
+ fprintf(stderr, "thread = 0x%lx\n", (unsigned long)THR);
+}
+#endif
+
PerlInterpreter *
perl_alloc()
{
perl_construct( sv_interp )
register PerlInterpreter *sv_interp;
{
+#if defined(USE_THREADS) && !defined(FAKE_THREADS)
+ struct thread *thr;
+#endif
+
if (!(curinterp = sv_interp))
return;
Zero(sv_interp, 1, PerlInterpreter);
#endif
- /* Init the real globals? */
+ /* Init the real globals? */
if (!linestr) {
+#ifdef USE_THREADS
+#ifdef NEED_PTHREAD_INIT
+ pthread_init();
+#endif /* NEED_PTHREAD_INIT */
+ New(53, thr, 1, struct thread);
+ MUTEX_INIT(&malloc_mutex);
+ MUTEX_INIT(&sv_mutex);
+ MUTEX_INIT(&eval_mutex);
+ COND_INIT(&eval_cond);
+ MUTEX_INIT(&nthreads_mutex);
+ COND_INIT(&nthreads_cond);
+ nthreads = 1;
+ cvcache = newHV();
+ thrflags = 0;
+ curcop = &compiling;
+#ifdef FAKE_THREADS
+ self = thr;
+ thr->next = thr->prev = thr->next_run = thr->prev_run = thr;
+ thr->wait_queue = 0;
+ thr->private = 0;
+#else
+ self = pthread_self();
+ if (pthread_key_create(&thr_key, thread_destruct))
+ croak("panic: pthread_key_create");
+ if (pthread_setspecific(thr_key, (void *) thr))
+ croak("panic: pthread_setspecific");
+#endif /* FAKE_THREADS */
+#endif /* USE_THREADS */
+
linestr = NEWSV(65,80);
sv_upgrade(linestr,SVt_PVIV);
nrs = newSVpv("\n", 1);
rs = SvREFCNT_inc(nrs);
+ sighandlerp = sighandler;
pidstatus = newHV();
#ifdef MSDOS
init_ids();
+ start_env.je_prev = NULL;
+ start_env.je_ret = -1;
+ start_env.je_mustcatch = TRUE;
+ top_env = &start_env;
STATUS_ALL_SUCCESS;
SET_NUMERIC_STANDARD();
fdpid = newAV(); /* for remembering popen pids by fd */
- init_stacks();
+ init_stacks(ARGS);
+ DEBUG( {
+ New(51,debname,128,char);
+ New(52,debdelim,128,char);
+ } )
+
ENTER;
}
+#ifdef USE_THREADS
+void
+thread_destruct(arg)
+void *arg;
+{
+ struct thread *thr = (struct thread *) arg;
+ /*
+ * Decrement the global thread count and signal anyone listening.
+ * The only official thread listening is the original thread while
+ * in perl_destruct. It waits until it's the only thread and then
+ * performs END blocks and other process clean-ups.
+ */
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(), "thread_destruct: 0x%lx\n", (unsigned long) thr));
+
+ Safefree(thr);
+ MUTEX_LOCK(&nthreads_mutex);
+ nthreads--;
+ COND_BROADCAST(&nthreads_cond);
+ MUTEX_UNLOCK(&nthreads_mutex);
+}
+#endif /* USE_THREADS */
+
void
perl_destruct(sv_interp)
register PerlInterpreter *sv_interp;
{
+ dTHR;
int destruct_level; /* 0=none, 1=full, 2=full with checks */
I32 last_sv_count;
HV *hv;
if (!(curinterp = sv_interp))
return;
+#ifdef USE_THREADS
+#ifndef FAKE_THREADS
+ /* Wait until all user-created threads go away */
+ MUTEX_LOCK(&nthreads_mutex);
+ while (nthreads > 1)
+ {
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(), "perl_destruct: waiting for %d threads\n",
+ nthreads - 1));
+ COND_WAIT(&nthreads_cond, &nthreads_mutex);
+ }
+ /* At this point, we're the last thread */
+ MUTEX_UNLOCK(&nthreads_mutex);
+ DEBUG_L(PerlIO_printf(PerlIO_stderr(), "perl_destruct: armageddon has arrived\n"));
+ MUTEX_DESTROY(&nthreads_mutex);
+ COND_DESTROY(&nthreads_cond);
+#endif /* !defined(FAKE_THREADS) */
+#endif /* USE_THREADS */
+
destruct_level = perl_destruct_level;
#ifdef DEBUGGING
{
}
#endif
- /* unhook hooks which will soon be, or use, destroyed data */
- SvREFCNT_dec(warnhook);
- warnhook = Nullsv;
- SvREFCNT_dec(diehook);
- diehook = Nullsv;
- SvREFCNT_dec(parsehook);
- parsehook = Nullsv;
-
LEAVE;
FREETMPS;
sv_clean_objs();
}
+ /* unhook hooks which will soon be, or use, destroyed data */
+ SvREFCNT_dec(warnhook);
+ warnhook = Nullsv;
+ SvREFCNT_dec(diehook);
+ diehook = Nullsv;
+ SvREFCNT_dec(parsehook);
+ parsehook = Nullsv;
+
if (destruct_level == 0){
DEBUG_P(debprofdump());
/* startup and shutdown function lists */
SvREFCNT_dec(beginav);
SvREFCNT_dec(endav);
+ SvREFCNT_dec(initav);
beginav = Nullav;
endav = Nullav;
+ initav = Nullav;
/* temp stack during pp_sort() */
SvREFCNT_dec(sortstack);
if (origfilename)
Safefree(origfilename);
nuke_stacks();
- hints = 0; /* Reset hints. Should hints be per-interpreter ? */
+ hints = 0; /* Reset hints. Should hints be per-interpreter ? */
DEBUG_P(debprofdump());
+#ifdef USE_THREADS
+ MUTEX_DESTROY(&sv_mutex);
+ MUTEX_DESTROY(&malloc_mutex);
+ MUTEX_DESTROY(&eval_mutex);
+ COND_DESTROY(&eval_cond);
+#endif /* USE_THREADS */
+
+ /* As the absolutely last thing, free the non-arena SV for mess() */
+
+ if (mess_sv) {
+ /* we know that type >= SVt_PV */
+ SvOOK_off(mess_sv);
+ Safefree(SvPVX(mess_sv));
+ Safefree(SvANY(mess_sv));
+ Safefree(mess_sv);
+ mess_sv = Nullsv;
+ }
}
void
return;
Safefree(sv_interp);
}
-#if !defined(STANDARD_C) && !defined(HAS_GETENV_PROTOTYPE)
-char *getenv _((char *)); /* Usually in <stdlib.h> */
-#endif
int
perl_parse(sv_interp, xsinit, argc, argv, env)
char **argv;
char **env;
{
+ dTHR;
register SV *sv;
register char *s;
char *scriptname = NULL;
VOL bool dosearch = FALSE;
char *validarg = "";
+ I32 oldscope;
AV* comppadlist;
+ dJMPENV;
+ int ret;
#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
#ifdef IAMSUID
main_cv = Nullcv;
time(&basetime);
- mustcatch = FALSE;
+ oldscope = scopestack_ix;
- switch (Sigsetjmp(top_env,1)) {
+ JMPENV_PUSH(ret);
+ switch (ret) {
case 1:
STATUS_ALL_FAILURE;
/* FALL THROUGH */
case 2:
/* my_exit() was called */
+ while (scopestack_ix > oldscope)
+ LEAVE;
curstash = defstash;
if (endav)
- calllist(endav);
+ call_list(oldscope, endav);
+ JMPENV_POP;
return STATUS_NATIVE_EXPORT;
case 3:
- mustcatch = FALSE;
+ JMPENV_POP;
PerlIO_printf(PerlIO_stderr(), "panic: top_env\n");
return 1;
}
sv = newSVpv("",0); /* first used for -I flags */
SAVEFREESV(sv);
init_main_stash();
+
for (argc--,argv++; argc > 0; argc--,argv++) {
if (argv[0][0] != '-' || !argv[0][1])
break;
#else
sv_catpv(Sv,"print \"\\nCharacteristics of this binary (from libperl): \\n\",");
#endif
-#if defined(DEBUGGING) || defined(NOEMBED) || defined(MULTIPLICITY)
- strcpy(buf,"\" Compile-time options:");
+#if defined(DEBUGGING) || defined(NO_EMBED) || defined(MULTIPLICITY)
+ sv_catpv(Sv,"\" Compile-time options:");
# ifdef DEBUGGING
- strcat(buf," DEBUGGING");
+ sv_catpv(Sv," DEBUGGING");
# endif
-# ifdef NOEMBED
- strcat(buf," NOEMBED");
+# ifdef NO_EMBED
+ sv_catpv(Sv," NO_EMBED");
# endif
# ifdef MULTIPLICITY
- strcat(buf," MULTIPLICITY");
+ sv_catpv(Sv," MULTIPLICITY");
# endif
- strcat(buf,"\\n\",");
- sv_catpv(Sv,buf);
+ sv_catpv(Sv,"\\n\",");
#endif
#if defined(LOCAL_PATCH_COUNT)
- if (LOCAL_PATCH_COUNT > 0)
- { int i;
- sv_catpv(Sv,"print \" Locally applied patches:\\n\",");
+ if (LOCAL_PATCH_COUNT > 0) {
+ int i;
+ sv_catpv(Sv,"\" Locally applied patches:\\n\",");
for (i = 1; i <= LOCAL_PATCH_COUNT; i++) {
- if (localpatches[i]) {
- sprintf(buf,"\" \\t%s\\n\",",localpatches[i]);
- sv_catpv(Sv,buf);
- }
+ if (localpatches[i])
+ sv_catpvf(Sv,"\" \\t%s\\n\",",localpatches[i]);
}
}
#endif
- sprintf(buf,"\" Built under %s\\n\",",OSNAME);
- sv_catpv(Sv,buf);
+ sv_catpvf(Sv,"\" Built under %s\\n\"",OSNAME);
#ifdef __DATE__
# ifdef __TIME__
- sprintf(buf,"\" Compiled at %s %s\\n\"",__DATE__,__TIME__);
+ sv_catpvf(Sv,",\" Compiled at %s %s\\n\"",__DATE__,__TIME__);
# else
- sprintf(buf,"\" Compiled on %s\\n\"",__DATE__);
+ sv_catpvf(Sv,",\" Compiled on %s\\n\"",__DATE__);
# endif
- sv_catpv(Sv,buf);
#endif
- sv_catpv(Sv,"; $\"=\"\\n \"; print \" \\@INC:\\n @INC\\n\"");
+ sv_catpv(Sv, "; \
+$\"=\"\\n \"; \
+@env = map { \"$_=\\\"$ENV{$_}\\\"\" } sort grep {/^PERL/} keys %ENV; \
+print \" \\%ENV:\\n @env\\n\" if @env; \
+print \" \\@INC:\\n @INC\\n\";");
}
else {
Sv = newSVpv("config_vars(qw(",0);
}
}
switch_end:
+
+ if (!tainting && (s = getenv("PERL5OPT"))) {
+ for (;;) {
+ while (isSPACE(*s))
+ s++;
+ if (*s == '-') {
+ s++;
+ if (isSPACE(*s))
+ continue;
+ }
+ if (!*s)
+ break;
+ if (!strchr("DIMUdmw", *s))
+ croak("Illegal switch in PERL5OPT: -%c", *s);
+ s = moreswitches(s);
+ }
+ }
+
if (!scriptname)
scriptname = argv[0];
if (e_fp) {
- if (PerlIO_flush(e_fp) || PerlIO_error(e_fp) || PerlIO_close(e_fp))
+ if (PerlIO_flush(e_fp) || PerlIO_error(e_fp) || PerlIO_close(e_fp)) {
+#ifndef MULTIPLICITY
+ warn("Did you forget to compile with -DMULTIPLICITY?");
+#endif
croak("Can't write to temp file for -e: %s", Strerror(errno));
+ }
e_fp = Nullfp;
argc++,argv--;
scriptname = e_tmpname;
comppad_name_fill = 0;
min_intro_pending = 0;
padix = 0;
+#ifdef USE_THREADS
+ av_store(comppad_name, 0, newSVpv("@_", 2));
+ curpad[0] = (SV*)newAV();
+ SvPADMY_on(curpad[0]); /* XXX Needed? */
+ CvOWNER(compcv) = 0;
+ New(666, CvMUTEXP(compcv), 1, perl_mutex);
+ MUTEX_INIT(CvMUTEXP(compcv));
+#endif /* USE_THREADS */
comppadlist = newAV();
AvREAL_off(comppadlist);
init_os_extras();
#endif
+#if defined(DEBUGGING) && defined(USE_THREADS) && defined(__linux__)
+ DEBUG_L(signal(SIGSEGV, (void(*)(int))catch_sigsegv););
+#endif
+
init_predump_symbols();
if (!do_undump)
init_postdump_symbols(argc,argv,env);
ENTER;
restartop = 0;
+ JMPENV_POP;
return 0;
}
perl_run(sv_interp)
PerlInterpreter *sv_interp;
{
+ dTHR;
+ I32 oldscope;
+ dJMPENV;
+ int ret;
+
if (!(curinterp = sv_interp))
return 255;
- switch (Sigsetjmp(top_env,1)) {
+
+ oldscope = scopestack_ix;
+
+ JMPENV_PUSH(ret);
+ switch (ret) {
case 1:
cxstack_ix = -1; /* start context stack again */
break;
case 2:
/* my_exit() was called */
+ while (scopestack_ix > oldscope)
+ LEAVE;
curstash = defstash;
if (endav)
- calllist(endav);
+ call_list(oldscope, endav);
FREETMPS;
#ifdef DEBUGGING_MSTATS
if (getenv("PERL_DEBUG_MSTATS"))
dump_mstats("after execution: ");
#endif
+ JMPENV_POP;
return STATUS_NATIVE_EXPORT;
case 3:
- mustcatch = FALSE;
if (!restartop) {
PerlIO_printf(PerlIO_stderr(), "panic: restartop\n");
FREETMPS;
+ JMPENV_POP;
return 1;
}
if (curstack != mainstack) {
if (!restartop) {
DEBUG_x(dump_all());
DEBUG(PerlIO_printf(Perl_debug_log, "\nEXECUTING...\n\n"));
+#ifdef USE_THREADS
+ DEBUG_L(PerlIO_printf(Perl_debug_log, "main thread is 0x%lx\n",
+ (unsigned long) thr));
+#endif /* USE_THREADS */
if (minus_c) {
PerlIO_printf(PerlIO_stderr(), "%s syntax OK\n", origfilename);
my_exit(0);
}
if (perldb && DBsingle)
- sv_setiv(DBsingle, 1);
+ sv_setiv(DBsingle, 1);
+ if (initav)
+ call_list(oldscope, initav);
}
/* do it */
}
my_exit(0);
+ /* NOTREACHED */
return 0;
}
I32 flags; /* See G_* flags in cop.h */
register char **argv; /* null terminated arg list */
{
+ dTHR;
dSP;
PUSHMARK(sp);
char *methname; /* name of the subroutine */
I32 flags; /* See G_* flags in cop.h */
{
+ dTHR;
dSP;
OP myop;
if (!op)
op = &myop;
XPUSHs(sv_2mortal(newSVpv(methname,0)));
PUTBACK;
- pp_method();
+ pp_method(ARGS);
return perl_call_sv(*stack_sp--, flags);
}
SV* sv;
I32 flags; /* See G_* flags in cop.h */
{
+ dTHR;
LOGOP myop; /* fake syntax tree node */
SV** sp = stack_sp;
I32 oldmark;
I32 retval;
- Sigjmp_buf oldtop;
I32 oldscope;
static CV *DBcv;
- bool oldmustcatch = mustcatch;
+ bool oldcatch = CATCH_GET;
+ dJMPENV;
+ int ret;
if (flags & G_DISCARD) {
ENTER;
}
Zero(&myop, 1, LOGOP);
- if (flags & G_NOARGS) {
- PUSHMARK(sp);
- }
- else
- myop.op_flags |= OPf_STACKED;
myop.op_next = Nullop;
- myop.op_flags |= OPf_KNOW;
- if (flags & G_ARRAY)
- myop.op_flags |= OPf_LIST;
- SAVESPTR(op);
+ if (!(flags & G_NOARGS))
+ myop.op_flags |= OPf_STACKED;
+ myop.op_flags |= ((flags & G_VOID) ? OPf_WANT_VOID :
+ (flags & G_ARRAY) ? OPf_WANT_LIST :
+ OPf_WANT_SCALAR);
+ SAVEOP();
op = (OP*)&myop;
EXTEND(stack_sp, 1);
op->op_private |= OPpENTERSUB_DB;
if (flags & G_EVAL) {
- Copy(top_env, oldtop, 1, Sigjmp_buf);
-
cLOGOP->op_other = op;
markstack_ptr--;
/* we're trying to emulate pp_entertry() here */
{
register CONTEXT *cx;
- I32 gimme = GIMME;
+ I32 gimme = GIMME_V;
ENTER;
SAVETMPS;
}
markstack_ptr++;
- restart:
- switch (Sigsetjmp(top_env,1)) {
+ JMPENV_PUSH(ret);
+ switch (ret) {
case 0:
break;
case 1:
/* my_exit() was called */
curstash = defstash;
FREETMPS;
- Copy(oldtop, top_env, 1, Sigjmp_buf);
+ JMPENV_POP;
if (statusvalue)
croak("Callback called exit");
my_exit_jump();
/* NOTREACHED */
case 3:
- mustcatch = FALSE;
if (restartop) {
op = restartop;
restartop = 0;
- goto restart;
+ break;
}
stack_sp = stack_base + oldmark;
if (flags & G_ARRAY)
}
}
else
- mustcatch = TRUE;
+ CATCH_SET(TRUE);
if (op == (OP*)&myop)
- op = pp_entersub();
+ op = pp_entersub(ARGS);
if (op)
runops();
retval = stack_sp - (stack_base + oldmark);
curpm = newpm;
LEAVE;
}
- Copy(oldtop, top_env, 1, Sigjmp_buf);
+ JMPENV_POP;
}
else
- mustcatch = oldmustcatch;
+ CATCH_SET(oldcatch);
if (flags & G_DISCARD) {
stack_sp = stack_base + oldmark;
SV* sv;
I32 flags; /* See G_* flags in cop.h */
{
+ dTHR;
UNOP myop; /* fake syntax tree node */
SV** sp = stack_sp;
I32 oldmark = sp - stack_base;
I32 retval;
- Sigjmp_buf oldtop;
I32 oldscope;
+ dJMPENV;
+ int ret;
if (flags & G_DISCARD) {
ENTER;
SAVETMPS;
}
- SAVESPTR(op);
+ SAVEOP();
op = (OP*)&myop;
Zero(op, 1, UNOP);
EXTEND(stack_sp, 1);
myop.op_flags = OPf_STACKED;
myop.op_next = Nullop;
myop.op_type = OP_ENTEREVAL;
- myop.op_flags |= OPf_KNOW;
+ myop.op_flags |= ((flags & G_VOID) ? OPf_WANT_VOID :
+ (flags & G_ARRAY) ? OPf_WANT_LIST :
+ OPf_WANT_SCALAR);
if (flags & G_KEEPERR)
myop.op_flags |= OPf_SPECIAL;
- if (flags & G_ARRAY)
- myop.op_flags |= OPf_LIST;
-
- Copy(top_env, oldtop, 1, Sigjmp_buf);
-restart:
- switch (Sigsetjmp(top_env,1)) {
+ JMPENV_PUSH(ret);
+ switch (ret) {
case 0:
break;
case 1:
/* my_exit() was called */
curstash = defstash;
FREETMPS;
- Copy(oldtop, top_env, 1, Sigjmp_buf);
+ JMPENV_POP;
if (statusvalue)
croak("Callback called exit");
my_exit_jump();
/* NOTREACHED */
case 3:
- mustcatch = FALSE;
if (restartop) {
op = restartop;
restartop = 0;
- goto restart;
+ break;
}
stack_sp = stack_base + oldmark;
if (flags & G_ARRAY)
}
if (op == (OP*)&myop)
- op = pp_entereval();
+ op = pp_entereval(ARGS);
if (op)
runops();
retval = stack_sp - (stack_base + oldmark);
sv_setpv(GvSV(errgv),"");
cleanup:
- Copy(oldtop, top_env, 1, Sigjmp_buf);
+ JMPENV_POP;
if (flags & G_DISCARD) {
stack_sp = stack_base + oldmark;
retval = 0;
return retval;
}
+SV*
+perl_eval_pv(p, croak_on_error)
+char* p;
+I32 croak_on_error;
+{
+ dTHR;
+ dSP;
+ SV* sv = newSVpv(p, 0);
+
+ PUSHMARK(sp);
+ perl_eval_sv(sv, G_SCALAR);
+ SvREFCNT_dec(sv);
+
+ SPAGAIN;
+ sv = POPs;
+ PUTBACK;
+
+ if (croak_on_error && SvTRUE(GvSV(errgv)))
+ croak(SvPVx(GvSV(errgv), na));
+
+ return sv;
+}
+
/* Require a module. */
void
forbid_setid("-d");
s++;
if (*s == ':' || *s == '=') {
- sprintf(buf, "use Devel::%s;", ++s);
+ my_setenv("PERL5DB", form("use Devel::%s;", ++s));
s += strlen(s);
- my_setenv("PERL5DB",buf);
}
if (!perldb) {
perldb = TRUE;
forbid_setid("-m"); /* XXX ? */
if (*++s) {
char *start;
+ SV *sv;
char *use = "use ";
/* -M-foo == 'no foo' */
if (*s == '-') { use = "no "; ++s; }
- Sv = newSVpv(use,0);
+ sv = newSVpv(use,0);
start = s;
/* We allow -M'Module qw(Foo Bar)' */
while(isALNUM(*s) || *s==':') ++s;
if (*s != '=') {
- sv_catpv(Sv, start);
+ sv_catpv(sv, start);
if (*(start-1) == 'm') {
if (*s != '\0')
croak("Can't use '%c' after -mname", *s);
- sv_catpv( Sv, " ()");
+ sv_catpv( sv, " ()");
}
} else {
- sv_catpvn(Sv, start, s-start);
- sv_catpv(Sv, " split(/,/,q{");
- sv_catpv(Sv, ++s);
- sv_catpv(Sv, "})");
+ sv_catpvn(sv, start, s-start);
+ sv_catpv(sv, " split(/,/,q{");
+ sv_catpv(sv, ++s);
+ sv_catpv(sv, "})");
}
s += strlen(s);
if (preambleav == NULL)
preambleav = newAV();
- av_push(preambleav, Sv);
+ av_push(preambleav, sv);
}
else
croak("No space allowed after -%c", *(s-1));
return s;
case 'T':
if (!tainting)
- croak("Too late for \"-T\" option (try putting it first)");
+ croak("Too late for \"-T\" option");
s++;
return s;
case 'u':
#endif
#ifdef OS2
printf("\n\nOS/2 port Copyright (c) 1990, 1991, Raymond Chen, Kai Uwe Rommel\n"
- "Version 5 port Copyright (c) 1994-1996, Andreas Kaiser, Ilya Zakharevich\n");
+ "Version 5 port Copyright (c) 1994-1997, Andreas Kaiser, Ilya Zakharevich\n");
#endif
#ifdef atarist
printf("atariST series port, ++jrb bammi@cadence.com\n");
my_unexec()
{
#ifdef UNEXEC
+ SV* prog;
+ SV* file;
int status;
extern int etext;
- sprintf (buf, "%s.perldump", origfilename);
- sprintf (tokenbuf, "%s/perl", BIN);
+ prog = newSVpv(BIN_EXP);
+ sv_catpv(prog, "/perl");
+ file = newSVpv(origfilename);
+ sv_catpv(file, ".perldump");
- status = unexec(buf, tokenbuf, &etext, sbrk(0), 0);
+ status = unexec(SvPVX(file), SvPVX(prog), &etext, sbrk(0), 0);
if (status)
- PerlIO_printf(PerlIO_stderr(), "unexec of %s into %s failed!\n", tokenbuf, buf);
+ PerlIO_printf(PerlIO_stderr(), "unexec of %s into %s failed!\n",
+ SvPVX(prog), SvPVX(file));
exit(status);
#else
# ifdef VMS
static void
init_main_stash()
{
+ dTHR;
GV *gv;
/* Note that strtab is a rather special HV. Assumptions are made
SV *sv;
#endif
{
+ dTHR;
char *xfound = Nullch;
char *xfailed = Nullch;
register char *s;
I32 len;
int retval;
#if defined(DOSISH) && !defined(OS2) && !defined(atarist)
-#define SEARCH_EXTS ".bat", ".cmd", NULL
+# define SEARCH_EXTS ".bat", ".cmd", NULL
+# define MAX_EXT_LEN 4
#endif
#ifdef VMS
# define SEARCH_EXTS ".pl", ".com", NULL
+# define MAX_EXT_LEN 4
#endif
/* additional extensions to try in each dir if scriptname not found */
#ifdef SEARCH_EXTS
char *ext[] = { SEARCH_EXTS };
int extidx = (strchr(scriptname,'.')) ? -1 : 0; /* has ext already */
+#else
+# define MAX_EXT_LEN 0
#endif
#ifdef VMS
hasdir = (strpbrk(scriptname,":[</") != Nullch) ;
/* The first time through, just add SEARCH_EXTS to whatever we
* already have, so we can check for default file types. */
- while (deftypes || (!hasdir && my_trnlnm("DCL$PATH",tokenbuf,idx++)) ) {
- if (deftypes) { deftypes = 0; *tokenbuf = '\0'; }
- strcat(tokenbuf,scriptname);
+ while (deftypes ||
+ (!hasdir && my_trnlnm("DCL$PATH",tokenbuf,idx++)) )
+ {
+ if (deftypes) {
+ deftypes = 0;
+ *tokenbuf = '\0';
+ }
+ if ((strlen(tokenbuf) + strlen(scriptname)
+ + MAX_EXT_LEN) >= sizeof tokenbuf)
+ continue; /* don't search dir with too-long name */
+ strcat(tokenbuf, scriptname);
#else /* !VMS */
if (dosearch && !strchr(scriptname, '/') && (s = getenv("PATH"))) {
-
bufend = s + strlen(s);
- while (*s) {
-#ifndef DOSISH
- s = cpytill(tokenbuf,s,bufend,':',&len);
-#else
-#ifdef atarist
- for (len = 0; *s && *s != ',' && *s != ';'; tokenbuf[len++] = *s++);
- tokenbuf[len] = '\0';
+ while (s < bufend) {
+#ifndef atarist
+ s = delimcpy(tokenbuf, tokenbuf + sizeof tokenbuf, s, bufend,
+#ifdef DOSISH
+ ';',
#else
- for (len = 0; *s && *s != ';'; tokenbuf[len++] = *s++);
- tokenbuf[len] = '\0';
-#endif
+ ':',
#endif
- if (*s)
+ &len);
+#else /* atarist */
+ for (len = 0; *s && *s != ',' && *s != ';'; len++, s++) {
+ if (len < sizeof tokenbuf)
+ tokenbuf[len] = *s;
+ }
+ if (len < sizeof tokenbuf)
+ tokenbuf[len] = '\0';
+#endif /* atarist */
+ if (s < bufend)
s++;
-#ifndef DOSISH
- if (len && tokenbuf[len-1] != '/')
-#else
-#ifdef atarist
- if (len && ((tokenbuf[len-1] != '\\') && (tokenbuf[len-1] != '/')))
-#else
- if (len && tokenbuf[len-1] != '\\')
-#endif
-#endif
- (void)strcat(tokenbuf+len,"/");
- (void)strcat(tokenbuf+len,scriptname);
+ if (len + 1 + strlen(scriptname) + MAX_EXT_LEN >= sizeof tokenbuf)
+ continue; /* don't search dir with too-long name */
+ if (len
+#if defined(atarist) && !defined(DOSISH)
+ && tokenbuf[len - 1] != '/'
+#endif
+#if defined(atarist) || defined(DOSISH)
+ && tokenbuf[len - 1] != '\\'
+#endif
+ )
+ tokenbuf[len++] = '/';
+ (void)strcpy(tokenbuf + len, scriptname);
#endif /* !VMS */
#ifdef SEARCH_EXTS
if (retval < 0)
continue;
if (S_ISREG(statbuf.st_mode)
- && cando(S_IRUSR,TRUE,&statbuf) && cando(S_IXUSR,TRUE,&statbuf)) {
+ && cando(S_IRUSR,TRUE,&statbuf)
+#ifndef DOSISH
+ && cando(S_IXUSR,TRUE,&statbuf)
+#endif
+ )
+ {
xfound = tokenbuf; /* bingo! */
break;
}
#endif
}
else if (preprocess) {
- char *cpp = CPPSTDIN;
+ char *cpp_cfg = CPPSTDIN;
+ SV *cpp = NEWSV(0,0);
+ SV *cmd = NEWSV(0,0);
+
+ if (strEQ(cpp_cfg, "cppstdin"))
+ sv_catpvf(cpp, "%s/", BIN_EXP);
+ sv_catpv(cpp, cpp_cfg);
- if (strEQ(cpp,"cppstdin"))
- sprintf(tokenbuf, "%s/%s", SCRIPTDIR, cpp);
- else
- sprintf(tokenbuf, "%s", cpp);
sv_catpv(sv,"-I");
sv_catpv(sv,PRIVLIB_EXP);
+
#ifdef MSDOS
- (void)sprintf(buf, "\
+ sv_setpvf(cmd, "\
sed %s -e \"/^[^#]/b\" \
-e \"/^#[ ]*include[ ]/b\" \
-e \"/^#[ ]*define[ ]/b\" \
-e \"/^#[ ]*undef[ ]/b\" \
-e \"/^#[ ]*endif/b\" \
-e \"s/^#.*//\" \
- %s | %s -C %s %s",
+ %s | %_ -C %_ %s",
(doextract ? "-e \"1,/^#/d\n\"" : ""),
#else
- (void)sprintf(buf, "\
+ sv_setpvf(cmd, "\
%s %s -e '/^[^#]/b' \
-e '/^#[ ]*include[ ]/b' \
-e '/^#[ ]*define[ ]/b' \
-e '/^#[ ]*undef[ ]/b' \
-e '/^#[ ]*endif/b' \
-e 's/^[ ]*#.*//' \
- %s | %s -C %s %s",
+ %s | %_ -C %_ %s",
#ifdef LOC_SED
LOC_SED,
#else
#endif
(doextract ? "-e '1,/^#/d\n'" : ""),
#endif
- scriptname, tokenbuf, SvPV(sv, na), CPPMINUS);
+ scriptname, cpp, sv, CPPMINUS);
doextract = FALSE;
#ifdef IAMSUID /* actually, this is caught earlier */
if (euid != uid && !euid) { /* if running suidperl */
croak("Can't do seteuid!\n");
}
#endif /* IAMSUID */
- rsfp = my_popen(buf,"r");
+ rsfp = my_popen(SvPVX(cmd), "r");
+ SvREFCNT_dec(cmd);
+ SvREFCNT_dec(cpp);
}
else if (!*scriptname) {
forbid_setid("program input from stdin");
#ifndef IAMSUID /* in case script is not readable before setuid */
if (euid && Stat(SvPVX(GvSV(curcop->cop_filegv)),&statbuf) >= 0 &&
statbuf.st_mode & (S_ISUID|S_ISGID)) {
- (void)sprintf(buf, "%s/sperl%s", BIN, patchlevel);
- execv(buf, origargv); /* try again */
+ /* try again */
+ execv(form("%s/sperl%s", BIN_EXP, patchlevel), origargv);
croak("Can't do setuid\n");
}
#endif
if (euid) { /* oops, we're not the setuid root perl */
(void)PerlIO_close(rsfp);
#ifndef IAMSUID
- (void)sprintf(buf, "%s/sperl%s", BIN, patchlevel);
- execv(buf, origargv); /* try again */
+ /* try again */
+ execv(form("%s/sperl%s", BIN_EXP, patchlevel), origargv);
#endif
croak("Can't do setuid\n");
}
for (which = 1; origargv[which] && origargv[which] != scriptname; which++) ;
if (!origargv[which])
croak("Permission denied");
- (void)sprintf(buf, "/dev/fd/%d/%.127s", PerlIO_fileno(rsfp), origargv[which]);
- origargv[which] = buf;
-
+ origargv[which] = savepv(form("/dev/fd/%d/%s",
+ PerlIO_fileno(rsfp), origargv[which]));
#if defined(HAS_FCNTL) && defined(F_SETFD)
fcntl(PerlIO_fileno(rsfp),F_SETFD,0); /* ensure no close-on-exec */
#endif
-
- (void)sprintf(tokenbuf, "%s/perl%s", BIN, patchlevel);
- execv(tokenbuf, origargv); /* try again */
+ execv(form("%s/perl%s", BIN_EXP, patchlevel), origargv); /* try again */
croak("Can't do setuid\n");
#endif /* IAMSUID */
#else /* !DOSUID */
if (euid != uid || egid != gid) { /* (suidperl doesn't exist, in fact) */
#ifndef SETUID_SCRIPTS_ARE_SECURE_NOW
+ dTHR;
Fstat(PerlIO_fileno(rsfp),&statbuf); /* may be either wrapped or real suid */
if ((euid != uid && euid == statbuf.st_uid && statbuf.st_mode & S_ISUID)
||
static void
init_debugger()
{
+ dTHR;
curstash = debstash;
dbargs = GvAV(gv_AVadd((gv_fetchpv("args", GV_ADDMULTI, SVt_PVAV))));
AvREAL_off(dbargs);
curstash = defstash;
}
-static void
-init_stacks()
+void
+init_stacks(ARGS)
+dARGS
{
curstack = newAV();
mainstack = curstack; /* remember in case we switch stacks */
cxstack_ix = -1;
New(50,tmps_stack,128,SV*);
+ tmps_floor = -1;
tmps_ix = -1;
tmps_max = 128;
- DEBUG( {
- New(51,debname,128,char);
- New(52,debdelim,128,char);
- } )
-
/*
* The following stacks almost certainly should be per-interpreter,
* but for now they're not. XXX
static void
nuke_stacks()
{
+ dTHR;
Safefree(cxstack);
Safefree(tmps_stack);
DEBUG( {
static void
init_predump_symbols()
{
+ dTHR;
GV *tmpgv;
GV *othergv;
HV *hv;
GvMULTI_on(envgv);
hv = GvHVn(envgv);
- hv_clear(hv);
+ hv_magic(hv, envgv, 'E');
#ifndef VMS /* VMS doesn't have 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 (!env)
env = environ;
- if (env != environ) {
+ if (env != environ)
environ[0] = Nullch;
- hv_magic(hv, envgv, 'E');
- }
for (; *env; env++) {
if (!(s = strchr(*env,'=')))
continue;
*s++ = '\0';
+#ifdef WIN32
+ (void)strupr(*env);
+#endif
sv = newSVpv(s--,0);
- sv_magic(sv, sv, 'e', *env, s - *env);
(void)hv_store(hv, *env, s - *env, sv, 0);
*s = '=';
+#if defined(__BORLANDC__) && defined(USE_WIN32_RTL_ENV)
+ /* Sins of the RTL. See note in my_setenv(). */
+ (void)putenv(savepv(*env));
+#endif
}
#endif
#ifdef DYNAMIC_ENV_FETCH
HvNAME(hv) = savepv(ENV_HV_NAME);
#endif
- hv_magic(hv, envgv, 'E');
}
TAINT_NOT;
if (tmpgv = gv_fetchpv("$",TRUE, SVt_PV))
#endif /* VMS */
}
-/* Use the ~-expanded versions of APPLIB (undocumented),
+/* Use the ~-expanded versions of APPLLIB (undocumented),
ARCHLIB PRIVLIB SITEARCH SITELIB and OLDARCHLIB
*/
#ifdef APPLLIB_EXP
}
void
-calllist(list)
+call_list(oldscope, list)
+I32 oldscope;
AV* list;
{
- Sigjmp_buf oldtop;
- STRLEN len;
+ dTHR;
line_t oldline = curcop->cop_line;
-
- Copy(top_env, oldtop, 1, Sigjmp_buf);
+ STRLEN len;
+ dJMPENV;
+ int ret;
while (AvFILL(list) >= 0) {
CV *cv = (CV*)av_shift(list);
SAVEFREESV(cv);
- switch (Sigsetjmp(top_env,1)) {
+ JMPENV_PUSH(ret);
+ switch (ret) {
case 0: {
SV* atsv = GvSV(errgv);
PUSHMARK(stack_sp);
perl_call_sv((SV*)cv, G_EVAL|G_DISCARD);
(void)SvPV(atsv, len);
if (len) {
- Copy(oldtop, top_env, 1, Sigjmp_buf);
+ JMPENV_POP;
curcop = &compiling;
curcop->cop_line = oldline;
if (list == beginav)
sv_catpv(atsv, "BEGIN failed--compilation aborted");
else
sv_catpv(atsv, "END failed--cleanup aborted");
+ while (scopestack_ix > oldscope)
+ LEAVE;
croak("%s", SvPVX(atsv));
}
}
/* FALL THROUGH */
case 2:
/* my_exit() was called */
+ while (scopestack_ix > oldscope)
+ LEAVE;
curstash = defstash;
if (endav)
- calllist(endav);
+ call_list(oldscope, endav);
FREETMPS;
- Copy(oldtop, top_env, 1, Sigjmp_buf);
+ JMPENV_POP;
curcop = &compiling;
curcop->cop_line = oldline;
if (statusvalue) {
FREETMPS;
break;
}
- Copy(oldtop, top_env, 1, Sigjmp_buf);
+ JMPENV_POP;
curcop = &compiling;
curcop->cop_line = oldline;
- Siglongjmp(top_env, 3);
+ JMPENV_JUMP(3);
}
+ JMPENV_POP;
}
-
- Copy(oldtop, top_env, 1, Sigjmp_buf);
}
void
my_exit(status)
U32 status;
{
+ dTHR;
+
+#ifdef USE_THREADS
+ DEBUG_L(PerlIO_printf(Perl_debug_log, "my_exit: thread 0x%lx, status %lu\n",
+ (unsigned long) thr, (unsigned long) status));
+#endif /* USE_THREADS */
switch (status) {
case 0:
STATUS_ALL_SUCCESS;
static void
my_exit_jump()
{
+ dTHR;
register CONTEXT *cx;
I32 gimme;
SV **newsp;
LEAVE;
}
- Siglongjmp(top_env, 2);
+ JMPENV_JUMP(2);
}