LCOV - code coverage report
Current view: top level - gcc - prefix.c (source / functions) Hit Total Coverage
Test: gcc.info Lines: 82 94 87.2 %
Date: 2020-03-28 11:57:23 Functions: 5 6 83.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* Utility to update paths from internal to external forms.
       2                 :            :    Copyright (C) 1997-2020 Free Software Foundation, Inc.
       3                 :            : 
       4                 :            : This file is part of GCC.
       5                 :            : 
       6                 :            : GCC is free software; you can redistribute it and/or modify it under
       7                 :            : the terms of the GNU Library General Public License as published by
       8                 :            : the Free Software Foundation; either version 3 of the License, or (at
       9                 :            : your option) any later version.
      10                 :            : 
      11                 :            : GCC is distributed in the hope that it will be useful,
      12                 :            : but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14                 :            : Library General Public License for more details.
      15                 :            : 
      16                 :            : You should have received a copy of the GNU Library General Public
      17                 :            : License along with GCC; see the file COPYING3.  If not see
      18                 :            : <http://www.gnu.org/licenses/>.  */
      19                 :            : 
      20                 :            : /* This file contains routines to update a path, both to canonicalize
      21                 :            :    the directory format and to handle any prefix translation.
      22                 :            : 
      23                 :            :    This file must be compiled with -DPREFIX= to specify the "prefix"
      24                 :            :    value used by configure.  If a filename does not begin with this
      25                 :            :    prefix, it will not be affected other than by directory canonicalization.
      26                 :            : 
      27                 :            :    Each caller of 'update_path' may specify both a filename and
      28                 :            :    a translation prefix and consist of the name of the package that contains
      29                 :            :    the file ("@GCC", "@BINUTIL", "@GNU", etc).
      30                 :            : 
      31                 :            :    If the prefix is not specified, the filename will only undergo
      32                 :            :    directory canonicalization.
      33                 :            : 
      34                 :            :    If it is specified, the string given by PREFIX will be replaced
      35                 :            :    by the specified prefix (with a '@' in front unless the prefix begins
      36                 :            :    with a '$') and further translation will be done as follows
      37                 :            :    until none of the two conditions below are met:
      38                 :            : 
      39                 :            :    1) If the filename begins with '@', the string between the '@' and
      40                 :            :    the end of the name or the first '/' or directory separator will
      41                 :            :    be considered a "key" and looked up as follows:
      42                 :            : 
      43                 :            :    -- If this is a Win32 OS, then the Registry will be examined for
      44                 :            :       an entry of "key" in
      45                 :            : 
      46                 :            :       HKEY_LOCAL_MACHINE\SOFTWARE\Free Software Foundation\<KEY>
      47                 :            : 
      48                 :            :       if found, that value will be used. <KEY> defaults to GCC version
      49                 :            :       string, but can be overridden at configuration time.
      50                 :            : 
      51                 :            :    -- If not found (or not a Win32 OS), the environment variable
      52                 :            :       key_ROOT (the value of "key" concatenated with the constant "_ROOT")
      53                 :            :       is tried.  If that fails, then PREFIX (see above) is used.
      54                 :            : 
      55                 :            :    2) If the filename begins with a '$', the rest of the string up
      56                 :            :    to the end or the first '/' or directory separator will be used
      57                 :            :    as an environment variable, whose value will be returned.
      58                 :            : 
      59                 :            :    Once all this is done, any '/' will be converted to DIR_SEPARATOR,
      60                 :            :    if they are different.
      61                 :            : 
      62                 :            :    NOTE:  using resolve_keyed_path under Win32 requires linking with
      63                 :            :    advapi32.dll.  */
      64                 :            : 
      65                 :            : 
      66                 :            : #include "config.h"
      67                 :            : #include "system.h"
      68                 :            : #include "coretypes.h"
      69                 :            : #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
      70                 :            : #include <windows.h>
      71                 :            : #endif
      72                 :            : #include "prefix.h"
      73                 :            : #include "common/common-target.h"
      74                 :            : 
      75                 :            : static const char *std_prefix = PREFIX;
      76                 :            : 
      77                 :            : static const char *get_key_value (char *);
      78                 :            : static char *translate_name (char *);
      79                 :            : static char *save_string (const char *, int);
      80                 :            : static void tr (char *, int, int);
      81                 :            : 
      82                 :            : #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
      83                 :            : static char *lookup_key (char *);
      84                 :            : static HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
      85                 :            : #endif
      86                 :            : 
      87                 :            : /* Given KEY, as above, return its value.  */
      88                 :            : 
      89                 :            : static const char *
      90                 :     203002 : get_key_value (char *key)
      91                 :            : {
      92                 :     203002 :   const char *prefix = 0;
      93                 :     203002 :   char *temp = 0;
      94                 :            : 
      95                 :            : #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
      96                 :            :   prefix = lookup_key (key);
      97                 :            : #endif
      98                 :            : 
      99                 :     203002 :   if (prefix == 0)
     100                 :     203002 :     prefix = getenv (temp = concat (key, "_ROOT", NULL));
     101                 :            : 
     102                 :     203002 :   if (prefix == 0)
     103                 :     203002 :     prefix = std_prefix;
     104                 :            : 
     105                 :     203002 :   free (temp);
     106                 :            : 
     107                 :     203002 :   return prefix;
     108                 :            : }
     109                 :            : 
     110                 :            : /* Return a copy of a string that has been placed in the heap.  */
     111                 :            : 
     112                 :            : static char *
     113                 :     203002 : save_string (const char *s, int len)
     114                 :            : {
     115                 :     203002 :   char *result = XNEWVEC (char, len + 1);
     116                 :            : 
     117                 :     203002 :   memcpy (result, s, len);
     118                 :     203002 :   result[len] = 0;
     119                 :     203002 :   return result;
     120                 :            : }
     121                 :            : 
     122                 :            : #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
     123                 :            : 
     124                 :            : #ifndef WIN32_REGISTRY_KEY
     125                 :            : # define WIN32_REGISTRY_KEY BASEVER
     126                 :            : #endif
     127                 :            : 
     128                 :            : /* Look up "key" in the registry, as above.  */
     129                 :            : 
     130                 :            : static char *
     131                 :            : lookup_key (char *key)
     132                 :            : {
     133                 :            :   char *dst;
     134                 :            :   DWORD size;
     135                 :            :   DWORD type;
     136                 :            :   LONG res;
     137                 :            : 
     138                 :            :   if (reg_key == (HKEY) INVALID_HANDLE_VALUE)
     139                 :            :     {
     140                 :            :       res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0,
     141                 :            :                            KEY_READ, &reg_key);
     142                 :            : 
     143                 :            :       if (res == ERROR_SUCCESS)
     144                 :            :         res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0,
     145                 :            :                              KEY_READ, &reg_key);
     146                 :            : 
     147                 :            :       if (res == ERROR_SUCCESS)
     148                 :            :         res = RegOpenKeyExA (reg_key, WIN32_REGISTRY_KEY, 0,
     149                 :            :                              KEY_READ, &reg_key);
     150                 :            : 
     151                 :            :       if (res != ERROR_SUCCESS)
     152                 :            :         {
     153                 :            :           reg_key = (HKEY) INVALID_HANDLE_VALUE;
     154                 :            :           return 0;
     155                 :            :         }
     156                 :            :     }
     157                 :            : 
     158                 :            :   size = 32;
     159                 :            :   dst = XNEWVEC (char, size);
     160                 :            : 
     161                 :            :   res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size);
     162                 :            :   if (res == ERROR_MORE_DATA && type == REG_SZ)
     163                 :            :     {
     164                 :            :       dst = XRESIZEVEC (char, dst, size);
     165                 :            :       res = RegQueryValueExA (reg_key, key, 0, &type, (LPBYTE) dst, &size);
     166                 :            :     }
     167                 :            : 
     168                 :            :   if (type != REG_SZ || res != ERROR_SUCCESS)
     169                 :            :     {
     170                 :            :       free (dst);
     171                 :            :       dst = 0;
     172                 :            :     }
     173                 :            : 
     174                 :            :   return dst;
     175                 :            : }
     176                 :            : #endif
     177                 :            : 
     178                 :            : /* If NAME, a malloc-ed string, starts with a '@' or '$', apply the
     179                 :            :    translation rules above and return a newly malloc-ed name.
     180                 :            :    Otherwise, return the given name.  */
     181                 :            : 
     182                 :            : static char *
     183                 :     203002 : translate_name (char *name)
     184                 :            : {
     185                 :     406004 :   char code;
     186                 :     406004 :   char *key, *old_name;
     187                 :     406004 :   const char *prefix;
     188                 :     406004 :   int keylen;
     189                 :            : 
     190                 :     609006 :   for (;;)
     191                 :            :     {
     192                 :     406004 :       code = name[0];
     193                 :     406004 :       if (code != '@' && code != '$')
     194                 :            :         break;
     195                 :            : 
     196                 :     609006 :       for (keylen = 0;
     197                 :     812008 :            (name[keylen + 1] != 0 && !IS_DIR_SEPARATOR (name[keylen + 1]));
     198                 :            :            keylen++)
     199                 :            :         ;
     200                 :            : 
     201                 :     203002 :       key = (char *) alloca (keylen + 1);
     202                 :     203002 :       memcpy (key, &name[1], keylen);
     203                 :     203002 :       key[keylen] = 0;
     204                 :            : 
     205                 :     203002 :       if (code == '@')
     206                 :            :         {
     207                 :     203002 :           prefix = get_key_value (key);
     208                 :     203002 :           if (prefix == 0)
     209                 :          0 :             prefix = std_prefix;
     210                 :            :         }
     211                 :            :       else
     212                 :          0 :         prefix = getenv (key);
     213                 :            : 
     214                 :     203002 :       if (prefix == 0)
     215                 :          0 :         prefix = PREFIX;
     216                 :            : 
     217                 :            :       /* We used to strip trailing DIR_SEPARATORs here, but that can
     218                 :            :          sometimes yield a result with no separator when one was coded
     219                 :            :          and intended by the user, causing two path components to run
     220                 :            :          together.  */
     221                 :            : 
     222                 :     203002 :       old_name = name;
     223                 :     203002 :       name = concat (prefix, &name[keylen + 1], NULL);
     224                 :     203002 :       free (old_name);
     225                 :            :     }
     226                 :            : 
     227                 :     203002 :   return name;
     228                 :            : }
     229                 :            : 
     230                 :            : /* In a NUL-terminated STRING, replace character C1 with C2 in-place.  */
     231                 :            : static void
     232                 :          0 : tr (char *string, int c1, int c2)
     233                 :            : {
     234                 :          0 :   do
     235                 :            :     {
     236                 :          0 :       if (*string == c1)
     237                 :          0 :         *string = c2;
     238                 :            :     }
     239                 :          0 :   while (*string++);
     240                 :          0 : }
     241                 :            : 
     242                 :            : /* Update PATH using KEY if PATH starts with PREFIX as a directory.
     243                 :            :    The returned string is always malloc-ed, and the caller is
     244                 :            :    responsible for freeing it.  */
     245                 :            : 
     246                 :            : char *
     247                 :    3907790 : update_path (const char *path, const char *key)
     248                 :            : {
     249                 :    3907790 :   char *result, *p;
     250                 :    3907790 :   const int len = strlen (std_prefix);
     251                 :            : 
     252                 :    3907790 :   if (! filename_ncmp (path, std_prefix, len)
     253                 :    1149190 :       && (IS_DIR_SEPARATOR (path[len])
     254                 :     833420 :           || path[len] == '\0')
     255                 :    4426560 :       && key != 0)
     256                 :            :     {
     257                 :     203002 :       bool free_key = false;
     258                 :            : 
     259                 :     203002 :       if (key[0] != '$')
     260                 :            :         {
     261                 :     203002 :           key = concat ("@", key, NULL);
     262                 :     203002 :           free_key = true;
     263                 :            :         }
     264                 :            : 
     265                 :     203002 :       result = concat (key, &path[len], NULL);
     266                 :     203002 :       if (free_key)
     267                 :     203002 :         free (CONST_CAST (char *, key));
     268                 :     203002 :       result = translate_name (result);
     269                 :            :     }
     270                 :            :   else
     271                 :    3704790 :     result = xstrdup (path);
     272                 :            : 
     273                 :    3907790 :   p = result;
     274                 :    7457270 :   while (1)
     275                 :            :     {
     276                 :    7457270 :       char *src, *dest;
     277                 :            : 
     278                 :    7457270 :       p = strchr (p, '.');
     279                 :    7457270 :       if (p == NULL)
     280                 :            :         break;
     281                 :            :       /* Look for `/../'  */
     282                 :    4445460 :       if (p[1] == '.'
     283                 :    2614000 :           && IS_DIR_SEPARATOR (p[2])
     284                 :    2614000 :           && (p != result && IS_DIR_SEPARATOR (p[-1])))
     285                 :            :         {
     286                 :    2614000 :           *p = 0;
     287                 :    2614000 :           if (!targetm_common.always_strip_dotdot
     288                 :    2614000 :               && access (result, X_OK) == 0)
     289                 :            :             {
     290                 :     895974 :               *p = '.';
     291                 :     895974 :               break;
     292                 :            :             }
     293                 :            :           else
     294                 :            :             {
     295                 :            :               /* We can't access the dir, so we won't be able to
     296                 :            :                  access dir/.. either.  Strip out `dir/../'.  If `dir'
     297                 :            :                  turns out to be `.', strip one more path component.  */
     298                 :            :               dest = p;
     299                 :    1718020 :               do
     300                 :            :                 {
     301                 :    1718020 :                   --dest;
     302                 :    3436040 :                   while (dest != result && IS_DIR_SEPARATOR (*dest))
     303                 :    1718020 :                     --dest;
     304                 :   16034900 :                   while (dest != result && !IS_DIR_SEPARATOR (dest[-1]))
     305                 :   14316800 :                     --dest;
     306                 :            :                 }
     307                 :    1718020 :               while (dest != result && *dest == '.');
     308                 :            :               /* If we have something like `./..' or `/..', don't
     309                 :            :                  strip anything more.  */
     310                 :    1718020 :               if (*dest == '.' || IS_DIR_SEPARATOR (*dest))
     311                 :            :                 {
     312                 :          0 :                   *p = '.';
     313                 :          0 :                   break;
     314                 :            :                 }
     315                 :    1718020 :               src = p + 3;
     316                 :    1718020 :               while (IS_DIR_SEPARATOR (*src))
     317                 :          0 :                 ++src;
     318                 :   39459400 :               p = dest;
     319                 :   39459400 :               while ((*dest++ = *src++) != 0)
     320                 :            :                 ;
     321                 :            :             }
     322                 :            :         }
     323                 :            :       else
     324                 :    1831460 :         ++p;
     325                 :            :     }
     326                 :            : 
     327                 :            : #ifdef UPDATE_PATH_HOST_CANONICALIZE
     328                 :            :   /* Perform host dependent canonicalization when needed.  */
     329                 :            :   UPDATE_PATH_HOST_CANONICALIZE (result);
     330                 :            : #endif
     331                 :            : 
     332                 :            : #ifdef DIR_SEPARATOR_2
     333                 :            :   /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR.  */
     334                 :            :   if (DIR_SEPARATOR_2 != DIR_SEPARATOR)
     335                 :            :     tr (result, DIR_SEPARATOR_2, DIR_SEPARATOR);
     336                 :            : #endif
     337                 :            : 
     338                 :            : #if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2)
     339                 :    3907790 :   if (DIR_SEPARATOR != '/')
     340                 :            :     tr (result, '/', DIR_SEPARATOR);
     341                 :            : #endif
     342                 :            : 
     343                 :    3907790 :   return result;
     344                 :            : }
     345                 :            : 
     346                 :            : /* Reset the standard prefix.  */
     347                 :            : void
     348                 :     203002 : set_std_prefix (const char *prefix, int len)
     349                 :            : {
     350                 :     203002 :   std_prefix = save_string (prefix, len);
     351                 :     203002 : }

Generated by: LCOV version 1.0

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto --enable-host-shared. GCC test suite is run with the built compiler.