logo

utils-std

Collection of commonly available Unix tools
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:

MMakefile4++--
Mcmd/rm.c105++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
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; }