xref: /reactos/sdk/lib/ucrt/stdio/output.cpp (revision e3e520d1)
1 //
2 // output.cpp
3 //
4 //      Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // The standard _output functions, which perform formatted output to a stream.
7 //
8 #include <corecrt_internal_stdio_output.h>
9 
10 
11 
12 using namespace __crt_stdio_output;
13 
14 
15 // Enclaves do not have a file system, but they do allow in-memory operations
16 // from stdio.
17 #ifndef _UCRT_ENCLAVE_BUILD
18 
19 template <template <typename, typename> class Base, typename Character>
20 static int __cdecl common_vfprintf(
21     unsigned __int64   const options,
22     FILE*              const stream,
23     Character const*   const format,
24     __crt_cached_ptd_host&   ptd,
25     va_list            const arglist
26     ) throw()
27 {
28     typedef output_processor<
29         Character,
30         stream_output_adapter<Character>,
31         Base<Character, stream_output_adapter<Character>>
32     > processor_type;
33 
34     _UCRT_VALIDATE_RETURN(ptd, stream != nullptr, EINVAL, -1);
35     _UCRT_VALIDATE_RETURN(ptd, format != nullptr, EINVAL, -1);
36 
37     return __acrt_lock_stream_and_call(stream, [&]() -> int
38     {
39         __acrt_stdio_temporary_buffering_guard const buffering(stream, ptd);
40 
41         processor_type processor(
42             stream_output_adapter<Character>(stream),
43             options,
44             format,
45             ptd,
46             arglist);
47 
48         return processor.process();
49     });
50 }
51 
52 extern "C" int __cdecl __stdio_common_vfprintf(
53     unsigned __int64 const options,
54     FILE*            const stream,
55     char const*      const format,
56     _locale_t        const locale,
57     va_list          const arglist
58     )
59 {
60     __crt_cached_ptd_host ptd(locale);
61     return common_vfprintf<standard_base>(options, stream, format, ptd, arglist);
62 }
63 
64 extern "C" int __cdecl __stdio_common_vfwprintf(
65     unsigned __int64 const options,
66     FILE*            const stream,
67     wchar_t const*   const format,
68     _locale_t        const locale,
69     va_list          const arglist
70     )
71 {
72     __crt_cached_ptd_host ptd(locale);
73     return common_vfprintf<standard_base>(options, stream, format, ptd, arglist);
74 }
75 
76 extern "C" int __cdecl __stdio_common_vfprintf_s(
77     unsigned __int64 const options,
78     FILE*            const stream,
79     char const*      const format,
80     _locale_t        const locale,
81     va_list          const arglist
82     )
83 {
84     __crt_cached_ptd_host ptd(locale);
85     return common_vfprintf<format_validation_base>(options, stream, format, ptd, arglist);
86 }
87 
88 extern "C" int __cdecl __stdio_common_vfwprintf_s(
89     unsigned __int64 const options,
90     FILE*            const stream,
91     wchar_t const*   const format,
92     _locale_t        const locale,
93     va_list          const arglist
94     )
95 {
96     __crt_cached_ptd_host ptd(locale);
97     return common_vfprintf<format_validation_base>(options, stream, format, ptd, arglist);
98 }
99 
100 extern "C" int __cdecl __stdio_common_vfprintf_p(
101     unsigned __int64 const options,
102     FILE*            const stream,
103     char const*      const format,
104     _locale_t        const locale,
105     va_list          const arglist
106     )
107 {
108     __crt_cached_ptd_host ptd(locale);
109     return common_vfprintf<positional_parameter_base>(options, stream, format, ptd, arglist);
110 }
111 
112 extern "C" int __cdecl __stdio_common_vfwprintf_p(
113     unsigned __int64 const options,
114     FILE*            const stream,
115     wchar_t const*   const format,
116     _locale_t        const locale,
117     va_list          const arglist
118     )
119 {
120     __crt_cached_ptd_host ptd(locale);
121     return common_vfprintf<positional_parameter_base>(options, stream, format, ptd, arglist);
122 }
123 
124 #endif /* _UCRT_ENCLAVE_BUILD */
125 
126 
127 template <template <typename, typename> class Base, typename Character>
128 _Success_(return >= 0)
129 static int __cdecl common_vsprintf(
130                                     unsigned __int64   const options,
131     _Out_writes_z_(buffer_count)    Character*         const buffer,
132                                     size_t             const buffer_count,
133                                     Character const*   const format,
134                                     __crt_cached_ptd_host&   ptd,
135                                     va_list            const arglist
136     ) throw()
137 {
138     typedef __acrt_stdio_char_traits<Character> char_traits;
139 
140     typedef output_processor<
141         Character,
142         string_output_adapter<Character>,
143         Base<Character, string_output_adapter<Character>>
144     > processor_type;
145 
146     _UCRT_VALIDATE_RETURN(ptd, format != nullptr,                      EINVAL, -1);
147     _UCRT_VALIDATE_RETURN(ptd, buffer_count == 0 || buffer != nullptr, EINVAL, -1);
148 
149     string_output_adapter_context<Character> context{};
150     context._buffer         = buffer;
151     context._buffer_count   = buffer_count;
152     context._buffer_used    = 0;
153 
154     // For the C Standard snprintf functions, we continue formatting even after
155     // the buffer is full so that we can return the number of characters that
156     // are required to complete the format operation.  For all other sprintf
157     // functions that have a buffer count, if no buffer was provided then we
158     // do the same.
159     context._continue_count =
160         (options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR) != 0 ||
161         buffer == nullptr;
162 
163     processor_type processor(
164         string_output_adapter<Character>(&context),
165         options,
166         format,
167         ptd,
168         arglist);
169 
170     int const result = processor.process();
171 
172     if (buffer == nullptr)
173     {
174         return result;
175     }
176 
177     // Otherwise, we formatted data into the buffer and need to terminate it:
178     if (options & _CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION)
179     {
180         if (buffer_count == 0 && result != 0)
181         {
182             return -1;
183         }
184         else if (context._buffer_used != buffer_count)
185         {
186             buffer[context._buffer_used] = '\0';
187         }
188         else if (result >= 0 && static_cast<size_t>(result) > buffer_count)
189         {
190             return -1;
191         }
192     }
193     else if (options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR)
194     {
195         if (buffer_count == 0)
196         {
197             // No-op
198         }
199         else if (result < 0)
200         {
201             buffer[0] = '\0';
202         }
203         else if (context._buffer_used == buffer_count)
204         {
205             buffer[buffer_count - 1] = '\0';
206         }
207         else
208         {
209             buffer[context._buffer_used] = '\0';
210         }
211     }
212     else
213     {
214         if (buffer_count == 0)
215         {
216             return -1;
217         }
218         else if (context._buffer_used == buffer_count)
219         {
220             buffer[buffer_count - 1] = '\0';
221             return -2;
222         }
223         else
224         {
225             buffer[context._buffer_used] = '\0';
226         }
227     }
228 
229 #pragma warning(suppress:__WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION) // 26036 needs work
230     return result;
231 }
232 
233 extern "C" int __cdecl __stdio_common_vsprintf(
234     unsigned __int64 const options,
235     char*            const buffer,
236     size_t           const buffer_count,
237     char const*      const format,
238     _locale_t        const locale,
239     va_list          const arglist
240     )
241 {
242     __crt_cached_ptd_host ptd(locale);
243     return common_vsprintf<standard_base>(options, buffer, buffer_count, format, ptd, arglist);
244 }
245 
246 extern "C" int __cdecl __stdio_common_vswprintf(
247     unsigned __int64 const options,
248     wchar_t*         const buffer,
249     size_t           const buffer_count,
250     wchar_t const*   const format,
251     _locale_t        const locale,
252     va_list          const arglist
253     )
254 {
255     __crt_cached_ptd_host ptd(locale);
256     return common_vsprintf<standard_base>(options, buffer, buffer_count, format, ptd, arglist);
257 }
258 
259 template <typename Character>
260 _Success_(return >= 0)
261 static int __cdecl common_vsprintf_s(
262                                     unsigned __int64   const options,
263     _Out_writes_z_(buffer_count)    Character*         const buffer,
264                                     size_t             const buffer_count,
265                                     Character const*   const format,
266                                     __crt_cached_ptd_host&   ptd,
267                                     va_list            const arglist
268     ) throw()
269 {
270     _UCRT_VALIDATE_RETURN(ptd, format != nullptr,                     EINVAL, -1);
271     _UCRT_VALIDATE_RETURN(ptd, buffer != nullptr && buffer_count > 0, EINVAL, -1);
272 
273     int const result = common_vsprintf<format_validation_base>(options, buffer, buffer_count, format, ptd, arglist);
274     if (result < 0)
275     {
276         buffer[0] = 0;
277         _SECURECRT__FILL_STRING(buffer, buffer_count, 1);
278     }
279 
280     if (result == -2)
281     {
282         _UCRT_VALIDATE_RETURN(ptd, ("Buffer too small", 0), ERANGE, -1);
283     }
284     else if (result >= 0)
285     {
286         _SECURECRT__FILL_STRING(buffer, buffer_count, result + 1);
287     }
288 
289     return result;
290 }
291 
292 extern "C" int __cdecl __stdio_common_vsprintf_s(
293     unsigned __int64 const options,
294     char*            const buffer,
295     size_t           const buffer_count,
296     char const*      const format,
297     _locale_t        const locale,
298     va_list          const arglist
299     )
300 {
301     __crt_cached_ptd_host ptd(locale);
302     return common_vsprintf_s(options, buffer, buffer_count, format, ptd, arglist);
303 }
304 
305 extern "C" int __cdecl __stdio_common_vswprintf_s(
306     unsigned __int64 const options,
307     wchar_t*         const buffer,
308     size_t           const buffer_count,
309     wchar_t const*   const format,
310     _locale_t        const locale,
311     va_list          const arglist
312     )
313 {
314     __crt_cached_ptd_host ptd(locale);
315     return common_vsprintf_s(options, buffer, buffer_count, format, ptd, arglist);
316 }
317 
318 template <typename Character>
319 _Success_(return >= 0)
320 static int __cdecl common_vsnprintf_s(
321                                     unsigned __int64   const options,
322     _Out_writes_z_(buffer_count)    Character*         const buffer,
323                                     size_t             const buffer_count,
324                                     size_t             const max_count,
325                                     Character const*   const format,
326                                     __crt_cached_ptd_host&   ptd,
327                                     va_list            const arglist
328     ) throw()
329 {
330     _UCRT_VALIDATE_RETURN(ptd, format != nullptr, EINVAL, -1);
331 
332     if (max_count == 0 && buffer == nullptr && buffer_count == 0)
333         return 0; // No work to do
334 
335     _UCRT_VALIDATE_RETURN(ptd, buffer != nullptr && buffer_count > 0, EINVAL, -1);
336 
337     int result = -1;
338     {
339         auto errno_restore_point = ptd.get_errno().create_guard();
340         errno_restore_point.disable();
341 
342         if (buffer_count > max_count)
343         {
344             result = common_vsprintf<format_validation_base>(options, buffer, max_count + 1, format, ptd, arglist);
345 
346             if (result == -2)
347             {
348                 // The string has been truncated; return -1:
349                 _SECURECRT__FILL_STRING(buffer, buffer_count, max_count + 1);
350                 if (ptd.get_errno().check(ERANGE))
351                 {
352                     errno_restore_point.enable();
353                 }
354 
355                 return -1;
356             }
357         }
358         else
359         {
360             result = common_vsprintf<format_validation_base>(options, buffer, buffer_count, format, ptd, arglist);
361             buffer[buffer_count - 1] = 0;
362 
363             // We allow truncation if count == _TRUNCATE
364             if (result == -2 && max_count == _TRUNCATE)
365             {
366                 if (ptd.get_errno().check(ERANGE))
367                 {
368                     errno_restore_point.enable();
369                 }
370 
371                 return -1;
372             }
373         }
374     }
375 
376     if (result < 0)
377     {
378         buffer[0] = 0;
379         _SECURECRT__FILL_STRING(buffer, buffer_count, 1);
380         if (result == -2)
381         {
382             _UCRT_VALIDATE_RETURN(ptd, ("Buffer too small", 0), ERANGE, -1);
383         }
384 
385         return -1;
386     }
387 
388     _SECURECRT__FILL_STRING(buffer, buffer_count, result + 1);
389 
390     return result < 0 ? -1 : result;
391 }
392 
393 extern "C" int __cdecl __stdio_common_vsnprintf_s(
394     unsigned __int64 const options,
395     char*            const buffer,
396     size_t           const buffer_count,
397     size_t           const max_count,
398     char const*      const format,
399     _locale_t        const locale,
400     va_list          const arglist
401     )
402 {
403     __crt_cached_ptd_host ptd(locale);
404     return common_vsnprintf_s(options, buffer, buffer_count, max_count, format, ptd, arglist);
405 }
406 
407 extern "C" int __cdecl __stdio_common_vsnwprintf_s(
408     unsigned __int64 const options,
409     wchar_t*         const buffer,
410     size_t           const buffer_count,
411     size_t           const max_count,
412     wchar_t const*   const format,
413     _locale_t        const locale,
414     va_list          const arglist
415     )
416 {
417     __crt_cached_ptd_host ptd(locale);
418     return common_vsnprintf_s(options, buffer, buffer_count, max_count, format, ptd, arglist);
419 }
420 
421 extern "C" int __cdecl __stdio_common_vsprintf_p(
422     unsigned __int64 const options,
423     char*            const buffer,
424     size_t           const buffer_count,
425     char const*      const format,
426     _locale_t        const locale,
427     va_list          const arglist
428     )
429 {
430     __crt_cached_ptd_host ptd(locale);
431     return common_vsprintf<positional_parameter_base>(options, buffer, buffer_count, format, ptd, arglist);
432 }
433 
434 extern "C" int __cdecl __stdio_common_vswprintf_p(
435     unsigned __int64 const options,
436     wchar_t*         const buffer,
437     size_t           const buffer_count,
438     wchar_t const*   const format,
439     _locale_t        const locale,
440     va_list          const arglist
441     )
442 {
443     __crt_cached_ptd_host ptd(locale);
444     return common_vsprintf<positional_parameter_base>(options, buffer, buffer_count, format, ptd, arglist);
445 }
446