dvitomp fix from Akira
[mplib] / src / texk / kpathsea / xgetcwd.c
1 /* xgetcwd.c: a from-scratch version of getwd.  Ideas from tcsh 5.20 source.
2
3    Copyright 1992, 1994, 1996, 2008 Karl Berry.
4    Copyright 2005 Olaf Weber.
5
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.
10
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.
15
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/>.  */
18
19 #include <kpathsea/config.h>
20
21 #if defined (HAVE_GETCWD) || defined (HAVE_GETWD)
22 #include <kpathsea/c-pathmx.h>
23 #else /* not HAVE_GETCWD && not HAVE_GETWD*/
24 #include <kpathsea/c-dir.h>
25 #include <kpathsea/xopendir.h>
26 #include <kpathsea/xstat.h>
27
28
29 static void
30 xchdir P1C(string, dirname)
31 {
32     if (chdir(dirname) != 0)
33         FATAL_PERROR(dirname);
34 }
35
36 #endif /* not HAVE_GETCWD && not HAVE_GETWD */
37
38
39 /* Return the pathname of the current directory, or give a fatal error.  */
40
41 string
42 xgetcwd P1H(void)
43 {
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     string path = (string)xmalloc(PATH_MAX + 1);
52   
53     if (getcwd (path, PATH_MAX + 1) == 0) {
54         fprintf(stderr, "getcwd: %s", path);
55         exit(EXIT_FAILURE);
56     }
57     
58     return path;
59 #elif defined (HAVE_GETWD)
60     string path = (string)xmalloc(PATH_MAX + 1);
61     
62     if (getwd (path) == 0) {
63         fprintf(stderr, "getwd: %s", path);
64         exit(EXIT_FAILURE);
65     }
66   
67     return path;
68 #else /* not HAVE_GETCWD && not HAVE_GETWD */
69     struct stat root_stat, cwd_stat;
70     string cwd_path = (string)xmalloc(2); /* In case we assign "/" below.  */
71   
72     *cwd_path = 0;
73   
74     /* Find the inodes of the root and current directories.  */
75     root_stat = xstat("/");
76     cwd_stat  = xstat(".");
77
78     /* Go up the directory hierarchy until we get to root, prepending each
79        directory we pass through to `cwd_path'.  */
80     while (!SAME_FILE_P(root_stat, cwd_stat)) {
81         struct dirent *e;
82         DIR *parent_dir;
83         boolean found = false;
84         
85         xchdir("..");
86         parent_dir = xopendir(".");
87
88         /* Look through the parent directory for the entry with the same
89            inode, so we can get its name.  */
90         while ((e = readdir (parent_dir)) != NULL && !found) {
91             struct stat test_stat;
92             test_stat = xlstat(e->d_name);
93             
94             if (SAME_FILE_P(test_stat, cwd_stat)) {
95                 /* We've found it.  Prepend the pathname.  */
96                 string temp = cwd_path;
97                 cwd_path = concat3("/", e->d_name, cwd_path);
98                 free(temp);
99               
100                 /* Set up to test the next parent.  */
101                 cwd_stat = xstat(".");
102               
103                 /* Stop reading this directory.  */
104                 found = true;
105             }
106         }
107         if (!found)
108             FATAL2("No inode %d/device %d in parent directory",
109                    cwd_stat.st_ino, cwd_stat.st_dev);
110       
111         xclosedir(parent_dir);
112     }
113   
114     /* If the current directory is the root, cwd_path will be the empty
115        string, and we will have not gone through the loop.  */
116     if (*cwd_path == 0)
117         strcpy(cwd_path, "/");
118     else
119         /* Go back to where we were.  */
120         xchdir(cwd_path);
121
122 #ifdef DOSISH
123     /* Prepend the drive letter to CWD_PATH, since this technique
124        never tells us what the drive is.
125  
126        Note that on MS-DOS/MS-Windows, the branch that works around
127        missing `getwd' will probably only work for DJGPP (which does
128        have `getwd'), because only DJGPP reports meaningful
129        st_ino numbers.  But someday, somebody might need this...  */
130     {
131         char drive[3];
132         string temp = cwd_path;
133     
134         /* Make the drive letter lower-case, unless it is beyond Z: (yes,
135            there ARE such drives, in case of Novell Netware on MS-DOS).  */
136         drive[0] = root_stat.st_dev + (root_stat.st_dev < 26 ? 'a' : 'A');
137         drive[1] = ':';
138         drive[2] = '\0';
139         
140         cwd_path = concat(drive, cwd_path);
141         free(temp);
142     }
143 #endif
144
145     return cwd_path;
146 #endif /* not HAVE_GETCWD && not HAVE_GETWD */
147 }