ReactOS 0.4.16-dev-927-g467dec4
write.cpp File Reference
#include <corecrt_internal_lowio.h>
#include <corecrt_internal_mbstring.h>
#include <corecrt_internal_ptd_propagation.h>
#include <ctype.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
Include dependency graph for write.cpp:

Go to the source code of this file.

Classes

struct  anonymous_namespace{write.cpp}::write_result
 

Namespaces

namespace  anonymous_namespace{write.cpp}
 

Functions

int __cdecl _write_internal (int const fh, void const *const buffer, unsigned const size, __crt_cached_ptd_host &ptd)
 
int __cdecl _write (int const fh, void const *const buffer, unsigned const size)
 
static bool __cdecl write_requires_double_translation_nolock (int const fh, __crt_cached_ptd_host &ptd) throw ()
 
static write_result __cdecl write_double_translated_ansi_nolock (int const fh, _In_reads_(buffer_size) char const *const buffer, unsigned const buffer_size, __crt_cached_ptd_host &ptd) throw ()
 
static write_result __cdecl write_double_translated_unicode_nolock (_In_reads_(buffer_size) char const *const buffer, _In_ _Pre_satisfies_((buffer_size % 2)==0) unsigned const buffer_size) throw ()
 
static write_result __cdecl write_text_ansi_nolock (int const fh, _In_reads_(buffer_size) char const *const buffer, unsigned const buffer_size) throw ()
 
static write_result __cdecl write_text_utf16le_nolock (int const fh, _In_reads_(buffer_size) char const *const buffer, unsigned const buffer_size) throw ()
 
static write_result __cdecl write_text_utf8_nolock (int const fh, _In_reads_(buffer_size) char const *const buffer, unsigned const buffer_size) throw ()
 
static write_result __cdecl write_binary_nolock (int const fh, _In_reads_(buffer_size) char const *const buffer, unsigned const buffer_size) throw ()
 
int __cdecl _write_nolock (int const fh, void const *const buffer, unsigned const buffer_size, __crt_cached_ptd_host &ptd)
 

Variables

static size_t const BUF_SIZE = 5 * 1024
 

Function Documentation

◆ _write()

int __cdecl _write ( int const  fh,
void const *const  buffer,
unsigned const  size 
)

Definition at line 75 of file write.cpp.

76{
77 __crt_cached_ptd_host ptd;
78 return _write_internal(fh, buffer, size, ptd);
79}
_In_ size_t const _In_ int _In_ bool const _In_ unsigned const _In_ __acrt_rounding_mode const _Inout_ __crt_cached_ptd_host & ptd
Definition: cvt.cpp:355
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
int __cdecl _write_internal(int const fh, void const *const buffer, unsigned const size, __crt_cached_ptd_host &ptd)
Definition: write.cpp:47

◆ _write_internal()

int __cdecl _write_internal ( int const  fh,
void const *const  buffer,
unsigned const  size,
__crt_cached_ptd_host &  ptd 
)

Definition at line 47 of file write.cpp.

48{
50 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, (fh >= 0 && (unsigned)fh < (unsigned)_nhandle), EBADF, -1);
52
54 int result = -1;
55 __try
56 {
57 if ((_osfile(fh) & FOPEN) == 0)
58 {
59 ptd.get_errno().set(EBADF);
60 ptd.get_doserrno().set(0);
61 _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0));
62 __leave;
63 }
64
66 }
68 {
70 }
72 return result;
73}
#define EBADF
Definition: acclib.h:82
int _nhandle
Definition: ioinit.cpp:34
void __cdecl __acrt_lowio_lock_fh(_In_ int _FileHandle)
void __cdecl __acrt_lowio_unlock_fh(_In_ int _FileHandle)
#define _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, expr, errorcode, retexpr)
#define _UCRT_CHECK_FH_CLEAR_OSSERR_RETURN(ptd, handle, errorcode, retexpr)
#define _ASSERTE(expr)
Definition: crtdbg.h:114
#define FOPEN
GLuint64EXT * result
Definition: glext.h:11304
#define __try
Definition: pseh2_64.h:188
#define __leave
Definition: pseh2_64.h:192
#define __endtry
Definition: pseh2_64.h:191
#define __finally
Definition: pseh2_64.h:190
#define _osfile(i)
Definition: internal.h:72
int __cdecl _write_nolock(int const fh, void const *const buffer, unsigned const buffer_size, __crt_cached_ptd_host &ptd)
Definition: write.cpp:644

Referenced by _write().

◆ _write_nolock()

int __cdecl _write_nolock ( int const  fh,
void const *const  buffer,
unsigned const  buffer_size,
__crt_cached_ptd_host &  ptd 
)

Definition at line 644 of file write.cpp.

645{
646 // If the buffer is empty, there is nothing to be written:
647 if (buffer_size == 0)
648 {
649 return 0;
650 }
651
652 // If the buffer is null, though... well, that is not allowed:
654
655 __crt_lowio_text_mode const fh_textmode = _textmode(fh);
656
657 // If the file is open for Unicode, the buffer size must always be even:
658 if (fh_textmode == __crt_lowio_text_mode::utf16le || fh_textmode == __crt_lowio_text_mode::utf8)
659 {
661 }
662
663 // If the file is opened for appending, seek to the end of the file. We
664 // ignore errors because the underlying file may not allow seeking.
665 if (_osfile(fh) & FAPPEND)
666 {
668 }
669
670 char const* const char_buffer = static_cast<char const*>(buffer);
671
672 // Dispatch the actual writing to one of the helper routines based on the
673 // text mode of the file and whether or not the file refers to the console.
674 //
675 // Note that in the event that the handle belongs to the console, WriteFile
676 // will generate garbage output. To print to the console correctly, we need
677 // to print ANSI. Also note that when printing to the console, we need to
678 // convert the characters to the console codepge.
679 write_result result = { 0 };
681 {
682 switch (fh_textmode)
683 {
686 break;
687
690 _Analysis_assume_((buffer_size % 2) == 0);
692 break;
693 }
694 }
695 else if (_osfile(fh) & FTEXT)
696 {
697 switch (fh_textmode)
698 {
700 result = write_text_ansi_nolock(fh, char_buffer, buffer_size);
701 break;
702
704 result = write_text_utf16le_nolock(fh, char_buffer, buffer_size);
705 break;
706
708 result = write_text_utf8_nolock(fh, char_buffer, buffer_size);
709 break;
710 }
711 }
712 else
713 {
714 result = write_binary_nolock(fh, char_buffer, buffer_size);
715 }
716
717
718 // Why did we not write anything? Lettuce find out...
719 if (result.char_count == 0)
720 {
721 // If nothing was written, check to see if it was due to an OS error:
722 if (result.error_code != 0)
723 {
724 // An OS error occurred. ERROR_ACCESS_DENIED should be mapped in
725 // this case to EBADF, not EACCES. All other errors are mapped
726 // normally:
727 if (result.error_code == ERROR_ACCESS_DENIED)
728 {
729 ptd.get_errno().set(EBADF);
730 ptd.get_doserrno().set(result.error_code);
731 }
732 else
733 {
735 }
736
737 return -1;
738 }
739
740 // If this file is a device and the first character was Ctrl+Z, then
741 // writing nothing is the expected behavior and is not an error:
742 if ((_osfile(fh) & FDEV) && *char_buffer == CTRLZ)
743 {
744 return 0;
745 }
746
747 // Otherwise, the error is reported as ENOSPC:
748 ptd.get_errno().set(ENOSPC);
749 ptd.get_doserrno().set(0);
750 return -1;
751 }
752
753 // The write succeeded. Return the adjusted number of bytes written:
754 return result.char_count - result.lf_count;
755}
#define EINVAL
Definition: acclib.h:90
_Check_return_opt_ __int64 __cdecl _lseeki64_nolock_internal(_In_ int _FileHandle, _In_ __int64 _Offset, _In_ int _Origin, _Inout_ __crt_cached_ptd_host &_Ptd)
__crt_lowio_text_mode
#define CTRLZ
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
#define ENOSPC
Definition: errno.h:34
void __cdecl __acrt_errno_map_os_error_ptd(unsigned long const oserrno, __crt_cached_ptd_host &ptd)
Definition: errno.cpp:97
#define _Analysis_assume_
Definition: no_sal2.h:388
#define _textmode(i)
Definition: internal.h:74
static write_result __cdecl write_text_ansi_nolock(int const fh, _In_reads_(buffer_size) char const *const buffer, unsigned const buffer_size)
Definition: write.cpp:405
static write_result __cdecl write_text_utf16le_nolock(int const fh, _In_reads_(buffer_size) char const *const buffer, unsigned const buffer_size)
Definition: write.cpp:462
static bool __cdecl write_requires_double_translation_nolock(int const fh, __crt_cached_ptd_host &ptd)
Definition: write.cpp:81
static write_result __cdecl write_text_utf8_nolock(int const fh, _In_reads_(buffer_size) char const *const buffer, unsigned const buffer_size)
Definition: write.cpp:524
static write_result __cdecl write_double_translated_ansi_nolock(int const fh, _In_reads_(buffer_size) char const *const buffer, unsigned const buffer_size, __crt_cached_ptd_host &ptd)
Definition: write.cpp:118
static write_result __cdecl write_double_translated_unicode_nolock(_In_reads_(buffer_size) char const *const buffer, _In_ _Pre_satisfies_((buffer_size % 2)==0) unsigned const buffer_size)
Definition: write.cpp:353
static write_result __cdecl write_binary_nolock(int const fh, _In_reads_(buffer_size) char const *const buffer, unsigned const buffer_size)
Definition: write.cpp:624
wchar_t const *const size_t const buffer_size
Definition: stat.cpp:95
#define FILE_END
Definition: winbase.h:115
#define const
Definition: zconf.h:233

Referenced by _write_internal().

◆ write_binary_nolock()

static write_result __cdecl write_binary_nolock ( int const  fh,
_In_reads_(buffer_size) char const *const  buffer,
unsigned const  buffer_size 
)
throw (
)
static

Definition at line 624 of file write.cpp.

629{
630 HANDLE const os_handle = reinterpret_cast<HANDLE>(_osfhnd(fh));
631
632 // Compared to text files, binary files are easy...
633 write_result result = { 0 };
634 if (!WriteFile(os_handle, buffer, buffer_size, &result.char_count, nullptr))
635 {
636 result.error_code = GetLastError();
637 }
638
639 return result;
640}
#define _osfhnd(i)
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
DWORD WINAPI GetLastError(void)
Definition: except.c:1042

Referenced by _write_nolock().

◆ write_double_translated_ansi_nolock()

static write_result __cdecl write_double_translated_ansi_nolock ( int const  fh,
_In_reads_(buffer_size) char const *const  buffer,
unsigned const  buffer_size,
__crt_cached_ptd_host &  ptd 
)
throw (
)
static

Definition at line 118 of file write.cpp.

124{
125 HANDLE const os_handle = reinterpret_cast<HANDLE>(_osfhnd(fh));
126 char const* const buffer_end = buffer + buffer_size;
127 UINT const console_cp = GetConsoleOutputCP();
128 _locale_t const locale = ptd.get_locale();
129 bool const is_utf8 = locale->locinfo->_public._locale_lc_codepage == CP_UTF8;
130
131 write_result result = { 0 };
132
133 for (char const* source_it = buffer; source_it < buffer_end; )
134 {
135 char const c = *source_it;
136
137 // We require double conversion, to convert from the source multibyte
138 // to Unicode, then from Unicode back to multibyte, but in the console
139 // codepage.
140 //
141 // Here, we have to take into account that _write() might be called
142 // byte-by-byte, so when we see a lead byte without a trail byte, we
143 // have to store it and return no error. When this function is called
144 // again, that byte will be combined with the next available character.
145 wchar_t wc[2] = { 0 };
146 int wc_used = 1;
147 if (is_utf8)
148 {
150 const int mb_buf_size = sizeof(_mbBuffer(fh));
151 int mb_buf_used;
152 for (mb_buf_used = 0; mb_buf_used < mb_buf_size && _mbBuffer(fh)[mb_buf_used]; ++mb_buf_used)
153 {}
154
155 if (mb_buf_used > 0)
156 {
157 const int mb_len = _utf8_no_of_trailbytes(_mbBuffer(fh)[0]) + 1;
158 _ASSERTE(1 < mb_len && mb_buf_used < mb_len);
159 const int remaining_bytes = mb_len - mb_buf_used;
160 if (remaining_bytes <= (buffer_end - source_it))
161 {
162 // We now have enough bytes to complete the code point
163 char mb_buffer[MB_LEN_MAX];
164
165 for (int i = 0; i < mb_buf_used; ++i)
166 {
167 mb_buffer[i] = _mbBuffer(fh)[i];
168 }
169 for (int i = 0; i < remaining_bytes; ++i)
170 {
171 mb_buffer[i + mb_buf_used] = source_it[i];
172 }
173
174 // Clear out the temp buffer
175 for (int i = 0; i < mb_buf_used; ++i)
176 {
177 _mbBuffer(fh)[i] = 0;
178 }
179
181 const char* str = mb_buffer;
182 if (mb_len == 4)
183 {
184 wc_used = 2;
185 }
186 if (__crt_mbstring::__mbsrtowcs_utf8(wc, &str, wc_used, &state, ptd) == -1)
187 {
188 return result;
189 }
190 source_it += (remaining_bytes - 1);
191 }
192 else
193 {
194 // Need to add some more bytes to the buffer for later
195 const auto bytes_to_add = buffer_end - source_it;
196 _ASSERTE(mb_buf_used + bytes_to_add < mb_buf_size);
197 for (int i = 0; i < bytes_to_add; ++i)
198 {
199 _mbBuffer(fh)[i + mb_buf_used] = source_it[i];
200 }
201 // Pretend we wrote the bytes, because this isn't an error *yet*.
202 result.char_count += static_cast<DWORD>(bytes_to_add);
203 return result;
204 }
205 }
206 else
207 {
208 const int mb_len = _utf8_no_of_trailbytes(*source_it) + 1;
209 const auto available_bytes = buffer_end - source_it;
210 if (mb_len <= (available_bytes))
211 {
212 // We have enough bytes to write the entire code point
214 const char* str = source_it;
215 if (mb_len == 4)
216 {
217 wc_used = 2;
218 }
219 if (__crt_mbstring::__mbsrtowcs_utf8(wc, &str, wc_used, &state, ptd) == -1)
220 {
221 return result;
222 }
223 source_it += (mb_len - 1);
224 }
225 else
226 {
227 // Not enough bytes for this code point
228 _ASSERTE(available_bytes <= sizeof(_mbBuffer(fh)));
229 for (int i = 0; i < available_bytes; ++i)
230 {
231 _mbBuffer(fh)[i] = source_it[i];
232 }
233 // Pretend we wrote the bytes, because this isn't an error *yet*.
234 result.char_count += static_cast<DWORD>(available_bytes);
235 return result;
236 }
237 }
238 }
239 else if (_dbcsBufferUsed(fh))
240 {
241 // We already have a DBCS lead byte buffered. Take the current
242 // character, combine it with the lead byte, and convert:
244
245 char mb_buffer[MB_LEN_MAX];
246 mb_buffer[0] = _dbcsBuffer(fh);
247 mb_buffer[1] = *source_it;
248
249 _dbcsBufferUsed(fh) = false;
250
251 if (_mbtowc_internal(wc, mb_buffer, 2, ptd) == -1)
252 {
253 return result;
254 }
255 }
256 else
257 {
258 if (_isleadbyte_fast_internal(*source_it, locale))
259 {
260 if ((source_it + 1) < buffer_end)
261 {
262 // And we have more bytes to read, just convert...
263 if (_mbtowc_internal(wc, source_it, 2, ptd) == -1)
264 {
265 return result;
266 }
267
268 // Increment the source_it to accomodate the DBCS character:
269 ++source_it;
270 }
271 else
272 {
273 // And we ran out of bytes to read, so buffer the lead byte:
274 _dbcsBuffer(fh) = *source_it;
275 _dbcsBufferUsed(fh) = true;
276
277 // We lie here that we actually wrote the last character, to
278 // ensure we don't consider this an error:
279 ++result.char_count;
280 return result;
281 }
282 }
283 else
284 {
285 // single character conversion:
286 if (_mbtowc_internal(wc, source_it, 1, ptd) == -1)
287 {
288 return result;
289 }
290 }
291 }
292
293 ++source_it;
294
295 // Translate the Unicode character into Multibyte in the console codepage
296 // and write the character to the file:
297 char mb_buffer[MB_LEN_MAX];
298 DWORD const size = static_cast<DWORD>(__acrt_WideCharToMultiByte(
299 console_cp, 0, wc, wc_used, mb_buffer, sizeof(mb_buffer), nullptr, nullptr));
300
301 if(size == 0)
302 return result;
303
304 DWORD written;
305 if (!WriteFile(os_handle, mb_buffer, size, &written, nullptr))
306 {
307 result.error_code = GetLastError();
308 return result;
309 }
310
311 // When we are converting, some conversions may result in:
312 //
313 // 2 MBCS characters => 1 wide character => 1 MBCS character.
314 //
315 // For example, when printing Japanese characters in the English console
316 // codepage, each source character is transformed into a single question
317 // mark. Therefore, we want to track the number of bytes we converted,
318 // plus the linefeed count, instead of how many bytes we actually wrote.
319 result.char_count = result.lf_count + static_cast<DWORD>(source_it - buffer);
320
321 // If the write succeeded but didn't write all of the characters, return:
322 if (written < size)
323 {
324 return result;
325 }
326
327 // If the original character that we read was an LF, write a CR too:
328 // CRT_REFACTOR TODO Doesn't this write LFCR instead of CRLF?
329 if (c == LF)
330 {
331 wchar_t const cr = CR;
332 if (!WriteFile(os_handle, &cr, 1, &written, nullptr))
333 {
334 result.error_code = GetLastError();
335 return result;
336 }
337
338 if (written < 1)
339 {
340 return result;
341 }
342
343 ++result.lf_count;
344 ++result.char_count;
345 }
346 }
347
348 return result;
349}
return __acrt_WideCharToMultiByte(code_page, 0, buffer.get(), -1, result_size !=0 ? result :nullptr, result_size, nullptr, nullptr)
static int state
Definition: maze.c:121
Definition: _locale.h:75
_Check_return_ __forceinline unsigned short __cdecl _isleadbyte_fast_internal(_In_ unsigned char const c, _In_ _locale_t const locale)
#define _dbcsBufferUsed(i)
__inline char _utf8_no_of_trailbytes(const unsigned char c)
#define _mbBuffer(i)
#define _dbcsBuffer(i)
UINT WINAPI DECLSPEC_HOTPATCH GetConsoleOutputCP(VOID)
Definition: console.c:2451
unsigned long DWORD
Definition: ntddk_ex.h:95
const GLubyte * c
Definition: glext.h:8905
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static int is_utf8(const char *src)
Definition: icy2utf8.c:336
#define MB_LEN_MAX
Definition: stdlib.h:19
#define buffer_end
Definition: intsym.h:274
int __cdecl _mbtowc_internal(wchar_t *pwc, const char *s, size_t n, __crt_cached_ptd_host &ptd)
Definition: mbtowc.cpp:45
size_t __cdecl __mbsrtowcs_utf8(wchar_t *dst, const char **src, size_t len, mbstate_t *ps, __crt_cached_ptd_host &ptd)
unsigned int UINT
Definition: ndis.h:50
const WCHAR * str
#define CP_UTF8
Definition: nls.h:20
#define LF
Definition: telnetd.h:24
#define CR
Definition: telnetd.h:23

Referenced by _write_nolock().

◆ write_double_translated_unicode_nolock()

static write_result __cdecl write_double_translated_unicode_nolock ( _In_reads_(buffer_size) char const *const  buffer,
_In_ _Pre_satisfies_((buffer_size % 2)==0) unsigned const  buffer_size 
)
throw (
)
static

Definition at line 353 of file write.cpp.

357{
358 // When writing to a Unicode file (UTF-8 or UTF-16LE) that corresponds to
359 // the console, we don't actually need double translation. We just need to
360 // print each character to the console, one-by-one. (This function is
361 // named what it is because its use is guarded by the double translation
362 // check, and to match the name of the corresponding ANSI function.)
363
364 write_result result = { 0 };
365
366 // Needed for SAL to clarify that buffer_size is even.
368 char const* const buffer_end = buffer + buffer_size;
369 for (char const* pch = buffer; pch < buffer_end; pch += 2)
370 {
371 wchar_t const c = *reinterpret_cast<wchar_t const*>(pch);
372
373 // _putwch_nolock does not depend on global state, no PTD needed to be propagated.
374 if (_putwch_nolock(c) == c)
375 {
376 result.char_count += 2;
377 }
378 else
379 {
380 result.error_code = GetLastError();
381 return result;
382 }
383
384 // If the character was a carriage return, also emit a line feed.
385 // CRT_REFACTOR TODO Doesn't this print LFCR instead of CRLF?
386 if (c == LF)
387 {
388 // _putwch_nolock does not depend on global state, no PTD needed to be propagated.
389 if (_putwch_nolock(CR) != CR)
390 {
391 result.error_code = GetLastError();
392 return result;
393 }
394
395 ++result.char_count;
396 ++result.lf_count;
397 }
398 }
399
400 return result;
401}
#define c
Definition: ke_i.h:80
#define pch(ap)
Definition: match.c:418
_Check_return_opt_ _CRTIMP wint_t __cdecl _putwch_nolock(wchar_t _WCh)
Definition: putwch.cpp:22

Referenced by _write_nolock().

◆ write_requires_double_translation_nolock()

static bool __cdecl write_requires_double_translation_nolock ( int const  fh,
__crt_cached_ptd_host &  ptd 
)
throw (
)
static

Definition at line 81 of file write.cpp.

82{
83 // Double translation is required if both [a] the current locale is not the C
84 // locale or the file is open in a non-ANSI mode and [b] we are writing to the
85 // console.
86
87 // If this isn't a TTY or a text mode screen, then it isn't the console:
88 if (!_isatty(fh))
89 {
90 return false;
91 }
92
93 if ((_osfile(fh) & FTEXT) == 0) {
94 return false;
95 }
96
97 // Get the current locale. If we're in the C locale and the file is open
98 // in ANSI mode, we don't need double translation:
99 bool const is_c_locale = ptd.get_locale()->locinfo->locale_name[LC_CTYPE] == nullptr;
100 if (is_c_locale && _textmode(fh) == __crt_lowio_text_mode::ansi)
101 {
102 return false;
103 }
104
105 // If we can't get the console mode, it's not the console:
106 DWORD mode;
107 if (!GetConsoleMode(reinterpret_cast<HANDLE>(_osfhnd(fh)), &mode))
108 {
109 return false;
110 }
111
112 // Otherwise, double translation is required:
113 return true;
114}
BOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode)
Definition: console.c:1569
GLenum mode
Definition: glext.h:6217
#define LC_CTYPE
Definition: locale.h:19
_Check_return_ _CRTIMP int __cdecl _isatty(_In_ int _FileHandle)

Referenced by _write_nolock().

◆ write_text_ansi_nolock()

static write_result __cdecl write_text_ansi_nolock ( int const  fh,
_In_reads_(buffer_size) char const *const  buffer,
unsigned const  buffer_size 
)
throw (
)
static

Definition at line 405 of file write.cpp.

410{
411 HANDLE const os_handle = reinterpret_cast<HANDLE>(_osfhnd(fh));
412 char const* const buffer_end = buffer + buffer_size;
413
414 write_result result = { 0 };
415
416 for (char const* source_it = buffer; source_it < buffer_end; )
417 {
418 char lfbuf[BUF_SIZE]; // The LF => CRLF translation buffer
419
420 // One-past-the-end of the translation buffer. Note that we subtract
421 // one to account for the case where we're pointing to the last element
422 // in the buffer and we need to write both a CR and an LF.
423 char* const lfbuf_end = lfbuf + sizeof(lfbuf) - 1;
424
425 // Translate the source buffer into the translation buffer. Note that
426 // both source_it and lfbuf_it are incremented in the loop.
427 char* lfbuf_it = lfbuf;
428 while (lfbuf_it < lfbuf_end && source_it < buffer_end)
429 {
430 char const c = *source_it++;
431
432 if (c == LF)
433 {
434 ++result.lf_count;
435 *lfbuf_it++ = CR;
436 }
437
438 *lfbuf_it++ = c;
439 }
440
441 DWORD const lfbuf_length = static_cast<DWORD>(lfbuf_it - lfbuf);
442
443 DWORD written;
444 if (!WriteFile(os_handle, lfbuf, lfbuf_length, &written, nullptr))
445 {
446 result.error_code = GetLastError();
447 return result;
448 }
449
450 result.char_count += written;
451 if (written < lfbuf_length)
452 {
453 return result; // The write succeeded but didn't write everything
454 }
455 }
456
457 return result;
458}
static size_t const BUF_SIZE
Definition: write.cpp:34

Referenced by _write_nolock().

◆ write_text_utf16le_nolock()

static write_result __cdecl write_text_utf16le_nolock ( int const  fh,
_In_reads_(buffer_size) char const *const  buffer,
unsigned const  buffer_size 
)
throw (
)
static

Definition at line 462 of file write.cpp.

467{
468 HANDLE const os_handle = reinterpret_cast<HANDLE>(_osfhnd(fh));
469 wchar_t const* const buffer_end = reinterpret_cast<wchar_t const*>(buffer + buffer_size);
470
471 write_result result = { 0 };
472
473 wchar_t const* source_it = reinterpret_cast<wchar_t const*>(buffer);
474 while (source_it < buffer_end)
475 {
476 wchar_t lfbuf[BUF_SIZE / sizeof(wchar_t)]; // The translation buffer
477
478 // One-past-the-end of the translation buffer. Note that we subtract
479 // one to account for the case where we're pointing to the last element
480 // in the buffer and we need to write both a CR and an LF.
481 wchar_t const* lfbuf_end = lfbuf + BUF_SIZE / sizeof(wchar_t) - 1;
482
483 // Translate the source buffer into the translation buffer. Note that
484 // both source_it and lfbuf_it are incremented in the loop.
485 wchar_t* lfbuf_it = lfbuf;
486 while (lfbuf_it < lfbuf_end && source_it < buffer_end)
487 {
488 wchar_t const c = *source_it++;
489
490 if (c == LF)
491 {
492 result.lf_count += 2;
493 *lfbuf_it++ = CR;
494 }
495
496 *lfbuf_it++ = c;
497 }
498
499 // Note that this length is in bytes, not wchar_t elemnts, since we need
500 // to tell WriteFile how many bytes (not characters) to write:
501 DWORD const lfbuf_length = static_cast<DWORD>(lfbuf_it - lfbuf) * sizeof(wchar_t);
502
503
504 // Attempt the write and return immediately if it fails:
505 DWORD written;
506 if (!WriteFile(os_handle, lfbuf, lfbuf_length, &written, nullptr))
507 {
508 result.error_code = GetLastError();
509 return result;
510 }
511
512 result.char_count += written;
513 if (written < lfbuf_length)
514 {
515 return result; // The write succeeded, but didn't write everything
516 }
517 }
518
519 return result;
520}
#define wchar_t
Definition: wchar.h:102

Referenced by _write_nolock().

◆ write_text_utf8_nolock()

static write_result __cdecl write_text_utf8_nolock ( int const  fh,
_In_reads_(buffer_size) char const *const  buffer,
unsigned const  buffer_size 
)
throw (
)
static

Definition at line 524 of file write.cpp.

529{
530 HANDLE const os_handle = reinterpret_cast<HANDLE>(_osfhnd(fh));
531 wchar_t const* const buffer_end = reinterpret_cast<wchar_t const*>(buffer + buffer_size);
532
533 write_result result = { 0 };
534
535 wchar_t const* source_it = reinterpret_cast<wchar_t const*>(buffer);
536 while (source_it < buffer_end)
537 {
538 // The translation buffer. We use two buffers: the first is used to
539 // store the UTF-16 LF => CRLF translation (this is that buffer here).
540 // The second is used for storing the conversion to UTF-8 (defined
541 // below). The sizes are selected to handle the worst-case scenario
542 // where each UTF-8 character is four bytes long.
543 wchar_t utf16_buf[BUF_SIZE / 6];
544
545 // One-past-the-end of the translation buffer. Note that we subtract
546 // one to account for the case where we're pointing to the last element
547 // in the buffer and we need to write both a CR and an LF.
548 wchar_t const* utf16_buf_end = utf16_buf + (BUF_SIZE / 6 - 1);
549
550 // Translate the source buffer into the translation buffer. Note that
551 // both source_it and lfbuf_it are incremented in the loop.
552 wchar_t* utf16_buf_it = utf16_buf;
553 while (utf16_buf_it < utf16_buf_end && source_it < buffer_end)
554 {
555 wchar_t const c = *source_it++;
556
557 if (c == LF)
558 {
559 // No need to count the number of line-feeds translated; we
560 // track the number of written characters by counting the total
561 // number of characters written from the UTF8 buffer (see below
562 // where we update the char_count).
563 *utf16_buf_it++ = CR;
564 }
565
566 *utf16_buf_it++ = c;
567 }
568
569 // Note that this length is in characters, not bytes.
570 DWORD const utf16_buf_length = static_cast<DWORD>(utf16_buf_it - utf16_buf);
571
572
573 // This is the second translation, where we translate the UTF-16 text to
574 // UTF-8, into the UTF-8 buffer:
575 char utf8_buf[(BUF_SIZE * 2) / 3];
576 DWORD const bytes_converted = static_cast<DWORD>(__acrt_WideCharToMultiByte(
577 CP_UTF8,
578 0,
579 utf16_buf,
580 utf16_buf_length,
581 utf8_buf,
582 sizeof(utf8_buf),
583 nullptr,
584 nullptr));
585
586 if (bytes_converted == 0)
587 {
588 result.error_code = GetLastError();
589 return result;
590 }
591
592 // Here, we need to make every attempt to write all of the converted
593 // characters to avoid corrupting the stream. If, for example, we write
594 // only half of the bytes of a UTF-8 character, the stream may be
595 // corrupted.
596 //
597 // This loop will ensure that we exit only if either (a) all of the
598 // bytes are written, ensuring that no partial MBCSes are written, or
599 // (b) there is an error in the stream.
600 for (DWORD bytes_written = 0; bytes_written < bytes_converted; )
601 {
602 char const* const current = utf8_buf + bytes_written;
603 DWORD const current_size = bytes_converted - bytes_written;
604
605 DWORD written;
606 if (!WriteFile(os_handle, current, current_size, &written, nullptr))
607 {
608 result.error_code = GetLastError();
609 return result;
610 }
611
612 bytes_written += written;
613 }
614
615 // If this chunk was committed successfully, update the character count:
616 result.char_count = static_cast<DWORD>(reinterpret_cast<char const*>(source_it) - buffer);
617 }
618
619 return result;
620}
struct task_struct * current
Definition: linux.c:32

Referenced by _write_nolock().

Variable Documentation

◆ BUF_SIZE

size_t const BUF_SIZE = 5 * 1024
static