IOStream.cxx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
  3. #include "kwsysPrivate.h"
  4. #include KWSYS_HEADER(Configure.hxx)
  5. // Include the streams library.
  6. #include <iostream>
  7. #include KWSYS_HEADER(IOStream.hxx)
  8. // Work-around CMake dependency scanning limitation. This must
  9. // duplicate the above list of headers.
  10. #if 0
  11. #include "Configure.hxx.in"
  12. #include "IOStream.hxx.in"
  13. #endif
  14. // Implement the rest of this file only if it is needed.
  15. #if KWSYS_IOS_NEED_OPERATORS_LL
  16. #include <stdio.h> // sscanf, sprintf
  17. #include <string.h> // memchr
  18. #if defined(_MAX_INT_DIG)
  19. #define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG
  20. #else
  21. #define KWSYS_IOS_INT64_MAX_DIG 32
  22. #endif
  23. namespace KWSYS_NAMESPACE {
  24. // Scan an input stream for an integer value.
  25. static int IOStreamScanStream(std::istream& is, char* buffer)
  26. {
  27. // Prepare to write to buffer.
  28. char* out = buffer;
  29. char* end = buffer + KWSYS_IOS_INT64_MAX_DIG - 1;
  30. // Look for leading sign.
  31. if (is.peek() == '+') {
  32. *out++ = '+';
  33. is.ignore();
  34. } else if (is.peek() == '-') {
  35. *out++ = '-';
  36. is.ignore();
  37. }
  38. // Determine the base. If not specified in the stream, try to
  39. // detect it from the input. A leading 0x means hex, and a leading
  40. // 0 alone means octal.
  41. int base = 0;
  42. int flags = is.flags() & std::ios_base::basefield;
  43. if (flags == std::ios_base::oct) {
  44. base = 8;
  45. } else if (flags == std::ios_base::dec) {
  46. base = 10;
  47. } else if (flags == std::ios_base::hex) {
  48. base = 16;
  49. }
  50. bool foundDigit = false;
  51. bool foundNonZero = false;
  52. if (is.peek() == '0') {
  53. foundDigit = true;
  54. is.ignore();
  55. if ((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16)) {
  56. base = 16;
  57. foundDigit = false;
  58. is.ignore();
  59. } else if (base == 0) {
  60. base = 8;
  61. }
  62. }
  63. // Determine the range of digits allowed for this number.
  64. const char* digits = "0123456789abcdefABCDEF";
  65. int maxDigitIndex = 10;
  66. if (base == 8) {
  67. maxDigitIndex = 8;
  68. } else if (base == 16) {
  69. maxDigitIndex = 10 + 6 + 6;
  70. }
  71. // Scan until an invalid digit is found.
  72. for (; is.peek() != EOF; is.ignore()) {
  73. if (memchr(digits, *out = (char)is.peek(), maxDigitIndex) != 0) {
  74. if ((foundNonZero || *out != '0') && out < end) {
  75. ++out;
  76. foundNonZero = true;
  77. }
  78. foundDigit = true;
  79. } else {
  80. break;
  81. }
  82. }
  83. // Correct the buffer contents for degenerate cases.
  84. if (foundDigit && !foundNonZero) {
  85. *out++ = '0';
  86. } else if (!foundDigit) {
  87. out = buffer;
  88. }
  89. // Terminate the string in the buffer.
  90. *out = '\0';
  91. return base;
  92. }
  93. // Read an integer value from an input stream.
  94. template <class T>
  95. std::istream& IOStreamScanTemplate(std::istream& is, T& value, char type)
  96. {
  97. int state = std::ios_base::goodbit;
  98. // Skip leading whitespace.
  99. std::istream::sentry okay(is);
  100. if (okay) {
  101. try {
  102. // Copy the string to a buffer and construct the format string.
  103. char buffer[KWSYS_IOS_INT64_MAX_DIG];
  104. #if defined(_MSC_VER)
  105. char format[] = "%I64_";
  106. const int typeIndex = 4;
  107. #else
  108. char format[] = "%ll_";
  109. const int typeIndex = 3;
  110. #endif
  111. switch (IOStreamScanStream(is, buffer)) {
  112. case 8:
  113. format[typeIndex] = 'o';
  114. break;
  115. case 0: // Default to decimal if not told otherwise.
  116. case 10:
  117. format[typeIndex] = type;
  118. break;
  119. case 16:
  120. format[typeIndex] = 'x';
  121. break;
  122. };
  123. // Use sscanf to parse the number from the buffer.
  124. T result;
  125. int success = (sscanf(buffer, format, &result) == 1) ? 1 : 0;
  126. // Set flags for resulting state.
  127. if (is.peek() == EOF) {
  128. state |= std::ios_base::eofbit;
  129. }
  130. if (!success) {
  131. state |= std::ios_base::failbit;
  132. } else {
  133. value = result;
  134. }
  135. } catch (...) {
  136. state |= std::ios_base::badbit;
  137. }
  138. }
  139. is.setstate(std::ios_base::iostate(state));
  140. return is;
  141. }
  142. // Print an integer value to an output stream.
  143. template <class T>
  144. std::ostream& IOStreamPrintTemplate(std::ostream& os, T value, char type)
  145. {
  146. std::ostream::sentry okay(os);
  147. if (okay) {
  148. try {
  149. // Construct the format string.
  150. char format[8];
  151. char* f = format;
  152. *f++ = '%';
  153. if (os.flags() & std::ios_base::showpos) {
  154. *f++ = '+';
  155. }
  156. if (os.flags() & std::ios_base::showbase) {
  157. *f++ = '#';
  158. }
  159. #if defined(_MSC_VER)
  160. *f++ = 'I';
  161. *f++ = '6';
  162. *f++ = '4';
  163. #else
  164. *f++ = 'l';
  165. *f++ = 'l';
  166. #endif
  167. long bflags = os.flags() & std::ios_base::basefield;
  168. if (bflags == std::ios_base::oct) {
  169. *f++ = 'o';
  170. } else if (bflags != std::ios_base::hex) {
  171. *f++ = type;
  172. } else if (os.flags() & std::ios_base::uppercase) {
  173. *f++ = 'X';
  174. } else {
  175. *f++ = 'x';
  176. }
  177. *f = '\0';
  178. // Use sprintf to print to a buffer and then write the
  179. // buffer to the stream.
  180. char buffer[2 * KWSYS_IOS_INT64_MAX_DIG];
  181. sprintf(buffer, format, value);
  182. os << buffer;
  183. } catch (...) {
  184. os.clear(os.rdstate() | std::ios_base::badbit);
  185. }
  186. }
  187. return os;
  188. }
  189. #if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG
  190. // Implement input stream operator for IOStreamSLL.
  191. std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value)
  192. {
  193. return IOStreamScanTemplate(is, value, 'd');
  194. }
  195. // Implement input stream operator for IOStreamULL.
  196. std::istream& IOStreamScan(std::istream& is, IOStreamULL& value)
  197. {
  198. return IOStreamScanTemplate(is, value, 'u');
  199. }
  200. #endif
  201. #if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG
  202. // Implement output stream operator for IOStreamSLL.
  203. std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value)
  204. {
  205. return IOStreamPrintTemplate(os, value, 'd');
  206. }
  207. // Implement output stream operator for IOStreamULL.
  208. std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value)
  209. {
  210. return IOStreamPrintTemplate(os, value, 'u');
  211. }
  212. #endif
  213. } // namespace KWSYS_NAMESPACE
  214. #else
  215. namespace KWSYS_NAMESPACE {
  216. // Create one public symbol in this object file to avoid warnings from
  217. // archivers.
  218. void IOStreamSymbolToAvoidWarning();
  219. void IOStreamSymbolToAvoidWarning()
  220. {
  221. }
  222. } // namespace KWSYS_NAMESPACE
  223. #endif // KWSYS_IOS_NEED_OPERATORS_LL