mingw: simplify PATH handling
On Windows the environment variable PATH contains a semicolon-separated list of directories to search for, in order, when looking for the location of a binary to run. get_path_split() parses it and returns an array of string copies, which is iterated by path_lookup(), which in turn passes each entry to lookup_prog(). Change lookup_prog() to take the directory name as a length-limited string instead of as a NUL-terminated one and parse PATH directly in path_lookup(). This avoids memory allocations, simplifying the code. Helped-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Rene Scharfe <l.s.r@web.de> Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
René Scharfe committed
May 20, 2017 at 21:35 UTC
e0ca1ca20a0bde51c4eb9242dd9521ac1ed08304
1 file changed
+23
-68
compat/mingw.c
+23
-68
@@ -940,65 +940,15 @@ static const char *parse_interpreter(const char *cmd)
940
return p+1;
941
}
942
943
-/*
944
- * Splits the PATH into parts.
945
- */
946
-static char **get_path_split(void)
947
-{
948
- char *p, **path, *envpath = mingw_getenv("PATH");
949
- int i, n = 0;
950
-
951
- if (!envpath || !*envpath)
952
- return NULL;
953
-
954
- envpath = xstrdup(envpath);
955
- p = envpath;
956
- while (p) {
957
- char *dir = p;
958
- p = strchr(p, ';');
959
- if (p) *p++ = '\0';
960
- if (*dir) { /* not earlier, catches series of ; */
961
- ++n;
962
- }
963
- }
964
- if (!n)
965
- return NULL;
966
-
967
- ALLOC_ARRAY(path, n + 1);
968
- p = envpath;
969
- i = 0;
970
- do {
971
- if (*p)
972
- path[i++] = xstrdup(p);
973
- p = p+strlen(p)+1;
974
- } while (i < n);
975
- path[i] = NULL;
976
-
977
- free(envpath);
978
-
979
- return path;
980
-}
981
-
982
-static void free_path_split(char **path)
983
-{
984
- char **p = path;
985
-
986
- if (!path)
987
- return;
988
-
989
- while (*p)
990
- free(*p++);
991
- free(path);
992
-}
993
-
943
/*
944
* exe_only means that we only want to detect .exe files, but not scripts
945
* (which do not have an extension)
946
*/
998
-static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
947
+static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
948
+ int isexe, int exe_only)
949
{
950
char path[MAX_PATH];
1001
- snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
951
+ snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
952
953
if (!isexe && access(path, F_OK) == 0)
954
return xstrdup(path);
@@ -1013,17 +963,29 @@ static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_on
963
* Determines the absolute path of cmd using the split path in path.
964
* If cmd contains a slash or backslash, no lookup is performed.
965
*/
1016
-static char *path_lookup(const char *cmd, char **path, int exe_only)
966
+static char *path_lookup(const char *cmd, int exe_only)
967
{
968
+ const char *path;
969
char *prog = NULL;
970
int len = strlen(cmd);
971
int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
972
973
if (strchr(cmd, '/') || strchr(cmd, '\\'))
1023
- prog = xstrdup(cmd);
974
+ return xstrdup(cmd);
975
+
976
+ path = mingw_getenv("PATH");
977
+ if (!path)
978
+ return NULL;
979
1025
- while (!prog && *path)
1026
- prog = lookup_prog(*path++, cmd, isexe, exe_only);
980
+ while (!prog) {
981
+ const char *sep = strchrnul(path, ';');
982
+ int dirlen = sep - path;
983
+ if (dirlen)
984
+ prog = lookup_prog(path, dirlen, cmd, isexe, exe_only);
985
+ if (!*sep)
986
+ break;
987
+ path = sep + 1;
988
+ }
989
990
return prog;
991
}
@@ -1190,8 +1152,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
1152
int fhin, int fhout, int fherr)
1153
{
1154
pid_t pid;
1193
- char **path = get_path_split();
1194
- char *prog = path_lookup(cmd, path, 0);
1155
+ char *prog = path_lookup(cmd, 0);
1156
1157
if (!prog) {
1158
errno = ENOENT;
@@ -1202,7 +1163,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
1163
1164
if (interpr) {
1165
const char *argv0 = argv[0];
1205
- char *iprog = path_lookup(interpr, path, 1);
1166
+ char *iprog = path_lookup(interpr, 1);
1167
argv[0] = prog;
1168
if (!iprog) {
1169
errno = ENOENT;
@@ -1220,21 +1181,18 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
1181
fhin, fhout, fherr);
1182
free(prog);
1183
}
1223
- free_path_split(path);
1184
return pid;
1185
}
1186
1187
static int try_shell_exec(const char *cmd, char *const *argv)
1188
{
1189
const char *interpr = parse_interpreter(cmd);
1230
- char **path;
1190
char *prog;
1191
int pid = 0;
1192
1193
if (!interpr)
1194
return 0;
1236
- path = get_path_split();
1237
- prog = path_lookup(interpr, path, 1);
1195
+ prog = path_lookup(interpr, 1);
1196
if (prog) {
1197
int argc = 0;
1198
const char **argv2;
@@ -1253,7 +1211,6 @@ static int try_shell_exec(const char *cmd, char *const *argv)
1211
free(prog);
1212
free(argv2);
1213
}
1256
- free_path_split(path);
1214
return pid;
1215
}
1216
@@ -1275,8 +1232,7 @@ int mingw_execv(const char *cmd, char *const *argv)
1232
1233
int mingw_execvp(const char *cmd, char *const *argv)
1234
{
1278
- char **path = get_path_split();
1279
- char *prog = path_lookup(cmd, path, 0);
1235
+ char *prog = path_lookup(cmd, 0);
1236
1237
if (prog) {
1238
mingw_execv(prog, argv);
@@ -1284,7 +1240,6 @@ int mingw_execvp(const char *cmd, char *const *argv)
1240
} else
1241
errno = ENOENT;
1242
1287
- free_path_split(path);
1243
return -1;
1244
}
1245