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