"Fossies" - the Fresh Open Source Software Archive

Member "OpenSP-1.5.2/intl/relocatable.c" (26 Aug 2005, 13113 Bytes) of package /linux/misc/old/OpenSP-1.5.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* Provide relocatable packages.
    2    Copyright (C) 2003-2004 Free Software Foundation, Inc.
    3    Written by Bruno Haible <bruno@clisp.org>, 2003.
    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 Street, Fifth Floor, Boston, MA 02110-1301,
   18    USA.  */
   19 
   20 
   21 /* Tell glibc's <stdio.h> to provide a prototype for getline().
   22    This must come before <config.h> because <config.h> may include
   23    <features.h>, and once <features.h> has been included, it's too late.  */
   24 #ifndef _GNU_SOURCE
   25 # define _GNU_SOURCE    1
   26 #endif
   27 
   28 #ifdef HAVE_CONFIG_H
   29 # include "config.h"
   30 #endif
   31 
   32 /* Specification.  */
   33 #include "relocatable.h"
   34 
   35 #if ENABLE_RELOCATABLE
   36 
   37 #include <stddef.h>
   38 #include <stdio.h>
   39 #include <stdlib.h>
   40 #include <string.h>
   41 
   42 #ifdef NO_XMALLOC
   43 # define xmalloc malloc
   44 #else
   45 # include "xalloc.h"
   46 #endif
   47 
   48 #if defined _WIN32 || defined __WIN32__
   49 # define WIN32_LEAN_AND_MEAN
   50 # include <windows.h>
   51 #endif
   52 
   53 #if DEPENDS_ON_LIBCHARSET
   54 # include <libcharset.h>
   55 #endif
   56 #if DEPENDS_ON_LIBICONV && HAVE_ICONV
   57 # include <iconv.h>
   58 #endif
   59 #if DEPENDS_ON_LIBINTL && ENABLE_NLS
   60 # include <libintl.h>
   61 #endif
   62 
   63 /* Faked cheap 'bool'.  */
   64 #undef bool
   65 #undef false
   66 #undef true
   67 #define bool int
   68 #define false 0
   69 #define true 1
   70 
   71 /* Pathname support.
   72    ISSLASH(C)           tests whether C is a directory separator character.
   73    IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
   74  */
   75 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
   76   /* Win32, Cygwin, OS/2, DOS */
   77 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
   78 # define HAS_DEVICE(P) \
   79     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
   80      && (P)[1] == ':')
   81 # define IS_PATH_WITH_DIR(P) \
   82     (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
   83 # define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
   84 #else
   85   /* Unix */
   86 # define ISSLASH(C) ((C) == '/')
   87 # define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
   88 # define FILE_SYSTEM_PREFIX_LEN(P) 0
   89 #endif
   90 
   91 /* Original installation prefix.  */
   92 static char *orig_prefix;
   93 static size_t orig_prefix_len;
   94 /* Current installation prefix.  */
   95 static char *curr_prefix;
   96 static size_t curr_prefix_len;
   97 /* These prefixes do not end in a slash.  Anything that will be concatenated
   98    to them must start with a slash.  */
   99 
  100 /* Sets the original and the current installation prefix of this module.
  101    Relocation simply replaces a pathname starting with the original prefix
  102    by the corresponding pathname with the current prefix instead.  Both
  103    prefixes should be directory names without trailing slash (i.e. use ""
  104    instead of "/").  */
  105 static void
  106 set_this_relocation_prefix (const char *orig_prefix_arg,
  107                 const char *curr_prefix_arg)
  108 {
  109   if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
  110       /* Optimization: if orig_prefix and curr_prefix are equal, the
  111      relocation is a nop.  */
  112       && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
  113     {
  114       /* Duplicate the argument strings.  */
  115       char *memory;
  116 
  117       orig_prefix_len = strlen (orig_prefix_arg);
  118       curr_prefix_len = strlen (curr_prefix_arg);
  119       memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
  120 #ifdef NO_XMALLOC
  121       if (memory != NULL)
  122 #endif
  123     {
  124       memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
  125       orig_prefix = memory;
  126       memory += orig_prefix_len + 1;
  127       memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
  128       curr_prefix = memory;
  129       return;
  130     }
  131     }
  132   orig_prefix = NULL;
  133   curr_prefix = NULL;
  134   /* Don't worry about wasted memory here - this function is usually only
  135      called once.  */
  136 }
  137 
  138 /* Sets the original and the current installation prefix of the package.
  139    Relocation simply replaces a pathname starting with the original prefix
  140    by the corresponding pathname with the current prefix instead.  Both
  141    prefixes should be directory names without trailing slash (i.e. use ""
  142    instead of "/").  */
  143 void
  144 set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
  145 {
  146   set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  147 
  148   /* Now notify all dependent libraries.  */
  149 #if DEPENDS_ON_LIBCHARSET
  150   libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  151 #endif
  152 #if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
  153   libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  154 #endif
  155 #if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
  156   libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
  157 #endif
  158 }
  159 
  160 #if !defined IN_LIBRARY || (defined PIC && defined INSTALLDIR)
  161 
  162 /* Convenience function:
  163    Computes the current installation prefix, based on the original
  164    installation prefix, the original installation directory of a particular
  165    file, and the current pathname of this file.  Returns NULL upon failure.  */
  166 #ifdef IN_LIBRARY
  167 #define compute_curr_prefix local_compute_curr_prefix
  168 static
  169 #endif
  170 const char *
  171 compute_curr_prefix (const char *orig_installprefix,
  172              const char *orig_installdir,
  173              const char *curr_pathname)
  174 {
  175   const char *curr_installdir;
  176   const char *rel_installdir;
  177 
  178   if (curr_pathname == NULL)
  179     return NULL;
  180 
  181   /* Determine the relative installation directory, relative to the prefix.
  182      This is simply the difference between orig_installprefix and
  183      orig_installdir.  */
  184   if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
  185       != 0)
  186     /* Shouldn't happen - nothing should be installed outside $(prefix).  */
  187     return NULL;
  188   rel_installdir = orig_installdir + strlen (orig_installprefix);
  189 
  190   /* Determine the current installation directory.  */
  191   {
  192     const char *p_base = curr_pathname + FILE_SYSTEM_PREFIX_LEN (curr_pathname);
  193     const char *p = curr_pathname + strlen (curr_pathname);
  194     char *q;
  195 
  196     while (p > p_base)
  197       {
  198     p--;
  199     if (ISSLASH (*p))
  200       break;
  201       }
  202 
  203     q = (char *) xmalloc (p - curr_pathname + 1);
  204 #ifdef NO_XMALLOC
  205     if (q == NULL)
  206       return NULL;
  207 #endif
  208     memcpy (q, curr_pathname, p - curr_pathname);
  209     q[p - curr_pathname] = '\0';
  210     curr_installdir = q;
  211   }
  212 
  213   /* Compute the current installation prefix by removing the trailing
  214      rel_installdir from it.  */
  215   {
  216     const char *rp = rel_installdir + strlen (rel_installdir);
  217     const char *cp = curr_installdir + strlen (curr_installdir);
  218     const char *cp_base =
  219       curr_installdir + FILE_SYSTEM_PREFIX_LEN (curr_installdir);
  220 
  221     while (rp > rel_installdir && cp > cp_base)
  222       {
  223     bool same = false;
  224     const char *rpi = rp;
  225     const char *cpi = cp;
  226 
  227     while (rpi > rel_installdir && cpi > cp_base)
  228       {
  229         rpi--;
  230         cpi--;
  231         if (ISSLASH (*rpi) || ISSLASH (*cpi))
  232           {
  233         if (ISSLASH (*rpi) && ISSLASH (*cpi))
  234           same = true;
  235         break;
  236           }
  237 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
  238         /* Win32, Cygwin, OS/2, DOS - case insignificant filesystem */
  239         if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
  240         != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
  241           break;
  242 #else
  243         if (*rpi != *cpi)
  244           break;
  245 #endif
  246       }
  247     if (!same)
  248       break;
  249     /* The last pathname component was the same.  opi and cpi now point
  250        to the slash before it.  */
  251     rp = rpi;
  252     cp = cpi;
  253       }
  254 
  255     if (rp > rel_installdir)
  256       /* Unexpected: The curr_installdir does not end with rel_installdir.  */
  257       return NULL;
  258 
  259     {
  260       size_t curr_prefix_len = cp - curr_installdir;
  261       char *curr_prefix;
  262 
  263       curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
  264 #ifdef NO_XMALLOC
  265       if (curr_prefix == NULL)
  266     return NULL;
  267 #endif
  268       memcpy (curr_prefix, curr_installdir, curr_prefix_len);
  269       curr_prefix[curr_prefix_len] = '\0';
  270 
  271       return curr_prefix;
  272     }
  273   }
  274 }
  275 
  276 #endif /* !IN_LIBRARY || PIC */
  277 
  278 #if defined PIC && defined INSTALLDIR
  279 
  280 /* Full pathname of shared library, or NULL.  */
  281 static char *shared_library_fullname;
  282 
  283 #if defined _WIN32 || defined __WIN32__
  284 
  285 /* Determine the full pathname of the shared library when it is loaded.  */
  286 
  287 BOOL WINAPI
  288 DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
  289 {
  290   (void) reserved;
  291 
  292   if (event == DLL_PROCESS_ATTACH)
  293     {
  294       /* The DLL is being loaded into an application's address range.  */
  295       static char location[MAX_PATH];
  296 
  297       if (!GetModuleFileName (module_handle, location, sizeof (location)))
  298     /* Shouldn't happen.  */
  299     return FALSE;
  300 
  301       if (!IS_PATH_WITH_DIR (location))
  302     /* Shouldn't happen.  */
  303     return FALSE;
  304 
  305       shared_library_fullname = strdup (location);
  306     }
  307 
  308   return TRUE;
  309 }
  310 
  311 #else /* Unix */
  312 
  313 static void
  314 find_shared_library_fullname ()
  315 {
  316 #if defined __linux__ && __GLIBC__ >= 2
  317   /* Linux has /proc/self/maps. glibc 2 has the getline() function.  */
  318   FILE *fp;
  319 
  320   /* Open the current process' maps file.  It describes one VMA per line.  */
  321   fp = fopen ("/proc/self/maps", "r");
  322   if (fp)
  323     {
  324       unsigned long address = (unsigned long) &find_shared_library_fullname;
  325       for (;;)
  326     {
  327       unsigned long start, end;
  328       int c;
  329 
  330       if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
  331         break;
  332       if (address >= start && address <= end - 1)
  333         {
  334           /* Found it.  Now see if this line contains a filename.  */
  335           while (c = getc (fp), c != EOF && c != '\n' && c != '/')
  336         continue;
  337           if (c == '/')
  338         {
  339           size_t size;
  340           int len;
  341 
  342           ungetc (c, fp);
  343           shared_library_fullname = NULL; size = 0;
  344           len = getline (&shared_library_fullname, &size, fp);
  345           if (len >= 0)
  346             {
  347               /* Success: filled shared_library_fullname.  */
  348               if (len > 0 && shared_library_fullname[len - 1] == '\n')
  349             shared_library_fullname[len - 1] = '\0';
  350             }
  351         }
  352           break;
  353         }
  354       while (c = getc (fp), c != EOF && c != '\n')
  355         continue;
  356     }
  357       fclose (fp);
  358     }
  359 #endif
  360 }
  361 
  362 #endif /* WIN32 / Unix */
  363 
  364 /* Return the full pathname of the current shared library.
  365    Return NULL if unknown.
  366    Guaranteed to work only on Linux and Woe32.  */
  367 static char *
  368 get_shared_library_fullname ()
  369 {
  370 #if !(defined _WIN32 || defined __WIN32__)
  371   static bool tried_find_shared_library_fullname;
  372   if (!tried_find_shared_library_fullname)
  373     {
  374       find_shared_library_fullname ();
  375       tried_find_shared_library_fullname = true;
  376     }
  377 #endif
  378   return shared_library_fullname;
  379 }
  380 
  381 #endif /* PIC */
  382 
  383 /* Returns the pathname, relocated according to the current installation
  384    directory.  */
  385 const char *
  386 relocate (const char *pathname)
  387 {
  388 #if defined PIC && defined INSTALLDIR
  389   static int initialized;
  390 
  391   /* Initialization code for a shared library.  */
  392   if (!initialized)
  393     {
  394       /* At this point, orig_prefix and curr_prefix likely have already been
  395      set through the main program's set_program_name_and_installdir
  396      function.  This is sufficient in the case that the library has
  397      initially been installed in the same orig_prefix.  But we can do
  398      better, to also cover the cases that 1. it has been installed
  399      in a different prefix before being moved to orig_prefix and (later)
  400      to curr_prefix, 2. unlike the program, it has not moved away from
  401      orig_prefix.  */
  402       const char *orig_installprefix = INSTALLPREFIX;
  403       const char *orig_installdir = INSTALLDIR;
  404       const char *curr_prefix_better;
  405 
  406       curr_prefix_better =
  407     compute_curr_prefix (orig_installprefix, orig_installdir,
  408                  get_shared_library_fullname ());
  409       if (curr_prefix_better == NULL)
  410     curr_prefix_better = curr_prefix;
  411 
  412       set_relocation_prefix (orig_installprefix, curr_prefix_better);
  413 
  414       initialized = 1;
  415     }
  416 #endif
  417 
  418   /* Note: It is not necessary to perform case insensitive comparison here,
  419      even for DOS-like filesystems, because the pathname argument was
  420      typically created from the same Makefile variable as orig_prefix came
  421      from.  */
  422   if (orig_prefix != NULL && curr_prefix != NULL
  423       && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
  424     {
  425       if (pathname[orig_prefix_len] == '\0')
  426     /* pathname equals orig_prefix.  */
  427     return curr_prefix;
  428       if (ISSLASH (pathname[orig_prefix_len]))
  429     {
  430       /* pathname starts with orig_prefix.  */
  431       const char *pathname_tail = &pathname[orig_prefix_len];
  432       char *result =
  433         (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
  434 
  435 #ifdef NO_XMALLOC
  436       if (result != NULL)
  437 #endif
  438         {
  439           memcpy (result, curr_prefix, curr_prefix_len);
  440           strcpy (result + curr_prefix_len, pathname_tail);
  441           return result;
  442         }
  443     }
  444     }
  445   /* Nothing to relocate.  */
  446   return pathname;
  447 }
  448 
  449 #endif