summaryrefslogtreecommitdiff
path: root/dmake/unix/xenix/pwd/getcwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'dmake/unix/xenix/pwd/getcwd.c')
-rw-r--r--dmake/unix/xenix/pwd/getcwd.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/dmake/unix/xenix/pwd/getcwd.c b/dmake/unix/xenix/pwd/getcwd.c
new file mode 100644
index 000000000000..f2359bcc795b
--- /dev/null
+++ b/dmake/unix/xenix/pwd/getcwd.c
@@ -0,0 +1,231 @@
+/*
+ getcwd -- get pathname of current working directory
+
+ public-domain implementation
+
+ last edit: 03-Nov-1990 Gwyn@BRL.MIL
+
+ complies with the following standards:
+ IEEE Std 1003.1-1988
+ SVID Issue 3
+ X/Open Portability Guide Issue 2 (when "XPG2" is defined)
+ X/Open Portability Guide Issue 3
+
+ This implementation of getcwd() 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(getcwd((char*)0,0)), assuming "XPG2" is defined below.
+
+ This implementation depends on every directory having entries for
+ "." and "..". It also depends on the internals of the <dirent.h>
+ data structures to some degree.
+
+ I considered using chdir() to ascend the hierarchy, followed by a
+ final chdir() to the path being returned by getcwd() 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.
+*/
+#define XPG2 /* define to support obsolete XPG2-mandated feature */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef M_XENIX
+# include <sys/ndir.h>
+# define dirent direct
+#else
+# include <dirent.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+typedef char *pointer; /* (void *) if you have it */
+
+extern void free();
+extern pointer malloc();
+extern int fstat(), stat();
+
+extern int errno; /* normally done by <errno.h> */
+
+#ifndef NULL
+#define NULL 0 /* amorphous null pointer constant */
+#endif
+
+#ifndef NAME_MAX
+#define NAME_MAX 255 /* maximum directory entry size */
+#endif
+
+
+char *
+getcwd( 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 dirent *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 ( buf != NULL && size <= 0
+#ifndef XPG2
+ || buf == NULL
+#endif
+ ) {
+ errno = EINVAL; /* invalid argument */
+ return NULL;
+ }
+
+ buffer = buf;
+#ifdef XPG2
+ if ( buf == NULL /* wants us to malloc() the string */
+ && (buffer = (char *) malloc( (unsigned) size )) == NULL
+ /* XXX -- actually should probably not pay attention to "size" arg */
+ ) {
+ errno = ENOMEM; /* cannot malloc() specified size */
+ return NULL;
+ }
+#endif
+
+ 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; )
+ {
+ dotdot -= 3; /* include one more "/.." section */
+ /* (first time is actually "..") */
+
+ /* 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 + NAME_MAX];
+
+ (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 NAME_MAX 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 */
+ /* XXX -- if buf==NULL, realloc here? */
+ return buffer;
+ }
+ }
+
+ errno = ENOMEM; /* actually, algorithm failure */
+
+ error:
+ if ( buf == NULL )
+ free( (pointer)buffer );
+
+ return NULL;
+ }
+