Reactos
1//
2// fputwc.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines the fputc() family of functions, which write a character to a stream.
7//
8#include <corecrt_internal_stdio.h>
9#include <corecrt_internal_mbstring.h>
10#include <corecrt_internal_ptd_propagation.h>
11
12
13
14static wint_t __cdecl fputwc_binary_nolock(wchar_t const c, __crt_stdio_stream const stream, __crt_cached_ptd_host& ptd) throw()
15{
16 stream->_cnt -= sizeof(wchar_t);
17
18 // If there is no room for the character in the buffer, flush the buffer and
19 // write the character:
20 if (stream->_cnt < 0)
21 {
22 return static_cast<wint_t>(__acrt_stdio_flush_and_write_wide_nolock(c, stream.public_stream(), ptd));
23 }
24
25 // Otherwise, there is sufficient room, so we can write directly to the buffer:
26 wchar_t*& wide_stream_ptr = reinterpret_cast<wchar_t*&>(stream->_ptr);
27 *wide_stream_ptr++ = c;
28
29 return c;
30}
31
32
33
34extern "C" wint_t __cdecl _fputwc_nolock_internal(wchar_t const c, FILE* const public_stream, __crt_cached_ptd_host& ptd)
35{
36 __crt_stdio_stream const stream(public_stream);
37
38 // If this stream is not file-backed, we can write the character directly:
39 if (stream.is_string_backed())
40 {
41 return fputwc_binary_nolock(c, stream, ptd);
42 }
43
44 __crt_lowio_text_mode const text_mode = _textmode_safe(_fileno(stream.public_stream()));
45
46 // If the file is open in a Unicode text mode, we can write the character
47 // directly to the stream:
48 if (text_mode == __crt_lowio_text_mode::utf16le || text_mode == __crt_lowio_text_mode::utf8)
49 {
50 return fputwc_binary_nolock(c, stream, ptd);
51 }
52
53 // If the file is open in binary mode, we can write the character directly
54 // to the stream:
55 if ((_osfile_safe(_fileno(stream.public_stream())) & FTEXT) == 0)
56 {
57 return fputwc_binary_nolock(c, stream, ptd);
58 }
59
60 // Otherwise, the file is open in ANSI text mode, and we need to translate
61 // the wide character to multibyte before we can write it:
62 char mbc[MB_LEN_MAX];
63
64 int size;
65 if (_wctomb_internal(&size, mbc, MB_LEN_MAX, c, ptd) != 0)
66 {
67 // If conversion failed, errno is set by wctomb_s and we return WEOF:
68 return WEOF;
69 }
70
71 // Write the character, byte-by-byte:
72 for (int i = 0; i < size; ++i)
73 {
74 if (_fputc_nolock_internal(mbc[i], stream.public_stream(), ptd) == EOF)
75 {
76 return WEOF;
77 }
78 }
79
80 return c;
81}
82
83extern "C" wint_t __cdecl _fputwc_nolock(wchar_t const c, FILE* const public_stream)
84{
85 __crt_cached_ptd_host ptd;
86 return _fputwc_nolock_internal(c, public_stream, ptd);
87}
88
89extern "C" wint_t __cdecl _putwc_nolock(wchar_t const c, FILE* const stream)
90{
91 return _fputwc_nolock(c, stream);
92}
93
94
95
96// Writes a wide character to a stream. Returns the wide character on success;
97// WEOF on failure.
98static wint_t __cdecl _fputwc_internal(wchar_t const c, FILE* const stream, __crt_cached_ptd_host& ptd)
99{
100 _UCRT_VALIDATE_RETURN(ptd, stream != nullptr, EINVAL, WEOF);
101
102 wint_t return_value = WEOF;
103
104 _lock_file(stream);
105 __try
106 {
107 return_value = _fputwc_nolock_internal(c, stream, ptd);
108 }
109 __finally
110 {
111 _unlock_file(stream);
112 }
113 __endtry
114
115 return return_value;
116}
117
118extern "C" wint_t __cdecl fputwc(wchar_t const c, FILE* const stream)
119{
120 __crt_cached_ptd_host ptd;
121 return _fputwc_internal(c, stream, ptd);
122}
123
124
125
126// Writes a wide character to a stream. See fputwc() for details.
127extern "C" wint_t __cdecl putwc(wchar_t const c, FILE* const stream)
128{
129 return fputwc(c, stream);
130}
131
132
133
134// Writes a wide character to stdout. See fputwc() for details.
135extern "C" wint_t __cdecl _fputwchar(wchar_t const c)
136{
137 return fputwc(c, stdout);
138}
139
140
141
142// Writes a wide character to stdout. See fputwc() for details.
143extern "C" wint_t __cdecl putwchar(wchar_t const c)
144{
145 return _fputwchar(c);
146}