diff options
Diffstat (limited to 'Source/kwsys/IOStream.cxx')
-rw-r--r-- | Source/kwsys/IOStream.cxx | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/Source/kwsys/IOStream.cxx b/Source/kwsys/IOStream.cxx new file mode 100644 index 0000000..e21f87d --- /dev/null +++ b/Source/kwsys/IOStream.cxx @@ -0,0 +1,255 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Configure.hxx) + +// Include the streams library. +#include <iostream> +#include KWSYS_HEADER(IOStream.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Configure.hxx.in" +# include "IOStream.hxx.in" +#endif + +// Implement the rest of this file only if it is needed. +#if KWSYS_IOS_NEED_OPERATORS_LL + +# include <stdio.h> // sscanf, sprintf +# include <string.h> // memchr + +# if defined(_MAX_INT_DIG) +# define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG +# else +# define KWSYS_IOS_INT64_MAX_DIG 32 +# endif + +namespace KWSYS_NAMESPACE { + +// Scan an input stream for an integer value. +static int IOStreamScanStream(std::istream& is, char* buffer) +{ + // Prepare to write to buffer. + char* out = buffer; + char* end = buffer + KWSYS_IOS_INT64_MAX_DIG - 1; + + // Look for leading sign. + if (is.peek() == '+') { + *out++ = '+'; + is.ignore(); + } else if (is.peek() == '-') { + *out++ = '-'; + is.ignore(); + } + + // Determine the base. If not specified in the stream, try to + // detect it from the input. A leading 0x means hex, and a leading + // 0 alone means octal. + int base = 0; + int flags = is.flags() & std::ios_base::basefield; + if (flags == std::ios_base::oct) { + base = 8; + } else if (flags == std::ios_base::dec) { + base = 10; + } else if (flags == std::ios_base::hex) { + base = 16; + } + bool foundDigit = false; + bool foundNonZero = false; + if (is.peek() == '0') { + foundDigit = true; + is.ignore(); + if ((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16)) { + base = 16; + foundDigit = false; + is.ignore(); + } else if (base == 0) { + base = 8; + } + } + + // Determine the range of digits allowed for this number. + const char* digits = "0123456789abcdefABCDEF"; + int maxDigitIndex = 10; + if (base == 8) { + maxDigitIndex = 8; + } else if (base == 16) { + maxDigitIndex = 10 + 6 + 6; + } + + // Scan until an invalid digit is found. + for (; is.peek() != EOF; is.ignore()) { + if (memchr(digits, *out = (char)is.peek(), maxDigitIndex) != 0) { + if ((foundNonZero || *out != '0') && out < end) { + ++out; + foundNonZero = true; + } + foundDigit = true; + } else { + break; + } + } + + // Correct the buffer contents for degenerate cases. + if (foundDigit && !foundNonZero) { + *out++ = '0'; + } else if (!foundDigit) { + out = buffer; + } + + // Terminate the string in the buffer. + *out = '\0'; + + return base; +} + +// Read an integer value from an input stream. +template <class T> +std::istream& IOStreamScanTemplate(std::istream& is, T& value, char type) +{ + int state = std::ios_base::goodbit; + + // Skip leading whitespace. + std::istream::sentry okay(is); + + if (okay) { + try { + // Copy the string to a buffer and construct the format string. + char buffer[KWSYS_IOS_INT64_MAX_DIG]; +# if defined(_MSC_VER) + char format[] = "%I64_"; + const int typeIndex = 4; +# else + char format[] = "%ll_"; + const int typeIndex = 3; +# endif + switch (IOStreamScanStream(is, buffer)) { + case 8: + format[typeIndex] = 'o'; + break; + case 0: // Default to decimal if not told otherwise. + case 10: + format[typeIndex] = type; + break; + case 16: + format[typeIndex] = 'x'; + break; + }; + + // Use sscanf to parse the number from the buffer. + T result; + int success = (sscanf(buffer, format, &result) == 1) ? 1 : 0; + + // Set flags for resulting state. + if (is.peek() == EOF) { + state |= std::ios_base::eofbit; + } + if (!success) { + state |= std::ios_base::failbit; + } else { + value = result; + } + } catch (...) { + state |= std::ios_base::badbit; + } + } + + is.setstate(std::ios_base::iostate(state)); + return is; +} + +// Print an integer value to an output stream. +template <class T> +std::ostream& IOStreamPrintTemplate(std::ostream& os, T value, char type) +{ + std::ostream::sentry okay(os); + if (okay) { + try { + // Construct the format string. + char format[8]; + char* f = format; + *f++ = '%'; + if (os.flags() & std::ios_base::showpos) { + *f++ = '+'; + } + if (os.flags() & std::ios_base::showbase) { + *f++ = '#'; + } +# if defined(_MSC_VER) + *f++ = 'I'; + *f++ = '6'; + *f++ = '4'; +# else + *f++ = 'l'; + *f++ = 'l'; +# endif + long bflags = os.flags() & std::ios_base::basefield; + if (bflags == std::ios_base::oct) { + *f++ = 'o'; + } else if (bflags != std::ios_base::hex) { + *f++ = type; + } else if (os.flags() & std::ios_base::uppercase) { + *f++ = 'X'; + } else { + *f++ = 'x'; + } + *f = '\0'; + + // Use sprintf to print to a buffer and then write the + // buffer to the stream. + char buffer[2 * KWSYS_IOS_INT64_MAX_DIG]; + sprintf(buffer, format, value); + os << buffer; + } catch (...) { + os.clear(os.rdstate() | std::ios_base::badbit); + } + } + return os; +} + +# if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG +// Implement input stream operator for IOStreamSLL. +std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value) +{ + return IOStreamScanTemplate(is, value, 'd'); +} + +// Implement input stream operator for IOStreamULL. +std::istream& IOStreamScan(std::istream& is, IOStreamULL& value) +{ + return IOStreamScanTemplate(is, value, 'u'); +} +# endif + +# if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG +// Implement output stream operator for IOStreamSLL. +std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value) +{ + return IOStreamPrintTemplate(os, value, 'd'); +} + +// Implement output stream operator for IOStreamULL. +std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value) +{ + return IOStreamPrintTemplate(os, value, 'u'); +} +# endif + +} // namespace KWSYS_NAMESPACE + +#else + +namespace KWSYS_NAMESPACE { + +// Create one public symbol in this object file to avoid warnings from +// archivers. +void IOStreamSymbolToAvoidWarning(); +void IOStreamSymbolToAvoidWarning() +{ +} + +} // namespace KWSYS_NAMESPACE + +#endif // KWSYS_IOS_NEED_OPERATORS_LL |