diff options
Diffstat (limited to 'libc/string/strerror_r.c')
-rw-r--r-- | libc/string/strerror_r.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/libc/string/strerror_r.c b/libc/string/strerror_r.c new file mode 100644 index 0000000..f43d417 --- /dev/null +++ b/libc/string/strerror_r.c @@ -0,0 +1,163 @@ +/* $OpenBSD: strerror_r.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */ +/* Public Domain <marc@snafu.org> */ + +#define sys_siglist _sys_siglist + +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <string.h> + +typedef struct { + int code; + const char* msg; +} CodeString; + +static const char* +__code_string_lookup( const CodeString* strings, + int code ) +{ + int nn = 0; + + for (;;) + { + if (strings[nn].code == 0) + break; + + if (strings[nn].code == code) + return strings[nn].msg; + + nn++; + } + return NULL; +} + + +static const CodeString _sys_error_strings[] = +{ +#define __BIONIC_ERRDEF(x,y,z) { y, z }, +#include <sys/_errdefs.h> + { 0, NULL } +}; + +static size_t +__digits10(unsigned int num) +{ + size_t i = 0; + + do { + num /= 10; + i++; + } while (num != 0); + + return i; +} + +static int +__itoa(int num, int sign, char *buffer, size_t start, size_t end) +{ + size_t pos; + unsigned int a; + int neg; + + if (sign && num < 0) { + a = -num; + neg = 1; + } + else { + a = num; + neg = 0; + } + + pos = start + __digits10(a); + if (neg) + pos++; + + if (pos < end) + buffer[pos] = '\0'; + else + return ERANGE; + pos--; + do { + buffer[pos] = (a % 10) + '0'; + pos--; + a /= 10; + } while (a != 0); + if (neg) + buffer[pos] = '-'; + return 0; +} + + +int +strerror_r(int errnum, char *strerrbuf, size_t buflen) +{ + int save_errno; + int len, ret = 0; + const char* msg; + + save_errno = errno; + msg = __code_string_lookup( _sys_error_strings, errnum ); + if (msg != NULL) { + len = strlcpy(strerrbuf, msg, buflen); + if ((size_t)len >= buflen) + ret = ERANGE; + } else { + len = strlcpy(strerrbuf, "Unknown error: ", buflen); + if ((size_t)len >= buflen) + ret = ERANGE; + else { + int ret = __itoa(errnum, 1, strerrbuf, len, buflen); + + if (ret == 0) + ret = EINVAL; + } + } + return ret; +} + +#if 0 +static const CodeString _sys_signal_strings[] = +{ +#define SIGDEF(x,y,z) { y, z }, +#include <sys/_sigdefs.h> +}; + + +static int +__num2string(int num, int sign, int setid, char *buf, size_t buflen, + char * list[], size_t max, const char *def) +{ + int ret = 0; + size_t len; + + if (0 <= num && num < max) { + len = strlcpy(buf, def, buflen); + if (len >= buflen) + ret = ERANGE; + } else { + len = strlcpy(buf, def, buflen); + if (len >= buflen) + ret = ERANGE; + else { + ret = __itoa(num, sign, buf, len, buflen); + if (ret == 0) + ret = EINVAL; + } + } + + return ret; +} + + + +#define USIGPREFIX "Unknown signal: " + +char * +__strsignal(int num, char *buf) +{ + __num2string(num, 0, 2, buf, NL_TEXTMAX, (char **)sys_siglist, NSIG, + USIGPREFIX); + return buf; +} +#endif |