1 /* $Header: dolist.c,v 3.0.1.8 90/08/09 03:15:56 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.8 90/08/09 03:15:56 lwall
10 * patch19: certain kinds of matching cause "panic: hint"
11 * patch19: $' broke on embedded nulls
12 * patch19: split on /\s+/, /^/ and ' ' is now special cased for speed
13 * patch19: split on /x/i didn't work
14 * patch19: couldn't unpack an 'A' or 'a' field in a scalar context
15 * patch19: unpack called bcopy on each character of a C/c field
16 * patch19: pack/unpack know about uudecode lines
17 * patch19: fixed sort on undefined strings and sped up slightly
18 * patch19: each and keys returned garbage on null key in DBM file
20 * Revision 3.0.1.7 90/03/27 15:48:42 lwall
21 * patch16: MSDOS support
22 * patch16: use of $`, $& or $' sometimes causes memory leakage
23 * patch16: splice(@array,0,$n) case cause duplicate free
24 * patch16: grep blows up on undefined array values
25 * patch16: .. now works using magical string increment
27 * Revision 3.0.1.6 90/03/12 16:33:02 lwall
28 * patch13: added list slice operator (LIST)[LIST]
29 * patch13: added splice operator: @oldelems = splice(@array,$offset,$len,LIST)
30 * patch13: made split('') act like split(//) rather than split(' ')
32 * Revision 3.0.1.5 90/02/28 17:09:44 lwall
33 * patch9: split now can split into more than 10000 elements
34 * patch9: @_ clobbered by ($foo,$bar) = split
35 * patch9: sped up pack and unpack
36 * patch9: unpack of single item now works in a scalar context
37 * patch9: slices ignored value of $[
38 * patch9: grep now returns number of items matched in scalar context
39 * patch9: grep iterations no longer in the regexp context of previous iteration
41 * Revision 3.0.1.4 89/12/21 19:58:46 lwall
42 * patch7: grep(1,@array) didn't work
43 * patch7: /$pat/; //; wrongly freed runtime pattern twice
45 * Revision 3.0.1.3 89/11/17 15:14:45 lwall
46 * patch5: grep() occasionally loses arguments or dumps core
48 * Revision 3.0.1.2 89/11/11 04:28:17 lwall
49 * patch2: non-existent slice values are now undefined rather than null
51 * Revision 3.0.1.1 89/10/26 23:11:51 lwall
52 * patch1: split in a subroutine wrongly freed referenced arguments
53 * patch1: reverse didn't work
55 * Revision 3.0 89/10/18 15:11:02 lwall
65 #pragma function(memcmp)
66 #endif /* BUGGY_MSC */
69 do_match(str,arg,gimme,arglast)
75 register STR **st = stack->ary_array;
76 register SPAT *spat = arg[2].arg_ptr.arg_spat;
78 register int sp = arglast[0] + 1;
79 STR *srchstr = st[sp];
80 register char *s = str_get(st[sp]);
81 char *strend = s + st[sp]->str_cur;
95 fatal("panic: do_match");
96 if (spat->spat_flags & SPAT_USED) {
101 if (gimme == G_ARRAY)
109 if (spat->spat_runtime) {
111 sp = eval(spat->spat_runtime,G_SCALAR,sp);
112 st = stack->ary_array;
113 t = str_get(tmpstr = st[sp--]);
117 deb("2.SPAT /%s/\n",t);
119 if (spat->spat_regexp)
120 regfree(spat->spat_regexp);
121 spat->spat_regexp = regcomp(t,t+tmpstr->str_cur,
122 spat->spat_flags & SPAT_FOLD);
123 if (!*spat->spat_regexp->precomp && lastspat)
125 if (spat->spat_flags & SPAT_KEEP) {
126 if (spat->spat_runtime)
127 arg_free(spat->spat_runtime); /* it won't change, so */
128 spat->spat_runtime = Nullarg; /* no point compiling again */
130 if (!spat->spat_regexp->nparens)
131 gimme = G_SCALAR; /* accidental array context? */
132 if (regexec(spat->spat_regexp, s, strend, s, 0,
133 srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
135 if (spat->spat_regexp->subbase)
141 if (gimme == G_ARRAY)
143 str_sset(str,&str_no);
154 if (spat->spat_flags & SPAT_ONCE)
158 deb("2.SPAT %c%s%c\n",ch,spat->spat_regexp->precomp,ch);
161 if (!*spat->spat_regexp->precomp && lastspat)
165 if (myhint < s || myhint > strend)
166 fatal("panic: hint in do_match");
168 if (spat->spat_regexp->regback >= 0) {
169 s -= spat->spat_regexp->regback;
176 else if (spat->spat_short) {
177 if (spat->spat_flags & SPAT_SCANFIRST) {
178 if (srchstr->str_pok & SP_STUDIED) {
179 if (screamfirst[spat->spat_short->str_rare] < 0)
181 else if (!(s = screaminstr(srchstr,spat->spat_short)))
183 else if (spat->spat_flags & SPAT_ALL)
187 else if (!(s = fbminstr((unsigned char*)s,
188 (unsigned char*)strend, spat->spat_short)))
191 else if (spat->spat_flags & SPAT_ALL)
193 if (s && spat->spat_regexp->regback >= 0) {
194 ++spat->spat_short->str_u.str_useful;
195 s -= spat->spat_regexp->regback;
202 else if (!multiline && (*spat->spat_short->str_ptr != *s ||
203 bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) ))
205 if (--spat->spat_short->str_u.str_useful < 0) {
206 str_free(spat->spat_short);
207 spat->spat_short = Nullstr; /* opt is being useless */
210 if (!spat->spat_regexp->nparens)
211 gimme = G_SCALAR; /* accidental array context? */
212 if (regexec(spat->spat_regexp, s, strend, t, 0,
213 srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
215 if (spat->spat_regexp->subbase)
218 if (spat->spat_flags & SPAT_ONCE)
219 spat->spat_flags |= SPAT_USED;
223 if (gimme == G_ARRAY)
225 str_sset(str,&str_no);
234 if (gimme == G_ARRAY) {
237 iters = spat->spat_regexp->nparens;
238 if (sp + iters >= stack->ary_max) {
239 astore(stack,sp + iters, Nullstr);
240 st = stack->ary_array; /* possibly realloced */
243 for (i = 1; i <= iters; i++) {
244 st[++sp] = str_static(&str_no);
245 if (s = spat->spat_regexp->startp[i]) {
246 len = spat->spat_regexp->endp[i] - s;
248 str_nset(st[sp],s,len);
254 str_sset(str,&str_yes);
261 ++spat->spat_short->str_u.str_useful;
263 if (spat->spat_flags & SPAT_ONCE)
264 spat->spat_flags |= SPAT_USED;
268 if (spat->spat_regexp->subbase)
269 Safefree(spat->spat_regexp->subbase);
270 tmps = spat->spat_regexp->subbase = nsavestr(t,strend-t);
271 spat->spat_regexp->subend = tmps + (strend-t);
272 tmps = spat->spat_regexp->startp[0] = tmps + (s - t);
273 spat->spat_regexp->endp[0] = tmps + spat->spat_short->str_cur;
276 str_sset(str,&str_yes);
282 ++spat->spat_short->str_u.str_useful;
283 if (gimme == G_ARRAY)
285 str_sset(str,&str_no);
292 #pragma intrinsic(memcmp)
293 #endif /* BUGGY_MSC */
296 do_split(str,spat,limit,gimme,arglast)
303 register ARRAY *ary = stack;
304 STR **st = ary->ary_array;
305 register int sp = arglast[0] + 1;
306 register char *s = str_get(st[sp]);
307 char *strend = s + st[sp--]->str_cur;
311 int maxiters = (strend - s) + 10;
314 int origlimit = limit;
318 fatal("panic: do_split");
319 else if (spat->spat_runtime) {
321 sp = eval(spat->spat_runtime,G_SCALAR,sp);
322 st = stack->ary_array;
323 m = str_get(dstr = st[sp--]);
325 if (*m == ' ' && dstr->str_cur == 1) {
326 str_set(dstr,"\\s+");
328 spat->spat_flags |= SPAT_SKIPWHITE;
330 if (spat->spat_regexp)
331 regfree(spat->spat_regexp);
332 spat->spat_regexp = regcomp(m,m+dstr->str_cur,
333 spat->spat_flags & SPAT_FOLD);
334 if (spat->spat_flags & SPAT_KEEP ||
335 (spat->spat_runtime->arg_type == O_ITEM &&
336 (spat->spat_runtime[1].arg_type & A_MASK) == A_SINGLE) ) {
337 arg_free(spat->spat_runtime); /* it won't change, so */
338 spat->spat_runtime = Nullarg; /* no point compiling again */
343 deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
346 ary = stab_xarray(spat->spat_repl[1].arg_ptr.arg_stab);
347 if (ary && (gimme != G_ARRAY || (spat->spat_flags & SPAT_ONCE))) {
349 if (!(ary->ary_flags & ARF_REAL)) {
350 ary->ary_flags |= ARF_REAL;
351 for (i = ary->ary_fill; i >= 0; i--)
352 ary->ary_array[i] = Nullstr; /* don't free mere refs */
355 sp = -1; /* temporarily switch stacks */
360 if (spat->spat_flags & SPAT_SKIPWHITE) {
365 limit = maxiters + 2;
366 if (strEQ("\\s+",spat->spat_regexp->precomp)) {
368 for (m = s; m < strend && !isspace(*m); m++) ;
372 dstr = Str_new(30,m-s);
374 dstr = str_static(&str_undef);
375 str_nset(dstr,s,m-s);
376 (void)astore(ary, ++sp, dstr);
377 for (s = m + 1; s < strend && isspace(*s); s++) ;
380 else if (strEQ("^",spat->spat_regexp->precomp)) {
382 for (m = s; m < strend && *m != '\n'; m++) ;
387 dstr = Str_new(30,m-s);
389 dstr = str_static(&str_undef);
390 str_nset(dstr,s,m-s);
391 (void)astore(ary, ++sp, dstr);
395 else if (spat->spat_short) {
396 i = spat->spat_short->str_cur;
398 int fold = (spat->spat_flags & SPAT_FOLD);
400 i = *spat->spat_short->str_ptr;
401 if (fold && isupper(i))
406 m < strend && *m != i &&
407 (!isupper(*m) || tolower(*m) != i);
412 for (m = s; m < strend && *m != i; m++) ;
416 dstr = Str_new(30,m-s);
418 dstr = str_static(&str_undef);
419 str_nset(dstr,s,m-s);
420 (void)astore(ary, ++sp, dstr);
426 while (s < strend && --limit &&
427 (m=fbminstr((unsigned char*)s, (unsigned char*)strend,
432 dstr = Str_new(31,m-s);
434 dstr = str_static(&str_undef);
435 str_nset(dstr,s,m-s);
436 (void)astore(ary, ++sp, dstr);
442 maxiters += (strend - s) * spat->spat_regexp->nparens;
443 while (s < strend && --limit &&
444 regexec(spat->spat_regexp, s, strend, orig, 1, Nullstr, TRUE) ) {
445 if (spat->spat_regexp->subbase
446 && spat->spat_regexp->subbase != orig) {
449 orig = spat->spat_regexp->subbase;
451 strend = s + (strend - m);
453 m = spat->spat_regexp->startp[0];
455 dstr = Str_new(32,m-s);
457 dstr = str_static(&str_undef);
458 str_nset(dstr,s,m-s);
459 (void)astore(ary, ++sp, dstr);
460 if (spat->spat_regexp->nparens) {
461 for (i = 1; i <= spat->spat_regexp->nparens; i++) {
462 s = spat->spat_regexp->startp[i];
463 m = spat->spat_regexp->endp[i];
465 dstr = Str_new(33,m-s);
467 dstr = str_static(&str_undef);
468 str_nset(dstr,s,m-s);
469 (void)astore(ary, ++sp, dstr);
472 s = spat->spat_regexp->endp[0];
478 iters = sp - arglast[0];
479 if (iters > maxiters)
481 if (s < strend || origlimit) { /* keep field after final delim? */
483 dstr = Str_new(34,strend-s);
485 dstr = str_static(&str_undef);
486 str_nset(dstr,s,strend-s);
487 (void)astore(ary, ++sp, dstr);
492 while (iters > 0 && ary->ary_array[sp]->str_cur == 0)
499 zaps = str_get(afetch(ary,sp,FALSE));
503 while (iters > 0 && (!zapb)) {
506 zaps = str_get(afetch(ary,iters-1,FALSE));
514 if (gimme == G_ARRAY) {
516 astore(stack, arglast[0] + 1 + sp, Nullstr);
517 Copy(ary->ary_array, stack->ary_array + arglast[0] + 1, sp, STR*);
518 return arglast[0] + sp;
522 if (gimme == G_ARRAY)
526 str_numset(str,(double)iters);
533 do_unpack(str,gimme,arglast)
538 STR **st = stack->ary_array;
539 register int sp = arglast[0] + 1;
540 register char *pat = str_get(st[sp++]);
541 register char *s = str_get(st[sp]);
542 char *strend = s + st[sp--]->str_cur;
544 register char *patend = pat + st[sp]->str_cur;
548 /* These must not be in registers: */
553 unsigned char auchar;
554 unsigned short aushort;
556 unsigned long aulong;
561 unsigned long culong;
564 if (gimme != G_ARRAY) { /* arrange to do first one only */
565 for (patend = pat; !isalpha(*patend); patend++);
566 if (*patend == 'a' || *patend == 'A' || *pat == '%') {
568 while (isdigit(*patend) || *patend == '*')
575 while (pat < patend) {
580 else if (*pat == '*')
581 len = strend - strbeg; /* long enough */
582 else if (isdigit(*pat)) {
584 while (isdigit(*pat))
585 len = (len * 10) + (*pat++ - '0');
588 len = (datumtype != '@');
593 if (len == 1 && pat[-1] != '1')
602 if (len > strend - s)
603 fatal("@ outside of string");
607 if (len > s - strbeg)
608 fatal("X outside of string");
612 if (len > strend - s)
613 fatal("x outside of string");
618 if (len > strend - s)
622 str = Str_new(35,len);
625 if (datumtype == 'A') {
626 aptr = s; /* borrow register */
627 s = str->str_ptr + len - 1;
628 while (s >= str->str_ptr && (!*s || isspace(*s)))
631 str->str_cur = s - str->str_ptr;
632 s = aptr; /* unborrow register */
634 (void)astore(stack, ++sp, str_2static(str));
637 if (len > strend - s)
642 if (aint >= 128) /* fake up signed chars */
650 if (aint >= 128) /* fake up signed chars */
653 str_numset(str,(double)aint);
654 (void)astore(stack, ++sp, str_2static(str));
659 if (len > strend - s)
672 str_numset(str,(double)auint);
673 (void)astore(stack, ++sp, str_2static(str));
678 along = (strend - s) / sizeof(short);
683 bcopy(s,(char*)&ashort,sizeof(short));
690 bcopy(s,(char*)&ashort,sizeof(short));
693 str_numset(str,(double)ashort);
694 (void)astore(stack, ++sp, str_2static(str));
700 along = (strend - s) / sizeof(unsigned short);
705 bcopy(s,(char*)&aushort,sizeof(unsigned short));
706 s += sizeof(unsigned short);
708 if (datumtype == 'n')
709 aushort = ntohs(aushort);
716 bcopy(s,(char*)&aushort,sizeof(unsigned short));
717 s += sizeof(unsigned short);
720 if (datumtype == 'n')
721 aushort = ntohs(aushort);
723 str_numset(str,(double)aushort);
724 (void)astore(stack, ++sp, str_2static(str));
729 along = (strend - s) / sizeof(int);
734 bcopy(s,(char*)&aint,sizeof(int));
737 cdouble += (double)aint;
744 bcopy(s,(char*)&aint,sizeof(int));
747 str_numset(str,(double)aint);
748 (void)astore(stack, ++sp, str_2static(str));
753 along = (strend - s) / sizeof(unsigned int);
758 bcopy(s,(char*)&auint,sizeof(unsigned int));
759 s += sizeof(unsigned int);
761 cdouble += (double)auint;
768 bcopy(s,(char*)&auint,sizeof(unsigned int));
769 s += sizeof(unsigned int);
771 str_numset(str,(double)auint);
772 (void)astore(stack, ++sp, str_2static(str));
777 along = (strend - s) / sizeof(long);
782 bcopy(s,(char*)&along,sizeof(long));
785 cdouble += (double)along;
792 bcopy(s,(char*)&along,sizeof(long));
795 str_numset(str,(double)along);
796 (void)astore(stack, ++sp, str_2static(str));
802 along = (strend - s) / sizeof(unsigned long);
807 bcopy(s,(char*)&aulong,sizeof(unsigned long));
808 s += sizeof(unsigned long);
810 if (datumtype == 'N')
811 aulong = ntohl(aulong);
814 cdouble += (double)aulong;
821 bcopy(s,(char*)&aulong,sizeof(unsigned long));
822 s += sizeof(unsigned long);
825 if (datumtype == 'N')
826 aulong = ntohl(aulong);
828 str_numset(str,(double)aulong);
829 (void)astore(stack, ++sp, str_2static(str));
834 along = (strend - s) / sizeof(char*);
838 if (sizeof(char*) > strend - s)
841 bcopy(s,(char*)&aptr,sizeof(char*));
847 (void)astore(stack, ++sp, str_2static(str));
850 /* float and double added gnb@melba.bby.oz.au 22/11/89 */
853 along = (strend - s) / sizeof(float);
858 bcopy(s, (char *)&afloat, sizeof(float));
865 bcopy(s, (char *)&afloat, sizeof(float));
867 str = Str_new(47, 0);
868 str_numset(str, (double)afloat);
869 (void)astore(stack, ++sp, str_2static(str));
875 along = (strend - s) / sizeof(double);
880 bcopy(s, (char *)&adouble, sizeof(double));
887 bcopy(s, (char *)&adouble, sizeof(double));
889 str = Str_new(48, 0);
890 str_numset(str, (double)adouble);
891 (void)astore(stack, ++sp, str_2static(str));
896 along = (strend - s) * 3 / 4;
897 str = Str_new(42,along);
898 while (s < strend && *s > ' ' && *s < 'a') {
903 len = (*s++ - ' ') & 077;
905 if (s < strend && *s >= ' ')
906 a = (*s++ - ' ') & 077;
909 if (s < strend && *s >= ' ')
910 b = (*s++ - ' ') & 077;
913 if (s < strend && *s >= ' ')
914 c = (*s++ - ' ') & 077;
917 if (s < strend && *s >= ' ')
918 d = (*s++ - ' ') & 077;
921 hunk[0] = a << 2 | b >> 4;
922 hunk[1] = b << 4 | c >> 2;
923 hunk[2] = c << 6 | d;
924 str_ncat(str,hunk, len > 3 ? 3 : len);
929 else if (s[1] == '\n') /* possible checksum byte */
932 (void)astore(stack, ++sp, str_2static(str));
937 if (index("fFdD", datumtype) ||
938 (checksum > 32 && index("iIlLN", datumtype)) ) {
943 while (checksum >= 16) {
947 while (checksum >= 4) {
953 along = (1 << checksum) - 1;
954 while (cdouble < 0.0)
956 cdouble = modf(cdouble / adouble, &trouble) * adouble;
957 str_numset(str,cdouble);
960 along = (1 << checksum) - 1;
961 culong &= (unsigned long)along;
962 str_numset(str,(double)culong);
964 (void)astore(stack, ++sp, str_2static(str));
972 do_slice(stab,str,numarray,lval,gimme,arglast)
980 register STR **st = stack->ary_array;
981 register int sp = arglast[1];
982 register int max = arglast[2];
985 register int magic = 0;
988 int oldarybase = arybase;
991 if (numarray == 2) { /* a slice of a LIST */
993 ary->ary_fill = arglast[3];
995 st[sp] = str; /* make stack size available */
996 str_numset(str,(double)(sp - 1));
999 ary = stab_array(stab); /* a slice of an array */
1003 if (stab == envstab)
1005 else if (stab == sigstab)
1008 else if (stab_hash(stab)->tbl_dbm)
1010 #endif /* SOME_DBM */
1012 hash = stab_hash(stab); /* a slice of an associative array */
1015 if (gimme == G_ARRAY) {
1019 st[sp-1] = afetch(ary,
1020 ((int)str_gnum(st[sp])) - arybase, lval);
1023 st[sp-1] = &str_undef;
1029 tmps = str_get(st[sp]);
1030 len = st[sp]->str_cur;
1031 st[sp-1] = hfetch(hash,tmps,len, lval);
1033 str_magic(st[sp-1],stab,magic,tmps,len);
1036 st[sp-1] = &str_undef;
1044 st[sp] = afetch(ary,
1045 ((int)str_gnum(st[max])) - arybase, lval);
1047 st[sp] = &str_undef;
1051 tmps = str_get(st[max]);
1052 len = st[max]->str_cur;
1053 st[sp] = hfetch(hash,tmps,len, lval);
1055 str_magic(st[sp],stab,magic,tmps,len);
1058 st[sp] = &str_undef;
1061 arybase = oldarybase;
1066 do_splice(ary,gimme,arglast)
1067 register ARRAY *ary;
1071 register STR **st = stack->ary_array;
1072 register int sp = arglast[1];
1073 int max = arglast[2] + 1;
1077 register int offset;
1078 register int length;
1085 offset = ((int)str_gnum(st[sp])) - arybase;
1087 offset += ary->ary_fill + 1;
1089 length = (int)str_gnum(st[sp++]);
1094 length = ary->ary_max; /* close enough to infinity */
1098 length = ary->ary_max;
1106 if (offset > ary->ary_fill + 1)
1107 offset = ary->ary_fill + 1;
1108 after = ary->ary_fill + 1 - (offset + length);
1109 if (after < 0) { /* not that much array */
1110 length += after; /* offset+length now in array */
1114 /* At this point, sp .. max-1 is our new LIST */
1117 diff = newlen - length;
1119 if (diff < 0) { /* shrinking the area */
1121 New(451, tmparyval, newlen, STR*); /* so remember insertion */
1122 Copy(st+sp, tmparyval, newlen, STR*);
1125 sp = arglast[0] + 1;
1126 if (gimme == G_ARRAY) { /* copy return vals to stack */
1127 if (sp + length >= stack->ary_max) {
1128 astore(stack,sp + length, Nullstr);
1129 st = stack->ary_array;
1131 Copy(ary->ary_array+offset, st+sp, length, STR*);
1132 if (ary->ary_flags & ARF_REAL) {
1133 for (i = length, dst = st+sp; i; i--)
1134 str_2static(*dst++); /* free them eventualy */
1139 st[sp] = ary->ary_array[offset+length-1];
1140 if (ary->ary_flags & ARF_REAL)
1141 str_2static(st[sp]);
1143 ary->ary_fill += diff;
1145 /* pull up or down? */
1147 if (offset < after) { /* easier to pull up */
1148 if (offset) { /* esp. if nothing to pull */
1149 src = &ary->ary_array[offset-1];
1150 dst = src - diff; /* diff is negative */
1151 for (i = offset; i > 0; i--) /* can't trust Copy */
1154 Zero(ary->ary_array, -diff, STR*);
1155 ary->ary_array -= diff; /* diff is negative */
1156 ary->ary_max += diff;
1159 if (after) { /* anything to pull down? */
1160 src = ary->ary_array + offset + length;
1161 dst = src + diff; /* diff is negative */
1162 Copy(src, dst, after, STR*);
1164 Zero(&ary->ary_array[ary->ary_fill+1], -diff, STR*);
1165 /* avoid later double free */
1168 for (src = tmparyval, dst = ary->ary_array + offset;
1170 *dst = Str_new(46,0);
1171 str_sset(*dst++,*src++);
1173 Safefree(tmparyval);
1176 else { /* no, expanding (or same) */
1178 New(452, tmparyval, length, STR*); /* so remember deletion */
1179 Copy(ary->ary_array+offset, tmparyval, length, STR*);
1182 if (diff > 0) { /* expanding */
1184 /* push up or down? */
1186 if (offset < after && diff <= ary->ary_array - ary->ary_alloc) {
1188 src = ary->ary_array;
1190 Copy(src, dst, offset, STR*);
1192 ary->ary_array -= diff; /* diff is positive */
1193 ary->ary_max += diff;
1194 ary->ary_fill += diff;
1197 if (ary->ary_fill + diff >= ary->ary_max) /* oh, well */
1198 astore(ary, ary->ary_fill + diff, Nullstr);
1200 ary->ary_fill += diff;
1202 dst = ary->ary_array + ary->ary_fill;
1204 for (i = after; i; i--) {
1205 if (*dst) /* str was hanging around */
1206 str_free(*dst); /* after $#foo */
1214 for (src = st+sp, dst = ary->ary_array + offset; newlen; newlen--) {
1215 *dst = Str_new(46,0);
1216 str_sset(*dst++,*src++);
1218 sp = arglast[0] + 1;
1219 if (gimme == G_ARRAY) { /* copy return vals to stack */
1221 Copy(tmparyval, st+sp, length, STR*);
1222 if (ary->ary_flags & ARF_REAL) {
1223 for (i = length, dst = st+sp; i; i--)
1224 str_2static(*dst++); /* free them eventualy */
1226 Safefree(tmparyval);
1231 st[sp] = tmparyval[length-1];
1232 if (ary->ary_flags & ARF_REAL)
1233 str_2static(st[sp]);
1234 Safefree(tmparyval);
1237 st[sp] = &str_undef;
1243 do_grep(arg,str,gimme,arglast)
1249 STR **st = stack->ary_array;
1250 register int dst = arglast[1];
1251 register int src = dst + 1;
1252 register int sp = arglast[2];
1253 register int i = sp - arglast[1];
1254 int oldsave = savestack->ary_fill;
1255 SPAT *oldspat = curspat;
1257 savesptr(&stab_val(defstab));
1258 if ((arg[1].arg_type & A_MASK) != A_EXPR) {
1259 arg[1].arg_type &= A_MASK;
1261 arg[1].arg_type |= A_DONT;
1263 arg = arg[1].arg_ptr.arg_arg;
1266 stab_val(defstab) = st[src];
1268 stab_val(defstab) = str_static(&str_undef);
1269 (void)eval(arg,G_SCALAR,sp);
1270 st = stack->ary_array;
1271 if (str_true(st[sp+1]))
1272 st[dst++] = st[src];
1276 restorelist(oldsave);
1277 if (gimme != G_ARRAY) {
1278 str_numset(str,(double)(dst - arglast[1]));
1280 st[arglast[0]+1] = str;
1281 return arglast[0]+1;
1283 return arglast[0] + (dst - arglast[1]);
1287 do_reverse(str,gimme,arglast)
1292 STR **st = stack->ary_array;
1293 register STR **up = &st[arglast[1]];
1294 register STR **down = &st[arglast[2]];
1295 register int i = arglast[2] - arglast[1];
1297 if (gimme != G_ARRAY) {
1298 str_sset(str,&str_undef);
1300 st[arglast[0]+1] = str;
1301 return arglast[0]+1;
1308 i = arglast[2] - arglast[1];
1309 Copy(down+1,up,i/2,STR*);
1310 return arglast[2] - 1;
1313 static CMD *sortcmd;
1314 static STAB *firststab = Nullstab;
1315 static STAB *secondstab = Nullstab;
1318 do_sort(str,stab,gimme,arglast)
1324 register STR **st = stack->ary_array;
1325 int sp = arglast[1];
1327 register int max = arglast[2] - sp;
1334 static ARRAY *sortstack = Null(ARRAY*);
1336 if (gimme != G_ARRAY) {
1337 str_sset(str,&str_undef);
1343 st += sp; /* temporarily make st point to args */
1344 for (i = 1; i <= max; i++) {
1346 if (!(*up)->str_pok)
1347 (void)str_2ptr(*up);
1355 if (stab_sub(stab) && (sortcmd = stab_sub(stab)->cmd)) {
1356 int oldtmps_base = tmps_base;
1359 sortstack = anew(Nullstab);
1360 sortstack->ary_flags = 0;
1364 tmps_base = tmps_max;
1366 firststab = stabent("a",TRUE);
1367 secondstab = stabent("b",TRUE);
1369 oldfirst = stab_val(firststab);
1370 oldsecond = stab_val(secondstab);
1372 qsort((char*)(st+sp+1),max,sizeof(STR*),sortsub);
1374 qsort(Nullch,max,sizeof(STR*),sortsub);
1376 stab_val(firststab) = oldfirst;
1377 stab_val(secondstab) = oldsecond;
1378 tmps_base = oldtmps_base;
1383 qsort((char*)(st+sp+1),max,sizeof(STR*),sortcmp);
1394 stab_val(firststab) = *str1;
1395 stab_val(secondstab) = *str2;
1396 cmd_exec(sortcmd,G_SCALAR,-1);
1397 return (int)str_gnum(*stack->ary_array);
1400 sortcmp(strp1,strp2)
1404 register STR *str1 = *strp1;
1405 register STR *str2 = *strp2;
1408 if (str1->str_cur < str2->str_cur) {
1409 if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
1414 else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
1416 else if (str1->str_cur == str2->str_cur)
1423 do_range(gimme,arglast)
1427 STR **st = stack->ary_array;
1428 register int sp = arglast[0];
1430 register ARRAY *ary = stack;
1434 if (gimme != G_ARRAY)
1435 fatal("panic: do_range");
1437 if (st[sp+1]->str_nok ||
1438 (looks_like_number(st[sp+1]) && *st[sp+1]->str_ptr != '0') ) {
1439 i = (int)str_gnum(st[sp+1]);
1440 max = (int)str_gnum(st[sp+2]);
1442 (void)astore(ary, ++sp, str = str_static(&str_no));
1443 str_numset(str,(double)i++);
1447 STR *final = str_static(st[sp+2]);
1448 char *tmps = str_get(final);
1450 str = str_static(st[sp+1]);
1451 while (!str->str_nok && str->str_cur <= final->str_cur &&
1452 strNE(str->str_ptr,tmps) ) {
1453 (void)astore(ary, ++sp, str);
1454 str = str_static(str);
1457 if (strEQ(str->str_ptr,tmps))
1458 (void)astore(ary, ++sp, str);
1464 do_tms(str,gimme,arglast)
1469 STR **st = stack->ary_array;
1470 register int sp = arglast[0];
1472 if (gimme != G_ARRAY) {
1473 str_sset(str,&str_undef);
1478 (void)times(×buf);
1485 (void)astore(stack,++sp,
1486 str_2static(str_nmake(((double)timesbuf.tms_utime)/HZ)));
1487 (void)astore(stack,++sp,
1488 str_2static(str_nmake(((double)timesbuf.tms_stime)/HZ)));
1489 (void)astore(stack,++sp,
1490 str_2static(str_nmake(((double)timesbuf.tms_cutime)/HZ)));
1491 (void)astore(stack,++sp,
1492 str_2static(str_nmake(((double)timesbuf.tms_cstime)/HZ)));
1494 (void)astore(stack,++sp,
1495 str_2static(str_nmake(0.0)));
1501 do_time(str,tmbuf,gimme,arglast)
1507 register ARRAY *ary = stack;
1508 STR **st = ary->ary_array;
1509 register int sp = arglast[0];
1511 if (!tmbuf || gimme != G_ARRAY) {
1512 str_sset(str,&str_undef);
1517 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_sec)));
1518 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_min)));
1519 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_hour)));
1520 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_mday)));
1521 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_mon)));
1522 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_year)));
1523 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_wday)));
1524 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_yday)));
1525 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_isdst)));
1530 do_kv(str,hash,kv,gimme,arglast)
1537 register ARRAY *ary = stack;
1538 STR **st = ary->ary_array;
1539 register int sp = arglast[0];
1541 register HENT *entry;
1544 int dokeys = (kv == O_KEYS || kv == O_HASH);
1545 int dovalues = (kv == O_VALUES || kv == O_HASH);
1547 if (gimme != G_ARRAY) {
1548 str_sset(str,&str_undef);
1553 (void)hiterinit(hash);
1554 while (entry = hiternext(hash)) {
1556 tmps = hiterkey(entry,&i);
1559 (void)astore(ary,++sp,str_2static(str_make(tmps,i)));
1562 tmpstr = Str_new(45,0);
1565 sprintf(buf,"%d%%%d=%d\n",entry->hent_hash,
1566 hash->tbl_max+1,entry->hent_hash & hash->tbl_max);
1567 str_set(tmpstr,buf);
1571 str_sset(tmpstr,hiterval(hash,entry));
1572 (void)astore(ary,++sp,str_2static(tmpstr));
1579 do_each(str,hash,gimme,arglast)
1585 STR **st = stack->ary_array;
1586 register int sp = arglast[0];
1587 static STR *mystrk = Nullstr;
1588 HENT *entry = hiternext(hash);
1598 if (gimme == G_ARRAY) {
1599 tmps = hiterkey(entry, &i);
1602 st[++sp] = mystrk = str_make(tmps,i);
1605 str_sset(str,hiterval(hash,entry));