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