1 /* $RCSfile: toke.c,v $$Revision: 4.0.1.7 $$Date: 92/06/11 21:16:30 $
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.7 92/06/11 21:16:30 lwall
10 * patch34: expectterm incorrectly set to indicate start of program or block
12 * Revision 4.0.1.6 92/06/08 16:03:49 lwall
13 * patch20: an EXPR may now start with a bareword
14 * patch20: print $fh EXPR can now expect term rather than operator in EXPR
15 * patch20: added ... as variant on ..
16 * patch20: new warning on spurious backslash
17 * patch20: new warning on missing $ for foreach variable
18 * patch20: "foo"x1024 now legal without space after x
19 * patch20: new warning on print accidentally used as function
20 * patch20: tr/stuff// wasn't working right
21 * patch20: 2. now eats the dot
22 * patch20: <@ARGV> now notices @ARGV
23 * patch20: tr/// now lets you say \-
25 * Revision 4.0.1.5 91/11/11 16:45:51 lwall
26 * patch19: default arg for shift was wrong after first subroutine definition
28 * Revision 4.0.1.4 91/11/05 19:02:48 lwall
29 * patch11: \x and \c were subject to double interpretation in regexps
30 * patch11: prepared for ctype implementations that don't define isascii()
31 * patch11: nested list operators could miscount parens
32 * patch11: once-thru blocks didn't display right in the debugger
33 * patch11: sort eval "whatever" didn't work
34 * patch11: underscore is now allowed within literal octal and hex numbers
36 * Revision 4.0.1.3 91/06/10 01:32:26 lwall
37 * patch10: m'$foo' now treats string as single quoted
38 * patch10: certain pattern optimizations were botched
40 * Revision 4.0.1.2 91/06/07 12:05:56 lwall
41 * patch4: new copyright notice
42 * patch4: debugger lost track of lines in eval
43 * patch4: //o and s///o now optimize themselves fully at runtime
44 * patch4: added global modifier for pattern matches
46 * Revision 4.0.1.1 91/04/12 09:18:18 lwall
47 * patch1: perl -de "print" wouldn't stop at the first statement
49 * Revision 4.0 91/03/20 01:42:14 lwall
58 static void set_csh();
71 /* which backslash sequences to keep in m// or s// */
73 static char *patleave = "\\.^$@dDwWsSbB+*?|()-nrtfeaxc0123456789[{]}";
75 char *reparse; /* if non-null, scanident found ${foo[$bar]} */
82 #define CLINE (cmdline = (curcmd->c_line < cmdline ? curcmd->c_line : cmdline))
85 #define PERL_META(c) ((c) | 128)
87 #define META(c) ((c) | 128)
90 #define RETURN(retval) return (bufptr = s,(int)retval)
91 #define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,(int)retval)
92 #define TERM(retval) return (CLINE, expectterm = FALSE,bufptr = s,(int)retval)
93 #define LOOPX(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)LOOPEX)
94 #define FTST(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)FILETEST)
95 #define FUN0(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC0)
96 #define FUN1(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC1)
97 #define FUN2(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2)
98 #define FUN2x(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2x)
99 #define FUN3(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC3)
100 #define FUN4(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC4)
101 #define FUN5(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC5)
102 #define FL(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST)
103 #define FL2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST2)
104 #define HFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)HSHFUN)
105 #define HFUN3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)HSHFUN3)
106 #define LFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LVALFUN)
107 #define AOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)ADDOP)
108 #define MOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)MULOP)
109 #define EOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)EQOP)
110 #define ROP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)RELOP)
111 #define FOP(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP)
112 #define FOP2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP2)
113 #define FOP3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP3)
114 #define FOP4(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP4)
115 #define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
116 #define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
118 static char *last_uni;
120 /* This bit of chicanery makes a unary function followed by
121 * a parenthesis into a function with one argument, highest precedence.
123 #define UNI(f) return(yylval.ival = f, \
126 last_uni = oldbufptr, \
127 (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
129 /* This does similarly for list operators, merely by pretending that the
130 * paren came before the listop rather than after.
133 #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
134 (*s = (char) PERL_META('('), bufptr = oldbufptr, '(') : \
135 (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
137 #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
138 (*s = (char) META('('), bufptr = oldbufptr, '(') : \
139 (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 && isSPACE(*s))
158 if (oldoldbufptr != last_uni)
160 while (isSPACE(*last_uni))
162 for (s = last_uni; isALNUM(*s); s++) ;
165 warn("Warning: Use of \"%s\" without parens is ambiguous", last_uni);
173 #define UNI(f) return uni(f,s)
174 #define LOP(f) return lop(f,s)
184 last_uni = oldbufptr;
219 #endif /* CRIPPLED_CC */
224 register char *s = bufptr;
227 static bool in_format = FALSE;
228 static bool firstline = TRUE;
229 extern int yychar; /* last token */
231 oldoldbufptr = oldbufptr;
238 fprintf(stderr,"Tokener at %s",s);
240 fprintf(stderr,"Tokener at %s\n",s);
244 if ((*s & 127) == '(') {
248 else if ((*s & 127) == '}') {
253 warn("Unrecognized character \\%03o ignored", *s++ & 255);
259 if ((*s & 127) == '(') {
263 else if ((*s & 127) == '}') {
268 warn("Unrecognized character \\%03o ignored", *s++ & 255);
272 goto fake_eof; /* emulate EOF on ^D or ^Z */
277 goto retry; /* ignore stray nulls */
281 if (minus_n || minus_p || perldb) {
285 char *pdb = getenv("PERLDB");
287 str_cat(linestr, pdb ? pdb : "require 'perldb.pl'");
288 str_cat(linestr, ";");
290 if (minus_n || minus_p) {
291 str_cat(linestr,"line: while (<>) {");
293 str_cat(linestr,"chop;");
295 str_cat(linestr,"@F=split(' ');");
297 oldoldbufptr = oldbufptr = s = str_get(linestr);
298 bufend = linestr->str_ptr + linestr->str_cur;
304 yylval.formval = load_format();
306 oldoldbufptr = oldbufptr = s = str_get(linestr) + 1;
307 bufend = linestr->str_ptr + linestr->str_cur;
313 #endif /* CRYPTSCRIPT */
315 if ((s = str_gets(linestr, rsfp, 0)) == Nullch) {
319 (void)mypclose(rsfp);
320 else if ((FILE*)rsfp == stdin)
326 if (minus_n || minus_p) {
327 str_set(linestr,minus_p ? ";}continue{print" : "");
328 str_cat(linestr,";}");
329 oldoldbufptr = oldbufptr = s = str_get(linestr);
330 bufend = linestr->str_ptr + linestr->str_cur;
331 minus_n = minus_p = 0;
334 oldoldbufptr = oldbufptr = s = str_get(linestr);
336 RETURN(';'); /* not infinite loop because rsfp is NULL now */
338 if (doextract && *linestr->str_ptr == '#')
341 oldoldbufptr = oldbufptr = bufptr = s;
343 STR *str = Str_new(85,0);
345 str_sset(str,linestr);
346 astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
354 bufend = linestr->str_ptr + linestr->str_cur;
355 if (curcmd->c_line == 1) {
356 if (*s == '#' && s[1] == '!') {
357 if (!in_eval && !instr(s,"perl") && instr(origargv[0],"perl")) {
365 while (s < bufend && !isSPACE(*s))
368 while (s < bufend && isSPACE(*s))
371 Newz(899,newargv,origargc+3,char*);
373 while (s < bufend && !isSPACE(*s))
376 Copy(origargv+1, newargv+2, origargc+1, char*);
382 fatal("Can't exec %s", cmd);
386 while (s < bufend && isSPACE(*s))
388 if (*s == ':') /* for csh's that have to exec sh scripts */
393 case ' ': case '\t': case '\f': case '\r': case 013:
397 if (preprocess && s == str_get(linestr) &&
398 s[1] == ' ' && (isDIGIT(s[2]) || strnEQ(s+2,"line ",5)) ) {
399 while (*s && !isDIGIT(*s))
401 curcmd->c_line = atoi(s)-1;
405 while (s < d && isSPACE(*s)) s++;
406 s[strlen(s)-1] = '\0'; /* wipe out newline */
409 s[strlen(s)-1] = '\0'; /* wipe out trailing quote */
412 curcmd->c_filestab = fstab(s);
414 curcmd->c_filestab = fstab(origfilename);
415 oldoldbufptr = oldbufptr = s = str_get(linestr);
419 if (in_eval && !rsfp) {
421 while (s < d && *s != '\n')
427 yylval.formval = load_format();
429 oldoldbufptr = oldbufptr = s = bufptr + 1;
440 if (s[1] && isALPHA(s[1]) && !isALPHA(s[2])) {
443 case 'r': FTST(O_FTEREAD);
444 case 'w': FTST(O_FTEWRITE);
445 case 'x': FTST(O_FTEEXEC);
446 case 'o': FTST(O_FTEOWNED);
447 case 'R': FTST(O_FTRREAD);
448 case 'W': FTST(O_FTRWRITE);
449 case 'X': FTST(O_FTREXEC);
450 case 'O': FTST(O_FTROWNED);
451 case 'e': FTST(O_FTIS);
452 case 'z': FTST(O_FTZERO);
453 case 's': FTST(O_FTSIZE);
454 case 'f': FTST(O_FTFILE);
455 case 'd': FTST(O_FTDIR);
456 case 'l': FTST(O_FTLINK);
457 case 'p': FTST(O_FTPIPE);
458 case 'S': FTST(O_FTSOCK);
459 case 'u': FTST(O_FTSUID);
460 case 'g': FTST(O_FTSGID);
461 case 'k': FTST(O_FTSVTX);
462 case 'b': FTST(O_FTBLK);
463 case 'c': FTST(O_FTCHR);
464 case 't': FTST(O_FTTTY);
465 case 'T': FTST(O_FTTEXT);
466 case 'B': FTST(O_FTBINARY);
467 case 'M': stabent("\024",TRUE); FTST(O_FTMTIME);
468 case 'A': stabent("\024",TRUE); FTST(O_FTATIME);
469 case 'C': stabent("\024",TRUE); FTST(O_FTCTIME);
481 if (isSPACE(*s) || !isSPACE(*bufptr))
494 if (isSPACE(*s) || !isSPACE(*bufptr))
504 s = scanident(s,bufend,tokenbuf);
505 yylval.stabval = stabent(tokenbuf,TRUE);
518 s = scanident(s,bufend,tokenbuf);
519 yylval.stabval = hadd(stabent(tokenbuf,TRUE));
535 yylval.ival = curcmd->c_line;
536 if (isSPACE(*s) || *s == '#')
537 cmdline = NOLINE; /* invalidate current command line number */
541 if (curcmd->c_line < cmdline)
542 cmdline = curcmd->c_line;
560 while (s < d && isSPACE(*s))
562 if (isALPHA(*s) || *s == '_' || *s == '\'')
563 *(--s) = '\\'; /* force next ident to WORD */
596 if (s[1] != '<' && !index(s,'>'))
598 s = scanstr(s, SCAN_DEF);
626 while (isALNUM(*s) || *s == '\'') \
628 while (d[-1] == '\'') \
634 if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_')) {
636 s = scanident(s,bufend,tokenbuf);
637 yylval.stabval = aadd(stabent(tokenbuf,TRUE));
641 s = scanident(s,bufend,tokenbuf);
642 if (reparse) { /* turn ${foo[bar]} into ($foo[bar]) */
650 yylval.stabval = stabent(tokenbuf,TRUE);
652 if (isSPACE(*s) && oldoldbufptr && oldoldbufptr < bufptr) {
654 while (isSPACE(*oldoldbufptr))
656 if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5)) {
657 if (index("&*<%", *s) && isALPHA(s[1]))
658 expectterm = TRUE; /* e.g. print $fh &sub */
659 else if (*s == '.' && isDIGIT(s[1]))
660 expectterm = TRUE; /* e.g. print $fh .3 */
661 else if (index("/?-+", *s) && !isSPACE(s[1]))
662 expectterm = TRUE; /* e.g. print $fh -1 */
669 s = scanident(s,bufend,tokenbuf);
672 yylval.stabval = aadd(stabent(tokenbuf,TRUE));
675 case '/': /* may either be division or pattern */
676 case '?': /* may either be conditional or pattern */
688 if (!expectterm || !isDIGIT(s[1])) {
697 yylval.ival = AF_COMMON;
705 case '0': case '1': case '2': case '3': case '4':
706 case '5': case '6': case '7': case '8': case '9':
707 case '\'': case '"': case '`':
708 s = scanstr(s, SCAN_DEF);
711 case '\\': /* some magic to force next word to be a WORD */
712 s++; /* used by do and sub to force a separate namespace */
713 if (!isALPHA(*s) && *s != '_' && *s != '\'') {
714 warn("Spurious backslash ignored");
721 if (strEQ(d,"__LINE__") || strEQ(d,"__FILE__")) {
722 ARG *arg = op_new(1);
725 arg->arg_type = O_ITEM;
727 (void)sprintf(tokenbuf,"%ld",(long)curcmd->c_line);
729 strcpy(tokenbuf, stab_val(curcmd->c_filestab)->str_ptr);
730 arg[1].arg_type = A_SINGLE;
731 arg[1].arg_ptr.arg_str = str_make(tokenbuf,strlen(tokenbuf));
734 else if (strEQ(d,"__END__")) {
739 if (!in_eval && (stab = stabent("DATA",FALSE))) {
740 stab->str_pok |= SP_MULTI;
742 stab_io(stab) = stio_new();
743 stab_io(stab)->ifp = rsfp;
744 #if defined(HAS_FCNTL) && defined(F_SETFD)
746 fcntl(fd,F_SETFD,fd >= 3);
749 stab_io(stab)->type = '|';
750 else if ((FILE*)rsfp == stdin)
751 stab_io(stab)->type = '-';
753 stab_io(stab)->type = '<';
762 if (strEQ(d,"alarm"))
764 if (strEQ(d,"accept"))
766 if (strEQ(d,"atan2"))
773 if (strEQ(d,"binmode"))
780 if (strEQ(d,"continue"))
782 if (strEQ(d,"chdir")) {
783 (void)stabent("ENV",TRUE); /* may use HOME */
786 if (strEQ(d,"close"))
788 if (strEQ(d,"closedir"))
792 if (strEQ(d,"caller"))
794 if (strEQ(d,"crypt")) {
796 static int cryptseen = 0;
803 if (strEQ(d,"chmod"))
805 if (strEQ(d,"chown"))
807 if (strEQ(d,"connect"))
811 if (strEQ(d,"chroot"))
818 while (s < d && isSPACE(*s))
820 if (isALPHA(*s) || *s == '_')
821 *(--s) = '\\'; /* force next ident to WORD */
826 if (strEQ(d,"defined"))
828 if (strEQ(d,"delete"))
830 if (strEQ(d,"dbmopen"))
832 if (strEQ(d,"dbmclose"))
841 if (strEQ(d,"elsif")) {
842 yylval.ival = curcmd->c_line;
845 if (strEQ(d,"eq") || strEQ(d,"EQ"))
849 if (strEQ(d,"eval")) {
850 allstabs = TRUE; /* must initialize everything since */
851 UNI(O_EVAL); /* we don't know what will be used */
859 if (strEQ(d,"exec")) {
863 if (strEQ(d,"endhostent"))
865 if (strEQ(d,"endnetent"))
867 if (strEQ(d,"endservent"))
869 if (strEQ(d,"endprotoent"))
871 if (strEQ(d,"endpwent"))
873 if (strEQ(d,"endgrent"))
878 if (strEQ(d,"for") || strEQ(d,"foreach")) {
879 yylval.ival = curcmd->c_line;
880 while (s < bufend && isSPACE(*s))
883 fatal("Missing $ on loop variable");
886 if (strEQ(d,"format")) {
888 while (s < d && isSPACE(*s))
890 if (isALPHA(*s) || *s == '_')
891 *(--s) = '\\'; /* force next ident to WORD */
893 allstabs = TRUE; /* must initialize everything since */
894 OPERATOR(FORMAT); /* we don't know what will be used */
898 if (strEQ(d,"fcntl"))
900 if (strEQ(d,"fileno"))
902 if (strEQ(d,"flock"))
907 if (strEQ(d,"gt") || strEQ(d,"GT"))
909 if (strEQ(d,"ge") || strEQ(d,"GE"))
915 if (strEQ(d,"gmtime"))
919 if (strnEQ(d,"get",3)) {
926 if (strEQ(d,"priority"))
928 if (strEQ(d,"protobyname"))
930 if (strEQ(d,"protobynumber"))
932 if (strEQ(d,"protoent"))
934 if (strEQ(d,"pwent"))
936 if (strEQ(d,"pwnam"))
938 if (strEQ(d,"pwuid"))
940 if (strEQ(d,"peername"))
943 else if (*d == 'h') {
944 if (strEQ(d,"hostbyname"))
946 if (strEQ(d,"hostbyaddr"))
948 if (strEQ(d,"hostent"))
951 else if (*d == 'n') {
952 if (strEQ(d,"netbyname"))
954 if (strEQ(d,"netbyaddr"))
956 if (strEQ(d,"netent"))
959 else if (*d == 's') {
960 if (strEQ(d,"servbyname"))
962 if (strEQ(d,"servbyport"))
964 if (strEQ(d,"servent"))
966 if (strEQ(d,"sockname"))
968 if (strEQ(d,"sockopt"))
971 else if (*d == 'g') {
972 if (strEQ(d,"grent"))
974 if (strEQ(d,"grnam"))
976 if (strEQ(d,"grgid"))
979 else if (*d == 'l') {
980 if (strEQ(d,"login"))
994 yylval.ival = curcmd->c_line;
997 if (strEQ(d,"index"))
1001 if (strEQ(d,"ioctl"))
1006 if (strEQ(d,"join"))
1011 if (strEQ(d,"keys"))
1013 if (strEQ(d,"kill"))
1018 if (strEQ(d,"last"))
1020 if (strEQ(d,"local"))
1022 if (strEQ(d,"length"))
1024 if (strEQ(d,"lt") || strEQ(d,"LT"))
1026 if (strEQ(d,"le") || strEQ(d,"LE"))
1028 if (strEQ(d,"localtime"))
1032 if (strEQ(d,"link"))
1034 if (strEQ(d,"listen"))
1036 if (strEQ(d,"lstat"))
1052 RETURN(1); /* force error */
1056 if (strEQ(d,"mkdir"))
1060 if (strEQ(d,"msgctl"))
1062 if (strEQ(d,"msgget"))
1064 if (strEQ(d,"msgrcv"))
1066 if (strEQ(d,"msgsnd"))
1073 if (strEQ(d,"next"))
1075 if (strEQ(d,"ne") || strEQ(d,"NE"))
1080 if (strEQ(d,"open"))
1086 if (strEQ(d,"opendir"))
1091 if (strEQ(d,"print")) {
1092 checkcomma(s,d,"filehandle");
1095 if (strEQ(d,"printf")) {
1096 checkcomma(s,d,"filehandle");
1099 if (strEQ(d,"push")) {
1100 yylval.ival = O_PUSH;
1105 if (strEQ(d,"pack"))
1107 if (strEQ(d,"package"))
1109 if (strEQ(d,"pipe"))
1115 s = scanstr(s-1, SCAN_DEF);
1118 if (strEQ(d,"qq")) {
1119 s = scanstr(s-2, SCAN_DEF);
1122 if (strEQ(d,"qx")) {
1123 s = scanstr(s-2, SCAN_DEF);
1129 if (strEQ(d,"return"))
1131 if (strEQ(d,"require")) {
1132 allstabs = TRUE; /* must initialize everything since */
1133 UNI(O_REQUIRE); /* we don't know what will be used */
1135 if (strEQ(d,"reset"))
1137 if (strEQ(d,"redo"))
1139 if (strEQ(d,"rename"))
1141 if (strEQ(d,"rand"))
1143 if (strEQ(d,"rmdir"))
1145 if (strEQ(d,"rindex"))
1147 if (strEQ(d,"read"))
1149 if (strEQ(d,"readdir"))
1151 if (strEQ(d,"rewinddir"))
1153 if (strEQ(d,"recv"))
1155 if (strEQ(d,"reverse"))
1157 if (strEQ(d,"readlink"))
1173 RETURN(1); /* force error */
1180 if (strEQ(d,"scalar"))
1186 if (strEQ(d,"select"))
1188 if (strEQ(d,"seek"))
1190 if (strEQ(d,"semctl"))
1192 if (strEQ(d,"semget"))
1194 if (strEQ(d,"semop"))
1196 if (strEQ(d,"send"))
1198 if (strEQ(d,"setpgrp"))
1200 if (strEQ(d,"setpriority"))
1201 FUN3(O_SETPRIORITY);
1202 if (strEQ(d,"sethostent"))
1204 if (strEQ(d,"setnetent"))
1206 if (strEQ(d,"setservent"))
1208 if (strEQ(d,"setprotoent"))
1210 if (strEQ(d,"setpwent"))
1212 if (strEQ(d,"setgrent"))
1214 if (strEQ(d,"seekdir"))
1216 if (strEQ(d,"setsockopt"))
1223 if (strEQ(d,"shift"))
1225 if (strEQ(d,"shmctl"))
1227 if (strEQ(d,"shmget"))
1229 if (strEQ(d,"shmread"))
1231 if (strEQ(d,"shmwrite"))
1233 if (strEQ(d,"shutdown"))
1244 if (strEQ(d,"sleep"))
1251 if (strEQ(d,"socket"))
1253 if (strEQ(d,"socketpair"))
1255 if (strEQ(d,"sort")) {
1256 checkcomma(s,d,"subroutine name");
1258 while (s < d && isSPACE(*s)) s++;
1259 if (*s == ';' || *s == ')') /* probably a close */
1260 fatal("sort is now a reserved word");
1261 if (isALPHA(*s) || *s == '_') {
1263 for (d = s; isALNUM(*d); d++) ;
1264 strncpy(tokenbuf,s,d-s);
1265 tokenbuf[d-s] = '\0';
1266 if (strNE(tokenbuf,"keys") &&
1267 strNE(tokenbuf,"values") &&
1268 strNE(tokenbuf,"split") &&
1269 strNE(tokenbuf,"grep") &&
1270 strNE(tokenbuf,"readdir") &&
1271 strNE(tokenbuf,"unpack") &&
1272 strNE(tokenbuf,"do") &&
1273 strNE(tokenbuf,"eval") &&
1274 (d >= bufend || isSPACE(*d)) )
1275 *(--s) = '\\'; /* force next ident to WORD */
1281 if (strEQ(d,"split"))
1283 if (strEQ(d,"sprintf"))
1285 if (strEQ(d,"splice")) {
1286 yylval.ival = O_SPLICE;
1291 if (strEQ(d,"sqrt"))
1295 if (strEQ(d,"srand"))
1301 if (strEQ(d,"stat"))
1303 if (strEQ(d,"study")) {
1309 if (strEQ(d,"substr"))
1311 if (strEQ(d,"sub")) {
1312 yylval.ival = savestack->ary_fill; /* restore stuff on reduce */
1316 subline = curcmd->c_line;
1318 while (s < d && isSPACE(*s))
1320 if (isALPHA(*s) || *s == '_' || *s == '\'') {
1321 str_sset(subname,curstname);
1322 str_ncat(subname,"'",1);
1323 for (d = s+1; isALNUM(*d) || *d == '\''; d++)
1328 str_ncat(subname,s,d-s);
1329 *(--s) = '\\'; /* force next ident to WORD */
1332 str_set(subname,"?");
1341 if (strEQ(d,"system")) {
1345 if (strEQ(d,"symlink"))
1347 if (strEQ(d,"syscall"))
1349 if (strEQ(d,"sysread"))
1351 if (strEQ(d,"syswrite"))
1360 if (strEQ(d,"tr")) {
1365 RETURN(1); /* force error */
1367 if (strEQ(d,"tell"))
1369 if (strEQ(d,"telldir"))
1371 if (strEQ(d,"time"))
1373 if (strEQ(d,"times"))
1375 if (strEQ(d,"truncate"))
1380 if (strEQ(d,"using"))
1382 if (strEQ(d,"until")) {
1383 yylval.ival = curcmd->c_line;
1386 if (strEQ(d,"unless")) {
1387 yylval.ival = curcmd->c_line;
1390 if (strEQ(d,"unlink"))
1392 if (strEQ(d,"undef"))
1394 if (strEQ(d,"unpack"))
1396 if (strEQ(d,"utime"))
1398 if (strEQ(d,"umask"))
1400 if (strEQ(d,"unshift")) {
1401 yylval.ival = O_UNSHIFT;
1407 if (strEQ(d,"values"))
1409 if (strEQ(d,"vec")) {
1416 if (strEQ(d,"while")) {
1417 yylval.ival = curcmd->c_line;
1420 if (strEQ(d,"warn"))
1422 if (strEQ(d,"wait"))
1424 if (strEQ(d,"waitpid"))
1426 if (strEQ(d,"wantarray")) {
1427 yylval.arg = op_new(1);
1428 yylval.arg->arg_type = O_ITEM;
1429 yylval.arg[1].arg_type = A_WANTARRAY;
1432 if (strEQ(d,"write"))
1436 if (*s == 'x' && isDIGIT(s[1]) && !expectterm) {
1464 yylval.cval = savestr(d);
1465 if (expectterm == 2) { /* special case: start of statement */
1466 while (isSPACE(*s)) s++;
1475 if (oldoldbufptr && oldoldbufptr < bufptr) {
1476 while (isSPACE(*oldoldbufptr))
1478 if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5))
1480 else if (*oldoldbufptr == 's' && strnEQ(oldoldbufptr,"sort",4))
1483 return (CLINE, bufptr = s, (int)WORD);
1487 checkcomma(s,name,what)
1494 if (dowarn && *s == ' ' && s[1] == '(') {
1497 for (w++; *w && isSPACE(*w); w++) ;
1498 if (!w || !*w || !index(";|}", *w)) /* an advisory hack only... */
1499 warn("%s (...) interpreted as function",name);
1501 while (s < bufend && isSPACE(*s))
1505 while (s < bufend && isSPACE(*s))
1507 if (isALPHA(*s) || *s == '_') {
1511 while (s < bufend && isSPACE(*s))
1516 "tell eof times getlogin wait length shift umask getppid \
1517 cos exp int log rand sin sqrt ord wantarray",
1522 fatal("No comma allowed after %s", what);
1528 scanident(s,send,dest)
1530 register char *send;
1544 while (isALNUM(*s) || *s == '\'')
1547 while (d > dest+1 && d[-1] == '\'')
1553 if (*d == '{' /* } */ ) {
1556 while (s < send && brackets) {
1557 if (!reparse && (d == dest || (*s && isALNUM(*s) ))) {
1567 if (reparse && reparse == s - 1)
1581 if (*d == '^' && (isUPPER(*s) || index("[\\]^_?", *s))) {
1592 scanconst(spat,string,len)
1597 register STR *tmpstr;
1601 char *origstring = string;
1602 static char *vert = "|";
1604 if (ninstr(string, string+len, vert, vert+1))
1608 tmpstr = Str_new(86,len);
1609 str_nset(tmpstr,string,len);
1610 t = str_get(tmpstr);
1612 tmpstr->str_u.str_useful = 100;
1613 for (d=t; d < e; ) {
1621 case '.': case '[': case '$': case '(': case ')': case '|': case '+':
1626 if (d[1] && index("wWbB0123456789sSdDlLuUExc",d[1])) {
1630 Move(d+1,d,e-d,char);
1655 if (d[1] == '*' || (d[1] == '{' && d[2] == '0') || d[1] == '?') {
1667 tmpstr->str_cur = d - t;
1669 spat->spat_flags |= SPAT_ALL;
1670 if (*origstring != '^')
1671 spat->spat_flags |= SPAT_SCANFIRST;
1672 spat->spat_short = tmpstr;
1673 spat->spat_slen = d - t;
1680 register SPAT *spat;
1685 STR *str = Str_new(93,0);
1688 Newz(801,spat,1,SPAT);
1689 spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
1690 curstash->tbl_spatroot = spat;
1699 spat->spat_flags |= SPAT_ONCE;
1702 fatal("panic: scanpat");
1704 s = str_append_till(str,s,bufend,s[-1],patleave);
1707 yyerror("Search pattern not terminated");
1708 yylval.arg = Nullarg;
1712 while (*s == 'i' || *s == 'o' || *s == 'g') {
1716 spat->spat_flags |= SPAT_FOLD;
1720 spat->spat_flags |= SPAT_KEEP;
1724 spat->spat_flags |= SPAT_GLOBAL;
1728 e = str->str_ptr + len;
1733 for (; d < e; d++) {
1736 else if ((*d == '$' && d[1] && d[1] != '|' && d[1] != ')') ||
1740 spat->spat_runtime = arg = op_new(1);
1741 arg->arg_type = O_ITEM;
1742 arg[1].arg_type = A_DOUBLE;
1743 arg[1].arg_ptr.arg_str = str_smake(str);
1744 d = scanident(d,bufend,buf);
1745 (void)stabent(buf,TRUE); /* make sure it's created */
1746 for (; d < e; d++) {
1749 else if (*d == '$' && d[1] && d[1] != '|' && d[1] != ')') {
1750 d = scanident(d,bufend,buf);
1751 (void)stabent(buf,TRUE);
1753 else if (*d == '@') {
1754 d = scanident(d,bufend,buf);
1755 if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
1756 strEQ(buf,"SIG") || strEQ(buf,"INC"))
1757 (void)stabent(buf,TRUE);
1760 goto got_pat; /* skip compiling for now */
1763 if (spat->spat_flags & SPAT_FOLD)
1764 StructCopy(spat, &savespat, SPAT);
1765 scanconst(spat,str->str_ptr,len);
1766 if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
1767 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1768 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1769 spat->spat_flags & SPAT_FOLD);
1770 /* Note that this regexp can still be used if someone says
1771 * something like /a/ && s//b/; so we can't delete it.
1775 if (spat->spat_flags & SPAT_FOLD)
1776 StructCopy(&savespat, spat, SPAT);
1777 if (spat->spat_short)
1778 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1779 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1780 spat->spat_flags & SPAT_FOLD);
1785 yylval.arg = make_match(O_MATCH,stab2arg(A_STAB,defstab),spat);
1793 register char *s = start;
1794 register SPAT *spat;
1798 STR *str = Str_new(93,0);
1801 if (term && (d = index("([{< )]}> )]}>",term)))
1804 Newz(802,spat,1,SPAT);
1805 spat->spat_next = curstash->tbl_spatroot; /* link into spat list */
1806 curstash->tbl_spatroot = spat;
1808 s = str_append_till(str,s+1,bufend,term,patleave);
1811 yyerror("Substitution pattern not terminated");
1812 yylval.arg = Nullarg;
1816 e = str->str_ptr + len;
1817 for (d = str->str_ptr; d < e; d++) {
1820 else if ((*d == '$' && d[1] && d[1] != '|' && /*(*/ d[1] != ')') ||
1824 spat->spat_runtime = arg = op_new(1);
1825 arg->arg_type = O_ITEM;
1826 arg[1].arg_type = A_DOUBLE;
1827 arg[1].arg_ptr.arg_str = str_smake(str);
1828 d = scanident(d,e,buf);
1829 (void)stabent(buf,TRUE); /* make sure it's created */
1831 if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') {
1832 d = scanident(d,e,buf);
1833 (void)stabent(buf,TRUE);
1835 else if (*d == '@' && d[-1] != '\\') {
1836 d = scanident(d,e,buf);
1837 if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
1838 strEQ(buf,"SIG") || strEQ(buf,"INC"))
1839 (void)stabent(buf,TRUE);
1842 goto get_repl; /* skip compiling for now */
1845 scanconst(spat,str->str_ptr,len);
1849 s = scanstr(s, SCAN_REPL);
1852 yyerror("Substitution replacement not terminated");
1853 yylval.arg = Nullarg;
1856 spat->spat_repl = yylval.arg;
1857 if ((spat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
1858 spat->spat_flags |= SPAT_CONST;
1859 else if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE) {
1863 spat->spat_flags |= SPAT_CONST;
1864 tmpstr = spat->spat_repl[1].arg_ptr.arg_str;
1865 e = tmpstr->str_ptr + tmpstr->str_cur;
1866 for (t = tmpstr->str_ptr; t < e; t++) {
1867 if (*t == '$' && t[1] && (index("`'&+0123456789",t[1]) ||
1868 (t[1] == '{' /*}*/ && isDIGIT(t[2])) ))
1869 spat->spat_flags &= ~SPAT_CONST;
1872 while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
1878 if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
1879 spat->spat_repl[1].arg_type = A_SINGLE;
1880 spat->spat_repl = make_op(
1881 (!es && spat->spat_repl[1].arg_type == A_SINGLE
1888 spat->spat_flags &= ~SPAT_CONST;
1892 spat->spat_flags |= SPAT_GLOBAL;
1897 spat->spat_flags |= SPAT_FOLD;
1898 if (!(spat->spat_flags & SPAT_SCANFIRST)) {
1899 str_free(spat->spat_short); /* anchored opt doesn't do */
1900 spat->spat_short = Nullstr; /* case insensitive match */
1901 spat->spat_slen = 0;
1906 spat->spat_flags |= SPAT_KEEP;
1909 if (spat->spat_short && (spat->spat_flags & SPAT_SCANFIRST))
1910 fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
1911 if (!spat->spat_runtime) {
1912 spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
1913 spat->spat_flags & SPAT_FOLD);
1916 yylval.arg = make_match(O_SUBST,stab2arg(A_STAB,defstab),spat);
1923 register SPAT *spat;
1925 if (!spat->spat_short && spat->spat_regexp->regstart &&
1926 (!spat->spat_regexp->regmust || spat->spat_regexp->reganch & ROPT_ANCH)
1928 if (!(spat->spat_regexp->reganch & ROPT_ANCH))
1929 spat->spat_flags |= SPAT_SCANFIRST;
1930 else if (spat->spat_flags & SPAT_FOLD)
1932 spat->spat_short = str_smake(spat->spat_regexp->regstart);
1934 else if (spat->spat_regexp->regmust) {/* is there a better short-circuit? */
1935 if (spat->spat_short &&
1936 str_eq(spat->spat_short,spat->spat_regexp->regmust))
1938 if (spat->spat_flags & SPAT_SCANFIRST) {
1939 str_free(spat->spat_short);
1940 spat->spat_short = Nullstr;
1943 str_free(spat->spat_regexp->regmust);
1944 spat->spat_regexp->regmust = Nullstr;
1948 if (!spat->spat_short || /* promote the better string */
1949 ((spat->spat_flags & SPAT_SCANFIRST) &&
1950 (spat->spat_short->str_cur < spat->spat_regexp->regmust->str_cur) )){
1951 str_free(spat->spat_short); /* ok if null */
1952 spat->spat_short = spat->spat_regexp->regmust;
1953 spat->spat_regexp->regmust = Nullstr;
1954 spat->spat_flags |= SPAT_SCANFIRST;
1963 register char *s = start;
1965 l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
1970 register short *tbl;
1978 New(803,tbl,256,short);
1979 arg[2].arg_type = A_NULL;
1980 arg[2].arg_ptr.arg_cval = (char*) tbl;
1982 s = scanstr(s, SCAN_TR);
1984 yyerror("Translation pattern not terminated");
1985 yylval.arg = Nullarg;
1988 tstr = yylval.arg[1].arg_ptr.arg_str;
1989 yylval.arg[1].arg_ptr.arg_str = Nullstr;
1990 arg_free(yylval.arg);
1992 tlen = tstr->str_cur;
1994 if (s[-1] == *start)
1997 s = scanstr(s, SCAN_TR|SCAN_REPL);
1999 yyerror("Translation replacement not terminated");
2000 yylval.arg = Nullarg;
2003 rstr = yylval.arg[1].arg_ptr.arg_str;
2004 yylval.arg[1].arg_ptr.arg_str = Nullstr;
2005 arg_free(yylval.arg);
2007 rlen = rstr->str_cur;
2009 complement = delete = squash = 0;
2010 while (*s == 'c' || *s == 'd' || *s == 's') {
2019 arg[2].arg_len = delete|squash;
2022 Zero(tbl, 256, short);
2023 for (i = 0; i < tlen; i++)
2024 tbl[t[i] & 0377] = -1;
2025 for (i = 0, j = 0; i < 256; i++) {
2031 tbl[i] = r[j-1] & 0377;
2036 tbl[i] = r[j++] & 0377;
2041 if (!rlen && !delete) {
2044 for (i = 0; i < 256; i++)
2046 for (i = 0, j = 0; i < tlen; i++,j++) {
2049 if (tbl[t[i] & 0377] == -1)
2050 tbl[t[i] & 0377] = -2;
2055 if (tbl[t[i] & 0377] == -1)
2056 tbl[t[i] & 0377] = r[j] & 0377;
2065 scanstr(start, in_what)
2069 register char *s = start;
2073 register char *send;
2074 register bool makesingle = FALSE;
2075 register STAB *stab;
2076 bool alwaysdollar = FALSE;
2077 bool hereis = FALSE;
2080 /* which backslash sequences to keep */
2081 char *leave = (in_what & SCAN_TR)
2082 ? "\\$@nrtfbeacx0123456789-"
2083 : "\\$@nrtfbeacx0123456789[{]}lLuUE";
2088 arg->arg_type = O_ITEM;
2091 default: /* a substitution replacement */
2092 arg[1].arg_type = A_DOUBLE;
2093 makesingle = TRUE; /* maybe disable runtime scanning */
2103 arg[1].arg_type = A_SINGLE;
2108 else if (s[1] == '.')
2122 yyerror("Illegal octal digit");
2124 case '0': case '1': case '2': case '3': case '4':
2125 case '5': case '6': case '7':
2129 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
2130 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
2134 i += (*s++ & 7) + 9;
2139 str = Str_new(92,0);
2140 str_numset(str,(double)i);
2142 Safefree(str->str_ptr);
2143 str->str_ptr = Nullch;
2144 str->str_len = str->str_cur = 0;
2146 arg[1].arg_ptr.arg_str = str;
2149 case '1': case '2': case '3': case '4': case '5':
2150 case '6': case '7': case '8': case '9': case '.':
2152 arg[1].arg_type = A_SINGLE;
2154 while (isDIGIT(*s) || *s == '_') {
2160 if (*s == '.' && s[1] != '.') {
2162 while (isDIGIT(*s) || *s == '_') {
2169 if (*s && index("eE",*s) && index("+-0123456789",s[1])) {
2171 if (*s == '+' || *s == '-')
2177 str = Str_new(92,0);
2178 str_numset(str,atof(tokenbuf));
2180 Safefree(str->str_ptr);
2181 str->str_ptr = Nullch;
2182 str->str_len = str->str_cur = 0;
2184 arg[1].arg_ptr.arg_str = str;
2187 if (in_what & (SCAN_REPL|SCAN_TR))
2194 if (*++s && index("`'\"",*s)) {
2196 s = cpytill(d,s,bufend,term,&len);
2208 } /* assuming tokenbuf won't clobber */
2213 if (rsfp || !(d=ninstr(s,bufend,d,d+1)))
2214 herewas = str_make(s,bufend-s);
2216 s--, herewas = str_make(s,d-s);
2217 s += herewas->str_cur;
2225 s = cpytill(d,s,bufend,'>',&len);
2229 fatal("Unterminated <> operator");
2232 while (*d && (isALNUM(*d) || *d == '\''))
2234 if (d - tokenbuf != len) {
2237 arg[1].arg_type = A_GLOB;
2239 alwaysdollar = TRUE; /* treat $) and $| as variables */
2245 (void)strcpy(d,"ARGV");
2247 arg[1].arg_type = A_INDREAD;
2248 arg[1].arg_ptr.arg_stab = stabent(d+1,TRUE);
2251 arg[1].arg_type = A_READ;
2252 arg[1].arg_ptr.arg_stab = stabent(d,TRUE);
2253 if (!stab_io(arg[1].arg_ptr.arg_stab))
2254 stab_io(arg[1].arg_ptr.arg_stab) = stio_new();
2255 if (strEQ(d,"ARGV")) {
2256 (void)aadd(arg[1].arg_ptr.arg_stab);
2257 stab_io(arg[1].arg_ptr.arg_stab)->flags |=
2278 arg[1].arg_type = A_SINGLE;
2285 arg[1].arg_type = A_DOUBLE;
2286 makesingle = TRUE; /* maybe disable runtime scanning */
2287 alwaysdollar = TRUE; /* treat $) and $| as variables */
2292 arg[1].arg_type = A_BACKTICK;
2294 alwaysdollar = TRUE; /* treat $) and $| as variables */
2298 STR *tmpstr2 = Nullstr;
2302 multi_start = curcmd->c_line;
2304 multi_open = multi_close = '<';
2307 if (term && (tmps = index("([{< )]}> )]}>",term)))
2311 tmpstr = Str_new(87,80);
2316 while (s < bufend &&
2317 (*s != term || bcmp(s,tokenbuf,len) != 0) ) {
2322 curcmd->c_line = multi_start;
2323 fatal("EOF in string");
2325 str_nset(tmpstr,d+1,s-d);
2327 str_ncat(herewas,s,bufend-s);
2328 str_replace(linestr,herewas);
2329 oldoldbufptr = oldbufptr = bufptr = s = str_get(linestr);
2330 bufend = linestr->str_ptr + linestr->str_cur;
2334 str_nset(tmpstr,"",0); /* avoid "uninitialized" warning */
2337 s = str_append_till(tmpstr,s+1,bufend,term,leave);
2338 while (s >= bufend) { /* multiple line string? */
2340 !(oldoldbufptr = oldbufptr = s = str_gets(linestr, rsfp, 0))) {
2341 curcmd->c_line = multi_start;
2342 fatal("EOF in string");
2346 STR *str = Str_new(88,0);
2348 str_sset(str,linestr);
2349 astore(stab_xarray(curcmd->c_filestab),
2350 (int)curcmd->c_line,str);
2352 bufend = linestr->str_ptr + linestr->str_cur;
2354 if (*s == term && bcmp(s,tokenbuf,len) == 0) {
2357 str_scat(linestr,herewas);
2358 bufend = linestr->str_ptr + linestr->str_cur;
2362 str_scat(tmpstr,linestr);
2366 s = str_append_till(tmpstr,s,bufend,term,leave);
2368 multi_end = curcmd->c_line;
2370 if (tmpstr->str_cur + 5 < tmpstr->str_len) {
2371 tmpstr->str_len = tmpstr->str_cur + 1;
2372 Renew(tmpstr->str_ptr, tmpstr->str_len, char);
2374 if (arg[1].arg_type == A_SINGLE) {
2375 arg[1].arg_ptr.arg_str = tmpstr;
2379 s = tmpstr->str_ptr;
2380 send = s + tmpstr->str_cur;
2381 while (s < send) { /* see if we can make SINGLE */
2382 if (*s == '\\' && s[1] && isDIGIT(s[1]) && !isDIGIT(s[2]) &&
2383 !alwaysdollar && s[1] != '0')
2384 *s = '$'; /* grandfather \digit in subst */
2385 if ((*s == '$' || *s == '@') && s+1 < send &&
2386 (alwaysdollar || (s[1] != ')' && s[1] != '|'))) {
2387 makesingle = FALSE; /* force interpretation */
2389 else if (*s == '\\' && s+1 < send) {
2390 if (index("lLuUE",s[1]))
2396 s = d = tmpstr->str_ptr; /* assuming shrinkage only */
2398 if (in_what & SCAN_TR) {
2399 if (*s != '\\' && s[1] == '-' && s+2 < send) {
2401 if (!tmpstr2) { /* oops, have to grow */
2402 tmpstr2 = str_smake(tmpstr);
2403 s = tmpstr2->str_ptr + (s - tmpstr->str_ptr);
2404 send = tmpstr2->str_ptr + (send - tmpstr->str_ptr);
2406 i = d - tmpstr->str_ptr;
2407 STR_GROW(tmpstr, tmpstr->str_len + 256);
2408 d = tmpstr->str_ptr + i;
2409 for (i = (s[0] & 0377); i <= (s[2] & 0377); i++)
2416 if ((*s == '$' && s+1 < send &&
2417 (alwaysdollar || /*(*/(s[1] != ')' && s[1] != '|')) ) ||
2418 (*s == '@' && s+1 < send) ) {
2419 if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
2421 len = scanident(s,send,tokenbuf) - s;
2422 if (*s == '$' || strEQ(tokenbuf,"ARGV")
2423 || strEQ(tokenbuf,"ENV")
2424 || strEQ(tokenbuf,"SIG")
2425 || strEQ(tokenbuf,"INC") )
2426 (void)stabent(tokenbuf,TRUE); /* add symbol */
2432 if (*s == '\\' && s+1 < send) {
2436 if (!makesingle && (!leave || (*s && index(leave,*s))))
2440 case '0': case '1': case '2': case '3':
2441 case '4': case '5': case '6': case '7':
2442 *d++ = scanoct(s, 3, &len);
2446 *d++ = scanhex(++s, 2, &len);
2485 if (arg[1].arg_type == A_DOUBLE && makesingle)
2486 arg[1].arg_type = A_SINGLE; /* now we can optimize on it */
2488 tmpstr->str_cur = d - tmpstr->str_ptr;
2489 if (arg[1].arg_type == A_GLOB) {
2490 arg[1].arg_ptr.arg_stab = stab = genstab();
2491 stab_io(stab) = stio_new();
2492 str_sset(stab_val(stab), tmpstr);
2495 arg[1].arg_ptr.arg_str = tmpstr;
2513 register FCMD *fprev = &froot;
2514 register FCMD *fcmd;
2521 Zero(&froot, 1, FCMD);
2523 while (s < bufend || (rsfp && (s = str_gets(linestr,rsfp, 0)) != Nullch)) {
2525 if (in_eval && !rsfp) {
2526 eol = index(s,'\n');
2531 eol = bufend = linestr->str_ptr + linestr->str_cur;
2533 STR *tmpstr = Str_new(89,0);
2535 str_nset(tmpstr, s, eol-s);
2536 astore(stab_xarray(curcmd->c_filestab), (int)curcmd->c_line,tmpstr);
2540 for (t = s+1; *t == ' ' || *t == '\t'; t++) ;
2543 return froot.f_next;
2550 flinebeg = Nullfcmd;
2554 Newz(804,fcmd,1,FCMD);
2555 fprev->f_next = fcmd;
2557 for (t=s; t < eol && *t != '@' && *t != '^'; t++) {
2567 fcmd->f_pre = nsavestr(s, t-s);
2568 fcmd->f_presize = t-s;
2572 fcmd->f_flags |= FC_NOBLANK;
2574 fcmd->f_flags |= FC_REPEAT;
2578 flinebeg = fcmd; /* start values here */
2580 fcmd->f_flags |= FC_CHOP; /* for doing text filling */
2583 fcmd->f_type = F_LINES;
2587 fcmd->f_type = F_LEFT;
2592 fcmd->f_type = F_RIGHT;
2597 fcmd->f_type = F_CENTER;
2603 /* Catch the special case @... and handle it as a string
2605 if (*s == '.' && s[1] == '.') {
2606 goto default_format;
2608 fcmd->f_type = F_DECIMAL;
2612 /* Read a format in the form @####.####, where either group
2613 of ### may be empty, or the final .### may be missing. */
2621 fcmd->f_decimals = s-p;
2622 fcmd->f_flags |= FC_DP;
2624 fcmd->f_decimals = 0;
2630 fcmd->f_type = F_LEFT;
2633 if (fcmd->f_flags & FC_CHOP && *s == '.') {
2634 fcmd->f_flags |= FC_MORE;
2643 (!rsfp || (s = str_gets(linestr, rsfp, 0)) == Nullch) )
2646 if (in_eval && !rsfp) {
2647 eol = index(s,'\n');
2652 eol = bufend = linestr->str_ptr + linestr->str_cur;
2654 STR *tmpstr = Str_new(90,0);
2656 str_nset(tmpstr, s, eol-s);
2657 astore(stab_xarray(curcmd->c_filestab),
2658 (int)curcmd->c_line,tmpstr);
2660 if (strnEQ(s,".\n",2)) {
2662 yyerror("Missing values line");
2663 return froot.f_next;
2669 str = flinebeg->f_unparsed = Str_new(91,eol - s);
2670 str->str_u.str_hash = curstash;
2671 str_nset(str,"(",1);
2672 flinebeg->f_line = curcmd->c_line;
2674 if (!flinebeg->f_next->f_type || index(s, ',')) {
2676 str_ncat(str, s, eol - s - 1);
2677 str_ncat(str,",$$);",5);
2682 while (s < eol && isSPACE(*s))
2687 case ' ': case '\t': case '\n': case ';':
2688 str_ncat(str, t, s - t);
2689 str_ncat(str, "," ,1);
2690 while (s < eol && (isSPACE(*s) || *s == ';'))
2695 str_ncat(str, t, s - t);
2697 s = scanident(s,eol,tokenbuf);
2698 str_ncat(str, t, s - t);
2700 if (s < eol && *s && index("$'\"",*s))
2701 str_ncat(str, ",", 1);
2703 case '"': case '\'':
2704 str_ncat(str, t, s - t);
2707 while (s < eol && (*s != *t || s[-1] == '\\'))
2711 str_ncat(str, t, s - t);
2713 if (s < eol && *s && index("$'\"",*s))
2714 str_ncat(str, ",", 1);
2717 yyerror("Please use commas to separate fields");
2720 str_ncat(str,"$$);",4);
2725 bufptr = str_get(linestr);
2726 yyerror("Format not terminated");
2727 return froot.f_next;
2735 cshlen = strlen(cshname);