160484Sobrien/* getpwd.c - get the working directory */
260484Sobrien
389857Sobrien/*
489857Sobrien
589857Sobrien@deftypefn Supplemental char* getpwd (void)
689857Sobrien
789857SobrienReturns the current working directory.  This implementation caches the
889857Sobrienresult on the assumption that the process will not call @code{chdir}
989857Sobrienbetween calls to @code{getpwd}.
1089857Sobrien
1189857Sobrien@end deftypefn
1289857Sobrien
1389857Sobrien*/
1489857Sobrien
1560484Sobrien#ifdef HAVE_CONFIG_H
1660484Sobrien#include "config.h"
1760484Sobrien#endif
1860484Sobrien
1960484Sobrien#include <sys/types.h>
2060484Sobrien
2160484Sobrien#include <errno.h>
2260484Sobrien#ifndef errno
2360484Sobrienextern int errno;
2460484Sobrien#endif
2560484Sobrien
2660484Sobrien#ifdef HAVE_STDLIB_H
2760484Sobrien#include <stdlib.h>
2860484Sobrien#endif
2960484Sobrien#ifdef HAVE_UNISTD_H
3060484Sobrien#include <unistd.h>
3160484Sobrien#endif
3260484Sobrien#ifdef HAVE_SYS_PARAM_H
3360484Sobrien#include <sys/param.h>
3460484Sobrien#endif
3560484Sobrien#if HAVE_SYS_STAT_H
3660484Sobrien#include <sys/stat.h>
3760484Sobrien#endif
38130561Sobrien#if HAVE_LIMITS_H
39130561Sobrien#include <limits.h>
40130561Sobrien#endif
4160484Sobrien
4260484Sobrien#include "libiberty.h"
4360484Sobrien
4460484Sobrien/* Virtually every UN*X system now in common use (except for pre-4.3-tahoe
4560484Sobrien   BSD systems) now provides getcwd as called for by POSIX.  Allow for
4660484Sobrien   the few exceptions to the general rule here.  */
4760484Sobrien
4860484Sobrien#if !defined(HAVE_GETCWD) && defined(HAVE_GETWD)
49218822Sdim/* Prototype in case the system headers doesn't provide it. */
50218822Sdimextern char *getwd ();
5160484Sobrien#define getcwd(buf,len) getwd(buf)
5260484Sobrien#endif
5360484Sobrien
5460484Sobrien#ifdef MAXPATHLEN
5560484Sobrien#define GUESSPATHLEN (MAXPATHLEN + 1)
5660484Sobrien#else
5760484Sobrien#define GUESSPATHLEN 100
5860484Sobrien#endif
5960484Sobrien
6060484Sobrien#if !(defined (VMS) || (defined(_WIN32) && !defined(__CYGWIN__)))
6160484Sobrien
6260484Sobrien/* Get the working directory.  Use the PWD environment variable if it's
6360484Sobrien   set correctly, since this is faster and gives more uniform answers
6460484Sobrien   to the user.  Yield the working directory if successful; otherwise,
6560484Sobrien   yield 0 and set errno.  */
6660484Sobrien
6760484Sobrienchar *
68218822Sdimgetpwd (void)
6960484Sobrien{
7060484Sobrien  static char *pwd;
7160484Sobrien  static int failure_errno;
7260484Sobrien
7360484Sobrien  char *p = pwd;
7460484Sobrien  size_t s;
7560484Sobrien  struct stat dotstat, pwdstat;
7660484Sobrien
7760484Sobrien  if (!p && !(errno = failure_errno))
7860484Sobrien    {
7960484Sobrien      if (! ((p = getenv ("PWD")) != 0
8060484Sobrien	     && *p == '/'
8160484Sobrien	     && stat (p, &pwdstat) == 0
8260484Sobrien	     && stat (".", &dotstat) == 0
8360484Sobrien	     && dotstat.st_ino == pwdstat.st_ino
8460484Sobrien	     && dotstat.st_dev == pwdstat.st_dev))
8560484Sobrien
8660484Sobrien	/* The shortcut didn't work.  Try the slow, ``sure'' way.  */
87218822Sdim	for (s = GUESSPATHLEN;  !getcwd (p = XNEWVEC (char, s), s);  s *= 2)
8860484Sobrien	  {
8960484Sobrien	    int e = errno;
9060484Sobrien	    free (p);
9160484Sobrien#ifdef ERANGE
9260484Sobrien	    if (e != ERANGE)
9360484Sobrien#endif
9460484Sobrien	      {
9560484Sobrien		errno = failure_errno = e;
9660484Sobrien		p = 0;
9760484Sobrien		break;
9860484Sobrien	      }
9960484Sobrien	  }
10060484Sobrien
10160484Sobrien      /* Cache the result.  This assumes that the program does
10260484Sobrien	 not invoke chdir between calls to getpwd.  */
10360484Sobrien      pwd = p;
10460484Sobrien    }
10560484Sobrien  return p;
10660484Sobrien}
10760484Sobrien
10860484Sobrien#else	/* VMS || _WIN32 && !__CYGWIN__ */
10960484Sobrien
11060484Sobrien#ifndef MAXPATHLEN
11160484Sobrien#define MAXPATHLEN 255
11260484Sobrien#endif
11360484Sobrien
11460484Sobrienchar *
115218822Sdimgetpwd (void)
11660484Sobrien{
11760484Sobrien  static char *pwd = 0;
11860484Sobrien
11960484Sobrien  if (!pwd)
120218822Sdim    pwd = getcwd (XNEWVEC (char, MAXPATHLEN + 1), MAXPATHLEN + 1
12160484Sobrien#ifdef VMS
12260484Sobrien		  , 0
12360484Sobrien#endif
12460484Sobrien		  );
12560484Sobrien  return pwd;
12660484Sobrien}
12760484Sobrien
12860484Sobrien#endif	/* VMS || _WIN32 && !__CYGWIN__ */
129