diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2017-07-15 22:56:11 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2017-07-15 22:56:11 -0400 |
commit | db2fa0e1059a2426a1afa4fc0c97d6f85f176641 (patch) | |
tree | bc3684b2e776af6ab55560aa0174c099c7f01196 | |
parent | 7b1adcebf65d2131c4d324e73a3e3eace6b2ec28 (diff) | |
download | bfs-db2fa0e1059a2426a1afa4fc0c97d6f85f176641.tar.xz |
Handle yes/no prompts correctly according to the locale
-rw-r--r-- | exec.c | 8 | ||||
-rw-r--r-- | util.c | 72 | ||||
-rw-r--r-- | util.h | 7 |
3 files changed, 80 insertions, 7 deletions
@@ -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; } @@ -11,10 +11,13 @@ #include "util.h" #include "bftw.h" +#include "dstring.h" #include <errno.h> #include <fcntl.h> +#include <langinfo.h> #include <regex.h> #include <stdarg.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> @@ -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; +} @@ -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 |