support.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // -*- C++ -*-
  2. //===----------------------- support/win32/support.h ----------------------===//
  3. //
  4. // The LLVM Compiler Infrastructure
  5. //
  6. // This file is dual licensed under the MIT and the University of Illinois Open
  7. // Source Licenses. See LICENSE.TXT for details.
  8. //
  9. //===----------------------------------------------------------------------===//
  10. #include <cstdarg> // va_start, va_end
  11. #include <cstddef> // size_t
  12. #include <cstdlib> // malloc
  13. #include <cstdio> // vsprintf, vsnprintf
  14. #include <cstring> // strcpy, wcsncpy
  15. #include <cwchar> // mbstate_t
  16. // Some of these functions aren't standard or if they conform, the name does not.
  17. int asprintf(char **sptr, const char *__restrict format, ...)
  18. {
  19. va_list ap;
  20. va_start(ap, format);
  21. int result;
  22. result = vasprintf(sptr, format, ap);
  23. va_end(ap);
  24. return result;
  25. }
  26. // Like sprintf, but when return value >= 0 it returns
  27. // a pointer to a malloc'd string in *sptr.
  28. // If return >= 0, use free to delete *sptr.
  29. int vasprintf( char **sptr, const char *__restrict format, va_list ap )
  30. {
  31. *sptr = NULL;
  32. // Query the count required.
  33. int count = _vsnprintf( NULL, 0, format, ap );
  34. if (count < 0)
  35. return count;
  36. size_t buffer_size = static_cast<size_t>(count) + 1;
  37. char* p = static_cast<char*>(malloc(buffer_size));
  38. if ( ! p )
  39. return -1;
  40. // If we haven't used exactly what was required, something is wrong.
  41. // Maybe bug in vsnprintf. Report the error and return.
  42. if (_vsnprintf(p, buffer_size, format, ap) != count) {
  43. free(p);
  44. return -1;
  45. }
  46. // All good. This is returning memory to the caller not freeing it.
  47. *sptr = p;
  48. return count;
  49. }
  50. // Returns >= 0: the number of wide characters found in the
  51. // multi byte sequence src (of src_size_bytes), that fit in the buffer dst
  52. // (of max_dest_chars elements size). The count returned excludes the
  53. // null terminator. When dst is NULL, no characters are copied
  54. // and no "out" parameters are updated.
  55. // Returns (size_t) -1: an incomplete sequence encountered.
  56. // Leaves *src pointing the next character to convert or NULL
  57. // if a null character was converted from *src.
  58. size_t mbsnrtowcs( wchar_t *__restrict dst, const char **__restrict src,
  59. size_t src_size_bytes, size_t max_dest_chars, mbstate_t *__restrict ps )
  60. {
  61. const size_t terminated_sequence = static_cast<size_t>(0);
  62. //const size_t invalid_sequence = static_cast<size_t>(-1);
  63. const size_t incomplete_sequence = static_cast< size_t>(-2);
  64. size_t dest_converted = 0;
  65. size_t source_converted = 0;
  66. size_t source_remaining = src_size_bytes;
  67. size_t result = 0;
  68. bool have_result = false;
  69. while ( source_remaining ) {
  70. if ( dst && dest_converted >= max_dest_chars )
  71. break;
  72. // Converts one multi byte character.
  73. // if result > 0, it's the size in bytes of that character.
  74. // othewise if result is zero it indicates the null character has been found.
  75. // otherwise it's an error and errno may be set.
  76. size_t char_size = mbrtowc( dst ? dst + dest_converted : NULL, *src + source_converted, source_remaining, ps );
  77. // Don't do anything to change errno from here on.
  78. if ( char_size > 0 ) {
  79. source_remaining -= char_size;
  80. source_converted += char_size;
  81. ++dest_converted;
  82. continue;
  83. }
  84. result = char_size;
  85. have_result = true;
  86. break;
  87. }
  88. if ( dst ) {
  89. if ( have_result && result == terminated_sequence )
  90. *src = NULL;
  91. else
  92. *src += source_converted;
  93. }
  94. if ( have_result && result != terminated_sequence && result != incomplete_sequence )
  95. return static_cast<size_t>(-1);
  96. return dest_converted;
  97. }
  98. // Converts max_source_chars from the wide character buffer pointer to by *src,
  99. // into the multi byte character sequence buffer stored at dst which must be
  100. // dst_size_bytes bytes in size.
  101. // Returns >= 0: the number of bytes in the sequence
  102. // converted from *src, excluding the null terminator.
  103. // Returns size_t(-1) if an error occurs, also sets errno.
  104. // If dst is NULL dst_size_bytes is ignored and no bytes are copied to dst
  105. // and no "out" parameters are updated.
  106. size_t wcsnrtombs( char *__restrict dst, const wchar_t **__restrict src,
  107. size_t max_source_chars, size_t dst_size_bytes, mbstate_t *__restrict ps )
  108. {
  109. //const size_t invalid_sequence = static_cast<size_t>(-1);
  110. size_t source_converted = 0;
  111. size_t dest_converted = 0;
  112. size_t dest_remaining = dst_size_bytes;
  113. size_t char_size = 0;
  114. const errno_t no_error = ( errno_t) 0;
  115. errno_t result = ( errno_t ) 0;
  116. bool have_result = false;
  117. bool terminator_found = false;
  118. while ( source_converted != max_source_chars ) {
  119. if ( ! dest_remaining )
  120. break;
  121. wchar_t c = (*src)[source_converted];
  122. if ( dst )
  123. result = wcrtomb_s( &char_size, dst + dest_converted, dest_remaining, c, ps);
  124. else
  125. result = wcrtomb_s( &char_size, NULL, 0, c, ps);
  126. // If result is zero there is no error and char_size contains the
  127. // size of the multi-byte-sequence converted.
  128. // Otherwise result indicates an errno type error.
  129. if ( result == no_error ) {
  130. if ( c == L'\0' ) {
  131. terminator_found = true;
  132. break;
  133. }
  134. ++source_converted;
  135. if ( dst )
  136. dest_remaining -= char_size;
  137. dest_converted += char_size;
  138. continue;
  139. }
  140. have_result = true;
  141. break;
  142. }
  143. if ( dst ) {
  144. if ( terminator_found )
  145. *src = NULL;
  146. else
  147. *src = *src + source_converted;
  148. }
  149. if ( have_result && result != no_error ) {
  150. errno = result;
  151. return static_cast<size_t>(-1);
  152. }
  153. return dest_converted;
  154. }