From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25811 invoked by alias); 19 Nov 2002 01:33:20 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 25804 invoked from network); 19 Nov 2002 01:33:18 -0000 Received: from unknown (HELO crack.them.org) (65.125.64.184) by sources.redhat.com with SMTP; 19 Nov 2002 01:33:18 -0000 Received: from nevyn.them.org ([66.93.61.169] ident=mail) by crack.them.org with asmtp (Exim 3.12 #1 (Debian)) id 18Dz8m-0001xn-00; Mon, 18 Nov 2002 21:33:32 -0600 Received: from drow by nevyn.them.org with local (Exim 3.36 #1 (Debian)) id 18DxHi-0004pY-00; Mon, 18 Nov 2002 20:34:38 -0500 Date: Mon, 18 Nov 2002 17:33:00 -0000 From: Daniel Jacobowitz To: DJ Delorie Cc: gcc-patches@sources.redhat.com Subject: Re: Add make_relative_prefix to libiberty Message-ID: <20021119013438.GA17693@nevyn.them.org> Mail-Followup-To: DJ Delorie , gcc-patches@sources.redhat.com References: <20021118174038.GA12204@nevyn.them.org> <200211181944.gAIJicS04560@greed.delorie.com> <20021119002605.GA21333@nevyn.them.org> <200211190052.gAJ0qpE06381@greed.delorie.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <200211190052.gAJ0qpE06381@greed.delorie.com> User-Agent: Mutt/1.5.1i X-SW-Source: 2002-11/txt/msg01094.txt.bz2 On Mon, Nov 18, 2002 at 07:52:51PM -0500, DJ Delorie wrote: > > > Which header? I do not see allocation rules, just a list of how > > different functions in libiberty allocate memory. A number of them use > > xmalloc to do it. Much simpler for an initialization function like > > this one. > > All I'm looking for is a short note in the header where the > declaration is (like "return value must be free'd by caller"). Oh, I see. > > > You have also changed the copyright terms (GPL -> LGPL). Do you have > > > the FSF's permission to do so? > > > > No. It was just me being sloppy; I apologize. I copied the wrong > > copyright notice; I think I grabbed it from lbasename. Since I see a > > number of GPL source files in libiberty, I assume that there is no > > problem with adding a GPL'd source file to the libiberty directory? > > Depends. If this function is primarily for GPL'd applications, I > don't see a problem. We've had cases where we want the "GPL plus > exception" for libstdc++, but I don't think this is the case. but we > can't change it anyway, so we might as well keep it GPL. > > > +This file is part of GCC. > > + > > +GCC is free software; you can redistribute it and/or modify it under > > +the terms of the GNU General Public License as published by the Free > > +Software Foundation; either version 2, or (at your option) any later > > +version. > > + > > +GCC is distributed in the hope that it will be useful, but WITHOUT ANY > > +WARRANTY; without even the implied warranty of MERCHANTABILITY or > > +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > > +for more details. > > + > > +You should have received a copy of the GNU General Public License > > +along with GCC; see the file COPYING. If not, write to the Free > > +Software Foundation, 59 Temple Place - Suite 330, Boston, MA > > +02111-1307, USA. */ > > Obviously, we shouldn't use "GCC" here ;-) Just quoting :) Should all the rest of the files in libiberty be updated to say they belong to libiberty? There's one from GDB (floatformat), one from GNU C Library (regex.c; that one's actually mastered elsewhere IIRC?), and several from GNU CC or GNU C Compiler. > > +/* > > + > > +@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, const char *@var{bin_prefix}, const char *@var{prefix}) > > + > > +Given pointers to the @code{argv[0]}, the default installation directory > > +for this program, and the default location of another directory, this function > > +returns the path to the other directory assuming the installation tree has moved > > +from @var{bin_prefix} to the new location of @var{progname}. > > Hmmm.. could we add a note about the rv's allocation here? > > And the big comment above make_relative_prefix itself has the text > which should go here. That's basically what I did when I did the > original set of docs - just resyntaxed the comments into texinfo. Okie. > > +#include "ansidecl.h" > > +#include "libiberty.h" > > The Makefile still has dependencies on obstack.h Fixed. While I was at it, I updated the docs and big comment to be actually _accurate_. If you work through the example that's been sitting there for a while, you'll notice it doesn't make much sense... Updated with your corrections. If this is OK with DJ, would a GCC maintainer please approve the move out of gcc.c? -- Daniel Jacobowitz MontaVista Software Debian GNU/Linux Developer 2002-11-18 Daniel Jacobowitz * libiberty.h (make_relative_prefix): Add prototype. 2002-11-18 Daniel Jacobowitz * Makefile.in: Add make-relative-prefix.c. * make-relative-prefix.c: New file. * functions.texi: Rebuilt. 2002-11-18 Daniel Jacobowitz * gcc.c (make_relative_prefix, split_directories) (free_split_directories): Removed. Index: gcc/gcc.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/gcc.c,v retrieving revision 1.344 diff -u -p -r1.344 gcc.c --- gcc/gcc.c 14 Oct 2002 07:15:38 -0000 1.344 +++ gcc/gcc.c 19 Nov 2002 01:30:22 -0000 @@ -267,11 +267,6 @@ static struct rusage rus, prus; struct path_prefix; static void init_spec PARAMS ((void)); -#ifndef VMS -static char **split_directories PARAMS ((const char *, int *)); -static void free_split_directories PARAMS ((char **)); -static char *make_relative_prefix PARAMS ((const char *, const char *, const char *)); -#endif /* VMS */ static void store_arg PARAMS ((const char *, int, int)); static char *load_specs PARAMS ((const char *)); static void read_specs PARAMS ((const char *, int)); @@ -2249,246 +2244,6 @@ putenv_from_prefixes (paths, env_var) { putenv (build_search_list (paths, env_var, 1)); } - -#ifndef VMS - -/* FIXME: the location independence code for VMS is hairier than this, - and hasn't been written. */ - -/* Split a filename into component directories. */ - -static char ** -split_directories (name, ptr_num_dirs) - const char *name; - int *ptr_num_dirs; -{ - int num_dirs = 0; - char **dirs; - const char *p, *q; - int ch; - - /* Count the number of directories. Special case MSDOS disk names as part - of the initial directory. */ - p = name; -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) - { - p += 3; - num_dirs++; - } -#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ - - while ((ch = *p++) != '\0') - { - if (IS_DIR_SEPARATOR (ch)) - { - num_dirs++; - while (IS_DIR_SEPARATOR (*p)) - p++; - } - } - - dirs = (char **) xmalloc (sizeof (char *) * (num_dirs + 2)); - - /* Now copy the directory parts. */ - num_dirs = 0; - p = name; -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) - { - dirs[num_dirs++] = save_string (p, 3); - p += 3; - } -#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ - - q = p; - while ((ch = *p++) != '\0') - { - if (IS_DIR_SEPARATOR (ch)) - { - while (IS_DIR_SEPARATOR (*p)) - p++; - - dirs[num_dirs++] = save_string (q, p - q); - q = p; - } - } - - if (p - 1 - q > 0) - dirs[num_dirs++] = save_string (q, p - 1 - q); - - dirs[num_dirs] = NULL; - if (ptr_num_dirs) - *ptr_num_dirs = num_dirs; - - return dirs; -} - -/* Release storage held by split directories. */ - -static void -free_split_directories (dirs) - char **dirs; -{ - int i = 0; - - while (dirs[i] != NULL) - free (dirs[i++]); - - free ((char *) dirs); -} - -/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets - to PREFIX starting with the directory portion of PROGNAME and a relative - pathname of the difference between BIN_PREFIX and PREFIX. - - For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is - /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this - function will return /red/green/blue/../omega. - - If no relative prefix can be found, return NULL. */ - -static char * -make_relative_prefix (progname, bin_prefix, prefix) - const char *progname; - const char *bin_prefix; - const char *prefix; -{ - char **prog_dirs, **bin_dirs, **prefix_dirs; - int prog_num, bin_num, prefix_num, std_loc_p; - int i, n, common; - - prog_dirs = split_directories (progname, &prog_num); - bin_dirs = split_directories (bin_prefix, &bin_num); - - /* If there is no full pathname, try to find the program by checking in each - of the directories specified in the PATH environment variable. */ - if (prog_num == 1) - { - char *temp; - - GET_ENVIRONMENT (temp, "PATH"); - if (temp) - { - char *startp, *endp, *nstore; - size_t prefixlen = strlen (temp) + 1; - if (prefixlen < 2) - prefixlen = 2; - - nstore = (char *) alloca (prefixlen + strlen (progname) + 1); - - startp = endp = temp; - while (1) - { - if (*endp == PATH_SEPARATOR || *endp == 0) - { - if (endp == startp) - { - nstore[0] = '.'; - nstore[1] = DIR_SEPARATOR; - nstore[2] = '\0'; - } - else - { - strncpy (nstore, startp, endp - startp); - if (! IS_DIR_SEPARATOR (endp[-1])) - { - nstore[endp - startp] = DIR_SEPARATOR; - nstore[endp - startp + 1] = 0; - } - else - nstore[endp - startp] = 0; - } - strcat (nstore, progname); - if (! access (nstore, X_OK) -#ifdef HAVE_HOST_EXECUTABLE_SUFFIX - || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK) -#endif - ) - { - free_split_directories (prog_dirs); - progname = nstore; - prog_dirs = split_directories (progname, &prog_num); - break; - } - - if (*endp == 0) - break; - endp = startp = endp + 1; - } - else - endp++; - } - } - } - - /* Remove the program name from comparison of directory names. */ - prog_num--; - - /* Determine if the compiler is installed in the standard location, and if - so, we don't need to specify relative directories. Also, if argv[0] - doesn't contain any directory specifiers, there is not much we can do. */ - std_loc_p = 0; - if (prog_num == bin_num) - { - for (i = 0; i < bin_num; i++) - { - if (strcmp (prog_dirs[i], bin_dirs[i]) != 0) - break; - } - - if (prog_num <= 0 || i == bin_num) - { - std_loc_p = 1; - free_split_directories (prog_dirs); - free_split_directories (bin_dirs); - prog_dirs = bin_dirs = (char **) 0; - return NULL; - } - } - - prefix_dirs = split_directories (prefix, &prefix_num); - - /* Find how many directories are in common between bin_prefix & prefix. */ - n = (prefix_num < bin_num) ? prefix_num : bin_num; - for (common = 0; common < n; common++) - { - if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0) - break; - } - - /* If there are no common directories, there can be no relative prefix. */ - if (common == 0) - { - free_split_directories (prog_dirs); - free_split_directories (bin_dirs); - free_split_directories (prefix_dirs); - return NULL; - } - - /* Build up the pathnames in argv[0]. */ - for (i = 0; i < prog_num; i++) - obstack_grow (&obstack, prog_dirs[i], strlen (prog_dirs[i])); - - /* Now build up the ..'s. */ - for (i = common; i < n; i++) - { - obstack_grow (&obstack, DIR_UP, sizeof (DIR_UP) - 1); - obstack_1grow (&obstack, DIR_SEPARATOR); - } - - /* Put in directories to move over to prefix. */ - for (i = common; i < prefix_num; i++) - obstack_grow (&obstack, prefix_dirs[i], strlen (prefix_dirs[i])); - - free_split_directories (prog_dirs); - free_split_directories (bin_dirs); - free_split_directories (prefix_dirs); - - obstack_1grow (&obstack, '\0'); - return obstack_finish (&obstack); -} -#endif /* VMS */ /* Check whether NAME can be accessed in MODE. This is like access, except that it never considers directories to be executable. */ Index: include/libiberty.h =================================================================== RCS file: /cvs/gcc/gcc/include/libiberty.h,v retrieving revision 1.29 diff -u -p -r1.29 libiberty.h --- include/libiberty.h 20 Sep 2002 00:21:54 -0000 1.29 +++ include/libiberty.h 19 Nov 2002 01:30:23 -0000 @@ -145,6 +145,12 @@ extern char * getpwd PARAMS ((void)); extern long get_run_time PARAMS ((void)); +/* Generate a relocated path to some installation directory. Allocates + return value using malloc. */ + +extern char *make_relative_prefix PARAMS ((const char *, const char *, + const char *)); + /* Choose a temporary directory to use for scratch files. */ extern char *choose_temp_base PARAMS ((void)) ATTRIBUTE_MALLOC; Index: libiberty/Makefile.in =================================================================== RCS file: /cvs/gcc/gcc/libiberty/Makefile.in,v retrieving revision 1.77 diff -u -p -r1.77 Makefile.in --- libiberty/Makefile.in 23 Sep 2002 03:52:51 -0000 1.77 +++ libiberty/Makefile.in 19 Nov 2002 01:30:24 -0000 @@ -135,6 +135,7 @@ CFILES = alloca.c argv.c asprintf.c atex hashtab.c hex.c \ index.c insque.c \ lbasename.c \ + make-relative-prefix.c \ make-temp-file.c md5.c memchr.c memcmp.c memcpy.c memmove.c \ memset.c mkstemps.c \ objalloc.c obstack.c \ @@ -159,6 +160,7 @@ REQUIRED_OFILES = regex.o cplus-dem.o cp getopt.o getopt1.o getpwd.o getruntime.o \ hashtab.o hex.o \ lbasename.o \ + make-relative-prefix.o \ make-temp-file.o \ objalloc.o obstack.o \ partition.o pexecute.o \ @@ -432,6 +434,7 @@ hashtab.o: config.h $(INCDIR)/ansidecl.h hex.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h lbasename.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \ $(INCDIR)/safe-ctype.h +make-relative-prefix.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h make-temp-file.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h md5.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/md5.h memchr.o: $(INCDIR)/ansidecl.h Index: libiberty/functions.texi =================================================================== RCS file: /cvs/gcc/gcc/libiberty/functions.texi,v retrieving revision 1.8 diff -u -p -r1.8 functions.texi --- libiberty/functions.texi 28 Mar 2002 04:04:20 -0000 1.8 +++ libiberty/functions.texi 19 Nov 2002 01:30:24 -0000 @@ -276,7 +276,7 @@ itself. @end deftypefn -@c getruntime.c:78 +@c getruntime.c:82 @deftypefn Replacement long get_run_time (void) Returns the time used so far, in microseconds. If possible, this is @@ -322,11 +322,12 @@ between calls to @code{getpwd}. Initializes the array mapping the current character set to corresponding hex values. This function must be called before any -call to @code{hex_p} or @code{hex_value}. +call to @code{hex_p} or @code{hex_value}. If you fail to call it, a +default ASCII-based table will normally be used on ASCII systems. @end deftypefn -@c hex.c:33 +@c hex.c:34 @deftypefn Extension int hex_p (int @var{c}) Evaluates to non-zero if the given character is a valid hex character, @@ -335,7 +336,7 @@ or zero if it is not. Note that the val @end deftypefn -@c hex.c:41 +@c hex.c:42 @deftypefn Extension int hex_value (int @var{c}) Returns the numeric equivalent of the given character when interpreted @@ -388,6 +389,22 @@ strings for particular input. In particular, the empty string returns the same empty string, and a path ending in @code{/} returns the empty string after it. + +@end deftypefn + +@c make-relative-prefix.c:24 +@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, const char *@var{bin_prefix}, const char *@var{prefix}) + +Given three strings @var{progname}, @var{bin_prefix}, @var{prefix}, return a string +that gets to @var{prefix} starting with the directory portion of @var{progname} and +a relative pathname of the difference between @var{bin_prefix} and @var{prefix}. + +For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, @var{prefix} +is @code{/alpha/beta/gamma/omega/}, and @var{progname} is @code{/red/green/blue/gcc}, +then this function will return @code{/red/green/blue/../../omega/}. + +The return value is normally allocated via @code{malloc}. If no relative prefix +can be found, return @code{NULL}. @end deftypefn Index: libiberty/make-relative-prefix.c =================================================================== RCS file: libiberty/make-relative-prefix.c diff -N libiberty/make-relative-prefix.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ libiberty/make-relative-prefix.c 19 Nov 2002 01:30:24 -0000 @@ -0,0 +1,387 @@ +/* Relative (relocatable) prefix support. + Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + +This file is part of libiberty. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* + +@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, const char *@var{bin_prefix}, const char *@var{prefix}) + +Given three strings @var{progname}, @var{bin_prefix}, @var{prefix}, return a string +that gets to @var{prefix} starting with the directory portion of @var{progname} and +a relative pathname of the difference between @var{bin_prefix} and @var{prefix}. + +For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, @var{prefix} +is @code{/alpha/beta/gamma/omega/}, and @var{progname} is @code{/red/green/blue/gcc}, +then this function will return @code{/red/green/blue/../../omega/}. + +The return value is normally allocated via @code{malloc}. If no relative prefix +can be found, return @code{NULL}. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include + +#include "ansidecl.h" +#include "libiberty.h" + +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) \ + || defined (__DJGPP__) || defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define HOST_EXECUTABLE_SUFFIX ".exe" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# define PATH_SEPARATOR ';' +#else +# define PATH_SEPARATOR ':' +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif + +#define DIR_UP ".." + +static char *save_string PARAMS ((const char *, int)); +static char **split_directories PARAMS ((const char *, int *)); +static void free_split_directories PARAMS ((char **)); + +static char * +save_string (s, len) + const char *s; + int len; +{ + char *result = malloc (len + 1); + + memcpy (result, s, len); + result[len] = 0; + return result; +} + +/* Split a filename into component directories. */ + +static char ** +split_directories (name, ptr_num_dirs) + const char *name; + int *ptr_num_dirs; +{ + int num_dirs = 0; + char **dirs; + const char *p, *q; + int ch; + + /* Count the number of directories. Special case MSDOS disk names as part + of the initial directory. */ + p = name; +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) + { + p += 3; + num_dirs++; + } +#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ + + while ((ch = *p++) != '\0') + { + if (IS_DIR_SEPARATOR (ch)) + { + num_dirs++; + while (IS_DIR_SEPARATOR (*p)) + p++; + } + } + + dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2)); + if (dirs == NULL) + return NULL; + + /* Now copy the directory parts. */ + num_dirs = 0; + p = name; +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) + { + dirs[num_dirs++] = save_string (p, 3); + if (dirs[num_dirs - 1] == NULL) + { + free (dirs); + return NULL; + } + p += 3; + } +#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ + + q = p; + while ((ch = *p++) != '\0') + { + if (IS_DIR_SEPARATOR (ch)) + { + while (IS_DIR_SEPARATOR (*p)) + p++; + + dirs[num_dirs++] = save_string (q, p - q); + if (dirs[num_dirs - 1] == NULL) + { + dirs[num_dirs] = NULL; + free_split_directories (dirs); + return NULL; + } + q = p; + } + } + + if (p - 1 - q > 0) + dirs[num_dirs++] = save_string (q, p - 1 - q); + dirs[num_dirs] = NULL; + + if (dirs[num_dirs - 1] == NULL) + { + free_split_directories (dirs); + return NULL; + } + + if (ptr_num_dirs) + *ptr_num_dirs = num_dirs; + return dirs; +} + +/* Release storage held by split directories. */ + +static void +free_split_directories (dirs) + char **dirs; +{ + int i = 0; + + while (dirs[i] != NULL) + free (dirs[i++]); + + free ((char *) dirs); +} + +/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets + to PREFIX starting with the directory portion of PROGNAME and a relative + pathname of the difference between BIN_PREFIX and PREFIX. + + For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is + /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this + function will return /red/green/blue/../../omega/. + + If no relative prefix can be found, return NULL. */ + +char * +make_relative_prefix (progname, bin_prefix, prefix) + const char *progname; + const char *bin_prefix; + const char *prefix; +{ + char **prog_dirs, **bin_dirs, **prefix_dirs; + int prog_num, bin_num, prefix_num; + int i, n, common; + int needed_len; + char *ret, *ptr; + + if (progname == NULL || bin_prefix == NULL || prefix == NULL) + return NULL; + + prog_dirs = split_directories (progname, &prog_num); + bin_dirs = split_directories (bin_prefix, &bin_num); + if (bin_dirs == NULL || prog_dirs == NULL) + return NULL; + + /* If there is no full pathname, try to find the program by checking in each + of the directories specified in the PATH environment variable. */ + if (prog_num == 1) + { + char *temp; + + temp = getenv ("PATH"); + if (temp) + { + char *startp, *endp, *nstore; + size_t prefixlen = strlen (temp) + 1; + if (prefixlen < 2) + prefixlen = 2; + + nstore = (char *) alloca (prefixlen + strlen (progname) + 1); + + startp = endp = temp; + while (1) + { + if (*endp == PATH_SEPARATOR || *endp == 0) + { + if (endp == startp) + { + nstore[0] = '.'; + nstore[1] = DIR_SEPARATOR; + nstore[2] = '\0'; + } + else + { + strncpy (nstore, startp, endp - startp); + if (! IS_DIR_SEPARATOR (endp[-1])) + { + nstore[endp - startp] = DIR_SEPARATOR; + nstore[endp - startp + 1] = 0; + } + else + nstore[endp - startp] = 0; + } + strcat (nstore, progname); + if (! access (nstore, X_OK) +#ifdef HAVE_HOST_EXECUTABLE_SUFFIX + || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK) +#endif + ) + { + free_split_directories (prog_dirs); + progname = nstore; + prog_dirs = split_directories (progname, &prog_num); + if (prog_dirs == NULL) + { + free_split_directories (bin_dirs); + return NULL; + } + break; + } + + if (*endp == 0) + break; + endp = startp = endp + 1; + } + else + endp++; + } + } + } + + /* Remove the program name from comparison of directory names. */ + prog_num--; + + /* If we are still installed in the standard location, we don't need to + specify relative directories. Also, if argv[0] still doesn't contain + any directory specifiers after the search above, then there is not much + we can do. */ + if (prog_num == bin_num) + { + for (i = 0; i < bin_num; i++) + { + if (strcmp (prog_dirs[i], bin_dirs[i]) != 0) + break; + } + + if (prog_num <= 0 || i == bin_num) + { + free_split_directories (prog_dirs); + free_split_directories (bin_dirs); + prog_dirs = bin_dirs = (char **) 0; + return NULL; + } + } + + prefix_dirs = split_directories (prefix, &prefix_num); + if (prefix_dirs == NULL) + { + free_split_directories (prog_dirs); + free_split_directories (bin_dirs); + return NULL; + } + + /* Find how many directories are in common between bin_prefix & prefix. */ + n = (prefix_num < bin_num) ? prefix_num : bin_num; + for (common = 0; common < n; common++) + { + if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0) + break; + } + + /* If there are no common directories, there can be no relative prefix. */ + if (common == 0) + { + free_split_directories (prog_dirs); + free_split_directories (bin_dirs); + free_split_directories (prefix_dirs); + return NULL; + } + + /* Two passes: first figure out the size of the result string, and + then construct it. */ + needed_len = 0; + for (i = 0; i < prog_num; i++) + needed_len += strlen (prog_dirs[i]); + needed_len += sizeof (DIR_UP) * (bin_num - common); + for (i = common; i < prefix_num; i++) + needed_len += strlen (prefix_dirs[i]); + needed_len += 1; /* Trailing NUL. */ + + ret = (char *) malloc (needed_len); + if (ret == NULL) + return NULL; + + /* Build up the pathnames in argv[0]. */ + for (i = 0; i < prog_num; i++) + strcat (ret, prog_dirs[i]); + + /* Now build up the ..'s. */ + ptr = ret + strlen(ret); + for (i = common; i < bin_num; i++) + { + strcpy (ptr, DIR_UP); + ptr += sizeof (DIR_UP) - 1; + *(ptr++) = DIR_SEPARATOR; + } + *ptr = '\0'; + + /* Put in directories to move over to prefix. */ + for (i = common; i < prefix_num; i++) + strcat (ret, prefix_dirs[i]); + + free_split_directories (prog_dirs); + free_split_directories (bin_dirs); + free_split_directories (prefix_dirs); + + return ret; +}