1 /* $Header: arg.c,v 2.0 88/06/05 00:08:04 root Exp $
4 * Revision 2.0 88/06/05 00:08:04 root
5 * Baseline version 2.0.
18 do_match(arg,retary,sarg,ptrmaxsarg,sargoff,cushion)
26 register SPAT *spat = arg[2].arg_ptr.arg_spat;
28 register char *s = str_get(sarg[1]);
29 char *strend = s + sarg[1]->str_cur;
34 fatal("panic: do_match");
36 *retary = sarg; /* assume no match */
37 *ptrmaxsarg = sargoff;
39 if (spat->spat_flags & SPAT_USED) {
46 if (spat->spat_runtime) {
47 t = str_get(eval(spat->spat_runtime,Null(STR***),-1));
50 deb("2.SPAT /%s/\n",t);
52 spat->spat_regexp = regcomp(t,spat->spat_flags & SPAT_FOLD,1);
53 if (!*spat->spat_regexp->precomp && lastspat)
55 if (regexec(spat->spat_regexp, s, strend, TRUE, 0,
56 sarg[1]->str_pok & 4 ? sarg[1] : Nullstr)) {
57 if (spat->spat_regexp->subbase)
70 if (spat->spat_flags & SPAT_ONCE)
74 deb("2.SPAT %c%s%c\n",ch,spat->spat_regexp->precomp,ch);
77 if (!*spat->spat_regexp->precomp && lastspat)
81 if (hint < s || hint > strend)
82 fatal("panic: hint in do_match");
85 if (spat->spat_regexp->regback >= 0) {
86 s -= spat->spat_regexp->regback;
93 else if (spat->spat_short) {
94 if (spat->spat_flags & SPAT_SCANFIRST) {
95 if (sarg[1]->str_pok == 5) {
96 if (screamfirst[spat->spat_short->str_rare] < 0)
98 else if (!(s = screaminstr(sarg[1],spat->spat_short)))
100 else if (spat->spat_flags & SPAT_ALL)
103 else if (!(s = fbminstr(s, strend, spat->spat_short)))
105 else if (spat->spat_flags & SPAT_ALL)
107 else if (spat->spat_regexp->regback >= 0) {
108 ++*(long*)&spat->spat_short->str_nval;
109 s -= spat->spat_regexp->regback;
116 else if (!multiline && (*spat->spat_short->str_ptr != *s ||
117 strnNE(spat->spat_short->str_ptr, s, spat->spat_slen) ))
119 if (--*(long*)&spat->spat_short->str_nval < 0) {
120 str_free(spat->spat_short);
121 spat->spat_short = Nullstr; /* opt is being useless */
124 if (regexec(spat->spat_regexp, s, strend, s == t, 0,
125 sarg[1]->str_pok & 4 ? sarg[1] : Nullstr)) {
126 if (spat->spat_regexp->subbase)
129 if (spat->spat_flags & SPAT_ONCE)
130 spat->spat_flags |= SPAT_USED;
139 if (retary && curspat == spat) {
142 iters = spat->spat_regexp->nparens;
143 *ptrmaxsarg = iters + sargoff;
144 sarg = (STR**)saferealloc((char*)(sarg - sargoff),
145 (iters+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
147 for (i = 1; i <= iters; i++) {
148 sarg[i] = str_static(&str_no);
149 if (s = spat->spat_regexp->startp[i]) {
150 len = spat->spat_regexp->endp[i] - s;
152 str_nset(sarg[i],s,len);
160 ++*(long*)&spat->spat_short->str_nval;
164 ++*(long*)&spat->spat_short->str_nval;
175 register char *s = str_get(str);
176 char *strend = s + str->str_cur;
179 spat = arg[2].arg_ptr.arg_spat;
181 fatal("panic: do_subst");
182 else if (spat->spat_runtime) {
183 m = str_get(eval(spat->spat_runtime,Null(STR***),-1));
184 spat->spat_regexp = regcomp(m,spat->spat_flags & SPAT_FOLD,1);
188 deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
191 if (!*spat->spat_regexp->precomp && lastspat)
195 if (hint < s || hint > strend)
196 fatal("panic: hint in do_match");
199 if (spat->spat_regexp->regback >= 0) {
200 s -= spat->spat_regexp->regback;
207 else if (spat->spat_short) {
208 if (spat->spat_flags & SPAT_SCANFIRST) {
209 if (str->str_pok == 5) {
210 if (screamfirst[spat->spat_short->str_rare] < 0)
212 else if (!(s = screaminstr(str,spat->spat_short)))
215 else if (!(s = fbminstr(s, strend, spat->spat_short)))
217 else if (spat->spat_regexp->regback >= 0) {
218 ++*(long*)&spat->spat_short->str_nval;
219 s -= spat->spat_regexp->regback;
226 else if (!multiline && (*spat->spat_short->str_ptr != *s ||
227 strnNE(spat->spat_short->str_ptr, s, spat->spat_slen) ))
229 if (--*(long*)&spat->spat_short->str_nval < 0) {
230 str_free(spat->spat_short);
231 spat->spat_short = Nullstr; /* opt is being useless */
234 if (regexec(spat->spat_regexp, s, strend, s == m, 1,
235 str->str_pok & 4 ? str : Nullstr)) {
238 dstr = str_new(str_len(str));
239 str_nset(dstr,m,s-m);
240 if (spat->spat_regexp->subbase)
244 m = spat->spat_regexp->startp[0];
246 fatal("Substitution loop");
247 if (spat->spat_regexp->subbase)
248 s = spat->spat_regexp->subbase;
249 str_ncat(dstr,s,m-s);
250 s = spat->spat_regexp->endp[0];
251 str_scat(dstr,eval(spat->spat_repl,Null(STR***),-1));
252 if (spat->spat_flags & SPAT_ONCE)
254 } while (regexec(spat->spat_regexp, s, strend, FALSE, 1, Nullstr));
256 str_replace(str,dstr);
263 ++*(long*)&spat->spat_short->str_nval;
274 register int matches = 0;
277 tbl = arg[2].arg_ptr.arg_cval;
280 fatal("panic: do_trans");
287 if (ch = tbl[*s & 0377]) {
298 do_split(spat,retary,sarg,ptrmaxsarg,sargoff,cushion)
306 register char *s = str_get(sarg[1]);
307 char *strend = s + sarg[1]->str_cur;
311 static ARRAY *myarray = Null(ARRAY*);
316 fatal("panic: do_split");
317 else if (spat->spat_runtime) {
318 m = str_get(eval(spat->spat_runtime,Null(STR***),-1));
319 if (!*m || (*m == ' ' && !m[1])) {
321 spat->spat_flags |= SPAT_SKIPWHITE;
323 if (spat->spat_runtime->arg_type == O_ITEM &&
324 spat->spat_runtime[1].arg_type == A_SINGLE) {
325 arg_free(spat->spat_runtime); /* it won't change, so */
326 spat->spat_runtime = Nullarg; /* no point compiling again */
328 spat->spat_regexp = regcomp(m,spat->spat_flags & SPAT_FOLD,1);
332 deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
338 ary = spat->spat_repl[1].arg_ptr.arg_stab->stab_array;
340 myarray = ary = anew(Nullstab);
342 if (spat->spat_flags & SPAT_SKIPWHITE) {
346 if (spat->spat_short) {
347 i = spat->spat_short->str_cur;
348 while (*s && (m = fbminstr(s, strend, spat->spat_short))) {
350 str_nset(dstr,s,m-s);
351 astore(ary, iters++, dstr);
353 fatal("Substitution loop");
358 while (*s && regexec(spat->spat_regexp, s, strend, (iters == 0), 1,
360 m = spat->spat_regexp->startp[0];
361 if (spat->spat_regexp->subbase)
362 s = spat->spat_regexp->subbase;
364 str_nset(dstr,s,m-s);
365 astore(ary, iters++, dstr);
367 fatal("Substitution loop");
368 s = spat->spat_regexp->endp[0];
371 if (*s) { /* ignore field after final "whitespace" */
372 dstr = str_new(0); /* if they interpolate, it's null anyway */
374 astore(ary, iters++, dstr);
377 while (iters > 0 && !*str_get(afetch(ary,iters-1)))
381 *ptrmaxsarg = iters + sargoff;
382 sarg = (STR**)saferealloc((char*)(sarg - sargoff),
383 (iters+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
385 for (i = 1; i <= iters; i++)
386 sarg[i] = afetch(ary,i-1);
393 do_join(arg,delim,str)
395 register char *delim;
398 STR **tmpary; /* must not be register */
402 (void)eval(arg[2].arg_ptr.arg_arg,&tmpary,-1);
403 items = (int)str_gnum(*tmpary);
406 str_sset(str,*elem++);
407 for (; items > 0; items--,elem++) {
412 safefree((char*)tmpary);
424 while ((forkprocess = fork()) == -1) {
432 return fdopen(pfd[1],"w");
437 dup(pfd[0]); /* substitute our pipe for stdin */
445 return fdopen(pfd[0],"r");
450 if (dup(pfd[1]) == 0)
451 dup(pfd[1]); /* substitute our pipe for stdout */
464 int len = strlen(name);
465 register STIO *stio = stab->stab_io;
466 char *myname = savestr(name);
471 forkprocess = 1; /* assume true if no fork */
472 while (len && isspace(name[len-1]))
475 stio = stab->stab_io = stio_new();
477 fd = fileno(stio->fp);
478 if (stio->type == '|')
479 result = pclose(stio->fp);
480 else if (stio->type != '-')
481 result = fclose(stio->fp);
484 if (result == EOF && fd > 2)
485 fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
491 for (name++; isspace(*name); name++) ;
493 fp = popen(name,"w");
495 fp = forkopen(name,"w");
496 stio->subprocess = forkprocess;
500 else if (*name == '>' && name[1] == '>') {
502 for (name += 2; isspace(*name); name++) ;
503 fp = fopen(name,"a");
505 else if (*name == '>' && name[1] == '&') {
506 for (name += 2; isspace(*name); name++) ;
510 stab = stabent(name,FALSE);
511 if (stab->stab_io && stab->stab_io->fp) {
512 fd = fileno(stab->stab_io->fp);
513 stio->type = stab->stab_io->type;
518 fp = fdopen(dup(fd),stio->type == 'a' ? "a" :
519 (stio->type == '<' ? "r" : "w") );
521 else if (*name == '>') {
522 for (name++; isspace(*name); name++) ;
523 if (strEQ(name,"-")) {
528 fp = fopen(name,"w");
532 for (name++; isspace(*name); name++) ;
533 if (strEQ(name,"-")) {
538 fp = fopen(name,"r");
540 else if (name[len-1] == '|') {
542 while (len && isspace(name[len-1]))
544 for (; isspace(*name); name++) ;
545 if (strNE(name,"-")) {
546 fp = popen(name,"r");
550 fp = forkopen(name,"r");
551 stio->subprocess = forkprocess;
557 for (; isspace(*name); name++) ;
558 if (strEQ(name,"-")) {
563 fp = fopen(name,"r");
570 stio->type != '|' && stio->type != '-' && stio->type != '%') {
571 if (fstat(fileno(fp),&statbuf) < 0) {
575 if ((statbuf.st_mode & S_IFMT) != S_IFREG &&
576 (statbuf.st_mode & S_IFMT) != S_IFCHR) {
591 int filemode,fileuid,filegid;
593 while (alen(stab->stab_array) >= 0) {
594 str = ashift(stab->stab_array);
595 str_sset(stab->stab_val,str);
596 STABSET(stab->stab_val);
597 oldname = str_get(stab->stab_val);
598 if (do_open(stab,oldname)) {
600 filemode = statbuf.st_mode;
601 fileuid = statbuf.st_uid;
602 filegid = statbuf.st_gid;
604 str_cat(str,inplace);
606 rename(oldname,str->str_ptr);
608 UNLINK(str->str_ptr);
609 link(oldname,str->str_ptr);
616 sprintf(tokenbuf,">%s",oldname);
617 errno = 0; /* in case sprintf set errno */
618 do_open(argvoutstab,tokenbuf);
619 defoutstab = argvoutstab;
621 fchmod(fileno(argvoutstab->stab_io->fp),filemode);
623 chmod(oldname,filemode);
626 fchown(fileno(argvoutstab->stab_io->fp),fileuid,filegid);
628 chown(oldname,fileuid,filegid);
632 return stab->stab_io->fp;
635 fprintf(stderr,"Can't open %s\n",str_get(str));
639 do_close(argvoutstab,FALSE);
640 defoutstab = stabent("stdout",TRUE);
646 do_close(stab,explicit)
651 register STIO *stio = stab->stab_io;
655 if (!stio) { /* never opened */
656 if (dowarn && explicit)
657 warn("Close on unopened file <%s>",stab->stab_name);
661 if (stio->type == '|')
662 retval = (pclose(stio->fp) >= 0);
663 else if (stio->type == '-')
666 retval = (fclose(stio->fp) != EOF);
667 if (stio->type == '%' && stio->subprocess) {
668 while ((tmp = wait(&status)) != stio->subprocess && tmp != -1)
673 statusvalue = (unsigned)status & 0xffff;
691 if (!stab) /* eof() */
692 stio = argvstab->stab_io;
694 stio = stab->stab_io;
701 #ifdef STDSTDIO /* (the code works without this) */
702 if (stio->fp->_cnt) /* cheat a little, since */
703 return FALSE; /* this is the most usual case */
708 ungetc(ch, stio->fp);
711 if (!stab) { /* not necessarily a real EOF yet? */
712 if (!nextargv(argvstab)) /* get another fp handy */
716 return TRUE; /* normal fp, definitely end of file */
730 stio = stab->stab_io;
731 if (!stio || !stio->fp)
734 return ftell(stio->fp);
738 warn("tell() on unopened file");
743 do_seek(stab, pos, whence)
753 stio = stab->stab_io;
754 if (!stio || !stio->fp)
757 return fseek(stio->fp, pos, whence) >= 0;
761 warn("seek() on unopened file");
766 static STAB *firststab = Nullstab;
767 static STAB *secondstab = Nullstab;
769 do_sort(arg,stab,retary,sarg,ptrmaxsarg,sargoff,cushion)
778 STR **tmpary; /* must not be register */
780 register bool retval;
788 (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
789 max = (int)str_gnum(*tmpary);
792 sarg = (STR**)saferealloc((char*)(sarg - sargoff),
793 (max+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
794 for (i = 1; i <= max; i++)
798 if (stab->stab_sub && (sortcmd = stab->stab_sub->cmd)) {
800 firststab = stabent("a",TRUE);
801 secondstab = stabent("b",TRUE);
803 oldfirst = firststab->stab_val;
804 oldsecond = secondstab->stab_val;
805 qsort((char*)(sarg+1),max,sizeof(STR*),sortsub);
806 firststab->stab_val = oldfirst;
807 secondstab->stab_val = oldsecond;
810 qsort((char*)(sarg+1),max,sizeof(STR*),sortcmp);
812 while (max > 0 && !sarg[max])
814 *ptrmaxsarg = max + sargoff;
816 safefree((char*)tmpary);
831 tmps = str_get(*str1);
832 return strcmp(tmps,str_get(*str2));
846 firststab->stab_val = *str1;
847 secondstab->stab_val = *str2;
848 return (int)str_gnum(cmd_exec(sortcmd));
851 do_stat(arg,retary,sarg,ptrmaxsarg,sargoff,cushion)
860 static ARRAY *myarray = Null(ARRAY*);
866 myarray = ary = anew(Nullstab);
868 if (arg[1].arg_type == A_LVAL) {
869 tmpstab = arg[1].arg_ptr.arg_stab;
870 if (!tmpstab->stab_io ||
871 fstat(fileno(tmpstab->stab_io->fp),&statbuf) < 0) {
876 if (stat(str_get(sarg[1]),&statbuf) < 0)
881 apush(ary,str_nmake((double)statbuf.st_dev));
882 apush(ary,str_nmake((double)statbuf.st_ino));
883 apush(ary,str_nmake((double)statbuf.st_mode));
884 apush(ary,str_nmake((double)statbuf.st_nlink));
885 apush(ary,str_nmake((double)statbuf.st_uid));
886 apush(ary,str_nmake((double)statbuf.st_gid));
887 apush(ary,str_nmake((double)statbuf.st_rdev));
888 apush(ary,str_nmake((double)statbuf.st_size));
889 apush(ary,str_nmake((double)statbuf.st_atime));
890 apush(ary,str_nmake((double)statbuf.st_mtime));
891 apush(ary,str_nmake((double)statbuf.st_ctime));
893 apush(ary,str_nmake((double)statbuf.st_blksize));
894 apush(ary,str_nmake((double)statbuf.st_blocks));
896 apush(ary,str_make(""));
897 apush(ary,str_make(""));
900 *ptrmaxsarg = max + sargoff;
901 sarg = (STR**)saferealloc((char*)(sarg - sargoff),
902 (max+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
903 for (i = 1; i <= max; i++)
904 sarg[i] = afetch(ary,i-1);
910 do_tms(retary,sarg,ptrmaxsarg,sargoff,cushion)
918 static ARRAY *myarray = Null(ARRAY*);
924 myarray = ary = anew(Nullstab);
934 apush(ary,str_nmake(((double)timesbuf.tms_utime)/HZ));
935 apush(ary,str_nmake(((double)timesbuf.tms_stime)/HZ));
936 apush(ary,str_nmake(((double)timesbuf.tms_cutime)/HZ));
937 apush(ary,str_nmake(((double)timesbuf.tms_cstime)/HZ));
939 *ptrmaxsarg = max + sargoff;
940 sarg = (STR**)saferealloc((char*)(sarg - sargoff),
941 (max+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
942 for (i = 1; i <= max; i++)
943 sarg[i] = afetch(ary,i-1);
949 do_time(tmbuf,retary,sarg,ptrmaxsarg,sargoff,cushion)
958 static ARRAY *myarray = Null(ARRAY*);
964 myarray = ary = anew(Nullstab);
971 apush(ary,str_nmake((double)tmbuf->tm_sec));
972 apush(ary,str_nmake((double)tmbuf->tm_min));
973 apush(ary,str_nmake((double)tmbuf->tm_hour));
974 apush(ary,str_nmake((double)tmbuf->tm_mday));
975 apush(ary,str_nmake((double)tmbuf->tm_mon));
976 apush(ary,str_nmake((double)tmbuf->tm_year));
977 apush(ary,str_nmake((double)tmbuf->tm_wday));
978 apush(ary,str_nmake((double)tmbuf->tm_yday));
979 apush(ary,str_nmake((double)tmbuf->tm_isdst));
981 *ptrmaxsarg = max + sargoff;
982 sarg = (STR**)saferealloc((char*)(sarg - sargoff),
983 (max+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
984 for (i = 1; i <= max; i++)
985 sarg[i] = afetch(ary,i-1);
992 do_sprintf(str,len,sarg)
1001 static STR *sargnull = &str_no;
1004 len--; /* don't count pattern string */
1006 for (s = str_get(*(sarg++)); *s; len--) {
1007 if (len <= 0 || !*sarg) {
1012 for (t = s; *t && *t != '%'; t++) ;
1014 break; /* not enough % patterns, oh well */
1015 for (t++; *sarg && *t && t != s; t++) {
1030 case 'D': case 'X': case 'O':
1033 case 'd': case 'x': case 'o': case 'c': case 'u':
1037 sprintf(buf,s,(long)str_gnum(*(sarg++)));
1039 sprintf(buf,s,(int)str_gnum(*(sarg++)));
1043 case 'E': case 'e': case 'f': case 'G': case 'g':
1046 sprintf(buf,s,str_gnum(*(sarg++)));
1053 if (strEQ(s,"%s")) { /* some printfs fail on >128 chars */
1055 str_scat(str,*(sarg++)); /* so handle simple case */
1058 sprintf(buf,s,str_get(*(sarg++)));
1078 warn("print to unopened file");
1084 ((str->str_nok && str->str_nval != 0.0) || str_gnum(str) != 0.0) )
1085 fprintf(fp, ofmt, str->str_nval);
1087 fputs(str_get(str),fp);
1096 STR **tmpary; /* must not be register */
1097 register STR **elem;
1098 register bool retval;
1103 warn("print to unopened file");
1106 (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
1107 items = (int)str_gnum(*tmpary);
1108 if (arg->arg_type == O_PRTF) {
1109 do_sprintf(arg->arg_ptr.arg_str,items,tmpary);
1110 retval = do_print(arg->arg_ptr.arg_str,fp);
1114 for (elem = tmpary+1; items > 0; items--,elem++) {
1117 retval = do_print(*elem, fp);
1124 safefree((char*)tmpary);
1132 STR **tmpary; /* must not be register */
1133 register STR **elem;
1138 (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
1139 items = (int)str_gnum(*tmpary);
1141 argv = (char**)safemalloc((items+1)*sizeof(char*));
1143 for (elem = tmpary+1; items > 0; items--,elem++) {
1145 *a++ = str_get(*elem);
1150 execvp(argv[0],argv);
1151 safefree((char*)argv);
1153 safefree((char*)tmpary);
1164 char *cmd = str_get(str);
1166 /* see if there are shell metacharacters in it */
1168 for (s = cmd; *s; s++) {
1169 if (*s != ' ' && !isalpha(*s) && index("$&*(){}[]'\";\\|?<>~`",*s)) {
1170 execl("/bin/sh","sh","-c",cmd,(char*)0);
1174 argv = (char**)safemalloc(((s - cmd) / 2 + 2)*sizeof(char*));
1177 for (s = cmd; *s;) {
1178 while (isspace(*s)) s++;
1181 while (*s && !isspace(*s)) s++;
1187 execvp(argv[0],argv);
1188 safefree((char*)argv);
1195 register ARRAY *ary;
1197 STR **tmpary; /* must not be register */
1198 register STR **elem;
1199 register STR *str = &str_no;
1202 (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
1203 items = (int)str_gnum(*tmpary);
1204 for (elem = tmpary+1; items > 0; items--,elem++) {
1207 str_sset(str,*elem);
1210 safefree((char*)tmpary);
1216 register ARRAY *ary;
1218 STR **tmpary; /* must not be register */
1219 register STR **elem;
1220 register STR *str = &str_no;
1224 (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
1225 items = (int)str_gnum(*tmpary);
1226 aunshift(ary,items);
1228 for (elem = tmpary+1; i < items; i++,elem++) {
1230 str_sset(str,*elem);
1233 safefree((char*)tmpary);
1236 apply(type,arg,sarg)
1241 STR **tmpary; /* must not be register */
1242 register STR **elem;
1251 for (elem = tmpary+1; *elem; elem++)
1255 (void)eval(arg[1].arg_ptr.arg_arg,&tmpary,-1);
1256 items = (int)str_gnum(*tmpary);
1261 val = (int)str_gnum(tmpary[1]);
1262 for (elem = tmpary+2; *elem; elem++)
1263 if (chmod(str_get(*elem),val))
1270 val = (int)str_gnum(tmpary[1]);
1271 val2 = (int)str_gnum(tmpary[2]);
1272 for (elem = tmpary+3; *elem; elem++)
1273 if (chown(str_get(*elem),val,val2))
1281 val = (int)str_gnum(tmpary[1]);
1284 for (elem = tmpary+2; *elem; elem++)
1286 if (killpg((int)(str_gnum(*elem)),val)) /* BSD */
1288 if (kill(-(int)(str_gnum(*elem)),val)) /* SYSV */
1293 for (elem = tmpary+2; *elem; elem++)
1294 if (kill((int)(str_gnum(*elem)),val))
1300 for (elem = tmpary+1; *elem; elem++) {
1302 if (euid || unsafe) {
1306 else { /* don't let root wipe out directories without -U */
1307 if (stat(s,&statbuf) < 0 ||
1308 (statbuf.st_mode & S_IFMT) == S_IFDIR )
1324 utbuf.atime = (long)str_gnum(tmpary[1]); /* time accessed */
1325 utbuf.mtime = (long)str_gnum(tmpary[2]); /* time modified */
1327 for (elem = tmpary+3; *elem; elem++)
1328 if (utime(str_get(*elem),&utbuf))
1336 safefree((char*)tmpary);
1343 register STR **sarg;
1349 char *oldfile = filename;
1350 int oldsave = savestack->ary_fill;
1351 int oldtmps_base = tmps_base;
1353 if (arg[2].arg_type == A_WORD)
1354 stab = arg[2].arg_ptr.arg_stab;
1356 stab = stabent(str_get(arg[2].arg_ptr.arg_stab->stab_val),TRUE);
1359 warn("Undefined subroutine called");
1362 sub = stab->stab_sub;
1365 warn("Undefined subroutine \"%s\" called", stab->stab_name);
1368 savearray = defstab->stab_array;
1369 defstab->stab_array = anew(defstab);
1370 if (arg[1].arg_flags & AF_SPECIAL)
1371 (void)do_push(arg,defstab->stab_array);
1372 else if (arg[1].arg_type != A_NULL) {
1374 str_sset(str,sarg[1]);
1375 apush(defstab->stab_array,str);
1378 if (sub->depth >= 2) { /* save temporaries on recursion? */
1379 if (sub->depth == 100 && dowarn)
1380 warn("Deep recursion on subroutine \"%s\"",stab->stab_name);
1381 savelist(sub->tosave->ary_array,sub->tosave->ary_fill);
1383 filename = sub->filename;
1384 tmps_base = tmps_max;
1386 str = cmd_exec(sub->cmd); /* so do it already */
1388 sub->depth--; /* assuming no longjumps out of here */
1389 afree(defstab->stab_array); /* put back old $_[] */
1390 defstab->stab_array = savearray;
1392 tmps_base = oldtmps_base;
1393 if (savestack->ary_fill > oldsave) {
1394 str = str_static(str); /* in case restore wipes old str */
1395 restorelist(oldsave);
1401 do_assign(retstr,arg,sarg)
1404 register STR **sarg;
1406 STR **tmpary; /* must not be register */
1407 register ARG *larg = arg[1].arg_ptr.arg_arg;
1408 register STR **elem;
1410 register ARRAY *ary;
1415 if (arg[2].arg_flags & AF_SPECIAL) {
1416 (void)eval(arg[2].arg_ptr.arg_arg,&tmpary,-1);
1417 items = (int)str_gnum(*tmpary);
1426 if (arg->arg_flags & AF_COMMON) { /* always true currently, alas */
1428 for (i=2,elem=tmpary+2; i <= items; i++,elem++) {
1429 *elem = str_static(*elem);
1433 if (larg->arg_type == O_LIST) {
1434 for (i=1,elem=tmpary+1; i <= larg->arg_len; i++) {
1435 switch (larg[i].arg_type) {
1438 str = STAB_STR(larg[i].arg_ptr.arg_stab);
1441 str = eval(larg[i].arg_ptr.arg_arg,Null(STR***),-1);
1444 if (larg->arg_flags & AF_LOCAL) {
1445 apush(savestack,str); /* save pointer */
1446 tmpstr = str_new(0);
1447 str_sset(tmpstr,str);
1448 apush(savestack,tmpstr); /* save value */
1451 str_sset(str,*(elem++));
1457 else { /* should be an array name */
1458 ary = larg[1].arg_ptr.arg_stab->stab_array;
1459 for (i=0,elem=tmpary+1; i < items; i++) {
1462 str_sset(str,*(elem++));
1465 ary->ary_fill = items - 1;/* they can get the extra ones back by */
1466 } /* setting $#ary larger than old fill */
1467 str_numset(retstr,(double)items);
1469 if (tmpary != sarg);
1470 safefree((char*)tmpary);
1474 do_kv(hash,kv,retary,sarg,ptrmaxsarg,sargoff,cushion)
1478 register STR **sarg;
1483 register ARRAY *ary;
1486 static ARRAY *myarray = Null(ARRAY*);
1487 register HENT *entry;
1491 myarray = ary = anew(Nullstab);
1495 while (entry = hiternext(hash)) {
1498 apush(ary,str_make(hiterkey(entry)));
1500 apush(ary,str_make(str_get(hiterval(entry))));
1502 if (retary) { /* array wanted */
1503 *ptrmaxsarg = max + sargoff;
1504 sarg = (STR**)saferealloc((char*)(sarg - sargoff),
1505 (max+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
1506 for (i = 1; i <= max; i++)
1507 sarg[i] = afetch(ary,i-1);
1514 do_each(hash,retary,sarg,ptrmaxsarg,sargoff,cushion)
1522 static STR *mystr = Nullstr;
1524 HENT *entry = hiternext(hash);
1531 if (retary) { /* array wanted */
1533 *ptrmaxsarg = 2 + sargoff;
1534 sarg = (STR**)saferealloc((char*)(sarg - sargoff),
1535 (2+2+cushion+sargoff)*sizeof(STR*)) + sargoff;
1536 sarg[1] = mystr = str_make(hiterkey(entry));
1537 retstr = sarg[2] = hiterval(entry);
1541 *ptrmaxsarg = sargoff;
1542 sarg = (STR**)saferealloc((char*)(sarg - sargoff),
1543 (2+cushion+sargoff)*sizeof(STR*)) + sargoff;
1549 retstr = hiterval(entry);
1561 if (arg[1].arg_flags & AF_SPECIAL) {
1562 stio = arg[1].arg_ptr.arg_stab->stab_io;
1563 if (stio && stio->fp)
1564 return fstat(fileno(stio->fp), &statbuf);
1567 warn("Stat on unopened file <%s>",
1568 arg[1].arg_ptr.arg_stab->stab_name);
1573 return stat(str_get(str),&statbuf);
1585 register STDCHAR *s;
1586 register STIO *stio;
1588 if (arg[1].arg_flags & AF_SPECIAL) {
1589 stio = arg[1].arg_ptr.arg_stab->stab_io;
1590 if (stio && stio->fp) {
1592 if (stio->fp->_cnt <= 0) {
1596 if (stio->fp->_cnt <= 0) /* null file is anything */
1598 len = stio->fp->_cnt + (stio->fp->_ptr - stio->fp->_base);
1599 s = stio->fp->_base;
1601 fatal("-T and -B not implemented on filehandles\n");
1606 warn("Test on unopened file <%s>",
1607 arg[1].arg_ptr.arg_stab->stab_name);
1612 i = open(str_get(str),0);
1615 len = read(i,tbuf,512);
1616 if (len <= 0) /* null file is anything */
1622 /* now scan s to look for textiness */
1624 for (i = 0; i < len; i++,s++) {
1625 if (!*s) { /* null never allowed in text */
1632 *s != '\n' && *s != '\r' && *s != '\b' &&
1633 *s != '\t' && *s != '\f' && *s != 27)
1637 if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
1647 register char *s = str_get(str);
1648 register int pos = str->str_cur;
1650 register int *sfirst;
1651 register int *snext;
1652 static int maxscream = -1;
1653 static STR *lastscream = Nullstr;
1655 if (lastscream && lastscream->str_pok == 5)
1656 lastscream->str_pok &= ~4;
1660 if (pos > maxscream) {
1661 if (maxscream < 0) {
1662 maxscream = pos + 80;
1663 screamfirst = (int*)safemalloc((MEM_SIZE)(256 * sizeof(int)));
1664 screamnext = (int*)safemalloc((MEM_SIZE)(maxscream * sizeof(int)));
1667 maxscream = pos + pos / 4;
1668 screamnext = (int*)saferealloc((char*)screamnext,
1669 (MEM_SIZE)(maxscream * sizeof(int)));
1673 sfirst = screamfirst;
1676 if (!sfirst || !snext)
1677 fatal("do_study: out of memory");
1679 for (ch = 256; ch; --ch)
1683 while (--pos >= 0) {
1685 if (sfirst[ch] >= 0)
1686 snext[pos] = sfirst[ch] - pos;
1698 #define A(e1,e2,e3) (e1+(e2<<1)+(e3<<2))
1699 opargs[O_ITEM] = A(1,0,0);
1700 opargs[O_ITEM2] = A(0,0,0);
1701 opargs[O_ITEM3] = A(0,0,0);
1702 opargs[O_CONCAT] = A(1,1,0);
1703 opargs[O_MATCH] = A(1,0,0);
1704 opargs[O_NMATCH] = A(1,0,0);
1705 opargs[O_SUBST] = A(1,0,0);
1706 opargs[O_NSUBST] = A(1,0,0);
1707 opargs[O_ASSIGN] = A(1,1,0);
1708 opargs[O_MULTIPLY] = A(1,1,0);
1709 opargs[O_DIVIDE] = A(1,1,0);
1710 opargs[O_MODULO] = A(1,1,0);
1711 opargs[O_ADD] = A(1,1,0);
1712 opargs[O_SUBTRACT] = A(1,1,0);
1713 opargs[O_LEFT_SHIFT] = A(1,1,0);
1714 opargs[O_RIGHT_SHIFT] = A(1,1,0);
1715 opargs[O_LT] = A(1,1,0);
1716 opargs[O_GT] = A(1,1,0);
1717 opargs[O_LE] = A(1,1,0);
1718 opargs[O_GE] = A(1,1,0);
1719 opargs[O_EQ] = A(1,1,0);
1720 opargs[O_NE] = A(1,1,0);
1721 opargs[O_BIT_AND] = A(1,1,0);
1722 opargs[O_XOR] = A(1,1,0);
1723 opargs[O_BIT_OR] = A(1,1,0);
1724 opargs[O_AND] = A(1,0,0); /* don't eval arg 2 (yet) */
1725 opargs[O_OR] = A(1,0,0); /* don't eval arg 2 (yet) */
1726 opargs[O_COND_EXPR] = A(1,0,0); /* don't eval args 2 or 3 */
1727 opargs[O_COMMA] = A(1,1,0);
1728 opargs[O_NEGATE] = A(1,0,0);
1729 opargs[O_NOT] = A(1,0,0);
1730 opargs[O_COMPLEMENT] = A(1,0,0);
1731 opargs[O_WRITE] = A(1,0,0);
1732 opargs[O_OPEN] = A(1,1,0);
1733 opargs[O_TRANS] = A(1,0,0);
1734 opargs[O_NTRANS] = A(1,0,0);
1735 opargs[O_CLOSE] = A(0,0,0);
1736 opargs[O_ARRAY] = A(1,0,0);
1737 opargs[O_HASH] = A(1,0,0);
1738 opargs[O_LARRAY] = A(1,0,0);
1739 opargs[O_LHASH] = A(1,0,0);
1740 opargs[O_PUSH] = A(1,0,0);
1741 opargs[O_POP] = A(0,0,0);
1742 opargs[O_SHIFT] = A(0,0,0);
1743 opargs[O_SPLIT] = A(1,0,0);
1744 opargs[O_LENGTH] = A(1,0,0);
1745 opargs[O_SPRINTF] = A(1,0,0);
1746 opargs[O_SUBSTR] = A(1,1,1);
1747 opargs[O_JOIN] = A(1,0,0);
1748 opargs[O_SLT] = A(1,1,0);
1749 opargs[O_SGT] = A(1,1,0);
1750 opargs[O_SLE] = A(1,1,0);
1751 opargs[O_SGE] = A(1,1,0);
1752 opargs[O_SEQ] = A(1,1,0);
1753 opargs[O_SNE] = A(1,1,0);
1754 opargs[O_SUBR] = A(1,0,0);
1755 opargs[O_PRINT] = A(1,1,0);
1756 opargs[O_CHDIR] = A(1,0,0);
1757 opargs[O_DIE] = A(1,0,0);
1758 opargs[O_EXIT] = A(1,0,0);
1759 opargs[O_RESET] = A(1,0,0);
1760 opargs[O_LIST] = A(0,0,0);
1761 opargs[O_EOF] = A(1,0,0);
1762 opargs[O_TELL] = A(1,0,0);
1763 opargs[O_SEEK] = A(1,1,1);
1764 opargs[O_LAST] = A(1,0,0);
1765 opargs[O_NEXT] = A(1,0,0);
1766 opargs[O_REDO] = A(1,0,0);
1767 opargs[O_GOTO] = A(1,0,0);
1768 opargs[O_INDEX] = A(1,1,0);
1769 opargs[O_TIME] = A(0,0,0);
1770 opargs[O_TMS] = A(0,0,0);
1771 opargs[O_LOCALTIME] = A(1,0,0);
1772 opargs[O_GMTIME] = A(1,0,0);
1773 opargs[O_STAT] = A(1,0,0);
1774 opargs[O_CRYPT] = A(1,1,0);
1775 opargs[O_EXP] = A(1,0,0);
1776 opargs[O_LOG] = A(1,0,0);
1777 opargs[O_SQRT] = A(1,0,0);
1778 opargs[O_INT] = A(1,0,0);
1779 opargs[O_PRTF] = A(1,1,0);
1780 opargs[O_ORD] = A(1,0,0);
1781 opargs[O_SLEEP] = A(1,0,0);
1782 opargs[O_FLIP] = A(1,0,0);
1783 opargs[O_FLOP] = A(0,1,0);
1784 opargs[O_KEYS] = A(0,0,0);
1785 opargs[O_VALUES] = A(0,0,0);
1786 opargs[O_EACH] = A(0,0,0);
1787 opargs[O_CHOP] = A(1,0,0);
1788 opargs[O_FORK] = A(1,0,0);
1789 opargs[O_EXEC] = A(1,0,0);
1790 opargs[O_SYSTEM] = A(1,0,0);
1791 opargs[O_OCT] = A(1,0,0);
1792 opargs[O_HEX] = A(1,0,0);
1793 opargs[O_CHMOD] = A(1,0,0);
1794 opargs[O_CHOWN] = A(1,0,0);
1795 opargs[O_KILL] = A(1,0,0);
1796 opargs[O_RENAME] = A(1,1,0);
1797 opargs[O_UNLINK] = A(1,0,0);
1798 opargs[O_UMASK] = A(1,0,0);
1799 opargs[O_UNSHIFT] = A(1,0,0);
1800 opargs[O_LINK] = A(1,1,0);
1801 opargs[O_REPEAT] = A(1,1,0);
1802 opargs[O_EVAL] = A(1,0,0);
1803 opargs[O_FTEREAD] = A(1,0,0);
1804 opargs[O_FTEWRITE] = A(1,0,0);
1805 opargs[O_FTEEXEC] = A(1,0,0);
1806 opargs[O_FTEOWNED] = A(1,0,0);
1807 opargs[O_FTRREAD] = A(1,0,0);
1808 opargs[O_FTRWRITE] = A(1,0,0);
1809 opargs[O_FTREXEC] = A(1,0,0);
1810 opargs[O_FTROWNED] = A(1,0,0);
1811 opargs[O_FTIS] = A(1,0,0);
1812 opargs[O_FTZERO] = A(1,0,0);
1813 opargs[O_FTSIZE] = A(1,0,0);
1814 opargs[O_FTFILE] = A(1,0,0);
1815 opargs[O_FTDIR] = A(1,0,0);
1816 opargs[O_FTLINK] = A(1,0,0);
1817 opargs[O_SYMLINK] = A(1,1,0);
1818 opargs[O_FTPIPE] = A(1,0,0);
1819 opargs[O_FTSUID] = A(1,0,0);
1820 opargs[O_FTSGID] = A(1,0,0);
1821 opargs[O_FTSVTX] = A(1,0,0);
1822 opargs[O_FTCHR] = A(1,0,0);
1823 opargs[O_FTBLK] = A(1,0,0);
1824 opargs[O_FTSOCK] = A(1,0,0);
1825 opargs[O_FTTTY] = A(1,0,0);
1826 opargs[O_DOFILE] = A(1,0,0);
1827 opargs[O_FTTEXT] = A(1,0,0);
1828 opargs[O_FTBINARY] = A(1,0,0);
1829 opargs[O_UTIME] = A(1,0,0);
1830 opargs[O_WAIT] = A(0,0,0);
1831 opargs[O_SORT] = A(1,0,0);
1832 opargs[O_STUDY] = A(1,0,0);
1833 opargs[O_DELETE] = A(1,0,0);