diff --git a/usr.bin/patch/pch.c b/usr.bin/patch/pch.c --- a/usr.bin/patch/pch.c +++ b/usr.bin/patch/pch.c @@ -214,11 +214,31 @@ skip_rest_of_patch = true; return true; } - ask("File to patch: "); + ask("File to patch (enter '*' to search): "); if (*buf != '\n') { - free(bestguess); - bestguess = xstrdup(buf); - filearg[0] = fetchname(buf, &exists, 0); + if (strcmp(buf, "*") == 0) { + for (int match = 0;; match++) { + char *presult; + int temp; + + temp = match; + presult = find_file(".", ".", bestguess, &temp); + if (presult == NULL) + break; + ask("Select this file, %s [y]: ", presult); + if (*buf != 'n') { + free(bestguess); + bestguess = presult; + filearg[0] = fetchname(bestguess, &exists, 0); + break; + } + free(presult); + } + } else { + free(bestguess); + bestguess = xstrdup(buf); + filearg[0] = fetchname(buf, &exists, 0); + } } /* * fetchname can now return buf = NULL, exists = true, to diff --git a/usr.bin/patch/util.h b/usr.bin/patch/util.h --- a/usr.bin/patch/util.h +++ b/usr.bin/patch/util.h @@ -46,6 +46,7 @@ void makedirs(const char *, bool); void version(void); void my_exit(int) __attribute__((noreturn)); +char * find_file(const char *, const char *, const char *, int *); /* in mkpath.c */ extern int mkpath(char *); diff --git a/usr.bin/patch/util.c b/usr.bin/patch/util.c --- a/usr.bin/patch/util.c +++ b/usr.bin/patch/util.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "common.h" #include "util.h" @@ -422,3 +423,61 @@ unlink(TMPPATNAME); exit(status); } + +/* + * Search for file recursivly. + */ +char * +find_file(const char *bname, const char *dname, const char *fname, int *pmatch) +{ + struct dirent *dp; + char *retval; + char *ddir; + DIR *dirp; + int len; + + if (strcmp(bname, ".") == 0 && strcmp(dname, ".") == 0) { + if (asprintf(&ddir, ".") < 0) + return (NULL); + } else { + if (asprintf(&ddir, "%s/%s", bname, dname) < 0) + return (NULL); + } + + dirp = opendir(ddir); + retval = NULL; + + if (dirp == NULL) { + free(ddir); + return (NULL); + } + + len = strlen(fname); + while ((dp = readdir(dirp)) != NULL) { + switch (dp->d_type) { + case DT_DIR: + if (strcmp(dp->d_name, ".") == 0 || + strcmp(dp->d_name, "..") == 0) + break; + retval = find_file(ddir, dp->d_name, fname, pmatch); + if (retval != NULL) + goto done; + break; + case DT_REG: + if (dp->d_namlen == len && + strcmp(dp->d_name, fname) == 0 && + (*pmatch)-- == 0) { + if (asprintf(&retval, "%s/%s", ddir, fname) < 0) + retval = NULL; + goto done; + } + break; + default: + break; + } + } +done: + closedir(dirp); + free(ddir); + return (retval); +}