xref: /reactos/sdk/lib/ucrt/misc/_strerr.cpp (revision 04e0dc4a)
1*04e0dc4aSTimo Kreuzer /***
2*04e0dc4aSTimo Kreuzer *_strerr.c - routine for indexing into system error list
3*04e0dc4aSTimo Kreuzer *
4*04e0dc4aSTimo Kreuzer *   Copyright (c) Microsoft Corporation. All rights reserved.
5*04e0dc4aSTimo Kreuzer *
6*04e0dc4aSTimo Kreuzer *Purpose:
7*04e0dc4aSTimo Kreuzer *   Returns system error message index by errno; conforms to the
8*04e0dc4aSTimo Kreuzer *   XENIX standard, much compatibility with 1983 uniforum draft standard.
9*04e0dc4aSTimo Kreuzer *
10*04e0dc4aSTimo Kreuzer *******************************************************************************/
11*04e0dc4aSTimo Kreuzer 
12*04e0dc4aSTimo Kreuzer #include <corecrt_internal.h>
13*04e0dc4aSTimo Kreuzer #include <corecrt_internal_traits.h>
14*04e0dc4aSTimo Kreuzer #include <malloc.h>
15*04e0dc4aSTimo Kreuzer #include <stdlib.h>
16*04e0dc4aSTimo Kreuzer #include <string.h>
17*04e0dc4aSTimo Kreuzer 
18*04e0dc4aSTimo Kreuzer 
19*04e0dc4aSTimo Kreuzer 
20*04e0dc4aSTimo Kreuzer /***
21*04e0dc4aSTimo Kreuzer *char *_strerror(message) - get system error message
22*04e0dc4aSTimo Kreuzer *
23*04e0dc4aSTimo Kreuzer *Purpose:
24*04e0dc4aSTimo Kreuzer *   builds an error message consisting of the users error message
25*04e0dc4aSTimo Kreuzer *   (the message parameter), followed by ": ", followed by the system
26*04e0dc4aSTimo Kreuzer *   error message (index through errno), followed by a newline.  If
27*04e0dc4aSTimo Kreuzer *   message is nullptr or a null string, returns a pointer to just
28*04e0dc4aSTimo Kreuzer *   the system error message.
29*04e0dc4aSTimo Kreuzer *
30*04e0dc4aSTimo Kreuzer *Entry:
31*04e0dc4aSTimo Kreuzer *   char *message - user's message to prefix system error message
32*04e0dc4aSTimo Kreuzer *
33*04e0dc4aSTimo Kreuzer *Exit:
34*04e0dc4aSTimo Kreuzer *   returns pointer to static memory containing error message.
35*04e0dc4aSTimo Kreuzer *   returns nullptr if malloc() fails in multi-thread versions.
36*04e0dc4aSTimo Kreuzer *
37*04e0dc4aSTimo Kreuzer *Exceptions:
38*04e0dc4aSTimo Kreuzer *
39*04e0dc4aSTimo Kreuzer *******************************************************************************/
40*04e0dc4aSTimo Kreuzer 
get_strerror_buffer(__acrt_ptd * const ptd,char)41*04e0dc4aSTimo Kreuzer static char*& __cdecl get_strerror_buffer(__acrt_ptd* const ptd, char) throw()
42*04e0dc4aSTimo Kreuzer {
43*04e0dc4aSTimo Kreuzer     return ptd->_strerror_buffer;
44*04e0dc4aSTimo Kreuzer }
45*04e0dc4aSTimo Kreuzer 
get_strerror_buffer(__acrt_ptd * const ptd,wchar_t)46*04e0dc4aSTimo Kreuzer static wchar_t*& __cdecl get_strerror_buffer(__acrt_ptd* const ptd, wchar_t) throw()
47*04e0dc4aSTimo Kreuzer {
48*04e0dc4aSTimo Kreuzer     return ptd->_wcserror_buffer;
49*04e0dc4aSTimo Kreuzer }
50*04e0dc4aSTimo Kreuzer 
append_message(_Inout_updates_z_ (buffer_count)char * const buffer,size_t const buffer_count,char const * const message)51*04e0dc4aSTimo Kreuzer static errno_t __cdecl append_message(
52*04e0dc4aSTimo Kreuzer     _Inout_updates_z_(buffer_count) char* const buffer,
53*04e0dc4aSTimo Kreuzer     size_t                                const buffer_count,
54*04e0dc4aSTimo Kreuzer     char const*                           const message
55*04e0dc4aSTimo Kreuzer     ) throw()
56*04e0dc4aSTimo Kreuzer {
57*04e0dc4aSTimo Kreuzer     return strncat_s(buffer, buffer_count, message, buffer_count - strlen(buffer) - 2);
58*04e0dc4aSTimo Kreuzer }
59*04e0dc4aSTimo Kreuzer 
append_message(_Inout_updates_z_ (buffer_count)wchar_t * const buffer,size_t const buffer_count,char const * const message)60*04e0dc4aSTimo Kreuzer static errno_t __cdecl append_message(
61*04e0dc4aSTimo Kreuzer     _Inout_updates_z_(buffer_count) wchar_t* const buffer,
62*04e0dc4aSTimo Kreuzer     size_t                                   const buffer_count,
63*04e0dc4aSTimo Kreuzer     char const*                              const message
64*04e0dc4aSTimo Kreuzer     ) throw()
65*04e0dc4aSTimo Kreuzer {
66*04e0dc4aSTimo Kreuzer     size_t const buffer_length = wcslen(buffer);
67*04e0dc4aSTimo Kreuzer     return mbstowcs_s(
68*04e0dc4aSTimo Kreuzer         nullptr,
69*04e0dc4aSTimo Kreuzer         buffer + buffer_length,
70*04e0dc4aSTimo Kreuzer         buffer_count - buffer_length,
71*04e0dc4aSTimo Kreuzer         message,
72*04e0dc4aSTimo Kreuzer         buffer_count - buffer_length - 2);
73*04e0dc4aSTimo Kreuzer }
74*04e0dc4aSTimo Kreuzer 
75*04e0dc4aSTimo Kreuzer template <typename Character>
76*04e0dc4aSTimo Kreuzer _Ret_z_
77*04e0dc4aSTimo Kreuzer _Success_(return != 0)
common_strerror(Character const * const message)78*04e0dc4aSTimo Kreuzer static Character* __cdecl common_strerror(
79*04e0dc4aSTimo Kreuzer     Character const* const message
80*04e0dc4aSTimo Kreuzer     ) throw()
81*04e0dc4aSTimo Kreuzer {
82*04e0dc4aSTimo Kreuzer     using traits = __crt_char_traits<Character>;
83*04e0dc4aSTimo Kreuzer 
84*04e0dc4aSTimo Kreuzer     errno_t const original_errno_value = errno;
85*04e0dc4aSTimo Kreuzer 
86*04e0dc4aSTimo Kreuzer     __acrt_ptd* const ptd = __acrt_getptd_noexit();
87*04e0dc4aSTimo Kreuzer     if (!ptd)
88*04e0dc4aSTimo Kreuzer         return nullptr;
89*04e0dc4aSTimo Kreuzer 
90*04e0dc4aSTimo Kreuzer     Character*& buffer = get_strerror_buffer(ptd, Character());
91*04e0dc4aSTimo Kreuzer     if (!buffer)
92*04e0dc4aSTimo Kreuzer         buffer = _calloc_crt_t(Character, strerror_buffer_count).detach();
93*04e0dc4aSTimo Kreuzer 
94*04e0dc4aSTimo Kreuzer     if (!buffer)
95*04e0dc4aSTimo Kreuzer         return nullptr;
96*04e0dc4aSTimo Kreuzer 
97*04e0dc4aSTimo Kreuzer     buffer[0] = '\0';
98*04e0dc4aSTimo Kreuzer 
99*04e0dc4aSTimo Kreuzer     // CRT_REFACTOR TODO AppCRT/DesktopCRT Dependencies
100*04e0dc4aSTimo Kreuzer     // (We should be using mbs* functions here).
101*04e0dc4aSTimo Kreuzer     if (message && message[0] != '\0')
102*04e0dc4aSTimo Kreuzer     {
103*04e0dc4aSTimo Kreuzer         Character const colon[] = { ':', ' ', '\0' };
104*04e0dc4aSTimo Kreuzer 
105*04e0dc4aSTimo Kreuzer         // Leave room for the ": \n\0"
106*04e0dc4aSTimo Kreuzer         _ERRCHECK(traits::tcsncat_s(buffer, strerror_buffer_count, message, strerror_buffer_count - 4));
107*04e0dc4aSTimo Kreuzer         _ERRCHECK(traits::tcscat_s(buffer, strerror_buffer_count, colon));
108*04e0dc4aSTimo Kreuzer     }
109*04e0dc4aSTimo Kreuzer 
110*04e0dc4aSTimo Kreuzer     char const* const system_message = _get_sys_err_msg(original_errno_value);
111*04e0dc4aSTimo Kreuzer     _ERRCHECK(append_message(buffer, strerror_buffer_count, system_message));
112*04e0dc4aSTimo Kreuzer 
113*04e0dc4aSTimo Kreuzer     Character const newline[] = { '\n', '\0' };
114*04e0dc4aSTimo Kreuzer     _ERRCHECK(traits::tcscat_s(buffer, strerror_buffer_count, newline));
115*04e0dc4aSTimo Kreuzer 
116*04e0dc4aSTimo Kreuzer     return buffer;
117*04e0dc4aSTimo Kreuzer }
118*04e0dc4aSTimo Kreuzer 
_strerror(char const * const message)119*04e0dc4aSTimo Kreuzer extern "C" char* __cdecl _strerror(char const* const message)
120*04e0dc4aSTimo Kreuzer {
121*04e0dc4aSTimo Kreuzer     return common_strerror(message);
122*04e0dc4aSTimo Kreuzer }
123*04e0dc4aSTimo Kreuzer 
__wcserror(wchar_t const * const message)124*04e0dc4aSTimo Kreuzer extern "C" wchar_t* __cdecl __wcserror(wchar_t const* const message)
125*04e0dc4aSTimo Kreuzer {
126*04e0dc4aSTimo Kreuzer     return common_strerror(message);
127*04e0dc4aSTimo Kreuzer }
128*04e0dc4aSTimo Kreuzer 
129*04e0dc4aSTimo Kreuzer 
130*04e0dc4aSTimo Kreuzer 
131*04e0dc4aSTimo Kreuzer /***
132*04e0dc4aSTimo Kreuzer *errno_t _strerror_s(buffer, sizeInTChars, message) - get system error message
133*04e0dc4aSTimo Kreuzer *
134*04e0dc4aSTimo Kreuzer *Purpose:
135*04e0dc4aSTimo Kreuzer *   builds an error message consisting of the users error message
136*04e0dc4aSTimo Kreuzer *   (the message parameter), followed by ": ", followed by the system
137*04e0dc4aSTimo Kreuzer *   error message (index through errno), followed by a newline.  If
138*04e0dc4aSTimo Kreuzer *   message is nullptr or a null string, returns a pointer to just
139*04e0dc4aSTimo Kreuzer *   the system error message.
140*04e0dc4aSTimo Kreuzer *
141*04e0dc4aSTimo Kreuzer *Entry:
142*04e0dc4aSTimo Kreuzer *   TCHAR * buffer - Destination buffer.
143*04e0dc4aSTimo Kreuzer *   size_t sizeInTChars - Size of the destination buffer.
144*04e0dc4aSTimo Kreuzer *   TCHAR * message - user's message to prefix system error message
145*04e0dc4aSTimo Kreuzer *
146*04e0dc4aSTimo Kreuzer *Exit:
147*04e0dc4aSTimo Kreuzer *   The error code.
148*04e0dc4aSTimo Kreuzer *
149*04e0dc4aSTimo Kreuzer *Exceptions:
150*04e0dc4aSTimo Kreuzer *   Input parameters are validated. Refer to the validation section of the function.
151*04e0dc4aSTimo Kreuzer *
152*04e0dc4aSTimo Kreuzer *******************************************************************************/
153*04e0dc4aSTimo Kreuzer 
154*04e0dc4aSTimo Kreuzer size_t const minimum_message_length = 5;
155*04e0dc4aSTimo Kreuzer 
156*04e0dc4aSTimo Kreuzer template <typename Character>
common_strerror_s(_Out_writes_z_ (buffer_count)Character * const buffer,size_t const buffer_count,Character const * const message)157*04e0dc4aSTimo Kreuzer static errno_t __cdecl common_strerror_s(
158*04e0dc4aSTimo Kreuzer     _Out_writes_z_(buffer_count)    Character*          const   buffer,
159*04e0dc4aSTimo Kreuzer                                     size_t              const   buffer_count,
160*04e0dc4aSTimo Kreuzer                                     Character const*    const   message
161*04e0dc4aSTimo Kreuzer     ) throw()
162*04e0dc4aSTimo Kreuzer {
163*04e0dc4aSTimo Kreuzer     using traits = __crt_char_traits<Character>;
164*04e0dc4aSTimo Kreuzer 
165*04e0dc4aSTimo Kreuzer     errno_t const original_errno_value = errno;
166*04e0dc4aSTimo Kreuzer 
167*04e0dc4aSTimo Kreuzer     _VALIDATE_RETURN_ERRCODE(buffer != nullptr, EINVAL);
168*04e0dc4aSTimo Kreuzer     _VALIDATE_RETURN_ERRCODE(buffer_count > 0,  EINVAL);
169*04e0dc4aSTimo Kreuzer     buffer[0] = '\0';
170*04e0dc4aSTimo Kreuzer 
171*04e0dc4aSTimo Kreuzer     if (message &&
172*04e0dc4aSTimo Kreuzer         message[0] != '\0' &&
173*04e0dc4aSTimo Kreuzer         traits::tcslen(message) < (buffer_count - 2 - minimum_message_length))
174*04e0dc4aSTimo Kreuzer     {
175*04e0dc4aSTimo Kreuzer         Character const colon[] = { ':', ' ', '\0' };
176*04e0dc4aSTimo Kreuzer         _ERRCHECK(traits::tcscpy_s(buffer, buffer_count, message));
177*04e0dc4aSTimo Kreuzer         _ERRCHECK(traits::tcscat_s(buffer, buffer_count, colon));
178*04e0dc4aSTimo Kreuzer     }
179*04e0dc4aSTimo Kreuzer 
180*04e0dc4aSTimo Kreuzer     // Append the error message at the end of the buffer:
181*04e0dc4aSTimo Kreuzer     return traits::tcserror_s(
182*04e0dc4aSTimo Kreuzer         buffer       + traits::tcslen(buffer),
183*04e0dc4aSTimo Kreuzer         buffer_count - traits::tcslen(buffer),
184*04e0dc4aSTimo Kreuzer         original_errno_value);
185*04e0dc4aSTimo Kreuzer }
186*04e0dc4aSTimo Kreuzer 
_strerror_s(char * const buffer,size_t const buffer_count,char const * const message)187*04e0dc4aSTimo Kreuzer extern "C" errno_t __cdecl _strerror_s(
188*04e0dc4aSTimo Kreuzer     char*       const buffer,
189*04e0dc4aSTimo Kreuzer     size_t      const buffer_count,
190*04e0dc4aSTimo Kreuzer     char const* const message
191*04e0dc4aSTimo Kreuzer     )
192*04e0dc4aSTimo Kreuzer {
193*04e0dc4aSTimo Kreuzer     return common_strerror_s(buffer, buffer_count, message);
194*04e0dc4aSTimo Kreuzer }
195*04e0dc4aSTimo Kreuzer 
__wcserror_s(wchar_t * const buffer,size_t const buffer_count,wchar_t const * const message)196*04e0dc4aSTimo Kreuzer extern "C" errno_t __cdecl __wcserror_s(
197*04e0dc4aSTimo Kreuzer     wchar_t*       const buffer,
198*04e0dc4aSTimo Kreuzer     size_t         const buffer_count,
199*04e0dc4aSTimo Kreuzer     wchar_t const* const message
200*04e0dc4aSTimo Kreuzer     )
201*04e0dc4aSTimo Kreuzer {
202*04e0dc4aSTimo Kreuzer     return common_strerror_s(buffer, buffer_count, message);
203*04e0dc4aSTimo Kreuzer }
204