LCOV - code coverage report
Current view: top level - libs/libgroff - relocate.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 39 88 44.3 %
Date: 2026-01-16 17:51:41 Functions: 5 7 71.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14