This is an automated email from Gerrit.

Andreas Fritiofson ([email protected]) just uploaded a new patch set 
to Gerrit, which you can find at http://openocd.zylin.com/3889

-- gerrit

commit b07211df5cfe2a404061d4626400457aac124d07
Author: Andreas Fritiofson <[email protected]>
Date:   Sat Nov 19 21:43:22 2016 +0100

    Search for scripts relative to the executable on all(?) platforms
    
    Add a helper to hide the platform-dependent method to get a
    canonical, absolute, /-separated path to the executable.
    
    Use this and the relative path from BINDIR to PKGDATADIR to
    construct a search path that finds the scripts even if the
    installation dir is moved, as long as the structure below $prefix
    is maintained.
    
    This method should fully support all the tricks you can to with
    autotools to customize the installed layout such as overriding the
    default directories at configure-time and overriding the configured
    directories at build-time.
    
    The exe path detection methods are combined from
    http://openocd.zylin.com/3388 by Rick Foos and
    http://openocd.zylin.com/3537 by Steven Stallion, as well as tips
    found all over internet.
    
    Change-Id: Ifc9cc9dd0bf52fbd67b1b0f2383318cda0c422c4
    Signed-off-by: Andreas Fritiofson <[email protected]>

diff --git a/configure.ac b/configure.ac
index a47a184..065be99 100644
--- a/configure.ac
+++ b/configure.ac
@@ -142,6 +142,7 @@ AC_CHECK_FUNCS([strnlen])
 AC_CHECK_FUNCS([gettimeofday])
 AC_CHECK_FUNCS([usleep])
 AC_CHECK_FUNCS([vasprintf])
+AC_CHECK_FUNCS([realpath])
 
 build_bitbang=no
 build_bitq=no
diff --git a/src/helper/options.c b/src/helper/options.c
index b7db10f..0f1e93f 100644
--- a/src/helper/options.c
+++ b/src/helper/options.c
@@ -50,52 +50,170 @@ int configuration_output_handler(struct command_context 
*context, const char *li
        return ERROR_OK;
 }
 
-#ifdef _WIN32
-static char *find_suffix(const char *text, const char *suffix)
+/* Return the canonical path to the directory the openocd executable is in.
+ * The path should be absolute, use / as path separator and have all symlinks
+ * resolved. The returned string is malloc'd. */
+static char *find_exe_path(void)
 {
-       size_t text_len = strlen(text);
-       size_t suffix_len = strlen(suffix);
+       char *exepath = NULL;
 
-       if (suffix_len == 0)
-               return (char *)text + text_len;
+       do {
+#if IS_WIN32
+               exepath = malloc(MAX_PATH);
+               if (exepath == NULL)
+                       break;
+               GetModuleFileName(NULL, exepath, MAX_PATH);
 
-       if (suffix_len > text_len || strncmp(text + text_len - suffix_len, 
suffix, suffix_len) != 0)
-               return NULL; /* Not a suffix of text */
+               /* Convert path separators to UNIX style, should work on 
Windows also. */
+               for (char *p = exepath; *p; p++) {
+                       if (*p == '\\')
+                               *p = '/';
+               }
 
-       return (char *)text + text_len - suffix_len;
-}
+#elif IS_DARWIN
+               exepath = malloc(PROC_PIDPATHINFO_MAXSIZE);
+               if (exepath == NULL)
+                       break;
+               if (proc_pidpath(getpid(), exepath, PROC_PIDPATHINFO_MAXSIZE) 
<= 0) {
+                       free(exepath);
+                       exepath = NULL;
+               }
+
+#elif defined(CTL_KERN) && defined(KERN_PROC) && defined(KERN_PROC_PATHNAME) 
/* *BSD */
+               path = malloc(PATH_MAX);
+               if (path == NULL)
+                       break;
+               int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+               size_t size = PATH_MAX;
+
+               if (sysctl(mib, (u_int)ARRAY_SIZE(mib), path, &size, NULL, 0) 
!= 0)
+                       break;
+
+#ifdef HAVE_REALPATH
+               exepath = realpath(path, NULL);
+               free(path);
+#else
+               exepath = path;
 #endif
 
-static void add_default_dirs(void)
-{
-       const char *run_prefix;
-       char *path;
+#elif defined(HAVE_REALPATH) /* Assume POSIX.1-2008 */
+               /* Try Unices in order of likelihood. */
+               exepath = realpath("/proc/self/exe", NULL); /* Linux */
+               if (exepath == NULL)
+                       exepath = realpath("/proc/self/path/a.out", NULL); /* 
Solaris */
+               if (exepath == NULL)
+                       exepath = realpath("/proc/curproc/file", NULL); /* 
FreeBSD (Should be covered above) */
+#endif
+       } while (0);
+
+       if (exepath != NULL) {
+               /* Strip executable file name, leaving path */
+               *strrchr(exepath, '/') = '\0';
+       } else {
+               LOG_WARNING("Could not determine executable path, using 
configured BINDIR.");
+               LOG_DEBUG("BINDIR = %s", BINDIR);
+#ifdef HAVE_REALPATH
+               exepath = realpath(BINDIR, NULL);
+#else
+               exepath = strdup(BINDIR);
+#endif
+       }
 
-#ifdef _WIN32
-       char strExePath[MAX_PATH];
-       GetModuleFileName(NULL, strExePath, MAX_PATH);
+       return exepath;
+}
 
-       /* Strip executable file name, leaving path */
-       *strrchr(strExePath, '\\') = '\0';
+static char *find_relative_path(const char *from, const char *to)
+{
+       size_t i;
 
-       /* Convert path separators to UNIX style, should work on Windows also. 
*/
-       for (char *p = strExePath; *p; p++) {
-               if (*p == '\\')
-                       *p = '/';
+       /* Skip common /-separated parts of from and to */
+       i = 0;
+       for (size_t n = 0; from[n] == to[n]; n++) {
+               if (from[n] == '\0') {
+                       i = n;
+                       break;
+               }
+               if (from[n] == '/')
+                       i = n + 1;
+       }
+       from += i;
+       to += i;
+
+       /* Count number of /-separated non-empty parts of from */
+       i = 0;
+       while (from[0] != '\0') {
+               if (from[0] != '/')
+                       i++;
+               char *next = strchr(from, '/');
+               if (next == NULL)
+                       break;
+               from = next + 1;
        }
 
-       char *end_of_prefix = find_suffix(strExePath, BINDIR);
-       if (end_of_prefix != NULL)
-               *end_of_prefix = '\0';
+       /* Prepend that number of ../ in front of to */
+       char *relpath = malloc(i * 3 + strlen(to) + 1);
+       relpath[0] = '\0';
+       for (size_t n = 0; n < i; n++)
+               strcat(relpath, "../");
+       strcat(relpath, to);
 
-       run_prefix = strExePath;
-#else
-       run_prefix = "";
-#endif
+       return relpath;
+}
+
+static void test_one_find_relative_path(const char *from, const char *to, 
const char *expected)
+{
+       char *result = find_relative_path(from, to);
+       LOG_DEBUG("Testing '%s'->'%s', expected '%s', got '%s'", from, to, 
expected, result);
+       assert(result != NULL);
+       assert(strcmp(result, expected) == 0);
+       free(result);
+}
+
+static void test_find_relative_path(void)
+{
+       test_one_find_relative_path(
+                       "/usr/local/bin",
+                       "/usr/local/share/openocd",
+                       "../share/openocd");
+       test_one_find_relative_path(
+                       "/usr/local/bin/",
+                       "/usr/local/share/openocd/",
+                       "../share/openocd/");
+       test_one_find_relative_path(
+                       "/usr/local/bin",
+                       "/usr/local2/bin",
+                       "../../local2/bin");
+       test_one_find_relative_path(
+                       "bin",
+                       "share/openocd",
+                       "../share/openocd");
+       test_one_find_relative_path(
+                       "C:/Build/OpenOCD/bin",
+                       "C:/Build/OpenOCD/share/openocd",
+                       "../share/openocd");
+       test_one_find_relative_path(
+                       "C:/Program/OpenOCD",
+                       "C:/Program/OpenOCD",
+                       "");
+       test_one_find_relative_path(
+                       "",
+                       "",
+                       "");
+}
+
+static void add_default_dirs(void)
+{
+       char *path;
+
+       test_find_relative_path();
+
+       char *exepath = find_exe_path();
+       char *bin2data = find_relative_path(BINDIR, PKGDATADIR);
 
        LOG_DEBUG("bindir=%s", BINDIR);
        LOG_DEBUG("pkgdatadir=%s", PKGDATADIR);
-       LOG_DEBUG("run_prefix=%s", run_prefix);
+       LOG_DEBUG("exepath=%s", exepath);
+       LOG_DEBUG("bin2data=%s", bin2data);
 
        /*
         * The directory containing OpenOCD-supplied scripts should be
@@ -129,17 +247,20 @@ static void add_default_dirs(void)
        }
 #endif
 
-       path = alloc_printf("%s%s%s", run_prefix, PKGDATADIR, "/site");
+       path = alloc_printf("%s/%s/%s", exepath, bin2data, "site");
        if (path) {
                add_script_search_dir(path);
                free(path);
        }
 
-       path = alloc_printf("%s%s%s", run_prefix, PKGDATADIR, "/scripts");
+       path = alloc_printf("%s/%s/%s", exepath, bin2data, "scripts");
        if (path) {
                add_script_search_dir(path);
                free(path);
        }
+
+       free(exepath);
+       free(bin2data);
 }
 
 int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])

-- 

------------------------------------------------------------------------------
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to