Thread View: gnu.utils.bug
1 messages
1 total messages
Started by Chip Salzenberg
Wed, 11 Oct 1989 15:58
GNU Make 3.56: Porting/Speed patch: Doug Gwyn's getcwd ( )
Author: Chip Salzenberg
Date: Wed, 11 Oct 1989 15:58
Date: Wed, 11 Oct 1989 15:58
232 lines
7101 bytes
7101 bytes
[PORTING AND SPEED PATCH]
Replace getcwd() and getwd() with Doug Gwyn's portable implementation.
Besides being faster (no fork/exec required), this function is robust
even when SIGCLD/SIGCHLD is caught, unlike the SCO Xenix version.
Index: make.h
***************
*** 89,92 ****
--- 89,93 ----
extern struct dep *copy_dep_chain ();
extern char *find_percent ();
+ extern char *getcurdir ();
#ifndef NO_ARCHIVES
***************
*** 131,142 ****
extern char **environ;
! #ifdef USG
! extern char *getcwd ();
! #define getwd(buf) getcwd (buf, MAXPATHLEN - 2)
! #else /* Not USG. */
! extern char *getwd ();
! #endif /* USG. */
-
extern char *reading_filename;
extern unsigned int *reading_lineno_ptr;
--- 132,137 ----
extern char **environ;
! #define getwd(buf) getcurdir (buf, MAXPATHLEN - 2)
extern char *reading_filename;
extern unsigned int *reading_lineno_ptr;
Index: dir.c
***************
*** 385,386 ****
--- 366,556 ----
printf (" impossibilities in %u directories.\n", dirs);
}
+
+ /*
+ getcurdir -- get current working directory name
+ (compatible with POSIX and SVID getcwd())
+
+ last edit: 21-Sep-1987 D A Gwyn
+
+ This public-domain getcurdir() routine can be used to replace the UNIX
+ System V library routine (which uses popen() to capture the output of
+ the "pwd" command). Once that is done, "pwd" can be reimplemented as
+ just puts(getcurdir()).
+
+ This implementation depends on every directory having entries for
+ "." and "..". It also depends on the internals of the readdir()
+ data structures to some degree.
+
+ I considered using chdir() to ascend the hierarchy, followed by a
+ final chdir() to the path being returned by getcurdir() to restore the
+ location, but decided that error recovery was too difficult that way.
+ The algorithm I settled on was inspired by my rewrite of the "pwd"
+ utility, combined with the dotdots[] array trick from the SVR2 shell.
+ */
+
+ char *
+ getcurdir(buf, size) /* returns pointer to CWD pathname */
+ char *buf; /* where to put name (NULL to malloc) */
+ int size; /* size of buf[] or malloc()ed memory */
+ {
+ static char dotdots[] =
+ "../../../../../../../../../../../../../../../../../../../../../../../../../..";
+ char *dotdot; /* -> dotdots[.], right to left */
+ DIR *dirp; /* -> parent directory stream */
+ struct direct *dir; /* -> directory entry */
+ struct stat stat1,
+ stat2; /* info from stat() */
+ struct stat *d = &stat1; /* -> info about "." */
+ struct stat *dd = &stat2; /* -> info about ".." */
+ register char *buffer; /* local copy of buf, or malloc()ed */
+ char *bufend; /* -> buffer[size] */
+ register char *endp; /* -> end of reversed string */
+ register char *dname; /* entry name ("" for root) */
+ int serrno = errno; /* save entry errno */
+
+ if (size == 0)
+ {
+ errno = EINVAL; /* invalid argument */
+ return NULL;
+ }
+
+ if ((buffer = buf) == NULL /* wants us to malloc() the string */
+ && (buffer = (char *) malloc((unsigned) size)) == NULL)
+ {
+ errno = ENOMEM; /* cannot malloc() specified size */
+ return NULL;
+ }
+
+ if (stat(".", dd) != 0) /* prime the pump */
+ goto error; /* errno already set */
+
+ endp = buffer; /* initially, empty string */
+ bufend = &buffer[size];
+
+ for (dotdot = &dotdots[sizeof(dotdots)]; dotdot != dotdots;)
+ {
+ /* include one more "/.." section */
+ /* (first time is actually "..") */
+ dotdot -= 3;
+
+ /* swap stat() info buffers */
+ {
+ register struct stat *temp = d;
+
+ d = dd; /* new current dir is old parent dir */
+ dd = temp;
+ }
+
+ if ((dirp = opendir(dotdot)) == NULL) /* new parent */
+ goto error; /* errno already set */
+
+ if (fstat(dirp->dd_fd, dd) != 0)
+ {
+ serrno = errno; /* set by fstat() */
+ (void) closedir(dirp);
+ errno = serrno; /* in case closedir() clobbered it */
+ goto error;
+ }
+
+ if (d->st_dev == dd->st_dev)
+ {
+ /* not crossing a mount point */
+
+ if (d->st_ino == dd->st_ino)
+ {
+ /* root directory */
+ dname = "";
+ goto append;
+ }
+
+ do
+ {
+ if ((dir = readdir(dirp)) == NULL)
+ {
+ (void) closedir(dirp);
+ errno = ENOENT; /* missing entry */
+ goto error;
+ }
+ } while (dir->d_ino != d->st_ino);
+ }
+ else
+ { /* crossing a mount point */
+ struct stat t; /* info re. test entry */
+ char name[sizeof(dotdots) + 1 + MAXNAMLEN];
+
+ (void) strcpy(name, dotdot);
+ dname = &name[strlen(name)];
+ *dname++ = '/';
+
+ do
+ {
+ if ((dir = readdir(dirp)) == NULL)
+ {
+ (void) closedir(dirp);
+ errno = ENOENT; /* missing entry */
+ goto error;
+ }
+
+ (void) strcpy(dname, dir->d_name);
+ /* must fit if MAXNAMLEN is not a lie */
+ } while (stat(name, &t) != 0
+ || t.st_ino != d->st_ino
+ || t.st_dev != d->st_dev);
+ }
+
+ dname = dir->d_name;
+
+ /* append "/" and reversed dname string onto buffer */
+ append:
+ if (endp != buffer /* avoid trailing / in final name */
+ || dname[0] == '\0' /* but allow "/" when CWD is root */
+ )
+ *endp++ = '/';
+
+ {
+ register char *app; /* traverses dname string */
+
+ for (app = dname; *app != '\0'; ++app)
+ ;
+
+ if (app - dname >= bufend - endp)
+ {
+ (void) closedir(dirp);
+ errno = ERANGE; /* won't fit allotted space */
+ goto error;
+ }
+
+ while (app != dname)
+ *endp++ = *--app;
+ }
+
+ (void) closedir(dirp);
+
+ if (dname[0] == '\0')
+ { /* reached root; wrap it up */
+ register char *startp; /* -> buffer[.] */
+
+ *endp = '\0'; /* plant null terminator */
+
+ /* straighten out reversed pathname string */
+ for (startp = buffer; --endp > startp; ++startp)
+ {
+ char temp = *endp;
+
+ *endp = *startp;
+ *startp = temp;
+ }
+
+ errno = serrno; /* restore entry errno */
+ return buffer;
+ }
+ }
+
+ errno = ENOMEM; /* actually, algorithm failure */
+
+ error:
+ if (buf == NULL)
+ free((char *) buffer);
+
+ return NULL;
+ }
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads