perl 3.0 patch #2 (combined patch)
[p5sagit/p5-mst-13.2.git] / dolist.c
CommitLineData
03a14243 1/* $Header: dolist.c,v 3.0.1.1 89/10/26 23:11:51 lwall Locked $
a687059c 2 *
3 * Copyright (c) 1989, Larry Wall
4 *
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.
7 *
8 * $Log: dolist.c,v $
03a14243 9 * Revision 3.0.1.1 89/10/26 23:11:51 lwall
10 * patch1: split in a subroutine wrongly freed referenced arguments
11 * patch1: reverse didn't work
12 *
a687059c 13 * Revision 3.0 89/10/18 15:11:02 lwall
14 * 3.0 baseline
15 *
16 */
17
18#include "EXTERN.h"
19#include "perl.h"
20
21
22int
23do_match(str,arg,gimme,arglast)
24STR *str;
25register ARG *arg;
26int gimme;
27int *arglast;
28{
29 register STR **st = stack->ary_array;
30 register SPAT *spat = arg[2].arg_ptr.arg_spat;
31 register char *t;
32 register int sp = arglast[0] + 1;
33 STR *srchstr = st[sp];
34 register char *s = str_get(st[sp]);
35 char *strend = s + st[sp]->str_cur;
36 STR *tmpstr;
37
38 if (!spat) {
39 if (gimme == G_ARRAY)
40 return --sp;
41 str_set(str,Yes);
42 STABSET(str);
43 st[sp] = str;
44 return sp;
45 }
46 if (!s)
47 fatal("panic: do_match");
48 if (spat->spat_flags & SPAT_USED) {
49#ifdef DEBUGGING
50 if (debug & 8)
51 deb("2.SPAT USED\n");
52#endif
53 if (gimme == G_ARRAY)
54 return --sp;
55 str_set(str,No);
56 STABSET(str);
57 st[sp] = str;
58 return sp;
59 }
60 --sp;
61 if (spat->spat_runtime) {
62 nointrp = "|)";
63 sp = eval(spat->spat_runtime,G_SCALAR,sp);
64 st = stack->ary_array;
65 t = str_get(tmpstr = st[sp--]);
66 nointrp = "";
67#ifdef DEBUGGING
68 if (debug & 8)
69 deb("2.SPAT /%s/\n",t);
70#endif
71 if (spat->spat_regexp)
72 regfree(spat->spat_regexp);
73 spat->spat_regexp = regcomp(t,t+tmpstr->str_cur,
74 spat->spat_flags & SPAT_FOLD,1);
75 if (!*spat->spat_regexp->precomp && lastspat)
76 spat = lastspat;
77 if (spat->spat_flags & SPAT_KEEP) {
78 arg_free(spat->spat_runtime); /* it won't change, so */
79 spat->spat_runtime = Nullarg; /* no point compiling again */
80 }
81 if (!spat->spat_regexp->nparens)
82 gimme = G_SCALAR; /* accidental array context? */
83 if (regexec(spat->spat_regexp, s, strend, s, 0,
84 srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
85 gimme == G_ARRAY)) {
86 if (spat->spat_regexp->subbase)
87 curspat = spat;
88 lastspat = spat;
89 goto gotcha;
90 }
91 else {
92 if (gimme == G_ARRAY)
93 return sp;
94 str_sset(str,&str_no);
95 STABSET(str);
96 st[++sp] = str;
97 return sp;
98 }
99 }
100 else {
101#ifdef DEBUGGING
102 if (debug & 8) {
103 char ch;
104
105 if (spat->spat_flags & SPAT_ONCE)
106 ch = '?';
107 else
108 ch = '/';
109 deb("2.SPAT %c%s%c\n",ch,spat->spat_regexp->precomp,ch);
110 }
111#endif
112 if (!*spat->spat_regexp->precomp && lastspat)
113 spat = lastspat;
114 t = s;
115 if (hint) {
116 if (hint < s || hint > strend)
117 fatal("panic: hint in do_match");
118 s = hint;
119 hint = Nullch;
120 if (spat->spat_regexp->regback >= 0) {
121 s -= spat->spat_regexp->regback;
122 if (s < t)
123 s = t;
124 }
125 else
126 s = t;
127 }
128 else if (spat->spat_short) {
129 if (spat->spat_flags & SPAT_SCANFIRST) {
130 if (srchstr->str_pok & SP_STUDIED) {
131 if (screamfirst[spat->spat_short->str_rare] < 0)
132 goto nope;
133 else if (!(s = screaminstr(srchstr,spat->spat_short)))
134 goto nope;
135 else if (spat->spat_flags & SPAT_ALL)
136 goto yup;
137 }
138#ifndef lint
139 else if (!(s = fbminstr((unsigned char*)s,
140 (unsigned char*)strend, spat->spat_short)))
141 goto nope;
142#endif
143 else if (spat->spat_flags & SPAT_ALL)
144 goto yup;
145 if (s && spat->spat_regexp->regback >= 0) {
146 ++spat->spat_short->str_u.str_useful;
147 s -= spat->spat_regexp->regback;
148 if (s < t)
149 s = t;
150 }
151 else
152 s = t;
153 }
154 else if (!multiline && (*spat->spat_short->str_ptr != *s ||
155 bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) ))
156 goto nope;
157 if (--spat->spat_short->str_u.str_useful < 0) {
158 str_free(spat->spat_short);
159 spat->spat_short = Nullstr; /* opt is being useless */
160 }
161 }
162 if (!spat->spat_regexp->nparens)
163 gimme = G_SCALAR; /* accidental array context? */
164 if (regexec(spat->spat_regexp, s, strend, t, 0,
165 srchstr->str_pok & SP_STUDIED ? srchstr : Nullstr,
166 gimme == G_ARRAY)) {
167 if (spat->spat_regexp->subbase)
168 curspat = spat;
169 lastspat = spat;
170 if (spat->spat_flags & SPAT_ONCE)
171 spat->spat_flags |= SPAT_USED;
172 goto gotcha;
173 }
174 else {
175 if (gimme == G_ARRAY)
176 return sp;
177 str_sset(str,&str_no);
178 STABSET(str);
179 st[++sp] = str;
180 return sp;
181 }
182 }
183 /*NOTREACHED*/
184
185 gotcha:
186 if (gimme == G_ARRAY) {
187 int iters, i, len;
188
189 iters = spat->spat_regexp->nparens;
190 if (sp + iters >= stack->ary_max) {
191 astore(stack,sp + iters, Nullstr);
192 st = stack->ary_array; /* possibly realloced */
193 }
194
195 for (i = 1; i <= iters; i++) {
196 st[++sp] = str_static(&str_no);
197 if (s = spat->spat_regexp->startp[i]) {
198 len = spat->spat_regexp->endp[i] - s;
199 if (len > 0)
200 str_nset(st[sp],s,len);
201 }
202 }
203 return sp;
204 }
205 else {
206 str_sset(str,&str_yes);
207 STABSET(str);
208 st[++sp] = str;
209 return sp;
210 }
211
212yup:
213 ++spat->spat_short->str_u.str_useful;
214 lastspat = spat;
215 if (spat->spat_flags & SPAT_ONCE)
216 spat->spat_flags |= SPAT_USED;
217 if (sawampersand) {
218 char *tmps;
219
220 tmps = spat->spat_regexp->subbase = nsavestr(t,strend-t);
221 tmps = spat->spat_regexp->startp[0] = tmps + (s - t);
222 spat->spat_regexp->endp[0] = tmps + spat->spat_short->str_cur;
223 curspat = spat;
224 }
225 str_sset(str,&str_yes);
226 STABSET(str);
227 st[++sp] = str;
228 return sp;
229
230nope:
231 ++spat->spat_short->str_u.str_useful;
232 if (gimme == G_ARRAY)
233 return sp;
234 str_sset(str,&str_no);
235 STABSET(str);
236 st[++sp] = str;
237 return sp;
238}
239
240int
241do_split(str,spat,limit,gimme,arglast)
242STR *str;
243register SPAT *spat;
244register int limit;
245int gimme;
246int *arglast;
247{
248 register ARRAY *ary = stack;
249 STR **st = ary->ary_array;
250 register int sp = arglast[0] + 1;
251 register char *s = str_get(st[sp]);
252 char *strend = s + st[sp--]->str_cur;
253 register STR *dstr;
254 register char *m;
255 int iters = 0;
256 int i;
257 char *orig;
258 int origlimit = limit;
259 int realarray = 0;
260
261 if (!spat || !s)
262 fatal("panic: do_split");
263 else if (spat->spat_runtime) {
264 nointrp = "|)";
265 sp = eval(spat->spat_runtime,G_SCALAR,sp);
266 st = stack->ary_array;
267 m = str_get(dstr = st[sp--]);
268 nointrp = "";
269 if (!dstr->str_cur || (*m == ' ' && dstr->str_cur == 1)) {
270 str_set(dstr,"\\s+");
271 m = dstr->str_ptr;
272 spat->spat_flags |= SPAT_SKIPWHITE;
273 }
274 if (spat->spat_regexp)
275 regfree(spat->spat_regexp);
276 spat->spat_regexp = regcomp(m,m+dstr->str_cur,
277 spat->spat_flags & SPAT_FOLD,1);
278 if (spat->spat_flags & SPAT_KEEP ||
279 (spat->spat_runtime->arg_type == O_ITEM &&
280 (spat->spat_runtime[1].arg_type & A_MASK) == A_SINGLE) ) {
281 arg_free(spat->spat_runtime); /* it won't change, so */
282 spat->spat_runtime = Nullarg; /* no point compiling again */
283 }
284 }
285#ifdef DEBUGGING
286 if (debug & 8) {
287 deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
288 }
289#endif
290 ary = stab_xarray(spat->spat_repl[1].arg_ptr.arg_stab);
291 if (ary && ((ary->ary_flags & ARF_REAL) || gimme != G_ARRAY)) {
a687059c 292 realarray = 1;
03a14243 293 if (!(ary->ary_flags & ARF_REAL)) {
294 ary->ary_flags |= ARF_REAL;
295 for (i = ary->ary_fill; i >= 0; i--)
296 ary->ary_array[i] = Nullstr; /* don't free mere refs */
297 }
a687059c 298 ary->ary_fill = -1;
299 sp = -1; /* temporarily switch stacks */
300 }
301 else
302 ary = stack;
303 orig = s;
304 if (spat->spat_flags & SPAT_SKIPWHITE) {
305 while (isspace(*s))
306 s++;
307 }
308 if (!limit)
309 limit = 10001;
310 if (spat->spat_short) {
311 i = spat->spat_short->str_cur;
312 if (i == 1) {
313 i = *spat->spat_short->str_ptr;
314 while (--limit) {
315 for (m = s; m < strend && *m != i; m++) ;
316 if (m >= strend)
317 break;
318 if (realarray)
319 dstr = Str_new(30,m-s);
320 else
321 dstr = str_static(&str_undef);
322 str_nset(dstr,s,m-s);
323 (void)astore(ary, ++sp, dstr);
324 s = m + 1;
325 }
326 }
327 else {
328#ifndef lint
329 while (s < strend && --limit &&
330 (m=fbminstr((unsigned char*)s, (unsigned char*)strend,
331 spat->spat_short)) )
332#endif
333 {
334 if (realarray)
335 dstr = Str_new(31,m-s);
336 else
337 dstr = str_static(&str_undef);
338 str_nset(dstr,s,m-s);
339 (void)astore(ary, ++sp, dstr);
340 s = m + i;
341 }
342 }
343 }
344 else {
345 while (s < strend && --limit &&
346 regexec(spat->spat_regexp, s, strend, orig, 1, Nullstr, TRUE) ) {
347 if (spat->spat_regexp->subbase
348 && spat->spat_regexp->subbase != orig) {
349 m = s;
350 s = orig;
351 orig = spat->spat_regexp->subbase;
352 s = orig + (m - s);
353 strend = s + (strend - m);
354 }
355 m = spat->spat_regexp->startp[0];
356 if (realarray)
357 dstr = Str_new(32,m-s);
358 else
359 dstr = str_static(&str_undef);
360 str_nset(dstr,s,m-s);
361 (void)astore(ary, ++sp, dstr);
362 if (spat->spat_regexp->nparens) {
363 for (i = 1; i <= spat->spat_regexp->nparens; i++) {
364 s = spat->spat_regexp->startp[i];
365 m = spat->spat_regexp->endp[i];
366 if (realarray)
367 dstr = Str_new(33,m-s);
368 else
369 dstr = str_static(&str_undef);
370 str_nset(dstr,s,m-s);
371 (void)astore(ary, ++sp, dstr);
372 }
373 }
374 s = spat->spat_regexp->endp[0];
375 }
376 }
377 if (realarray)
378 iters = sp + 1;
379 else
380 iters = sp - arglast[0];
381 if (iters > 9999)
382 fatal("Split loop");
383 if (s < strend || origlimit) { /* keep field after final delim? */
384 if (realarray)
385 dstr = Str_new(34,strend-s);
386 else
387 dstr = str_static(&str_undef);
388 str_nset(dstr,s,strend-s);
389 (void)astore(ary, ++sp, dstr);
390 iters++;
391 }
392 else {
393#ifndef I286
394 while (iters > 0 && ary->ary_array[sp]->str_cur == 0)
395 iters--,sp--;
396#else
397 char *zaps;
398 int zapb;
399
400 if (iters > 0) {
401 zaps = str_get(afetch(ary,sp,FALSE));
402 zapb = (int) *zaps;
403 }
404
405 while (iters > 0 && (!zapb)) {
406 iters--,sp--;
407 if (iters > 0) {
408 zaps = str_get(afetch(ary,iters-1,FALSE));
409 zapb = (int) *zaps;
410 }
411 }
412#endif
413 }
414 if (realarray) {
415 ary->ary_fill = sp;
416 if (gimme == G_ARRAY) {
417 sp++;
418 astore(stack, arglast[0] + 1 + sp, Nullstr);
419 Copy(ary->ary_array, stack->ary_array + arglast[0] + 1, sp, STR*);
420 return arglast[0] + sp;
421 }
422 }
423 else {
424 if (gimme == G_ARRAY)
425 return sp;
426 }
427 sp = arglast[0] + 1;
428 str_numset(str,(double)iters);
429 STABSET(str);
430 st[sp] = str;
431 return sp;
432}
433
434int
435do_unpack(str,gimme,arglast)
436STR *str;
437int gimme;
438int *arglast;
439{
440 STR **st = stack->ary_array;
441 register int sp = arglast[0] + 1;
442 register char *pat = str_get(st[sp++]);
443 register char *s = str_get(st[sp]);
444 char *strend = s + st[sp--]->str_cur;
445 register char *patend = pat + st[sp]->str_cur;
446 int datumtype;
447 register int len;
448
449 /* These must not be in registers: */
450 char achar;
451 short ashort;
452 int aint;
453 long along;
454 unsigned char auchar;
455 unsigned short aushort;
456 unsigned int auint;
457 unsigned long aulong;
458 char *aptr;
459
460 if (gimme != G_ARRAY) {
461 str_sset(str,&str_undef);
462 STABSET(str);
463 st[sp] = str;
464 return sp;
465 }
466 sp--;
467 while (pat < patend) {
468 datumtype = *pat++;
469 if (isdigit(*pat)) {
470 len = atoi(pat);
471 while (isdigit(*pat))
472 pat++;
473 }
474 else
475 len = 1;
476 switch(datumtype) {
477 default:
478 break;
479 case 'x':
480 s += len;
481 break;
482 case 'A':
483 case 'a':
484 if (s + len > strend)
485 len = strend - s;
486 str = Str_new(35,len);
487 str_nset(str,s,len);
488 s += len;
489 if (datumtype == 'A') {
490 aptr = s; /* borrow register */
491 s = str->str_ptr + len - 1;
492 while (s >= str->str_ptr && (!*s || isspace(*s)))
493 s--;
494 *++s = '\0';
495 str->str_cur = s - str->str_ptr;
496 s = aptr; /* unborrow register */
497 }
498 (void)astore(stack, ++sp, str_2static(str));
499 break;
500 case 'c':
501 while (len-- > 0) {
502 if (s + sizeof(char) > strend)
503 achar = 0;
504 else {
505 bcopy(s,(char*)&achar,sizeof(char));
506 s += sizeof(char);
507 }
508 str = Str_new(36,0);
509 aint = achar;
510 if (aint >= 128) /* fake up signed chars */
511 aint -= 256;
512 str_numset(str,(double)aint);
513 (void)astore(stack, ++sp, str_2static(str));
514 }
515 break;
516 case 'C':
517 while (len-- > 0) {
518 if (s + sizeof(unsigned char) > strend)
519 auchar = 0;
520 else {
521 bcopy(s,(char*)&auchar,sizeof(unsigned char));
522 s += sizeof(unsigned char);
523 }
524 str = Str_new(37,0);
525 auint = auchar; /* some can't cast uchar to double */
526 str_numset(str,(double)auint);
527 (void)astore(stack, ++sp, str_2static(str));
528 }
529 break;
530 case 's':
531 while (len-- > 0) {
532 if (s + sizeof(short) > strend)
533 ashort = 0;
534 else {
535 bcopy(s,(char*)&ashort,sizeof(short));
536 s += sizeof(short);
537 }
538 str = Str_new(38,0);
539 str_numset(str,(double)ashort);
540 (void)astore(stack, ++sp, str_2static(str));
541 }
542 break;
543 case 'n':
544 case 'S':
545 while (len-- > 0) {
546 if (s + sizeof(unsigned short) > strend)
547 aushort = 0;
548 else {
549 bcopy(s,(char*)&aushort,sizeof(unsigned short));
550 s += sizeof(unsigned short);
551 }
552 str = Str_new(39,0);
553#ifdef NTOHS
554 if (datumtype == 'n')
555 aushort = ntohs(aushort);
556#endif
557 str_numset(str,(double)aushort);
558 (void)astore(stack, ++sp, str_2static(str));
559 }
560 break;
561 case 'i':
562 while (len-- > 0) {
563 if (s + sizeof(int) > strend)
564 aint = 0;
565 else {
566 bcopy(s,(char*)&aint,sizeof(int));
567 s += sizeof(int);
568 }
569 str = Str_new(40,0);
570 str_numset(str,(double)aint);
571 (void)astore(stack, ++sp, str_2static(str));
572 }
573 break;
574 case 'I':
575 while (len-- > 0) {
576 if (s + sizeof(unsigned int) > strend)
577 auint = 0;
578 else {
579 bcopy(s,(char*)&auint,sizeof(unsigned int));
580 s += sizeof(unsigned int);
581 }
582 str = Str_new(41,0);
583 str_numset(str,(double)auint);
584 (void)astore(stack, ++sp, str_2static(str));
585 }
586 break;
587 case 'l':
588 while (len-- > 0) {
589 if (s + sizeof(long) > strend)
590 along = 0;
591 else {
592 bcopy(s,(char*)&along,sizeof(long));
593 s += sizeof(long);
594 }
595 str = Str_new(42,0);
596 str_numset(str,(double)along);
597 (void)astore(stack, ++sp, str_2static(str));
598 }
599 break;
600 case 'N':
601 case 'L':
602 while (len-- > 0) {
603 if (s + sizeof(unsigned long) > strend)
604 aulong = 0;
605 else {
606 bcopy(s,(char*)&aulong,sizeof(unsigned long));
607 s += sizeof(unsigned long);
608 }
609 str = Str_new(43,0);
610#ifdef NTOHL
611 if (datumtype == 'N')
612 aulong = ntohl(aulong);
613#endif
614 str_numset(str,(double)aulong);
615 (void)astore(stack, ++sp, str_2static(str));
616 }
617 break;
618 case 'p':
619 while (len-- > 0) {
620 if (s + sizeof(char*) > strend)
621 aptr = 0;
622 else {
623 bcopy(s,(char*)&aptr,sizeof(char*));
624 s += sizeof(char*);
625 }
626 str = Str_new(44,0);
627 if (aptr)
628 str_set(str,aptr);
629 (void)astore(stack, ++sp, str_2static(str));
630 }
631 break;
632 }
633 }
634 return sp;
635}
636
637int
638do_slice(stab,numarray,lval,gimme,arglast)
639register STAB *stab;
640int numarray;
641int lval;
642int gimme;
643int *arglast;
644{
645 register STR **st = stack->ary_array;
646 register int sp = arglast[1];
647 register int max = arglast[2];
648 register char *tmps;
649 register int len;
650 register int magic = 0;
651
652 if (lval && !numarray) {
653 if (stab == envstab)
654 magic = 'E';
655 else if (stab == sigstab)
656 magic = 'S';
657#ifdef SOME_DBM
658 else if (stab_hash(stab)->tbl_dbm)
659 magic = 'D';
660#endif /* SOME_DBM */
661 }
662
663 if (gimme == G_ARRAY) {
664 if (numarray) {
665 while (sp < max) {
666 if (st[++sp]) {
667 st[sp-1] = afetch(stab_array(stab),(int)str_gnum(st[sp]),
668 lval);
669 }
670 else
671 st[sp-1] = Nullstr;
672 }
673 }
674 else {
675 while (sp < max) {
676 if (st[++sp]) {
677 tmps = str_get(st[sp]);
678 len = st[sp]->str_cur;
679 st[sp-1] = hfetch(stab_hash(stab),tmps,len, lval);
680 if (magic)
681 str_magic(st[sp-1],stab,magic,tmps,len);
682 }
683 else
684 st[sp-1] = Nullstr;
685 }
686 }
687 sp--;
688 }
689 else {
690 if (numarray) {
691 if (st[max])
692 st[sp] = afetch(stab_array(stab),(int)str_gnum(st[max]), lval);
693 else
694 st[sp] = Nullstr;
695 }
696 else {
697 if (st[max]) {
698 tmps = str_get(st[max]);
699 len = st[max]->str_cur;
700 st[sp] = hfetch(stab_hash(stab),tmps,len, lval);
701 if (magic)
702 str_magic(st[sp],stab,magic,tmps,len);
703 }
704 else
705 st[sp] = Nullstr;
706 }
707 }
708 return sp;
709}
710
711int
712do_grep(arg,str,gimme,arglast)
713register ARG *arg;
714STR *str;
715int gimme;
716int *arglast;
717{
718 STR **st = stack->ary_array;
719 register STR **dst = &st[arglast[1]];
720 register STR **src = dst + 1;
721 register int sp = arglast[2];
722 register int i = sp - arglast[1];
723 int oldsave = savestack->ary_fill;
724
725 savesptr(&stab_val(defstab));
726 if ((arg[1].arg_type & A_MASK) != A_EXPR)
727 dehoist(arg,1);
728 arg = arg[1].arg_ptr.arg_arg;
729 while (i-- > 0) {
730 stab_val(defstab) = *src;
731 (void)eval(arg,G_SCALAR,sp);
732 if (str_true(st[sp+1]))
733 *dst++ = *src;
734 src++;
735 }
736 restorelist(oldsave);
737 if (gimme != G_ARRAY) {
738 str_sset(str,&str_undef);
739 STABSET(str);
740 st[arglast[0]+1] = str;
741 return arglast[0]+1;
742 }
743 return arglast[0] + (dst - &st[arglast[1]]);
744}
745
746int
747do_reverse(str,gimme,arglast)
748STR *str;
749int gimme;
750int *arglast;
751{
752 STR **st = stack->ary_array;
753 register STR **up = &st[arglast[1]];
754 register STR **down = &st[arglast[2]];
755 register int i = arglast[2] - arglast[1];
756
757 if (gimme != G_ARRAY) {
758 str_sset(str,&str_undef);
759 STABSET(str);
760 st[arglast[0]+1] = str;
761 return arglast[0]+1;
762 }
763 while (i-- > 0) {
764 *up++ = *down;
03a14243 765 if (i-- > 0)
766 *down-- = *up;
a687059c 767 }
03a14243 768 i = arglast[2] - arglast[1];
769 Copy(down+1,up,i/2,STR*);
a687059c 770 return arglast[2] - 1;
771}
772
773static CMD *sortcmd;
774static STAB *firststab = Nullstab;
775static STAB *secondstab = Nullstab;
776
777int
778do_sort(str,stab,gimme,arglast)
779STR *str;
780STAB *stab;
781int gimme;
782int *arglast;
783{
784 STR **st = stack->ary_array;
785 int sp = arglast[1];
786 register STR **up;
787 register int max = arglast[2] - sp;
788 register int i;
789 int sortcmp();
790 int sortsub();
791 STR *oldfirst;
792 STR *oldsecond;
793 ARRAY *oldstack;
794 static ARRAY *sortstack = Null(ARRAY*);
795
796 if (gimme != G_ARRAY) {
797 str_sset(str,&str_undef);
798 STABSET(str);
799 st[sp] = str;
800 return sp;
801 }
802 up = &st[sp];
803 for (i = 0; i < max; i++) {
804 if ((*up = up[1]) && !(*up)->str_pok)
805 (void)str_2ptr(*up);
806 up++;
807 }
808 sp--;
809 if (max > 1) {
810 if (stab_sub(stab) && (sortcmd = stab_sub(stab)->cmd)) {
811 int oldtmps_base = tmps_base;
812
813 if (!sortstack) {
814 sortstack = anew(Nullstab);
815 sortstack->ary_flags = 0;
816 }
817 oldstack = stack;
818 stack = sortstack;
819 tmps_base = tmps_max;
820 if (!firststab) {
821 firststab = stabent("a",TRUE);
822 secondstab = stabent("b",TRUE);
823 }
824 oldfirst = stab_val(firststab);
825 oldsecond = stab_val(secondstab);
826#ifndef lint
827 qsort((char*)(st+sp+1),max,sizeof(STR*),sortsub);
828#else
829 qsort(Nullch,max,sizeof(STR*),sortsub);
830#endif
831 stab_val(firststab) = oldfirst;
832 stab_val(secondstab) = oldsecond;
833 tmps_base = oldtmps_base;
834 stack = oldstack;
835 }
836#ifndef lint
837 else
838 qsort((char*)(st+sp+1),max,sizeof(STR*),sortcmp);
839#endif
840 }
841 up = &st[arglast[1]];
842 while (max > 0 && !*up)
843 max--,up--;
844 return sp+max;
845}
846
847int
848sortsub(str1,str2)
849STR **str1;
850STR **str2;
851{
852 if (!*str1)
853 return -1;
854 if (!*str2)
855 return 1;
856 stab_val(firststab) = *str1;
857 stab_val(secondstab) = *str2;
858 cmd_exec(sortcmd,G_SCALAR,-1);
859 return (int)str_gnum(*stack->ary_array);
860}
861
862sortcmp(strp1,strp2)
863STR **strp1;
864STR **strp2;
865{
866 register STR *str1 = *strp1;
867 register STR *str2 = *strp2;
868 int retval;
869
870 if (!str1)
871 return -1;
872 if (!str2)
873 return 1;
874
875 if (str1->str_cur < str2->str_cur) {
876 if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
877 return retval;
878 else
879 return -1;
880 }
881 else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
882 return retval;
883 else if (str1->str_cur == str2->str_cur)
884 return 0;
885 else
886 return 1;
887}
888
889int
890do_range(gimme,arglast)
891int gimme;
892int *arglast;
893{
894 STR **st = stack->ary_array;
895 register int sp = arglast[0];
896 register int i = (int)str_gnum(st[sp+1]);
897 register ARRAY *ary = stack;
898 register STR *str;
899 int max = (int)str_gnum(st[sp+2]);
900
901 if (gimme != G_ARRAY)
902 fatal("panic: do_range");
903
904 while (i <= max) {
905 (void)astore(ary, ++sp, str = str_static(&str_no));
906 str_numset(str,(double)i++);
907 }
908 return sp;
909}
910
911int
912do_tms(str,gimme,arglast)
913STR *str;
914int gimme;
915int *arglast;
916{
917 STR **st = stack->ary_array;
918 register int sp = arglast[0];
919
920 if (gimme != G_ARRAY) {
921 str_sset(str,&str_undef);
922 STABSET(str);
923 st[++sp] = str;
924 return sp;
925 }
926 (void)times(&timesbuf);
927
928#ifndef HZ
929#define HZ 60
930#endif
931
932#ifndef lint
933 (void)astore(stack,++sp,
934 str_2static(str_nmake(((double)timesbuf.tms_utime)/HZ)));
935 (void)astore(stack,++sp,
936 str_2static(str_nmake(((double)timesbuf.tms_stime)/HZ)));
937 (void)astore(stack,++sp,
938 str_2static(str_nmake(((double)timesbuf.tms_cutime)/HZ)));
939 (void)astore(stack,++sp,
940 str_2static(str_nmake(((double)timesbuf.tms_cstime)/HZ)));
941#else
942 (void)astore(stack,++sp,
943 str_2static(str_nmake(0.0)));
944#endif
945 return sp;
946}
947
948int
949do_time(str,tmbuf,gimme,arglast)
950STR *str;
951struct tm *tmbuf;
952int gimme;
953int *arglast;
954{
955 register ARRAY *ary = stack;
956 STR **st = ary->ary_array;
957 register int sp = arglast[0];
958
959 if (!tmbuf || gimme != G_ARRAY) {
960 str_sset(str,&str_undef);
961 STABSET(str);
962 st[++sp] = str;
963 return sp;
964 }
965 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_sec)));
966 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_min)));
967 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_hour)));
968 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_mday)));
969 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_mon)));
970 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_year)));
971 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_wday)));
972 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_yday)));
973 (void)astore(ary,++sp,str_2static(str_nmake((double)tmbuf->tm_isdst)));
974 return sp;
975}
976
977int
978do_kv(str,hash,kv,gimme,arglast)
979STR *str;
980HASH *hash;
981int kv;
982int gimme;
983int *arglast;
984{
985 register ARRAY *ary = stack;
986 STR **st = ary->ary_array;
987 register int sp = arglast[0];
988 int i;
989 register HENT *entry;
990 char *tmps;
991 STR *tmpstr;
992 int dokeys = (kv == O_KEYS || kv == O_HASH);
993 int dovalues = (kv == O_VALUES || kv == O_HASH);
994
995 if (gimme != G_ARRAY) {
996 str_sset(str,&str_undef);
997 STABSET(str);
998 st[++sp] = str;
999 return sp;
1000 }
1001 (void)hiterinit(hash);
1002 while (entry = hiternext(hash)) {
1003 if (dokeys) {
1004 tmps = hiterkey(entry,&i);
1005 (void)astore(ary,++sp,str_2static(str_make(tmps,i)));
1006 }
1007 if (dovalues) {
1008 tmpstr = Str_new(45,0);
1009#ifdef DEBUGGING
1010 if (debug & 8192) {
1011 sprintf(buf,"%d%%%d=%d\n",entry->hent_hash,
1012 hash->tbl_max+1,entry->hent_hash & hash->tbl_max);
1013 str_set(tmpstr,buf);
1014 }
1015 else
1016#endif
1017 str_sset(tmpstr,hiterval(hash,entry));
1018 (void)astore(ary,++sp,str_2static(tmpstr));
1019 }
1020 }
1021 return sp;
1022}
1023
1024int
1025do_each(str,hash,gimme,arglast)
1026STR *str;
1027HASH *hash;
1028int gimme;
1029int *arglast;
1030{
1031 STR **st = stack->ary_array;
1032 register int sp = arglast[0];
1033 static STR *mystrk = Nullstr;
1034 HENT *entry = hiternext(hash);
1035 int i;
1036 char *tmps;
1037
1038 if (mystrk) {
1039 str_free(mystrk);
1040 mystrk = Nullstr;
1041 }
1042
1043 if (entry) {
1044 if (gimme == G_ARRAY) {
1045 tmps = hiterkey(entry, &i);
1046 st[++sp] = mystrk = str_make(tmps,i);
1047 }
1048 st[++sp] = str;
1049 str_sset(str,hiterval(hash,entry));
1050 STABSET(str);
1051 return sp;
1052 }
1053 else
1054 return sp;
1055}