Newer
Older
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
Brad King
committed
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Configure.hxx)
// Include the streams library.
#include <iostream>
Brad King
committed
#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"
Brad King
committed
#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
Brad King
committed
#if defined(_MAX_INT_DIG)
#define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG
#else
#define KWSYS_IOS_INT64_MAX_DIG 32
#endif
Brad King
committed
Brad King
committed
// Scan an input stream for an integer value.
static int IOStreamScanStream(std::istream& is, char* buffer)
Brad King
committed
{
// 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();
}
Brad King
committed
// 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;
}
Brad King
committed
bool foundDigit = false;
bool foundNonZero = false;
Brad King
committed
foundDigit = true;
is.ignore();
if ((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16)) {
Brad King
committed
base = 16;
foundDigit = false;
is.ignore();
Brad King
committed
base = 8;
}
Brad King
committed
// Determine the range of digits allowed for this number.
const char* digits = "0123456789abcdefABCDEF";
int maxDigitIndex = 10;
Brad King
committed
maxDigitIndex = 8;
} else if (base == 16) {
maxDigitIndex = 10 + 6 + 6;
}
Brad King
committed
// 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) {
Brad King
committed
++out;
foundNonZero = true;
}
foundDigit = true;
} else {
Brad King
committed
break;
}
Brad King
committed
// Correct the buffer contents for degenerate cases.
if (foundDigit && !foundNonZero) {
Brad King
committed
*out++ = '0';
Brad King
committed
out = buffer;
Brad King
committed
// 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)
Brad King
committed
{
int state = std::ios_base::goodbit;
Brad King
committed
// Skip leading whitespace.
std::istream::sentry okay(is);
Brad King
committed
Brad King
committed
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;
Brad King
committed
};
// Use sscanf to parse the number from the buffer.
T result;
int success = (sscanf(buffer, format, &result) == 1) ? 1 : 0;
Brad King
committed
// 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;
Brad King
committed
}
Brad King
committed
is.setstate(std::ios_base::iostate(state));
Brad King
committed
return is;
}
// Print an integer value to an output stream.
template <class T>
std::ostream& IOStreamPrintTemplate(std::ostream& os, T value, char type)
Brad King
committed
{
std::ostream::sentry okay(os);
Brad King
committed
try {
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// 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);
Brad King
committed
}
Brad King
committed
return os;
}
#if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG
Brad King
committed
// Implement input stream operator for IOStreamSLL.
std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value)
Brad King
committed
{
return IOStreamScanTemplate(is, value, 'd');
}
// Implement input stream operator for IOStreamULL.
std::istream& IOStreamScan(std::istream& is, IOStreamULL& value)
Brad King
committed
{
return IOStreamScanTemplate(is, value, 'u');
}
Brad King
committed
#if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG
Brad King
committed
// Implement output stream operator for IOStreamSLL.
std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value)
Brad King
committed
{
return IOStreamPrintTemplate(os, value, 'd');
}
// Implement output stream operator for IOStreamULL.
std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value)
Brad King
committed
{
return IOStreamPrintTemplate(os, value, 'u');
}
Brad King
committed
} // namespace KWSYS_NAMESPACE
#else
// Create one public symbol in this object file to avoid warnings from
// archivers.
void IOStreamSymbolToAvoidWarning()
{
}
} // namespace KWSYS_NAMESPACE
Brad King
committed
#endif // KWSYS_IOS_NEED_OPERATORS_LL