1151497Sru// -*- C++ -*- 2151497Sru/* Provide relocation for macro and font files. 3151497Sru Copyright (C) 2005 Free Software Foundation, Inc. 4151497Sru 5151497Sru This program is free software; you can redistribute it and/or modify it 6151497Sru under the terms of the GNU Library General Public License as published 7151497Sru by the Free Software Foundation; either version 2, or (at your option) 8151497Sru any later version. 9151497Sru 10151497Sru This program is distributed in the hope that it will be useful, 11151497Sru but WITHOUT ANY WARRANTY; without even the implied warranty of 12151497Sru MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13151497Sru Library General Public License for more details. 14151497Sru 15151497Sru You should have received a copy of the GNU Library General Public 16151497Sru License along with this program; if not, write to the Free Software 17151497Sru Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, 18151497Sru USA. */ 19151497Sru 20151497Sru// Made after relocation code in kpathsea and gettext. 21151497Sru 22151497Sru#include "lib.h" 23151497Sru 24151497Sru#include <errno.h> 25151497Sru#include <stdlib.h> 26151497Sru 27151497Sru#include "defs.h" 28151497Sru#include "posix.h" 29151497Sru#include "nonposix.h" 30151497Sru#include "relocate.h" 31151497Sru 32151497Sru#if defined _WIN32 33151497Sru# define WIN32_LEAN_AND_MEAN 34151497Sru# include <windows.h> 35151497Sru#endif 36151497Sru 37151497Sru#define INSTALLPATHLEN (sizeof(INSTALLPATH) - 1) 38151497Sru#ifndef DEBUG 39151497Sru# define DEBUG 0 40151497Sru#endif 41151497Sru 42151497Sruextern "C" const char *program_name; 43151497Sru 44151497Sru// The prefix (parent directory) corresponding to the binary. 45151497Sruchar *curr_prefix = 0; 46151497Srusize_t curr_prefix_len = 0; 47151497Sru 48151497Sru// Return the directory part of a filename, or `.' if no path separators. 49151497Sruchar *xdirname(char *s) 50151497Sru{ 51151497Sru static const char dot[] = "."; 52151497Sru if (!s) 53151497Sru return 0; 54151497Sru // DIR_SEPS[] are possible directory separator characters, see nonposix.h. 55151497Sru // We want the rightmost separator of all possible ones. 56151497Sru // Example: d:/foo\\bar. 57151497Sru char *p = strrchr(s, DIR_SEPS[0]); 58151497Sru const char *sep = &DIR_SEPS[1]; 59151497Sru while (*sep) { 60151497Sru char *p1 = strrchr(s, *sep); 61151497Sru if (p1 && (!p || p1 > p)) 62151497Sru p = p1; 63151497Sru sep++; 64151497Sru } 65151497Sru if (p) 66151497Sru *p = '\0'; 67151497Sru else 68151497Sru s = (char *)dot; 69151497Sru return s; 70151497Sru} 71151497Sru 72151497Sru// Return the full path of NAME along the path PATHP. 73151497Sru// Adapted from search_path::open_file in searchpath.cpp. 74151497Sruchar *searchpath(const char *name, const char *pathp) 75151497Sru{ 76151497Sru char *path; 77151497Sru if (!name || !*name) 78151497Sru return 0; 79151497Sru#if DEBUG 80151497Sru fprintf(stderr, "searchpath: pathp: `%s'\n", pathp); 81151497Sru fprintf(stderr, "searchpath: trying `%s'\n", name); 82151497Sru#endif 83151497Sru // Try first NAME as such; success if NAME is an absolute filename, 84151497Sru // or if NAME is found in the current directory. 85151497Sru if (!access (name, F_OK)) { 86151497Sru path = new char[path_name_max()]; 87151497Sru#ifdef _WIN32 88151497Sru path = _fullpath(path, name, path_name_max()); 89151497Sru#else 90151497Sru path = realpath(name, path); 91151497Sru#endif 92151497Sru#if DEBUG 93151497Sru fprintf(stderr, "searchpath: found `%s'\n", path); 94151497Sru#endif 95151497Sru return path; 96151497Sru } 97151497Sru // Secondly, try the current directory. 98151497Sru // Now search along PATHP. 99151497Sru size_t namelen = strlen(name); 100151497Sru char *p = (char *)pathp; 101151497Sru for (;;) { 102151497Sru char *end = strchr(p, PATH_SEP_CHAR); 103151497Sru if (!end) 104151497Sru end = strchr(p, '\0'); 105151497Sru int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; 106151497Sru path = new char[end - p + need_slash + namelen + 1]; 107151497Sru memcpy(path, p, end - p); 108151497Sru if (need_slash) 109151497Sru path[end - p] = '/'; 110151497Sru strcpy(path + (end - p) + need_slash, name); 111151497Sru#if DEBUG 112151497Sru fprintf(stderr, "searchpath: trying `%s'\n", path); 113151497Sru#endif 114151497Sru if (!access(path, F_OK)) { 115151497Sru#if DEBUG 116151497Sru fprintf(stderr, "searchpath: found `%s'\n", name); 117151497Sru#endif 118151497Sru return path; 119151497Sru } 120151497Sru a_delete path; 121151497Sru if (*end == '\0') 122151497Sru break; 123151497Sru p = end + 1; 124151497Sru } 125151497Sru return 0; 126151497Sru} 127151497Sru 128151497Sru// Search NAME along PATHP with the elements of PATHEXT in turn added. 129151497Sruchar *searchpathext(const char *name, const char *pathext, const char *pathp) 130151497Sru{ 131151497Sru char *found = 0; 132151497Sru char *tmpathext = strsave(pathext); // strtok modifies this string, 133151497Sru // so make a copy 134151497Sru char *ext = strtok(tmpathext, PATH_SEP); 135151497Sru while (ext) { 136151497Sru char *namex = new char[strlen(name) + strlen(ext) + 1]; 137151497Sru strcpy(namex, name); 138151497Sru strcat(namex, ext); 139151497Sru found = searchpath(namex, pathp); 140151497Sru a_delete namex; 141151497Sru if (found) 142151497Sru break; 143151497Sru ext = strtok(0, PATH_SEP); 144151497Sru } 145151497Sru a_delete tmpathext; 146151497Sru return found; 147151497Sru} 148151497Sru 149151497Sru// Convert an MS path to a POSIX path. 150151497Sruchar *msw2posixpath(char *path) 151151497Sru{ 152151497Sru char *s = path; 153151497Sru while (*s) { 154151497Sru if (*s == '\\') 155151497Sru *s = '/'; 156151497Sru *s++; 157151497Sru } 158151497Sru return path; 159151497Sru} 160151497Sru 161151497Sru// Compute the current prefix. 162151497Sruvoid set_current_prefix() 163151497Sru{ 164151497Sru char *pathextstr; 165151497Sru curr_prefix = new char[path_name_max()]; 166151497Sru // Obtain the full path of the current binary; 167151497Sru // using GetModuleFileName on MS-Windows, 168151497Sru // and searching along PATH on other systems. 169151497Sru#ifdef _WIN32 170151497Sru int len = GetModuleFileName(0, curr_prefix, path_name_max()); 171151497Sru if (len) 172151497Sru len = GetShortPathName(curr_prefix, curr_prefix, path_name_max()); 173151497Sru# if DEBUG 174151497Sru fprintf(stderr, "curr_prefix: %s\n", curr_prefix); 175151497Sru# endif /* DEBUG */ 176151497Sru#else /* !_WIN32 */ 177151497Sru curr_prefix = searchpath(program_name, getenv("PATH")); 178151497Sru if (!curr_prefix && !strchr(program_name, '.')) { // try with extensions 179151497Sru pathextstr = strsave(getenv("PATHEXT")); 180151497Sru if (!pathextstr) 181151497Sru pathextstr = strsave(PATH_EXT); 182151497Sru curr_prefix = searchpathext(program_name, pathextstr, getenv("PATH")); 183151497Sru a_delete pathextstr; 184151497Sru } 185151497Sru if (!curr_prefix) 186151497Sru return; 187151497Sru#endif /* !_WIN32 */ 188151497Sru msw2posixpath(curr_prefix); 189151497Sru#if DEBUG 190151497Sru fprintf(stderr, "curr_prefix: %s\n", curr_prefix); 191151497Sru#endif 192151497Sru curr_prefix = xdirname(curr_prefix); // directory of executable 193151497Sru curr_prefix = xdirname(curr_prefix); // parent directory of executable 194151497Sru curr_prefix_len = strlen(curr_prefix); 195151497Sru#if DEBUG 196151497Sru fprintf(stderr, "curr_prefix: %s\n", curr_prefix); 197151497Sru fprintf(stderr, "curr_prefix_len: %d\n", curr_prefix_len); 198151497Sru#endif 199151497Sru} 200151497Sru 201151497Sru// Strip the installation prefix and replace it 202151497Sru// with the current installation prefix; return the relocated path. 203151497Sruchar *relocatep(const char *path) 204151497Sru{ 205151497Sru#if DEBUG 206151497Sru fprintf(stderr, "relocatep: path = %s\n", path); 207151497Sru fprintf(stderr, "relocatep: INSTALLPATH = %s\n", INSTALLPATH); 208151497Sru fprintf(stderr, "relocatep: INSTALLPATHLEN = %d\n", INSTALLPATHLEN); 209151497Sru#endif 210151497Sru if (!curr_prefix) 211151497Sru set_current_prefix(); 212151497Sru if (strncmp(INSTALLPATH, path, INSTALLPATHLEN)) 213151497Sru return strsave(path); 214151497Sru char *relative_path = (char *)path + INSTALLPATHLEN; 215151497Sru size_t relative_path_len = strlen(relative_path); 216151497Sru char *relocated_path = new char[curr_prefix_len + relative_path_len + 1]; 217151497Sru strcpy(relocated_path, curr_prefix); 218151497Sru strcat(relocated_path, relative_path); 219151497Sru#if DEBUG 220151497Sru fprintf(stderr, "relocated_path: %s\n", relocated_path); 221151497Sru#endif /* DEBUG */ 222151497Sru return relocated_path; 223151497Sru} 224151497Sru 225151497Sru// Return the original pathname if it exists; 226151497Sru// otherwise return the relocated path. 227151497Sruchar *relocate(const char *path) 228151497Sru{ 229151497Sru char *p; 230151497Sru if (access(path, F_OK)) 231151497Sru p = relocatep(path); 232151497Sru else 233151497Sru p = strsave(path); 234151497Sru#if DEBUG 235151497Sru fprintf (stderr, "relocate: %s\n", p); 236151497Sru#endif 237151497Sru return p; 238151497Sru} 239