IOStream.cxx 6.4 KB

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