1 /* $RCSfile: toke.c,v $$Revision: 4.0.1.6 $$Date: 92/06/08 16:03:49 $
3 * Copyright (c) 1991, Larry Wall
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
9 * Revision 4.0.1.6 92/06/08 16:03:49 lwall
10 * patch20: an EXPR may now start with a bareword
11 * patch20: print $fh EXPR can now expect term rather than operator in EXPR
12 * patch20: added ... as variant on ..
13 * patch20: new warning on spurious backslash
14 * patch20: new warning on missing $ for foreach variable
15 * patch20: "foo"x1024 now legal without space after x
16 * patch20: new warning on print accidentally used as function
17 * patch20: tr/stuff// wasn't working right
18 * patch20: 2. now eats the dot
19 * patch20: <@ARGV> now notices @ARGV
20 * patch20: tr/// now lets you say \-
22 * Revision 4.0.1.5 91/11/11 16:45:51 lwall
23 * patch19: default arg for shift was wrong after first subroutine definition
25 * Revision 4.0.1.4 91/11/05 19:02:48 lwall
26 * patch11: \x and \c were subject to double interpretation in regexps
27 * patch11: prepared for ctype implementations that don't define isascii()
28 * patch11: nested list operators could miscount parens
29 * patch11: once-thru blocks didn't display right in the debugger
30 * patch11: sort eval "whatever" didn't work
31 * patch11: underscore is now allowed within literal octal and hex numbers
33 * Revision 4.0.1.3 91/06/10 01:32:26 lwall
34 * patch10: m'$foo' now treats string as single quoted
35 * patch10: certain pattern optimizations were botched
37 * Revision 4.0.1.2 91/06/07 12:05:56 lwall
38 * patch4: new copyright notice
39 * patch4: debugger lost track of lines in eval
40 * patch4: //o and s///o now optimize themselves fully at runtime
41 * patch4: added global modifier for pattern matches
43 * Revision 4.0.1.1 91/04/12 09:18:18 lwall
44 * patch1: perl -de "print" wouldn't stop at the first statement
46 * Revision 4.0 91/03/20 01:42:14 lwall
55 static void set_csh();
68 /* which backslash sequences to keep in m// or s// */
70 static char *patleave = "\\.^$@dDwWsSbB+*?|()-nrtfeaxc0123456789[{]}";
72 char *reparse; /* if non-null, scanident found ${foo[$bar]} */
79 #define CLINE (cmdline = (curcmd->c_line < cmdline ? curcmd->c_line : cmdline))
82 #define PERL_META(c) ((c) | 128)
84 #define META(c) ((c) | 128)
87 #define RETURN(retval) return (bufptr = s,(int)retval)
88 #define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,(int)retval)
89 #define TERM(retval) return (CLINE, expectterm = FALSE,bufptr = s,(int)retval)
90 #define LOOPX(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)LOOPEX)
91 #define FTST(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)FILETEST)
92 #define FUN0(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC0)
93 #define FUN1(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC1)
94 #define FUN2(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2)
95 #define FUN2x(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2x)
96 #define FUN3(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC3)
97 #define FUN4(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC4)
98 #define FUN5(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC5)
99 #define FL(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST)
100 #define FL2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST2)
101 #define HFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)HSHFUN)
102 #define HFUN3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)HSHFUN3)
103 #define LFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LVALFUN)
104 #define AOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)ADDOP)
105 #define MOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)MULOP)
106 #define EOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)EQOP)
107 #define ROP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)RELOP)
108 #define FOP(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP)
109 #define FOP2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP2)
110 #define FOP3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP3)
111 #define FOP4(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP4)
112 #define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
113 #define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
115 static char *last_uni;
117 /* This bit of chicanery makes a unary function followed by
118 * a parenthesis into a function with one argument, highest precedence.
120 #define UNI(f) return(yylval.ival = f, \
123 last_uni = oldbufptr, \
124 (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
126 /* This does similarly for list operators, merely by pretending that the
127 * paren came before the listop rather than after.
130 #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
131 (*s = (char) PERL_META('('), bufptr = oldbufptr, '(') : \
132 (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
134 #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
135 (*s = (char) META('('), bufptr = oldbufptr, '(') : \
136 (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
138 /* grandfather return to old style */
139 #define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
145 while (s < bufend && isSPACE(*s))
155 if (oldoldbufptr != last_uni)
157 while (isSPACE(*last_uni))
159 for (s = last_uni; isALNUM(*s); s++) ;
162 warn("Warning: Use of \"%s\" without parens is ambiguous", last_uni);
170 #define UNI(f) return uni(f,s)
171 #define LOP(f) return lop(f,s)
181 last_uni = oldbufptr;
216 #endif /* CRIPPLED_CC */
221 register char *s = bufptr;
224 static bool in_format = FALSE;
225 static bool firstline = TRUE;
226 extern int yychar; /* last token */
228 oldoldbufptr = oldbufptr;
235 fprintf(stderr,"Tokener at %s",s);
237 fprintf(stderr,"Tokener at %s\n",s);
241 if ((*s & 127) == '(') {
245 else if ((*s & 127) == '}') {
250 warn("Unrecognized character \\%03o ignored", *s++ & 255);
256 if ((*s & 127) == '(') {
260 else if ((*s & 127) == '}') {
265 warn("Unrecognized character \\%03o ignored", *s++ & 255);
269 goto fake_eof; /* emulate EOF on ^D or ^Z */
274 goto retry; /* ignore stray nulls */
278 if (minus_n || minus_p || perldb) {
282 char *pdb = getenv("PERLDB");
284 str_cat(linestr, pdb ? pdb : "require 'perldb.pl'");
285 str_cat(linestr, ";");
287 if (minus_n || minus_p) {
288 str_cat(linestr,"line: while (<>) {");
290 str_cat(linestr,"chop;");
292 str_cat(linestr,"@F=split(' ');");
294 oldoldbufptr = oldbufptr = s = str_get(linestr);
295 bufend = linestr->str_ptr + linestr->str_cur;
301 yylval.formval = load_format();
303 oldoldbufptr = oldbufptr = s = str_get(linestr) + 1;
304 bufend = linestr->str_ptr + linestr->str_cur;
310 #endif /* CRYPTSCRIPT */
312 if ((s = str_gets(linestr, rsfp, 0)) == Nullch) {
316 (void)mypclose(rsfp);
317 else if ((FILE*)rsfp == stdin)
323 if (minus_n || minus_p) {
324 str_set(linestr,minus_p ? ";}continue{print" : "");
325 str_cat(linestr,";}");
326 oldoldbufptr = oldbufptr = s = str_get(linestr);
327 bufend = linestr->str_ptr + linestr->str_cur;
328 minus_n = minus_p = 0;
331 oldoldbufptr = oldbufptr = s = str_get(linestr);
333 RETURN(';'); /* not infinite loop because rsfp is NULL now */
335 if (doextract && *linestr->str_ptr == '#')
338 oldoldbufptr = oldbufptr = bufptr = s;
340 STR *str = Str_new(85,0);
342 str_sset(str,linestr);
343 astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
351 bufend = linestr->str_ptr + linestr->str_cur;
352 if (curcmd->c_line == 1) {
353 if (*s == '#' && s[1] == '!') {
354 if (!in_eval && !instr(s,"perl") && instr(origargv[0],"perl")) {
362 while (s < bufend && !isSPACE(*s))
365 while (s < bufend && isSPACE(*s))
368 Newz(899,newargv,origargc+3,char*);
370 while (s < bufend && !isSPACE(*s))
373 Copy(origargv+1, newargv+2, origargc+1, char*);
379 fatal("Can't exec %s", cmd);
383 while (s < bufend && isSPACE(*s))
385 if (*s == ':') /* for csh's that have to exec sh scripts */
390 case ' ': case '\t': case '\f': case '\r': case 013:
394 if (preprocess && s == str_get(linestr) &&
395 s[1] == ' ' && (isDIGIT(s[2]) || strnEQ(s+2,"line ",5)) ) {
396 while (*s && !isDIGIT(*s))
398 curcmd->c_line = atoi(s)-1;
402 while (s < d && isSPACE(*s)) s++;
403 s[strlen(s)-1] = '\0'; /* wipe out newline */
406 s[strlen(s)-1] = '\0'; /* wipe out trailing quote */
409 curcmd->c_filestab = fstab(s);
411 curcmd->c_filestab = fstab(origfilename);
412 oldoldbufptr = oldbufptr = s = str_get(linestr);
416 if (in_eval && !rsfp) {
418 while (s < d && *s != '\n')
424 yylval.formval = load_format();
426 oldoldbufptr = oldbufptr = s = bufptr + 1;
437 if (s[1] && isALPHA(s[1]) && !isALPHA(s[2])) {
440 case 'r': FTST(O_FTEREAD);
441 case 'w': FTST(O_FTEWRITE);
442 case 'x': FTST(O_FTEEXEC);
443 case 'o': FTST(O_FTEOWNED);
444 case 'R': FTST(O_FTRREAD);
445 case 'W': FTST(O_FTRWRITE);
446 case 'X': FTST(O_FTREXEC);
447 case 'O': FTST(O_FTROWNED);
448 case 'e': FTST(O_FTIS);
449 case 'z': FTST(O_FTZERO);
450 case 's': FTST(O_FTSIZE);
451 case 'f': FTST(O_FTFILE);
452 case 'd': FTST(O_FTDIR);
453 case 'l': FTST(O_FTLINK);
454 case 'p': FTST(O_FTPIPE);
455 case 'S': FTST(O_FTSOCK);
456 case 'u': FTST(O_FTSUID);
457 case 'g': FTST(O_FTSGID);
458 case 'k': FTST(O_FTSVTX);
459 case 'b': FTST(O_FTBLK);
460 case 'c': FTST(O_FTCHR);
461 case 't': FTST(O_FTTTY);
462 case 'T': FTST(O_FTTEXT);
463 case 'B': FTST(O_FTBINARY);
464 case 'M': stabent("\024",TRUE); FTST(O_FTMTIME);
465 case 'A': stabent("\024",TRUE); FTST(O_FTATIME);
466 case 'C': stabent("\024",TRUE); FTST(O_FTCTIME);
478 if (isSPACE(*s) || !isSPACE(*bufptr))
491 if (isSPACE(*s) || !isSPACE(*bufptr))
501 s = scanident(s,bufend,tokenbuf);
502 yylval.stabval = stabent(tokenbuf,TRUE);
515 s = scanident(s,bufend,tokenbuf);
516 yylval.stabval = hadd(stabent(tokenbuf,TRUE));
532 yylval.ival = curcmd->c_line;
533 if (isSPACE(*s) || *s == '#')
534 cmdline = NOLINE; /* invalidate current command line number */
537 if (curcmd->c_line < cmdline)
538 cmdline = curcmd->c_line;
556 while (s < d && isSPACE(*s))
558 if (isALPHA(*s) || *s == '_' || *s == '\'')
559 *(--s) = '\\'; /* force next ident to WORD */
592 if (s[1] != '<' && !index(s,'>'))
594 s = scanstr(s, SCAN_DEF);
622 while (isALNUM(*s) || *s == '\'') \
624 while (d[-1] == '\'') \
630 if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_')) {
632 s = scanident(s,bufend,tokenbuf);
633 yylval.stabval = aadd(stabent(tokenbuf,TRUE));
637 s = scanident(s,bufend,tokenbuf);
638 if (reparse) { /* turn ${foo[bar]} into ($foo[bar]) */
646 yylval.stabval = stabent(tokenbuf,TRUE);
648 if (isSPACE(*s) && oldoldbufptr && oldoldbufptr < bufptr) {
650 while (isSPACE(*oldoldbufptr))
652 if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5)) {
653 if (index("&*<%", *s) && isALPHA(s[1]))
654 expectterm = TRUE; /* e.g. print $fh &sub */
655 else if (*s == '.' && isDIGIT(s[1]))
656 expectterm = TRUE; /* e.g. print $fh .3 */
657 else if (index("/?-+", *s) && !isSPACE(s[1]))
658 expectterm = TRUE; /* e.g. print $fh -1 */
665 s = scanident(s,bufend,tokenbuf);
668 yylval.stabval = aadd(stabent(tokenbuf,TRUE));
671 case '/': /* may either be division or pattern */
672 case '?': /* may either be conditional or pattern */
684 if (!expectterm || !isDIGIT(s[1])) {
693 yylval.ival = AF_COMMON;
701 case '0': case '1': case '2': case '3': case '4':
702 case '5': case '6': case '7': case '8': case '9':
703 case '\'': case '"': case '`':
704 s = scanstr(s, SCAN_DEF);
707 case '\\': /* some magic to force next word to be a WORD */
708 s++; /* used by do and sub to force a separate namespace */
709 if (!isALPHA(*s) && *s != '_' && *s != '\'') {
710 warn("Spurious backslash ignored");
717 if (strEQ(d,"__LINE__") || strEQ(d,"__FILE__")) {
718 ARG *arg = op_new(1);
721 arg->arg_type = O_ITEM;
723 (void)sprintf(tokenbuf,"%ld",(long)curcmd->c_line);
725 strcpy(tokenbuf, stab_val(curcmd->c_filestab)->str_ptr);
726 arg[1].arg_type = A_SINGLE;
727 arg[1].arg_ptr.arg_str = str_make(tokenbuf,strlen(tokenbuf));
730 else if (strEQ(d,"__END__")) {
735 if (!in_eval && (stab = stabent("DATA",FALSE))) {
736 stab->str_pok |= SP_MULTI;
738 stab_io(stab) = stio_new();
739 stab_io(stab)->ifp = rsfp;
740 #if defined(HAS_FCNTL) && defined(F_SETFD)
742 fcntl(fd,F_SETFD,fd >= 3);
745 stab_io(stab)->type = '|';
746 else if ((FILE*)rsfp == stdin)
747 stab_io(stab)->type = '-';
749 stab_io(stab)->type = '<';
758 if (strEQ(d,"alarm"))
760 if (strEQ(d,"accept"))
762 if (strEQ(d,"atan2"))
769 if (strEQ(d,"binmode"))
776 if (strEQ(d,"continue"))
778 if (strEQ(d,"chdir")) {
779 (void)stabent("ENV",TRUE); /* may use HOME */
782 if (strEQ(d,"close"))
784 if (strEQ(d,"closedir"))
788 if (strEQ(d,"caller"))
790 if (strEQ(d,"crypt")) {
792 static int cryptseen = 0;
799 if (strEQ(d,"chmod"))
801 if (strEQ(d,"chown"))
803 if (strEQ(d,"connect"))
807 if (strEQ(d,"chroot"))
814 while (s < d && isSPACE(*s))
816 if (isALPHA(*s) || *s == '_')
817 *(--s) = '\\'; /* force next ident to WORD */
822 if (strEQ(d,"defined"))
824 if (strEQ(d,"delete"))
826 if (strEQ(d,"dbmopen"))
828 if (strEQ(d,"dbmclose"))
837 if (strEQ(d,"elsif")) {
838 yylval.ival = curcmd->c_line;
841 if (strEQ(d,"eq") || strEQ(d,"EQ"))
845 if (strEQ(d,"eval")) {
846 allstabs = TRUE; /* must initialize everything since */
847 UNI(O_EVAL); /* we don't know what will be used */
855 if (strEQ(d,"exec")) {
859 if (strEQ(d,"endhostent"))
861 if (strEQ(d,"endnetent"))
863 if (strEQ(d,"endservent"))
865 if (strEQ(d,"endprotoent"))
867 if (strEQ(d,"endpwent"))
869 if (strEQ(d,"endgrent"))
874 if (strEQ(d,"for") || strEQ(d,"foreach")) {
875 yylval.ival = curcmd->c_line;
876 while (s < bufend && isSPACE(*s))
879 fatal("Missing $ on loop variable");
882 if (strEQ(d,"format")) {
884 while (s < d && isSPACE(*s))
886 if (isALPHA(*s) || *s == '_')
887 *(--s) = '\\'; /* force next ident to WORD */
889 allstabs = TRUE; /* must initialize everything since */
890 OPERATOR(FORMAT); /* we don't know what will be used */
894 if (strEQ(d,"fcntl"))
896 if (strEQ(d,"fileno"))
898 if (strEQ(d,"flock"))
903 if (strEQ(d,"gt") || strEQ(d,"GT"))
905 if (strEQ(d,"ge") || strEQ(d,"GE"))
911 if (strEQ(d,"gmtime"))
915 if (strnEQ(d,"get",3)) {
922 if (strEQ(d,"priority"))
924 if (strEQ(d,"protobyname"))
926 if (strEQ(d,"protobynumber"))
928 if (strEQ(d,"protoent"))
930 if (strEQ(d,"pwent"))
932 if (strEQ(d,"pwnam"))
934 if (strEQ(d,"pwuid"))
936 if (strEQ(d,"peername"))
939 else if (*d == 'h') {
940 if (strEQ(d,"hostbyname"))
942 if (strEQ(d,"hostbyaddr"))
944 if (strEQ(d,"hostent"))
947 else if (*d == 'n') {
948 if (strEQ(d,"netbyname"))
950 if (strEQ(d,"netbyaddr"))
952 if (strEQ(d,"netent"))
955 else if (*d == 's') {
956 if (strEQ(d,"servbyname"))
958 if (strEQ(d,"servbyport"))
960 if (strEQ(d,"servent"))
962 if (strEQ(d,"sockname"))
964 if (strEQ(d,"sockopt"))
967 else if (*d == 'g') {
968 if (strEQ(d,"grent"))
970 if (strEQ(d,"grnam"))
972 if (strEQ(d,"grgid"))
975 else if (*d == 'l') {
976 if (strEQ(d,"login"))
990 yylval.ival = curcmd->c_line;
993 if (strEQ(d,"index"))
997 if (strEQ(d,"ioctl"))
1002 if (strEQ(d,"join"))
1007 if (strEQ(d,"keys"))
1009 if (strEQ(d,"kill"))
1014 if (strEQ(d,"last"))
1016 if (strEQ(d,"local"))
1018 if (strEQ(d,"length"))
1020 if (strEQ(d,"lt") || strEQ(d,"LT"))
1022 if (strEQ(d,"le") || strEQ(d,"LE"))
1024 if (strEQ(d,"localtime"))
1028 if (strEQ(d,"link"))
1030 if (strEQ(d,"listen"))
1032 if (strEQ(d,"lstat"))
1048 RETURN(1); /* force error */
1052 if (strEQ(d,"mkdir"))
1056 if (strEQ(d,"msgctl"))
1058 if (strEQ(d,"msgget"))
1060 if (strEQ(d,"msgrcv"))
1062 if (strEQ(d,"msgsnd"))
1069 if (strEQ(d,"next"))
1071 if (strEQ(d,"ne") || strEQ(d,"NE"))
1076 if (strEQ(d,"open"))
1082 if (strEQ(d,"opendir"))
1087 if (strEQ(d,"print")) {
1088 checkcomma(s,d,"filehandle");
1091 if (strEQ(d,"printf")) {
1092 checkcomma(s,d,"filehandle");
1095 if (strEQ(d,"push")) {
1096 yylval.ival = O_PUSH;
1101 if (strEQ(d,"pack"))
1103 if (strEQ(d,"package"))
1105 if (strEQ(d,"pipe"))
1111 s = scanstr(s-1, SCAN_DEF);
1114 if (strEQ(d,"qq")) {
1115 s = scanstr(s-2, SCAN_DEF);
1118 if (strEQ(d,"qx")) {
1119 s = scanstr(s-2, SCAN_DEF);
1125 if (strEQ(d,"return"))
1127 if (strEQ(d,"require")) {
1128 allstabs = TRUE; /* must initialize everything since */
1129 UNI(O_REQUIRE); /* we don't know what will be used */
1131 if (strEQ(d,"reset"))
1133 if (strEQ(d,"redo"))
1135 if (strEQ(d,"rename"))
1137 if (strEQ(d,"rand"))
1139 if (strEQ(d,"rmdir"))
1141 if (strEQ(d,"rindex"))
1143 if (strEQ(d,"read"))
1145 if (strEQ(d,"readdir"))
1147 if (strEQ(d,"rewinddir"))
1149 if (strEQ(d,"recv"))
1151 if (strEQ(d,"reverse"))
1153 if (strEQ(d,"readlink"))
1169 RETURN(1); /* force error */
1176 if (strEQ(d,"scalar"))
1182 if (strEQ(d,"select"))
1184 if (strEQ(d,"seek"))
1186 if (strEQ(d,"semctl"))
1188 if (strEQ(d,"semget"))
1190 if (strEQ(d,"semop"))
1192 if (strEQ(d,"send"))
1194 if (strEQ(d,"setpgrp"))
1196 if (strEQ(d,"setpriority"))
1197 FUN3(O_SETPRIORITY);
1198 if (strEQ(d,"sethostent"))
1200 if (strEQ(d,"setnetent"))
1202 if (strEQ(d,"setservent"))
1204 if (strEQ(d,"setprotoent"))
1206 if (strEQ(d,"setpwent"))
1208 if (strEQ(d,"setgrent"))
1210 if (strEQ(d,"seekdir"))
1212 if (strEQ(d,"setsockopt"))
1219 if (strEQ(d,"shift"))
1221 if (strEQ(d,"shmctl"))
1223 if (strEQ(d,"shmget"))
1225 if (strEQ(d,"shmread"))
1227 if (strEQ(d,"shmwrite"))
1229 if (strEQ(d,"shutdown"))
1240 if (strEQ(d,"sleep"))
1247 if (strEQ(d,"socket"))
1249 if (strEQ(d,"socketpair"))
1251 if (strEQ(d,"sort")) {
1252 checkcomma(s,d,"subroutine name");
1254 while (s < d && isSPACE(*s)) s++;
1255 if (*s == ';' || *s == ')') /* probably a close */
1256 fatal("sort is now a reserved word");
1257 if (isALPHA(*s) || *s == '_') {
1259 for (d = s; isALNUM(*d); d++) ;
1260 strncpy(tokenbuf,s,d-s);
1261 tokenbuf[d-s] = '\0';
1262 if (strNE(tokenbuf,"keys") &&
1263 strNE(tokenbuf,"values") &&
1264 strNE(tokenbuf,"split") &&
1265 strNE(tokenbuf,"grep") &&
1266 strNE(tokenbuf,"readdir") &&
1267 strNE(tokenbuf,"unpack") &&
1268 strNE(tokenbuf,"do") &&
1269 strNE(tokenbuf,"eval") &&
1270 (d >= bufend || isSPACE(*d)) )
1271 *(--s) = '\\'; /* force next ident to WORD */
1277 if (strEQ(d,"split"))
1279 if (strEQ(d,"sprintf"))
1281 if (strEQ(d,"splice")) {
1282 yylval.ival = O_SPLICE;
1287 if (strEQ(d,"sqrt"))
1291 if (strEQ(d,"srand"))
1297 if (strEQ(d,"stat"))
1299 if (strEQ(d,"study")) {
1305 if (strEQ(d,"substr"))
1307 if (strEQ(d,"sub")) {
1308 yylval.ival = savestack->ary_fill; /* restore stuff on reduce */
1312 subline = curcmd->c_line;
1314 while (s < d && isSPACE(*s))
1316 if (isALPHA(*s) || *s == '_' || *s == '\'') {
1317 str_sset(subname,curstname);
1318 str_ncat(subname,"'",1);
1319 for (d = s+1; isALNUM(*d) || *d == '\''; d++)
1324 str_ncat(subname,s,d-s);
1325 *(--s) = '\\'; /* force next ident to WORD */
1328 str_set(subname,"?");
1337 if (strEQ(d,"system")) {
1341 if (strEQ(d,"symlink"))
1343 if (strEQ(d,"syscall"))
1345 if (strEQ(d,"sysread"))
1347 if (strEQ(d,"syswrite"))
1356 if (strEQ(d,"tr")) {
1361 RETURN(1); /* force error */
1363 if (strEQ(d,"tell"))
1365 if (strEQ(d,"telldir"))
1367 if (strEQ(d,"time"))
1369 if (strEQ(d,"times"))
1371 if (strEQ(d,"truncate"))
1376 if (strEQ(d,"using"))
1378 if (strEQ(d,"until")) {
1379 yylval.ival = curcmd->c_line;
1382 if (strEQ(d,"unless")) {
1383 yylval.ival = curcmd->c_line;
1386 if (strEQ(d,"unlink"))
1388 if (strEQ(d,"undef"))
1390 if (strEQ(d,"unpack"))
1392 if (strEQ(d,"utime"))
1394 if (strEQ(d,"umask"))
1396 if (strEQ(d,"unshift")) {
1397 yylval.ival = O_UNSHIFT;
1403 if (strEQ(d,"values"))
1405 if (strEQ(d,"vec")) {
1412 if (strEQ(d,"while")) {
1413 yylval.ival = curcmd->c_line;
1416 if (strEQ(d,"warn"))
1418 if (strEQ(d,"wait"))
1420 if (strEQ(d,"waitpid"))
1422 if (strEQ(d,"wantarray")) {
1423 yylval.arg = op_new(1);
1424 yylval.arg->arg_type = O_ITEM;
1425 yylval.arg[1].arg_type = A_WANTARRAY;
1428 if (strEQ(d,"write"))
1432 if (*s == 'x' && isDIGIT(s[1]) && !expectterm) {
1460 yylval.cval = savestr(d);
1461 if (expectterm == 2) { /* special case: start of statement */
1462 while (isSPACE(*s)) s++;
1471 if (oldoldbufptr && oldoldbufptr < bufptr) {
1472 while (isSPACE(*oldoldbufptr))
1474 if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5))
1476 else if (*oldoldbufptr == 's' && strnEQ(oldoldbufptr,"sort",4))
1479 return (CLINE, bufptr = s, (int)WORD);
1483 checkcomma(s,name,what)
1490 if (dowarn && *s == ' ' && s[1] == '(') {
1493 for (w++; *w && isSPACE(*w); w++) ;
1494 if (!w || !*w || !index(";|}", *w)) /* an advisory hack only... */
1495 warn("%s (...) interpreted as function",name);
1497 while (s < bufend && isSPACE(*s))
1501 while (s < bufend && isSPACE(*s))
1503 if (isALPHA(*s) || *s == '_') {
1507 while (s < bufend && isSPACE(*s))
1512 "tell eof times getlogin wait length shift umask getppid \
1513 cos exp int log rand sin sqrt ord wantarray",
1518 fatal("No comma allowed after %s", what);
1524 scanident(s,send,dest)
1526 register char *send;
1540 while (isALNUM(*s) || *s == '\'')
1543 while (d > dest+1 && d[-1] == '\'')
1549 if (*d == '{' /* } */ ) {
1552 while (s < send && brackets) {
1553 if (!reparse && (d == dest || (*s && isALNUM(*s) ))) {
1563 if (reparse && reparse == s - 1)
1577 if (*d == '^' && (isUPPER(*s) || index("[\\]^_?", *s))) {
1588 scanconst(spat,string,len)
1593 register STR *tmpstr;
1597 char *origstring = string;
1598 static char *vert = "|";
1600 if (ninstr(string, string+len, vert, vert+1))
1604 tmpstr = Str_new(86,len);
1605 str_nset(tmpstr,string,len);
1606 t = str_get(tmpstr);
1608 tmpstr->str_u.str_useful = 100;
1609 for (d=t; d < e; ) {
1617 case '.': case '[': case '$': case '(': case ')': case '|': case '+':
1622 if (d[1] && index("wWbB0123456789sSdDlLuUExc",d[1])) {
1626 Move(d+1,d,e-d,char);
1651 if (d[1] == '*' || (d[1] == '{' && d[2] == '0') || d[1] == '?') {
1663 tmpstr->str_cur = d - t;
1665 spat->spat_flags |= SPAT_ALL;
1666 if (*origstring != '^')
1667 spat->spat_flags |= SPAT_SCANFIRST;
1668 spat->spat_short = tmpstr;
1669 spat->spat_slen = d - t;
1676 register SPAT *spat;
1681 STR *str = Str_new(93,0);
1684 Newz(801,spat,1,SPAT);
1685 spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
1686 curstash->tbl_spatroot = spat;
1695 spat->spat_flags |= SPAT_ONCE;
1698 fatal("panic: scanpat");
1700 s = str_append_till(str,s,bufend,s[-1],patleave);
1703 yyerror("Search pattern not terminated");
1704 yylval.arg = Nullarg;
1708 while (*s == 'i' || *s == 'o' || *s == 'g') {
1712 spat->spat_flags |= SPAT_FOLD;
1716 spat->spat_flags |= SPAT_KEEP;
1720 spat->spat_flags |= SPAT_GLOBAL;
1724 e = str->str_ptr + len;
1729 for (; d < e; d++) {
1732 else if ((*d == '$' && d[1] && d[1] != '|' && d[1] != ')') ||
1736 spat->spat_runtime = arg = op_new(1);
1737 arg->arg_type = O_ITEM;
1738 arg[1].arg_type = A_DOUBLE;
1739 arg[1].arg_ptr.arg_str = str_smake(str);
1740 d = scanident(d,bufend,buf);
1741 (void)stabent(buf,TRUE); /* make sure it's created */
1742 for (; d < e; d++) {
1745 else if (*d == '$' && d[1] && d[1] != '|' && d[1] != ')') {
1746 d = scanident(d,bufend,buf);
1747 (void)stabent(buf,TRUE);
1749 else if (*d == '@') {
1750 d = scanident(d,bufend,buf);
1751 if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
1752 strEQ(buf,"SIG") || strEQ(buf,"INC"))
1753 (void)stabent(buf,TRUE);
1756 goto got_pat; /* skip compiling for now */
1759 if (spat->spat_flags & SPAT_FOLD)
1760 StructCopy(spat, &savespat, SPAT);
1761 scanconst(spat,str->str_ptr,len);
1762 if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
1763 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1764 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1765 spat->spat_flags & SPAT_FOLD);
1766 /* Note that this regexp can still be used if someone says
1767 * something like /a/ && s//b/; so we can't delete it.
1771 if (spat->spat_flags & SPAT_FOLD)
1772 StructCopy(&savespat, spat, SPAT);
1773 if (spat->spat_short)
1774 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1775 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1776 spat->spat_flags & SPAT_FOLD);
1781 yylval.arg = make_match(O_MATCH,stab2arg(A_STAB,defstab),spat);
1789 register char *s = start;
1790 register SPAT *spat;
1794 STR *str = Str_new(93,0);
1797 if (term && (d = index("([{< )]}> )]}>",term)))
1800 Newz(802,spat,1,SPAT);
1801 spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
1802 curstash->tbl_spatroot = spat;
1804 s = str_append_till(str,s+1,bufend,term,patleave);
1807 yyerror("Substitution pattern not terminated");
1808 yylval.arg = Nullarg;
1812 e = str->str_ptr + len;
1813 for (d = str->str_ptr; d < e; d++) {
1816 else if ((*d == '$' && d[1] && d[1] != '|' && /*(*/ d[1] != ')') ||
1820 spat->spat_runtime = arg = op_new(1);
1821 arg->arg_type = O_ITEM;
1822 arg[1].arg_type = A_DOUBLE;
1823 arg[1].arg_ptr.arg_str = str_smake(str);
1824 d = scanident(d,e,buf);
1825 (void)stabent(buf,TRUE); /* make sure it's created */
1827 if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') {
1828 d = scanident(d,e,buf);
1829 (void)stabent(buf,TRUE);
1831 else if (*d == '@' && d[-1] != '\\') {
1832 d = scanident(d,e,buf);
1833 if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
1834 strEQ(buf,"SIG") || strEQ(buf,"INC"))
1835 (void)stabent(buf,TRUE);
1838 goto get_repl; /* skip compiling for now */
1841 scanconst(spat,str->str_ptr,len);
1845 s = scanstr(s, SCAN_REPL);
1848 yyerror("Substitution replacement not terminated");
1849 yylval.arg = Nullarg;
1852 spat->spat_repl = yylval.arg;
1853 if ((spat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
1854 spat->spat_flags |= SPAT_CONST;
1855 else if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE) {
1859 spat->spat_flags |= SPAT_CONST;
1860 tmpstr = spat->spat_repl[1].arg_ptr.arg_str;
1861 e = tmpstr->str_ptr + tmpstr->str_cur;
1862 for (t = tmpstr->str_ptr; t < e; t++) {
1863 if (*t == '$' && t[1] && (index("`'&+0123456789",t[1]) ||
1864 (t[1] == '{' /*}*/ && isDIGIT(t[2])) ))
1865 spat->spat_flags &= ~SPAT_CONST;
1868 while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
1874 if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
1875 spat->spat_repl[1].arg_type = A_SINGLE;
1876 spat->spat_repl = make_op(
1877 (!es && spat->spat_repl[1].arg_type == A_SINGLE
1884 spat->spat_flags &= ~SPAT_CONST;
1888 spat->spat_flags |= SPAT_GLOBAL;
1893 spat->spat_flags |= SPAT_FOLD;
1894 if (!(spat->spat_flags & SPAT_SCANFIRST)) {
1895 str_free(spat->spat_short); /* anchored opt doesn't do */
1896 spat->spat_short = Nullstr; /* case insensitive match */
1897 spat->spat_slen = 0;
1902 spat->spat_flags |= SPAT_KEEP;
1905 if (spat->spat_short && (spat->spat_flags & SPAT_SCANFIRST))
1906 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1907 if (!spat->spat_runtime) {
1908 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1909 spat->spat_flags & SPAT_FOLD);
1912 yylval.arg = make_match(O_SUBST,stab2arg(A_STAB,defstab),spat);
1919 register SPAT *spat;
1921 if (!spat->spat_short && spat->spat_regexp->regstart &&
1922 (!spat->spat_regexp->regmust || spat->spat_regexp->reganch & ROPT_ANCH)
1924 if (!(spat->spat_regexp->reganch & ROPT_ANCH))
1925 spat->spat_flags |= SPAT_SCANFIRST;
1926 else if (spat->spat_flags & SPAT_FOLD)
1928 spat->spat_short = str_smake(spat->spat_regexp->regstart);
1930 else if (spat->spat_regexp->regmust) {/* is there a better short-circuit? */
1931 if (spat->spat_short &&
1932 str_eq(spat->spat_short,spat->spat_regexp->regmust))
1934 if (spat->spat_flags & SPAT_SCANFIRST) {
1935 str_free(spat->spat_short);
1936 spat->spat_short = Nullstr;
1939 str_free(spat->spat_regexp->regmust);
1940 spat->spat_regexp->regmust = Nullstr;
1944 if (!spat->spat_short || /* promote the better string */
1945 ((spat->spat_flags & SPAT_SCANFIRST) &&
1946 (spat->spat_short->str_cur < spat->spat_regexp->regmust->str_cur) )){
1947 str_free(spat->spat_short); /* ok if null */
1948 spat->spat_short = spat->spat_regexp->regmust;
1949 spat->spat_regexp->regmust = Nullstr;
1950 spat->spat_flags |= SPAT_SCANFIRST;
1959 register char *s = start;
1961 l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
1966 register short *tbl;
1974 New(803,tbl,256,short);
1975 arg[2].arg_type = A_NULL;
1976 arg[2].arg_ptr.arg_cval = (char*) tbl;
1978 s = scanstr(s, SCAN_TR);
1980 yyerror("Translation pattern not terminated");
1981 yylval.arg = Nullarg;
1984 tstr = yylval.arg[1].arg_ptr.arg_str;
1985 yylval.arg[1].arg_ptr.arg_str = Nullstr;
1986 arg_free(yylval.arg);
1988 tlen = tstr->str_cur;
1990 if (s[-1] == *start)
1993 s = scanstr(s, SCAN_TR|SCAN_REPL);
1995 yyerror("Translation replacement not terminated");
1996 yylval.arg = Nullarg;
1999 rstr = yylval.arg[1].arg_ptr.arg_str;
2000 yylval.arg[1].arg_ptr.arg_str = Nullstr;
2001 arg_free(yylval.arg);
2003 rlen = rstr->str_cur;
2005 complement = delete = squash = 0;
2006 while (*s == 'c' || *s == 'd' || *s == 's') {
2015 arg[2].arg_len = delete|squash;
2018 Zero(tbl, 256, short);
2019 for (i = 0; i < tlen; i++)
2020 tbl[t[i] & 0377] = -1;
2021 for (i = 0, j = 0; i < 256; i++) {
2027 tbl[i] = r[j-1] & 0377;
2032 tbl[i] = r[j++] & 0377;
2037 if (!rlen && !delete) {
2040 for (i = 0; i < 256; i++)
2042 for (i = 0, j = 0; i < tlen; i++,j++) {
2045 if (tbl[t[i] & 0377] == -1)
2046 tbl[t[i] & 0377] = -2;
2051 if (tbl[t[i] & 0377] == -1)
2052 tbl[t[i] & 0377] = r[j] & 0377;
2061 scanstr(start, in_what)
2065 register char *s = start;
2069 register char *send;
2070 register bool makesingle = FALSE;
2071 register STAB *stab;
2072 bool alwaysdollar = FALSE;
2073 bool hereis = FALSE;
2076 /* which backslash sequences to keep */
2077 char *leave = (in_what & SCAN_TR)
2078 ? "\\$@nrtfbeacx0123456789-"
2079 : "\\$@nrtfbeacx0123456789[{]}lLuUE";
2084 arg->arg_type = O_ITEM;
2087 default: /* a substitution replacement */
2088 arg[1].arg_type = A_DOUBLE;
2089 makesingle = TRUE; /* maybe disable runtime scanning */
2099 arg[1].arg_type = A_SINGLE;
2104 else if (s[1] == '.')
2118 yyerror("Illegal octal digit");
2120 case '0': case '1': case '2': case '3': case '4':
2121 case '5': case '6': case '7':
2125 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
2126 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
2130 i += (*s++ & 7) + 9;
2135 str = Str_new(92,0);
2136 str_numset(str,(double)i);
2138 Safefree(str->str_ptr);
2139 str->str_ptr = Nullch;
2140 str->str_len = str->str_cur = 0;
2142 arg[1].arg_ptr.arg_str = str;
2145 case '1': case '2': case '3': case '4': case '5':
2146 case '6': case '7': case '8': case '9': case '.':
2148 arg[1].arg_type = A_SINGLE;
2150 while (isDIGIT(*s) || *s == '_') {
2156 if (*s == '.' && s[1] != '.') {
2158 while (isDIGIT(*s) || *s == '_') {
2165 if (*s && index("eE",*s) && index("+-0123456789",s[1])) {
2167 if (*s == '+' || *s == '-')
2173 str = Str_new(92,0);
2174 str_numset(str,atof(tokenbuf));
2176 Safefree(str->str_ptr);
2177 str->str_ptr = Nullch;
2178 str->str_len = str->str_cur = 0;
2180 arg[1].arg_ptr.arg_str = str;
2183 if (in_what & (SCAN_REPL|SCAN_TR))
2190 if (*++s && index("`'\"",*s)) {
2192 s = cpytill(d,s,bufend,term,&len);
2204 } /* assuming tokenbuf won't clobber */
2209 if (rsfp || !(d=ninstr(s,bufend,d,d+1)))
2210 herewas = str_make(s,bufend-s);
2212 s--, herewas = str_make(s,d-s);
2213 s += herewas->str_cur;
2221 s = cpytill(d,s,bufend,'>',&len);
2225 fatal("Unterminated <> operator");
2228 while (*d && (isALNUM(*d) || *d == '\''))
2230 if (d - tokenbuf != len) {
2233 arg[1].arg_type = A_GLOB;
2235 alwaysdollar = TRUE; /* treat $) and $| as variables */
2241 (void)strcpy(d,"ARGV");
2243 arg[1].arg_type = A_INDREAD;
2244 arg[1].arg_ptr.arg_stab = stabent(d+1,TRUE);
2247 arg[1].arg_type = A_READ;
2248 arg[1].arg_ptr.arg_stab = stabent(d,TRUE);
2249 if (!stab_io(arg[1].arg_ptr.arg_stab))
2250 stab_io(arg[1].arg_ptr.arg_stab) = stio_new();
2251 if (strEQ(d,"ARGV")) {
2252 (void)aadd(arg[1].arg_ptr.arg_stab);
2253 stab_io(arg[1].arg_ptr.arg_stab)->flags |=
2274 arg[1].arg_type = A_SINGLE;
2281 arg[1].arg_type = A_DOUBLE;
2282 makesingle = TRUE; /* maybe disable runtime scanning */
2283 alwaysdollar = TRUE; /* treat $) and $| as variables */
2288 arg[1].arg_type = A_BACKTICK;
2290 alwaysdollar = TRUE; /* treat $) and $| as variables */
2294 STR *tmpstr2 = Nullstr;
2298 multi_start = curcmd->c_line;
2300 multi_open = multi_close = '<';
2303 if (term && (tmps = index("([{< )]}> )]}>",term)))
2307 tmpstr = Str_new(87,80);
2312 while (s < bufend &&
2313 (*s != term || bcmp(s,tokenbuf,len) != 0) ) {
2318 curcmd->c_line = multi_start;
2319 fatal("EOF in string");
2321 str_nset(tmpstr,d+1,s-d);
2323 str_ncat(herewas,s,bufend-s);
2324 str_replace(linestr,herewas);
2325 oldoldbufptr = oldbufptr = bufptr = s = str_get(linestr);
2326 bufend = linestr->str_ptr + linestr->str_cur;
2330 str_nset(tmpstr,"",0); /* avoid "uninitialized" warning */
2333 s = str_append_till(tmpstr,s+1,bufend,term,leave);
2334 while (s >= bufend) { /* multiple line string? */
2336 !(oldoldbufptr = oldbufptr = s = str_gets(linestr, rsfp, 0))) {
2337 curcmd->c_line = multi_start;
2338 fatal("EOF in string");
2342 STR *str = Str_new(88,0);
2344 str_sset(str,linestr);
2345 astore(stab_xarray(curcmd->c_filestab),
2346 (int)curcmd->c_line,str);
2348 bufend = linestr->str_ptr + linestr->str_cur;
2350 if (*s == term && bcmp(s,tokenbuf,len) == 0) {
2353 str_scat(linestr,herewas);
2354 bufend = linestr->str_ptr + linestr->str_cur;
2358 str_scat(tmpstr,linestr);
2362 s = str_append_till(tmpstr,s,bufend,term,leave);
2364 multi_end = curcmd->c_line;
2366 if (tmpstr->str_cur + 5 < tmpstr->str_len) {
2367 tmpstr->str_len = tmpstr->str_cur + 1;
2368 Renew(tmpstr->str_ptr, tmpstr->str_len, char);
2370 if (arg[1].arg_type == A_SINGLE) {
2371 arg[1].arg_ptr.arg_str = tmpstr;
2375 s = tmpstr->str_ptr;
2376 send = s + tmpstr->str_cur;
2377 while (s < send) { /* see if we can make SINGLE */
2378 if (*s == '\\' && s[1] && isDIGIT(s[1]) && !isDIGIT(s[2]) &&
2379 !alwaysdollar && s[1] != '0')
2380 *s = '$'; /* grandfather \digit in subst */
2381 if ((*s == '$' || *s == '@') && s+1 < send &&
2382 (alwaysdollar || (s[1] != ')' && s[1] != '|'))) {
2383 makesingle = FALSE; /* force interpretation */
2385 else if (*s == '\\' && s+1 < send) {
2386 if (index("lLuUE",s[1]))
2392 s = d = tmpstr->str_ptr; /* assuming shrinkage only */
2394 if (in_what & SCAN_TR) {
2395 if (*s != '\\' && s[1] == '-' && s+2 < send) {
2397 if (!tmpstr2) { /* oops, have to grow */
2398 tmpstr2 = str_smake(tmpstr);
2399 s = tmpstr2->str_ptr + (s - tmpstr->str_ptr);
2400 send = tmpstr2->str_ptr + (send - tmpstr->str_ptr);
2402 i = d - tmpstr->str_ptr;
2403 STR_GROW(tmpstr, tmpstr->str_len + 256);
2404 d = tmpstr->str_ptr + i;
2405 for (i = (s[0] & 0377); i <= (s[2] & 0377); i++)
2412 if ((*s == '$' && s+1 < send &&
2413 (alwaysdollar || /*(*/(s[1] != ')' && s[1] != '|')) ) ||
2414 (*s == '@' && s+1 < send) ) {
2415 if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
2417 len = scanident(s,send,tokenbuf) - s;
2418 if (*s == '$' || strEQ(tokenbuf,"ARGV")
2419 || strEQ(tokenbuf,"ENV")
2420 || strEQ(tokenbuf,"SIG")
2421 || strEQ(tokenbuf,"INC") )
2422 (void)stabent(tokenbuf,TRUE); /* add symbol */
2428 if (*s == '\\' && s+1 < send) {
2432 if (!makesingle && (!leave || (*s && index(leave,*s))))
2436 case '0': case '1': case '2': case '3':
2437 case '4': case '5': case '6': case '7':
2438 *d++ = scanoct(s, 3, &len);
2442 *d++ = scanhex(++s, 2, &len);
2481 if (arg[1].arg_type == A_DOUBLE && makesingle)
2482 arg[1].arg_type = A_SINGLE; /* now we can optimize on it */
2484 tmpstr->str_cur = d - tmpstr->str_ptr;
2485 if (arg[1].arg_type == A_GLOB) {
2486 arg[1].arg_ptr.arg_stab = stab = genstab();
2487 stab_io(stab) = stio_new();
2488 str_sset(stab_val(stab), tmpstr);
2491 arg[1].arg_ptr.arg_str = tmpstr;
2509 register FCMD *fprev = &froot;
2510 register FCMD *fcmd;
2517 Zero(&froot, 1, FCMD);
2519 while (s < bufend || (rsfp && (s = str_gets(linestr,rsfp, 0)) != Nullch)) {
2521 if (in_eval && !rsfp) {
2522 eol = index(s,'\n');
2527 eol = bufend = linestr->str_ptr + linestr->str_cur;
2529 STR *tmpstr = Str_new(89,0);
2531 str_nset(tmpstr, s, eol-s);
2532 astore(stab_xarray(curcmd->c_filestab), (int)curcmd->c_line,tmpstr);
2536 for (t = s+1; *t == ' ' || *t == '\t'; t++) ;
2539 return froot.f_next;
2546 flinebeg = Nullfcmd;
2550 Newz(804,fcmd,1,FCMD);
2551 fprev->f_next = fcmd;
2553 for (t=s; t < eol && *t != '@' && *t != '^'; t++) {
2563 fcmd->f_pre = nsavestr(s, t-s);
2564 fcmd->f_presize = t-s;
2568 fcmd->f_flags |= FC_NOBLANK;
2570 fcmd->f_flags |= FC_REPEAT;
2574 flinebeg = fcmd; /* start values here */
2576 fcmd->f_flags |= FC_CHOP; /* for doing text filling */
2579 fcmd->f_type = F_LINES;
2583 fcmd->f_type = F_LEFT;
2588 fcmd->f_type = F_RIGHT;
2593 fcmd->f_type = F_CENTER;
2599 /* Catch the special case @... and handle it as a string
2601 if (*s == '.' && s[1] == '.') {
2602 goto default_format;
2604 fcmd->f_type = F_DECIMAL;
2608 /* Read a format in the form @####.####, where either group
2609 of ### may be empty, or the final .### may be missing. */
2617 fcmd->f_decimals = s-p;
2618 fcmd->f_flags |= FC_DP;
2620 fcmd->f_decimals = 0;
2626 fcmd->f_type = F_LEFT;
2629 if (fcmd->f_flags & FC_CHOP && *s == '.') {
2630 fcmd->f_flags |= FC_MORE;
2639 (!rsfp || (s = str_gets(linestr, rsfp, 0)) == Nullch) )
2642 if (in_eval && !rsfp) {
2643 eol = index(s,'\n');
2648 eol = bufend = linestr->str_ptr + linestr->str_cur;
2650 STR *tmpstr = Str_new(90,0);
2652 str_nset(tmpstr, s, eol-s);
2653 astore(stab_xarray(curcmd->c_filestab),
2654 (int)curcmd->c_line,tmpstr);
2656 if (strnEQ(s,".\n",2)) {
2658 yyerror("Missing values line");
2659 return froot.f_next;
2665 str = flinebeg->f_unparsed = Str_new(91,eol - s);
2666 str->str_u.str_hash = curstash;
2667 str_nset(str,"(",1);
2668 flinebeg->f_line = curcmd->c_line;
2670 if (!flinebeg->f_next->f_type || index(s, ',')) {
2672 str_ncat(str, s, eol - s - 1);
2673 str_ncat(str,",$$);",5);
2678 while (s < eol && isSPACE(*s))
2683 case ' ': case '\t': case '\n': case ';':
2684 str_ncat(str, t, s - t);
2685 str_ncat(str, "," ,1);
2686 while (s < eol && (isSPACE(*s) || *s == ';'))
2691 str_ncat(str, t, s - t);
2693 s = scanident(s,eol,tokenbuf);
2694 str_ncat(str, t, s - t);
2696 if (s < eol && *s && index("$'\"",*s))
2697 str_ncat(str, ",", 1);
2699 case '"': case '\'':
2700 str_ncat(str, t, s - t);
2703 while (s < eol && (*s != *t || s[-1] == '\\'))
2707 str_ncat(str, t, s - t);
2709 if (s < eol && *s && index("$'\"",*s))
2710 str_ncat(str, ",", 1);
2713 yyerror("Please use commas to separate fields");
2716 str_ncat(str,"$$);",4);
2721 bufptr = str_get(linestr);
2722 yyerror("Format not terminated");
2723 return froot.f_next;
2731 cshlen = strlen(cshname);