home *** CD-ROM | disk | FTP | other *** search
- From: lwall@netlabs.com (Larry Wall)
- Newsgroups: comp.sources.misc
- Subject: v18i034: perl - The perl programming language, Part16/36
- Message-ID: <1991Apr16.185430.874@sparky.IMD.Sterling.COM>
- Date: 16 Apr 91 18:54:30 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Checksum-Snefru: 89266026 5d1bcbee 30d38392 89a80905
-
- Submitted-by: Larry Wall <lwall@netlabs.com>
- Posting-number: Volume 18, Issue 34
- Archive-name: perl/part16
-
- [There are 36 kits for perl version 4.0.]
-
- #! /bin/sh
-
- # Make a new directory for the perl sources, cd to it, and run kits 1
- # thru 36 through sh. When all 36 kits have been run, read README.
-
- echo "This is perl 4.0 kit 16 (of 36). If kit 16 is complete, the line"
- echo '"'"End of kit 16 (of 36)"'" will echo at the end.'
- echo ""
- export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
- mkdir emacs 2>/dev/null
- echo Extracting perl.c
- sed >perl.c <<'!STUFFY!FUNK!' -e 's/X//'
- Xchar rcsid[] = "$RCSfile: perl.c,v $$Revision: 4.0.1.1 $$Date: 91/04/11 17:49:05 $\nPatch level: ###\n";
- X/*
- X * Copyright (c) 1989, Larry Wall
- X *
- X * You may distribute under the terms of the GNU General Public License
- X * as specified in the README file that comes with the perl 3.0 kit.
- X *
- X * $Log: perl.c,v $
- X * Revision 4.0.1.1 91/04/11 17:49:05 lwall
- X * patch1: fixed undefined environ problem
- X *
- X * Revision 4.0 91/03/20 01:37:44 lwall
- X * 4.0 baseline.
- X *
- X */
- X
- X#include "EXTERN.h"
- X#include "perl.h"
- X#include "perly.h"
- X#ifdef MSDOS
- X#include "patchlev.h"
- X#else
- X#include "patchlevel.h"
- X#endif
- X
- X#ifdef IAMSUID
- X#ifndef DOSUID
- X#define DOSUID
- X#endif
- X#endif
- X
- X#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
- X#ifdef DOSUID
- X#undef DOSUID
- X#endif
- X#endif
- X
- Xstatic char* moreswitches();
- Xstatic char* cddir;
- Xstatic bool minus_c;
- Xstatic char patchlevel[6];
- Xstatic char *nrs = "\n";
- Xstatic int nrschar = '\n'; /* final char of rs, or 0777 if none */
- Xstatic int nrslen = 1;
- X
- Xmain(argc,argv,env)
- Xregister int argc;
- Xregister char **argv;
- Xregister char **env;
- X{
- X register STR *str;
- X register char *s;
- X char *index(), *strcpy(), *getenv();
- X bool dosearch = FALSE;
- X#ifdef DOSUID
- X char *validarg = "";
- X#endif
- X
- X#ifdef SETUID_SCRIPTS_ARE_SECURE_NOW
- X#ifdef IAMSUID
- X#undef IAMSUID
- X fatal("suidperl is no longer needed since the kernel can now execute\n\
- Xsetuid perl scripts securely.\n");
- X#endif
- X#endif
- X
- X origargv = argv;
- X origargc = argc;
- X origenviron = environ;
- X uid = (int)getuid();
- X euid = (int)geteuid();
- X gid = (int)getgid();
- X egid = (int)getegid();
- X sprintf(patchlevel,"%3.3s%2.2d", index(rcsid,'4'), PATCHLEVEL);
- X#ifdef MSDOS
- X /*
- X * There is no way we can refer to them from Perl so close them to save
- X * space. The other alternative would be to provide STDAUX and STDPRN
- X * filehandles.
- X */
- X (void)fclose(stdaux);
- X (void)fclose(stdprn);
- X#endif
- X if (do_undump) {
- X origfilename = savestr(argv[0]);
- X do_undump = 0;
- X loop_ptr = -1; /* start label stack again */
- X goto just_doit;
- X }
- X (void)sprintf(index(rcsid,'#'), "%d\n", PATCHLEVEL);
- X linestr = Str_new(65,80);
- X str_nset(linestr,"",0);
- X str = str_make("",0); /* first used for -I flags */
- X curstash = defstash = hnew(0);
- X curstname = str_make("main",4);
- X stab_xhash(stabent("_main",TRUE)) = defstash;
- X defstash->tbl_name = "main";
- X incstab = hadd(aadd(stabent("INC",TRUE)));
- X incstab->str_pok |= SP_MULTI;
- X for (argc--,argv++; argc > 0; argc--,argv++) {
- X if (argv[0][0] != '-' || !argv[0][1])
- X break;
- X#ifdef DOSUID
- X if (*validarg)
- X validarg = " PHOOEY ";
- X else
- X validarg = argv[0];
- X#endif
- X s = argv[0]+1;
- X reswitch:
- X switch (*s) {
- X case '0':
- X case 'a':
- X case 'c':
- X case 'd':
- X case 'D':
- X case 'i':
- X case 'l':
- X case 'n':
- X case 'p':
- X case 'u':
- X case 'U':
- X case 'v':
- X case 'w':
- X if (s = moreswitches(s))
- X goto reswitch;
- X break;
- X
- X case 'e':
- X#ifdef TAINT
- X if (euid != uid || egid != gid)
- X fatal("No -e allowed in setuid scripts");
- X#endif
- X if (!e_fp) {
- X e_tmpname = savestr(TMPPATH);
- X (void)mktemp(e_tmpname);
- X e_fp = fopen(e_tmpname,"w");
- X if (!e_fp)
- X fatal("Cannot open temporary file");
- X }
- X if (argv[1]) {
- X fputs(argv[1],e_fp);
- X argc--,argv++;
- X }
- X (void)putc('\n', e_fp);
- X break;
- X case 'I':
- X#ifdef TAINT
- X if (euid != uid || egid != gid)
- X fatal("No -I allowed in setuid scripts");
- X#endif
- X str_cat(str,"-");
- X str_cat(str,s);
- X str_cat(str," ");
- X if (*++s) {
- X (void)apush(stab_array(incstab),str_make(s,0));
- X }
- X else if (argv[1]) {
- X (void)apush(stab_array(incstab),str_make(argv[1],0));
- X str_cat(str,argv[1]);
- X argc--,argv++;
- X str_cat(str," ");
- X }
- X break;
- X case 'P':
- X#ifdef TAINT
- X if (euid != uid || egid != gid)
- X fatal("No -P allowed in setuid scripts");
- X#endif
- X preprocess = TRUE;
- X s++;
- X goto reswitch;
- X case 's':
- X#ifdef TAINT
- X if (euid != uid || egid != gid)
- X fatal("No -s allowed in setuid scripts");
- X#endif
- X doswitches = TRUE;
- X s++;
- X goto reswitch;
- X case 'S':
- X dosearch = TRUE;
- X s++;
- X goto reswitch;
- X case 'x':
- X doextract = TRUE;
- X s++;
- X if (*s)
- X cddir = savestr(s);
- X break;
- X case '-':
- X argc--,argv++;
- X goto switch_end;
- X case 0:
- X break;
- X default:
- X fatal("Unrecognized switch: -%s",s);
- X }
- X }
- X switch_end:
- X if (e_fp) {
- X (void)fclose(e_fp);
- X argc++,argv--;
- X argv[0] = e_tmpname;
- X }
- X
- X#ifdef MSDOS
- X#define PERLLIB_SEP ';'
- X#else
- X#define PERLLIB_SEP ':'
- X#endif
- X#ifndef TAINT /* Can't allow arbitrary PERLLIB in setuid script */
- X {
- X char * s2 = getenv("PERLLIB");
- X
- X if ( s2 ) {
- X /* Break at all separators */
- X while ( *s2 ) {
- X /* First, skip any consecutive separators */
- X while ( *s2 == PERLLIB_SEP ) {
- X /* Uncomment the next line for PATH semantics */
- X /* (void)apush(stab_array(incstab),str_make(".",1)); */
- X s2++;
- X }
- X if ( (s = index(s2,PERLLIB_SEP)) != Nullch ) {
- X (void)apush(stab_array(incstab),str_make(s2,(int)(s-s2)));
- X s2 = s+1;
- X } else {
- X (void)apush(stab_array(incstab),str_make(s2,0));
- X break;
- X }
- X }
- X }
- X }
- X#endif /* TAINT */
- X
- X#ifndef PRIVLIB
- X#define PRIVLIB "/usr/local/lib/perl"
- X#endif
- X (void)apush(stab_array(incstab),str_make(PRIVLIB,0));
- X (void)apush(stab_array(incstab),str_make(".",1));
- X
- X str_set(&str_no,No);
- X str_set(&str_yes,Yes);
- X
- X /* open script */
- X
- X if (argv[0] == Nullch)
- X#ifdef MSDOS
- X {
- X if ( isatty(fileno(stdin)) )
- X moreswitches("v");
- X argv[0] = "-";
- X }
- X#else
- X argv[0] = "-";
- X#endif
- X if (dosearch && !index(argv[0], '/') && (s = getenv("PATH"))) {
- X char *xfound = Nullch, *xfailed = Nullch;
- X int len;
- X
- X bufend = s + strlen(s);
- X while (*s) {
- X#ifndef MSDOS
- X s = cpytill(tokenbuf,s,bufend,':',&len);
- X#else
- X for (len = 0; *s && *s != ';'; tokenbuf[len++] = *s++);
- X tokenbuf[len] = '\0';
- X#endif
- X if (*s)
- X s++;
- X#ifndef MSDOS
- X if (len && tokenbuf[len-1] != '/')
- X#else
- X if (len && tokenbuf[len-1] != '\\')
- X#endif
- X (void)strcat(tokenbuf+len,"/");
- X (void)strcat(tokenbuf+len,argv[0]);
- X#ifdef DEBUGGING
- X if (debug & 1)
- X fprintf(stderr,"Looking for %s\n",tokenbuf);
- X#endif
- X if (stat(tokenbuf,&statbuf) < 0) /* not there? */
- X continue;
- X if (S_ISREG(statbuf.st_mode)
- X && cando(S_IRUSR,TRUE,&statbuf) && cando(S_IXUSR,TRUE,&statbuf)) {
- X xfound = tokenbuf; /* bingo! */
- X break;
- X }
- X if (!xfailed)
- X xfailed = savestr(tokenbuf);
- X }
- X if (!xfound)
- X fatal("Can't execute %s", xfailed ? xfailed : argv[0] );
- X if (xfailed)
- X Safefree(xfailed);
- X argv[0] = savestr(xfound);
- X }
- X
- X fdpid = anew(Nullstab); /* for remembering popen pids by fd */
- X pidstatus = hnew(COEFFSIZE);/* for remembering status of dead pids */
- X
- X origfilename = savestr(argv[0]);
- X curcmd->c_filestab = fstab(origfilename);
- X if (strEQ(origfilename,"-"))
- X argv[0] = "";
- X if (preprocess) {
- X str_cat(str,"-I");
- X str_cat(str,PRIVLIB);
- X (void)sprintf(buf, "\
- X%ssed %s -e '/^[^#]/b' \
- X -e '/^#[ ]*include[ ]/b' \
- X -e '/^#[ ]*define[ ]/b' \
- X -e '/^#[ ]*if[ ]/b' \
- X -e '/^#[ ]*ifdef[ ]/b' \
- X -e '/^#[ ]*ifndef[ ]/b' \
- X -e '/^#[ ]*else/b' \
- X -e '/^#[ ]*endif/b' \
- X -e 's/^#.*//' \
- X %s | %s -C %s %s",
- X#ifdef MSDOS
- X "",
- X#else
- X "/bin/",
- X#endif
- X (doextract ? "-e '1,/^#/d\n'" : ""),
- X argv[0], CPPSTDIN, str_get(str), CPPMINUS);
- X#ifdef DEBUGGING
- X if (debug & 64) {
- X fputs(buf,stderr);
- X fputs("\n",stderr);
- X }
- X#endif
- X doextract = FALSE;
- X#ifdef IAMSUID /* actually, this is caught earlier */
- X if (euid != uid && !euid) /* if running suidperl */
- X#ifdef HAS_SETEUID
- X (void)seteuid(uid); /* musn't stay setuid root */
- X#else
- X#ifdef HAS_SETREUID
- X (void)setreuid(-1, uid);
- X#else
- X setuid(uid);
- X#endif
- X#endif
- X#endif /* IAMSUID */
- X rsfp = mypopen(buf,"r");
- X }
- X else if (!*argv[0])
- X rsfp = stdin;
- X else
- X rsfp = fopen(argv[0],"r");
- X if (rsfp == Nullfp) {
- X#ifdef DOSUID
- X#ifndef IAMSUID /* in case script is not readable before setuid */
- X if (euid && stat(stab_val(curcmd->c_filestab)->str_ptr,&statbuf) >= 0 &&
- X statbuf.st_mode & (S_ISUID|S_ISGID)) {
- X (void)sprintf(buf, "%s/sperl%s", BIN, patchlevel);
- X execv(buf, origargv); /* try again */
- X fatal("Can't do setuid\n");
- X }
- X#endif
- X#endif
- X fatal("Can't open perl script \"%s\": %s\n",
- X stab_val(curcmd->c_filestab)->str_ptr, strerror(errno));
- X }
- X str_free(str); /* free -I directories */
- X str = Nullstr;
- X
- X /* do we need to emulate setuid on scripts? */
- X
- X /* This code is for those BSD systems that have setuid #! scripts disabled
- X * in the kernel because of a security problem. Merely defining DOSUID
- X * in perl will not fix that problem, but if you have disabled setuid
- X * scripts in the kernel, this will attempt to emulate setuid and setgid
- X * on scripts that have those now-otherwise-useless bits set. The setuid
- X * root version must be called suidperl or sperlN.NNN. If regular perl
- X * discovers that it has opened a setuid script, it calls suidperl with
- X * the same argv that it had. If suidperl finds that the script it has
- X * just opened is NOT setuid root, it sets the effective uid back to the
- X * uid. We don't just make perl setuid root because that loses the
- X * effective uid we had before invoking perl, if it was different from the
- X * uid.
- X *
- X * DOSUID must be defined in both perl and suidperl, and IAMSUID must
- X * be defined in suidperl only. suidperl must be setuid root. The
- X * Configure script will set this up for you if you want it.
- X *
- X * There is also the possibility of have a script which is running
- X * set-id due to a C wrapper. We want to do the TAINT checks
- X * on these set-id scripts, but don't want to have the overhead of
- X * them in normal perl, and can't use suidperl because it will lose
- X * the effective uid info, so we have an additional non-setuid root
- X * version called taintperl or tperlN.NNN that just does the TAINT checks.
- X */
- X
- X#ifdef DOSUID
- X if (fstat(fileno(rsfp),&statbuf) < 0) /* normal stat is insecure */
- X fatal("Can't stat script \"%s\"",origfilename);
- X if (statbuf.st_mode & (S_ISUID|S_ISGID)) {
- X int len;
- X
- X#ifdef IAMSUID
- X#ifndef HAS_SETREUID
- X /* On this access check to make sure the directories are readable,
- X * there is actually a small window that the user could use to make
- X * filename point to an accessible directory. So there is a faint
- X * chance that someone could execute a setuid script down in a
- X * non-accessible directory. I don't know what to do about that.
- X * But I don't think it's too important. The manual lies when
- X * it says access() is useful in setuid programs.
- X */
- X if (access(stab_val(curcmd->c_filestab)->str_ptr,1)) /*double check*/
- X fatal("Permission denied");
- X#else
- X /* If we can swap euid and uid, then we can determine access rights
- X * with a simple stat of the file, and then compare device and
- X * inode to make sure we did stat() on the same file we opened.
- X * Then we just have to make sure he or she can execute it.
- X */
- X {
- X struct stat tmpstatbuf;
- X
- X if (setreuid(euid,uid) < 0 || getuid() != euid || geteuid() != uid)
- X fatal("Can't swap uid and euid"); /* really paranoid */
- X if (stat(stab_val(curcmd->c_filestab)->str_ptr,&tmpstatbuf) < 0)
- X fatal("Permission denied"); /* testing full pathname here */
- X if (tmpstatbuf.st_dev != statbuf.st_dev ||
- X tmpstatbuf.st_ino != statbuf.st_ino) {
- X (void)fclose(rsfp);
- X if (rsfp = mypopen("/bin/mail root","w")) { /* heh, heh */
- X fprintf(rsfp,
- X"User %d tried to run dev %d ino %d in place of dev %d ino %d!\n\
- X(Filename of set-id script was %s, uid %d gid %d.)\n\nSincerely,\nperl\n",
- X uid,tmpstatbuf.st_dev, tmpstatbuf.st_ino,
- X statbuf.st_dev, statbuf.st_ino,
- X stab_val(curcmd->c_filestab)->str_ptr,
- X statbuf.st_uid, statbuf.st_gid);
- X (void)mypclose(rsfp);
- X }
- X fatal("Permission denied\n");
- X }
- X if (setreuid(uid,euid) < 0 || getuid() != uid || geteuid() != euid)
- X fatal("Can't reswap uid and euid");
- X if (!cando(S_IXUSR,FALSE,&statbuf)) /* can real uid exec? */
- X fatal("Permission denied\n");
- X }
- X#endif /* HAS_SETREUID */
- X#endif /* IAMSUID */
- X
- X if (!S_ISREG(statbuf.st_mode))
- X fatal("Permission denied");
- X if (statbuf.st_mode & S_IWOTH)
- X fatal("Setuid/gid script is writable by world");
- X doswitches = FALSE; /* -s is insecure in suid */
- X curcmd->c_line++;
- X if (fgets(tokenbuf,sizeof tokenbuf, rsfp) == Nullch ||
- X strnNE(tokenbuf,"#!",2) ) /* required even on Sys V */
- X fatal("No #! line");
- X s = tokenbuf+2;
- X if (*s == ' ') s++;
- X while (!isspace(*s)) s++;
- X if (strnNE(s-4,"perl",4) && strnNE(s-9,"perl",4)) /* sanity check */
- X fatal("Not a perl script");
- X while (*s == ' ' || *s == '\t') s++;
- X /*
- X * #! arg must be what we saw above. They can invoke it by
- X * mentioning suidperl explicitly, but they may not add any strange
- X * arguments beyond what #! says if they do invoke suidperl that way.
- X */
- X len = strlen(validarg);
- X if (strEQ(validarg," PHOOEY ") ||
- X strnNE(s,validarg,len) || !isspace(s[len]))
- X fatal("Args must match #! line");
- X
- X#ifndef IAMSUID
- X if (euid != uid && (statbuf.st_mode & S_ISUID) &&
- X euid == statbuf.st_uid)
- X if (!do_undump)
- X fatal("YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\
- XFIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
- X#endif /* IAMSUID */
- X
- X if (euid) { /* oops, we're not the setuid root perl */
- X (void)fclose(rsfp);
- X#ifndef IAMSUID
- X (void)sprintf(buf, "%s/sperl%s", BIN, patchlevel);
- X execv(buf, origargv); /* try again */
- X#endif
- X fatal("Can't do setuid\n");
- X }
- X
- X if (statbuf.st_mode & S_ISGID && statbuf.st_gid != egid)
- X#ifdef HAS_SETEGID
- X (void)setegid(statbuf.st_gid);
- X#else
- X#ifdef HAS_SETREGID
- X (void)setregid((GIDTYPE)-1,statbuf.st_gid);
- X#else
- X setgid(statbuf.st_gid);
- X#endif
- X#endif
- X if (statbuf.st_mode & S_ISUID) {
- X if (statbuf.st_uid != euid)
- X#ifdef HAS_SETEUID
- X (void)seteuid(statbuf.st_uid); /* all that for this */
- X#else
- X#ifdef HAS_SETREUID
- X (void)setreuid((UIDTYPE)-1,statbuf.st_uid);
- X#else
- X setuid(statbuf.st_uid);
- X#endif
- X#endif
- X }
- X else if (uid) /* oops, mustn't run as root */
- X#ifdef HAS_SETEUID
- X (void)seteuid((UIDTYPE)uid);
- X#else
- X#ifdef HAS_SETREUID
- X (void)setreuid((UIDTYPE)-1,(UIDTYPE)uid);
- X#else
- X setuid((UIDTYPE)uid);
- X#endif
- X#endif
- X uid = (int)getuid();
- X euid = (int)geteuid();
- X gid = (int)getgid();
- X egid = (int)getegid();
- X if (!cando(S_IXUSR,TRUE,&statbuf))
- X fatal("Permission denied\n"); /* they can't do this */
- X }
- X#ifdef IAMSUID
- X else if (preprocess)
- X fatal("-P not allowed for setuid/setgid script\n");
- X else
- X fatal("Script is not setuid/setgid in suidperl\n");
- X#else
- X#ifndef TAINT /* we aren't taintperl or suidperl */
- X /* script has a wrapper--can't run suidperl or we lose euid */
- X else if (euid != uid || egid != gid) {
- X (void)fclose(rsfp);
- X (void)sprintf(buf, "%s/tperl%s", BIN, patchlevel);
- X execv(buf, origargv); /* try again */
- X fatal("Can't run setuid script with taint checks");
- X }
- X#endif /* TAINT */
- X#endif /* IAMSUID */
- X#else /* !DOSUID */
- X#ifndef TAINT /* we aren't taintperl or suidperl */
- X if (euid != uid || egid != gid) { /* (suidperl doesn't exist, in fact) */
- X#ifndef SETUID_SCRIPTS_ARE_SECURE_NOW
- X fstat(fileno(rsfp),&statbuf); /* may be either wrapped or real suid */
- X if ((euid != uid && euid == statbuf.st_uid && statbuf.st_mode & S_ISUID)
- X ||
- X (egid != gid && egid == statbuf.st_gid && statbuf.st_mode & S_ISGID)
- X )
- X if (!do_undump)
- X fatal("YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\
- XFIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
- X#endif /* SETUID_SCRIPTS_ARE_SECURE_NOW */
- X /* not set-id, must be wrapped */
- X (void)fclose(rsfp);
- X (void)sprintf(buf, "%s/tperl%s", BIN, patchlevel);
- X execv(buf, origargv); /* try again */
- X fatal("Can't run setuid script with taint checks");
- X }
- X#endif /* TAINT */
- X#endif /* DOSUID */
- X
- X#if !defined(IAMSUID) && !defined(TAINT)
- X
- X /* skip forward in input to the real script? */
- X
- X while (doextract) {
- X if ((s = str_gets(linestr, rsfp, 0)) == Nullch)
- X fatal("No Perl script found in input\n");
- X if (*s == '#' && s[1] == '!' && instr(s,"perl")) {
- X ungetc('\n',rsfp); /* to keep line count right */
- X doextract = FALSE;
- X if (s = instr(s,"perl -")) {
- X s += 6;
- X while (s = moreswitches(s)) ;
- X }
- X if (cddir && chdir(cddir) < 0)
- X fatal("Can't chdir to %s",cddir);
- X }
- X }
- X#endif /* !defined(IAMSUID) && !defined(TAINT) */
- X
- X defstab = stabent("_",TRUE);
- X
- X if (perldb) {
- X debstash = hnew(0);
- X stab_xhash(stabent("_DB",TRUE)) = debstash;
- X curstash = debstash;
- X dbargs = stab_xarray(aadd((tmpstab = stabent("args",TRUE))));
- X tmpstab->str_pok |= SP_MULTI;
- X dbargs->ary_flags = 0;
- X subname = str_make("main",4);
- X DBstab = stabent("DB",TRUE);
- X DBstab->str_pok |= SP_MULTI;
- X DBline = stabent("dbline",TRUE);
- X DBline->str_pok |= SP_MULTI;
- X DBsub = hadd(tmpstab = stabent("sub",TRUE));
- X tmpstab->str_pok |= SP_MULTI;
- X DBsingle = stab_val((tmpstab = stabent("single",TRUE)));
- X tmpstab->str_pok |= SP_MULTI;
- X DBtrace = stab_val((tmpstab = stabent("trace",TRUE)));
- X tmpstab->str_pok |= SP_MULTI;
- X DBsignal = stab_val((tmpstab = stabent("signal",TRUE)));
- X tmpstab->str_pok |= SP_MULTI;
- X curstash = defstash;
- X }
- X
- X /* init tokener */
- X
- X bufend = bufptr = str_get(linestr);
- X
- X savestack = anew(Nullstab); /* for saving non-local values */
- X stack = anew(Nullstab); /* for saving non-local values */
- X stack->ary_flags = 0; /* not a real array */
- X afill(stack,63); afill(stack,-1); /* preextend stack */
- X afill(savestack,63); afill(savestack,-1);
- X
- X /* now parse the script */
- X
- X error_count = 0;
- X if (yyparse() || error_count) {
- X if (minus_c)
- X fatal("%s had compilation errors.\n", origfilename);
- X else {
- X fatal("Execution of %s aborted due to compilation errors.\n",
- X origfilename);
- X }
- X }
- X
- X New(50,loop_stack,128,struct loop);
- X#ifdef DEBUGGING
- X if (debug) {
- X New(51,debname,128,char);
- X New(52,debdelim,128,char);
- X }
- X#endif
- X curstash = defstash;
- X
- X preprocess = FALSE;
- X if (e_fp) {
- X e_fp = Nullfp;
- X (void)UNLINK(e_tmpname);
- X }
- X
- X /* initialize everything that won't change if we undump */
- X
- X if (sigstab = stabent("SIG",allstabs)) {
- X sigstab->str_pok |= SP_MULTI;
- X (void)hadd(sigstab);
- X }
- X
- X magicalize("!#?^~=-%.+&*()<>,\\/[|`':\004\t\024\027");
- X userinit(); /* in case linked C routines want magical variables */
- X
- X amperstab = stabent("&",allstabs);
- X leftstab = stabent("`",allstabs);
- X rightstab = stabent("'",allstabs);
- X sawampersand = (amperstab || leftstab || rightstab);
- X if (tmpstab = stabent(":",allstabs))
- X str_set(STAB_STR(tmpstab),chopset);
- X if (tmpstab = stabent("\024",allstabs))
- X time(&basetime);
- X
- X /* these aren't necessarily magical */
- X if (tmpstab = stabent(";",allstabs))
- X str_set(STAB_STR(tmpstab),"\034");
- X if (tmpstab = stabent("]",allstabs)) {
- X str = STAB_STR(tmpstab);
- X str_set(str,rcsid);
- X str->str_u.str_nval = atof(patchlevel);
- X str->str_nok = 1;
- X }
- X str_nset(stab_val(stabent("\"", TRUE)), " ", 1);
- X
- X stdinstab = stabent("STDIN",TRUE);
- X stdinstab->str_pok |= SP_MULTI;
- X stab_io(stdinstab) = stio_new();
- X stab_io(stdinstab)->ifp = stdin;
- X tmpstab = stabent("stdin",TRUE);
- X stab_io(tmpstab) = stab_io(stdinstab);
- X tmpstab->str_pok |= SP_MULTI;
- X
- X tmpstab = stabent("STDOUT",TRUE);
- X tmpstab->str_pok |= SP_MULTI;
- X stab_io(tmpstab) = stio_new();
- X stab_io(tmpstab)->ofp = stab_io(tmpstab)->ifp = stdout;
- X defoutstab = tmpstab;
- X tmpstab = stabent("stdout",TRUE);
- X stab_io(tmpstab) = stab_io(defoutstab);
- X tmpstab->str_pok |= SP_MULTI;
- X
- X curoutstab = stabent("STDERR",TRUE);
- X curoutstab->str_pok |= SP_MULTI;
- X stab_io(curoutstab) = stio_new();
- X stab_io(curoutstab)->ofp = stab_io(curoutstab)->ifp = stderr;
- X tmpstab = stabent("stderr",TRUE);
- X stab_io(tmpstab) = stab_io(curoutstab);
- X tmpstab->str_pok |= SP_MULTI;
- X curoutstab = defoutstab; /* switch back to STDOUT */
- X
- X statname = Str_new(66,0); /* last filename we did stat on */
- X
- X /* now that script is parsed, we can modify record separator */
- X
- X rs = nrs;
- X rslen = nrslen;
- X rschar = nrschar;
- X str_nset(stab_val(stabent("/", TRUE)), rs, rslen);
- X
- X if (do_undump)
- X my_unexec();
- X
- X just_doit: /* come here if running an undumped a.out */
- X argc--,argv++; /* skip name of script */
- X if (doswitches) {
- X for (; argc > 0 && **argv == '-'; argc--,argv++) {
- X if (argv[0][1] == '-') {
- X argc--,argv++;
- X break;
- X }
- X if (s = index(argv[0], '=')) {
- X *s++ = '\0';
- X str_set(stab_val(stabent(argv[0]+1,TRUE)),s);
- X }
- X else
- X str_numset(stab_val(stabent(argv[0]+1,TRUE)),(double)1.0);
- X }
- X }
- X#ifdef TAINT
- X tainted = 1;
- X#endif
- X if (tmpstab = stabent("0",allstabs)) {
- X str_set(stab_val(tmpstab),origfilename);
- X magicname("0", Nullch, 0);
- X }
- X if (tmpstab = stabent("\020",allstabs))
- X str_set(stab_val(tmpstab),origargv[0]);
- X if (argvstab = stabent("ARGV",allstabs)) {
- X argvstab->str_pok |= SP_MULTI;
- X (void)aadd(argvstab);
- X aclear(stab_array(argvstab));
- X for (; argc > 0; argc--,argv++) {
- X (void)apush(stab_array(argvstab),str_make(argv[0],0));
- X }
- X }
- X#ifdef TAINT
- X (void) stabent("ENV",TRUE); /* must test PATH and IFS */
- X#endif
- X if (envstab = stabent("ENV",allstabs)) {
- X envstab->str_pok |= SP_MULTI;
- X (void)hadd(envstab);
- X hclear(stab_hash(envstab), FALSE);
- X if (env != environ)
- X environ[0] = Nullch;
- X for (; *env; env++) {
- X if (!(s = index(*env,'=')))
- X continue;
- X *s++ = '\0';
- X str = str_make(s--,0);
- X str_magic(str, envstab, 'E', *env, s - *env);
- X (void)hstore(stab_hash(envstab), *env, s - *env, str, 0);
- X *s = '=';
- X }
- X }
- X#ifdef TAINT
- X tainted = 0;
- X#endif
- X if (tmpstab = stabent("$",allstabs))
- X str_numset(STAB_STR(tmpstab),(double)getpid());
- X
- X if (dowarn) {
- X stab_check('A','Z');
- X stab_check('a','z');
- X }
- X
- X if (setjmp(top_env)) /* sets goto_targ on longjump */
- X loop_ptr = -1; /* start label stack again */
- X
- X#ifdef DEBUGGING
- X if (debug & 1024)
- X dump_all();
- X if (debug)
- X fprintf(stderr,"\nEXECUTING...\n\n");
- X#endif
- X
- X if (minus_c) {
- X fprintf(stderr,"%s syntax OK\n", origfilename);
- X exit(0);
- X }
- X
- X /* do it */
- X
- X (void) cmd_exec(main_root,G_SCALAR,-1);
- X
- X if (goto_targ)
- X fatal("Can't find label \"%s\"--aborting",goto_targ);
- X exit(0);
- X /* NOTREACHED */
- X}
- X
- Xvoid
- Xmagicalize(list)
- Xregister char *list;
- X{
- X char sym[2];
- X
- X sym[1] = '\0';
- X while (*sym = *list++)
- X magicname(sym, Nullch, 0);
- X}
- X
- Xvoid
- Xmagicname(sym,name,namlen)
- Xchar *sym;
- Xchar *name;
- Xint namlen;
- X{
- X register STAB *stab;
- X
- X if (stab = stabent(sym,allstabs)) {
- X stab_flags(stab) = SF_VMAGIC;
- X str_magic(stab_val(stab), stab, 0, name, namlen);
- X }
- X}
- X
- X/* this routine is in perl.c by virtue of being sort of an alternate main() */
- X
- Xint
- Xdo_eval(str,optype,stash,gimme,arglast)
- XSTR *str;
- Xint optype;
- XHASH *stash;
- Xint gimme;
- Xint *arglast;
- X{
- X STR **st = stack->ary_array;
- X int retval;
- X CMD *myroot = Nullcmd;
- X ARRAY *ar;
- X int i;
- X CMD * VOLATILE oldcurcmd = curcmd;
- X VOLATILE int oldtmps_base = tmps_base;
- X VOLATILE int oldsave = savestack->ary_fill;
- X VOLATILE int oldperldb = perldb;
- X SPAT * VOLATILE oldspat = curspat;
- X SPAT * VOLATILE oldlspat = lastspat;
- X static char *last_eval = Nullch;
- X static CMD *last_root = Nullcmd;
- X VOLATILE int sp = arglast[0];
- X char *specfilename;
- X char *tmpfilename;
- X int parsing = 1;
- X
- X tmps_base = tmps_max;
- X if (curstash != stash) {
- X (void)savehptr(&curstash);
- X curstash = stash;
- X }
- X str_set(stab_val(stabent("@",TRUE)),"");
- X if (curcmd->c_line == 0) /* don't debug debugger... */
- X perldb = FALSE;
- X curcmd = &compiling;
- X if (optype == O_EVAL) { /* normal eval */
- X curcmd->c_filestab = fstab("(eval)");
- X curcmd->c_line = 1;
- X str_sset(linestr,str);
- X str_cat(linestr,";"); /* be kind to them */
- X }
- X else {
- X if (last_root && !in_eval) {
- X Safefree(last_eval);
- X last_eval = Nullch;
- X cmd_free(last_root);
- X last_root = Nullcmd;
- X }
- X specfilename = str_get(str);
- X str_set(linestr,"");
- X if (optype == O_REQUIRE && &str_undef !=
- X hfetch(stab_hash(incstab), specfilename, strlen(specfilename), 0)) {
- X curcmd = oldcurcmd;
- X tmps_base = oldtmps_base;
- X st[++sp] = &str_yes;
- X perldb = oldperldb;
- X return sp;
- X }
- X tmpfilename = savestr(specfilename);
- X if (index("/.", *tmpfilename))
- X rsfp = fopen(tmpfilename,"r");
- X else {
- X ar = stab_array(incstab);
- X for (i = 0; i <= ar->ary_fill; i++) {
- X (void)sprintf(buf, "%s/%s",
- X str_get(afetch(ar,i,TRUE)), specfilename);
- X rsfp = fopen(buf,"r");
- X if (rsfp) {
- X char *s = buf;
- X
- X if (*s == '.' && s[1] == '/')
- X s += 2;
- X Safefree(tmpfilename);
- X tmpfilename = savestr(s);
- X break;
- X }
- X }
- X }
- X curcmd->c_filestab = fstab(tmpfilename);
- X Safefree(tmpfilename);
- X tmpfilename = Nullch;
- X if (!rsfp) {
- X curcmd = oldcurcmd;
- X tmps_base = oldtmps_base;
- X if (optype == O_REQUIRE) {
- X sprintf(tokenbuf,"Can't locate %s in @INC", specfilename);
- X if (instr(tokenbuf,".h "))
- X strcat(tokenbuf," (change .h to .ph maybe?)");
- X if (instr(tokenbuf,".ph "))
- X strcat(tokenbuf," (did you run h2ph?)");
- X fatal("%s",tokenbuf);
- X }
- X if (gimme != G_ARRAY)
- X st[++sp] = &str_undef;
- X perldb = oldperldb;
- X return sp;
- X }
- X curcmd->c_line = 0;
- X }
- X in_eval++;
- X oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
- X bufend = bufptr + linestr->str_cur;
- X if (++loop_ptr >= loop_max) {
- X loop_max += 128;
- X Renew(loop_stack, loop_max, struct loop);
- X }
- X loop_stack[loop_ptr].loop_label = "_EVAL_";
- X loop_stack[loop_ptr].loop_sp = sp;
- X#ifdef DEBUGGING
- X if (debug & 4) {
- X deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
- X }
- X#endif
- X eval_root = Nullcmd;
- X if (setjmp(loop_stack[loop_ptr].loop_env)) {
- X retval = 1;
- X }
- X else {
- X error_count = 0;
- X if (rsfp) {
- X retval = yyparse();
- X retval |= error_count;
- X }
- X else if (last_root && *bufptr == *last_eval && strEQ(bufptr,last_eval)){
- X retval = 0;
- X eval_root = last_root; /* no point in reparsing */
- X }
- X else if (in_eval == 1) {
- X if (last_root) {
- X Safefree(last_eval);
- X last_eval = Nullch;
- X cmd_free(last_root);
- X }
- X last_root = Nullcmd;
- X last_eval = savestr(bufptr);
- X retval = yyparse();
- X retval |= error_count;
- X if (!retval)
- X last_root = eval_root;
- X if (!last_root) {
- X Safefree(last_eval);
- X last_eval = Nullch;
- X }
- X }
- X else
- X retval = yyparse();
- X }
- X myroot = eval_root; /* in case cmd_exec does another eval! */
- X
- X if (retval) {
- X st = stack->ary_array;
- X sp = arglast[0];
- X if (gimme != G_ARRAY)
- X st[++sp] = &str_undef;
- X if (parsing) {
- X#ifndef MANGLEDPARSE
- X#ifdef DEBUGGING
- X if (debug & 128)
- X fprintf(stderr,"Freeing eval_root %lx\n",(long)eval_root);
- X#endif
- X cmd_free(eval_root);
- X#endif
- X if (eval_root == last_root)
- X last_root = Nullcmd;
- X eval_root = myroot = Nullcmd;
- X }
- X if (rsfp) {
- X fclose(rsfp);
- X rsfp = 0;
- X }
- X }
- X else {
- X parsing = 0;
- X sp = cmd_exec(eval_root,gimme,sp);
- X st = stack->ary_array;
- X for (i = arglast[0] + 1; i <= sp; i++)
- X st[i] = str_mortal(st[i]);
- X /* if we don't save result, free zaps it */
- X if (in_eval != 1 && myroot != last_root)
- X cmd_free(myroot);
- X }
- X
- X perldb = oldperldb;
- X in_eval--;
- X#ifdef DEBUGGING
- X if (debug & 4) {
- X char *tmps = loop_stack[loop_ptr].loop_label;
- X deb("(Popping label #%d %s)\n",loop_ptr,
- X tmps ? tmps : "" );
- X }
- X#endif
- X loop_ptr--;
- X tmps_base = oldtmps_base;
- X curspat = oldspat;
- X lastspat = oldlspat;
- X if (savestack->ary_fill > oldsave) /* let them use local() */
- X restorelist(oldsave);
- X
- X if (optype != O_EVAL) {
- X if (retval) {
- X if (optype == O_REQUIRE)
- X fatal("%s", str_get(stab_val(stabent("@",TRUE))));
- X }
- X else {
- X curcmd = oldcurcmd;
- X if (gimme == G_SCALAR ? str_true(st[sp]) : sp > arglast[0]) {
- X (void)hstore(stab_hash(incstab), specfilename,
- X strlen(specfilename), str_smake(stab_val(curcmd->c_filestab)),
- X 0 );
- X }
- X else if (optype == O_REQUIRE)
- X fatal("%s did not return a true value", specfilename);
- X }
- X }
- X curcmd = oldcurcmd;
- X return sp;
- X}
- X
- X/* This routine handles any switches that can be given during run */
- X
- Xstatic char *
- Xmoreswitches(s)
- Xchar *s;
- X{
- X int numlen;
- X
- X reswitch:
- X switch (*s) {
- X case '0':
- X nrschar = scanoct(s, 4, &numlen);
- X nrs = nsavestr("\n",1);
- X *nrs = nrschar;
- X if (nrschar > 0377) {
- X nrslen = 0;
- X nrs = "";
- X }
- X else if (!nrschar && numlen >= 2) {
- X nrslen = 2;
- X nrs = "\n\n";
- X nrschar = '\n';
- X }
- X return s + numlen;
- X case 'a':
- X minus_a = TRUE;
- X s++;
- X return s;
- X case 'c':
- X minus_c = TRUE;
- X s++;
- X return s;
- X case 'd':
- X#ifdef TAINT
- X if (euid != uid || egid != gid)
- X fatal("No -d allowed in setuid scripts");
- X#endif
- X perldb = TRUE;
- X s++;
- X return s;
- X case 'D':
- X#ifdef DEBUGGING
- X#ifdef TAINT
- X if (euid != uid || egid != gid)
- X fatal("No -D allowed in setuid scripts");
- X#endif
- X debug = atoi(s+1) | 32768;
- X#else
- X warn("Recompile perl with -DDEBUGGING to use -D switch\n");
- X#endif
- X for (s++; isdigit(*s); s++) ;
- X return s;
- X case 'i':
- X inplace = savestr(s+1);
- X for (s = inplace; *s && !isspace(*s); s++) ;
- X *s = '\0';
- X break;
- X case 'I':
- X#ifdef TAINT
- X if (euid != uid || egid != gid)
- X fatal("No -I allowed in setuid scripts");
- X#endif
- X if (*++s) {
- X (void)apush(stab_array(incstab),str_make(s,0));
- X }
- X else
- X fatal("No space allowed after -I");
- X break;
- X case 'l':
- X minus_l = TRUE;
- X s++;
- X if (isdigit(*s)) {
- X ors = savestr("\n");
- X orslen = 1;
- X *ors = scanoct(s, 3 + (*s == '0'), &numlen);
- X s += numlen;
- X }
- X else {
- X ors = nsavestr(nrs,nrslen);
- X orslen = nrslen;
- X }
- X return s;
- X case 'n':
- X minus_n = TRUE;
- X s++;
- X return s;
- X case 'p':
- X minus_p = TRUE;
- X s++;
- X return s;
- X case 'u':
- X do_undump = TRUE;
- X s++;
- X return s;
- X case 'U':
- X unsafe = TRUE;
- X s++;
- X return s;
- X case 'v':
- X fputs("\nThis is perl, version 4.0\n\n",stdout);
- X fputs(rcsid,stdout);
- X fputs("\nCopyright (c) 1989, 1990, 1991, Larry Wall\n",stdout);
- X#ifdef MSDOS
- X fputs("MS-DOS port Copyright (c) 1989, 1990, Diomidis Spinellis\n",
- X stdout);
- X#ifdef OS2
- X fputs("OS/2 port Copyright (c) 1990, Raymond Chen, Kai Uwe Rommel\n",
- X stdout);
- X#endif
- X#endif
- X fputs("\n\
- XPerl may be copied only under the terms of the GNU General Public License,\n\
- Xa copy of which can be found with the Perl 4.0 distribution kit.\n",stdout);
- X#ifdef MSDOS
- X usage(origargv[0]);
- X#endif
- X exit(0);
- X case 'w':
- X dowarn = TRUE;
- X s++;
- X return s;
- X case ' ':
- X case '\n':
- X case '\t':
- X break;
- X default:
- X fatal("Switch meaningless after -x: -%s",s);
- X }
- X return Nullch;
- X}
- X
- X/* compliments of Tom Christiansen */
- X
- X/* unexec() can be found in the Gnu emacs distribution */
- X
- Xmy_unexec()
- X{
- X#ifdef UNEXEC
- X int status;
- X extern int etext;
- X static char dumpname[BUFSIZ];
- X static char perlpath[256];
- X
- X sprintf (dumpname, "%s.perldump", origfilename);
- X sprintf (perlpath, "%s/perl", BIN);
- X
- X status = unexec(dumpname, perlpath, &etext, sbrk(0), 0);
- X if (status)
- X fprintf(stderr, "unexec of %s into %s failed!\n", perlpath, dumpname);
- X exit(status);
- X#else
- X# ifndef SIGABRT
- X# define SIGABRT SIGILL
- X# endif
- X# ifndef SIGILL
- X# define SIGILL 6 /* blech */
- X# endif
- X kill(getpid(),SIGABRT); /* for use with undump */
- X#endif
- X}
- X
- !STUFFY!FUNK!
- echo Extracting emacs/perldb.pl
- sed >emacs/perldb.pl <<'!STUFFY!FUNK!' -e 's/X//'
- Xpackage DB;
- X
- X# modified Perl debugger, to be run from Emacs in perldb-mode
- X# Ray Lischner (uunet!mntgfx!lisch) as of 5 Nov 1990
- X
- X$header = '$Header: perldb.pl,v 4.0 91/03/20 01:18:58 lwall Locked $';
- X#
- X# This file is automatically included if you do perl -d.
- X# It's probably not useful to include this yourself.
- X#
- X# Perl supplies the values for @line and %sub. It effectively inserts
- X# a do DB'DB(<linenum>); in front of every place that can
- X# have a breakpoint. It also inserts a do 'perldb.pl' before the first line.
- X#
- X# $Log: perldb.pl,v $
- X# Revision 4.0 91/03/20 01:18:58 lwall
- X# 4.0 baseline.
- X#
- X# Revision 3.0.1.6 91/01/11 18:08:58 lwall
- X# patch42: @_ couldn't be accessed from debugger
- X#
- X# Revision 3.0.1.5 90/11/10 01:40:26 lwall
- X# patch38: the debugger wouldn't stop correctly or do action routines
- X#
- X# Revision 3.0.1.4 90/10/15 17:40:38 lwall
- X# patch29: added caller
- X# patch29: the debugger now understands packages and evals
- X# patch29: scripts now run at almost full speed under the debugger
- X# patch29: more variables are settable from debugger
- X#
- X# Revision 3.0.1.3 90/08/09 04:00:58 lwall
- X# patch19: debugger now allows continuation lines
- X# patch19: debugger can now dump lists of variables
- X# patch19: debugger can now add aliases easily from prompt
- X#
- X# Revision 3.0.1.2 90/03/12 16:39:39 lwall
- X# patch13: perl -d didn't format stack traces of *foo right
- X# patch13: perl -d wiped out scalar return values of subroutines
- X#
- X# Revision 3.0.1.1 89/10/26 23:14:02 lwall
- X# patch1: RCS expanded an unintended $Header in lib/perldb.pl
- X#
- X# Revision 3.0 89/10/18 15:19:46 lwall
- X# 3.0 baseline
- X#
- X# Revision 2.0 88/06/05 00:09:45 root
- X# Baseline version 2.0.
- X#
- X#
- X
- Xopen(IN, "</dev/tty") || open(IN, "<&STDIN"); # so we don't dingle stdin
- Xopen(OUT,">/dev/tty") || open(OUT, ">&STDOUT"); # so we don't dongle stdout
- Xselect(OUT);
- X$| = 1; # for DB'OUT
- Xselect(STDOUT);
- X$| = 1; # for real STDOUT
- X$sub = '';
- X
- X# Is Perl being run from Emacs?
- X$emacs = $main'ARGV[$[] eq '-emacs';
- Xshift(@main'ARGV) if $emacs;
- X
- X$header =~ s/.Header: ([^,]+),v(\s+\S+\s+\S+).*$/$1$2/;
- Xprint OUT "\nLoading DB routines from $header\n\nEnter h for help.\n\n";
- X
- Xsub DB {
- X &save;
- X ($package, $filename, $line) = caller;
- X $usercontext = '($@, $!, $[, $,, $/, $\) = @saved;' .
- X "package $package;"; # this won't let them modify, alas
- X local(*dbline) = "_<$filename";
- X $max = $#dbline;
- X if (($stop,$action) = split(/\0/,$dbline{$line})) {
- X if ($stop eq '1') {
- X $signal |= 1;
- X }
- X else {
- X $evalarg = "\$DB'signal |= do {$stop;}"; &eval;
- X $dbline{$line} =~ s/;9($|\0)/$1/;
- X }
- X }
- X if ($single || $trace || $signal) {
- X if ($emacs) {
- X print OUT "\032\032$filename:$line:0\n";
- X } else {
- X print OUT "$package'" unless $sub =~ /'/;
- X print OUT "$sub($filename:$line):\t",$dbline[$line];
- X for ($i = $line + 1; $i <= $max && $dbline[$i] == 0; ++$i) {
- X last if $dbline[$i] =~ /^\s*(}|#|\n)/;
- X print OUT "$sub($filename:$i):\t",$dbline[$i];
- X }
- X }
- X }
- X $evalarg = $action, &eval if $action;
- X if ($single || $signal) {
- X $evalarg = $pre, &eval if $pre;
- X print OUT $#stack . " levels deep in subroutine calls!\n"
- X if $single & 4;
- X $start = $line;
- X while ((print OUT " DB<", $#hist+1, "> "), $cmd=&gets) {
- X $single = 0;
- X $signal = 0;
- X $cmd eq '' && exit 0;
- X chop($cmd);
- X $cmd =~ s/\\$// && do {
- X print OUT " cont: ";
- X $cmd .= &gets;
- X redo;
- X };
- X $cmd =~ /^q$/ && exit 0;
- X $cmd =~ /^$/ && ($cmd = $laststep);
- X push(@hist,$cmd) if length($cmd) > 1;
- X ($i) = split(/\s+/,$cmd);
- X eval "\$cmd =~ $alias{$i}", print OUT $@ if $alias{$i};
- X $cmd =~ /^h$/ && do {
- X print OUT "
- XT Stack trace.
- Xs Single step.
- Xn Next, steps over subroutine calls.
- Xr Return from current subroutine.
- Xc [line] Continue; optionally inserts a one-time-only breakpoint
- X at the specified line.
- X<CR> Repeat last n or s.
- Xl min+incr List incr+1 lines starting at min.
- Xl min-max List lines.
- Xl line List line;
- Xl List next window.
- X- List previous window.
- Xw line List window around line.
- Xl subname List subroutine.
- Xf filename Switch to filename.
- X/pattern/ Search forwards for pattern; final / is optional.
- X?pattern? Search backwards for pattern.
- XL List breakpoints and actions.
- XS List subroutine names.
- Xt Toggle trace mode.
- Xb [line] [condition]
- X Set breakpoint; line defaults to the current execution line;
- X condition breaks if it evaluates to true, defaults to \'1\'.
- Xb subname [condition]
- X Set breakpoint at first line of subroutine.
- Xd [line] Delete breakpoint.
- XD Delete all breakpoints.
- Xa [line] command
- X Set an action to be done before the line is executed.
- X Sequence is: check for breakpoint, print line if necessary,
- X do action, prompt user if breakpoint or step, evaluate line.
- XA Delete all actions.
- XV [pkg [vars]] List some (default all) variables in package (default current).
- XX [vars] Same as \"V currentpackage [vars]\".
- X< command Define command before prompt.
- X| command Define command after prompt.
- X! number Redo command (default previous command).
- X! -number Redo number\'th to last command.
- XH -number Display last number commands (default all).
- Xq or ^D Quit.
- Xp expr Same as \"print DB'OUT expr\" in current package.
- X= [alias value] Define a command alias, or list current aliases.
- Xcommand Execute as a perl statement in current package.
- X
- X";
- X next; };
- X $cmd =~ /^t$/ && do {
- X $trace = !$trace;
- X print OUT "Trace = ".($trace?"on":"off")."\n";
- X next; };
- X $cmd =~ /^S$/ && do {
- X foreach $subname (sort(keys %sub)) {
- X print OUT $subname,"\n";
- X }
- X next; };
- X $cmd =~ s/^X\b/V $package/;
- X $cmd =~ /^V$/ && do {
- X $cmd = 'V $package'; };
- X $cmd =~ /^V\s*(\S+)\s*(.*)/ && do {
- X $packname = $1;
- X @vars = split(' ',$2);
- X do 'dumpvar.pl' unless defined &main'dumpvar;
- X if (defined &main'dumpvar) {
- X &main'dumpvar($packname,@vars);
- X }
- X else {
- X print DB'OUT "dumpvar.pl not available.\n";
- X }
- X next; };
- X $cmd =~ /^f\s*(.*)/ && do {
- X $file = $1;
- X if (!$file) {
- X print OUT "The old f command is now the r command.\n";
- X print OUT "The new f command switches filenames.\n";
- X next;
- X }
- X if (!defined $_main{'_<' . $file}) {
- X if (($try) = grep(m#^_<.*$file#, keys %_main)) {
- X $file = substr($try,2);
- X print "\n$file:\n";
- X }
- X }
- X if (!defined $_main{'_<' . $file}) {
- X print OUT "There's no code here anything matching $file.\n";
- X next;
- X }
- X elsif ($file ne $filename) {
- X *dbline = "_<$file";
- X $max = $#dbline;
- X $filename = $file;
- X $start = 1;
- X $cmd = "l";
- X } };
- X $cmd =~ /^l\s*(['A-Za-z_]['\w]*)/ && do {
- X $subname = $1;
- X $subname = "main'" . $subname unless $subname =~ /'/;
- X $subname = "main" . $subname if substr($subname,0,1) eq "'";
- X ($file,$subrange) = split(/:/,$sub{$subname});
- X if ($file ne $filename) {
- X *dbline = "_<$file";
- X $max = $#dbline;
- X $filename = $file;
- X }
- X if ($subrange) {
- X if (eval($subrange) < -$window) {
- X $subrange =~ s/-.*/+/;
- X }
- X $cmd = "l $subrange";
- X } else {
- X print OUT "Subroutine $1 not found.\n";
- X next;
- X } };
- X $cmd =~ /^w\s*(\d*)$/ && do {
- X $incr = $window - 1;
- X $start = $1 if $1;
- X $start -= $preview;
- X $cmd = 'l ' . $start . '-' . ($start + $incr); };
- X $cmd =~ /^-$/ && do {
- X $incr = $window - 1;
- X $cmd = 'l ' . ($start-$window*2) . '+'; };
- X $cmd =~ /^l$/ && do {
- X $incr = $window - 1;
- X $cmd = 'l ' . $start . '-' . ($start + $incr); };
- X $cmd =~ /^l\s*(\d*)\+(\d*)$/ && do {
- X $start = $1 if $1;
- X $incr = $2;
- X $incr = $window - 1 unless $incr;
- X $cmd = 'l ' . $start . '-' . ($start + $incr); };
- X $cmd =~ /^l\s*(([\d\$\.]+)([-,]([\d\$\.]+))?)?/ && do {
- X $end = (!$2) ? $max : ($4 ? $4 : $2);
- X $end = $max if $end > $max;
- X $i = $2;
- X $i = $line if $i eq '.';
- X $i = 1 if $i < 1;
- X if ($emacs) {
- X print OUT "\032\032$filename:$i:0\n";
- X $i = $end;
- X } else {
- X for (; $i <= $end; $i++) {
- X print OUT "$i:\t", $dbline[$i];
- X last if $signal;
- X }
- X }
- X $start = $i; # remember in case they want more
- X $start = $max if $start > $max;
- X next; };
- X $cmd =~ /^D$/ && do {
- X print OUT "Deleting all breakpoints...\n";
- X for ($i = 1; $i <= $max ; $i++) {
- X if (defined $dbline{$i}) {
- X $dbline{$i} =~ s/^[^\0]+//;
- X if ($dbline{$i} =~ s/^\0?$//) {
- X delete $dbline{$i};
- X }
- X }
- X }
- X next; };
- X $cmd =~ /^L$/ && do {
- X for ($i = 1; $i <= $max; $i++) {
- X if (defined $dbline{$i}) {
- X print OUT "$i:\t", $dbline[$i];
- X ($stop,$action) = split(/\0/, $dbline{$i});
- X print OUT " break if (", $stop, ")\n"
- X if $stop;
- X print OUT " action: ", $action, "\n"
- X if $action;
- X last if $signal;
- X }
- X }
- X next; };
- X $cmd =~ /^b\s*(['A-Za-z_]['\w]*)\s*(.*)/ && do {
- X $subname = $1;
- X $cond = $2 || '1';
- X $subname = "$package'" . $subname unless $subname =~ /'/;
- X $subname = "main" . $subname if substr($subname,0,1) eq "'";
- X ($filename,$i) = split(/[:-]/, $sub{$subname});
- X if ($i) {
- X *dbline = "_<$filename";
- X ++$i while $dbline[$i] == 0 && $i < $#dbline;
- X $dbline{$i} =~ s/^[^\0]*/$cond/;
- X } else {
- X print OUT "Subroutine $subname not found.\n";
- X }
- X next; };
- X $cmd =~ /^b\s*(\d*)\s*(.*)/ && do {
- X $i = ($1?$1:$line);
- X $cond = $2 || '1';
- X if ($dbline[$i] == 0) {
- X print OUT "Line $i not breakable.\n";
- X } else {
- X $dbline{$i} =~ s/^[^\0]*/$cond/;
- X }
- X next; };
- X $cmd =~ /^d\s*(\d+)?/ && do {
- X $i = ($1?$1:$line);
- X $dbline{$i} =~ s/^[^\0]*//;
- X delete $dbline{$i} if $dbline{$i} eq '';
- X next; };
- X $cmd =~ /^A$/ && do {
- X for ($i = 1; $i <= $max ; $i++) {
- X if (defined $dbline{$i}) {
- X $dbline{$i} =~ s/\0[^\0]*//;
- X delete $dbline{$i} if $dbline{$i} eq '';
- X }
- X }
- X next; };
- X $cmd =~ /^<\s*(.*)/ && do {
- X $pre = do action($1);
- X next; };
- X $cmd =~ /^>\s*(.*)/ && do {
- X $post = do action($1);
- X next; };
- X $cmd =~ /^a\s*(\d+)(\s+(.*))?/ && do {
- X $i = $1;
- X if ($dbline[$i] == 0) {
- X print OUT "Line $i may not have an action.\n";
- X } else {
- X $dbline{$i} =~ s/\0[^\0]*//;
- X $dbline{$i} .= "\0" . do action($3);
- X }
- X next; };
- X $cmd =~ /^n$/ && do {
- X $single = 2;
- X $laststep = $cmd;
- X last; };
- X $cmd =~ /^s$/ && do {
- X $single = 1;
- X $laststep = $cmd;
- X last; };
- X $cmd =~ /^c\s*(\d*)\s*$/ && do {
- X $i = $1;
- X if ($i) {
- X if ($dbline[$i] == 0) {
- X print OUT "Line $i not breakable.\n";
- X next;
- X }
- X $dbline{$i} =~ s/(\0|$)/;9$1/; # add one-time-only b.p.
- X }
- X for ($i=0; $i <= $#stack; ) {
- X $stack[$i++] &= ~1;
- X }
- X last; };
- X $cmd =~ /^r$/ && do {
- X $stack[$#stack] |= 2;
- X last; };
- X $cmd =~ /^T$/ && do {
- X local($p,$f,$l,$s,$h,$a,@a,@sub);
- X for ($i = 1; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
- X @a = @args;
- X for (@a) {
- X if (/^StB\000/ && length($_) == length($_main{'_main'})) {
- X $_ = sprintf("%s",$_);
- X }
- X else {
- X s/'/\\'/g;
- X s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
- X s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
- X s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
- X }
- X }
- X $w = $w ? '@ = ' : '$ = ';
- X $a = $h ? '(' . join(', ', @a) . ')' : '';
- X push(@sub, "$w&$s$a from file $f line $l\n");
- X last if $signal;
- X }
- X for ($i=0; $i <= $#sub; $i++) {
- X last if $signal;
- X print OUT $sub[$i];
- X }
- X next; };
- X $cmd =~ /^\/(.*)$/ && do {
- X $inpat = $1;
- X $inpat =~ s:([^\\])/$:$1:;
- X if ($inpat ne "") {
- X eval '$inpat =~ m'."\n$inpat\n";
- X if ($@ ne "") {
- X print OUT "$@";
- X next;
- X }
- X $pat = $inpat;
- X }
- X $end = $start;
- X eval '
- X for (;;) {
- X ++$start;
- X $start = 1 if ($start > $max);
- X last if ($start == $end);
- X if ($dbline[$start] =~ m'."\n$pat\n".'i) {
- X if ($emacs) {
- X print OUT "\032\032$filename:$start:0\n";
- X } else {
- X print OUT "$start:\t", $dbline[$start], "\n";
- X }
- X last;
- X }
- X } ';
- X print OUT "/$pat/: not found\n" if ($start == $end);
- X next; };
- X $cmd =~ /^\?(.*)$/ && do {
- X $inpat = $1;
- X $inpat =~ s:([^\\])\?$:$1:;
- X if ($inpat ne "") {
- X eval '$inpat =~ m'."\n$inpat\n";
- X if ($@ ne "") {
- X print OUT "$@";
- X next;
- X }
- X $pat = $inpat;
- X }
- X $end = $start;
- X eval '
- X for (;;) {
- X --$start;
- X $start = $max if ($start <= 0);
- X last if ($start == $end);
- X if ($dbline[$start] =~ m'."\n$pat\n".'i) {
- X if ($emacs) {
- X print OUT "\032\032$filename:$start:0\n";
- X } else {
- X print OUT "$start:\t", $dbline[$start], "\n";
- X }
- X last;
- X }
- X } ';
- X print OUT "?$pat?: not found\n" if ($start == $end);
- X next; };
- X $cmd =~ /^!+\s*(-)?(\d+)?$/ && do {
- X pop(@hist) if length($cmd) > 1;
- X $i = ($1?($#hist-($2?$2:1)):($2?$2:$#hist));
- X $cmd = $hist[$i] . "\n";
- X print OUT $cmd;
- X redo; };
- X $cmd =~ /^!(.+)$/ && do {
- X $pat = "^$1";
- X pop(@hist) if length($cmd) > 1;
- X for ($i = $#hist; $i; --$i) {
- X last if $hist[$i] =~ $pat;
- X }
- X if (!$i) {
- X print OUT "No such command!\n\n";
- X next;
- X }
- X $cmd = $hist[$i] . "\n";
- X print OUT $cmd;
- X redo; };
- X $cmd =~ /^H\s*(-(\d+))?/ && do {
- X $end = $2?($#hist-$2):0;
- X $hist = 0 if $hist < 0;
- X for ($i=$#hist; $i>$end; $i--) {
- X print OUT "$i: ",$hist[$i],"\n"
- X unless $hist[$i] =~ /^.?$/;
- X };
- X next; };
- X $cmd =~ s/^p( .*)?$/print DB'OUT$1/;
- X $cmd =~ /^=/ && do {
- X if (local($k,$v) = ($cmd =~ /^=\s*(\S+)\s+(.*)/)) {
- X $alias{$k}="s~$k~$v~";
- X print OUT "$k = $v\n";
- X } elsif ($cmd =~ /^=\s*$/) {
- X foreach $k (sort keys(%alias)) {
- X if (($v = $alias{$k}) =~ s~^s\~$k\~(.*)\~$~$1~) {
- X print OUT "$k = $v\n";
- X } else {
- X print OUT "$k\t$alias{$k}\n";
- X };
- X };
- X };
- X next; };
- X $evalarg = $cmd; &eval;
- X print OUT "\n";
- X }
- X if ($post) {
- X $evalarg = $post; &eval;
- X }
- X }
- X ($@, $!, $[, $,, $/, $\) = @saved;
- X}
- X
- Xsub save {
- X @saved = ($@, $!, $[, $,, $/, $\);
- X $[ = 0; $, = ""; $/ = "\n"; $\ = "";
- X}
- X
- X# The following takes its argument via $evalarg to preserve current @_
- X
- Xsub eval {
- X eval "$usercontext $evalarg; &DB'save";
- X print OUT $@;
- X}
- X
- Xsub action {
- X local($action) = @_;
- X while ($action =~ s/\\$//) {
- X print OUT "+ ";
- X $action .= &gets;
- X }
- X $action;
- X}
- X
- Xsub gets {
- X local($.);
- X <IN>;
- X}
- X
- Xsub catch {
- X $signal = 1;
- X}
- X
- Xsub sub {
- X push(@stack, $single);
- X $single &= 1;
- X $single |= 4 if $#stack == $deep;
- X if (wantarray) {
- X @i = &$sub;
- X $single |= pop(@stack);
- X @i;
- X }
- X else {
- X $i = &$sub;
- X $single |= pop(@stack);
- X $i;
- X }
- X}
- X
- X$single = 1; # so it stops on first executable statement
- X@hist = ('?');
- X$SIG{'INT'} = "DB'catch";
- X$deep = 100; # warning if stack gets this deep
- X$window = 10;
- X$preview = 3;
- X
- X@stack = (0);
- X@ARGS = @ARGV;
- Xfor (@args) {
- X s/'/\\'/g;
- X s/(.*)/'$1'/ unless /^-?[\d.]+$/;
- X}
- X
- Xif (-f '.perldb') {
- X do './.perldb';
- X}
- Xelsif (-f "$ENV{'LOGDIR'}/.perldb") {
- X do "$ENV{'LOGDIR'}/.perldb";
- X}
- Xelsif (-f "$ENV{'HOME'}/.perldb") {
- X do "$ENV{'HOME'}/.perldb";
- X}
- X
- X1;
- !STUFFY!FUNK!
- echo Extracting perlsh
- sed >perlsh <<'!STUFFY!FUNK!' -e 's/X//'
- X#!/usr/bin/perl
- X
- X# Poor man's perl shell.
- X
- X# Simply type two carriage returns every time you want to evaluate.
- X# Note that it must be a complete perl statement--don't type double
- X# carriage return in the middle of a loop.
- X
- X$/ = ''; # set paragraph mode
- X$SHlinesep = "\n";
- Xwhile ($SHcmd = <>) {
- X $/ = $SHlinesep;
- X eval $SHcmd; print $@ || "\n";
- X $SHlinesep = $/; $/ = '';
- X}
- !STUFFY!FUNK!
- echo " "
- echo "End of kit 16 (of 36)"
- cat /dev/null >kit16isdone
- run=''
- config=''
- for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36; do
- if test -f kit${iskit}isdone; then
- run="$run $iskit"
- else
- todo="$todo $iskit"
- fi
- done
- case $todo in
- '')
- echo "You have run all your kits. Please read README and then type Configure."
- for combo in *:AA; do
- if test -f "$combo"; then
- realfile=`basename $combo :AA`
- cat $realfile:[A-Z][A-Z] >$realfile
- rm -rf $realfile:[A-Z][A-Z]
- fi
- done
- rm -rf kit*isdone
- chmod 755 Configure
- ;;
- *) echo "You have run$run."
- echo "You still need to run$todo."
- ;;
- esac
- : Someone might mail this, so...
- exit
-
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-