1 /* xgetcwd.c: a from-scratch version of getwd. Ideas from the tcsh 5.20
2 source, apparently uncopyrighted.
4 Copyright 2005 Olaf Weber.
5 Copyright 1992, 94, 96 Karl Berry.
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <kpathsea/config.h>
24 #if defined (HAVE_GETCWD) || defined (HAVE_GETWD)
25 #include <kpathsea/c-pathmx.h>
26 #else /* not HAVE_GETCWD && not HAVE_GETWD*/
27 #include <kpathsea/c-dir.h>
28 #include <kpathsea/xopendir.h>
29 #include <kpathsea/xstat.h>
33 xchdir P1C(string, dirname)
35 if (chdir(dirname) != 0)
36 FATAL_PERROR(dirname);
39 #endif /* not HAVE_GETCWD && not HAVE_GETWD */
42 /* Return the pathname of the current directory, or give a fatal error. */
47 /* If the system provides getcwd, use it. If not, use getwd if
48 available. But provide a way not to use getcwd: on some systems
49 getcwd forks, which is expensive and may in fact be impossible for
50 large programs like tex. If your system needs this define and it
51 is not detected by configure, let me know.
52 -- Olaf Weber <infovore@xs4all.nl */
53 #if defined (HAVE_GETCWD) && !defined (GETCWD_FORKS)
54 string path = (string)xmalloc(PATH_MAX + 1);
56 if (getcwd (path, PATH_MAX + 1) == 0) {
57 fprintf(stderr, "getcwd: %s", path);
62 #elif defined (HAVE_GETWD)
63 string path = (string)xmalloc(PATH_MAX + 1);
65 if (getwd (path) == 0) {
66 fprintf(stderr, "getwd: %s", path);
71 #else /* not HAVE_GETCWD && not HAVE_GETWD */
72 struct stat root_stat, cwd_stat;
73 string cwd_path = (string)xmalloc(2); /* In case we assign "/" below. */
77 /* Find the inodes of the root and current directories. */
78 root_stat = xstat("/");
79 cwd_stat = xstat(".");
81 /* Go up the directory hierarchy until we get to root, prepending each
82 directory we pass through to `cwd_path'. */
83 while (!SAME_FILE_P(root_stat, cwd_stat)) {
86 boolean found = false;
89 parent_dir = xopendir(".");
91 /* Look through the parent directory for the entry with the same
92 inode, so we can get its name. */
93 while ((e = readdir (parent_dir)) != NULL && !found) {
94 struct stat test_stat;
95 test_stat = xlstat(e->d_name);
97 if (SAME_FILE_P(test_stat, cwd_stat)) {
98 /* We've found it. Prepend the pathname. */
99 string temp = cwd_path;
100 cwd_path = concat3("/", e->d_name, cwd_path);
103 /* Set up to test the next parent. */
104 cwd_stat = xstat(".");
106 /* Stop reading this directory. */
111 FATAL2("No inode %d/device %d in parent directory",
112 cwd_stat.st_ino, cwd_stat.st_dev);
114 xclosedir(parent_dir);
117 /* If the current directory is the root, cwd_path will be the empty
118 string, and we will have not gone through the loop. */
120 strcpy(cwd_path, "/");
122 /* Go back to where we were. */
126 /* Prepend the drive letter to CWD_PATH, since this technique
127 never tells us what the drive is.
129 Note that on MS-DOS/MS-Windows, the branch that works around
130 missing `getwd' will probably only work for DJGPP (which does
131 have `getwd'), because only DJGPP reports meaningful
132 st_ino numbers. But someday, somebody might need this... */
135 string temp = cwd_path;
137 /* Make the drive letter lower-case, unless it is beyond Z: (yes,
138 there ARE such drives, in case of Novell Netware on MS-DOS). */
139 drive[0] = root_stat.st_dev + (root_stat.st_dev < 26 ? 'a' : 'A');
143 cwd_path = concat(drive, cwd_path);
149 #endif /* not HAVE_GETCWD && not HAVE_GETWD */