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