summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2017-07-15 22:56:11 -0400
committerTavian Barnes <tavianator@tavianator.com>2017-07-15 22:56:11 -0400
commitdb2fa0e1059a2426a1afa4fc0c97d6f85f176641 (patch)
treebc3684b2e776af6ab55560aa0174c099c7f01196
parent7b1adcebf65d2131c4d324e73a3e3eace6b2ec28 (diff)
downloadbfs-db2fa0e1059a2426a1afa4fc0c97d6f85f176641.tar.xz
Handle yes/no prompts correctly according to the locale
-rw-r--r--exec.c8
-rw-r--r--util.c72
-rw-r--r--util.h7
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 <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(&regex, pattern, REG_EXTENDED);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = regexec(&regex, response, 0, NULL, 0);
+ regfree(&regex);
+ 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