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. 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. 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. 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. 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. 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. 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. 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