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