beta-0.89.2
[luatex.git] / source / texk / kpathsea / xgetcwd.c
blobdae50ddb99878102a2b89dde562f3ea626af64c5
1 /* xgetcwd.c: a from-scratch version of getwd. Ideas from tcsh 5.20 source.
3 Copyright 1992, 1994, 1996, 2008, 2011 Karl Berry.
4 Copyright 2005 Olaf Weber.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with this library; if not, see <http://www.gnu.org/licenses/>. */
19 #include <kpathsea/config.h>
21 #if (defined (HAVE_GETCWD) && !defined (GETCWD_FORKS)) || defined (HAVE_GETWD)
22 #include <kpathsea/c-pathmx.h>
23 #else /* (not HAVE_GETCWD || GETCWD_FORKS) && not HAVE_GETWD */
24 #include <kpathsea/c-dir.h>
25 #include <kpathsea/xopendir.h>
26 #include <kpathsea/xstat.h>
29 static void
30 xchdir (string dirname)
32 if (chdir(dirname) != 0)
33 _PERROR(dirname);
36 #endif /* (not HAVE_GETCWD || GETCWD_FORKS) && not HAVE_GETWD */
39 /* Return the pathname of the current directory, or give a fatal error. */
41 string
42 xgetcwd (void)
44 /* If the system provides getcwd, use it. If not, use getwd if
45 available. But provide a way not to use getcwd: on some systems
46 getcwd forks, which is expensive and may in fact be impossible for
47 large programs like tex. If your system needs this define and it
48 is not detected by configure, let me know.
49 -- Olaf Weber <infovore@xs4all.nl */
50 #if defined (HAVE_GETCWD) && !defined (GETCWD_FORKS)
51 char path[PATH_MAX + 1];
52 #if defined(WIN32)
53 string pp;
54 #endif
56 if (getcwd (path, PATH_MAX + 1) == NULL) {
57 FATAL_PERROR ("getcwd");
60 #if defined(WIN32)
61 for (pp = path; *pp; pp++) {
62 if (*pp == '\\')
63 *pp = '/';
64 else if (IS_KANJI(pp))
65 pp++;
67 #endif
69 return xstrdup (path);
70 #elif defined (HAVE_GETWD)
71 char path[PATH_MAX + 1];
73 if (getwd (path) == NULL) {
74 FATAL_PERROR ("getwd");
77 return xstrdup (path);
78 #else /* (not HAVE_GETCWD || GETCWD_FORKS) && not HAVE_GETWD */
79 struct stat root_stat, cwd_stat;
80 string cwd_path = (string)xmalloc(2); /* In case we assign "/" below. */
82 *cwd_path = 0;
84 /* Find the inodes of the root and current directories. */
85 root_stat = xstat("/");
86 cwd_stat = xstat(".");
88 /* Go up the directory hierarchy until we get to root, prepending each
89 directory we pass through to `cwd_path'. */
90 while (!SAME_FILE_P(root_stat, cwd_stat)) {
91 struct dirent *e;
92 DIR *parent_dir;
93 boolean found = false;
95 xchdir("..");
96 parent_dir = xopendir(".");
98 /* Look through the parent directory for the entry with the same
99 inode, so we can get its name. */
100 while ((e = readdir (parent_dir)) != NULL && !found) {
101 struct stat test_stat;
102 test_stat = xlstat(e->d_name);
104 if (SAME_FILE_P(test_stat, cwd_stat)) {
105 /* We've found it. Prepend the pathname. */
106 string temp = cwd_path;
107 cwd_path = concat3("/", e->d_name, cwd_path);
108 free(temp);
110 /* Set up to test the next parent. */
111 cwd_stat = xstat(".");
113 /* Stop reading this directory. */
114 found = true;
117 if (!found)
118 LIB_FATAL2("No inode %d/device %d in parent directory",
119 cwd_stat.st_ino, cwd_stat.st_dev);
121 xclosedir(parent_dir);
124 /* If the current directory is the root, cwd_path will be the empty
125 string, and we will have not gone through the loop. */
126 if (*cwd_path == 0)
127 strcpy(cwd_path, "/");
128 else
129 /* Go back to where we were. */
130 xchdir(cwd_path);
132 #ifdef DOSISH
133 /* Prepend the drive letter to CWD_PATH, since this technique
134 never tells us what the drive is.
136 Note that on MS-DOS/MS-Windows, the branch that works around
137 missing `getwd' will probably only work for DJGPP (which does
138 have `getwd'), because only DJGPP reports meaningful
139 st_ino numbers. But someday, somebody might need this... */
141 char drive[3];
142 string temp = cwd_path;
144 /* Make the drive letter lower-case, unless it is beyond Z: (yes,
145 there ARE such drives, in case of Novell Netware on MS-DOS). */
146 drive[0] = root_stat.st_dev + (root_stat.st_dev < 26 ? 'a' : 'A');
147 drive[1] = ':';
148 drive[2] = '\0';
150 cwd_path = concat(drive, cwd_path);
151 free(temp);
153 #endif
155 return cwd_path;
156 #endif /* (not HAVE_GETCWD || GETCWD_FORKS) && not HAVE_GETWD */