xref: /reactos/sdk/lib/ucrt/conio/putch.cpp (revision fe93a3f9)
1 //
2 // putch.cpp
3 //
4 //      Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // Defines _putch(), which writes a character to the console.
7 //
8 #include <conio.h>
9 #include <corecrt_internal_lowio.h>
10 #include <corecrt_internal_mbstring.h>
11 #include <corecrt_internal_stdio.h>
12 #include <corecrt_internal_ptd_propagation.h>
13 #include <stdlib.h>
14 
15 // Writes a wide character to the console.  Returns the character on success,
16 // EOF on failure.
17 extern "C" int __cdecl _putch(int const c)
18 {
19     return __acrt_lock_and_call(__acrt_conio_lock, [&]
20     {
21         return _putch_nolock(c);
22     });
23 }
24 
25 extern "C" int __cdecl _putch_nolock_internal(int const c, __crt_cached_ptd_host& ptd)
26 {
27     __acrt_ptd*     const raw_ptd      = ptd.get_raw_ptd();
28     unsigned char*  const ch_buf       = raw_ptd->_putch_buffer;
29     unsigned short* const pch_buf_used = &raw_ptd->_putch_buffer_used;
30 
31     // We can only use the character directly if we are sure that the machine
32     // is big-endian.
33     int result = c;
34 
35     // Why are we using putwch to write to Console when we could have
36     // written straight away to Console? The problem we have in writing to
37     // Console is that CRT codepage is different from Console codepage and
38     // thus to write to console, we will need to convert the codepage. Here
39     // we can use unicode version of these routines and this way we will
40     // only have to do one conversion and rest will be handled by putwch.
41 
42     // The usual way people call putch is character by character. Also
43     // there is no way we can convert partial MBCS to unicode character. To
44     // address this issue, we buffer all the lead bytes and combine them
45     // with trail bytes and then do the conversion.
46     if (*pch_buf_used == 1)
47     {
48         _ASSERTE(isleadbyte(ch_buf[0]) != 0);
49 
50         ch_buf[1] = static_cast<unsigned char>(c);
51     }
52     else
53     {
54         ch_buf[0] = static_cast<unsigned char>(c);
55     }
56 
57     if (*pch_buf_used == 0 && isleadbyte(ch_buf[0]))
58     {
59         // We still need trail byte, wait for it.
60         *pch_buf_used = 1;
61     }
62     else
63     {
64         wchar_t wchar;
65         if (_mbtowc_internal(&wchar, reinterpret_cast<char const*>(ch_buf), *pch_buf_used + 1, ptd) == -1 ||
66             _putwch_nolock(wchar) == WEOF)
67         {
68             result = EOF;
69         }
70 
71         // Since we have processed full MBCS character, we should reset ch_buf_used.
72         *pch_buf_used = 0;
73     }
74 
75     return result;
76 }
77 
78 extern "C" int __cdecl _putch_nolock(int const c)
79 {
80      __crt_cached_ptd_host ptd;
81      return _putch_nolock_internal(c, ptd);
82 }
83