1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50: #ifdef HAVE_CONFIG_H
51: #include "config.h"
52: #endif
53:
54: #ifdef HAVE_STDLIB_H
55: #include <stdlib.h>
56: #endif
57: #ifdef HAVE_UNISTD_H
58: #include <unistd.h>
59: #endif
60:
61: #include <string.h>
62:
63: #include "ansidecl.h"
64: #include "libiberty.h"
65:
66: #ifndef R_OK
67: #define R_OK 4
68: #define W_OK 2
69: #define X_OK 1
70: #endif
71:
72: #ifndef DIR_SEPARATOR
73: # define DIR_SEPARATOR '/'
74: #endif
75:
76: #if defined (_WIN32) || defined (__MSDOS__) \
77: || defined (__DJGPP__) || defined (__OS2__)
78: # define HAVE_DOS_BASED_FILE_SYSTEM
79: # define HAVE_HOST_EXECUTABLE_SUFFIX
80: # define HOST_EXECUTABLE_SUFFIX ".exe"
81: # ifndef DIR_SEPARATOR_2
82: # define DIR_SEPARATOR_2 '\\'
83: # endif
84: # define PATH_SEPARATOR ';'
85: #else
86: # define PATH_SEPARATOR ':'
87: #endif
88:
89: #ifndef DIR_SEPARATOR_2
90: # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
91: #else
92: # define IS_DIR_SEPARATOR(ch) \
93: (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
94: #endif
95:
96: #define DIR_UP ".."
97:
98: static char *save_string (const char *, int);
99: static char **split_directories (const char *, int *);
100: static void free_split_directories (char **);
101:
102: static char *
103: save_string (const char *s, int len)
104: {
105: char *result = (char *) malloc (len + 1);
106:
107: memcpy (result, s, len);
108: result[len] = 0;
109: return result;
110: }
111:
112:
113:
114: static char **
115: split_directories (const char *name, int *ptr_num_dirs)
116: {
117: int num_dirs = 0;
118: char **dirs;
119: const char *p, *q;
120: int ch;
121:
122:
123:
124: p = name;
125: #ifdef HAVE_DOS_BASED_FILE_SYSTEM
126: if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
127: {
128: p += 3;
129: num_dirs++;
130: }
131: #endif
132:
133: while ((ch = *p++) != '\0')
134: {
135: if (IS_DIR_SEPARATOR (ch))
136: {
137: num_dirs++;
138: while (IS_DIR_SEPARATOR (*p))
139: p++;
140: }
141: }
142:
143: dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2));
144: if (dirs == NULL)
145: return NULL;
146:
147:
148: num_dirs = 0;
149: p = name;
150: #ifdef HAVE_DOS_BASED_FILE_SYSTEM
151: if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
152: {
153: dirs[num_dirs++] = save_string (p, 3);
154: if (dirs[num_dirs - 1] == NULL)
155: {
156: free (dirs);
157: return NULL;
158: }
159: p += 3;
160: }
161: #endif
162:
163: q = p;
164: while ((ch = *p++) != '\0')
165: {
166: if (IS_DIR_SEPARATOR (ch))
167: {
168: while (IS_DIR_SEPARATOR (*p))
169: p++;
170:
171: dirs[num_dirs++] = save_string (q, p - q);
172: if (dirs[num_dirs - 1] == NULL)
173: {
174: dirs[num_dirs] = NULL;
175: free_split_directories (dirs);
176: return NULL;
177: }
178: q = p;
179: }
180: }
181:
182: if (p - 1 - q > 0)
183: dirs[num_dirs++] = save_string (q, p - 1 - q);
184: dirs[num_dirs] = NULL;
185:
186: if (dirs[num_dirs - 1] == NULL)
187: {
188: free_split_directories (dirs);
189: return NULL;
190: }
191:
192: if (ptr_num_dirs)
193: *ptr_num_dirs = num_dirs;
194: return dirs;
195: }
196:
197:
198:
199: static void
200: free_split_directories (char **dirs)
201: {
202: int i = 0;
203:
204: while (dirs[i] != NULL)
205: free (dirs[i++]);
206:
207: free ((char *) dirs);
208: }
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220: static char *
221: make_relative_prefix_1 (const char *progname, const char *bin_prefix,
222: const char *prefix, const int resolve_links)
223: {
224: char **prog_dirs, **bin_dirs, **prefix_dirs;
225: int prog_num, bin_num, prefix_num;
226: int i, n, common;
227: int needed_len;
228: char *ret, *ptr, *full_progname = NULL;
229:
230: if (progname == NULL || bin_prefix == NULL || prefix == NULL)
231: return NULL;
232:
233:
234:
235: if (lbasename (progname) == progname)
236: {
237: char *temp;
238:
239: temp = getenv ("PATH");
240: if (temp)
241: {
242: char *startp, *endp, *nstore;
243: size_t prefixlen = strlen (temp) + 1;
244: if (prefixlen < 2)
245: prefixlen = 2;
246:
247: nstore = (char *) alloca (prefixlen + strlen (progname) + 1);
248:
249: startp = endp = temp;
250: while (1)
251: {
252: if (*endp == PATH_SEPARATOR || *endp == 0)
253: {
254: if (endp == startp)
255: {
256: nstore[0] = '.';
257: nstore[1] = DIR_SEPARATOR;
258: nstore[2] = '\0';
259: }
260: else
261: {
262: strncpy (nstore, startp, endp - startp);
263: if (! IS_DIR_SEPARATOR (endp[-1]))
264: {
265: nstore[endp - startp] = DIR_SEPARATOR;
266: nstore[endp - startp + 1] = 0;
267: }
268: else
269: nstore[endp - startp] = 0;
270: }
271: strcat (nstore, progname);
272: if (! access (nstore, X_OK)
273: #ifdef HAVE_HOST_EXECUTABLE_SUFFIX
274: || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK)
275: #endif
276: )
277: {
278: progname = nstore;
279: break;
280: }
281:
282: if (*endp == 0)
283: break;
284: endp = startp = endp + 1;
285: }
286: else
287: endp++;
288: }
289: }
290: }
291:
292: if ( resolve_links )
293: {
294: full_progname = lrealpath (progname);
295: if (full_progname == NULL)
296: return NULL;
297: }
298: else
299: full_progname = strdup(progname);
300:
301: prog_dirs = split_directories (full_progname, &prog_num);
302: free (full_progname);
303: if (prog_dirs == NULL)
304: return NULL;
305:
306: bin_dirs = split_directories (bin_prefix, &bin_num);
307: if (bin_dirs == NULL)
308: {
309: free_split_directories (prog_dirs);
310: return NULL;
311: }
312:
313:
314: prog_num--;
315:
316:
317:
318:
319:
320: if (prog_num == bin_num)
321: {
322: for (i = 0; i < bin_num; i++)
323: {
324: if (strcmp (prog_dirs[i], bin_dirs[i]) != 0)
325: break;
326: }
327:
328: if (prog_num <= 0 || i == bin_num)
329: {
330: free_split_directories (prog_dirs);
331: free_split_directories (bin_dirs);
332: prog_dirs = bin_dirs = (char **) 0;
333: return NULL;
334: }
335: }
336:
337: prefix_dirs = split_directories (prefix, &prefix_num);
338: if (prefix_dirs == NULL)
339: {
340: free_split_directories (prog_dirs);
341: free_split_directories (bin_dirs);
342: return NULL;
343: }
344:
345:
346: n = (prefix_num < bin_num) ? prefix_num : bin_num;
347: for (common = 0; common < n; common++)
348: {
349: if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0)
350: break;
351: }
352:
353:
354: if (common == 0)
355: {
356: free_split_directories (prog_dirs);
357: free_split_directories (bin_dirs);
358: free_split_directories (prefix_dirs);
359: return NULL;
360: }
361:
362:
363:
364: needed_len = 0;
365: for (i = 0; i < prog_num; i++)
366: needed_len += strlen (prog_dirs[i]);
367: needed_len += sizeof (DIR_UP) * (bin_num - common);
368: for (i = common; i < prefix_num; i++)
369: needed_len += strlen (prefix_dirs[i]);
370: needed_len += 1;
371:
372: ret = (char *) malloc (needed_len);
373: if (ret == NULL)
374: return NULL;
375:
376:
377: *ret = '\0';
378: for (i = 0; i < prog_num; i++)
379: strcat (ret, prog_dirs[i]);
380:
381:
382: ptr = ret + strlen(ret);
383: for (i = common; i < bin_num; i++)
384: {
385: strcpy (ptr, DIR_UP);
386: ptr += sizeof (DIR_UP) - 1;
387: *(ptr++) = DIR_SEPARATOR;
388: }
389: *ptr = '\0';
390:
391:
392: for (i = common; i < prefix_num; i++)
393: strcat (ret, prefix_dirs[i]);
394:
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:
404:
405:
406:
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:
416:
417:
418:
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: