1 /* $Header: dolist.c,v 3.0.1.4 89/12/21 19:58:46 lwall Locked $
3 * Copyright (c) 1989, Larry Wall
5 * You may distribute under the terms of the GNU General Public License
6 * as specified in the README file that comes with the perl 3.0 kit.
9 * Revision 3.0.1.4 89/12/21 19:58:46 lwall
10 * patch7: grep(1,@array) didn't work
11 * patch7: /$pat/; //; wrongly freed runtime pattern twice
13 * Revision 3.0.1.3 89/11/17 15:14:45 lwall
14 * patch5: grep() occasionally loses arguments or dumps core
16 * Revision 3.0.1.2 89/11/11 04:28:17 lwall
17 * patch2: non-existent slice values are now undefined rather than null
19 * Revision 3.0.1.1 89/10/26 23:11:51 lwall
20 * patch1: split in a subroutine wrongly freed referenced arguments
21 * patch1: reverse didn't work
23 * Revision 3.0 89/10/18 15:11:02 lwall
33 do_match(str,arg,gimme,arglast)
39 register STR **st = stack->ary_array;
40 register SPAT *spat = arg[2].arg_ptr.arg_spat;
42 register int sp = arglast[0] + 1;
43 STR *srchstr = st[sp];
44 register char *s = str_get(st[sp]);
45 char *strend = s + st[sp]->str_cur;
57 fatal("panic: do_match");
58 if (spat->spat_flags & SPAT_USED) {
71 if (spat->spat_runtime) {
73 sp = eval(spat->spat_runtime,G_SCALAR,sp);
74 st = stack->ary_array;
75 t = str_get(tmpstr = st[sp--]);
79 deb("2.SPAT /%s/\n",t);
81 if (spat->spat_regexp)
82 regfree(spat->spat_regexp);
83 spat->spat_regexp = regcomp(t,t+tmpstr->str_cur,
84 spat->spat_flags & SPAT_FOLD,1);
85 if (!*spat->spat_regexp->precomp && lastspat)
87 if (spat->spat_flags & SPAT_KEEP) {
88 if (spat->spat_runtime)
89 arg_free(spat->spat_runtime); /* it won't change, so */
90 spat->spat_runtime = Nullarg; /* no point compiling again */
92 if (!spat->spat_regexp->nparens)
93 gimme = G_SCALAR; /* accidental array context? */
94 if (regexec(spat->spat_regexp, s, strend, s, 0,
95 srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
97 if (spat->spat_regexp->subbase)
103 if (gimme == G_ARRAY)
105 str_sset(str,&str_no);
116 if (spat->spat_flags & SPAT_ONCE)
120 deb("2.SPAT %c%s%c\n",ch,spat->spat_regexp->precomp,ch);
123 if (!*spat->spat_regexp->precomp && lastspat)
127 if (hint < s || hint > strend)
128 fatal("panic: hint in do_match");
131 if (spat->spat_regexp->regback >= 0) {
132 s -= spat->spat_regexp->regback;
139 else if (spat->spat_short) {
140 if (spat->spat_flags & SPAT_SCANFIRST) {
141 if (srchstr->str_pok & SP_STUDIED) {
142 if (screamfirst[spat->spat_short->str_rare] < 0)
144 else if (!(s = screaminstr(srchstr,spat->spat_short)))
146 else if (spat->spat_flags & SPAT_ALL)
150 else if (!(s = fbminstr((unsigned char*)s,
151 (unsigned char*)strend, spat->spat_short)))
154 else if (spat->spat_flags & SPAT_ALL)
156 if (s && spat->spat_regexp->regback >= 0) {
157 ++spat->spat_short->str_u.str_useful;
158 s -= spat->spat_regexp->regback;
165 else if (!multiline && (*spat->spat_short->str_ptr != *s ||
166 bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) ))
168 if (--spat->spat_short->str_u.str_useful < 0) {
169 str_free(spat->spat_short);
170 spat->spat_short = Nullstr; /* opt is being useless */
173 if (!spat->spat_regexp->nparens)
174 gimme = G_SCALAR; /* accidental array context? */
175 if (regexec(spat->spat_regexp, s, strend, t, 0,
176 srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
178 if (spat->spat_regexp->subbase)
181 if (spat->spat_flags & SPAT_ONCE)
182 spat->spat_flags |= SPAT_USED;
186 if (gimme == G_ARRAY)
188 str_sset(str,&str_no);
197 if (gimme == G_ARRAY) {
200 iters = spat->spat_regexp->nparens;
201 if (sp + iters >= stack->ary_max) {
202 astore(stack,sp + iters, Nullstr);
203 st = stack->ary_array; /* possibly realloced */
206 for (i = 1; i <= iters; i++) {
207 st[++sp] = str_static(&str_no);
208 if (s = spat->spat_regexp->startp[i]) {
209 len = spat->spat_regexp->endp[i] - s;
211 str_nset(st[sp],s,len);
217 str_sset(str,&str_yes);
224 ++spat->spat_short->str_u.str_useful;
226 if (spat->spat_flags & SPAT_ONCE)
227 spat->spat_flags |= SPAT_USED;
231 tmps = spat->spat_regexp->subbase = nsavestr(t,strend-t);
232 tmps = spat->spat_regexp->startp[0] = tmps + (s - t);
233 spat->spat_regexp->endp[0] = tmps + spat->spat_short->str_cur;
236 str_sset(str,&str_yes);
242 ++spat->spat_short->str_u.str_useful;
243 if (gimme == G_ARRAY)
245 str_sset(str,&str_no);
252 do_split(str,spat,limit,gimme,arglast)
259 register ARRAY *ary = stack;
260 STR **st = ary->ary_array;
261 register int sp = arglast[0] + 1;
262 register char *s = str_get(st[sp]);
263 char *strend = s + st[sp--]->str_cur;
269 int origlimit = limit;
273 fatal("panic: do_split");
274 else if (spat->spat_runtime) {
276 sp = eval(spat->spat_runtime,G_SCALAR,sp);
277 st = stack->ary_array;
278 m = str_get(dstr = st[sp--]);
280 if (!dstr->str_cur || (*m == ' ' && dstr->str_cur == 1)) {
281 str_set(dstr,"\\s+");
283 spat->spat_flags |= SPAT_SKIPWHITE;
285 if (spat->spat_regexp)
286 regfree(spat->spat_regexp);
287 spat->spat_regexp = regcomp(m,m+dstr->str_cur,
288 spat->spat_flags & SPAT_FOLD,1);
289 if (spat->spat_flags & SPAT_KEEP ||
290 (spat->spat_runtime->arg_type == O_ITEM &&
291 (spat->spat_runtime[1].arg_type & A_MASK) == A_SINGLE) ) {
292 arg_free(spat->spat_runtime); /* it won't change, so */
293 spat->spat_runtime = Nullarg; /* no point compiling again */
298 deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
301 ary = stab_xarray(spat->spat_repl[1].arg_ptr.arg_stab);
302 if (ary && ((ary->ary_flags & ARF_REAL) || gimme != G_ARRAY)) {
304 if (!(ary->ary_flags & ARF_REAL)) {
305 ary->ary_flags |= ARF_REAL;
306 for (i = ary->ary_fill; i >= 0; i--)
307 ary->ary_array[i] = Nullstr; /* don't free mere refs */
310 sp = -1; /* temporarily switch stacks */
315 if (spat->spat_flags & SPAT_SKIPWHITE) {
321 if (spat->spat_short) {
322 i = spat->spat_short->str_cur;
324 i = *spat->spat_short->str_ptr;
326 for (m = s; m < strend && *m != i; m++) ;
330 dstr = Str_new(30,m-s);
332 dstr = str_static(&str_undef);
333 str_nset(dstr,s,m-s);
334 (void)astore(ary, ++sp, dstr);
340 while (s < strend && --limit &&
341 (m=fbminstr((unsigned char*)s, (unsigned char*)strend,
346 dstr = Str_new(31,m-s);
348 dstr = str_static(&str_undef);
349 str_nset(dstr,s,m-s);
350 (void)astore(ary, ++sp, dstr);
356 while (s < strend && --limit &&
357 regexec(spat->spat_regexp, s, strend, orig, 1, Nullstr, TRUE) ) {
358 if (spat->spat_regexp->subbase
359 && spat->spat_regexp->subbase != orig) {
362 orig = spat->spat_regexp->subbase;
364 strend = s + (strend - m);
366 m = spat->spat_regexp->startp[0];
368 dstr = Str_new(32,m-s);
370 dstr = str_static(&str_undef);
371 str_nset(dstr,s,m-s);
372 (void)astore(ary, ++sp, dstr);
373 if (spat->spat_regexp->nparens) {
374 for (i = 1; i <= spat->spat_regexp->nparens; i++) {
375 s = spat->spat_regexp->startp[i];
376 m = spat->spat_regexp->endp[i];
378 dstr = Str_new(33,m-s);
380 dstr = str_static(&str_undef);
381 str_nset(dstr,s,m-s);
382 (void)astore(ary, ++sp, dstr);
385 s = spat->spat_regexp->endp[0];
391 iters = sp - arglast[0];
394 if (s < strend || origlimit) { /* keep field after final delim? */
396 dstr = Str_new(34,strend-s);
398 dstr = str_static(&str_undef);
399 str_nset(dstr,s,strend-s);
400 (void)astore(ary, ++sp, dstr);
405 while (iters > 0 && ary->ary_array[sp]->str_cur == 0)
412 zaps = str_get(afetch(ary,sp,FALSE));
416 while (iters > 0 && (!zapb)) {
419 zaps = str_get(afetch(ary,iters-1,FALSE));
427 if (gimme == G_ARRAY) {
429 astore(stack, arglast[0] + 1 + sp, Nullstr);
430 Copy(ary->ary_array, stack->ary_array + arglast[0] + 1, sp, STR*);
431 return arglast[0] + sp;
435 if (gimme == G_ARRAY)
439 str_numset(str,(double)iters);
446 do_unpack(str,gimme,arglast)
451 STR **st = stack->ary_array;
452 register int sp = arglast[0] + 1;
453 register char *pat = str_get(st[sp++]);
454 register char *s = str_get(st[sp]);
455 char *strend = s + st[sp--]->str_cur;
456 register char *patend = pat + st[sp]->str_cur;
460 /* These must not be in registers: */
465 unsigned char auchar;
466 unsigned short aushort;
468 unsigned long aulong;
471 if (gimme != G_ARRAY) {
472 str_sset(str,&str_undef);
478 while (pat < patend) {
482 while (isdigit(*pat))
495 if (s + len > strend)
497 str = Str_new(35,len);
500 if (datumtype == 'A') {
501 aptr = s; /* borrow register */
502 s = str->str_ptr + len - 1;
503 while (s >= str->str_ptr && (!*s || isspace(*s)))
506 str->str_cur = s - str->str_ptr;
507 s = aptr; /* unborrow register */
509 (void)astore(stack, ++sp, str_2static(str));
513 if (s + sizeof(char) > strend)
516 bcopy(s,(char*)&achar,sizeof(char));
521 if (aint >= 128) /* fake up signed chars */
523 str_numset(str,(double)aint);
524 (void)astore(stack, ++sp, str_2static(str));
529 if (s + sizeof(unsigned char) > strend)
532 bcopy(s,(char*)&auchar,sizeof(unsigned char));
533 s += sizeof(unsigned char);
536 auint = auchar; /* some can't cast uchar to double */
537 str_numset(str,(double)auint);
538 (void)astore(stack, ++sp, str_2static(str));
543 if (s + sizeof(short) > strend)
546 bcopy(s,(char*)&ashort,sizeof(short));
550 str_numset(str,(double)ashort);
551 (void)astore(stack, ++sp, str_2static(str));
557 if (s + sizeof(unsigned short) > strend)
560 bcopy(s,(char*)&aushort,sizeof(unsigned short));
561 s += sizeof(unsigned short);
565 if (datumtype == 'n')
566 aushort = ntohs(aushort);
568 str_numset(str,(double)aushort);
569 (void)astore(stack, ++sp, str_2static(str));
574 if (s + sizeof(int) > strend)
577 bcopy(s,(char*)&aint,sizeof(int));
581 str_numset(str,(double)aint);
582 (void)astore(stack, ++sp, str_2static(str));
587 if (s + sizeof(unsigned int) > strend)
590 bcopy(s,(char*)&auint,sizeof(unsigned int));
591 s += sizeof(unsigned int);
594 str_numset(str,(double)auint);
595 (void)astore(stack, ++sp, str_2static(str));
600 if (s + sizeof(long) > strend)
603 bcopy(s,(char*)&along,sizeof(long));
607 str_numset(str,(double)along);
608 (void)astore(stack, ++sp, str_2static(str));
614 if (s + sizeof(unsigned long) > strend)
617 bcopy(s,(char*)&aulong,sizeof(unsigned long));
618 s += sizeof(unsigned long);
622 if (datumtype == 'N')
623 aulong = ntohl(aulong);
625 str_numset(str,(double)aulong);
626 (void)astore(stack, ++sp, str_2static(str));
631 if (s + sizeof(char*) > strend)
634 bcopy(s,(char*)&aptr,sizeof(char*));
640 (void)astore(stack, ++sp, str_2static(str));
649 do_slice(stab,numarray,lval,gimme,arglast)
656 register STR **st = stack->ary_array;
657 register int sp = arglast[1];
658 register int max = arglast[2];
661 register int magic = 0;
663 if (lval && !numarray) {
666 else if (stab == sigstab)
669 else if (stab_hash(stab)->tbl_dbm)
671 #endif /* SOME_DBM */
674 if (gimme == G_ARRAY) {
678 st[sp-1] = afetch(stab_array(stab),(int)str_gnum(st[sp]),
682 st[sp-1] = &str_undef;
688 tmps = str_get(st[sp]);
689 len = st[sp]->str_cur;
690 st[sp-1] = hfetch(stab_hash(stab),tmps,len, lval);
692 str_magic(st[sp-1],stab,magic,tmps,len);
695 st[sp-1] = &str_undef;
703 st[sp] = afetch(stab_array(stab),(int)str_gnum(st[max]), lval);
709 tmps = str_get(st[max]);
710 len = st[max]->str_cur;
711 st[sp] = hfetch(stab_hash(stab),tmps,len, lval);
713 str_magic(st[sp],stab,magic,tmps,len);
723 do_grep(arg,str,gimme,arglast)
729 STR **st = stack->ary_array;
730 register int dst = arglast[1];
731 register int src = dst + 1;
732 register int sp = arglast[2];
733 register int i = sp - arglast[1];
734 int oldsave = savestack->ary_fill;
736 savesptr(&stab_val(defstab));
737 if ((arg[1].arg_type & A_MASK) != A_EXPR) {
738 arg[1].arg_type &= A_MASK;
740 arg[1].arg_type |= A_DONT;
742 arg = arg[1].arg_ptr.arg_arg;
744 stab_val(defstab) = st[src];
745 (void)eval(arg,G_SCALAR,sp);
746 st = stack->ary_array;
747 if (str_true(st[sp+1]))
751 restorelist(oldsave);
752 if (gimme != G_ARRAY) {
753 str_sset(str,&str_undef);
755 st[arglast[0]+1] = str;
758 return arglast[0] + (dst - arglast[1]);
762 do_reverse(str,gimme,arglast)
767 STR **st = stack->ary_array;
768 register STR **up = &st[arglast[1]];
769 register STR **down = &st[arglast[2]];
770 register int i = arglast[2] - arglast[1];
772 if (gimme != G_ARRAY) {
773 str_sset(str,&str_undef);
775 st[arglast[0]+1] = str;
783 i = arglast[2] - arglast[1];
784 Copy(down+1,up,i/2,STR*);
785 return arglast[2] - 1;
789 static STAB *firststab = Nullstab;
790 static STAB *secondstab = Nullstab;
793 do_sort(str,stab,gimme,arglast)
799 STR **st = stack->ary_array;
802 register int max = arglast[2] - sp;
809 static ARRAY *sortstack = Null(ARRAY*);
811 if (gimme != G_ARRAY) {
812 str_sset(str,&str_undef);
818 for (i = 0; i < max; i++) {
819 if ((*up = up[1]) && !(*up)->str_pok)
825 if (stab_sub(stab) && (sortcmd = stab_sub(stab)->cmd)) {
826 int oldtmps_base = tmps_base;
829 sortstack = anew(Nullstab);
830 sortstack->ary_flags = 0;
834 tmps_base = tmps_max;
836 firststab = stabent("a",TRUE);
837 secondstab = stabent("b",TRUE);
839 oldfirst = stab_val(firststab);
840 oldsecond = stab_val(secondstab);
842 qsort((char*)(st+sp+1),max,sizeof(STR*),sortsub);
844 qsort(Nullch,max,sizeof(STR*),sortsub);
846 stab_val(firststab) = oldfirst;
847 stab_val(secondstab) = oldsecond;
848 tmps_base = oldtmps_base;
853 qsort((char*)(st+sp+1),max,sizeof(STR*),sortcmp);
856 up = &st[arglast[1]];
857 while (max > 0 && !*up)
871 stab_val(firststab) = *str1;
872 stab_val(secondstab) = *str2;
873 cmd_exec(sortcmd,G_SCALAR,-1);
874 return (int)str_gnum(*stack->ary_array);
881 register STR *str1 = *strp1;
882 register STR *str2 = *strp2;
890 if (str1->str_cur < str2->str_cur) {
891 if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
896 else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
898 else if (str1->str_cur == str2->str_cur)
905 do_range(gimme,arglast)
909 STR **st = stack->ary_array;
910 register int sp = arglast[0];
911 register int i = (int)str_gnum(st[sp+1]);
912 register ARRAY *ary = stack;
914 int max = (int)str_gnum(st[sp+2]);
916 if (gimme != G_ARRAY)
917 fatal("panic: do_range");
920 (void)astore(ary, ++sp, str = str_static(&str_no));
921 str_numset(str,(double)i++);
927 do_tms(str,gimme,arglast)
932 STR **st = stack->ary_array;
933 register int sp = arglast[0];
935 if (gimme != G_ARRAY) {
936 str_sset(str,&str_undef);
941 (void)times(×buf);
948 (void)astore(stack,++sp,
949 str_2static(str_nmake(((double)timesbuf.tms_utime)/HZ)));
950 (void)astore(stack,++sp,
951 str_2static(str_nmake(((double)timesbuf.tms_stime)/HZ)));
952 (void)astore(stack,++sp,
953 str_2static(str_nmake(((double)timesbuf.tms_cutime)/HZ)));
954 (void)astore(stack,++sp,
955 str_2static(str_nmake(((double)timesbuf.tms_cstime)/HZ)));
957 (void)astore(stack,++sp,
958 str_2static(str_nmake(0.0)));
964 do_time(str,tmbuf,gimme,arglast)
970 register ARRAY *ary = stack;
971 STR **st = ary->ary_array;
972 register int sp = arglast[0];
974 if (!tmbuf || gimme != G_ARRAY) {
975 str_sset(str,&str_undef);
980 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_sec)));
981 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_min)));
982 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_hour)));
983 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_mday)));
984 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_mon)));
985 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_year)));
986 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_wday)));
987 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_yday)));
988 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_isdst)));
993 do_kv(str,hash,kv,gimme,arglast)
1000 register ARRAY *ary = stack;
1001 STR **st = ary->ary_array;
1002 register int sp = arglast[0];
1004 register HENT *entry;
1007 int dokeys = (kv == O_KEYS || kv == O_HASH);
1008 int dovalues = (kv == O_VALUES || kv == O_HASH);
1010 if (gimme != G_ARRAY) {
1011 str_sset(str,&str_undef);
1016 (void)hiterinit(hash);
1017 while (entry = hiternext(hash)) {
1019 tmps = hiterkey(entry,&i);
1020 (void)astore(ary,++sp,str_2static(str_make(tmps,i)));
1023 tmpstr = Str_new(45,0);
1026 sprintf(buf,"%d%%%d=%d\n",entry->hent_hash,
1027 hash->tbl_max+1,entry->hent_hash & hash->tbl_max);
1028 str_set(tmpstr,buf);
1032 str_sset(tmpstr,hiterval(hash,entry));
1033 (void)astore(ary,++sp,str_2static(tmpstr));
1040 do_each(str,hash,gimme,arglast)
1046 STR **st = stack->ary_array;
1047 register int sp = arglast[0];
1048 static STR *mystrk = Nullstr;
1049 HENT *entry = hiternext(hash);
1059 if (gimme == G_ARRAY) {
1060 tmps = hiterkey(entry, &i);
1061 st[++sp] = mystrk = str_make(tmps,i);
1064 str_sset(str,hiterval(hash,entry));