Skip to content

Commit e0ca1ca

Browse files
rscharfegitster
authored andcommitted
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 <[email protected]> Signed-off-by: Rene Scharfe <[email protected]> Acked-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 10c78a1 commit e0ca1ca

File tree

1 file changed

+23
-68
lines changed

1 file changed

+23
-68
lines changed

compat/mingw.c

Lines changed: 23 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -940,65 +940,15 @@ static const char *parse_interpreter(const char *cmd)
940940
return p+1;
941941
}
942942

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-
994943
/*
995944
* exe_only means that we only want to detect .exe files, but not scripts
996945
* (which do not have an extension)
997946
*/
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)
999949
{
1000950
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);
1002952

1003953
if (!isexe && access(path, F_OK) == 0)
1004954
return xstrdup(path);
@@ -1013,17 +963,29 @@ static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_on
1013963
* Determines the absolute path of cmd using the split path in path.
1014964
* If cmd contains a slash or backslash, no lookup is performed.
1015965
*/
1016-
static char *path_lookup(const char *cmd, char **path, int exe_only)
966+
static char *path_lookup(const char *cmd, int exe_only)
1017967
{
968+
const char *path;
1018969
char *prog = NULL;
1019970
int len = strlen(cmd);
1020971
int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
1021972

1022973
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;
1024979

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+
}
1027989

1028990
return prog;
1029991
}
@@ -1190,8 +1152,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
11901152
int fhin, int fhout, int fherr)
11911153
{
11921154
pid_t pid;
1193-
char **path = get_path_split();
1194-
char *prog = path_lookup(cmd, path, 0);
1155+
char *prog = path_lookup(cmd, 0);
11951156

11961157
if (!prog) {
11971158
errno = ENOENT;
@@ -1202,7 +1163,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
12021163

12031164
if (interpr) {
12041165
const char *argv0 = argv[0];
1205-
char *iprog = path_lookup(interpr, path, 1);
1166+
char *iprog = path_lookup(interpr, 1);
12061167
argv[0] = prog;
12071168
if (!iprog) {
12081169
errno = ENOENT;
@@ -1220,21 +1181,18 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
12201181
fhin, fhout, fherr);
12211182
free(prog);
12221183
}
1223-
free_path_split(path);
12241184
return pid;
12251185
}
12261186

12271187
static int try_shell_exec(const char *cmd, char *const *argv)
12281188
{
12291189
const char *interpr = parse_interpreter(cmd);
1230-
char **path;
12311190
char *prog;
12321191
int pid = 0;
12331192

12341193
if (!interpr)
12351194
return 0;
1236-
path = get_path_split();
1237-
prog = path_lookup(interpr, path, 1);
1195+
prog = path_lookup(interpr, 1);
12381196
if (prog) {
12391197
int argc = 0;
12401198
const char **argv2;
@@ -1253,7 +1211,6 @@ static int try_shell_exec(const char *cmd, char *const *argv)
12531211
free(prog);
12541212
free(argv2);
12551213
}
1256-
free_path_split(path);
12571214
return pid;
12581215
}
12591216

@@ -1275,16 +1232,14 @@ int mingw_execv(const char *cmd, char *const *argv)
12751232

12761233
int mingw_execvp(const char *cmd, char *const *argv)
12771234
{
1278-
char **path = get_path_split();
1279-
char *prog = path_lookup(cmd, path, 0);
1235+
char *prog = path_lookup(cmd, 0);
12801236

12811237
if (prog) {
12821238
mingw_execv(prog, argv);
12831239
free(prog);
12841240
} else
12851241
errno = ENOENT;
12861242

1287-
free_path_split(path);
12881243
return -1;
12891244
}
12901245

0 commit comments

Comments
 (0)