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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [libiberty/] [make-relative-prefix.c] - Blame information for rev 147

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

Line No. Rev Author Line
1 21 khays
/* Relative (relocatable) prefix support.
2
   Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3
   1999, 2000, 2001, 2002, 2006 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
 
62
#include <string.h>
63
 
64
#include "ansidecl.h"
65
#include "libiberty.h"
66
 
67
#ifndef R_OK
68
#define R_OK 4
69
#define W_OK 2
70
#define X_OK 1
71
#endif
72
 
73
#ifndef DIR_SEPARATOR
74
#  define DIR_SEPARATOR '/'
75
#endif
76
 
77
#if defined (_WIN32) || defined (__MSDOS__) \
78
    || defined (__DJGPP__) || defined (__OS2__)
79
#  define HAVE_DOS_BASED_FILE_SYSTEM
80
#  define HAVE_HOST_EXECUTABLE_SUFFIX
81
#  define HOST_EXECUTABLE_SUFFIX ".exe"
82
#  ifndef DIR_SEPARATOR_2 
83
#    define DIR_SEPARATOR_2 '\\'
84
#  endif
85
#  define PATH_SEPARATOR ';'
86
#else
87
#  define PATH_SEPARATOR ':'
88
#endif
89
 
90
#ifndef DIR_SEPARATOR_2
91
#  define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
92
#else
93
#  define IS_DIR_SEPARATOR(ch) \
94
        (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
95
#endif
96
 
97
#define DIR_UP ".."
98
 
99
static char *save_string (const char *, int);
100
static char **split_directories (const char *, int *);
101
static void free_split_directories (char **);
102
 
103
static char *
104
save_string (const char *s, int len)
105
{
106
  char *result = (char *) malloc (len + 1);
107
 
108
  memcpy (result, s, len);
109
  result[len] = 0;
110
  return result;
111
}
112
 
113
/* Split a filename into component directories.  */
114
 
115
static char **
116
split_directories (const char *name, int *ptr_num_dirs)
117
{
118
  int num_dirs = 0;
119
  char **dirs;
120
  const char *p, *q;
121
  int ch;
122
 
123
  /* Count the number of directories.  Special case MSDOS disk names as part
124
     of the initial directory.  */
125
  p = name;
126
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
127
  if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
128
    {
129
      p += 3;
130
      num_dirs++;
131
    }
132
#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
133
 
134
  while ((ch = *p++) != '\0')
135
    {
136
      if (IS_DIR_SEPARATOR (ch))
137
        {
138
          num_dirs++;
139
          while (IS_DIR_SEPARATOR (*p))
140
            p++;
141
        }
142
    }
143
 
144
  dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2));
145
  if (dirs == NULL)
146
    return NULL;
147
 
148
  /* Now copy the directory parts.  */
149
  num_dirs = 0;
150
  p = name;
151
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
152
  if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
153
    {
154
      dirs[num_dirs++] = save_string (p, 3);
155
      if (dirs[num_dirs - 1] == NULL)
156
        {
157
          free (dirs);
158
          return NULL;
159
        }
160
      p += 3;
161
    }
162
#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
163
 
164
  q = p;
165
  while ((ch = *p++) != '\0')
166
    {
167
      if (IS_DIR_SEPARATOR (ch))
168
        {
169
          while (IS_DIR_SEPARATOR (*p))
170
            p++;
171
 
172
          dirs[num_dirs++] = save_string (q, p - q);
173
          if (dirs[num_dirs - 1] == NULL)
174
            {
175
              dirs[num_dirs] = NULL;
176
              free_split_directories (dirs);
177
              return NULL;
178
            }
179
          q = p;
180
        }
181
    }
182
 
183
  if (p - 1 - q > 0)
184
    dirs[num_dirs++] = save_string (q, p - 1 - q);
185
  dirs[num_dirs] = NULL;
186
 
187
  if (dirs[num_dirs - 1] == NULL)
188
    {
189
      free_split_directories (dirs);
190
      return NULL;
191
    }
192
 
193
  if (ptr_num_dirs)
194
    *ptr_num_dirs = num_dirs;
195
  return dirs;
196
}
197
 
198
/* Release storage held by split directories.  */
199
 
200
static void
201
free_split_directories (char **dirs)
202
{
203
  int i = 0;
204
 
205
  if (dirs != NULL)
206
    {
207
      while (dirs[i] != NULL)
208
        free (dirs[i++]);
209
 
210
      free ((char *) dirs);
211
    }
212
}
213
 
214
/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets
215
   to PREFIX starting with the directory portion of PROGNAME and a relative
216
   pathname of the difference between BIN_PREFIX and PREFIX.
217
 
218
   For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is
219
   /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this
220
   function will return /red/green/blue/../../omega/.
221
 
222
   If no relative prefix can be found, return NULL.  */
223
 
224
static char *
225
make_relative_prefix_1 (const char *progname, const char *bin_prefix,
226
                        const char *prefix, const int resolve_links)
227
{
228
  char **prog_dirs = NULL, **bin_dirs = NULL, **prefix_dirs = NULL;
229
  int prog_num, bin_num, prefix_num;
230
  int i, n, common;
231
  int needed_len;
232
  char *ret = NULL, *ptr, *full_progname;
233
 
234
  if (progname == NULL || bin_prefix == NULL || prefix == NULL)
235
    return NULL;
236
 
237
  /* If there is no full pathname, try to find the program by checking in each
238
     of the directories specified in the PATH environment variable.  */
239
  if (lbasename (progname) == progname)
240
    {
241
      char *temp;
242
 
243
      temp = getenv ("PATH");
244
      if (temp)
245
        {
246
          char *startp, *endp, *nstore;
247
          size_t prefixlen = strlen (temp) + 1;
248
          if (prefixlen < 2)
249
            prefixlen = 2;
250
 
251
          nstore = (char *) alloca (prefixlen + strlen (progname) + 1);
252
 
253
          startp = endp = temp;
254
          while (1)
255
            {
256
              if (*endp == PATH_SEPARATOR || *endp == 0)
257
                {
258
                  if (endp == startp)
259
                    {
260
                      nstore[0] = '.';
261
                      nstore[1] = DIR_SEPARATOR;
262
                      nstore[2] = '\0';
263
                    }
264
                  else
265
                    {
266
                      strncpy (nstore, startp, endp - startp);
267
                      if (! IS_DIR_SEPARATOR (endp[-1]))
268
                        {
269
                          nstore[endp - startp] = DIR_SEPARATOR;
270
                          nstore[endp - startp + 1] = 0;
271
                        }
272
                      else
273
                        nstore[endp - startp] = 0;
274
                    }
275
                  strcat (nstore, progname);
276
                  if (! access (nstore, X_OK)
277
#ifdef HAVE_HOST_EXECUTABLE_SUFFIX
278
                      || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK)
279
#endif
280
                      )
281
                    {
282
                      progname = nstore;
283
                      break;
284
                    }
285
 
286
                  if (*endp == 0)
287
                    break;
288
                  endp = startp = endp + 1;
289
                }
290
              else
291
                endp++;
292
            }
293
        }
294
    }
295
 
296
  if (resolve_links)
297
    full_progname = lrealpath (progname);
298
  else
299
    full_progname = strdup (progname);
300
  if (full_progname == NULL)
301
    return NULL;
302
 
303
  prog_dirs = split_directories (full_progname, &prog_num);
304
  free (full_progname);
305
  if (prog_dirs == NULL)
306
    return NULL;
307
 
308
  bin_dirs = split_directories (bin_prefix, &bin_num);
309
  if (bin_dirs == NULL)
310
    goto bailout;
311
 
312
  /* Remove the program name from comparison of directory names.  */
313
  prog_num--;
314
 
315
  /* If we are still installed in the standard location, we don't need to
316
     specify relative directories.  Also, if argv[0] still doesn't contain
317
     any directory specifiers after the search above, then there is not much
318
     we can do.  */
319
  if (prog_num == bin_num)
320
    {
321
      for (i = 0; i < bin_num; i++)
322
        {
323
          if (strcmp (prog_dirs[i], bin_dirs[i]) != 0)
324
            break;
325
        }
326
 
327
      if (prog_num <= 0 || i == bin_num)
328
        goto bailout;
329
    }
330
 
331
  prefix_dirs = split_directories (prefix, &prefix_num);
332
  if (prefix_dirs == NULL)
333
    goto bailout;
334
 
335
  /* Find how many directories are in common between bin_prefix & prefix.  */
336
  n = (prefix_num < bin_num) ? prefix_num : bin_num;
337
  for (common = 0; common < n; common++)
338
    {
339
      if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0)
340
        break;
341
    }
342
 
343
  /* If there are no common directories, there can be no relative prefix.  */
344
  if (common == 0)
345
    goto bailout;
346
 
347
  /* Two passes: first figure out the size of the result string, and
348
     then construct it.  */
349
  needed_len = 0;
350
  for (i = 0; i < prog_num; i++)
351
    needed_len += strlen (prog_dirs[i]);
352
  needed_len += sizeof (DIR_UP) * (bin_num - common);
353
  for (i = common; i < prefix_num; i++)
354
    needed_len += strlen (prefix_dirs[i]);
355
  needed_len += 1; /* Trailing NUL.  */
356
 
357
  ret = (char *) malloc (needed_len);
358
  if (ret == NULL)
359
    goto bailout;
360
 
361
  /* Build up the pathnames in argv[0].  */
362
  *ret = '\0';
363
  for (i = 0; i < prog_num; i++)
364
    strcat (ret, prog_dirs[i]);
365
 
366
  /* Now build up the ..'s.  */
367
  ptr = ret + strlen(ret);
368
  for (i = common; i < bin_num; i++)
369
    {
370
      strcpy (ptr, DIR_UP);
371
      ptr += sizeof (DIR_UP) - 1;
372
      *(ptr++) = DIR_SEPARATOR;
373
    }
374
  *ptr = '\0';
375
 
376
  /* Put in directories to move over to prefix.  */
377
  for (i = common; i < prefix_num; i++)
378
    strcat (ret, prefix_dirs[i]);
379
 
380
 bailout:
381
  free_split_directories (prog_dirs);
382
  free_split_directories (bin_dirs);
383
  free_split_directories (prefix_dirs);
384
 
385
  return ret;
386
}
387
 
388
 
389
/* Do the full job, including symlink resolution.
390
   This path will find files installed in the same place as the
391
   program even when a soft link has been made to the program
392
   from somwhere else. */
393
 
394
char *
395
make_relative_prefix (const char *progname, const char *bin_prefix,
396
                      const char *prefix)
397
{
398
  return make_relative_prefix_1 (progname, bin_prefix, prefix, 1);
399
}
400
 
401
/* Make the relative pathname without attempting to resolve any links.
402
   '..' etc may also be left in the pathname.
403
   This will find the files the user meant the program to find if the
404
   installation is patched together with soft links. */
405
 
406
char *
407
make_relative_prefix_ignore_links (const char *progname,
408
                                   const char *bin_prefix,
409
                                   const char *prefix)
410
{
411
  return make_relative_prefix_1 (progname, bin_prefix, prefix, 0);
412
}
413
 

powered by: WebSVN 2.1.0

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