perl 3.0 patch #21 patch #19, continued
[perl.git] / doarg.c
1 /* $Header: doarg.c,v 3.0.1.6 90/08/09 02:48:38 lwall Locked $
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:        doarg.c,v $
9  * Revision 3.0.1.6  90/08/09  02:48:38  lwall
10  * patch19: fixed double include of <signal.h>
11  * patch19: pack/unpack can now do native float and double
12  * patch19: pack/unpack can now have absolute and negative positioning
13  * patch19: pack/unpack can now have use * to specify all the rest of input
14  * patch19: unpack can do checksumming
15  * patch19: $< and $> better supported on machines without setreuid
16  * patch19: Added support for linked-in C subroutines
17  * 
18  * Revision 3.0.1.5  90/03/27  15:39:03  lwall
19  * patch16: MSDOS support
20  * patch16: support for machines that can't cast negative floats to unsigned ints
21  * patch16: sprintf($s,...,$s,...) didn't work
22  * 
23  * Revision 3.0.1.4  90/03/12  16:28:42  lwall
24  * patch13: pack of ascii strings could call str_ncat() with negative length
25  * patch13: printf("%s", *foo) was busted
26  * 
27  * Revision 3.0.1.3  90/02/28  16:56:58  lwall
28  * patch9: split now can split into more than 10000 elements
29  * patch9: sped up pack and unpack
30  * patch9: pack of unsigned ints and longs blew up some places
31  * patch9: sun3 can't cast negative float to unsigned int or long
32  * patch9: local($.) didn't work
33  * patch9: grep(s/foo/bar/, @abc = @xyz) modified @xyz rather than @abc
34  * patch9: syscall returned stack size rather than value of system call
35  * 
36  * Revision 3.0.1.2  89/12/21  19:52:15  lwall
37  * patch7: a pattern wouldn't match a null string before the first character
38  * patch7: certain patterns didn't match correctly at end of string
39  * 
40  * Revision 3.0.1.1  89/11/11  04:17:20  lwall
41  * patch2: printf %c, %D, %X and %O didn't work right
42  * patch2: printf of unsigned vs signed needed separate casts on some machines
43  * 
44  * Revision 3.0  89/10/18  15:10:41  lwall
45  * 3.0 baseline
46  * 
47  */
48
49 #include "EXTERN.h"
50 #include "perl.h"
51
52 #ifndef NSIG
53 #include <signal.h>
54 #endif
55
56 extern unsigned char fold[];
57
58 int wantarray;
59
60 #ifdef BUGGY_MSC
61  #pragma function(memcmp)
62 #endif /* BUGGY_MSC */
63
64 int
65 do_subst(str,arg,sp)
66 STR *str;
67 ARG *arg;
68 int sp;
69 {
70     register SPAT *spat;
71     SPAT *rspat;
72     register STR *dstr;
73     register char *s = str_get(str);
74     char *strend = s + str->str_cur;
75     register char *m;
76     char *c;
77     register char *d;
78     int clen;
79     int iters = 0;
80     int maxiters = (strend - s) + 10;
81     register int i;
82     bool once;
83     char *orig;
84     int safebase;
85
86     rspat = spat = arg[2].arg_ptr.arg_spat;
87     if (!spat || !s)
88         fatal("panic: do_subst");
89     else if (spat->spat_runtime) {
90         nointrp = "|)";
91         (void)eval(spat->spat_runtime,G_SCALAR,sp);
92         m = str_get(dstr = stack->ary_array[sp+1]);
93         nointrp = "";
94         if (spat->spat_regexp)
95             regfree(spat->spat_regexp);
96         spat->spat_regexp = regcomp(m,m+dstr->str_cur,
97             spat->spat_flags & SPAT_FOLD);
98         if (spat->spat_flags & SPAT_KEEP) {
99             arg_free(spat->spat_runtime);       /* it won't change, so */
100             spat->spat_runtime = Nullarg;       /* no point compiling again */
101         }
102     }
103 #ifdef DEBUGGING
104     if (debug & 8) {
105         deb("2.SPAT /%s/\n",spat->spat_regexp->precomp);
106     }
107 #endif
108     safebase = ((!spat->spat_regexp || !spat->spat_regexp->nparens) &&
109       !sawampersand);
110     if (!*spat->spat_regexp->precomp && lastspat)
111         spat = lastspat;
112     orig = m = s;
113     if (hint) {
114         if (hint < s || hint > strend)
115             fatal("panic: hint in do_match");
116         s = hint;
117         hint = Nullch;
118         if (spat->spat_regexp->regback >= 0) {
119             s -= spat->spat_regexp->regback;
120             if (s < m)
121                 s = m;
122         }
123         else
124             s = m;
125     }
126     else if (spat->spat_short) {
127         if (spat->spat_flags & SPAT_SCANFIRST) {
128             if (str->str_pok & SP_STUDIED) {
129                 if (screamfirst[spat->spat_short->str_rare] < 0)
130                     goto nope;
131                 else if (!(s = screaminstr(str,spat->spat_short)))
132                     goto nope;
133             }
134 #ifndef lint
135             else if (!(s = fbminstr((unsigned char*)s, (unsigned char*)strend,
136               spat->spat_short)))
137                 goto nope;
138 #endif
139             if (s && spat->spat_regexp->regback >= 0) {
140                 ++spat->spat_short->str_u.str_useful;
141                 s -= spat->spat_regexp->regback;
142                 if (s < m)
143                     s = m;
144             }
145             else
146                 s = m;
147         }
148         else if (!multiline && (*spat->spat_short->str_ptr != *s ||
149           bcmp(spat->spat_short->str_ptr, s, spat->spat_slen) ))
150             goto nope;
151         if (--spat->spat_short->str_u.str_useful < 0) {
152             str_free(spat->spat_short);
153             spat->spat_short = Nullstr; /* opt is being useless */
154         }
155     }
156     once = ((rspat->spat_flags & SPAT_ONCE) != 0);
157     if (rspat->spat_flags & SPAT_CONST) {       /* known replacement string? */
158         if ((rspat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
159             dstr = rspat->spat_repl[1].arg_ptr.arg_str;
160         else {                                  /* constant over loop, anyway */
161             (void)eval(rspat->spat_repl,G_SCALAR,sp);
162             dstr = stack->ary_array[sp+1];
163         }
164         c = str_get(dstr);
165         clen = dstr->str_cur;
166         if (clen <= spat->spat_slen + spat->spat_regexp->regback) {
167                                         /* can do inplace substitution */
168             if (regexec(spat->spat_regexp, s, strend, orig, 0,
169               str->str_pok & SP_STUDIED ? str : Nullstr, safebase)) {
170                 if (spat->spat_regexp->subbase) /* oops, no we can't */
171                     goto long_way;
172                 d = s;
173                 lastspat = spat;
174                 str->str_pok = SP_VALID;        /* disable possible screamer */
175                 if (once) {
176                     m = spat->spat_regexp->startp[0];
177                     d = spat->spat_regexp->endp[0];
178                     s = orig;
179                     if (m - s > strend - d) {   /* faster to shorten from end */
180                         if (clen) {
181                             (void)bcopy(c, m, clen);
182                             m += clen;
183                         }
184                         i = strend - d;
185                         if (i > 0) {
186                             (void)bcopy(d, m, i);
187                             m += i;
188                         }
189                         *m = '\0';
190                         str->str_cur = m - s;
191                         STABSET(str);
192                         str_numset(arg->arg_ptr.arg_str, 1.0);
193                         stack->ary_array[++sp] = arg->arg_ptr.arg_str;
194                         return sp;
195                     }
196                     else if (i = m - s) {       /* faster from front */
197                         d -= clen;
198                         m = d;
199                         str_chop(str,d-i);
200                         s += i;
201                         while (i--)
202                             *--d = *--s;
203                         if (clen)
204                             (void)bcopy(c, m, clen);
205                         STABSET(str);
206                         str_numset(arg->arg_ptr.arg_str, 1.0);
207                         stack->ary_array[++sp] = arg->arg_ptr.arg_str;
208                         return sp;
209                     }
210                     else if (clen) {
211                         d -= clen;
212                         str_chop(str,d);
213                         (void)bcopy(c,d,clen);
214                         STABSET(str);
215                         str_numset(arg->arg_ptr.arg_str, 1.0);
216                         stack->ary_array[++sp] = arg->arg_ptr.arg_str;
217                         return sp;
218                     }
219                     else {
220                         str_chop(str,d);
221                         STABSET(str);
222                         str_numset(arg->arg_ptr.arg_str, 1.0);
223                         stack->ary_array[++sp] = arg->arg_ptr.arg_str;
224                         return sp;
225                     }
226                     /* NOTREACHED */
227                 }
228                 do {
229                     if (iters++ > maxiters)
230                         fatal("Substitution loop");
231                     m = spat->spat_regexp->startp[0];
232                     if (i = m - s) {
233                         if (s != d)
234                             (void)bcopy(s,d,i);
235                         d += i;
236                     }
237                     if (clen) {
238                         (void)bcopy(c,d,clen);
239                         d += clen;
240                     }
241                     s = spat->spat_regexp->endp[0];
242                 } while (regexec(spat->spat_regexp, s, strend, orig, s == m,
243                     Nullstr, TRUE));    /* (don't match same null twice) */
244                 if (s != d) {
245                     i = strend - s;
246                     str->str_cur = d - str->str_ptr + i;
247                     (void)bcopy(s,d,i+1);               /* include the Null */
248                 }
249                 STABSET(str);
250                 str_numset(arg->arg_ptr.arg_str, (double)iters);
251                 stack->ary_array[++sp] = arg->arg_ptr.arg_str;
252                 return sp;
253             }
254             str_numset(arg->arg_ptr.arg_str, 0.0);
255             stack->ary_array[++sp] = arg->arg_ptr.arg_str;
256             return sp;
257         }
258     }
259     else
260         c = Nullch;
261     if (regexec(spat->spat_regexp, s, strend, orig, 0,
262       str->str_pok & SP_STUDIED ? str : Nullstr, safebase)) {
263     long_way:
264         dstr = Str_new(25,str_len(str));
265         str_nset(dstr,m,s-m);
266         if (spat->spat_regexp->subbase)
267             curspat = spat;
268         lastspat = spat;
269         do {
270             if (iters++ > maxiters)
271                 fatal("Substitution loop");
272             if (spat->spat_regexp->subbase
273               && spat->spat_regexp->subbase != orig) {
274                 m = s;
275                 s = orig;
276                 orig = spat->spat_regexp->subbase;
277                 s = orig + (m - s);
278                 strend = s + (strend - m);
279             }
280             m = spat->spat_regexp->startp[0];
281             str_ncat(dstr,s,m-s);
282             s = spat->spat_regexp->endp[0];
283             if (c) {
284                 if (clen)
285                     str_ncat(dstr,c,clen);
286             }
287             else {
288                 (void)eval(rspat->spat_repl,G_SCALAR,sp);
289                 str_scat(dstr,stack->ary_array[sp+1]);
290             }
291             if (once)
292                 break;
293         } while (regexec(spat->spat_regexp, s, strend, orig, s == m, Nullstr,
294             safebase));
295         str_ncat(dstr,s,strend - s);
296         str_replace(str,dstr);
297         STABSET(str);
298         str_numset(arg->arg_ptr.arg_str, (double)iters);
299         stack->ary_array[++sp] = arg->arg_ptr.arg_str;
300         return sp;
301     }
302     str_numset(arg->arg_ptr.arg_str, 0.0);
303     stack->ary_array[++sp] = arg->arg_ptr.arg_str;
304     return sp;
305
306 nope:
307     ++spat->spat_short->str_u.str_useful;
308     str_numset(arg->arg_ptr.arg_str, 0.0);
309     stack->ary_array[++sp] = arg->arg_ptr.arg_str;
310     return sp;
311 }
312 #ifdef BUGGY_MSC
313  #pragma intrinsic(memcmp)
314 #endif /* BUGGY_MSC */
315
316 int
317 do_trans(str,arg)
318 STR *str;
319 register ARG *arg;
320 {
321     register char *tbl;
322     register char *s;
323     register int matches = 0;
324     register int ch;
325     register char *send;
326
327     tbl = arg[2].arg_ptr.arg_cval;
328     s = str_get(str);
329     send = s + str->str_cur;
330     if (!tbl || !s)
331         fatal("panic: do_trans");
332 #ifdef DEBUGGING
333     if (debug & 8) {
334         deb("2.TBL\n");
335     }
336 #endif
337     while (s < send) {
338         if (ch = tbl[*s & 0377]) {
339             matches++;
340             *s = ch;
341         }
342         s++;
343     }
344     STABSET(str);
345     return matches;
346 }
347
348 void
349 do_join(str,arglast)
350 register STR *str;
351 int *arglast;
352 {
353     register STR **st = stack->ary_array;
354     register int sp = arglast[1];
355     register int items = arglast[2] - sp;
356     register char *delim = str_get(st[sp]);
357     int delimlen = st[sp]->str_cur;
358
359     st += ++sp;
360     if (items-- > 0)
361         str_sset(str,*st++);
362     else
363         str_set(str,"");
364     for (; items > 0; items--,st++) {
365         str_ncat(str,delim,delimlen);
366         str_scat(str,*st);
367     }
368     STABSET(str);
369 }
370
371 void
372 do_pack(str,arglast)
373 register STR *str;
374 int *arglast;
375 {
376     register STR **st = stack->ary_array;
377     register int sp = arglast[1];
378     register int items;
379     register char *pat = str_get(st[sp]);
380     register char *patend = pat + st[sp]->str_cur;
381     register int len;
382     int datumtype;
383     STR *fromstr;
384     static char *null10 = "\0\0\0\0\0\0\0\0\0\0";
385     static char *space10 = "          ";
386
387     /* These must not be in registers: */
388     char achar;
389     short ashort;
390     int aint;
391     unsigned int auint;
392     long along;
393     unsigned long aulong;
394     char *aptr;
395     float afloat;
396     double adouble;
397
398     items = arglast[2] - sp;
399     st += ++sp;
400     str_nset(str,"",0);
401     while (pat < patend) {
402 #define NEXTFROM (items-- > 0 ? *st++ : &str_no)
403         datumtype = *pat++;
404         if (*pat == '*') {
405             len = index("@Xxu",datumtype) ? 0 : items;
406             pat++;
407         }
408         else if (isdigit(*pat)) {
409             len = *pat++ - '0';
410             while (isdigit(*pat))
411                 len = (len * 10) + (*pat++ - '0');
412         }
413         else
414             len = 1;
415         switch(datumtype) {
416         default:
417             break;
418         case '%':
419             fatal("% may only be used in unpack");
420         case '@':
421             len -= str->str_cur;
422             if (len > 0)
423                 goto grow;
424             len = -len;
425             if (len > 0)
426                 goto shrink;
427             break;
428         case 'X':
429           shrink:
430             str->str_cur -= len;
431             if (str->str_cur < 0)
432                 fatal("X outside of string");
433             str->str_ptr[str->str_cur] = '\0';
434             break;
435         case 'x':
436           grow:
437             while (len >= 10) {
438                 str_ncat(str,null10,10);
439                 len -= 10;
440             }
441             str_ncat(str,null10,len);
442             break;
443         case 'A':
444         case 'a':
445             fromstr = NEXTFROM;
446             aptr = str_get(fromstr);
447             if (pat[-1] == '*')
448                 len = fromstr->str_cur;
449             if (fromstr->str_cur > len)
450                 str_ncat(str,aptr,len);
451             else {
452                 str_ncat(str,aptr,fromstr->str_cur);
453                 len -= fromstr->str_cur;
454                 if (datumtype == 'A') {
455                     while (len >= 10) {
456                         str_ncat(str,space10,10);
457                         len -= 10;
458                     }
459                     str_ncat(str,space10,len);
460                 }
461                 else {
462                     while (len >= 10) {
463                         str_ncat(str,null10,10);
464                         len -= 10;
465                     }
466                     str_ncat(str,null10,len);
467                 }
468             }
469             break;
470         case 'C':
471         case 'c':
472             while (len-- > 0) {
473                 fromstr = NEXTFROM;
474                 aint = (int)str_gnum(fromstr);
475                 achar = aint;
476                 str_ncat(str,&achar,sizeof(char));
477             }
478             break;
479         /* Float and double added by gnb@melba.bby.oz.au  22/11/89 */
480         case 'f':
481         case 'F':
482             while (len-- > 0) {
483                 fromstr = NEXTFROM;
484                 afloat = (float)str_gnum(fromstr);
485                 str_ncat(str, (char *)&afloat, sizeof (float));
486             }
487             break;
488         case 'd':
489         case 'D':
490             while (len-- > 0) {
491                 fromstr = NEXTFROM;
492                 adouble = (double)str_gnum(fromstr);
493                 str_ncat(str, (char *)&adouble, sizeof (double));
494             }
495             break;
496         case 'n':
497             while (len-- > 0) {
498                 fromstr = NEXTFROM;
499                 ashort = (short)str_gnum(fromstr);
500 #ifdef HTONS
501                 ashort = htons(ashort);
502 #endif
503                 str_ncat(str,(char*)&ashort,sizeof(short));
504             }
505             break;
506         case 'S':
507         case 's':
508             while (len-- > 0) {
509                 fromstr = NEXTFROM;
510                 ashort = (short)str_gnum(fromstr);
511                 str_ncat(str,(char*)&ashort,sizeof(short));
512             }
513             break;
514         case 'I':
515             while (len-- > 0) {
516                 fromstr = NEXTFROM;
517                 auint = U_I(str_gnum(fromstr));
518                 str_ncat(str,(char*)&auint,sizeof(unsigned int));
519             }
520             break;
521         case 'i':
522             while (len-- > 0) {
523                 fromstr = NEXTFROM;
524                 aint = (int)str_gnum(fromstr);
525                 str_ncat(str,(char*)&aint,sizeof(int));
526             }
527             break;
528         case 'N':
529             while (len-- > 0) {
530                 fromstr = NEXTFROM;
531                 along = (long)str_gnum(fromstr);
532 #ifdef HTONL
533                 along = htonl(along);
534 #endif
535                 str_ncat(str,(char*)&along,sizeof(long));
536             }
537             break;
538         case 'L':
539             while (len-- > 0) {
540                 fromstr = NEXTFROM;
541                 aulong = U_L(str_gnum(fromstr));
542                 str_ncat(str,(char*)&aulong,sizeof(unsigned long));
543             }
544             break;
545         case 'l':
546             while (len-- > 0) {
547                 fromstr = NEXTFROM;
548                 along = (long)str_gnum(fromstr);
549                 str_ncat(str,(char*)&along,sizeof(long));
550             }
551             break;
552         case 'p':
553             while (len-- > 0) {
554                 fromstr = NEXTFROM;
555                 aptr = str_get(fromstr);
556                 str_ncat(str,(char*)&aptr,sizeof(char*));
557             }
558             break;
559         case 'u':
560             fromstr = NEXTFROM;
561             aptr = str_get(fromstr);
562             aint = fromstr->str_cur;
563             STR_GROW(str,aint * 4 / 3);
564             if (len <= 1)
565                 len = 45;
566             else
567                 len = len / 3 * 3;
568             while (aint > 0) {
569                 int todo;
570
571                 if (aint > len)
572                     todo = len;
573                 else
574                     todo = aint;
575                 doencodes(str, aptr, todo);
576                 aint -= todo;
577                 aptr += todo;
578             }
579             break;
580         }
581     }
582     STABSET(str);
583 }
584 #undef NEXTFROM
585
586 doencodes(str, s, len)
587 register STR *str;
588 register char *s;
589 register int len;
590 {
591     char hunk[5];
592
593     *hunk = len + ' ';
594     str_ncat(str, hunk, 1);
595     hunk[4] = '\0';
596     while (len > 0) {
597         hunk[0] = ' ' + (077 & (*s >> 2));
598         hunk[1] = ' ' + (077 & ((*s << 4) & 060 | (s[1] >> 4) & 017));
599         hunk[2] = ' ' + (077 & ((s[1] << 2) & 074 | (s[2] >> 6) & 03));
600         hunk[3] = ' ' + (077 & (s[2] & 077));
601         str_ncat(str, hunk, 4);
602         s += 3;
603         len -= 3;
604     }
605     str_ncat(str, "\n", 1);
606 }
607
608 void
609 do_sprintf(str,len,sarg)
610 register STR *str;
611 register int len;
612 register STR **sarg;
613 {
614     register char *s;
615     register char *t;
616     bool dolong;
617     char ch;
618     static STR *sargnull = &str_no;
619     register char *send;
620     char *xs;
621     int xlen;
622     double value;
623     char *origs;
624
625     str_set(str,"");
626     len--;                      /* don't count pattern string */
627     origs = s = str_get(*sarg);
628     send = s + (*sarg)->str_cur;
629     sarg++;
630     for ( ; s < send; len--) {
631         if (len <= 0 || !*sarg) {
632             sarg = &sargnull;
633             len = 0;
634         }
635         dolong = FALSE;
636         for (t = s; t < send && *t != '%'; t++) ;
637         if (t >= send)
638             break;              /* not enough % patterns, oh well */
639         for (t++; *sarg && t < send && t != s; t++) {
640             switch (*t) {
641             default:
642                 ch = *(++t);
643                 *t = '\0';
644                 (void)sprintf(buf,s);
645                 s = t;
646                 *(t--) = ch;
647                 len++;
648                 break;
649             case '0': case '1': case '2': case '3': case '4':
650             case '5': case '6': case '7': case '8': case '9': 
651             case '.': case '#': case '-': case '+':
652                 break;
653             case 'l':
654                 dolong = TRUE;
655                 break;
656             case 'c':
657                 ch = *(++t);
658                 *t = '\0';
659                 xlen = (int)str_gnum(*(sarg++));
660                 if (strEQ(t-2,"%c")) {  /* some printfs fail on null chars */
661                     *buf = xlen;
662                     str_ncat(str,s,t - s - 2);
663                     str_ncat(str,buf,1);  /* so handle simple case */
664                     *buf = '\0';
665                 }
666                 else
667                     (void)sprintf(buf,s,xlen);
668                 s = t;
669                 *(t--) = ch;
670                 break;
671             case 'D':
672                 dolong = TRUE;
673                 /* FALL THROUGH */
674             case 'd':
675                 ch = *(++t);
676                 *t = '\0';
677                 if (dolong)
678                     (void)sprintf(buf,s,(long)str_gnum(*(sarg++)));
679                 else
680                     (void)sprintf(buf,s,(int)str_gnum(*(sarg++)));
681                 s = t;
682                 *(t--) = ch;
683                 break;
684             case 'X': case 'O':
685                 dolong = TRUE;
686                 /* FALL THROUGH */
687             case 'x': case 'o': case 'u':
688                 ch = *(++t);
689                 *t = '\0';
690                 value = str_gnum(*(sarg++));
691                 if (dolong)
692                     (void)sprintf(buf,s,U_L(value));
693                 else
694                     (void)sprintf(buf,s,U_I(value));
695                 s = t;
696                 *(t--) = ch;
697                 break;
698             case 'E': case 'e': case 'f': case 'G': case 'g':
699                 ch = *(++t);
700                 *t = '\0';
701                 (void)sprintf(buf,s,str_gnum(*(sarg++)));
702                 s = t;
703                 *(t--) = ch;
704                 break;
705             case 's':
706                 ch = *(++t);
707                 *t = '\0';
708                 xs = str_get(*sarg);
709                 xlen = (*sarg)->str_cur;
710                 if (*xs == 'S' && xs[1] == 't' && xs[2] == 'B'
711                   && xlen == sizeof(STBP) && strlen(xs) < xlen) {
712                     xs = stab_name(((STAB*)(*sarg))); /* a stab value! */
713                     sprintf(tokenbuf,"*%s",xs); /* reformat to non-binary */
714                     xs = tokenbuf;
715                     xlen = strlen(tokenbuf);
716                 }
717                 if (strEQ(t-2,"%s")) {  /* some printfs fail on >128 chars */
718                     *buf = '\0';
719                     str_ncat(str,s,t - s - 2);
720                     *t = ch;
721                     str_ncat(str,xs,xlen);  /* so handle simple case */
722                 }
723                 else {
724                     if (origs == xs) {          /* sprintf($s,...$s...) */
725                         strcpy(tokenbuf+64,s);
726                         s = tokenbuf+64;
727                         *t = ch;
728                     }
729                     (void)sprintf(buf,s,xs);
730                 }
731                 sarg++;
732                 s = t;
733                 *(t--) = ch;
734                 break;
735             }
736         }
737         if (s < t && t >= send) {
738             str_cat(str,s);
739             s = t;
740             break;
741         }
742         str_cat(str,buf);
743     }
744     if (*s) {
745         (void)sprintf(buf,s,0,0,0,0);
746         str_cat(str,buf);
747     }
748     STABSET(str);
749 }
750
751 STR *
752 do_push(ary,arglast)
753 register ARRAY *ary;
754 int *arglast;
755 {
756     register STR **st = stack->ary_array;
757     register int sp = arglast[1];
758     register int items = arglast[2] - sp;
759     register STR *str = &str_undef;
760
761     for (st += ++sp; items > 0; items--,st++) {
762         str = Str_new(26,0);
763         if (*st)
764             str_sset(str,*st);
765         (void)apush(ary,str);
766     }
767     return str;
768 }
769
770 int
771 do_unshift(ary,arglast)
772 register ARRAY *ary;
773 int *arglast;
774 {
775     register STR **st = stack->ary_array;
776     register int sp = arglast[1];
777     register int items = arglast[2] - sp;
778     register STR *str;
779     register int i;
780
781     aunshift(ary,items);
782     i = 0;
783     for (st += ++sp; i < items; i++,st++) {
784         str = Str_new(27,0);
785         str_sset(str,*st);
786         (void)astore(ary,i,str);
787     }
788 }
789
790 int
791 do_subr(arg,gimme,arglast)
792 register ARG *arg;
793 int gimme;
794 int *arglast;
795 {
796     register STR **st = stack->ary_array;
797     register int sp = arglast[1];
798     register int items = arglast[2] - sp;
799     register SUBR *sub;
800     ARRAY *savearray;
801     STAB *stab;
802     char *oldfile = filename;
803     int oldsave = savestack->ary_fill;
804     int oldtmps_base = tmps_base;
805
806     if ((arg[1].arg_type & A_MASK) == A_WORD)
807         stab = arg[1].arg_ptr.arg_stab;
808     else {
809         STR *tmpstr = stab_val(arg[1].arg_ptr.arg_stab);
810
811         if (tmpstr)
812             stab = stabent(str_get(tmpstr),TRUE);
813         else
814             stab = Nullstab;
815     }
816     if (!stab)
817         fatal("Undefined subroutine called");
818     saveint(&wantarray);
819     wantarray = gimme;
820     sub = stab_sub(stab);
821     if (!sub)
822         fatal("Undefined subroutine \"%s\" called", stab_name(stab));
823     if (sub->usersub) {
824         st[sp] = arg->arg_ptr.arg_str;
825         if ((arg[2].arg_type & A_MASK) == A_NULL)
826             items = 0;
827         return sub->usersub(sub->userindex,sp,items);
828     }
829     if ((arg[2].arg_type & A_MASK) != A_NULL) {
830         savearray = stab_xarray(defstab);
831         stab_xarray(defstab) = afake(defstab, items, &st[sp+1]);
832     }
833     savelong(&sub->depth);
834     sub->depth++;
835     if (sub->depth >= 2) {      /* save temporaries on recursion? */
836         if (sub->depth == 100 && dowarn)
837             warn("Deep recursion on subroutine \"%s\"",stab_name(stab));
838         savelist(sub->tosave->ary_array,sub->tosave->ary_fill);
839     }
840     filename = sub->filename;
841     tmps_base = tmps_max;
842     sp = cmd_exec(sub->cmd,gimme,--sp);         /* so do it already */
843     st = stack->ary_array;
844
845     if ((arg[2].arg_type & A_MASK) != A_NULL) {
846         afree(stab_xarray(defstab));  /* put back old $_[] */
847         stab_xarray(defstab) = savearray;
848     }
849     filename = oldfile;
850     tmps_base = oldtmps_base;
851     if (savestack->ary_fill > oldsave) {
852         for (items = arglast[0] + 1; items <= sp; items++)
853             st[items] = str_static(st[items]);
854                 /* in case restore wipes old str */
855         restorelist(oldsave);
856     }
857     return sp;
858 }
859
860 int
861 do_dbsubr(arg,gimme,arglast)
862 register ARG *arg;
863 int gimme;
864 int *arglast;
865 {
866     register STR **st = stack->ary_array;
867     register int sp = arglast[1];
868     register int items = arglast[2] - sp;
869     register SUBR *sub;
870     ARRAY *savearray;
871     STR *str;
872     STAB *stab;
873     char *oldfile = filename;
874     int oldsave = savestack->ary_fill;
875     int oldtmps_base = tmps_base;
876
877     if ((arg[1].arg_type & A_MASK) == A_WORD)
878         stab = arg[1].arg_ptr.arg_stab;
879     else {
880         STR *tmpstr = stab_val(arg[1].arg_ptr.arg_stab);
881
882         if (tmpstr)
883             stab = stabent(str_get(tmpstr),TRUE);
884         else
885             stab = Nullstab;
886     }
887     if (!stab)
888         fatal("Undefined subroutine called");
889     saveint(&wantarray);
890     wantarray = gimme;
891 /* begin differences */
892     str = stab_val(DBsub);
893     saveitem(str);
894     str_set(str,stab_name(stab));
895     sub = stab_sub(DBsub);
896     if (!sub)
897         fatal("No DBsub routine");
898 /* end differences */
899     if ((arg[2].arg_type & A_MASK) != A_NULL) {
900         savearray = stab_xarray(defstab);
901         stab_xarray(defstab) = afake(defstab, items, &st[sp+1]);
902     }
903     savelong(&sub->depth);
904     sub->depth++;
905     if (sub->depth >= 2) {      /* save temporaries on recursion? */
906         if (sub->depth == 100 && dowarn)
907             warn("Deep recursion on subroutine \"%s\"",stab_name(stab));
908         savelist(sub->tosave->ary_array,sub->tosave->ary_fill);
909     }
910     filename = sub->filename;
911     tmps_base = tmps_max;
912     sp = cmd_exec(sub->cmd,gimme, --sp);        /* so do it already */
913     st = stack->ary_array;
914
915     if ((arg[2].arg_type & A_MASK) != A_NULL) {
916         afree(stab_xarray(defstab));  /* put back old $_[] */
917         stab_xarray(defstab) = savearray;
918     }
919     filename = oldfile;
920     tmps_base = oldtmps_base;
921     if (savestack->ary_fill > oldsave) {
922         for (items = arglast[0] + 1; items <= sp; items++)
923             st[items] = str_static(st[items]);
924                 /* in case restore wipes old str */
925         restorelist(oldsave);
926     }
927     return sp;
928 }
929
930 int
931 do_assign(arg,gimme,arglast)
932 register ARG *arg;
933 int gimme;
934 int *arglast;
935 {
936
937     register STR **st = stack->ary_array;
938     STR **firstrelem = st + arglast[1] + 1;
939     STR **firstlelem = st + arglast[0] + 1;
940     STR **lastrelem = st + arglast[2];
941     STR **lastlelem = st + arglast[1];
942     register STR **relem;
943     register STR **lelem;
944
945     register STR *str;
946     register ARRAY *ary;
947     register int makelocal;
948     HASH *hash;
949     int i;
950
951     makelocal = (arg->arg_flags & AF_LOCAL);
952     localizing = makelocal;
953     delaymagic = DM_DELAY;              /* catch simultaneous items */
954
955     /* If there's a common identifier on both sides we have to take
956      * special care that assigning the identifier on the left doesn't
957      * clobber a value on the right that's used later in the list.
958      */
959     if (arg->arg_flags & AF_COMMON) {
960         for (relem = firstrelem; relem <= lastrelem; relem++) {
961             if (str = *relem)
962                 *relem = str_static(str);
963         }
964     }
965     relem = firstrelem;
966     lelem = firstlelem;
967     ary = Null(ARRAY*);
968     hash = Null(HASH*);
969     while (lelem <= lastlelem) {
970         str = *lelem++;
971         if (str->str_state >= SS_HASH) {
972             if (str->str_state == SS_ARY) {
973                 if (makelocal)
974                     ary = saveary(str->str_u.str_stab);
975                 else {
976                     ary = stab_array(str->str_u.str_stab);
977                     ary->ary_fill = -1;
978                 }
979                 i = 0;
980                 while (relem <= lastrelem) {    /* gobble up all the rest */
981                     str = Str_new(28,0);
982                     if (*relem)
983                         str_sset(str,*relem);
984                     *(relem++) = str;
985                     (void)astore(ary,i++,str);
986                 }
987             }
988             else if (str->str_state == SS_HASH) {
989                 char *tmps;
990                 STR *tmpstr;
991
992                 if (makelocal)
993                     hash = savehash(str->str_u.str_stab);
994                 else {
995                     hash = stab_hash(str->str_u.str_stab);
996                     hclear(hash);
997                 }
998                 while (relem < lastrelem) {     /* gobble up all the rest */
999                     if (*relem)
1000                         str = *(relem++);
1001                     else
1002                         str = &str_no, relem++;
1003                     tmps = str_get(str);
1004                     tmpstr = Str_new(29,0);
1005                     if (*relem)
1006                         str_sset(tmpstr,*relem);        /* value */
1007                     *(relem++) = tmpstr;
1008                     (void)hstore(hash,tmps,str->str_cur,tmpstr,0);
1009                 }
1010             }
1011             else
1012                 fatal("panic: do_assign");
1013         }
1014         else {
1015             if (makelocal)
1016                 saveitem(str);
1017             if (relem <= lastrelem) {
1018                 str_sset(str, *relem);
1019                 *(relem++) = str;
1020             }
1021             else {
1022                 str_nset(str, "", 0);
1023                 if (gimme == G_ARRAY) {
1024                     i = ++lastrelem - firstrelem;
1025                     relem++;            /* tacky, I suppose */
1026                     astore(stack,i,str);
1027                     if (st != stack->ary_array) {
1028                         st = stack->ary_array;
1029                         firstrelem = st + arglast[1] + 1;
1030                         firstlelem = st + arglast[0] + 1;
1031                         lastlelem = st + arglast[1];
1032                         lastrelem = st + i;
1033                         relem = lastrelem + 1;
1034                     }
1035                 }
1036             }
1037             STABSET(str);
1038         }
1039     }
1040     if (delaymagic > 1) {
1041         if (delaymagic & DM_REUID) {
1042 #ifdef SETREUID
1043             setreuid(uid,euid);
1044 #else
1045             if (uid != euid || setuid(uid) < 0)
1046                 fatal("No setreuid available");
1047 #endif
1048         }
1049         if (delaymagic & DM_REGID) {
1050 #ifdef SETREGID
1051             setregid(gid,egid);
1052 #else
1053             if (gid != egid || setgid(gid) < 0)
1054                 fatal("No setregid available");
1055 #endif
1056         }
1057     }
1058     delaymagic = 0;
1059     localizing = FALSE;
1060     if (gimme == G_ARRAY) {
1061         i = lastrelem - firstrelem + 1;
1062         if (ary || hash)
1063             Copy(firstrelem, firstlelem, i, STR*);
1064         return arglast[0] + i;
1065     }
1066     else {
1067         str_numset(arg->arg_ptr.arg_str,(double)(arglast[2] - arglast[1]));
1068         *firstlelem = arg->arg_ptr.arg_str;
1069         return arglast[0] + 1;
1070     }
1071 }
1072
1073 int
1074 do_study(str,arg,gimme,arglast)
1075 STR *str;
1076 ARG *arg;
1077 int gimme;
1078 int *arglast;
1079 {
1080     register unsigned char *s;
1081     register int pos = str->str_cur;
1082     register int ch;
1083     register int *sfirst;
1084     register int *snext;
1085     static int maxscream = -1;
1086     static STR *lastscream = Nullstr;
1087     int retval;
1088     int retarg = arglast[0] + 1;
1089
1090 #ifndef lint
1091     s = (unsigned char*)(str_get(str));
1092 #else
1093     s = Null(unsigned char*);
1094 #endif
1095     if (lastscream)
1096         lastscream->str_pok &= ~SP_STUDIED;
1097     lastscream = str;
1098     if (pos <= 0) {
1099         retval = 0;
1100         goto ret;
1101     }
1102     if (pos > maxscream) {
1103         if (maxscream < 0) {
1104             maxscream = pos + 80;
1105             New(301,screamfirst, 256, int);
1106             New(302,screamnext, maxscream, int);
1107         }
1108         else {
1109             maxscream = pos + pos / 4;
1110             Renew(screamnext, maxscream, int);
1111         }
1112     }
1113
1114     sfirst = screamfirst;
1115     snext = screamnext;
1116
1117     if (!sfirst || !snext)
1118         fatal("do_study: out of memory");
1119
1120     for (ch = 256; ch; --ch)
1121         *sfirst++ = -1;
1122     sfirst -= 256;
1123
1124     while (--pos >= 0) {
1125         ch = s[pos];
1126         if (sfirst[ch] >= 0)
1127             snext[pos] = sfirst[ch] - pos;
1128         else
1129             snext[pos] = -pos;
1130         sfirst[ch] = pos;
1131
1132         /* If there were any case insensitive searches, we must assume they
1133          * all are.  This speeds up insensitive searches much more than
1134          * it slows down sensitive ones.
1135          */
1136         if (sawi)
1137             sfirst[fold[ch]] = pos;
1138     }
1139
1140     str->str_pok |= SP_STUDIED;
1141     retval = 1;
1142   ret:
1143     str_numset(arg->arg_ptr.arg_str,(double)retval);
1144     stack->ary_array[retarg] = arg->arg_ptr.arg_str;
1145     return retarg;
1146 }
1147
1148 int
1149 do_defined(str,arg,gimme,arglast)
1150 STR *str;
1151 register ARG *arg;
1152 int gimme;
1153 int *arglast;
1154 {
1155     register int type;
1156     register int retarg = arglast[0] + 1;
1157     int retval;
1158
1159     if ((arg[1].arg_type & A_MASK) != A_LEXPR)
1160         fatal("Illegal argument to defined()");
1161     arg = arg[1].arg_ptr.arg_arg;
1162     type = arg->arg_type;
1163
1164     if (type == O_ARRAY || type == O_LARRAY)
1165         retval = stab_xarray(arg[1].arg_ptr.arg_stab) != 0;
1166     else if (type == O_HASH || type == O_LHASH)
1167         retval = stab_xhash(arg[1].arg_ptr.arg_stab) != 0;
1168     else if (type == O_ASLICE || type == O_LASLICE)
1169         retval = stab_xarray(arg[1].arg_ptr.arg_stab) != 0;
1170     else if (type == O_HSLICE || type == O_LHSLICE)
1171         retval = stab_xhash(arg[1].arg_ptr.arg_stab) != 0;
1172     else if (type == O_SUBR || type == O_DBSUBR)
1173         retval = stab_sub(arg[1].arg_ptr.arg_stab) != 0;
1174     else
1175         retval = FALSE;
1176     str_numset(str,(double)retval);
1177     stack->ary_array[retarg] = str;
1178     return retarg;
1179 }
1180
1181 int
1182 do_undef(str,arg,gimme,arglast)
1183 STR *str;
1184 register ARG *arg;
1185 int gimme;
1186 int *arglast;
1187 {
1188     register int type;
1189     register STAB *stab;
1190     int retarg = arglast[0] + 1;
1191
1192     if ((arg[1].arg_type & A_MASK) != A_LEXPR)
1193         fatal("Illegal argument to undef()");
1194     arg = arg[1].arg_ptr.arg_arg;
1195     type = arg->arg_type;
1196
1197     if (type == O_ARRAY || type == O_LARRAY) {
1198         stab = arg[1].arg_ptr.arg_stab;
1199         afree(stab_xarray(stab));
1200         stab_xarray(stab) = Null(ARRAY*);
1201     }
1202     else if (type == O_HASH || type == O_LHASH) {
1203         stab = arg[1].arg_ptr.arg_stab;
1204         (void)hfree(stab_xhash(stab));
1205         stab_xhash(stab) = Null(HASH*);
1206     }
1207     else if (type == O_SUBR || type == O_DBSUBR) {
1208         stab = arg[1].arg_ptr.arg_stab;
1209         cmd_free(stab_sub(stab)->cmd);
1210         afree(stab_sub(stab)->tosave);
1211         Safefree(stab_sub(stab));
1212         stab_sub(stab) = Null(SUBR*);
1213     }
1214     else
1215         fatal("Can't undefine that kind of object");
1216     str_numset(str,0.0);
1217     stack->ary_array[retarg] = str;
1218     return retarg;
1219 }
1220
1221 int
1222 do_vec(lvalue,astr,arglast)
1223 int lvalue;
1224 STR *astr;
1225 int *arglast;
1226 {
1227     STR **st = stack->ary_array;
1228     int sp = arglast[0];
1229     register STR *str = st[++sp];
1230     register int offset = (int)str_gnum(st[++sp]);
1231     register int size = (int)str_gnum(st[++sp]);
1232     unsigned char *s = (unsigned char*)str_get(str);
1233     unsigned long retnum;
1234     int len;
1235
1236     sp = arglast[1];
1237     offset *= size;             /* turn into bit offset */
1238     len = (offset + size + 7) / 8;
1239     if (offset < 0 || size < 1)
1240         retnum = 0;
1241     else if (!lvalue && len > str->str_cur)
1242         retnum = 0;
1243     else {
1244         if (len > str->str_cur) {
1245             STR_GROW(str,len);
1246             (void)bzero(str->str_ptr + str->str_cur, len - str->str_cur);
1247             str->str_cur = len;
1248         }
1249         s = (unsigned char*)str_get(str);
1250         if (size < 8)
1251             retnum = (s[offset >> 3] >> (offset & 7)) & ((1 << size) - 1);
1252         else {
1253             offset >>= 3;
1254             if (size == 8)
1255                 retnum = s[offset];
1256             else if (size == 16)
1257                 retnum = (s[offset] << 8) + s[offset+1];
1258             else if (size == 32)
1259                 retnum = (s[offset] << 24) + (s[offset + 1] << 16) +
1260                         (s[offset + 2] << 8) + s[offset+3];
1261         }
1262
1263         if (lvalue) {                      /* it's an lvalue! */
1264             struct lstring *lstr = (struct lstring*)astr;
1265
1266             astr->str_magic = str;
1267             st[sp]->str_rare = 'v';
1268             lstr->lstr_offset = offset;
1269             lstr->lstr_len = size;
1270         }
1271     }
1272
1273     str_numset(astr,(double)retnum);
1274     st[sp] = astr;
1275     return sp;
1276 }
1277
1278 void
1279 do_vecset(mstr,str)
1280 STR *mstr;
1281 STR *str;
1282 {
1283     struct lstring *lstr = (struct lstring*)str;
1284     register int offset;
1285     register int size;
1286     register unsigned char *s = (unsigned char*)mstr->str_ptr;
1287     register unsigned long lval = U_L(str_gnum(str));
1288     int mask;
1289
1290     mstr->str_rare = 0;
1291     str->str_magic = Nullstr;
1292     offset = lstr->lstr_offset;
1293     size = lstr->lstr_len;
1294     if (size < 8) {
1295         mask = (1 << size) - 1;
1296         size = offset & 7;
1297         lval &= mask;
1298         offset >>= 3;
1299         s[offset] &= ~(mask << size);
1300         s[offset] |= lval << size;
1301     }
1302     else {
1303         if (size == 8)
1304             s[offset] = lval & 255;
1305         else if (size == 16) {
1306             s[offset] = (lval >> 8) & 255;
1307             s[offset+1] = lval & 255;
1308         }
1309         else if (size == 32) {
1310             s[offset] = (lval >> 24) & 255;
1311             s[offset+1] = (lval >> 16) & 255;
1312             s[offset+2] = (lval >> 8) & 255;
1313             s[offset+3] = lval & 255;
1314         }
1315     }
1316 }
1317
1318 do_chop(astr,str)
1319 register STR *astr;
1320 register STR *str;
1321 {
1322     register char *tmps;
1323     register int i;
1324     ARRAY *ary;
1325     HASH *hash;
1326     HENT *entry;
1327
1328     if (!str)
1329         return;
1330     if (str->str_state == SS_ARY) {
1331         ary = stab_array(str->str_u.str_stab);
1332         for (i = 0; i <= ary->ary_fill; i++)
1333             do_chop(astr,ary->ary_array[i]);
1334         return;
1335     }
1336     if (str->str_state == SS_HASH) {
1337         hash = stab_hash(str->str_u.str_stab);
1338         (void)hiterinit(hash);
1339         while (entry = hiternext(hash))
1340             do_chop(astr,hiterval(hash,entry));
1341         return;
1342     }
1343     tmps = str_get(str);
1344     if (!tmps)
1345         return;
1346     tmps += str->str_cur - (str->str_cur != 0);
1347     str_nset(astr,tmps,1);      /* remember last char */
1348     *tmps = '\0';                               /* wipe it out */
1349     str->str_cur = tmps - str->str_ptr;
1350     str->str_nok = 0;
1351 }
1352
1353 do_vop(optype,str,left,right)
1354 STR *str;
1355 STR *left;
1356 STR *right;
1357 {
1358     register char *s = str_get(str);
1359     register char *l = str_get(left);
1360     register char *r = str_get(right);
1361     register int len;
1362
1363     len = left->str_cur;
1364     if (len > right->str_cur)
1365         len = right->str_cur;
1366     if (str->str_cur > len)
1367         str->str_cur = len;
1368     else if (str->str_cur < len) {
1369         STR_GROW(str,len);
1370         (void)bzero(str->str_ptr + str->str_cur, len - str->str_cur);
1371         str->str_cur = len;
1372         s = str_get(str);
1373     }
1374     switch (optype) {
1375     case O_BIT_AND:
1376         while (len--)
1377             *s++ = *l++ & *r++;
1378         break;
1379     case O_XOR:
1380         while (len--)
1381             *s++ = *l++ ^ *r++;
1382         goto mop_up;
1383     case O_BIT_OR:
1384         while (len--)
1385             *s++ = *l++ | *r++;
1386       mop_up:
1387         len = str->str_cur;
1388         if (right->str_cur > len)
1389             str_ncat(str,right->str_ptr+len,right->str_cur - len);
1390         else if (left->str_cur > len)
1391             str_ncat(str,left->str_ptr+len,left->str_cur - len);
1392         break;
1393     }
1394 }
1395
1396 int
1397 do_syscall(arglast)
1398 int *arglast;
1399 {
1400     register STR **st = stack->ary_array;
1401     register int sp = arglast[1];
1402     register int items = arglast[2] - sp;
1403     long arg[8];
1404     register int i = 0;
1405     int retval = -1;
1406
1407 #ifdef SYSCALL
1408 #ifdef TAINT
1409     for (st += ++sp; items--; st++)
1410         tainted |= (*st)->str_tainted;
1411     st = stack->ary_array;
1412     sp = arglast[1];
1413     items = arglast[2] - sp;
1414 #endif
1415 #ifdef TAINT
1416     taintproper("Insecure dependency in syscall");
1417 #endif
1418     /* This probably won't work on machines where sizeof(long) != sizeof(int)
1419      * or where sizeof(long) != sizeof(char*).  But such machines will
1420      * not likely have syscall implemented either, so who cares?
1421      */
1422     while (items--) {
1423         if (st[++sp]->str_nok || !i)
1424             arg[i++] = (long)str_gnum(st[sp]);
1425 #ifndef lint
1426         else
1427             arg[i++] = (long)st[sp]->str_ptr;
1428 #endif /* lint */
1429     }
1430     sp = arglast[1];
1431     items = arglast[2] - sp;
1432     switch (items) {
1433     case 0:
1434         fatal("Too few args to syscall");
1435     case 1:
1436         retval = syscall(arg[0]);
1437         break;
1438     case 2:
1439         retval = syscall(arg[0],arg[1]);
1440         break;
1441     case 3:
1442         retval = syscall(arg[0],arg[1],arg[2]);
1443         break;
1444     case 4:
1445         retval = syscall(arg[0],arg[1],arg[2],arg[3]);
1446         break;
1447     case 5:
1448         retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4]);
1449         break;
1450     case 6:
1451         retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
1452         break;
1453     case 7:
1454         retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
1455         break;
1456     case 8:
1457         retval = syscall(arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
1458           arg[7]);
1459         break;
1460     }
1461     return retval;
1462 #else
1463     fatal("syscall() unimplemented");
1464 #endif
1465 }
1466
1467