>From f6d09944cf382f2abb3fa75d9f9a8801eda90fba Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Mon, 21 Sep 2026 20:05:18 -0400 Subject: [PATCH 21/21] convert getopt to use new locale string table lookups since the getopt implementation is not just a trivial error lookup function, and mostly stands on its own, __getopt_msg with its coupling to stdio locking and locale machinery is moved to its own file. its declarations are left in stdio_impl.h for now, but should probably be moved at some point. --- src/internal/stdio_impl.h | 4 +++- src/misc/getopt.c | 16 ++------------ src/misc/getopt_long.c | 9 ++++---- src/misc/getopt_msg.c | 44 +++++++++++++++++++++++++++++++++++++++ src/misc/getopt_msg.h | 4 ++++ 5 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 src/misc/getopt_msg.c create mode 100644 src/misc/getopt_msg.h diff --git a/src/internal/stdio_impl.h b/src/internal/stdio_impl.h index 0b2438d6..e6e9fe4c 100644 --- a/src/internal/stdio_impl.h +++ b/src/internal/stdio_impl.h @@ -92,7 +92,9 @@ hidden void __do_orphaned_stdio_locks(void); #define MAYBE_WAITERS 0x40000000 -hidden void __getopt_msg(const char *, const char *, const char *, size_t); +hidden void __getopt_msg(const char *, const int *, const char *, size_t); +extern hidden const int __getopt_inval[], __getopt_req_arg[], + __getopt_bad_arg[], __getopt_ambig[]; #define feof(f) ((f)->flags & F_EOF) #define ferror(f) ((f)->flags & F_ERR) diff --git a/src/misc/getopt.c b/src/misc/getopt.c index e34d6ccf..1783ef8b 100644 --- a/src/misc/getopt.c +++ b/src/misc/getopt.c @@ -13,17 +13,6 @@ int optind=1, opterr=1, optopt, __optpos, __optreset=0; #define optpos __optpos weak_alias(__optreset, optreset); -void __getopt_msg(const char *a, const char *b, const char *c, size_t l) -{ - FILE *f = stderr; - FLOCK(f); - fputs(a, f)>=0 - && fwrite(b, strlen(b), 1, f) - && fwrite(c, 1, l, f)==l - && putc('\n', f); - FUNLOCK(f); -} - int getopt(int argc, char * const argv[], const char *optstring) { int i; @@ -80,7 +69,7 @@ int getopt(int argc, char * const argv[], const char *optstring) if (d != c || c == ':') { optopt = c; if (optstring[0] != ':' && opterr) - __getopt_msg(argv[0], ": unrecognized option: ", optchar, k); + __getopt_msg(argv[0], __getopt_inval, optchar, k); return '?'; } if (optstring[i] == ':') { @@ -94,8 +83,7 @@ int getopt(int argc, char * const argv[], const char *optstring) optopt = c; if (optstring[0] == ':') return ':'; if (opterr) __getopt_msg(argv[0], - ": option requires an argument: ", - optchar, k); + __getopt_req_arg, optchar, k); return '?'; } } diff --git a/src/misc/getopt_long.c b/src/misc/getopt_long.c index 6949ab1c..643f30e2 100644 --- a/src/misc/getopt_long.c +++ b/src/misc/getopt_long.c @@ -6,6 +6,7 @@ #include #include #include "stdio_impl.h" +#include "locale_impl.h" extern int __optpos, __optreset; @@ -96,7 +97,7 @@ static int __getopt_long_core(int argc, char *const *argv, const char *optstring if (colon || !opterr) return '?'; __getopt_msg(argv[0], - ": option does not take an argument: ", + __getopt_bad_arg, longopts[i].name, strlen(longopts[i].name)); return '?'; @@ -108,7 +109,7 @@ static int __getopt_long_core(int argc, char *const *argv, const char *optstring if (colon) return ':'; if (!opterr) return '?'; __getopt_msg(argv[0], - ": option requires an argument: ", + __getopt_req_arg, longopts[i].name, strlen(longopts[i].name)); return '?'; @@ -126,8 +127,8 @@ static int __getopt_long_core(int argc, char *const *argv, const char *optstring optopt = 0; if (!colon && opterr) __getopt_msg(argv[0], cnt ? - ": option is ambiguous: " : - ": unrecognized option: ", + __getopt_ambig : + __getopt_inval, argv[optind]+2, strlen(argv[optind]+2)); optind++; diff --git a/src/misc/getopt_msg.c b/src/misc/getopt_msg.c new file mode 100644 index 00000000..fb892e93 --- /dev/null +++ b/src/misc/getopt_msg.c @@ -0,0 +1,44 @@ +#include +#include "stdio_impl.h" +#include "locale_impl.h" + +#define M_TABLE "../misc/getopt_msg.h", getopt_msg_data, 0 +#define ERRDOMAIN_GETOPT 4 +#define GETOPT_INVAL 0 +#define GETOPT_REQ_ARG 1 +#define GETOPT_BAD_ARG 2 +#define GETOPT_AMBIG 3 + +static const struct { + unsigned char header[8]; + unsigned char offsets[8]; + struct { + #include "mdecl.h" + } errors; +} getopt_msgs = { + .header = { 0,0,0,0,0,0,0,8-1, }, + .offsets = { [ERRDOMAIN_GETOPT] = 1 }, + .errors = { + #include "mdata.h" + }, +}; + +const int __getopt_inval[] = LPATH(ERRDOMAIN_GETOPT, GETOPT_INVAL); +const int __getopt_req_arg[] = LPATH(ERRDOMAIN_GETOPT, GETOPT_REQ_ARG); +const int __getopt_bad_arg[] = LPATH(ERRDOMAIN_GETOPT, GETOPT_BAD_ARG); +const int __getopt_ambig[] = LPATH(ERRDOMAIN_GETOPT, GETOPT_AMBIG); + +void __getopt_msg(const char *a, const int *p, const char *c, size_t l) +{ + const char *b = __loc_lookup((const void *)&getopt_msgs, + LMEMB(CURRENT_LOCALE,LC_MESSAGES,errors), p, 0); + FILE *f = stderr; + FLOCK(f); + fputs(a, f)>=0 + && fwrite(": ", 2, 1, f) + && fwrite(b, strlen(b), 1, f) + && fwrite(": ", 2, 1, f) + && fwrite(c, 1, l, f)==l + && putc('\n', f); + FUNLOCK(f); +} diff --git a/src/misc/getopt_msg.h b/src/misc/getopt_msg.h new file mode 100644 index 00000000..8c13449b --- /dev/null +++ b/src/misc/getopt_msg.h @@ -0,0 +1,4 @@ +M(GETOPT_INVAL, "unrecognized option") +M(GETOPT_REQ_ARG, "option requires an argument") +M(GETOPT_BAD_ARG, "option does not take an argument") +M(GETOPT_AMBIG, "option is ambiguous") -- 2.21.0