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