New, improved, more Posix-compliant strerror_r implementation,
complete with documentation. Reviewed by: mike@ gad@ MFC after: 1 week
This commit is contained in:
parent
5a31fd21e9
commit
f61a2ede84
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=87434
@ -81,16 +81,7 @@ function renders the same result into
|
||||
.Fa strerrbuf
|
||||
for a maximum of
|
||||
.Fa buflen
|
||||
characters and returns 0 upon success. If insufficient
|
||||
storage is provided in
|
||||
.Fa strerrbuf
|
||||
(as specified in
|
||||
.Fa buflen )
|
||||
to contain the error string,
|
||||
.Er ERANGE
|
||||
is returned and the string in
|
||||
.Fa strerrbuf
|
||||
may not be null-terminated.
|
||||
characters and returns 0 upon success.
|
||||
.Pp
|
||||
The
|
||||
.Fn perror
|
||||
@ -114,9 +105,25 @@ otherwise, only the error message string is printed.
|
||||
If
|
||||
.Fa errnum
|
||||
is not a recognized error number,
|
||||
the error message string will contain
|
||||
.Fn strerror
|
||||
returns an error message string containing
|
||||
.Dq Li "Unknown error:\ "
|
||||
followed by the error number in decimal.
|
||||
followed by the error number in decimal, while
|
||||
.Fn strerror_r
|
||||
returns
|
||||
.Er EINVAL .
|
||||
.Pp
|
||||
If insufficient storage is provided in
|
||||
.Fa strerrbuf
|
||||
(as specified in
|
||||
.Fa buflen )
|
||||
to contain the error string,
|
||||
.Fn strerror_r
|
||||
returns
|
||||
.Er ERANGE
|
||||
and the contents of
|
||||
.Fa strerrbuf
|
||||
are indeterminate.
|
||||
.Pp
|
||||
The message strings can be accessed directly using the external
|
||||
array
|
||||
|
@ -41,88 +41,87 @@ __FBSDID("$FreeBSD$");
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
int
|
||||
strerror_r(int errnum, char *strerrbuf, size_t buflen)
|
||||
{
|
||||
#define UPREFIX "Unknown error: "
|
||||
unsigned int uerr;
|
||||
char *p, *t;
|
||||
char tmp[40]; /* 64-bit number + slop */
|
||||
int len;
|
||||
int len;
|
||||
|
||||
uerr = errnum; /* convert to unsigned */
|
||||
if (uerr < sys_nerr) {
|
||||
len = strlcpy(strerrbuf, (char *)sys_errlist[uerr], buflen);
|
||||
return (len <= buflen) ? 0 : ERANGE;
|
||||
if ((errnum > 0) && (errnum < sys_nerr)) {
|
||||
len = strlcpy(strerrbuf, (char *)sys_errlist[errnum], buflen);
|
||||
return ((len <= buflen) ? 0 : ERANGE);
|
||||
}
|
||||
|
||||
/* Print unknown errno by hand so we don't link to stdio(3). */
|
||||
t = tmp;
|
||||
if (errnum < 0)
|
||||
uerr = -uerr;
|
||||
do {
|
||||
*t++ = "0123456789"[uerr % 10];
|
||||
} while (uerr /= 10);
|
||||
|
||||
if (errnum < 0)
|
||||
*t++ = '-';
|
||||
|
||||
strlcpy(strerrbuf, UPREFIX, buflen);
|
||||
for (p = strerrbuf + sizeof(UPREFIX) - 1; p < strerrbuf + buflen; ) {
|
||||
*p++ = *--t;
|
||||
if (t <= tmp)
|
||||
break;
|
||||
}
|
||||
|
||||
if (p < strerrbuf + buflen) {
|
||||
*p = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ERANGE;
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NOTE: the following length should be enough to hold the longest defined
|
||||
* error message in sys_errlist, defined in ../gen/errlst.c. This is a WAG
|
||||
* that is better than the previous value.
|
||||
*/
|
||||
#define ERR_LEN 64
|
||||
|
||||
char *
|
||||
strerror(num)
|
||||
int num;
|
||||
int num;
|
||||
{
|
||||
unsigned int uerr;
|
||||
static char ebuf[ERR_LEN];
|
||||
char *p, *t;
|
||||
unsigned int uerr;
|
||||
static char const unknown_prefix[] = "Unknown error: ";
|
||||
|
||||
uerr = num; /* convert to unsigned */
|
||||
if (uerr < sys_nerr)
|
||||
return (char *)sys_errlist[uerr];
|
||||
/*
|
||||
* Define a buffer size big enough to describe a 64-bit
|
||||
* number in ASCII decimal (19), with optional leading sign
|
||||
* (+1) and trailing NUL (+1).
|
||||
*/
|
||||
# define NUMLEN 21
|
||||
# define EBUFLEN (sizeof unknown_prefix + NUMLEN)
|
||||
char tmp[NUMLEN]; /* temporary number */
|
||||
static char ebuf[EBUFLEN]; /* error message */
|
||||
|
||||
/* strerror can't fail so handle truncation semi-elegantly */
|
||||
if (strerror_r(num, ebuf, (size_t) ERR_LEN) != 0)
|
||||
ebuf[ERR_LEN - 1] = '\0';
|
||||
if ((num > 0) && (num < sys_nerr))
|
||||
return ((char *)sys_errlist[num]);
|
||||
|
||||
return ebuf;
|
||||
/*
|
||||
* Print unknown errno by hand so we don't link to stdio(3).
|
||||
* This collects the ASCII digits in reverse order.
|
||||
*/
|
||||
uerr = (num > 0) ? num : -num;
|
||||
t = tmp;
|
||||
do {
|
||||
*t++ = "0123456789"[uerr % 10];
|
||||
} while (uerr /= 10);
|
||||
if (num < 0)
|
||||
*t++ = '-';
|
||||
|
||||
/*
|
||||
* Copy the "unknown" message and the number into the caller
|
||||
* supplied buffer, inverting the number string.
|
||||
*/
|
||||
strcpy(ebuf, unknown_prefix);
|
||||
for (p = ebuf + sizeof unknown_prefix - 1; t >= tmp; )
|
||||
*p++ = *--t;
|
||||
*p = '\0';
|
||||
return (ebuf);
|
||||
}
|
||||
|
||||
|
||||
#ifdef STANDALONE_TEST
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
main()
|
||||
{
|
||||
char mybuf[64];
|
||||
int ret;
|
||||
char mybuf[64];
|
||||
int ret;
|
||||
|
||||
printf("strerror(47) yeilds: %s\n", strerror(47));
|
||||
printf("strerror(437) yeilds: %s\n", strerror(437));
|
||||
printf("strerror(LONG_MAX) yeilds: %s\n", strerror(LONG_MAX));
|
||||
printf("strerror(LONG_MIN) yeilds: %s\n", strerror(LONG_MIN));
|
||||
printf("strerror(ULONG_MAX) yeilds: %s\n", strerror(ULONG_MAX));
|
||||
|
||||
memset(mybuf, '*', 63); mybuf[63] = '\0';
|
||||
strerror_r(11, mybuf, 64);
|
||||
printf("strerror_r(11) yeilds: %s\n", mybuf);
|
||||
strerror_r(1234, mybuf, 64);
|
||||
printf("strerror_r(1234) yeilds: %s\n", mybuf);
|
||||
memset(mybuf, '*', 63);
|
||||
ret = strerror_r(4321, mybuf, 16);
|
||||
|
||||
memset(mybuf, '*', 63); mybuf[63] = '\0';
|
||||
ret = strerror_r(1234, mybuf, 64);
|
||||
printf("strerror_r(1234) returns %d (%s)\n", ret, mybuf);
|
||||
|
||||
memset(mybuf, '*', 63); mybuf[63] = '\0';
|
||||
ret = strerror_r(1, mybuf, 10);
|
||||
printf("strerror_r on short buffer returns %d (%s)\n", ret, mybuf);
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user