home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume30 / perl / patch33 < prev    next >
Text File  |  1992-06-11  |  46KB  |  1,850 lines

  1. Newsgroups: comp.sources.misc
  2. From: lwall@netlabs.com (Larry Wall)
  3. Subject:  v30i044:  perl - The perl programming language, Patch33
  4. Message-ID: <1992Jun11.181002.1679@sparky.imd.sterling.com>
  5. X-Md4-Signature: 439bcf7bec81c24f76aee025c9511c5f
  6. Date: Thu, 11 Jun 1992 18:10:02 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: lwall@netlabs.com (Larry Wall)
  10. Posting-number: Volume 30, Issue 44
  11. Archive-name: perl/patch33
  12. Environment: UNIX, MS-DOS, OS2
  13. Patch-To: perl: Volume 18, Issue 19-54
  14.  
  15. System: perl version 4.0
  16. Patch #: 33
  17. Priority: highish
  18. Subject: patch #20, continued
  19.  
  20. Description:
  21.     See patch #20.
  22.  
  23. Fix:    From rn, say "| patch -p -N -d DIR", where DIR is your perl source
  24.     directory.  Outside of rn, say "cd DIR; patch -p -N <thisarticle".
  25.     If you don't have the patch program, apply the following by hand,
  26.     or get patch (version 2.0, latest patchlevel).
  27.  
  28.     After patching:
  29.         Configure -d
  30.         make depend
  31.         make
  32.         make test
  33.         make install
  34.  
  35.     If patch indicates that patchlevel is the wrong version, you may need
  36.     to apply one or more previous patches, or the patch may already
  37.     have been applied.  See the patchlevel.h file to find out what has or
  38.     has not been applied.  In any event, don't continue with the patch.
  39.  
  40.     If you are missing previous patches they can be obtained from me:
  41.  
  42.     Larry Wall
  43.     lwall@netlabs.com
  44.  
  45.     If you send a mail message of the following form it will greatly speed
  46.     processing:
  47.  
  48.     Subject: Command
  49.     @SH mailpatch PATH perl 4.0 LIST
  50.            ^ note the c
  51.  
  52.     where PATH is a return path FROM ME TO YOU either in Internet notation,
  53.     or in bang notation from some well-known host, and LIST is the number
  54.     of one or more patches you need, separated by spaces, commas, and/or
  55.     hyphens.  Saying 35- says everything from 35 to the end.
  56.  
  57.  
  58. Index: patchlevel.h
  59. Prereq: 32
  60. 1c1
  61. < #define PATCHLEVEL 32
  62. ---
  63. > #define PATCHLEVEL 33
  64.  
  65. Index: toke.c
  66. *** toke.c.old    Mon Jun  8 17:52:16 1992
  67. --- toke.c    Mon Jun  8 17:52:17 1992
  68. ***************
  69. *** 1,4 ****
  70. ! /* $RCSfile: toke.c,v $$Revision: 4.0.1.5 $$Date: 91/11/11 16:45:51 $
  71.    *
  72.    *    Copyright (c) 1991, Larry Wall
  73.    *
  74. --- 1,4 ----
  75. ! /* $RCSfile: toke.c,v $$Revision: 4.0.1.6 $$Date: 92/06/08 16:03:49 $
  76.    *
  77.    *    Copyright (c) 1991, Larry Wall
  78.    *
  79. ***************
  80. *** 6,11 ****
  81. --- 6,24 ----
  82.    *    License or the Artistic License, as specified in the README file.
  83.    *
  84.    * $Log:    toke.c,v $
  85. +  * Revision 4.0.1.6  92/06/08  16:03:49  lwall
  86. +  * patch20: an EXPR may now start with a bareword
  87. +  * patch20: print $fh EXPR can now expect term rather than operator in EXPR
  88. +  * patch20: added ... as variant on ..
  89. +  * patch20: new warning on spurious backslash
  90. +  * patch20: new warning on missing $ for foreach variable
  91. +  * patch20: "foo"x1024 now legal without space after x
  92. +  * patch20: new warning on print accidentally used as function
  93. +  * patch20: tr/stuff// wasn't working right
  94. +  * patch20: 2. now eats the dot
  95. +  * patch20: <@ARGV> now notices @ARGV
  96. +  * patch20: tr/// now lets you say \-
  97. +  * 
  98.    * Revision 4.0.1.5  91/11/11  16:45:51  lwall
  99.    * patch19: default arg for shift was wrong after first subroutine definition
  100.    * 
  101. ***************
  102. *** 39,44 ****
  103. --- 52,59 ----
  104.   #include "perl.h"
  105.   #include "perly.h"
  106.   
  107. + static void set_csh();
  108.   #ifdef I_FCNTL
  109.   #include <fcntl.h>
  110.   #endif
  111. ***************
  112. *** 63,69 ****
  113. --- 78,88 ----
  114.   #endif
  115.   #define CLINE (cmdline = (curcmd->c_line < cmdline ? curcmd->c_line : cmdline))
  116.   
  117. + #ifdef atarist
  118. + #define PERL_META(c) ((c) | 128)
  119. + #else
  120.   #define META(c) ((c) | 128)
  121. + #endif
  122.   
  123.   #define RETURN(retval) return (bufptr = s,(int)retval)
  124.   #define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,(int)retval)
  125. ***************
  126. *** 93,110 ****
  127.   #define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
  128.   #define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
  129.   
  130.   /* This bit of chicanery makes a unary function followed by
  131.    * a parenthesis into a function with one argument, highest precedence.
  132.    */
  133. ! #define UNI(f) return(yylval.ival = f,expectterm = TRUE,bufptr = s, \
  134.       (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
  135.   
  136.   /* This does similarly for list operators, merely by pretending that the
  137.    * paren came before the listop rather than after.
  138.    */
  139.   #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
  140.       (*s = (char) META('('), bufptr = oldbufptr, '(') : \
  141.       (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
  142.   /* grandfather return to old style */
  143.   #define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
  144.   
  145. --- 112,140 ----
  146.   #define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
  147.   #define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
  148.   
  149. + static char *last_uni;
  150.   /* This bit of chicanery makes a unary function followed by
  151.    * a parenthesis into a function with one argument, highest precedence.
  152.    */
  153. ! #define UNI(f) return(yylval.ival = f, \
  154. !     expectterm = TRUE, \
  155. !     bufptr = s, \
  156. !     last_uni = oldbufptr, \
  157.       (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
  158.   
  159.   /* This does similarly for list operators, merely by pretending that the
  160.    * paren came before the listop rather than after.
  161.    */
  162. + #ifdef atarist
  163.   #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
  164. +     (*s = (char) PERL_META('('), bufptr = oldbufptr, '(') : \
  165. +     (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
  166. + #else
  167. + #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
  168.       (*s = (char) META('('), bufptr = oldbufptr, '(') : \
  169.       (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
  170. + #endif
  171.   /* grandfather return to old style */
  172.   #define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
  173.   
  174. ***************
  175. *** 117,122 ****
  176. --- 147,168 ----
  177.       return s;
  178.   }
  179.   
  180. + void
  181. + check_uni() {
  182. +     char *s;
  183. +     char ch;
  184. +     if (oldoldbufptr != last_uni)
  185. +     return;
  186. +     while (isSPACE(*last_uni))
  187. +     last_uni++;
  188. +     for (s = last_uni; isALNUM(*s); s++) ;
  189. +     ch = *s;
  190. +     *s = '\0';
  191. +     warn("Warning: Use of \"%s\" without parens is ambiguous", last_uni);
  192. +     *s = ch;
  193. + }
  194.   #ifdef CRIPPLED_CC
  195.   
  196.   #undef UNI
  197. ***************
  198. *** 132,137 ****
  199. --- 178,184 ----
  200.       yylval.ival = f;
  201.       expectterm = TRUE;
  202.       bufptr = s;
  203. +     last_uni = oldbufptr;
  204.       if (*s == '(')
  205.       return FUNC1;
  206.       s = skipspace(s);
  207. ***************
  208. *** 150,156 ****
  209. --- 197,207 ----
  210.       if (*s != '(')
  211.       s = skipspace(s);
  212.       if (*s == '(') {
  213. + #ifdef atarist
  214. +     *s = PERL_META('(');
  215. + #else
  216.       *s = META('(');
  217. + #endif
  218.       bufptr = oldbufptr;
  219.       return '(';
  220.       }
  221. ***************
  222. *** 164,169 ****
  223. --- 215,221 ----
  224.   
  225.   #endif /* CRIPPLED_CC */
  226.   
  227. + int
  228.   yylex()
  229.   {
  230.       register char *s = bufptr;
  231. ***************
  232. *** 190,195 ****
  233. --- 242,251 ----
  234.           *s++ = '(';
  235.           oldbufptr = s;
  236.       }
  237. +     else if ((*s & 127) == '}') {
  238. +         *s++ = '}';
  239. +         RETURN('}');
  240. +     }
  241.       else
  242.           warn("Unrecognized character \\%03o ignored", *s++ & 255);
  243.       goto retry;
  244. ***************
  245. *** 201,206 ****
  246. --- 257,266 ----
  247.           *s++ = '(';
  248.           oldbufptr = s;
  249.       }
  250. +     else if ((*s & 127) == '}') {
  251. +         *s++ = '}';
  252. +         RETURN('}');
  253. +     }
  254.       else
  255.           warn("Unrecognized character \\%03o ignored", *s++ & 255);
  256.       goto retry;
  257. ***************
  258. *** 212,217 ****
  259. --- 272,278 ----
  260.           RETURN(0);
  261.       if (s++ < bufend)
  262.           goto retry;            /* ignore stray nulls */
  263. +     last_uni = 0;
  264.       if (firstline) {
  265.           firstline = FALSE;
  266.           if (minus_n || minus_p || perldb) {
  267. ***************
  268. *** 413,420 ****
  269.           s++;
  270.           RETURN(DEC);
  271.       }
  272. !     if (expectterm)
  273.           OPERATOR('-');
  274.       else
  275.           AOP(O_SUBTRACT);
  276.       case '+':
  277. --- 474,484 ----
  278.           s++;
  279.           RETURN(DEC);
  280.       }
  281. !     if (expectterm) {
  282. !         if (isSPACE(*s) || !isSPACE(*bufptr))
  283. !         check_uni();
  284.           OPERATOR('-');
  285. +     }
  286.       else
  287.           AOP(O_SUBTRACT);
  288.       case '+':
  289. ***************
  290. *** 423,435 ****
  291.           s++;
  292.           RETURN(INC);
  293.       }
  294. !     if (expectterm)
  295.           OPERATOR('+');
  296.       else
  297.           AOP(O_ADD);
  298.   
  299.       case '*':
  300.       if (expectterm) {
  301.           s = scanident(s,bufend,tokenbuf);
  302.           yylval.stabval = stabent(tokenbuf,TRUE);
  303.           TERM(STAR);
  304. --- 487,503 ----
  305.           s++;
  306.           RETURN(INC);
  307.       }
  308. !     if (expectterm) {
  309. !         if (isSPACE(*s) || !isSPACE(*bufptr))
  310. !         check_uni();
  311.           OPERATOR('+');
  312. +     }
  313.       else
  314.           AOP(O_ADD);
  315.   
  316.       case '*':
  317.       if (expectterm) {
  318. +         check_uni();
  319.           s = scanident(s,bufend,tokenbuf);
  320.           yylval.stabval = stabent(tokenbuf,TRUE);
  321.           TERM(STAR);
  322. ***************
  323. *** 442,447 ****
  324. --- 510,517 ----
  325.       MOP(O_MULTIPLY);
  326.       case '%':
  327.       if (expectterm) {
  328. +         if (!isALPHA(s[1]))
  329. +         check_uni();
  330.           s = scanident(s,bufend,tokenbuf);
  331.           yylval.stabval = hadd(stabent(tokenbuf,TRUE));
  332.           TERM(HSH);
  333. ***************
  334. *** 473,480 ****
  335.       tmp = *s++;
  336.       TERM(tmp);
  337.       case '}':
  338. !     tmp = *s++;
  339. !     RETURN(tmp);
  340.       case '&':
  341.       s++;
  342.       tmp = *s++;
  343. --- 543,550 ----
  344.       tmp = *s++;
  345.       TERM(tmp);
  346.       case '}':
  347. !     *s |= 128;
  348. !     RETURN(';');
  349.       case '&':
  350.       s++;
  351.       tmp = *s++;
  352. ***************
  353. *** 487,492 ****
  354. --- 557,564 ----
  355.           s++;
  356.           if (isALPHA(*s) || *s == '_' || *s == '\'')
  357.           *(--s) = '\\';    /* force next ident to WORD */
  358. +         else
  359. +         check_uni();
  360.           OPERATOR(AMPER);
  361.       }
  362.       OPERATOR('&');
  363. ***************
  364. *** 517,523 ****
  365.       OPERATOR('!');
  366.       case '<':
  367.       if (expectterm) {
  368. !         s = scanstr(s);
  369.           TERM(RSTRING);
  370.       }
  371.       s++;
  372. --- 589,597 ----
  373.       OPERATOR('!');
  374.       case '<':
  375.       if (expectterm) {
  376. !         if (s[1] != '<' && !index(s,'>'))
  377. !         check_uni();
  378. !         s = scanstr(s, SCAN_DEF);
  379.           TERM(RSTRING);
  380.       }
  381.       s++;
  382. ***************
  383. *** 570,576 ****
  384.           goto retry;
  385.       }
  386.       yylval.stabval = stabent(tokenbuf,TRUE);
  387. !     TERM(REG);
  388.   
  389.       case '@':
  390.       d = s;
  391. --- 644,664 ----
  392.           goto retry;
  393.       }
  394.       yylval.stabval = stabent(tokenbuf,TRUE);
  395. !     expectterm = FALSE;
  396. !     if (isSPACE(*s) && oldoldbufptr && oldoldbufptr < bufptr) {
  397. !         s++;
  398. !         while (isSPACE(*oldoldbufptr))
  399. !         oldoldbufptr++;
  400. !         if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5)) {
  401. !         if (index("&*<%", *s) && isALPHA(s[1]))
  402. !             expectterm = TRUE;        /* e.g. print $fh &sub */
  403. !         else if (*s == '.' && isDIGIT(s[1]))
  404. !             expectterm = TRUE;        /* e.g. print $fh .3 */
  405. !         else if (index("/?-+", *s) && !isSPACE(s[1]))
  406. !             expectterm = TRUE;        /* e.g. print $fh -1 */
  407. !         }
  408. !     }
  409. !     RETURN(REG);
  410.   
  411.       case '@':
  412.       d = s;
  413. ***************
  414. *** 583,588 ****
  415. --- 671,677 ----
  416.       case '/':            /* may either be division or pattern */
  417.       case '?':            /* may either be conditional or pattern */
  418.       if (expectterm) {
  419. +         check_uni();
  420.           s = scanpat(s);
  421.           TERM(PATTERN);
  422.       }
  423. ***************
  424. *** 596,603 ****
  425. --- 685,700 ----
  426.           tmp = *s++;
  427.           if (*s == tmp) {
  428.           s++;
  429. +         if (*s == tmp) {
  430. +             s++;
  431. +             yylval.ival = 0;
  432. +         }
  433. +         else
  434. +             yylval.ival = AF_COMMON;
  435.           OPERATOR(DOTDOT);
  436.           }
  437. +         if (expectterm)
  438. +         check_uni();
  439.           AOP(O_CONCAT);
  440.       }
  441.       /* FALL THROUGH */
  442. ***************
  443. *** 604,614 ****
  444.       case '0': case '1': case '2': case '3': case '4':
  445.       case '5': case '6': case '7': case '8': case '9':
  446.       case '\'': case '"': case '`':
  447. !     s = scanstr(s);
  448.       TERM(RSTRING);
  449.   
  450.       case '\\':    /* some magic to force next word to be a WORD */
  451.       s++;    /* used by do and sub to force a separate namespace */
  452.       /* FALL THROUGH */
  453.       case '_':
  454.       SNARFWORD;
  455. --- 701,715 ----
  456.       case '0': case '1': case '2': case '3': case '4':
  457.       case '5': case '6': case '7': case '8': case '9':
  458.       case '\'': case '"': case '`':
  459. !     s = scanstr(s, SCAN_DEF);
  460.       TERM(RSTRING);
  461.   
  462.       case '\\':    /* some magic to force next word to be a WORD */
  463.       s++;    /* used by do and sub to force a separate namespace */
  464. +     if (!isALPHA(*s) && *s != '_' && *s != '\'') {
  465. +         warn("Spurious backslash ignored");
  466. +         goto retry;
  467. +     }
  468.       /* FALL THROUGH */
  469.       case '_':
  470.       SNARFWORD;
  471. ***************
  472. *** 627,640 ****
  473.           TERM(RSTRING);
  474.           }
  475.           else if (strEQ(d,"__END__")) {
  476. - #ifndef TAINT
  477.           STAB *stab;
  478.           int fd;
  479.   
  480.           /*SUPPRESS 560*/
  481. !         if (stab = stabent("DATA",FALSE)) {
  482.               stab->str_pok |= SP_MULTI;
  483. !             stab_io(stab) = stio_new();
  484.               stab_io(stab)->ifp = rsfp;
  485.   #if defined(HAS_FCNTL) && defined(F_SETFD)
  486.               fd = fileno(rsfp);
  487. --- 728,741 ----
  488.           TERM(RSTRING);
  489.           }
  490.           else if (strEQ(d,"__END__")) {
  491.           STAB *stab;
  492.           int fd;
  493.   
  494.           /*SUPPRESS 560*/
  495. !         if (!in_eval && (stab = stabent("DATA",FALSE))) {
  496.               stab->str_pok |= SP_MULTI;
  497. !             if (!stab_io(stab))
  498. !             stab_io(stab) = stio_new();
  499.               stab_io(stab)->ifp = rsfp;
  500.   #if defined(HAS_FCNTL) && defined(F_SETFD)
  501.               fd = fileno(rsfp);
  502. ***************
  503. *** 648,654 ****
  504.               stab_io(stab)->type = '<';
  505.               rsfp = Nullfp;
  506.           }
  507. - #endif
  508.           goto fake_eof;
  509.           }
  510.       }
  511. --- 749,754 ----
  512. ***************
  513. *** 773,778 ****
  514. --- 873,882 ----
  515.       SNARFWORD;
  516.       if (strEQ(d,"for") || strEQ(d,"foreach")) {
  517.           yylval.ival = curcmd->c_line;
  518. +         while (s < bufend && isSPACE(*s))
  519. +         s++;
  520. +         if (isALPHA(*s))
  521. +         fatal("Missing $ on loop variable");
  522.           OPERATOR(FOR);
  523.       }
  524.       if (strEQ(d,"format")) {
  525. ***************
  526. *** 981,991 ****
  527.       case 'p': case 'P':
  528.       SNARFWORD;
  529.       if (strEQ(d,"print")) {
  530. !         checkcomma(s,"filehandle");
  531.           LOP(O_PRINT);
  532.       }
  533.       if (strEQ(d,"printf")) {
  534. !         checkcomma(s,"filehandle");
  535.           LOP(O_PRTF);
  536.       }
  537.       if (strEQ(d,"push")) {
  538. --- 1085,1095 ----
  539.       case 'p': case 'P':
  540.       SNARFWORD;
  541.       if (strEQ(d,"print")) {
  542. !         checkcomma(s,d,"filehandle");
  543.           LOP(O_PRINT);
  544.       }
  545.       if (strEQ(d,"printf")) {
  546. !         checkcomma(s,d,"filehandle");
  547.           LOP(O_PRTF);
  548.       }
  549.       if (strEQ(d,"push")) {
  550. ***************
  551. *** 999,1018 ****
  552.       if (strEQ(d,"package"))
  553.           OPERATOR(PACKAGE);
  554.       if (strEQ(d,"pipe"))
  555. !         FOP22(O_PIPE);
  556.       break;
  557.       case 'q': case 'Q':
  558.       SNARFWORD;
  559.       if (strEQ(d,"q")) {
  560. !         s = scanstr(s-1);
  561.           TERM(RSTRING);
  562.       }
  563.       if (strEQ(d,"qq")) {
  564. !         s = scanstr(s-2);
  565.           TERM(RSTRING);
  566.       }
  567.       if (strEQ(d,"qx")) {
  568. !         s = scanstr(s-2);
  569.           TERM(RSTRING);
  570.       }
  571.       break;
  572. --- 1103,1122 ----
  573.       if (strEQ(d,"package"))
  574.           OPERATOR(PACKAGE);
  575.       if (strEQ(d,"pipe"))
  576. !         FOP22(O_PIPE_OP);
  577.       break;
  578.       case 'q': case 'Q':
  579.       SNARFWORD;
  580.       if (strEQ(d,"q")) {
  581. !         s = scanstr(s-1, SCAN_DEF);
  582.           TERM(RSTRING);
  583.       }
  584.       if (strEQ(d,"qq")) {
  585. !         s = scanstr(s-2, SCAN_DEF);
  586.           TERM(RSTRING);
  587.       }
  588.       if (strEQ(d,"qx")) {
  589. !         s = scanstr(s-2, SCAN_DEF);
  590.           TERM(RSTRING);
  591.       }
  592.       break;
  593. ***************
  594. *** 1145,1151 ****
  595.           if (strEQ(d,"socketpair"))
  596.           FOP25(O_SOCKPAIR);
  597.           if (strEQ(d,"sort")) {
  598. !         checkcomma(s,"subroutine name");
  599.           d = bufend;
  600.           while (s < d && isSPACE(*s)) s++;
  601.           if (*s == ';' || *s == ')')        /* probably a close */
  602. --- 1249,1255 ----
  603.           if (strEQ(d,"socketpair"))
  604.           FOP25(O_SOCKPAIR);
  605.           if (strEQ(d,"sort")) {
  606. !         checkcomma(s,d,"subroutine name");
  607.           d = bufend;
  608.           while (s < d && isSPACE(*s)) s++;
  609.           if (*s == ';' || *s == ')')        /* probably a close */
  610. ***************
  611. *** 1154,1159 ****
  612. --- 1258,1264 ----
  613.               /*SUPPRESS 530*/
  614.               for (d = s; isALNUM(*d); d++) ;
  615.               strncpy(tokenbuf,s,d-s);
  616. +             tokenbuf[d-s] = '\0';
  617.               if (strNE(tokenbuf,"keys") &&
  618.               strNE(tokenbuf,"values") &&
  619.               strNE(tokenbuf,"split") &&
  620. ***************
  621. *** 1324,1332 ****
  622.           FOP(O_WRITE);
  623.       break;
  624.       case 'x': case 'X':
  625. !     SNARFWORD;
  626. !     if (!expectterm && strEQ(d,"x"))
  627.           MOP(O_REPEAT);
  628.       break;
  629.       case 'y': case 'Y':
  630.       if (s[1] == '\'') {
  631. --- 1429,1444 ----
  632.           FOP(O_WRITE);
  633.       break;
  634.       case 'x': case 'X':
  635. !     if (*s == 'x' && isDIGIT(s[1]) && !expectterm) {
  636. !         s++;
  637.           MOP(O_REPEAT);
  638. +     }
  639. +     SNARFWORD;
  640. +     if (strEQ(d,"x")) {
  641. +         if (!expectterm)
  642. +         MOP(O_REPEAT);
  643. +         check_uni();
  644. +     }
  645.       break;
  646.       case 'y': case 'Y':
  647.       if (s[1] == '\'') {
  648. ***************
  649. *** 1346,1351 ****
  650. --- 1458,1472 ----
  651.       break;
  652.       }
  653.       yylval.cval = savestr(d);
  654. +     if (expectterm == 2) {        /* special case: start of statement */
  655. +     while (isSPACE(*s)) s++;
  656. +     if (*s == ':') {
  657. +         s++;
  658. +         CLINE;
  659. +         OPERATOR(LABEL);
  660. +     }
  661. +     TERM(WORD);
  662. +     }
  663.       expectterm = FALSE;
  664.       if (oldoldbufptr && oldoldbufptr < bufptr) {
  665.       while (isSPACE(*oldoldbufptr))
  666. ***************
  667. *** 1359,1376 ****
  668.   }
  669.   
  670.   void
  671. ! checkcomma(s,what)
  672.   register char *s;
  673.   char *what;
  674.   {
  675. !     char *someword;
  676.   
  677.       if (*s == '(')
  678.       s++;
  679.       while (s < bufend && isSPACE(*s))
  680.       s++;
  681.       if (isALPHA(*s) || *s == '_') {
  682. !     someword = s++;
  683.       while (isALNUM(*s))
  684.           s++;
  685.       while (s < bufend && isSPACE(*s))
  686. --- 1480,1507 ----
  687.   }
  688.   
  689.   void
  690. ! checkcomma(s,name,what)
  691.   register char *s;
  692. + char *name;
  693.   char *what;
  694.   {
  695. !     char *w;
  696.   
  697. +     if (dowarn && *s == ' ' && s[1] == '(') {
  698. +     w = index(s,')');
  699. +     if (w)
  700. +         for (w++; *w && isSPACE(*w); w++) ;
  701. +     if (!w || !*w || !index(";|}", *w))    /* an advisory hack only... */
  702. +         warn("%s (...) interpreted as function",name);
  703. +     }
  704. +     while (s < bufend && isSPACE(*s))
  705. +     s++;
  706.       if (*s == '(')
  707.       s++;
  708.       while (s < bufend && isSPACE(*s))
  709.       s++;
  710.       if (isALPHA(*s) || *s == '_') {
  711. !     w = s++;
  712.       while (isALNUM(*s))
  713.           s++;
  714.       while (s < bufend && isSPACE(*s))
  715. ***************
  716. *** 1377,1388 ****
  717.           s++;
  718.       if (*s == ',') {
  719.           *s = '\0';
  720. !         someword = instr(
  721.             "tell eof times getlogin wait length shift umask getppid \
  722.             cos exp int log rand sin sqrt ord wantarray",
  723. !           someword);
  724.           *s = ',';
  725. !         if (someword)
  726.           return;
  727.           fatal("No comma allowed after %s", what);
  728.       }
  729. --- 1508,1519 ----
  730.           s++;
  731.       if (*s == ',') {
  732.           *s = '\0';
  733. !         w = instr(
  734.             "tell eof times getlogin wait length shift umask getppid \
  735.             cos exp int log rand sin sqrt ord wantarray",
  736. !           w);
  737.           *s = ',';
  738. !         if (w)
  739.           return;
  740.           fatal("No comma allowed after %s", what);
  741.       }
  742. ***************
  743. *** 1492,1498 ****
  744.           e = d;
  745.           break;
  746.           }
  747. !         (void)bcopy(d+1,d,e-d);
  748.           e--;
  749.           switch(*d) {
  750.           case 'n':
  751. --- 1623,1629 ----
  752.           e = d;
  753.           break;
  754.           }
  755. !         Move(d+1,d,e-d,char);
  756.           e--;
  757.           switch(*d) {
  758.           case 'n':
  759. ***************
  760. *** 1626,1636 ****
  761.       }
  762.       }
  763.       if (spat->spat_flags & SPAT_FOLD)
  764. ! #ifdef STRUCTCOPY
  765. !     savespat = *spat;
  766. ! #else
  767. !     (void)bcopy((char *)spat, (char *)&savespat, sizeof(SPAT));
  768. ! #endif
  769.       scanconst(spat,str->str_ptr,len);
  770.       if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
  771.       fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  772. --- 1757,1763 ----
  773.       }
  774.       }
  775.       if (spat->spat_flags & SPAT_FOLD)
  776. !     StructCopy(spat, &savespat, SPAT);
  777.       scanconst(spat,str->str_ptr,len);
  778.       if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
  779.       fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  780. ***************
  781. *** 1642,1652 ****
  782.       }
  783.       else {
  784.       if (spat->spat_flags & SPAT_FOLD)
  785. ! #ifdef STRUCTCOPY
  786. !         *spat = savespat;
  787. ! #else
  788. !         (void)bcopy((char *)&savespat, (char *)spat, sizeof(SPAT));
  789. ! #endif
  790.       if (spat->spat_short)
  791.           fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  792.       spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  793. --- 1769,1775 ----
  794.       }
  795.       else {
  796.       if (spat->spat_flags & SPAT_FOLD)
  797. !     StructCopy(&savespat, spat, SPAT);
  798.       if (spat->spat_short)
  799.           fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  800.       spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  801. ***************
  802. *** 1660,1679 ****
  803.   }
  804.   
  805.   char *
  806. ! scansubst(s)
  807. ! register char *s;
  808.   {
  809.       register SPAT *spat;
  810.       register char *d;
  811.       register char *e;
  812.       int len;
  813.       STR *str = Str_new(93,0);
  814.   
  815.       Newz(802,spat,1,SPAT);
  816.       spat->spat_next = curstash->tbl_spatroot;    /* link into spat list */
  817.       curstash->tbl_spatroot = spat;
  818.   
  819. !     s = str_append_till(str,s+1,bufend,*s,patleave);
  820.       if (s >= bufend) {
  821.       str_free(str);
  822.       yyerror("Substitution pattern not terminated");
  823. --- 1783,1807 ----
  824.   }
  825.   
  826.   char *
  827. ! scansubst(start)
  828. ! char *start;
  829.   {
  830. +     register char *s = start;
  831.       register SPAT *spat;
  832.       register char *d;
  833.       register char *e;
  834.       int len;
  835.       STR *str = Str_new(93,0);
  836. +     char term = *s;
  837.   
  838. +     if (term && (d = index("([{< )]}> )]}>",term)))
  839. +     term = d[5];
  840.       Newz(802,spat,1,SPAT);
  841.       spat->spat_next = curstash->tbl_spatroot;    /* link into spat list */
  842.       curstash->tbl_spatroot = spat;
  843.   
  844. !     s = str_append_till(str,s+1,bufend,term,patleave);
  845.       if (s >= bufend) {
  846.       str_free(str);
  847.       yyerror("Substitution pattern not terminated");
  848. ***************
  849. *** 1712,1718 ****
  850.       }
  851.       scanconst(spat,str->str_ptr,len);
  852.   get_repl:
  853. !     s = scanstr(s);
  854.       if (s >= bufend) {
  855.       str_free(str);
  856.       yyerror("Substitution replacement not terminated");
  857. --- 1840,1848 ----
  858.       }
  859.       scanconst(spat,str->str_ptr,len);
  860.   get_repl:
  861. !     if (term != *start)
  862. !     s++;
  863. !     s = scanstr(s, SCAN_REPL);
  864.       if (s >= bufend) {
  865.       str_free(str);
  866.       yyerror("Substitution replacement not terminated");
  867. ***************
  868. *** 1736,1747 ****
  869.       }
  870.       }
  871.       while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
  872.       if (*s == 'e') {
  873.           s++;
  874.           if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
  875.           spat->spat_repl[1].arg_type = A_SINGLE;
  876.           spat->spat_repl = make_op(
  877. !         (spat->spat_repl[1].arg_type == A_SINGLE ? O_EVALONCE : O_EVAL),
  878.           2,
  879.           spat->spat_repl,
  880.           Nullarg,
  881. --- 1866,1882 ----
  882.       }
  883.       }
  884.       while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
  885. +     int es = 0;
  886.       if (*s == 'e') {
  887.           s++;
  888. +         es++;
  889.           if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
  890.           spat->spat_repl[1].arg_type = A_SINGLE;
  891.           spat->spat_repl = make_op(
  892. !         (!es && spat->spat_repl[1].arg_type == A_SINGLE
  893. !             ? O_EVALONCE
  894. !             : O_EVAL),
  895.           2,
  896.           spat->spat_repl,
  897.           Nullarg,
  898. ***************
  899. *** 1818,1853 ****
  900.   }
  901.   
  902.   char *
  903. ! expand_charset(s,len,retlen)
  904. ! register char *s;
  905. ! int len;
  906. ! int *retlen;
  907.   {
  908. !     char t[520];
  909. !     register char *d = t;
  910. !     register int i;
  911. !     register char *send = s + len;
  912. !     while (s < send && d - t <= 256) {
  913. !     if (s[1] == '-' && s+2 < send) {
  914. !         for (i = (s[0] & 0377); i <= (s[2] & 0377); i++)
  915. !         *d++ = i;
  916. !         s += 3;
  917. !     }
  918. !     else
  919. !         *d++ = *s++;
  920. !     }
  921. !     *d = '\0';
  922. !     *retlen = d - t;
  923. !     return nsavestr(t,d-t);
  924. ! }
  925. ! char *
  926. ! scantrans(s)
  927. ! register char *s;
  928. ! {
  929.       ARG *arg =
  930.       l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
  931.       register char *t;
  932.       register char *r;
  933.       register short *tbl;
  934. --- 1953,1966 ----
  935.   }
  936.   
  937.   char *
  938. ! scantrans(start)
  939. ! char *start;
  940.   {
  941. !     register char *s = start;
  942.       ARG *arg =
  943.       l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
  944. +     STR *tstr;
  945. +     STR *rstr;
  946.       register char *t;
  947.       register char *r;
  948.       register short *tbl;
  949. ***************
  950. *** 1861,1881 ****
  951.       New(803,tbl,256,short);
  952.       arg[2].arg_type = A_NULL;
  953.       arg[2].arg_ptr.arg_cval = (char*) tbl;
  954. !     s = scanstr(s);
  955.       if (s >= bufend) {
  956.       yyerror("Translation pattern not terminated");
  957.       yylval.arg = Nullarg;
  958.       return s;
  959.       }
  960. !     t = expand_charset(yylval.arg[1].arg_ptr.arg_str->str_ptr,
  961. !     yylval.arg[1].arg_ptr.arg_str->str_cur,&tlen);
  962.       arg_free(yylval.arg);
  963. !     s = scanstr(s-1);
  964.       if (s >= bufend) {
  965.       yyerror("Translation replacement not terminated");
  966.       yylval.arg = Nullarg;
  967.       return s;
  968.       }
  969.       complement = delete = squash = 0;
  970.       while (*s == 'c' || *s == 'd' || *s == 's') {
  971.       if (*s == 'c')
  972. --- 1974,2007 ----
  973.       New(803,tbl,256,short);
  974.       arg[2].arg_type = A_NULL;
  975.       arg[2].arg_ptr.arg_cval = (char*) tbl;
  976. !     s = scanstr(s, SCAN_TR);
  977.       if (s >= bufend) {
  978.       yyerror("Translation pattern not terminated");
  979.       yylval.arg = Nullarg;
  980.       return s;
  981.       }
  982. !     tstr = yylval.arg[1].arg_ptr.arg_str; 
  983. !     yylval.arg[1].arg_ptr.arg_str = Nullstr; 
  984.       arg_free(yylval.arg);
  985. !     t = tstr->str_ptr;
  986. !     tlen = tstr->str_cur;
  987. !     if (s[-1] == *start)
  988. !     s--;
  989. !     s = scanstr(s, SCAN_TR|SCAN_REPL);
  990.       if (s >= bufend) {
  991.       yyerror("Translation replacement not terminated");
  992.       yylval.arg = Nullarg;
  993.       return s;
  994.       }
  995. +     rstr = yylval.arg[1].arg_ptr.arg_str; 
  996. +     yylval.arg[1].arg_ptr.arg_str = Nullstr; 
  997. +     arg_free(yylval.arg);
  998. +     r = rstr->str_ptr;
  999. +     rlen = rstr->str_cur;
  1000.       complement = delete = squash = 0;
  1001.       while (*s == 'c' || *s == 'd' || *s == 's') {
  1002.       if (*s == 'c')
  1003. ***************
  1004. *** 1886,1900 ****
  1005.           squash = 1;
  1006.       s++;
  1007.       }
  1008. -     r = expand_charset(yylval.arg[1].arg_ptr.arg_str->str_ptr,
  1009. -     yylval.arg[1].arg_ptr.arg_str->str_cur,&rlen);
  1010. -     arg_free(yylval.arg);
  1011.       arg[2].arg_len = delete|squash;
  1012.       yylval.arg = arg;
  1013. -     if (!rlen && !delete) {
  1014. -     Safefree(r);
  1015. -     r = t; rlen = tlen;
  1016. -     }
  1017.       if (complement) {
  1018.       Zero(tbl, 256, short);
  1019.       for (i = 0; i < tlen; i++)
  1020. --- 2012,2019 ----
  1021. ***************
  1022. *** 1904,1918 ****
  1023.           if (j >= rlen) {
  1024.               if (delete)
  1025.               tbl[i] = -2;
  1026.               else
  1027. !             tbl[i] = r[j-1];
  1028.           }
  1029.           else
  1030. !             tbl[i] = r[j++];
  1031.           }
  1032.       }
  1033.       }
  1034.       else {
  1035.       for (i = 0; i < 256; i++)
  1036.           tbl[i] = -1;
  1037.       for (i = 0, j = 0; i < tlen; i++,j++) {
  1038. --- 2023,2042 ----
  1039.           if (j >= rlen) {
  1040.               if (delete)
  1041.               tbl[i] = -2;
  1042. +             else if (rlen)
  1043. +             tbl[i] = r[j-1] & 0377;
  1044.               else
  1045. !             tbl[i] = i;
  1046.           }
  1047.           else
  1048. !             tbl[i] = r[j++] & 0377;
  1049.           }
  1050.       }
  1051.       }
  1052.       else {
  1053. +     if (!rlen && !delete) {
  1054. +         r = t; rlen = tlen;
  1055. +     }
  1056.       for (i = 0; i < 256; i++)
  1057.           tbl[i] = -1;
  1058.       for (i = 0, j = 0; i < tlen; i++,j++) {
  1059. ***************
  1060. *** 1928,1943 ****
  1061.           tbl[t[i] & 0377] = r[j] & 0377;
  1062.       }
  1063.       }
  1064. !     if (r != t)
  1065. !     Safefree(r);
  1066. !     Safefree(t);
  1067.       return s;
  1068.   }
  1069.   
  1070.   char *
  1071. ! scanstr(s)
  1072. ! register char *s;
  1073.   {
  1074.       register char term;
  1075.       register char *d;
  1076.       register ARG *arg;
  1077. --- 2052,2068 ----
  1078.           tbl[t[i] & 0377] = r[j] & 0377;
  1079.       }
  1080.       }
  1081. !     str_free(tstr);
  1082. !     str_free(rstr);
  1083.       return s;
  1084.   }
  1085.   
  1086.   char *
  1087. ! scanstr(start, in_what)
  1088. ! char *start;
  1089. ! int in_what;
  1090.   {
  1091. +     register char *s = start;
  1092.       register char term;
  1093.       register char *d;
  1094.       register ARG *arg;
  1095. ***************
  1096. *** 1948,1954 ****
  1097.       bool hereis = FALSE;
  1098.       STR *herewas;
  1099.       STR *str;
  1100. !     char *leave = "\\$@nrtfbeacx0123456789[{]}lLuUE"; /* which backslash sequences to keep */
  1101.       int len;
  1102.   
  1103.       arg = op_new(1);
  1104. --- 2073,2082 ----
  1105.       bool hereis = FALSE;
  1106.       STR *herewas;
  1107.       STR *str;
  1108. !     /* which backslash sequences to keep */
  1109. !     char *leave = (in_what & SCAN_TR)
  1110. !     ? "\\$@nrtfbeacx0123456789-"
  1111. !     : "\\$@nrtfbeacx0123456789[{]}lLuUE";
  1112.       int len;
  1113.   
  1114.       arg = op_new(1);
  1115. ***************
  1116. *** 2025,2031 ****
  1117.           else
  1118.           *d++ = *s++;
  1119.       }
  1120. !     if (*s == '.' && s[1] && index("0123456789eE ;",s[1])) {
  1121.           *d++ = *s++;
  1122.           while (isDIGIT(*s) || *s == '_') {
  1123.           if (*s == '_')
  1124. --- 2153,2159 ----
  1125.           else
  1126.           *d++ = *s++;
  1127.       }
  1128. !     if (*s == '.' && s[1] != '.') {
  1129.           *d++ = *s++;
  1130.           while (isDIGIT(*s) || *s == '_') {
  1131.           if (*s == '_')
  1132. ***************
  1133. *** 2052,2057 ****
  1134. --- 2180,2187 ----
  1135.       arg[1].arg_ptr.arg_str = str;
  1136.       break;
  1137.       case '<':
  1138. +     if (in_what & (SCAN_REPL|SCAN_TR))
  1139. +         goto do_double;
  1140.       if (*++s == '<') {
  1141.           hereis = TRUE;
  1142.           d = tokenbuf;
  1143. ***************
  1144. *** 2091,2108 ****
  1145.       s = cpytill(d,s,bufend,'>',&len);
  1146.       if (s < bufend)
  1147.           s++;
  1148.       if (*d == '$') d++;
  1149.       while (*d && (isALNUM(*d) || *d == '\''))
  1150.           d++;
  1151.       if (d - tokenbuf != len) {
  1152. !         d = tokenbuf;
  1153.           arg[1].arg_type = A_GLOB;
  1154. -         d = nsavestr(d,len);
  1155. -         arg[1].arg_ptr.arg_stab = stab = genstab();
  1156. -         stab_io(stab) = stio_new();
  1157. -         stab_val(stab) = str_make(d,len);
  1158. -         Safefree(d);
  1159.           set_csh();
  1160.       }
  1161.       else {
  1162.           d = tokenbuf;
  1163. --- 2221,2239 ----
  1164.       s = cpytill(d,s,bufend,'>',&len);
  1165.       if (s < bufend)
  1166.           s++;
  1167. +     else
  1168. +         fatal("Unterminated <> operator");
  1169.       if (*d == '$') d++;
  1170.       while (*d && (isALNUM(*d) || *d == '\''))
  1171.           d++;
  1172.       if (d - tokenbuf != len) {
  1173. !         s = start;
  1174. !         term = *s;
  1175.           arg[1].arg_type = A_GLOB;
  1176.           set_csh();
  1177. +         alwaysdollar = TRUE;    /* treat $) and $| as variables */
  1178. +         goto snarf_it;
  1179.       }
  1180.       else {
  1181.           d = tokenbuf;
  1182. ***************
  1183. *** 2160,2165 ****
  1184. --- 2291,2297 ----
  1185.         snarf_it:
  1186.       {
  1187.           STR *tmpstr;
  1188. +         STR *tmpstr2 = Nullstr;
  1189.           char *tmps;
  1190.   
  1191.           CLINE;
  1192. ***************
  1193. *** 2235,2241 ****
  1194.           tmpstr->str_len = tmpstr->str_cur + 1;
  1195.           Renew(tmpstr->str_ptr, tmpstr->str_len, char);
  1196.           }
  1197. !         if ((arg[1].arg_type & A_MASK) == A_SINGLE) {
  1198.           arg[1].arg_ptr.arg_str = tmpstr;
  1199.           break;
  1200.           }
  1201. --- 2367,2373 ----
  1202.           tmpstr->str_len = tmpstr->str_cur + 1;
  1203.           Renew(tmpstr->str_ptr, tmpstr->str_len, char);
  1204.           }
  1205. !         if (arg[1].arg_type == A_SINGLE) {
  1206.           arg[1].arg_ptr.arg_str = tmpstr;
  1207.           break;
  1208.           }
  1209. ***************
  1210. *** 2259,2280 ****
  1211.           }
  1212.           s = d = tmpstr->str_ptr;    /* assuming shrinkage only */
  1213.           while (s < send) {
  1214. !         if ((*s == '$' && s+1 < send &&
  1215. !             (alwaysdollar || /*(*/ (s[1] != ')' && s[1] != '|')) ) ||
  1216. !             (*s == '@' && s+1 < send) ) {
  1217. !             if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
  1218. !             *d++ = *s++;
  1219. !             len = scanident(s,send,tokenbuf) - s;
  1220. !             if (*s == '$' || strEQ(tokenbuf,"ARGV")
  1221. !               || strEQ(tokenbuf,"ENV")
  1222. !               || strEQ(tokenbuf,"SIG")
  1223. !               || strEQ(tokenbuf,"INC") )
  1224. !             (void)stabent(tokenbuf,TRUE); /* make sure it exists */
  1225. !             while (len--)
  1226. !             *d++ = *s++;
  1227. !             continue;
  1228.           }
  1229. !         else if (*s == '\\' && s+1 < send) {
  1230.               s++;
  1231.               switch (*s) {
  1232.               default:
  1233. --- 2391,2431 ----
  1234.           }
  1235.           s = d = tmpstr->str_ptr;    /* assuming shrinkage only */
  1236.           while (s < send) {
  1237. !         if (in_what & SCAN_TR) {
  1238. !             if (*s != '\\' && s[1] == '-' && s+2 < send) {
  1239. !             int i;
  1240. !             if (!tmpstr2) {    /* oops, have to grow */
  1241. !                 tmpstr2 = str_smake(tmpstr);
  1242. !                 s = tmpstr2->str_ptr + (s - tmpstr->str_ptr);
  1243. !                 send = tmpstr2->str_ptr + (send - tmpstr->str_ptr);
  1244. !             }
  1245. !             i = d - tmpstr->str_ptr;
  1246. !             STR_GROW(tmpstr, tmpstr->str_len + 256);
  1247. !             d = tmpstr->str_ptr + i;
  1248. !             for (i = (s[0] & 0377); i <= (s[2] & 0377); i++)
  1249. !                 *d++ = i;
  1250. !             s += 3;
  1251. !             continue;
  1252. !             }
  1253.           }
  1254. !         else {
  1255. !             if ((*s == '$' && s+1 < send &&
  1256. !             (alwaysdollar || /*(*/(s[1] != ')' && s[1] != '|')) ) ||
  1257. !             (*s == '@' && s+1 < send) ) {
  1258. !             if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
  1259. !                 *d++ = *s++;
  1260. !             len = scanident(s,send,tokenbuf) - s;
  1261. !             if (*s == '$' || strEQ(tokenbuf,"ARGV")
  1262. !               || strEQ(tokenbuf,"ENV")
  1263. !               || strEQ(tokenbuf,"SIG")
  1264. !               || strEQ(tokenbuf,"INC") )
  1265. !                 (void)stabent(tokenbuf,TRUE); /* add symbol */
  1266. !             while (len--)
  1267. !                 *d++ = *s++;
  1268. !             continue;
  1269. !             }
  1270. !         }
  1271. !         if (*s == '\\' && s+1 < send) {
  1272.               s++;
  1273.               switch (*s) {
  1274.               default:
  1275. ***************
  1276. *** 2327,2338 ****
  1277.           }
  1278.           *d = '\0';
  1279.   
  1280. !         if ((arg[1].arg_type & A_MASK) == A_DOUBLE && makesingle)
  1281. !             arg[1].arg_type = A_SINGLE;    /* now we can optimize on it */
  1282.   
  1283.           tmpstr->str_cur = d - tmpstr->str_ptr;
  1284. !         arg[1].arg_ptr.arg_str = tmpstr;
  1285.           s = tmps;
  1286.           break;
  1287.       }
  1288.       }
  1289. --- 2478,2497 ----
  1290.           }
  1291.           *d = '\0';
  1292.   
  1293. !         if (arg[1].arg_type == A_DOUBLE && makesingle)
  1294. !         arg[1].arg_type = A_SINGLE;    /* now we can optimize on it */
  1295.   
  1296.           tmpstr->str_cur = d - tmpstr->str_ptr;
  1297. !         if (arg[1].arg_type == A_GLOB) {
  1298. !         arg[1].arg_ptr.arg_stab = stab = genstab();
  1299. !         stab_io(stab) = stio_new();
  1300. !         str_sset(stab_val(stab), tmpstr);
  1301. !         }
  1302. !         else
  1303. !         arg[1].arg_ptr.arg_str = tmpstr;
  1304.           s = tmps;
  1305. +         if (tmpstr2)
  1306. +         str_free(tmpstr2);
  1307.           break;
  1308.       }
  1309.       }
  1310. ***************
  1311. *** 2564,2569 ****
  1312. --- 2723,2729 ----
  1313.       return froot.f_next;
  1314.   }
  1315.   
  1316. + static void
  1317.   set_csh()
  1318.   {
  1319.   #ifdef CSH
  1320.  
  1321. Index: atarist/wildmat.c
  1322. *** atarist/wildmat.c.old    Mon Jun  8 17:45:40 1992
  1323. --- atarist/wildmat.c    Mon Jun  8 17:45:41 1992
  1324. ***************
  1325. *** 0 ****
  1326. --- 1,507 ----
  1327. + /*  $Revision: 4.0.1.1 $
  1328. + **
  1329. + **  Do shell-style pattern matching for ?, \, [], and * characters.
  1330. + **  Might not be robust in face of malformed patterns; e.g., "foo[a-"
  1331. + **  could cause a segmentation violation.  It is 8bit clean.
  1332. + **
  1333. + **  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  1334. + **  Rich $alz is now <rsalz@bbn.com>.
  1335. + **  April, 1991:  Replaced mutually-recursive calls with in-line code
  1336. + **  for the star character.
  1337. + **
  1338. + **  Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
  1339. + **  This can greatly speed up failing wildcard patterns.  For example:
  1340. + **    pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
  1341. + **    text 1:     -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
  1342. + **    text 2:     -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
  1343. + **  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
  1344. + **  the ABORT, then it takes 22310 calls to fail.  Ugh.  The following
  1345. + **  explanation is from Lars:
  1346. + **  The precondition that must be fulfilled is that DoMatch will consume
  1347. + **  at least one character in text.  This is true if *p is neither '*' nor
  1348. + **  '\0'.)  The last return has ABORT instead of FALSE to avoid quadratic
  1349. + **  behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx".  With
  1350. + **  FALSE, each star-loop has to run to the end of the text; with ABORT
  1351. + **  only the last one does.
  1352. + **
  1353. + **  Once the control of one instance of DoMatch enters the star-loop, that
  1354. + **  instance will return either TRUE or ABORT, and any calling instance
  1355. + **  will therefore return immediately after (without calling recursively
  1356. + **  again).  In effect, only one star-loop is ever active.  It would be
  1357. + **  possible to modify the code to maintain this context explicitly,
  1358. + **  eliminating all recursive calls at the cost of some complication and
  1359. + **  loss of clarity (and the ABORT stuff seems to be unclear enough by
  1360. + **  itself).  I think it would be unwise to try to get this into a
  1361. + **  released version unless you have a good test data base to try it out
  1362. + **  on.
  1363. + */
  1364. + #define TRUE            1
  1365. + #define FALSE            0
  1366. + #define ABORT            -1
  1367. +     /* What character marks an inverted character class? */
  1368. + #define NEGATE_CLASS        '^'
  1369. +     /* Is "*" a common pattern? */
  1370. + #define OPTIMIZE_JUST_STAR
  1371. +     /* Do tar(1) matching rules, which ignore a trailing slash? */
  1372. + #undef MATCH_TAR_PATTERN
  1373. + /*
  1374. + **  Match text and p, return TRUE, FALSE, or ABORT.
  1375. + */
  1376. + static int
  1377. + DoMatch(text, p)
  1378. +     char    *text;
  1379. +     char    *p;
  1380. + {
  1381. +     int    last;
  1382. +     int    matched;
  1383. +     int    reverse;
  1384. +     for ( ; *p; text++, p++) {
  1385. +     if (*text == '\0' && *p != '*')
  1386. +         return ABORT;
  1387. +     switch (*p) {
  1388. +     case '\\':
  1389. +         /* Literal match with following character. */
  1390. +         p++;
  1391. +         /* FALLTHROUGH */
  1392. +     default:
  1393. +         if (*text != *p)
  1394. +         return FALSE;
  1395. +         continue;
  1396. +     case '?':
  1397. +         /* Match anything. */
  1398. +         continue;
  1399. +     case '*':
  1400. +         while (*++p == '*')
  1401. +         /* Consecutive stars act just like one. */
  1402. +         continue;
  1403. +         if (*p == '\0')
  1404. +         /* Trailing star matches everything. */
  1405. +         return TRUE;
  1406. +         while (*text)
  1407. +         if ((matched = DoMatch(text++, p)) != FALSE)
  1408. +             return matched;
  1409. +         return ABORT;
  1410. +     case '[':
  1411. +         reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
  1412. +         if (reverse)
  1413. +         /* Inverted character class. */
  1414. +         p++;
  1415. +         for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
  1416. +         /* This next line requires a good C compiler. */
  1417. +         if (*p == '-' ? *text <= *++p && *text >= last : *text == *p)
  1418. +             matched = TRUE;
  1419. +         if (matched == reverse)
  1420. +         return FALSE;
  1421. +         continue;
  1422. +     }
  1423. +     }
  1424. + #ifdef    MATCH_TAR_PATTERN
  1425. +     if (*text == '/')
  1426. +     return TRUE;
  1427. + #endif    /* MATCH_TAR_ATTERN */
  1428. +     return *text == '\0';
  1429. + }
  1430. + /*
  1431. + **  User-level routine.  Returns TRUE or FALSE.
  1432. + */
  1433. + int
  1434. + wildmat(text, p)
  1435. +     char    *text;
  1436. +     char    *p;
  1437. + {
  1438. + #ifdef    OPTIMIZE_JUST_STAR
  1439. +     if (p[0] == '*' && p[1] == '\0')
  1440. +     return TRUE;
  1441. + #endif    /* OPTIMIZE_JUST_STAR */
  1442. +     return DoMatch(text, p) == TRUE;
  1443. + }
  1444. + #include <stdio.h>
  1445. + #include <sys/types.h>
  1446. + #include <dirent.h>
  1447. + #include <sys/stat.h>
  1448. + #if __STDC__
  1449. + #ifdef unix
  1450. + #define _SIZE_T    /* unix defines size_t in sys/types.h */
  1451. + #endif
  1452. + #ifndef _COMPILER_H
  1453. + #  include <compiler.h>
  1454. + #endif
  1455. + #include <stddef.h>
  1456. + #include <stdlib.h>
  1457. + #else
  1458. + extern char *malloc(), *realloc();
  1459. + extern char *rindex(),  *strdup();
  1460. + #define __PROTO(x) ()
  1461. + #endif
  1462. + #include <string.h>
  1463. + #define MAX_DIR    32    /* max depth of dir recursion */
  1464. + static struct {
  1465. +     char *dir, *patt;
  1466. + } dir_stack[MAX_DIR];
  1467. + static int stack_p;
  1468. + static char **matches;
  1469. + static int nmatches;
  1470. + static void *ck_memalloc __PROTO((void *));
  1471. + #define ck_strdup(p) ck_memalloc(strdup(p))
  1472. + #define ck_malloc(s) ck_memalloc(malloc(s))
  1473. + #define ck_realloc(p, s) ck_memalloc(realloc(p, s))
  1474. + #define DEBUGX(x) 
  1475. + /*
  1476. +  * return true if patt contains a wildcard char
  1477. +  */
  1478. + int contains_wild(patt)
  1479. + char *patt;
  1480. + {
  1481. +     char c;
  1482. +     char *p;
  1483. +     /* only check for wilds in the basename part of the pathname only */
  1484. +     if((p = rindex(patt, '/')) == NULL)
  1485. +     p = rindex(patt, '\\');
  1486. +     if(!p)
  1487. +     p = patt;
  1488. +     while((c = *p++))
  1489. +     if((c == '*') || (c == '?') || (c == '['))
  1490. +         return 1;
  1491. +     return 0;
  1492. + }
  1493. + #ifndef ZOO
  1494. + void free_all()
  1495. + {
  1496. +     char **p;
  1497. +     if(!matches)
  1498. +     return;
  1499. +     for(p = matches; *p; p++)
  1500. +     free(*p);
  1501. +     free(matches);
  1502. +     matches = NULL;
  1503. + }
  1504. + #endif
  1505. + static void push(dir, patt)
  1506. + char *dir;
  1507. + char *patt;
  1508. + {
  1509. +     if(stack_p < (MAX_DIR - 2))
  1510. +     stack_p++;
  1511. +     else
  1512. +     {
  1513. +     fprintf(stderr,"directory stack overflow\n");
  1514. +     exit(99);
  1515. +     }
  1516. +     dir_stack[stack_p].dir = dir;
  1517. +     dir_stack[stack_p].patt = patt;
  1518. + }
  1519. + /*
  1520. +  * glob patt
  1521. +  * if decend_dir is true, recursively decend any directories encountered.
  1522. +  * returns pointer to all matches encountered.
  1523. +  * if the initial patt is a directory, and decend_dir is true, it is
  1524. +  * equivalent to specifying the pattern "patt\*"
  1525. +  *
  1526. +  * Restrictions:
  1527. +  *  - handles wildcards only in the base part of a pathname
  1528. +  *    ie: will not handle \foo\*\bar\ (wildcard in the middle of pathname)
  1529. +  *
  1530. +  *  - max dir recursion is MAX_DIR
  1531. +  *
  1532. +  *  - on certain failures it will just skip potential matches as if they
  1533. +  *    were not present.
  1534. +  *
  1535. +  *  ++jrb    bammi@cadence.com
  1536. +  */
  1537. + static char **do_match __PROTO((int decend_dir));
  1538. + char **glob(patt, decend_dir)
  1539. + char *patt;
  1540. + int decend_dir;
  1541. + {
  1542. +     char *dir, *basepatt, *p;
  1543. +     struct stat s;
  1544. +     DEBUGX((fprintf(stderr,"glob(%s, %d)\n", patt, decend_dir)));
  1545. +     matches = NULL;
  1546. +     nmatches = 0;
  1547. +     stack_p = -1;
  1548. +     /* first check for wildcards */
  1549. +     if(contains_wild(patt))
  1550. +     {
  1551. +     /* break it up into dir and base patt, do_matches and return */
  1552. +     p = ck_strdup(patt);
  1553. +     if((basepatt = rindex(p, '/')) == NULL)
  1554. +         basepatt = rindex(p, '\\');
  1555. +         if(basepatt)
  1556. +         {
  1557. +         dir = p;
  1558. +         *basepatt++ = '\0';
  1559. +         basepatt = ck_strdup(basepatt);
  1560. +         }
  1561. +         else
  1562. +         {
  1563. +         dir = ck_strdup(".");
  1564. +         basepatt = p;
  1565. +         }
  1566. +         if(strcmp(basepatt, "*.*") == 0)
  1567. +         {
  1568. +             /* the desktop, and other braindead shells strike again */
  1569. +             basepatt[1] = '\0';
  1570. +         }
  1571. +     push(dir, basepatt);
  1572. +     DEBUGX((fprintf(stderr, "calling %s, %s\n", dir, basepatt)));
  1573. +     return do_match(decend_dir);
  1574. +     }
  1575. +     /* if no wilds, check for dir */
  1576. +     if(decend_dir && (!stat(patt, &s)))
  1577. +     {
  1578. +     if((s.st_mode & S_IFMT) == S_IFDIR)
  1579. +     {   /* is a dir */
  1580. +         size_t len = strlen(patt);
  1581. +         
  1582. +         dir = ck_strdup(patt);
  1583. +         --len;
  1584. +         if(len && ((dir[len] == '/') 
  1585. + #ifdef atarist
  1586. +            || (dir[len] == '\\')
  1587. + #endif
  1588. +          ))
  1589. +         dir[len] = '\0';
  1590. +         basepatt = ck_strdup("*");
  1591. +         push(dir, basepatt);
  1592. +         DEBUGX((fprintf(stderr, "calling %s, %s\n", dir, basepatt)));
  1593. +         return do_match(decend_dir);
  1594. +         }
  1595. +     }
  1596. +     return NULL;
  1597. + }
  1598. + static char **do_match(decend_dir)
  1599. + int decend_dir;
  1600. + {
  1601. +     DIR *dirp;
  1602. +     struct dirent *d;
  1603. +     struct stat s;
  1604. +     char *dir, *basepatt;
  1605. +     while(stack_p >= 0)
  1606. +     {
  1607. +     dir = ck_strdup(dir_stack[stack_p].dir); 
  1608. +     free(dir_stack[stack_p].dir);
  1609. +         basepatt = ck_strdup(dir_stack[stack_p].patt);
  1610. +     free(dir_stack[stack_p--].patt);
  1611. +     
  1612. +         DEBUGX((fprintf(stderr,"dir %s patt %s stack %d\n", dir, basepatt, stack_p)));
  1613. +         dirp = opendir(dir);
  1614. +     if(!dirp)
  1615. +     {
  1616. +         free(dir);
  1617. +         DEBUGX((fprintf(stderr,"no dir\n")));
  1618. +         continue;
  1619. +         }
  1620. +     
  1621. +         while((d = readdir(dirp)))
  1622. +         {
  1623. +         char *p = ck_malloc(strlen(dir) + strlen(d->d_name) + 2L);
  1624. +             if(strcmp(dir, "."))
  1625. +                                      /* If we have a full pathname then */
  1626. +         {                 /* let's append the directory info */
  1627. +         strcpy(p, dir);
  1628. + #ifndef unix
  1629. +         strcat(p, "\\");
  1630. + #else
  1631. +         strcat(p, "/");
  1632. + #endif
  1633. +         strcat(p, d->d_name);
  1634. +         }
  1635. +         else              /* Otherwise, the name is just fine, */
  1636. +         strcpy(p, d->d_name); /* there's no need for './' -- bjsjr */
  1637. +         DEBUGX((fprintf(stderr, "Testing %s\n", p)));
  1638. +         if(!stat(p, &s))    /* if stat fails, ignore it */
  1639. +             {
  1640. +             if( ((s.st_mode & S_IFMT) == S_IFREG) ||
  1641. +             ((s.st_mode & S_IFMT) == S_IFLNK) )
  1642. +             {  /* it is a file/symbolic link */
  1643. +             if(wildmat(d->d_name, basepatt))
  1644. +             {  /* it matches pattern */
  1645. +             DEBUGX((fprintf(stderr,"File Matched\n")));
  1646. +             if(matches == NULL)
  1647. +                 matches = (char **)ck_malloc(sizeof(char *));
  1648. +             else
  1649. +                 matches = (char **)
  1650. +                   ck_realloc(matches, (nmatches+1)*sizeof(char *)); 
  1651. +             matches[nmatches++] = p;
  1652. +             } /* no match */
  1653. +             else
  1654. +             {
  1655. +             DEBUGX((fprintf(stderr,"No File Match\n")));
  1656. +                 free(p);
  1657. +             }
  1658. +         } else if(decend_dir && ((s.st_mode & S_IFMT) == S_IFDIR))
  1659. +         {
  1660. +             if(!((!strcmp(d->d_name,".")) || (!strcmp(d->d_name, "..")
  1661. + #ifdef atarist
  1662. +                      || (!strcmp(d->d_name, ".dir"))
  1663. + #endif
  1664. +                 )))
  1665. +             {
  1666. +             char *push_p = ck_strdup("*");
  1667. +             push(p, push_p);
  1668. +             DEBUGX((fprintf(stderr,"Dir pushed\n")));
  1669. +             }
  1670. +             else
  1671. +             {
  1672. +             DEBUGX((fprintf(stderr, "DIR skipped\n")));
  1673. +             free(p);
  1674. +             }
  1675. +             }
  1676. +         else
  1677. +         {
  1678. +             DEBUGX((fprintf(stderr, "Not a dir/no decend\n")));
  1679. +             free(p);
  1680. +         }
  1681. +         } /* stat */
  1682. +         else
  1683. +         {
  1684. +         DEBUGX((fprintf(stderr, "Stat failed\n")));
  1685. +         free(p);
  1686. +         }
  1687. +         } /* while readdir */
  1688. +         closedir(dirp);
  1689. +     free(basepatt);
  1690. +     free(dir);
  1691. +     DEBUGX((fprintf(stderr, "Dir done\n\n")));
  1692. +     } /* while dirs in stack */
  1693. +     
  1694. +     if(!nmatches)
  1695. +     {
  1696. +     DEBUGX((fprintf(stderr, "No matches\n")));
  1697. +     return NULL;
  1698. +     }
  1699. +     
  1700. +     matches = (char **)realloc(matches, (nmatches+1)*sizeof(char *));
  1701. +     if(!matches)
  1702. +     {  return NULL; }
  1703. +     matches[nmatches] = NULL;
  1704. +     DEBUGX((fprintf(stderr, "%d matches\n", nmatches)));    
  1705. +     return matches;
  1706. + }
  1707. + #ifdef ZOO
  1708. + #include "errors.i"
  1709. + #endif
  1710. + static void *ck_memalloc(p)
  1711. + void *p;
  1712. + {
  1713. +     if(!p)
  1714. +     {
  1715. + #ifndef ZOO
  1716. +         fprintf(stderr, "Out of memory\n");
  1717. +     exit(98);
  1718. + #else
  1719. +         prterror('f', no_memory);
  1720. + #endif
  1721. +     }
  1722. +     return p;
  1723. + }
  1724. + #ifdef TEST_GLOB
  1725. + void test(path, dec)
  1726. + char *path;
  1727. + int dec;
  1728. + {
  1729. +     char **m;
  1730. +     char **matches;
  1731. +     printf("Testing %s %d\n", path, dec);
  1732. +     matches = glob(path, dec);
  1733. +     if(!matches)
  1734. +     {
  1735. +     printf("No matches\n");
  1736. +     }
  1737. +     else
  1738. +     {
  1739. +         for(m = matches; *m; m++)
  1740. +         printf("%s\n", *m);
  1741. +     putchar('\n');
  1742. +         free_all();
  1743. +     }
  1744. + }
  1745. + int main()
  1746. + {
  1747. + #ifndef unix
  1748. +     test("e:\\lib\\*.olb", 0);
  1749. +     test("e:\\lib", 0);
  1750. +     test("e:\\lib\\", 1);
  1751. + #else
  1752. +     test("/net/acae127/home/bammi/News/comp.sources.misc/*.c", 0);
  1753. +     test("/net/acae127/home/bammi/News/comp.sources.misc", 0);
  1754. +     test("/net/acae127/home/bammi/News/comp.sources.misc", 1);
  1755. +     test("/net/acae127/home/bammi/atari/cross-gcc", 1);
  1756. + #endif
  1757. +     
  1758. +     return 0;
  1759. + }
  1760. + #endif
  1761. + #ifdef    TEST_WILDMAT
  1762. + #include <stdio.h>
  1763. + /* Yes, we use gets not fgets.  Sue me. */
  1764. + extern char    *gets();
  1765. + main()
  1766. + {
  1767. +     char    pattern[80];
  1768. +     char    text[80];
  1769. +     printf("Wildmat tester.  Enter pattern, then strings to test.\n");
  1770. +     printf("A blank line gets prompts for a new pattern; a blank pattern\n");
  1771. +     printf("exits the program.\n\n");
  1772. +     for ( ; ; ) {
  1773. +     printf("Enter pattern:  ");
  1774. +     if (gets(pattern) == NULL)
  1775. +         break;
  1776. +     for ( ; ; ) {
  1777. +         printf("Enter text:  ");
  1778. +         if (gets(text) == NULL)
  1779. +         exit(0);
  1780. +         if (text[0] == '\0')
  1781. +         /* Blank line; go back and get a new pattern. */
  1782. +         break;
  1783. +         printf("      %s\n", wildmat(text, pattern) ? "YES" : "NO");
  1784. +     }
  1785. +     }
  1786. +     exit(0);
  1787. +     /* NOTREACHED */
  1788. + }
  1789. + #endif    /* TEST_WILDMAT */
  1790.  
  1791. *** End of Patch 33 ***
  1792. exit 0 # Just in case...
  1793.