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