From db2fa0e1059a2426a1afa4fc0c97d6f85f176641 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 15 Jul 2017 22:56:11 -0400 Subject: Handle yes/no prompts correctly according to the locale --- exec.c | 8 +------- util.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ util.h | 7 +++++++ 3 files changed, 80 insertions(+), 7 deletions(-) diff --git a/exec.c b/exec.c index 3178dbe..62eeaee 100644 --- a/exec.c +++ b/exec.c @@ -342,14 +342,8 @@ static int bfs_exec_spawn(const struct bfs_exec *execbuf) { fprintf(stderr, "%s ", execbuf->argv[i]); } fprintf(stderr, "? "); - fflush(stderr); - int c = getchar(); - bool exec = c == 'y' || c == 'Y'; - while (c != '\n' && c != EOF) { - c = getchar(); - } - if (!exec) { + if (ynprompt() <= 0) { errno = 0; return -1; } diff --git a/util.c b/util.c index e64157b..81eeda0 100644 --- a/util.c +++ b/util.c @@ -11,10 +11,13 @@ #include "util.h" #include "bftw.h" +#include "dstring.h" #include #include +#include #include #include +#include #include #include #include @@ -314,3 +317,72 @@ enum bftw_typeflag dirent_to_typeflag(const struct dirent *de) { return BFTW_UNKNOWN; } + +/** Read a line from standard input. */ +static char *xgetline() { + char *line = dstralloc(0); + if (!line) { + return NULL; + } + + while (true) { + int c = getchar(); + if (c == '\n' || c == EOF) { + break; + } + + if (dstrapp(&line, c) != 0) { + goto error; + } + } + + return line; + +error: + dstrfree(line); + return NULL; +} + +/** Compile and execute a regular expression for xrpmatch(). */ +static int xrpregex(nl_item item, const char *response) { + const char *pattern = nl_langinfo(item); + if (!pattern) { + return REG_BADPAT; + } + + regex_t regex; + int ret = regcomp(®ex, pattern, REG_EXTENDED); + if (ret != 0) { + return ret; + } + + ret = regexec(®ex, response, 0, NULL, 0); + regfree(®ex); + return ret; +} + +/** Check if a response is affirmative or negative. */ +static int xrpmatch(const char *response) { + int ret = xrpregex(NOEXPR, response); + if (ret == 0) { + return 0; + } else if (ret != REG_NOMATCH) { + return -1; + } + + ret = xrpregex(YESEXPR, response); + if (ret == 0) { + return 1; + } else { + return -1; + } +} + +int ynprompt() { + fflush(stderr); + + char *line = xgetline(); + int ret = line ? xrpmatch(line) : -1; + dstrfree(line); + return ret; +} diff --git a/util.h b/util.h index 256abd8..3c58f2a 100644 --- a/util.h +++ b/util.h @@ -143,4 +143,11 @@ enum bftw_typeflag mode_to_typeflag(mode_t mode); */ enum bftw_typeflag dirent_to_typeflag(const struct dirent *de); +/** + * Process a yes/no prompt. + * + * @return 1 for yes, 0 for no, and -1 for unknown. + */ +int ynprompt(void); + #endif // BFS_UTIL_H -- cgit v1.2.3