From 1852fcc44e3fdece6ee1e26c48a7d2c29ad90089 Mon Sep 17 00:00:00 2001 From: ikbenlike Date: Sat, 5 Aug 2023 03:40:35 +0200 Subject: [PATCH] options/glibc: implement strerrordesc_np, strerrorname_np --- options/ansi/generic/string-stubs.cpp | 147 +++++++++++++++++++++++++- options/ansi/include/string.h | 4 + tests/glibc/strerrordesc.c | 10 ++ tests/glibc/strerrorname.c | 10 ++ tests/meson.build | 2 + 5 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 tests/glibc/strerrordesc.c create mode 100644 tests/glibc/strerrorname.c diff --git a/options/ansi/generic/string-stubs.cpp b/options/ansi/generic/string-stubs.cpp index d03e342bd2..9b1c88d610 100644 --- a/options/ansi/generic/string-stubs.cpp +++ b/options/ansi/generic/string-stubs.cpp @@ -1,3 +1,7 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include #include #include @@ -337,7 +341,9 @@ wchar_t *wmemset(wchar_t *d, wchar_t c, size_t n) { return ret; } -char *strerror(int e) { +namespace { + +const char *strerror_base(int e) { const char *s; switch(e) { case EAGAIN: s = "Operation would block (EAGAIN)"; break; @@ -452,10 +458,21 @@ char *strerror(int e) { case ERESTART: s = "Interrupted system call should be restarted (ERESTART)"; break; case EUSERS: s = "Too many users (EUSERS)"; break; default: - s = "Unknown error code (?)"; + s = nullptr; } + return s; +} + +} // anonymous namespace + +char *strerror(int e) { + const char *s = strerror_base(e); + if(s == nullptr) + s = "Unknown error code (?)"; + return const_cast(s); } + // strlen() is defined in options/internals. // POSIX extensions. @@ -474,6 +491,132 @@ void *mempcpy(void *dest, const void *src, size_t len) { } // GNU extensions. +const char *strerrorname_np(int e) { + const char *s; +#define X(x) case x: s = #x; break; + switch(e) { + X(EAGAIN) + X(EACCES) + X(EBADF) + X(EEXIST) + X(EFAULT) + X(EINTR) + X(EINVAL) + X(EIO) + X(EISDIR) + X(ENOENT) + X(ENOMEM) + X(ENOTDIR) + X(ENOSYS) + X(EPERM) + X(EPIPE) + X(ESPIPE) + X(ENXIO) + X(ENOEXEC) + X(ENOSPC) + X(ENOTSOCK) + X(ENOTCONN) + X(EDOM) + X(EILSEQ) + X(ERANGE) + X(E2BIG) + X(EADDRINUSE) + X(EADDRNOTAVAIL) + X(EAFNOSUPPORT) + X(EALREADY) + X(EBADMSG) + X(EBUSY) + X(ECANCELED) + X(ECHILD) + X(ECONNABORTED) + X(ECONNREFUSED) + X(ECONNRESET) + X(EDEADLK) + X(EDESTADDRREQ) + X(EDQUOT) + X(EFBIG) + X(EHOSTUNREACH) + X(EIDRM) + X(EINPROGRESS) + X(EISCONN) + X(ELOOP) + X(EMFILE) + X(EMLINK) + X(EMSGSIZE) + X(EMULTIHOP) + X(ENAMETOOLONG) + X(ENETDOWN) + X(ENETRESET) + X(ENETUNREACH) + X(ENFILE) + X(ENOBUFS) + X(ENODEV) + X(ENOLCK) + X(ENOLINK) + X(ENOMSG) + X(ENOPROTOOPT) + X(ENOTEMPTY) + X(ENOTRECOVERABLE) + X(ENOTSUP) + X(ENOTTY) + X(EOVERFLOW) +#if EOPNOTSUPP != ENOTSUP + /* these are aliases on the mlibc abi */ + X(EOPNOTSUPP) +#endif + X(EOWNERDEAD) + X(EPROTO) + X(EPROTONOSUPPORT) + X(EPROTOTYPE) + X(EROFS) + X(ESRCH) + X(ESTALE) + X(ETIMEDOUT) + X(ETXTBSY) + X(EXDEV) + X(ENODATA) + X(ETIME) + X(ENOKEY) + X(ESHUTDOWN) + X(EHOSTDOWN) + X(EBADFD) + X(ENOMEDIUM) + X(ENOTBLK) + X(ENONET) + X(EPFNOSUPPORT) + X(ESOCKTNOSUPPORT) + X(ESTRPIPE) + X(EREMOTEIO) + X(ERFKILL) + X(EBADR) + X(EUNATCH) + X(EMEDIUMTYPE) + X(EREMOTE) + X(EKEYREJECTED) + X(EUCLEAN) + X(EBADSLT) + X(ENOANO) + X(ENOCSI) + X(ENOSTR) + X(ETOOMANYREFS) + X(ENOPKG) + X(EKEYREVOKED) + X(EXFULL) + X(ELNRNG) + X(ENOTUNIQ) + X(ERESTART) + X(EUSERS) + default: + s = nullptr; + } +#undef X + return s; +} + +const char *strerrordesc_np(int e) { + return strerror_base(e); +} + // Taken from musl. int strverscmp(const char *l0, const char *r0) { const unsigned char *l = (const unsigned char *)l0; diff --git a/options/ansi/include/string.h b/options/ansi/include/string.h index 8478e6bae7..e9ff386871 100644 --- a/options/ansi/include/string.h +++ b/options/ansi/include/string.h @@ -60,6 +60,10 @@ int strerror_r(int, char *, size_t); void *mempcpy(void *, const void *, size_t); // GNU extensions. +#ifdef _GNU_SOURCE +const char *strerrorname_np(int e); +const char *strerrordesc_np(int e); +#endif int strverscmp(const char *l0, const char *r0); int ffsl(long i); int ffsll(long long i); diff --git a/tests/glibc/strerrordesc.c b/tests/glibc/strerrordesc.c new file mode 100644 index 0000000000..ca825d5e83 --- /dev/null +++ b/tests/glibc/strerrordesc.c @@ -0,0 +1,10 @@ +#define _GNU_SOURCE +#include +#include +#include + +int main(void) { + const char *s = strerrordesc_np(EINVAL); + assert(!strcmp(s, "Invalid argument (EINVAL)")); + assert(strerrordesc_np(0) == NULL); +} diff --git a/tests/glibc/strerrorname.c b/tests/glibc/strerrorname.c new file mode 100644 index 0000000000..5a38a6c31f --- /dev/null +++ b/tests/glibc/strerrorname.c @@ -0,0 +1,10 @@ +#define _GNU_SOURCE +#include +#include +#include + +int main(void) { + const char *s = strerrorname_np(EINVAL); + assert(!strcmp(s, "EINVAL")); + assert(strerrorname_np(0) == NULL); +} diff --git a/tests/meson.build b/tests/meson.build index 3557f9c6db..ca6a55ff2d 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -95,6 +95,8 @@ all_test_cases = [ 'glibc/error_expect_fail', 'glibc/error', 'glibc/error_at_line', + 'glibc/strerrorname', + 'glibc/strerrordesc', 'linux/xattr', 'linux/pthread_setname_np', 'linux/pthread_attr',