commit: 29c71c751b82e06d6ec8bcd0cc722c0f2500657d
parent 1d99f8e0247a2ccaf3dfdbbb1f1326495a3bec6c
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sun, 21 Apr 2024 19:50:21 +0200
cmd/rm: Add locale support (yesexpr and noexpr)
Diffstat:
M | Makefile | 4 | ++-- |
M | cmd/rm.c | 105 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------- |
2 files changed, 88 insertions(+), 21 deletions(-)
diff --git a/Makefile b/Makefile
@@ -19,8 +19,8 @@ all: $(EXE) $(MAN1SO)
TEST_LIBS = test-lib/mode test-lib/strtodur test-lib/symbolize_mode
.PHONY: check
check: all $(TEST_LIBS) check-man
- MALLOC_CHECK_=3 POSIX_ME_HARDER=1 POSIXLY_CORRECT=1 LDSTATIC=$(LDSTATIC) kyua test || (kyua report --verbose --results-filter=broken,failed; false)
- MALLOC_CHECK_=3 POSIX_ME_HARDER=1 POSIXLY_CORRECT=1 $(CRAM) test-cmd/*.t
+ MALLOC_CHECK_=3 POSIX_ME_HARDER=1 POSIXLY_CORRECT=1 LC_ALL=C.UTF-8 LDSTATIC=$(LDSTATIC) kyua test || (kyua report --verbose --results-filter=broken,failed; false)
+ MALLOC_CHECK_=3 POSIX_ME_HARDER=1 POSIXLY_CORRECT=1 LC_ALL=C.UTF-8 $(CRAM) test-cmd/*.t
.PHONY: check-man
check-man:
diff --git a/cmd/rm.c b/cmd/rm.c
@@ -10,12 +10,15 @@
#endif
#include <assert.h>
-#include <ctype.h> // isprint
-#include <dirent.h> // fdopendir, readdir, closedir
-#include <errno.h> // errno
-#include <fcntl.h> // AT_FDCWD
-#include <limits.h> // PATH_MAX
-#include <stdarg.h> // va_list
+#include <ctype.h> // isprint
+#include <dirent.h> // fdopendir, readdir, closedir
+#include <errno.h> // errno
+#include <fcntl.h> // AT_FDCWD
+#include <langinfo.h> // nl_langinfo
+#include <limits.h> // PATH_MAX
+#include <locale.h> // setlocale
+#include <regex.h> // regcomp
+#include <stdarg.h> // va_list
#include <stdbool.h>
#include <stdio.h> // fprintf, getline
#include <stdlib.h> // free
@@ -26,6 +29,52 @@
bool opt_d = false, force = false, recurse = false, verbose = false, opt_i = false;
char *argv0 = "rm";
+// Needs to be executed after setlocale
+regex_t consent_yesexpr_r;
+regex_t consent_noexpr_r;
+static void
+consent_init()
+{
+ char *yesexpr = nl_langinfo(YESEXPR);
+ int yesexpr_ret = regcomp(&consent_yesexpr_r, yesexpr, REG_EXTENDED | REG_NOSUB);
+ if(yesexpr_ret != 0)
+ {
+ char errstr[64] = "";
+ regerror(yesexpr_ret, &consent_yesexpr_r, errstr, 100);
+ fprintf(
+ stderr, "%s: Got errorneous yesexpr regex /%s/ from locale: %s\n", argv0, yesexpr, errstr);
+
+ errno = 0;
+ fprintf(stderr, "%s: Fallbacking to /^[Yy]/\n", argv0);
+ yesexpr_ret = regcomp(&consent_yesexpr_r, "^[Yy]", REG_EXTENDED | REG_NOSUB);
+ assert(yesexpr_ret == 0);
+ }
+ assert(errno == 0);
+
+ char *noexpr = nl_langinfo(NOEXPR);
+ int noexpr_ret = regcomp(&consent_noexpr_r, noexpr, REG_EXTENDED | REG_NOSUB);
+ if(noexpr_ret != 0)
+ {
+ char errstr[64] = "";
+ regerror(noexpr_ret, &consent_noexpr_r, errstr, 100);
+ fprintf(
+ stderr, "%s: Got errorneous noexpr regex /%s/ from locale: %s\n", argv0, noexpr, errstr);
+
+ errno = 0;
+ fprintf(stderr, "%s: Fallbacking to /^[Nn]/\n", argv0);
+ noexpr_ret = regcomp(&consent_noexpr_r, "^[Nn]", REG_EXTENDED | REG_NOSUB);
+ assert(noexpr_ret == 0);
+ }
+ assert(errno == 0);
+}
+
+static void
+consent_finish()
+{
+ regfree(&consent_yesexpr_r);
+ regfree(&consent_noexpr_r);
+}
+
// Consent therefore defaults to no
static bool
consentf(const char *restrict fmt, ...)
@@ -70,25 +119,31 @@ consentf(const char *restrict fmt, ...)
// isatty changes errno if not a TTY *sigh*
errno = 0;
- // Only consider the first character for now
- switch(line[0])
+ if(line[nread - 1] == '\n') line[--nread] = 0;
+
+ if(line[0] == 0 || line[0] == '\n' || line[0] == '\r')
{
- case 'y':
- case 'Y':
- result = true;
- goto end;
- case 'n':
- case 'N':
- goto end;
- case '\n':
- case '\r':
fprintf(stderr, "%s: Got empty response, considering it false\n", argv0);
goto end;
- default:
- fprintf(stderr, "%s: User entry (%c) isn't [yn], considering it false\n", argv0, line[0]);
+ }
+
+ if(regexec(&consent_yesexpr_r, line, 0, 0, 0) == 0)
+ {
+ result = true;
goto end;
}
+ if(regexec(&consent_noexpr_r, line, 0, 0, 0) == 0)
+ {
+ result = false;
+ goto end;
+ }
+
+ fprintf(stderr,
+ "%s: User entry \"%s\" neither affirmative nor negative, considering it false\n",
+ argv0,
+ line);
+
end:
if(len != 0) free(line);
return result;
@@ -277,6 +332,16 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
+ errno = 0;
+ setlocale(LC_ALL, "");
+ if(errno != 0)
+ {
+ fprintf(stderr, "%s: Warning: Failed to initialize locales: %s\n", argv0, strerror(errno));
+ errno = 0;
+ }
+
+ consent_init();
+
if(argc == 0 && !force)
{
fprintf(stderr, "rm: missing operand\n");
@@ -292,5 +357,7 @@ main(int argc, char *argv[])
if(ret != 0) err = 1;
}
+ consent_finish();
+
return err;
}