]> Savannah Git Hosting - gnulib.git/commitdiff
findprog-in: Allow overriding the current directory.
authorBruno Haible <bruno@clisp.org>
Mon, 14 Dec 2020 19:56:04 +0000 (20:56 +0100)
committerBruno Haible <bruno@clisp.org>
Mon, 14 Dec 2020 22:48:26 +0000 (23:48 +0100)
* lib/findprog.h (find_in_given_path): Add directory argument.
* lib/findprog-in.c (find_in_given_path): Likewise.
* lib/execute.c (execute): Update caller.
* lib/spawn-pipe.c (create_pipe): Likewise.
* lib/windows-spawn.c (spawnpvech): Likewise.
* NEWS: Mention the change.

ChangeLog
NEWS
lib/execute.c
lib/findprog-in.c
lib/findprog.h
lib/spawn-pipe.c
lib/windows-spawn.c

index f909f61222256abd2caece97b2e4146bb8382221..1a8e1a1c4958140e6b2878b42df3f8d09146f9b2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2020-12-14  Bruno Haible  <bruno@clisp.org>
+
+       findprog-in: Allow overriding the current directory.
+       * lib/findprog.h (find_in_given_path): Add directory argument.
+       * lib/findprog-in.c (find_in_given_path): Likewise.
+       * lib/execute.c (execute): Update caller.
+       * lib/spawn-pipe.c (create_pipe): Likewise.
+       * lib/windows-spawn.c (spawnpvech): Likewise.
+       * NEWS: Mention the change.
+
 2020-12-14  Bruno Haible  <bruno@clisp.org>
 
        posix_spawn-internal: Make better use of 'const'.
diff --git a/NEWS b/NEWS
index f484881ecb4814815a593cd4eec1b64d05895d3c..09d1987fb6d6b4a5713e682590bad418a05e80b4 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -60,6 +60,11 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2020-12-14  findprog-in     The function 'find_in_given_path' now takes a 3rd
+                            argument 'const char *directory'. To maintain the
+                            previous behaviour, insert NULL as additional 3rd
+                            argument.
+
 2020-12-11  sh-quote        The argv argument of the 'shell_quote_argv' function
                             is now of type 'const char * const *'.  You no
                             longer need to cast read-only strings to 'char *'
index bdc0c0c016f203dba20e7a6d6a3ddd7ed3690d7e..41a2239c8d572c31e599a94cabdd4aafeeb9121d 100644 (file)
@@ -126,7 +126,7 @@ execute (const char *progname,
       if (! IS_ABSOLUTE_FILE_NAME (prog_path))
         {
           const char *resolved_prog =
-            find_in_given_path (prog_path, getenv ("PATH"), false);
+            find_in_given_path (prog_path, getenv ("PATH"), NULL, false);
           if (resolved_prog == NULL)
             goto fail_with_errno;
           if (resolved_prog != prog_path)
index 863f67e13fdec507f780837af8ca540eb0219c39..63b8419630f788cb75141f2cf36846073b6835bf 100644 (file)
@@ -73,7 +73,7 @@ static const char * const suffixes[] =
 
 const char *
 find_in_given_path (const char *progname, const char *path,
-                    bool optimize_for_exec)
+                    const char *directory, bool optimize_for_exec)
 {
   {
     bool has_slash = false;
@@ -101,6 +101,12 @@ find_in_given_path (const char *progname, const char *path,
                with such a suffix is actually executable.  */
             int failure_errno;
             size_t i;
+
+            const char *directory_as_prefix =
+              (directory != NULL && IS_RELATIVE_FILE_NAME (progname)
+               ? directory
+               : "");
+
             #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
             const char *progbasename;
 
@@ -126,9 +132,10 @@ find_in_given_path (const char *progname, const char *path,
                 if ((*suffix != '\0') != (strchr (progbasename, '.') != NULL))
                 #endif
                   {
-                    /* Concatenate progname and suffix.  */
+                    /* Concatenate directory_as_prefix, progname, suffix.  */
                     char *progpathname =
-                      concatenated_filename ("", progname, suffix);
+                      concatenated_filename (directory_as_prefix, progname,
+                                             suffix);
 
                     if (progpathname == NULL)
                       return NULL; /* errno is set here */
@@ -194,6 +201,8 @@ find_in_given_path (const char *progname, const char *path,
       {
         const char *dir;
         bool last;
+        char *dir_as_prefix_to_free;
+        const char *dir_as_prefix;
         size_t i;
 
         /* Extract next directory in PATH.  */
@@ -207,6 +216,25 @@ find_in_given_path (const char *progname, const char *path,
         if (dir == cp)
           dir = ".";
 
+        /* Concatenate directory and dir.  */
+        if (directory != NULL && IS_RELATIVE_FILE_NAME (dir))
+          {
+            dir_as_prefix_to_free =
+              concatenated_filename (directory, dir, NULL);
+            if (dir_as_prefix_to_free == NULL)
+              {
+                /* errno is set here.  */
+                failure_errno = errno;
+                goto failed;
+              }
+            dir_as_prefix = dir_as_prefix_to_free;
+          }
+        else
+          {
+            dir_as_prefix_to_free = NULL;
+            dir_as_prefix = dir;
+          }
+
         /* Try all platform-dependent suffixes.  */
         for (i = 0; i < sizeof (suffixes) / sizeof (suffixes[0]); i++)
           {
@@ -218,14 +246,15 @@ find_in_given_path (const char *progname, const char *path,
             if ((*suffix != '\0') != (strchr (progname, '.') != NULL))
             #endif
               {
-                /* Concatenate dir, progname, and suffix.  */
+                /* Concatenate dir_as_prefix, progname, and suffix.  */
                 char *progpathname =
-                  concatenated_filename (dir, progname, suffix);
+                  concatenated_filename (dir_as_prefix, progname, suffix);
 
                 if (progpathname == NULL)
                   {
                     /* errno is set here.  */
                     failure_errno = errno;
+                    free (dir_as_prefix_to_free);
                     goto failed;
                   }
 
@@ -249,7 +278,7 @@ find_in_given_path (const char *progname, const char *path,
                                 free (progpathname);
 
                                 /* Add the "./" prefix for real, that
-                                   xconcatenated_filename() optimized away.
+                                   concatenated_filename() optimized away.
                                    This avoids a second PATH search when the
                                    caller uses execl/execv/execlp/execvp.  */
                                 progpathname =
@@ -258,6 +287,7 @@ find_in_given_path (const char *progname, const char *path,
                                   {
                                     /* errno is set here.  */
                                     failure_errno = errno;
+                                    free (dir_as_prefix_to_free);
                                     goto failed;
                                   }
                                 progpathname[0] = '.';
@@ -266,6 +296,7 @@ find_in_given_path (const char *progname, const char *path,
                                         strlen (progname) + 1);
                               }
 
+                            free (dir_as_prefix_to_free);
                             free (path_copy);
                             return progpathname;
                           }
@@ -281,6 +312,8 @@ find_in_given_path (const char *progname, const char *path,
               }
           }
 
+        free (dir_as_prefix_to_free);
+
         if (last)
           break;
       }
index c020290d87497759d3b8775a5452add9d36a9eaa..6e21aa2a837b42e7c86d3a221a6a4c5941b6fba4 100644 (file)
@@ -42,6 +42,10 @@ extern const char *find_in_path (const char *progname);
    directory.  A null PATH is equivalent to an empty PATH, that is, to the
    singleton list that contains only the current directory.
 
+   If DIRECTORY is not NULL, all relative filenames (i.e. PROGNAME when it
+   contains a slash, and the PATH elements) are considered relative to
+   DIRECTORY instead of relative to the current directory of this process.
+
    Determines the pathname that would be called by execlp/execvp of PROGNAME.
    - If successful, it returns a pathname containing a slash (either absolute
      or relative to the current directory).  The returned string can be used
@@ -62,6 +66,7 @@ extern const char *find_in_path (const char *progname);
      - On POSIX systems excluding Cygwin: a '/',
      - On Windows, OS/2, DOS platforms: a '/' or '\'. */
 extern const char *find_in_given_path (const char *progname, const char *path,
+                                       const char *directory,
                                        bool optimize_for_exec);
 
 
index bd34959d506b52df7b0055ec33efa145d1223350..d48352097b5ed944db3547d953319a3f36799a72 100644 (file)
@@ -154,7 +154,7 @@ create_pipe (const char *progname,
       if (! IS_ABSOLUTE_FILE_NAME (prog_path))
         {
           const char *resolved_prog =
-            find_in_given_path (prog_path, getenv ("PATH"), false);
+            find_in_given_path (prog_path, getenv ("PATH"), NULL, false);
           if (resolved_prog == NULL)
             goto fail_with_errno;
           if (resolved_prog != prog_path)
index 509727c74e9c829f13823558259dca925e85b323..19251aea970e36959758342412f1ebe51ca400b4 100644 (file)
@@ -223,7 +223,7 @@ spawnpvech (int mode,
 
   /* Implement the 'p' letter: search for PROGNAME in getenv ("PATH").  */
   const char *resolved_progname =
-    find_in_given_path (progname, getenv ("PATH"), false);
+    find_in_given_path (progname, getenv ("PATH"), NULL, false);
   if (resolved_progname == NULL)
     return -1;