[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] findprog: Support searching in a specified path string
From: |
Bruno Haible |
Subject: |
Re: [PATCH] findprog: Support searching in a specified path string |
Date: |
Sun, 08 Sep 2019 18:25:40 +0200 |
User-agent: |
KMail/5.1.3 (Linux/4.4.0-159-generic; KDE/5.18.0; x86_64; ; ) |
Hi Paul,
Here's the implementation I'm committing.
I feel that merging the two functions in a single file would add more
contortions than benefit.
2019-09-08 Bruno Haible <address@hidden>
findprog-in: New module.
Suggested by Paul Smith <address@hidden>.
* lib/findprog.h (find_in_given_path): New declaration.
* lib/findprog-in.c: New file, based on lib/findprog.c.
* m4/findprog-in.m4: New file, based on m4/findprog.m4.
* modules/findprog-in: New file.
diff --git a/lib/findprog.h b/lib/findprog.h
index a354f67..9bc8a60 100644
--- a/lib/findprog.h
+++ b/lib/findprog.h
@@ -21,16 +21,29 @@ extern "C" {
#endif
-/* Look up a program in the PATH.
- Attempt to determine the pathname that would be called by execlp/execvp
- of PROGNAME. If successful, return a pathname containing a slash
- (either absolute or relative to the current directory). Otherwise,
- return PROGNAME unmodified.
+/* Looks up a program in the PATH.
+ Attempts to determine 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). Otherwise, it
+ returns PROGNAME unmodified.
Because of the latter case, callers should use execlp/execvp, not
execl/execv on the returned pathname.
The returned string is freshly malloc()ed if it is != PROGNAME. */
extern const char *find_in_path (const char *progname);
+/* Looks up a program in the given PATH-like string.
+ The PATH argument consists of a list of directories, separated by ':' or
+ (on native Windows) by ';'. An empty PATH element designates the current
+ directory. A null PATH is equivalent to an empty PATH, that is, to the
+ singleton list that contains only the current directory.
+ 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
+ with either execl/execv or execlp/execvp. It is freshly malloc()ed if it
+ is != PROGNAME.
+ - Otherwise, it returns NULL. */
+extern const char *find_in_given_path (const char *progname, const char *path);
+
#ifdef __cplusplus
}
diff --git a/lib/findprog-in.c b/lib/findprog-in.c
new file mode 100644
index 0000000..3d70b7b
--- /dev/null
+++ b/lib/findprog-in.c
@@ -0,0 +1,178 @@
+/* Locating a program in a given path.
+ Copyright (C) 2001-2004, 2006-2019 Free Software Foundation, Inc.
+ Written by Bruno Haible <address@hidden>, 2001, 2019.
+
+ This program 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 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see <https://www.gnu.org/licenses/>. */
+
+
+#include <config.h>
+
+/* Specification. */
+#include "findprog.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "filename.h"
+#include "concat-filename.h"
+#include "xalloc.h"
+
+#if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined
__DJGPP__
+ /* Native Windows, OS/2, DOS */
+# define NATIVE_SLASH '\\'
+#else
+ /* Unix */
+# define NATIVE_SLASH '/'
+#endif
+
+/* Separator in PATH like lists of pathnames. */
+#if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined
__DJGPP__
+ /* Native Windows, OS/2, DOS */
+# define PATH_SEPARATOR ';'
+#else
+ /* Unix */
+# define PATH_SEPARATOR ':'
+#endif
+
+/* The list of suffixes that the execlp/execvp function tries when searching
+ for the program. */
+static const char * const suffixes[] =
+ {
+ #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
+ "", ".com", ".exe", ".bat", ".cmd"
+ /* Note: Files without any suffix are not considered executable. */
+ /* Note: The cmd.exe program does a different lookup: It searches according
+ to the PATHEXT environment variable.
+ See <https://stackoverflow.com/questions/7839150/>.
+ Also, it executes files ending .bat and .cmd directly without letting
the
+ kernel interpret the program file. */
+ #elif defined __CYGWIN__
+ "", ".exe", ".com"
+ #elif defined __EMX__
+ "", ".exe"
+ #elif defined __DJGPP__
+ "", ".com", ".exe", ".bat"
+ #else /* Unix */
+ ""
+ #endif
+ };
+
+const char *
+find_in_given_path (const char *progname, const char *path)
+{
+ {
+ bool has_slash = false;
+ const char *p;
+
+ for (p = progname; *p != '\0'; p++)
+ if (ISSLASH (*p))
+ {
+ has_slash = true;
+ break;
+ }
+ if (has_slash)
+ /* If progname contains a slash, it is either absolute or relative to
+ the current directory. PATH is not used.
+ We could try the various suffixes and see whether one of the files
+ with such a suffix is actually executable. But this is not needed,
+ since the execl/execv/execlp/execvp functions will do these tests
+ anyway. */
+ return progname;
+ }
+
+ if (path == NULL)
+ /* If PATH is not set, the default search path is implementation dependent.
+ In practice, it is treated like an empty PATH. */
+ path = "";
+
+ {
+ /* Make a copy, to prepare for destructive modifications. */
+ char *path_copy = xstrdup (path);
+ char *path_rest;
+ char *cp;
+
+ for (path_rest = path_copy; ; path_rest = cp + 1)
+ {
+ const char *dir;
+ bool last;
+ size_t i;
+
+ /* Extract next directory in PATH. */
+ dir = path_rest;
+ for (cp = path_rest; *cp != '\0' && *cp != PATH_SEPARATOR; cp++)
+ ;
+ last = (*cp == '\0');
+ *cp = '\0';
+
+ /* Empty PATH components designate the current directory. */
+ if (dir == cp)
+ dir = ".";
+
+ /* Try all platform-dependent suffixes. */
+ for (i = 0; i < sizeof (suffixes) / sizeof (suffixes[0]); i++)
+ {
+ const char *suffix = suffixes[i];
+
+ #if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
+ /* File names without a '.' are not considered executable. */
+ if (*suffix != '\0' || strchr (progname, '.') != NULL)
+ #endif
+ {
+ /* Concatenate dir and progname. */
+ char *progpathname =
+ xconcatenated_filename (dir, progname, suffix);
+
+ /* On systems which have the eaccess() system call, let's use
+ it. On other systems, let's hope that this program is not
+ installed setuid or setgid, so that it is ok to call
+ access() despite its design flaw. */
+ if (eaccess (progpathname, X_OK) == 0)
+ {
+ /* Found! */
+ if (strcmp (progpathname, progname) == 0)
+ {
+ free (progpathname);
+
+ /* Add the "./" prefix for real, that
+ xconcatenated_filename() optimized away. This
+ avoids a second PATH search when the caller uses
+ execl/execv/execlp/execvp. */
+ progpathname =
+ XNMALLOC (2 + strlen (progname) + 1, char);
+ progpathname[0] = '.';
+ progpathname[1] = NATIVE_SLASH;
+ memcpy (progpathname + 2, progname,
+ strlen (progname) + 1);
+ }
+
+ free (path_copy);
+ return progpathname;
+ }
+
+ free (progpathname);
+ }
+ }
+
+ if (last)
+ break;
+ }
+
+ /* Not found in PATH. */
+ free (path_copy);
+ }
+
+ return NULL;
+}
diff --git a/m4/findprog-in.m4 b/m4/findprog-in.m4
new file mode 100644
index 0000000..baa7e6b
--- /dev/null
+++ b/m4/findprog-in.m4
@@ -0,0 +1,11 @@
+# findprog-in.m4 serial 1
+dnl Copyright (C) 2003, 2009-2019 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FINDPROG_IN],
+[
+ dnl Prerequisites of lib/findprog-in.c.
+ AC_REQUIRE([gl_FUNC_EACCESS])
+])
diff --git a/modules/findprog-in b/modules/findprog-in
new file mode 100644
index 0000000..ce7faa5
--- /dev/null
+++ b/modules/findprog-in
@@ -0,0 +1,30 @@
+Description:
+Locating a program in a given path.
+
+Files:
+lib/findprog.h
+lib/findprog-in.c
+m4/findprog-in.m4
+m4/eaccess.m4
+
+Depends-on:
+stdbool
+filename
+xalloc
+xconcat-filename
+unistd
+
+configure.ac:
+gl_FINDPROG_IN
+
+Makefile.am:
+lib_SOURCES += findprog.h findprog-in.c
+
+Include:
+"findprog.h"
+
+License:
+GPL
+
+Maintainer:
+all
- [PATCH] findprog: Support searching in a specified path string, Paul Smith, 2019/09/06
- Re: [PATCH] findprog: Support searching in a specified path string, Paul Smith, 2019/09/06
- Re: [PATCH] findprog: Support searching in a specified path string, Bruno Haible, 2019/09/07
- Re: [PATCH] findprog: Support searching in a specified path string, Paul Smith, 2019/09/07
- Re: [PATCH] findprog: Support searching in a specified path string, Bruno Haible, 2019/09/08
- Re: [PATCH] findprog: Support searching in a specified path string, Paul Smith, 2019/09/08
- Re: [PATCH] findprog: Support searching in a specified path string, Bruno Haible, 2019/09/08
- Re: [PATCH] findprog: Support searching in a specified path string,
Bruno Haible <=
- Re: [PATCH] findprog: Support searching in a specified path string, Paul Smith, 2019/09/08
- Re: [PATCH] findprog: Support searching in a specified path string, Bruno Haible, 2019/09/08
- Re: [PATCH] findprog: Support searching in a specified path string, Paul Smith, 2019/09/08
- Re: [PATCH] findprog: Support searching in a specified path string, Bruno Haible, 2019/09/09
- Re: [PATCH] findprog: Support searching in a specified path string, Paul Smith, 2019/09/10
- Re: [PATCH] findprog: Support searching in a specified path string, Bruno Haible, 2019/09/14