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