Line data Source code
1 : /* Provide relocation for macro and font files.
2 :
3 : Copyright 2005-2024 Free Software Foundation, Inc.
4 :
5 : This file is part of groff, the GNU roff typesetting system.
6 :
7 : This file is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU Lesser General Public License as published
9 : by the Free Software Foundation, either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This file is distributed in the hope that it will be useful, but WITHOUT
13 : ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 : License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 :
20 : // Made after relocation code in kpathsea and gettext.
21 :
22 : #ifdef HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 :
26 : #include <assert.h>
27 : #include <errno.h>
28 : #include <stdlib.h>
29 :
30 : #include "lib.h"
31 :
32 : #include "defs.h"
33 : #include "posix.h"
34 : #include "nonposix.h"
35 : #include "relocate.h"
36 :
37 : #if defined _WIN32
38 : # define WIN32_LEAN_AND_MEAN
39 : # include <windows.h>
40 : #endif
41 :
42 : #define INSTALLPATHLEN (sizeof(INSTALLPATH) - 1)
43 : #ifndef DEBUG
44 : # define DEBUG 0
45 : #endif
46 :
47 : extern "C" const char *program_name;
48 :
49 : // The prefix (parent directory) corresponding to the binary.
50 : char *curr_prefix = 0;
51 : size_t curr_prefix_len = 0;
52 :
53 : // Return the directory part of a filename, or '.' if no path separators.
54 34 : char *xdirname(char *s)
55 : {
56 : static const char dot[] = ".";
57 34 : if (!s)
58 0 : return 0;
59 : // DIR_SEPS[] are possible directory separator characters, see nonposix.h.
60 : // We want the rightmost separator of all possible ones.
61 : // Example: d:/foo\\bar.
62 34 : char *p = strrchr(s, DIR_SEPS[0]);
63 34 : const char *sep = &DIR_SEPS[1];
64 34 : while (*sep) {
65 0 : char *p1 = strrchr(s, *sep);
66 0 : if (p1 && (!p || p1 > p))
67 0 : p = p1;
68 0 : sep++;
69 : }
70 34 : if (p)
71 34 : *p = '\0';
72 : else
73 0 : s = (char *)dot;
74 34 : return s;
75 : }
76 :
77 : // Return the full path of NAME along the path PATHP.
78 : // Adapted from search_path::open_file in searchpath.cpp.
79 17 : char *searchpath(const char *name, const char *pathp)
80 : {
81 : char *path;
82 17 : if (!name || !*name)
83 0 : return 0;
84 : #if DEBUG
85 : fprintf(stderr, "searchpath: pathp: '%s'\n", pathp);
86 : fprintf(stderr, "searchpath: trying '%s'\n", name);
87 : #endif
88 : // Try first NAME as such; success if NAME is an absolute filename,
89 : // or if NAME is found in the current directory.
90 17 : if (!access (name, F_OK)) {
91 17 : path = new char[path_name_max()];
92 : #ifdef _WIN32
93 : path = _fullpath(path, name, path_name_max());
94 : #else
95 17 : path = realpath(name, path);
96 : #endif
97 : #if DEBUG
98 : fprintf(stderr, "searchpath: found '%s'\n", path);
99 : #endif
100 17 : return path;
101 : }
102 : // Secondly, try the current directory.
103 : // Now search along PATHP.
104 0 : size_t namelen = strlen(name);
105 0 : char *p = (char *)pathp;
106 : for (;;) {
107 0 : char *end = strchr(p, PATH_SEP_CHAR);
108 0 : if (!end)
109 0 : end = strchr(p, '\0');
110 0 : int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0;
111 0 : path = new char[end - p + need_slash + namelen + 1];
112 0 : memcpy(path, p, end - p);
113 0 : if (need_slash)
114 0 : path[end - p] = '/';
115 0 : strcpy(path + (end - p) + need_slash, name);
116 : #if DEBUG
117 : fprintf(stderr, "searchpath: trying '%s'\n", path);
118 : #endif
119 0 : if (!access(path, F_OK)) {
120 : #if DEBUG
121 : fprintf(stderr, "searchpath: found '%s'\n", name);
122 : #endif
123 0 : return path;
124 : }
125 0 : delete[] path;
126 0 : if (*end == '\0')
127 0 : break;
128 0 : p = end + 1;
129 0 : }
130 0 : return 0;
131 : }
132 :
133 : // Search NAME along PATHP with the elements of PATHEXT in turn added.
134 0 : char *searchpathext(const char *name, const char *pathext, const char *pathp)
135 : {
136 0 : char *found = 0;
137 0 : char *tmpathext = strsave(pathext); // strtok modifies this string,
138 : // so make a copy
139 0 : char *ext = strtok(tmpathext, PATH_SEP);
140 0 : while (ext) {
141 0 : char *namex = new char[strlen(name) + strlen(ext) + 1];
142 0 : strcpy(namex, name);
143 0 : strcat(namex, ext);
144 0 : found = searchpath(namex, pathp);
145 0 : delete[] namex;
146 0 : if (found)
147 0 : break;
148 0 : ext = strtok(0, PATH_SEP);
149 : }
150 0 : delete[] tmpathext;
151 0 : return found;
152 : }
153 :
154 : // Convert an MS path to a POSIX path.
155 17 : char *msw2posixpath(char *path)
156 : {
157 17 : char *s = path;
158 714 : while (*s) {
159 697 : if (*s == '\\')
160 0 : *s = '/';
161 697 : s++;
162 : }
163 17 : return path;
164 : }
165 :
166 : // Compute the current prefix.
167 17 : void set_current_prefix()
168 : {
169 : // Obtain the full path of the current binary;
170 : // using GetModuleFileName on MS-Windows,
171 : // and searching along PATH on other systems.
172 : #ifdef _WIN32
173 : char *pathextstr;
174 : curr_prefix = new char[path_name_max()];
175 : int len = GetModuleFileName(0, curr_prefix, path_name_max());
176 : if (len)
177 : len = GetShortPathName(curr_prefix, curr_prefix, path_name_max());
178 : # if DEBUG
179 : fprintf(stderr, "curr_prefix: %s\n", curr_prefix);
180 : # endif /* DEBUG */
181 : if (!curr_prefix && !strchr(program_name, '.')) { // try with extensions
182 : pathextstr = strsave(getenv("PATHEXT"));
183 : if (!pathextstr)
184 : pathextstr = strsave(PATH_EXT);
185 : curr_prefix = searchpathext(program_name, pathextstr, getenv("PATH"));
186 : delete[] pathextstr;
187 : }
188 : #else /* !_WIN32 */
189 17 : curr_prefix = searchpath(program_name, getenv("PATH"));
190 17 : if (!curr_prefix)
191 0 : return;
192 : #endif /* !_WIN32 */
193 17 : msw2posixpath(curr_prefix);
194 : #if DEBUG
195 : fprintf(stderr, "curr_prefix: %s\n", curr_prefix);
196 : #endif
197 17 : curr_prefix = xdirname(curr_prefix); // directory of executable
198 17 : curr_prefix = xdirname(curr_prefix); // parent directory of executable
199 17 : curr_prefix_len = strlen(curr_prefix);
200 : #if DEBUG
201 : fprintf(stderr, "curr_prefix: %s\n", curr_prefix);
202 : fprintf(stderr, "curr_prefix_len: %d\n", curr_prefix_len);
203 : #endif
204 : }
205 :
206 : // Strip the installation prefix and replace it
207 : // with the current installation prefix; return the relocated path.
208 17 : char *relocatep(const char *path)
209 : {
210 : #if DEBUG
211 : fprintf(stderr, "relocatep: path = %s\n", path);
212 : fprintf(stderr, "relocatep: INSTALLPATH = %s\n", INSTALLPATH);
213 : fprintf(stderr, "relocatep: INSTALLPATHLEN = %d\n", INSTALLPATHLEN);
214 : #endif
215 17 : if (!curr_prefix)
216 17 : set_current_prefix();
217 17 : if (strncmp(INSTALLPATH, path, INSTALLPATHLEN))
218 0 : return strsave(path);
219 17 : char *relative_path = (char *)path + INSTALLPATHLEN;
220 17 : size_t relative_path_len = strlen(relative_path);
221 17 : char *relocated_path = (char *)malloc(curr_prefix_len
222 17 : + relative_path_len + 1);
223 17 : assert(0 != curr_prefix);
224 17 : strcpy(relocated_path, curr_prefix);
225 17 : strcat(relocated_path, relative_path);
226 : #if DEBUG
227 : fprintf(stderr, "relocated_path: %s\n", relocated_path);
228 : #endif /* DEBUG */
229 17 : return relocated_path;
230 : }
231 :
232 : // Return the original pathname if it exists;
233 : // otherwise return the relocated path.
234 0 : char *relocate(const char *path)
235 : {
236 : char *p;
237 0 : if (access(path, F_OK))
238 0 : p = relocatep(path);
239 : else
240 0 : p = strsave(path);
241 : #if DEBUG
242 : fprintf (stderr, "relocate: %s\n", p);
243 : #endif
244 0 : return p;
245 : }
246 :
247 : // Local Variables:
248 : // fill-column: 72
249 : // mode: C++
250 : // End:
251 : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:
|