xref: /openbsd-src/lib/libc/string/strerror_r.c (revision 298116df5b000b61a69743d21c92035418df8900)
1 /* $OpenBSD: strerror_r.c,v 1.5 2005/05/26 12:56:01 otto Exp $ */
2 /* Public Domain <marc@snafu.org> */
3 
4 #if defined(LIBC_SCCS) && !defined(lint)
5 static char *rcsid = "$OpenBSD: strerror_r.c,v 1.5 2005/05/26 12:56:01 otto Exp $";
6 #endif /* LIBC_SCCS and not lint */
7 
8 #ifdef NLS
9 #define catclose	_catclose
10 #define catgets		_catgets
11 #define catopen		_catopen
12 #include <nl_types.h>
13 #endif
14 
15 #define sys_errlist	_sys_errlist
16 #define sys_nerr	_sys_nerr
17 #define sys_siglist	_sys_siglist
18 
19 #include <errno.h>
20 #include <limits.h>
21 #include <signal.h>
22 #include <string.h>
23 
24 static size_t
25 __digits10(unsigned int num)
26 {
27 	size_t i = 0;
28 
29 	do {
30 		num /= 10;
31 		i++;
32 	} while (num != 0);
33 
34 	return i;
35 }
36 
37 static int
38 __itoa(int num, int sign, char *buffer, size_t start, size_t end)
39 {
40 	size_t pos;
41 	unsigned int a;
42 	int neg;
43 
44 	if (sign && num < 0) {
45 		a = -num;
46 		neg = 1;
47 	}
48 	else {
49 		a = num;
50 		neg = 0;
51 	}
52 
53 	pos = start + __digits10(a);
54 	if (neg)
55 	    pos++;
56 
57 	if (pos < end)
58 		buffer[pos] = '\0';
59 	else
60 		return ERANGE;
61 	pos--;
62 	do {
63 		buffer[pos] = (a % 10) + '0';
64 		pos--;
65 		a /= 10;
66 	} while (a != 0);
67 	if (neg)
68 		buffer[pos] = '-';
69 	return 0;
70 }
71 
72 
73 static int
74 __num2string(int num, int sign, int setid, char *buf, size_t buflen,
75     char * list[], size_t max, const char *def)
76 {
77 	int ret = 0;
78 	size_t len;
79 
80 #ifdef NLS
81 	nl_catd catd;
82 	catd = catopen("libc", 0);
83 #endif
84 
85 	if (0 <= num && num < max) {
86 #ifdef NLS
87 		len = strlcpy(buf, catgets(catd, setid, num, list[num]),
88 		    buflen);
89 #else
90 		len = strlcpy(buf, def, buflen);
91 #endif
92 		if (len >= buflen)
93 			ret = ERANGE;
94 	} else {
95 #ifdef NLS
96 		len = strlcpy(buf, catgets(catd, setid, 0xffff, def), buflen);
97 #else
98 		len = strlcpy(buf, def, buflen);
99 #endif
100 		if (len >= buflen)
101 			ret = ERANGE;
102 		else {
103 			ret = __itoa(num, sign, buf, len, buflen);
104 			if (ret == 0)
105 				ret = EINVAL;
106 		}
107 	}
108 
109 #ifdef NLS
110 	catclose(catd);
111 #endif
112 
113 	return ret;
114 }
115 
116 #define	UPREFIX	"Unknown error: "
117 
118 int
119 strerror_r(int errnum, char *strerrbuf, size_t buflen)
120 {
121 	int save_errno;
122 	int ret_errno;
123 
124 	save_errno = errno;
125 
126 	ret_errno = __num2string(errnum, 1, 1, strerrbuf, buflen,
127 	    sys_errlist, sys_nerr, UPREFIX);
128 
129 	errno = ret_errno ? ret_errno : save_errno;
130 	return (ret_errno);
131 }
132 
133 #define USIGPREFIX "Unknown signal: "
134 
135 char *
136 __strsignal(int num, char *buf)
137 {
138 	__num2string(num, 0, 2, buf, NL_TEXTMAX, (char **)sys_siglist, NSIG,
139 	    USIGPREFIX);
140 	return buf;
141 }
142