xref: /netbsd-src/external/gpl2/groff/dist/src/libs/libgroff/relocate.cpp (revision 89a07cf815a29524268025a1139fac4c5190f765)
1 /*	$NetBSD: relocate.cpp,v 1.1.1.1 2016/01/13 18:41:48 christos Exp $	*/
2 
3 // -*- C++ -*-
4 /* Provide relocation for macro and font files.
5    Copyright (C) 2005 Free Software Foundation, Inc.
6 
7    This program is free software; you can redistribute it and/or modify it
8    under the terms of the GNU Library General Public License as published
9    by the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11 
12    This program 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    Library General Public License for more details.
16 
17    You should have received a copy of the GNU Library General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301,
20    USA.  */
21 
22 // Made after relocation code in kpathsea and gettext.
23 
24 #include "lib.h"
25 
26 #include <errno.h>
27 #include <stdlib.h>
28 
29 #include "defs.h"
30 #include "posix.h"
31 #include "nonposix.h"
32 #include "relocate.h"
33 
34 #if defined _WIN32
35 # define WIN32_LEAN_AND_MEAN
36 # include <windows.h>
37 #endif
38 
39 #define INSTALLPATHLEN (sizeof(INSTALLPATH) - 1)
40 #ifndef DEBUG
41 # define DEBUG 0
42 #endif
43 
44 extern "C" const char *program_name;
45 
46 // The prefix (parent directory) corresponding to the binary.
47 char *curr_prefix = 0;
48 size_t curr_prefix_len = 0;
49 
50 // Return the directory part of a filename, or `.' if no path separators.
xdirname(char * s)51 char *xdirname(char *s)
52 {
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++;
66   }
67   if (p)
68     *p = '\0';
69   else
70     s = (char *)dot;
71   return s;
72 }
73 
74 // Return the full path of NAME along the path PATHP.
75 // Adapted from search_path::open_file in searchpath.cpp.
searchpath(const char * name,const char * pathp)76 char *searchpath(const char *name, const char *pathp)
77 {
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;
98   }
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;
121     }
122     a_delete path;
123     if (*end == '\0')
124       break;
125     p = end + 1;
126   }
127   return 0;
128 }
129 
130 // Search NAME along PATHP with the elements of PATHEXT in turn added.
searchpathext(const char * name,const char * pathext,const char * pathp)131 char *searchpathext(const char *name, const char *pathext, const char *pathp)
132 {
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);
146   }
147   a_delete tmpathext;
148   return found;
149 }
150 
151 // Convert an MS path to a POSIX path.
msw2posixpath(char * path)152 char *msw2posixpath(char *path)
153 {
154   char *s = path;
155   while (*s) {
156     if (*s == '\\')
157       *s = '/';
158     *s++;
159   }
160   return path;
161 }
162 
163 // Compute the current prefix.
set_current_prefix()164 void set_current_prefix()
165 {
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;
186   }
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
201 }
202 
203 // Strip the installation prefix and replace it
204 // with the current installation prefix; return the relocated path.
relocatep(const char * path)205 char *relocatep(const char *path)
206 {
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;
225 }
226 
227 // Return the original pathname if it exists;
228 // otherwise return the relocated path.
relocate(const char * path)229 char *relocate(const char *path)
230 {
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;
240 }
241