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
ed01e4f95a
commit
4405d11737
@ -81,16 +81,7 @@ function renders the same result into
|
|||||||
.Fa strerrbuf
|
.Fa strerrbuf
|
||||||
for a maximum of
|
for a maximum of
|
||||||
.Fa buflen
|
.Fa buflen
|
||||||
characters and returns 0 upon success. If insufficient
|
characters and returns 0 upon success.
|
||||||
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.
|
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
.Fn perror
|
.Fn perror
|
||||||
@ -114,9 +105,25 @@ otherwise, only the error message string is printed.
|
|||||||
If
|
If
|
||||||
.Fa errnum
|
.Fa errnum
|
||||||
is not a recognized error number,
|
is not a recognized error number,
|
||||||
the error message string will contain
|
.Fn strerror
|
||||||
|
returns an error message string containing
|
||||||
.Dq Li "Unknown error:\ "
|
.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
|
.Pp
|
||||||
The message strings can be accessed directly using the external
|
The message strings can be accessed directly using the external
|
||||||
array
|
array
|
||||||
|
@ -41,88 +41,87 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
strerror_r(int errnum, char *strerrbuf, size_t buflen)
|
strerror_r(int errnum, char *strerrbuf, size_t buflen)
|
||||||
{
|
{
|
||||||
#define UPREFIX "Unknown error: "
|
int len;
|
||||||
unsigned int uerr;
|
|
||||||
char *p, *t;
|
|
||||||
char tmp[40]; /* 64-bit number + slop */
|
|
||||||
int len;
|
|
||||||
|
|
||||||
uerr = errnum; /* convert to unsigned */
|
if ((errnum > 0) && (errnum < sys_nerr)) {
|
||||||
if (uerr < sys_nerr) {
|
len = strlcpy(strerrbuf, (char *)sys_errlist[errnum], buflen);
|
||||||
len = strlcpy(strerrbuf, (char *)sys_errlist[uerr], buflen);
|
return ((len <= buflen) ? 0 : ERANGE);
|
||||||
return (len <= buflen) ? 0 : ERANGE;
|
|
||||||
}
|
}
|
||||||
|
return (EINVAL);
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 *
|
char *
|
||||||
strerror(num)
|
strerror(num)
|
||||||
int num;
|
int num;
|
||||||
{
|
{
|
||||||
unsigned int uerr;
|
char *p, *t;
|
||||||
static char ebuf[ERR_LEN];
|
unsigned int uerr;
|
||||||
|
static char const unknown_prefix[] = "Unknown error: ";
|
||||||
|
|
||||||
uerr = num; /* convert to unsigned */
|
/*
|
||||||
if (uerr < sys_nerr)
|
* Define a buffer size big enough to describe a 64-bit
|
||||||
return (char *)sys_errlist[uerr];
|
* 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 ((num > 0) && (num < sys_nerr))
|
||||||
if (strerror_r(num, ebuf, (size_t) ERR_LEN) != 0)
|
return ((char *)sys_errlist[num]);
|
||||||
ebuf[ERR_LEN - 1] = '\0';
|
|
||||||
|
|
||||||
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
|
#ifdef STANDALONE_TEST
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
char mybuf[64];
|
char mybuf[64];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
printf("strerror(47) yeilds: %s\n", strerror(47));
|
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);
|
strerror_r(11, mybuf, 64);
|
||||||
printf("strerror_r(11) yeilds: %s\n", mybuf);
|
printf("strerror_r(11) yeilds: %s\n", mybuf);
|
||||||
strerror_r(1234, mybuf, 64);
|
|
||||||
printf("strerror_r(1234) yeilds: %s\n", mybuf);
|
memset(mybuf, '*', 63); mybuf[63] = '\0';
|
||||||
memset(mybuf, '*', 63);
|
ret = strerror_r(1234, mybuf, 64);
|
||||||
ret = strerror_r(4321, mybuf, 16);
|
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);
|
printf("strerror_r on short buffer returns %d (%s)\n", ret, mybuf);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user