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