diff lib/progreloc.c @ 7023:d78abd0c0b70

Update from GNU gettext 0.15.
author Bruno Haible <bruno@clisp.org>
date Sat, 22 Jul 2006 16:17:20 +0000
parents 96c32553b4c6
children 1c4ed7637c24
line wrap: on
line diff
--- a/lib/progreloc.c	Sat Jul 22 16:03:47 2006 +0000
+++ b/lib/progreloc.c	Sat Jul 22 16:17:20 2006 +0000
@@ -1,5 +1,5 @@
 /* Provide relocatable programs.
-   Copyright (C) 2003-2004 Free Software Foundation, Inc.
+   Copyright (C) 2003-2006 Free Software Foundation, Inc.
    Written by Bruno Haible <bruno@clisp.org>, 2003.
 
    This program is free software; you can redistribute it and/or modify
@@ -34,12 +34,16 @@
 #endif
 #include <sys/stat.h>
 
-#if defined _WIN32 || defined __WIN32__
-# undef WIN32   /* avoid warning on mingw32 */
-# define WIN32
+/* Get declaration of _NSGetExecutablePath on MacOS X 10.2 or newer.  */
+#if HAVE_MACH_O_DYLD_H
+# include <mach-o/dyld.h>
 #endif
 
-#ifdef WIN32
+#if defined _WIN32 || defined __WIN32__
+# define WIN32_NATIVE
+#endif
+
+#if defined WIN32_NATIVE || defined __CYGWIN__
 # define WIN32_LEAN_AND_MEAN
 # include <windows.h>
 #endif
@@ -90,7 +94,8 @@
 static bool
 maybe_executable (const char *filename)
 {
-#if !defined WIN32
+  /* Woe32 lacks the access() function, but Cygwin doesn't.  */
+#if !(defined WIN32_NATIVE && !defined __CYGWIN__)
   if (access (filename, X_OK) < 0)
     return false;
 
@@ -125,16 +130,39 @@
 static char *
 find_executable (const char *argv0)
 {
-#ifdef WIN32
-  char buf[1024];
-  int length = GetModuleFileName (NULL, buf, sizeof (buf));
+#if defined WIN32_NATIVE || defined __CYGWIN__
+  char location[MAX_PATH];
+  int length = GetModuleFileName (NULL, location, sizeof (location));
   if (length < 0)
     return NULL;
-  if (!IS_PATH_WITH_DIR (buf))
+  if (!IS_PATH_WITH_DIR (location))
     /* Shouldn't happen.  */
     return NULL;
-  return xstrdup (buf);
-#else /* Unix */
+  {
+#if defined __CYGWIN__
+    /* cygwin-1.5.13 (2005-03-01) or newer would also allow a Linux-like
+       implementation: readlink of "/proc/self/exe".  But using the
+       result of the Win32 system call is simpler and is consistent with the
+       code in relocatable.c.  */
+    /* On Cygwin, we need to convert paths coming from Win32 system calls
+       to the Unix-like slashified notation.  */
+    static char location_as_posix_path[2 * MAX_PATH];
+    /* There's no error return defined for cygwin_conv_to_posix_path.
+       See cygwin-api/func-cygwin-conv-to-posix-path.html.
+       Does it overflow the buffer of expected size MAX_PATH or does it
+       truncate the path?  I don't know.  Let's catch both.  */
+    cygwin_conv_to_posix_path (location, location_as_posix_path);
+    location_as_posix_path[MAX_PATH - 1] = '\0';
+    if (strlen (location_as_posix_path) >= MAX_PATH - 1)
+      /* A sign of buffer overflow or path truncation.  */
+      return NULL;
+    /* Call canonicalize_file_name, because Cygwin supports symbolic links.  */
+    return canonicalize_file_name (location_as_posix_path);
+#else
+    return xstrdup (location);
+#endif
+  }
+#else /* Unix && !Cygwin */
 #ifdef __linux__
   /* The executable is accessible as /proc/<pid>/exe.  In newer Linux
      versions, also as /proc/self/exe.  Linux >= 2.1 provides a symlink
@@ -160,6 +188,16 @@
     }
   }
 #endif
+#if HAVE_MACH_O_DYLD_H && HAVE__NSGETEXECUTABLEPATH
+  /* On MacOS X 10.2 or newer, the function
+       int _NSGetExecutablePath (char *buf, unsigned long *bufsize);
+     can be used to retrieve the executable's full path.  */
+  char location[4096];
+  unsigned long length = sizeof (location);
+  if (_NSGetExecutablePath (location, &length) == 0
+      && location[0] == '/')
+    return canonicalize_file_name (location);
+#endif
   /* Guess the executable's full path.  We assume the executable has been
      called via execlp() or execvp() with properly set up argv[0].  The
      login(1) convention to add a '-' prefix to argv[0] is not supported.  */
@@ -259,21 +297,50 @@
 {
   const char *argv0_stripped = argv0;
 
-  /* Relocatable programs are renamed to .bin by install-reloc.  Remove
-     this suffix here.  */
+  /* Relocatable programs are renamed to .bin by install-reloc.  Or, more
+     generally, their suffix is changed from $exeext to .bin$exeext.
+     Remove the ".bin" here.  */
   {
     size_t argv0_len = strlen (argv0);
-    if (argv0_len > 4 && memcmp (argv0 + argv0_len - 4, ".bin", 4) == 0)
-      {
-	char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
+    const size_t exeext_len = sizeof (EXEEXT) - sizeof ("");
+    if (argv0_len > 4 + exeext_len)
+      if (memcmp (argv0 + argv0_len - exeext_len - 4, ".bin", 4) == 0)
+	{
+	  if (sizeof (EXEEXT) > sizeof (""))
+	    {
+	      /* Compare using an inlined copy of c_strncasecmp(), because
+		 the filenames may have undergone a case conversion since
+		 they were packaged.  In other words, EXEEXT may be ".exe"
+		 on one system and ".EXE" on another.  */
+	      static const char exeext[] = EXEEXT;
+	      const char *s1 = argv0 + argv0_len - exeext_len;
+	      const char *s2 = exeext;
+	      for (; *s1 != '\0'; s1++, s2++)
+		{
+		  unsigned char c1 = *s1;
+		  unsigned char c2 = *s2;
+		  if ((c1 >= 'A' && c1 <= 'Z' ? c1 - 'A' + 'a' : c1)
+		      != (c2 >= 'A' && c2 <= 'Z' ? c2 - 'A' + 'a' : c2))
+		    goto done_stripping;
+		}
+	    }
+	  /* Remove ".bin" before EXEEXT or its equivalent.  */
+	  {
+	    char *shorter = (char *) xmalloc (argv0_len - 4 + 1);
 #ifdef NO_XMALLOC
-	if (shorter != NULL)
+	    if (shorter != NULL)
 #endif
-	  {
-	    memcpy (shorter, argv0, argv0_len - 4);
-	    shorter[argv0_len - 4] = '\0';
-	    argv0_stripped = shorter;
+	      {
+		memcpy (shorter, argv0, argv0_len - exeext_len - 4);
+		if (sizeof (EXEEXT) > sizeof (""))
+		  memcpy (shorter + argv0_len - exeext_len - 4,
+			  argv0 + argv0_len - exeext_len - 4,
+			  exeext_len);
+		shorter[argv0_len - 4] = '\0';
+		argv0_stripped = shorter;
+	      }
 	  }
+	 done_stripping: ;
       }
   }