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