1 /* $RCSfile: util.c,v $$Revision: 4.0.1.1 $$Date: 91/04/12 09:19:25 $
3 * Copyright (c) 1989, Larry Wall
5 * You may distribute under the terms of the GNU General Public License
6 * as specified in the README file that comes with the perl 3.0 kit.
9 * Revision 4.0.1.1 91/04/12 09:19:25 lwall
10 * patch1: random cleanup in cpp namespace
12 * Revision 4.0 91/03/20 01:56:39 lwall
20 #if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
36 # include <sys/file.h>
41 static char nomem[] = "Out of memory!\n";
43 /* paranoid version of malloc */
49 /* NOTE: Do not call the next three routines directly. Use the macros
50 * in handy.h, so that we can easily redefine everything to do tracking of
51 * allocated hunks back to the original New to track down any memory leaks.
65 #endif /* ! __STDC__ */
69 fprintf(stderr, "Allocation too large: %lx\n", size) FLUSH;
75 fatal("panic: malloc");
77 ptr = malloc(size?size:1); /* malloc(0) is NASTY on our system */
81 fprintf(stderr,"0x%x: (%05d) malloc %d bytes\n",ptr,an++,size);
84 fprintf(stderr,"0x%lx: (%05d) malloc %d bytes\n",ptr,an++,size);
90 fputs(nomem,stderr) FLUSH;
99 /* paranoid version of realloc */
102 saferealloc(where,size)
113 #endif /* ! __STDC__ */
117 fprintf(stderr, "Reallocation too large: %lx\n", size) FLUSH;
122 fatal("Null realloc");
125 fatal("panic: realloc");
127 ptr = realloc(where,size?size:1); /* realloc(0) is NASTY on our system */
131 fprintf(stderr,"0x%x: (%05d) rfree\n",where,an++);
132 fprintf(stderr,"0x%x: (%05d) realloc %d bytes\n",ptr,an++,size);
136 fprintf(stderr,"0x%lx: (%05d) rfree\n",where,an++);
137 fprintf(stderr,"0x%lx: (%05d) realloc %d bytes\n",ptr,an++,size);
144 fputs(nomem,stderr) FLUSH;
153 /* safe version of free */
162 fprintf(stderr,"0x%x: (%05d) free\n",where,an++);
165 fprintf(stderr,"0x%lx: (%05d) free\n",where,an++);
175 #define ALIGN sizeof(long)
182 register char *where;
184 where = safemalloc(size + ALIGN);
188 return where + ALIGN;
192 safexrealloc(where,size)
196 return saferealloc(where - ALIGN, size + ALIGN) + ALIGN;
208 x = where[0] + 100 * where[1];
217 for (i = 0; i < MAXXCOUNT; i++) {
218 if (xcount[i] != lastxcount[i]) {
219 fprintf(stderr,"%2d %2d\t%ld\n", i / 100, i % 100, xcount[i]);
220 lastxcount[i] = xcount[i];
225 #endif /* LEAKTEST */
227 /* copy a string up to some (non-backslashed) delimiter, if any */
230 cpytill(to,from,fromend,delim,retlen)
233 register char *fromend;
239 for (; from < fromend; from++,to++) {
241 if (from[1] == delim)
243 else if (from[1] == '\\')
246 else if (*from == delim)
251 *retlen = to - origto;
255 /* return ptr to little string in big string, NULL if not found */
256 /* This routine was donated by Corey Satten. */
261 register char *little;
263 register char *s, *x;
274 for (x=big,s=little; *s; /**/ ) {
288 /* same as instr but allow embedded nulls */
291 ninstr(big, bigend, little, lend)
293 register char *bigend;
297 register char *s, *x;
298 register int first = *little;
299 register char *littleend = lend;
301 if (!first && little > littleend)
303 bigend -= littleend - little++;
304 while (big <= bigend) {
307 for (x=big,s=little; s < littleend; /**/ ) {
319 /* reverse of the above--find last substring */
322 rninstr(big, bigend, little, lend)
328 register char *bigbeg;
329 register char *s, *x;
330 register int first = *little;
331 register char *littleend = lend;
333 if (!first && little > littleend)
336 big = bigend - (littleend - little++);
337 while (big >= bigbeg) {
340 for (x=big+2,s=little; s < littleend; /**/ ) {
352 unsigned char fold[] = {
353 0, 1, 2, 3, 4, 5, 6, 7,
354 8, 9, 10, 11, 12, 13, 14, 15,
355 16, 17, 18, 19, 20, 21, 22, 23,
356 24, 25, 26, 27, 28, 29, 30, 31,
357 32, 33, 34, 35, 36, 37, 38, 39,
358 40, 41, 42, 43, 44, 45, 46, 47,
359 48, 49, 50, 51, 52, 53, 54, 55,
360 56, 57, 58, 59, 60, 61, 62, 63,
361 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
362 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
363 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
364 'x', 'y', 'z', 91, 92, 93, 94, 95,
365 96, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
366 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
367 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
368 'X', 'Y', 'Z', 123, 124, 125, 126, 127,
369 128, 129, 130, 131, 132, 133, 134, 135,
370 136, 137, 138, 139, 140, 141, 142, 143,
371 144, 145, 146, 147, 148, 149, 150, 151,
372 152, 153, 154, 155, 156, 157, 158, 159,
373 160, 161, 162, 163, 164, 165, 166, 167,
374 168, 169, 170, 171, 172, 173, 174, 175,
375 176, 177, 178, 179, 180, 181, 182, 183,
376 184, 185, 186, 187, 188, 189, 190, 191,
377 192, 193, 194, 195, 196, 197, 198, 199,
378 200, 201, 202, 203, 204, 205, 206, 207,
379 208, 209, 210, 211, 212, 213, 214, 215,
380 216, 217, 218, 219, 220, 221, 222, 223,
381 224, 225, 226, 227, 228, 229, 230, 231,
382 232, 233, 234, 235, 236, 237, 238, 239,
383 240, 241, 242, 243, 244, 245, 246, 247,
384 248, 249, 250, 251, 252, 253, 254, 255
387 static unsigned char freq[] = {
388 1, 2, 84, 151, 154, 155, 156, 157,
389 165, 246, 250, 3, 158, 7, 18, 29,
390 40, 51, 62, 73, 85, 96, 107, 118,
391 129, 140, 147, 148, 149, 150, 152, 153,
392 255, 182, 224, 205, 174, 176, 180, 217,
393 233, 232, 236, 187, 235, 228, 234, 226,
394 222, 219, 211, 195, 188, 193, 185, 184,
395 191, 183, 201, 229, 181, 220, 194, 162,
396 163, 208, 186, 202, 200, 218, 198, 179,
397 178, 214, 166, 170, 207, 199, 209, 206,
398 204, 160, 212, 216, 215, 192, 175, 173,
399 243, 172, 161, 190, 203, 189, 164, 230,
400 167, 248, 227, 244, 242, 255, 241, 231,
401 240, 253, 169, 210, 245, 237, 249, 247,
402 239, 168, 252, 251, 254, 238, 223, 221,
403 213, 225, 177, 197, 171, 196, 159, 4,
404 5, 6, 8, 9, 10, 11, 12, 13,
405 14, 15, 16, 17, 19, 20, 21, 22,
406 23, 24, 25, 26, 27, 28, 30, 31,
407 32, 33, 34, 35, 36, 37, 38, 39,
408 41, 42, 43, 44, 45, 46, 47, 48,
409 49, 50, 52, 53, 54, 55, 56, 57,
410 58, 59, 60, 61, 63, 64, 65, 66,
411 67, 68, 69, 70, 71, 72, 74, 75,
412 76, 77, 78, 79, 80, 81, 82, 83,
413 86, 87, 88, 89, 90, 91, 92, 93,
414 94, 95, 97, 98, 99, 100, 101, 102,
415 103, 104, 105, 106, 108, 109, 110, 111,
416 112, 113, 114, 115, 116, 117, 119, 120,
417 121, 122, 123, 124, 125, 126, 127, 128,
418 130, 131, 132, 133, 134, 135, 136, 137,
419 138, 139, 141, 142, 143, 144, 145, 146
423 fbmcompile(str, iflag)
427 register unsigned char *s;
428 register unsigned char *table;
430 register int len = str->str_cur;
432 unsigned int frequency = 256;
434 Str_Grow(str,len+258);
436 table = (unsigned char*)(str->str_ptr + len + 1);
438 table = Null(unsigned char*);
441 for (i = 0; i < 256; i++) {
446 while (s >= (unsigned char*)(str->str_ptr))
449 if (table[*s] == len) {
452 table[*s] = table[fold[*s]] = i;
466 str->str_pok |= SP_FBM; /* deep magic */
469 s = (unsigned char*)(str->str_ptr); /* deeper magic */
471 s = Null(unsigned char*);
474 register unsigned int tmp, foldtmp;
475 str->str_pok |= SP_CASEFOLD;
476 for (i = 0; i < len; i++) {
478 foldtmp=freq[fold[s[i]]];
479 if (tmp < frequency && foldtmp < frequency) {
481 /* choose most frequent among the two */
482 frequency = (tmp > foldtmp) ? tmp : foldtmp;
487 for (i = 0; i < len; i++) {
488 if (freq[s[i]] < frequency) {
490 frequency = freq[s[i]];
494 str->str_rare = s[rarest];
495 str->str_state = rarest;
498 fprintf(stderr,"rarest char %c at %d\n",str->str_rare, str->str_state);
503 fbminstr(big, bigend, littlestr)
505 register unsigned char *bigend;
508 register unsigned char *s;
510 register int littlelen;
511 register unsigned char *little;
512 register unsigned char *table;
513 register unsigned char *olds;
514 register unsigned char *oldlittle;
517 if (!(littlestr->str_pok & SP_FBM))
518 return ninstr((char*)big,(char*)bigend,
519 littlestr->str_ptr, littlestr->str_ptr + littlestr->str_cur);
522 littlelen = littlestr->str_cur;
524 if (littlestr->str_pok & SP_TAIL && !multiline) { /* tail anchored? */
525 if (littlelen > bigend - big)
527 little = (unsigned char*)littlestr->str_ptr;
528 if (littlestr->str_pok & SP_CASEFOLD) { /* oops, fake it */
529 big = bigend - littlelen; /* just start near end */
530 if (bigend[-1] == '\n' && little[littlelen-1] != '\n')
534 s = bigend - littlelen;
535 if (*s == *little && bcmp(s,little,littlelen)==0)
536 return (char*)s; /* how sweet it is */
537 else if (bigend[-1] == '\n' && little[littlelen-1] != '\n'
540 if (*s == *little && bcmp(s,little,littlelen)==0)
546 table = (unsigned char*)(littlestr->str_ptr + littlelen + 1);
548 table = Null(unsigned char*);
550 if (--littlelen >= bigend - big)
553 oldlittle = little = table - 2;
554 if (littlestr->str_pok & SP_CASEFOLD) { /* case insensitive? */
557 if (tmp = table[*s]) {
559 if (bigend - s > tmp) {
564 if ((s += tmp) < bigend)
570 tmp = littlelen; /* less expensive than calling strncmp() */
573 if (*--s == *--little || fold[*s] == *little)
575 s = olds + 1; /* here we pay the price for failure */
577 if (s < bigend) /* fake up continue to outer loop */
590 if (tmp = table[*s]) {
592 if (bigend - s > tmp) {
597 if ((s += tmp) < bigend)
603 tmp = littlelen; /* less expensive than calling strncmp() */
606 if (*--s == *--little)
608 s = olds + 1; /* here we pay the price for failure */
610 if (s < bigend) /* fake up continue to outer loop */
624 screaminstr(bigstr, littlestr)
628 register unsigned char *s, *x;
629 register unsigned char *big;
631 register int previous;
633 register unsigned char *little;
634 register unsigned char *bigend;
635 register unsigned char *littleend;
637 if ((pos = screamfirst[littlestr->str_rare]) < 0)
640 little = (unsigned char *)(littlestr->str_ptr);
642 little = Null(unsigned char *);
644 littleend = little + littlestr->str_cur;
646 previous = littlestr->str_state;
648 big = (unsigned char *)(bigstr->str_ptr);
650 big = Null(unsigned char*);
652 bigend = big + bigstr->str_cur;
654 while (pos < previous) {
656 if (!(pos += screamnext[pos]))
660 if (littlestr->str_pok & SP_CASEFOLD) { /* case insignificant? */
662 if (big[pos] != first && big[pos] != fold[first])
664 for (x=big+pos+1,s=little; s < littleend; /**/ ) {
667 if (*s++ != *x++ && fold[*(s-1)] != *(x-1)) {
674 return (char *)(big+pos);
680 pos += screamnext[pos] /* does this goof up anywhere? */
688 if (big[pos] != first)
690 for (x=big+pos+1,s=little; s < littleend; /**/ ) {
700 return (char *)(big+pos);
706 pos += screamnext[pos]
715 /* copy a string to a safe spot */
721 register char *newaddr;
723 New(902,newaddr,strlen(str)+1,char);
724 (void)strcpy(newaddr,str);
728 /* same thing but with a known length */
735 register char *newaddr;
737 New(903,newaddr,len+1,char);
738 (void)bcopy(str,newaddr,len); /* might not be null terminated */
739 newaddr[len] = '\0'; /* is now */
743 /* grow a static string to at least a certain length */
746 growstr(strptr,curlen,newlen)
751 if (newlen > *curlen) { /* need more room? */
753 Renew(*strptr,newlen,char);
755 New(905,*strptr,newlen,char);
762 mess(pat,a1,a2,a3,a4)
769 (void)sprintf(s,pat,a1,a2,a3,a4);
772 if (curcmd->c_line) {
773 (void)sprintf(s," at %s line %ld",
774 stab_val(curcmd->c_filestab)->str_ptr, (long)curcmd->c_line);
778 stab_io(last_in_stab) &&
779 stab_io(last_in_stab)->lines ) {
780 (void)sprintf(s,", <%s> line %ld",
781 last_in_stab == argvstab ? "" : stab_name(last_in_stab),
782 (long)stab_io(last_in_stab)->lines);
785 (void)strcpy(s,".\n");
790 fatal(pat,a1,a2,a3,a4)
795 extern char *e_tmpname;
798 mess(pat,a1,a2,a3,a4);
800 str_set(stab_val(stabent("@",TRUE)),buf);
802 while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
803 strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
806 deb("(Skipping label #%d %s)\n",loop_ptr,
807 loop_stack[loop_ptr].loop_label);
814 deb("(Found label #%d %s)\n",loop_ptr,
815 loop_stack[loop_ptr].loop_label);
820 fatal("Bad label: %s", tmps);
822 longjmp(loop_stack[loop_ptr].loop_env, 1);
825 (void)fflush(stderr);
827 (void)UNLINK(e_tmpname);
829 exit((int)((errno&255)?errno:((statusvalue&255)?statusvalue:255)));
833 warn(pat,a1,a2,a3,a4)
837 mess(pat,a1,a2,a3,a4);
845 (void)fflush(stderr);
864 pat = va_arg(args, char *);
866 (void) vsprintf(s,pat,args);
870 if (curcmd->c_line) {
871 (void)sprintf(s," at %s line %ld",
872 stab_val(curcmd->c_filestab)->str_ptr, (long)curcmd->c_line);
876 stab_io(last_in_stab) &&
877 stab_io(last_in_stab)->lines ) {
878 (void)sprintf(s,", <%s> line %ld",
879 last_in_stab == argvstab ? "" : last_in_stab->str_magic->str_ptr,
880 (long)stab_io(last_in_stab)->lines);
883 (void)strcpy(s,".\n");
893 extern char *e_tmpname;
904 str_set(stab_val(stabent("@",TRUE)),buf);
906 while (loop_ptr >= 0 && (!loop_stack[loop_ptr].loop_label ||
907 strNE(tmps,loop_stack[loop_ptr].loop_label) )) {
910 deb("(Skipping label #%d %s)\n",loop_ptr,
911 loop_stack[loop_ptr].loop_label);
918 deb("(Found label #%d %s)\n",loop_ptr,
919 loop_stack[loop_ptr].loop_label);
924 fatal("Bad label: %s", tmps);
926 longjmp(loop_stack[loop_ptr].loop_env, 1);
929 (void)fflush(stderr);
931 (void)UNLINK(e_tmpname);
933 exit((int)((errno&255)?errno:((statusvalue&255)?statusvalue:255)));
957 (void)fflush(stderr);
965 register int i=envix(nam); /* where does it go? */
967 if (environ == origenviron) { /* need we copy environment? */
972 for (max = i; environ[max]; max++) ;
973 New(901,tmpenv, max+2, char*);
974 for (j=0; j<max; j++) /* copy environment */
975 tmpenv[j] = savestr(environ[j]);
976 tmpenv[max] = Nullch;
977 environ = tmpenv; /* tell exec where it is now */
981 environ[i] = environ[i+1];
986 if (!environ[i]) { /* does not exist yet */
987 Renew(environ, i+2, char*); /* just expand it a bit */
988 environ[i+1] = Nullch; /* make sure it's null terminated */
991 Safefree(environ[i]);
992 New(904, environ[i], strlen(nam) + strlen(val) + 2, char);
994 (void)sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
996 /* MS-DOS requires environment variable names to be in uppercase */
997 /* [Tom Dinger, 27 August 1990: Well, it doesn't _require_ it, but
998 * some utilities and applications may break because they only look
999 * for upper case strings. (Fixed strupr() bug here.)]
1001 strcpy(environ[i],nam); strupr(environ[i]);
1002 (void)sprintf(environ[i] + strlen(nam),"=%s",val);
1010 register int i, len = strlen(nam);
1012 for (i = 0; environ[i]; i++) {
1013 if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
1014 break; /* strnEQ must come first to avoid */
1015 } /* potential SEGV's */
1020 unlnk(f) /* unlink all versions of a file */
1025 for (i = 0; unlink(f) >= 0; i++) ;
1034 register char *from;
1069 vsprintf(dest, pat, args)
1070 char *dest, *pat, *args;
1074 fakebuf._ptr = dest;
1075 fakebuf._cnt = 32767;
1079 fakebuf._flag = _IOWRT|_IOSTRG;
1080 _doprnt(pat, args, &fakebuf); /* what a kludge */
1081 (void)putc('\0', &fakebuf);
1085 return 0; /* perl doesn't use return value */
1091 vfprintf(fd, pat, args)
1095 _doprnt(pat, args, fd);
1096 return 0; /* wrong, but perl doesn't use the return value */
1099 #endif /* HAS_VPRINTF */
1100 #endif /* I_VARARGS */
1103 #if BYTEORDER != 0x4321
1108 #if (BYTEORDER & 1) == 0
1111 result = ((s & 255) << 8) + ((s >> 8) & 255);
1124 char c[sizeof(long)];
1127 #if BYTEORDER == 0x1234
1128 u.c[0] = (l >> 24) & 255;
1129 u.c[1] = (l >> 16) & 255;
1130 u.c[2] = (l >> 8) & 255;
1134 #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
1135 fatal("Unknown BYTEORDER\n");
1140 for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
1141 u.c[o & 0xf] = (l >> s) & 255;
1154 char c[sizeof(long)];
1157 #if BYTEORDER == 0x1234
1158 u.c[0] = (l >> 24) & 255;
1159 u.c[1] = (l >> 16) & 255;
1160 u.c[2] = (l >> 8) & 255;
1164 #if ((BYTEORDER - 0x1111) & 0x444) || !(BYTEORDER & 0xf)
1165 fatal("Unknown BYTEORDER\n");
1172 for (o = BYTEORDER - 0x1111, s = 0; s < (sizeof(long)*8); o >>= 4, s += 8) {
1173 l |= (u.c[o & 0xf] & 255) << s;
1180 #endif /* BYTEORDER != 0x4321 */
1181 #endif /* HAS_HTONS */
1190 register int this, that;
1193 int doexec = strNE(cmd,"-");
1197 this = (*mode == 'w');
1199 while ((pid = (doexec?vfork():fork())) < 0) {
1200 if (errno != EAGAIN) {
1203 fatal("Can't fork");
1212 if (p[THIS] != (*mode == 'r')) {
1213 dup2(p[THIS], *mode == 'r');
1217 #if !defined(I_FCNTL) || !defined(F_SETFD)
1223 for (fd = 3; fd < NOFILE; fd++)
1226 do_exec(cmd); /* may or may not use the shell */
1229 if (tmpstab = stabent("$",allstabs))
1230 str_numset(STAB_STR(tmpstab),(double)getpid());
1232 hclear(pidstatus, FALSE); /* we have no children */
1237 do_execfree(); /* free any memory malloced by child on vfork */
1239 if (p[that] < p[this]) {
1240 dup2(p[this], p[that]);
1244 str = afetch(fdpid,p[this],TRUE);
1245 str->str_u.str_useful = pid;
1247 return fdopen(p[this], mode);
1256 struct stat tmpstatbuf;
1258 fprintf(stderr,"%s", s);
1259 for (fd = 0; fd < 32; fd++) {
1260 if (fstat(fd,&tmpstatbuf) >= 0)
1261 fprintf(stderr," %d",fd);
1263 fprintf(stderr,"\n");
1272 #if defined(HAS_FCNTL) && defined(F_DUPFD)
1274 fcntl(oldfd, F_DUPFD, newfd);
1283 while ((fd = dup(oldfd)) != newfd) /* good enough for low fd's */
1286 close(fdtmp[--fdx]);
1297 void (*hstat)(), (*istat)(), (*qstat)();
1299 int (*hstat)(), (*istat)(), (*qstat)();
1305 str = afetch(fdpid,fileno(ptr),TRUE);
1306 astore(fdpid,fileno(ptr),Nullstr);
1308 pid = (int)str->str_u.str_useful;
1309 hstat = signal(SIGHUP, SIG_IGN);
1310 istat = signal(SIGINT, SIG_IGN);
1311 qstat = signal(SIGQUIT, SIG_IGN);
1312 pid = wait4pid(pid, &status, 0);
1313 signal(SIGHUP, hstat);
1314 signal(SIGINT, istat);
1315 signal(SIGQUIT, qstat);
1316 return(pid < 0 ? pid : status);
1320 wait4pid(pid,statusp,flags)
1332 return wait4((pid==-1)?0:pid,statusp,flags,Null(struct rusage *));
1335 return waitpid(pid,statusp,flags);
1338 sprintf(spid, "%d", pid);
1339 str = hfetch(pidstatus,spid,strlen(spid),FALSE);
1340 if (str != &str_undef) {
1341 *statusp = (int)str->str_u.str_useful;
1342 hdelete(pidstatus,spid,strlen(spid));
1349 hiterinit(pidstatus);
1350 if (entry = hiternext(pidstatus)) {
1351 pid = atoi(hiterkey(entry,statusp));
1352 str = hiterval(entry);
1353 *statusp = (int)str->str_u.str_useful;
1354 sprintf(spid, "%d", pid);
1355 hdelete(pidstatus,spid,strlen(spid));
1360 fatal("Can't do waitpid with flags");
1362 while ((result = wait(statusp)) != pid && pid > 0 && result >= 0)
1363 pidgone(result,*statusp);
1376 #if defined(HAS_WAIT4) || defined(HAS_WAITPID)
1381 sprintf(spid, "%d", pid);
1382 str = hfetch(pidstatus,spid,strlen(spid),TRUE);
1383 str->str_u.str_useful = status;
1391 register unsigned char *s1;
1392 register unsigned char *s2;
1398 if (tmp = *s1++ - *s2++)
1403 #endif /* HAS_MEMCMP */
1406 repeatcpy(to,from,len,count)
1408 register char *from;
1413 register char *frombase = from;
1421 while (count-- > 0) {
1422 for (todo = len; todo > 0; todo--) {
1429 #ifndef CASTNEGFLOAT
1437 # define BIGDOUBLE 2147483648.0
1439 return (unsigned long)(f-(long)(f/BIGDOUBLE)*BIGDOUBLE)|0x80000000;
1442 return (unsigned long)f;
1444 return (unsigned long)along;
1454 char *fa = rindex(a,'/');
1455 char *fb = rindex(b,'/');
1456 struct stat tmpstatbuf1;
1457 struct stat tmpstatbuf2;
1459 #define MAXPATHLEN 1024
1461 char tmpbuf[MAXPATHLEN+1];
1476 strncpy(tmpbuf, a, fa - a);
1477 if (stat(tmpbuf, &tmpstatbuf1) < 0)
1482 strncpy(tmpbuf, b, fb - b);
1483 if (stat(tmpbuf, &tmpstatbuf2) < 0)
1485 return tmpstatbuf1.st_dev == tmpstatbuf2.st_dev &&
1486 tmpstatbuf1.st_ino == tmpstatbuf2.st_ino;
1488 #endif /* !HAS_RENAME */
1491 scanoct(start, len, retlen)
1496 register char *s = start;
1497 register unsigned long retval = 0;
1499 while (len-- && *s >= '0' && *s <= '7') {
1501 retval |= *s++ - '0';
1503 *retlen = s - start;
1508 scanhex(start, len, retlen)
1513 register char *s = start;
1514 register unsigned long retval = 0;
1517 while (len-- && *s && (tmp = index(hexdigit, *s))) {
1519 retval |= (tmp - hexdigit) & 15;
1522 *retlen = s - start;