1 /* $Header: dolist.c,v 3.0.1.9 90/08/13 22:15:35 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.9 90/08/13 22:15:35 lwall
10 * patch28: defined(@array) and defined(%array) didn't work right
12 * Revision 3.0.1.8 90/08/09 03:15:56 lwall
13 * patch19: certain kinds of matching cause "panic: hint"
14 * patch19: $' broke on embedded nulls
15 * patch19: split on /\s+/, /^/ and ' ' is now special cased for speed
16 * patch19: split on /x/i didn't work
17 * patch19: couldn't unpack an 'A' or 'a' field in a scalar context
18 * patch19: unpack called bcopy on each character of a C/c field
19 * patch19: pack/unpack know about uudecode lines
20 * patch19: fixed sort on undefined strings and sped up slightly
21 * patch19: each and keys returned garbage on null key in DBM file
23 * Revision 3.0.1.7 90/03/27 15:48:42 lwall
24 * patch16: MSDOS support
25 * patch16: use of $`, $& or $' sometimes causes memory leakage
26 * patch16: splice(@array,0,$n) case cause duplicate free
27 * patch16: grep blows up on undefined array values
28 * patch16: .. now works using magical string increment
30 * Revision 3.0.1.6 90/03/12 16:33:02 lwall
31 * patch13: added list slice operator (LIST)[LIST]
32 * patch13: added splice operator: @oldelems = splice(@array,$offset,$len,LIST)
33 * patch13: made split('') act like split(//) rather than split(' ')
35 * Revision 3.0.1.5 90/02/28 17:09:44 lwall
36 * patch9: split now can split into more than 10000 elements
37 * patch9: @_ clobbered by ($foo,$bar) = split
38 * patch9: sped up pack and unpack
39 * patch9: unpack of single item now works in a scalar context
40 * patch9: slices ignored value of $[
41 * patch9: grep now returns number of items matched in scalar context
42 * patch9: grep iterations no longer in the regexp context of previous iteration
44 * Revision 3.0.1.4 89/12/21 19:58:46 lwall
45 * patch7: grep(1,@array) didn't work
46 * patch7: /$pat/; //; wrongly freed runtime pattern twice
48 * Revision 3.0.1.3 89/11/17 15:14:45 lwall
49 * patch5: grep() occasionally loses arguments or dumps core
51 * Revision 3.0.1.2 89/11/11 04:28:17 lwall
52 * patch2: non-existent slice values are now undefined rather than null
54 * Revision 3.0.1.1 89/10/26 23:11:51 lwall
55 * patch1: split in a subroutine wrongly freed referenced arguments
56 * patch1: reverse didn't work
58 * Revision 3.0 89/10/18 15:11:02 lwall
68 #pragma function(memcmp)
69 #endif /* BUGGY_MSC */
72 do_match(str,arg,gimme,arglast)
78 register STR **st = stack->ary_array;
79 register SPAT *spat = arg[2].arg_ptr.arg_spat;
81 register int sp = arglast[0] + 1;
82 STR *srchstr = st[sp];
83 register char *s = str_get(st[sp]);
84 char *strend = s + st[sp]->str_cur;
98 fatal("panic: do_match");
99 if (spat->spat_flags & SPAT_USED) {
102 deb("2.SPAT USED\n");
104 if (gimme == G_ARRAY)
112 if (spat->spat_runtime) {
114 sp = eval(spat->spat_runtime,G_SCALAR,sp);
115 st = stack->ary_array;
116 t = str_get(tmpstr = st[sp--]);
120 deb("2.SPAT /%s/\n",t);
122 if (spat->spat_regexp)
123 regfree(spat->spat_regexp);
124 spat->spat_regexp = regcomp(t,t+tmpstr->str_cur,
125 spat->spat_flags & SPAT_FOLD);
126 if (!*spat->spat_regexp->precomp && lastspat)
128 if (spat->spat_flags & SPAT_KEEP) {
129 if (spat->spat_runtime)
130 arg_free(spat->spat_runtime); /* it won't change, so */
131 spat->spat_runtime = Nullarg; /* no point compiling again */
133 if (!spat->spat_regexp->nparens)
134 gimme = G_SCALAR; /* accidental array context? */
135 if (regexec(spat->spat_regexp, s, strend, s, 0,
136 srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
138 if (spat->spat_regexp->subbase)
144 if (gimme == G_ARRAY)
146 str_sset(str,&str_no);
157 if (spat->spat_flags & SPAT_ONCE)
161 deb("2.SPAT %c%s%c\n",ch,spat->spat_regexp->precomp,ch);
164 if (!*spat->spat_regexp->precomp && lastspat)
168 if (myhint < s || myhint > strend)
169 fatal("panic: hint in do_match");
171 if (spat->spat_regexp->regback >= 0) {
172 s -= spat->spat_regexp->regback;
179 else if (spat->spat_short) {
180 if (spat->spat_flags & SPAT_SCANFIRST) {
181 if (srchstr->str_pok & SP_STUDIED) {
182 if (screamfirst[spat->spat_short->str_rare] < 0)
184 else if (!(s = screaminstr(srchstr,spat->spat_short)))
186 else if (spat->spat_flags & SPAT_ALL)
190 else if (!(s = fbminstr((unsigned char*)s,
191 (unsigned char*)strend, spat->spat_short)))
194 else if (spat->spat_flags & SPAT_ALL)
196 if (s && spat->spat_regexp->regback >= 0) {
197 ++spat->spat_short->str_u.str_useful;
198 s -= spat->spat_regexp->regback;
205 else if (!multiline && (*spat->spat_short->str_ptr != *s ||
206 bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) ))
208 if (--spat->spat_short->str_u.str_useful < 0) {
209 str_free(spat->spat_short);
210 spat->spat_short = Nullstr; /* opt is being useless */
213 if (!spat->spat_regexp->nparens)
214 gimme = G_SCALAR; /* accidental array context? */
215 if (regexec(spat->spat_regexp, s, strend, t, 0,
216 srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
218 if (spat->spat_regexp->subbase)
221 if (spat->spat_flags & SPAT_ONCE)
222 spat->spat_flags |= SPAT_USED;
226 if (gimme == G_ARRAY)
228 str_sset(str,&str_no);
237 if (gimme == G_ARRAY) {
240 iters = spat->spat_regexp->nparens;
241 if (sp + iters >= stack->ary_max) {
242 astore(stack,sp + iters, Nullstr);
243 st = stack->ary_array; /* possibly realloced */
246 for (i = 1; i <= iters; i++) {
247 st[++sp] = str_static(&str_no);
248 if (s = spat->spat_regexp->startp[i]) {
249 len = spat->spat_regexp->endp[i] - s;
251 str_nset(st[sp],s,len);
257 str_sset(str,&str_yes);
264 ++spat->spat_short->str_u.str_useful;
266 if (spat->spat_flags & SPAT_ONCE)
267 spat->spat_flags |= SPAT_USED;
271 if (spat->spat_regexp->subbase)
272 Safefree(spat->spat_regexp->subbase);
273 tmps = spat->spat_regexp->subbase = nsavestr(t,strend-t);
274 spat->spat_regexp->subend = tmps + (strend-t);
275 tmps = spat->spat_regexp->startp[0] = tmps + (s - t);
276 spat->spat_regexp->endp[0] = tmps + spat->spat_short->str_cur;
279 str_sset(str,&str_yes);
285 ++spat->spat_short->str_u.str_useful;
286 if (gimme == G_ARRAY)
288 str_sset(str,&str_no);
295 #pragma intrinsic(memcmp)
296 #endif /* BUGGY_MSC */
299 do_split(str,spat,limit,gimme,arglast)
306 register ARRAY *ary = stack;
307 STR **st = ary->ary_array;
308 register int sp = arglast[0] + 1;
309 register char *s = str_get(st[sp]);
310 char *strend = s + st[sp--]->str_cur;
314 int maxiters = (strend - s) + 10;
317 int origlimit = limit;
321 fatal("panic: do_split");
322 else if (spat->spat_runtime) {
324 sp = eval(spat->spat_runtime,G_SCALAR,sp);
325 st = stack->ary_array;
326 m = str_get(dstr = st[sp--]);
328 if (*m == ' ' && dstr->str_cur == 1) {
329 str_set(dstr,"\\s+");
331 spat->spat_flags |= SPAT_SKIPWHITE;
333 if (spat->spat_regexp)
334 regfree(spat->spat_regexp);
335 spat->spat_regexp = regcomp(m,m+dstr->str_cur,
336 spat->spat_flags & SPAT_FOLD);
337 if (spat->spat_flags & SPAT_KEEP ||
338 (spat->spat_runtime->arg_type == O_ITEM &&
339 (spat->spat_runtime[1].arg_type & A_MASK) == A_SINGLE) ) {
340 arg_free(spat->spat_runtime); /* it won't change, so */
341 spat->spat_runtime = Nullarg; /* no point compiling again */
346 deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
349 ary = stab_xarray(spat->spat_repl[1].arg_ptr.arg_stab);
350 if (ary && (gimme != G_ARRAY || (spat->spat_flags & SPAT_ONCE))) {
352 if (!(ary->ary_flags & ARF_REAL)) {
353 ary->ary_flags |= ARF_REAL;
354 for (i = ary->ary_fill; i >= 0; i--)
355 ary->ary_array[i] = Nullstr; /* don't free mere refs */
358 sp = -1; /* temporarily switch stacks */
363 if (spat->spat_flags & SPAT_SKIPWHITE) {
368 limit = maxiters + 2;
369 if (strEQ("\\s+",spat->spat_regexp->precomp)) {
371 for (m = s; m < strend && !isspace(*m); m++) ;
375 dstr = Str_new(30,m-s);
377 dstr = str_static(&str_undef);
378 str_nset(dstr,s,m-s);
379 (void)astore(ary, ++sp, dstr);
380 for (s = m + 1; s < strend && isspace(*s); s++) ;
383 else if (strEQ("^",spat->spat_regexp->precomp)) {
385 for (m = s; m < strend && *m != '\n'; m++) ;
390 dstr = Str_new(30,m-s);
392 dstr = str_static(&str_undef);
393 str_nset(dstr,s,m-s);
394 (void)astore(ary, ++sp, dstr);
398 else if (spat->spat_short) {
399 i = spat->spat_short->str_cur;
401 int fold = (spat->spat_flags & SPAT_FOLD);
403 i = *spat->spat_short->str_ptr;
404 if (fold && isupper(i))
409 m < strend && *m != i &&
410 (!isupper(*m) || tolower(*m) != i);
415 for (m = s; m < strend && *m != i; m++) ;
419 dstr = Str_new(30,m-s);
421 dstr = str_static(&str_undef);
422 str_nset(dstr,s,m-s);
423 (void)astore(ary, ++sp, dstr);
429 while (s < strend && --limit &&
430 (m=fbminstr((unsigned char*)s, (unsigned char*)strend,
435 dstr = Str_new(31,m-s);
437 dstr = str_static(&str_undef);
438 str_nset(dstr,s,m-s);
439 (void)astore(ary, ++sp, dstr);
445 maxiters += (strend - s) * spat->spat_regexp->nparens;
446 while (s < strend && --limit &&
447 regexec(spat->spat_regexp, s, strend, orig, 1, Nullstr, TRUE) ) {
448 if (spat->spat_regexp->subbase
449 && spat->spat_regexp->subbase != orig) {
452 orig = spat->spat_regexp->subbase;
454 strend = s + (strend - m);
456 m = spat->spat_regexp->startp[0];
458 dstr = Str_new(32,m-s);
460 dstr = str_static(&str_undef);
461 str_nset(dstr,s,m-s);
462 (void)astore(ary, ++sp, dstr);
463 if (spat->spat_regexp->nparens) {
464 for (i = 1; i <= spat->spat_regexp->nparens; i++) {
465 s = spat->spat_regexp->startp[i];
466 m = spat->spat_regexp->endp[i];
468 dstr = Str_new(33,m-s);
470 dstr = str_static(&str_undef);
471 str_nset(dstr,s,m-s);
472 (void)astore(ary, ++sp, dstr);
475 s = spat->spat_regexp->endp[0];
481 iters = sp - arglast[0];
482 if (iters > maxiters)
484 if (s < strend || origlimit) { /* keep field after final delim? */
486 dstr = Str_new(34,strend-s);
488 dstr = str_static(&str_undef);
489 str_nset(dstr,s,strend-s);
490 (void)astore(ary, ++sp, dstr);
495 while (iters > 0 && ary->ary_array[sp]->str_cur == 0)
502 zaps = str_get(afetch(ary,sp,FALSE));
506 while (iters > 0 && (!zapb)) {
509 zaps = str_get(afetch(ary,iters-1,FALSE));
517 if (gimme == G_ARRAY) {
519 astore(stack, arglast[0] + 1 + sp, Nullstr);
520 Copy(ary->ary_array, stack->ary_array + arglast[0] + 1, sp, STR*);
521 return arglast[0] + sp;
525 if (gimme == G_ARRAY)
529 str_numset(str,(double)iters);
536 do_unpack(str,gimme,arglast)
541 STR **st = stack->ary_array;
542 register int sp = arglast[0] + 1;
543 register char *pat = str_get(st[sp++]);
544 register char *s = str_get(st[sp]);
545 char *strend = s + st[sp--]->str_cur;
547 register char *patend = pat + st[sp]->str_cur;
551 /* These must not be in registers: */
556 unsigned char auchar;
557 unsigned short aushort;
559 unsigned long aulong;
564 unsigned long culong;
567 if (gimme != G_ARRAY) { /* arrange to do first one only */
568 for (patend = pat; !isalpha(*patend); patend++);
569 if (*patend == 'a' || *patend == 'A' || *pat == '%') {
571 while (isdigit(*patend) || *patend == '*')
578 while (pat < patend) {
583 else if (*pat == '*')
584 len = strend - strbeg; /* long enough */
585 else if (isdigit(*pat)) {
587 while (isdigit(*pat))
588 len = (len * 10) + (*pat++ - '0');
591 len = (datumtype != '@');
596 if (len == 1 && pat[-1] != '1')
605 if (len > strend - s)
606 fatal("@ outside of string");
610 if (len > s - strbeg)
611 fatal("X outside of string");
615 if (len > strend - s)
616 fatal("x outside of string");
621 if (len > strend - s)
625 str = Str_new(35,len);
628 if (datumtype == 'A') {
629 aptr = s; /* borrow register */
630 s = str->str_ptr + len - 1;
631 while (s >= str->str_ptr && (!*s || isspace(*s)))
634 str->str_cur = s - str->str_ptr;
635 s = aptr; /* unborrow register */
637 (void)astore(stack, ++sp, str_2static(str));
640 if (len > strend - s)
645 if (aint >= 128) /* fake up signed chars */
653 if (aint >= 128) /* fake up signed chars */
656 str_numset(str,(double)aint);
657 (void)astore(stack, ++sp, str_2static(str));
662 if (len > strend - s)
675 str_numset(str,(double)auint);
676 (void)astore(stack, ++sp, str_2static(str));
681 along = (strend - s) / sizeof(short);
686 bcopy(s,(char*)&ashort,sizeof(short));
693 bcopy(s,(char*)&ashort,sizeof(short));
696 str_numset(str,(double)ashort);
697 (void)astore(stack, ++sp, str_2static(str));
703 along = (strend - s) / sizeof(unsigned short);
708 bcopy(s,(char*)&aushort,sizeof(unsigned short));
709 s += sizeof(unsigned short);
711 if (datumtype == 'n')
712 aushort = ntohs(aushort);
719 bcopy(s,(char*)&aushort,sizeof(unsigned short));
720 s += sizeof(unsigned short);
723 if (datumtype == 'n')
724 aushort = ntohs(aushort);
726 str_numset(str,(double)aushort);
727 (void)astore(stack, ++sp, str_2static(str));
732 along = (strend - s) / sizeof(int);
737 bcopy(s,(char*)&aint,sizeof(int));
740 cdouble += (double)aint;
747 bcopy(s,(char*)&aint,sizeof(int));
750 str_numset(str,(double)aint);
751 (void)astore(stack, ++sp, str_2static(str));
756 along = (strend - s) / sizeof(unsigned int);
761 bcopy(s,(char*)&auint,sizeof(unsigned int));
762 s += sizeof(unsigned int);
764 cdouble += (double)auint;
771 bcopy(s,(char*)&auint,sizeof(unsigned int));
772 s += sizeof(unsigned int);
774 str_numset(str,(double)auint);
775 (void)astore(stack, ++sp, str_2static(str));
780 along = (strend - s) / sizeof(long);
785 bcopy(s,(char*)&along,sizeof(long));
788 cdouble += (double)along;
795 bcopy(s,(char*)&along,sizeof(long));
798 str_numset(str,(double)along);
799 (void)astore(stack, ++sp, str_2static(str));
805 along = (strend - s) / sizeof(unsigned long);
810 bcopy(s,(char*)&aulong,sizeof(unsigned long));
811 s += sizeof(unsigned long);
813 if (datumtype == 'N')
814 aulong = ntohl(aulong);
817 cdouble += (double)aulong;
824 bcopy(s,(char*)&aulong,sizeof(unsigned long));
825 s += sizeof(unsigned long);
828 if (datumtype == 'N')
829 aulong = ntohl(aulong);
831 str_numset(str,(double)aulong);
832 (void)astore(stack, ++sp, str_2static(str));
837 along = (strend - s) / sizeof(char*);
841 if (sizeof(char*) > strend - s)
844 bcopy(s,(char*)&aptr,sizeof(char*));
850 (void)astore(stack, ++sp, str_2static(str));
853 /* float and double added gnb@melba.bby.oz.au 22/11/89 */
856 along = (strend - s) / sizeof(float);
861 bcopy(s, (char *)&afloat, sizeof(float));
868 bcopy(s, (char *)&afloat, sizeof(float));
870 str = Str_new(47, 0);
871 str_numset(str, (double)afloat);
872 (void)astore(stack, ++sp, str_2static(str));
878 along = (strend - s) / sizeof(double);
883 bcopy(s, (char *)&adouble, sizeof(double));
890 bcopy(s, (char *)&adouble, sizeof(double));
892 str = Str_new(48, 0);
893 str_numset(str, (double)adouble);
894 (void)astore(stack, ++sp, str_2static(str));
899 along = (strend - s) * 3 / 4;
900 str = Str_new(42,along);
901 while (s < strend && *s > ' ' && *s < 'a') {
906 len = (*s++ - ' ') & 077;
908 if (s < strend && *s >= ' ')
909 a = (*s++ - ' ') & 077;
912 if (s < strend && *s >= ' ')
913 b = (*s++ - ' ') & 077;
916 if (s < strend && *s >= ' ')
917 c = (*s++ - ' ') & 077;
920 if (s < strend && *s >= ' ')
921 d = (*s++ - ' ') & 077;
924 hunk[0] = a << 2 | b >> 4;
925 hunk[1] = b << 4 | c >> 2;
926 hunk[2] = c << 6 | d;
927 str_ncat(str,hunk, len > 3 ? 3 : len);
932 else if (s[1] == '\n') /* possible checksum byte */
935 (void)astore(stack, ++sp, str_2static(str));
940 if (index("fFdD", datumtype) ||
941 (checksum > 32 && index("iIlLN", datumtype)) ) {
946 while (checksum >= 16) {
950 while (checksum >= 4) {
956 along = (1 << checksum) - 1;
957 while (cdouble < 0.0)
959 cdouble = modf(cdouble / adouble, &trouble) * adouble;
960 str_numset(str,cdouble);
963 along = (1 << checksum) - 1;
964 culong &= (unsigned long)along;
965 str_numset(str,(double)culong);
967 (void)astore(stack, ++sp, str_2static(str));
975 do_slice(stab,str,numarray,lval,gimme,arglast)
983 register STR **st = stack->ary_array;
984 register int sp = arglast[1];
985 register int max = arglast[2];
988 register int magic = 0;
991 int oldarybase = arybase;
994 if (numarray == 2) { /* a slice of a LIST */
996 ary->ary_fill = arglast[3];
998 st[sp] = str; /* make stack size available */
999 str_numset(str,(double)(sp - 1));
1002 ary = stab_array(stab); /* a slice of an array */
1006 if (stab == envstab)
1008 else if (stab == sigstab)
1011 else if (stab_hash(stab)->tbl_dbm)
1013 #endif /* SOME_DBM */
1015 hash = stab_hash(stab); /* a slice of an associative array */
1018 if (gimme == G_ARRAY) {
1022 st[sp-1] = afetch(ary,
1023 ((int)str_gnum(st[sp])) - arybase, lval);
1026 st[sp-1] = &str_undef;
1032 tmps = str_get(st[sp]);
1033 len = st[sp]->str_cur;
1034 st[sp-1] = hfetch(hash,tmps,len, lval);
1036 str_magic(st[sp-1],stab,magic,tmps,len);
1039 st[sp-1] = &str_undef;
1047 st[sp] = afetch(ary,
1048 ((int)str_gnum(st[max])) - arybase, lval);
1050 st[sp] = &str_undef;
1054 tmps = str_get(st[max]);
1055 len = st[max]->str_cur;
1056 st[sp] = hfetch(hash,tmps,len, lval);
1058 str_magic(st[sp],stab,magic,tmps,len);
1061 st[sp] = &str_undef;
1064 arybase = oldarybase;
1069 do_splice(ary,gimme,arglast)
1070 register ARRAY *ary;
1074 register STR **st = stack->ary_array;
1075 register int sp = arglast[1];
1076 int max = arglast[2] + 1;
1080 register int offset;
1081 register int length;
1088 offset = ((int)str_gnum(st[sp])) - arybase;
1090 offset += ary->ary_fill + 1;
1092 length = (int)str_gnum(st[sp++]);
1097 length = ary->ary_max; /* close enough to infinity */
1101 length = ary->ary_max;
1109 if (offset > ary->ary_fill + 1)
1110 offset = ary->ary_fill + 1;
1111 after = ary->ary_fill + 1 - (offset + length);
1112 if (after < 0) { /* not that much array */
1113 length += after; /* offset+length now in array */
1115 if (!ary->ary_alloc) {
1121 /* At this point, sp .. max-1 is our new LIST */
1124 diff = newlen - length;
1126 if (diff < 0) { /* shrinking the area */
1128 New(451, tmparyval, newlen, STR*); /* so remember insertion */
1129 Copy(st+sp, tmparyval, newlen, STR*);
1132 sp = arglast[0] + 1;
1133 if (gimme == G_ARRAY) { /* copy return vals to stack */
1134 if (sp + length >= stack->ary_max) {
1135 astore(stack,sp + length, Nullstr);
1136 st = stack->ary_array;
1138 Copy(ary->ary_array+offset, st+sp, length, STR*);
1139 if (ary->ary_flags & ARF_REAL) {
1140 for (i = length, dst = st+sp; i; i--)
1141 str_2static(*dst++); /* free them eventualy */
1146 st[sp] = ary->ary_array[offset+length-1];
1147 if (ary->ary_flags & ARF_REAL)
1148 str_2static(st[sp]);
1150 ary->ary_fill += diff;
1152 /* pull up or down? */
1154 if (offset < after) { /* easier to pull up */
1155 if (offset) { /* esp. if nothing to pull */
1156 src = &ary->ary_array[offset-1];
1157 dst = src - diff; /* diff is negative */
1158 for (i = offset; i > 0; i--) /* can't trust Copy */
1161 Zero(ary->ary_array, -diff, STR*);
1162 ary->ary_array -= diff; /* diff is negative */
1163 ary->ary_max += diff;
1166 if (after) { /* anything to pull down? */
1167 src = ary->ary_array + offset + length;
1168 dst = src + diff; /* diff is negative */
1169 Copy(src, dst, after, STR*);
1171 Zero(&ary->ary_array[ary->ary_fill+1], -diff, STR*);
1172 /* avoid later double free */
1175 for (src = tmparyval, dst = ary->ary_array + offset;
1177 *dst = Str_new(46,0);
1178 str_sset(*dst++,*src++);
1180 Safefree(tmparyval);
1183 else { /* no, expanding (or same) */
1185 New(452, tmparyval, length, STR*); /* so remember deletion */
1186 Copy(ary->ary_array+offset, tmparyval, length, STR*);
1189 if (diff > 0) { /* expanding */
1191 /* push up or down? */
1193 if (offset < after && diff <= ary->ary_array - ary->ary_alloc) {
1195 src = ary->ary_array;
1197 Copy(src, dst, offset, STR*);
1199 ary->ary_array -= diff; /* diff is positive */
1200 ary->ary_max += diff;
1201 ary->ary_fill += diff;
1204 if (ary->ary_fill + diff >= ary->ary_max) /* oh, well */
1205 astore(ary, ary->ary_fill + diff, Nullstr);
1207 ary->ary_fill += diff;
1209 dst = ary->ary_array + ary->ary_fill;
1211 for (i = after; i; i--) {
1212 if (*dst) /* str was hanging around */
1213 str_free(*dst); /* after $#foo */
1221 for (src = st+sp, dst = ary->ary_array + offset; newlen; newlen--) {
1222 *dst = Str_new(46,0);
1223 str_sset(*dst++,*src++);
1225 sp = arglast[0] + 1;
1226 if (gimme == G_ARRAY) { /* copy return vals to stack */
1228 Copy(tmparyval, st+sp, length, STR*);
1229 if (ary->ary_flags & ARF_REAL) {
1230 for (i = length, dst = st+sp; i; i--)
1231 str_2static(*dst++); /* free them eventualy */
1233 Safefree(tmparyval);
1238 st[sp] = tmparyval[length-1];
1239 if (ary->ary_flags & ARF_REAL)
1240 str_2static(st[sp]);
1241 Safefree(tmparyval);
1244 st[sp] = &str_undef;
1250 do_grep(arg,str,gimme,arglast)
1256 STR **st = stack->ary_array;
1257 register int dst = arglast[1];
1258 register int src = dst + 1;
1259 register int sp = arglast[2];
1260 register int i = sp - arglast[1];
1261 int oldsave = savestack->ary_fill;
1262 SPAT *oldspat = curspat;
1264 savesptr(&stab_val(defstab));
1265 if ((arg[1].arg_type & A_MASK) != A_EXPR) {
1266 arg[1].arg_type &= A_MASK;
1268 arg[1].arg_type |= A_DONT;
1270 arg = arg[1].arg_ptr.arg_arg;
1273 stab_val(defstab) = st[src];
1275 stab_val(defstab) = str_static(&str_undef);
1276 (void)eval(arg,G_SCALAR,sp);
1277 st = stack->ary_array;
1278 if (str_true(st[sp+1]))
1279 st[dst++] = st[src];
1283 restorelist(oldsave);
1284 if (gimme != G_ARRAY) {
1285 str_numset(str,(double)(dst - arglast[1]));
1287 st[arglast[0]+1] = str;
1288 return arglast[0]+1;
1290 return arglast[0] + (dst - arglast[1]);
1294 do_reverse(str,gimme,arglast)
1299 STR **st = stack->ary_array;
1300 register STR **up = &st[arglast[1]];
1301 register STR **down = &st[arglast[2]];
1302 register int i = arglast[2] - arglast[1];
1304 if (gimme != G_ARRAY) {
1305 str_sset(str,&str_undef);
1307 st[arglast[0]+1] = str;
1308 return arglast[0]+1;
1315 i = arglast[2] - arglast[1];
1316 Copy(down+1,up,i/2,STR*);
1317 return arglast[2] - 1;
1320 static CMD *sortcmd;
1321 static STAB *firststab = Nullstab;
1322 static STAB *secondstab = Nullstab;
1325 do_sort(str,stab,gimme,arglast)
1331 register STR **st = stack->ary_array;
1332 int sp = arglast[1];
1334 register int max = arglast[2] - sp;
1341 static ARRAY *sortstack = Null(ARRAY*);
1343 if (gimme != G_ARRAY) {
1344 str_sset(str,&str_undef);
1350 st += sp; /* temporarily make st point to args */
1351 for (i = 1; i <= max; i++) {
1353 if (!(*up)->str_pok)
1354 (void)str_2ptr(*up);
1362 if (stab_sub(stab) && (sortcmd = stab_sub(stab)->cmd)) {
1363 int oldtmps_base = tmps_base;
1366 sortstack = anew(Nullstab);
1367 sortstack->ary_flags = 0;
1371 tmps_base = tmps_max;
1373 firststab = stabent("a",TRUE);
1374 secondstab = stabent("b",TRUE);
1376 oldfirst = stab_val(firststab);
1377 oldsecond = stab_val(secondstab);
1379 qsort((char*)(st+sp+1),max,sizeof(STR*),sortsub);
1381 qsort(Nullch,max,sizeof(STR*),sortsub);
1383 stab_val(firststab) = oldfirst;
1384 stab_val(secondstab) = oldsecond;
1385 tmps_base = oldtmps_base;
1390 qsort((char*)(st+sp+1),max,sizeof(STR*),sortcmp);
1401 stab_val(firststab) = *str1;
1402 stab_val(secondstab) = *str2;
1403 cmd_exec(sortcmd,G_SCALAR,-1);
1404 return (int)str_gnum(*stack->ary_array);
1407 sortcmp(strp1,strp2)
1411 register STR *str1 = *strp1;
1412 register STR *str2 = *strp2;
1415 if (str1->str_cur < str2->str_cur) {
1416 if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
1421 else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
1423 else if (str1->str_cur == str2->str_cur)
1430 do_range(gimme,arglast)
1434 STR **st = stack->ary_array;
1435 register int sp = arglast[0];
1437 register ARRAY *ary = stack;
1441 if (gimme != G_ARRAY)
1442 fatal("panic: do_range");
1444 if (st[sp+1]->str_nok ||
1445 (looks_like_number(st[sp+1]) && *st[sp+1]->str_ptr != '0') ) {
1446 i = (int)str_gnum(st[sp+1]);
1447 max = (int)str_gnum(st[sp+2]);
1449 (void)astore(ary, ++sp, str = str_static(&str_no));
1450 str_numset(str,(double)i++);
1454 STR *final = str_static(st[sp+2]);
1455 char *tmps = str_get(final);
1457 str = str_static(st[sp+1]);
1458 while (!str->str_nok && str->str_cur <= final->str_cur &&
1459 strNE(str->str_ptr,tmps) ) {
1460 (void)astore(ary, ++sp, str);
1461 str = str_static(str);
1464 if (strEQ(str->str_ptr,tmps))
1465 (void)astore(ary, ++sp, str);
1471 do_tms(str,gimme,arglast)
1476 STR **st = stack->ary_array;
1477 register int sp = arglast[0];
1479 if (gimme != G_ARRAY) {
1480 str_sset(str,&str_undef);
1485 (void)times(×buf);
1492 (void)astore(stack,++sp,
1493 str_2static(str_nmake(((double)timesbuf.tms_utime)/HZ)));
1494 (void)astore(stack,++sp,
1495 str_2static(str_nmake(((double)timesbuf.tms_stime)/HZ)));
1496 (void)astore(stack,++sp,
1497 str_2static(str_nmake(((double)timesbuf.tms_cutime)/HZ)));
1498 (void)astore(stack,++sp,
1499 str_2static(str_nmake(((double)timesbuf.tms_cstime)/HZ)));
1501 (void)astore(stack,++sp,
1502 str_2static(str_nmake(0.0)));
1508 do_time(str,tmbuf,gimme,arglast)
1514 register ARRAY *ary = stack;
1515 STR **st = ary->ary_array;
1516 register int sp = arglast[0];
1518 if (!tmbuf || gimme != G_ARRAY) {
1519 str_sset(str,&str_undef);
1524 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_sec)));
1525 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_min)));
1526 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_hour)));
1527 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_mday)));
1528 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_mon)));
1529 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_year)));
1530 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_wday)));
1531 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_yday)));
1532 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_isdst)));
1537 do_kv(str,hash,kv,gimme,arglast)
1544 register ARRAY *ary = stack;
1545 STR **st = ary->ary_array;
1546 register int sp = arglast[0];
1548 register HENT *entry;
1551 int dokeys = (kv == O_KEYS || kv == O_HASH);
1552 int dovalues = (kv == O_VALUES || kv == O_HASH);
1554 if (gimme != G_ARRAY) {
1555 str_sset(str,&str_undef);
1560 (void)hiterinit(hash);
1561 while (entry = hiternext(hash)) {
1563 tmps = hiterkey(entry,&i);
1566 (void)astore(ary,++sp,str_2static(str_make(tmps,i)));
1569 tmpstr = Str_new(45,0);
1572 sprintf(buf,"%d%%%d=%d\n",entry->hent_hash,
1573 hash->tbl_max+1,entry->hent_hash & hash->tbl_max);
1574 str_set(tmpstr,buf);
1578 str_sset(tmpstr,hiterval(hash,entry));
1579 (void)astore(ary,++sp,str_2static(tmpstr));
1586 do_each(str,hash,gimme,arglast)
1592 STR **st = stack->ary_array;
1593 register int sp = arglast[0];
1594 static STR *mystrk = Nullstr;
1595 HENT *entry = hiternext(hash);
1605 if (gimme == G_ARRAY) {
1606 tmps = hiterkey(entry, &i);
1609 st[++sp] = mystrk = str_make(tmps,i);
1612 str_sset(str,hiterval(hash,entry));