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