perl 3.0 patch #22 patch #19, continued
[p5sagit/p5-mst-13.2.git] / toke.c
diff --git a/toke.c b/toke.c
index 67376ed..40df16a 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -1,4 +1,4 @@
-/* $Header: toke.c,v 3.0.1.4 89/12/21 20:26:56 lwall Locked $
+/* $Header: toke.c,v 3.0.1.7 90/03/27 16:32:37 lwall Locked $
  *
  *    Copyright (c) 1989, Larry Wall
  *
@@ -6,6 +6,22 @@
  *    as specified in the README file that comes with the perl 3.0 kit.
  *
  * $Log:       toke.c,v $
+ * Revision 3.0.1.7  90/03/27  16:32:37  lwall
+ * patch16: MSDOS support
+ * patch16: formats didn't work inside eval
+ * patch16: final semicolon in program wasn't optional with -p or -n
+ * 
+ * Revision 3.0.1.6  90/03/12  17:06:36  lwall
+ * patch13: last semicolon of program is now optional, just for Randal
+ * patch13: added splice operator: @oldelems = splice(@array,$offset,$len,LIST)
+ * 
+ * Revision 3.0.1.5  90/02/28  18:47:06  lwall
+ * patch9: return grandfathered to never be function call
+ * patch9: non-existent perldb.pl now gives reasonable error message
+ * patch9: perl can now start up other interpreters scripts
+ * patch9: line numbers were bogus during certain portions of foreach evaluation
+ * patch9: null hereis core dumped
+ * 
  * Revision 3.0.1.4  89/12/21  20:26:56  lwall
  * patch7: -d switch incompatible with -p or -n
  * patch7: " ''$foo'' " didn't parse right
@@ -78,6 +94,8 @@ char *reparse;                /* if non-null, scanreg found ${foo[$bar]} */
 #define LOP(f) return(*s == '(' || (s = skipspace(s), *s == '(') ? \
        (*s = META('('), bufptr = oldbufptr, '(') : \
        (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
+/* grandfather return to old style */
+#define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
 
 char *
 skipspace(s)
@@ -171,7 +189,8 @@ yylex()
            if (minus_n || minus_p || perldb) {
                str_set(linestr,"");
                if (perldb)
-                   str_cat(linestr,"do 'perldb.pl'; print $@;");
+                   str_cat(linestr,
+"do 'perldb.pl' || die \"Can't find perldb.pl in @INC\"; print $@;");
                if (minus_n || minus_p) {
                    str_cat(linestr,"line: while (<>) {");
                    if (minus_a)
@@ -183,6 +202,7 @@ yylex()
            }
        }
        if (in_format) {
+           bufptr = bufend;
            yylval.formval = load_format();
            in_format = FALSE;
            oldoldbufptr = oldbufptr = s = str_get(linestr) + 1;
@@ -197,8 +217,8 @@ yylex()
                (void)fclose(rsfp);
            rsfp = Nullfp;
            if (minus_n || minus_p) {
-               str_set(linestr,minus_p ? "}continue{print;" : "");
-               str_cat(linestr,"}");
+               str_set(linestr,minus_p ? ";}continue{print" : "");
+               str_cat(linestr,";}");
                oldoldbufptr = oldbufptr = s = str_get(linestr);
                bufend = linestr->str_ptr + linestr->str_cur;
                minus_n = minus_p = 0;
@@ -206,7 +226,7 @@ yylex()
            }
            oldoldbufptr = oldbufptr = s = str_get(linestr);
            str_set(linestr,"");
-           RETURN(0);
+           RETURN(';');        /* not infinite loop because rsfp is NULL now */
        }
        oldoldbufptr = oldbufptr = bufptr = s;
        if (perldb) {
@@ -222,12 +242,42 @@ yylex()
        }
 #endif
        bufend = linestr->str_ptr + linestr->str_cur;
-       if (firstline) {
-           while (s < bufend && isspace(*s))
-               s++;
-           if (*s == ':')      /* for csh's that have to exec sh scripts */
-               s++;
-           firstline = FALSE;
+       if (line == 1) {
+           if (*s == '#' && s[1] == '!') {
+               if (!in_eval && !instr(s,"perl") && instr(origargv[0],"perl")) {
+                   char **newargv;
+                   char *cmd;
+
+                   s += 2;
+                   if (*s == ' ')
+                       s++;
+                   cmd = s;
+                   while (s < bufend && !isspace(*s))
+                       s++;
+                   *s++ = '\0';
+                   while (s < bufend && isspace(*s))
+                       s++;
+                   if (s < bufend) {
+                       Newz(899,newargv,origargc+3,char*);
+                       newargv[1] = s;
+                       while (s < bufend && !isspace(*s))
+                           s++;
+                       *s = '\0';
+                       Copy(origargv+1, newargv+2, origargc+1, char*);
+                   }
+                   else
+                       newargv = origargv;
+                   newargv[0] = cmd;
+                   execv(cmd,newargv);
+                   fatal("Can't exec %s", cmd);
+               }
+           }
+           else {
+               while (s < bufend && isspace(*s))
+                   s++;
+               if (*s == ':')  /* for csh's that have to exec sh scripts */
+                   s++;
+           }
        }
        goto retry;
     case ' ': case '\t': case '\f':
@@ -258,10 +308,16 @@ yylex()
            d = bufend;
            while (s < d && *s != '\n')
                s++;
-           if (s < d) {
+           if (s < d)
                s++;
-               line++;
+           if (in_format) {
+               bufptr = s;
+               yylval.formval = load_format();
+               in_format = FALSE;
+               oldoldbufptr = oldbufptr = s = bufptr + 1;
+               TERM(FORMLIST);
            }
+           line++;
        }
        else {
            *s = '\0';
@@ -512,6 +568,8 @@ yylex()
        SNARFWORD;
        if (strEQ(d,"bind"))
            FOP2(O_BIND);
+       if (strEQ(d,"binmode"))
+           FOP(O_BINMODE);
        break;
     case 'c': case 'C':
        SNARFWORD;
@@ -519,8 +577,10 @@ yylex()
            LFUN(O_CHOP);
        if (strEQ(d,"continue"))
            OPERATOR(CONTINUE);
-       if (strEQ(d,"chdir"))
+       if (strEQ(d,"chdir")) {
+           (void)stabent("ENV",TRUE);  /* may use HOME */
            UNI(O_CHDIR);
+       }
        if (strEQ(d,"close"))
            FOP(O_CLOSE);
        if (strEQ(d,"closedir"))
@@ -606,10 +666,10 @@ yylex()
        break;
     case 'f': case 'F':
        SNARFWORD;
-       if (strEQ(d,"for"))
-           OPERATOR(FOR);
-       if (strEQ(d,"foreach"))
+       if (strEQ(d,"for") || strEQ(d,"foreach")) {
+           yylval.ival = line;
            OPERATOR(FOR);
+       }
        if (strEQ(d,"format")) {
            d = bufend;
            while (s < d && isspace(*s))
@@ -819,6 +879,8 @@ yylex()
            FL2(O_PACK);
        if (strEQ(d,"package"))
            OPERATOR(PACKAGE);
+       if (strEQ(d,"pipe"))
+           FOP22(O_PIPE);
        break;
     case 'q': case 'Q':
        SNARFWORD;
@@ -834,7 +896,7 @@ yylex()
     case 'r': case 'R':
        SNARFWORD;
        if (strEQ(d,"return"))
-           LOP(O_RETURN);
+           OLDLOP(O_RETURN);
        if (strEQ(d,"reset"))
            UNI(O_RESET);
        if (strEQ(d,"redo"))
@@ -964,6 +1026,10 @@ yylex()
                TERM(SPLIT);
            if (strEQ(d,"sprintf"))
                FL(O_SPRINTF);
+           if (strEQ(d,"splice")) {
+               yylval.ival = O_SPLICE;
+               OPERATOR(PUSH);
+           }
            break;
        case 'q':
            if (strEQ(d,"sqrt"))
@@ -1483,7 +1549,8 @@ get_repl:
        tmpstr = spat->spat_repl[1].arg_ptr.arg_str;
        e = tmpstr->str_ptr + tmpstr->str_cur;
        for (t = tmpstr->str_ptr; t < e; t++) {
-           if (*t == '$' && t[1] && index("`'&+0123456789",t[1]))
+           if (*t == '$' && t[1] && (index("`'&+0123456789",t[1]) ||
+             (t[1] == '{' /*}*/ && isdigit(t[2])) ))
                spat->spat_flags &= ~SPAT_CONST;
        }
     }
@@ -1861,7 +1928,7 @@ register char *s;
                    term = tmps[5];
                multi_close = term;
            }
-           tmpstr = Str_new(87,0);
+           tmpstr = Str_new(87,80);
            if (hereis) {
                term = *tokenbuf;
                if (!rsfp) {
@@ -1946,7 +2013,7 @@ register char *s;
                if ((*s == '$' && s+1 < send &&
                    (alwaysdollar || /*(*/ (s[1] != ')' && s[1] != '|')) ) ||
                    (*s == '@' && s+1 < send) ) {
-                   len = scanreg(s,bufend,tokenbuf) - s;
+                   len = scanreg(s,send,tokenbuf) - s;
                    if (*s == '$' || strEQ(tokenbuf,"ARGV")
                      || strEQ(tokenbuf,"ENV")
                      || strEQ(tokenbuf,"SIG")
@@ -2021,6 +2088,7 @@ load_format()
 {
     FCMD froot;
     FCMD *flinebeg;
+    char *eol;
     register FCMD *fprev = &froot;
     register FCMD *fcmd;
     register char *s;
@@ -2030,7 +2098,8 @@ load_format()
     bool repeater;
 
     Zero(&froot, 1, FCMD);
-    while ((s = str_gets(linestr,rsfp, 0)) != Nullch) {
+    s = bufptr;
+    while (s < bufend || (s = str_gets(linestr,rsfp, 0)) != Nullch) {
        line++;
        if (perldb) {
            STR *tmpstr = Str_new(89,0);
@@ -2038,21 +2107,29 @@ load_format()
            str_sset(tmpstr,linestr);
            astore(lineary,(int)line,tmpstr);
        }
-       bufend = linestr->str_ptr + linestr->str_cur;
-       if (strEQ(s,".\n")) {
+       if (in_eval && !rsfp) {
+           eol = index(s,'\n');
+           if (!eol++)
+               eol = bufend;
+       }
+       else
+           eol = bufend = linestr->str_ptr + linestr->str_cur;
+       if (strnEQ(s,".\n",2)) {
            bufptr = s;
            return froot.f_next;
        }
-       if (*s == '#')
+       if (*s == '#') {
+           s = eol;
            continue;
+       }
        flinebeg = Nullfcmd;
        noblank = FALSE;
        repeater = FALSE;
-       while (s < bufend) {
+       while (s < eol) {
            Newz(804,fcmd,1,FCMD);
            fprev->f_next = fcmd;
            fprev = fcmd;
-           for (t=s; t < bufend && *t != '@' && *t != '^'; t++) {
+           for (t=s; t < eol && *t != '@' && *t != '^'; t++) {
                if (*t == '~') {
                    noblank = TRUE;
                    *t = ' ';
@@ -2065,7 +2142,7 @@ load_format()
            fcmd->f_pre = nsavestr(s, t-s);
            fcmd->f_presize = t-s;
            s = t;
-           if (s >= bufend) {
+           if (s >= eol) {
                if (noblank)
                    fcmd->f_flags |= FC_NOBLANK;
                if (repeater)
@@ -2109,7 +2186,7 @@ load_format()
        }
        if (flinebeg) {
          again:
-           if ((s = str_gets(linestr, rsfp, 0)) == Nullch)
+           if (s >= bufend && (s = str_gets(linestr, rsfp, 0)) == Nullch)
                goto badform;
            line++;
            if (perldb) {
@@ -2118,55 +2195,67 @@ load_format()
                str_sset(tmpstr,linestr);
                astore(lineary,(int)line,tmpstr);
            }
-           if (strEQ(s,".\n")) {
+           if (in_eval && !rsfp) {
+               eol = index(s,'\n');
+               if (!eol++)
+                   eol = bufend;
+           }
+           else
+               eol = bufend = linestr->str_ptr + linestr->str_cur;
+           if (strnEQ(s,".\n",2)) {
                bufptr = s;
                yyerror("Missing values line");
                return froot.f_next;
            }
-           if (*s == '#')
+           if (*s == '#') {
+               s = eol;
                goto again;
-           bufend = linestr->str_ptr + linestr->str_cur;
-           str = flinebeg->f_unparsed = Str_new(91,bufend - bufptr);
+           }
+           str = flinebeg->f_unparsed = Str_new(91,eol - s);
            str->str_u.str_hash = curstash;
            str_nset(str,"(",1);
            flinebeg->f_line = line;
-           if (!flinebeg->f_next->f_type || index(linestr->str_ptr, ',')) {
-               str_scat(str,linestr);
+           eol[-1] = '\0';
+           if (!flinebeg->f_next->f_type || index(s, ',')) {
+               eol[-1] = '\n';
+               str_ncat(str, s, eol - s - 1);
                str_ncat(str,",$$);",5);
+               s = eol;
            }
            else {
-               while (s < bufend && isspace(*s))
+               eol[-1] = '\n';
+               while (s < eol && isspace(*s))
                    s++;
                t = s;
-               while (s < bufend) {
+               while (s < eol) {
                    switch (*s) {
                    case ' ': case '\t': case '\n': case ';':
                        str_ncat(str, t, s - t);
                        str_ncat(str, "," ,1);
-                       while (s < bufend && (isspace(*s) || *s == ';'))
+                       while (s < eol && (isspace(*s) || *s == ';'))
                            s++;
                        t = s;
                        break;
                    case '$':
                        str_ncat(str, t, s - t);
                        t = s;
-                       s = scanreg(s,bufend,tokenbuf);
+                       s = scanreg(s,eol,tokenbuf);
                        str_ncat(str, t, s - t);
                        t = s;
-                       if (s < bufend && *s && index("$'\"",*s))
+                       if (s < eol && *s && index("$'\"",*s))
                            str_ncat(str, ",", 1);
                        break;
                    case '"': case '\'':
                        str_ncat(str, t, s - t);
                        t = s;
                        s++;
-                       while (s < bufend && (*s != *t || s[-1] == '\\'))
+                       while (s < eol && (*s != *t || s[-1] == '\\'))
                            s++;
-                       if (s < bufend)
+                       if (s < eol)
                            s++;
                        str_ncat(str, t, s - t);
                        t = s;
-                       if (s < bufend && *s && index("$'\"",*s))
+                       if (s < eol && *s && index("$'\"",*s))
                            str_ncat(str, ",", 1);
                        break;
                    default: