perl 4.0.00: (no release announcement available)
[p5sagit/p5-mst-13.2.git] / perl.c
diff --git a/perly.c b/perl.c
similarity index 88%
rename from perly.c
rename to perl.c
index 87acead..6ea64ec 100644 (file)
--- a/perly.c
+++ b/perl.c
@@ -1,64 +1,13 @@
-char rcsid[] = "$Header: perly.c,v 3.0.1.10 91/01/11 18:22:48 lwall Locked $\nPatch level: ###\n";
+char rcsid[] = "$Header: perl.c,v 4.0 91/03/20 01:37:44 lwall Locked $\nPatch level: ###\n";
 /*
  *    Copyright (c) 1989, Larry Wall
  *
  *    You may distribute under the terms of the GNU General Public License
  *    as specified in the README file that comes with the perl 3.0 kit.
  *
- * $Log:       perly.c,v $
- * Revision 3.0.1.10  91/01/11  18:22:48  lwall
- * patch42: added -0 option
- * patch42: ANSIfied the stat mode checking
- * patch42: executables for multiple versions may now coexist
- * 
- * Revision 3.0.1.9  90/11/10  01:53:26  lwall
- * patch38: random cleanup
- * patch38: more msdos/os2 upgrades
- * patch38: references to $0 produced core dumps
- * patch38: added hooks for unexec()
- * 
- * Revision 3.0.1.8  90/10/16  10:14:20  lwall
- * patch29: *foo now prints as *package'foo
- * patch29: added waitpid
- * patch29: the debugger now understands packages and evals
- * patch29: added -M, -A and -C
- * patch29: -w sometimes printed spurious warnings about ARGV and ENV
- * patch29: require "./foo" didn't work right
- * patch29: require error messages referred to wrong file
- * 
- * Revision 3.0.1.7  90/08/13  22:22:22  lwall
- * patch28: defined(@array) and defined(%array) didn't work right
- * 
- * Revision 3.0.1.6  90/08/09  04:55:50  lwall
- * patch19: added -x switch to extract script from input trash
- * patch19: Added -c switch to do compilation only
- * patch19: added numeric interpretation of $]
- * patch19: added require operator
- * patch19: $0, %ENV, @ARGV were wrong in dumped script
- * patch19: . is now explicitly in @INC (and last)
- * 
- * Revision 3.0.1.5  90/03/27  16:20:57  lwall
- * patch16: MSDOS support
- * patch16: do FILE inside eval blows up
- * 
- * Revision 3.0.1.4  90/02/28  18:06:41  lwall
- * patch9: perl can now start up other interpreters scripts
- * patch9: nested evals clobbered their longjmp environment
- * patch9: eval could mistakenly return undef in array context
- * 
- * Revision 3.0.1.3  89/12/21  20:15:41  lwall
- * patch7: ANSI strerror() is now supported
- * patch7: errno may now be a macro with an lvalue
- * patch7: allowed setuid scripts to have a space after #!
- * 
- * Revision 3.0.1.2  89/11/17  15:34:42  lwall
- * patch5: fixed possible confusion about current effective gid
- * 
- * Revision 3.0.1.1  89/11/11  04:50:04  lwall
- * patch2: moved yydebug to where its type didn't matter
- * 
- * Revision 3.0  89/10/18  15:22:21  lwall
- * 3.0 baseline
+ * $Log:       perl.c,v $
+ * Revision 4.0  91/03/20  01:37:44  lwall
+ * 4.0 baseline.
  * 
  */
 
@@ -85,9 +34,14 @@ char rcsid[] = "$Header: perly.c,v 3.0.1.10 91/01/11 18:22:48 lwall Locked $\nPa
 
 static char* moreswitches();
 static char* cddir;
+#ifndef __STDC__
 extern char **environ;
+#endif /* ! __STDC__ */
 static bool minus_c;
 static char patchlevel[6];
+static char *nrs = "\n";
+static int nrschar = '\n';      /* final char of rs, or 0777 if none */
+static int nrslen = 1;
 
 main(argc,argv,env)
 register int argc;
@@ -112,11 +66,12 @@ setuid perl scripts securely.\n");
 
     origargv = argv;
     origargc = argc;
+    origenviron = environ;
     uid = (int)getuid();
     euid = (int)geteuid();
     gid = (int)getgid();
     egid = (int)getegid();
-    sprintf(patchlevel,"%3.3s%2.2d", rcsid+19, PATCHLEVEL);
+    sprintf(patchlevel,"%3.3s%2.2d", index(rcsid,'4'), PATCHLEVEL);
 #ifdef MSDOS
     /*
      * There is no way we can refer to them from Perl so close them to save
@@ -160,6 +115,7 @@ setuid perl scripts securely.\n");
        case 'd':
        case 'D':
        case 'i':
+       case 'l':
        case 'n':
        case 'p':
        case 'u':
@@ -247,6 +203,37 @@ setuid perl scripts securely.\n");
        argc++,argv--;
        argv[0] = e_tmpname;
     }
+
+#ifdef MSDOS
+#define PERLLIB_SEP ';'
+#else
+#define PERLLIB_SEP ':'
+#endif
+#ifndef TAINT          /* Can't allow arbitrary PERLLIB in setuid script */
+    {
+       char * s2 = getenv("PERLLIB");
+
+       if ( s2 ) {
+           /* Break at all separators */
+           while ( *s2 ) {
+               /* First, skip any consecutive separators */
+               while ( *s2 == PERLLIB_SEP ) {
+                   /* Uncomment the next line for PATH semantics */
+                   /* (void)apush(stab_array(incstab),str_make(".",1)); */
+                   s2++;
+               }
+               if ( (s = index(s2,PERLLIB_SEP)) != Nullch ) {
+                   (void)apush(stab_array(incstab),str_make(s2,(int)(s-s2)));
+                   s2 = s+1;
+               } else {
+                   (void)apush(stab_array(incstab),str_make(s2,0));
+                   break;
+               }
+           }
+       }
+    }
+#endif /* TAINT */
+
 #ifndef PRIVLIB
 #define PRIVLIB "/usr/local/lib/perl"
 #endif
@@ -347,10 +334,10 @@ setuid perl scripts securely.\n");
        doextract = FALSE;
 #ifdef IAMSUID                         /* actually, this is caught earlier */
        if (euid != uid && !euid)       /* if running suidperl */
-#ifdef SETEUID
+#ifdef HAS_SETEUID
            (void)seteuid(uid);         /* musn't stay setuid root */
 #else
-#ifdef SETREUID
+#ifdef HAS_SETREUID
            (void)setreuid(-1, uid);
 #else
            setuid(uid);
@@ -378,6 +365,7 @@ setuid perl scripts securely.\n");
          stab_val(curcmd->c_filestab)->str_ptr, strerror(errno));
     }
     str_free(str);             /* free -I directories */
+    str = Nullstr;
 
     /* do we need to emulate setuid on scripts? */
 
@@ -413,7 +401,7 @@ setuid perl scripts securely.\n");
        int len;
 
 #ifdef IAMSUID
-#ifndef SETREUID
+#ifndef HAS_SETREUID
        /* On this access check to make sure the directories are readable,
         * there is actually a small window that the user could use to make
         * filename point to an accessible directory.  So there is a faint
@@ -457,7 +445,7 @@ setuid perl scripts securely.\n");
            if (!cando(S_IXUSR,FALSE,&statbuf))         /* can real uid exec? */
                fatal("Permission denied\n");
        }
-#endif /* SETREUID */
+#endif /* HAS_SETREUID */
 #endif /* IAMSUID */
 
        if (!S_ISREG(statbuf.st_mode))
@@ -503,10 +491,10 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
        }
 
        if (statbuf.st_mode & S_ISGID && statbuf.st_gid != egid)
-#ifdef SETEGID
+#ifdef HAS_SETEGID
            (void)setegid(statbuf.st_gid);
 #else
-#ifdef SETREGID
+#ifdef HAS_SETREGID
            (void)setregid((GIDTYPE)-1,statbuf.st_gid);
 #else
            setgid(statbuf.st_gid);
@@ -514,10 +502,10 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
 #endif
        if (statbuf.st_mode & S_ISUID) {
            if (statbuf.st_uid != euid)
-#ifdef SETEUID
+#ifdef HAS_SETEUID
                (void)seteuid(statbuf.st_uid);  /* all that for this */
 #else
-#ifdef SETREUID
+#ifdef HAS_SETREUID
                (void)setreuid((UIDTYPE)-1,statbuf.st_uid);
 #else
                setuid(statbuf.st_uid);
@@ -525,10 +513,10 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
 #endif
        }
        else if (uid)                   /* oops, mustn't run as root */
-#ifdef SETEUID
+#ifdef HAS_SETEUID
            (void)seteuid((UIDTYPE)uid);
 #else
-#ifdef SETREUID
+#ifdef HAS_SETREUID
            (void)setreuid((UIDTYPE)-1,(UIDTYPE)uid);
 #else
            setuid((UIDTYPE)uid);
@@ -668,7 +656,7 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
        (void)hadd(sigstab);
     }
 
-    magicalize("!#?^~=-%123456789.+&*()<>,\\/[|`':\024");
+    magicalize("!#?^~=-%.+&*()<>,\\/[|`':\004\t\024\027");
     userinit();                /* in case linked C routines want magical variables */
 
     amperstab = stabent("&",allstabs);
@@ -719,6 +707,13 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
 
     statname = Str_new(66,0);          /* last filename we did stat on */
 
+    /* now that script is parsed, we can modify record separator */
+
+    rs = nrs;
+    rslen = nrslen;
+    rschar = nrschar;
+    str_nset(stab_val(stabent("/", TRUE)), rs, rslen);
+
     if (do_undump)
        my_unexec();
 
@@ -730,14 +725,23 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
                argc--,argv++;
                break;
            }
-           str_numset(stab_val(stabent(argv[0]+1,TRUE)),(double)1.0);
+           if (s = index(argv[0], '=')) {
+               *s++ = '\0';
+               str_set(stab_val(stabent(argv[0]+1,TRUE)),s);
+           }
+           else
+               str_numset(stab_val(stabent(argv[0]+1,TRUE)),(double)1.0);
        }
     }
 #ifdef TAINT
     tainted = 1;
 #endif
-    if (tmpstab = stabent("0",allstabs))
+    if (tmpstab = stabent("0",allstabs)) {
        str_set(stab_val(tmpstab),origfilename);
+       magicname("0", Nullch, 0);
+    }
+    if (tmpstab = stabent("\020",allstabs))
+       str_set(stab_val(tmpstab),origargv[0]);
     if (argvstab = stabent("ARGV",allstabs)) {
        argvstab->str_pok |= SP_MULTI;
        (void)aadd(argvstab);
@@ -801,6 +805,7 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
     /* NOTREACHED */
 }
 
+void
 magicalize(list)
 register char *list;
 {
@@ -811,7 +816,7 @@ register char *list;
        magicname(sym, Nullch, 0);
 }
 
-int
+void
 magicname(sym,name,namlen)
 char *sym;
 char *name;
@@ -825,7 +830,7 @@ int namlen;
     }
 }
 
-/* this routine is in perly.c by virtue of being sort of an alternate main() */
+/* this routine is in perl.c by virtue of being sort of an alternate main() */
 
 int
 do_eval(str,optype,stash,gimme,arglast)
@@ -837,7 +842,7 @@ int *arglast;
 {
     STR **st = stack->ary_array;
     int retval;
-    CMD *myroot;
+    CMD *myroot = Nullcmd;
     ARRAY *ar;
     int i;
     CMD * VOLATILE oldcurcmd = curcmd;
@@ -845,11 +850,13 @@ int *arglast;
     VOLATILE int oldsave = savestack->ary_fill;
     VOLATILE int oldperldb = perldb;
     SPAT * VOLATILE oldspat = curspat;
+    SPAT * VOLATILE oldlspat = lastspat;
     static char *last_eval = Nullch;
     static CMD *last_root = Nullcmd;
     VOLATILE int sp = arglast[0];
     char *specfilename;
     char *tmpfilename;
+    int parsing = 1;
 
     tmps_base = tmps_max;
     if (curstash != stash) {
@@ -869,6 +876,7 @@ int *arglast;
     else {
        if (last_root && !in_eval) {
            Safefree(last_eval);
+           last_eval = Nullch;
            cmd_free(last_root);
            last_root = Nullcmd;
        }
@@ -904,6 +912,7 @@ int *arglast;
        }
        curcmd->c_filestab = fstab(tmpfilename);
        Safefree(tmpfilename);
+       tmpfilename = Nullch;
        if (!rsfp) {
            curcmd = oldcurcmd;
            tmps_base = oldtmps_base;
@@ -936,9 +945,9 @@ int *arglast;
        deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
     }
 #endif
+    eval_root = Nullcmd;
     if (setjmp(loop_stack[loop_ptr].loop_env)) {
        retval = 1;
-       last_root = Nullcmd;
     }
     else {
        error_count = 0;
@@ -953,14 +962,19 @@ int *arglast;
        else if (in_eval == 1) {
            if (last_root) {
                Safefree(last_eval);
+               last_eval = Nullch;
                cmd_free(last_root);
            }
-           last_eval = savestr(bufptr);
            last_root = Nullcmd;
+           last_eval = savestr(bufptr);
            retval = yyparse();
            retval |= error_count;
            if (!retval)
                last_root = eval_root;
+           if (!last_root) {
+               Safefree(last_eval);
+               last_eval = Nullch;
+           }
        }
        else
            retval = yyparse();
@@ -972,17 +986,29 @@ int *arglast;
        sp = arglast[0];
        if (gimme != G_ARRAY)
            st[++sp] = &str_undef;
-       last_root = Nullcmd;    /* can't free on error, for some reason */
+       if (parsing) {
+#ifndef MANGLEDPARSE
+#ifdef DEBUGGING
+           if (debug & 128)
+               fprintf(stderr,"Freeing eval_root %lx\n",(long)eval_root);
+#endif
+           cmd_free(eval_root);
+#endif
+           if (eval_root == last_root)
+               last_root = Nullcmd;
+           eval_root = myroot = Nullcmd;
+       }
        if (rsfp) {
            fclose(rsfp);
            rsfp = 0;
        }
     }
     else {
+       parsing = 0;
        sp = cmd_exec(eval_root,gimme,sp);
        st = stack->ary_array;
        for (i = arglast[0] + 1; i <= sp; i++)
-           st[i] = str_static(st[i]);
+           st[i] = str_mortal(st[i]);
                                /* if we don't save result, free zaps it */
        if (in_eval != 1 && myroot != last_root)
            cmd_free(myroot);
@@ -1000,6 +1026,7 @@ int *arglast;
     loop_ptr--;
     tmps_base = oldtmps_base;
     curspat = oldspat;
+    lastspat = oldlspat;
     if (savestack->ary_fill > oldsave) /* let them use local() */
        restorelist(oldsave);
 
@@ -1029,17 +1056,24 @@ static char *
 moreswitches(s)
 char *s;
 {
+    int numlen;
+
   reswitch:
     switch (*s) {
     case '0':
-       record_separator = 0;
-       if (s[1] == '0' && !isdigit(s[2]))
-           rslen = 0;
-       while (*s >= '0' && *s <= '7') {
-           record_separator <<= 3;
-           record_separator += *s++ & 7;
+       nrschar = scanoct(s, 4, &numlen);
+       nrs = nsavestr("\n",1);
+       *nrs = nrschar;
+       if (nrschar > 0377) {
+           nrslen = 0;
+           nrs = "";
        }
-       return s;
+       else if (!nrschar && numlen >= 2) {
+           nrslen = 2;
+           nrs = "\n\n";
+           nrschar = '\n';
+       }
+       return s + numlen;
     case 'a':
        minus_a = TRUE;
        s++;
@@ -1062,16 +1096,16 @@ char *s;
        if (euid != uid || egid != gid)
            fatal("No -D allowed in setuid scripts");
 #endif
-       debug = atoi(s+1);
+       debug = atoi(s+1) | 32768;
 #else
        warn("Recompile perl with -DDEBUGGING to use -D switch\n");
 #endif
-       break;
+       for (s++; isdigit(*s); s++) ;
+       return s;
     case 'i':
        inplace = savestr(s+1);
        for (s = inplace; *s && !isspace(*s); s++) ;
        *s = '\0';
-       argvoutstab = stabent("ARGVOUT",TRUE);
        break;
     case 'I':
 #ifdef TAINT
@@ -1084,6 +1118,20 @@ char *s;
        else
            fatal("No space allowed after -I");
        break;
+    case 'l':
+       minus_l = TRUE;
+       s++;
+       if (isdigit(*s)) {
+           ors = savestr("\n");
+           orslen = 1;
+           *ors = scanoct(s, 3 + (*s == '0'), &numlen);
+           s += numlen;
+       }
+       else {
+           ors = nsavestr(nrs,nrslen);
+           orslen = nrslen;
+       }
+       return s;
     case 'n':
        minus_n = TRUE;
        s++;
@@ -1101,9 +1149,9 @@ char *s;
        s++;
        return s;
     case 'v':
-       fputs("\nThis is perl, version 3.0\n\n",stdout);
+       fputs("\nThis is perl, version 4.0\n\n",stdout);
        fputs(rcsid,stdout);
-       fputs("\nCopyright (c) 1989, 1990, Larry Wall\n",stdout);
+       fputs("\nCopyright (c) 1989, 1990, 1991, Larry Wall\n",stdout);
 #ifdef MSDOS
        fputs("MS-DOS port Copyright (c) 1989, 1990, Diomidis Spinellis\n",
        stdout);
@@ -1114,7 +1162,7 @@ char *s;
 #endif
        fputs("\n\
 Perl may be copied only under the terms of the GNU General Public License,\n\
-a copy of which can be found with the Perl 3.0 distribution kit.\n",stdout);
+a copy of which can be found with the Perl 4.0 distribution kit.\n",stdout);
 #ifdef MSDOS
         usage(origargv[0]);
 #endif
@@ -1153,7 +1201,13 @@ my_unexec()
        fprintf(stderr, "unexec of %s into %s failed!\n", perlpath, dumpname);
     exit(status);
 #else
-    abort();           /* for use with undump */
+#   ifndef SIGABRT
+#      define SIGABRT SIGILL
+#   endif
+#   ifndef SIGILL
+#      define SIGILL 6         /* blech */
+#   endif
+    kill(getpid(),SIGABRT);    /* for use with undump */
 #endif
 }