mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
Update LLVM to latest upstream. (#1080)
Also change header guards to WPI header guards. Remove StringRef::c_str() customization, replacing the handful of uses with Twine or SmallString. TCPStream: Include errno.h and make Windows includes lowercase for consistency. Upstream LLVM version: eb4186cca7924fb1706357545311a2fa3de40c59
This commit is contained in:
@@ -46,13 +46,42 @@
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "wpi/ConvertUTF.h"
|
||||
#ifdef CVTUTF_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* This code extensively uses fall-through switches.
|
||||
* Keep the compiler from warning about that.
|
||||
*/
|
||||
#if defined(__clang__) && defined(__has_warning)
|
||||
# if __has_warning("-Wimplicit-fallthrough")
|
||||
# define ConvertUTF_DISABLE_WARNINGS \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wimplicit-fallthrough\"")
|
||||
# define ConvertUTF_RESTORE_WARNINGS \
|
||||
_Pragma("clang diagnostic pop")
|
||||
# endif
|
||||
#elif defined(__GNUC__) && __GNUC__ > 6
|
||||
# define ConvertUTF_DISABLE_WARNINGS \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
|
||||
# define ConvertUTF_RESTORE_WARNINGS \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
#ifndef ConvertUTF_DISABLE_WARNINGS
|
||||
# define ConvertUTF_DISABLE_WARNINGS
|
||||
#endif
|
||||
#ifndef ConvertUTF_RESTORE_WARNINGS
|
||||
# define ConvertUTF_RESTORE_WARNINGS
|
||||
#endif
|
||||
|
||||
ConvertUTF_DISABLE_WARNINGS
|
||||
|
||||
namespace wpi {
|
||||
|
||||
static const int halfShift = 10; /* used for shifting by 10 bits */
|
||||
|
||||
static const UTF32 halfBase = 0x0010000UL;
|
||||
@@ -110,7 +139,7 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
|
||||
* into an inline function.
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (
|
||||
@@ -272,9 +301,9 @@ ConversionResult ConvertUTF16toUTF8 (
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
|
||||
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
|
||||
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
|
||||
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
|
||||
}
|
||||
target += bytesToWrite;
|
||||
@@ -325,9 +354,9 @@ ConversionResult ConvertUTF32toUTF8 (
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
|
||||
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
|
||||
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; /* FALLTHRU */
|
||||
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
|
||||
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
|
||||
}
|
||||
target += bytesToWrite;
|
||||
@@ -356,8 +385,8 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) {
|
||||
switch (length) {
|
||||
default: return false;
|
||||
/* Everything else falls through when "true"... */
|
||||
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; /* FALLTHRU */
|
||||
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; /* FALLTHRU */
|
||||
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
|
||||
switch (*source) {
|
||||
@@ -368,7 +397,6 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) {
|
||||
case 0xF4: if (a > 0x8F) return false; break;
|
||||
default: if (a < 0x80) return false;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
|
||||
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
|
||||
}
|
||||
@@ -532,11 +560,11 @@ ConversionResult ConvertUTF8toUTF16 (
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
case 5: ch += *source++; ch <<= 6; /* FALLTHRU */ /* remember, illegal UTF-8 */
|
||||
case 4: ch += *source++; ch <<= 6; /* FALLTHRU */ /* remember, illegal UTF-8 */
|
||||
case 3: ch += *source++; ch <<= 6; /* FALLTHRU */
|
||||
case 2: ch += *source++; ch <<= 6; /* FALLTHRU */
|
||||
case 1: ch += *source++; ch <<= 6; /* FALLTHRU */
|
||||
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
||||
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
|
||||
case 3: ch += *source++; ch <<= 6;
|
||||
case 2: ch += *source++; ch <<= 6;
|
||||
case 1: ch += *source++; ch <<= 6;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
@@ -636,11 +664,11 @@ static ConversionResult ConvertUTF8toUTF32Impl(
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
case 5: ch += *source++; ch <<= 6; /* FALLTHRU */
|
||||
case 4: ch += *source++; ch <<= 6; /* FALLTHRU */
|
||||
case 3: ch += *source++; ch <<= 6; /* FALLTHRU */
|
||||
case 2: ch += *source++; ch <<= 6; /* FALLTHRU */
|
||||
case 1: ch += *source++; ch <<= 6; /* FALLTHRU */
|
||||
case 5: ch += *source++; ch <<= 6;
|
||||
case 4: ch += *source++; ch <<= 6;
|
||||
case 3: ch += *source++; ch <<= 6;
|
||||
case 2: ch += *source++; ch <<= 6;
|
||||
case 1: ch += *source++; ch <<= 6;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
@@ -687,8 +715,6 @@ ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
|
||||
flags, /*InputIsPartial=*/false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Note A.
|
||||
@@ -707,3 +733,7 @@ ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
|
||||
similarly unrolled loops.
|
||||
|
||||
--------------------------------------------------------------------- */
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
ConvertUTF_RESTORE_WARNINGS
|
||||
|
||||
264
wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp
Normal file
264
wpiutil/src/main/native/cpp/llvm/NativeFormatting.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
//===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/NativeFormatting.h"
|
||||
|
||||
#include "wpi/ArrayRef.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Format.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
static int format_to_buffer(T Value, char (&Buffer)[N]) {
|
||||
char *EndPtr = std::end(Buffer);
|
||||
char *CurPtr = EndPtr;
|
||||
|
||||
do {
|
||||
*--CurPtr = '0' + char(Value % 10);
|
||||
Value /= 10;
|
||||
} while (Value);
|
||||
return EndPtr - CurPtr;
|
||||
}
|
||||
|
||||
static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
|
||||
assert(!Buffer.empty());
|
||||
|
||||
ArrayRef<char> ThisGroup;
|
||||
int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
|
||||
ThisGroup = Buffer.take_front(InitialDigits);
|
||||
S.write(ThisGroup.data(), ThisGroup.size());
|
||||
|
||||
Buffer = Buffer.drop_front(InitialDigits);
|
||||
assert(Buffer.size() % 3 == 0);
|
||||
while (!Buffer.empty()) {
|
||||
S << ',';
|
||||
ThisGroup = Buffer.take_front(3);
|
||||
S.write(ThisGroup.data(), 3);
|
||||
Buffer = Buffer.drop_front(3);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
|
||||
IntegerStyle Style, bool IsNegative) {
|
||||
static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
|
||||
|
||||
char NumberBuffer[128];
|
||||
std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
|
||||
|
||||
size_t Len = 0;
|
||||
Len = format_to_buffer(N, NumberBuffer);
|
||||
|
||||
if (IsNegative)
|
||||
S << '-';
|
||||
|
||||
if (Len < MinDigits && Style != IntegerStyle::Number) {
|
||||
for (size_t I = Len; I < MinDigits; ++I)
|
||||
S << '0';
|
||||
}
|
||||
|
||||
if (Style == IntegerStyle::Number) {
|
||||
writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
|
||||
} else {
|
||||
S.write(std::end(NumberBuffer) - Len, Len);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
|
||||
IntegerStyle Style, bool IsNegative = false) {
|
||||
// Output using 32-bit div/mod if possible.
|
||||
if (N == static_cast<uint32_t>(N))
|
||||
write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
|
||||
IsNegative);
|
||||
else
|
||||
write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void write_signed(raw_ostream &S, T N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
static_assert(std::is_signed<T>::value, "Value is not signed!");
|
||||
|
||||
using UnsignedT = typename std::make_unsigned<T>::type;
|
||||
|
||||
if (N >= 0) {
|
||||
write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
|
||||
return;
|
||||
}
|
||||
|
||||
UnsignedT UN = -(UnsignedT)N;
|
||||
write_unsigned(S, UN, MinDigits, Style, true);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_unsigned(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, int N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_signed(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_unsigned(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_signed(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_unsigned(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_integer(raw_ostream &S, long long N, size_t MinDigits,
|
||||
IntegerStyle Style) {
|
||||
write_signed(S, N, MinDigits, Style);
|
||||
}
|
||||
|
||||
void wpi::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
|
||||
Optional<size_t> Width) {
|
||||
const size_t kMaxWidth = 128u;
|
||||
|
||||
size_t W = std::min(kMaxWidth, Width.getValueOr(0u));
|
||||
|
||||
unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
|
||||
bool Prefix = (Style == HexPrintStyle::PrefixLower ||
|
||||
Style == HexPrintStyle::PrefixUpper);
|
||||
bool Upper =
|
||||
(Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
|
||||
unsigned PrefixChars = Prefix ? 2 : 0;
|
||||
unsigned NumChars =
|
||||
std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);
|
||||
|
||||
char NumberBuffer[kMaxWidth];
|
||||
::memset(NumberBuffer, '0', wpi::array_lengthof(NumberBuffer));
|
||||
if (Prefix)
|
||||
NumberBuffer[1] = 'x';
|
||||
char *EndPtr = NumberBuffer + NumChars;
|
||||
char *CurPtr = EndPtr;
|
||||
while (N) {
|
||||
unsigned char x = static_cast<unsigned char>(N) % 16;
|
||||
*--CurPtr = hexdigit(x, !Upper);
|
||||
N /= 16;
|
||||
}
|
||||
|
||||
S.write(NumberBuffer, NumChars);
|
||||
}
|
||||
|
||||
void wpi::write_double(raw_ostream &S, double N, FloatStyle Style,
|
||||
Optional<size_t> Precision) {
|
||||
size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
|
||||
|
||||
if (std::isnan(N)) {
|
||||
S << "nan";
|
||||
return;
|
||||
} else if (std::isinf(N)) {
|
||||
S << "INF";
|
||||
return;
|
||||
}
|
||||
|
||||
char Letter;
|
||||
if (Style == FloatStyle::Exponent)
|
||||
Letter = 'e';
|
||||
else if (Style == FloatStyle::ExponentUpper)
|
||||
Letter = 'E';
|
||||
else
|
||||
Letter = 'f';
|
||||
|
||||
SmallString<8> Spec;
|
||||
wpi::raw_svector_ostream Out(Spec);
|
||||
Out << "%." << Prec << Letter;
|
||||
|
||||
if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
|
||||
#ifdef _WIN32
|
||||
// On MSVCRT and compatible, output of %e is incompatible to Posix
|
||||
// by default. Number of exponent digits should be at least 2. "%+03d"
|
||||
// FIXME: Implement our formatter to here or Support/Format.h!
|
||||
#if defined(__MINGW32__)
|
||||
// FIXME: It should be generic to C++11.
|
||||
if (N == 0.0 && std::signbit(N)) {
|
||||
char NegativeZero[] = "-0.000000e+00";
|
||||
if (Style == FloatStyle::ExponentUpper)
|
||||
NegativeZero[strlen(NegativeZero) - 4] = 'E';
|
||||
S << NegativeZero;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
int fpcl = _fpclass(N);
|
||||
|
||||
// negative zero
|
||||
if (fpcl == _FPCLASS_NZ) {
|
||||
char NegativeZero[] = "-0.000000e+00";
|
||||
if (Style == FloatStyle::ExponentUpper)
|
||||
NegativeZero[strlen(NegativeZero) - 4] = 'E';
|
||||
S << NegativeZero;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
char buf[32];
|
||||
unsigned len;
|
||||
len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
|
||||
if (len <= sizeof(buf) - 2) {
|
||||
if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
|
||||
buf[len - 3] == '0') {
|
||||
int cs = buf[len - 4];
|
||||
if (cs == '+' || cs == '-') {
|
||||
int c1 = buf[len - 2];
|
||||
int c0 = buf[len - 1];
|
||||
if (isdigit(static_cast<unsigned char>(c1)) &&
|
||||
isdigit(static_cast<unsigned char>(c0))) {
|
||||
// Trim leading '0': "...e+012" -> "...e+12\0"
|
||||
buf[len - 3] = c1;
|
||||
buf[len - 2] = c0;
|
||||
buf[--len] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
S << buf;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Style == FloatStyle::Percent)
|
||||
N *= 100.0;
|
||||
|
||||
char Buf[32];
|
||||
format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
|
||||
S << Buf;
|
||||
if (Style == FloatStyle::Percent)
|
||||
S << '%';
|
||||
}
|
||||
|
||||
bool wpi::isPrefixedHexStyle(HexPrintStyle S) {
|
||||
return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
|
||||
}
|
||||
|
||||
size_t wpi::getDefaultPrecision(FloatStyle Style) {
|
||||
switch (Style) {
|
||||
case FloatStyle::Exponent:
|
||||
case FloatStyle::ExponentUpper:
|
||||
return 6; // Number of decimal places.
|
||||
case FloatStyle::Fixed:
|
||||
case FloatStyle::Percent:
|
||||
return 2; // Number of decimal places.
|
||||
}
|
||||
LLVM_BUILTIN_UNREACHABLE;
|
||||
}
|
||||
@@ -30,16 +30,29 @@ using namespace wpi;
|
||||
namespace {
|
||||
using wpi::StringRef;
|
||||
using wpi::sys::path::is_separator;
|
||||
using wpi::sys::path::Style;
|
||||
|
||||
inline Style real_style(Style style) {
|
||||
#ifdef _WIN32
|
||||
const char *separators = "\\/";
|
||||
const char preferred_separator = '\\';
|
||||
return (style == Style::posix) ? Style::posix : Style::windows;
|
||||
#else
|
||||
const char separators = '/';
|
||||
const char preferred_separator = '/';
|
||||
return (style == Style::windows) ? Style::windows : Style::posix;
|
||||
#endif
|
||||
}
|
||||
|
||||
StringRef find_first_component(StringRef path) {
|
||||
inline const char *separators(Style style) {
|
||||
if (real_style(style) == Style::windows)
|
||||
return "\\/";
|
||||
return "/";
|
||||
}
|
||||
|
||||
inline char preferred_separator(Style style) {
|
||||
if (real_style(style) == Style::windows)
|
||||
return '\\';
|
||||
return '/';
|
||||
}
|
||||
|
||||
StringRef find_first_component(StringRef path, Style style) {
|
||||
// Look for this first component in the following order.
|
||||
// * empty (in this case we return an empty string)
|
||||
// * either C: or {//,\\}net.
|
||||
@@ -49,101 +62,94 @@ namespace {
|
||||
if (path.empty())
|
||||
return path;
|
||||
|
||||
#ifdef _WIN32
|
||||
// C:
|
||||
if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) &&
|
||||
path[1] == ':')
|
||||
return path.substr(0, 2);
|
||||
#endif
|
||||
if (real_style(style) == Style::windows) {
|
||||
// C:
|
||||
if (path.size() >= 2 &&
|
||||
std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':')
|
||||
return path.substr(0, 2);
|
||||
}
|
||||
|
||||
// //net
|
||||
if ((path.size() > 2) &&
|
||||
is_separator(path[0]) &&
|
||||
path[0] == path[1] &&
|
||||
!is_separator(path[2])) {
|
||||
if ((path.size() > 2) && is_separator(path[0], style) &&
|
||||
path[0] == path[1] && !is_separator(path[2], style)) {
|
||||
// Find the next directory separator.
|
||||
size_t end = path.find_first_of(separators, 2);
|
||||
size_t end = path.find_first_of(separators(style), 2);
|
||||
return path.substr(0, end);
|
||||
}
|
||||
|
||||
// {/,\}
|
||||
if (is_separator(path[0]))
|
||||
if (is_separator(path[0], style))
|
||||
return path.substr(0, 1);
|
||||
|
||||
// * {file,directory}name
|
||||
size_t end = path.find_first_of(separators);
|
||||
size_t end = path.find_first_of(separators(style));
|
||||
return path.substr(0, end);
|
||||
}
|
||||
|
||||
size_t filename_pos(StringRef str) {
|
||||
if (str.size() == 2 &&
|
||||
is_separator(str[0]) &&
|
||||
str[0] == str[1])
|
||||
return 0;
|
||||
|
||||
if (str.size() > 0 && is_separator(str[str.size() - 1]))
|
||||
// Returns the first character of the filename in str. For paths ending in
|
||||
// '/', it returns the position of the '/'.
|
||||
size_t filename_pos(StringRef str, Style style) {
|
||||
if (str.size() > 0 && is_separator(str[str.size() - 1], style))
|
||||
return str.size() - 1;
|
||||
|
||||
size_t pos = str.find_last_of(separators, str.size() - 1);
|
||||
size_t pos = str.find_last_of(separators(style), str.size() - 1);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (pos == StringRef::npos)
|
||||
pos = str.find_last_of(':', str.size() - 2);
|
||||
#endif
|
||||
if (real_style(style) == Style::windows) {
|
||||
if (pos == StringRef::npos)
|
||||
pos = str.find_last_of(':', str.size() - 2);
|
||||
}
|
||||
|
||||
if (pos == StringRef::npos ||
|
||||
(pos == 1 && is_separator(str[0])))
|
||||
if (pos == StringRef::npos || (pos == 1 && is_separator(str[0], style)))
|
||||
return 0;
|
||||
|
||||
return pos + 1;
|
||||
}
|
||||
|
||||
size_t root_dir_start(StringRef str) {
|
||||
// Returns the position of the root directory in str. If there is no root
|
||||
// directory in str, it returns StringRef::npos.
|
||||
size_t root_dir_start(StringRef str, Style style) {
|
||||
// case "c:/"
|
||||
#ifdef _WIN32
|
||||
if (str.size() > 2 &&
|
||||
str[1] == ':' &&
|
||||
is_separator(str[2]))
|
||||
return 2;
|
||||
#endif
|
||||
|
||||
// case "//"
|
||||
if (str.size() == 2 &&
|
||||
is_separator(str[0]) &&
|
||||
str[0] == str[1])
|
||||
return StringRef::npos;
|
||||
if (real_style(style) == Style::windows) {
|
||||
if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style))
|
||||
return 2;
|
||||
}
|
||||
|
||||
// case "//net"
|
||||
if (str.size() > 3 &&
|
||||
is_separator(str[0]) &&
|
||||
str[0] == str[1] &&
|
||||
!is_separator(str[2])) {
|
||||
return str.find_first_of(separators, 2);
|
||||
if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] &&
|
||||
!is_separator(str[2], style)) {
|
||||
return str.find_first_of(separators(style), 2);
|
||||
}
|
||||
|
||||
// case "/"
|
||||
if (str.size() > 0 && is_separator(str[0]))
|
||||
if (str.size() > 0 && is_separator(str[0], style))
|
||||
return 0;
|
||||
|
||||
return StringRef::npos;
|
||||
}
|
||||
|
||||
size_t parent_path_end(StringRef path) {
|
||||
size_t end_pos = filename_pos(path);
|
||||
// Returns the position past the end of the "parent path" of path. The parent
|
||||
// path will not end in '/', unless the parent is the root directory. If the
|
||||
// path has no parent, 0 is returned.
|
||||
size_t parent_path_end(StringRef path, Style style) {
|
||||
size_t end_pos = filename_pos(path, style);
|
||||
|
||||
bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]);
|
||||
bool filename_was_sep =
|
||||
path.size() > 0 && is_separator(path[end_pos], style);
|
||||
|
||||
// Skip separators except for root dir.
|
||||
size_t root_dir_pos = root_dir_start(path.substr(0, end_pos));
|
||||
|
||||
while(end_pos > 0 &&
|
||||
(end_pos - 1) != root_dir_pos &&
|
||||
is_separator(path[end_pos - 1]))
|
||||
// Skip separators until we reach root dir (or the start of the string).
|
||||
size_t root_dir_pos = root_dir_start(path, style);
|
||||
while (end_pos > 0 &&
|
||||
(root_dir_pos == StringRef::npos || end_pos > root_dir_pos) &&
|
||||
is_separator(path[end_pos - 1], style))
|
||||
--end_pos;
|
||||
|
||||
if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
|
||||
return StringRef::npos;
|
||||
if (end_pos == root_dir_pos && !filename_was_sep) {
|
||||
// We've reached the root dir and the input path was *not* ending in a
|
||||
// sequence of slashes. Include the root dir in the parent path.
|
||||
return root_dir_pos + 1;
|
||||
}
|
||||
|
||||
// Otherwise, just include before the last slash.
|
||||
return end_pos;
|
||||
}
|
||||
} // end unnamed namespace
|
||||
@@ -152,11 +158,12 @@ namespace wpi {
|
||||
namespace sys {
|
||||
namespace path {
|
||||
|
||||
const_iterator begin(StringRef path) {
|
||||
const_iterator begin(StringRef path, Style style) {
|
||||
const_iterator i;
|
||||
i.Path = path;
|
||||
i.Component = find_first_component(path);
|
||||
i.Component = find_first_component(path, style);
|
||||
i.Position = 0;
|
||||
i.S = style;
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -181,32 +188,26 @@ const_iterator &const_iterator::operator++() {
|
||||
|
||||
// Both POSIX and Windows treat paths that begin with exactly two separators
|
||||
// specially.
|
||||
bool was_net = Component.size() > 2 &&
|
||||
is_separator(Component[0]) &&
|
||||
Component[1] == Component[0] &&
|
||||
!is_separator(Component[2]);
|
||||
bool was_net = Component.size() > 2 && is_separator(Component[0], S) &&
|
||||
Component[1] == Component[0] && !is_separator(Component[2], S);
|
||||
|
||||
// Handle separators.
|
||||
if (is_separator(Path[Position])) {
|
||||
if (is_separator(Path[Position], S)) {
|
||||
// Root dir.
|
||||
if (was_net
|
||||
#ifdef _WIN32
|
||||
if (was_net ||
|
||||
// c:/
|
||||
|| Component.endswith(":")
|
||||
#endif
|
||||
) {
|
||||
(real_style(S) == Style::windows && Component.endswith(":"))) {
|
||||
Component = Path.substr(Position, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Skip extra separators.
|
||||
while (Position != Path.size() &&
|
||||
is_separator(Path[Position])) {
|
||||
while (Position != Path.size() && is_separator(Path[Position], S)) {
|
||||
++Position;
|
||||
}
|
||||
|
||||
// Treat trailing '/' as a '.'.
|
||||
if (Position == Path.size()) {
|
||||
// Treat trailing '/' as a '.', unless it is the root dir.
|
||||
if (Position == Path.size() && Component != "/") {
|
||||
--Position;
|
||||
Component = ".";
|
||||
return *this;
|
||||
@@ -214,7 +215,7 @@ const_iterator &const_iterator::operator++() {
|
||||
}
|
||||
|
||||
// Find next component.
|
||||
size_t end_pos = Path.find_first_of(separators, Position);
|
||||
size_t end_pos = Path.find_first_of(separators(S), Position);
|
||||
Component = Path.slice(Position, end_pos);
|
||||
|
||||
return *this;
|
||||
@@ -228,10 +229,11 @@ ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const {
|
||||
return Position - RHS.Position;
|
||||
}
|
||||
|
||||
reverse_iterator rbegin(StringRef Path) {
|
||||
reverse_iterator rbegin(StringRef Path, Style style) {
|
||||
reverse_iterator I;
|
||||
I.Path = Path;
|
||||
I.Position = Path.size();
|
||||
I.S = style;
|
||||
return ++I;
|
||||
}
|
||||
|
||||
@@ -244,27 +246,25 @@ reverse_iterator rend(StringRef Path) {
|
||||
}
|
||||
|
||||
reverse_iterator &reverse_iterator::operator++() {
|
||||
// If we're at the end and the previous char was a '/', return '.' unless
|
||||
// we are the root path.
|
||||
size_t root_dir_pos = root_dir_start(Path);
|
||||
if (Position == Path.size() &&
|
||||
Path.size() > root_dir_pos + 1 &&
|
||||
is_separator(Path[Position - 1])) {
|
||||
size_t root_dir_pos = root_dir_start(Path, S);
|
||||
|
||||
// Skip separators unless it's the root directory.
|
||||
size_t end_pos = Position;
|
||||
while (end_pos > 0 && (end_pos - 1) != root_dir_pos &&
|
||||
is_separator(Path[end_pos - 1], S))
|
||||
--end_pos;
|
||||
|
||||
// Treat trailing '/' as a '.', unless it is the root dir.
|
||||
if (Position == Path.size() && !Path.empty() &&
|
||||
is_separator(Path.back(), S) &&
|
||||
(root_dir_pos == StringRef::npos || end_pos - 1 > root_dir_pos)) {
|
||||
--Position;
|
||||
Component = ".";
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Skip separators unless it's the root directory.
|
||||
size_t end_pos = Position;
|
||||
|
||||
while(end_pos > 0 &&
|
||||
(end_pos - 1) != root_dir_pos &&
|
||||
is_separator(Path[end_pos - 1]))
|
||||
--end_pos;
|
||||
|
||||
// Find next separator.
|
||||
size_t start_pos = filename_pos(Path.substr(0, end_pos));
|
||||
size_t start_pos = filename_pos(Path.substr(0, end_pos), S);
|
||||
Component = Path.slice(start_pos, end_pos);
|
||||
Position = start_pos;
|
||||
return *this;
|
||||
@@ -279,21 +279,15 @@ ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const {
|
||||
return Position - RHS.Position;
|
||||
}
|
||||
|
||||
StringRef root_path(StringRef path) {
|
||||
const_iterator b = begin(path),
|
||||
pos = b,
|
||||
e = end(path);
|
||||
StringRef root_path(StringRef path, Style style) {
|
||||
const_iterator b = begin(path, style), pos = b, e = end(path);
|
||||
if (b != e) {
|
||||
bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
|
||||
bool has_drive =
|
||||
#ifdef _WIN32
|
||||
b->endswith(":");
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
bool has_net =
|
||||
b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
|
||||
bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
|
||||
|
||||
if (has_net || has_drive) {
|
||||
if ((++pos != e) && is_separator((*pos)[0])) {
|
||||
if ((++pos != e) && is_separator((*pos)[0], style)) {
|
||||
// {C:/,//net/}, so get the first two components.
|
||||
return path.substr(0, b->size() + pos->size());
|
||||
} else {
|
||||
@@ -303,7 +297,7 @@ StringRef root_path(StringRef path) {
|
||||
}
|
||||
|
||||
// POSIX style root directory.
|
||||
if (is_separator((*b)[0])) {
|
||||
if (is_separator((*b)[0], style)) {
|
||||
return *b;
|
||||
}
|
||||
}
|
||||
@@ -311,17 +305,12 @@ StringRef root_path(StringRef path) {
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
StringRef root_name(StringRef path) {
|
||||
const_iterator b = begin(path),
|
||||
e = end(path);
|
||||
StringRef root_name(StringRef path, Style style) {
|
||||
const_iterator b = begin(path, style), e = end(path);
|
||||
if (b != e) {
|
||||
bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
|
||||
bool has_drive =
|
||||
#ifdef _WIN32
|
||||
b->endswith(":");
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
bool has_net =
|
||||
b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
|
||||
bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
|
||||
|
||||
if (has_net || has_drive) {
|
||||
// just {C:,//net}, return the first component.
|
||||
@@ -333,27 +322,21 @@ StringRef root_name(StringRef path) {
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
StringRef root_directory(StringRef path) {
|
||||
const_iterator b = begin(path),
|
||||
pos = b,
|
||||
e = end(path);
|
||||
StringRef root_directory(StringRef path, Style style) {
|
||||
const_iterator b = begin(path, style), pos = b, e = end(path);
|
||||
if (b != e) {
|
||||
bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
|
||||
bool has_drive =
|
||||
#ifdef _WIN32
|
||||
b->endswith(":");
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
bool has_net =
|
||||
b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0];
|
||||
bool has_drive = (real_style(style) == Style::windows) && b->endswith(":");
|
||||
|
||||
if ((has_net || has_drive) &&
|
||||
// {C:,//net}, skip to the next component.
|
||||
(++pos != e) && is_separator((*pos)[0])) {
|
||||
(++pos != e) && is_separator((*pos)[0], style)) {
|
||||
return *pos;
|
||||
}
|
||||
|
||||
// POSIX style root directory.
|
||||
if (!has_net && is_separator((*b)[0])) {
|
||||
if (!has_net && is_separator((*b)[0], style)) {
|
||||
return *b;
|
||||
}
|
||||
}
|
||||
@@ -362,15 +345,13 @@ StringRef root_directory(StringRef path) {
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
StringRef relative_path(StringRef path) {
|
||||
StringRef root = root_path(path);
|
||||
StringRef relative_path(StringRef path, Style style) {
|
||||
StringRef root = root_path(path, style);
|
||||
return path.substr(root.size());
|
||||
}
|
||||
|
||||
void append(SmallVectorImpl<char> &path, const Twine &a,
|
||||
const Twine &b,
|
||||
const Twine &c,
|
||||
const Twine &d) {
|
||||
void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
|
||||
const Twine &b, const Twine &c, const Twine &d) {
|
||||
SmallString<32> a_storage;
|
||||
SmallString<32> b_storage;
|
||||
SmallString<32> c_storage;
|
||||
@@ -383,13 +364,11 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
|
||||
if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
|
||||
|
||||
for (auto &component : components) {
|
||||
bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]);
|
||||
bool component_has_sep = !component.empty() && is_separator(component[0]);
|
||||
bool is_root_name = has_root_name(component);
|
||||
|
||||
bool path_has_sep =
|
||||
!path.empty() && is_separator(path[path.size() - 1], style);
|
||||
if (path_has_sep) {
|
||||
// Strip separators from beginning of component.
|
||||
size_t loc = component.find_first_not_of(separators);
|
||||
size_t loc = component.find_first_not_of(separators(style));
|
||||
StringRef c = component.substr(loc);
|
||||
|
||||
// Append it.
|
||||
@@ -397,43 +376,52 @@ void append(SmallVectorImpl<char> &path, const Twine &a,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!component_has_sep && !(path.empty() || is_root_name)) {
|
||||
bool component_has_sep =
|
||||
!component.empty() && is_separator(component[0], style);
|
||||
if (!component_has_sep &&
|
||||
!(path.empty() || has_root_name(component, style))) {
|
||||
// Add a separator.
|
||||
path.push_back(preferred_separator);
|
||||
path.push_back(preferred_separator(style));
|
||||
}
|
||||
|
||||
path.append(component.begin(), component.end());
|
||||
}
|
||||
}
|
||||
|
||||
void append(SmallVectorImpl<char> &path,
|
||||
const_iterator begin, const_iterator end) {
|
||||
for (; begin != end; ++begin)
|
||||
path::append(path, *begin);
|
||||
void append(SmallVectorImpl<char> &path, const Twine &a, const Twine &b,
|
||||
const Twine &c, const Twine &d) {
|
||||
append(path, Style::native, a, b, c, d);
|
||||
}
|
||||
|
||||
StringRef parent_path(StringRef path) {
|
||||
size_t end_pos = parent_path_end(path);
|
||||
void append(SmallVectorImpl<char> &path, const_iterator begin,
|
||||
const_iterator end, Style style) {
|
||||
for (; begin != end; ++begin)
|
||||
path::append(path, style, *begin);
|
||||
}
|
||||
|
||||
StringRef parent_path(StringRef path, Style style) {
|
||||
size_t end_pos = parent_path_end(path, style);
|
||||
if (end_pos == StringRef::npos)
|
||||
return StringRef();
|
||||
else
|
||||
return path.substr(0, end_pos);
|
||||
}
|
||||
|
||||
void remove_filename(SmallVectorImpl<char> &path) {
|
||||
size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()));
|
||||
void remove_filename(SmallVectorImpl<char> &path, Style style) {
|
||||
size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style);
|
||||
if (end_pos != StringRef::npos)
|
||||
path.set_size(end_pos);
|
||||
}
|
||||
|
||||
void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) {
|
||||
void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
|
||||
Style style) {
|
||||
StringRef p(path.begin(), path.size());
|
||||
SmallString<32> ext_storage;
|
||||
StringRef ext = extension.toStringRef(ext_storage);
|
||||
|
||||
// Erase existing extension.
|
||||
size_t pos = p.find_last_of('.');
|
||||
if (pos != StringRef::npos && pos >= filename_pos(p))
|
||||
if (pos != StringRef::npos && pos >= filename_pos(p, style))
|
||||
path.set_size(pos);
|
||||
|
||||
// Append '.' if needed.
|
||||
@@ -445,8 +433,8 @@ void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) {
|
||||
}
|
||||
|
||||
void replace_path_prefix(SmallVectorImpl<char> &Path,
|
||||
const StringRef &OldPrefix,
|
||||
const StringRef &NewPrefix) {
|
||||
const StringRef &OldPrefix, const StringRef &NewPrefix,
|
||||
Style style) {
|
||||
if (OldPrefix.empty() && NewPrefix.empty())
|
||||
return;
|
||||
|
||||
@@ -462,43 +450,58 @@ void replace_path_prefix(SmallVectorImpl<char> &Path,
|
||||
|
||||
StringRef RelPath = OrigPath.substr(OldPrefix.size());
|
||||
SmallString<256> NewPath;
|
||||
path::append(NewPath, NewPrefix);
|
||||
path::append(NewPath, RelPath);
|
||||
path::append(NewPath, style, NewPrefix);
|
||||
path::append(NewPath, style, RelPath);
|
||||
Path.swap(NewPath);
|
||||
}
|
||||
|
||||
void native(const Twine &path, SmallVectorImpl<char> &result) {
|
||||
void native(const Twine &path, SmallVectorImpl<char> &result, Style style) {
|
||||
assert((!path.isSingleStringRef() ||
|
||||
path.getSingleStringRef().data() != result.data()) &&
|
||||
"path and result are not allowed to overlap!");
|
||||
// Clear result.
|
||||
result.clear();
|
||||
path.toVector(result);
|
||||
native(result);
|
||||
native(result, style);
|
||||
}
|
||||
|
||||
void native(SmallVectorImpl<char> &Path) {
|
||||
#ifdef _WIN32
|
||||
std::replace(Path.begin(), Path.end(), '/', '\\');
|
||||
#else
|
||||
for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
|
||||
if (*PI == '\\') {
|
||||
auto PN = PI + 1;
|
||||
if (PN < PE && *PN == '\\')
|
||||
++PI; // increment once, the for loop will move over the escaped slash
|
||||
else
|
||||
*PI = '/';
|
||||
void native(SmallVectorImpl<char> &Path, Style style) {
|
||||
if (Path.empty())
|
||||
return;
|
||||
if (real_style(style) == Style::windows) {
|
||||
std::replace(Path.begin(), Path.end(), '/', '\\');
|
||||
if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) {
|
||||
SmallString<128> PathHome;
|
||||
home_directory(PathHome);
|
||||
PathHome.append(Path.begin() + 1, Path.end());
|
||||
Path = PathHome;
|
||||
}
|
||||
} else {
|
||||
for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) {
|
||||
if (*PI == '\\') {
|
||||
auto PN = PI + 1;
|
||||
if (PN < PE && *PN == '\\')
|
||||
++PI; // increment once, the for loop will move over the escaped slash
|
||||
else
|
||||
*PI = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
StringRef filename(StringRef path) {
|
||||
return *rbegin(path);
|
||||
std::string convert_to_slash(StringRef path, Style style) {
|
||||
if (real_style(style) != Style::windows)
|
||||
return path;
|
||||
|
||||
std::string s = path.str();
|
||||
std::replace(s.begin(), s.end(), '\\', '/');
|
||||
return s;
|
||||
}
|
||||
|
||||
StringRef stem(StringRef path) {
|
||||
StringRef fname = filename(path);
|
||||
StringRef filename(StringRef path, Style style) { return *rbegin(path, style); }
|
||||
|
||||
StringRef stem(StringRef path, Style style) {
|
||||
StringRef fname = filename(path, style);
|
||||
size_t pos = fname.find_last_of('.');
|
||||
if (pos == StringRef::npos)
|
||||
return fname;
|
||||
@@ -510,8 +513,8 @@ StringRef stem(StringRef path) {
|
||||
return fname.substr(0, pos);
|
||||
}
|
||||
|
||||
StringRef extension(StringRef path) {
|
||||
StringRef fname = filename(path);
|
||||
StringRef extension(StringRef path, Style style) {
|
||||
StringRef fname = filename(path, style);
|
||||
size_t pos = fname.find_last_of('.');
|
||||
if (pos == StringRef::npos)
|
||||
return StringRef();
|
||||
@@ -523,132 +526,134 @@ StringRef extension(StringRef path) {
|
||||
return fname.substr(pos);
|
||||
}
|
||||
|
||||
bool is_separator(char value) {
|
||||
switch(value) {
|
||||
#ifdef _WIN32
|
||||
case '\\': // fall through
|
||||
#endif
|
||||
case '/': return true;
|
||||
default: return false;
|
||||
}
|
||||
bool is_separator(char value, Style style) {
|
||||
if (value == '/')
|
||||
return true;
|
||||
if (real_style(style) == Style::windows)
|
||||
return value == '\\';
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char preferred_separator_string[] = { preferred_separator, '\0' };
|
||||
|
||||
StringRef get_separator() {
|
||||
return preferred_separator_string;
|
||||
StringRef get_separator(Style style) {
|
||||
if (real_style(style) == Style::windows)
|
||||
return "\\";
|
||||
return "/";
|
||||
}
|
||||
|
||||
bool has_root_name(const Twine &path) {
|
||||
bool has_root_name(const Twine &path, Style style) {
|
||||
SmallString<128> path_storage;
|
||||
StringRef p = path.toStringRef(path_storage);
|
||||
|
||||
return !root_name(p).empty();
|
||||
return !root_name(p, style).empty();
|
||||
}
|
||||
|
||||
bool has_root_directory(const Twine &path) {
|
||||
bool has_root_directory(const Twine &path, Style style) {
|
||||
SmallString<128> path_storage;
|
||||
StringRef p = path.toStringRef(path_storage);
|
||||
|
||||
return !root_directory(p).empty();
|
||||
return !root_directory(p, style).empty();
|
||||
}
|
||||
|
||||
bool has_root_path(const Twine &path) {
|
||||
bool has_root_path(const Twine &path, Style style) {
|
||||
SmallString<128> path_storage;
|
||||
StringRef p = path.toStringRef(path_storage);
|
||||
|
||||
return !root_path(p).empty();
|
||||
return !root_path(p, style).empty();
|
||||
}
|
||||
|
||||
bool has_relative_path(const Twine &path) {
|
||||
bool has_relative_path(const Twine &path, Style style) {
|
||||
SmallString<128> path_storage;
|
||||
StringRef p = path.toStringRef(path_storage);
|
||||
|
||||
return !relative_path(p).empty();
|
||||
return !relative_path(p, style).empty();
|
||||
}
|
||||
|
||||
bool has_filename(const Twine &path) {
|
||||
bool has_filename(const Twine &path, Style style) {
|
||||
SmallString<128> path_storage;
|
||||
StringRef p = path.toStringRef(path_storage);
|
||||
|
||||
return !filename(p).empty();
|
||||
return !filename(p, style).empty();
|
||||
}
|
||||
|
||||
bool has_parent_path(const Twine &path) {
|
||||
bool has_parent_path(const Twine &path, Style style) {
|
||||
SmallString<128> path_storage;
|
||||
StringRef p = path.toStringRef(path_storage);
|
||||
|
||||
return !parent_path(p).empty();
|
||||
return !parent_path(p, style).empty();
|
||||
}
|
||||
|
||||
bool has_stem(const Twine &path) {
|
||||
bool has_stem(const Twine &path, Style style) {
|
||||
SmallString<128> path_storage;
|
||||
StringRef p = path.toStringRef(path_storage);
|
||||
|
||||
return !stem(p).empty();
|
||||
return !stem(p, style).empty();
|
||||
}
|
||||
|
||||
bool has_extension(const Twine &path) {
|
||||
bool has_extension(const Twine &path, Style style) {
|
||||
SmallString<128> path_storage;
|
||||
StringRef p = path.toStringRef(path_storage);
|
||||
|
||||
return !extension(p).empty();
|
||||
return !extension(p, style).empty();
|
||||
}
|
||||
|
||||
bool is_absolute(const Twine &path) {
|
||||
bool is_absolute(const Twine &path, Style style) {
|
||||
SmallString<128> path_storage;
|
||||
StringRef p = path.toStringRef(path_storage);
|
||||
|
||||
bool rootDir = has_root_directory(p),
|
||||
#ifdef _WIN32
|
||||
rootName = has_root_name(p);
|
||||
#else
|
||||
rootName = true;
|
||||
#endif
|
||||
bool rootDir = has_root_directory(p, style);
|
||||
bool rootName =
|
||||
(real_style(style) != Style::windows) || has_root_name(p, style);
|
||||
|
||||
return rootDir && rootName;
|
||||
}
|
||||
|
||||
bool is_relative(const Twine &path) { return !is_absolute(path); }
|
||||
bool is_relative(const Twine &path, Style style) {
|
||||
return !is_absolute(path, style);
|
||||
}
|
||||
|
||||
StringRef remove_leading_dotslash(StringRef Path) {
|
||||
StringRef remove_leading_dotslash(StringRef Path, Style style) {
|
||||
// Remove leading "./" (or ".//" or "././" etc.)
|
||||
while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1])) {
|
||||
while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) {
|
||||
Path = Path.substr(2);
|
||||
while (Path.size() > 0 && is_separator(Path[0]))
|
||||
while (Path.size() > 0 && is_separator(Path[0], style))
|
||||
Path = Path.substr(1);
|
||||
}
|
||||
return Path;
|
||||
}
|
||||
|
||||
static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot) {
|
||||
static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot,
|
||||
Style style) {
|
||||
SmallVector<StringRef, 16> components;
|
||||
|
||||
// Skip the root path, then look for traversal in the components.
|
||||
StringRef rel = path::relative_path(path);
|
||||
for (StringRef C : wpi::make_range(path::begin(rel), path::end(rel))) {
|
||||
StringRef rel = path::relative_path(path, style);
|
||||
for (StringRef C :
|
||||
wpi::make_range(path::begin(rel, style), path::end(rel))) {
|
||||
if (C == ".")
|
||||
continue;
|
||||
if (remove_dot_dot) {
|
||||
if (C == "..") {
|
||||
if (!components.empty())
|
||||
components.pop_back();
|
||||
// Leading ".." will remain in the path unless it's at the root.
|
||||
if (remove_dot_dot && C == "..") {
|
||||
if (!components.empty() && components.back() != "..") {
|
||||
components.pop_back();
|
||||
continue;
|
||||
}
|
||||
if (path::is_absolute(path, style))
|
||||
continue;
|
||||
}
|
||||
components.push_back(C);
|
||||
}
|
||||
|
||||
SmallString<256> buffer = path::root_path(path);
|
||||
SmallString<256> buffer = path::root_path(path, style);
|
||||
for (StringRef C : components)
|
||||
path::append(buffer, C);
|
||||
path::append(buffer, style, C);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot) {
|
||||
bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot,
|
||||
Style style) {
|
||||
StringRef p(path.data(), path.size());
|
||||
|
||||
SmallString<256> result = remove_dots(p, remove_dot_dot);
|
||||
SmallString<256> result = remove_dots(p, remove_dot_dot, style);
|
||||
if (result == path)
|
||||
return false;
|
||||
|
||||
@@ -674,12 +679,9 @@ static std::error_code make_absolute(const Twine ¤t_directory,
|
||||
bool use_current_directory) {
|
||||
StringRef p(path.data(), path.size());
|
||||
|
||||
bool rootDirectory = path::has_root_directory(p),
|
||||
#ifdef _WIN32
|
||||
rootName = path::has_root_name(p);
|
||||
#else
|
||||
rootName = true;
|
||||
#endif
|
||||
bool rootDirectory = path::has_root_directory(p);
|
||||
bool rootName =
|
||||
(real_style(Style::native) != Style::windows) || path::has_root_name(p);
|
||||
|
||||
// Already absolute.
|
||||
if (rootName && rootDirectory)
|
||||
@@ -736,15 +738,22 @@ std::error_code make_absolute(SmallVectorImpl<char> &path) {
|
||||
return make_absolute(Twine(), path, false);
|
||||
}
|
||||
|
||||
bool exists(file_status status) {
|
||||
bool exists(const basic_file_status &status) {
|
||||
return status_known(status) && status.type() != file_type::file_not_found;
|
||||
}
|
||||
|
||||
bool status_known(file_status s) {
|
||||
bool status_known(const basic_file_status &s) {
|
||||
return s.type() != file_type::status_error;
|
||||
}
|
||||
|
||||
bool is_directory(file_status status) {
|
||||
file_type get_file_type(const Twine &Path, bool Follow) {
|
||||
file_status st;
|
||||
if (status(Path, st, Follow))
|
||||
return file_type::status_error;
|
||||
return st.type();
|
||||
}
|
||||
|
||||
bool is_directory(const basic_file_status &status) {
|
||||
return status.type() == file_type::directory_file;
|
||||
}
|
||||
|
||||
@@ -756,7 +765,7 @@ std::error_code is_directory(const Twine &path, bool &result) {
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
bool is_regular_file(file_status status) {
|
||||
bool is_regular_file(const basic_file_status &status) {
|
||||
return status.type() == file_type::regular_file;
|
||||
}
|
||||
|
||||
@@ -768,7 +777,19 @@ std::error_code is_regular_file(const Twine &path, bool &result) {
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
bool is_other(file_status status) {
|
||||
bool is_symlink_file(const basic_file_status &status) {
|
||||
return status.type() == file_type::symlink_file;
|
||||
}
|
||||
|
||||
std::error_code is_symlink_file(const Twine &path, bool &result) {
|
||||
file_status st;
|
||||
if (std::error_code ec = status(path, st, false))
|
||||
return ec;
|
||||
result = is_symlink_file(st);
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
bool is_other(const basic_file_status &status) {
|
||||
return exists(status) &&
|
||||
!is_regular_file(status) &&
|
||||
!is_directory(status);
|
||||
@@ -782,15 +803,20 @@ std::error_code is_other(const Twine &Path, bool &Result) {
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
void directory_entry::replace_filename(const Twine &filename, file_status st) {
|
||||
void directory_entry::replace_filename(const Twine &filename,
|
||||
basic_file_status st) {
|
||||
SmallString<128> path = path::parent_path(Path);
|
||||
path::append(path, filename);
|
||||
Path = path.str();
|
||||
Status = st;
|
||||
}
|
||||
|
||||
std::error_code directory_entry::status(file_status &result) const {
|
||||
return fs::status(Path, result);
|
||||
ErrorOr<perms> getPermissions(const Twine &Path) {
|
||||
file_status Status;
|
||||
if (std::error_code EC = status(Path, Status))
|
||||
return EC;
|
||||
|
||||
return Status.permissions();
|
||||
}
|
||||
|
||||
} // end namespace fs
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
#include "wpi/SmallPtrSet.h"
|
||||
#include "wpi/DenseMapInfo.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/memory.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace wpi;
|
||||
@@ -30,8 +32,7 @@ void SmallPtrSetImplBase::shrink_and_clear() {
|
||||
NumNonEmpty = NumTombstones = 0;
|
||||
|
||||
// Install the new array. Clear all the buckets to empty.
|
||||
CurArray = (const void**)malloc(sizeof(void*) * CurArraySize);
|
||||
assert(CurArray && "Failed to allocate memory?");
|
||||
CurArray = (const void**)CheckedMalloc(sizeof(void*) * CurArraySize);
|
||||
memset(CurArray, -1, CurArraySize*sizeof(void*));
|
||||
}
|
||||
|
||||
@@ -60,38 +61,13 @@ SmallPtrSetImplBase::insert_imp_big(const void *Ptr) {
|
||||
return std::make_pair(Bucket, true);
|
||||
}
|
||||
|
||||
bool SmallPtrSetImplBase::erase_imp(const void * Ptr) {
|
||||
if (isSmall()) {
|
||||
// Check to see if it is in the set.
|
||||
for (const void **APtr = CurArray, **E = CurArray + NumNonEmpty; APtr != E;
|
||||
++APtr)
|
||||
if (*APtr == Ptr) {
|
||||
// If it is in the set, replace this element.
|
||||
*APtr = getTombstoneMarker();
|
||||
++NumTombstones;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Okay, we know we have space. Find a hash bucket.
|
||||
void **Bucket = const_cast<void**>(FindBucketFor(Ptr));
|
||||
if (*Bucket != Ptr) return false; // Not in the set?
|
||||
|
||||
// Set this as a tombstone.
|
||||
*Bucket = getTombstoneMarker();
|
||||
++NumTombstones;
|
||||
return true;
|
||||
}
|
||||
|
||||
const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const {
|
||||
unsigned Bucket = DenseMapInfo<void *>::getHashValue(Ptr) & (CurArraySize-1);
|
||||
unsigned ArraySize = CurArraySize;
|
||||
unsigned ProbeAmt = 1;
|
||||
const void *const *Array = CurArray;
|
||||
const void *const *Tombstone = nullptr;
|
||||
while (1) {
|
||||
while (true) {
|
||||
// If we found an empty bucket, the pointer doesn't exist in the set.
|
||||
// Return a tombstone if we've seen one so far, or the empty bucket if
|
||||
// not.
|
||||
@@ -120,8 +96,7 @@ void SmallPtrSetImplBase::Grow(unsigned NewSize) {
|
||||
bool WasSmall = isSmall();
|
||||
|
||||
// Install the new array. Clear all the buckets to empty.
|
||||
CurArray = (const void**)malloc(sizeof(void*) * NewSize);
|
||||
assert(CurArray && "Failed to allocate memory?");
|
||||
CurArray = (const void**) CheckedMalloc(sizeof(void*) * NewSize);
|
||||
CurArraySize = NewSize;
|
||||
memset(CurArray, -1, NewSize*sizeof(void*));
|
||||
|
||||
@@ -148,8 +123,7 @@ SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
|
||||
CurArray = SmallArray;
|
||||
// Otherwise, allocate new heap space (unless we were the same size)
|
||||
} else {
|
||||
CurArray = (const void**)malloc(sizeof(void*) * that.CurArraySize);
|
||||
assert(CurArray && "Failed to allocate memory?");
|
||||
CurArray = (const void**)CheckedMalloc(sizeof(void*) * that.CurArraySize);
|
||||
}
|
||||
|
||||
// Copy over the that array.
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/memory.h"
|
||||
using namespace wpi;
|
||||
|
||||
/// grow_pod - This is an implementation of the grow() method which only works
|
||||
@@ -25,15 +26,14 @@ void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes,
|
||||
|
||||
void *NewElts;
|
||||
if (BeginX == FirstEl) {
|
||||
NewElts = malloc(NewCapacityInBytes);
|
||||
NewElts = CheckedMalloc(NewCapacityInBytes);
|
||||
|
||||
// Copy the elements over. No need to run dtors on PODs.
|
||||
memcpy(NewElts, this->BeginX, CurSizeBytes);
|
||||
} else {
|
||||
// If this wasn't grown from the inline copy, grow the allocated space.
|
||||
NewElts = realloc(this->BeginX, NewCapacityInBytes);
|
||||
NewElts = CheckedRealloc(this->BeginX, NewCapacityInBytes);
|
||||
}
|
||||
assert(NewElts && "Out of memory");
|
||||
|
||||
this->EndX = (char*)NewElts+CurSizeBytes;
|
||||
this->BeginX = NewElts;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/raw_ostream.h"
|
||||
using namespace wpi;
|
||||
|
||||
/// StrInStrNoCase - Portable version of strcasestr. Locates the first
|
||||
@@ -56,3 +57,18 @@ void wpi::SplitString(StringRef Source,
|
||||
S = getToken(S.second, Delimiters);
|
||||
}
|
||||
}
|
||||
|
||||
void wpi::PrintEscapedString(StringRef Name, raw_ostream &Out) {
|
||||
for (unsigned i = 0, e = Name.size(); i != e; ++i) {
|
||||
unsigned char C = Name[i];
|
||||
if (isprint(C) && C != '\\' && C != '"')
|
||||
Out << C;
|
||||
else
|
||||
Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
|
||||
}
|
||||
}
|
||||
|
||||
void wpi::printLowerCase(StringRef String, raw_ostream &Out) {
|
||||
for (const char C : String)
|
||||
Out << toLower(C);
|
||||
}
|
||||
|
||||
@@ -12,10 +12,12 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/StringMap.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/memory.h"
|
||||
#include <cassert>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
/// Returns the number of buckets to allocate to ensure that the DenseMap can
|
||||
@@ -51,20 +53,23 @@ StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) {
|
||||
void StringMapImpl::init(unsigned InitSize) {
|
||||
assert((InitSize & (InitSize-1)) == 0 &&
|
||||
"Init Size must be a power of 2 or zero!");
|
||||
NumBuckets = InitSize ? InitSize : 16;
|
||||
|
||||
unsigned NewNumBuckets = InitSize ? InitSize : 16;
|
||||
NumItems = 0;
|
||||
NumTombstones = 0;
|
||||
|
||||
TheTable = (StringMapEntryBase **)calloc(NumBuckets+1,
|
||||
sizeof(StringMapEntryBase **) +
|
||||
sizeof(unsigned));
|
||||
TheTable = static_cast<StringMapEntryBase **>(
|
||||
CheckedCalloc(NewNumBuckets+1,
|
||||
sizeof(StringMapEntryBase **) + sizeof(unsigned)));
|
||||
|
||||
// Set the member only if TheTable was successfully allocated
|
||||
NumBuckets = NewNumBuckets;
|
||||
|
||||
// Allocate one extra bucket, set it to look filled so the iterators stop at
|
||||
// end.
|
||||
TheTable[NumBuckets] = (StringMapEntryBase*)2;
|
||||
}
|
||||
|
||||
|
||||
/// LookupBucketFor - Look up the bucket that the specified string should end
|
||||
/// up in. If it already exists as a key in the map, the Item pointer for the
|
||||
/// specified bucket will be non-null. Otherwise, it will be null. In either
|
||||
@@ -82,7 +87,7 @@ unsigned StringMapImpl::LookupBucketFor(StringRef Name) {
|
||||
|
||||
unsigned ProbeAmt = 1;
|
||||
int FirstTombstone = -1;
|
||||
while (1) {
|
||||
while (true) {
|
||||
StringMapEntryBase *BucketItem = TheTable[BucketNo];
|
||||
// If we found an empty bucket, this key isn't in the table yet, return it.
|
||||
if (LLVM_LIKELY(!BucketItem)) {
|
||||
@@ -136,7 +141,7 @@ int StringMapImpl::FindKey(StringRef Key) const {
|
||||
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
|
||||
|
||||
unsigned ProbeAmt = 1;
|
||||
while (1) {
|
||||
while (true) {
|
||||
StringMapEntryBase *BucketItem = TheTable[BucketNo];
|
||||
// If we found an empty bucket, this key isn't in the table yet, return.
|
||||
if (LLVM_LIKELY(!BucketItem))
|
||||
@@ -192,8 +197,6 @@ StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// RehashTable - Grow the table, redistributing values into the buckets with
|
||||
/// the appropriate mod-of-hashtable-size.
|
||||
unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
|
||||
@@ -215,9 +218,9 @@ unsigned StringMapImpl::RehashTable(unsigned BucketNo) {
|
||||
unsigned NewBucketNo = BucketNo;
|
||||
// Allocate one extra bucket which will always be non-empty. This allows the
|
||||
// iterators to stop at end.
|
||||
StringMapEntryBase **NewTableArray =
|
||||
(StringMapEntryBase **)calloc(NewSize+1, sizeof(StringMapEntryBase *) +
|
||||
sizeof(unsigned));
|
||||
auto NewTableArray = static_cast<StringMapEntryBase **>(
|
||||
CheckedCalloc(NewSize+1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
|
||||
|
||||
unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
|
||||
NewTableArray[NewSize] = (StringMapEntryBase*)2;
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Hashing.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include <bitset>
|
||||
#include <climits>
|
||||
#include <ostream>
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
@@ -20,28 +22,12 @@ using namespace wpi;
|
||||
const size_t StringRef::npos;
|
||||
#endif
|
||||
|
||||
static char ascii_tolower(char x) noexcept {
|
||||
if (x >= 'A' && x <= 'Z')
|
||||
return x - 'A' + 'a';
|
||||
return x;
|
||||
}
|
||||
|
||||
static char ascii_toupper(char x) noexcept {
|
||||
if (x >= 'a' && x <= 'z')
|
||||
return x - 'a' + 'A';
|
||||
return x;
|
||||
}
|
||||
|
||||
static bool ascii_isdigit(char x) noexcept {
|
||||
return x >= '0' && x <= '9';
|
||||
}
|
||||
|
||||
// strncasecmp() is not available on non-POSIX systems, so define an
|
||||
// alternative function here.
|
||||
static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) noexcept {
|
||||
for (size_t I = 0; I < Length; ++I) {
|
||||
unsigned char LHC = ascii_tolower(LHS[I]);
|
||||
unsigned char RHC = ascii_tolower(RHS[I]);
|
||||
unsigned char LHC = toLower(LHS[I]);
|
||||
unsigned char RHC = toLower(RHS[I]);
|
||||
if (LHC != RHC)
|
||||
return LHC < RHC ? -1 : 1;
|
||||
}
|
||||
@@ -50,36 +36,41 @@ static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) no
|
||||
|
||||
/// compare_lower - Compare strings, ignoring case.
|
||||
int StringRef::compare_lower(StringRef RHS) const noexcept {
|
||||
if (int Res = ascii_strncasecmp(Data, RHS.Data, std::min(size(), RHS.size())))
|
||||
if (int Res = ascii_strncasecmp(Data, RHS.Data, std::min(Length, RHS.Length)))
|
||||
return Res;
|
||||
if (size() == RHS.size())
|
||||
if (Length == RHS.Length)
|
||||
return 0;
|
||||
return size() < RHS.size() ? -1 : 1;
|
||||
return Length < RHS.Length ? -1 : 1;
|
||||
}
|
||||
|
||||
/// Check if this string starts with the given \p Prefix, ignoring case.
|
||||
bool StringRef::startswith_lower(StringRef Prefix) const noexcept {
|
||||
return size() >= Prefix.size() &&
|
||||
ascii_strncasecmp(Data, Prefix.Data, Prefix.size()) == 0;
|
||||
return Length >= Prefix.Length &&
|
||||
ascii_strncasecmp(Data, Prefix.Data, Prefix.Length) == 0;
|
||||
}
|
||||
|
||||
/// Check if this string ends with the given \p Suffix, ignoring case.
|
||||
bool StringRef::endswith_lower(StringRef Suffix) const noexcept {
|
||||
return size() >= Suffix.size() &&
|
||||
ascii_strncasecmp(end() - Suffix.size(), Suffix.Data, Suffix.size()) == 0;
|
||||
return Length >= Suffix.Length &&
|
||||
ascii_strncasecmp(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0;
|
||||
}
|
||||
|
||||
size_t StringRef::find_lower(char C, size_t From) const noexcept {
|
||||
char L = toLower(C);
|
||||
return find_if([L](char D) { return toLower(D) == L; }, From);
|
||||
}
|
||||
|
||||
/// compare_numeric - Compare strings, handle embedded numbers.
|
||||
int StringRef::compare_numeric(StringRef RHS) const noexcept {
|
||||
for (size_t I = 0, E = std::min(size(), RHS.size()); I != E; ++I) {
|
||||
for (size_t I = 0, E = std::min(Length, RHS.Length); I != E; ++I) {
|
||||
// Check for sequences of digits.
|
||||
if (ascii_isdigit(Data[I]) && ascii_isdigit(RHS.Data[I])) {
|
||||
if (isDigit(Data[I]) && isDigit(RHS.Data[I])) {
|
||||
// The longer sequence of numbers is considered larger.
|
||||
// This doesn't really handle prefixed zeros well.
|
||||
size_t J;
|
||||
for (J = I + 1; J != E + 1; ++J) {
|
||||
bool ld = J < size() && ascii_isdigit(Data[J]);
|
||||
bool rd = J < RHS.size() && ascii_isdigit(RHS.Data[J]);
|
||||
bool ld = J < Length && isDigit(Data[J]);
|
||||
bool rd = J < RHS.Length && isDigit(RHS.Data[J]);
|
||||
if (ld != rd)
|
||||
return rd ? -1 : 1;
|
||||
if (!rd)
|
||||
@@ -95,9 +86,9 @@ int StringRef::compare_numeric(StringRef RHS) const noexcept {
|
||||
if (Data[I] != RHS.Data[I])
|
||||
return (unsigned char)Data[I] < (unsigned char)RHS.Data[I] ? -1 : 1;
|
||||
}
|
||||
if (size() == RHS.size())
|
||||
if (Length == RHS.Length)
|
||||
return 0;
|
||||
return size() < RHS.size() ? -1 : 1;
|
||||
return Length < RHS.Length ? -1 : 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -107,7 +98,7 @@ int StringRef::compare_numeric(StringRef RHS) const noexcept {
|
||||
std::string StringRef::lower() const {
|
||||
std::string Result(size(), char());
|
||||
for (size_type i = 0, e = size(); i != e; ++i) {
|
||||
Result[i] = ascii_tolower(Data[i]);
|
||||
Result[i] = toLower(Data[i]);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
@@ -115,25 +106,11 @@ std::string StringRef::lower() const {
|
||||
std::string StringRef::upper() const {
|
||||
std::string Result(size(), char());
|
||||
for (size_type i = 0, e = size(); i != e; ++i) {
|
||||
Result[i] = ascii_toupper(Data[i]);
|
||||
Result[i] = toUpper(Data[i]);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
const char *StringRef::c_str(wpi::SmallVectorImpl<char>& buf) const {
|
||||
if (is_null_terminated()) {
|
||||
// If null terminated, return data directly
|
||||
return data();
|
||||
} else {
|
||||
// If not null terminated, use SmallVectorImpl to store data
|
||||
// copy data, and return a known null terminated string
|
||||
buf.clear();
|
||||
buf.append(begin(), end());
|
||||
buf.push_back(0);
|
||||
return buf.begin();
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// String Searching
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -144,19 +121,23 @@ const char *StringRef::c_str(wpi::SmallVectorImpl<char>& buf) const {
|
||||
/// \return - The index of the first occurrence of \arg Str, or npos if not
|
||||
/// found.
|
||||
size_t StringRef::find(StringRef Str, size_t From) const noexcept {
|
||||
if (From > size())
|
||||
if (From > Length)
|
||||
return npos;
|
||||
|
||||
const char *Start = Data + From;
|
||||
size_t Size = Length - From;
|
||||
|
||||
const char *Needle = Str.data();
|
||||
size_t N = Str.size();
|
||||
if (N == 0)
|
||||
return From;
|
||||
|
||||
size_t Size = size() - From;
|
||||
if (Size < N)
|
||||
return npos;
|
||||
if (N == 1) {
|
||||
const char *Ptr = (const char *)::memchr(Start, Needle[0], Size);
|
||||
return Ptr == nullptr ? npos : Ptr - Data;
|
||||
}
|
||||
|
||||
const char *Start = Data + From;
|
||||
const char *Stop = Start + (Size - N + 1);
|
||||
|
||||
// For short haystacks or unsupported needles fall back to the naive algorithm
|
||||
@@ -176,25 +157,49 @@ size_t StringRef::find(StringRef Str, size_t From) const noexcept {
|
||||
BadCharSkip[(uint8_t)Str[i]] = N-1-i;
|
||||
|
||||
do {
|
||||
if (std::memcmp(Start, Needle, N) == 0)
|
||||
return Start - Data;
|
||||
uint8_t Last = Start[N - 1];
|
||||
if (LLVM_UNLIKELY(Last == (uint8_t)Needle[N - 1]))
|
||||
if (std::memcmp(Start, Needle, N - 1) == 0)
|
||||
return Start - Data;
|
||||
|
||||
// Otherwise skip the appropriate number of bytes.
|
||||
Start += BadCharSkip[(uint8_t)Start[N-1]];
|
||||
Start += BadCharSkip[Last];
|
||||
} while (Start < Stop);
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t StringRef::find_lower(StringRef Str, size_t From) const noexcept {
|
||||
StringRef This = substr(From);
|
||||
while (This.size() >= Str.size()) {
|
||||
if (This.startswith_lower(Str))
|
||||
return From;
|
||||
This = This.drop_front();
|
||||
++From;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t StringRef::rfind_lower(char C, size_t From) const noexcept {
|
||||
From = std::min(From, Length);
|
||||
size_t i = From;
|
||||
while (i != 0) {
|
||||
--i;
|
||||
if (toLower(Data[i]) == toLower(C))
|
||||
return i;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// rfind - Search for the last string \arg Str in the string.
|
||||
///
|
||||
/// \return - The index of the last occurrence of \arg Str, or npos if not
|
||||
/// found.
|
||||
size_t StringRef::rfind(StringRef Str) const noexcept {
|
||||
size_t N = Str.size();
|
||||
if (N > size())
|
||||
if (N > Length)
|
||||
return npos;
|
||||
for (size_t i = size() - N + 1, e = 0; i != e;) {
|
||||
for (size_t i = Length - N + 1, e = 0; i != e;) {
|
||||
--i;
|
||||
if (substr(i, N).equals(Str))
|
||||
return i;
|
||||
@@ -202,6 +207,18 @@ size_t StringRef::rfind(StringRef Str) const noexcept {
|
||||
return npos;
|
||||
}
|
||||
|
||||
size_t StringRef::rfind_lower(StringRef Str) const noexcept {
|
||||
size_t N = Str.size();
|
||||
if (N > Length)
|
||||
return npos;
|
||||
for (size_t i = Length - N + 1, e = 0; i != e;) {
|
||||
--i;
|
||||
if (substr(i, N).equals_lower(Str))
|
||||
return i;
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
/// find_first_of - Find the first character in the string that is in \arg
|
||||
/// Chars, or npos if not found.
|
||||
///
|
||||
@@ -212,7 +229,7 @@ StringRef::size_type StringRef::find_first_of(StringRef Chars,
|
||||
for (size_type i = 0; i != Chars.size(); ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, size()), e = size(); i != e; ++i)
|
||||
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
|
||||
if (CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
@@ -221,7 +238,7 @@ StringRef::size_type StringRef::find_first_of(StringRef Chars,
|
||||
/// find_first_not_of - Find the first character in the string that is not
|
||||
/// \arg C or npos if not found.
|
||||
StringRef::size_type StringRef::find_first_not_of(char C, size_t From) const noexcept {
|
||||
for (size_type i = std::min(From, size()), e = size(); i != e; ++i)
|
||||
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
|
||||
if (Data[i] != C)
|
||||
return i;
|
||||
return npos;
|
||||
@@ -237,7 +254,7 @@ StringRef::size_type StringRef::find_first_not_of(StringRef Chars,
|
||||
for (size_type i = 0; i != Chars.size(); ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, size()), e = size(); i != e; ++i)
|
||||
for (size_type i = std::min(From, Length), e = Length; i != e; ++i)
|
||||
if (!CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
@@ -253,7 +270,7 @@ StringRef::size_type StringRef::find_last_of(StringRef Chars,
|
||||
for (size_type i = 0; i != Chars.size(); ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, size()) - 1, e = -1; i != e; --i)
|
||||
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
|
||||
if (CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
@@ -262,7 +279,7 @@ StringRef::size_type StringRef::find_last_of(StringRef Chars,
|
||||
/// find_last_not_of - Find the last character in the string that is not
|
||||
/// \arg C, or npos if not found.
|
||||
StringRef::size_type StringRef::find_last_not_of(char C, size_t From) const noexcept {
|
||||
for (size_type i = std::min(From, size()) - 1, e = -1; i != e; --i)
|
||||
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
|
||||
if (Data[i] != C)
|
||||
return i;
|
||||
return npos;
|
||||
@@ -278,7 +295,7 @@ StringRef::size_type StringRef::find_last_not_of(StringRef Chars,
|
||||
for (size_type i = 0, e = Chars.size(); i != e; ++i)
|
||||
CharBits.set((unsigned char)Chars[i]);
|
||||
|
||||
for (size_type i = std::min(From, size()) - 1, e = -1; i != e; --i)
|
||||
for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
|
||||
if (!CharBits.test((unsigned char)Data[i]))
|
||||
return i;
|
||||
return npos;
|
||||
@@ -346,15 +363,18 @@ void StringRef::split(SmallVectorImpl<StringRef> &A, char Separator,
|
||||
size_t StringRef::count(StringRef Str) const noexcept {
|
||||
size_t Count = 0;
|
||||
size_t N = Str.size();
|
||||
if (N > size())
|
||||
if (N > Length)
|
||||
return 0;
|
||||
for (size_t i = 0, e = size() - N + 1; i != e; ++i)
|
||||
for (size_t i = 0, e = Length - N + 1; i != e; ++i)
|
||||
if (substr(i, N).equals(Str))
|
||||
++Count;
|
||||
return Count;
|
||||
}
|
||||
|
||||
static unsigned GetAutoSenseRadix(StringRef &Str) noexcept {
|
||||
if (Str.empty())
|
||||
return 10;
|
||||
|
||||
if (Str.startswith("0x") || Str.startswith("0X")) {
|
||||
Str = Str.substr(2);
|
||||
return 16;
|
||||
@@ -370,17 +390,16 @@ static unsigned GetAutoSenseRadix(StringRef &Str) noexcept {
|
||||
return 8;
|
||||
}
|
||||
|
||||
if (Str.startswith("0"))
|
||||
if (Str[0] == '0' && Str.size() > 1 && isDigit(Str[1])) {
|
||||
Str = Str.substr(1);
|
||||
return 8;
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
||||
/// GetAsUnsignedInteger - Workhorse method that converts a integer character
|
||||
/// sequence of radix up to 36 to an unsigned long long value.
|
||||
bool wpi::getAsUnsignedInteger(StringRef Str, unsigned Radix,
|
||||
unsigned long long &Result) noexcept {
|
||||
bool wpi::consumeUnsignedInteger(StringRef &Str, unsigned Radix,
|
||||
unsigned long long &Result) noexcept {
|
||||
// Autosense radix if not specified.
|
||||
if (Radix == 0)
|
||||
Radix = GetAutoSenseRadix(Str);
|
||||
@@ -389,44 +408,51 @@ bool wpi::getAsUnsignedInteger(StringRef Str, unsigned Radix,
|
||||
if (Str.empty()) return true;
|
||||
|
||||
// Parse all the bytes of the string given this radix. Watch for overflow.
|
||||
StringRef Str2 = Str;
|
||||
Result = 0;
|
||||
while (!Str.empty()) {
|
||||
while (!Str2.empty()) {
|
||||
unsigned CharVal;
|
||||
if (Str[0] >= '0' && Str[0] <= '9')
|
||||
CharVal = Str[0]-'0';
|
||||
else if (Str[0] >= 'a' && Str[0] <= 'z')
|
||||
CharVal = Str[0]-'a'+10;
|
||||
else if (Str[0] >= 'A' && Str[0] <= 'Z')
|
||||
CharVal = Str[0]-'A'+10;
|
||||
if (Str2[0] >= '0' && Str2[0] <= '9')
|
||||
CharVal = Str2[0] - '0';
|
||||
else if (Str2[0] >= 'a' && Str2[0] <= 'z')
|
||||
CharVal = Str2[0] - 'a' + 10;
|
||||
else if (Str2[0] >= 'A' && Str2[0] <= 'Z')
|
||||
CharVal = Str2[0] - 'A' + 10;
|
||||
else
|
||||
return true;
|
||||
break;
|
||||
|
||||
// If the parsed value is larger than the integer radix, the string is
|
||||
// invalid.
|
||||
// If the parsed value is larger than the integer radix, we cannot
|
||||
// consume any more characters.
|
||||
if (CharVal >= Radix)
|
||||
return true;
|
||||
break;
|
||||
|
||||
// Add in this character.
|
||||
unsigned long long PrevResult = Result;
|
||||
Result = Result*Radix+CharVal;
|
||||
Result = Result * Radix + CharVal;
|
||||
|
||||
// Check for overflow by shifting back and seeing if bits were lost.
|
||||
if (Result/Radix < PrevResult)
|
||||
if (Result / Radix < PrevResult)
|
||||
return true;
|
||||
|
||||
Str = Str.substr(1);
|
||||
Str2 = Str2.substr(1);
|
||||
}
|
||||
|
||||
// We consider the operation a failure if no characters were consumed
|
||||
// successfully.
|
||||
if (Str.size() == Str2.size())
|
||||
return true;
|
||||
|
||||
Str = Str2;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wpi::getAsSignedInteger(StringRef Str, unsigned Radix,
|
||||
long long &Result) noexcept {
|
||||
bool wpi::consumeSignedInteger(StringRef &Str, unsigned Radix,
|
||||
long long &Result) noexcept {
|
||||
unsigned long long ULLVal;
|
||||
|
||||
// Handle positive strings first.
|
||||
if (Str.empty() || Str.front() != '-') {
|
||||
if (getAsUnsignedInteger(Str, Radix, ULLVal) ||
|
||||
if (consumeUnsignedInteger(Str, Radix, ULLVal) ||
|
||||
// Check for value so large it overflows a signed value.
|
||||
(long long)ULLVal < 0)
|
||||
return true;
|
||||
@@ -435,17 +461,46 @@ bool wpi::getAsSignedInteger(StringRef Str, unsigned Radix,
|
||||
}
|
||||
|
||||
// Get the positive part of the value.
|
||||
if (getAsUnsignedInteger(Str.substr(1), Radix, ULLVal) ||
|
||||
StringRef Str2 = Str.drop_front(1);
|
||||
if (consumeUnsignedInteger(Str2, Radix, ULLVal) ||
|
||||
// Reject values so large they'd overflow as negative signed, but allow
|
||||
// "-0". This negates the unsigned so that the negative isn't undefined
|
||||
// on signed overflow.
|
||||
(long long)-ULLVal > 0)
|
||||
return true;
|
||||
|
||||
Str = Str2;
|
||||
Result = -ULLVal;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// GetAsUnsignedInteger - Workhorse method that converts a integer character
|
||||
/// sequence of radix up to 36 to an unsigned long long value.
|
||||
bool wpi::getAsUnsignedInteger(StringRef Str, unsigned Radix,
|
||||
unsigned long long &Result) noexcept {
|
||||
if (consumeUnsignedInteger(Str, Radix, Result))
|
||||
return true;
|
||||
|
||||
// For getAsUnsignedInteger, we require the whole string to be consumed or
|
||||
// else we consider it a failure.
|
||||
return !Str.empty();
|
||||
}
|
||||
|
||||
bool wpi::getAsSignedInteger(StringRef Str, unsigned Radix,
|
||||
long long &Result) noexcept {
|
||||
if (consumeSignedInteger(Str, Radix, Result))
|
||||
return true;
|
||||
|
||||
// For getAsSignedInteger, we require the whole string to be consumed or else
|
||||
// we consider it a failure.
|
||||
return !Str.empty();
|
||||
}
|
||||
|
||||
std::ostream &wpi::operator<<(std::ostream &os, StringRef string) {
|
||||
os.write(string.data(), string.size());
|
||||
return os;
|
||||
}
|
||||
|
||||
// Implementation of StringRef hashing.
|
||||
hash_code wpi::hash_value(StringRef S) {
|
||||
return hash_combine_range(S.begin(), S.end());
|
||||
|
||||
@@ -160,10 +160,10 @@ void Twine::printRepr(raw_ostream &OS) const {
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void Twine::dump() const {
|
||||
LLVM_DUMP_METHOD void Twine::dump() const {
|
||||
print(errs());
|
||||
}
|
||||
|
||||
void Twine::dumpRepr() const {
|
||||
LLVM_DUMP_METHOD void Twine::dumpRepr() const {
|
||||
printRepr(errs());
|
||||
}
|
||||
|
||||
@@ -145,21 +145,20 @@ static std::error_code fillStatus(int StatRet, const struct stat &Status,
|
||||
else if (S_ISLNK(Status.st_mode))
|
||||
Type = file_type::symlink_file;
|
||||
|
||||
perms Perms = static_cast<perms>(Status.st_mode);
|
||||
Result =
|
||||
file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_atime,
|
||||
Status.st_mtime, Status.st_uid, Status.st_gid,
|
||||
Status.st_size);
|
||||
perms Perms = static_cast<perms>(Status.st_mode) & all_perms;
|
||||
Result = file_status(Type, Perms, Status.st_dev, Status.st_nlink,
|
||||
Status.st_ino, Status.st_atime, Status.st_mtime,
|
||||
Status.st_uid, Status.st_gid, Status.st_size);
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code status(const Twine &Path, file_status &Result) {
|
||||
std::error_code status(const Twine &Path, file_status &Result, bool Follow) {
|
||||
SmallString<128> PathStorage;
|
||||
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
|
||||
|
||||
struct stat Status;
|
||||
int StatRet = ::lstat(P.begin(), &Status);
|
||||
int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status);
|
||||
return fillStatus(StatRet, Status, Result);
|
||||
}
|
||||
|
||||
@@ -170,7 +169,8 @@ std::error_code status(int FD, file_status &Result) {
|
||||
}
|
||||
|
||||
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
|
||||
StringRef path){
|
||||
StringRef path,
|
||||
bool follow_symlinks) {
|
||||
SmallString<128> path_null(path);
|
||||
DIR *directory = ::opendir(path_null.c_str());
|
||||
if (!directory)
|
||||
@@ -179,7 +179,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
|
||||
it.IterationHandle = reinterpret_cast<intptr_t>(directory);
|
||||
// Add something for replace_filename to replace.
|
||||
path::append(path_null, ".");
|
||||
it.CurrentEntry = directory_entry(path_null.str());
|
||||
it.CurrentEntry = directory_entry(path_null.str(), follow_symlinks);
|
||||
return directory_iterator_increment(it);
|
||||
}
|
||||
|
||||
@@ -208,6 +208,13 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
ErrorOr<basic_file_status> directory_entry::status() const {
|
||||
file_status s;
|
||||
if (auto EC = fs::status(Path, s, FollowSymlinks))
|
||||
return EC;
|
||||
return s;
|
||||
}
|
||||
|
||||
#if !defined(F_GETPATH)
|
||||
static bool hasProcSelfFD() {
|
||||
// If we have a /proc filesystem mounted, we can quickly establish the
|
||||
@@ -260,6 +267,10 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
|
||||
int OpenFlags = O_CREAT;
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
OpenFlags |= O_CLOEXEC;
|
||||
#endif
|
||||
|
||||
if (Flags & F_RW)
|
||||
OpenFlags |= O_RDWR;
|
||||
else
|
||||
@@ -267,7 +278,7 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
|
||||
if (Flags & F_Append)
|
||||
OpenFlags |= O_APPEND;
|
||||
else
|
||||
else if (!(Flags & F_NoTrunc))
|
||||
OpenFlags |= O_TRUNC;
|
||||
|
||||
if (Flags & F_Excl)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
// These two headers must be included last, and make sure shlobj is required
|
||||
// after Windows.h to make sure it picks up our definition of _WIN32_WINNT
|
||||
#include "WindowsSupport.h"
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#undef max
|
||||
@@ -38,6 +39,7 @@
|
||||
using namespace wpi;
|
||||
|
||||
using wpi::sys::windows::UTF8ToUTF16;
|
||||
using wpi::sys::windows::CurCPToUTF16;
|
||||
using wpi::sys::windows::UTF16ToUTF8;
|
||||
using wpi::sys::path::widenPath;
|
||||
|
||||
@@ -87,13 +89,16 @@ std::error_code widenPath(const Twine &Path8,
|
||||
return EC;
|
||||
FullPath.append(CurPath);
|
||||
}
|
||||
// Traverse the requested path, canonicalizing . and .. as we go (because
|
||||
// the \\?\ prefix is documented to treat them as real components).
|
||||
// The iterators don't report separators and append() always attaches
|
||||
// preferred_separator so we don't need to call native() on the result.
|
||||
// Traverse the requested path, canonicalizing . and .. (because the \\?\
|
||||
// prefix is documented to treat them as real components). Ignore
|
||||
// separators, which can be returned from the iterator if the path has a
|
||||
// drive name. We don't need to call native() on the result since append()
|
||||
// always attaches preferred_separator.
|
||||
for (wpi::sys::path::const_iterator I = wpi::sys::path::begin(Path8Str),
|
||||
E = wpi::sys::path::end(Path8Str);
|
||||
I != E; ++I) {
|
||||
if (I->size() == 1 && is_separator((*I)[0]))
|
||||
continue;
|
||||
if (I->size() == 1 && *I == ".")
|
||||
continue;
|
||||
if (I->size() == 2 && *I == "..")
|
||||
@@ -214,6 +219,15 @@ static bool isReservedName(StringRef path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static file_type file_type_from_attrs(DWORD Attrs) {
|
||||
return (Attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file
|
||||
: file_type::regular_file;
|
||||
}
|
||||
|
||||
static perms perms_from_attrs(DWORD Attrs) {
|
||||
return (Attrs & FILE_ATTRIBUTE_READONLY) ? (all_read | all_exe) : all_all;
|
||||
}
|
||||
|
||||
static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
|
||||
if (FileHandle == INVALID_HANDLE_VALUE)
|
||||
goto handle_status_error;
|
||||
@@ -243,19 +257,14 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
|
||||
if (!::GetFileInformationByHandle(FileHandle, &Info))
|
||||
goto handle_status_error;
|
||||
|
||||
{
|
||||
file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
? file_type::directory_file
|
||||
: file_type::regular_file;
|
||||
Result =
|
||||
file_status(Type, Info.ftLastAccessTime.dwHighDateTime,
|
||||
Info.ftLastAccessTime.dwLowDateTime,
|
||||
Info.ftLastWriteTime.dwHighDateTime,
|
||||
Info.ftLastWriteTime.dwLowDateTime,
|
||||
Info.dwVolumeSerialNumber, Info.nFileSizeHigh,
|
||||
Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow);
|
||||
return std::error_code();
|
||||
}
|
||||
Result = file_status(
|
||||
file_type_from_attrs(Info.dwFileAttributes),
|
||||
perms_from_attrs(Info.dwFileAttributes), Info.nNumberOfLinks,
|
||||
Info.ftLastAccessTime.dwHighDateTime, Info.ftLastAccessTime.dwLowDateTime,
|
||||
Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime,
|
||||
Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow,
|
||||
Info.nFileIndexHigh, Info.nFileIndexLow);
|
||||
return std::error_code();
|
||||
|
||||
handle_status_error:
|
||||
DWORD LastError = ::GetLastError();
|
||||
@@ -269,7 +278,7 @@ handle_status_error:
|
||||
return mapWindowsError(LastError);
|
||||
}
|
||||
|
||||
std::error_code status(const Twine &path, file_status &result) {
|
||||
std::error_code status(const Twine &path, file_status &result, bool Follow) {
|
||||
SmallString<128> path_storage;
|
||||
SmallVector<wchar_t, 128> path_utf16;
|
||||
|
||||
@@ -286,28 +295,19 @@ std::error_code status(const Twine &path, file_status &result) {
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
return getStatus(INVALID_HANDLE_VALUE, result);
|
||||
|
||||
DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS;
|
||||
// Handle reparse points.
|
||||
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
ScopedFileHandle h(
|
||||
::CreateFileW(path_utf16.begin(),
|
||||
0, // Attributes only.
|
||||
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
0));
|
||||
if (!h)
|
||||
return getStatus(INVALID_HANDLE_VALUE, result);
|
||||
}
|
||||
if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||
Flags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||
|
||||
ScopedFileHandle h(
|
||||
::CreateFileW(path_utf16.begin(), 0, // Attributes only.
|
||||
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
|
||||
if (!h)
|
||||
return getStatus(INVALID_HANDLE_VALUE, result);
|
||||
NULL, OPEN_EXISTING, Flags, 0));
|
||||
if (!h)
|
||||
return getStatus(INVALID_HANDLE_VALUE, result);
|
||||
|
||||
return getStatus(h, result);
|
||||
return getStatus(h, result);
|
||||
}
|
||||
|
||||
std::error_code status(int FD, file_status &Result) {
|
||||
@@ -315,8 +315,19 @@ std::error_code status(int FD, file_status &Result) {
|
||||
return getStatus(FileHandle, Result);
|
||||
}
|
||||
|
||||
static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) {
|
||||
return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes),
|
||||
perms_from_attrs(FindData->dwFileAttributes),
|
||||
FindData->ftLastAccessTime.dwHighDateTime,
|
||||
FindData->ftLastAccessTime.dwLowDateTime,
|
||||
FindData->ftLastWriteTime.dwHighDateTime,
|
||||
FindData->ftLastWriteTime.dwLowDateTime,
|
||||
FindData->nFileSizeHigh, FindData->nFileSizeLow);
|
||||
}
|
||||
|
||||
std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
|
||||
StringRef path){
|
||||
StringRef path,
|
||||
bool follow_symlinks) {
|
||||
SmallVector<wchar_t, 128> path_utf16;
|
||||
|
||||
if (std::error_code ec = widenPath(path, path_utf16))
|
||||
@@ -334,7 +345,9 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
|
||||
|
||||
// Get the first directory entry.
|
||||
WIN32_FIND_DATAW FirstFind;
|
||||
ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
|
||||
ScopedFindHandle FindHandle(::FindFirstFileExW(
|
||||
c_str(path_utf16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch,
|
||||
NULL, FIND_FIRST_EX_LARGE_FETCH));
|
||||
if (!FindHandle)
|
||||
return mapWindowsError(::GetLastError());
|
||||
|
||||
@@ -361,7 +374,8 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
|
||||
it.IterationHandle = intptr_t(FindHandle.take());
|
||||
SmallString<128> directory_entry_path(path);
|
||||
path::append(directory_entry_path, directory_entry_name_utf8);
|
||||
it.CurrentEntry = directory_entry(directory_entry_path);
|
||||
it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks,
|
||||
status_from_find_data(&FirstFind));
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
@@ -397,12 +411,18 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
|
||||
directory_entry_path_utf8))
|
||||
return ec;
|
||||
|
||||
it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
|
||||
it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8),
|
||||
status_from_find_data(&FindData));
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
ErrorOr<basic_file_status> directory_entry::status() const {
|
||||
return Status;
|
||||
}
|
||||
|
||||
std::error_code openFileForRead(const Twine &Name, int &ResultFD,
|
||||
SmallVectorImpl<char> *RealPath) {
|
||||
ResultFD = -1;
|
||||
SmallVector<wchar_t, 128> PathUTF16;
|
||||
|
||||
if (std::error_code EC = widenPath(Name, PathUTF16))
|
||||
@@ -425,8 +445,8 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
|
||||
return EC;
|
||||
}
|
||||
|
||||
int FD = ::_open_osfhandle(intptr_t(H), 0);
|
||||
if (FD == -1) {
|
||||
ResultFD = ::_open_osfhandle(intptr_t(H), 0);
|
||||
if (ResultFD == -1) {
|
||||
::CloseHandle(H);
|
||||
return mapWindowsError(ERROR_INVALID_HANDLE);
|
||||
}
|
||||
@@ -447,7 +467,6 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
|
||||
}
|
||||
}
|
||||
|
||||
ResultFD = FD;
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
@@ -457,6 +476,7 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
assert((!(Flags & F_Excl) || !(Flags & F_Append)) &&
|
||||
"Cannot specify both 'excl' and 'append' file creation flags!");
|
||||
|
||||
ResultFD = -1;
|
||||
SmallVector<wchar_t, 128> PathUTF16;
|
||||
|
||||
if (std::error_code EC = widenPath(Name, PathUTF16))
|
||||
@@ -465,18 +485,24 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
DWORD CreationDisposition;
|
||||
if (Flags & F_Excl)
|
||||
CreationDisposition = CREATE_NEW;
|
||||
else if (Flags & F_Append)
|
||||
else if ((Flags & F_Append) || (Flags & F_NoTrunc))
|
||||
CreationDisposition = OPEN_ALWAYS;
|
||||
else
|
||||
CreationDisposition = CREATE_ALWAYS;
|
||||
|
||||
DWORD Access = GENERIC_WRITE;
|
||||
DWORD Attributes = FILE_ATTRIBUTE_NORMAL;
|
||||
if (Flags & F_RW)
|
||||
Access |= GENERIC_READ;
|
||||
if (Flags & F_Delete) {
|
||||
Access |= DELETE;
|
||||
Attributes |= FILE_FLAG_DELETE_ON_CLOSE;
|
||||
}
|
||||
|
||||
HANDLE H = ::CreateFileW(PathUTF16.begin(), Access,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||
CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
HANDLE H =
|
||||
::CreateFileW(PathUTF16.data(), Access,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL, CreationDisposition, Attributes, NULL);
|
||||
|
||||
if (H == INVALID_HANDLE_VALUE) {
|
||||
DWORD LastError = ::GetLastError();
|
||||
@@ -498,13 +524,12 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
if (Flags & F_Text)
|
||||
OpenFlags |= _O_TEXT;
|
||||
|
||||
int FD = ::_open_osfhandle(intptr_t(H), OpenFlags);
|
||||
if (FD == -1) {
|
||||
ResultFD = ::_open_osfhandle(intptr_t(H), OpenFlags);
|
||||
if (ResultFD == -1) {
|
||||
::CloseHandle(H);
|
||||
return mapWindowsError(ERROR_INVALID_HANDLE);
|
||||
}
|
||||
|
||||
ResultFD = FD;
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
@@ -577,23 +602,26 @@ void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
|
||||
} // end namespace path
|
||||
|
||||
namespace windows {
|
||||
std::error_code UTF8ToUTF16(wpi::StringRef utf8,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
if (!utf8.empty()) {
|
||||
int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(),
|
||||
utf8.size(), utf16.begin(), 0);
|
||||
std::error_code CodePageToUTF16(unsigned codepage,
|
||||
wpi::StringRef original,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
if (!original.empty()) {
|
||||
int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(),
|
||||
original.size(), utf16.begin(), 0);
|
||||
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
|
||||
utf16.reserve(len + 1);
|
||||
utf16.set_size(len);
|
||||
|
||||
len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(),
|
||||
utf8.size(), utf16.begin(), utf16.size());
|
||||
len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(),
|
||||
original.size(), utf16.begin(), utf16.size());
|
||||
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
// Make utf16 null terminated.
|
||||
@@ -603,32 +631,44 @@ std::error_code UTF8ToUTF16(wpi::StringRef utf8,
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code UTF8ToUTF16(wpi::StringRef utf8,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
return CodePageToUTF16(CP_UTF8, utf8, utf16);
|
||||
}
|
||||
|
||||
std::error_code CurCPToUTF16(wpi::StringRef curcp,
|
||||
wpi::SmallVectorImpl<wchar_t> &utf16) {
|
||||
return CodePageToUTF16(CP_ACP, curcp, utf16);
|
||||
}
|
||||
|
||||
static
|
||||
std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16,
|
||||
size_t utf16_len,
|
||||
wpi::SmallVectorImpl<char> &utf8) {
|
||||
wpi::SmallVectorImpl<char> &converted) {
|
||||
if (utf16_len) {
|
||||
// Get length.
|
||||
int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(),
|
||||
int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(),
|
||||
0, NULL, NULL);
|
||||
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
|
||||
utf8.reserve(len);
|
||||
utf8.set_size(len);
|
||||
converted.reserve(len);
|
||||
converted.set_size(len);
|
||||
|
||||
// Now do the actual conversion.
|
||||
len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(),
|
||||
utf8.size(), NULL, NULL);
|
||||
len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(),
|
||||
converted.size(), NULL, NULL);
|
||||
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
return mapWindowsError(::GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
// Make utf8 null terminated.
|
||||
utf8.push_back(0);
|
||||
utf8.pop_back();
|
||||
// Make the new string null terminated.
|
||||
converted.push_back(0);
|
||||
converted.pop_back();
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
@@ -639,8 +679,8 @@ std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
|
||||
}
|
||||
|
||||
std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
|
||||
wpi::SmallVectorImpl<char> &utf8) {
|
||||
return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8);
|
||||
wpi::SmallVectorImpl<char> &curcp) {
|
||||
return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp);
|
||||
}
|
||||
|
||||
} // end namespace windows
|
||||
|
||||
@@ -39,10 +39,10 @@
|
||||
#include "wpi/StringRef.h"
|
||||
#include "wpi/Twine.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include <system_error>
|
||||
#include <windows.h>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <windows.h>
|
||||
|
||||
/// Determines if the program is running on Windows 8 or newer. This
|
||||
/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended
|
||||
@@ -199,6 +199,8 @@ std::error_code widenPath(const Twine &Path8,
|
||||
|
||||
namespace windows {
|
||||
std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
|
||||
/// Convert to UTF16 from the current code page used in the system
|
||||
std::error_code CurCPToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
|
||||
std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
|
||||
SmallVectorImpl<char> &utf8);
|
||||
/// Convert from UTF16 to the current code page used in the system
|
||||
|
||||
@@ -12,15 +12,21 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "wpi/raw_ostream.h"
|
||||
#include "wpi/STLExtras.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/Compiler.h"
|
||||
#include "wpi/FileSystem.h"
|
||||
#include "wpi/Format.h"
|
||||
#include "wpi/MathExtras.h"
|
||||
#include "wpi/NativeFormatting.h"
|
||||
#include "wpi/WindowsError.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <iterator>
|
||||
#include <sys/stat.h>
|
||||
#include <system_error>
|
||||
|
||||
@@ -49,7 +55,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifdef _WIN32
|
||||
#include "Windows/WindowsSupport.h"
|
||||
#endif
|
||||
|
||||
@@ -102,73 +108,28 @@ void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(unsigned long N) {
|
||||
// Zero is a special case.
|
||||
if (N == 0)
|
||||
return *this << '0';
|
||||
|
||||
char NumberBuffer[20];
|
||||
char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
|
||||
char *CurPtr = EndPtr;
|
||||
|
||||
while (N) {
|
||||
*--CurPtr = '0' + char(N % 10);
|
||||
N /= 10;
|
||||
}
|
||||
return write(CurPtr, EndPtr-CurPtr);
|
||||
write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(long N) {
|
||||
if (N < 0) {
|
||||
*this << '-';
|
||||
// Avoid undefined behavior on LONG_MIN with a cast.
|
||||
N = -(unsigned long)N;
|
||||
}
|
||||
|
||||
return this->operator<<(static_cast<unsigned long>(N));
|
||||
write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(unsigned long long N) {
|
||||
// Output using 32-bit div/mod when possible.
|
||||
if (N == static_cast<unsigned long>(N))
|
||||
return this->operator<<(static_cast<unsigned long>(N));
|
||||
|
||||
char NumberBuffer[20];
|
||||
char *EndPtr = std::end(NumberBuffer);
|
||||
char *CurPtr = EndPtr;
|
||||
|
||||
while (N) {
|
||||
*--CurPtr = '0' + char(N % 10);
|
||||
N /= 10;
|
||||
}
|
||||
return write(CurPtr, EndPtr-CurPtr);
|
||||
write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(long long N) {
|
||||
if (N < 0) {
|
||||
*this << '-';
|
||||
// Avoid undefined behavior on INT64_MIN with a cast.
|
||||
N = -(unsigned long long)N;
|
||||
}
|
||||
|
||||
return this->operator<<(static_cast<unsigned long long>(N));
|
||||
write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write_hex(unsigned long long N) {
|
||||
// Zero is a special case.
|
||||
if (N == 0)
|
||||
return *this << '0';
|
||||
|
||||
char NumberBuffer[16];
|
||||
char *EndPtr = std::end(NumberBuffer);
|
||||
char *CurPtr = EndPtr;
|
||||
|
||||
while (N) {
|
||||
unsigned char x = static_cast<unsigned char>(N) % 16;
|
||||
*--CurPtr = hexdigit(x, /*LowerCase*/true);
|
||||
N /= 16;
|
||||
}
|
||||
|
||||
return write(CurPtr, EndPtr-CurPtr);
|
||||
wpi::write_hex(*this, N, HexPrintStyle::Lower);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::write_escaped(StringRef Str,
|
||||
@@ -212,54 +173,15 @@ raw_ostream &raw_ostream::write_escaped(StringRef Str,
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const void *P) {
|
||||
*this << '0' << 'x';
|
||||
|
||||
return write_hex((uintptr_t) P);
|
||||
wpi::write_hex(*this, (uintptr_t)P, HexPrintStyle::PrefixLower);
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(double N) {
|
||||
#ifdef _WIN32
|
||||
// On MSVCRT and compatible, output of %e is incompatible to Posix
|
||||
// by default. Number of exponent digits should be at least 2. "%+03d"
|
||||
// FIXME: Implement our formatter to here or Support/Format.h!
|
||||
#if defined(__MINGW32__)
|
||||
// FIXME: It should be generic to C++11.
|
||||
if (N == 0.0 && std::signbit(N))
|
||||
return *this << "-0.000000e+00";
|
||||
#else
|
||||
int fpcl = _fpclass(N);
|
||||
|
||||
// negative zero
|
||||
if (fpcl == _FPCLASS_NZ)
|
||||
return *this << "-0.000000e+00";
|
||||
#endif
|
||||
|
||||
char buf[16];
|
||||
unsigned len;
|
||||
len = format("%e", N).snprint(buf, sizeof(buf));
|
||||
if (len <= sizeof(buf) - 2) {
|
||||
if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') {
|
||||
int cs = buf[len - 4];
|
||||
if (cs == '+' || cs == '-') {
|
||||
int c1 = buf[len - 2];
|
||||
int c0 = buf[len - 1];
|
||||
if (isdigit(static_cast<unsigned char>(c1)) &&
|
||||
isdigit(static_cast<unsigned char>(c0))) {
|
||||
// Trim leading '0': "...e+012" -> "...e+12\0"
|
||||
buf[len - 3] = c1;
|
||||
buf[len - 2] = c0;
|
||||
buf[--len] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this->operator<<(buf);
|
||||
}
|
||||
#endif
|
||||
return this->operator<<(format("%e", N));
|
||||
wpi::write_double(*this, N, FloatStyle::Exponent);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void raw_ostream::flush_nonempty() {
|
||||
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
|
||||
size_t Length = OutBufCur - OutBufStart;
|
||||
@@ -336,10 +258,10 @@ void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
|
||||
// Handle short strings specially, memcpy isn't very good at very short
|
||||
// strings.
|
||||
switch (Size) {
|
||||
case 4: OutBufCur[3] = Ptr[3]; // FALL THROUGH
|
||||
case 3: OutBufCur[2] = Ptr[2]; // FALL THROUGH
|
||||
case 2: OutBufCur[1] = Ptr[1]; // FALL THROUGH
|
||||
case 1: OutBufCur[0] = Ptr[0]; // FALL THROUGH
|
||||
case 4: OutBufCur[3] = Ptr[3]; LLVM_FALLTHROUGH;
|
||||
case 3: OutBufCur[2] = Ptr[2]; LLVM_FALLTHROUGH;
|
||||
case 2: OutBufCur[1] = Ptr[1]; LLVM_FALLTHROUGH;
|
||||
case 1: OutBufCur[0] = Ptr[0]; LLVM_FALLTHROUGH;
|
||||
case 0: break;
|
||||
default:
|
||||
memcpy(OutBufCur, Ptr, Size);
|
||||
@@ -374,7 +296,7 @@ raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
|
||||
// space. Iterate until we win.
|
||||
SmallVector<char, 128> V;
|
||||
|
||||
while (1) {
|
||||
while (true) {
|
||||
V.resize(NextBufferSize);
|
||||
|
||||
// Try formatting into the SmallVector.
|
||||
@@ -391,82 +313,160 @@ raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
|
||||
unsigned Len = FS.Str.size();
|
||||
int PadAmount = FS.Width - Len;
|
||||
if (FS.RightJustify && (PadAmount > 0))
|
||||
this->indent(PadAmount);
|
||||
this->operator<<(FS.Str);
|
||||
if (!FS.RightJustify && (PadAmount > 0))
|
||||
if (FS.Str.size() >= FS.Width || FS.Justify == FormattedString::JustifyNone) {
|
||||
this->operator<<(FS.Str);
|
||||
return *this;
|
||||
}
|
||||
const size_t Difference = FS.Width - FS.Str.size();
|
||||
switch (FS.Justify) {
|
||||
case FormattedString::JustifyLeft:
|
||||
this->operator<<(FS.Str);
|
||||
this->indent(Difference);
|
||||
break;
|
||||
case FormattedString::JustifyRight:
|
||||
this->indent(Difference);
|
||||
this->operator<<(FS.Str);
|
||||
break;
|
||||
case FormattedString::JustifyCenter: {
|
||||
int PadAmount = Difference / 2;
|
||||
this->indent(PadAmount);
|
||||
this->operator<<(FS.Str);
|
||||
this->indent(Difference - PadAmount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false && "Bad Justification");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
|
||||
if (FN.Hex) {
|
||||
unsigned Nibbles = (64 - countLeadingZeros(FN.HexValue)+3)/4;
|
||||
unsigned PrefixChars = FN.HexPrefix ? 2 : 0;
|
||||
unsigned Width = std::max(FN.Width, Nibbles + PrefixChars);
|
||||
|
||||
char NumberBuffer[20] = "0x0000000000000000";
|
||||
if (!FN.HexPrefix)
|
||||
NumberBuffer[1] = '0';
|
||||
char *EndPtr = NumberBuffer+Width;
|
||||
char *CurPtr = EndPtr;
|
||||
unsigned long long N = FN.HexValue;
|
||||
while (N) {
|
||||
unsigned char x = static_cast<unsigned char>(N) % 16;
|
||||
*--CurPtr = hexdigit(x, !FN.Upper);
|
||||
N /= 16;
|
||||
}
|
||||
|
||||
return write(NumberBuffer, Width);
|
||||
HexPrintStyle Style;
|
||||
if (FN.Upper && FN.HexPrefix)
|
||||
Style = HexPrintStyle::PrefixUpper;
|
||||
else if (FN.Upper && !FN.HexPrefix)
|
||||
Style = HexPrintStyle::Upper;
|
||||
else if (!FN.Upper && FN.HexPrefix)
|
||||
Style = HexPrintStyle::PrefixLower;
|
||||
else
|
||||
Style = HexPrintStyle::Lower;
|
||||
wpi::write_hex(*this, FN.HexValue, Style, FN.Width);
|
||||
} else {
|
||||
// Zero is a special case.
|
||||
if (FN.DecValue == 0) {
|
||||
this->indent(FN.Width-1);
|
||||
return *this << '0';
|
||||
}
|
||||
char NumberBuffer[32];
|
||||
char *EndPtr = NumberBuffer+sizeof(NumberBuffer);
|
||||
char *CurPtr = EndPtr;
|
||||
bool Neg = (FN.DecValue < 0);
|
||||
uint64_t N = Neg ? -static_cast<uint64_t>(FN.DecValue) : FN.DecValue;
|
||||
while (N) {
|
||||
*--CurPtr = '0' + char(N % 10);
|
||||
N /= 10;
|
||||
}
|
||||
int Len = EndPtr - CurPtr;
|
||||
int Pad = FN.Width - Len;
|
||||
if (Neg)
|
||||
--Pad;
|
||||
if (Pad > 0)
|
||||
this->indent(Pad);
|
||||
if (Neg)
|
||||
*this << '-';
|
||||
return write(CurPtr, Len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
|
||||
static const char Spaces[] = " "
|
||||
" "
|
||||
" ";
|
||||
|
||||
// Usually the indentation is small, handle it with a fastpath.
|
||||
if (NumSpaces < array_lengthof(Spaces))
|
||||
return write(Spaces, NumSpaces);
|
||||
|
||||
while (NumSpaces) {
|
||||
unsigned NumToWrite = std::min(NumSpaces,
|
||||
(unsigned)array_lengthof(Spaces)-1);
|
||||
write(Spaces, NumToWrite);
|
||||
NumSpaces -= NumToWrite;
|
||||
wpi::SmallString<16> Buffer;
|
||||
wpi::raw_svector_ostream Stream(Buffer);
|
||||
wpi::write_integer(Stream, FN.DecValue, 0, IntegerStyle::Integer);
|
||||
if (Buffer.size() < FN.Width)
|
||||
indent(FN.Width - Buffer.size());
|
||||
(*this) << Buffer;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) {
|
||||
if (FB.Bytes.empty())
|
||||
return *this;
|
||||
|
||||
size_t LineIndex = 0;
|
||||
auto Bytes = FB.Bytes;
|
||||
const size_t Size = Bytes.size();
|
||||
HexPrintStyle HPS = FB.Upper ? HexPrintStyle::Upper : HexPrintStyle::Lower;
|
||||
uint64_t OffsetWidth = 0;
|
||||
if (FB.FirstByteOffset.hasValue()) {
|
||||
// Figure out how many nibbles are needed to print the largest offset
|
||||
// represented by this data set, so that we can align the offset field
|
||||
// to the right width.
|
||||
size_t Lines = Size / FB.NumPerLine;
|
||||
uint64_t MaxOffset = *FB.FirstByteOffset + Lines * FB.NumPerLine;
|
||||
unsigned Power = 0;
|
||||
if (MaxOffset > 0)
|
||||
Power = wpi::Log2_64_Ceil(MaxOffset);
|
||||
OffsetWidth = std::max<uint64_t>(4, wpi::alignTo(Power, 4) / 4);
|
||||
}
|
||||
|
||||
// The width of a block of data including all spaces for group separators.
|
||||
unsigned NumByteGroups =
|
||||
alignTo(FB.NumPerLine, FB.ByteGroupSize) / FB.ByteGroupSize;
|
||||
unsigned BlockCharWidth = FB.NumPerLine * 2 + NumByteGroups - 1;
|
||||
|
||||
while (!Bytes.empty()) {
|
||||
indent(FB.IndentLevel);
|
||||
|
||||
if (FB.FirstByteOffset.hasValue()) {
|
||||
uint64_t Offset = FB.FirstByteOffset.getValue();
|
||||
wpi::write_hex(*this, Offset + LineIndex, HPS, OffsetWidth);
|
||||
*this << ": ";
|
||||
}
|
||||
|
||||
auto Line = Bytes.take_front(FB.NumPerLine);
|
||||
|
||||
size_t CharsPrinted = 0;
|
||||
// Print the hex bytes for this line in groups
|
||||
for (size_t I = 0; I < Line.size(); ++I, CharsPrinted += 2) {
|
||||
if (I && (I % FB.ByteGroupSize) == 0) {
|
||||
++CharsPrinted;
|
||||
*this << " ";
|
||||
}
|
||||
wpi::write_hex(*this, Line[I], HPS, 2);
|
||||
}
|
||||
|
||||
if (FB.ASCII) {
|
||||
// Print any spaces needed for any bytes that we didn't print on this
|
||||
// line so that the ASCII bytes are correctly aligned.
|
||||
assert(BlockCharWidth >= CharsPrinted);
|
||||
indent(BlockCharWidth - CharsPrinted + 2);
|
||||
*this << "|";
|
||||
|
||||
// Print the ASCII char values for each byte on this line
|
||||
for (uint8_t Byte : Line) {
|
||||
if (isprint(Byte))
|
||||
*this << static_cast<char>(Byte);
|
||||
else
|
||||
*this << '.';
|
||||
}
|
||||
*this << '|';
|
||||
}
|
||||
|
||||
Bytes = Bytes.drop_front(Line.size());
|
||||
LineIndex += Line.size();
|
||||
if (LineIndex < Size)
|
||||
*this << '\n';
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <char C>
|
||||
static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
|
||||
static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
||||
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C};
|
||||
|
||||
// Usually the indentation is small, handle it with a fastpath.
|
||||
if (NumChars < array_lengthof(Chars))
|
||||
return OS.write(Chars, NumChars);
|
||||
|
||||
while (NumChars) {
|
||||
unsigned NumToWrite = std::min(NumChars,
|
||||
(unsigned)array_lengthof(Chars)-1);
|
||||
OS.write(Chars, NumToWrite);
|
||||
NumChars -= NumToWrite;
|
||||
}
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// indent - Insert 'NumSpaces' spaces.
|
||||
raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
|
||||
return write_padding<' '>(*this, NumSpaces);
|
||||
}
|
||||
|
||||
/// write_zeros - Insert 'NumZeros' nulls.
|
||||
raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) {
|
||||
return write_padding<'\0'>(*this, NumZeros);
|
||||
}
|
||||
|
||||
void raw_ostream::anchor() {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Formatted Output
|
||||
@@ -483,8 +483,7 @@ void format_object_base::home() {
|
||||
static int getFD(StringRef Filename, std::error_code &EC,
|
||||
sys::fs::OpenFlags Flags) {
|
||||
// Handle "-" as stdout. Note that when we do this, we consider ourself
|
||||
// the owner of stdout. This means that we can do things like close the
|
||||
// file descriptor when we're done and set the "binary" flag globally.
|
||||
// the owner of stdout and may set the "binary" flag globally based on Flags.
|
||||
if (Filename == "-") {
|
||||
EC = std::error_code();
|
||||
// If user requested binary then put stdout into binary mode if
|
||||
@@ -498,12 +497,10 @@ static int getFD(StringRef Filename, std::error_code &EC,
|
||||
}
|
||||
|
||||
int FD;
|
||||
|
||||
EC = sys::fs::openFileForWrite(Filename, FD, Flags);
|
||||
if (EC)
|
||||
return -1;
|
||||
|
||||
EC = std::error_code();
|
||||
return FD;
|
||||
}
|
||||
|
||||
@@ -514,13 +511,21 @@ raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
||||
/// FD is the file descriptor that this writes to. If ShouldClose is true, this
|
||||
/// closes the file when the stream is destroyed.
|
||||
raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
|
||||
: raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose),
|
||||
Error(false) {
|
||||
: raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose) {
|
||||
if (FD < 0 ) {
|
||||
ShouldClose = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not attempt to close stdout or stderr. We used to try to maintain the
|
||||
// property that tools that support writing file to stdout should not also
|
||||
// write informational output to stdout, but in practice we were never able to
|
||||
// maintain this invariant. Many features have been added to LLVM and clang
|
||||
// (-fdump-record-layouts, optimization remarks, etc) that print to stdout, so
|
||||
// users must simply be aware that mixed output and remarks is a possibility.
|
||||
if (FD <= STDERR_FILENO)
|
||||
ShouldClose = false;
|
||||
|
||||
// Get the starting position.
|
||||
off_t loc = ::lseek(FD, 0, SEEK_CUR);
|
||||
#ifdef _WIN32
|
||||
@@ -539,7 +544,7 @@ raw_fd_ostream::~raw_fd_ostream() {
|
||||
if (FD >= 0) {
|
||||
flush();
|
||||
if (ShouldClose && ::close(FD) < 0)
|
||||
error_detected();
|
||||
error_detected(std::error_code(errno, std::generic_category()));
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
@@ -551,25 +556,29 @@ raw_fd_ostream::~raw_fd_ostream() {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
assert(FD >= 0 && "File already closed.");
|
||||
pos += Size;
|
||||
|
||||
#ifndef _WIN32
|
||||
bool ShouldWriteInChunks = false;
|
||||
#else
|
||||
// The maximum write size is limited to SSIZE_MAX because a write
|
||||
// greater than SSIZE_MAX is implementation-defined in POSIX.
|
||||
// Since SSIZE_MAX is not portable, we use SIZE_MAX >> 1 instead.
|
||||
size_t MaxWriteSize = SIZE_MAX >> 1;
|
||||
|
||||
#if defined(__linux__)
|
||||
// It is observed that Linux returns EINVAL for a very large write (>2G).
|
||||
// Make it a reasonably small value.
|
||||
MaxWriteSize = 1024 * 1024 * 1024;
|
||||
#elif defined(_WIN32)
|
||||
// Writing a large size of output to Windows console returns ENOMEM. It seems
|
||||
// that, prior to Windows 8, WriteFile() is redirecting to WriteConsole(), and
|
||||
// the latter has a size limit (66000 bytes or less, depending on heap usage).
|
||||
bool ShouldWriteInChunks = !!::_isatty(FD) && !RunningWindows8OrGreater();
|
||||
if (::_isatty(FD) && !RunningWindows8OrGreater())
|
||||
MaxWriteSize = 32767;
|
||||
#endif
|
||||
|
||||
do {
|
||||
size_t ChunkSize = Size;
|
||||
if (ChunkSize > 32767 && ShouldWriteInChunks)
|
||||
ChunkSize = 32767;
|
||||
|
||||
size_t ChunkSize = std::min(Size, MaxWriteSize);
|
||||
#ifdef _WIN32
|
||||
int ret = ::_write(FD, Ptr, ChunkSize);
|
||||
#else
|
||||
@@ -593,7 +602,7 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
|
||||
continue;
|
||||
|
||||
// Otherwise it's a non-recoverable error. Note it and quit.
|
||||
error_detected();
|
||||
error_detected(std::error_code(errno, std::generic_category()));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -610,16 +619,20 @@ void raw_fd_ostream::close() {
|
||||
ShouldClose = false;
|
||||
flush();
|
||||
if (::close(FD) < 0)
|
||||
error_detected();
|
||||
error_detected(std::error_code(errno, std::generic_category()));
|
||||
FD = -1;
|
||||
}
|
||||
|
||||
uint64_t raw_fd_ostream::seek(uint64_t off) {
|
||||
assert(SupportsSeeking && "Stream does not support seeking!");
|
||||
flush();
|
||||
#ifdef _WIN32
|
||||
pos = ::_lseeki64(FD, off, SEEK_SET);
|
||||
#else
|
||||
pos = ::lseek(FD, off, SEEK_SET);
|
||||
#endif
|
||||
if (pos == (uint64_t)-1)
|
||||
error_detected();
|
||||
error_detected(std::error_code(errno, std::generic_category()));
|
||||
return pos;
|
||||
}
|
||||
|
||||
@@ -651,6 +664,8 @@ size_t raw_fd_ostream::preferred_buffer_size() const {
|
||||
#endif
|
||||
}
|
||||
|
||||
void raw_fd_ostream::anchor() {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// outs(), errs(), nulls()
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -658,10 +673,7 @@ size_t raw_fd_ostream::preferred_buffer_size() const {
|
||||
/// outs() - This returns a reference to a raw_ostream for standard output.
|
||||
/// Use it like: outs() << "foo" << "bar";
|
||||
raw_ostream &wpi::outs() {
|
||||
// Set buffer settings to model stdout behavior. Delete the file descriptor
|
||||
// when the program exits, forcing error detection. This means that if you
|
||||
// ever call outs(), you can't open another raw_fd_ostream on stdout, as we'll
|
||||
// close stdout twice and print an error the second time.
|
||||
// Set buffer settings to model stdout behavior.
|
||||
std::error_code EC;
|
||||
static raw_fd_ostream S("-", EC, sys::fs::F_None);
|
||||
assert(!EC);
|
||||
@@ -682,7 +694,6 @@ raw_ostream &wpi::nulls() {
|
||||
return S;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// raw_string_ostream
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -778,3 +789,5 @@ uint64_t raw_null_ostream::current_pos() const {
|
||||
|
||||
void raw_null_ostream::pwrite_impl(const char * /*Ptr*/, size_t /*Size*/,
|
||||
uint64_t /*Offset*/) {}
|
||||
|
||||
void raw_pwrite_stream::anchor() {}
|
||||
|
||||
Reference in New Issue
Block a user