IOStream.cxx 6.23 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
      // Copy the string to a buffer and construct the format string.
      char buffer[KWSYS_IOS_INT64_MAX_DIG];
121
#  if defined(_MSC_VER)
122 123
      char format[] = "%I64_";
      const int typeIndex = 4;
124
#  else
125 126
      char format[] = "%ll_";
      const int typeIndex = 3;
127
#  endif
128 129 130 131 132 133 134 135 136 137 138
      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
      // 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++ = '#';
      }
180
#  if defined(_MSC_VER)
181 182 183
      *f++ = 'I';
      *f++ = '6';
      *f++ = '4';
184
#  else
185 186
      *f++ = 'l';
      *f++ = 'l';
187
#  endif
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
      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