1 /* $Header: toke.c,v 3.0.1.10 90/10/16 11:20:46 lwall Locked $
3 * Copyright (c) 1989, Larry Wall
5 * You may distribute under the terms of the GNU General Public License
6 * as specified in the README file that comes with the perl 3.0 kit.
9 * Revision 3.0.1.10 90/10/16 11:20:46 lwall
10 * patch29: the length of a search pattern was limited
11 * patch29: added DATA filehandle to read stuff after __END__
12 * patch29: added -M, -A and -C
13 * patch29: added cmp and <=>
14 * patch29: added caller
15 * patch29: added scalar
16 * patch29: added sysread and syswrite
17 * patch29: added SysV IPC
18 * patch29: added waitpid
19 * patch29: tr/// now understands c, d and s options, and handles nulls right
20 * patch29: 0x80000000 now makes unsigned value
21 * patch29: Null could not be used as a delimiter
22 * patch29: added @###.## fields to format
24 * Revision 3.0.1.9 90/08/13 22:37:25 lwall
25 * patch28: defined(@array) and defined(%array) didn't work right
27 * Revision 3.0.1.8 90/08/09 05:39:58 lwall
28 * patch19: added require operator
29 * patch19: added -x switch to extract script from input trash
30 * patch19: bare @name didn't add array to symbol table
31 * patch19: Added __LINE__ and __FILE__ tokens
32 * patch19: Added __END__ token
33 * patch19: Numeric literals are now stored only in floating point
34 * patch19: some support for FPS compiler misfunction
35 * patch19: "\\$foo" not handled right
36 * patch19: program and data can now both come from STDIN
37 * patch19: "here" strings caused warnings about uninitialized variables
39 * Revision 3.0.1.7 90/03/27 16:32:37 lwall
40 * patch16: MSDOS support
41 * patch16: formats didn't work inside eval
42 * patch16: final semicolon in program wasn't optional with -p or -n
44 * Revision 3.0.1.6 90/03/12 17:06:36 lwall
45 * patch13: last semicolon of program is now optional, just for Randal
46 * patch13: added splice operator: @oldelems = splice(@array,$offset,$len,LIST)
48 * Revision 3.0.1.5 90/02/28 18:47:06 lwall
49 * patch9: return grandfathered to never be function call
50 * patch9: non-existent perldb.pl now gives reasonable error message
51 * patch9: perl can now start up other interpreters scripts
52 * patch9: line numbers were bogus during certain portions of foreach evaluation
53 * patch9: null hereis core dumped
55 * Revision 3.0.1.4 89/12/21 20:26:56 lwall
56 * patch7: -d switch incompatible with -p or -n
57 * patch7: " ''$foo'' " didn't parse right
58 * patch7: grandfathered m'pat' and s'pat'repl' to not be package qualifiers
60 * Revision 3.0.1.3 89/11/17 15:43:15 lwall
61 * patch5: IBM PC/RT compiler can't deal with UNI() and LOP() macros
62 * patch5: } misadjusted expection of subsequent term or operator
63 * patch5: y/abcde// didn't work
65 * Revision 3.0.1.2 89/11/11 05:04:42 lwall
66 * patch2: fixed a CLINE macro conflict
68 * Revision 3.0.1.1 89/10/26 23:26:21 lwall
69 * patch1: disambiguated word after "sort" better
71 * Revision 3.0 89/10/18 15:32:33 lwall
84 /* which backslash sequences to keep in m// or s// */
86 static char *patleave = "\\.^$@dDwWsSbB+*?|()-nrtf0123456789[{]}";
88 char *reparse; /* if non-null, scanreg found ${foo[$bar]} */
93 #define CLINE (cmdline = (curcmd->c_line < cmdline ? curcmd->c_line : cmdline))
95 #define META(c) ((c) | 128)
97 #define RETURN(retval) return (bufptr = s,(int)retval)
98 #define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,(int)retval)
99 #define TERM(retval) return (CLINE, expectterm = FALSE,bufptr = s,(int)retval)
100 #define LOOPX(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)LOOPEX)
101 #define FTST(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)FILETEST)
102 #define FUN0(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC0)
103 #define FUN1(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC1)
104 #define FUN2(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2)
105 #define FUN2x(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2x)
106 #define FUN3(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC3)
107 #define FUN4(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC4)
108 #define FUN5(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC5)
109 #define FL(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST)
110 #define FL2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST2)
111 #define HFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)HSHFUN)
112 #define HFUN3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)HSHFUN3)
113 #define LFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LVALFUN)
114 #define AOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)ADDOP)
115 #define MOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)MULOP)
116 #define EOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)EQOP)
117 #define ROP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)RELOP)
118 #define FOP(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP)
119 #define FOP2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP2)
120 #define FOP3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP3)
121 #define FOP4(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP4)
122 #define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
123 #define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
125 /* This bit of chicanery makes a unary function followed by
126 * a parenthesis into a function with one argument, highest precedence.
128 #define UNI(f) return(yylval.ival = f,expectterm = TRUE,bufptr = s, \
129 (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
131 /* This does similarly for list operators, merely by pretending that the
132 * paren came before the listop rather than after.
134 #define LOP(f) return(*s == '(' || (s = skipspace(s), *s == '(') ? \
135 (*s = META('('), bufptr = oldbufptr, '(') : \
136 (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
137 /* grandfather return to old style */
138 #define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
144 while (s < bufend && isascii(*s) && isspace(*s))
153 #define UNI(f) return uni(f,s)
154 #define LOP(f) return lop(f,s)
193 #endif /* CRIPPLED_CC */
197 register char *s = bufptr;
200 static bool in_format = FALSE;
201 static bool firstline = TRUE;
202 extern int yychar; /* last token */
204 oldoldbufptr = oldbufptr;
211 fprintf(stderr,"Tokener at %s",s);
213 fprintf(stderr,"Tokener at %s\n",s);
217 if ((*s & 127) == '(')
220 warn("Unrecognized character \\%03o ignored", *s++);
226 if ((*s & 127) == '(')
229 warn("Unrecognized character \\%03o ignored", *s++);
233 goto fake_eof; /* emulate EOF on ^D or ^Z */
238 goto retry; /* ignore stray nulls */
241 if (minus_n || minus_p || perldb) {
245 char *pdb = getenv("PERLDB");
247 str_cat(linestr, pdb ? pdb : "require 'perldb.pl'");
248 str_cat(linestr, ";");
250 if (minus_n || minus_p) {
251 str_cat(linestr,"line: while (<>) {");
253 str_cat(linestr,"@F=split(' ');");
255 oldoldbufptr = oldbufptr = s = str_get(linestr);
256 bufend = linestr->str_ptr + linestr->str_cur;
262 yylval.formval = load_format();
264 oldoldbufptr = oldbufptr = s = str_get(linestr) + 1;
265 bufend = linestr->str_ptr + linestr->str_cur;
271 #endif /* CRYPTSCRIPT */
273 if ((s = str_gets(linestr, rsfp, 0)) == Nullch) {
277 (void)mypclose(rsfp);
278 else if (rsfp == stdin)
284 if (minus_n || minus_p) {
285 str_set(linestr,minus_p ? ";}continue{print" : "");
286 str_cat(linestr,";}");
287 oldoldbufptr = oldbufptr = s = str_get(linestr);
288 bufend = linestr->str_ptr + linestr->str_cur;
289 minus_n = minus_p = 0;
292 oldoldbufptr = oldbufptr = s = str_get(linestr);
294 RETURN(';'); /* not infinite loop because rsfp is NULL now */
296 if (doextract && *linestr->str_ptr == '#')
299 oldoldbufptr = oldbufptr = bufptr = s;
301 STR *str = Str_new(85,0);
303 str_sset(str,linestr);
304 astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
312 bufend = linestr->str_ptr + linestr->str_cur;
313 if (curcmd->c_line == 1) {
314 if (*s == '#' && s[1] == '!') {
315 if (!in_eval && !instr(s,"perl") && instr(origargv[0],"perl")) {
323 while (s < bufend && !isspace(*s))
326 while (s < bufend && isspace(*s))
329 Newz(899,newargv,origargc+3,char*);
331 while (s < bufend && !isspace(*s))
334 Copy(origargv+1, newargv+2, origargc+1, char*);
340 fatal("Can't exec %s", cmd);
344 while (s < bufend && isspace(*s))
346 if (*s == ':') /* for csh's that have to exec sh scripts */
351 case ' ': case '\t': case '\f':
355 if (preprocess && s == str_get(linestr) &&
356 s[1] == ' ' && isdigit(s[2])) {
357 curcmd->c_line = atoi(s+2)-1;
358 for (s += 2; isdigit(*s); s++) ;
360 while (s < d && isspace(*s)) s++;
361 s[strlen(s)-1] = '\0'; /* wipe out newline */
364 s[strlen(s)-1] = '\0'; /* wipe out trailing quote */
367 curcmd->c_filestab = fstab(s);
369 curcmd->c_filestab = fstab(origfilename);
370 oldoldbufptr = oldbufptr = s = str_get(linestr);
374 if (in_eval && !rsfp) {
376 while (s < d && *s != '\n')
381 STR *str = Str_new(85,0);
383 str_nset(str,linestr->str_ptr, s - linestr->str_ptr);
384 astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
385 str_chop(linestr, s);
389 yylval.formval = load_format();
391 oldoldbufptr = oldbufptr = s = bufptr + 1;
402 if (s[1] && isalpha(s[1]) && !isalpha(s[2])) {
405 case 'r': FTST(O_FTEREAD);
406 case 'w': FTST(O_FTEWRITE);
407 case 'x': FTST(O_FTEEXEC);
408 case 'o': FTST(O_FTEOWNED);
409 case 'R': FTST(O_FTRREAD);
410 case 'W': FTST(O_FTRWRITE);
411 case 'X': FTST(O_FTREXEC);
412 case 'O': FTST(O_FTROWNED);
413 case 'e': FTST(O_FTIS);
414 case 'z': FTST(O_FTZERO);
415 case 's': FTST(O_FTSIZE);
416 case 'f': FTST(O_FTFILE);
417 case 'd': FTST(O_FTDIR);
418 case 'l': FTST(O_FTLINK);
419 case 'p': FTST(O_FTPIPE);
420 case 'S': FTST(O_FTSOCK);
421 case 'u': FTST(O_FTSUID);
422 case 'g': FTST(O_FTSGID);
423 case 'k': FTST(O_FTSVTX);
424 case 'b': FTST(O_FTBLK);
425 case 'c': FTST(O_FTCHR);
426 case 't': FTST(O_FTTTY);
427 case 'T': FTST(O_FTTEXT);
428 case 'B': FTST(O_FTBINARY);
429 case 'M': stabent("\024",TRUE); FTST(O_FTMTIME);
430 case 'A': stabent("\024",TRUE); FTST(O_FTATIME);
431 case 'C': stabent("\024",TRUE); FTST(O_FTCTIME);
459 s = scanreg(s,bufend,tokenbuf);
460 yylval.stabval = stabent(tokenbuf,TRUE);
471 s = scanreg(s,bufend,tokenbuf);
472 yylval.stabval = hadd(stabent(tokenbuf,TRUE));
488 if (isspace(*s) || *s == '#')
489 cmdline = NOLINE; /* invalidate current command line number */
492 if (curcmd->c_line < cmdline)
493 cmdline = curcmd->c_line;
511 while (s < d && isspace(*s))
513 if (isalpha(*s) || *s == '_' || *s == '\'')
514 *(--s) = '\\'; /* force next ident to WORD */
573 while (isascii(*s) && \
574 (isalpha(*s) || isdigit(*s) || *s == '_' || *s == '\'')) \
576 while (d[-1] == '\'') \
582 if (s[1] == '#' && (isalpha(s[2]) || s[2] == '_')) {
584 s = scanreg(s,bufend,tokenbuf);
585 yylval.stabval = aadd(stabent(tokenbuf,TRUE));
589 s = scanreg(s,bufend,tokenbuf);
590 if (reparse) { /* turn ${foo[bar]} into ($foo[bar]) */
598 yylval.stabval = stabent(tokenbuf,TRUE);
603 s = scanreg(s,bufend,tokenbuf);
606 yylval.stabval = aadd(stabent(tokenbuf,TRUE));
609 case '/': /* may either be division or pattern */
610 case '?': /* may either be conditional or pattern */
621 if (!expectterm || !isdigit(s[1])) {
630 case '0': case '1': case '2': case '3': case '4':
631 case '5': case '6': case '7': case '8': case '9':
632 case '\'': case '"': case '`':
636 case '\\': /* some magic to force next word to be a WORD */
637 s++; /* used by do and sub to force a separate namespace */
642 if (strEQ(d,"__LINE__") || strEQ(d,"__FILE__")) {
643 ARG *arg = op_new(1);
646 arg->arg_type = O_ITEM;
648 (void)sprintf(tokenbuf,"%ld",(long)curcmd->c_line);
650 strcpy(tokenbuf, stab_val(curcmd->c_filestab)->str_ptr);
651 arg[1].arg_type = A_SINGLE;
652 arg[1].arg_ptr.arg_str = str_make(tokenbuf,strlen(tokenbuf));
655 else if (strEQ(d,"__END__")) {
660 if (stab = stabent("DATA",FALSE)) {
661 stab->str_pok |= SP_MULTI;
662 stab_io(stab) = stio_new();
663 stab_io(stab)->ifp = rsfp;
664 #if defined(FCNTL) && defined(F_SETFD)
666 fcntl(fd,F_SETFD,fd >= 3);
669 stab_io(stab)->type = '|';
670 else if (rsfp == stdin)
671 stab_io(stab)->type = '-';
673 stab_io(stab)->type = '<';
683 if (strEQ(d,"accept"))
685 if (strEQ(d,"atan2"))
692 if (strEQ(d,"binmode"))
699 if (strEQ(d,"continue"))
701 if (strEQ(d,"chdir")) {
702 (void)stabent("ENV",TRUE); /* may use HOME */
705 if (strEQ(d,"close"))
707 if (strEQ(d,"closedir"))
711 if (strEQ(d,"caller"))
713 if (strEQ(d,"crypt")) {
719 if (strEQ(d,"chmod"))
721 if (strEQ(d,"chown"))
723 if (strEQ(d,"connect"))
727 if (strEQ(d,"chroot"))
734 while (s < d && isspace(*s))
736 if (isalpha(*s) || *s == '_')
737 *(--s) = '\\'; /* force next ident to WORD */
742 if (strEQ(d,"defined"))
744 if (strEQ(d,"delete"))
746 if (strEQ(d,"dbmopen"))
748 if (strEQ(d,"dbmclose"))
757 if (strEQ(d,"elsif")) {
758 yylval.ival = curcmd->c_line;
761 if (strEQ(d,"eq") || strEQ(d,"EQ"))
765 if (strEQ(d,"eval")) {
766 allstabs = TRUE; /* must initialize everything since */
767 UNI(O_EVAL); /* we don't know what will be used */
775 if (strEQ(d,"exec")) {
779 if (strEQ(d,"endhostent"))
781 if (strEQ(d,"endnetent"))
783 if (strEQ(d,"endservent"))
785 if (strEQ(d,"endprotoent"))
787 if (strEQ(d,"endpwent"))
789 if (strEQ(d,"endgrent"))
794 if (strEQ(d,"for") || strEQ(d,"foreach")) {
795 yylval.ival = curcmd->c_line;
798 if (strEQ(d,"format")) {
800 while (s < d && isspace(*s))
802 if (isalpha(*s) || *s == '_')
803 *(--s) = '\\'; /* force next ident to WORD */
805 allstabs = TRUE; /* must initialize everything since */
806 OPERATOR(FORMAT); /* we don't know what will be used */
810 if (strEQ(d,"fcntl"))
812 if (strEQ(d,"fileno"))
814 if (strEQ(d,"flock"))
819 if (strEQ(d,"gt") || strEQ(d,"GT"))
821 if (strEQ(d,"ge") || strEQ(d,"GE"))
827 if (strEQ(d,"gmtime"))
831 if (strnEQ(d,"get",3)) {
838 if (strEQ(d,"priority"))
840 if (strEQ(d,"protobyname"))
842 if (strEQ(d,"protobynumber"))
844 if (strEQ(d,"protoent"))
846 if (strEQ(d,"pwent"))
848 if (strEQ(d,"pwnam"))
850 if (strEQ(d,"pwuid"))
852 if (strEQ(d,"peername"))
855 else if (*d == 'h') {
856 if (strEQ(d,"hostbyname"))
858 if (strEQ(d,"hostbyaddr"))
860 if (strEQ(d,"hostent"))
863 else if (*d == 'n') {
864 if (strEQ(d,"netbyname"))
866 if (strEQ(d,"netbyaddr"))
868 if (strEQ(d,"netent"))
871 else if (*d == 's') {
872 if (strEQ(d,"servbyname"))
874 if (strEQ(d,"servbyport"))
876 if (strEQ(d,"servent"))
878 if (strEQ(d,"sockname"))
880 if (strEQ(d,"sockopt"))
883 else if (*d == 'g') {
884 if (strEQ(d,"grent"))
886 if (strEQ(d,"grnam"))
888 if (strEQ(d,"grgid"))
891 else if (*d == 'l') {
892 if (strEQ(d,"login"))
906 yylval.ival = curcmd->c_line;
909 if (strEQ(d,"index"))
913 if (strEQ(d,"ioctl"))
932 if (strEQ(d,"local"))
934 if (strEQ(d,"length"))
936 if (strEQ(d,"lt") || strEQ(d,"LT"))
938 if (strEQ(d,"le") || strEQ(d,"LE"))
940 if (strEQ(d,"localtime"))
946 if (strEQ(d,"listen"))
948 if (strEQ(d,"lstat"))
964 RETURN(1); /* force error */
968 if (strEQ(d,"mkdir"))
972 if (strEQ(d,"msgctl"))
974 if (strEQ(d,"msgget"))
976 if (strEQ(d,"msgrcv"))
978 if (strEQ(d,"msgsnd"))
987 if (strEQ(d,"ne") || strEQ(d,"NE"))
998 if (strEQ(d,"opendir"))
1003 if (strEQ(d,"print")) {
1004 checkcomma(s,"filehandle");
1007 if (strEQ(d,"printf")) {
1008 checkcomma(s,"filehandle");
1011 if (strEQ(d,"push")) {
1012 yylval.ival = O_PUSH;
1017 if (strEQ(d,"pack"))
1019 if (strEQ(d,"package"))
1021 if (strEQ(d,"pipe"))
1030 if (strEQ(d,"qq")) {
1037 if (strEQ(d,"return"))
1039 if (strEQ(d,"require")) {
1040 allstabs = TRUE; /* must initialize everything since */
1041 UNI(O_REQUIRE); /* we don't know what will be used */
1043 if (strEQ(d,"reset"))
1045 if (strEQ(d,"redo"))
1047 if (strEQ(d,"rename"))
1049 if (strEQ(d,"rand"))
1051 if (strEQ(d,"rmdir"))
1053 if (strEQ(d,"rindex"))
1055 if (strEQ(d,"read"))
1057 if (strEQ(d,"readdir"))
1059 if (strEQ(d,"rewinddir"))
1061 if (strEQ(d,"recv"))
1063 if (strEQ(d,"reverse"))
1065 if (strEQ(d,"readlink"))
1081 RETURN(1); /* force error */
1088 if (strEQ(d,"scalar"))
1094 if (strEQ(d,"select"))
1096 if (strEQ(d,"seek"))
1098 if (strEQ(d,"semctl"))
1100 if (strEQ(d,"semget"))
1102 if (strEQ(d,"semop"))
1104 if (strEQ(d,"send"))
1106 if (strEQ(d,"setpgrp"))
1108 if (strEQ(d,"setpriority"))
1109 FUN3(O_SETPRIORITY);
1110 if (strEQ(d,"sethostent"))
1112 if (strEQ(d,"setnetent"))
1114 if (strEQ(d,"setservent"))
1116 if (strEQ(d,"setprotoent"))
1118 if (strEQ(d,"setpwent"))
1120 if (strEQ(d,"setgrent"))
1122 if (strEQ(d,"seekdir"))
1124 if (strEQ(d,"setsockopt"))
1131 if (strEQ(d,"shift"))
1133 if (strEQ(d,"shmctl"))
1135 if (strEQ(d,"shmget"))
1137 if (strEQ(d,"shmread"))
1139 if (strEQ(d,"shmwrite"))
1141 if (strEQ(d,"shutdown"))
1152 if (strEQ(d,"sleep"))
1159 if (strEQ(d,"socket"))
1161 if (strEQ(d,"socketpair"))
1163 if (strEQ(d,"sort")) {
1164 checkcomma(s,"subroutine name");
1166 while (s < d && isascii(*s) && isspace(*s)) s++;
1167 if (*s == ';' || *s == ')') /* probably a close */
1168 fatal("sort is now a reserved word");
1169 if (isascii(*s) && (isalpha(*s) || *s == '_')) {
1170 for (d = s; isalpha(*d) || isdigit(*d) || *d == '_'; d++) ;
1171 strncpy(tokenbuf,s,d-s);
1172 if (strNE(tokenbuf,"keys") &&
1173 strNE(tokenbuf,"values") &&
1174 strNE(tokenbuf,"split") &&
1175 strNE(tokenbuf,"grep") &&
1176 strNE(tokenbuf,"readdir") &&
1177 strNE(tokenbuf,"unpack") &&
1178 strNE(tokenbuf,"do") &&
1179 (d >= bufend || isspace(*d)) )
1180 *(--s) = '\\'; /* force next ident to WORD */
1186 if (strEQ(d,"split"))
1188 if (strEQ(d,"sprintf"))
1190 if (strEQ(d,"splice")) {
1191 yylval.ival = O_SPLICE;
1196 if (strEQ(d,"sqrt"))
1200 if (strEQ(d,"srand"))
1206 if (strEQ(d,"stat"))
1208 if (strEQ(d,"study")) {
1214 if (strEQ(d,"substr"))
1216 if (strEQ(d,"sub")) {
1217 subline = curcmd->c_line;
1219 while (s < d && isspace(*s))
1221 if (isalpha(*s) || *s == '_' || *s == '\'') {
1223 str_sset(subname,curstname);
1224 str_ncat(subname,"'",1);
1226 isalpha(*d) || isdigit(*d) || *d == '_' || *d == '\'';
1230 str_ncat(subname,s,d-s);
1232 *(--s) = '\\'; /* force next ident to WORD */
1235 str_set(subname,"?");
1244 if (strEQ(d,"system")) {
1248 if (strEQ(d,"symlink"))
1250 if (strEQ(d,"syscall"))
1252 if (strEQ(d,"sysread"))
1254 if (strEQ(d,"syswrite"))
1263 if (strEQ(d,"tr")) {
1268 RETURN(1); /* force error */
1270 if (strEQ(d,"tell"))
1272 if (strEQ(d,"telldir"))
1274 if (strEQ(d,"time"))
1276 if (strEQ(d,"times"))
1278 if (strEQ(d,"truncate"))
1283 if (strEQ(d,"using"))
1285 if (strEQ(d,"until")) {
1286 yylval.ival = curcmd->c_line;
1289 if (strEQ(d,"unless")) {
1290 yylval.ival = curcmd->c_line;
1293 if (strEQ(d,"unlink"))
1295 if (strEQ(d,"undef"))
1297 if (strEQ(d,"unpack"))
1299 if (strEQ(d,"utime"))
1301 if (strEQ(d,"umask"))
1303 if (strEQ(d,"unshift")) {
1304 yylval.ival = O_UNSHIFT;
1310 if (strEQ(d,"values"))
1312 if (strEQ(d,"vec")) {
1319 if (strEQ(d,"while")) {
1320 yylval.ival = curcmd->c_line;
1323 if (strEQ(d,"warn"))
1325 if (strEQ(d,"wait"))
1327 if (strEQ(d,"waitpid"))
1329 if (strEQ(d,"wantarray")) {
1330 yylval.arg = op_new(1);
1331 yylval.arg->arg_type = O_ITEM;
1332 yylval.arg[1].arg_type = A_WANTARRAY;
1335 if (strEQ(d,"write"))
1340 if (!expectterm && strEQ(d,"x"))
1360 yylval.cval = savestr(d);
1362 if (oldoldbufptr && oldoldbufptr < bufptr) {
1363 while (isspace(*oldoldbufptr))
1365 if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5))
1367 else if (*oldoldbufptr == 's' && strnEQ(oldoldbufptr,"sort",4))
1370 return (CLINE, bufptr = s, (int)WORD);
1382 while (s < bufend && isascii(*s) && isspace(*s))
1384 if (isascii(*s) && (isalpha(*s) || *s == '_')) {
1386 while (isalpha(*s) || isdigit(*s) || *s == '_')
1388 while (s < bufend && isspace(*s))
1393 "tell eof times getlogin wait length shift umask getppid \
1394 cos exp int log rand sin sqrt ord wantarray",
1399 fatal("No comma allowed after %s", what);
1405 scanreg(s,send,dest)
1407 register char *send;
1421 while (isalpha(*s) || isdigit(*s) || *s == '_' || *s == '\'')
1424 while (d > dest+1 && d[-1] == '\'')
1430 if (*d == '{' /* } */ ) {
1433 while (s < send && brackets) {
1434 if (!reparse && (d == dest || (*s && isascii(*s) &&
1435 (isalpha(*s) || isdigit(*s) || *s == '_') ))) {
1445 if (reparse && reparse == s - 1)
1459 if (*d == '^' && !isspace(*s))
1465 scanconst(string,len)
1469 register STR *retstr;
1474 if (index(string,'|')) {
1477 retstr = Str_new(86,len);
1478 str_nset(retstr,string,len);
1479 t = str_get(retstr);
1481 retstr->str_u.str_useful = 100;
1482 for (d=t; d < e; ) {
1490 case '.': case '[': case '$': case '(': case ')': case '|': case '+':
1494 if (d[1] && index("wWbB0123456789sSdD",d[1])) {
1498 (void)bcopy(d+1,d,e-d);
1517 if (d[1] == '*' || (d[1] == '{' && d[2] == '0') || d[1] == '?') {
1529 retstr->str_cur = d - t;
1537 register SPAT *spat;
1542 STR *str = Str_new(93,0);
1544 Newz(801,spat,1,SPAT);
1545 spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
1546 curstash->tbl_spatroot = spat;
1555 spat->spat_flags |= SPAT_ONCE;
1558 fatal("panic: scanpat");
1560 s = str_append_till(str,s,bufend,s[-1],patleave);
1563 yyerror("Search pattern not terminated");
1564 yylval.arg = Nullarg;
1568 while (*s == 'i' || *s == 'o') {
1572 spat->spat_flags |= SPAT_FOLD;
1576 spat->spat_flags |= SPAT_KEEP;
1580 e = str->str_ptr + len;
1581 for (d = str->str_ptr; d < e; d++) {
1584 else if ((*d == '$' && d[1] && d[1] != '|' && d[1] != ')') ||
1588 spat->spat_runtime = arg = op_new(1);
1589 arg->arg_type = O_ITEM;
1590 arg[1].arg_type = A_DOUBLE;
1591 arg[1].arg_ptr.arg_str = str_smake(str);
1592 d = scanreg(d,bufend,buf);
1593 (void)stabent(buf,TRUE); /* make sure it's created */
1594 for (; d < e; d++) {
1597 else if (*d == '$' && d[1] && d[1] != '|' && d[1] != ')') {
1598 d = scanreg(d,bufend,buf);
1599 (void)stabent(buf,TRUE);
1601 else if (*d == '@') {
1602 d = scanreg(d,bufend,buf);
1603 if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
1604 strEQ(buf,"SIG") || strEQ(buf,"INC"))
1605 (void)stabent(buf,TRUE);
1608 goto got_pat; /* skip compiling for now */
1611 if (spat->spat_flags & SPAT_FOLD)
1615 (void)bcopy((char *)spat, (char *)&savespat, sizeof(SPAT));
1617 if (*str->str_ptr == '^') {
1618 spat->spat_short = scanconst(str->str_ptr+1,len-1);
1619 if (spat->spat_short) {
1620 spat->spat_slen = spat->spat_short->str_cur;
1621 if (spat->spat_slen == len - 1)
1622 spat->spat_flags |= SPAT_ALL;
1626 spat->spat_flags |= SPAT_SCANFIRST;
1627 spat->spat_short = scanconst(str->str_ptr,len);
1628 if (spat->spat_short) {
1629 spat->spat_slen = spat->spat_short->str_cur;
1630 if (spat->spat_slen == len)
1631 spat->spat_flags |= SPAT_ALL;
1634 if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
1635 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1636 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1637 spat->spat_flags & SPAT_FOLD);
1638 /* Note that this regexp can still be used if someone says
1639 * something like /a/ && s//b/; so we can't delete it.
1643 if (spat->spat_flags & SPAT_FOLD)
1647 (void)bcopy((char *)&savespat, (char *)spat, sizeof(SPAT));
1649 if (spat->spat_short)
1650 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1651 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1652 spat->spat_flags & SPAT_FOLD,1);
1657 yylval.arg = make_match(O_MATCH,stab2arg(A_STAB,defstab),spat);
1665 register SPAT *spat;
1669 STR *str = Str_new(93,0);
1671 Newz(802,spat,1,SPAT);
1672 spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
1673 curstash->tbl_spatroot = spat;
1675 s = str_append_till(str,s+1,bufend,*s,patleave);
1678 yyerror("Substitution pattern not terminated");
1679 yylval.arg = Nullarg;
1683 e = str->str_ptr + len;
1684 for (d = str->str_ptr; d < e; d++) {
1687 else if ((*d == '$' && d[1] && d[1] != '|' && /*(*/ d[1] != ')') ||
1691 spat->spat_runtime = arg = op_new(1);
1692 arg->arg_type = O_ITEM;
1693 arg[1].arg_type = A_DOUBLE;
1694 arg[1].arg_ptr.arg_str = str_smake(str);
1695 d = scanreg(d,bufend,buf);
1696 (void)stabent(buf,TRUE); /* make sure it's created */
1698 if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') {
1699 d = scanreg(d,bufend,buf);
1700 (void)stabent(buf,TRUE);
1702 else if (*d == '@' && d[-1] != '\\') {
1703 d = scanreg(d,bufend,buf);
1704 if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
1705 strEQ(buf,"SIG") || strEQ(buf,"INC"))
1706 (void)stabent(buf,TRUE);
1709 goto get_repl; /* skip compiling for now */
1712 if (*str->str_ptr == '^') {
1713 spat->spat_short = scanconst(str->str_ptr+1,len-1);
1714 if (spat->spat_short)
1715 spat->spat_slen = spat->spat_short->str_cur;
1718 spat->spat_flags |= SPAT_SCANFIRST;
1719 spat->spat_short = scanconst(str->str_ptr,len);
1720 if (spat->spat_short)
1721 spat->spat_slen = spat->spat_short->str_cur;
1727 yyerror("Substitution replacement not terminated");
1728 yylval.arg = Nullarg;
1731 spat->spat_repl = yylval.arg;
1732 spat->spat_flags |= SPAT_ONCE;
1733 if ((spat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
1734 spat->spat_flags |= SPAT_CONST;
1735 else if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE) {
1739 spat->spat_flags |= SPAT_CONST;
1740 tmpstr = spat->spat_repl[1].arg_ptr.arg_str;
1741 e = tmpstr->str_ptr + tmpstr->str_cur;
1742 for (t = tmpstr->str_ptr; t < e; t++) {
1743 if (*t == '$' && t[1] && (index("`'&+0123456789",t[1]) ||
1744 (t[1] == '{' /*}*/ && isdigit(t[2])) ))
1745 spat->spat_flags &= ~SPAT_CONST;
1748 while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
1751 if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
1752 spat->spat_repl[1].arg_type = A_SINGLE;
1753 spat->spat_repl = make_op(O_EVAL,2,
1757 spat->spat_flags &= ~SPAT_CONST;
1761 spat->spat_flags &= ~SPAT_ONCE;
1766 spat->spat_flags |= SPAT_FOLD;
1767 if (!(spat->spat_flags & SPAT_SCANFIRST)) {
1768 str_free(spat->spat_short); /* anchored opt doesn't do */
1769 spat->spat_short = Nullstr; /* case insensitive match */
1770 spat->spat_slen = 0;
1775 spat->spat_flags |= SPAT_KEEP;
1778 if (spat->spat_short && (spat->spat_flags & SPAT_SCANFIRST))
1779 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1780 if (!spat->spat_runtime) {
1781 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1782 spat->spat_flags & SPAT_FOLD,1);
1785 yylval.arg = make_match(O_SUBST,stab2arg(A_STAB,defstab),spat);
1791 register SPAT *spat;
1793 if (spat->spat_regexp->regmust) { /* is there a better short-circuit? */
1794 if (spat->spat_short &&
1795 str_eq(spat->spat_short,spat->spat_regexp->regmust))
1797 if (spat->spat_flags & SPAT_SCANFIRST) {
1798 str_free(spat->spat_short);
1799 spat->spat_short = Nullstr;
1802 str_free(spat->spat_regexp->regmust);
1803 spat->spat_regexp->regmust = Nullstr;
1807 if (!spat->spat_short || /* promote the better string */
1808 ((spat->spat_flags & SPAT_SCANFIRST) &&
1809 (spat->spat_short->str_cur < spat->spat_regexp->regmust->str_cur) )){
1810 str_free(spat->spat_short); /* ok if null */
1811 spat->spat_short = spat->spat_regexp->regmust;
1812 spat->spat_regexp->regmust = Nullstr;
1813 spat->spat_flags |= SPAT_SCANFIRST;
1819 expand_charset(s,len,retlen)
1825 register char *d = t;
1827 register char *send = s + len;
1829 while (s < send && d - t <= 256) {
1830 if (s[1] == '-' && s+2 < send) {
1831 for (i = s[0]; i <= s[2]; i++)
1840 return nsavestr(t,d-t);
1848 l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
1851 register short *tbl;
1859 New(803,tbl,256,short);
1860 arg[2].arg_type = A_NULL;
1861 arg[2].arg_ptr.arg_cval = (char*) tbl;
1864 yyerror("Translation pattern not terminated");
1865 yylval.arg = Nullarg;
1868 t = expand_charset(yylval.arg[1].arg_ptr.arg_str->str_ptr,
1869 yylval.arg[1].arg_ptr.arg_str->str_cur,&tlen);
1870 free_arg(yylval.arg);
1873 yyerror("Translation replacement not terminated");
1874 yylval.arg = Nullarg;
1877 complement = delete = squash = 0;
1878 while (*s == 'c' || *s == 'd' || *s == 's') {
1887 r = expand_charset(yylval.arg[1].arg_ptr.arg_str->str_ptr,
1888 yylval.arg[1].arg_ptr.arg_str->str_cur,&rlen);
1889 free_arg(yylval.arg);
1890 arg[2].arg_len = delete|squash;
1892 if (!rlen && !delete) {
1897 Zero(tbl, 256, short);
1898 for (i = 0; i < tlen; i++)
1899 tbl[t[i] & 0377] = -1;
1900 for (i = 0, j = 0; i < 256; i++,j++) {
1914 for (i = 0; i < 256; i++)
1916 for (i = 0, j = 0; i < tlen; i++,j++) {
1919 if (tbl[t[i] & 0377] == -1)
1920 tbl[t[i] & 0377] = -2;
1925 if (tbl[t[i] & 0377] == -1)
1926 tbl[t[i] & 0377] = r[j];
1942 register char *send;
1943 register bool makesingle = FALSE;
1944 register STAB *stab;
1945 bool alwaysdollar = FALSE;
1946 bool hereis = FALSE;
1949 char *leave = "\\$@nrtfb0123456789[{]}"; /* which backslash sequences to keep */
1954 arg->arg_type = O_ITEM;
1957 default: /* a substitution replacement */
1958 arg[1].arg_type = A_DOUBLE;
1959 makesingle = TRUE; /* maybe disable runtime scanning */
1969 arg[1].arg_type = A_SINGLE;
1974 else if (s[1] == '.')
1985 yyerror("Illegal octal digit");
1987 case '0': case '1': case '2': case '3': case '4':
1988 case '5': case '6': case '7':
1992 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1993 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1997 i += (*s++ & 7) + 9;
2002 str = Str_new(92,0);
2003 str_numset(str,(double)i);
2005 Safefree(str->str_ptr);
2006 str->str_ptr = Nullch;
2007 str->str_len = str->str_cur = 0;
2009 arg[1].arg_ptr.arg_str = str;
2012 case '1': case '2': case '3': case '4': case '5':
2013 case '6': case '7': case '8': case '9': case '.':
2015 arg[1].arg_type = A_SINGLE;
2017 while (isdigit(*s) || *s == '_') {
2023 if (*s == '.' && s[1] && index("0123456789eE ;",s[1])) {
2025 while (isdigit(*s) || *s == '_') {
2032 if (*s && index("eE",*s) && index("+-0123456789",s[1])) {
2034 if (*s == '+' || *s == '-')
2040 str = Str_new(92,0);
2041 str_numset(str,atof(tokenbuf));
2043 Safefree(str->str_ptr);
2044 str->str_ptr = Nullch;
2045 str->str_len = str->str_cur = 0;
2047 arg[1].arg_ptr.arg_str = str;
2055 if (*++s && index("`'\"",*s)) {
2057 s = cpytill(d,s,bufend,term,&len);
2067 while (isascii(*s) && (isalpha(*s) || isdigit(*s) || *s == '_'))
2069 } /* assuming tokenbuf won't clobber */
2074 if (rsfp || !(d=ninstr(s,bufend,d,d+1)))
2075 herewas = str_make(s,bufend-s);
2077 s--, herewas = str_make(s,d-s);
2078 s += herewas->str_cur;
2086 s = cpytill(d,s,bufend,'>',&len);
2091 (isalpha(*d) || isdigit(*d) || *d == '_' || *d == '\''))
2093 if (d - tokenbuf != len) {
2095 arg[1].arg_type = A_GLOB;
2096 d = nsavestr(d,len);
2097 arg[1].arg_ptr.arg_stab = stab = genstab();
2098 stab_io(stab) = stio_new();
2099 stab_val(stab) = str_make(d,len);
2106 (void)strcpy(d,"ARGV");
2108 arg[1].arg_type = A_INDREAD;
2109 arg[1].arg_ptr.arg_stab = stabent(d+1,TRUE);
2112 arg[1].arg_type = A_READ;
2113 arg[1].arg_ptr.arg_stab = stabent(d,TRUE);
2114 if (!stab_io(arg[1].arg_ptr.arg_stab))
2115 stab_io(arg[1].arg_ptr.arg_stab) = stio_new();
2116 if (strEQ(d,"ARGV")) {
2117 (void)aadd(arg[1].arg_ptr.arg_stab);
2118 stab_io(arg[1].arg_ptr.arg_stab)->flags |=
2135 arg[1].arg_type = A_SINGLE;
2142 arg[1].arg_type = A_DOUBLE;
2143 makesingle = TRUE; /* maybe disable runtime scanning */
2144 alwaysdollar = TRUE; /* treat $) and $| as variables */
2149 arg[1].arg_type = A_BACKTICK;
2151 alwaysdollar = TRUE; /* treat $) and $| as variables */
2157 multi_start = curcmd->c_line;
2159 multi_open = multi_close = '<';
2162 if (term && (tmps = index("([{< )]}> )]}>",term)))
2166 tmpstr = Str_new(87,80);
2171 while (s < bufend &&
2172 (*s != term || bcmp(s,tokenbuf,len) != 0) ) {
2177 curcmd->c_line = multi_start;
2178 fatal("EOF in string");
2180 str_nset(tmpstr,d+1,s-d);
2182 str_ncat(herewas,s,bufend-s);
2183 str_replace(linestr,herewas);
2184 oldoldbufptr = oldbufptr = bufptr = s = str_get(linestr);
2185 bufend = linestr->str_ptr + linestr->str_cur;
2189 str_nset(tmpstr,"",0); /* avoid "uninitialized" warning */
2192 s = str_append_till(tmpstr,s+1,bufend,term,leave);
2193 while (s >= bufend) { /* multiple line string? */
2195 !(oldoldbufptr = oldbufptr = s = str_gets(linestr, rsfp, 0))) {
2196 curcmd->c_line = multi_start;
2197 fatal("EOF in string");
2201 STR *str = Str_new(88,0);
2203 str_sset(str,linestr);
2204 astore(stab_xarray(curcmd->c_filestab),
2205 (int)curcmd->c_line,str);
2207 bufend = linestr->str_ptr + linestr->str_cur;
2209 if (*s == term && bcmp(s,tokenbuf,len) == 0) {
2212 str_scat(linestr,herewas);
2213 bufend = linestr->str_ptr + linestr->str_cur;
2217 str_scat(tmpstr,linestr);
2221 s = str_append_till(tmpstr,s,bufend,term,leave);
2223 multi_end = curcmd->c_line;
2225 if (tmpstr->str_cur + 5 < tmpstr->str_len) {
2226 tmpstr->str_len = tmpstr->str_cur + 1;
2227 Renew(tmpstr->str_ptr, tmpstr->str_len, char);
2229 if ((arg[1].arg_type & A_MASK) == A_SINGLE) {
2230 arg[1].arg_ptr.arg_str = tmpstr;
2234 s = tmpstr->str_ptr;
2235 send = s + tmpstr->str_cur;
2236 while (s < send) { /* see if we can make SINGLE */
2237 if (*s == '\\' && s[1] && isdigit(s[1]) && !isdigit(s[2]) &&
2238 !alwaysdollar && s[1] != '0')
2239 *s = '$'; /* grandfather \digit in subst */
2240 if ((*s == '$' || *s == '@') && s+1 < send &&
2241 (alwaysdollar || (s[1] != ')' && s[1] != '|'))) {
2242 makesingle = FALSE; /* force interpretation */
2244 else if (*s == '\\' && s+1 < send) {
2249 s = d = tmpstr->str_ptr; /* assuming shrinkage only */
2251 if ((*s == '$' && s+1 < send &&
2252 (alwaysdollar || /*(*/ (s[1] != ')' && s[1] != '|')) ) ||
2253 (*s == '@' && s+1 < send) ) {
2254 len = scanreg(s,send,tokenbuf) - s;
2255 if (*s == '$' || strEQ(tokenbuf,"ARGV")
2256 || strEQ(tokenbuf,"ENV")
2257 || strEQ(tokenbuf,"SIG")
2258 || strEQ(tokenbuf,"INC") )
2259 (void)stabent(tokenbuf,TRUE); /* make sure it exists */
2264 else if (*s == '\\' && s+1 < send) {
2268 if (!makesingle && (!leave || (*s && index(leave,*s))))
2272 case '0': case '1': case '2': case '3':
2273 case '4': case '5': case '6': case '7':
2275 if (s < send && *s && index("01234567",*s)) {
2279 if (s < send && *s && index("01234567",*s)) {
2308 if ((arg[1].arg_type & A_MASK) == A_DOUBLE && makesingle)
2309 arg[1].arg_type = A_SINGLE; /* now we can optimize on it */
2311 tmpstr->str_cur = d - tmpstr->str_ptr;
2312 arg[1].arg_ptr.arg_str = tmpstr;
2328 register FCMD *fprev = &froot;
2329 register FCMD *fcmd;
2336 Zero(&froot, 1, FCMD);
2338 while (s < bufend || (s = str_gets(linestr,rsfp, 0)) != Nullch) {
2340 if (in_eval && !rsfp) {
2341 eol = index(s,'\n');
2346 eol = bufend = linestr->str_ptr + linestr->str_cur;
2348 STR *tmpstr = Str_new(89,0);
2350 str_nset(tmpstr, s, eol-s);
2351 astore(stab_xarray(curcmd->c_filestab), (int)curcmd->c_line,tmpstr);
2353 if (strnEQ(s,".\n",2)) {
2355 return froot.f_next;
2361 flinebeg = Nullfcmd;
2365 Newz(804,fcmd,1,FCMD);
2366 fprev->f_next = fcmd;
2368 for (t=s; t < eol && *t != '@' && *t != '^'; t++) {
2378 fcmd->f_pre = nsavestr(s, t-s);
2379 fcmd->f_presize = t-s;
2383 fcmd->f_flags |= FC_NOBLANK;
2385 fcmd->f_flags |= FC_REPEAT;
2389 flinebeg = fcmd; /* start values here */
2391 fcmd->f_flags |= FC_CHOP; /* for doing text filling */
2394 fcmd->f_type = F_LINES;
2398 fcmd->f_type = F_LEFT;
2403 fcmd->f_type = F_RIGHT;
2408 fcmd->f_type = F_CENTER;
2414 /* Catch the special case @... and handle it as a string
2416 if (*s == '.' && s[1] == '.') {
2417 goto default_format;
2419 fcmd->f_type = F_DECIMAL;
2423 /* Read a format in the form @####.####, where either group
2424 of ### may be empty, or the final .### may be missing. */
2432 fcmd->f_decimals = s-p;
2433 fcmd->f_flags |= FC_DP;
2435 fcmd->f_decimals = 0;
2441 fcmd->f_type = F_LEFT;
2444 if (fcmd->f_flags & FC_CHOP && *s == '.') {
2445 fcmd->f_flags |= FC_MORE;
2453 if (s >= bufend && (s = str_gets(linestr, rsfp, 0)) == Nullch)
2456 if (in_eval && !rsfp) {
2457 eol = index(s,'\n');
2462 eol = bufend = linestr->str_ptr + linestr->str_cur;
2464 STR *tmpstr = Str_new(90,0);
2466 str_nset(tmpstr, s, eol-s);
2467 astore(stab_xarray(curcmd->c_filestab),
2468 (int)curcmd->c_line,tmpstr);
2470 if (strnEQ(s,".\n",2)) {
2472 yyerror("Missing values line");
2473 return froot.f_next;
2479 str = flinebeg->f_unparsed = Str_new(91,eol - s);
2480 str->str_u.str_hash = curstash;
2481 str_nset(str,"(",1);
2482 flinebeg->f_line = curcmd->c_line;
2484 if (!flinebeg->f_next->f_type || index(s, ',')) {
2486 str_ncat(str, s, eol - s - 1);
2487 str_ncat(str,",$$);",5);
2492 while (s < eol && isspace(*s))
2497 case ' ': case '\t': case '\n': case ';':
2498 str_ncat(str, t, s - t);
2499 str_ncat(str, "," ,1);
2500 while (s < eol && (isspace(*s) || *s == ';'))
2505 str_ncat(str, t, s - t);
2507 s = scanreg(s,eol,tokenbuf);
2508 str_ncat(str, t, s - t);
2510 if (s < eol && *s && index("$'\"",*s))
2511 str_ncat(str, ",", 1);
2513 case '"': case '\'':
2514 str_ncat(str, t, s - t);
2517 while (s < eol && (*s != *t || s[-1] == '\\'))
2521 str_ncat(str, t, s - t);
2523 if (s < eol && *s && index("$'\"",*s))
2524 str_ncat(str, ",", 1);
2527 yyerror("Please use commas to separate fields");
2530 str_ncat(str,"$$);",4);
2535 bufptr = str_get(linestr);
2536 yyerror("Format not terminated");
2537 return froot.f_next;
2544 cshlen = strlen(cshname);