1 /* $Header: toke.c,v 3.0.1.11 90/11/10 02:13:44 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.11 90/11/10 02:13:44 lwall
10 * patch38: added alarm function
11 * patch38: tr was busted in metacharacters on signed char machines
13 * Revision 3.0.1.10 90/10/16 11:20:46 lwall
14 * patch29: the length of a search pattern was limited
15 * patch29: added DATA filehandle to read stuff after __END__
16 * patch29: added -M, -A and -C
17 * patch29: added cmp and <=>
18 * patch29: added caller
19 * patch29: added scalar
20 * patch29: added sysread and syswrite
21 * patch29: added SysV IPC
22 * patch29: added waitpid
23 * patch29: tr/// now understands c, d and s options, and handles nulls right
24 * patch29: 0x80000000 now makes unsigned value
25 * patch29: Null could not be used as a delimiter
26 * patch29: added @###.## fields to format
28 * Revision 3.0.1.9 90/08/13 22:37:25 lwall
29 * patch28: defined(@array) and defined(%array) didn't work right
31 * Revision 3.0.1.8 90/08/09 05:39:58 lwall
32 * patch19: added require operator
33 * patch19: added -x switch to extract script from input trash
34 * patch19: bare @name didn't add array to symbol table
35 * patch19: Added __LINE__ and __FILE__ tokens
36 * patch19: Added __END__ token
37 * patch19: Numeric literals are now stored only in floating point
38 * patch19: some support for FPS compiler misfunction
39 * patch19: "\\$foo" not handled right
40 * patch19: program and data can now both come from STDIN
41 * patch19: "here" strings caused warnings about uninitialized variables
43 * Revision 3.0.1.7 90/03/27 16:32:37 lwall
44 * patch16: MSDOS support
45 * patch16: formats didn't work inside eval
46 * patch16: final semicolon in program wasn't optional with -p or -n
48 * Revision 3.0.1.6 90/03/12 17:06:36 lwall
49 * patch13: last semicolon of program is now optional, just for Randal
50 * patch13: added splice operator: @oldelems = splice(@array,$offset,$len,LIST)
52 * Revision 3.0.1.5 90/02/28 18:47:06 lwall
53 * patch9: return grandfathered to never be function call
54 * patch9: non-existent perldb.pl now gives reasonable error message
55 * patch9: perl can now start up other interpreters scripts
56 * patch9: line numbers were bogus during certain portions of foreach evaluation
57 * patch9: null hereis core dumped
59 * Revision 3.0.1.4 89/12/21 20:26:56 lwall
60 * patch7: -d switch incompatible with -p or -n
61 * patch7: " ''$foo'' " didn't parse right
62 * patch7: grandfathered m'pat' and s'pat'repl' to not be package qualifiers
64 * Revision 3.0.1.3 89/11/17 15:43:15 lwall
65 * patch5: IBM PC/RT compiler can't deal with UNI() and LOP() macros
66 * patch5: } misadjusted expection of subsequent term or operator
67 * patch5: y/abcde// didn't work
69 * Revision 3.0.1.2 89/11/11 05:04:42 lwall
70 * patch2: fixed a CLINE macro conflict
72 * Revision 3.0.1.1 89/10/26 23:26:21 lwall
73 * patch1: disambiguated word after "sort" better
75 * Revision 3.0 89/10/18 15:32:33 lwall
88 /* which backslash sequences to keep in m// or s// */
90 static char *patleave = "\\.^$@dDwWsSbB+*?|()-nrtf0123456789[{]}";
92 char *reparse; /* if non-null, scanreg found ${foo[$bar]} */
97 #define CLINE (cmdline = (curcmd->c_line < cmdline ? curcmd->c_line : cmdline))
99 #define META(c) ((c) | 128)
101 #define RETURN(retval) return (bufptr = s,(int)retval)
102 #define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,(int)retval)
103 #define TERM(retval) return (CLINE, expectterm = FALSE,bufptr = s,(int)retval)
104 #define LOOPX(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)LOOPEX)
105 #define FTST(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)FILETEST)
106 #define FUN0(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC0)
107 #define FUN1(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC1)
108 #define FUN2(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2)
109 #define FUN2x(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2x)
110 #define FUN3(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC3)
111 #define FUN4(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC4)
112 #define FUN5(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC5)
113 #define FL(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST)
114 #define FL2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST2)
115 #define HFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)HSHFUN)
116 #define HFUN3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)HSHFUN3)
117 #define LFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LVALFUN)
118 #define AOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)ADDOP)
119 #define MOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)MULOP)
120 #define EOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)EQOP)
121 #define ROP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)RELOP)
122 #define FOP(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP)
123 #define FOP2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP2)
124 #define FOP3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP3)
125 #define FOP4(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP4)
126 #define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
127 #define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
129 /* This bit of chicanery makes a unary function followed by
130 * a parenthesis into a function with one argument, highest precedence.
132 #define UNI(f) return(yylval.ival = f,expectterm = TRUE,bufptr = s, \
133 (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
135 /* This does similarly for list operators, merely by pretending that the
136 * paren came before the listop rather than after.
138 #define LOP(f) return(*s == '(' || (s = skipspace(s), *s == '(') ? \
139 (*s = META('('), bufptr = oldbufptr, '(') : \
140 (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
141 /* grandfather return to old style */
142 #define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
148 while (s < bufend && isascii(*s) && isspace(*s))
157 #define UNI(f) return uni(f,s)
158 #define LOP(f) return lop(f,s)
197 #endif /* CRIPPLED_CC */
201 register char *s = bufptr;
204 static bool in_format = FALSE;
205 static bool firstline = TRUE;
206 extern int yychar; /* last token */
208 oldoldbufptr = oldbufptr;
215 fprintf(stderr,"Tokener at %s",s);
217 fprintf(stderr,"Tokener at %s\n",s);
221 if ((*s & 127) == '(')
224 warn("Unrecognized character \\%03o ignored", *s++);
230 if ((*s & 127) == '(')
233 warn("Unrecognized character \\%03o ignored", *s++);
237 goto fake_eof; /* emulate EOF on ^D or ^Z */
242 goto retry; /* ignore stray nulls */
245 if (minus_n || minus_p || perldb) {
249 char *pdb = getenv("PERLDB");
251 str_cat(linestr, pdb ? pdb : "require 'perldb.pl'");
252 str_cat(linestr, ";");
254 if (minus_n || minus_p) {
255 str_cat(linestr,"line: while (<>) {");
257 str_cat(linestr,"@F=split(' ');");
259 oldoldbufptr = oldbufptr = s = str_get(linestr);
260 bufend = linestr->str_ptr + linestr->str_cur;
266 yylval.formval = load_format();
268 oldoldbufptr = oldbufptr = s = str_get(linestr) + 1;
269 bufend = linestr->str_ptr + linestr->str_cur;
275 #endif /* CRYPTSCRIPT */
277 if ((s = str_gets(linestr, rsfp, 0)) == Nullch) {
281 (void)mypclose(rsfp);
282 else if (rsfp == stdin)
288 if (minus_n || minus_p) {
289 str_set(linestr,minus_p ? ";}continue{print" : "");
290 str_cat(linestr,";}");
291 oldoldbufptr = oldbufptr = s = str_get(linestr);
292 bufend = linestr->str_ptr + linestr->str_cur;
293 minus_n = minus_p = 0;
296 oldoldbufptr = oldbufptr = s = str_get(linestr);
298 RETURN(';'); /* not infinite loop because rsfp is NULL now */
300 if (doextract && *linestr->str_ptr == '#')
303 oldoldbufptr = oldbufptr = bufptr = s;
305 STR *str = Str_new(85,0);
307 str_sset(str,linestr);
308 astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
316 bufend = linestr->str_ptr + linestr->str_cur;
317 if (curcmd->c_line == 1) {
318 if (*s == '#' && s[1] == '!') {
319 if (!in_eval && !instr(s,"perl") && instr(origargv[0],"perl")) {
327 while (s < bufend && !isspace(*s))
330 while (s < bufend && isspace(*s))
333 Newz(899,newargv,origargc+3,char*);
335 while (s < bufend && !isspace(*s))
338 Copy(origargv+1, newargv+2, origargc+1, char*);
344 fatal("Can't exec %s", cmd);
348 while (s < bufend && isspace(*s))
350 if (*s == ':') /* for csh's that have to exec sh scripts */
355 case ' ': case '\t': case '\f':
359 if (preprocess && s == str_get(linestr) &&
360 s[1] == ' ' && isdigit(s[2])) {
361 curcmd->c_line = atoi(s+2)-1;
362 for (s += 2; isdigit(*s); s++) ;
364 while (s < d && isspace(*s)) s++;
365 s[strlen(s)-1] = '\0'; /* wipe out newline */
368 s[strlen(s)-1] = '\0'; /* wipe out trailing quote */
371 curcmd->c_filestab = fstab(s);
373 curcmd->c_filestab = fstab(origfilename);
374 oldoldbufptr = oldbufptr = s = str_get(linestr);
378 if (in_eval && !rsfp) {
380 while (s < d && *s != '\n')
385 STR *str = Str_new(85,0);
387 str_nset(str,linestr->str_ptr, s - linestr->str_ptr);
388 astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
389 str_chop(linestr, s);
393 yylval.formval = load_format();
395 oldoldbufptr = oldbufptr = s = bufptr + 1;
406 if (s[1] && isalpha(s[1]) && !isalpha(s[2])) {
409 case 'r': FTST(O_FTEREAD);
410 case 'w': FTST(O_FTEWRITE);
411 case 'x': FTST(O_FTEEXEC);
412 case 'o': FTST(O_FTEOWNED);
413 case 'R': FTST(O_FTRREAD);
414 case 'W': FTST(O_FTRWRITE);
415 case 'X': FTST(O_FTREXEC);
416 case 'O': FTST(O_FTROWNED);
417 case 'e': FTST(O_FTIS);
418 case 'z': FTST(O_FTZERO);
419 case 's': FTST(O_FTSIZE);
420 case 'f': FTST(O_FTFILE);
421 case 'd': FTST(O_FTDIR);
422 case 'l': FTST(O_FTLINK);
423 case 'p': FTST(O_FTPIPE);
424 case 'S': FTST(O_FTSOCK);
425 case 'u': FTST(O_FTSUID);
426 case 'g': FTST(O_FTSGID);
427 case 'k': FTST(O_FTSVTX);
428 case 'b': FTST(O_FTBLK);
429 case 'c': FTST(O_FTCHR);
430 case 't': FTST(O_FTTTY);
431 case 'T': FTST(O_FTTEXT);
432 case 'B': FTST(O_FTBINARY);
433 case 'M': stabent("\024",TRUE); FTST(O_FTMTIME);
434 case 'A': stabent("\024",TRUE); FTST(O_FTATIME);
435 case 'C': stabent("\024",TRUE); FTST(O_FTCTIME);
463 s = scanreg(s,bufend,tokenbuf);
464 yylval.stabval = stabent(tokenbuf,TRUE);
475 s = scanreg(s,bufend,tokenbuf);
476 yylval.stabval = hadd(stabent(tokenbuf,TRUE));
492 if (isspace(*s) || *s == '#')
493 cmdline = NOLINE; /* invalidate current command line number */
496 if (curcmd->c_line < cmdline)
497 cmdline = curcmd->c_line;
515 while (s < d && isspace(*s))
517 if (isalpha(*s) || *s == '_' || *s == '\'')
518 *(--s) = '\\'; /* force next ident to WORD */
577 while (isascii(*s) && \
578 (isalpha(*s) || isdigit(*s) || *s == '_' || *s == '\'')) \
580 while (d[-1] == '\'') \
586 if (s[1] == '#' && (isalpha(s[2]) || s[2] == '_')) {
588 s = scanreg(s,bufend,tokenbuf);
589 yylval.stabval = aadd(stabent(tokenbuf,TRUE));
593 s = scanreg(s,bufend,tokenbuf);
594 if (reparse) { /* turn ${foo[bar]} into ($foo[bar]) */
602 yylval.stabval = stabent(tokenbuf,TRUE);
607 s = scanreg(s,bufend,tokenbuf);
610 yylval.stabval = aadd(stabent(tokenbuf,TRUE));
613 case '/': /* may either be division or pattern */
614 case '?': /* may either be conditional or pattern */
625 if (!expectterm || !isdigit(s[1])) {
634 case '0': case '1': case '2': case '3': case '4':
635 case '5': case '6': case '7': case '8': case '9':
636 case '\'': case '"': case '`':
640 case '\\': /* some magic to force next word to be a WORD */
641 s++; /* used by do and sub to force a separate namespace */
646 if (strEQ(d,"__LINE__") || strEQ(d,"__FILE__")) {
647 ARG *arg = op_new(1);
650 arg->arg_type = O_ITEM;
652 (void)sprintf(tokenbuf,"%ld",(long)curcmd->c_line);
654 strcpy(tokenbuf, stab_val(curcmd->c_filestab)->str_ptr);
655 arg[1].arg_type = A_SINGLE;
656 arg[1].arg_ptr.arg_str = str_make(tokenbuf,strlen(tokenbuf));
659 else if (strEQ(d,"__END__")) {
664 if (stab = stabent("DATA",FALSE)) {
665 stab->str_pok |= SP_MULTI;
666 stab_io(stab) = stio_new();
667 stab_io(stab)->ifp = rsfp;
668 #if defined(FCNTL) && defined(F_SETFD)
670 fcntl(fd,F_SETFD,fd >= 3);
673 stab_io(stab)->type = '|';
674 else if (rsfp == stdin)
675 stab_io(stab)->type = '-';
677 stab_io(stab)->type = '<';
687 if (strEQ(d,"alarm"))
689 if (strEQ(d,"accept"))
691 if (strEQ(d,"atan2"))
698 if (strEQ(d,"binmode"))
705 if (strEQ(d,"continue"))
707 if (strEQ(d,"chdir")) {
708 (void)stabent("ENV",TRUE); /* may use HOME */
711 if (strEQ(d,"close"))
713 if (strEQ(d,"closedir"))
717 if (strEQ(d,"caller"))
719 if (strEQ(d,"crypt")) {
725 if (strEQ(d,"chmod"))
727 if (strEQ(d,"chown"))
729 if (strEQ(d,"connect"))
733 if (strEQ(d,"chroot"))
740 while (s < d && isspace(*s))
742 if (isalpha(*s) || *s == '_')
743 *(--s) = '\\'; /* force next ident to WORD */
748 if (strEQ(d,"defined"))
750 if (strEQ(d,"delete"))
752 if (strEQ(d,"dbmopen"))
754 if (strEQ(d,"dbmclose"))
763 if (strEQ(d,"elsif")) {
764 yylval.ival = curcmd->c_line;
767 if (strEQ(d,"eq") || strEQ(d,"EQ"))
771 if (strEQ(d,"eval")) {
772 allstabs = TRUE; /* must initialize everything since */
773 UNI(O_EVAL); /* we don't know what will be used */
781 if (strEQ(d,"exec")) {
785 if (strEQ(d,"endhostent"))
787 if (strEQ(d,"endnetent"))
789 if (strEQ(d,"endservent"))
791 if (strEQ(d,"endprotoent"))
793 if (strEQ(d,"endpwent"))
795 if (strEQ(d,"endgrent"))
800 if (strEQ(d,"for") || strEQ(d,"foreach")) {
801 yylval.ival = curcmd->c_line;
804 if (strEQ(d,"format")) {
806 while (s < d && isspace(*s))
808 if (isalpha(*s) || *s == '_')
809 *(--s) = '\\'; /* force next ident to WORD */
811 allstabs = TRUE; /* must initialize everything since */
812 OPERATOR(FORMAT); /* we don't know what will be used */
816 if (strEQ(d,"fcntl"))
818 if (strEQ(d,"fileno"))
820 if (strEQ(d,"flock"))
825 if (strEQ(d,"gt") || strEQ(d,"GT"))
827 if (strEQ(d,"ge") || strEQ(d,"GE"))
833 if (strEQ(d,"gmtime"))
837 if (strnEQ(d,"get",3)) {
844 if (strEQ(d,"priority"))
846 if (strEQ(d,"protobyname"))
848 if (strEQ(d,"protobynumber"))
850 if (strEQ(d,"protoent"))
852 if (strEQ(d,"pwent"))
854 if (strEQ(d,"pwnam"))
856 if (strEQ(d,"pwuid"))
858 if (strEQ(d,"peername"))
861 else if (*d == 'h') {
862 if (strEQ(d,"hostbyname"))
864 if (strEQ(d,"hostbyaddr"))
866 if (strEQ(d,"hostent"))
869 else if (*d == 'n') {
870 if (strEQ(d,"netbyname"))
872 if (strEQ(d,"netbyaddr"))
874 if (strEQ(d,"netent"))
877 else if (*d == 's') {
878 if (strEQ(d,"servbyname"))
880 if (strEQ(d,"servbyport"))
882 if (strEQ(d,"servent"))
884 if (strEQ(d,"sockname"))
886 if (strEQ(d,"sockopt"))
889 else if (*d == 'g') {
890 if (strEQ(d,"grent"))
892 if (strEQ(d,"grnam"))
894 if (strEQ(d,"grgid"))
897 else if (*d == 'l') {
898 if (strEQ(d,"login"))
912 yylval.ival = curcmd->c_line;
915 if (strEQ(d,"index"))
919 if (strEQ(d,"ioctl"))
938 if (strEQ(d,"local"))
940 if (strEQ(d,"length"))
942 if (strEQ(d,"lt") || strEQ(d,"LT"))
944 if (strEQ(d,"le") || strEQ(d,"LE"))
946 if (strEQ(d,"localtime"))
952 if (strEQ(d,"listen"))
954 if (strEQ(d,"lstat"))
970 RETURN(1); /* force error */
974 if (strEQ(d,"mkdir"))
978 if (strEQ(d,"msgctl"))
980 if (strEQ(d,"msgget"))
982 if (strEQ(d,"msgrcv"))
984 if (strEQ(d,"msgsnd"))
993 if (strEQ(d,"ne") || strEQ(d,"NE"))
1004 if (strEQ(d,"opendir"))
1009 if (strEQ(d,"print")) {
1010 checkcomma(s,"filehandle");
1013 if (strEQ(d,"printf")) {
1014 checkcomma(s,"filehandle");
1017 if (strEQ(d,"push")) {
1018 yylval.ival = O_PUSH;
1023 if (strEQ(d,"pack"))
1025 if (strEQ(d,"package"))
1027 if (strEQ(d,"pipe"))
1036 if (strEQ(d,"qq")) {
1043 if (strEQ(d,"return"))
1045 if (strEQ(d,"require")) {
1046 allstabs = TRUE; /* must initialize everything since */
1047 UNI(O_REQUIRE); /* we don't know what will be used */
1049 if (strEQ(d,"reset"))
1051 if (strEQ(d,"redo"))
1053 if (strEQ(d,"rename"))
1055 if (strEQ(d,"rand"))
1057 if (strEQ(d,"rmdir"))
1059 if (strEQ(d,"rindex"))
1061 if (strEQ(d,"read"))
1063 if (strEQ(d,"readdir"))
1065 if (strEQ(d,"rewinddir"))
1067 if (strEQ(d,"recv"))
1069 if (strEQ(d,"reverse"))
1071 if (strEQ(d,"readlink"))
1087 RETURN(1); /* force error */
1094 if (strEQ(d,"scalar"))
1100 if (strEQ(d,"select"))
1102 if (strEQ(d,"seek"))
1104 if (strEQ(d,"semctl"))
1106 if (strEQ(d,"semget"))
1108 if (strEQ(d,"semop"))
1110 if (strEQ(d,"send"))
1112 if (strEQ(d,"setpgrp"))
1114 if (strEQ(d,"setpriority"))
1115 FUN3(O_SETPRIORITY);
1116 if (strEQ(d,"sethostent"))
1118 if (strEQ(d,"setnetent"))
1120 if (strEQ(d,"setservent"))
1122 if (strEQ(d,"setprotoent"))
1124 if (strEQ(d,"setpwent"))
1126 if (strEQ(d,"setgrent"))
1128 if (strEQ(d,"seekdir"))
1130 if (strEQ(d,"setsockopt"))
1137 if (strEQ(d,"shift"))
1139 if (strEQ(d,"shmctl"))
1141 if (strEQ(d,"shmget"))
1143 if (strEQ(d,"shmread"))
1145 if (strEQ(d,"shmwrite"))
1147 if (strEQ(d,"shutdown"))
1158 if (strEQ(d,"sleep"))
1165 if (strEQ(d,"socket"))
1167 if (strEQ(d,"socketpair"))
1169 if (strEQ(d,"sort")) {
1170 checkcomma(s,"subroutine name");
1172 while (s < d && isascii(*s) && isspace(*s)) s++;
1173 if (*s == ';' || *s == ')') /* probably a close */
1174 fatal("sort is now a reserved word");
1175 if (isascii(*s) && (isalpha(*s) || *s == '_')) {
1176 for (d = s; isalpha(*d) || isdigit(*d) || *d == '_'; d++) ;
1177 strncpy(tokenbuf,s,d-s);
1178 if (strNE(tokenbuf,"keys") &&
1179 strNE(tokenbuf,"values") &&
1180 strNE(tokenbuf,"split") &&
1181 strNE(tokenbuf,"grep") &&
1182 strNE(tokenbuf,"readdir") &&
1183 strNE(tokenbuf,"unpack") &&
1184 strNE(tokenbuf,"do") &&
1185 (d >= bufend || isspace(*d)) )
1186 *(--s) = '\\'; /* force next ident to WORD */
1192 if (strEQ(d,"split"))
1194 if (strEQ(d,"sprintf"))
1196 if (strEQ(d,"splice")) {
1197 yylval.ival = O_SPLICE;
1202 if (strEQ(d,"sqrt"))
1206 if (strEQ(d,"srand"))
1212 if (strEQ(d,"stat"))
1214 if (strEQ(d,"study")) {
1220 if (strEQ(d,"substr"))
1222 if (strEQ(d,"sub")) {
1223 subline = curcmd->c_line;
1225 while (s < d && isspace(*s))
1227 if (isalpha(*s) || *s == '_' || *s == '\'') {
1229 str_sset(subname,curstname);
1230 str_ncat(subname,"'",1);
1232 isalpha(*d) || isdigit(*d) || *d == '_' || *d == '\'';
1236 str_ncat(subname,s,d-s);
1238 *(--s) = '\\'; /* force next ident to WORD */
1241 str_set(subname,"?");
1250 if (strEQ(d,"system")) {
1254 if (strEQ(d,"symlink"))
1256 if (strEQ(d,"syscall"))
1258 if (strEQ(d,"sysread"))
1260 if (strEQ(d,"syswrite"))
1269 if (strEQ(d,"tr")) {
1274 RETURN(1); /* force error */
1276 if (strEQ(d,"tell"))
1278 if (strEQ(d,"telldir"))
1280 if (strEQ(d,"time"))
1282 if (strEQ(d,"times"))
1284 if (strEQ(d,"truncate"))
1289 if (strEQ(d,"using"))
1291 if (strEQ(d,"until")) {
1292 yylval.ival = curcmd->c_line;
1295 if (strEQ(d,"unless")) {
1296 yylval.ival = curcmd->c_line;
1299 if (strEQ(d,"unlink"))
1301 if (strEQ(d,"undef"))
1303 if (strEQ(d,"unpack"))
1305 if (strEQ(d,"utime"))
1307 if (strEQ(d,"umask"))
1309 if (strEQ(d,"unshift")) {
1310 yylval.ival = O_UNSHIFT;
1316 if (strEQ(d,"values"))
1318 if (strEQ(d,"vec")) {
1325 if (strEQ(d,"while")) {
1326 yylval.ival = curcmd->c_line;
1329 if (strEQ(d,"warn"))
1331 if (strEQ(d,"wait"))
1333 if (strEQ(d,"waitpid"))
1335 if (strEQ(d,"wantarray")) {
1336 yylval.arg = op_new(1);
1337 yylval.arg->arg_type = O_ITEM;
1338 yylval.arg[1].arg_type = A_WANTARRAY;
1341 if (strEQ(d,"write"))
1346 if (!expectterm && strEQ(d,"x"))
1366 yylval.cval = savestr(d);
1368 if (oldoldbufptr && oldoldbufptr < bufptr) {
1369 while (isspace(*oldoldbufptr))
1371 if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5))
1373 else if (*oldoldbufptr == 's' && strnEQ(oldoldbufptr,"sort",4))
1376 return (CLINE, bufptr = s, (int)WORD);
1388 while (s < bufend && isascii(*s) && isspace(*s))
1390 if (isascii(*s) && (isalpha(*s) || *s == '_')) {
1392 while (isalpha(*s) || isdigit(*s) || *s == '_')
1394 while (s < bufend && isspace(*s))
1399 "tell eof times getlogin wait length shift umask getppid \
1400 cos exp int log rand sin sqrt ord wantarray",
1405 fatal("No comma allowed after %s", what);
1411 scanreg(s,send,dest)
1413 register char *send;
1427 while (isalpha(*s) || isdigit(*s) || *s == '_' || *s == '\'')
1430 while (d > dest+1 && d[-1] == '\'')
1436 if (*d == '{' /* } */ ) {
1439 while (s < send && brackets) {
1440 if (!reparse && (d == dest || (*s && isascii(*s) &&
1441 (isalpha(*s) || isdigit(*s) || *s == '_') ))) {
1451 if (reparse && reparse == s - 1)
1465 if (*d == '^' && !isspace(*s))
1471 scanconst(string,len)
1475 register STR *retstr;
1480 if (index(string,'|')) {
1483 retstr = Str_new(86,len);
1484 str_nset(retstr,string,len);
1485 t = str_get(retstr);
1487 retstr->str_u.str_useful = 100;
1488 for (d=t; d < e; ) {
1496 case '.': case '[': case '$': case '(': case ')': case '|': case '+':
1500 if (d[1] && index("wWbB0123456789sSdD",d[1])) {
1504 (void)bcopy(d+1,d,e-d);
1523 if (d[1] == '*' || (d[1] == '{' && d[2] == '0') || d[1] == '?') {
1535 retstr->str_cur = d - t;
1543 register SPAT *spat;
1548 STR *str = Str_new(93,0);
1550 Newz(801,spat,1,SPAT);
1551 spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
1552 curstash->tbl_spatroot = spat;
1561 spat->spat_flags |= SPAT_ONCE;
1564 fatal("panic: scanpat");
1566 s = str_append_till(str,s,bufend,s[-1],patleave);
1569 yyerror("Search pattern not terminated");
1570 yylval.arg = Nullarg;
1574 while (*s == 'i' || *s == 'o') {
1578 spat->spat_flags |= SPAT_FOLD;
1582 spat->spat_flags |= SPAT_KEEP;
1586 e = str->str_ptr + len;
1587 for (d = str->str_ptr; d < e; d++) {
1590 else if ((*d == '$' && d[1] && d[1] != '|' && d[1] != ')') ||
1594 spat->spat_runtime = arg = op_new(1);
1595 arg->arg_type = O_ITEM;
1596 arg[1].arg_type = A_DOUBLE;
1597 arg[1].arg_ptr.arg_str = str_smake(str);
1598 d = scanreg(d,bufend,buf);
1599 (void)stabent(buf,TRUE); /* make sure it's created */
1600 for (; d < e; d++) {
1603 else if (*d == '$' && d[1] && d[1] != '|' && d[1] != ')') {
1604 d = scanreg(d,bufend,buf);
1605 (void)stabent(buf,TRUE);
1607 else if (*d == '@') {
1608 d = scanreg(d,bufend,buf);
1609 if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
1610 strEQ(buf,"SIG") || strEQ(buf,"INC"))
1611 (void)stabent(buf,TRUE);
1614 goto got_pat; /* skip compiling for now */
1617 if (spat->spat_flags & SPAT_FOLD)
1621 (void)bcopy((char *)spat, (char *)&savespat, sizeof(SPAT));
1623 if (*str->str_ptr == '^') {
1624 spat->spat_short = scanconst(str->str_ptr+1,len-1);
1625 if (spat->spat_short) {
1626 spat->spat_slen = spat->spat_short->str_cur;
1627 if (spat->spat_slen == len - 1)
1628 spat->spat_flags |= SPAT_ALL;
1632 spat->spat_flags |= SPAT_SCANFIRST;
1633 spat->spat_short = scanconst(str->str_ptr,len);
1634 if (spat->spat_short) {
1635 spat->spat_slen = spat->spat_short->str_cur;
1636 if (spat->spat_slen == len)
1637 spat->spat_flags |= SPAT_ALL;
1640 if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
1641 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1642 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1643 spat->spat_flags & SPAT_FOLD);
1644 /* Note that this regexp can still be used if someone says
1645 * something like /a/ && s//b/; so we can't delete it.
1649 if (spat->spat_flags & SPAT_FOLD)
1653 (void)bcopy((char *)&savespat, (char *)spat, sizeof(SPAT));
1655 if (spat->spat_short)
1656 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1657 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1658 spat->spat_flags & SPAT_FOLD,1);
1663 yylval.arg = make_match(O_MATCH,stab2arg(A_STAB,defstab),spat);
1671 register SPAT *spat;
1675 STR *str = Str_new(93,0);
1677 Newz(802,spat,1,SPAT);
1678 spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
1679 curstash->tbl_spatroot = spat;
1681 s = str_append_till(str,s+1,bufend,*s,patleave);
1684 yyerror("Substitution pattern not terminated");
1685 yylval.arg = Nullarg;
1689 e = str->str_ptr + len;
1690 for (d = str->str_ptr; d < e; d++) {
1693 else if ((*d == '$' && d[1] && d[1] != '|' && /*(*/ d[1] != ')') ||
1697 spat->spat_runtime = arg = op_new(1);
1698 arg->arg_type = O_ITEM;
1699 arg[1].arg_type = A_DOUBLE;
1700 arg[1].arg_ptr.arg_str = str_smake(str);
1701 d = scanreg(d,bufend,buf);
1702 (void)stabent(buf,TRUE); /* make sure it's created */
1704 if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') {
1705 d = scanreg(d,bufend,buf);
1706 (void)stabent(buf,TRUE);
1708 else if (*d == '@' && d[-1] != '\\') {
1709 d = scanreg(d,bufend,buf);
1710 if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
1711 strEQ(buf,"SIG") || strEQ(buf,"INC"))
1712 (void)stabent(buf,TRUE);
1715 goto get_repl; /* skip compiling for now */
1718 if (*str->str_ptr == '^') {
1719 spat->spat_short = scanconst(str->str_ptr+1,len-1);
1720 if (spat->spat_short)
1721 spat->spat_slen = spat->spat_short->str_cur;
1724 spat->spat_flags |= SPAT_SCANFIRST;
1725 spat->spat_short = scanconst(str->str_ptr,len);
1726 if (spat->spat_short)
1727 spat->spat_slen = spat->spat_short->str_cur;
1733 yyerror("Substitution replacement not terminated");
1734 yylval.arg = Nullarg;
1737 spat->spat_repl = yylval.arg;
1738 spat->spat_flags |= SPAT_ONCE;
1739 if ((spat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
1740 spat->spat_flags |= SPAT_CONST;
1741 else if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE) {
1745 spat->spat_flags |= SPAT_CONST;
1746 tmpstr = spat->spat_repl[1].arg_ptr.arg_str;
1747 e = tmpstr->str_ptr + tmpstr->str_cur;
1748 for (t = tmpstr->str_ptr; t < e; t++) {
1749 if (*t == '$' && t[1] && (index("`'&+0123456789",t[1]) ||
1750 (t[1] == '{' /*}*/ && isdigit(t[2])) ))
1751 spat->spat_flags &= ~SPAT_CONST;
1754 while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
1757 if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
1758 spat->spat_repl[1].arg_type = A_SINGLE;
1759 spat->spat_repl = make_op(O_EVAL,2,
1763 spat->spat_flags &= ~SPAT_CONST;
1767 spat->spat_flags &= ~SPAT_ONCE;
1772 spat->spat_flags |= SPAT_FOLD;
1773 if (!(spat->spat_flags & SPAT_SCANFIRST)) {
1774 str_free(spat->spat_short); /* anchored opt doesn't do */
1775 spat->spat_short = Nullstr; /* case insensitive match */
1776 spat->spat_slen = 0;
1781 spat->spat_flags |= SPAT_KEEP;
1784 if (spat->spat_short && (spat->spat_flags & SPAT_SCANFIRST))
1785 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1786 if (!spat->spat_runtime) {
1787 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1788 spat->spat_flags & SPAT_FOLD,1);
1791 yylval.arg = make_match(O_SUBST,stab2arg(A_STAB,defstab),spat);
1797 register SPAT *spat;
1799 if (spat->spat_regexp->regmust) { /* is there a better short-circuit? */
1800 if (spat->spat_short &&
1801 str_eq(spat->spat_short,spat->spat_regexp->regmust))
1803 if (spat->spat_flags & SPAT_SCANFIRST) {
1804 str_free(spat->spat_short);
1805 spat->spat_short = Nullstr;
1808 str_free(spat->spat_regexp->regmust);
1809 spat->spat_regexp->regmust = Nullstr;
1813 if (!spat->spat_short || /* promote the better string */
1814 ((spat->spat_flags & SPAT_SCANFIRST) &&
1815 (spat->spat_short->str_cur < spat->spat_regexp->regmust->str_cur) )){
1816 str_free(spat->spat_short); /* ok if null */
1817 spat->spat_short = spat->spat_regexp->regmust;
1818 spat->spat_regexp->regmust = Nullstr;
1819 spat->spat_flags |= SPAT_SCANFIRST;
1825 expand_charset(s,len,retlen)
1831 register char *d = t;
1833 register char *send = s + len;
1835 while (s < send && d - t <= 256) {
1836 if (s[1] == '-' && s+2 < send) {
1837 for (i = s[0]; i <= s[2]; i++)
1846 return nsavestr(t,d-t);
1854 l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
1857 register short *tbl;
1865 New(803,tbl,256,short);
1866 arg[2].arg_type = A_NULL;
1867 arg[2].arg_ptr.arg_cval = (char*) tbl;
1870 yyerror("Translation pattern not terminated");
1871 yylval.arg = Nullarg;
1874 t = expand_charset(yylval.arg[1].arg_ptr.arg_str->str_ptr,
1875 yylval.arg[1].arg_ptr.arg_str->str_cur,&tlen);
1876 free_arg(yylval.arg);
1879 yyerror("Translation replacement not terminated");
1880 yylval.arg = Nullarg;
1883 complement = delete = squash = 0;
1884 while (*s == 'c' || *s == 'd' || *s == 's') {
1893 r = expand_charset(yylval.arg[1].arg_ptr.arg_str->str_ptr,
1894 yylval.arg[1].arg_ptr.arg_str->str_cur,&rlen);
1895 free_arg(yylval.arg);
1896 arg[2].arg_len = delete|squash;
1898 if (!rlen && !delete) {
1903 Zero(tbl, 256, short);
1904 for (i = 0; i < tlen; i++)
1905 tbl[t[i] & 0377] = -1;
1906 for (i = 0, j = 0; i < 256; i++,j++) {
1920 for (i = 0; i < 256; i++)
1922 for (i = 0, j = 0; i < tlen; i++,j++) {
1925 if (tbl[t[i] & 0377] == -1)
1926 tbl[t[i] & 0377] = -2;
1931 if (tbl[t[i] & 0377] == -1)
1932 tbl[t[i] & 0377] = r[j] & 0377;
1948 register char *send;
1949 register bool makesingle = FALSE;
1950 register STAB *stab;
1951 bool alwaysdollar = FALSE;
1952 bool hereis = FALSE;
1955 char *leave = "\\$@nrtfb0123456789[{]}"; /* which backslash sequences to keep */
1960 arg->arg_type = O_ITEM;
1963 default: /* a substitution replacement */
1964 arg[1].arg_type = A_DOUBLE;
1965 makesingle = TRUE; /* maybe disable runtime scanning */
1975 arg[1].arg_type = A_SINGLE;
1980 else if (s[1] == '.')
1991 yyerror("Illegal octal digit");
1993 case '0': case '1': case '2': case '3': case '4':
1994 case '5': case '6': case '7':
1998 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1999 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
2003 i += (*s++ & 7) + 9;
2008 str = Str_new(92,0);
2009 str_numset(str,(double)i);
2011 Safefree(str->str_ptr);
2012 str->str_ptr = Nullch;
2013 str->str_len = str->str_cur = 0;
2015 arg[1].arg_ptr.arg_str = str;
2018 case '1': case '2': case '3': case '4': case '5':
2019 case '6': case '7': case '8': case '9': case '.':
2021 arg[1].arg_type = A_SINGLE;
2023 while (isdigit(*s) || *s == '_') {
2029 if (*s == '.' && s[1] && index("0123456789eE ;",s[1])) {
2031 while (isdigit(*s) || *s == '_') {
2038 if (*s && index("eE",*s) && index("+-0123456789",s[1])) {
2040 if (*s == '+' || *s == '-')
2046 str = Str_new(92,0);
2047 str_numset(str,atof(tokenbuf));
2049 Safefree(str->str_ptr);
2050 str->str_ptr = Nullch;
2051 str->str_len = str->str_cur = 0;
2053 arg[1].arg_ptr.arg_str = str;
2061 if (*++s && index("`'\"",*s)) {
2063 s = cpytill(d,s,bufend,term,&len);
2073 while (isascii(*s) && (isalpha(*s) || isdigit(*s) || *s == '_'))
2075 } /* assuming tokenbuf won't clobber */
2080 if (rsfp || !(d=ninstr(s,bufend,d,d+1)))
2081 herewas = str_make(s,bufend-s);
2083 s--, herewas = str_make(s,d-s);
2084 s += herewas->str_cur;
2092 s = cpytill(d,s,bufend,'>',&len);
2097 (isalpha(*d) || isdigit(*d) || *d == '_' || *d == '\''))
2099 if (d - tokenbuf != len) {
2101 arg[1].arg_type = A_GLOB;
2102 d = nsavestr(d,len);
2103 arg[1].arg_ptr.arg_stab = stab = genstab();
2104 stab_io(stab) = stio_new();
2105 stab_val(stab) = str_make(d,len);
2112 (void)strcpy(d,"ARGV");
2114 arg[1].arg_type = A_INDREAD;
2115 arg[1].arg_ptr.arg_stab = stabent(d+1,TRUE);
2118 arg[1].arg_type = A_READ;
2119 arg[1].arg_ptr.arg_stab = stabent(d,TRUE);
2120 if (!stab_io(arg[1].arg_ptr.arg_stab))
2121 stab_io(arg[1].arg_ptr.arg_stab) = stio_new();
2122 if (strEQ(d,"ARGV")) {
2123 (void)aadd(arg[1].arg_ptr.arg_stab);
2124 stab_io(arg[1].arg_ptr.arg_stab)->flags |=
2141 arg[1].arg_type = A_SINGLE;
2148 arg[1].arg_type = A_DOUBLE;
2149 makesingle = TRUE; /* maybe disable runtime scanning */
2150 alwaysdollar = TRUE; /* treat $) and $| as variables */
2155 arg[1].arg_type = A_BACKTICK;
2157 alwaysdollar = TRUE; /* treat $) and $| as variables */
2163 multi_start = curcmd->c_line;
2165 multi_open = multi_close = '<';
2168 if (term && (tmps = index("([{< )]}> )]}>",term)))
2172 tmpstr = Str_new(87,80);
2177 while (s < bufend &&
2178 (*s != term || bcmp(s,tokenbuf,len) != 0) ) {
2183 curcmd->c_line = multi_start;
2184 fatal("EOF in string");
2186 str_nset(tmpstr,d+1,s-d);
2188 str_ncat(herewas,s,bufend-s);
2189 str_replace(linestr,herewas);
2190 oldoldbufptr = oldbufptr = bufptr = s = str_get(linestr);
2191 bufend = linestr->str_ptr + linestr->str_cur;
2195 str_nset(tmpstr,"",0); /* avoid "uninitialized" warning */
2198 s = str_append_till(tmpstr,s+1,bufend,term,leave);
2199 while (s >= bufend) { /* multiple line string? */
2201 !(oldoldbufptr = oldbufptr = s = str_gets(linestr, rsfp, 0))) {
2202 curcmd->c_line = multi_start;
2203 fatal("EOF in string");
2207 STR *str = Str_new(88,0);
2209 str_sset(str,linestr);
2210 astore(stab_xarray(curcmd->c_filestab),
2211 (int)curcmd->c_line,str);
2213 bufend = linestr->str_ptr + linestr->str_cur;
2215 if (*s == term && bcmp(s,tokenbuf,len) == 0) {
2218 str_scat(linestr,herewas);
2219 bufend = linestr->str_ptr + linestr->str_cur;
2223 str_scat(tmpstr,linestr);
2227 s = str_append_till(tmpstr,s,bufend,term,leave);
2229 multi_end = curcmd->c_line;
2231 if (tmpstr->str_cur + 5 < tmpstr->str_len) {
2232 tmpstr->str_len = tmpstr->str_cur + 1;
2233 Renew(tmpstr->str_ptr, tmpstr->str_len, char);
2235 if ((arg[1].arg_type & A_MASK) == A_SINGLE) {
2236 arg[1].arg_ptr.arg_str = tmpstr;
2240 s = tmpstr->str_ptr;
2241 send = s + tmpstr->str_cur;
2242 while (s < send) { /* see if we can make SINGLE */
2243 if (*s == '\\' && s[1] && isdigit(s[1]) && !isdigit(s[2]) &&
2244 !alwaysdollar && s[1] != '0')
2245 *s = '$'; /* grandfather \digit in subst */
2246 if ((*s == '$' || *s == '@') && s+1 < send &&
2247 (alwaysdollar || (s[1] != ')' && s[1] != '|'))) {
2248 makesingle = FALSE; /* force interpretation */
2250 else if (*s == '\\' && s+1 < send) {
2255 s = d = tmpstr->str_ptr; /* assuming shrinkage only */
2257 if ((*s == '$' && s+1 < send &&
2258 (alwaysdollar || /*(*/ (s[1] != ')' && s[1] != '|')) ) ||
2259 (*s == '@' && s+1 < send) ) {
2260 len = scanreg(s,send,tokenbuf) - s;
2261 if (*s == '$' || strEQ(tokenbuf,"ARGV")
2262 || strEQ(tokenbuf,"ENV")
2263 || strEQ(tokenbuf,"SIG")
2264 || strEQ(tokenbuf,"INC") )
2265 (void)stabent(tokenbuf,TRUE); /* make sure it exists */
2270 else if (*s == '\\' && s+1 < send) {
2274 if (!makesingle && (!leave || (*s && index(leave,*s))))
2278 case '0': case '1': case '2': case '3':
2279 case '4': case '5': case '6': case '7':
2281 if (s < send && *s && index("01234567",*s)) {
2285 if (s < send && *s && index("01234567",*s)) {
2314 if ((arg[1].arg_type & A_MASK) == A_DOUBLE && makesingle)
2315 arg[1].arg_type = A_SINGLE; /* now we can optimize on it */
2317 tmpstr->str_cur = d - tmpstr->str_ptr;
2318 arg[1].arg_ptr.arg_str = tmpstr;
2334 register FCMD *fprev = &froot;
2335 register FCMD *fcmd;
2342 Zero(&froot, 1, FCMD);
2344 while (s < bufend || (s = str_gets(linestr,rsfp, 0)) != Nullch) {
2346 if (in_eval && !rsfp) {
2347 eol = index(s,'\n');
2352 eol = bufend = linestr->str_ptr + linestr->str_cur;
2354 STR *tmpstr = Str_new(89,0);
2356 str_nset(tmpstr, s, eol-s);
2357 astore(stab_xarray(curcmd->c_filestab), (int)curcmd->c_line,tmpstr);
2359 if (strnEQ(s,".\n",2)) {
2361 return froot.f_next;
2367 flinebeg = Nullfcmd;
2371 Newz(804,fcmd,1,FCMD);
2372 fprev->f_next = fcmd;
2374 for (t=s; t < eol && *t != '@' && *t != '^'; t++) {
2384 fcmd->f_pre = nsavestr(s, t-s);
2385 fcmd->f_presize = t-s;
2389 fcmd->f_flags |= FC_NOBLANK;
2391 fcmd->f_flags |= FC_REPEAT;
2395 flinebeg = fcmd; /* start values here */
2397 fcmd->f_flags |= FC_CHOP; /* for doing text filling */
2400 fcmd->f_type = F_LINES;
2404 fcmd->f_type = F_LEFT;
2409 fcmd->f_type = F_RIGHT;
2414 fcmd->f_type = F_CENTER;
2420 /* Catch the special case @... and handle it as a string
2422 if (*s == '.' && s[1] == '.') {
2423 goto default_format;
2425 fcmd->f_type = F_DECIMAL;
2429 /* Read a format in the form @####.####, where either group
2430 of ### may be empty, or the final .### may be missing. */
2438 fcmd->f_decimals = s-p;
2439 fcmd->f_flags |= FC_DP;
2441 fcmd->f_decimals = 0;
2447 fcmd->f_type = F_LEFT;
2450 if (fcmd->f_flags & FC_CHOP && *s == '.') {
2451 fcmd->f_flags |= FC_MORE;
2459 if (s >= bufend && (s = str_gets(linestr, rsfp, 0)) == Nullch)
2462 if (in_eval && !rsfp) {
2463 eol = index(s,'\n');
2468 eol = bufend = linestr->str_ptr + linestr->str_cur;
2470 STR *tmpstr = Str_new(90,0);
2472 str_nset(tmpstr, s, eol-s);
2473 astore(stab_xarray(curcmd->c_filestab),
2474 (int)curcmd->c_line,tmpstr);
2476 if (strnEQ(s,".\n",2)) {
2478 yyerror("Missing values line");
2479 return froot.f_next;
2485 str = flinebeg->f_unparsed = Str_new(91,eol - s);
2486 str->str_u.str_hash = curstash;
2487 str_nset(str,"(",1);
2488 flinebeg->f_line = curcmd->c_line;
2490 if (!flinebeg->f_next->f_type || index(s, ',')) {
2492 str_ncat(str, s, eol - s - 1);
2493 str_ncat(str,",$$);",5);
2498 while (s < eol && isspace(*s))
2503 case ' ': case '\t': case '\n': case ';':
2504 str_ncat(str, t, s - t);
2505 str_ncat(str, "," ,1);
2506 while (s < eol && (isspace(*s) || *s == ';'))
2511 str_ncat(str, t, s - t);
2513 s = scanreg(s,eol,tokenbuf);
2514 str_ncat(str, t, s - t);
2516 if (s < eol && *s && index("$'\"",*s))
2517 str_ncat(str, ",", 1);
2519 case '"': case '\'':
2520 str_ncat(str, t, s - t);
2523 while (s < eol && (*s != *t || s[-1] == '\\'))
2527 str_ncat(str, t, s - t);
2529 if (s < eol && *s && index("$'\"",*s))
2530 str_ncat(str, ",", 1);
2533 yyerror("Please use commas to separate fields");
2536 str_ncat(str,"$$);",4);
2541 bufptr = str_get(linestr);
2542 yyerror("Format not terminated");
2543 return froot.f_next;
2550 cshlen = strlen(cshname);