IOStream.cxx 6.19 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3 4 5 6
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Configure.hxx)

// Include the streams library.
7
#include <iostream>
8 9 10 11 12
#include KWSYS_HEADER(IOStream.hxx)

// Work-around CMake dependency scanning limitation.  This must
// duplicate the above list of headers.
#if 0
13 14
#include "Configure.hxx.in"
#include "IOStream.hxx.in"
15 16 17 18 19
#endif

// Implement the rest of this file only if it is needed.
#if KWSYS_IOS_NEED_OPERATORS_LL

20 21
#include <stdio.h>  // sscanf, sprintf
#include <string.h> // memchr
22

23 24 25 26 27
#if defined(_MAX_INT_DIG)
#define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG
#else
#define KWSYS_IOS_INT64_MAX_DIG 32
#endif
28

29
namespace KWSYS_NAMESPACE {
30 31

// Scan an input stream for an integer value.
32
static int IOStreamScanStream(std::istream& is, char* buffer)
33 34 35 36 37 38
{
  // Prepare to write to buffer.
  char* out = buffer;
  char* end = buffer + KWSYS_IOS_INT64_MAX_DIG - 1;

  // Look for leading sign.
39 40 41 42 43 44 45
  if (is.peek() == '+') {
    *out++ = '+';
    is.ignore();
  } else if (is.peek() == '-') {
    *out++ = '-';
    is.ignore();
  }
46 47 48 49 50

  // 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;
51
  int flags = is.flags() & std::ios_base::basefield;
52 53 54 55 56 57 58
  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;
  }
59 60
  bool foundDigit = false;
  bool foundNonZero = false;
61
  if (is.peek() == '0') {
62 63
    foundDigit = true;
    is.ignore();
64
    if ((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16)) {
65 66 67
      base = 16;
      foundDigit = false;
      is.ignore();
68
    } else if (base == 0) {
69 70
      base = 8;
    }
71
  }
72 73 74 75

  // Determine the range of digits allowed for this number.
  const char* digits = "0123456789abcdefABCDEF";
  int maxDigitIndex = 10;
76
  if (base == 8) {
77
    maxDigitIndex = 8;
78 79 80
  } else if (base == 16) {
    maxDigitIndex = 10 + 6 + 6;
  }
81 82

  // Scan until an invalid digit is found.
83 84 85
  for (; is.peek() != EOF; is.ignore()) {
    if (memchr(digits, *out = (char)is.peek(), maxDigitIndex) != 0) {
      if ((foundNonZero || *out != '0') && out < end) {
86 87 88
        ++out;
        foundNonZero = true;
      }
89 90
      foundDigit = true;
    } else {
91 92
      break;
    }
93
  }
94 95

  // Correct the buffer contents for degenerate cases.
96
  if (foundDigit && !foundNonZero) {
97
    *out++ = '0';
98
  } else if (!foundDigit) {
99
    out = buffer;
100
  }
101 102 103 104 105 106 107 108 109

  // Terminate the string in the buffer.
  *out = '\0';

  return base;
}

// Read an integer value from an input stream.
template <class T>
110
std::istream& IOStreamScanTemplate(std::istream& is, T& value, char type)
111
{
112
  int state = std::ios_base::goodbit;
113 114

  // Skip leading whitespace.
115
  std::istream::sentry okay(is);
116

117
  if (okay) {
118
    try {
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
      // 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;
139 140
      };

141 142 143
      // Use sscanf to parse the number from the buffer.
      T result;
      int success = (sscanf(buffer, format, &result) == 1) ? 1 : 0;
144

145 146 147 148 149 150 151 152 153 154 155
      // 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;
156
    }
157
  }
158

159
  is.setstate(std::ios_base::iostate(state));
160 161 162 163 164
  return is;
}

// Print an integer value to an output stream.
template <class T>
165
std::ostream& IOStreamPrintTemplate(std::ostream& os, T value, char type)
166
{
167
  std::ostream::sentry okay(os);
168
  if (okay) {
169
    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);
207
    }
208
  }
209 210 211
  return os;
}

212
#if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG
213
// Implement input stream operator for IOStreamSLL.
214
std::istream& IOStreamScan(std::istream& is, IOStreamSLL& value)
215 216 217 218 219
{
  return IOStreamScanTemplate(is, value, 'd');
}

// Implement input stream operator for IOStreamULL.
220
std::istream& IOStreamScan(std::istream& is, IOStreamULL& value)
221 222 223
{
  return IOStreamScanTemplate(is, value, 'u');
}
224
#endif
225

226
#if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG
227
// Implement output stream operator for IOStreamSLL.
228
std::ostream& IOStreamPrint(std::ostream& os, IOStreamSLL value)
229 230 231 232 233
{
  return IOStreamPrintTemplate(os, value, 'd');
}

// Implement output stream operator for IOStreamULL.
234
std::ostream& IOStreamPrint(std::ostream& os, IOStreamULL value)
235 236 237
{
  return IOStreamPrintTemplate(os, value, 'u');
}
238
#endif
239 240 241

} // namespace KWSYS_NAMESPACE

242 243
#else

244
namespace KWSYS_NAMESPACE {
245 246 247

// Create one public symbol in this object file to avoid warnings from
// archivers.
248
void IOStreamSymbolToAvoidWarning();
249 250 251 252 253 254
void IOStreamSymbolToAvoidWarning()
{
}

} // namespace KWSYS_NAMESPACE

255
#endif // KWSYS_IOS_NEED_OPERATORS_LL