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