b4e32631743c5cf0240349b8f95a3990727cabfb
[p5sagit/p5-mst-13.2.git] / util.c
1 /* $RCSfile: util.c,v $$Revision: 4.0.1.6 $$Date: 92/06/11 21:18:47 $
2  *
3  *    Copyright (c) 1991, Larry Wall
4  *
5  *    You may distribute under the terms of either the GNU General Public
6  *    License or the Artistic License, as specified in the README file.
7  *
8  * $Log:        util.c,v $
9  * Revision 4.0.1.6  92/06/11  21:18:47  lwall
10  * patch34: boneheaded typo in my_bcopy()
11  * 
12  * Revision 4.0.1.5  92/06/08  16:08:37  lwall
13  * patch20: removed implicit int declarations on functions
14  * patch20: Perl now distinguishes overlapped copies from non-overlapped
15  * patch20: fixed confusion between a *var's real name and its effective name
16  * patch20: bcopy() and memcpy() now tested for overlap safety
17  * patch20: added Atari ST portability
18  * 
19  * Revision 4.0.1.4  91/11/11  16:48:54  lwall
20  * patch19: study was busted by 4.018
21  * patch19: added little-endian pack/unpack options
22  * 
23  * Revision 4.0.1.3  91/11/05  19:18:26  lwall
24  * patch11: safe malloc code now integrated into Perl's malloc when possible
25  * patch11: index("little", "longer string") could visit faraway places
26  * patch11: warn '-' x 10000 dumped core
27  * patch11: forked exec on non-existent program now issues a warning
28  * 
29  * Revision 4.0.1.2  91/06/07  12:10:42  lwall
30  * patch4: new copyright notice
31  * patch4: made some allowances for "semi-standard" C
32  * patch4: index() could blow up searching for null string
33  * patch4: taintchecks could improperly modify parent in vfork()
34  * patch4: exec would close files even if you cleared close-on-exec flag
35  * 
36  * Revision 4.0.1.1  91/04/12  09:19:25  lwall
37  * patch1: random cleanup in cpp namespace
38  * 
39  * Revision 4.0  91/03/20  01:56:39  lwall
40  * 4.0 baseline.
41  * 
42  */
43 /*SUPPRESS 112*/
44
45 #include "EXTERN.h"
46 #include "perl.h"
47
48 #if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
49 #include <signal.h>
50 #endif
51
52 #ifdef I_VFORK
53 #  include <vfork.h>
54 #endif
55
56 #ifdef I_VARARGS
57 #  include <varargs.h>
58 #endif
59
60 #ifdef I_FCNTL
61 #  include <fcntl.h>
62 #endif
63 #ifdef I_SYS_FILE
64 #  include <sys/file.h>
65 #endif
66
67 #define FLUSH
68
69 #ifndef safemalloc
70
71 static char nomem[] = "Out of memory!\n";
72
73 /* paranoid version of malloc */
74
75 #ifdef DEBUGGING
76 static int an = 0;
77 #endif
78
79 /* NOTE:  Do not call the next three routines directly.  Use the macros
80  * in handy.h, so that we can easily redefine everything to do tracking of
81  * allocated hunks back to the original New to track down any memory leaks.
82  */
83
84 char *
85 safemalloc(size)
86 #ifdef MSDOS
87 unsigned long size;
88 #else
89 MEM_SIZE size;
90 #endif /* MSDOS */
91 {
92     char *ptr;
93 #ifndef STANDARD_C
94     char *malloc();
95 #endif /* ! STANDARD_C */
96
97 #ifdef MSDOS
98         if (size > 0xffff) {
99                 fprintf(stderr, "Allocation too large: %lx\n", size) FLUSH;
100                 exit(1);
101         }
102 #endif /* MSDOS */
103 #ifdef DEBUGGING
104     if ((long)size < 0)
105         fatal("panic: malloc");
106 #endif
107     ptr = malloc(size?size:1);  /* malloc(0) is NASTY on our system */
108 #ifdef DEBUGGING
109 #  if !(defined(I286) || defined(atarist))
110     if (debug & 128)
111         fprintf(stderr,"0x%x: (%05d) malloc %ld bytes\n",ptr,an++,(long)size);
112 #  else
113     if (debug & 128)
114         fprintf(stderr,"0x%lx: (%05d) malloc %ld bytes\n",ptr,an++,(long)size);
115 #  endif
116 #endif
117     if (ptr != Nullch)
118         return ptr;
119     else if (nomemok)
120         return Nullch;
121     else {
122         fputs(nomem,stderr) FLUSH;
123         exit(1);
124     }
125     /*NOTREACHED*/
126 #ifdef lint
127     return ptr;
128 #endif
129 }
130
131 /* paranoid version of realloc */
132
133 char *
134 saferealloc(where,size)
135 char *where;
136 #ifndef MSDOS
137 MEM_SIZE size;
138 #else
139 unsigned long size;
140 #endif /* MSDOS */
141 {
142     char *ptr;
143 #ifndef STANDARD_C
144     char *realloc();
145 #endif /* ! STANDARD_C */
146
147 #ifdef MSDOS
148         if (size > 0xffff) {
149                 fprintf(stderr, "Reallocation too large: %lx\n", size) FLUSH;
150                 exit(1);
151         }
152 #endif /* MSDOS */
153     if (!where)
154         fatal("Null realloc");
155 #ifdef DEBUGGING
156     if ((long)size < 0)
157         fatal("panic: realloc");
158 #endif
159     ptr = realloc(where,size?size:1);   /* realloc(0) is NASTY on our system */
160 #ifdef DEBUGGING
161 #  if !(defined(I286) || defined(atarist))
162     if (debug & 128) {
163         fprintf(stderr,"0x%x: (%05d) rfree\n",where,an++);
164         fprintf(stderr,"0x%x: (%05d) realloc %ld bytes\n",ptr,an++,(long)size);
165     }
166 #  else
167     if (debug & 128) {
168         fprintf(stderr,"0x%lx: (%05d) rfree\n",where,an++);
169         fprintf(stderr,"0x%lx: (%05d) realloc %ld bytes\n",ptr,an++,(long)size);
170     }
171 #  endif
172 #endif
173     if (ptr != Nullch)
174         return ptr;
175     else if (nomemok)
176         return Nullch;
177     else {
178         fputs(nomem,stderr) FLUSH;
179         exit(1);
180     }
181     /*NOTREACHED*/
182 #ifdef lint
183     return ptr;
184 #endif
185 }
186
187 /* safe version of free */
188
189 void
190 safefree(where)
191 char *where;
192 {
193 #ifdef DEBUGGING
194 #  if !(defined(I286) || defined(atarist))
195     if (debug & 128)
196         fprintf(stderr,"0x%x: (%05d) free\n",where,an++);
197 #  else
198     if (debug & 128)
199         fprintf(stderr,"0x%lx: (%05d) free\n",where,an++);
200 #  endif
201 #endif
202     if (where) {
203         /*SUPPRESS 701*/
204         free(where);
205     }
206 }
207
208 #endif /* !safemalloc */
209
210 #ifdef LEAKTEST
211
212 #define ALIGN sizeof(long)
213
214 char *
215 safexmalloc(x,size)
216 int x;
217 MEM_SIZE size;
218 {
219     register char *where;
220
221     where = safemalloc(size + ALIGN);
222     xcount[x]++;
223     where[0] = x % 100;
224     where[1] = x / 100;
225     return where + ALIGN;
226 }
227
228 char *
229 safexrealloc(where,size)
230 char *where;
231 MEM_SIZE size;
232 {
233     return saferealloc(where - ALIGN, size + ALIGN) + ALIGN;
234 }
235
236 void
237 safexfree(where)
238 char *where;
239 {
240     int x;
241
242     if (!where)
243         return;
244     where -= ALIGN;
245     x = where[0] + 100 * where[1];
246     xcount[x]--;
247     safefree(where);
248 }
249
250 static void
251 xstat()
252 {
253     register int i;
254
255     for (i = 0; i < MAXXCOUNT; i++) {
256         if (xcount[i] > lastxcount[i]) {
257             fprintf(stderr,"%2d %2d\t%ld\n", i / 100, i % 100, xcount[i]);
258             lastxcount[i] = xcount[i];
259         }
260     }
261 }
262
263 #endif /* LEAKTEST */
264
265 /* copy a string up to some (non-backslashed) delimiter, if any */
266
267 char *
268 cpytill(to,from,fromend,delim,retlen)
269 register char *to;
270 register char *from;
271 register char *fromend;
272 register int delim;
273 int *retlen;
274 {
275     char *origto = to;
276
277     for (; from < fromend; from++,to++) {
278         if (*from == '\\') {
279             if (from[1] == delim)
280                 from++;
281             else if (from[1] == '\\')
282                 *to++ = *from++;
283         }
284         else if (*from == delim)
285             break;
286         *to = *from;
287     }
288     *to = '\0';
289     *retlen = to - origto;
290     return from;
291 }
292
293 /* return ptr to little string in big string, NULL if not found */
294 /* This routine was donated by Corey Satten. */
295
296 char *
297 instr(big, little)
298 register char *big;
299 register char *little;
300 {
301     register char *s, *x;
302     register int first;
303
304     if (!little)
305         return big;
306     first = *little++;
307     if (!first)
308         return big;
309     while (*big) {
310         if (*big++ != first)
311             continue;
312         for (x=big,s=little; *s; /**/ ) {
313             if (!*x)
314                 return Nullch;
315             if (*s++ != *x++) {
316                 s--;
317                 break;
318             }
319         }
320         if (!*s)
321             return big-1;
322     }
323     return Nullch;
324 }
325
326 /* same as instr but allow embedded nulls */
327
328 char *
329 ninstr(big, bigend, little, lend)
330 register char *big;
331 register char *bigend;
332 char *little;
333 char *lend;
334 {
335     register char *s, *x;
336     register int first = *little;
337     register char *littleend = lend;
338
339     if (!first && little > littleend)
340         return big;
341     if (bigend - big < littleend - little)
342         return Nullch;
343     bigend -= littleend - little++;
344     while (big <= bigend) {
345         if (*big++ != first)
346             continue;
347         for (x=big,s=little; s < littleend; /**/ ) {
348             if (*s++ != *x++) {
349                 s--;
350                 break;
351             }
352         }
353         if (s >= littleend)
354             return big-1;
355     }
356     return Nullch;
357 }
358
359 /* reverse of the above--find last substring */
360
361 char *
362 rninstr(big, bigend, little, lend)
363 register char *big;
364 char *bigend;
365 char *little;
366 char *lend;
367 {
368     register char *bigbeg;
369     register char *s, *x;
370     register int first = *little;
371     register char *littleend = lend;
372
373     if (!first && little > littleend)
374         return bigend;
375     bigbeg = big;
376     big = bigend - (littleend - little++);
377     while (big >= bigbeg) {
378         if (*big-- != first)
379             continue;
380         for (x=big+2,s=little; s < littleend; /**/ ) {
381             if (*s++ != *x++) {
382                 s--;
383                 break;
384             }
385         }
386         if (s >= littleend)
387             return big+1;
388     }
389     return Nullch;
390 }
391
392 unsigned char fold[] = {
393         0,      1,      2,      3,      4,      5,      6,      7,
394         8,      9,      10,     11,     12,     13,     14,     15,
395         16,     17,     18,     19,     20,     21,     22,     23,
396         24,     25,     26,     27,     28,     29,     30,     31,
397         32,     33,     34,     35,     36,     37,     38,     39,
398         40,     41,     42,     43,     44,     45,     46,     47,
399         48,     49,     50,     51,     52,     53,     54,     55,
400         56,     57,     58,     59,     60,     61,     62,     63,
401         64,     'a',    'b',    'c',    'd',    'e',    'f',    'g',
402         'h',    'i',    'j',    'k',    'l',    'm',    'n',    'o',
403         'p',    'q',    'r',    's',    't',    'u',    'v',    'w',
404         'x',    'y',    'z',    91,     92,     93,     94,     95,
405         96,     'A',    'B',    'C',    'D',    'E',    'F',    'G',
406         'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
407         'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
408         'X',    'Y',    'Z',    123,    124,    125,    126,    127,
409         128,    129,    130,    131,    132,    133,    134,    135,
410         136,    137,    138,    139,    140,    141,    142,    143,
411         144,    145,    146,    147,    148,    149,    150,    151,
412         152,    153,    154,    155,    156,    157,    158,    159,
413         160,    161,    162,    163,    164,    165,    166,    167,
414         168,    169,    170,    171,    172,    173,    174,    175,
415         176,    177,    178,    179,    180,    181,    182,    183,
416         184,    185,    186,    187,    188,    189,    190,    191,
417         192,    193,    194,    195,    196,    197,    198,    199,
418         200,    201,    202,    203,    204,    205,    206,    207,
419         208,    209,    210,    211,    212,    213,    214,    215,
420         216,    217,    218,    219,    220,    221,    222,    223,    
421         224,    225,    226,    227,    228,    229,    230,    231,
422         232,    233,    234,    235,    236,    237,    238,    239,
423         240,    241,    242,    243,    244,    245,    246,    247,
424         248,    249,    250,    251,    252,    253,    254,    255
425 };
426
427 static unsigned char freq[] = {
428         1,      2,      84,     151,    154,    155,    156,    157,
429         165,    246,    250,    3,      158,    7,      18,     29,
430         40,     51,     62,     73,     85,     96,     107,    118,
431         129,    140,    147,    148,    149,    150,    152,    153,
432         255,    182,    224,    205,    174,    176,    180,    217,
433         233,    232,    236,    187,    235,    228,    234,    226,
434         222,    219,    211,    195,    188,    193,    185,    184,
435         191,    183,    201,    229,    181,    220,    194,    162,
436         163,    208,    186,    202,    200,    218,    198,    179,
437         178,    214,    166,    170,    207,    199,    209,    206,
438         204,    160,    212,    216,    215,    192,    175,    173,
439         243,    172,    161,    190,    203,    189,    164,    230,
440         167,    248,    227,    244,    242,    255,    241,    231,
441         240,    253,    169,    210,    245,    237,    249,    247,
442         239,    168,    252,    251,    254,    238,    223,    221,
443         213,    225,    177,    197,    171,    196,    159,    4,
444         5,      6,      8,      9,      10,     11,     12,     13,
445         14,     15,     16,     17,     19,     20,     21,     22,
446         23,     24,     25,     26,     27,     28,     30,     31,
447         32,     33,     34,     35,     36,     37,     38,     39,
448         41,     42,     43,     44,     45,     46,     47,     48,
449         49,     50,     52,     53,     54,     55,     56,     57,
450         58,     59,     60,     61,     63,     64,     65,     66,
451         67,     68,     69,     70,     71,     72,     74,     75,
452         76,     77,     78,     79,     80,     81,     82,     83,
453         86,     87,     88,     89,     90,     91,     92,     93,
454         94,     95,     97,     98,     99,     100,    101,    102,
455         103,    104,    105,    106,    108,    109,    110,    111,
456         112,    113,    114,    115,    116,    117,    119,    120,
457         121,    122,    123,    124,    125,    126,    127,    128,
458         130,    131,    132,    133,    134,    135,    136,    137,
459         138,    139,    141,    142,    143,    144,    145,    146
460 };
461
462 void
463 fbmcompile(str, iflag)
464 STR *str;
465 int iflag;
466 {
467     register unsigned char *s;
468     register unsigned char *table;
469     register unsigned int i;
470     register unsigned int len = str->str_cur;
471     int rarest = 0;
472     unsigned int frequency = 256;
473
474     Str_Grow(str,len+258);
475 #ifndef lint
476     table = (unsigned char*)(str->str_ptr + len + 1);
477 #else
478     table = Null(unsigned char*);
479 #endif
480     s = table - 2;
481     for (i = 0; i < 256; i++) {
482         table[i] = len;
483     }
484     i = 0;
485 #ifndef lint
486     while (s >= (unsigned char*)(str->str_ptr))
487 #endif
488     {
489         if (table[*s] == len) {
490 #ifndef pdp11
491             if (iflag)
492                 table[*s] = table[fold[*s]] = i;
493 #else
494             if (iflag) {
495                 int j;
496                 j = fold[*s];
497                 table[j] = i;
498                 table[*s] = i;
499             }
500 #endif /* pdp11 */
501             else
502                 table[*s] = i;
503         }
504         s--,i++;
505     }
506     str->str_pok |= SP_FBM;             /* deep magic */
507
508 #ifndef lint
509     s = (unsigned char*)(str->str_ptr);         /* deeper magic */
510 #else
511     s = Null(unsigned char*);
512 #endif
513     if (iflag) {
514         register unsigned int tmp, foldtmp;
515         str->str_pok |= SP_CASEFOLD;
516         for (i = 0; i < len; i++) {
517             tmp=freq[s[i]];
518             foldtmp=freq[fold[s[i]]];
519             if (tmp < frequency && foldtmp < frequency) {
520                 rarest = i;
521                 /* choose most frequent among the two */
522                 frequency = (tmp > foldtmp) ? tmp : foldtmp;
523             }
524         }
525     }
526     else {
527         for (i = 0; i < len; i++) {
528             if (freq[s[i]] < frequency) {
529                 rarest = i;
530                 frequency = freq[s[i]];
531             }
532         }
533     }
534     str->str_rare = s[rarest];
535     str->str_state = rarest;
536 #ifdef DEBUGGING
537     if (debug & 512)
538         fprintf(stderr,"rarest char %c at %d\n",str->str_rare, str->str_state);
539 #endif
540 }
541
542 char *
543 fbminstr(big, bigend, littlestr)
544 unsigned char *big;
545 register unsigned char *bigend;
546 STR *littlestr;
547 {
548     register unsigned char *s;
549     register int tmp;
550     register int littlelen;
551     register unsigned char *little;
552     register unsigned char *table;
553     register unsigned char *olds;
554     register unsigned char *oldlittle;
555
556 #ifndef lint
557     if (!(littlestr->str_pok & SP_FBM)) {
558         if (!littlestr->str_ptr)
559             return (char*)big;
560         return ninstr((char*)big,(char*)bigend,
561                 littlestr->str_ptr, littlestr->str_ptr + littlestr->str_cur);
562     }
563 #endif
564
565     littlelen = littlestr->str_cur;
566 #ifndef lint
567     if (littlestr->str_pok & SP_TAIL && !multiline) {   /* tail anchored? */
568         if (littlelen > bigend - big)
569             return Nullch;
570         little = (unsigned char*)littlestr->str_ptr;
571         if (littlestr->str_pok & SP_CASEFOLD) { /* oops, fake it */
572             big = bigend - littlelen;           /* just start near end */
573             if (bigend[-1] == '\n' && little[littlelen-1] != '\n')
574                 big--;
575         }
576         else {
577             s = bigend - littlelen;
578             if (*s == *little && bcmp(s,little,littlelen)==0)
579                 return (char*)s;                /* how sweet it is */
580             else if (bigend[-1] == '\n' && little[littlelen-1] != '\n'
581               && s > big) {
582                     s--;
583                 if (*s == *little && bcmp(s,little,littlelen)==0)
584                     return (char*)s;
585             }
586             return Nullch;
587         }
588     }
589     table = (unsigned char*)(littlestr->str_ptr + littlelen + 1);
590 #else
591     table = Null(unsigned char*);
592 #endif
593     if (--littlelen >= bigend - big)
594         return Nullch;
595     s = big + littlelen;
596     oldlittle = little = table - 2;
597     if (littlestr->str_pok & SP_CASEFOLD) {     /* case insensitive? */
598         if (s < bigend) {
599           top1:
600             /*SUPPRESS 560*/
601             if (tmp = table[*s]) {
602 #ifdef POINTERRIGOR
603                 if (bigend - s > tmp) {
604                     s += tmp;
605                     goto top1;
606                 }
607 #else
608                 if ((s += tmp) < bigend)
609                     goto top1;
610 #endif
611                 return Nullch;
612             }
613             else {
614                 tmp = littlelen;        /* less expensive than calling strncmp() */
615                 olds = s;
616                 while (tmp--) {
617                     if (*--s == *--little || fold[*s] == *little)
618                         continue;
619                     s = olds + 1;       /* here we pay the price for failure */
620                     little = oldlittle;
621                     if (s < bigend)     /* fake up continue to outer loop */
622                         goto top1;
623                     return Nullch;
624                 }
625 #ifndef lint
626                 return (char *)s;
627 #endif
628             }
629         }
630     }
631     else {
632         if (s < bigend) {
633           top2:
634             /*SUPPRESS 560*/
635             if (tmp = table[*s]) {
636 #ifdef POINTERRIGOR
637                 if (bigend - s > tmp) {
638                     s += tmp;
639                     goto top2;
640                 }
641 #else
642                 if ((s += tmp) < bigend)
643                     goto top2;
644 #endif
645                 return Nullch;
646             }
647             else {
648                 tmp = littlelen;        /* less expensive than calling strncmp() */
649                 olds = s;
650                 while (tmp--) {
651                     if (*--s == *--little)
652                         continue;
653                     s = olds + 1;       /* here we pay the price for failure */
654                     little = oldlittle;
655                     if (s < bigend)     /* fake up continue to outer loop */
656                         goto top2;
657                     return Nullch;
658                 }
659 #ifndef lint
660                 return (char *)s;
661 #endif
662             }
663         }
664     }
665     return Nullch;
666 }
667
668 char *
669 screaminstr(bigstr, littlestr)
670 STR *bigstr;
671 STR *littlestr;
672 {
673     register unsigned char *s, *x;
674     register unsigned char *big;
675     register int pos;
676     register int previous;
677     register int first;
678     register unsigned char *little;
679     register unsigned char *bigend;
680     register unsigned char *littleend;
681
682     if ((pos = screamfirst[littlestr->str_rare]) < 0) 
683         return Nullch;
684 #ifndef lint
685     little = (unsigned char *)(littlestr->str_ptr);
686 #else
687     little = Null(unsigned char *);
688 #endif
689     littleend = little + littlestr->str_cur;
690     first = *little++;
691     previous = littlestr->str_state;
692 #ifndef lint
693     big = (unsigned char *)(bigstr->str_ptr);
694 #else
695     big = Null(unsigned char*);
696 #endif
697     bigend = big + bigstr->str_cur;
698     while (pos < previous) {
699 #ifndef lint
700         if (!(pos += screamnext[pos]))
701 #endif
702             return Nullch;
703     }
704 #ifdef POINTERRIGOR
705     if (littlestr->str_pok & SP_CASEFOLD) {     /* case insignificant? */
706         do {
707             if (big[pos-previous] != first && big[pos-previous] != fold[first])
708                 continue;
709             for (x=big+pos+1-previous,s=little; s < littleend; /**/ ) {
710                 if (x >= bigend)
711                     return Nullch;
712                 if (*s++ != *x++ && fold[*(s-1)] != *(x-1)) {
713                     s--;
714                     break;
715                 }
716             }
717             if (s == littleend)
718 #ifndef lint
719                 return (char *)(big+pos-previous);
720 #else
721                 return Nullch;
722 #endif
723         } while (
724 #ifndef lint
725                 pos += screamnext[pos]  /* does this goof up anywhere? */
726 #else
727                 pos += screamnext[0]
728 #endif
729             );
730     }
731     else {
732         do {
733             if (big[pos-previous] != first)
734                 continue;
735             for (x=big+pos+1-previous,s=little; s < littleend; /**/ ) {
736                 if (x >= bigend)
737                     return Nullch;
738                 if (*s++ != *x++) {
739                     s--;
740                     break;
741                 }
742             }
743             if (s == littleend)
744 #ifndef lint
745                 return (char *)(big+pos-previous);
746 #else
747                 return Nullch;
748 #endif
749         } while (
750 #ifndef lint
751                 pos += screamnext[pos]
752 #else
753                 pos += screamnext[0]
754 #endif
755             );
756     }
757 #else /* !POINTERRIGOR */
758     big -= previous;
759     if (littlestr->str_pok & SP_CASEFOLD) {     /* case insignificant? */
760         do {
761             if (big[pos] != first && big[pos] != fold[first])
762                 continue;
763             for (x=big+pos+1,s=little; s < littleend; /**/ ) {
764                 if (x >= bigend)
765                     return Nullch;
766                 if (*s++ != *x++ && fold[*(s-1)] != *(x-1)) {
767                     s--;
768                     break;
769                 }
770             }
771             if (s == littleend)
772 #ifndef lint
773                 return (char *)(big+pos);
774 #else
775                 return Nullch;
776 #endif
777         } while (
778 #ifndef lint
779                 pos += screamnext[pos]  /* does this goof up anywhere? */
780 #else
781                 pos += screamnext[0]
782 #endif
783             );
784     }
785     else {
786         do {
787             if (big[pos] != first)
788                 continue;
789             for (x=big+pos+1,s=little; s < littleend; /**/ ) {
790                 if (x >= bigend)
791                     return Nullch;
792                 if (*s++ != *x++) {
793                     s--;
794                     break;
795                 }
796             }
797             if (s == littleend)
798 #ifndef lint
799                 return (char *)(big+pos);
800 #else
801                 return Nullch;
802 #endif
803         } while (
804 #ifndef lint
805                 pos += screamnext[pos]
806 #else
807                 pos += screamnext[0]
808 #endif
809             );
810     }
811 #endif /* POINTERRIGOR */
812     return Nullch;
813 }
814
815 /* copy a string to a safe spot */
816
817 char *
818 savestr(str)
819 char *str;
820 {
821     register char *newaddr;
822
823     New(902,newaddr,strlen(str)+1,char);
824     (void)strcpy(newaddr,str);
825     return newaddr;
826 }
827
828 /* same thing but with a known length */
829
830 char *
831 nsavestr(str, len)
832 char *str;
833 register int len;
834 {
835     register char *newaddr;
836
837     New(903,newaddr,len+1,char);
838     Copy(str,newaddr,len,char);         /* might not be null terminated */
839     newaddr[len] = '\0';                /* is now */
840     return newaddr;
841 }
842
843 /* grow a static string to at least a certain length */
844
845 void
846 growstr(strptr,curlen,newlen)
847 char **strptr;
848 int *curlen;
849 int newlen;
850 {
851     if (newlen > *curlen) {             /* need more room? */
852         if (*curlen)
853             Renew(*strptr,newlen,char);
854         else
855             New(905,*strptr,newlen,char);
856         *curlen = newlen;
857     }
858 }
859
860 #ifndef I_VARARGS
861 /*VARARGS1*/
862 char *
863 mess(pat,a1,a2,a3,a4)
864 char *pat;
865 long a1, a2, a3, a4;
866 {
867     char *s;
868     int usermess = strEQ(pat,"%s");
869     STR *tmpstr;
870
871     s = buf;
872     if (usermess) {
873         tmpstr = str_mortal(&str_undef);
874         str_set(tmpstr, (char*)a1);
875         *s++ = tmpstr->str_ptr[tmpstr->str_cur-1];
876     }
877     else {
878         (void)sprintf(s,pat,a1,a2,a3,a4);
879         s += strlen(s);
880     }
881
882     if (s[-1] != '\n') {
883         if (curcmd->c_line) {
884             (void)sprintf(s," at %s line %ld",
885               stab_val(curcmd->c_filestab)->str_ptr, (long)curcmd->c_line);
886             s += strlen(s);
887         }
888         if (last_in_stab &&
889             stab_io(last_in_stab) &&
890             stab_io(last_in_stab)->lines ) {
891             (void)sprintf(s,", <%s> line %ld",
892               last_in_stab == argvstab ? "" : stab_ename(last_in_stab),
893               (long)stab_io(last_in_stab)->lines);
894             s += strlen(s);
895         }
896         (void)strcpy(s,".\n");
897         if (usermess)
898             str_cat(tmpstr,buf+1);
899     }
900     if (usermess)
901         return tmpstr->str_ptr;
902     else
903         return buf;
904 }
905
906 /*VARARGS1*/
907 void fatal(pat,a1,a2,a3,a4)
908 char *pat;
909 long a1, a2, a3, a4;
910 {
911     extern FILE *e_fp;
912     extern char *e_tmpname;
913     char *tmps;
914     char *message;
915
916     message = mess(pat,a1,a2,a3,a4);
917     if (in_eval) {
918         str_set(stab_val(stabent("@",TRUE)),message);
919         tmps = "_EVAL_";
920         while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
921           strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
922 #ifdef DEBUGGING
923             if (debug & 4) {
924                 deb("(Skipping label #%d %s)\n",loop_ptr,
925                     loop_stack[loop_ptr].loop_label);
926             }
927 #endif
928             loop_ptr--;
929         }
930 #ifdef DEBUGGING
931         if (debug & 4) {
932             deb("(Found label #%d %s)\n",loop_ptr,
933                 loop_stack[loop_ptr].loop_label);
934         }
935 #endif
936         if (loop_ptr < 0) {
937             in_eval = 0;
938             fatal("Bad label: %s", tmps);
939         }
940         longjmp(loop_stack[loop_ptr].loop_env, 1);
941     }
942     fputs(message,stderr);
943     (void)fflush(stderr);
944     if (e_fp)
945         (void)UNLINK(e_tmpname);
946     statusvalue >>= 8;
947     exit((int)((errno&255)?errno:((statusvalue&255)?statusvalue:255)));
948 }
949
950 /*VARARGS1*/
951 void warn(pat,a1,a2,a3,a4)
952 char *pat;
953 long a1, a2, a3, a4;
954 {
955     char *message;
956
957     message = mess(pat,a1,a2,a3,a4);
958     fputs(message,stderr);
959 #ifdef LEAKTEST
960 #ifdef DEBUGGING
961     if (debug & 4096)
962         xstat();
963 #endif
964 #endif
965     (void)fflush(stderr);
966 }
967 #else
968 /*VARARGS0*/
969 char *
970 mess(args)
971 va_list args;
972 {
973     char *pat;
974     char *s;
975     STR *tmpstr;
976     int usermess;
977 #ifndef HAS_VPRINTF
978 #ifdef CHARVSPRINTF
979     char *vsprintf();
980 #else
981     int vsprintf();
982 #endif
983 #endif
984
985 #ifdef lint
986     pat = Nullch;
987 #else
988     pat = va_arg(args, char *);
989 #endif
990     s = buf;
991     usermess = strEQ(pat, "%s");
992     if (usermess) {
993         tmpstr = str_mortal(&str_undef);
994         str_set(tmpstr, va_arg(args, char *));
995         *s++ = tmpstr->str_ptr[tmpstr->str_cur-1];
996     }
997     else {
998         (void) vsprintf(s,pat,args);
999         s += strlen(s);
1000     }
1001
1002     if (s[-1] != '\n') {
1003         if (curcmd->c_line) {
1004             (void)sprintf(s," at %s line %ld",
1005               stab_val(curcmd->c_filestab)->str_ptr, (long)curcmd->c_line);
1006             s += strlen(s);
1007         }
1008         if (last_in_stab &&
1009             stab_io(last_in_stab) &&
1010             stab_io(last_in_stab)->lines ) {
1011             (void)sprintf(s,", <%s> line %ld",
1012               last_in_stab == argvstab ? "" : last_in_stab->str_magic->str_ptr,
1013               (long)stab_io(last_in_stab)->lines);
1014             s += strlen(s);
1015         }
1016         (void)strcpy(s,".\n");
1017         if (usermess)
1018             str_cat(tmpstr,buf+1);
1019     }
1020
1021     if (usermess)
1022         return tmpstr->str_ptr;
1023     else
1024         return buf;
1025 }
1026
1027 /*VARARGS0*/
1028 void fatal(va_alist)
1029 va_dcl
1030 {
1031     va_list args;
1032     extern FILE *e_fp;
1033     extern char *e_tmpname;
1034     char *tmps;
1035     char *message;
1036
1037 #ifndef lint
1038     va_start(args);
1039 #else
1040     args = 0;
1041 #endif
1042     message = mess(args);
1043     va_end(args);
1044     if (in_eval) {
1045         str_set(stab_val(stabent("@",TRUE)),message);
1046         tmps = "_EVAL_";
1047         while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
1048           strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
1049 #ifdef DEBUGGING
1050             if (debug & 4) {
1051                 deb("(Skipping label #%d %s)\n",loop_ptr,
1052                     loop_stack[loop_ptr].loop_label);
1053             }
1054 #endif
1055             loop_ptr--;
1056         }
1057 #ifdef DEBUGGING
1058         if (debug & 4) {
1059             deb("(Found label #%d %s)\n",loop_ptr,
1060                 loop_stack[loop_ptr].loop_label);
1061         }
1062 #endif
1063         if (loop_ptr < 0) {
1064             in_eval = 0;
1065             fatal("Bad label: %s", tmps);
1066         }
1067         longjmp(loop_stack[loop_ptr].loop_env, 1);
1068     }
1069     fputs(message,stderr);
1070     (void)fflush(stderr);
1071     if (e_fp)
1072         (void)UNLINK(e_tmpname);
1073     statusvalue >>= 8;
1074     exit((int)((errno&255)?errno:((statusvalue&255)?statusvalue:255)));
1075 }
1076
1077 /*VARARGS0*/
1078 void warn(va_alist)
1079 va_dcl
1080 {
1081     va_list args;
1082     char *message;
1083
1084 #ifndef lint
1085     va_start(args);
1086 #else
1087     args = 0;
1088 #endif
1089     message = mess(args);
1090     va_end(args);
1091
1092     fputs(message,stderr);
1093 #ifdef LEAKTEST
1094 #ifdef DEBUGGING
1095     if (debug & 4096)
1096         xstat();
1097 #endif
1098 #endif
1099     (void)fflush(stderr);
1100 }
1101 #endif
1102
1103 void
1104 my_setenv(nam,val)
1105 char *nam, *val;
1106 {
1107     register int i=envix(nam);          /* where does it go? */
1108
1109     if (environ == origenviron) {       /* need we copy environment? */
1110         int j;
1111         int max;
1112         char **tmpenv;
1113
1114         /*SUPPRESS 530*/
1115         for (max = i; environ[max]; max++) ;
1116         New(901,tmpenv, max+2, char*);
1117         for (j=0; j<max; j++)           /* copy environment */
1118             tmpenv[j] = savestr(environ[j]);
1119         tmpenv[max] = Nullch;
1120         environ = tmpenv;               /* tell exec where it is now */
1121     }
1122     if (!val) {
1123         while (environ[i]) {
1124             environ[i] = environ[i+1];
1125             i++;
1126         }
1127         return;
1128     }
1129     if (!environ[i]) {                  /* does not exist yet */
1130         Renew(environ, i+2, char*);     /* just expand it a bit */
1131         environ[i+1] = Nullch;  /* make sure it's null terminated */
1132     }
1133     else
1134         Safefree(environ[i]);
1135     New(904, environ[i], strlen(nam) + strlen(val) + 2, char);
1136 #ifndef MSDOS
1137     (void)sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
1138 #else
1139     /* MS-DOS requires environment variable names to be in uppercase */
1140     /* [Tom Dinger, 27 August 1990: Well, it doesn't _require_ it, but
1141      * some utilities and applications may break because they only look
1142      * for upper case strings. (Fixed strupr() bug here.)]
1143      */
1144     strcpy(environ[i],nam); strupr(environ[i]);
1145     (void)sprintf(environ[i] + strlen(nam),"=%s",val);
1146 #endif /* MSDOS */
1147 }
1148
1149 int
1150 envix(nam)
1151 char *nam;
1152 {
1153     register int i, len = strlen(nam);
1154
1155     for (i = 0; environ[i]; i++) {
1156         if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
1157             break;                      /* strnEQ must come first to avoid */
1158     }                                   /* potential SEGV's */
1159     return i;
1160 }
1161
1162 #ifdef EUNICE
1163 int
1164 unlnk(f)        /* unlink all versions of a file */
1165 char *f;
1166 {
1167     int i;
1168
1169     for (i = 0; unlink(f) >= 0; i++) ;
1170     return i ? 0 : -1;
1171 }
1172 #endif
1173
1174 #if !defined(HAS_BCOPY) || !defined(SAFE_BCOPY)
1175 char *
1176 my_bcopy(from,to,len)
1177 register char *from;
1178 register char *to;
1179 register int len;
1180 {
1181     char *retval = to;
1182
1183     if (from - to >= 0) {
1184         while (len--)
1185             *to++ = *from++;
1186     }
1187     else {
1188         to += len;
1189         from += len;
1190         while (len--)
1191             *(--to) = *(--from);
1192     }
1193     return retval;
1194 }
1195 #endif
1196
1197 #if !defined(HAS_BZERO) && !defined(HAS_MEMSET)
1198 char *
1199 my_bzero(loc,len)
1200 register char *loc;
1201 register int len;
1202 {
1203     char *retval = loc;
1204
1205     while (len--)
1206         *loc++ = 0;
1207     return retval;
1208 }
1209 #endif
1210
1211 #ifndef HAS_MEMCMP
1212 int
1213 my_memcmp(s1,s2,len)
1214 register unsigned char *s1;
1215 register unsigned char *s2;
1216 register int len;
1217 {
1218     register int tmp;
1219
1220     while (len--) {
1221         if (tmp = *s1++ - *s2++)
1222             return tmp;
1223     }
1224     return 0;
1225 }
1226 #endif /* HAS_MEMCMP */
1227
1228 #ifdef I_VARARGS
1229 #ifndef HAS_VPRINTF
1230
1231 #ifdef CHARVSPRINTF
1232 char *
1233 #else
1234 int
1235 #endif
1236 vsprintf(dest, pat, args)
1237 char *dest, *pat, *args;
1238 {
1239     FILE fakebuf;
1240
1241     fakebuf._ptr = dest;
1242     fakebuf._cnt = 32767;
1243 #ifndef _IOSTRG
1244 #define _IOSTRG 0
1245 #endif
1246     fakebuf._flag = _IOWRT|_IOSTRG;
1247     _doprnt(pat, args, &fakebuf);       /* what a kludge */
1248     (void)putc('\0', &fakebuf);
1249 #ifdef CHARVSPRINTF
1250     return(dest);
1251 #else
1252     return 0;           /* perl doesn't use return value */
1253 #endif
1254 }
1255
1256 #ifdef DEBUGGING
1257 int
1258 vfprintf(fd, pat, args)
1259 FILE *fd;
1260 char *pat, *args;
1261 {
1262     _doprnt(pat, args, fd);
1263     return 0;           /* wrong, but perl doesn't use the return value */
1264 }
1265 #endif
1266 #endif /* HAS_VPRINTF */
1267 #endif /* I_VARARGS */
1268
1269 /*
1270  * I think my_swap(), htonl() and ntohl() have never been used.
1271  * perl.h contains last-chance references to my_swap(), my_htonl()
1272  * and my_ntohl().  I presume these are the intended functions;
1273  * but htonl() and ntohl() have the wrong names.  There are no
1274  * functions my_htonl() and my_ntohl() defined anywhere.
1275  * -DWS
1276  */
1277 #ifdef MYSWAP
1278 #if BYTEORDER != 0x4321
1279 short
1280 my_swap(s)
1281 short s;
1282 {
1283 #if (BYTEORDER & 1) == 0
1284     short result;
1285
1286     result = ((s & 255) << 8) + ((s >> 8) & 255);
1287     return result;
1288 #else
1289     return s;
1290 #endif
1291 }
1292
1293 long
1294 htonl(l)
1295 register long l;
1296 {
1297     union {
1298         long result;
1299         char c[sizeof(long)];
1300     } u;
1301
1302 #if BYTEORDER == 0x1234
1303     u.c[0] = (l >> 24) & 255;
1304     u.c[1] = (l >> 16) & 255;
1305     u.c[2] = (l >> 8) & 255;
1306     u.c[3] = l & 255;
1307     return u.result;
1308 #else
1309 #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
1310     fatal("Unknown BYTEORDER\n");
1311 #else
1312     register int o;
1313     register int s;
1314
1315     for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
1316         u.c[o & 0xf] = (l >> s) & 255;
1317     }
1318     return u.result;
1319 #endif
1320 #endif
1321 }
1322
1323 long
1324 ntohl(l)
1325 register long l;
1326 {
1327     union {
1328         long l;
1329         char c[sizeof(long)];
1330     } u;
1331
1332 #if BYTEORDER == 0x1234
1333     u.c[0] = (l >> 24) & 255;
1334     u.c[1] = (l >> 16) & 255;
1335     u.c[2] = (l >> 8) & 255;
1336     u.c[3] = l & 255;
1337     return u.l;
1338 #else
1339 #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
1340     fatal("Unknown BYTEORDER\n");
1341 #else
1342     register int o;
1343     register int s;
1344
1345     u.l = l;
1346     l = 0;
1347     for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
1348         l |= (u.c[o & 0xf] & 255) << s;
1349     }
1350     return l;
1351 #endif
1352 #endif
1353 }
1354
1355 #endif /* BYTEORDER != 0x4321 */
1356 #endif /* MYSWAP */
1357
1358 /*
1359  * Little-endian byte order functions - 'v' for 'VAX', or 'reVerse'.
1360  * If these functions are defined,
1361  * the BYTEORDER is neither 0x1234 nor 0x4321.
1362  * However, this is not assumed.
1363  * -DWS
1364  */
1365
1366 #define HTOV(name,type)                                         \
1367         type                                                    \
1368         name (n)                                                \
1369         register type n;                                        \
1370         {                                                       \
1371             union {                                             \
1372                 type value;                                     \
1373                 char c[sizeof(type)];                           \
1374             } u;                                                \
1375             register int i;                                     \
1376             register int s;                                     \
1377             for (i = 0, s = 0; i < sizeof(u.c); i++, s += 8) {  \
1378                 u.c[i] = (n >> s) & 0xFF;                       \
1379             }                                                   \
1380             return u.value;                                     \
1381         }
1382
1383 #define VTOH(name,type)                                         \
1384         type                                                    \
1385         name (n)                                                \
1386         register type n;                                        \
1387         {                                                       \
1388             union {                                             \
1389                 type value;                                     \
1390                 char c[sizeof(type)];                           \
1391             } u;                                                \
1392             register int i;                                     \
1393             register int s;                                     \
1394             u.value = n;                                        \
1395             n = 0;                                              \
1396             for (i = 0, s = 0; i < sizeof(u.c); i++, s += 8) {  \
1397                 n += (u.c[i] & 0xFF) << s;                      \
1398             }                                                   \
1399             return n;                                           \
1400         }
1401
1402 #if defined(HAS_HTOVS) && !defined(htovs)
1403 HTOV(htovs,short)
1404 #endif
1405 #if defined(HAS_HTOVL) && !defined(htovl)
1406 HTOV(htovl,long)
1407 #endif
1408 #if defined(HAS_VTOHS) && !defined(vtohs)
1409 VTOH(vtohs,short)
1410 #endif
1411 #if defined(HAS_VTOHL) && !defined(vtohl)
1412 VTOH(vtohl,long)
1413 #endif
1414
1415 #ifndef DOSISH
1416 FILE *
1417 mypopen(cmd,mode)
1418 char    *cmd;
1419 char    *mode;
1420 {
1421     int p[2];
1422     register int this, that;
1423     register int pid;
1424     STR *str;
1425     int doexec = strNE(cmd,"-");
1426
1427     if (pipe(p) < 0)
1428         return Nullfp;
1429     this = (*mode == 'w');
1430     that = !this;
1431 #ifdef TAINT
1432     if (doexec) {
1433         taintenv();
1434         taintproper("Insecure dependency in exec");
1435     }
1436 #endif
1437     while ((pid = (doexec?vfork():fork())) < 0) {
1438         if (errno != EAGAIN) {
1439             close(p[this]);
1440             if (!doexec)
1441                 fatal("Can't fork");
1442             return Nullfp;
1443         }
1444         sleep(5);
1445     }
1446     if (pid == 0) {
1447 #define THIS that
1448 #define THAT this
1449         close(p[THAT]);
1450         if (p[THIS] != (*mode == 'r')) {
1451             dup2(p[THIS], *mode == 'r');
1452             close(p[THIS]);
1453         }
1454         if (doexec) {
1455 #if !defined(HAS_FCNTL) || !defined(F_SETFD)
1456             int fd;
1457
1458 #ifndef NOFILE
1459 #define NOFILE 20
1460 #endif
1461             for (fd = maxsysfd + 1; fd < NOFILE; fd++)
1462                 close(fd);
1463 #endif
1464             do_exec(cmd);       /* may or may not use the shell */
1465             warn("Can't exec \"%s\": %s", cmd, strerror(errno));
1466             _exit(1);
1467         }
1468         /*SUPPRESS 560*/
1469         if (tmpstab = stabent("$",allstabs))
1470             str_numset(STAB_STR(tmpstab),(double)getpid());
1471         forkprocess = 0;
1472         hclear(pidstatus, FALSE);       /* we have no children */
1473         return Nullfp;
1474 #undef THIS
1475 #undef THAT
1476     }
1477     do_execfree();      /* free any memory malloced by child on vfork */
1478     close(p[that]);
1479     if (p[that] < p[this]) {
1480         dup2(p[this], p[that]);
1481         close(p[this]);
1482         p[this] = p[that];
1483     }
1484     str = afetch(fdpid,p[this],TRUE);
1485     str->str_u.str_useful = pid;
1486     forkprocess = pid;
1487     return fdopen(p[this], mode);
1488 }
1489 #else
1490 #ifdef atarist
1491 FILE *popen();
1492 FILE *
1493 mypopen(cmd,mode)
1494 char    *cmd;
1495 char    *mode;
1496 {
1497     return popen(cmd, mode);
1498 }
1499 #endif
1500
1501 #endif /* !DOSISH */
1502
1503 #ifdef NOTDEF
1504 dumpfds(s)
1505 char *s;
1506 {
1507     int fd;
1508     struct stat tmpstatbuf;
1509
1510     fprintf(stderr,"%s", s);
1511     for (fd = 0; fd < 32; fd++) {
1512         if (fstat(fd,&tmpstatbuf) >= 0)
1513             fprintf(stderr," %d",fd);
1514     }
1515     fprintf(stderr,"\n");
1516 }
1517 #endif
1518
1519 #ifndef HAS_DUP2
1520 dup2(oldfd,newfd)
1521 int oldfd;
1522 int newfd;
1523 {
1524 #if defined(HAS_FCNTL) && defined(F_DUPFD)
1525     close(newfd);
1526     fcntl(oldfd, F_DUPFD, newfd);
1527 #else
1528     int fdtmp[256];
1529     int fdx = 0;
1530     int fd;
1531
1532     if (oldfd == newfd)
1533         return 0;
1534     close(newfd);
1535     while ((fd = dup(oldfd)) != newfd)  /* good enough for low fd's */
1536         fdtmp[fdx++] = fd;
1537     while (fdx > 0)
1538         close(fdtmp[--fdx]);
1539 #endif
1540 }
1541 #endif
1542
1543 #ifndef DOSISH
1544 int
1545 mypclose(ptr)
1546 FILE *ptr;
1547 {
1548 #ifdef VOIDSIG
1549     void (*hstat)(), (*istat)(), (*qstat)();
1550 #else
1551     int (*hstat)(), (*istat)(), (*qstat)();
1552 #endif
1553     int status;
1554     STR *str;
1555     int pid;
1556
1557     str = afetch(fdpid,fileno(ptr),TRUE);
1558     pid = (int)str->str_u.str_useful;
1559     astore(fdpid,fileno(ptr),Nullstr);
1560     fclose(ptr);
1561 #ifdef UTS
1562     if(kill(pid, 0) < 0) { return(pid); }   /* HOM 12/23/91 */
1563 #endif
1564     hstat = signal(SIGHUP, SIG_IGN);
1565     istat = signal(SIGINT, SIG_IGN);
1566     qstat = signal(SIGQUIT, SIG_IGN);
1567     pid = wait4pid(pid, &status, 0);
1568     signal(SIGHUP, hstat);
1569     signal(SIGINT, istat);
1570     signal(SIGQUIT, qstat);
1571     return(pid < 0 ? pid : status);
1572 }
1573
1574 int
1575 wait4pid(pid,statusp,flags)
1576 int pid;
1577 int *statusp;
1578 int flags;
1579 {
1580 #if !defined(HAS_WAIT4) && !defined(HAS_WAITPID)
1581     int result;
1582     STR *str;
1583     char spid[16];
1584 #endif
1585
1586     if (!pid)
1587         return -1;
1588 #ifdef HAS_WAIT4
1589     return wait4((pid==-1)?0:pid,statusp,flags,Null(struct rusage *));
1590 #else
1591 #ifdef HAS_WAITPID
1592     return waitpid(pid,statusp,flags);
1593 #else
1594     if (pid > 0) {
1595         sprintf(spid, "%d", pid);
1596         str = hfetch(pidstatus,spid,strlen(spid),FALSE);
1597         if (str != &str_undef) {
1598             *statusp = (int)str->str_u.str_useful;
1599             hdelete(pidstatus,spid,strlen(spid));
1600             return pid;
1601         }
1602     }
1603     else {
1604         HENT *entry;
1605
1606         hiterinit(pidstatus);
1607         if (entry = hiternext(pidstatus)) {
1608             pid = atoi(hiterkey(entry,statusp));
1609             str = hiterval(pidstatus,entry);
1610             *statusp = (int)str->str_u.str_useful;
1611             sprintf(spid, "%d", pid);
1612             hdelete(pidstatus,spid,strlen(spid));
1613             return pid;
1614         }
1615     }
1616     if (flags)
1617         fatal("Can't do waitpid with flags");
1618     else {
1619         while ((result = wait(statusp)) != pid && pid > 0 && result >= 0)
1620             pidgone(result,*statusp);
1621         if (result < 0)
1622             *statusp = -1;
1623     }
1624     return result;
1625 #endif
1626 #endif
1627 }
1628 #endif /* !DOSISH */
1629
1630 void
1631 /*SUPPRESS 590*/
1632 pidgone(pid,status)
1633 int pid;
1634 int status;
1635 {
1636 #if defined(HAS_WAIT4) || defined(HAS_WAITPID)
1637 #else
1638     register STR *str;
1639     char spid[16];
1640
1641     sprintf(spid, "%d", pid);
1642     str = hfetch(pidstatus,spid,strlen(spid),TRUE);
1643     str->str_u.str_useful = status;
1644 #endif
1645     return;
1646 }
1647
1648 #ifdef atarist
1649 int pclose();
1650 int
1651 mypclose(ptr)
1652 FILE *ptr;
1653 {
1654     return pclose(ptr);
1655 }
1656 #endif
1657
1658 void
1659 repeatcpy(to,from,len,count)
1660 register char *to;
1661 register char *from;
1662 int len;
1663 register int count;
1664 {
1665     register int todo;
1666     register char *frombase = from;
1667
1668     if (len == 1) {
1669         todo = *from;
1670         while (count-- > 0)
1671             *to++ = todo;
1672         return;
1673     }
1674     while (count-- > 0) {
1675         for (todo = len; todo > 0; todo--) {
1676             *to++ = *from++;
1677         }
1678         from = frombase;
1679     }
1680 }
1681
1682 #ifndef CASTNEGFLOAT
1683 unsigned long
1684 castulong(f)
1685 double f;
1686 {
1687     long along;
1688
1689 #if CASTFLAGS & 2
1690 #   define BIGDOUBLE 2147483648.0
1691     if (f >= BIGDOUBLE)
1692         return (unsigned long)(f-(long)(f/BIGDOUBLE)*BIGDOUBLE)|0x80000000;
1693 #endif
1694     if (f >= 0.0)
1695         return (unsigned long)f;
1696     along = (long)f;
1697     return (unsigned long)along;
1698 }
1699 #endif
1700
1701 #ifndef HAS_RENAME
1702 int
1703 same_dirent(a,b)
1704 char *a;
1705 char *b;
1706 {
1707     char *fa = rindex(a,'/');
1708     char *fb = rindex(b,'/');
1709     struct stat tmpstatbuf1;
1710     struct stat tmpstatbuf2;
1711 #ifndef MAXPATHLEN
1712 #define MAXPATHLEN 1024
1713 #endif
1714     char tmpbuf[MAXPATHLEN+1];
1715
1716     if (fa)
1717         fa++;
1718     else
1719         fa = a;
1720     if (fb)
1721         fb++;
1722     else
1723         fb = b;
1724     if (strNE(a,b))
1725         return FALSE;
1726     if (fa == a)
1727         strcpy(tmpbuf,".");
1728     else
1729         strncpy(tmpbuf, a, fa - a);
1730     if (stat(tmpbuf, &tmpstatbuf1) < 0)
1731         return FALSE;
1732     if (fb == b)
1733         strcpy(tmpbuf,".");
1734     else
1735         strncpy(tmpbuf, b, fb - b);
1736     if (stat(tmpbuf, &tmpstatbuf2) < 0)
1737         return FALSE;
1738     return tmpstatbuf1.st_dev == tmpstatbuf2.st_dev &&
1739            tmpstatbuf1.st_ino == tmpstatbuf2.st_ino;
1740 }
1741 #endif /* !HAS_RENAME */
1742
1743 unsigned long
1744 scanoct(start, len, retlen)
1745 char *start;
1746 int len;
1747 int *retlen;
1748 {
1749     register char *s = start;
1750     register unsigned long retval = 0;
1751
1752     while (len-- && *s >= '0' && *s <= '7') {
1753         retval <<= 3;
1754         retval |= *s++ - '0';
1755     }
1756     *retlen = s - start;
1757     return retval;
1758 }
1759
1760 unsigned long
1761 scanhex(start, len, retlen)
1762 char *start;
1763 int len;
1764 int *retlen;
1765 {
1766     register char *s = start;
1767     register unsigned long retval = 0;
1768     char *tmp;
1769
1770     while (len-- && *s && (tmp = index(hexdigit, *s))) {
1771         retval <<= 4;
1772         retval |= (tmp - hexdigit) & 15;
1773         s++;
1774     }
1775     *retlen = s - start;
1776     return retval;
1777 }