This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
0487d93de0335eb84217b864eaa2389e26799f6c
[perl5.git] / util.c
1 /* $Header: util.c,v 3.0.1.7 90/08/13 22:40:26 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:        util.c,v $
9  * Revision 3.0.1.7  90/08/13  22:40:26  lwall
10  * patch28: the NSIG hack didn't work right on Xenix
11  * patch28: rename was busted on systems without rename system call
12  * 
13  * Revision 3.0.1.6  90/08/09  05:44:55  lwall
14  * patch19: fixed double include of <signal.h>
15  * patch19: various MSDOS and OS/2 patches folded in
16  * patch19: open(STDOUT,"|command") left wrong descriptor attached to STDOUT
17  * 
18  * Revision 3.0.1.5  90/03/27  16:35:13  lwall
19  * patch16: MSDOS support
20  * patch16: support for machines that can't cast negative floats to unsigned ints
21  * patch16: tail anchored pattern could dump if string to search was shorter
22  * 
23  * Revision 3.0.1.4  90/03/01  10:26:48  lwall
24  * patch9: fbminstr() called instr() rather than ninstr()
25  * patch9: nested evals clobbered their longjmp environment
26  * patch9: piped opens returned undefined rather than 0 in child
27  * patch9: the x operator is now up to 10 times faster
28  * 
29  * Revision 3.0.1.3  89/12/21  20:27:41  lwall
30  * patch7: errno may now be a macro with an lvalue
31  * 
32  * Revision 3.0.1.2  89/11/17  15:46:35  lwall
33  * patch5: BZERO separate from BCOPY now
34  * patch5: byteorder now is a hex value
35  * 
36  * Revision 3.0.1.1  89/11/11  05:06:13  lwall
37  * patch2: made dup2 a little better
38  * 
39  * Revision 3.0  89/10/18  15:32:43  lwall
40  * 3.0 baseline
41  * 
42  */
43
44 #include "EXTERN.h"
45 #include "perl.h"
46
47 #if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
48 #include <signal.h>
49 #endif
50
51 #ifdef I_VFORK
52 #  include <vfork.h>
53 #endif
54
55 #ifdef I_VARARGS
56 #  include <varargs.h>
57 #endif
58
59 #define FLUSH
60
61 static char nomem[] = "Out of memory!\n";
62
63 /* paranoid version of malloc */
64
65 #ifdef DEBUGGING
66 static int an = 0;
67 #endif
68
69 /* NOTE:  Do not call the next three routines directly.  Use the macros
70  * in handy.h, so that we can easily redefine everything to do tracking of
71  * allocated hunks back to the original New to track down any memory leaks.
72  */
73
74 char *
75 safemalloc(size)
76 #ifdef MSDOS
77 unsigned long size;
78 #else
79 MEM_SIZE size;
80 #endif /* MSDOS */
81 {
82     char *ptr;
83     char *malloc();
84
85 #ifdef MSDOS
86         if (size > 0xffff) {
87                 fprintf(stderr, "Allocation too large: %lx\n", size) FLUSH;
88                 exit(1);
89         }
90 #endif /* MSDOS */
91     ptr = malloc(size?size:1);  /* malloc(0) is NASTY on our system */
92 #ifdef DEBUGGING
93 #  ifndef I286
94     if (debug & 128)
95         fprintf(stderr,"0x%x: (%05d) malloc %d bytes\n",ptr,an++,size);
96 #  else
97     if (debug & 128)
98         fprintf(stderr,"0x%lx: (%05d) malloc %d bytes\n",ptr,an++,size);
99 #  endif
100 #endif
101     if (ptr != Nullch)
102         return ptr;
103     else {
104         fputs(nomem,stdout) FLUSH;
105         exit(1);
106     }
107     /*NOTREACHED*/
108 #ifdef lint
109     return ptr;
110 #endif
111 }
112
113 /* paranoid version of realloc */
114
115 char *
116 saferealloc(where,size)
117 char *where;
118 #ifndef MSDOS
119 MEM_SIZE size;
120 #else
121 unsigned long size;
122 #endif /* MSDOS */
123 {
124     char *ptr;
125     char *realloc();
126
127 #ifdef MSDOS
128         if (size > 0xffff) {
129                 fprintf(stderr, "Reallocation too large: %lx\n", size) FLUSH;
130                 exit(1);
131         }
132 #endif /* MSDOS */
133     if (!where)
134         fatal("Null realloc");
135     ptr = realloc(where,size?size:1);   /* realloc(0) is NASTY on our system */
136 #ifdef DEBUGGING
137 #  ifndef I286
138     if (debug & 128) {
139         fprintf(stderr,"0x%x: (%05d) rfree\n",where,an++);
140         fprintf(stderr,"0x%x: (%05d) realloc %d bytes\n",ptr,an++,size);
141     }
142 #  else
143     if (debug & 128) {
144         fprintf(stderr,"0x%lx: (%05d) rfree\n",where,an++);
145         fprintf(stderr,"0x%lx: (%05d) realloc %d bytes\n",ptr,an++,size);
146     }
147 #  endif
148 #endif
149     if (ptr != Nullch)
150         return ptr;
151     else {
152         fputs(nomem,stdout) FLUSH;
153         exit(1);
154     }
155     /*NOTREACHED*/
156 #ifdef lint
157     return ptr;
158 #endif
159 }
160
161 /* safe version of free */
162
163 void
164 safefree(where)
165 char *where;
166 {
167 #ifdef DEBUGGING
168 #  ifndef I286
169     if (debug & 128)
170         fprintf(stderr,"0x%x: (%05d) free\n",where,an++);
171 #  else
172     if (debug & 128)
173         fprintf(stderr,"0x%lx: (%05d) free\n",where,an++);
174 #  endif
175 #endif
176     if (where) {
177         free(where);
178     }
179 }
180
181 #ifdef LEAKTEST
182
183 #define ALIGN sizeof(long)
184
185 char *
186 safexmalloc(x,size)
187 int x;
188 MEM_SIZE size;
189 {
190     register char *where;
191
192     where = safemalloc(size + ALIGN);
193     xcount[x]++;
194     where[0] = x % 100;
195     where[1] = x / 100;
196     return where + ALIGN;
197 }
198
199 char *
200 safexrealloc(where,size)
201 char *where;
202 MEM_SIZE size;
203 {
204     return saferealloc(where - ALIGN, size + ALIGN) + ALIGN;
205 }
206
207 void
208 safexfree(where)
209 char *where;
210 {
211     int x;
212
213     if (!where)
214         return;
215     where -= ALIGN;
216     x = where[0] + 100 * where[1];
217     xcount[x]--;
218     safefree(where);
219 }
220
221 xstat()
222 {
223     register int i;
224
225     for (i = 0; i < MAXXCOUNT; i++) {
226         if (xcount[i] != lastxcount[i]) {
227             fprintf(stderr,"%2d %2d\t%ld\n", i / 100, i % 100, xcount[i]);
228             lastxcount[i] = xcount[i];
229         }
230     }
231 }
232
233 #endif /* LEAKTEST */
234
235 /* copy a string up to some (non-backslashed) delimiter, if any */
236
237 char *
238 cpytill(to,from,fromend,delim,retlen)
239 register char *to;
240 register char *from;
241 register char *fromend;
242 register int delim;
243 int *retlen;
244 {
245     char *origto = to;
246
247     for (; from < fromend; from++,to++) {
248         if (*from == '\\') {
249             if (from[1] == delim)
250                 from++;
251             else if (from[1] == '\\')
252                 *to++ = *from++;
253         }
254         else if (*from == delim)
255             break;
256         *to = *from;
257     }
258     *to = '\0';
259     *retlen = to - origto;
260     return from;
261 }
262
263 /* return ptr to little string in big string, NULL if not found */
264 /* This routine was donated by Corey Satten. */
265
266 char *
267 instr(big, little)
268 register char *big;
269 register char *little;
270 {
271     register char *s, *x;
272     register int first;
273
274     if (!little)
275         return big;
276     first = *little++;
277     if (!first)
278         return big;
279     while (*big) {
280         if (*big++ != first)
281             continue;
282         for (x=big,s=little; *s; /**/ ) {
283             if (!*x)
284                 return Nullch;
285             if (*s++ != *x++) {
286                 s--;
287                 break;
288             }
289         }
290         if (!*s)
291             return big-1;
292     }
293     return Nullch;
294 }
295
296 /* same as instr but allow embedded nulls */
297
298 char *
299 ninstr(big, bigend, little, lend)
300 register char *big;
301 register char *bigend;
302 char *little;
303 char *lend;
304 {
305     register char *s, *x;
306     register int first = *little;
307     register char *littleend = lend;
308
309     if (!first && little > littleend)
310         return big;
311     bigend -= littleend - little++;
312     while (big <= bigend) {
313         if (*big++ != first)
314             continue;
315         for (x=big,s=little; s < littleend; /**/ ) {
316             if (*s++ != *x++) {
317                 s--;
318                 break;
319             }
320         }
321         if (s >= littleend)
322             return big-1;
323     }
324     return Nullch;
325 }
326
327 /* reverse of the above--find last substring */
328
329 char *
330 rninstr(big, bigend, little, lend)
331 register char *big;
332 char *bigend;
333 char *little;
334 char *lend;
335 {
336     register char *bigbeg;
337     register char *s, *x;
338     register int first = *little;
339     register char *littleend = lend;
340
341     if (!first && little > littleend)
342         return bigend;
343     bigbeg = big;
344     big = bigend - (littleend - little++);
345     while (big >= bigbeg) {
346         if (*big-- != first)
347             continue;
348         for (x=big+2,s=little; s < littleend; /**/ ) {
349             if (*s++ != *x++) {
350                 s--;
351                 break;
352             }
353         }
354         if (s >= littleend)
355             return big+1;
356     }
357     return Nullch;
358 }
359
360 unsigned char fold[] = {
361         0,      1,      2,      3,      4,      5,      6,      7,
362         8,      9,      10,     11,     12,     13,     14,     15,
363         16,     17,     18,     19,     20,     21,     22,     23,
364         24,     25,     26,     27,     28,     29,     30,     31,
365         32,     33,     34,     35,     36,     37,     38,     39,
366         40,     41,     42,     43,     44,     45,     46,     47,
367         48,     49,     50,     51,     52,     53,     54,     55,
368         56,     57,     58,     59,     60,     61,     62,     63,
369         64,     'a',    'b',    'c',    'd',    'e',    'f',    'g',
370         'h',    'i',    'j',    'k',    'l',    'm',    'n',    'o',
371         'p',    'q',    'r',    's',    't',    'u',    'v',    'w',
372         'x',    'y',    'z',    91,     92,     93,     94,     95,
373         96,     'A',    'B',    'C',    'D',    'E',    'F',    'G',
374         'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
375         'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
376         'X',    'Y',    'Z',    123,    124,    125,    126,    127,
377         128,    129,    130,    131,    132,    133,    134,    135,
378         136,    137,    138,    139,    140,    141,    142,    143,
379         144,    145,    146,    147,    148,    149,    150,    151,
380         152,    153,    154,    155,    156,    157,    158,    159,
381         160,    161,    162,    163,    164,    165,    166,    167,
382         168,    169,    170,    171,    172,    173,    174,    175,
383         176,    177,    178,    179,    180,    181,    182,    183,
384         184,    185,    186,    187,    188,    189,    190,    191,
385         192,    193,    194,    195,    196,    197,    198,    199,
386         200,    201,    202,    203,    204,    205,    206,    207,
387         208,    209,    210,    211,    212,    213,    214,    215,
388         216,    217,    218,    219,    220,    221,    222,    223,    
389         224,    225,    226,    227,    228,    229,    230,    231,
390         232,    233,    234,    235,    236,    237,    238,    239,
391         240,    241,    242,    243,    244,    245,    246,    247,
392         248,    249,    250,    251,    252,    253,    254,    255
393 };
394
395 static unsigned char freq[] = {
396         1,      2,      84,     151,    154,    155,    156,    157,
397         165,    246,    250,    3,      158,    7,      18,     29,
398         40,     51,     62,     73,     85,     96,     107,    118,
399         129,    140,    147,    148,    149,    150,    152,    153,
400         255,    182,    224,    205,    174,    176,    180,    217,
401         233,    232,    236,    187,    235,    228,    234,    226,
402         222,    219,    211,    195,    188,    193,    185,    184,
403         191,    183,    201,    229,    181,    220,    194,    162,
404         163,    208,    186,    202,    200,    218,    198,    179,
405         178,    214,    166,    170,    207,    199,    209,    206,
406         204,    160,    212,    216,    215,    192,    175,    173,
407         243,    172,    161,    190,    203,    189,    164,    230,
408         167,    248,    227,    244,    242,    255,    241,    231,
409         240,    253,    169,    210,    245,    237,    249,    247,
410         239,    168,    252,    251,    254,    238,    223,    221,
411         213,    225,    177,    197,    171,    196,    159,    4,
412         5,      6,      8,      9,      10,     11,     12,     13,
413         14,     15,     16,     17,     19,     20,     21,     22,
414         23,     24,     25,     26,     27,     28,     30,     31,
415         32,     33,     34,     35,     36,     37,     38,     39,
416         41,     42,     43,     44,     45,     46,     47,     48,
417         49,     50,     52,     53,     54,     55,     56,     57,
418         58,     59,     60,     61,     63,     64,     65,     66,
419         67,     68,     69,     70,     71,     72,     74,     75,
420         76,     77,     78,     79,     80,     81,     82,     83,
421         86,     87,     88,     89,     90,     91,     92,     93,
422         94,     95,     97,     98,     99,     100,    101,    102,
423         103,    104,    105,    106,    108,    109,    110,    111,
424         112,    113,    114,    115,    116,    117,    119,    120,
425         121,    122,    123,    124,    125,    126,    127,    128,
426         130,    131,    132,    133,    134,    135,    136,    137,
427         138,    139,    141,    142,    143,    144,    145,    146
428 };
429
430 void
431 fbmcompile(str, iflag)
432 STR *str;
433 int iflag;
434 {
435     register unsigned char *s;
436     register unsigned char *table;
437     register int i;
438     register int len = str->str_cur;
439     int rarest = 0;
440     int frequency = 256;
441
442     Str_Grow(str,len+258);
443 #ifndef lint
444     table = (unsigned char*)(str->str_ptr + len + 1);
445 #else
446     table = Null(unsigned char*);
447 #endif
448     s = table - 2;
449     for (i = 0; i < 256; i++) {
450         table[i] = len;
451     }
452     i = 0;
453 #ifndef lint
454     while (s >= (unsigned char*)(str->str_ptr))
455 #endif
456     {
457         if (table[*s] == len) {
458 #ifndef pdp11
459             if (iflag)
460                 table[*s] = table[fold[*s]] = i;
461 #else
462             if (iflag) {
463                 int j;
464                 j = fold[*s];
465                 table[j] = i;
466                 table[*s] = i;
467             }
468 #endif /* pdp11 */
469             else
470                 table[*s] = i;
471         }
472         s--,i++;
473     }
474     str->str_pok |= SP_FBM;             /* deep magic */
475
476 #ifndef lint
477     s = (unsigned char*)(str->str_ptr);         /* deeper magic */
478 #else
479     s = Null(unsigned char*);
480 #endif
481     if (iflag) {
482         register int tmp, foldtmp;
483         str->str_pok |= SP_CASEFOLD;
484         for (i = 0; i < len; i++) {
485             tmp=freq[s[i]];
486             foldtmp=freq[fold[s[i]]];
487             if (tmp < frequency && foldtmp < frequency) {
488                 rarest = i;
489                 /* choose most frequent among the two */
490                 frequency = (tmp > foldtmp) ? tmp : foldtmp;
491             }
492         }
493     }
494     else {
495         for (i = 0; i < len; i++) {
496             if (freq[s[i]] < frequency) {
497                 rarest = i;
498                 frequency = freq[s[i]];
499             }
500         }
501     }
502     str->str_rare = s[rarest];
503     str->str_state = rarest;
504 #ifdef DEBUGGING
505     if (debug & 512)
506         fprintf(stderr,"rarest char %c at %d\n",str->str_rare, str->str_state);
507 #endif
508 }
509
510 char *
511 fbminstr(big, bigend, littlestr)
512 unsigned char *big;
513 register unsigned char *bigend;
514 STR *littlestr;
515 {
516     register unsigned char *s;
517     register int tmp;
518     register int littlelen;
519     register unsigned char *little;
520     register unsigned char *table;
521     register unsigned char *olds;
522     register unsigned char *oldlittle;
523
524 #ifndef lint
525     if (!(littlestr->str_pok & SP_FBM))
526         return ninstr((char*)big,(char*)bigend,
527                 littlestr->str_ptr, littlestr->str_ptr + littlestr->str_cur);
528 #endif
529
530     littlelen = littlestr->str_cur;
531 #ifndef lint
532     if (littlestr->str_pok & SP_TAIL && !multiline) {   /* tail anchored? */
533         if (littlelen > bigend - big)
534             return Nullch;
535         little = (unsigned char*)littlestr->str_ptr;
536         if (littlestr->str_pok & SP_CASEFOLD) { /* oops, fake it */
537             big = bigend - littlelen;           /* just start near end */
538             if (bigend[-1] == '\n' && little[littlelen-1] != '\n')
539                 big--;
540         }
541         else {
542             s = bigend - littlelen;
543             if (*s == *little && bcmp(s,little,littlelen)==0)
544                 return (char*)s;                /* how sweet it is */
545             else if (bigend[-1] == '\n' && little[littlelen-1] != '\n') {
546                     s--;
547                 if (*s == *little && bcmp(s,little,littlelen)==0)
548                     return (char*)s;
549             }
550             return Nullch;
551         }
552     }
553     table = (unsigned char*)(littlestr->str_ptr + littlelen + 1);
554 #else
555     table = Null(unsigned char*);
556 #endif
557     if (--littlelen >= bigend - big)
558         return Nullch;
559     s = big + littlelen;
560     oldlittle = little = table - 2;
561     if (littlestr->str_pok & SP_CASEFOLD) {     /* case insensitive? */
562         while (s < bigend) {
563           top1:
564             if (tmp = table[*s]) {
565 #ifdef POINTERRIGOR
566                 if (bigend - s > tmp) {
567                     s += tmp;
568                     goto top1;
569                 }
570 #else
571                 if ((s += tmp) < bigend)
572                     goto top1;
573 #endif
574                 return Nullch;
575             }
576             else {
577                 tmp = littlelen;        /* less expensive than calling strncmp() */
578                 olds = s;
579                 while (tmp--) {
580                     if (*--s == *--little || fold[*s] == *little)
581                         continue;
582                     s = olds + 1;       /* here we pay the price for failure */
583                     little = oldlittle;
584                     if (s < bigend)     /* fake up continue to outer loop */
585                         goto top1;
586                     return Nullch;
587                 }
588 #ifndef lint
589                 return (char *)s;
590 #endif
591             }
592         }
593     }
594     else {
595         while (s < bigend) {
596           top2:
597             if (tmp = table[*s]) {
598 #ifdef POINTERRIGOR
599                 if (bigend - s > tmp) {
600                     s += tmp;
601                     goto top2;
602                 }
603 #else
604                 if ((s += tmp) < bigend)
605                     goto top2;
606 #endif
607                 return Nullch;
608             }
609             else {
610                 tmp = littlelen;        /* less expensive than calling strncmp() */
611                 olds = s;
612                 while (tmp--) {
613                     if (*--s == *--little)
614                         continue;
615                     s = olds + 1;       /* here we pay the price for failure */
616                     little = oldlittle;
617                     if (s < bigend)     /* fake up continue to outer loop */
618                         goto top2;
619                     return Nullch;
620                 }
621 #ifndef lint
622                 return (char *)s;
623 #endif
624             }
625         }
626     }
627     return Nullch;
628 }
629
630 char *
631 screaminstr(bigstr, littlestr)
632 STR *bigstr;
633 STR *littlestr;
634 {
635     register unsigned char *s, *x;
636     register unsigned char *big;
637     register int pos;
638     register int previous;
639     register int first;
640     register unsigned char *little;
641     register unsigned char *bigend;
642     register unsigned char *littleend;
643
644     if ((pos = screamfirst[littlestr->str_rare]) < 0) 
645         return Nullch;
646 #ifndef lint
647     little = (unsigned char *)(littlestr->str_ptr);
648 #else
649     little = Null(unsigned char *);
650 #endif
651     littleend = little + littlestr->str_cur;
652     first = *little++;
653     previous = littlestr->str_state;
654 #ifndef lint
655     big = (unsigned char *)(bigstr->str_ptr);
656 #else
657     big = Null(unsigned char*);
658 #endif
659     bigend = big + bigstr->str_cur;
660     big -= previous;
661     while (pos < previous) {
662 #ifndef lint
663         if (!(pos += screamnext[pos]))
664 #endif
665             return Nullch;
666     }
667     if (littlestr->str_pok & SP_CASEFOLD) {     /* case insignificant? */
668         do {
669             if (big[pos] != first && big[pos] != fold[first])
670                 continue;
671             for (x=big+pos+1,s=little; s < littleend; /**/ ) {
672                 if (x >= bigend)
673                     return Nullch;
674                 if (*s++ != *x++ && fold[*(s-1)] != *(x-1)) {
675                     s--;
676                     break;
677                 }
678             }
679             if (s == littleend)
680 #ifndef lint
681                 return (char *)(big+pos);
682 #else
683                 return Nullch;
684 #endif
685         } while (
686 #ifndef lint
687                 pos += screamnext[pos]  /* does this goof up anywhere? */
688 #else
689                 pos += screamnext[0]
690 #endif
691             );
692     }
693     else {
694         do {
695             if (big[pos] != first)
696                 continue;
697             for (x=big+pos+1,s=little; s < littleend; /**/ ) {
698                 if (x >= bigend)
699                     return Nullch;
700                 if (*s++ != *x++) {
701                     s--;
702                     break;
703                 }
704             }
705             if (s == littleend)
706 #ifndef lint
707                 return (char *)(big+pos);
708 #else
709                 return Nullch;
710 #endif
711         } while (
712 #ifndef lint
713                 pos += screamnext[pos]
714 #else
715                 pos += screamnext[0]
716 #endif
717             );
718     }
719     return Nullch;
720 }
721
722 /* copy a string to a safe spot */
723
724 char *
725 savestr(str)
726 char *str;
727 {
728     register char *newaddr;
729
730     New(902,newaddr,strlen(str)+1,char);
731     (void)strcpy(newaddr,str);
732     return newaddr;
733 }
734
735 /* same thing but with a known length */
736
737 char *
738 nsavestr(str, len)
739 char *str;
740 register int len;
741 {
742     register char *newaddr;
743
744     New(903,newaddr,len+1,char);
745     (void)bcopy(str,newaddr,len);       /* might not be null terminated */
746     newaddr[len] = '\0';                /* is now */
747     return newaddr;
748 }
749
750 /* grow a static string to at least a certain length */
751
752 void
753 growstr(strptr,curlen,newlen)
754 char **strptr;
755 int *curlen;
756 int newlen;
757 {
758     if (newlen > *curlen) {             /* need more room? */
759         if (*curlen)
760             Renew(*strptr,newlen,char);
761         else
762             New(905,*strptr,newlen,char);
763         *curlen = newlen;
764     }
765 }
766
767 #ifndef VARARGS
768 /*VARARGS1*/
769 mess(pat,a1,a2,a3,a4)
770 char *pat;
771 long a1, a2, a3, a4;
772 {
773     char *s;
774
775     s = buf;
776     (void)sprintf(s,pat,a1,a2,a3,a4);
777     s += strlen(s);
778     if (s[-1] != '\n') {
779         if (curcmd->c_line) {
780             (void)sprintf(s," at %s line %ld", filename, (long)curcmd->c_line);
781             s += strlen(s);
782         }
783         if (last_in_stab &&
784             stab_io(last_in_stab) &&
785             stab_io(last_in_stab)->lines ) {
786             (void)sprintf(s,", <%s> line %ld",
787               last_in_stab == argvstab ? "" : stab_name(last_in_stab),
788               (long)stab_io(last_in_stab)->lines);
789             s += strlen(s);
790         }
791         (void)strcpy(s,".\n");
792     }
793 }
794
795 /*VARARGS1*/
796 fatal(pat,a1,a2,a3,a4)
797 char *pat;
798 long a1, a2, a3, a4;
799 {
800     extern FILE *e_fp;
801     extern char *e_tmpname;
802     char *tmps;
803
804     mess(pat,a1,a2,a3,a4);
805     if (in_eval) {
806         str_set(stab_val(stabent("@",TRUE)),buf);
807         tmps = "_EVAL_";
808         while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
809           strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
810 #ifdef DEBUGGING
811             if (debug & 4) {
812                 deb("(Skipping label #%d %s)\n",loop_ptr,
813                     loop_stack[loop_ptr].loop_label);
814             }
815 #endif
816             loop_ptr--;
817         }
818 #ifdef DEBUGGING
819         if (debug & 4) {
820             deb("(Found label #%d %s)\n",loop_ptr,
821                 loop_stack[loop_ptr].loop_label);
822         }
823 #endif
824         if (loop_ptr < 0) {
825             in_eval = 0;
826             fatal("Bad label: %s", tmps);
827         }
828         longjmp(loop_stack[loop_ptr].loop_env, 1);
829     }
830     fputs(buf,stderr);
831     (void)fflush(stderr);
832     if (e_fp)
833         (void)UNLINK(e_tmpname);
834     statusvalue >>= 8;
835     exit(errno?errno:(statusvalue?statusvalue:255));
836 }
837
838 /*VARARGS1*/
839 warn(pat,a1,a2,a3,a4)
840 char *pat;
841 long a1, a2, a3, a4;
842 {
843     mess(pat,a1,a2,a3,a4);
844     fputs(buf,stderr);
845 #ifdef LEAKTEST
846 #ifdef DEBUGGING
847     if (debug & 4096)
848         xstat();
849 #endif
850 #endif
851     (void)fflush(stderr);
852 }
853 #else
854 /*VARARGS0*/
855 mess(args)
856 va_list args;
857 {
858     char *pat;
859     char *s;
860 #ifdef CHARVSPRINTF
861     char *vsprintf();
862 #else
863     int vsprintf();
864 #endif
865
866     s = buf;
867 #ifdef lint
868     pat = Nullch;
869 #else
870     pat = va_arg(args, char *);
871 #endif
872     (void) vsprintf(s,pat,args);
873
874     s += strlen(s);
875     if (s[-1] != '\n') {
876         if (curcmd->c_line) {
877             (void)sprintf(s," at %s line %ld", filename, (long)curcmd->c_line);
878             s += strlen(s);
879         }
880         if (last_in_stab &&
881             stab_io(last_in_stab) &&
882             stab_io(last_in_stab)->lines ) {
883             (void)sprintf(s,", <%s> line %ld",
884               last_in_stab == argvstab ? "" : last_in_stab->str_magic->str_ptr,
885               (long)stab_io(last_in_stab)->lines);
886             s += strlen(s);
887         }
888         (void)strcpy(s,".\n");
889     }
890 }
891
892 /*VARARGS0*/
893 fatal(va_alist)
894 va_dcl
895 {
896     va_list args;
897     extern FILE *e_fp;
898     extern char *e_tmpname;
899     char *tmps;
900
901 #ifndef lint
902     va_start(args);
903 #else
904     args = 0;
905 #endif
906     mess(args);
907     va_end(args);
908     if (in_eval) {
909         str_set(stab_val(stabent("@",TRUE)),buf);
910         tmps = "_EVAL_";
911         while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
912           strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
913 #ifdef DEBUGGING
914             if (debug & 4) {
915                 deb("(Skipping label #%d %s)\n",loop_ptr,
916                     loop_stack[loop_ptr].loop_label);
917             }
918 #endif
919             loop_ptr--;
920         }
921 #ifdef DEBUGGING
922         if (debug & 4) {
923             deb("(Found label #%d %s)\n",loop_ptr,
924                 loop_stack[loop_ptr].loop_label);
925         }
926 #endif
927         if (loop_ptr < 0) {
928             in_eval = 0;
929             fatal("Bad label: %s", tmps);
930         }
931         longjmp(loop_stack[loop_ptr].loop_env, 1);
932     }
933     fputs(buf,stderr);
934     (void)fflush(stderr);
935     if (e_fp)
936         (void)UNLINK(e_tmpname);
937     statusvalue >>= 8;
938     exit((int)(errno?errno:(statusvalue?statusvalue:255)));
939 }
940
941 /*VARARGS0*/
942 warn(va_alist)
943 va_dcl
944 {
945     va_list args;
946
947 #ifndef lint
948     va_start(args);
949 #else
950     args = 0;
951 #endif
952     mess(args);
953     va_end(args);
954
955     fputs(buf,stderr);
956 #ifdef LEAKTEST
957 #ifdef DEBUGGING
958     if (debug & 4096)
959         xstat();
960 #endif
961 #endif
962     (void)fflush(stderr);
963 }
964 #endif
965
966 static bool firstsetenv = TRUE;
967 extern char **environ;
968
969 void
970 setenv(nam,val)
971 char *nam, *val;
972 {
973     register int i=envix(nam);          /* where does it go? */
974
975     if (!val) {
976         while (environ[i]) {
977             environ[i] = environ[i+1];
978             i++;
979         }
980         return;
981     }
982     if (!environ[i]) {                  /* does not exist yet */
983         if (firstsetenv) {              /* need we copy environment? */
984             int j;
985             char **tmpenv;
986
987             New(901,tmpenv, i+2, char*);
988             firstsetenv = FALSE;
989             for (j=0; j<i; j++)         /* copy environment */
990                 tmpenv[j] = environ[j];
991             environ = tmpenv;           /* tell exec where it is now */
992         }
993         else
994             Renew(environ, i+2, char*); /* just expand it a bit */
995         environ[i+1] = Nullch;  /* make sure it's null terminated */
996     }
997     New(904, environ[i], strlen(nam) + strlen(val) + 2, char);
998                                         /* this may or may not be in */
999                                         /* the old environ structure */
1000 #ifndef MSDOS
1001     (void)sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
1002 #else
1003     /* MS-DOS requires environment variable names to be in uppercase */
1004     strcpy(environ[i],nam); strupr(environ[i],nam);
1005     (void)sprintf(environ[i] + strlen(nam),"=%s",val);
1006 #endif /* MSDOS */
1007 }
1008
1009 int
1010 envix(nam)
1011 char *nam;
1012 {
1013     register int i, len = strlen(nam);
1014
1015     for (i = 0; environ[i]; i++) {
1016         if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
1017             break;                      /* strnEQ must come first to avoid */
1018     }                                   /* potential SEGV's */
1019     return i;
1020 }
1021
1022 #ifdef EUNICE
1023 unlnk(f)        /* unlink all versions of a file */
1024 char *f;
1025 {
1026     int i;
1027
1028     for (i = 0; unlink(f) >= 0; i++) ;
1029     return i ? 0 : -1;
1030 }
1031 #endif
1032
1033 #ifndef MEMCPY
1034 #ifndef BCOPY
1035 char *
1036 bcopy(from,to,len)
1037 register char *from;
1038 register char *to;
1039 register int len;
1040 {
1041     char *retval = to;
1042
1043     while (len--)
1044         *to++ = *from++;
1045     return retval;
1046 }
1047 #endif
1048
1049 #ifndef BZERO
1050 char *
1051 bzero(loc,len)
1052 register char *loc;
1053 register int len;
1054 {
1055     char *retval = loc;
1056
1057     while (len--)
1058         *loc++ = 0;
1059     return retval;
1060 }
1061 #endif
1062 #endif
1063
1064 #ifdef VARARGS
1065 #ifndef VPRINTF
1066
1067 #ifdef CHARVSPRINTF
1068 char *
1069 #else
1070 int
1071 #endif
1072 vsprintf(dest, pat, args)
1073 char *dest, *pat, *args;
1074 {
1075     FILE fakebuf;
1076
1077     fakebuf._ptr = dest;
1078     fakebuf._cnt = 32767;
1079     fakebuf._flag = _IOWRT|_IOSTRG;
1080     _doprnt(pat, args, &fakebuf);       /* what a kludge */
1081     (void)putc('\0', &fakebuf);
1082 #ifdef CHARVSPRINTF
1083     return(dest);
1084 #else
1085     return 0;           /* perl doesn't use return value */
1086 #endif
1087 }
1088
1089 #ifdef DEBUGGING
1090 int
1091 vfprintf(fd, pat, args)
1092 FILE *fd;
1093 char *pat, *args;
1094 {
1095     _doprnt(pat, args, fd);
1096     return 0;           /* wrong, but perl doesn't use the return value */
1097 }
1098 #endif
1099 #endif /* VPRINTF */
1100 #endif /* VARARGS */
1101
1102 #ifdef MYSWAP
1103 #if BYTEORDER != 0x4321
1104 short
1105 my_swap(s)
1106 short s;
1107 {
1108 #if (BYTEORDER & 1) == 0
1109     short result;
1110
1111     result = ((s & 255) << 8) + ((s >> 8) & 255);
1112     return result;
1113 #else
1114     return s;
1115 #endif
1116 }
1117
1118 long
1119 htonl(l)
1120 register long l;
1121 {
1122     union {
1123         long result;
1124         char c[sizeof(long)];
1125     } u;
1126
1127 #if BYTEORDER == 0x1234
1128     u.c[0] = (l >> 24) & 255;
1129     u.c[1] = (l >> 16) & 255;
1130     u.c[2] = (l >> 8) & 255;
1131     u.c[3] = l & 255;
1132     return u.result;
1133 #else
1134 #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
1135     fatal("Unknown BYTEORDER\n");
1136 #else
1137     register int o;
1138     register int s;
1139
1140     for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
1141         u.c[o & 0xf] = (l >> s) & 255;
1142     }
1143     return u.result;
1144 #endif
1145 #endif
1146 }
1147
1148 long
1149 ntohl(l)
1150 register long l;
1151 {
1152     union {
1153         long l;
1154         char c[sizeof(long)];
1155     } u;
1156
1157 #if BYTEORDER == 0x1234
1158     u.c[0] = (l >> 24) & 255;
1159     u.c[1] = (l >> 16) & 255;
1160     u.c[2] = (l >> 8) & 255;
1161     u.c[3] = l & 255;
1162     return u.l;
1163 #else
1164 #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
1165     fatal("Unknown BYTEORDER\n");
1166 #else
1167     register int o;
1168     register int s;
1169
1170     u.l = l;
1171     l = 0;
1172     for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
1173         l |= (u.c[o & 0xf] & 255) << s;
1174     }
1175     return l;
1176 #endif
1177 #endif
1178 }
1179
1180 #endif /* BYTEORDER != 0x4321 */
1181 #endif /* HTONS */
1182
1183 #ifndef MSDOS
1184 FILE *
1185 mypopen(cmd,mode)
1186 char    *cmd;
1187 char    *mode;
1188 {
1189     int p[2];
1190     register int this, that;
1191     register int pid;
1192     STR *str;
1193     int doexec = strNE(cmd,"-");
1194
1195     if (pipe(p) < 0)
1196         return Nullfp;
1197     this = (*mode == 'w');
1198     that = !this;
1199     while ((pid = (doexec?vfork():fork())) < 0) {
1200         if (errno != EAGAIN) {
1201             close(p[this]);
1202             if (!doexec)
1203                 fatal("Can't fork");
1204             return Nullfp;
1205         }
1206         sleep(5);
1207     }
1208     if (pid == 0) {
1209 #define THIS that
1210 #define THAT this
1211         close(p[THAT]);
1212         if (p[THIS] != (*mode == 'r')) {
1213             dup2(p[THIS], *mode == 'r');
1214             close(p[THIS]);
1215         }
1216         if (doexec) {
1217 #if !defined(FCNTL) || !defined(F_SETFD)
1218             int fd;
1219
1220 #ifndef NOFILE
1221 #define NOFILE 20
1222 #endif
1223             for (fd = 3; fd < NOFILE; fd++)
1224                 close(fd);
1225 #endif
1226             do_exec(cmd);       /* may or may not use the shell */
1227             _exit(1);
1228         }
1229         if (tmpstab = stabent("$",allstabs))
1230             str_numset(STAB_STR(tmpstab),(double)getpid());
1231         forkprocess = 0;
1232         return Nullfp;
1233 #undef THIS
1234 #undef THAT
1235     }
1236     do_execfree();      /* free any memory malloced by child on vfork */
1237     close(p[that]);
1238     if (p[that] < p[this]) {
1239         dup2(p[this], p[that]);
1240         close(p[this]);
1241         p[this] = p[that];
1242     }
1243     str = afetch(pidstatary,p[this],TRUE);
1244     str_numset(str,(double)pid);
1245     str->str_cur = 0;
1246     forkprocess = pid;
1247     return fdopen(p[this], mode);
1248 }
1249 #endif /* !MSDOS */
1250
1251 #ifdef NOTDEF
1252 dumpfds(s)
1253 char *s;
1254 {
1255     int fd;
1256     struct stat tmpstatbuf;
1257
1258     fprintf(stderr,"%s", s);
1259     for (fd = 0; fd < 32; fd++) {
1260         if (fstat(fd,&tmpstatbuf) >= 0)
1261             fprintf(stderr," %d",fd);
1262     }
1263     fprintf(stderr,"\n");
1264 }
1265 #endif
1266
1267 #ifndef DUP2
1268 dup2(oldfd,newfd)
1269 int oldfd;
1270 int newfd;
1271 {
1272 #if defined(FCNTL) && defined(F_DUPFD)
1273     close(newfd);
1274     fcntl(oldfd, F_DUPFD, newfd);
1275 #else
1276     int fdtmp[20];
1277     int fdx = 0;
1278     int fd;
1279
1280     close(newfd);
1281     while ((fd = dup(oldfd)) != newfd)  /* good enough for low fd's */
1282         fdtmp[fdx++] = fd;
1283     while (fdx > 0)
1284         close(fdtmp[--fdx]);
1285 #endif
1286 }
1287 #endif
1288
1289 #ifndef MSDOS
1290 int
1291 mypclose(ptr)
1292 FILE *ptr;
1293 {
1294 #ifdef VOIDSIG
1295     void (*hstat)(), (*istat)(), (*qstat)();
1296 #else
1297     int (*hstat)(), (*istat)(), (*qstat)();
1298 #endif
1299     int status;
1300     STR *str;
1301     register int pid;
1302
1303     str = afetch(pidstatary,fileno(ptr),TRUE);
1304     fclose(ptr);
1305     pid = (int)str_gnum(str);
1306     if (!pid)
1307         return -1;
1308     hstat = signal(SIGHUP, SIG_IGN);
1309     istat = signal(SIGINT, SIG_IGN);
1310     qstat = signal(SIGQUIT, SIG_IGN);
1311 #ifdef WAIT4
1312     if (wait4(pid,&status,0,Null(struct rusage *)) < 0)
1313         status = -1;
1314 #else
1315     if (pid < 0)                /* already exited? */
1316         status = str->str_cur;
1317     else {
1318         int result;
1319
1320         while ((result = wait(&status)) != pid && result >= 0)
1321             pidgone(result,status);
1322         if (result < 0)
1323             status = -1;
1324     }
1325 #endif
1326     signal(SIGHUP, hstat);
1327     signal(SIGINT, istat);
1328     signal(SIGQUIT, qstat);
1329     str_numset(str,0.0);
1330     return(status);
1331 }
1332 #endif /* !MSDOS */
1333
1334 pidgone(pid,status)
1335 int pid;
1336 int status;
1337 {
1338 #ifdef WAIT4
1339     return;
1340 #else
1341     register int count;
1342     register STR *str;
1343
1344     for (count = pidstatary->ary_fill; count >= 0; --count) {
1345         if ((str = afetch(pidstatary,count,FALSE)) &&
1346           ((int)str->str_u.str_nval) == pid) {
1347             str_numset(str, -str->str_u.str_nval);
1348             str->str_cur = status;
1349             return;
1350         }
1351     }
1352 #endif
1353 }
1354
1355 #ifndef MEMCMP
1356 memcmp(s1,s2,len)
1357 register unsigned char *s1;
1358 register unsigned char *s2;
1359 register int len;
1360 {
1361     register int tmp;
1362
1363     while (len--) {
1364         if (tmp = *s1++ - *s2++)
1365             return tmp;
1366     }
1367     return 0;
1368 }
1369 #endif /* MEMCMP */
1370
1371 void
1372 repeatcpy(to,from,len,count)
1373 register char *to;
1374 register char *from;
1375 int len;
1376 register int count;
1377 {
1378     register int todo;
1379     register char *frombase = from;
1380
1381     if (len == 1) {
1382         todo = *from;
1383         while (count-- > 0)
1384             *to++ = todo;
1385         return;
1386     }
1387     while (count-- > 0) {
1388         for (todo = len; todo > 0; todo--) {
1389             *to++ = *from++;
1390         }
1391         from = frombase;
1392     }
1393 }
1394
1395 #ifndef CASTNEGFLOAT
1396 unsigned long
1397 castulong(f)
1398 double f;
1399 {
1400     long along;
1401
1402     if (f >= 0.0)
1403         return (unsigned long)f;
1404     along = (long)f;
1405     return (unsigned long)along;
1406 }
1407 #endif
1408
1409 #ifndef RENAME
1410 int
1411 same_dirent(a,b)
1412 char *a;
1413 char *b;
1414 {
1415     char *fa = rindex(a,'/');
1416     char *fb = rindex(b,'/');
1417     struct stat tmpstatbuf1;
1418     struct stat tmpstatbuf2;
1419 #ifndef MAXPATHLEN
1420 #define MAXPATHLEN 1024
1421 #endif
1422     char tmpbuf[MAXPATHLEN+1];
1423
1424     if (fa)
1425         fa++;
1426     else
1427         fa = a;
1428     if (fb)
1429         fb++;
1430     else
1431         fb = b;
1432     if (strNE(a,b))
1433         return FALSE;
1434     if (fa == a)
1435         strcpy(tmpbuf,".");
1436     else
1437         strncpy(tmpbuf, a, fa - a);
1438     if (stat(tmpbuf, &tmpstatbuf1) < 0)
1439         return FALSE;
1440     if (fb == b)
1441         strcpy(tmpbuf,".");
1442     else
1443         strncpy(tmpbuf, b, fb - b);
1444     if (stat(tmpbuf, &tmpstatbuf2) < 0)
1445         return FALSE;
1446     return tmpstatbuf1.st_dev == tmpstatbuf2.st_dev &&
1447            tmpstatbuf1.st_ino == tmpstatbuf2.st_ino;
1448 }
1449 #endif /* !RENAME */