1/* fullpath.c - fully resolve a pathname.  */
2
3#include "config.h"
4#include "system.h"
5
6
7#ifdef FULL_PATHS_IN_ERRORS
8#if !(defined (VMS) || (defined(_WIN32) && !defined(__CYGWIN__)))
9
10extern char *getpwd PROTO((void));
11
12char *
13convert_to_full_path(const char *file)
14{
15  static char *full_path_buffer = 0;
16  const char *cwd;
17  char *outp, *inp;
18
19  if (file == NULL || file[0] == '/')    /* file already full path */
20    return (char *)file;
21
22  cwd = getpwd ();
23  if (!cwd)
24    return (char *)file;
25
26  if (full_path_buffer == NULL)
27    full_path_buffer = xmalloc (2 * MAXPATHLEN + 1);
28
29  strcpy (full_path_buffer, cwd);
30  strcat (full_path_buffer, "/");
31  strcat (full_path_buffer, file);
32
33  /* Now make a copy of full_path_buffer into full_path_buffer, shortening the
34     filename (by taking out slashes and dots) as we go.  */
35
36  outp = inp = full_path_buffer;
37  *outp++ = *inp++;        	/* copy first slash */
38  for (;;)
39    {
40      if (!inp[0])
41	break;
42      /* ??? FIXME: Care for POSIXly correct leading double slash.  */
43      else if (inp[0] == '/' && outp[-1] == '/')
44	{
45	  inp++;
46	  continue;
47	}
48      else if (inp[0] == '.' && outp[-1] == '/')
49	{
50	  if (!inp[1])
51	    break;
52	  else if (inp[1] == '/')
53	    {
54	      inp += 2;
55	      continue;
56	    }
57	  else if ((inp[1] == '.') && (inp[2] == 0 || inp[2] == '/'))
58	    {
59	      inp += (inp[2] == '/') ? 3 : 2;
60	      outp -= 2;
61	      while (outp >= full_path_buffer && *outp != '/')
62		outp--;
63	      if (outp < full_path_buffer)
64		{
65		  /* Catch cases like /.. where we try to backup to a
66		     point above the absolute root of the logical file
67		     system.  */
68
69		  return (char *)file;
70		}
71	      *++outp = '\0';
72	      continue;
73	    }
74	}
75      *outp++ = *inp++;
76    }
77
78  /* On exit, make sure that there is a trailing null, and make sure that
79     the last character of the returned string is *not* a slash.  */
80
81  *outp = '\0';
82  if (outp[-1] == '/')
83    *--outp  = '\0';
84
85  return full_path_buffer;
86}
87
88
89#else	/* VMS || _WIN32 && !__CYGWIN__ */
90
91char *
92convert_to_full_path(const char *file)
93{
94  return (char *) file;
95}
96
97#endif /* VMS || _WIN32 && !__CYGWIN__ */
98#endif /* FULL_PATHS_IN_ERRORS */
99