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