PageRenderTime 49ms CodeModel.GetById 2ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/groff/src/libs/libgroff/relocate.cpp

https://bitbucket.org/freebsd/freebsd-head/
C++ | 238 lines | 182 code | 15 blank | 41 comment | 31 complexity | 453714e0def9b3fa94dc35999c1d181b MD5 | raw file
  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}