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