OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libiberty/] [make-relative-prefix.c] - Blame information for rev 746

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 736 jeremybenn
/* Relative (relocatable) prefix support.
2
   Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3
   1999, 2000, 2001, 2002, 2006, 2012 Free Software Foundation, Inc.
4
 
5
This file is part of libiberty.
6
 
7
GCC is free software; you can redistribute it and/or modify it under
8
the terms of the GNU General Public License as published by the Free
9
Software Foundation; either version 2, or (at your option) any later
10
version.
11
 
12
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13
WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with GCC; see the file COPYING.  If not, write to the Free
19
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20
02110-1301, USA.  */
21
 
22
/*
23
 
24
@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, @
25
  const char *@var{bin_prefix}, const char *@var{prefix})
26
 
27
Given three paths @var{progname}, @var{bin_prefix}, @var{prefix},
28
return the path that is in the same position relative to
29
@var{progname}'s directory as @var{prefix} is relative to
30
@var{bin_prefix}.  That is, a string starting with the directory
31
portion of @var{progname}, followed by a relative pathname of the
32
difference between @var{bin_prefix} and @var{prefix}.
33
 
34
If @var{progname} does not contain any directory separators,
35
@code{make_relative_prefix} will search @env{PATH} to find a program
36
named @var{progname}.  Also, if @var{progname} is a symbolic link,
37
the symbolic link will be resolved.
38
 
39
For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta},
40
@var{prefix} is @code{/alpha/beta/gamma/omega/}, and @var{progname} is
41
@code{/red/green/blue/gcc}, then this function will return
42
@code{/red/green/blue/../../omega/}.
43
 
44
The return value is normally allocated via @code{malloc}.  If no
45
relative prefix can be found, return @code{NULL}.
46
 
47
@end deftypefn
48
 
49
*/
50
 
51
#ifdef HAVE_CONFIG_H
52
#include "config.h"
53
#endif
54
 
55
#ifdef HAVE_STDLIB_H
56
#include <stdlib.h>
57
#endif
58
#ifdef HAVE_UNISTD_H
59
#include <unistd.h>
60
#endif
61
#ifdef HAVE_SYS_STAT_H
62
#include <sys/stat.h>
63
#endif
64
 
65
#include <string.h>
66
 
67
#include "ansidecl.h"
68
#include "libiberty.h"
69
 
70
#ifndef R_OK
71
#define R_OK 4
72
#define W_OK 2
73
#define X_OK 1
74
#endif
75
 
76
#ifndef DIR_SEPARATOR
77
#  define DIR_SEPARATOR '/'
78
#endif
79
 
80
#if defined (_WIN32) || defined (__MSDOS__) \
81
    || defined (__DJGPP__) || defined (__OS2__)
82
#  define HAVE_DOS_BASED_FILE_SYSTEM
83
#  define HAVE_HOST_EXECUTABLE_SUFFIX
84
#  define HOST_EXECUTABLE_SUFFIX ".exe"
85
#  ifndef DIR_SEPARATOR_2 
86
#    define DIR_SEPARATOR_2 '\\'
87
#  endif
88
#  define PATH_SEPARATOR ';'
89
#else
90
#  define PATH_SEPARATOR ':'
91
#endif
92
 
93
#ifndef DIR_SEPARATOR_2
94
#  define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
95
#else
96
#  define IS_DIR_SEPARATOR(ch) \
97
        (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
98
#endif
99
 
100
#define DIR_UP ".."
101
 
102
static char *save_string (const char *, int);
103
static char **split_directories (const char *, int *);
104
static void free_split_directories (char **);
105
 
106
static char *
107
save_string (const char *s, int len)
108
{
109
  char *result = (char *) malloc (len + 1);
110
 
111
  memcpy (result, s, len);
112
  result[len] = 0;
113
  return result;
114
}
115
 
116
/* Split a filename into component directories.  */
117
 
118
static char **
119
split_directories (const char *name, int *ptr_num_dirs)
120
{
121
  int num_dirs = 0;
122
  char **dirs;
123
  const char *p, *q;
124
  int ch;
125
 
126
  /* Count the number of directories.  Special case MSDOS disk names as part
127
     of the initial directory.  */
128
  p = name;
129
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
130
  if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
131
    {
132
      p += 3;
133
      num_dirs++;
134
    }
135
#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
136
 
137
  while ((ch = *p++) != '\0')
138
    {
139
      if (IS_DIR_SEPARATOR (ch))
140
        {
141
          num_dirs++;
142
          while (IS_DIR_SEPARATOR (*p))
143
            p++;
144
        }
145
    }
146
 
147
  dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2));
148
  if (dirs == NULL)
149
    return NULL;
150
 
151
  /* Now copy the directory parts.  */
152
  num_dirs = 0;
153
  p = name;
154
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
155
  if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
156
    {
157
      dirs[num_dirs++] = save_string (p, 3);
158
      if (dirs[num_dirs - 1] == NULL)
159
        {
160
          free (dirs);
161
          return NULL;
162
        }
163
      p += 3;
164
    }
165
#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
166
 
167
  q = p;
168
  while ((ch = *p++) != '\0')
169
    {
170
      if (IS_DIR_SEPARATOR (ch))
171
        {
172
          while (IS_DIR_SEPARATOR (*p))
173
            p++;
174
 
175
          dirs[num_dirs++] = save_string (q, p - q);
176
          if (dirs[num_dirs - 1] == NULL)
177
            {
178
              dirs[num_dirs] = NULL;
179
              free_split_directories (dirs);
180
              return NULL;
181
            }
182
          q = p;
183
        }
184
    }
185
 
186
  if (p - 1 - q > 0)
187
    dirs[num_dirs++] = save_string (q, p - 1 - q);
188
  dirs[num_dirs] = NULL;
189
 
190
  if (dirs[num_dirs - 1] == NULL)
191
    {
192
      free_split_directories (dirs);
193
      return NULL;
194
    }
195
 
196
  if (ptr_num_dirs)
197
    *ptr_num_dirs = num_dirs;
198
  return dirs;
199
}
200
 
201
/* Release storage held by split directories.  */
202
 
203
static void
204
free_split_directories (char **dirs)
205
{
206
  int i = 0;
207
 
208
  if (dirs != NULL)
209
    {
210
      while (dirs[i] != NULL)
211
        free (dirs[i++]);
212
 
213
      free ((char *) dirs);
214
    }
215
}
216
 
217
/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets
218
   to PREFIX starting with the directory portion of PROGNAME and a relative
219
   pathname of the difference between BIN_PREFIX and PREFIX.
220
 
221
   For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is
222
   /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this
223
   function will return /red/green/blue/../../omega/.
224
 
225
   If no relative prefix can be found, return NULL.  */
226
 
227
static char *
228
make_relative_prefix_1 (const char *progname, const char *bin_prefix,
229
                        const char *prefix, const int resolve_links)
230
{
231
  char **prog_dirs = NULL, **bin_dirs = NULL, **prefix_dirs = NULL;
232
  int prog_num, bin_num, prefix_num;
233
  int i, n, common;
234
  int needed_len;
235
  char *ret = NULL, *ptr, *full_progname;
236
 
237
  if (progname == NULL || bin_prefix == NULL || prefix == NULL)
238
    return NULL;
239
 
240
  /* If there is no full pathname, try to find the program by checking in each
241
     of the directories specified in the PATH environment variable.  */
242
  if (lbasename (progname) == progname)
243
    {
244
      char *temp;
245
 
246
      temp = getenv ("PATH");
247
      if (temp)
248
        {
249
          char *startp, *endp, *nstore;
250
          size_t prefixlen = strlen (temp) + 1;
251
          size_t len;
252
          if (prefixlen < 2)
253
            prefixlen = 2;
254
 
255
          len = prefixlen + strlen (progname) + 1;
256
#ifdef HAVE_HOST_EXECUTABLE_SUFFIX
257
          len += strlen (HOST_EXECUTABLE_SUFFIX);
258
#endif
259
          nstore = (char *) alloca (len);
260
 
261
          startp = endp = temp;
262
          while (1)
263
            {
264
              if (*endp == PATH_SEPARATOR || *endp == 0)
265
                {
266
                  if (endp == startp)
267
                    {
268
                      nstore[0] = '.';
269
                      nstore[1] = DIR_SEPARATOR;
270
                      nstore[2] = '\0';
271
                    }
272
                  else
273
                    {
274
                      memcpy (nstore, startp, endp - startp);
275
                      if (! IS_DIR_SEPARATOR (endp[-1]))
276
                        {
277
                          nstore[endp - startp] = DIR_SEPARATOR;
278
                          nstore[endp - startp + 1] = 0;
279
                        }
280
                      else
281
                        nstore[endp - startp] = 0;
282
                    }
283
                  strcat (nstore, progname);
284
                  if (! access (nstore, X_OK)
285
#ifdef HAVE_HOST_EXECUTABLE_SUFFIX
286
                      || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK)
287
#endif
288
                      )
289
                    {
290
#if defined (HAVE_SYS_STAT_H) && defined (S_ISREG)
291
                      struct stat st;
292
                      if (stat (nstore, &st) >= 0 && S_ISREG (st.st_mode))
293
#endif
294
                        {
295
                          progname = nstore;
296
                          break;
297
                        }
298
                    }
299
 
300
                  if (*endp == 0)
301
                    break;
302
                  endp = startp = endp + 1;
303
                }
304
              else
305
                endp++;
306
            }
307
        }
308
    }
309
 
310
  if (resolve_links)
311
    full_progname = lrealpath (progname);
312
  else
313
    full_progname = strdup (progname);
314
  if (full_progname == NULL)
315
    return NULL;
316
 
317
  prog_dirs = split_directories (full_progname, &prog_num);
318
  free (full_progname);
319
  if (prog_dirs == NULL)
320
    return NULL;
321
 
322
  bin_dirs = split_directories (bin_prefix, &bin_num);
323
  if (bin_dirs == NULL)
324
    goto bailout;
325
 
326
  /* Remove the program name from comparison of directory names.  */
327
  prog_num--;
328
 
329
  /* If we are still installed in the standard location, we don't need to
330
     specify relative directories.  Also, if argv[0] still doesn't contain
331
     any directory specifiers after the search above, then there is not much
332
     we can do.  */
333
  if (prog_num == bin_num)
334
    {
335
      for (i = 0; i < bin_num; i++)
336
        {
337
          if (strcmp (prog_dirs[i], bin_dirs[i]) != 0)
338
            break;
339
        }
340
 
341
      if (prog_num <= 0 || i == bin_num)
342
        goto bailout;
343
    }
344
 
345
  prefix_dirs = split_directories (prefix, &prefix_num);
346
  if (prefix_dirs == NULL)
347
    goto bailout;
348
 
349
  /* Find how many directories are in common between bin_prefix & prefix.  */
350
  n = (prefix_num < bin_num) ? prefix_num : bin_num;
351
  for (common = 0; common < n; common++)
352
    {
353
      if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0)
354
        break;
355
    }
356
 
357
  /* If there are no common directories, there can be no relative prefix.  */
358
  if (common == 0)
359
    goto bailout;
360
 
361
  /* Two passes: first figure out the size of the result string, and
362
     then construct it.  */
363
  needed_len = 0;
364
  for (i = 0; i < prog_num; i++)
365
    needed_len += strlen (prog_dirs[i]);
366
  needed_len += sizeof (DIR_UP) * (bin_num - common);
367
  for (i = common; i < prefix_num; i++)
368
    needed_len += strlen (prefix_dirs[i]);
369
  needed_len += 1; /* Trailing NUL.  */
370
 
371
  ret = (char *) malloc (needed_len);
372
  if (ret == NULL)
373
    goto bailout;
374
 
375
  /* Build up the pathnames in argv[0].  */
376
  *ret = '\0';
377
  for (i = 0; i < prog_num; i++)
378
    strcat (ret, prog_dirs[i]);
379
 
380
  /* Now build up the ..'s.  */
381
  ptr = ret + strlen(ret);
382
  for (i = common; i < bin_num; i++)
383
    {
384
      strcpy (ptr, DIR_UP);
385
      ptr += sizeof (DIR_UP) - 1;
386
      *(ptr++) = DIR_SEPARATOR;
387
    }
388
  *ptr = '\0';
389
 
390
  /* Put in directories to move over to prefix.  */
391
  for (i = common; i < prefix_num; i++)
392
    strcat (ret, prefix_dirs[i]);
393
 
394
 bailout:
395
  free_split_directories (prog_dirs);
396
  free_split_directories (bin_dirs);
397
  free_split_directories (prefix_dirs);
398
 
399
  return ret;
400
}
401
 
402
 
403
/* Do the full job, including symlink resolution.
404
   This path will find files installed in the same place as the
405
   program even when a soft link has been made to the program
406
   from somwhere else. */
407
 
408
char *
409
make_relative_prefix (const char *progname, const char *bin_prefix,
410
                      const char *prefix)
411
{
412
  return make_relative_prefix_1 (progname, bin_prefix, prefix, 1);
413
}
414
 
415
/* Make the relative pathname without attempting to resolve any links.
416
   '..' etc may also be left in the pathname.
417
   This will find the files the user meant the program to find if the
418
   installation is patched together with soft links. */
419
 
420
char *
421
make_relative_prefix_ignore_links (const char *progname,
422
                                   const char *bin_prefix,
423
                                   const char *prefix)
424
{
425
  return make_relative_prefix_1 (progname, bin_prefix, prefix, 0);
426
}
427
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.