CMake/Source/kwsys/IOStream.cxx

251 lines
6.4 KiB
C++

/*============================================================================
KWSys - Kitware System Library
Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#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