xref: /reactos/sdk/lib/ucrt/stdio/fgetwc.cpp (revision fe11f7a2)
1 //
2 // fgetwc.cpp
3 //
4 //      Copyright (c) Microsoft Corporation.  All rights reserved.
5 //
6 // Functions that read the next wide character from a stream and return it.  If
7 // the read causes the stream to reach EOF, WEOF is returned and the EOF bit is
8 // set on the stream.
9 //
10 #include <corecrt_internal_stdio.h>
11 
12 
13 
14 extern "C" wint_t __cdecl _fgetwc_nolock(FILE* const public_stream)
15 {
16     __crt_stdio_stream const stream(public_stream);
17 
18     // If the stream is backed by a real file and is open in a Unicode text mode,
19     // we need to read two bytes (note that we read two bytes for both UTF-8 and
20     // UTF-16 backed streams, since lowio translates UTF-8 to UTF-16 when we read.
21     if (!stream.is_string_backed() &&
22         _textmode_safe(_fileno(stream.public_stream())) != __crt_lowio_text_mode::ansi)
23     {
24         wchar_t wc;
25 
26         // Compose the wide character by reading byte-by-byte from the stream:
27         char* const wc_first = reinterpret_cast<char*>(&wc);
28         char* const wc_last  = wc_first + sizeof(wc);
29 
30         for (char* it = wc_first; it != wc_last; ++it)
31         {
32             int const c = _getc_nolock(stream.public_stream());
33             if (c == EOF)
34                 return WEOF;
35 
36             *it = static_cast<char>(c);
37         }
38 
39         return wc;
40     }
41 
42     if (!stream.is_string_backed() &&
43         (_osfile_safe(_fileno(stream.public_stream())) & FTEXT))
44     {
45         int size = 1;
46         int ch;
47         char mbc[4];
48         wchar_t wch;
49 
50         /* text (multi-byte) mode */
51         if ((ch = _getc_nolock(stream.public_stream())) == EOF)
52             return WEOF;
53 
54         mbc[0] = static_cast<char>(ch);
55 
56         if (isleadbyte(static_cast<unsigned char>(mbc[0])))
57         {
58             if ((ch = _getc_nolock(stream.public_stream())) == EOF)
59             {
60                 ungetc(mbc[0], stream.public_stream());
61                 return WEOF;
62             }
63             mbc[1] = static_cast<char>(ch);
64             size = 2;
65         }
66 
67         if (mbtowc(&wch, mbc, size) == -1)
68         {
69             // Conversion failed! Set errno and return failure:
70             errno = EILSEQ;
71             return WEOF;
72         }
73 
74         return wch;
75     }
76 
77     // binary (Unicode) mode
78     if (stream->_cnt >= static_cast<int>(sizeof(wchar_t)))
79     {
80         stream->_cnt -= static_cast<int>(sizeof(wchar_t));
81         return *reinterpret_cast<wchar_t*&>(stream->_ptr)++;
82     }
83     else
84     {
85         return static_cast<wint_t>(__acrt_stdio_refill_and_read_wide_nolock(stream.public_stream()));
86     }
87 }
88 
89 
90 
91 extern "C" wint_t __cdecl _getwc_nolock(FILE* const stream)
92 {
93     return _fgetwc_nolock(stream);
94 }
95 
96 
97 
98 extern "C" wint_t __cdecl fgetwc(FILE* const stream)
99 {
100     _VALIDATE_RETURN(stream != nullptr, EINVAL, WEOF);
101 
102     wint_t return_value = 0;
103 
104     _lock_file(stream);
105     __try
106     {
107         return_value = _fgetwc_nolock(stream);
108     }
109     __finally
110     {
111         _unlock_file(stream);
112     }
113     __endtry
114 
115     return return_value;
116 }
117 
118 
119 
120 extern "C" wint_t __cdecl getwc(FILE* const stream)
121 {
122     return fgetwc(stream);
123 }
124 
125 
126 
127 extern "C" wint_t __cdecl _fgetwchar()
128 {
129     return fgetwc(stdin);
130 }
131 
132 
133 
134 extern "C" wint_t __cdecl getwchar()
135 {
136     return _fgetwchar();
137 }
138