relocate.cpp revision 256281
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 42extern "C" const char *program_name; 43 44// The prefix (parent directory) corresponding to the binary. 45char *curr_prefix = 0; 46size_t curr_prefix_len = 0; 47 48// Return the directory part of a filename, or `.' if no path separators. 49char *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. 74char *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. 129char *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. 150char *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. 162void 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. 203char *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. 227char *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} 239