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