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