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