summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/Support
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Support')
-rw-r--r--contrib/llvm/lib/Support/APFloat.cpp696
-rw-r--r--contrib/llvm/lib/Support/APInt.cpp62
-rw-r--r--contrib/llvm/lib/Support/Allocator.cpp7
-rw-r--r--contrib/llvm/lib/Support/BlockFrequency.cpp150
-rw-r--r--contrib/llvm/lib/Support/CommandLine.cpp352
-rw-r--r--contrib/llvm/lib/Support/Compression.cpp7
-rw-r--r--contrib/llvm/lib/Support/ConstantRange.cpp21
-rw-r--r--contrib/llvm/lib/Support/ConvertUTFWrapper.cpp55
-rw-r--r--contrib/llvm/lib/Support/CrashRecoveryContext.cpp44
-rw-r--r--contrib/llvm/lib/Support/DataStream.cpp15
-rw-r--r--contrib/llvm/lib/Support/Disassembler.cpp10
-rw-r--r--contrib/llvm/lib/Support/Dwarf.cpp55
-rw-r--r--contrib/llvm/lib/Support/DynamicLibrary.cpp41
-rw-r--r--contrib/llvm/lib/Support/Errno.cpp33
-rw-r--r--contrib/llvm/lib/Support/ErrorHandling.cpp22
-rw-r--r--contrib/llvm/lib/Support/FileOutputBuffer.cpp29
-rw-r--r--contrib/llvm/lib/Support/FileUtilities.cpp33
-rw-r--r--contrib/llvm/lib/Support/FormattedStream.cpp45
-rw-r--r--contrib/llvm/lib/Support/GraphWriter.cpp71
-rw-r--r--contrib/llvm/lib/Support/Host.cpp217
-rw-r--r--contrib/llvm/lib/Support/Locale.cpp33
-rw-r--r--contrib/llvm/lib/Support/LocaleGeneric.inc17
-rw-r--r--contrib/llvm/lib/Support/LocaleWindows.inc15
-rw-r--r--contrib/llvm/lib/Support/LocaleXlocale.inc61
-rw-r--r--contrib/llvm/lib/Support/LockFileManager.cpp31
-rw-r--r--contrib/llvm/lib/Support/MD5.cpp286
-rw-r--r--contrib/llvm/lib/Support/MemoryBuffer.cpp132
-rw-r--r--contrib/llvm/lib/Support/MemoryObject.cpp6
-rw-r--r--contrib/llvm/lib/Support/Path.cpp1132
-rw-r--r--contrib/llvm/lib/Support/PathV2.cpp949
-rw-r--r--contrib/llvm/lib/Support/PrettyStackTrace.cpp58
-rw-r--r--contrib/llvm/lib/Support/Process.cpp18
-rw-r--r--contrib/llvm/lib/Support/Program.cpp51
-rw-r--r--contrib/llvm/lib/Support/Regex.cpp9
-rw-r--r--contrib/llvm/lib/Support/SmallPtrSet.cpp9
-rw-r--r--contrib/llvm/lib/Support/SourceMgr.cpp21
-rw-r--r--contrib/llvm/lib/Support/StreamableMemoryObject.cpp11
-rw-r--r--contrib/llvm/lib/Support/StringRef.cpp31
-rw-r--r--contrib/llvm/lib/Support/StringRefMemoryObject.cpp29
-rw-r--r--contrib/llvm/lib/Support/SystemUtils.cpp22
-rw-r--r--contrib/llvm/lib/Support/TargetRegistry.cpp6
-rw-r--r--contrib/llvm/lib/Support/ThreadLocal.cpp2
-rw-r--r--contrib/llvm/lib/Support/Timer.cpp4
-rw-r--r--contrib/llvm/lib/Support/ToolOutputFile.cpp20
-rw-r--r--contrib/llvm/lib/Support/Triple.cpp27
-rw-r--r--contrib/llvm/lib/Support/Unicode.cpp367
-rw-r--r--contrib/llvm/lib/Support/Unix/Memory.inc7
-rw-r--r--contrib/llvm/lib/Support/Unix/Path.inc1197
-rw-r--r--contrib/llvm/lib/Support/Unix/PathV2.inc693
-rw-r--r--contrib/llvm/lib/Support/Unix/Process.inc119
-rw-r--r--contrib/llvm/lib/Support/Unix/Program.inc217
-rw-r--r--contrib/llvm/lib/Support/Unix/Signals.inc18
-rw-r--r--contrib/llvm/lib/Support/Unix/ThreadLocal.inc2
-rw-r--r--contrib/llvm/lib/Support/Unix/TimeValue.inc19
-rw-r--r--contrib/llvm/lib/Support/Unix/Unix.h14
-rw-r--r--contrib/llvm/lib/Support/Windows/DynamicLibrary.inc15
-rw-r--r--contrib/llvm/lib/Support/Windows/Memory.inc4
-rw-r--r--contrib/llvm/lib/Support/Windows/Path.inc1712
-rw-r--r--contrib/llvm/lib/Support/Windows/PathV2.inc1022
-rw-r--r--contrib/llvm/lib/Support/Windows/Process.inc116
-rw-r--r--contrib/llvm/lib/Support/Windows/Program.inc288
-rw-r--r--contrib/llvm/lib/Support/Windows/RWMutex.inc4
-rw-r--r--contrib/llvm/lib/Support/Windows/Signals.inc56
-rw-r--r--contrib/llvm/lib/Support/Windows/TimeValue.inc38
-rw-r--r--contrib/llvm/lib/Support/Windows/Windows.h30
-rw-r--r--contrib/llvm/lib/Support/YAMLParser.cpp111
-rw-r--r--contrib/llvm/lib/Support/YAMLTraits.cpp100
-rw-r--r--contrib/llvm/lib/Support/raw_ostream.cpp48
68 files changed, 5492 insertions, 5650 deletions
diff --git a/contrib/llvm/lib/Support/APFloat.cpp b/contrib/llvm/lib/Support/APFloat.cpp
index 6182e34..676e2d4 100644
--- a/contrib/llvm/lib/Support/APFloat.cpp
+++ b/contrib/llvm/lib/Support/APFloat.cpp
@@ -25,7 +25,13 @@
using namespace llvm;
-#define convolve(lhs, rhs) ((lhs) * 4 + (rhs))
+/// A macro used to combine two fcCategory enums into one key which can be used
+/// in a switch statement to classify how the interaction of two APFloat's
+/// categories affects an operation.
+///
+/// TODO: If clang source code is ever allowed to use constexpr in its own
+/// codebase, change this into a static inline function.
+#define PackCategoriesIntoKey(_lhs, _rhs) ((_lhs) * 4 + (_rhs))
/* Assumed in hexadecimal significand parsing, and conversion to
hexadecimal strings. */
@@ -38,11 +44,11 @@ namespace llvm {
struct fltSemantics {
/* The largest E such that 2^E is representable; this matches the
definition of IEEE 754. */
- exponent_t maxExponent;
+ APFloat::ExponentType maxExponent;
/* The smallest E such that 2^E is a normalized number; this
matches the definition of IEEE 754. */
- exponent_t minExponent;
+ APFloat::ExponentType minExponent;
/* Number of bits in the significand. This includes the integer
bit. */
@@ -288,9 +294,9 @@ interpretDecimal(StringRef::iterator begin, StringRef::iterator end,
}
/* Adjust the exponents for any decimal point. */
- D->exponent += static_cast<exponent_t>((dot - p) - (dot > p));
+ D->exponent += static_cast<APFloat::ExponentType>((dot - p) - (dot > p));
D->normalizedExponent = (D->exponent +
- static_cast<exponent_t>((p - D->firstSigDigit)
+ static_cast<APFloat::ExponentType>((p - D->firstSigDigit)
- (dot > D->firstSigDigit && dot < p)));
}
@@ -313,8 +319,8 @@ trailingHexadecimalFraction(StringRef::iterator p, StringRef::iterator end,
else if (digitValue < 8 && digitValue > 0)
return lfLessThanHalf;
- /* Otherwise we need to find the first non-zero digit. */
- while (*p == '0')
+ // Otherwise we need to find the first non-zero digit.
+ while (p != end && (*p == '0' || *p == '.'))
p++;
assert(p != end && "Invalid trailing hexadecimal fraction!");
@@ -580,7 +586,7 @@ APFloat::initialize(const fltSemantics *ourSemantics)
void
APFloat::freeSignificand()
{
- if (partCount() > 1)
+ if (needsCleanup())
delete [] significand.parts;
}
@@ -592,14 +598,14 @@ APFloat::assign(const APFloat &rhs)
sign = rhs.sign;
category = rhs.category;
exponent = rhs.exponent;
- if (category == fcNormal || category == fcNaN)
+ if (isFiniteNonZero() || category == fcNaN)
copySignificand(rhs);
}
void
APFloat::copySignificand(const APFloat &rhs)
{
- assert(category == fcNormal || category == fcNaN);
+ assert(isFiniteNonZero() || category == fcNaN);
assert(rhs.partCount() >= partCount());
APInt::tcAssign(significandParts(), rhs.significandParts(),
@@ -679,12 +685,73 @@ APFloat::operator=(const APFloat &rhs)
bool
APFloat::isDenormal() const {
- return isNormal() && (exponent == semantics->minExponent) &&
+ return isFiniteNonZero() && (exponent == semantics->minExponent) &&
(APInt::tcExtractBit(significandParts(),
semantics->precision - 1) == 0);
}
bool
+APFloat::isSmallest() const {
+ // The smallest number by magnitude in our format will be the smallest
+ // denormal, i.e. the floating point number with exponent being minimum
+ // exponent and significand bitwise equal to 1 (i.e. with MSB equal to 0).
+ return isFiniteNonZero() && exponent == semantics->minExponent &&
+ significandMSB() == 0;
+}
+
+bool APFloat::isSignificandAllOnes() const {
+ // Test if the significand excluding the integral bit is all ones. This allows
+ // us to test for binade boundaries.
+ const integerPart *Parts = significandParts();
+ const unsigned PartCount = partCount();
+ for (unsigned i = 0; i < PartCount - 1; i++)
+ if (~Parts[i])
+ return false;
+
+ // Set the unused high bits to all ones when we compare.
+ const unsigned NumHighBits =
+ PartCount*integerPartWidth - semantics->precision + 1;
+ assert(NumHighBits <= integerPartWidth && "Can not have more high bits to "
+ "fill than integerPartWidth");
+ const integerPart HighBitFill =
+ ~integerPart(0) << (integerPartWidth - NumHighBits);
+ if (~(Parts[PartCount - 1] | HighBitFill))
+ return false;
+
+ return true;
+}
+
+bool APFloat::isSignificandAllZeros() const {
+ // Test if the significand excluding the integral bit is all zeros. This
+ // allows us to test for binade boundaries.
+ const integerPart *Parts = significandParts();
+ const unsigned PartCount = partCount();
+
+ for (unsigned i = 0; i < PartCount - 1; i++)
+ if (Parts[i])
+ return false;
+
+ const unsigned NumHighBits =
+ PartCount*integerPartWidth - semantics->precision + 1;
+ assert(NumHighBits <= integerPartWidth && "Can not have more high bits to "
+ "clear than integerPartWidth");
+ const integerPart HighBitMask = ~integerPart(0) >> NumHighBits;
+
+ if (Parts[PartCount - 1] & HighBitMask)
+ return false;
+
+ return true;
+}
+
+bool
+APFloat::isLargest() const {
+ // The largest number by magnitude in our format will be the floating point
+ // number with maximum exponent and with significand that is all ones.
+ return isFiniteNonZero() && exponent == semantics->maxExponent
+ && isSignificandAllOnes();
+}
+
+bool
APFloat::bitwiseIsEqual(const APFloat &rhs) const {
if (this == &rhs)
return true;
@@ -694,7 +761,7 @@ APFloat::bitwiseIsEqual(const APFloat &rhs) const {
return false;
if (category==fcZero || category==fcInfinity)
return true;
- else if (category==fcNormal && exponent!=rhs.exponent)
+ else if (isFiniteNonZero() && exponent!=rhs.exponent)
return false;
else {
int i= partCount();
@@ -711,6 +778,7 @@ APFloat::bitwiseIsEqual(const APFloat &rhs) const {
APFloat::APFloat(const fltSemantics &ourSemantics, integerPart value) {
initialize(&ourSemantics);
sign = 0;
+ category = fcNormal;
zeroSignificand();
exponent = ourSemantics.precision - 1;
significandParts()[0] = value;
@@ -728,17 +796,6 @@ APFloat::APFloat(const fltSemantics &ourSemantics, uninitializedTag tag) {
initialize(&ourSemantics);
}
-APFloat::APFloat(const fltSemantics &ourSemantics,
- fltCategory ourCategory, bool negative) {
- initialize(&ourSemantics);
- category = ourCategory;
- sign = negative;
- if (category == fcNormal)
- category = fcZero;
- else if (ourCategory == fcNaN)
- makeNaN();
-}
-
APFloat::APFloat(const fltSemantics &ourSemantics, StringRef text) {
initialize(&ourSemantics);
convertFromString(text, rmNearestTiesToEven);
@@ -780,8 +837,6 @@ APFloat::significandParts() const
integerPart *
APFloat::significandParts()
{
- assert(category == fcNormal || category == fcNaN);
-
if (partCount() > 1)
return significand.parts;
else
@@ -791,7 +846,6 @@ APFloat::significandParts()
void
APFloat::zeroSignificand()
{
- category = fcNormal;
APInt::tcSet(significandParts(), 0, partCount());
}
@@ -872,7 +926,21 @@ APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend)
omsb = APInt::tcMSB(fullSignificand, newPartsCount) + 1;
exponent += rhs.exponent;
+ // Assume the operands involved in the multiplication are single-precision
+ // FP, and the two multiplicants are:
+ // *this = a23 . a22 ... a0 * 2^e1
+ // rhs = b23 . b22 ... b0 * 2^e2
+ // the result of multiplication is:
+ // *this = c47 c46 . c45 ... c0 * 2^(e1+e2)
+ // Note that there are two significant bits at the left-hand side of the
+ // radix point. Move the radix point toward left by one bit, and adjust
+ // exponent accordingly.
+ exponent += 1;
+
if (addend) {
+ // The intermediate result of the multiplication has "2 * precision"
+ // signicant bit; adjust the addend to be consistent with mul result.
+ //
Significand savedSignificand = significand;
const fltSemantics *savedSemantics = semantics;
fltSemantics extendedSemantics;
@@ -880,8 +948,9 @@ APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend)
unsigned int extendedPrecision;
/* Normalize our MSB. */
- extendedPrecision = precision + precision - 1;
+ extendedPrecision = 2 * precision;
if (omsb != extendedPrecision) {
+ assert(extendedPrecision > omsb);
APInt::tcShiftLeft(fullSignificand, newPartsCount,
extendedPrecision - omsb);
exponent -= extendedPrecision - omsb;
@@ -912,8 +981,18 @@ APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend)
omsb = APInt::tcMSB(fullSignificand, newPartsCount) + 1;
}
- exponent -= (precision - 1);
+ // Convert the result having "2 * precision" significant-bits back to the one
+ // having "precision" significant-bits. First, move the radix point from
+ // poision "2*precision - 1" to "precision - 1". The exponent need to be
+ // adjusted by "2*precision - 1" - "precision - 1" = "precision".
+ exponent -= precision;
+ // In case MSB resides at the left-hand side of radix point, shift the
+ // mantissa right by some amount to make sure the MSB reside right before
+ // the radix point (i.e. "MSB . rest-significant-bits").
+ //
+ // Note that the result is not normalized when "omsb < precision". So, the
+ // caller needs to call APFloat::normalize() if normalized value is expected.
if (omsb > precision) {
unsigned int bits, significantParts;
lostFraction lf;
@@ -1035,7 +1114,7 @@ lostFraction
APFloat::shiftSignificandRight(unsigned int bits)
{
/* Our exponent should not overflow. */
- assert((exponent_t) (exponent + bits) >= exponent);
+ assert((ExponentType) (exponent + bits) >= exponent);
exponent += bits;
@@ -1064,8 +1143,8 @@ APFloat::compareAbsoluteValue(const APFloat &rhs) const
int compare;
assert(semantics == rhs.semantics);
- assert(category == fcNormal);
- assert(rhs.category == fcNormal);
+ assert(isFiniteNonZero());
+ assert(rhs.isFiniteNonZero());
compare = exponent - rhs.exponent;
@@ -1117,7 +1196,7 @@ APFloat::roundAwayFromZero(roundingMode rounding_mode,
unsigned int bit) const
{
/* NaNs and infinities should not have lost fractions. */
- assert(category == fcNormal || category == fcZero);
+ assert(isFiniteNonZero() || category == fcZero);
/* Current callers never pass this so we don't handle it. */
assert(lost_fraction != lfExactlyZero);
@@ -1155,7 +1234,7 @@ APFloat::normalize(roundingMode rounding_mode,
unsigned int omsb; /* One, not zero, based MSB. */
int exponentChange;
- if (category != fcNormal)
+ if (!isFiniteNonZero())
return opOK;
/* Before rounding normalize the exponent of fcNormal numbers. */
@@ -1259,42 +1338,43 @@ APFloat::normalize(roundingMode rounding_mode,
APFloat::opStatus
APFloat::addOrSubtractSpecials(const APFloat &rhs, bool subtract)
{
- switch (convolve(category, rhs.category)) {
+ switch (PackCategoriesIntoKey(category, rhs.category)) {
default:
llvm_unreachable(0);
- case convolve(fcNaN, fcZero):
- case convolve(fcNaN, fcNormal):
- case convolve(fcNaN, fcInfinity):
- case convolve(fcNaN, fcNaN):
- case convolve(fcNormal, fcZero):
- case convolve(fcInfinity, fcNormal):
- case convolve(fcInfinity, fcZero):
+ case PackCategoriesIntoKey(fcNaN, fcZero):
+ case PackCategoriesIntoKey(fcNaN, fcNormal):
+ case PackCategoriesIntoKey(fcNaN, fcInfinity):
+ case PackCategoriesIntoKey(fcNaN, fcNaN):
+ case PackCategoriesIntoKey(fcNormal, fcZero):
+ case PackCategoriesIntoKey(fcInfinity, fcNormal):
+ case PackCategoriesIntoKey(fcInfinity, fcZero):
return opOK;
- case convolve(fcZero, fcNaN):
- case convolve(fcNormal, fcNaN):
- case convolve(fcInfinity, fcNaN):
+ case PackCategoriesIntoKey(fcZero, fcNaN):
+ case PackCategoriesIntoKey(fcNormal, fcNaN):
+ case PackCategoriesIntoKey(fcInfinity, fcNaN):
+ sign = false;
category = fcNaN;
copySignificand(rhs);
return opOK;
- case convolve(fcNormal, fcInfinity):
- case convolve(fcZero, fcInfinity):
+ case PackCategoriesIntoKey(fcNormal, fcInfinity):
+ case PackCategoriesIntoKey(fcZero, fcInfinity):
category = fcInfinity;
sign = rhs.sign ^ subtract;
return opOK;
- case convolve(fcZero, fcNormal):
+ case PackCategoriesIntoKey(fcZero, fcNormal):
assign(rhs);
sign = rhs.sign ^ subtract;
return opOK;
- case convolve(fcZero, fcZero):
+ case PackCategoriesIntoKey(fcZero, fcZero):
/* Sign depends on rounding mode; handled by caller. */
return opOK;
- case convolve(fcInfinity, fcInfinity):
+ case PackCategoriesIntoKey(fcInfinity, fcInfinity):
/* Differently signed infinities can only be validly
subtracted. */
if (((sign ^ rhs.sign)!=0) != subtract) {
@@ -1304,7 +1384,7 @@ APFloat::addOrSubtractSpecials(const APFloat &rhs, bool subtract)
return opOK;
- case convolve(fcNormal, fcNormal):
+ case PackCategoriesIntoKey(fcNormal, fcNormal):
return opDivByZero;
}
}
@@ -1385,41 +1465,43 @@ APFloat::addOrSubtractSignificand(const APFloat &rhs, bool subtract)
APFloat::opStatus
APFloat::multiplySpecials(const APFloat &rhs)
{
- switch (convolve(category, rhs.category)) {
+ switch (PackCategoriesIntoKey(category, rhs.category)) {
default:
llvm_unreachable(0);
- case convolve(fcNaN, fcZero):
- case convolve(fcNaN, fcNormal):
- case convolve(fcNaN, fcInfinity):
- case convolve(fcNaN, fcNaN):
+ case PackCategoriesIntoKey(fcNaN, fcZero):
+ case PackCategoriesIntoKey(fcNaN, fcNormal):
+ case PackCategoriesIntoKey(fcNaN, fcInfinity):
+ case PackCategoriesIntoKey(fcNaN, fcNaN):
+ sign = false;
return opOK;
- case convolve(fcZero, fcNaN):
- case convolve(fcNormal, fcNaN):
- case convolve(fcInfinity, fcNaN):
+ case PackCategoriesIntoKey(fcZero, fcNaN):
+ case PackCategoriesIntoKey(fcNormal, fcNaN):
+ case PackCategoriesIntoKey(fcInfinity, fcNaN):
+ sign = false;
category = fcNaN;
copySignificand(rhs);
return opOK;
- case convolve(fcNormal, fcInfinity):
- case convolve(fcInfinity, fcNormal):
- case convolve(fcInfinity, fcInfinity):
+ case PackCategoriesIntoKey(fcNormal, fcInfinity):
+ case PackCategoriesIntoKey(fcInfinity, fcNormal):
+ case PackCategoriesIntoKey(fcInfinity, fcInfinity):
category = fcInfinity;
return opOK;
- case convolve(fcZero, fcNormal):
- case convolve(fcNormal, fcZero):
- case convolve(fcZero, fcZero):
+ case PackCategoriesIntoKey(fcZero, fcNormal):
+ case PackCategoriesIntoKey(fcNormal, fcZero):
+ case PackCategoriesIntoKey(fcZero, fcZero):
category = fcZero;
return opOK;
- case convolve(fcZero, fcInfinity):
- case convolve(fcInfinity, fcZero):
+ case PackCategoriesIntoKey(fcZero, fcInfinity):
+ case PackCategoriesIntoKey(fcInfinity, fcZero):
makeNaN();
return opInvalidOp;
- case convolve(fcNormal, fcNormal):
+ case PackCategoriesIntoKey(fcNormal, fcNormal):
return opOK;
}
}
@@ -1427,41 +1509,40 @@ APFloat::multiplySpecials(const APFloat &rhs)
APFloat::opStatus
APFloat::divideSpecials(const APFloat &rhs)
{
- switch (convolve(category, rhs.category)) {
+ switch (PackCategoriesIntoKey(category, rhs.category)) {
default:
llvm_unreachable(0);
- case convolve(fcNaN, fcZero):
- case convolve(fcNaN, fcNormal):
- case convolve(fcNaN, fcInfinity):
- case convolve(fcNaN, fcNaN):
- case convolve(fcInfinity, fcZero):
- case convolve(fcInfinity, fcNormal):
- case convolve(fcZero, fcInfinity):
- case convolve(fcZero, fcNormal):
- return opOK;
-
- case convolve(fcZero, fcNaN):
- case convolve(fcNormal, fcNaN):
- case convolve(fcInfinity, fcNaN):
+ case PackCategoriesIntoKey(fcZero, fcNaN):
+ case PackCategoriesIntoKey(fcNormal, fcNaN):
+ case PackCategoriesIntoKey(fcInfinity, fcNaN):
category = fcNaN;
copySignificand(rhs);
+ case PackCategoriesIntoKey(fcNaN, fcZero):
+ case PackCategoriesIntoKey(fcNaN, fcNormal):
+ case PackCategoriesIntoKey(fcNaN, fcInfinity):
+ case PackCategoriesIntoKey(fcNaN, fcNaN):
+ sign = false;
+ case PackCategoriesIntoKey(fcInfinity, fcZero):
+ case PackCategoriesIntoKey(fcInfinity, fcNormal):
+ case PackCategoriesIntoKey(fcZero, fcInfinity):
+ case PackCategoriesIntoKey(fcZero, fcNormal):
return opOK;
- case convolve(fcNormal, fcInfinity):
+ case PackCategoriesIntoKey(fcNormal, fcInfinity):
category = fcZero;
return opOK;
- case convolve(fcNormal, fcZero):
+ case PackCategoriesIntoKey(fcNormal, fcZero):
category = fcInfinity;
return opDivByZero;
- case convolve(fcInfinity, fcInfinity):
- case convolve(fcZero, fcZero):
+ case PackCategoriesIntoKey(fcInfinity, fcInfinity):
+ case PackCategoriesIntoKey(fcZero, fcZero):
makeNaN();
return opInvalidOp;
- case convolve(fcNormal, fcNormal):
+ case PackCategoriesIntoKey(fcNormal, fcNormal):
return opOK;
}
}
@@ -1469,35 +1550,36 @@ APFloat::divideSpecials(const APFloat &rhs)
APFloat::opStatus
APFloat::modSpecials(const APFloat &rhs)
{
- switch (convolve(category, rhs.category)) {
+ switch (PackCategoriesIntoKey(category, rhs.category)) {
default:
llvm_unreachable(0);
- case convolve(fcNaN, fcZero):
- case convolve(fcNaN, fcNormal):
- case convolve(fcNaN, fcInfinity):
- case convolve(fcNaN, fcNaN):
- case convolve(fcZero, fcInfinity):
- case convolve(fcZero, fcNormal):
- case convolve(fcNormal, fcInfinity):
+ case PackCategoriesIntoKey(fcNaN, fcZero):
+ case PackCategoriesIntoKey(fcNaN, fcNormal):
+ case PackCategoriesIntoKey(fcNaN, fcInfinity):
+ case PackCategoriesIntoKey(fcNaN, fcNaN):
+ case PackCategoriesIntoKey(fcZero, fcInfinity):
+ case PackCategoriesIntoKey(fcZero, fcNormal):
+ case PackCategoriesIntoKey(fcNormal, fcInfinity):
return opOK;
- case convolve(fcZero, fcNaN):
- case convolve(fcNormal, fcNaN):
- case convolve(fcInfinity, fcNaN):
+ case PackCategoriesIntoKey(fcZero, fcNaN):
+ case PackCategoriesIntoKey(fcNormal, fcNaN):
+ case PackCategoriesIntoKey(fcInfinity, fcNaN):
+ sign = false;
category = fcNaN;
copySignificand(rhs);
return opOK;
- case convolve(fcNormal, fcZero):
- case convolve(fcInfinity, fcZero):
- case convolve(fcInfinity, fcNormal):
- case convolve(fcInfinity, fcInfinity):
- case convolve(fcZero, fcZero):
+ case PackCategoriesIntoKey(fcNormal, fcZero):
+ case PackCategoriesIntoKey(fcInfinity, fcZero):
+ case PackCategoriesIntoKey(fcInfinity, fcNormal):
+ case PackCategoriesIntoKey(fcInfinity, fcInfinity):
+ case PackCategoriesIntoKey(fcZero, fcZero):
makeNaN();
return opInvalidOp;
- case convolve(fcNormal, fcNormal):
+ case PackCategoriesIntoKey(fcNormal, fcNormal):
return opOK;
}
}
@@ -1578,7 +1660,7 @@ APFloat::multiply(const APFloat &rhs, roundingMode rounding_mode)
sign ^= rhs.sign;
fs = multiplySpecials(rhs);
- if (category == fcNormal) {
+ if (isFiniteNonZero()) {
lostFraction lost_fraction = multiplySignificand(rhs, 0);
fs = normalize(rounding_mode, lost_fraction);
if (lost_fraction != lfExactlyZero)
@@ -1597,7 +1679,7 @@ APFloat::divide(const APFloat &rhs, roundingMode rounding_mode)
sign ^= rhs.sign;
fs = divideSpecials(rhs);
- if (category == fcNormal) {
+ if (isFiniteNonZero()) {
lostFraction lost_fraction = divideSignificand(rhs);
fs = normalize(rounding_mode, lost_fraction);
if (lost_fraction != lfExactlyZero)
@@ -1651,7 +1733,7 @@ APFloat::mod(const APFloat &rhs, roundingMode rounding_mode)
opStatus fs;
fs = modSpecials(rhs);
- if (category == fcNormal && rhs.category == fcNormal) {
+ if (isFiniteNonZero() && rhs.isFiniteNonZero()) {
APFloat V = *this;
unsigned int origSign = sign;
@@ -1697,9 +1779,9 @@ APFloat::fusedMultiplyAdd(const APFloat &multiplicand,
/* If and only if all arguments are normal do we need to do an
extended-precision calculation. */
- if (category == fcNormal &&
- multiplicand.category == fcNormal &&
- addend.category == fcNormal) {
+ if (isFiniteNonZero() &&
+ multiplicand.isFiniteNonZero() &&
+ addend.isFiniteNonZero()) {
lostFraction lost_fraction;
lost_fraction = multiplySignificand(multiplicand, &addend);
@@ -1736,7 +1818,7 @@ APFloat::opStatus APFloat::roundToIntegral(roundingMode rounding_mode) {
// If the exponent is large enough, we know that this value is already
// integral, and the arithmetic below would potentially cause it to saturate
// to +/-Inf. Bail out early instead.
- if (category == fcNormal && exponent+1 >= (int)semanticsPrecision(*semantics))
+ if (isFiniteNonZero() && exponent+1 >= (int)semanticsPrecision(*semantics))
return opOK;
// The algorithm here is quite simple: we add 2^(p-1), where p is the
@@ -1780,36 +1862,36 @@ APFloat::compare(const APFloat &rhs) const
assert(semantics == rhs.semantics);
- switch (convolve(category, rhs.category)) {
+ switch (PackCategoriesIntoKey(category, rhs.category)) {
default:
llvm_unreachable(0);
- case convolve(fcNaN, fcZero):
- case convolve(fcNaN, fcNormal):
- case convolve(fcNaN, fcInfinity):
- case convolve(fcNaN, fcNaN):
- case convolve(fcZero, fcNaN):
- case convolve(fcNormal, fcNaN):
- case convolve(fcInfinity, fcNaN):
+ case PackCategoriesIntoKey(fcNaN, fcZero):
+ case PackCategoriesIntoKey(fcNaN, fcNormal):
+ case PackCategoriesIntoKey(fcNaN, fcInfinity):
+ case PackCategoriesIntoKey(fcNaN, fcNaN):
+ case PackCategoriesIntoKey(fcZero, fcNaN):
+ case PackCategoriesIntoKey(fcNormal, fcNaN):
+ case PackCategoriesIntoKey(fcInfinity, fcNaN):
return cmpUnordered;
- case convolve(fcInfinity, fcNormal):
- case convolve(fcInfinity, fcZero):
- case convolve(fcNormal, fcZero):
+ case PackCategoriesIntoKey(fcInfinity, fcNormal):
+ case PackCategoriesIntoKey(fcInfinity, fcZero):
+ case PackCategoriesIntoKey(fcNormal, fcZero):
if (sign)
return cmpLessThan;
else
return cmpGreaterThan;
- case convolve(fcNormal, fcInfinity):
- case convolve(fcZero, fcInfinity):
- case convolve(fcZero, fcNormal):
+ case PackCategoriesIntoKey(fcNormal, fcInfinity):
+ case PackCategoriesIntoKey(fcZero, fcInfinity):
+ case PackCategoriesIntoKey(fcZero, fcNormal):
if (rhs.sign)
return cmpGreaterThan;
else
return cmpLessThan;
- case convolve(fcInfinity, fcInfinity):
+ case PackCategoriesIntoKey(fcInfinity, fcInfinity):
if (sign == rhs.sign)
return cmpEqual;
else if (sign)
@@ -1817,10 +1899,10 @@ APFloat::compare(const APFloat &rhs) const
else
return cmpGreaterThan;
- case convolve(fcZero, fcZero):
+ case PackCategoriesIntoKey(fcZero, fcZero):
return cmpEqual;
- case convolve(fcNormal, fcNormal):
+ case PackCategoriesIntoKey(fcNormal, fcNormal):
break;
}
@@ -1877,8 +1959,25 @@ APFloat::convert(const fltSemantics &toSemantics,
X86SpecialNan = true;
}
+ // If this is a truncation of a denormal number, and the target semantics
+ // has larger exponent range than the source semantics (this can happen
+ // when truncating from PowerPC double-double to double format), the
+ // right shift could lose result mantissa bits. Adjust exponent instead
+ // of performing excessive shift.
+ if (shift < 0 && isFiniteNonZero()) {
+ int exponentChange = significandMSB() + 1 - fromSemantics.precision;
+ if (exponent + exponentChange < toSemantics.minExponent)
+ exponentChange = toSemantics.minExponent - exponent;
+ if (exponentChange < shift)
+ exponentChange = shift;
+ if (exponentChange < 0) {
+ shift -= exponentChange;
+ exponent += exponentChange;
+ }
+ }
+
// If this is a truncation, perform the shift before we narrow the storage.
- if (shift < 0 && (category==fcNormal || category==fcNaN))
+ if (shift < 0 && (isFiniteNonZero() || category==fcNaN))
lostFraction = shiftRight(significandParts(), oldPartCount, -shift);
// Fix the storage so it can hold to new value.
@@ -1887,14 +1986,14 @@ APFloat::convert(const fltSemantics &toSemantics,
integerPart *newParts;
newParts = new integerPart[newPartCount];
APInt::tcSet(newParts, 0, newPartCount);
- if (category==fcNormal || category==fcNaN)
+ if (isFiniteNonZero() || category==fcNaN)
APInt::tcAssign(newParts, significandParts(), oldPartCount);
freeSignificand();
significand.parts = newParts;
} else if (newPartCount == 1 && oldPartCount != 1) {
// Switch to built-in storage for a single part.
integerPart newPart = 0;
- if (category==fcNormal || category==fcNaN)
+ if (isFiniteNonZero() || category==fcNaN)
newPart = significandParts()[0];
freeSignificand();
significand.part = newPart;
@@ -1905,10 +2004,10 @@ APFloat::convert(const fltSemantics &toSemantics,
// If this is an extension, perform the shift now that the storage is
// available.
- if (shift > 0 && (category==fcNormal || category==fcNaN))
+ if (shift > 0 && (isFiniteNonZero() || category==fcNaN))
APInt::tcShiftLeft(significandParts(), newPartCount, shift);
- if (category == fcNormal) {
+ if (isFiniteNonZero()) {
fs = normalize(rounding_mode, lostFraction);
*losesInfo = (fs != opOK);
} else if (category == fcNaN) {
@@ -2204,56 +2303,46 @@ APFloat::opStatus
APFloat::convertFromHexadecimalString(StringRef s, roundingMode rounding_mode)
{
lostFraction lost_fraction = lfExactlyZero;
- integerPart *significand;
- unsigned int bitPos, partsCount;
- StringRef::iterator dot, firstSignificantDigit;
+ category = fcNormal;
zeroSignificand();
exponent = 0;
- category = fcNormal;
- significand = significandParts();
- partsCount = partCount();
- bitPos = partsCount * integerPartWidth;
+ integerPart *significand = significandParts();
+ unsigned partsCount = partCount();
+ unsigned bitPos = partsCount * integerPartWidth;
+ bool computedTrailingFraction = false;
- /* Skip leading zeroes and any (hexa)decimal point. */
+ // Skip leading zeroes and any (hexa)decimal point.
StringRef::iterator begin = s.begin();
StringRef::iterator end = s.end();
+ StringRef::iterator dot;
StringRef::iterator p = skipLeadingZeroesAndAnyDot(begin, end, &dot);
- firstSignificantDigit = p;
+ StringRef::iterator firstSignificantDigit = p;
- for (; p != end;) {
+ while (p != end) {
integerPart hex_value;
if (*p == '.') {
assert(dot == end && "String contains multiple dots");
dot = p++;
- if (p == end) {
- break;
- }
+ continue;
}
hex_value = hexDigitValue(*p);
- if (hex_value == -1U) {
+ if (hex_value == -1U)
break;
- }
p++;
- if (p == end) {
- break;
- } else {
- /* Store the number whilst 4-bit nibbles remain. */
- if (bitPos) {
- bitPos -= 4;
- hex_value <<= bitPos % integerPartWidth;
- significand[bitPos / integerPartWidth] |= hex_value;
- } else {
- lost_fraction = trailingHexadecimalFraction(p, end, hex_value);
- while (p != end && hexDigitValue(*p) != -1U)
- p++;
- break;
- }
+ // Store the number while we have space.
+ if (bitPos) {
+ bitPos -= 4;
+ hex_value <<= bitPos % integerPartWidth;
+ significand[bitPos / integerPartWidth] |= hex_value;
+ } else if (!computedTrailingFraction) {
+ lost_fraction = trailingHexadecimalFraction(p, end, hex_value);
+ computedTrailingFraction = true;
}
}
@@ -2316,8 +2405,8 @@ APFloat::roundSignificandWithExponent(const integerPart *decSigParts,
excessPrecision = calcSemantics.precision - semantics->precision;
truncatedBits = excessPrecision;
- APFloat decSig(calcSemantics, fcZero, sign);
- APFloat pow5(calcSemantics, fcZero, false);
+ APFloat decSig = APFloat::getZero(calcSemantics, sign);
+ APFloat pow5(calcSemantics);
sigStatus = decSig.convertFromUnsignedParts(decSigParts, sigPartCount,
rmNearestTiesToEven);
@@ -2402,7 +2491,14 @@ APFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode)
42039/12655 < L < 28738/8651 [ numerator <= 65536 ]
*/
- if (decDigitValue(*D.firstSigDigit) >= 10U) {
+ // Test if we have a zero number allowing for strings with no null terminators
+ // and zero decimals with non-zero exponents.
+ //
+ // We computed firstSigDigit by ignoring all zeros and dots. Thus if
+ // D->firstSigDigit equals str.end(), every digit must be a zero and there can
+ // be at most one dot. On the other hand, if we have a zero with a non-zero
+ // exponent, then we know that D.firstSigDigit will be non-numeric.
+ if (D.firstSigDigit == str.end() || decDigitValue(*D.firstSigDigit) >= 10U) {
category = fcZero;
fs = opOK;
@@ -2419,6 +2515,7 @@ APFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode)
(D.normalizedExponent + 1) * 28738 <=
8651 * (semantics->minExponent - (int) semantics->precision)) {
/* Underflow to zero and round. */
+ category = fcNormal;
zeroSignificand();
fs = normalize(rounding_mode, lfLessThanHalf);
@@ -2485,11 +2582,40 @@ APFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode)
return fs;
}
+bool
+APFloat::convertFromStringSpecials(StringRef str) {
+ if (str.equals("inf") || str.equals("INFINITY")) {
+ makeInf(false);
+ return true;
+ }
+
+ if (str.equals("-inf") || str.equals("-INFINITY")) {
+ makeInf(true);
+ return true;
+ }
+
+ if (str.equals("nan") || str.equals("NaN")) {
+ makeNaN(false, false);
+ return true;
+ }
+
+ if (str.equals("-nan") || str.equals("-NaN")) {
+ makeNaN(false, true);
+ return true;
+ }
+
+ return false;
+}
+
APFloat::opStatus
APFloat::convertFromString(StringRef str, roundingMode rounding_mode)
{
assert(!str.empty() && "Invalid string length");
+ // Handle special cases.
+ if (convertFromStringSpecials(str))
+ return opOK;
+
/* Handle a leading minus sign. */
StringRef::iterator p = str.begin();
size_t slen = str.size();
@@ -2686,7 +2812,7 @@ APFloat::convertNormalToHexString(char *dst, unsigned int hexDigits,
}
hash_code llvm::hash_value(const APFloat &Arg) {
- if (Arg.category != APFloat::fcNormal)
+ if (!Arg.isFiniteNonZero())
return hash_combine((uint8_t)Arg.category,
// NaN has no sign, fix it at zero.
Arg.isNaN() ? (uint8_t)0 : (uint8_t)Arg.sign,
@@ -2717,7 +2843,7 @@ APFloat::convertF80LongDoubleAPFloatToAPInt() const
uint64_t myexponent, mysignificand;
- if (category==fcNormal) {
+ if (isFiniteNonZero()) {
myexponent = exponent+16383; //bias
mysignificand = significandParts()[0];
if (myexponent==1 && !(mysignificand & 0x8000000000000000ULL))
@@ -2774,7 +2900,7 @@ APFloat::convertPPCDoubleDoubleAPFloatToAPInt() const
// just set the second double to zero. Otherwise, re-convert back to
// the extended format and compute the difference. This now should
// convert exactly to double.
- if (u.category == fcNormal && losesInfo) {
+ if (u.isFiniteNonZero() && losesInfo) {
fs = u.convert(extendedSemantics, rmNearestTiesToEven, &losesInfo);
assert(fs == opOK && !losesInfo);
(void)fs;
@@ -2800,7 +2926,7 @@ APFloat::convertQuadrupleAPFloatToAPInt() const
uint64_t myexponent, mysignificand, mysignificand2;
- if (category==fcNormal) {
+ if (isFiniteNonZero()) {
myexponent = exponent+16383; //bias
mysignificand = significandParts()[0];
mysignificand2 = significandParts()[1];
@@ -2836,7 +2962,7 @@ APFloat::convertDoubleAPFloatToAPInt() const
uint64_t myexponent, mysignificand;
- if (category==fcNormal) {
+ if (isFiniteNonZero()) {
myexponent = exponent+1023; //bias
mysignificand = *significandParts();
if (myexponent==1 && !(mysignificand & 0x10000000000000LL))
@@ -2866,7 +2992,7 @@ APFloat::convertFloatAPFloatToAPInt() const
uint32_t myexponent, mysignificand;
- if (category==fcNormal) {
+ if (isFiniteNonZero()) {
myexponent = exponent+127; //bias
mysignificand = (uint32_t)*significandParts();
if (myexponent == 1 && !(mysignificand & 0x800000))
@@ -2895,7 +3021,7 @@ APFloat::convertHalfAPFloatToAPInt() const
uint32_t myexponent, mysignificand;
- if (category==fcNormal) {
+ if (isFiniteNonZero()) {
myexponent = exponent+15; //bias
mysignificand = (uint32_t)*significandParts();
if (myexponent == 1 && !(mysignificand & 0x400))
@@ -3018,7 +3144,7 @@ APFloat::initFromPPCDoubleDoubleAPInt(const APInt &api)
(void)fs;
// Unless we have a special case, add in second double.
- if (category == fcNormal) {
+ if (isFiniteNonZero()) {
APFloat v(IEEEdouble, APInt(64, i2));
fs = v.convert(PPCDoubleDouble, rmNearestTiesToEven, &losesInfo);
assert(fs == opOK && !losesInfo);
@@ -3211,55 +3337,75 @@ APFloat::getAllOnesValue(unsigned BitWidth, bool isIEEE)
}
}
-APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) {
- APFloat Val(Sem, fcNormal, Negative);
-
+/// Make this number the largest magnitude normal number in the given
+/// semantics.
+void APFloat::makeLargest(bool Negative) {
// We want (in interchange format):
// sign = {Negative}
// exponent = 1..10
// significand = 1..1
+ category = fcNormal;
+ sign = Negative;
+ exponent = semantics->maxExponent;
- Val.exponent = Sem.maxExponent; // unbiased
+ // Use memset to set all but the highest integerPart to all ones.
+ integerPart *significand = significandParts();
+ unsigned PartCount = partCount();
+ memset(significand, 0xFF, sizeof(integerPart)*(PartCount - 1));
- // 1-initialize all bits....
- Val.zeroSignificand();
- integerPart *significand = Val.significandParts();
- unsigned N = partCountForBits(Sem.precision);
- for (unsigned i = 0; i != N; ++i)
- significand[i] = ~((integerPart) 0);
+ // Set the high integerPart especially setting all unused top bits for
+ // internal consistency.
+ const unsigned NumUnusedHighBits =
+ PartCount*integerPartWidth - semantics->precision;
+ significand[PartCount - 1] = ~integerPart(0) >> NumUnusedHighBits;
+}
+
+/// Make this number the smallest magnitude denormal number in the given
+/// semantics.
+void APFloat::makeSmallest(bool Negative) {
+ // We want (in interchange format):
+ // sign = {Negative}
+ // exponent = 0..0
+ // significand = 0..01
+ category = fcNormal;
+ sign = Negative;
+ exponent = semantics->minExponent;
+ APInt::tcSet(significandParts(), 1, partCount());
+}
- // ...and then clear the top bits for internal consistency.
- if (Sem.precision % integerPartWidth != 0)
- significand[N-1] &=
- (((integerPart) 1) << (Sem.precision % integerPartWidth)) - 1;
+APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) {
+ // We want (in interchange format):
+ // sign = {Negative}
+ // exponent = 1..10
+ // significand = 1..1
+ APFloat Val(Sem, uninitialized);
+ Val.makeLargest(Negative);
return Val;
}
APFloat APFloat::getSmallest(const fltSemantics &Sem, bool Negative) {
- APFloat Val(Sem, fcNormal, Negative);
-
// We want (in interchange format):
// sign = {Negative}
// exponent = 0..0
// significand = 0..01
-
- Val.exponent = Sem.minExponent; // unbiased
- Val.zeroSignificand();
- Val.significandParts()[0] = 1;
+ APFloat Val(Sem, uninitialized);
+ Val.makeSmallest(Negative);
return Val;
}
APFloat APFloat::getSmallestNormalized(const fltSemantics &Sem, bool Negative) {
- APFloat Val(Sem, fcNormal, Negative);
+ APFloat Val(Sem, uninitialized);
// We want (in interchange format):
// sign = {Negative}
// exponent = 0..0
// significand = 10..0
- Val.exponent = Sem.minExponent;
+ Val.category = fcNormal;
Val.zeroSignificand();
+ Val.sign = Negative;
+ Val.exponent = Sem.minExponent;
Val.significandParts()[partCountForBits(Sem.precision)-1] |=
(((integerPart) 1) << ((Sem.precision - 1) % integerPartWidth));
@@ -3400,11 +3546,14 @@ void APFloat::toString(SmallVectorImpl<char> &Str,
// Set FormatPrecision if zero. We want to do this before we
// truncate trailing zeros, as those are part of the precision.
if (!FormatPrecision) {
- // It's an interesting question whether to use the nominal
- // precision or the active precision here for denormals.
+ // We use enough digits so the number can be round-tripped back to an
+ // APFloat. The formula comes from "How to Print Floating-Point Numbers
+ // Accurately" by Steele and White.
+ // FIXME: Using a formula based purely on the precision is conservative;
+ // we can print fewer digits depending on the actual value being printed.
- // FormatPrecision = ceil(significandBits / lg_2(10))
- FormatPrecision = (semantics->precision * 59 + 195) / 196;
+ // FormatPrecision = 2 + floor(significandBits / lg_2(10))
+ FormatPrecision = 2 + semantics->precision * 59 / 196;
}
// Ignore trailing binary zeros.
@@ -3564,7 +3713,7 @@ void APFloat::toString(SmallVectorImpl<char> &Str,
bool APFloat::getExactInverse(APFloat *inv) const {
// Special floats and denormals have no exact inverse.
- if (category != fcNormal)
+ if (!isFiniteNonZero())
return false;
// Check that the number is a power of two by making sure that only the
@@ -3579,10 +3728,10 @@ bool APFloat::getExactInverse(APFloat *inv) const {
// Avoid multiplication with a denormal, it is not safe on all platforms and
// may be slower than a normal division.
- if (reciprocal.significandMSB() + 1 < reciprocal.semantics->precision)
+ if (reciprocal.isDenormal())
return false;
- assert(reciprocal.category == fcNormal &&
+ assert(reciprocal.isFiniteNonZero() &&
reciprocal.significandLSB() == reciprocal.semantics->precision - 1);
if (inv)
@@ -3590,3 +3739,148 @@ bool APFloat::getExactInverse(APFloat *inv) const {
return true;
}
+
+bool APFloat::isSignaling() const {
+ if (!isNaN())
+ return false;
+
+ // IEEE-754R 2008 6.2.1: A signaling NaN bit string should be encoded with the
+ // first bit of the trailing significand being 0.
+ return !APInt::tcExtractBit(significandParts(), semantics->precision - 2);
+}
+
+/// IEEE-754R 2008 5.3.1: nextUp/nextDown.
+///
+/// *NOTE* since nextDown(x) = -nextUp(-x), we only implement nextUp with
+/// appropriate sign switching before/after the computation.
+APFloat::opStatus APFloat::next(bool nextDown) {
+ // If we are performing nextDown, swap sign so we have -x.
+ if (nextDown)
+ changeSign();
+
+ // Compute nextUp(x)
+ opStatus result = opOK;
+
+ // Handle each float category separately.
+ switch (category) {
+ case fcInfinity:
+ // nextUp(+inf) = +inf
+ if (!isNegative())
+ break;
+ // nextUp(-inf) = -getLargest()
+ makeLargest(true);
+ break;
+ case fcNaN:
+ // IEEE-754R 2008 6.2 Par 2: nextUp(sNaN) = qNaN. Set Invalid flag.
+ // IEEE-754R 2008 6.2: nextUp(qNaN) = qNaN. Must be identity so we do not
+ // change the payload.
+ if (isSignaling()) {
+ result = opInvalidOp;
+ // For consistency, propogate the sign of the sNaN to the qNaN.
+ makeNaN(false, isNegative(), 0);
+ }
+ break;
+ case fcZero:
+ // nextUp(pm 0) = +getSmallest()
+ makeSmallest(false);
+ break;
+ case fcNormal:
+ // nextUp(-getSmallest()) = -0
+ if (isSmallest() && isNegative()) {
+ APInt::tcSet(significandParts(), 0, partCount());
+ category = fcZero;
+ exponent = 0;
+ break;
+ }
+
+ // nextUp(getLargest()) == INFINITY
+ if (isLargest() && !isNegative()) {
+ APInt::tcSet(significandParts(), 0, partCount());
+ category = fcInfinity;
+ exponent = semantics->maxExponent + 1;
+ break;
+ }
+
+ // nextUp(normal) == normal + inc.
+ if (isNegative()) {
+ // If we are negative, we need to decrement the significand.
+
+ // We only cross a binade boundary that requires adjusting the exponent
+ // if:
+ // 1. exponent != semantics->minExponent. This implies we are not in the
+ // smallest binade or are dealing with denormals.
+ // 2. Our significand excluding the integral bit is all zeros.
+ bool WillCrossBinadeBoundary =
+ exponent != semantics->minExponent && isSignificandAllZeros();
+
+ // Decrement the significand.
+ //
+ // We always do this since:
+ // 1. If we are dealing with a non binade decrement, by definition we
+ // just decrement the significand.
+ // 2. If we are dealing with a normal -> normal binade decrement, since
+ // we have an explicit integral bit the fact that all bits but the
+ // integral bit are zero implies that subtracting one will yield a
+ // significand with 0 integral bit and 1 in all other spots. Thus we
+ // must just adjust the exponent and set the integral bit to 1.
+ // 3. If we are dealing with a normal -> denormal binade decrement,
+ // since we set the integral bit to 0 when we represent denormals, we
+ // just decrement the significand.
+ integerPart *Parts = significandParts();
+ APInt::tcDecrement(Parts, partCount());
+
+ if (WillCrossBinadeBoundary) {
+ // Our result is a normal number. Do the following:
+ // 1. Set the integral bit to 1.
+ // 2. Decrement the exponent.
+ APInt::tcSetBit(Parts, semantics->precision - 1);
+ exponent--;
+ }
+ } else {
+ // If we are positive, we need to increment the significand.
+
+ // We only cross a binade boundary that requires adjusting the exponent if
+ // the input is not a denormal and all of said input's significand bits
+ // are set. If all of said conditions are true: clear the significand, set
+ // the integral bit to 1, and increment the exponent. If we have a
+ // denormal always increment since moving denormals and the numbers in the
+ // smallest normal binade have the same exponent in our representation.
+ bool WillCrossBinadeBoundary = !isDenormal() && isSignificandAllOnes();
+
+ if (WillCrossBinadeBoundary) {
+ integerPart *Parts = significandParts();
+ APInt::tcSet(Parts, 0, partCount());
+ APInt::tcSetBit(Parts, semantics->precision - 1);
+ assert(exponent != semantics->maxExponent &&
+ "We can not increment an exponent beyond the maxExponent allowed"
+ " by the given floating point semantics.");
+ exponent++;
+ } else {
+ incrementSignificand();
+ }
+ }
+ break;
+ }
+
+ // If we are performing nextDown, swap sign so we have -nextUp(-x)
+ if (nextDown)
+ changeSign();
+
+ return result;
+}
+
+void
+APFloat::makeInf(bool Negative) {
+ category = fcInfinity;
+ sign = Negative;
+ exponent = semantics->maxExponent + 1;
+ APInt::tcSet(significandParts(), 0, partCount());
+}
+
+void
+APFloat::makeZero(bool Negative) {
+ category = fcZero;
+ sign = Negative;
+ exponent = semantics->minExponent-1;
+ APInt::tcSet(significandParts(), 0, partCount());
+}
diff --git a/contrib/llvm/lib/Support/APInt.cpp b/contrib/llvm/lib/Support/APInt.cpp
index e853475..89f96bd 100644
--- a/contrib/llvm/lib/Support/APInt.cpp
+++ b/contrib/llvm/lib/Support/APInt.cpp
@@ -692,14 +692,14 @@ unsigned APInt::countLeadingZerosSlowCase() const {
unsigned i = getNumWords();
integerPart MSW = pVal[i-1] & MSWMask;
if (MSW)
- return CountLeadingZeros_64(MSW) - (APINT_BITS_PER_WORD - BitsInMSW);
+ return llvm::countLeadingZeros(MSW) - (APINT_BITS_PER_WORD - BitsInMSW);
unsigned Count = BitsInMSW;
for (--i; i > 0u; --i) {
if (pVal[i-1] == 0)
Count += APINT_BITS_PER_WORD;
else {
- Count += CountLeadingZeros_64(pVal[i-1]);
+ Count += llvm::countLeadingZeros(pVal[i-1]);
break;
}
}
@@ -735,13 +735,13 @@ unsigned APInt::countLeadingOnes() const {
unsigned APInt::countTrailingZeros() const {
if (isSingleWord())
- return std::min(unsigned(CountTrailingZeros_64(VAL)), BitWidth);
+ return std::min(unsigned(llvm::countTrailingZeros(VAL)), BitWidth);
unsigned Count = 0;
unsigned i = 0;
for (; i < getNumWords() && pVal[i] == 0; ++i)
Count += APINT_BITS_PER_WORD;
if (i < getNumWords())
- Count += CountTrailingZeros_64(pVal[i]);
+ Count += llvm::countTrailingZeros(pVal[i]);
return std::min(Count, BitWidth);
}
@@ -1512,7 +1512,7 @@ static void KnuthDiv(unsigned *u, unsigned *v, unsigned *q, unsigned* r,
// and v so that its high bits are shifted to the top of v's range without
// overflow. Note that this can require an extra word in u so that u must
// be of length m+n+1.
- unsigned shift = CountLeadingZeros_32(v[n-1]);
+ unsigned shift = countLeadingZeros(v[n-1]);
unsigned v_carry = 0;
unsigned u_carry = 0;
if (shift) {
@@ -2304,24 +2304,7 @@ namespace {
static unsigned int
partMSB(integerPart value)
{
- unsigned int n, msb;
-
- if (value == 0)
- return -1U;
-
- n = integerPartWidth / 2;
-
- msb = 0;
- do {
- if (value >> n) {
- value >>= n;
- msb += n;
- }
-
- n >>= 1;
- } while (n);
-
- return msb;
+ return findLastSet(value, ZB_Max);
}
/* Returns the bit number of the least significant set bit of a
@@ -2329,24 +2312,7 @@ namespace {
static unsigned int
partLSB(integerPart value)
{
- unsigned int n, lsb;
-
- if (value == 0)
- return -1U;
-
- lsb = integerPartWidth - 1;
- n = integerPartWidth / 2;
-
- do {
- if (value << n) {
- value <<= n;
- lsb -= n;
- }
-
- n >>= 1;
- } while (n);
-
- return lsb;
+ return findFirstSet(value, ZB_Max);
}
}
@@ -2888,6 +2854,20 @@ APInt::tcIncrement(integerPart *dst, unsigned int parts)
return i == parts;
}
+/* Decrement a bignum in-place, return the borrow flag. */
+integerPart
+APInt::tcDecrement(integerPart *dst, unsigned int parts) {
+ for (unsigned int i = 0; i < parts; i++) {
+ // If the current word is non-zero, then the decrement has no effect on the
+ // higher-order words of the integer and no borrow can occur. Exit early.
+ if (dst[i]--)
+ return 0;
+ }
+ // If every word was zero, then there is a borrow.
+ return 1;
+}
+
+
/* Set the least significant BITS bits of a bignum, clear the
rest. */
void
diff --git a/contrib/llvm/lib/Support/Allocator.cpp b/contrib/llvm/lib/Support/Allocator.cpp
index 3c4191b..6e7a541 100644
--- a/contrib/llvm/lib/Support/Allocator.cpp
+++ b/contrib/llvm/lib/Support/Allocator.cpp
@@ -26,6 +26,10 @@ BumpPtrAllocator::BumpPtrAllocator(size_t size, size_t threshold,
: SlabSize(size), SizeThreshold(std::min(size, threshold)),
Allocator(allocator), CurSlab(0), BytesAllocated(0) { }
+BumpPtrAllocator::BumpPtrAllocator(size_t size, size_t threshold)
+ : SlabSize(size), SizeThreshold(std::min(size, threshold)),
+ Allocator(DefaultSlabAllocator), CurSlab(0), BytesAllocated(0) { }
+
BumpPtrAllocator::~BumpPtrAllocator() {
DeallocateSlabs(CurSlab);
}
@@ -167,9 +171,6 @@ void BumpPtrAllocator::PrintStats() const {
<< " (includes alignment, etc)\n";
}
-MallocSlabAllocator BumpPtrAllocator::DefaultSlabAllocator =
- MallocSlabAllocator();
-
SlabAllocator::~SlabAllocator() { }
MallocSlabAllocator::~MallocSlabAllocator() { }
diff --git a/contrib/llvm/lib/Support/BlockFrequency.cpp b/contrib/llvm/lib/Support/BlockFrequency.cpp
index 84a993e..00efe90 100644
--- a/contrib/llvm/lib/Support/BlockFrequency.cpp
+++ b/contrib/llvm/lib/Support/BlockFrequency.cpp
@@ -18,76 +18,94 @@
using namespace llvm;
-namespace {
-
-/// mult96bit - Multiply FREQ by N and store result in W array.
-void mult96bit(uint64_t freq, uint32_t N, uint64_t W[2]) {
+/// Multiply FREQ by N and store result in W array.
+static void mult96bit(uint64_t freq, uint32_t N, uint32_t W[3]) {
uint64_t u0 = freq & UINT32_MAX;
uint64_t u1 = freq >> 32;
- // Represent 96-bit value as w[2]:w[1]:w[0];
- uint32_t w[3] = { 0, 0, 0 };
-
+ // Represent 96-bit value as W[2]:W[1]:W[0];
uint64_t t = u0 * N;
uint64_t k = t >> 32;
- w[0] = t;
+ W[0] = t;
t = u1 * N + k;
- w[1] = t;
- w[2] = t >> 32;
-
- // W[1] - higher bits.
- // W[0] - lower bits.
- W[0] = w[0] + ((uint64_t) w[1] << 32);
- W[1] = w[2];
+ W[1] = t;
+ W[2] = t >> 32;
}
-
-/// div96bit - Divide 96-bit value stored in W array by D. Return 64-bit frequency.
-uint64_t div96bit(uint64_t W[2], uint32_t D) {
- uint64_t y = W[0];
- uint64_t x = W[1];
- int i;
-
- for (i = 1; i <= 64 && x; ++i) {
- uint32_t t = (int)x >> 31;
- x = (x << 1) | (y >> 63);
- y = y << 1;
- if ((x | t) >= D) {
- x -= D;
- ++y;
+/// Divide 96-bit value stored in W[2]:W[1]:W[0] by D. Since our word size is a
+/// 32 bit unsigned integer, we can use a short division algorithm.
+static uint64_t divrem96bit(uint32_t W[3], uint32_t D, uint32_t *Rout) {
+ // We assume that W[2] is non-zero since if W[2] is not then the user should
+ // just use hardware division.
+ assert(W[2] && "This routine assumes that W[2] is non-zero since if W[2] is "
+ "zero, the caller should just use 64/32 hardware.");
+ uint32_t Q[3] = { 0, 0, 0 };
+
+ // The generalized short division algorithm sets i to m + n - 1, where n is
+ // the number of words in the divisior and m is the number of words by which
+ // the divident exceeds the divisor (i.e. m + n == the length of the dividend
+ // in words). Due to our assumption that W[2] is non-zero, we know that the
+ // dividend is of length 3 implying since n is 1 that m = 2. Thus we set i to
+ // m + n - 1 = 2 + 1 - 1 = 2.
+ uint32_t R = 0;
+ for (int i = 2; i >= 0; --i) {
+ uint64_t PartialD = uint64_t(R) << 32 | W[i];
+ if (PartialD == 0) {
+ Q[i] = 0;
+ R = 0;
+ } else if (PartialD < D) {
+ Q[i] = 0;
+ R = uint32_t(PartialD);
+ } else if (PartialD == D) {
+ Q[i] = 1;
+ R = 0;
+ } else {
+ Q[i] = uint32_t(PartialD / D);
+ R = uint32_t(PartialD - (Q[i] * D));
}
}
- return y << (64 - i + 1);
-}
+ // If Q[2] is non-zero, then we overflowed.
+ uint64_t Result;
+ if (Q[2]) {
+ Result = UINT64_MAX;
+ R = D;
+ } else {
+ // Form the final uint64_t result, avoiding endianness issues.
+ Result = uint64_t(Q[0]) | (uint64_t(Q[1]) << 32);
+ }
+
+ if (Rout)
+ *Rout = R;
+ return Result;
}
+uint32_t BlockFrequency::scale(uint32_t N, uint32_t D) {
+ assert(D != 0 && "Division by zero");
-BlockFrequency &BlockFrequency::operator*=(const BranchProbability &Prob) {
- uint32_t n = Prob.getNumerator();
- uint32_t d = Prob.getDenominator();
-
- assert(n <= d && "Probability must be less or equal to 1.");
-
- // Calculate Frequency * n.
- uint64_t mulLo = (Frequency & UINT32_MAX) * n;
- uint64_t mulHi = (Frequency >> 32) * n;
- uint64_t mulRes = (mulHi << 32) + mulLo;
-
- // If there was overflow use 96-bit operations.
- if (mulHi > UINT32_MAX || mulRes < mulLo) {
- // 96-bit value represented as W[1]:W[0].
- uint64_t W[2];
-
- // Probability is less or equal to 1 which means that results must fit
- // 64-bit.
- mult96bit(Frequency, n, W);
- Frequency = div96bit(W, d);
- return *this;
+ // Calculate Frequency * N.
+ uint64_t MulLo = (Frequency & UINT32_MAX) * N;
+ uint64_t MulHi = (Frequency >> 32) * N;
+ uint64_t MulRes = (MulHi << 32) + MulLo;
+
+ // If the product fits in 64 bits, just use built-in division.
+ if (MulHi <= UINT32_MAX && MulRes >= MulLo) {
+ Frequency = MulRes / D;
+ return MulRes % D;
}
- Frequency = mulRes / d;
+ // Product overflowed, use 96-bit operations.
+ // 96-bit value represented as W[2]:W[1]:W[0].
+ uint32_t W[3];
+ uint32_t R;
+ mult96bit(Frequency, N, W);
+ Frequency = divrem96bit(W, D, &R);
+ return R;
+}
+
+BlockFrequency &BlockFrequency::operator*=(const BranchProbability &Prob) {
+ scale(Prob.getNumerator(), Prob.getDenominator());
return *this;
}
@@ -98,6 +116,17 @@ BlockFrequency::operator*(const BranchProbability &Prob) const {
return Freq;
}
+BlockFrequency &BlockFrequency::operator/=(const BranchProbability &Prob) {
+ scale(Prob.getDenominator(), Prob.getNumerator());
+ return *this;
+}
+
+BlockFrequency BlockFrequency::operator/(const BranchProbability &Prob) const {
+ BlockFrequency Freq(Frequency);
+ Freq /= Prob;
+ return Freq;
+}
+
BlockFrequency &BlockFrequency::operator+=(const BlockFrequency &Freq) {
uint64_t Before = Freq.Frequency;
Frequency += Freq.Frequency;
@@ -116,8 +145,21 @@ BlockFrequency::operator+(const BlockFrequency &Prob) const {
return Freq;
}
+uint32_t BlockFrequency::scale(const BranchProbability &Prob) {
+ return scale(Prob.getNumerator(), Prob.getDenominator());
+}
+
void BlockFrequency::print(raw_ostream &OS) const {
- OS << Frequency;
+ // Convert fixed-point number to decimal.
+ OS << Frequency / getEntryFrequency() << ".";
+ uint64_t Rem = Frequency % getEntryFrequency();
+ uint64_t Eps = 1;
+ do {
+ Rem *= 10;
+ Eps *= 10;
+ OS << Rem / getEntryFrequency();
+ Rem = Rem % getEntryFrequency();
+ } while (Rem >= Eps/2);
}
namespace llvm {
diff --git a/contrib/llvm/lib/Support/CommandLine.cpp b/contrib/llvm/lib/Support/CommandLine.cpp
index 18d3db5..44a88d8 100644
--- a/contrib/llvm/lib/Support/CommandLine.cpp
+++ b/contrib/llvm/lib/Support/CommandLine.cpp
@@ -17,12 +17,14 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/CommandLine.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/config.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Host.h"
@@ -58,6 +60,7 @@ TEMPLATE_INSTANTIATION(class opt<char>);
TEMPLATE_INSTANTIATION(class opt<bool>);
} } // end namespace llvm::cl
+// Pin the vtables to this file.
void GenericOptionValue::anchor() {}
void OptionValue<boolOrDefault>::anchor() {}
void OptionValue<std::string>::anchor() {}
@@ -72,6 +75,7 @@ void parser<double>::anchor() {}
void parser<float>::anchor() {}
void parser<std::string>::anchor() {}
void parser<char>::anchor() {}
+void StringSaver::anchor() {}
//===----------------------------------------------------------------------===//
@@ -435,39 +439,248 @@ static bool EatsUnboundedNumberOfValues(const Option *O) {
O->getNumOccurrencesFlag() == cl::OneOrMore;
}
-/// ParseCStringVector - Break INPUT up wherever one or more
-/// whitespace characters are found, and store the resulting tokens in
-/// OUTPUT. The tokens stored in OUTPUT are dynamically allocated
-/// using strdup(), so it is the caller's responsibility to free()
-/// them later.
+static bool isWhitespace(char C) {
+ return strchr(" \t\n\r\f\v", C);
+}
+
+static bool isQuote(char C) {
+ return C == '\"' || C == '\'';
+}
+
+static bool isGNUSpecial(char C) {
+ return strchr("\\\"\' ", C);
+}
+
+void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv) {
+ SmallString<128> Token;
+ for (size_t I = 0, E = Src.size(); I != E; ++I) {
+ // Consume runs of whitespace.
+ if (Token.empty()) {
+ while (I != E && isWhitespace(Src[I]))
+ ++I;
+ if (I == E) break;
+ }
+
+ // Backslashes can escape backslashes, spaces, and other quotes. Otherwise
+ // they are literal. This makes it much easier to read Windows file paths.
+ if (I + 1 < E && Src[I] == '\\' && isGNUSpecial(Src[I + 1])) {
+ ++I; // Skip the escape.
+ Token.push_back(Src[I]);
+ continue;
+ }
+
+ // Consume a quoted string.
+ if (isQuote(Src[I])) {
+ char Quote = Src[I++];
+ while (I != E && Src[I] != Quote) {
+ // Backslashes are literal, unless they escape a special character.
+ if (Src[I] == '\\' && I + 1 != E && isGNUSpecial(Src[I + 1]))
+ ++I;
+ Token.push_back(Src[I]);
+ ++I;
+ }
+ if (I == E) break;
+ continue;
+ }
+
+ // End the token if this is whitespace.
+ if (isWhitespace(Src[I])) {
+ if (!Token.empty())
+ NewArgv.push_back(Saver.SaveString(Token.c_str()));
+ Token.clear();
+ continue;
+ }
+
+ // This is a normal character. Append it.
+ Token.push_back(Src[I]);
+ }
+
+ // Append the last token after hitting EOF with no whitespace.
+ if (!Token.empty())
+ NewArgv.push_back(Saver.SaveString(Token.c_str()));
+}
+
+/// Backslashes are interpreted in a rather complicated way in the Windows-style
+/// command line, because backslashes are used both to separate path and to
+/// escape double quote. This method consumes runs of backslashes as well as the
+/// following double quote if it's escaped.
+///
+/// * If an even number of backslashes is followed by a double quote, one
+/// backslash is output for every pair of backslashes, and the last double
+/// quote remains unconsumed. The double quote will later be interpreted as
+/// the start or end of a quoted string in the main loop outside of this
+/// function.
+///
+/// * If an odd number of backslashes is followed by a double quote, one
+/// backslash is output for every pair of backslashes, and a double quote is
+/// output for the last pair of backslash-double quote. The double quote is
+/// consumed in this case.
///
-static void ParseCStringVector(std::vector<char *> &OutputVector,
- const char *Input) {
- // Characters which will be treated as token separators:
- StringRef Delims = " \v\f\t\r\n";
-
- StringRef WorkStr(Input);
- while (!WorkStr.empty()) {
- // If the first character is a delimiter, strip them off.
- if (Delims.find(WorkStr[0]) != StringRef::npos) {
- size_t Pos = WorkStr.find_first_not_of(Delims);
- if (Pos == StringRef::npos) Pos = WorkStr.size();
- WorkStr = WorkStr.substr(Pos);
+/// * Otherwise, backslashes are interpreted literally.
+static size_t parseBackslash(StringRef Src, size_t I, SmallString<128> &Token) {
+ size_t E = Src.size();
+ int BackslashCount = 0;
+ // Skip the backslashes.
+ do {
+ ++I;
+ ++BackslashCount;
+ } while (I != E && Src[I] == '\\');
+
+ bool FollowedByDoubleQuote = (I != E && Src[I] == '"');
+ if (FollowedByDoubleQuote) {
+ Token.append(BackslashCount / 2, '\\');
+ if (BackslashCount % 2 == 0)
+ return I - 1;
+ Token.push_back('"');
+ return I;
+ }
+ Token.append(BackslashCount, '\\');
+ return I - 1;
+}
+
+void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv) {
+ SmallString<128> Token;
+
+ // This is a small state machine to consume characters until it reaches the
+ // end of the source string.
+ enum { INIT, UNQUOTED, QUOTED } State = INIT;
+ for (size_t I = 0, E = Src.size(); I != E; ++I) {
+ // INIT state indicates that the current input index is at the start of
+ // the string or between tokens.
+ if (State == INIT) {
+ if (isWhitespace(Src[I]))
+ continue;
+ if (Src[I] == '"') {
+ State = QUOTED;
+ continue;
+ }
+ if (Src[I] == '\\') {
+ I = parseBackslash(Src, I, Token);
+ State = UNQUOTED;
+ continue;
+ }
+ Token.push_back(Src[I]);
+ State = UNQUOTED;
continue;
}
- // Find position of first delimiter.
- size_t Pos = WorkStr.find_first_of(Delims);
- if (Pos == StringRef::npos) Pos = WorkStr.size();
+ // UNQUOTED state means that it's reading a token not quoted by double
+ // quotes.
+ if (State == UNQUOTED) {
+ // Whitespace means the end of the token.
+ if (isWhitespace(Src[I])) {
+ NewArgv.push_back(Saver.SaveString(Token.c_str()));
+ Token.clear();
+ State = INIT;
+ continue;
+ }
+ if (Src[I] == '"') {
+ State = QUOTED;
+ continue;
+ }
+ if (Src[I] == '\\') {
+ I = parseBackslash(Src, I, Token);
+ continue;
+ }
+ Token.push_back(Src[I]);
+ continue;
+ }
- // Everything from 0 to Pos is the next word to copy.
- char *NewStr = (char*)malloc(Pos+1);
- memcpy(NewStr, WorkStr.data(), Pos);
- NewStr[Pos] = 0;
- OutputVector.push_back(NewStr);
+ // QUOTED state means that it's reading a token quoted by double quotes.
+ if (State == QUOTED) {
+ if (Src[I] == '"') {
+ State = UNQUOTED;
+ continue;
+ }
+ if (Src[I] == '\\') {
+ I = parseBackslash(Src, I, Token);
+ continue;
+ }
+ Token.push_back(Src[I]);
+ }
+ }
+ // Append the last token after hitting EOF with no whitespace.
+ if (!Token.empty())
+ NewArgv.push_back(Saver.SaveString(Token.c_str()));
+}
- WorkStr = WorkStr.substr(Pos);
+static bool ExpandResponseFile(const char *FName, StringSaver &Saver,
+ TokenizerCallback Tokenizer,
+ SmallVectorImpl<const char *> &NewArgv) {
+ OwningPtr<MemoryBuffer> MemBuf;
+ if (MemoryBuffer::getFile(FName, MemBuf))
+ return false;
+ StringRef Str(MemBuf->getBufferStart(), MemBuf->getBufferSize());
+
+ // If we have a UTF-16 byte order mark, convert to UTF-8 for parsing.
+ ArrayRef<char> BufRef(MemBuf->getBufferStart(), MemBuf->getBufferEnd());
+ std::string UTF8Buf;
+ if (hasUTF16ByteOrderMark(BufRef)) {
+ if (!convertUTF16ToUTF8String(BufRef, UTF8Buf))
+ return false;
+ Str = StringRef(UTF8Buf);
}
+
+ // Tokenize the contents into NewArgv.
+ Tokenizer(Str, Saver, NewArgv);
+
+ return true;
+}
+
+/// \brief Expand response files on a command line recursively using the given
+/// StringSaver and tokenization strategy.
+bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
+ SmallVectorImpl<const char *> &Argv) {
+ unsigned RspFiles = 0;
+ bool AllExpanded = false;
+
+ // Don't cache Argv.size() because it can change.
+ for (unsigned I = 0; I != Argv.size(); ) {
+ const char *Arg = Argv[I];
+ if (Arg[0] != '@') {
+ ++I;
+ continue;
+ }
+
+ // If we have too many response files, leave some unexpanded. This avoids
+ // crashing on self-referential response files.
+ if (RspFiles++ > 20)
+ return false;
+
+ // Replace this response file argument with the tokenization of its
+ // contents. Nested response files are expanded in subsequent iterations.
+ // FIXME: If a nested response file uses a relative path, is it relative to
+ // the cwd of the process or the response file?
+ SmallVector<const char *, 0> ExpandedArgv;
+ if (!ExpandResponseFile(Arg + 1, Saver, Tokenizer, ExpandedArgv)) {
+ AllExpanded = false;
+ continue;
+ }
+ Argv.erase(Argv.begin() + I);
+ Argv.insert(Argv.begin() + I, ExpandedArgv.begin(), ExpandedArgv.end());
+ }
+ return AllExpanded;
+}
+
+namespace {
+ class StrDupSaver : public StringSaver {
+ std::vector<char*> Dups;
+ public:
+ ~StrDupSaver() {
+ for (std::vector<char *>::iterator I = Dups.begin(), E = Dups.end();
+ I != E; ++I) {
+ char *Dup = *I;
+ free(Dup);
+ }
+ }
+ const char *SaveString(const char *Str) LLVM_OVERRIDE {
+ char *Dup = strdup(Str);
+ Dups.push_back(Dup);
+ return Dup;
+ }
+ };
}
/// ParseEnvironmentOptions - An alternative entry point to the
@@ -488,56 +701,15 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar,
// Get program's "name", which we wouldn't know without the caller
// telling us.
- std::vector<char*> newArgv;
- newArgv.push_back(strdup(progName));
+ SmallVector<const char *, 20> newArgv;
+ StrDupSaver Saver;
+ newArgv.push_back(Saver.SaveString(progName));
// Parse the value of the environment variable into a "command line"
// and hand it off to ParseCommandLineOptions().
- ParseCStringVector(newArgv, envValue);
+ TokenizeGNUCommandLine(envValue, Saver, newArgv);
int newArgc = static_cast<int>(newArgv.size());
ParseCommandLineOptions(newArgc, &newArgv[0], Overview);
-
- // Free all the strdup()ed strings.
- for (std::vector<char*>::iterator i = newArgv.begin(), e = newArgv.end();
- i != e; ++i)
- free(*i);
-}
-
-
-/// ExpandResponseFiles - Copy the contents of argv into newArgv,
-/// substituting the contents of the response files for the arguments
-/// of type @file.
-static void ExpandResponseFiles(unsigned argc, const char*const* argv,
- std::vector<char*>& newArgv) {
- for (unsigned i = 1; i != argc; ++i) {
- const char *arg = argv[i];
-
- if (arg[0] == '@') {
- sys::PathWithStatus respFile(++arg);
-
- // Check that the response file is not empty (mmap'ing empty
- // files can be problematic).
- const sys::FileStatus *FileStat = respFile.getFileStatus();
- if (FileStat && FileStat->getSize() != 0) {
-
- // If we could open the file, parse its contents, otherwise
- // pass the @file option verbatim.
-
- // TODO: we should also support recursive loading of response files,
- // since this is how gcc behaves. (From their man page: "The file may
- // itself contain additional @file options; any such options will be
- // processed recursively.")
-
- // Mmap the response file into memory.
- OwningPtr<MemoryBuffer> respFilePtr;
- if (!MemoryBuffer::getFile(respFile.c_str(), respFilePtr)) {
- ParseCStringVector(newArgv, respFilePtr->getBufferStart());
- continue;
- }
- }
- }
- newArgv.push_back(strdup(arg));
- }
}
void cl::ParseCommandLineOptions(int argc, const char * const *argv,
@@ -552,9 +724,11 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv,
"No options specified!");
// Expand response files.
- std::vector<char*> newArgv;
- newArgv.push_back(strdup(argv[0]));
- ExpandResponseFiles(argc, argv, newArgv);
+ SmallVector<const char *, 20> newArgv;
+ for (int i = 0; i != argc; ++i)
+ newArgv.push_back(argv[i]);
+ StrDupSaver Saver;
+ ExpandResponseFiles(Saver, TokenizeGNUCommandLine, newArgv);
argv = &newArgv[0];
argc = static_cast<int>(newArgv.size());
@@ -848,12 +1022,6 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv,
PositionalOpts.clear();
MoreHelp->clear();
- // Free the memory allocated by ExpandResponseFiles.
- // Free all the strdup()ed strings.
- for (std::vector<char*>::iterator i = newArgv.begin(), e = newArgv.end();
- i != e; ++i)
- free(*i);
-
// If we had an error processing our arguments, don't let the program execute
if (ErrorParsing) exit(1);
}
@@ -913,11 +1081,20 @@ size_t alias::getOptionWidth() const {
return std::strlen(ArgStr)+6;
}
+static void printHelpStr(StringRef HelpStr, size_t Indent,
+ size_t FirstLineIndentedBy) {
+ std::pair<StringRef, StringRef> Split = HelpStr.split('\n');
+ outs().indent(Indent - FirstLineIndentedBy) << " - " << Split.first << "\n";
+ while (!Split.second.empty()) {
+ Split = Split.second.split('\n');
+ outs().indent(Indent) << Split.first << "\n";
+ }
+}
+
// Print out the option for the alias.
void alias::printOptionInfo(size_t GlobalWidth) const {
- size_t L = std::strlen(ArgStr);
outs() << " -" << ArgStr;
- outs().indent(GlobalWidth-L-6) << " - " << HelpStr << "\n";
+ printHelpStr(HelpStr, GlobalWidth, std::strlen(ArgStr) + 6);
}
//===----------------------------------------------------------------------===//
@@ -946,7 +1123,7 @@ void basic_parser_impl::printOptionInfo(const Option &O,
if (const char *ValName = getValueName())
outs() << "=<" << getValueStr(O, ValName) << '>';
- outs().indent(GlobalWidth-getOptionWidth(O)) << " - " << O.HelpStr << '\n';
+ printHelpStr(O.HelpStr, GlobalWidth, getOptionWidth(O));
}
void basic_parser_impl::printOptionName(const Option &O,
@@ -1087,9 +1264,8 @@ size_t generic_parser_base::getOptionWidth(const Option &O) const {
void generic_parser_base::printOptionInfo(const Option &O,
size_t GlobalWidth) const {
if (O.hasArgStr()) {
- size_t L = std::strlen(O.ArgStr);
outs() << " -" << O.ArgStr;
- outs().indent(GlobalWidth-L-6) << " - " << O.HelpStr << '\n';
+ printHelpStr(O.HelpStr, GlobalWidth, std::strlen(O.ArgStr) + 6);
for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
size_t NumSpaces = GlobalWidth-strlen(getOption(i))-8;
@@ -1100,9 +1276,9 @@ void generic_parser_base::printOptionInfo(const Option &O,
if (O.HelpStr[0])
outs() << " " << O.HelpStr << '\n';
for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
- size_t L = std::strlen(getOption(i));
- outs() << " -" << getOption(i);
- outs().indent(GlobalWidth-L-8) << " - " << getDescription(i) << '\n';
+ const char *Option = getOption(i);
+ outs() << " -" << Option;
+ printHelpStr(getDescription(i), GlobalWidth, std::strlen(Option) + 8);
}
}
}
diff --git a/contrib/llvm/lib/Support/Compression.cpp b/contrib/llvm/lib/Support/Compression.cpp
index fd8a874..b5ddb70 100644
--- a/contrib/llvm/lib/Support/Compression.cpp
+++ b/contrib/llvm/lib/Support/Compression.cpp
@@ -81,6 +81,10 @@ zlib::Status zlib::uncompress(StringRef InputBuffer,
return Res;
}
+uint32_t zlib::crc32(StringRef Buffer) {
+ return ::crc32(0, (const Bytef *)Buffer.data(), Buffer.size());
+}
+
#else
bool zlib::isAvailable() { return false; }
zlib::Status zlib::compress(StringRef InputBuffer,
@@ -93,5 +97,8 @@ zlib::Status zlib::uncompress(StringRef InputBuffer,
size_t UncompressedSize) {
return zlib::StatusUnsupported;
}
+uint32_t zlib::crc32(StringRef Buffer) {
+ llvm_unreachable("zlib::crc32 is unavailable");
+}
#endif
diff --git a/contrib/llvm/lib/Support/ConstantRange.cpp b/contrib/llvm/lib/Support/ConstantRange.cpp
index 5c58950..265b6e9 100644
--- a/contrib/llvm/lib/Support/ConstantRange.cpp
+++ b/contrib/llvm/lib/Support/ConstantRange.cpp
@@ -38,13 +38,14 @@ ConstantRange::ConstantRange(uint32_t BitWidth, bool Full) {
/// Initialize a range to hold the single specified value.
///
-ConstantRange::ConstantRange(const APInt &V) : Lower(V), Upper(V + 1) {}
+ConstantRange::ConstantRange(APIntMoveTy V)
+ : Lower(llvm_move(V)), Upper(Lower + 1) {}
-ConstantRange::ConstantRange(const APInt &L, const APInt &U) :
- Lower(L), Upper(U) {
- assert(L.getBitWidth() == U.getBitWidth() &&
+ConstantRange::ConstantRange(APIntMoveTy L, APIntMoveTy U)
+ : Lower(llvm_move(L)), Upper(llvm_move(U)) {
+ assert(Lower.getBitWidth() == Upper.getBitWidth() &&
"ConstantRange with unequal bit widths");
- assert((L != U || (L.isMaxValue() || L.isMinValue())) &&
+ assert((Lower != Upper || (Lower.isMaxValue() || Lower.isMinValue())) &&
"Lower == Upper, but they aren't min or max value!");
}
@@ -143,9 +144,6 @@ bool ConstantRange::isSignWrappedSet() const {
/// getSetSize - Return the number of elements in this set.
///
APInt ConstantRange::getSetSize() const {
- if (isEmptySet())
- return APInt(getBitWidth()+1, 0);
-
if (isFullSet()) {
APInt Size(getBitWidth()+1, 0);
Size.setBit(getBitWidth());
@@ -432,7 +430,7 @@ ConstantRange ConstantRange::zeroExtend(uint32_t DstTySize) const {
APInt LowerExt(DstTySize, 0);
if (!Upper) // special case: [X, 0) -- not really wrapping around
LowerExt = Lower.zext(DstTySize);
- return ConstantRange(LowerExt, APInt(DstTySize, 1).shl(SrcTySize));
+ return ConstantRange(LowerExt, APInt::getOneBitSet(DstTySize, SrcTySize));
}
return ConstantRange(Lower.zext(DstTySize), Upper.zext(DstTySize));
@@ -447,6 +445,11 @@ ConstantRange ConstantRange::signExtend(uint32_t DstTySize) const {
unsigned SrcTySize = getBitWidth();
assert(SrcTySize < DstTySize && "Not a value extension");
+
+ // special case: [X, INT_MIN) -- not really wrapping around
+ if (Upper.isMinSignedValue())
+ return ConstantRange(Lower.sext(DstTySize), Upper.zext(DstTySize));
+
if (isFullSet() || isSignWrappedSet()) {
return ConstantRange(APInt::getHighBitsSet(DstTySize,DstTySize-SrcTySize+1),
APInt::getLowBitsSet(DstTySize, SrcTySize-1) + 1);
diff --git a/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp b/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp
index 458fbb0..e45335d 100644
--- a/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp
+++ b/contrib/llvm/lib/Support/ConvertUTFWrapper.cpp
@@ -8,6 +8,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/SwapByteOrder.h"
+#include <string>
+#include <vector>
namespace llvm {
@@ -72,5 +75,57 @@ bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
return true;
}
+bool hasUTF16ByteOrderMark(ArrayRef<char> S) {
+ return (S.size() >= 2 &&
+ ((S[0] == '\xff' && S[1] == '\xfe') ||
+ (S[0] == '\xfe' && S[1] == '\xff')));
+}
+
+bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out) {
+ assert(Out.empty());
+
+ // Error out on an uneven byte count.
+ if (SrcBytes.size() % 2)
+ return false;
+
+ // Avoid OOB by returning early on empty input.
+ if (SrcBytes.empty())
+ return true;
+
+ const UTF16 *Src = reinterpret_cast<const UTF16 *>(SrcBytes.begin());
+ const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(SrcBytes.end());
+
+ // Byteswap if necessary.
+ std::vector<UTF16> ByteSwapped;
+ if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) {
+ ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
+ for (unsigned I = 0, E = ByteSwapped.size(); I != E; ++I)
+ ByteSwapped[I] = llvm::sys::SwapByteOrder_16(ByteSwapped[I]);
+ Src = &ByteSwapped[0];
+ SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
+ }
+
+ // Skip the BOM for conversion.
+ if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_NATIVE)
+ Src++;
+
+ // Just allocate enough space up front. We'll shrink it later.
+ Out.resize(SrcBytes.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
+ UTF8 *Dst = reinterpret_cast<UTF8 *>(&Out[0]);
+ UTF8 *DstEnd = Dst + Out.size();
+
+ ConversionResult CR =
+ ConvertUTF16toUTF8(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
+ assert(CR != targetExhausted);
+
+ if (CR != conversionOK) {
+ Out.clear();
+ return false;
+ }
+
+ Out.resize(reinterpret_cast<char *>(Dst) - &Out[0]);
+ return true;
+}
+
} // end namespace llvm
diff --git a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp
index 182c362..92c370d 100644
--- a/contrib/llvm/lib/Support/CrashRecoveryContext.cpp
+++ b/contrib/llvm/lib/Support/CrashRecoveryContext.cpp
@@ -11,6 +11,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/ThreadLocal.h"
#include <cstdio>
@@ -21,27 +22,34 @@ namespace {
struct CrashRecoveryContextImpl;
-static sys::ThreadLocal<const CrashRecoveryContextImpl> CurrentContext;
+static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext;
struct CrashRecoveryContextImpl {
CrashRecoveryContext *CRC;
std::string Backtrace;
::jmp_buf JumpBuffer;
volatile unsigned Failed : 1;
+ unsigned SwitchedThread : 1;
public:
CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC),
- Failed(false) {
- CurrentContext.set(this);
+ Failed(false),
+ SwitchedThread(false) {
+ CurrentContext->set(this);
}
~CrashRecoveryContextImpl() {
- CurrentContext.erase();
+ if (!SwitchedThread)
+ CurrentContext->erase();
}
+ /// \brief Called when the separate crash-recovery thread was finished, to
+ /// indicate that we don't need to clear the thread-local CurrentContext.
+ void setSwitchedThread() { SwitchedThread = true; }
+
void HandleCrash() {
// Eliminate the current context entry, to avoid re-entering in case the
// cleanup code crashes.
- CurrentContext.erase();
+ CurrentContext->erase();
assert(!Failed && "Crash recovery context already failed!");
Failed = true;
@@ -55,10 +63,10 @@ public:
}
-static sys::Mutex gCrashRecoveryContexMutex;
+static ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex;
static bool gCrashRecoveryEnabled = false;
-static sys::ThreadLocal<const CrashRecoveryContextCleanup>
+static ManagedStatic<sys::ThreadLocal<const CrashRecoveryContextCleanup> >
tlIsRecoveringFromCrash;
CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
@@ -66,7 +74,7 @@ CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {}
CrashRecoveryContext::~CrashRecoveryContext() {
// Reclaim registered resources.
CrashRecoveryContextCleanup *i = head;
- tlIsRecoveringFromCrash.set(head);
+ tlIsRecoveringFromCrash->set(head);
while (i) {
CrashRecoveryContextCleanup *tmp = i;
i = tmp->next;
@@ -74,21 +82,21 @@ CrashRecoveryContext::~CrashRecoveryContext() {
tmp->recoverResources();
delete tmp;
}
- tlIsRecoveringFromCrash.erase();
+ tlIsRecoveringFromCrash->erase();
CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl;
delete CRCI;
}
bool CrashRecoveryContext::isRecoveringFromCrash() {
- return tlIsRecoveringFromCrash.get() != 0;
+ return tlIsRecoveringFromCrash->get() != 0;
}
CrashRecoveryContext *CrashRecoveryContext::GetCurrent() {
if (!gCrashRecoveryEnabled)
return 0;
- const CrashRecoveryContextImpl *CRCI = CurrentContext.get();
+ const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
if (!CRCI)
return 0;
@@ -147,7 +155,7 @@ CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) {
static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
// Lookup the current thread local recovery object.
- const CrashRecoveryContextImpl *CRCI = CurrentContext.get();
+ const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
if (!CRCI) {
// Something has gone horribly wrong, so let's just tell everyone
@@ -175,7 +183,7 @@ static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
static sys::ThreadLocal<const void> sCurrentExceptionHandle;
void CrashRecoveryContext::Enable() {
- sys::ScopedLock L(gCrashRecoveryContexMutex);
+ sys::ScopedLock L(*gCrashRecoveryContextMutex);
if (gCrashRecoveryEnabled)
return;
@@ -191,7 +199,7 @@ void CrashRecoveryContext::Enable() {
}
void CrashRecoveryContext::Disable() {
- sys::ScopedLock L(gCrashRecoveryContexMutex);
+ sys::ScopedLock L(*gCrashRecoveryContextMutex);
if (!gCrashRecoveryEnabled)
return;
@@ -229,7 +237,7 @@ static struct sigaction PrevActions[NumSignals];
static void CrashRecoverySignalHandler(int Signal) {
// Lookup the current thread local recovery object.
- const CrashRecoveryContextImpl *CRCI = CurrentContext.get();
+ const CrashRecoveryContextImpl *CRCI = CurrentContext->get();
if (!CRCI) {
// We didn't find a crash recovery context -- this means either we got a
@@ -260,7 +268,7 @@ static void CrashRecoverySignalHandler(int Signal) {
}
void CrashRecoveryContext::Enable() {
- sys::ScopedLock L(gCrashRecoveryContexMutex);
+ sys::ScopedLock L(*gCrashRecoveryContextMutex);
if (gCrashRecoveryEnabled)
return;
@@ -279,7 +287,7 @@ void CrashRecoveryContext::Enable() {
}
void CrashRecoveryContext::Disable() {
- sys::ScopedLock L(gCrashRecoveryContexMutex);
+ sys::ScopedLock L(*gCrashRecoveryContextMutex);
if (!gCrashRecoveryEnabled)
return;
@@ -342,5 +350,7 @@ bool CrashRecoveryContext::RunSafelyOnThread(void (*Fn)(void*), void *UserData,
unsigned RequestedStackSize) {
RunSafelyOnThreadInfo Info = { Fn, UserData, this, false };
llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize);
+ if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl)
+ CRC->setSwitchedThread();
return Info.Result;
}
diff --git a/contrib/llvm/lib/Support/DataStream.cpp b/contrib/llvm/lib/Support/DataStream.cpp
index 0a02281..0bd0c68 100644
--- a/contrib/llvm/lib/Support/DataStream.cpp
+++ b/contrib/llvm/lib/Support/DataStream.cpp
@@ -17,6 +17,7 @@
#define DEBUG_TYPE "Data-stream"
#include "llvm/Support/DataStream.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/system_error.h"
#include <cerrno>
@@ -27,7 +28,6 @@
#else
#include <io.h>
#endif
-#include <fcntl.h>
using namespace llvm;
// Interface goals:
@@ -66,18 +66,11 @@ public:
error_code OpenFile(const std::string &Filename) {
if (Filename == "-") {
Fd = 0;
- sys::Program::ChangeStdinToBinary();
+ sys::ChangeStdinToBinary();
return error_code::success();
}
-
- int OpenFlags = O_RDONLY;
-#ifdef O_BINARY
- OpenFlags |= O_BINARY; // Open input file in binary mode on win32.
-#endif
- Fd = ::open(Filename.c_str(), OpenFlags);
- if (Fd == -1)
- return error_code(errno, posix_category());
- return error_code::success();
+
+ return sys::fs::openFileForRead(Filename, Fd);
}
};
diff --git a/contrib/llvm/lib/Support/Disassembler.cpp b/contrib/llvm/lib/Support/Disassembler.cpp
index b3244fa..27df3a9 100644
--- a/contrib/llvm/lib/Support/Disassembler.cpp
+++ b/contrib/llvm/lib/Support/Disassembler.cpp
@@ -41,10 +41,10 @@ bool llvm::sys::hasDisassembler()
std::string llvm::sys::disassembleBuffer(uint8_t* start, size_t length,
uint64_t pc) {
- std::stringstream res;
-
#if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) \
&& USE_UDIS86
+ std::stringstream res;
+
unsigned bits;
# if defined(__i386__)
bits = 32;
@@ -66,9 +66,9 @@ std::string llvm::sys::disassembleBuffer(uint8_t* start, size_t length,
while (ud_disassemble(&ud_obj)) {
res << ud_insn_off(&ud_obj) << ":\t" << ud_insn_asm(&ud_obj) << "\n";
}
-#else
- res << "No disassembler available. See configure help for options.\n";
-#endif
return res.str();
+#else
+ return "No disassembler available. See configure help for options.\n";
+#endif
}
diff --git a/contrib/llvm/lib/Support/Dwarf.cpp b/contrib/llvm/lib/Support/Dwarf.cpp
index 0a24883..c000b63 100644
--- a/contrib/llvm/lib/Support/Dwarf.cpp
+++ b/contrib/llvm/lib/Support/Dwarf.cpp
@@ -12,6 +12,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/ErrorHandling.h"
+
using namespace llvm;
using namespace dwarf;
@@ -59,8 +61,8 @@ const char *llvm::dwarf::TagString(unsigned Tag) {
case DW_TAG_namelist_item: return "DW_TAG_namelist_item";
case DW_TAG_packed_type: return "DW_TAG_packed_type";
case DW_TAG_subprogram: return "DW_TAG_subprogram";
- case DW_TAG_template_type_parameter: return "DW_TAG_template_type_parameter";
- case DW_TAG_template_value_parameter:return "DW_TAG_template_value_parameter";
+ case DW_TAG_template_type_parameter: return "DW_TAG_template_type_parameter";
+ case DW_TAG_template_value_parameter: return "DW_TAG_template_value_parameter";
case DW_TAG_thrown_type: return "DW_TAG_thrown_type";
case DW_TAG_try_block: return "DW_TAG_try_block";
case DW_TAG_variant_part: return "DW_TAG_variant_part";
@@ -230,6 +232,7 @@ const char *llvm::dwarf::AttributeString(unsigned Attribute) {
case DW_AT_body_end: return "DW_AT_body_end";
case DW_AT_GNU_vector: return "DW_AT_GNU_vector";
case DW_AT_GNU_template_name: return "DW_AT_GNU_template_name";
+ case DW_AT_GNU_odr_signature: return "DW_AT_GNU_odr_signature";
case DW_AT_MIPS_assumed_size: return "DW_AT_MIPS_assumed_size";
case DW_AT_lo_user: return "DW_AT_lo_user";
case DW_AT_hi_user: return "DW_AT_hi_user";
@@ -723,3 +726,51 @@ const char *llvm::dwarf::CallFrameString(unsigned Encoding) {
}
return 0;
}
+
+const char *llvm::dwarf::AtomTypeString(unsigned AT) {
+ switch (AT) {
+ case dwarf::DW_ATOM_null:
+ return "DW_ATOM_null";
+ case dwarf::DW_ATOM_die_offset:
+ return "DW_ATOM_die_offset";
+ case DW_ATOM_cu_offset:
+ return "DW_ATOM_cu_offset";
+ case DW_ATOM_die_tag:
+ return "DW_ATOM_die_tag";
+ case DW_ATOM_type_flags:
+ return "DW_ATOM_type_flags";
+ }
+ return 0;
+}
+
+const char *llvm::dwarf::GDBIndexEntryKindString(GDBIndexEntryKind Kind) {
+ switch (Kind) {
+ case GIEK_NONE:
+ return "NONE";
+ case GIEK_TYPE:
+ return "TYPE";
+ case GIEK_VARIABLE:
+ return "VARIABLE";
+ case GIEK_FUNCTION:
+ return "FUNCTION";
+ case GIEK_OTHER:
+ return "OTHER";
+ case GIEK_UNUSED5:
+ return "UNUSED5";
+ case GIEK_UNUSED6:
+ return "UNUSED6";
+ case GIEK_UNUSED7:
+ return "UNUSED7";
+ }
+ llvm_unreachable("Unknown GDBIndexEntryKind value");
+}
+
+const char *llvm::dwarf::GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage) {
+ switch (Linkage) {
+ case GIEL_EXTERNAL:
+ return "EXTERNAL";
+ case GIEL_STATIC:
+ return "STATIC";
+ }
+ llvm_unreachable("Unknown GDBIndexEntryLinkage value");
+}
diff --git a/contrib/llvm/lib/Support/DynamicLibrary.cpp b/contrib/llvm/lib/Support/DynamicLibrary.cpp
index f14cb45..a825c68 100644
--- a/contrib/llvm/lib/Support/DynamicLibrary.cpp
+++ b/contrib/llvm/lib/Support/DynamicLibrary.cpp
@@ -14,39 +14,22 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Mutex.h"
+#include "llvm-c/Support.h"
#include <cstdio>
#include <cstring>
// Collection of symbol name/value pairs to be searched prior to any libraries.
-static llvm::StringMap<void *> *ExplicitSymbols = 0;
-
-namespace {
-
-struct ExplicitSymbolsDeleter {
- ~ExplicitSymbolsDeleter() {
- delete ExplicitSymbols;
- }
-};
-
-}
-
-static ExplicitSymbolsDeleter Dummy;
-
-
-static llvm::sys::SmartMutex<true>& getMutex() {
- static llvm::sys::SmartMutex<true> HandlesMutex;
- return HandlesMutex;
-}
+static llvm::ManagedStatic<llvm::StringMap<void *> > ExplicitSymbols;
+static llvm::ManagedStatic<llvm::sys::SmartMutex<true> > SymbolsMutex;
void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
void *symbolValue) {
- SmartScopedLock<true> lock(getMutex());
- if (ExplicitSymbols == 0)
- ExplicitSymbols = new StringMap<void*>();
+ SmartScopedLock<true> lock(*SymbolsMutex);
(*ExplicitSymbols)[symbolName] = symbolValue;
}
@@ -72,7 +55,7 @@ static DenseSet<void *> *OpenedHandles = 0;
DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
std::string *errMsg) {
- SmartScopedLock<true> lock(getMutex());
+ SmartScopedLock<true> lock(*SymbolsMutex);
void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
if (handle == 0) {
@@ -126,10 +109,10 @@ void *SearchForAddressOfSpecialSymbol(const char* symbolName);
}
void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
- SmartScopedLock<true> Lock(getMutex());
+ SmartScopedLock<true> Lock(*SymbolsMutex);
// First check symbols added via AddSymbol().
- if (ExplicitSymbols) {
+ if (ExplicitSymbols.isConstructed()) {
StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);
if (i != ExplicitSymbols->end())
@@ -187,3 +170,11 @@ void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
}
#endif // LLVM_ON_WIN32
+
+//===----------------------------------------------------------------------===//
+// C API.
+//===----------------------------------------------------------------------===//
+
+LLVMBool LLVMLoadLibraryPermanently(const char* Filename) {
+ return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
+}
diff --git a/contrib/llvm/lib/Support/Errno.cpp b/contrib/llvm/lib/Support/Errno.cpp
index 730220f..1eefa3e 100644
--- a/contrib/llvm/lib/Support/Errno.cpp
+++ b/contrib/llvm/lib/Support/Errno.cpp
@@ -14,8 +14,6 @@
#include "llvm/Support/Errno.h"
#include "llvm/Config/config.h" // Get autoconf configuration settings
#include "llvm/Support/raw_ostream.h"
-
-#if HAVE_STRING_H
#include <string.h>
#if HAVE_ERRNO_H
@@ -41,28 +39,27 @@ std::string StrError(int errnum) {
char buffer[MaxErrStrLen];
buffer[0] = '\0';
std::string str;
+ if (errnum == 0)
+ return str;
+
#ifdef HAVE_STRERROR_R
// strerror_r is thread-safe.
- if (errnum)
-# if defined(__GLIBC__) && defined(_GNU_SOURCE)
- // glibc defines its own incompatible version of strerror_r
- // which may not use the buffer supplied.
- str = strerror_r(errnum,buffer,MaxErrStrLen-1);
-# else
- strerror_r(errnum,buffer,MaxErrStrLen-1);
- str = buffer;
-# endif
+#if defined(__GLIBC__) && defined(_GNU_SOURCE)
+ // glibc defines its own incompatible version of strerror_r
+ // which may not use the buffer supplied.
+ str = strerror_r(errnum, buffer, MaxErrStrLen - 1);
+#else
+ strerror_r(errnum, buffer, MaxErrStrLen - 1);
+ str = buffer;
+#endif
#elif HAVE_DECL_STRERROR_S // "Windows Secure API"
- if (errnum) {
- strerror_s(buffer, MaxErrStrLen - 1, errnum);
- str = buffer;
- }
+ strerror_s(buffer, MaxErrStrLen - 1, errnum);
+ str = buffer;
#elif defined(HAVE_STRERROR)
// Copy the thread un-safe result of strerror into
// the buffer as fast as possible to minimize impact
// of collision of strerror in multiple threads.
- if (errnum)
- str = strerror(errnum);
+ str = strerror(errnum);
#else
// Strange that this system doesn't even have strerror
// but, oh well, just use a generic message
@@ -75,5 +72,3 @@ std::string StrError(int errnum) {
} // namespace sys
} // namespace llvm
-
-#endif // HAVE_STRING_H
diff --git a/contrib/llvm/lib/Support/ErrorHandling.cpp b/contrib/llvm/lib/Support/ErrorHandling.cpp
index f4b591e..1eafb96 100644
--- a/contrib/llvm/lib/Support/ErrorHandling.cpp
+++ b/contrib/llvm/lib/Support/ErrorHandling.cpp
@@ -20,6 +20,7 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm-c/Core.h"
#include <cassert>
#include <cstdlib>
@@ -96,4 +97,25 @@ void llvm::llvm_unreachable_internal(const char *msg, const char *file,
dbgs() << " at " << file << ":" << line;
dbgs() << "!\n";
abort();
+#ifdef LLVM_BUILTIN_UNREACHABLE
+ // Windows systems and possibly others don't declare abort() to be noreturn,
+ // so use the unreachable builtin to avoid a Clang self-host warning.
+ LLVM_BUILTIN_UNREACHABLE;
+#endif
+}
+
+static void bindingsErrorHandler(void *user_data, const std::string& reason,
+ bool gen_crash_diag) {
+ LLVMFatalErrorHandler handler =
+ LLVM_EXTENSION reinterpret_cast<LLVMFatalErrorHandler>(user_data);
+ handler(reason.c_str());
+}
+
+void LLVMInstallFatalErrorHandler(LLVMFatalErrorHandler Handler) {
+ install_fatal_error_handler(bindingsErrorHandler,
+ LLVM_EXTENSION reinterpret_cast<void *>(Handler));
+}
+
+void LLVMResetFatalErrorHandler() {
+ remove_fatal_error_handler();
}
diff --git a/contrib/llvm/lib/Support/FileOutputBuffer.cpp b/contrib/llvm/lib/Support/FileOutputBuffer.cpp
index 1ee69b6..ed084fa 100644
--- a/contrib/llvm/lib/Support/FileOutputBuffer.cpp
+++ b/contrib/llvm/lib/Support/FileOutputBuffer.cpp
@@ -62,11 +62,16 @@ error_code FileOutputBuffer::create(StringRef FilePath,
if (EC)
return EC;
+ unsigned Mode = sys::fs::all_read | sys::fs::all_write;
+ // If requested, make the output file executable.
+ if (Flags & F_executable)
+ Mode |= sys::fs::all_exe;
+
// Create new file in same directory but with random name.
SmallString<128> TempFilePath;
int FD;
- EC = sys::fs::unique_file(Twine(FilePath) + ".tmp%%%%%%%",
- FD, TempFilePath, false, 0644);
+ EC = sys::fs::createUniqueFile(Twine(FilePath) + ".tmp%%%%%%%", FD,
+ TempFilePath, Mode);
if (EC)
return EC;
@@ -75,26 +80,6 @@ error_code FileOutputBuffer::create(StringRef FilePath,
if (EC)
return EC;
- // If requested, make the output file executable.
- if ( Flags & F_executable ) {
- sys::fs::file_status Stat2;
- EC = sys::fs::status(Twine(TempFilePath), Stat2);
- if (EC)
- return EC;
-
- sys::fs::perms new_perms = Stat2.permissions();
- if ( new_perms & sys::fs::owner_read )
- new_perms |= sys::fs::owner_exe;
- if ( new_perms & sys::fs::group_read )
- new_perms |= sys::fs::group_exe;
- if ( new_perms & sys::fs::others_read )
- new_perms |= sys::fs::others_exe;
- new_perms |= sys::fs::add_perms;
- EC = sys::fs::permissions(Twine(TempFilePath), new_perms);
- if (EC)
- return EC;
- }
-
Result.reset(new FileOutputBuffer(MappedFile.get(), FilePath, TempFilePath));
if (Result)
MappedFile.take();
diff --git a/contrib/llvm/lib/Support/FileUtilities.cpp b/contrib/llvm/lib/Support/FileUtilities.cpp
index 4d7b239..7f5d540 100644
--- a/contrib/llvm/lib/Support/FileUtilities.cpp
+++ b/contrib/llvm/lib/Support/FileUtilities.cpp
@@ -171,43 +171,20 @@ static bool CompareNumbers(const char *&F1P, const char *&F2P,
/// error occurs, allowing the caller to distinguish between a failed diff and a
/// file system error.
///
-int llvm::DiffFilesWithTolerance(const sys::PathWithStatus &FileA,
- const sys::PathWithStatus &FileB,
+int llvm::DiffFilesWithTolerance(StringRef NameA,
+ StringRef NameB,
double AbsTol, double RelTol,
std::string *Error) {
- const sys::FileStatus *FileAStat = FileA.getFileStatus(false, Error);
- if (!FileAStat)
- return 2;
- const sys::FileStatus *FileBStat = FileB.getFileStatus(false, Error);
- if (!FileBStat)
- return 2;
-
- // Check for zero length files because some systems croak when you try to
- // mmap an empty file.
- size_t A_size = FileAStat->getSize();
- size_t B_size = FileBStat->getSize();
-
- // If they are both zero sized then they're the same
- if (A_size == 0 && B_size == 0)
- return 0;
-
- // If only one of them is zero sized then they can't be the same
- if ((A_size == 0 || B_size == 0)) {
- if (Error)
- *Error = "Files differ: one is zero-sized, the other isn't";
- return 1;
- }
-
// Now its safe to mmap the files into memory because both files
// have a non-zero size.
OwningPtr<MemoryBuffer> F1;
- if (error_code ec = MemoryBuffer::getFile(FileA.c_str(), F1)) {
+ if (error_code ec = MemoryBuffer::getFile(NameA, F1)) {
if (Error)
*Error = ec.message();
return 2;
}
OwningPtr<MemoryBuffer> F2;
- if (error_code ec = MemoryBuffer::getFile(FileB.c_str(), F2)) {
+ if (error_code ec = MemoryBuffer::getFile(NameB, F2)) {
if (Error)
*Error = ec.message();
return 2;
@@ -220,6 +197,8 @@ int llvm::DiffFilesWithTolerance(const sys::PathWithStatus &FileA,
const char *File2End = F2->getBufferEnd();
const char *F1P = File1Start;
const char *F2P = File2Start;
+ uint64_t A_size = F1->getBufferSize();
+ uint64_t B_size = F2->getBufferSize();
// Are the buffers identical? Common case: Handle this efficiently.
if (A_size == B_size &&
diff --git a/contrib/llvm/lib/Support/FormattedStream.cpp b/contrib/llvm/lib/Support/FormattedStream.cpp
index 231ae48..9febf66 100644
--- a/contrib/llvm/lib/Support/FormattedStream.cpp
+++ b/contrib/llvm/lib/Support/FormattedStream.cpp
@@ -17,38 +17,43 @@
using namespace llvm;
-/// CountColumns - Examine the given char sequence and figure out which
-/// column we end up in after output.
+/// UpdatePosition - Examine the given char sequence and figure out which
+/// column we end up in after output, and how many line breaks are contained.
///
-static unsigned CountColumns(unsigned Column, const char *Ptr, size_t Size) {
- // Keep track of the current column by scanning the string for
- // special characters
+static void UpdatePosition(std::pair<unsigned, unsigned> &Position, const char *Ptr, size_t Size) {
+ unsigned &Column = Position.first;
+ unsigned &Line = Position.second;
+ // Keep track of the current column and line by scanning the string for
+ // special characters
for (const char *End = Ptr + Size; Ptr != End; ++Ptr) {
++Column;
- if (*Ptr == '\n' || *Ptr == '\r')
+ switch (*Ptr) {
+ case '\n':
+ Line += 1;
+ case '\r':
Column = 0;
- else if (*Ptr == '\t')
+ break;
+ case '\t':
// Assumes tab stop = 8 characters.
Column += (8 - (Column & 0x7)) & 0x7;
+ break;
+ }
}
-
- return Column;
}
-/// ComputeColumn - Examine the current output and figure out which
-/// column we end up in after output.
-void formatted_raw_ostream::ComputeColumn(const char *Ptr, size_t Size) {
+/// ComputePosition - Examine the current output and update line and column
+/// counts.
+void formatted_raw_ostream::ComputePosition(const char *Ptr, size_t Size) {
// If our previous scan pointer is inside the buffer, assume we already
// scanned those bytes. This depends on raw_ostream to not change our buffer
// in unexpected ways.
- if (Ptr <= Scanned && Scanned <= Ptr + Size) {
+ if (Ptr <= Scanned && Scanned <= Ptr + Size)
// Scan all characters added since our last scan to determine the new
// column.
- ColumnScanned = CountColumns(ColumnScanned, Scanned,
- Size - (Scanned - Ptr));
- } else
- ColumnScanned = CountColumns(ColumnScanned, Ptr, Size);
+ UpdatePosition(Position, Scanned, Size - (Scanned - Ptr));
+ else
+ UpdatePosition(Position, Ptr, Size);
// Update the scanning pointer.
Scanned = Ptr + Size;
@@ -60,16 +65,16 @@ void formatted_raw_ostream::ComputeColumn(const char *Ptr, size_t Size) {
///
formatted_raw_ostream &formatted_raw_ostream::PadToColumn(unsigned NewCol) {
// Figure out what's in the buffer and add it to the column count.
- ComputeColumn(getBufferStart(), GetNumBytesInBuffer());
+ ComputePosition(getBufferStart(), GetNumBytesInBuffer());
// Output spaces until we reach the desired column.
- indent(std::max(int(NewCol - ColumnScanned), 1));
+ indent(std::max(int(NewCol - getColumn()), 1));
return *this;
}
void formatted_raw_ostream::write_impl(const char *Ptr, size_t Size) {
// Figure out what's in the buffer and add it to the column count.
- ComputeColumn(Ptr, Size);
+ ComputePosition(Ptr, Size);
// Write the data to the underlying stream (which is unbuffered, so
// the data will be immediately written out).
diff --git a/contrib/llvm/lib/Support/GraphWriter.cpp b/contrib/llvm/lib/Support/GraphWriter.cpp
index bff182f..85be415 100644
--- a/contrib/llvm/lib/Support/GraphWriter.cpp
+++ b/contrib/llvm/lib/Support/GraphWriter.cpp
@@ -14,6 +14,7 @@
#include "llvm/Support/GraphWriter.h"
#include "llvm/Config/config.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
using namespace llvm;
@@ -64,31 +65,46 @@ StringRef llvm::DOT::getColorString(unsigned ColorNumber) {
return Colors[ColorNumber % NumColors];
}
+std::string llvm::createGraphFilename(const Twine &Name, int &FD) {
+ FD = -1;
+ SmallString<128> Filename;
+ error_code EC = sys::fs::createTemporaryFile(Name, "dot", FD, Filename);
+ if (EC) {
+ errs() << "Error: " << EC.message() << "\n";
+ return "";
+ }
+
+ errs() << "Writing '" << Filename << "'... ";
+ return Filename.str();
+}
+
// Execute the graph viewer. Return true if successful.
static bool LLVM_ATTRIBUTE_UNUSED
-ExecGraphViewer(const sys::Path &ExecPath, std::vector<const char*> &args,
- const sys::Path &Filename, bool wait, std::string &ErrMsg) {
+ExecGraphViewer(StringRef ExecPath, std::vector<const char*> &args,
+ StringRef Filename, bool wait, std::string &ErrMsg) {
if (wait) {
- if (sys::Program::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) {
+ if (sys::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) {
errs() << "Error: " << ErrMsg << "\n";
return false;
}
- Filename.eraseFromDisk();
+ bool Existed;
+ sys::fs::remove(Filename, Existed);
errs() << " done. \n";
}
else {
- sys::Program::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg);
+ sys::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg);
errs() << "Remember to erase graph file: " << Filename.str() << "\n";
}
return true;
}
-void llvm::DisplayGraph(const sys::Path &Filename, bool wait,
+void llvm::DisplayGraph(StringRef FilenameRef, bool wait,
GraphProgram::Name program) {
+ std::string Filename = FilenameRef;
wait &= !ViewBackground;
std::string ErrMsg;
#if HAVE_GRAPHVIZ
- sys::Path Graphviz(LLVM_PATH_GRAPHVIZ);
+ std::string Graphviz(LLVM_PATH_GRAPHVIZ);
std::vector<const char*> args;
args.push_back(Graphviz.c_str());
@@ -99,9 +115,9 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait,
if (!ExecGraphViewer(Graphviz, args, Filename, wait, ErrMsg))
return;
-#elif HAVE_XDOT_PY
+#elif HAVE_XDOT
std::vector<const char*> args;
- args.push_back(LLVM_PATH_XDOT_PY);
+ args.push_back(LLVM_PATH_XDOT);
args.push_back(Filename.c_str());
switch (program) {
@@ -115,53 +131,51 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait,
args.push_back(0);
errs() << "Running 'xdot.py' program... ";
- if (!ExecGraphViewer(sys::Path(LLVM_PATH_XDOT_PY), args, Filename, wait, ErrMsg))
+ if (!ExecGraphViewer(LLVM_PATH_XDOT, args, Filename, wait, ErrMsg))
return;
#elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \
HAVE_TWOPI || HAVE_CIRCO))
- sys::Path PSFilename = Filename;
- PSFilename.appendSuffix("ps");
-
- sys::Path prog;
+ std::string PSFilename = Filename + ".ps";
+ std::string prog;
// Set default grapher
#if HAVE_CIRCO
- prog = sys::Path(LLVM_PATH_CIRCO);
+ prog = LLVM_PATH_CIRCO;
#endif
#if HAVE_TWOPI
- prog = sys::Path(LLVM_PATH_TWOPI);
+ prog = LLVM_PATH_TWOPI;
#endif
#if HAVE_NEATO
- prog = sys::Path(LLVM_PATH_NEATO);
+ prog = LLVM_PATH_NEATO;
#endif
#if HAVE_FDP
- prog = sys::Path(LLVM_PATH_FDP);
+ prog = LLVM_PATH_FDP;
#endif
#if HAVE_DOT
- prog = sys::Path(LLVM_PATH_DOT);
+ prog = LLVM_PATH_DOT;
#endif
// Find which program the user wants
#if HAVE_DOT
if (program == GraphProgram::DOT)
- prog = sys::Path(LLVM_PATH_DOT);
+ prog = LLVM_PATH_DOT;
#endif
#if (HAVE_FDP)
if (program == GraphProgram::FDP)
- prog = sys::Path(LLVM_PATH_FDP);
+ prog = LLVM_PATH_FDP;
#endif
#if (HAVE_NEATO)
if (program == GraphProgram::NEATO)
- prog = sys::Path(LLVM_PATH_NEATO);
+ prog = LLVM_PATH_NEATO;
#endif
#if (HAVE_TWOPI)
if (program == GraphProgram::TWOPI)
- prog = sys::Path(LLVM_PATH_TWOPI);
+ prog = LLVM_PATH_TWOPI;
#endif
#if (HAVE_CIRCO)
if (program == GraphProgram::CIRCO)
- prog = sys::Path(LLVM_PATH_CIRCO);
+ prog = LLVM_PATH_CIRCO;
#endif
std::vector<const char*> args;
@@ -174,12 +188,12 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait,
args.push_back(PSFilename.c_str());
args.push_back(0);
- errs() << "Running '" << prog.str() << "' program... ";
+ errs() << "Running '" << prog << "' program... ";
if (!ExecGraphViewer(prog, args, Filename, wait, ErrMsg))
return;
- sys::Path gv(LLVM_PATH_GV);
+ std::string gv(LLVM_PATH_GV);
args.clear();
args.push_back(gv.c_str());
args.push_back(PSFilename.c_str());
@@ -191,7 +205,7 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait,
return;
#elif HAVE_DOTTY
- sys::Path dotty(LLVM_PATH_DOTTY);
+ std::string dotty(LLVM_PATH_DOTTY);
std::vector<const char*> args;
args.push_back(dotty.c_str());
@@ -205,5 +219,8 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait,
errs() << "Running 'dotty' program... ";
if (!ExecGraphViewer(dotty, args, Filename, wait, ErrMsg))
return;
+#else
+ (void)Filename;
+ (void)ErrMsg;
#endif
}
diff --git a/contrib/llvm/lib/Support/Host.cpp b/contrib/llvm/lib/Support/Host.cpp
index a7c7a95..6e9a5c9 100644
--- a/contrib/llvm/lib/Support/Host.cpp
+++ b/contrib/llvm/lib/Support/Host.cpp
@@ -52,8 +52,54 @@ using namespace llvm;
/// GetX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in the
/// specified arguments. If we can't run cpuid on the host, return true.
-static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX,
- unsigned *rEBX, unsigned *rECX, unsigned *rEDX) {
+static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
+ unsigned *rECX, unsigned *rEDX) {
+#if defined(__GNUC__) || defined(__clang__)
+ #if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64)
+ // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually.
+ asm ("movq\t%%rbx, %%rsi\n\t"
+ "cpuid\n\t"
+ "xchgq\t%%rbx, %%rsi\n\t"
+ : "=a" (*rEAX),
+ "=S" (*rEBX),
+ "=c" (*rECX),
+ "=d" (*rEDX)
+ : "a" (value));
+ return false;
+ #elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)
+ asm ("movl\t%%ebx, %%esi\n\t"
+ "cpuid\n\t"
+ "xchgl\t%%ebx, %%esi\n\t"
+ : "=a" (*rEAX),
+ "=S" (*rEBX),
+ "=c" (*rECX),
+ "=d" (*rEDX)
+ : "a" (value));
+ return false;
+// pedantic #else returns to appease -Wunreachable-code (so we don't generate
+// postprocessed code that looks like "return true; return false;")
+ #else
+ return true;
+ #endif
+#elif defined(_MSC_VER)
+ // The MSVC intrinsic is portable across x86 and x64.
+ int registers[4];
+ __cpuid(registers, value);
+ *rEAX = registers[0];
+ *rEBX = registers[1];
+ *rECX = registers[2];
+ *rEDX = registers[3];
+ return false;
+#else
+ return true;
+#endif
+}
+
+/// GetX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return the
+/// 4 values in the specified arguments. If we can't run cpuid on the host,
+/// return true.
+bool GetX86CpuIDAndInfoEx(unsigned value, unsigned subleaf, unsigned *rEAX,
+ unsigned *rEBX, unsigned *rECX, unsigned *rEDX) {
#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64)
#if defined(__GNUC__)
// gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually.
@@ -64,16 +110,22 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX,
"=S" (*rEBX),
"=c" (*rECX),
"=d" (*rEDX)
- : "a" (value));
+ : "a" (value),
+ "c" (subleaf));
return false;
#elif defined(_MSC_VER)
- int registers[4];
- __cpuid(registers, value);
- *rEAX = registers[0];
- *rEBX = registers[1];
- *rECX = registers[2];
- *rEDX = registers[3];
- return false;
+ // __cpuidex was added in MSVC++ 9.0 SP1
+ #if (_MSC_VER > 1500) || (_MSC_VER == 1500 && _MSC_FULL_VER >= 150030729)
+ int registers[4];
+ __cpuidex(registers, value, subleaf);
+ *rEAX = registers[0];
+ *rEBX = registers[1];
+ *rECX = registers[2];
+ *rEDX = registers[3];
+ return false;
+ #else
+ return true;
+ #endif
#else
return true;
#endif
@@ -86,11 +138,13 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX,
"=S" (*rEBX),
"=c" (*rECX),
"=d" (*rEDX)
- : "a" (value));
+ : "a" (value),
+ "c" (subleaf));
return false;
#elif defined(_MSC_VER)
__asm {
mov eax,value
+ mov ecx,subleaf
cpuid
mov esi,rEAX
mov dword ptr [esi],eax
@@ -102,8 +156,6 @@ static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX,
mov dword ptr [esi],edx
}
return false;
-// pedantic #else returns to appease -Wunreachable-code (so we don't generate
-// postprocessed code that looks like "return true; return false;")
#else
return true;
#endif
@@ -148,21 +200,27 @@ std::string sys::getHostCPUName() {
unsigned Model = 0;
DetectX86FamilyModel(EAX, Family, Model);
+ union {
+ unsigned u[3];
+ char c[12];
+ } text;
+
+ GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1);
+
+ unsigned MaxLeaf = EAX;
bool HasSSE3 = (ECX & 0x1);
+ bool HasSSE41 = (ECX & 0x80000);
// If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV
// indicates that the AVX registers will be saved and restored on context
// switch, then we have full AVX support.
const unsigned AVXBits = (1 << 27) | (1 << 28);
bool HasAVX = ((ECX & AVXBits) == AVXBits) && OSHasAVXSupport();
+ bool HasAVX2 = HasAVX && MaxLeaf >= 0x7 &&
+ !GetX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX) &&
+ (EBX & 0x20);
GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
bool Em64T = (EDX >> 29) & 0x1;
- union {
- unsigned u[3];
- char c[12];
- } text;
-
- GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1);
if (memcmp(text.c, "GenuineIntel", 12) == 0) {
switch (Family) {
case 3:
@@ -244,7 +302,8 @@ std::string sys::getHostCPUName() {
// 17h. All processors are manufactured using the 45 nm process.
//
// 45nm: Penryn , Wolfdale, Yorkfield (XE)
- return "penryn";
+ // Not all Penryn processors support SSE 4.1 (such as the Pentium brand)
+ return HasSSE41 ? "penryn" : "core2";
case 26: // Intel Core i7 processor and Intel Xeon processor. All
// processors are manufactured using the 45 nm process.
@@ -269,10 +328,20 @@ std::string sys::getHostCPUName() {
// Ivy Bridge:
case 58:
+ case 62: // Ivy Bridge EP
// Not all Ivy Bridge processors support AVX (such as the Pentium
// versions instead of the i7 versions).
return HasAVX ? "core-avx-i" : "corei7";
+ // Haswell:
+ case 60:
+ case 63:
+ case 69:
+ case 70:
+ // Not all Haswell processors support AVX too (such as the Pentium
+ // versions instead of the i7 versions).
+ return HasAVX2 ? "core-avx2" : "corei7";
+
case 28: // Most 45 nm Intel Atom processors
case 38: // 45 nm Atom Lincroft
case 39: // 32 nm Atom Medfield
@@ -280,6 +349,12 @@ std::string sys::getHostCPUName() {
case 54: // 32 nm Atom Midview
return "atom";
+ // Atom Silvermont codes from the Intel software optimization guide.
+ case 55:
+ case 74:
+ case 77:
+ return "slm";
+
default: return (Em64T) ? "x86-64" : "i686";
}
case 15: {
@@ -357,9 +432,11 @@ std::string sys::getHostCPUName() {
case 21:
if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback.
return "btver1";
- if (Model > 15 && Model <= 31)
- return "bdver2";
- return "bdver1";
+ if (Model >= 0x30)
+ return "bdver3"; // 30h-3Fh: Steamroller
+ if (Model >= 0x10)
+ return "bdver2"; // 10h-1Fh: Piledriver
+ return "bdver1"; // 00h-0Fh: Bulldozer
case 22:
if (!HasAVX) // If the OS doesn't support AVX provide a sane fallback.
return "btver1";
@@ -544,6 +621,48 @@ std::string sys::getHostCPUName() {
return "generic";
}
+#elif defined(__linux__) && defined(__s390x__)
+std::string sys::getHostCPUName() {
+ // STIDP is a privileged operation, so use /proc/cpuinfo instead.
+ // Note: We cannot mmap /proc/cpuinfo here and then process the resulting
+ // memory buffer because the 'file' has 0 size (it can be read from only
+ // as a stream).
+
+ std::string Err;
+ DataStreamer *DS = getDataFileStreamer("/proc/cpuinfo", &Err);
+ if (!DS) {
+ DEBUG(dbgs() << "Unable to open /proc/cpuinfo: " << Err << "\n");
+ return "generic";
+ }
+
+ // The "processor 0:" line comes after a fair amount of other information,
+ // including a cache breakdown, but this should be plenty.
+ char buffer[2048];
+ size_t CPUInfoSize = DS->GetBytes((unsigned char*) buffer, sizeof(buffer));
+ delete DS;
+
+ StringRef Str(buffer, CPUInfoSize);
+ SmallVector<StringRef, 32> Lines;
+ Str.split(Lines, "\n");
+ for (unsigned I = 0, E = Lines.size(); I != E; ++I) {
+ if (Lines[I].startswith("processor ")) {
+ size_t Pos = Lines[I].find("machine = ");
+ if (Pos != StringRef::npos) {
+ Pos += sizeof("machine = ") - 1;
+ unsigned int Id;
+ if (!Lines[I].drop_front(Pos).getAsInteger(10, Id)) {
+ if (Id >= 2827)
+ return "zEC12";
+ if (Id >= 2817)
+ return "z196";
+ }
+ }
+ break;
+ }
+ }
+
+ return "generic";
+}
#else
std::string sys::getHostCPUName() {
return "generic";
@@ -570,41 +689,31 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
SmallVector<StringRef, 32> Lines;
Str.split(Lines, "\n");
- // Look for the CPU implementer line.
- StringRef Implementer;
- for (unsigned I = 0, E = Lines.size(); I != E; ++I)
- if (Lines[I].startswith("CPU implementer"))
- Implementer = Lines[I].substr(15).ltrim("\t :");
-
- if (Implementer == "0x41") { // ARM Ltd.
- SmallVector<StringRef, 32> CPUFeatures;
+ SmallVector<StringRef, 32> CPUFeatures;
- // Look for the CPU features.
- for (unsigned I = 0, E = Lines.size(); I != E; ++I)
- if (Lines[I].startswith("Features")) {
- Lines[I].split(CPUFeatures, " ");
- break;
- }
-
- for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) {
- StringRef LLVMFeatureStr = StringSwitch<StringRef>(CPUFeatures[I])
- .Case("half", "fp16")
- .Case("neon", "neon")
- .Case("vfpv3", "vfp3")
- .Case("vfpv3d16", "d16")
- .Case("vfpv4", "vfp4")
- .Case("idiva", "hwdiv-arm")
- .Case("idivt", "hwdiv")
- .Default("");
-
- if (LLVMFeatureStr != "")
- Features.GetOrCreateValue(LLVMFeatureStr).setValue(true);
+ // Look for the CPU features.
+ for (unsigned I = 0, E = Lines.size(); I != E; ++I)
+ if (Lines[I].startswith("Features")) {
+ Lines[I].split(CPUFeatures, " ");
+ break;
}
- return true;
+ for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) {
+ StringRef LLVMFeatureStr = StringSwitch<StringRef>(CPUFeatures[I])
+ .Case("half", "fp16")
+ .Case("neon", "neon")
+ .Case("vfpv3", "vfp3")
+ .Case("vfpv3d16", "d16")
+ .Case("vfpv4", "vfp4")
+ .Case("idiva", "hwdiv-arm")
+ .Case("idivt", "hwdiv")
+ .Default("");
+
+ if (LLVMFeatureStr != "")
+ Features.GetOrCreateValue(LLVMFeatureStr).setValue(true);
}
- return false;
+ return true;
}
#else
bool sys::getHostCPUFeatures(StringMap<bool> &Features){
@@ -613,7 +722,7 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features){
#endif
std::string sys::getProcessTriple() {
- Triple PT(LLVM_HOST_TRIPLE);
+ Triple PT(Triple::normalize(LLVM_HOST_TRIPLE));
if (sizeof(void *) == 8 && PT.isArch32Bit())
PT = PT.get64BitArchVariant();
diff --git a/contrib/llvm/lib/Support/Locale.cpp b/contrib/llvm/lib/Support/Locale.cpp
index 17b9b6c..35ddf7f 100644
--- a/contrib/llvm/lib/Support/Locale.cpp
+++ b/contrib/llvm/lib/Support/Locale.cpp
@@ -1,10 +1,31 @@
#include "llvm/Support/Locale.h"
-#include "llvm/Config/config.h"
+#include "llvm/Support/Unicode.h"
-#ifdef __APPLE__
-#include "LocaleXlocale.inc"
-#elif LLVM_ON_WIN32
-#include "LocaleWindows.inc"
+namespace llvm {
+namespace sys {
+namespace locale {
+
+int columnWidth(StringRef Text) {
+#if LLVM_ON_WIN32
+ return Text.size();
#else
-#include "LocaleGeneric.inc"
+ return llvm::sys::unicode::columnWidthUTF8(Text);
#endif
+}
+
+bool isPrint(int UCS) {
+#if LLVM_ON_WIN32
+ // Restrict characters that we'll try to print to the the lower part of ASCII
+ // except for the control characters (0x20 - 0x7E). In general one can not
+ // reliably output code points U+0080 and higher using narrow character C/C++
+ // output functions in Windows, because the meaning of the upper 128 codes is
+ // determined by the active code page in the console.
+ return ' ' <= UCS && UCS <= '~';
+#else
+ return llvm::sys::unicode::isPrintable(UCS);
+#endif
+}
+
+} // namespace locale
+} // namespace sys
+} // namespace llvm
diff --git a/contrib/llvm/lib/Support/LocaleGeneric.inc b/contrib/llvm/lib/Support/LocaleGeneric.inc
deleted file mode 100644
index 278deee..0000000
--- a/contrib/llvm/lib/Support/LocaleGeneric.inc
+++ /dev/null
@@ -1,17 +0,0 @@
-#include <cwctype>
-
-namespace llvm {
-namespace sys {
-namespace locale {
-
-int columnWidth(StringRef s) {
- return s.size();
-}
-
-bool isPrint(int c) {
- return iswprint(c);
-}
-
-}
-}
-}
diff --git a/contrib/llvm/lib/Support/LocaleWindows.inc b/contrib/llvm/lib/Support/LocaleWindows.inc
deleted file mode 100644
index 28e429c..0000000
--- a/contrib/llvm/lib/Support/LocaleWindows.inc
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace llvm {
-namespace sys {
-namespace locale {
-
-int columnWidth(StringRef s) {
- return s.size();
-}
-
-bool isPrint(int c) {
- return ' ' <= c && c <= '~';
-}
-
-}
-}
-}
diff --git a/contrib/llvm/lib/Support/LocaleXlocale.inc b/contrib/llvm/lib/Support/LocaleXlocale.inc
deleted file mode 100644
index 389fe3d..0000000
--- a/contrib/llvm/lib/Support/LocaleXlocale.inc
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/ManagedStatic.h"
-#include <cassert>
-#include <xlocale.h>
-
-
-namespace {
- struct locale_holder {
- locale_holder()
- : l(newlocale(LC_CTYPE_MASK,"en_US.UTF-8",LC_GLOBAL_LOCALE))
- {
- assert(NULL!=l);
- }
- ~locale_holder() {
- freelocale(l);
- }
-
- int mbswidth(llvm::SmallString<16> s) const {
- // this implementation assumes no '\0' in s
- assert(s.size()==strlen(s.c_str()));
-
- size_t size = mbstowcs_l(NULL,s.c_str(),0,l);
- assert(size!=(size_t)-1);
- if (size==0)
- return 0;
- llvm::SmallVector<wchar_t,200> ws(size);
- size = mbstowcs_l(&ws[0],s.c_str(),ws.size(),l);
- assert(ws.size()==size);
- return wcswidth_l(&ws[0],ws.size(),l);
- }
-
- int isprint(int c) const {
- return iswprint_l(c,l);
- }
-
- private:
-
- locale_t l;
- };
-
- llvm::ManagedStatic<locale_holder> l;
-}
-
-namespace llvm {
-namespace sys {
-namespace locale {
-
-int columnWidth(StringRef s) {
- int width = l->mbswidth(s);
- assert(width>=0);
- return width;
-}
-
-bool isPrint(int c) {
- return l->isprint(c);
-}
-
-}
-}
-}
diff --git a/contrib/llvm/lib/Support/LockFileManager.cpp b/contrib/llvm/lib/Support/LockFileManager.cpp
index 2917e27..eeec274 100644
--- a/contrib/llvm/lib/Support/LockFileManager.cpp
+++ b/contrib/llvm/lib/Support/LockFileManager.cpp
@@ -7,9 +7,11 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/LockFileManager.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-#include <fstream>
#include <sys/stat.h>
#include <sys/types.h>
#if LLVM_ON_WIN32
@@ -35,16 +37,20 @@ LockFileManager::readLockFile(StringRef LockFileName) {
// Read the owning host and PID out of the lock file. If it appears that the
// owning process is dead, the lock file is invalid.
- int PID = 0;
- std::string Hostname;
- std::ifstream Input(LockFileName.str().c_str());
- if (Input >> Hostname >> PID && PID > 0 &&
- processStillExecuting(Hostname, PID))
- return std::make_pair(Hostname, PID);
+ OwningPtr<MemoryBuffer> MB;
+ if (MemoryBuffer::getFile(LockFileName, MB))
+ return None;
+
+ StringRef Hostname;
+ StringRef PIDStr;
+ tie(Hostname, PIDStr) = getToken(MB->getBuffer(), " ");
+ PIDStr = PIDStr.substr(PIDStr.find_first_not_of(" "));
+ int PID;
+ if (!PIDStr.getAsInteger(10, PID))
+ return std::make_pair(std::string(Hostname), PID);
// Delete the lock file. It's invalid anyway.
- bool Existed;
- sys::fs::remove(LockFileName, Existed);
+ sys::fs::remove(LockFileName);
return None;
}
@@ -78,10 +84,9 @@ LockFileManager::LockFileManager(StringRef FileName)
UniqueLockFileName += "-%%%%%%%%";
int UniqueLockFileID;
if (error_code EC
- = sys::fs::unique_file(UniqueLockFileName.str(),
- UniqueLockFileID,
- UniqueLockFileName,
- /*makeAbsolute=*/false)) {
+ = sys::fs::createUniqueFile(UniqueLockFileName.str(),
+ UniqueLockFileID,
+ UniqueLockFileName)) {
Error = EC;
return;
}
diff --git a/contrib/llvm/lib/Support/MD5.cpp b/contrib/llvm/lib/Support/MD5.cpp
new file mode 100644
index 0000000..514466c
--- /dev/null
+++ b/contrib/llvm/lib/Support/MD5.cpp
@@ -0,0 +1,286 @@
+/*
+ * This code is derived from (original license follows):
+ *
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's. No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible. Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstring>
+
+// The basic MD5 functions.
+
+// F and G are optimized compared to their RFC 1321 definitions for
+// architectures that lack an AND-NOT instruction, just like in Colin Plumb's
+// implementation.
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+// The MD5 transformation for all four rounds.
+#define STEP(f, a, b, c, d, x, t, s) \
+ (a) += f((b), (c), (d)) + (x) + (t); \
+ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+ (a) += (b);
+
+// SET reads 4 input bytes in little-endian byte order and stores them
+// in a properly aligned word in host byte order.
+#define SET(n) \
+ (block[(n)] = \
+ (MD5_u32plus) ptr[(n) * 4] | ((MD5_u32plus) ptr[(n) * 4 + 1] << 8) | \
+ ((MD5_u32plus) ptr[(n) * 4 + 2] << 16) | \
+ ((MD5_u32plus) ptr[(n) * 4 + 3] << 24))
+#define GET(n) (block[(n)])
+
+namespace llvm {
+
+/// \brief This processes one or more 64-byte data blocks, but does NOT update
+///the bit counters. There are no alignment requirements.
+const uint8_t *MD5::body(ArrayRef<uint8_t> Data) {
+ const uint8_t *ptr;
+ MD5_u32plus a, b, c, d;
+ MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+ unsigned long Size = Data.size();
+
+ ptr = Data.data();
+
+ a = this->a;
+ b = this->b;
+ c = this->c;
+ d = this->d;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+
+ // Round 1
+ STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+ STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+ STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+ STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+ STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+ STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+ STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+ STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+ STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+ STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+ STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+ STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+ STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+ STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+ STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+ STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+ // Round 2
+ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+ STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+ STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+ STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+ STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+ STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+ STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+ STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+ STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+ STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+ STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+ STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+ STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+ STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+ STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+ STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+ // Round 3
+ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+ STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
+ STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+ STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
+ STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+ STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+ STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+ STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
+ STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+ STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
+ STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+ STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
+ STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+ STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
+ STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+ STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+ // Round 4
+ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+ STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+ STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+ STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+ STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+ STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+ STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+ STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+ STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+ STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+ STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+ STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+ STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+ STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+ STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+ STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+
+ ptr += 64;
+ } while (Size -= 64);
+
+ this->a = a;
+ this->b = b;
+ this->c = c;
+ this->d = d;
+
+ return ptr;
+}
+
+MD5::MD5()
+ : a(0x67452301), b(0xefcdab89), c(0x98badcfe), d(0x10325476), hi(0), lo(0) {
+}
+
+/// Incrementally add the bytes in \p Data to the hash.
+void MD5::update(ArrayRef<uint8_t> Data) {
+ MD5_u32plus saved_lo;
+ unsigned long used, free;
+ const uint8_t *Ptr = Data.data();
+ unsigned long Size = Data.size();
+
+ saved_lo = lo;
+ if ((lo = (saved_lo + Size) & 0x1fffffff) < saved_lo)
+ hi++;
+ hi += Size >> 29;
+
+ used = saved_lo & 0x3f;
+
+ if (used) {
+ free = 64 - used;
+
+ if (Size < free) {
+ memcpy(&buffer[used], Ptr, Size);
+ return;
+ }
+
+ memcpy(&buffer[used], Ptr, free);
+ Ptr = Ptr + free;
+ Size -= free;
+ body(ArrayRef<uint8_t>(buffer, 64));
+ }
+
+ if (Size >= 64) {
+ Ptr = body(ArrayRef<uint8_t>(Ptr, Size & ~(unsigned long) 0x3f));
+ Size &= 0x3f;
+ }
+
+ memcpy(buffer, Ptr, Size);
+}
+
+/// Add the bytes in the StringRef \p Str to the hash.
+// Note that this isn't a string and so this won't include any trailing NULL
+// bytes.
+void MD5::update(StringRef Str) {
+ ArrayRef<uint8_t> SVal((const uint8_t *)Str.data(), Str.size());
+ update(SVal);
+}
+
+/// \brief Finish the hash and place the resulting hash into \p result.
+/// \param result is assumed to be a minimum of 16-bytes in size.
+void MD5::final(MD5Result &result) {
+ unsigned long used, free;
+
+ used = lo & 0x3f;
+
+ buffer[used++] = 0x80;
+
+ free = 64 - used;
+
+ if (free < 8) {
+ memset(&buffer[used], 0, free);
+ body(ArrayRef<uint8_t>(buffer, 64));
+ used = 0;
+ free = 64;
+ }
+
+ memset(&buffer[used], 0, free - 8);
+
+ lo <<= 3;
+ buffer[56] = lo;
+ buffer[57] = lo >> 8;
+ buffer[58] = lo >> 16;
+ buffer[59] = lo >> 24;
+ buffer[60] = hi;
+ buffer[61] = hi >> 8;
+ buffer[62] = hi >> 16;
+ buffer[63] = hi >> 24;
+
+ body(ArrayRef<uint8_t>(buffer, 64));
+
+ result[0] = a;
+ result[1] = a >> 8;
+ result[2] = a >> 16;
+ result[3] = a >> 24;
+ result[4] = b;
+ result[5] = b >> 8;
+ result[6] = b >> 16;
+ result[7] = b >> 24;
+ result[8] = c;
+ result[9] = c >> 8;
+ result[10] = c >> 16;
+ result[11] = c >> 24;
+ result[12] = d;
+ result[13] = d >> 8;
+ result[14] = d >> 16;
+ result[15] = d >> 24;
+}
+
+void MD5::stringifyResult(MD5Result &result, SmallString<32> &Str) {
+ raw_svector_ostream Res(Str);
+ for (int i = 0; i < 16; ++i)
+ Res << format("%.2x", result[i]);
+}
+
+}
diff --git a/contrib/llvm/lib/Support/MemoryBuffer.cpp b/contrib/llvm/lib/Support/MemoryBuffer.cpp
index 7c5ab96..dcd5529 100644
--- a/contrib/llvm/lib/Support/MemoryBuffer.cpp
+++ b/contrib/llvm/lib/Support/MemoryBuffer.cpp
@@ -33,8 +33,7 @@
#include <unistd.h>
#else
#include <io.h>
-// Simplistic definitinos of these macros to allow files to be read with
-// MapInFilePages.
+// Simplistic definitinos of these macros for use in getOpenFile.
#ifndef S_ISREG
#define S_ISREG(x) (1)
#endif
@@ -42,7 +41,6 @@
#define S_ISBLK(x) (0)
#endif
#endif
-#include <fcntl.h>
using namespace llvm;
//===----------------------------------------------------------------------===//
@@ -174,20 +172,12 @@ error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename,
return getFile(Filename, result, FileSize);
}
-error_code MemoryBuffer::getFileOrSTDIN(const char *Filename,
- OwningPtr<MemoryBuffer> &result,
- int64_t FileSize) {
- if (strcmp(Filename, "-") == 0)
- return getSTDIN(result);
- return getFile(Filename, result, FileSize);
-}
-
//===----------------------------------------------------------------------===//
// MemoryBuffer::getFile implementation.
//===----------------------------------------------------------------------===//
namespace {
-/// \brief Memorry maps a file descriptor using sys::fs::mapped_file_region.
+/// \brief Memory maps a file descriptor using sys::fs::mapped_file_region.
///
/// This handles converting the offset into a legal offset on the platform.
class MemoryBufferMMapFile : public MemoryBuffer {
@@ -227,7 +217,7 @@ public:
};
}
-static error_code getMemoryBufferForStream(int FD,
+static error_code getMemoryBufferForStream(int FD,
StringRef BufferName,
OwningPtr<MemoryBuffer> &result) {
const ssize_t ChunkSize = 4096*4;
@@ -248,41 +238,36 @@ static error_code getMemoryBufferForStream(int FD,
return error_code::success();
}
-error_code MemoryBuffer::getFile(StringRef Filename,
+static error_code getFileAux(const char *Filename,
+ OwningPtr<MemoryBuffer> &result, int64_t FileSize,
+ bool RequiresNullTerminator);
+
+error_code MemoryBuffer::getFile(Twine Filename,
OwningPtr<MemoryBuffer> &result,
int64_t FileSize,
bool RequiresNullTerminator) {
// Ensure the path is null terminated.
- SmallString<256> PathBuf(Filename.begin(), Filename.end());
- return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize,
- RequiresNullTerminator);
+ SmallString<256> PathBuf;
+ StringRef NullTerminatedName = Filename.toNullTerminatedStringRef(PathBuf);
+ return getFileAux(NullTerminatedName.data(), result, FileSize,
+ RequiresNullTerminator);
}
-error_code MemoryBuffer::getFile(const char *Filename,
- OwningPtr<MemoryBuffer> &result,
- int64_t FileSize,
- bool RequiresNullTerminator) {
- // FIXME: Review if this check is unnecessary on windows as well.
-#ifdef LLVM_ON_WIN32
- // First check that the "file" is not a directory
- bool is_dir = false;
- error_code err = sys::fs::is_directory(Filename, is_dir);
- if (err)
- return err;
- if (is_dir)
- return make_error_code(errc::is_a_directory);
-#endif
-
- int OpenFlags = O_RDONLY;
-#ifdef O_BINARY
- OpenFlags |= O_BINARY; // Open input file in binary mode on win32.
-#endif
- int FD = ::open(Filename, OpenFlags);
- if (FD == -1)
- return error_code(errno, posix_category());
-
- error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize,
- 0, RequiresNullTerminator);
+static error_code getOpenFileImpl(int FD, const char *Filename,
+ OwningPtr<MemoryBuffer> &Result,
+ uint64_t FileSize, uint64_t MapSize,
+ int64_t Offset, bool RequiresNullTerminator);
+
+static error_code getFileAux(const char *Filename,
+ OwningPtr<MemoryBuffer> &result, int64_t FileSize,
+ bool RequiresNullTerminator) {
+ int FD;
+ error_code EC = sys::fs::openFileForRead(Filename, FD);
+ if (EC)
+ return EC;
+
+ error_code ret = getOpenFileImpl(FD, Filename, result, FileSize, FileSize, 0,
+ RequiresNullTerminator);
close(FD);
return ret;
}
@@ -295,7 +280,7 @@ static bool shouldUseMmap(int FD,
int PageSize) {
// We don't use mmap for small files because this can severely fragment our
// address space.
- if (MapSize < 4096*4)
+ if (MapSize < 4 * 4096 || MapSize < (unsigned)PageSize)
return false;
if (!RequiresNullTerminator)
@@ -307,12 +292,11 @@ static bool shouldUseMmap(int FD,
// FIXME: this chunk of code is duplicated, but it avoids a fstat when
// RequiresNullTerminator = false and MapSize != -1.
if (FileSize == size_t(-1)) {
- struct stat FileInfo;
- // TODO: This should use fstat64 when available.
- if (fstat(FD, &FileInfo) == -1) {
- return error_code(errno, posix_category());
- }
- FileSize = FileInfo.st_size;
+ sys::fs::file_status Status;
+ error_code EC = sys::fs::status(FD, Status);
+ if (EC)
+ return EC;
+ FileSize = Status.getSize();
}
// If we need a null terminator and the end of the map is inside the file,
@@ -322,6 +306,15 @@ static bool shouldUseMmap(int FD,
if (End != FileSize)
return false;
+#if defined(_WIN32) || defined(__CYGWIN__)
+ // Don't peek the next page if file is multiple of *physical* pagesize(4k)
+ // but is not multiple of AllocationGranularity(64k),
+ // when a null terminator is required.
+ // FIXME: It's not good to hardcode 4096 here. dwPageSize shows 4096.
+ if ((FileSize & (4096 - 1)) == 0)
+ return false;
+#endif
+
// Don't try to map files that are exactly a multiple of the system page size
// if we need a null terminator.
if ((FileSize & (PageSize -1)) == 0)
@@ -330,11 +323,10 @@ static bool shouldUseMmap(int FD,
return true;
}
-error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
- OwningPtr<MemoryBuffer> &result,
- uint64_t FileSize, uint64_t MapSize,
- int64_t Offset,
- bool RequiresNullTerminator) {
+static error_code getOpenFileImpl(int FD, const char *Filename,
+ OwningPtr<MemoryBuffer> &result,
+ uint64_t FileSize, uint64_t MapSize,
+ int64_t Offset, bool RequiresNullTerminator) {
static int PageSize = sys::process::get_self()->page_size();
// Default is to map the full file.
@@ -342,20 +334,20 @@ error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
// If we don't know the file size, use fstat to find out. fstat on an open
// file descriptor is cheaper than stat on a random path.
if (FileSize == uint64_t(-1)) {
- struct stat FileInfo;
- // TODO: This should use fstat64 when available.
- if (fstat(FD, &FileInfo) == -1) {
- return error_code(errno, posix_category());
- }
+ sys::fs::file_status Status;
+ error_code EC = sys::fs::status(FD, Status);
+ if (EC)
+ return EC;
// If this not a file or a block device (e.g. it's a named pipe
// or character device), we can't trust the size. Create the memory
// buffer by copying off the stream.
- if (!S_ISREG(FileInfo.st_mode) && !S_ISBLK(FileInfo.st_mode)) {
+ sys::fs::file_type Type = Status.type();
+ if (Type != sys::fs::file_type::regular_file &&
+ Type != sys::fs::file_type::block_file)
return getMemoryBufferForStream(FD, Filename, result);
- }
- FileSize = FileInfo.st_size;
+ FileSize = Status.getSize();
}
MapSize = FileSize;
}
@@ -411,6 +403,20 @@ error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
return error_code::success();
}
+error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
+ OwningPtr<MemoryBuffer> &Result,
+ uint64_t FileSize,
+ bool RequiresNullTerminator) {
+ return getOpenFileImpl(FD, Filename, Result, FileSize, FileSize, 0,
+ RequiresNullTerminator);
+}
+
+error_code MemoryBuffer::getOpenFileSlice(int FD, const char *Filename,
+ OwningPtr<MemoryBuffer> &Result,
+ uint64_t MapSize, int64_t Offset) {
+ return getOpenFileImpl(FD, Filename, Result, -1, MapSize, Offset, false);
+}
+
//===----------------------------------------------------------------------===//
// MemoryBuffer::getSTDIN implementation.
//===----------------------------------------------------------------------===//
@@ -420,7 +426,7 @@ error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) {
//
// FIXME: That isn't necessarily true, we should try to mmap stdin and
// fallback if it fails.
- sys::Program::ChangeStdinToBinary();
+ sys::ChangeStdinToBinary();
return getMemoryBufferForStream(0, "<stdin>", result);
}
diff --git a/contrib/llvm/lib/Support/MemoryObject.cpp b/contrib/llvm/lib/Support/MemoryObject.cpp
index b20ab89..02b5b50 100644
--- a/contrib/llvm/lib/Support/MemoryObject.cpp
+++ b/contrib/llvm/lib/Support/MemoryObject.cpp
@@ -15,8 +15,7 @@ MemoryObject::~MemoryObject() {
int MemoryObject::readBytes(uint64_t address,
uint64_t size,
- uint8_t* buf,
- uint64_t* copied) const {
+ uint8_t* buf) const {
uint64_t current = address;
uint64_t limit = getBase() + getExtent();
@@ -30,8 +29,5 @@ int MemoryObject::readBytes(uint64_t address,
current++;
}
- if (copied)
- *copied = current - address;
-
return 0;
}
diff --git a/contrib/llvm/lib/Support/Path.cpp b/contrib/llvm/lib/Support/Path.cpp
index d070375..c869b30 100644
--- a/contrib/llvm/lib/Support/Path.cpp
+++ b/contrib/llvm/lib/Support/Path.cpp
@@ -1,4 +1,4 @@
-//===-- Path.cpp - Implement OS Path Concept --------------------*- C++ -*-===//
+//===-- Path.cpp - Implement OS Path Concept ------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,80 +7,900 @@
//
//===----------------------------------------------------------------------===//
//
-// This header file implements the operating system Path concept.
+// This file implements the operating system Path API.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/Path.h"
-#include "llvm/Config/config.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
-#include <cassert>
+#include <cctype>
+#include <cstdio>
#include <cstring>
-#include <ostream>
-using namespace llvm;
-using namespace sys;
+#include <fcntl.h>
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
namespace {
-using support::ulittle32_t;
+ using llvm::StringRef;
+ using llvm::sys::path::is_separator;
+
+#ifdef LLVM_ON_WIN32
+ const char *separators = "\\/";
+ const char prefered_separator = '\\';
+#else
+ const char separators = '/';
+ const char prefered_separator = '/';
+#endif
+
+ StringRef find_first_component(StringRef path) {
+ // Look for this first component in the following order.
+ // * empty (in this case we return an empty string)
+ // * either C: or {//,\\}net.
+ // * {/,\}
+ // * {.,..}
+ // * {file,directory}name
+
+ if (path.empty())
+ return path;
+
+#ifdef LLVM_ON_WIN32
+ // C:
+ if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) &&
+ path[1] == ':')
+ return path.substr(0, 2);
+#endif
+
+ // //net
+ if ((path.size() > 2) &&
+ is_separator(path[0]) &&
+ path[0] == path[1] &&
+ !is_separator(path[2])) {
+ // Find the next directory separator.
+ size_t end = path.find_first_of(separators, 2);
+ return path.substr(0, end);
+ }
+
+ // {/,\}
+ if (is_separator(path[0]))
+ return path.substr(0, 1);
+
+ if (path.startswith(".."))
+ return path.substr(0, 2);
+
+ if (path[0] == '.')
+ return path.substr(0, 1);
+
+ // * {file,directory}name
+ size_t end = path.find_first_of(separators);
+ 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]))
+ return str.size() - 1;
+
+ size_t pos = str.find_last_of(separators, str.size() - 1);
+
+#ifdef LLVM_ON_WIN32
+ if (pos == StringRef::npos)
+ pos = str.find_last_of(':', str.size() - 2);
+#endif
+
+ if (pos == StringRef::npos ||
+ (pos == 1 && is_separator(str[0])))
+ return 0;
+
+ return pos + 1;
+ }
+
+ size_t root_dir_start(StringRef str) {
+ // case "c:/"
+#ifdef LLVM_ON_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;
+
+ // 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);
+ }
+
+ // case "/"
+ if (str.size() > 0 && is_separator(str[0]))
+ return 0;
+
+ return StringRef::npos;
+ }
+
+ size_t parent_path_end(StringRef path) {
+ size_t end_pos = filename_pos(path);
+
+ bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]);
+
+ // 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]))
+ --end_pos;
+
+ if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
+ return StringRef::npos;
+
+ return end_pos;
+ }
+} // end unnamed namespace
+
+enum FSEntity {
+ FS_Dir,
+ FS_File,
+ FS_Name
+};
+
+// Implemented in Unix/Path.inc and Windows/Path.inc.
+static llvm::error_code
+createUniqueEntity(const llvm::Twine &Model, int &ResultFD,
+ llvm::SmallVectorImpl<char> &ResultPath,
+ bool MakeAbsolute, unsigned Mode, FSEntity Type);
+
+namespace llvm {
+namespace sys {
+namespace path {
+
+const_iterator begin(StringRef path) {
+ const_iterator i;
+ i.Path = path;
+ i.Component = find_first_component(path);
+ i.Position = 0;
+ return i;
}
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only TRULY operating system
-//=== independent code.
-//===----------------------------------------------------------------------===//
+const_iterator end(StringRef path) {
+ const_iterator i;
+ i.Path = path;
+ i.Position = path.size();
+ return i;
+}
+
+const_iterator &const_iterator::operator++() {
+ assert(Position < Path.size() && "Tried to increment past end!");
+
+ // Increment Position to past the current component
+ Position += Component.size();
+
+ // Check for end.
+ if (Position == Path.size()) {
+ Component = StringRef();
+ return *this;
+ }
+
+ // 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]);
+
+ // Handle separators.
+ if (is_separator(Path[Position])) {
+ // Root dir.
+ if (was_net
+#ifdef LLVM_ON_WIN32
+ // c:/
+ || Component.endswith(":")
+#endif
+ ) {
+ Component = Path.substr(Position, 1);
+ return *this;
+ }
+
+ // Skip extra separators.
+ while (Position != Path.size() &&
+ is_separator(Path[Position])) {
+ ++Position;
+ }
+
+ // Treat trailing '/' as a '.'.
+ if (Position == Path.size()) {
+ --Position;
+ Component = ".";
+ return *this;
+ }
+ }
+
+ // Find next component.
+ size_t end_pos = Path.find_first_of(separators, Position);
+ Component = Path.slice(Position, end_pos);
+
+ return *this;
+}
+
+const_iterator &const_iterator::operator--() {
+ // If we're at the end and the previous char was a '/', return '.'.
+ if (Position == Path.size() &&
+ Path.size() > 1 &&
+ is_separator(Path[Position - 1])
+#ifdef LLVM_ON_WIN32
+ && Path[Position - 2] != ':'
+#endif
+ ) {
+ --Position;
+ Component = ".";
+ return *this;
+ }
+
+ // Skip separators unless it's the root directory.
+ size_t root_dir_pos = root_dir_start(Path);
+ 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));
+ Component = Path.slice(start_pos, end_pos);
+ Position = start_pos;
+ return *this;
+}
+
+bool const_iterator::operator==(const const_iterator &RHS) const {
+ return Path.begin() == RHS.Path.begin() &&
+ Position == RHS.Position;
+}
+
+bool const_iterator::operator!=(const const_iterator &RHS) const {
+ return !(*this == RHS);
+}
+
+ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const {
+ return Position - RHS.Position;
+}
+
+const StringRef root_path(StringRef path) {
+ const_iterator b = begin(path),
+ 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 LLVM_ON_WIN32
+ b->endswith(":");
+#else
+ false;
+#endif
+
+ if (has_net || has_drive) {
+ if ((++pos != e) && is_separator((*pos)[0])) {
+ // {C:/,//net/}, so get the first two components.
+ return path.substr(0, b->size() + pos->size());
+ } else {
+ // just {C:,//net}, return the first component.
+ return *b;
+ }
+ }
+
+ // POSIX style root directory.
+ if (is_separator((*b)[0])) {
+ return *b;
+ }
+ }
+
+ return StringRef();
+}
+
+const StringRef root_name(StringRef path) {
+ const_iterator b = begin(path),
+ e = end(path);
+ if (b != e) {
+ bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
+ bool has_drive =
+#ifdef LLVM_ON_WIN32
+ b->endswith(":");
+#else
+ false;
+#endif
+
+ if (has_net || has_drive) {
+ // just {C:,//net}, return the first component.
+ return *b;
+ }
+ }
+
+ // No path or no name.
+ return StringRef();
+}
+
+const StringRef root_directory(StringRef path) {
+ const_iterator b = begin(path),
+ 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 LLVM_ON_WIN32
+ b->endswith(":");
+#else
+ false;
+#endif
+
+ if ((has_net || has_drive) &&
+ // {C:,//net}, skip to the next component.
+ (++pos != e) && is_separator((*pos)[0])) {
+ return *pos;
+ }
+
+ // POSIX style root directory.
+ if (!has_net && is_separator((*b)[0])) {
+ return *b;
+ }
+ }
+
+ // No path or no root.
+ return StringRef();
+}
+
+const StringRef relative_path(StringRef path) {
+ StringRef root = root_path(path);
+ return path.substr(root.size());
+}
+
+void append(SmallVectorImpl<char> &path, const Twine &a,
+ const Twine &b,
+ const Twine &c,
+ const Twine &d) {
+ SmallString<32> a_storage;
+ SmallString<32> b_storage;
+ SmallString<32> c_storage;
+ SmallString<32> d_storage;
+
+ SmallVector<StringRef, 4> components;
+ if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage));
+ if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage));
+ if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage));
+ if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
+
+ for (SmallVectorImpl<StringRef>::const_iterator i = components.begin(),
+ e = components.end();
+ i != e; ++i) {
+ bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]);
+ bool component_has_sep = !i->empty() && is_separator((*i)[0]);
+ bool is_root_name = has_root_name(*i);
+
+ if (path_has_sep) {
+ // Strip separators from beginning of component.
+ size_t loc = i->find_first_not_of(separators);
+ StringRef c = i->substr(loc);
+
+ // Append it.
+ path.append(c.begin(), c.end());
+ continue;
+ }
+
+ if (!component_has_sep && !(path.empty() || is_root_name)) {
+ // Add a separator.
+ path.push_back(prefered_separator);
+ }
+
+ path.append(i->begin(), i->end());
+ }
+}
+
+void append(SmallVectorImpl<char> &path,
+ const_iterator begin, const_iterator end) {
+ for (; begin != end; ++begin)
+ path::append(path, *begin);
+}
+
+const StringRef parent_path(StringRef path) {
+ size_t end_pos = parent_path_end(path);
+ 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()));
+ if (end_pos != StringRef::npos)
+ path.set_size(end_pos);
+}
+
+void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) {
+ 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))
+ path.set_size(pos);
-bool Path::operator==(const Path &that) const {
- return path == that.path;
+ // Append '.' if needed.
+ if (ext.size() > 0 && ext[0] != '.')
+ path.push_back('.');
+
+ // Append extension.
+ path.append(ext.begin(), ext.end());
+}
+
+void native(const Twine &path, SmallVectorImpl<char> &result) {
+ 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);
+}
+
+void native(SmallVectorImpl<char> &path) {
+#ifdef LLVM_ON_WIN32
+ std::replace(path.begin(), path.end(), '/', '\\');
+#endif
}
-bool Path::operator<(const Path& that) const {
- return path < that.path;
+const StringRef filename(StringRef path) {
+ return *(--end(path));
}
-LLVMFileType
-sys::IdentifyFileType(const char *magic, unsigned length) {
- assert(magic && "Invalid magic number string");
- assert(length >=4 && "Invalid magic number length");
- switch ((unsigned char)magic[0]) {
+const StringRef stem(StringRef path) {
+ StringRef fname = filename(path);
+ size_t pos = fname.find_last_of('.');
+ if (pos == StringRef::npos)
+ return fname;
+ else
+ if ((fname.size() == 1 && fname == ".") ||
+ (fname.size() == 2 && fname == ".."))
+ return fname;
+ else
+ return fname.substr(0, pos);
+}
+
+const StringRef extension(StringRef path) {
+ StringRef fname = filename(path);
+ size_t pos = fname.find_last_of('.');
+ if (pos == StringRef::npos)
+ return StringRef();
+ else
+ if ((fname.size() == 1 && fname == ".") ||
+ (fname.size() == 2 && fname == ".."))
+ return StringRef();
+ else
+ return fname.substr(pos);
+}
+
+bool is_separator(char value) {
+ switch(value) {
+#ifdef LLVM_ON_WIN32
+ case '\\': // fall through
+#endif
+ case '/': return true;
+ default: return false;
+ }
+}
+
+void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result) {
+ result.clear();
+
+#ifdef __APPLE__
+ // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR.
+ int ConfName = erasedOnReboot? _CS_DARWIN_USER_TEMP_DIR
+ : _CS_DARWIN_USER_CACHE_DIR;
+ size_t ConfLen = confstr(ConfName, 0, 0);
+ if (ConfLen > 0) {
+ do {
+ result.resize(ConfLen);
+ ConfLen = confstr(ConfName, result.data(), result.size());
+ } while (ConfLen > 0 && ConfLen != result.size());
+
+ if (ConfLen > 0) {
+ assert(result.back() == 0);
+ result.pop_back();
+ return;
+ }
+
+ result.clear();
+ }
+#endif
+
+ // Check whether the temporary directory is specified by an environment
+ // variable.
+ const char *EnvironmentVariable;
+#ifdef LLVM_ON_WIN32
+ EnvironmentVariable = "TEMP";
+#else
+ EnvironmentVariable = "TMPDIR";
+#endif
+ if (char *RequestedDir = getenv(EnvironmentVariable)) {
+ result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
+ return;
+ }
+
+ // Fall back to a system default.
+ const char *DefaultResult;
+#ifdef LLVM_ON_WIN32
+ (void)erasedOnReboot;
+ DefaultResult = "C:\\TEMP";
+#else
+ if (erasedOnReboot)
+ DefaultResult = "/tmp";
+ else
+ DefaultResult = "/var/tmp";
+#endif
+ result.append(DefaultResult, DefaultResult + strlen(DefaultResult));
+}
+
+bool has_root_name(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
+
+ return !root_name(p).empty();
+}
+
+bool has_root_directory(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
+
+ return !root_directory(p).empty();
+}
+
+bool has_root_path(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
+
+ return !root_path(p).empty();
+}
+
+bool has_relative_path(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
+
+ return !relative_path(p).empty();
+}
+
+bool has_filename(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
+
+ return !filename(p).empty();
+}
+
+bool has_parent_path(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
+
+ return !parent_path(p).empty();
+}
+
+bool has_stem(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
+
+ return !stem(p).empty();
+}
+
+bool has_extension(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
+
+ return !extension(p).empty();
+}
+
+bool is_absolute(const Twine &path) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
+
+ bool rootDir = has_root_directory(p),
+#ifdef LLVM_ON_WIN32
+ rootName = has_root_name(p);
+#else
+ rootName = true;
+#endif
+
+ return rootDir && rootName;
+}
+
+bool is_relative(const Twine &path) {
+ return !is_absolute(path);
+}
+
+} // end namespace path
+
+namespace fs {
+
+error_code getUniqueID(const Twine Path, UniqueID &Result) {
+ file_status Status;
+ error_code EC = status(Path, Status);
+ if (EC)
+ return EC;
+ Result = Status.getUniqueID();
+ return error_code::success();
+}
+
+error_code createUniqueFile(const Twine &Model, int &ResultFd,
+ SmallVectorImpl<char> &ResultPath, unsigned Mode) {
+ return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File);
+}
+
+error_code createUniqueFile(const Twine &Model,
+ SmallVectorImpl<char> &ResultPath) {
+ int Dummy;
+ return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name);
+}
+
+static error_code createTemporaryFile(const Twine &Model, int &ResultFD,
+ llvm::SmallVectorImpl<char> &ResultPath,
+ FSEntity Type) {
+ SmallString<128> Storage;
+ StringRef P = Model.toNullTerminatedStringRef(Storage);
+ assert(P.find_first_of(separators) == StringRef::npos &&
+ "Model must be a simple filename.");
+ // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage.
+ return createUniqueEntity(P.begin(), ResultFD, ResultPath,
+ true, owner_read | owner_write, Type);
+}
+
+static error_code
+createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD,
+ llvm::SmallVectorImpl<char> &ResultPath,
+ FSEntity Type) {
+ const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%.";
+ return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath,
+ Type);
+}
+
+
+error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
+ int &ResultFD,
+ SmallVectorImpl<char> &ResultPath) {
+ return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File);
+}
+
+error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
+ SmallVectorImpl<char> &ResultPath) {
+ int Dummy;
+ return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name);
+}
+
+
+// This is a mkdtemp with a different pattern. We use createUniqueEntity mostly
+// for consistency. We should try using mkdtemp.
+error_code createUniqueDirectory(const Twine &Prefix,
+ SmallVectorImpl<char> &ResultPath) {
+ int Dummy;
+ return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath,
+ true, 0, FS_Dir);
+}
+
+error_code make_absolute(SmallVectorImpl<char> &path) {
+ StringRef p(path.data(), path.size());
+
+ bool rootDirectory = path::has_root_directory(p),
+#ifdef LLVM_ON_WIN32
+ rootName = path::has_root_name(p);
+#else
+ rootName = true;
+#endif
+
+ // Already absolute.
+ if (rootName && rootDirectory)
+ return error_code::success();
+
+ // All of the following conditions will need the current directory.
+ SmallString<128> current_dir;
+ if (error_code ec = current_path(current_dir)) return ec;
+
+ // Relative path. Prepend the current directory.
+ if (!rootName && !rootDirectory) {
+ // Append path to the current directory.
+ path::append(current_dir, p);
+ // Set path to the result.
+ path.swap(current_dir);
+ return error_code::success();
+ }
+
+ if (!rootName && rootDirectory) {
+ StringRef cdrn = path::root_name(current_dir);
+ SmallString<128> curDirRootName(cdrn.begin(), cdrn.end());
+ path::append(curDirRootName, p);
+ // Set path to the result.
+ path.swap(curDirRootName);
+ return error_code::success();
+ }
+
+ if (rootName && !rootDirectory) {
+ StringRef pRootName = path::root_name(p);
+ StringRef bRootDirectory = path::root_directory(current_dir);
+ StringRef bRelativePath = path::relative_path(current_dir);
+ StringRef pRelativePath = path::relative_path(p);
+
+ SmallString<128> res;
+ path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath);
+ path.swap(res);
+ return error_code::success();
+ }
+
+ llvm_unreachable("All rootName and rootDirectory combinations should have "
+ "occurred above!");
+}
+
+error_code create_directories(const Twine &path, bool &existed) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
+
+ StringRef parent = path::parent_path(p);
+ if (!parent.empty()) {
+ bool parent_exists;
+ if (error_code ec = fs::exists(parent, parent_exists)) return ec;
+
+ if (!parent_exists)
+ if (error_code ec = create_directories(parent, existed)) return ec;
+ }
+
+ return create_directory(p, existed);
+}
+
+bool exists(file_status status) {
+ return status_known(status) && status.type() != file_type::file_not_found;
+}
+
+bool status_known(file_status s) {
+ return s.type() != file_type::status_error;
+}
+
+bool is_directory(file_status status) {
+ return status.type() == file_type::directory_file;
+}
+
+error_code is_directory(const Twine &path, bool &result) {
+ file_status st;
+ if (error_code ec = status(path, st))
+ return ec;
+ result = is_directory(st);
+ return error_code::success();
+}
+
+bool is_regular_file(file_status status) {
+ return status.type() == file_type::regular_file;
+}
+
+error_code is_regular_file(const Twine &path, bool &result) {
+ file_status st;
+ if (error_code ec = status(path, st))
+ return ec;
+ result = is_regular_file(st);
+ return error_code::success();
+}
+
+bool is_symlink(file_status status) {
+ return status.type() == file_type::symlink_file;
+}
+
+error_code is_symlink(const Twine &path, bool &result) {
+ file_status st;
+ if (error_code ec = status(path, st))
+ return ec;
+ result = is_symlink(st);
+ return error_code::success();
+}
+
+bool is_other(file_status status) {
+ return exists(status) &&
+ !is_regular_file(status) &&
+ !is_directory(status) &&
+ !is_symlink(status);
+}
+
+void directory_entry::replace_filename(const Twine &filename, file_status st) {
+ SmallString<128> path(Path.begin(), Path.end());
+ path::remove_filename(path);
+ path::append(path, filename);
+ Path = path.str();
+ Status = st;
+}
+
+error_code has_magic(const Twine &path, const Twine &magic, bool &result) {
+ SmallString<32> MagicStorage;
+ StringRef Magic = magic.toStringRef(MagicStorage);
+ SmallString<32> Buffer;
+
+ if (error_code ec = get_magic(path, Magic.size(), Buffer)) {
+ if (ec == errc::value_too_large) {
+ // Magic.size() > file_size(Path).
+ result = false;
+ return error_code::success();
+ }
+ return ec;
+ }
+
+ result = Magic == Buffer;
+ return error_code::success();
+}
+
+/// @brief Identify the magic in magic.
+ file_magic identify_magic(StringRef Magic) {
+ if (Magic.size() < 4)
+ return file_magic::unknown;
+ switch ((unsigned char)Magic[0]) {
+ case 0x00: {
+ // COFF short import library file
+ if (Magic[1] == (char)0x00 && Magic[2] == (char)0xff &&
+ Magic[3] == (char)0xff)
+ return file_magic::coff_import_library;
+ // Windows resource file
+ const char Expected[] = { 0, 0, 0, 0, '\x20', 0, 0, 0, '\xff' };
+ if (Magic.size() >= sizeof(Expected) &&
+ memcmp(Magic.data(), Expected, sizeof(Expected)) == 0)
+ return file_magic::windows_resource;
+ // 0x0000 = COFF unknown machine type
+ if (Magic[1] == 0)
+ return file_magic::coff_object;
+ break;
+ }
case 0xDE: // 0x0B17C0DE = BC wraper
- if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 &&
- magic[3] == (char)0x0B)
- return Bitcode_FileType;
+ if (Magic[1] == (char)0xC0 && Magic[2] == (char)0x17 &&
+ Magic[3] == (char)0x0B)
+ return file_magic::bitcode;
break;
case 'B':
- if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE)
- return Bitcode_FileType;
+ if (Magic[1] == 'C' && Magic[2] == (char)0xC0 && Magic[3] == (char)0xDE)
+ return file_magic::bitcode;
break;
case '!':
- if (length >= 8)
- if (memcmp(magic,"!<arch>\n",8) == 0)
- return Archive_FileType;
+ if (Magic.size() >= 8)
+ if (memcmp(Magic.data(),"!<arch>\n",8) == 0)
+ return file_magic::archive;
break;
case '\177':
- if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') {
- bool Data2MSB = magic[5] == 2;
+ if (Magic.size() >= 18 && Magic[1] == 'E' && Magic[2] == 'L' &&
+ Magic[3] == 'F') {
+ bool Data2MSB = Magic[5] == 2;
unsigned high = Data2MSB ? 16 : 17;
unsigned low = Data2MSB ? 17 : 16;
- if (length >= 18 && magic[high] == 0)
- switch (magic[low]) {
+ if (Magic[high] == 0)
+ switch (Magic[low]) {
default: break;
- case 1: return ELF_Relocatable_FileType;
- case 2: return ELF_Executable_FileType;
- case 3: return ELF_SharedObject_FileType;
- case 4: return ELF_Core_FileType;
+ case 1: return file_magic::elf_relocatable;
+ case 2: return file_magic::elf_executable;
+ case 3: return file_magic::elf_shared_object;
+ case 4: return file_magic::elf_core;
}
}
break;
case 0xCA:
- if (magic[1] == char(0xFE) && magic[2] == char(0xBA) &&
- magic[3] == char(0xBE)) {
+ if (Magic[1] == char(0xFE) && Magic[2] == char(0xBA) &&
+ Magic[3] == char(0xBE)) {
// This is complicated by an overlap with Java class files.
// See the Mach-O section in /usr/share/file/magic for details.
- if (length >= 8 && magic[7] < 43)
- // FIXME: Universal Binary of any type.
- return Mach_O_DynamicallyLinkedSharedLib_FileType;
+ if (Magic.size() >= 8 && Magic[7] < 43)
+ return file_magic::macho_universal_binary;
}
break;
@@ -91,29 +911,29 @@ sys::IdentifyFileType(const char *magic, unsigned length) {
case 0xCE:
case 0xCF: {
uint16_t type = 0;
- if (magic[0] == char(0xFE) && magic[1] == char(0xED) &&
- magic[2] == char(0xFA) &&
- (magic[3] == char(0xCE) || magic[3] == char(0xCF))) {
+ if (Magic[0] == char(0xFE) && Magic[1] == char(0xED) &&
+ Magic[2] == char(0xFA) &&
+ (Magic[3] == char(0xCE) || Magic[3] == char(0xCF))) {
/* Native endian */
- if (length >= 16) type = magic[14] << 8 | magic[15];
- } else if ((magic[0] == char(0xCE) || magic[0] == char(0xCF)) &&
- magic[1] == char(0xFA) && magic[2] == char(0xED) &&
- magic[3] == char(0xFE)) {
+ if (Magic.size() >= 16) type = Magic[14] << 8 | Magic[15];
+ } else if ((Magic[0] == char(0xCE) || Magic[0] == char(0xCF)) &&
+ Magic[1] == char(0xFA) && Magic[2] == char(0xED) &&
+ Magic[3] == char(0xFE)) {
/* Reverse endian */
- if (length >= 14) type = magic[13] << 8 | magic[12];
+ if (Magic.size() >= 14) type = Magic[13] << 8 | Magic[12];
}
switch (type) {
default: break;
- case 1: return Mach_O_Object_FileType;
- case 2: return Mach_O_Executable_FileType;
- case 3: return Mach_O_FixedVirtualMemorySharedLib_FileType;
- case 4: return Mach_O_Core_FileType;
- case 5: return Mach_O_PreloadExecutable_FileType;
- case 6: return Mach_O_DynamicallyLinkedSharedLib_FileType;
- case 7: return Mach_O_DynamicLinker_FileType;
- case 8: return Mach_O_Bundle_FileType;
- case 9: return Mach_O_DynamicallyLinkedSharedLibStub_FileType;
- case 10: return Mach_O_DSYMCompanion_FileType;
+ case 1: return file_magic::macho_object;
+ case 2: return file_magic::macho_executable;
+ case 3: return file_magic::macho_fixed_virtual_memory_shared_lib;
+ case 4: return file_magic::macho_core;
+ case 5: return file_magic::macho_preload_executable;
+ case 6: return file_magic::macho_dynamically_linked_shared_lib;
+ case 7: return file_magic::macho_dynamic_linker;
+ case 8: return file_magic::macho_bundle;
+ case 9: return file_magic::macho_dynamic_linker;
+ case 10: return file_magic::macho_dsym_companion;
}
break;
}
@@ -123,170 +943,94 @@ sys::IdentifyFileType(const char *magic, unsigned length) {
case 0x66: // MPS R4000 Windows
case 0x50: // mc68K
case 0x4c: // 80386 Windows
- if (magic[1] == 0x01)
- return COFF_FileType;
+ if (Magic[1] == 0x01)
+ return file_magic::coff_object;
case 0x90: // PA-RISC Windows
case 0x68: // mc68K Windows
- if (magic[1] == 0x02)
- return COFF_FileType;
+ if (Magic[1] == 0x02)
+ return file_magic::coff_object;
break;
case 0x4d: // Possible MS-DOS stub on Windows PE file
- if (magic[1] == 0x5a) {
- uint32_t off = *reinterpret_cast<const ulittle32_t *>(magic + 0x3c);
+ if (Magic[1] == 0x5a) {
+ uint32_t off =
+ *reinterpret_cast<const support::ulittle32_t*>(Magic.data() + 0x3c);
// PE/COFF file, either EXE or DLL.
- if (off < length && memcmp(magic + off, "PE\0\0",4) == 0)
- return COFF_FileType;
+ if (off < Magic.size() && memcmp(Magic.data() + off, "PE\0\0",4) == 0)
+ return file_magic::pecoff_executable;
}
break;
case 0x64: // x86-64 Windows.
- if (magic[1] == char(0x86))
- return COFF_FileType;
+ if (Magic[1] == char(0x86))
+ return file_magic::coff_object;
break;
default:
break;
}
- return Unknown_FileType;
+ return file_magic::unknown;
}
-bool
-Path::isArchive() const {
- fs::file_magic type;
- if (fs::identify_magic(str(), type))
- return false;
- return type == fs::file_magic::archive;
-}
+error_code identify_magic(const Twine &path, file_magic &result) {
+ SmallString<32> Magic;
+ error_code ec = get_magic(path, Magic.capacity(), Magic);
+ if (ec && ec != errc::value_too_large)
+ return ec;
-bool
-Path::isDynamicLibrary() const {
- fs::file_magic type;
- if (fs::identify_magic(str(), type))
- return false;
- switch (type) {
- default: return false;
- case fs::file_magic::macho_fixed_virtual_memory_shared_lib:
- case fs::file_magic::macho_dynamically_linked_shared_lib:
- case fs::file_magic::macho_dynamically_linked_shared_lib_stub:
- case fs::file_magic::elf_shared_object:
- case fs::file_magic::pecoff_executable: return true;
- }
+ result = identify_magic(Magic);
+ return error_code::success();
}
-bool
-Path::isObjectFile() const {
- fs::file_magic type;
- if (fs::identify_magic(str(), type) || type == fs::file_magic::unknown)
- return false;
- return true;
-}
-
-Path
-Path::FindLibrary(std::string& name) {
- std::vector<sys::Path> LibPaths;
- GetSystemLibraryPaths(LibPaths);
- for (unsigned i = 0; i < LibPaths.size(); ++i) {
- sys::Path FullPath(LibPaths[i]);
- FullPath.appendComponent("lib" + name + LTDL_SHLIB_EXT);
- if (FullPath.isDynamicLibrary())
- return FullPath;
- FullPath.eraseSuffix();
- FullPath.appendSuffix("a");
- if (FullPath.isArchive())
- return FullPath;
+namespace {
+error_code remove_all_r(StringRef path, file_type ft, uint32_t &count) {
+ if (ft == file_type::directory_file) {
+ // This code would be a lot better with exceptions ;/.
+ error_code ec;
+ directory_iterator i(path, ec);
+ if (ec) return ec;
+ for (directory_iterator e; i != e; i.increment(ec)) {
+ if (ec) return ec;
+ file_status st;
+ if (error_code ec = i->status(st)) return ec;
+ if (error_code ec = remove_all_r(i->path(), st.type(), count)) return ec;
+ }
+ bool obviously_this_exists;
+ if (error_code ec = remove(path, obviously_this_exists)) return ec;
+ assert(obviously_this_exists);
+ ++count; // Include the directory itself in the items removed.
+ } else {
+ bool obviously_this_exists;
+ if (error_code ec = remove(path, obviously_this_exists)) return ec;
+ assert(obviously_this_exists);
+ ++count;
}
- return sys::Path();
-}
-StringRef Path::GetDLLSuffix() {
- return &(LTDL_SHLIB_EXT[1]);
+ return error_code::success();
}
+} // end unnamed namespace
-void
-Path::appendSuffix(StringRef suffix) {
- if (!suffix.empty()) {
- path.append(".");
- path.append(suffix);
- }
-}
-
-bool
-Path::isBitcodeFile() const {
- fs::file_magic type;
- if (fs::identify_magic(str(), type))
- return false;
- return type == fs::file_magic::bitcode;
-}
-
-bool Path::hasMagicNumber(StringRef Magic) const {
- std::string actualMagic;
- if (getMagicNumber(actualMagic, static_cast<unsigned>(Magic.size())))
- return Magic == actualMagic;
- return false;
-}
-
-static void getPathList(const char*path, std::vector<Path>& Paths) {
- const char* at = path;
- const char* delim = strchr(at, PathSeparator);
- Path tmpPath;
- while (delim != 0) {
- std::string tmp(at, size_t(delim-at));
- if (tmpPath.set(tmp))
- if (tmpPath.canRead())
- Paths.push_back(tmpPath);
- at = delim + 1;
- delim = strchr(at, PathSeparator);
- }
+error_code remove_all(const Twine &path, uint32_t &num_removed) {
+ SmallString<128> path_storage;
+ StringRef p = path.toStringRef(path_storage);
- if (*at != 0)
- if (tmpPath.set(std::string(at)))
- if (tmpPath.canRead())
- Paths.push_back(tmpPath);
+ file_status fs;
+ if (error_code ec = status(path, fs))
+ return ec;
+ num_removed = 0;
+ return remove_all_r(p, fs.type(), num_removed);
}
-static StringRef getDirnameCharSep(StringRef path, const char *Sep) {
- assert(Sep[0] != '\0' && Sep[1] == '\0' &&
- "Sep must be a 1-character string literal.");
- if (path.empty())
- return ".";
-
- // If the path is all slashes, return a single slash.
- // Otherwise, remove all trailing slashes.
-
- signed pos = static_cast<signed>(path.size()) - 1;
-
- while (pos >= 0 && path[pos] == Sep[0])
- --pos;
-
- if (pos < 0)
- return path[0] == Sep[0] ? Sep : ".";
-
- // Any slashes left?
- signed i = 0;
-
- while (i < pos && path[i] != Sep[0])
- ++i;
-
- if (i == pos) // No slashes? Return "."
- return ".";
-
- // There is at least one slash left. Remove all trailing non-slashes.
- while (pos >= 0 && path[pos] != Sep[0])
- --pos;
-
- // Remove any trailing slashes.
- while (pos >= 0 && path[pos] == Sep[0])
- --pos;
-
- if (pos < 0)
- return path[0] == Sep[0] ? Sep : ".";
-
- return path.substr(0, pos+1);
+error_code directory_entry::status(file_status &result) const {
+ return fs::status(Path, result);
}
-// Include the truly platform-specific parts of this class.
+} // end namespace fs
+} // end namespace sys
+} // end namespace llvm
+
+// Include the truly platform-specific parts.
#if defined(LLVM_ON_UNIX)
#include "Unix/Path.inc"
#endif
diff --git a/contrib/llvm/lib/Support/PathV2.cpp b/contrib/llvm/lib/Support/PathV2.cpp
deleted file mode 100644
index ac53a9e9..0000000
--- a/contrib/llvm/lib/Support/PathV2.cpp
+++ /dev/null
@@ -1,949 +0,0 @@
-//===-- PathV2.cpp - Implement OS Path Concept ------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the operating system PathV2 API.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/PathV2.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileSystem.h"
-#include <cctype>
-#include <cstdio>
-#include <cstring>
-#ifdef __APPLE__
-#include <unistd.h>
-#endif
-
-namespace {
- using llvm::StringRef;
- using llvm::sys::path::is_separator;
-
-#ifdef LLVM_ON_WIN32
- const char *separators = "\\/";
- const char prefered_separator = '\\';
-#else
- const char separators = '/';
- const char prefered_separator = '/';
-#endif
-
- StringRef find_first_component(StringRef path) {
- // Look for this first component in the following order.
- // * empty (in this case we return an empty string)
- // * either C: or {//,\\}net.
- // * {/,\}
- // * {.,..}
- // * {file,directory}name
-
- if (path.empty())
- return path;
-
-#ifdef LLVM_ON_WIN32
- // C:
- if (path.size() >= 2 && std::isalpha(static_cast<unsigned char>(path[0])) &&
- path[1] == ':')
- return path.substr(0, 2);
-#endif
-
- // //net
- if ((path.size() > 2) &&
- is_separator(path[0]) &&
- path[0] == path[1] &&
- !is_separator(path[2])) {
- // Find the next directory separator.
- size_t end = path.find_first_of(separators, 2);
- return path.substr(0, end);
- }
-
- // {/,\}
- if (is_separator(path[0]))
- return path.substr(0, 1);
-
- if (path.startswith(".."))
- return path.substr(0, 2);
-
- if (path[0] == '.')
- return path.substr(0, 1);
-
- // * {file,directory}name
- size_t end = path.find_first_of(separators, 2);
- 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]))
- return str.size() - 1;
-
- size_t pos = str.find_last_of(separators, str.size() - 1);
-
-#ifdef LLVM_ON_WIN32
- if (pos == StringRef::npos)
- pos = str.find_last_of(':', str.size() - 2);
-#endif
-
- if (pos == StringRef::npos ||
- (pos == 1 && is_separator(str[0])))
- return 0;
-
- return pos + 1;
- }
-
- size_t root_dir_start(StringRef str) {
- // case "c:/"
-#ifdef LLVM_ON_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;
-
- // 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);
- }
-
- // case "/"
- if (str.size() > 0 && is_separator(str[0]))
- return 0;
-
- return StringRef::npos;
- }
-
- size_t parent_path_end(StringRef path) {
- size_t end_pos = filename_pos(path);
-
- bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]);
-
- // 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]))
- --end_pos;
-
- if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep)
- return StringRef::npos;
-
- return end_pos;
- }
-} // end unnamed namespace
-
-namespace llvm {
-namespace sys {
-namespace path {
-
-const_iterator begin(StringRef path) {
- const_iterator i;
- i.Path = path;
- i.Component = find_first_component(path);
- i.Position = 0;
- return i;
-}
-
-const_iterator end(StringRef path) {
- const_iterator i;
- i.Path = path;
- i.Position = path.size();
- return i;
-}
-
-const_iterator &const_iterator::operator++() {
- assert(Position < Path.size() && "Tried to increment past end!");
-
- // Increment Position to past the current component
- Position += Component.size();
-
- // Check for end.
- if (Position == Path.size()) {
- Component = StringRef();
- return *this;
- }
-
- // 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]);
-
- // Handle separators.
- if (is_separator(Path[Position])) {
- // Root dir.
- if (was_net
-#ifdef LLVM_ON_WIN32
- // c:/
- || Component.endswith(":")
-#endif
- ) {
- Component = Path.substr(Position, 1);
- return *this;
- }
-
- // Skip extra separators.
- while (Position != Path.size() &&
- is_separator(Path[Position])) {
- ++Position;
- }
-
- // Treat trailing '/' as a '.'.
- if (Position == Path.size()) {
- --Position;
- Component = ".";
- return *this;
- }
- }
-
- // Find next component.
- size_t end_pos = Path.find_first_of(separators, Position);
- Component = Path.slice(Position, end_pos);
-
- return *this;
-}
-
-const_iterator &const_iterator::operator--() {
- // If we're at the end and the previous char was a '/', return '.'.
- if (Position == Path.size() &&
- Path.size() > 1 &&
- is_separator(Path[Position - 1])
-#ifdef LLVM_ON_WIN32
- && Path[Position - 2] != ':'
-#endif
- ) {
- --Position;
- Component = ".";
- return *this;
- }
-
- // Skip separators unless it's the root directory.
- size_t root_dir_pos = root_dir_start(Path);
- 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));
- Component = Path.slice(start_pos, end_pos);
- Position = start_pos;
- return *this;
-}
-
-bool const_iterator::operator==(const const_iterator &RHS) const {
- return Path.begin() == RHS.Path.begin() &&
- Position == RHS.Position;
-}
-
-bool const_iterator::operator!=(const const_iterator &RHS) const {
- return !(*this == RHS);
-}
-
-ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const {
- return Position - RHS.Position;
-}
-
-const StringRef root_path(StringRef path) {
- const_iterator b = begin(path),
- 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 LLVM_ON_WIN32
- b->endswith(":");
-#else
- false;
-#endif
-
- if (has_net || has_drive) {
- if ((++pos != e) && is_separator((*pos)[0])) {
- // {C:/,//net/}, so get the first two components.
- return path.substr(0, b->size() + pos->size());
- } else {
- // just {C:,//net}, return the first component.
- return *b;
- }
- }
-
- // POSIX style root directory.
- if (is_separator((*b)[0])) {
- return *b;
- }
- }
-
- return StringRef();
-}
-
-const StringRef root_name(StringRef path) {
- const_iterator b = begin(path),
- e = end(path);
- if (b != e) {
- bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0];
- bool has_drive =
-#ifdef LLVM_ON_WIN32
- b->endswith(":");
-#else
- false;
-#endif
-
- if (has_net || has_drive) {
- // just {C:,//net}, return the first component.
- return *b;
- }
- }
-
- // No path or no name.
- return StringRef();
-}
-
-const StringRef root_directory(StringRef path) {
- const_iterator b = begin(path),
- 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 LLVM_ON_WIN32
- b->endswith(":");
-#else
- false;
-#endif
-
- if ((has_net || has_drive) &&
- // {C:,//net}, skip to the next component.
- (++pos != e) && is_separator((*pos)[0])) {
- return *pos;
- }
-
- // POSIX style root directory.
- if (!has_net && is_separator((*b)[0])) {
- return *b;
- }
- }
-
- // No path or no root.
- return StringRef();
-}
-
-const StringRef relative_path(StringRef path) {
- StringRef root = root_path(path);
- return path.substr(root.size());
-}
-
-void append(SmallVectorImpl<char> &path, const Twine &a,
- const Twine &b,
- const Twine &c,
- const Twine &d) {
- SmallString<32> a_storage;
- SmallString<32> b_storage;
- SmallString<32> c_storage;
- SmallString<32> d_storage;
-
- SmallVector<StringRef, 4> components;
- if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage));
- if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage));
- if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage));
- if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage));
-
- for (SmallVectorImpl<StringRef>::const_iterator i = components.begin(),
- e = components.end();
- i != e; ++i) {
- bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]);
- bool component_has_sep = !i->empty() && is_separator((*i)[0]);
- bool is_root_name = has_root_name(*i);
-
- if (path_has_sep) {
- // Strip separators from beginning of component.
- size_t loc = i->find_first_not_of(separators);
- StringRef c = i->substr(loc);
-
- // Append it.
- path.append(c.begin(), c.end());
- continue;
- }
-
- if (!component_has_sep && !(path.empty() || is_root_name)) {
- // Add a separator.
- path.push_back(prefered_separator);
- }
-
- path.append(i->begin(), i->end());
- }
-}
-
-void append(SmallVectorImpl<char> &path,
- const_iterator begin, const_iterator end) {
- for (; begin != end; ++begin)
- path::append(path, *begin);
-}
-
-const StringRef parent_path(StringRef path) {
- size_t end_pos = parent_path_end(path);
- 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()));
- if (end_pos != StringRef::npos)
- path.set_size(end_pos);
-}
-
-void replace_extension(SmallVectorImpl<char> &path, const Twine &extension) {
- 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))
- path.set_size(pos);
-
- // Append '.' if needed.
- if (ext.size() > 0 && ext[0] != '.')
- path.push_back('.');
-
- // Append extension.
- path.append(ext.begin(), ext.end());
-}
-
-void native(const Twine &path, SmallVectorImpl<char> &result) {
- // Clear result.
- result.clear();
-#ifdef LLVM_ON_WIN32
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
- result.reserve(p.size());
- for (StringRef::const_iterator i = p.begin(),
- e = p.end();
- i != e;
- ++i) {
- if (*i == '/')
- result.push_back('\\');
- else
- result.push_back(*i);
- }
-#else
- path.toVector(result);
-#endif
-}
-
-const StringRef filename(StringRef path) {
- return *(--end(path));
-}
-
-const StringRef stem(StringRef path) {
- StringRef fname = filename(path);
- size_t pos = fname.find_last_of('.');
- if (pos == StringRef::npos)
- return fname;
- else
- if ((fname.size() == 1 && fname == ".") ||
- (fname.size() == 2 && fname == ".."))
- return fname;
- else
- return fname.substr(0, pos);
-}
-
-const StringRef extension(StringRef path) {
- StringRef fname = filename(path);
- size_t pos = fname.find_last_of('.');
- if (pos == StringRef::npos)
- return StringRef();
- else
- if ((fname.size() == 1 && fname == ".") ||
- (fname.size() == 2 && fname == ".."))
- return StringRef();
- else
- return fname.substr(pos);
-}
-
-bool is_separator(char value) {
- switch(value) {
-#ifdef LLVM_ON_WIN32
- case '\\': // fall through
-#endif
- case '/': return true;
- default: return false;
- }
-}
-
-void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result) {
- result.clear();
-
-#ifdef __APPLE__
- // On Darwin, use DARWIN_USER_TEMP_DIR or DARWIN_USER_CACHE_DIR.
- int ConfName = erasedOnReboot? _CS_DARWIN_USER_TEMP_DIR
- : _CS_DARWIN_USER_CACHE_DIR;
- size_t ConfLen = confstr(ConfName, 0, 0);
- if (ConfLen > 0) {
- do {
- result.resize(ConfLen);
- ConfLen = confstr(ConfName, result.data(), result.size());
- } while (ConfLen > 0 && ConfLen != result.size());
-
- if (ConfLen > 0) {
- assert(result.back() == 0);
- result.pop_back();
- return;
- }
-
- result.clear();
- }
-#endif
-
- // Check whether the temporary directory is specified by an environment
- // variable.
- const char *EnvironmentVariable;
-#ifdef LLVM_ON_WIN32
- EnvironmentVariable = "TEMP";
-#else
- EnvironmentVariable = "TMPDIR";
-#endif
- if (char *RequestedDir = getenv(EnvironmentVariable)) {
- result.append(RequestedDir, RequestedDir + strlen(RequestedDir));
- return;
- }
-
- // Fall back to a system default.
- const char *DefaultResult;
-#ifdef LLVM_ON_WIN32
- (void)erasedOnReboot;
- DefaultResult = "C:\\TEMP";
-#else
- if (erasedOnReboot)
- DefaultResult = "/tmp";
- else
- DefaultResult = "/var/tmp";
-#endif
- result.append(DefaultResult, DefaultResult + strlen(DefaultResult));
-}
-
-bool has_root_name(const Twine &path) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- return !root_name(p).empty();
-}
-
-bool has_root_directory(const Twine &path) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- return !root_directory(p).empty();
-}
-
-bool has_root_path(const Twine &path) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- return !root_path(p).empty();
-}
-
-bool has_relative_path(const Twine &path) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- return !relative_path(p).empty();
-}
-
-bool has_filename(const Twine &path) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- return !filename(p).empty();
-}
-
-bool has_parent_path(const Twine &path) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- return !parent_path(p).empty();
-}
-
-bool has_stem(const Twine &path) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- return !stem(p).empty();
-}
-
-bool has_extension(const Twine &path) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- return !extension(p).empty();
-}
-
-bool is_absolute(const Twine &path) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- bool rootDir = has_root_directory(p),
-#ifdef LLVM_ON_WIN32
- rootName = has_root_name(p);
-#else
- rootName = true;
-#endif
-
- return rootDir && rootName;
-}
-
-bool is_relative(const Twine &path) {
- return !is_absolute(path);
-}
-
-} // end namespace path
-
-namespace fs {
-
-error_code make_absolute(SmallVectorImpl<char> &path) {
- StringRef p(path.data(), path.size());
-
- bool rootDirectory = path::has_root_directory(p),
-#ifdef LLVM_ON_WIN32
- rootName = path::has_root_name(p);
-#else
- rootName = true;
-#endif
-
- // Already absolute.
- if (rootName && rootDirectory)
- return error_code::success();
-
- // All of the following conditions will need the current directory.
- SmallString<128> current_dir;
- if (error_code ec = current_path(current_dir)) return ec;
-
- // Relative path. Prepend the current directory.
- if (!rootName && !rootDirectory) {
- // Append path to the current directory.
- path::append(current_dir, p);
- // Set path to the result.
- path.swap(current_dir);
- return error_code::success();
- }
-
- if (!rootName && rootDirectory) {
- StringRef cdrn = path::root_name(current_dir);
- SmallString<128> curDirRootName(cdrn.begin(), cdrn.end());
- path::append(curDirRootName, p);
- // Set path to the result.
- path.swap(curDirRootName);
- return error_code::success();
- }
-
- if (rootName && !rootDirectory) {
- StringRef pRootName = path::root_name(p);
- StringRef bRootDirectory = path::root_directory(current_dir);
- StringRef bRelativePath = path::relative_path(current_dir);
- StringRef pRelativePath = path::relative_path(p);
-
- SmallString<128> res;
- path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath);
- path.swap(res);
- return error_code::success();
- }
-
- llvm_unreachable("All rootName and rootDirectory combinations should have "
- "occurred above!");
-}
-
-error_code create_directories(const Twine &path, bool &existed) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- StringRef parent = path::parent_path(p);
- if (!parent.empty()) {
- bool parent_exists;
- if (error_code ec = fs::exists(parent, parent_exists)) return ec;
-
- if (!parent_exists)
- if (error_code ec = create_directories(parent, existed)) return ec;
- }
-
- return create_directory(p, existed);
-}
-
-bool exists(file_status status) {
- return status_known(status) && status.type() != file_type::file_not_found;
-}
-
-bool status_known(file_status s) {
- return s.type() != file_type::status_error;
-}
-
-bool is_directory(file_status status) {
- return status.type() == file_type::directory_file;
-}
-
-error_code is_directory(const Twine &path, bool &result) {
- file_status st;
- if (error_code ec = status(path, st))
- return ec;
- result = is_directory(st);
- return error_code::success();
-}
-
-bool is_regular_file(file_status status) {
- return status.type() == file_type::regular_file;
-}
-
-error_code is_regular_file(const Twine &path, bool &result) {
- file_status st;
- if (error_code ec = status(path, st))
- return ec;
- result = is_regular_file(st);
- return error_code::success();
-}
-
-bool is_symlink(file_status status) {
- return status.type() == file_type::symlink_file;
-}
-
-error_code is_symlink(const Twine &path, bool &result) {
- file_status st;
- if (error_code ec = status(path, st))
- return ec;
- result = is_symlink(st);
- return error_code::success();
-}
-
-bool is_other(file_status status) {
- return exists(status) &&
- !is_regular_file(status) &&
- !is_directory(status) &&
- !is_symlink(status);
-}
-
-void directory_entry::replace_filename(const Twine &filename, file_status st) {
- SmallString<128> path(Path.begin(), Path.end());
- path::remove_filename(path);
- path::append(path, filename);
- Path = path.str();
- Status = st;
-}
-
-error_code has_magic(const Twine &path, const Twine &magic, bool &result) {
- SmallString<32> MagicStorage;
- StringRef Magic = magic.toStringRef(MagicStorage);
- SmallString<32> Buffer;
-
- if (error_code ec = get_magic(path, Magic.size(), Buffer)) {
- if (ec == errc::value_too_large) {
- // Magic.size() > file_size(Path).
- result = false;
- return error_code::success();
- }
- return ec;
- }
-
- result = Magic == Buffer;
- return error_code::success();
-}
-
-/// @brief Identify the magic in magic.
-file_magic identify_magic(StringRef magic) {
- if (magic.size() < 4)
- return file_magic::unknown;
- switch ((unsigned char)magic[0]) {
- case 0xDE: // 0x0B17C0DE = BC wraper
- if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 &&
- magic[3] == (char)0x0B)
- return file_magic::bitcode;
- break;
- case 'B':
- if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE)
- return file_magic::bitcode;
- break;
- case '!':
- if (magic.size() >= 8)
- if (memcmp(magic.data(),"!<arch>\n",8) == 0)
- return file_magic::archive;
- break;
-
- case '\177':
- if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') {
- bool Data2MSB = magic[5] == 2;
- unsigned high = Data2MSB ? 16 : 17;
- unsigned low = Data2MSB ? 17 : 16;
- if (magic.size() >= 18 && magic[high] == 0)
- switch (magic[low]) {
- default: break;
- case 1: return file_magic::elf_relocatable;
- case 2: return file_magic::elf_executable;
- case 3: return file_magic::elf_shared_object;
- case 4: return file_magic::elf_core;
- }
- }
- break;
-
- case 0xCA:
- if (magic[1] == char(0xFE) && magic[2] == char(0xBA) &&
- magic[3] == char(0xBE)) {
- // This is complicated by an overlap with Java class files.
- // See the Mach-O section in /usr/share/file/magic for details.
- if (magic.size() >= 8 && magic[7] < 43)
- // FIXME: Universal Binary of any type.
- return file_magic::macho_dynamically_linked_shared_lib;
- }
- break;
-
- // The two magic numbers for mach-o are:
- // 0xfeedface - 32-bit mach-o
- // 0xfeedfacf - 64-bit mach-o
- case 0xFE:
- case 0xCE:
- case 0xCF: {
- uint16_t type = 0;
- if (magic[0] == char(0xFE) && magic[1] == char(0xED) &&
- magic[2] == char(0xFA) &&
- (magic[3] == char(0xCE) || magic[3] == char(0xCF))) {
- /* Native endian */
- if (magic.size() >= 16) type = magic[14] << 8 | magic[15];
- } else if ((magic[0] == char(0xCE) || magic[0] == char(0xCF)) &&
- magic[1] == char(0xFA) && magic[2] == char(0xED) &&
- magic[3] == char(0xFE)) {
- /* Reverse endian */
- if (magic.size() >= 14) type = magic[13] << 8 | magic[12];
- }
- switch (type) {
- default: break;
- case 1: return file_magic::macho_object;
- case 2: return file_magic::macho_executable;
- case 3: return file_magic::macho_fixed_virtual_memory_shared_lib;
- case 4: return file_magic::macho_core;
- case 5: return file_magic::macho_preload_executabl;
- case 6: return file_magic::macho_dynamically_linked_shared_lib;
- case 7: return file_magic::macho_dynamic_linker;
- case 8: return file_magic::macho_bundle;
- case 9: return file_magic::macho_dynamic_linker;
- case 10: return file_magic::macho_dsym_companion;
- }
- break;
- }
- case 0xF0: // PowerPC Windows
- case 0x83: // Alpha 32-bit
- case 0x84: // Alpha 64-bit
- case 0x66: // MPS R4000 Windows
- case 0x50: // mc68K
- case 0x4c: // 80386 Windows
- if (magic[1] == 0x01)
- return file_magic::coff_object;
-
- case 0x90: // PA-RISC Windows
- case 0x68: // mc68K Windows
- if (magic[1] == 0x02)
- return file_magic::coff_object;
- break;
-
- case 0x4d: // Possible MS-DOS stub on Windows PE file
- if (magic[1] == 0x5a) {
- uint32_t off =
- *reinterpret_cast<const support::ulittle32_t*>(magic.data() + 0x3c);
- // PE/COFF file, either EXE or DLL.
- if (off < magic.size() && memcmp(magic.data() + off, "PE\0\0",4) == 0)
- return file_magic::pecoff_executable;
- }
- break;
-
- case 0x64: // x86-64 Windows.
- if (magic[1] == char(0x86))
- return file_magic::coff_object;
- break;
-
- default:
- break;
- }
- return file_magic::unknown;
-}
-
-error_code identify_magic(const Twine &path, file_magic &result) {
- SmallString<32> Magic;
- error_code ec = get_magic(path, Magic.capacity(), Magic);
- if (ec && ec != errc::value_too_large)
- return ec;
-
- result = identify_magic(Magic);
- return error_code::success();
-}
-
-namespace {
-error_code remove_all_r(StringRef path, file_type ft, uint32_t &count) {
- if (ft == file_type::directory_file) {
- // This code would be a lot better with exceptions ;/.
- error_code ec;
- directory_iterator i(path, ec);
- if (ec) return ec;
- for (directory_iterator e; i != e; i.increment(ec)) {
- if (ec) return ec;
- file_status st;
- if (error_code ec = i->status(st)) return ec;
- if (error_code ec = remove_all_r(i->path(), st.type(), count)) return ec;
- }
- bool obviously_this_exists;
- if (error_code ec = remove(path, obviously_this_exists)) return ec;
- assert(obviously_this_exists);
- ++count; // Include the directory itself in the items removed.
- } else {
- bool obviously_this_exists;
- if (error_code ec = remove(path, obviously_this_exists)) return ec;
- assert(obviously_this_exists);
- ++count;
- }
-
- return error_code::success();
-}
-} // end unnamed namespace
-
-error_code remove_all(const Twine &path, uint32_t &num_removed) {
- SmallString<128> path_storage;
- StringRef p = path.toStringRef(path_storage);
-
- file_status fs;
- if (error_code ec = status(path, fs))
- return ec;
- num_removed = 0;
- return remove_all_r(p, fs.type(), num_removed);
-}
-
-error_code directory_entry::status(file_status &result) const {
- return fs::status(Path, result);
-}
-
-} // end namespace fs
-} // end namespace sys
-} // end namespace llvm
-
-// Include the truly platform-specific parts.
-#if defined(LLVM_ON_UNIX)
-#include "Unix/PathV2.inc"
-#endif
-#if defined(LLVM_ON_WIN32)
-#include "Windows/PathV2.inc"
-#endif
diff --git a/contrib/llvm/lib/Support/PrettyStackTrace.cpp b/contrib/llvm/lib/Support/PrettyStackTrace.cpp
index 23ee5ab..722f4ca 100644
--- a/contrib/llvm/lib/Support/PrettyStackTrace.cpp
+++ b/contrib/llvm/lib/Support/PrettyStackTrace.cpp
@@ -15,10 +15,12 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h" // Get autoconf configuration settings
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/ThreadLocal.h"
#include "llvm/Support/Watchdog.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm-c/Core.h"
#ifdef HAVE_CRASHREPORTERCLIENT_H
#include <CrashReporterClient.h>
@@ -26,12 +28,7 @@
using namespace llvm;
-namespace llvm {
- bool DisablePrettyStackTrace = false;
-}
-
-// FIXME: This should be thread local when llvm supports threads.
-static sys::ThreadLocal<const PrettyStackTraceEntry> PrettyStackTraceHead;
+static ManagedStatic<sys::ThreadLocal<const PrettyStackTraceEntry> > PrettyStackTraceHead;
static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){
unsigned NextID = 0;
@@ -49,12 +46,12 @@ static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){
/// PrintCurStackTrace - Print the current stack trace to the specified stream.
static void PrintCurStackTrace(raw_ostream &OS) {
// Don't print an empty trace.
- if (PrettyStackTraceHead.get() == 0) return;
+ if (PrettyStackTraceHead->get() == 0) return;
// If there are pretty stack frames registered, walk and emit them.
OS << "Stack dump:\n";
- PrintStack(PrettyStackTraceHead.get(), OS);
+ PrintStack(PrettyStackTraceHead->get(), OS);
OS.flush();
}
@@ -102,26 +99,28 @@ static void CrashHandler(void *) {
#endif
}
-static bool RegisterCrashPrinter() {
- if (!DisablePrettyStackTrace)
- sys::AddSignalHandler(CrashHandler, 0);
- return false;
-}
-
PrettyStackTraceEntry::PrettyStackTraceEntry() {
- // The first time this is called, we register the crash printer.
- static bool HandlerRegistered = RegisterCrashPrinter();
- (void)HandlerRegistered;
-
// Link ourselves.
- NextEntry = PrettyStackTraceHead.get();
- PrettyStackTraceHead.set(this);
+ NextEntry = PrettyStackTraceHead->get();
+ PrettyStackTraceHead->set(this);
}
PrettyStackTraceEntry::~PrettyStackTraceEntry() {
- assert(PrettyStackTraceHead.get() == this &&
+ // Do nothing if PrettyStackTraceHead is uninitialized. This can only happen
+ // if a shutdown occurred after we created the PrettyStackTraceEntry. That
+ // does occur in the following idiom:
+ //
+ // PrettyStackTraceProgram X(...);
+ // llvm_shutdown_obj Y;
+ //
+ // Without this check, we may end up removing ourselves from the stack trace
+ // after PrettyStackTraceHead has already been destroyed.
+ if (!PrettyStackTraceHead.isConstructed())
+ return;
+
+ assert(PrettyStackTraceHead->get() == this &&
"Pretty stack trace entry destruction is out of order");
- PrettyStackTraceHead.set(getNextEntry());
+ PrettyStackTraceHead->set(getNextEntry());
}
void PrettyStackTraceString::print(raw_ostream &OS) const {
@@ -135,3 +134,18 @@ void PrettyStackTraceProgram::print(raw_ostream &OS) const {
OS << ArgV[i] << ' ';
OS << '\n';
}
+
+static bool RegisterCrashPrinter() {
+ sys::AddSignalHandler(CrashHandler, 0);
+ return false;
+}
+
+void llvm::EnablePrettyStackTrace() {
+ // The first time this is called, we register the crash printer.
+ static bool HandlerRegistered = RegisterCrashPrinter();
+ (void)HandlerRegistered;
+}
+
+void LLVMEnablePrettyStackTrace() {
+ EnablePrettyStackTrace();
+}
diff --git a/contrib/llvm/lib/Support/Process.cpp b/contrib/llvm/lib/Support/Process.cpp
index 2c0d37b..d5168f0 100644
--- a/contrib/llvm/lib/Support/Process.cpp
+++ b/contrib/llvm/lib/Support/Process.cpp
@@ -80,6 +80,24 @@ TimeValue self_process::get_wall_time() const {
#endif
+#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
+
+#define ALLCOLORS(FGBG,BOLD) {\
+ COLOR(FGBG, "0", BOLD),\
+ COLOR(FGBG, "1", BOLD),\
+ COLOR(FGBG, "2", BOLD),\
+ COLOR(FGBG, "3", BOLD),\
+ COLOR(FGBG, "4", BOLD),\
+ COLOR(FGBG, "5", BOLD),\
+ COLOR(FGBG, "6", BOLD),\
+ COLOR(FGBG, "7", BOLD)\
+ }
+
+static const char colorcodes[2][2][8][10] = {
+ { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
+ { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
+};
+
// Include the platform-specific parts of this class.
#ifdef LLVM_ON_UNIX
#include "Unix/Process.inc"
diff --git a/contrib/llvm/lib/Support/Program.cpp b/contrib/llvm/lib/Support/Program.cpp
index 201d5c0..83f2ec4 100644
--- a/contrib/llvm/lib/Support/Program.cpp
+++ b/contrib/llvm/lib/Support/Program.cpp
@@ -22,33 +22,40 @@ using namespace sys;
//=== independent code.
//===----------------------------------------------------------------------===//
-int
-Program::ExecuteAndWait(const Path& path,
- const char** args,
- const char** envp,
- const Path** redirects,
- unsigned secondsToWait,
- unsigned memoryLimit,
- std::string* ErrMsg,
+static bool Execute(ProcessInfo &PI, StringRef Program, const char **args,
+ const char **env, const StringRef **Redirects,
+ unsigned memoryLimit, std::string *ErrMsg);
+
+int sys::ExecuteAndWait(StringRef Program, const char **args, const char **envp,
+ const StringRef **redirects, unsigned secondsToWait,
+ unsigned memoryLimit, std::string *ErrMsg,
bool *ExecutionFailed) {
- Program prg;
- if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) {
- if (ExecutionFailed) *ExecutionFailed = false;
- return prg.Wait(path, secondsToWait, ErrMsg);
+ ProcessInfo PI;
+ if (Execute(PI, Program, args, envp, redirects, memoryLimit, ErrMsg)) {
+ if (ExecutionFailed)
+ *ExecutionFailed = false;
+ ProcessInfo Result = Wait(PI, secondsToWait, true, ErrMsg);
+ return Result.ReturnCode;
}
- if (ExecutionFailed) *ExecutionFailed = true;
+
+ if (ExecutionFailed)
+ *ExecutionFailed = true;
+
return -1;
}
-void
-Program::ExecuteNoWait(const Path& path,
- const char** args,
- const char** envp,
- const Path** redirects,
- unsigned memoryLimit,
- std::string* ErrMsg) {
- Program prg;
- prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg);
+ProcessInfo sys::ExecuteNoWait(StringRef Program, const char **args,
+ const char **envp, const StringRef **redirects,
+ unsigned memoryLimit, std::string *ErrMsg,
+ bool *ExecutionFailed) {
+ ProcessInfo PI;
+ if (ExecutionFailed)
+ *ExecutionFailed = false;
+ if (!Execute(PI, Program, args, envp, redirects, memoryLimit, ErrMsg))
+ if (ExecutionFailed)
+ *ExecutionFailed = true;
+
+ return PI;
}
// Include the platform-specific parts of this class.
diff --git a/contrib/llvm/lib/Support/Regex.cpp b/contrib/llvm/lib/Support/Regex.cpp
index efc8b90..5413641 100644
--- a/contrib/llvm/lib/Support/Regex.cpp
+++ b/contrib/llvm/lib/Support/Regex.cpp
@@ -43,7 +43,7 @@ bool Regex::isValid(std::string &Error) {
size_t len = llvm_regerror(error, preg, NULL, 0);
- Error.resize(len);
+ Error.resize(len - 1);
llvm_regerror(error, preg, &Error[0], len);
return false;
}
@@ -168,3 +168,10 @@ std::string Regex::sub(StringRef Repl, StringRef String,
return Res;
}
+
+bool Regex::isLiteralERE(StringRef Str) {
+ // Check for regex metacharacters. This list was derived from our regex
+ // implementation in regcomp.c and double checked against the POSIX extended
+ // regular expression specification.
+ return Str.find_first_of("()^$|*+?.[]\\{}") == StringRef::npos;
+}
diff --git a/contrib/llvm/lib/Support/SmallPtrSet.cpp b/contrib/llvm/lib/Support/SmallPtrSet.cpp
index f0fed77..dd417b4 100644
--- a/contrib/llvm/lib/Support/SmallPtrSet.cpp
+++ b/contrib/llvm/lib/Support/SmallPtrSet.cpp
@@ -202,8 +202,13 @@ void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) {
} else if (CurArraySize != RHS.CurArraySize) {
if (isSmall())
CurArray = (const void**)malloc(sizeof(void*) * RHS.CurArraySize);
- else
- CurArray = (const void**)realloc(CurArray, sizeof(void*)*RHS.CurArraySize);
+ else {
+ const void **T = (const void**)realloc(CurArray,
+ sizeof(void*) * RHS.CurArraySize);
+ if (!T)
+ free(CurArray);
+ CurArray = T;
+ }
assert(CurArray && "Failed to allocate memory?");
}
diff --git a/contrib/llvm/lib/Support/SourceMgr.cpp b/contrib/llvm/lib/Support/SourceMgr.cpp
index fac3cad..d4b94f8 100644
--- a/contrib/llvm/lib/Support/SourceMgr.cpp
+++ b/contrib/llvm/lib/Support/SourceMgr.cpp
@@ -52,9 +52,9 @@ SourceMgr::~SourceMgr() {
/// AddIncludeFile - Search for a file with the specified name in the current
/// directory or in one of the IncludeDirs. If no file is found, this returns
/// ~0, otherwise it returns the buffer ID of the stacked file.
-unsigned SourceMgr::AddIncludeFile(const std::string &Filename,
- SMLoc IncludeLoc,
- std::string &IncludedFile) {
+size_t SourceMgr::AddIncludeFile(const std::string &Filename,
+ SMLoc IncludeLoc,
+ std::string &IncludedFile) {
OwningPtr<MemoryBuffer> NewBuf;
IncludedFile = Filename;
MemoryBuffer::getFile(IncludedFile.c_str(), NewBuf);
@@ -65,7 +65,7 @@ unsigned SourceMgr::AddIncludeFile(const std::string &Filename,
MemoryBuffer::getFile(IncludedFile.c_str(), NewBuf);
}
- if (NewBuf == 0) return ~0U;
+ if (!NewBuf) return ~0U;
return AddNewSourceBuffer(NewBuf.take(), IncludeLoc);
}
@@ -211,7 +211,8 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
LineStr, ColRanges, FixIts);
}
-void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
+void SourceMgr::PrintMessage(raw_ostream &OS, SMLoc Loc,
+ SourceMgr::DiagKind Kind,
const Twine &Msg, ArrayRef<SMRange> Ranges,
ArrayRef<SMFixIt> FixIts, bool ShowColors) const {
SMDiagnostic Diagnostic = GetMessage(Loc, Kind, Msg, Ranges, FixIts);
@@ -222,8 +223,6 @@ void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
return;
}
- raw_ostream &OS = errs();
-
if (Loc != SMLoc()) {
int CurBuf = FindBufferContainingLoc(Loc);
assert(CurBuf != -1 && "Invalid or unspecified location!");
@@ -233,6 +232,12 @@ void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
Diagnostic.print(0, OS, ShowColors);
}
+void SourceMgr::PrintMessage(SMLoc Loc, SourceMgr::DiagKind Kind,
+ const Twine &Msg, ArrayRef<SMRange> Ranges,
+ ArrayRef<SMFixIt> FixIts, bool ShowColors) const {
+ PrintMessage(llvm::errs(), Loc, Kind, Msg, Ranges, FixIts, ShowColors);
+}
+
//===----------------------------------------------------------------------===//
// SMDiagnostic Implementation
//===----------------------------------------------------------------------===//
@@ -465,7 +470,7 @@ void SMDiagnostic::print(const char *ProgName, raw_ostream &S,
if (FixItInsertionLine.empty())
return;
- for (size_t i = 0, e = FixItInsertionLine.size(), OutCol = 0; i != e; ++i) {
+ for (size_t i = 0, e = FixItInsertionLine.size(), OutCol = 0; i < e; ++i) {
if (i >= LineContents.size() || LineContents[i] != '\t') {
S << FixItInsertionLine[i];
++OutCol;
diff --git a/contrib/llvm/lib/Support/StreamableMemoryObject.cpp b/contrib/llvm/lib/Support/StreamableMemoryObject.cpp
index 59e27a2..2ed7c5c 100644
--- a/contrib/llvm/lib/Support/StreamableMemoryObject.cpp
+++ b/contrib/llvm/lib/Support/StreamableMemoryObject.cpp
@@ -31,8 +31,7 @@ public:
virtual int readByte(uint64_t address, uint8_t* ptr) const LLVM_OVERRIDE;
virtual int readBytes(uint64_t address,
uint64_t size,
- uint8_t* buf,
- uint64_t* copied) const LLVM_OVERRIDE;
+ uint8_t *buf) const LLVM_OVERRIDE;
virtual const uint8_t *getPointer(uint64_t address,
uint64_t size) const LLVM_OVERRIDE;
virtual bool isValidAddress(uint64_t address) const LLVM_OVERRIDE {
@@ -67,11 +66,9 @@ int RawMemoryObject::readByte(uint64_t address, uint8_t* ptr) const {
int RawMemoryObject::readBytes(uint64_t address,
uint64_t size,
- uint8_t* buf,
- uint64_t* copied) const {
+ uint8_t *buf) const {
if (!validAddress(address) || !validAddress(address + size - 1)) return -1;
memcpy(buf, (uint8_t *)(uintptr_t)(address + FirstChar), size);
- if (copied) *copied = size;
return size;
}
@@ -111,11 +108,9 @@ int StreamingMemoryObject::readByte(uint64_t address, uint8_t* ptr) const {
int StreamingMemoryObject::readBytes(uint64_t address,
uint64_t size,
- uint8_t* buf,
- uint64_t* copied) const {
+ uint8_t *buf) const {
if (!fetchToPos(address + size - 1)) return -1;
memcpy(buf, &Bytes[address + BytesSkipped], size);
- if (copied) *copied = size;
return 0;
}
diff --git a/contrib/llvm/lib/Support/StringRef.cpp b/contrib/llvm/lib/Support/StringRef.cpp
index d7a0bfa..bfae754 100644
--- a/contrib/llvm/lib/Support/StringRef.cpp
+++ b/contrib/llvm/lib/Support/StringRef.cpp
@@ -37,20 +37,39 @@ static bool ascii_isdigit(char x) {
return x >= '0' && x <= '9';
}
-/// compare_lower - Compare strings, ignoring case.
-int StringRef::compare_lower(StringRef RHS) const {
- for (size_t I = 0, E = min(Length, RHS.Length); I != E; ++I) {
- unsigned char LHC = ascii_tolower(Data[I]);
- unsigned char RHC = ascii_tolower(RHS.Data[I]);
+// 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) {
+ for (size_t I = 0; I < Length; ++I) {
+ unsigned char LHC = ascii_tolower(LHS[I]);
+ unsigned char RHC = ascii_tolower(RHS[I]);
if (LHC != RHC)
return LHC < RHC ? -1 : 1;
}
+ return 0;
+}
+/// compare_lower - Compare strings, ignoring case.
+int StringRef::compare_lower(StringRef RHS) const {
+ if (int Res = ascii_strncasecmp(Data, RHS.Data, min(Length, RHS.Length)))
+ return Res;
if (Length == RHS.Length)
return 0;
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 {
+ 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 {
+ return Length >= Suffix.Length &&
+ ascii_strncasecmp(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0;
+}
+
/// compare_numeric - Compare strings, handle embedded numbers.
int StringRef::compare_numeric(StringRef RHS) const {
for (size_t I = 0, E = min(Length, RHS.Length); I != E; ++I) {
@@ -85,7 +104,7 @@ int StringRef::compare_numeric(StringRef RHS) const {
// Compute the edit distance between the two given strings.
unsigned StringRef::edit_distance(llvm::StringRef Other,
bool AllowReplacements,
- unsigned MaxEditDistance) {
+ unsigned MaxEditDistance) const {
return llvm::ComputeEditDistance(
llvm::ArrayRef<char>(data(), size()),
llvm::ArrayRef<char>(Other.data(), Other.size()),
diff --git a/contrib/llvm/lib/Support/StringRefMemoryObject.cpp b/contrib/llvm/lib/Support/StringRefMemoryObject.cpp
new file mode 100644
index 0000000..e035ed1
--- /dev/null
+++ b/contrib/llvm/lib/Support/StringRefMemoryObject.cpp
@@ -0,0 +1,29 @@
+//===- lib/Support/StringRefMemoryObject.cpp --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/StringRefMemoryObject.h"
+
+using namespace llvm;
+
+int StringRefMemoryObject::readByte(uint64_t Addr, uint8_t *Byte) const {
+ if (Addr >= Base + getExtent() || Addr < Base)
+ return -1;
+ *Byte = Bytes[Addr - Base];
+ return 0;
+}
+
+int StringRefMemoryObject::readBytes(uint64_t Addr,
+ uint64_t Size,
+ uint8_t *Buf) const {
+ uint64_t Offset = Addr - Base;
+ if (Addr >= Base + getExtent() || Offset + Size > getExtent() || Addr < Base)
+ return -1;
+ memcpy(Buf, Bytes.data() + Offset, Size);
+ return 0;
+}
diff --git a/contrib/llvm/lib/Support/SystemUtils.cpp b/contrib/llvm/lib/Support/SystemUtils.cpp
index 54b5e97..2036364 100644
--- a/contrib/llvm/lib/Support/SystemUtils.cpp
+++ b/contrib/llvm/lib/Support/SystemUtils.cpp
@@ -31,25 +31,3 @@ bool llvm::CheckBitcodeOutputToConsole(raw_ostream &stream_to_check,
}
return false;
}
-
-/// PrependMainExecutablePath - Prepend the path to the program being executed
-/// to \p ExeName, given the value of argv[0] and the address of main()
-/// itself. This allows us to find another LLVM tool if it is built in the same
-/// directory. An empty string is returned on error; note that this function
-/// just mainpulates the path and doesn't check for executability.
-/// @brief Find a named executable.
-sys::Path llvm::PrependMainExecutablePath(const std::string &ExeName,
- const char *Argv0, void *MainAddr) {
- // Check the directory that the calling program is in. We can do
- // this if ProgramPath contains at least one / character, indicating that it
- // is a relative path to the executable itself.
- sys::Path Result = sys::Path::GetMainExecutable(Argv0, MainAddr);
- Result.eraseComponent();
-
- if (!Result.isEmpty()) {
- Result.appendComponent(ExeName);
- Result.appendSuffix(sys::Path::GetEXESuffix());
- }
-
- return Result;
-}
diff --git a/contrib/llvm/lib/Support/TargetRegistry.cpp b/contrib/llvm/lib/Support/TargetRegistry.cpp
index 9c81327..0c90c17 100644
--- a/contrib/llvm/lib/Support/TargetRegistry.cpp
+++ b/contrib/llvm/lib/Support/TargetRegistry.cpp
@@ -135,9 +135,9 @@ const Target *TargetRegistry::getClosestTargetForJIT(std::string &Error) {
return TheTarget;
}
-static int TargetArraySortFn(const void *LHS, const void *RHS) {
- typedef std::pair<StringRef, const Target*> pair_ty;
- return ((const pair_ty*)LHS)->first.compare(((const pair_ty*)RHS)->first);
+static int TargetArraySortFn(const std::pair<StringRef, const Target *> *LHS,
+ const std::pair<StringRef, const Target *> *RHS) {
+ return LHS->first.compare(RHS->first);
}
void TargetRegistry::printRegisteredTargetsForVersion() {
diff --git a/contrib/llvm/lib/Support/ThreadLocal.cpp b/contrib/llvm/lib/Support/ThreadLocal.cpp
index 0587aae..868b6ea 100644
--- a/contrib/llvm/lib/Support/ThreadLocal.cpp
+++ b/contrib/llvm/lib/Support/ThreadLocal.cpp
@@ -23,7 +23,7 @@
// Define all methods as no-ops if threading is explicitly disabled
namespace llvm {
using namespace sys;
-ThreadLocalImpl::ThreadLocalImpl() { }
+ThreadLocalImpl::ThreadLocalImpl() : data() { }
ThreadLocalImpl::~ThreadLocalImpl() { }
void ThreadLocalImpl::setInstance(const void* d) {
typedef int SIZE_TOO_BIG[sizeof(d) <= sizeof(data) ? 1 : -1];
diff --git a/contrib/llvm/lib/Support/Timer.cpp b/contrib/llvm/lib/Support/Timer.cpp
index 896d869..100b21e 100644
--- a/contrib/llvm/lib/Support/Timer.cpp
+++ b/contrib/llvm/lib/Support/Timer.cpp
@@ -66,8 +66,8 @@ raw_ostream *llvm::CreateInfoOutputFile() {
// compensate for this, the test-suite Makefiles have code to delete the
// info output file before running commands which write to it.
std::string Error;
- raw_ostream *Result = new raw_fd_ostream(OutputFilename.c_str(),
- Error, raw_fd_ostream::F_Append);
+ raw_ostream *Result =
+ new raw_fd_ostream(OutputFilename.c_str(), Error, sys::fs::F_Append);
if (Error.empty())
return Result;
diff --git a/contrib/llvm/lib/Support/ToolOutputFile.cpp b/contrib/llvm/lib/Support/ToolOutputFile.cpp
index e7ca927..5c1268a 100644
--- a/contrib/llvm/lib/Support/ToolOutputFile.cpp
+++ b/contrib/llvm/lib/Support/ToolOutputFile.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"
using namespace llvm;
@@ -19,25 +20,30 @@ tool_output_file::CleanupInstaller::CleanupInstaller(const char *filename)
: Filename(filename), Keep(false) {
// Arrange for the file to be deleted if the process is killed.
if (Filename != "-")
- sys::RemoveFileOnSignal(sys::Path(Filename));
+ sys::RemoveFileOnSignal(Filename);
}
tool_output_file::CleanupInstaller::~CleanupInstaller() {
// Delete the file if the client hasn't told us not to.
- if (!Keep && Filename != "-")
- sys::Path(Filename).eraseFromDisk();
+ if (!Keep && Filename != "-") {
+ bool Existed;
+ sys::fs::remove(Filename, Existed);
+ }
// Ok, the file is successfully written and closed, or deleted. There's no
// further need to clean it up on signals.
if (Filename != "-")
- sys::DontRemoveFileOnSignal(sys::Path(Filename));
+ sys::DontRemoveFileOnSignal(Filename);
}
tool_output_file::tool_output_file(const char *filename, std::string &ErrorInfo,
- unsigned Flags)
- : Installer(filename),
- OS(filename, ErrorInfo, Flags) {
+ sys::fs::OpenFlags Flags)
+ : Installer(filename), OS(filename, ErrorInfo, Flags) {
// If open fails, no cleanup is needed.
if (!ErrorInfo.empty())
Installer.Keep = true;
}
+
+tool_output_file::tool_output_file(const char *Filename, int FD)
+ : Installer(Filename), OS(FD, true) {
+}
diff --git a/contrib/llvm/lib/Support/Triple.cpp b/contrib/llvm/lib/Support/Triple.cpp
index 412e34c..6c978a0 100644
--- a/contrib/llvm/lib/Support/Triple.cpp
+++ b/contrib/llvm/lib/Support/Triple.cpp
@@ -28,6 +28,7 @@ const char *Triple::getArchTypeName(ArchType Kind) {
case mips64el:return "mips64el";
case msp430: return "msp430";
case ppc64: return "powerpc64";
+ case ppc64le: return "powerpc64le";
case ppc: return "powerpc";
case r600: return "r600";
case sparc: return "sparc";
@@ -38,7 +39,6 @@ const char *Triple::getArchTypeName(ArchType Kind) {
case x86: return "i386";
case x86_64: return "x86_64";
case xcore: return "xcore";
- case mblaze: return "mblaze";
case nvptx: return "nvptx";
case nvptx64: return "nvptx64";
case le32: return "le32";
@@ -61,10 +61,9 @@ const char *Triple::getArchTypePrefix(ArchType Kind) {
case thumb: return "arm";
case ppc64:
+ case ppc64le:
case ppc: return "ppc";
- case mblaze: return "mblaze";
-
case mips:
case mipsel:
case mips64:
@@ -104,6 +103,7 @@ const char *Triple::getVendorTypeName(VendorType Kind) {
case BGQ: return "bgq";
case Freescale: return "fsl";
case IBM: return "ibm";
+ case NVIDIA: return "nvidia";
}
llvm_unreachable("Invalid VendorType!");
@@ -135,6 +135,8 @@ const char *Triple::getOSTypeName(OSType Kind) {
case CNK: return "cnk";
case Bitrig: return "bitrig";
case AIX: return "aix";
+ case CUDA: return "cuda";
+ case NVCL: return "nvcl";
}
llvm_unreachable("Invalid OSType");
@@ -168,7 +170,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) {
.Case("ppc64", ppc64)
.Case("ppc32", ppc)
.Case("ppc", ppc)
- .Case("mblaze", mblaze)
+ .Case("ppc64le", ppc64le)
.Case("r600", r600)
.Case("hexagon", hexagon)
.Case("sparc", sparc)
@@ -198,7 +200,7 @@ const char *Triple::getArchNameForAssembler() {
.Case("x86_64", "x86_64")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
- .Cases("mblaze", "microblaze", "mblaze")
+ .Case("powerpc64le", "ppc64le")
.Case("arm", "arm")
.Cases("armv4t", "thumbv4t", "armv4t")
.Cases("armv5", "armv5e", "thumbv5", "thumbv5e", "armv5")
@@ -219,10 +221,10 @@ static Triple::ArchType parseArch(StringRef ArchName) {
.Cases("i386", "i486", "i586", "i686", Triple::x86)
// FIXME: Do we need to support these?
.Cases("i786", "i886", "i986", Triple::x86)
- .Cases("amd64", "x86_64", Triple::x86_64)
+ .Cases("amd64", "x86_64", "x86_64h", Triple::x86_64)
.Case("powerpc", Triple::ppc)
.Cases("powerpc64", "ppu", Triple::ppc64)
- .Case("mblaze", Triple::mblaze)
+ .Case("powerpc64le", Triple::ppc64le)
.Case("aarch64", Triple::aarch64)
.Cases("arm", "xscale", Triple::arm)
// FIXME: It would be good to replace these with explicit names for all the
@@ -239,7 +241,7 @@ static Triple::ArchType parseArch(StringRef ArchName) {
.Case("hexagon", Triple::hexagon)
.Case("s390x", Triple::systemz)
.Case("sparc", Triple::sparc)
- .Case("sparcv9", Triple::sparcv9)
+ .Cases("sparcv9", "sparc64", Triple::sparcv9)
.Case("tce", Triple::tce)
.Case("xcore", Triple::xcore)
.Case("nvptx", Triple::nvptx)
@@ -260,6 +262,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) {
.Case("bgq", Triple::BGQ)
.Case("fsl", Triple::Freescale)
.Case("ibm", Triple::IBM)
+ .Case("nvidia", Triple::NVIDIA)
.Default(Triple::UnknownVendor);
}
@@ -287,6 +290,8 @@ static Triple::OSType parseOS(StringRef OSName) {
.StartsWith("cnk", Triple::CNK)
.StartsWith("bitrig", Triple::Bitrig)
.StartsWith("aix", Triple::AIX)
+ .StartsWith("cuda", Triple::CUDA)
+ .StartsWith("nvcl", Triple::NVCL)
.Default(Triple::UnknownOS);
}
@@ -672,7 +677,6 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) {
case llvm::Triple::arm:
case llvm::Triple::hexagon:
case llvm::Triple::le32:
- case llvm::Triple::mblaze:
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::nvptx:
@@ -691,6 +695,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) {
case llvm::Triple::mips64el:
case llvm::Triple::nvptx64:
case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
case llvm::Triple::sparcv9:
case llvm::Triple::systemz:
case llvm::Triple::x86_64:
@@ -719,6 +724,7 @@ Triple Triple::get32BitArchVariant() const {
case Triple::aarch64:
case Triple::msp430:
case Triple::systemz:
+ case Triple::ppc64le:
T.setArch(UnknownArch);
break;
@@ -727,7 +733,6 @@ Triple Triple::get32BitArchVariant() const {
case Triple::arm:
case Triple::hexagon:
case Triple::le32:
- case Triple::mblaze:
case Triple::mips:
case Triple::mipsel:
case Triple::nvptx:
@@ -760,7 +765,6 @@ Triple Triple::get64BitArchVariant() const {
case Triple::arm:
case Triple::hexagon:
case Triple::le32:
- case Triple::mblaze:
case Triple::msp430:
case Triple::r600:
case Triple::tce:
@@ -775,6 +779,7 @@ Triple Triple::get64BitArchVariant() const {
case Triple::mips64el:
case Triple::nvptx64:
case Triple::ppc64:
+ case Triple::ppc64le:
case Triple::sparcv9:
case Triple::systemz:
case Triple::x86_64:
diff --git a/contrib/llvm/lib/Support/Unicode.cpp b/contrib/llvm/lib/Support/Unicode.cpp
new file mode 100644
index 0000000..b719bd8
--- /dev/null
+++ b/contrib/llvm/lib/Support/Unicode.cpp
@@ -0,0 +1,367 @@
+//===- llvm/Support/Unicode.cpp - Unicode character properties -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements functions that allow querying certain properties of
+// Unicode characters.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Unicode.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/UnicodeCharRanges.h"
+
+namespace llvm {
+namespace sys {
+namespace unicode {
+
+bool isPrintable(int UCS) {
+ // Sorted list of non-overlapping intervals of code points that are not
+ // supposed to be printable.
+ static const UnicodeCharRange NonPrintableRanges[] = {
+ { 0x0000, 0x001F }, { 0x007F, 0x009F }, { 0x034F, 0x034F },
+ { 0x0378, 0x0379 }, { 0x037F, 0x0383 }, { 0x038B, 0x038B },
+ { 0x038D, 0x038D }, { 0x03A2, 0x03A2 }, { 0x0528, 0x0530 },
+ { 0x0557, 0x0558 }, { 0x0560, 0x0560 }, { 0x0588, 0x0588 },
+ { 0x058B, 0x058E }, { 0x0590, 0x0590 }, { 0x05C8, 0x05CF },
+ { 0x05EB, 0x05EF }, { 0x05F5, 0x0605 }, { 0x061C, 0x061D },
+ { 0x06DD, 0x06DD }, { 0x070E, 0x070F }, { 0x074B, 0x074C },
+ { 0x07B2, 0x07BF }, { 0x07FB, 0x07FF }, { 0x082E, 0x082F },
+ { 0x083F, 0x083F }, { 0x085C, 0x085D }, { 0x085F, 0x089F },
+ { 0x08A1, 0x08A1 }, { 0x08AD, 0x08E3 }, { 0x08FF, 0x08FF },
+ { 0x0978, 0x0978 }, { 0x0980, 0x0980 }, { 0x0984, 0x0984 },
+ { 0x098D, 0x098E }, { 0x0991, 0x0992 }, { 0x09A9, 0x09A9 },
+ { 0x09B1, 0x09B1 }, { 0x09B3, 0x09B5 }, { 0x09BA, 0x09BB },
+ { 0x09C5, 0x09C6 }, { 0x09C9, 0x09CA }, { 0x09CF, 0x09D6 },
+ { 0x09D8, 0x09DB }, { 0x09DE, 0x09DE }, { 0x09E4, 0x09E5 },
+ { 0x09FC, 0x0A00 }, { 0x0A04, 0x0A04 }, { 0x0A0B, 0x0A0E },
+ { 0x0A11, 0x0A12 }, { 0x0A29, 0x0A29 }, { 0x0A31, 0x0A31 },
+ { 0x0A34, 0x0A34 }, { 0x0A37, 0x0A37 }, { 0x0A3A, 0x0A3B },
+ { 0x0A3D, 0x0A3D }, { 0x0A43, 0x0A46 }, { 0x0A49, 0x0A4A },
+ { 0x0A4E, 0x0A50 }, { 0x0A52, 0x0A58 }, { 0x0A5D, 0x0A5D },
+ { 0x0A5F, 0x0A65 }, { 0x0A76, 0x0A80 }, { 0x0A84, 0x0A84 },
+ { 0x0A8E, 0x0A8E }, { 0x0A92, 0x0A92 }, { 0x0AA9, 0x0AA9 },
+ { 0x0AB1, 0x0AB1 }, { 0x0AB4, 0x0AB4 }, { 0x0ABA, 0x0ABB },
+ { 0x0AC6, 0x0AC6 }, { 0x0ACA, 0x0ACA }, { 0x0ACE, 0x0ACF },
+ { 0x0AD1, 0x0ADF }, { 0x0AE4, 0x0AE5 }, { 0x0AF2, 0x0B00 },
+ { 0x0B04, 0x0B04 }, { 0x0B0D, 0x0B0E }, { 0x0B11, 0x0B12 },
+ { 0x0B29, 0x0B29 }, { 0x0B31, 0x0B31 }, { 0x0B34, 0x0B34 },
+ { 0x0B3A, 0x0B3B }, { 0x0B45, 0x0B46 }, { 0x0B49, 0x0B4A },
+ { 0x0B4E, 0x0B55 }, { 0x0B58, 0x0B5B }, { 0x0B5E, 0x0B5E },
+ { 0x0B64, 0x0B65 }, { 0x0B78, 0x0B81 }, { 0x0B84, 0x0B84 },
+ { 0x0B8B, 0x0B8D }, { 0x0B91, 0x0B91 }, { 0x0B96, 0x0B98 },
+ { 0x0B9B, 0x0B9B }, { 0x0B9D, 0x0B9D }, { 0x0BA0, 0x0BA2 },
+ { 0x0BA5, 0x0BA7 }, { 0x0BAB, 0x0BAD }, { 0x0BBA, 0x0BBD },
+ { 0x0BC3, 0x0BC5 }, { 0x0BC9, 0x0BC9 }, { 0x0BCE, 0x0BCF },
+ { 0x0BD1, 0x0BD6 }, { 0x0BD8, 0x0BE5 }, { 0x0BFB, 0x0C00 },
+ { 0x0C04, 0x0C04 }, { 0x0C0D, 0x0C0D }, { 0x0C11, 0x0C11 },
+ { 0x0C29, 0x0C29 }, { 0x0C34, 0x0C34 }, { 0x0C3A, 0x0C3C },
+ { 0x0C45, 0x0C45 }, { 0x0C49, 0x0C49 }, { 0x0C4E, 0x0C54 },
+ { 0x0C57, 0x0C57 }, { 0x0C5A, 0x0C5F }, { 0x0C64, 0x0C65 },
+ { 0x0C70, 0x0C77 }, { 0x0C80, 0x0C81 }, { 0x0C84, 0x0C84 },
+ { 0x0C8D, 0x0C8D }, { 0x0C91, 0x0C91 }, { 0x0CA9, 0x0CA9 },
+ { 0x0CB4, 0x0CB4 }, { 0x0CBA, 0x0CBB }, { 0x0CC5, 0x0CC5 },
+ { 0x0CC9, 0x0CC9 }, { 0x0CCE, 0x0CD4 }, { 0x0CD7, 0x0CDD },
+ { 0x0CDF, 0x0CDF }, { 0x0CE4, 0x0CE5 }, { 0x0CF0, 0x0CF0 },
+ { 0x0CF3, 0x0D01 }, { 0x0D04, 0x0D04 }, { 0x0D0D, 0x0D0D },
+ { 0x0D11, 0x0D11 }, { 0x0D3B, 0x0D3C }, { 0x0D45, 0x0D45 },
+ { 0x0D49, 0x0D49 }, { 0x0D4F, 0x0D56 }, { 0x0D58, 0x0D5F },
+ { 0x0D64, 0x0D65 }, { 0x0D76, 0x0D78 }, { 0x0D80, 0x0D81 },
+ { 0x0D84, 0x0D84 }, { 0x0D97, 0x0D99 }, { 0x0DB2, 0x0DB2 },
+ { 0x0DBC, 0x0DBC }, { 0x0DBE, 0x0DBF }, { 0x0DC7, 0x0DC9 },
+ { 0x0DCB, 0x0DCE }, { 0x0DD5, 0x0DD5 }, { 0x0DD7, 0x0DD7 },
+ { 0x0DE0, 0x0DF1 }, { 0x0DF5, 0x0E00 }, { 0x0E3B, 0x0E3E },
+ { 0x0E5C, 0x0E80 }, { 0x0E83, 0x0E83 }, { 0x0E85, 0x0E86 },
+ { 0x0E89, 0x0E89 }, { 0x0E8B, 0x0E8C }, { 0x0E8E, 0x0E93 },
+ { 0x0E98, 0x0E98 }, { 0x0EA0, 0x0EA0 }, { 0x0EA4, 0x0EA4 },
+ { 0x0EA6, 0x0EA6 }, { 0x0EA8, 0x0EA9 }, { 0x0EAC, 0x0EAC },
+ { 0x0EBA, 0x0EBA }, { 0x0EBE, 0x0EBF }, { 0x0EC5, 0x0EC5 },
+ { 0x0EC7, 0x0EC7 }, { 0x0ECE, 0x0ECF }, { 0x0EDA, 0x0EDB },
+ { 0x0EE0, 0x0EFF }, { 0x0F48, 0x0F48 }, { 0x0F6D, 0x0F70 },
+ { 0x0F98, 0x0F98 }, { 0x0FBD, 0x0FBD }, { 0x0FCD, 0x0FCD },
+ { 0x0FDB, 0x0FFF }, { 0x10C6, 0x10C6 }, { 0x10C8, 0x10CC },
+ { 0x10CE, 0x10CF }, { 0x115F, 0x1160 }, { 0x1249, 0x1249 },
+ { 0x124E, 0x124F }, { 0x1257, 0x1257 }, { 0x1259, 0x1259 },
+ { 0x125E, 0x125F }, { 0x1289, 0x1289 }, { 0x128E, 0x128F },
+ { 0x12B1, 0x12B1 }, { 0x12B6, 0x12B7 }, { 0x12BF, 0x12BF },
+ { 0x12C1, 0x12C1 }, { 0x12C6, 0x12C7 }, { 0x12D7, 0x12D7 },
+ { 0x1311, 0x1311 }, { 0x1316, 0x1317 }, { 0x135B, 0x135C },
+ { 0x137D, 0x137F }, { 0x139A, 0x139F }, { 0x13F5, 0x13FF },
+ { 0x169D, 0x169F }, { 0x16F1, 0x16FF }, { 0x170D, 0x170D },
+ { 0x1715, 0x171F }, { 0x1737, 0x173F }, { 0x1754, 0x175F },
+ { 0x176D, 0x176D }, { 0x1771, 0x1771 }, { 0x1774, 0x177F },
+ { 0x17B4, 0x17B5 }, { 0x17DE, 0x17DF }, { 0x17EA, 0x17EF },
+ { 0x17FA, 0x17FF }, { 0x180B, 0x180D }, { 0x180F, 0x180F },
+ { 0x181A, 0x181F }, { 0x1878, 0x187F }, { 0x18AB, 0x18AF },
+ { 0x18F6, 0x18FF }, { 0x191D, 0x191F }, { 0x192C, 0x192F },
+ { 0x193C, 0x193F }, { 0x1941, 0x1943 }, { 0x196E, 0x196F },
+ { 0x1975, 0x197F }, { 0x19AC, 0x19AF }, { 0x19CA, 0x19CF },
+ { 0x19DB, 0x19DD }, { 0x1A1C, 0x1A1D }, { 0x1A5F, 0x1A5F },
+ { 0x1A7D, 0x1A7E }, { 0x1A8A, 0x1A8F }, { 0x1A9A, 0x1A9F },
+ { 0x1AAE, 0x1AFF }, { 0x1B4C, 0x1B4F }, { 0x1B7D, 0x1B7F },
+ { 0x1BF4, 0x1BFB }, { 0x1C38, 0x1C3A }, { 0x1C4A, 0x1C4C },
+ { 0x1C80, 0x1CBF }, { 0x1CC8, 0x1CCF }, { 0x1CF7, 0x1CFF },
+ { 0x1DE7, 0x1DFB }, { 0x1F16, 0x1F17 }, { 0x1F1E, 0x1F1F },
+ { 0x1F46, 0x1F47 }, { 0x1F4E, 0x1F4F }, { 0x1F58, 0x1F58 },
+ { 0x1F5A, 0x1F5A }, { 0x1F5C, 0x1F5C }, { 0x1F5E, 0x1F5E },
+ { 0x1F7E, 0x1F7F }, { 0x1FB5, 0x1FB5 }, { 0x1FC5, 0x1FC5 },
+ { 0x1FD4, 0x1FD5 }, { 0x1FDC, 0x1FDC }, { 0x1FF0, 0x1FF1 },
+ { 0x1FF5, 0x1FF5 }, { 0x1FFF, 0x1FFF }, { 0x200B, 0x200F },
+ { 0x202A, 0x202E }, { 0x2060, 0x206F }, { 0x2072, 0x2073 },
+ { 0x208F, 0x208F }, { 0x209D, 0x209F }, { 0x20BB, 0x20CF },
+ { 0x20F1, 0x20FF }, { 0x218A, 0x218F }, { 0x23F4, 0x23FF },
+ { 0x2427, 0x243F }, { 0x244B, 0x245F }, { 0x2700, 0x2700 },
+ { 0x2B4D, 0x2B4F }, { 0x2B5A, 0x2BFF }, { 0x2C2F, 0x2C2F },
+ { 0x2C5F, 0x2C5F }, { 0x2CF4, 0x2CF8 }, { 0x2D26, 0x2D26 },
+ { 0x2D28, 0x2D2C }, { 0x2D2E, 0x2D2F }, { 0x2D68, 0x2D6E },
+ { 0x2D71, 0x2D7E }, { 0x2D97, 0x2D9F }, { 0x2DA7, 0x2DA7 },
+ { 0x2DAF, 0x2DAF }, { 0x2DB7, 0x2DB7 }, { 0x2DBF, 0x2DBF },
+ { 0x2DC7, 0x2DC7 }, { 0x2DCF, 0x2DCF }, { 0x2DD7, 0x2DD7 },
+ { 0x2DDF, 0x2DDF }, { 0x2E3C, 0x2E7F }, { 0x2E9A, 0x2E9A },
+ { 0x2EF4, 0x2EFF }, { 0x2FD6, 0x2FEF }, { 0x2FFC, 0x2FFF },
+ { 0x3040, 0x3040 }, { 0x3097, 0x3098 }, { 0x3100, 0x3104 },
+ { 0x312E, 0x3130 }, { 0x3164, 0x3164 }, { 0x318F, 0x318F },
+ { 0x31BB, 0x31BF }, { 0x31E4, 0x31EF }, { 0x321F, 0x321F },
+ { 0x32FF, 0x32FF }, { 0x4DB6, 0x4DBF }, { 0x9FCD, 0x9FFF },
+ { 0xA48D, 0xA48F }, { 0xA4C7, 0xA4CF }, { 0xA62C, 0xA63F },
+ { 0xA698, 0xA69E }, { 0xA6F8, 0xA6FF }, { 0xA78F, 0xA78F },
+ { 0xA794, 0xA79F }, { 0xA7AB, 0xA7F7 }, { 0xA82C, 0xA82F },
+ { 0xA83A, 0xA83F }, { 0xA878, 0xA87F }, { 0xA8C5, 0xA8CD },
+ { 0xA8DA, 0xA8DF }, { 0xA8FC, 0xA8FF }, { 0xA954, 0xA95E },
+ { 0xA97D, 0xA97F }, { 0xA9CE, 0xA9CE }, { 0xA9DA, 0xA9DD },
+ { 0xA9E0, 0xA9FF }, { 0xAA37, 0xAA3F }, { 0xAA4E, 0xAA4F },
+ { 0xAA5A, 0xAA5B }, { 0xAA7C, 0xAA7F }, { 0xAAC3, 0xAADA },
+ { 0xAAF7, 0xAB00 }, { 0xAB07, 0xAB08 }, { 0xAB0F, 0xAB10 },
+ { 0xAB17, 0xAB1F }, { 0xAB27, 0xAB27 }, { 0xAB2F, 0xABBF },
+ { 0xABEE, 0xABEF }, { 0xABFA, 0xABFF }, { 0xD7A4, 0xD7AF },
+ { 0xD7C7, 0xD7CA }, { 0xD7FC, 0xDFFF }, { 0xFA6E, 0xFA6F },
+ { 0xFADA, 0xFAFF }, { 0xFB07, 0xFB12 }, { 0xFB18, 0xFB1C },
+ { 0xFB37, 0xFB37 }, { 0xFB3D, 0xFB3D }, { 0xFB3F, 0xFB3F },
+ { 0xFB42, 0xFB42 }, { 0xFB45, 0xFB45 }, { 0xFBC2, 0xFBD2 },
+ { 0xFD40, 0xFD4F }, { 0xFD90, 0xFD91 }, { 0xFDC8, 0xFDEF },
+ { 0xFDFE, 0xFE0F }, { 0xFE1A, 0xFE1F }, { 0xFE27, 0xFE2F },
+ { 0xFE53, 0xFE53 }, { 0xFE67, 0xFE67 }, { 0xFE6C, 0xFE6F },
+ { 0xFE75, 0xFE75 }, { 0xFEFD, 0xFEFF }, { 0xFF00, 0xFF00 },
+ { 0xFFA0, 0xFFA0 }, { 0xFFBF, 0xFFC1 }, { 0xFFC8, 0xFFC9 },
+ { 0xFFD0, 0xFFD1 }, { 0xFFD8, 0xFFD9 }, { 0xFFDD, 0xFFDF },
+ { 0xFFE7, 0xFFE7 }, { 0xFFEF, 0xFFFB }, { 0xFFFE, 0xFFFF },
+ { 0x1000C, 0x1000C }, { 0x10027, 0x10027 }, { 0x1003B, 0x1003B },
+ { 0x1003E, 0x1003E }, { 0x1004E, 0x1004F }, { 0x1005E, 0x1007F },
+ { 0x100FB, 0x100FF }, { 0x10103, 0x10106 }, { 0x10134, 0x10136 },
+ { 0x1018B, 0x1018F }, { 0x1019C, 0x101CF }, { 0x101FE, 0x1027F },
+ { 0x1029D, 0x1029F }, { 0x102D1, 0x102FF }, { 0x1031F, 0x1031F },
+ { 0x10324, 0x1032F }, { 0x1034B, 0x1037F }, { 0x1039E, 0x1039E },
+ { 0x103C4, 0x103C7 }, { 0x103D6, 0x103FF }, { 0x1049E, 0x1049F },
+ { 0x104AA, 0x107FF }, { 0x10806, 0x10807 }, { 0x10809, 0x10809 },
+ { 0x10836, 0x10836 }, { 0x10839, 0x1083B }, { 0x1083D, 0x1083E },
+ { 0x10856, 0x10856 }, { 0x10860, 0x108FF }, { 0x1091C, 0x1091E },
+ { 0x1093A, 0x1093E }, { 0x10940, 0x1097F }, { 0x109B8, 0x109BD },
+ { 0x109C0, 0x109FF }, { 0x10A04, 0x10A04 }, { 0x10A07, 0x10A0B },
+ { 0x10A14, 0x10A14 }, { 0x10A18, 0x10A18 }, { 0x10A34, 0x10A37 },
+ { 0x10A3B, 0x10A3E }, { 0x10A48, 0x10A4F }, { 0x10A59, 0x10A5F },
+ { 0x10A80, 0x10AFF }, { 0x10B36, 0x10B38 }, { 0x10B56, 0x10B57 },
+ { 0x10B73, 0x10B77 }, { 0x10B80, 0x10BFF }, { 0x10C49, 0x10E5F },
+ { 0x10E7F, 0x10FFF }, { 0x1104E, 0x11051 }, { 0x11070, 0x1107F },
+ { 0x110BD, 0x110BD }, { 0x110C2, 0x110CF }, { 0x110E9, 0x110EF },
+ { 0x110FA, 0x110FF }, { 0x11135, 0x11135 }, { 0x11144, 0x1117F },
+ { 0x111C9, 0x111CF }, { 0x111DA, 0x1167F }, { 0x116B8, 0x116BF },
+ { 0x116CA, 0x11FFF }, { 0x1236F, 0x123FF }, { 0x12463, 0x1246F },
+ { 0x12474, 0x12FFF }, { 0x1342F, 0x167FF }, { 0x16A39, 0x16EFF },
+ { 0x16F45, 0x16F4F }, { 0x16F7F, 0x16F8E }, { 0x16FA0, 0x1AFFF },
+ { 0x1B002, 0x1CFFF }, { 0x1D0F6, 0x1D0FF }, { 0x1D127, 0x1D128 },
+ { 0x1D173, 0x1D17A }, { 0x1D1DE, 0x1D1FF }, { 0x1D246, 0x1D2FF },
+ { 0x1D357, 0x1D35F }, { 0x1D372, 0x1D3FF }, { 0x1D455, 0x1D455 },
+ { 0x1D49D, 0x1D49D }, { 0x1D4A0, 0x1D4A1 }, { 0x1D4A3, 0x1D4A4 },
+ { 0x1D4A7, 0x1D4A8 }, { 0x1D4AD, 0x1D4AD }, { 0x1D4BA, 0x1D4BA },
+ { 0x1D4BC, 0x1D4BC }, { 0x1D4C4, 0x1D4C4 }, { 0x1D506, 0x1D506 },
+ { 0x1D50B, 0x1D50C }, { 0x1D515, 0x1D515 }, { 0x1D51D, 0x1D51D },
+ { 0x1D53A, 0x1D53A }, { 0x1D53F, 0x1D53F }, { 0x1D545, 0x1D545 },
+ { 0x1D547, 0x1D549 }, { 0x1D551, 0x1D551 }, { 0x1D6A6, 0x1D6A7 },
+ { 0x1D7CC, 0x1D7CD }, { 0x1D800, 0x1EDFF }, { 0x1EE04, 0x1EE04 },
+ { 0x1EE20, 0x1EE20 }, { 0x1EE23, 0x1EE23 }, { 0x1EE25, 0x1EE26 },
+ { 0x1EE28, 0x1EE28 }, { 0x1EE33, 0x1EE33 }, { 0x1EE38, 0x1EE38 },
+ { 0x1EE3A, 0x1EE3A }, { 0x1EE3C, 0x1EE41 }, { 0x1EE43, 0x1EE46 },
+ { 0x1EE48, 0x1EE48 }, { 0x1EE4A, 0x1EE4A }, { 0x1EE4C, 0x1EE4C },
+ { 0x1EE50, 0x1EE50 }, { 0x1EE53, 0x1EE53 }, { 0x1EE55, 0x1EE56 },
+ { 0x1EE58, 0x1EE58 }, { 0x1EE5A, 0x1EE5A }, { 0x1EE5C, 0x1EE5C },
+ { 0x1EE5E, 0x1EE5E }, { 0x1EE60, 0x1EE60 }, { 0x1EE63, 0x1EE63 },
+ { 0x1EE65, 0x1EE66 }, { 0x1EE6B, 0x1EE6B }, { 0x1EE73, 0x1EE73 },
+ { 0x1EE78, 0x1EE78 }, { 0x1EE7D, 0x1EE7D }, { 0x1EE7F, 0x1EE7F },
+ { 0x1EE8A, 0x1EE8A }, { 0x1EE9C, 0x1EEA0 }, { 0x1EEA4, 0x1EEA4 },
+ { 0x1EEAA, 0x1EEAA }, { 0x1EEBC, 0x1EEEF }, { 0x1EEF2, 0x1EFFF },
+ { 0x1F02C, 0x1F02F }, { 0x1F094, 0x1F09F }, { 0x1F0AF, 0x1F0B0 },
+ { 0x1F0BF, 0x1F0C0 }, { 0x1F0D0, 0x1F0D0 }, { 0x1F0E0, 0x1F0FF },
+ { 0x1F10B, 0x1F10F }, { 0x1F12F, 0x1F12F }, { 0x1F16C, 0x1F16F },
+ { 0x1F19B, 0x1F1E5 }, { 0x1F203, 0x1F20F }, { 0x1F23B, 0x1F23F },
+ { 0x1F249, 0x1F24F }, { 0x1F252, 0x1F2FF }, { 0x1F321, 0x1F32F },
+ { 0x1F336, 0x1F336 }, { 0x1F37D, 0x1F37F }, { 0x1F394, 0x1F39F },
+ { 0x1F3C5, 0x1F3C5 }, { 0x1F3CB, 0x1F3DF }, { 0x1F3F1, 0x1F3FF },
+ { 0x1F43F, 0x1F43F }, { 0x1F441, 0x1F441 }, { 0x1F4F8, 0x1F4F8 },
+ { 0x1F4FD, 0x1F4FF }, { 0x1F53E, 0x1F53F }, { 0x1F544, 0x1F54F },
+ { 0x1F568, 0x1F5FA }, { 0x1F641, 0x1F644 }, { 0x1F650, 0x1F67F },
+ { 0x1F6C6, 0x1F6FF }, { 0x1F774, 0x1FFFF }, { 0x2A6D7, 0x2A6FF },
+ { 0x2B735, 0x2B73F }, { 0x2B81E, 0x2F7FF }, { 0x2FA1E, 0xF0000 },
+ { 0xFFFFE, 0xFFFFF }, { 0x10FFFE, 0x10FFFF }
+ };
+ static const UnicodeCharSet NonPrintables(NonPrintableRanges);
+
+ return UCS >= 0 && UCS <= 0x10FFFF && !NonPrintables.contains(UCS);
+}
+
+/// Gets the number of positions a character is likely to occupy when output
+/// on a terminal ("character width"). This depends on the implementation of the
+/// terminal, and there's no standard definition of character width.
+/// The implementation defines it in a way that is expected to be compatible
+/// with a generic Unicode-capable terminal.
+/// \return Character width:
+/// * ErrorNonPrintableCharacter (-1) for non-printable characters (as
+/// identified by isPrintable);
+/// * 0 for non-spacing and enclosing combining marks;
+/// * 2 for CJK characters excluding halfwidth forms;
+/// * 1 for all remaining characters.
+static inline int charWidth(int UCS)
+{
+ if (!isPrintable(UCS))
+ return ErrorNonPrintableCharacter;
+
+ // Sorted list of non-spacing and enclosing combining mark intervals as
+ // defined in "3.6 Combination" of
+ // http://www.unicode.org/versions/Unicode6.2.0/UnicodeStandard-6.2.pdf
+ static const UnicodeCharRange CombiningCharacterRanges[] = {
+ { 0x0300, 0x036F }, { 0x0483, 0x0489 }, { 0x0591, 0x05BD },
+ { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 },
+ { 0x05C7, 0x05C7 }, { 0x0610, 0x061A }, { 0x064B, 0x065F },
+ { 0x0670, 0x0670 }, { 0x06D6, 0x06DC }, { 0x06DF, 0x06E4 },
+ { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x0711, 0x0711 },
+ { 0x0730, 0x074A }, { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 },
+ { 0x0816, 0x0819 }, { 0x081B, 0x0823 }, { 0x0825, 0x0827 },
+ { 0x0829, 0x082D }, { 0x0859, 0x085B }, { 0x08E4, 0x08FE },
+ { 0x0900, 0x0902 }, { 0x093A, 0x093A }, { 0x093C, 0x093C },
+ { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0957 },
+ { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC },
+ { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 },
+ { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 },
+ { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A51, 0x0A51 },
+ { 0x0A70, 0x0A71 }, { 0x0A75, 0x0A75 }, { 0x0A81, 0x0A82 },
+ { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 },
+ { 0x0ACD, 0x0ACD }, { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 },
+ { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B44 },
+ { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B62, 0x0B63 },
+ { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD },
+ { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D },
+ { 0x0C55, 0x0C56 }, { 0x0C62, 0x0C63 }, { 0x0CBC, 0x0CBC },
+ { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
+ { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D44 }, { 0x0D4D, 0x0D4D },
+ { 0x0D62, 0x0D63 }, { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 },
+ { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A },
+ { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 },
+ { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 },
+ { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 },
+ { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 },
+ { 0x0F8D, 0x0F97 }, { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 },
+ { 0x102D, 0x1030 }, { 0x1032, 0x1037 }, { 0x1039, 0x103A },
+ { 0x103D, 0x103E }, { 0x1058, 0x1059 }, { 0x105E, 0x1060 },
+ { 0x1071, 0x1074 }, { 0x1082, 0x1082 }, { 0x1085, 0x1086 },
+ { 0x108D, 0x108D }, { 0x109D, 0x109D }, { 0x135D, 0x135F },
+ { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
+ { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
+ { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
+ { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
+ { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
+ { 0x1A17, 0x1A18 }, { 0x1A56, 0x1A56 }, { 0x1A58, 0x1A5E },
+ { 0x1A60, 0x1A60 }, { 0x1A62, 0x1A62 }, { 0x1A65, 0x1A6C },
+ { 0x1A73, 0x1A7C }, { 0x1A7F, 0x1A7F }, { 0x1B00, 0x1B03 },
+ { 0x1B34, 0x1B34 }, { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C },
+ { 0x1B42, 0x1B42 }, { 0x1B6B, 0x1B73 }, { 0x1B80, 0x1B81 },
+ { 0x1BA2, 0x1BA5 }, { 0x1BA8, 0x1BA9 }, { 0x1BAB, 0x1BAB },
+ { 0x1BE6, 0x1BE6 }, { 0x1BE8, 0x1BE9 }, { 0x1BED, 0x1BED },
+ { 0x1BEF, 0x1BF1 }, { 0x1C2C, 0x1C33 }, { 0x1C36, 0x1C37 },
+ { 0x1CD0, 0x1CD2 }, { 0x1CD4, 0x1CE0 }, { 0x1CE2, 0x1CE8 },
+ { 0x1CED, 0x1CED }, { 0x1CF4, 0x1CF4 }, { 0x1DC0, 0x1DE6 },
+ { 0x1DFC, 0x1DFF }, { 0x20D0, 0x20F0 }, { 0x2CEF, 0x2CF1 },
+ { 0x2D7F, 0x2D7F }, { 0x2DE0, 0x2DFF }, { 0x302A, 0x302D },
+ { 0x3099, 0x309A }, { 0xA66F, 0xA672 }, { 0xA674, 0xA67D },
+ { 0xA69F, 0xA69F }, { 0xA6F0, 0xA6F1 }, { 0xA802, 0xA802 },
+ { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, { 0xA825, 0xA826 },
+ { 0xA8C4, 0xA8C4 }, { 0xA8E0, 0xA8F1 }, { 0xA926, 0xA92D },
+ { 0xA947, 0xA951 }, { 0xA980, 0xA982 }, { 0xA9B3, 0xA9B3 },
+ { 0xA9B6, 0xA9B9 }, { 0xA9BC, 0xA9BC }, { 0xAA29, 0xAA2E },
+ { 0xAA31, 0xAA32 }, { 0xAA35, 0xAA36 }, { 0xAA43, 0xAA43 },
+ { 0xAA4C, 0xAA4C }, { 0xAAB0, 0xAAB0 }, { 0xAAB2, 0xAAB4 },
+ { 0xAAB7, 0xAAB8 }, { 0xAABE, 0xAABF }, { 0xAAC1, 0xAAC1 },
+ { 0xAAEC, 0xAAED }, { 0xAAF6, 0xAAF6 }, { 0xABE5, 0xABE5 },
+ { 0xABE8, 0xABE8 }, { 0xABED, 0xABED }, { 0xFB1E, 0xFB1E },
+ { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE26 }, { 0x101FD, 0x101FD },
+ { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
+ { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x11001, 0x11001 },
+ { 0x11038, 0x11046 }, { 0x11080, 0x11081 }, { 0x110B3, 0x110B6 },
+ { 0x110B9, 0x110BA }, { 0x11100, 0x11102 }, { 0x11127, 0x1112B },
+ { 0x1112D, 0x11134 }, { 0x11180, 0x11181 }, { 0x111B6, 0x111BE },
+ { 0x116AB, 0x116AB }, { 0x116AD, 0x116AD }, { 0x116B0, 0x116B5 },
+ { 0x116B7, 0x116B7 }, { 0x16F8F, 0x16F92 }, { 0x1D167, 0x1D169 },
+ { 0x1D17B, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
+ { 0x1D242, 0x1D244 }, { 0xE0100, 0xE01EF },
+ };
+ static const UnicodeCharSet CombiningCharacters(CombiningCharacterRanges);
+
+ if (CombiningCharacters.contains(UCS))
+ return 0;
+
+ static const UnicodeCharRange DoubleWidthCharacterRanges[] = {
+ // Hangul Jamo
+ { 0x1100, 0x11FF },
+ // Deprecated fullwidth angle brackets
+ { 0x2329, 0x232A },
+ // CJK Misc, CJK Unified Ideographs, Yijing Hexagrams, Yi
+ // excluding U+303F (IDEOGRAPHIC HALF FILL SPACE)
+ { 0x2E80, 0x303E }, { 0x3040, 0xA4CF },
+ // Hangul
+ { 0xAC00, 0xD7A3 }, { 0xD7B0, 0xD7C6 }, { 0xD7CB, 0xD7FB },
+ // CJK Unified Ideographs
+ { 0xF900, 0xFAFF },
+ // Vertical forms
+ { 0xFE10, 0xFE19 },
+ // CJK Compatibility Forms + Small Form Variants
+ { 0xFE30, 0xFE6F },
+ // Fullwidth forms
+ { 0xFF01, 0xFF60 }, { 0xFFE0, 0xFFE6 },
+ // CJK Unified Ideographs
+ { 0x20000, 0x2A6DF }, { 0x2A700, 0x2B81F }, { 0x2F800, 0x2FA1F }
+ };
+ static const UnicodeCharSet DoubleWidthCharacters(DoubleWidthCharacterRanges);
+
+ if (DoubleWidthCharacters.contains(UCS))
+ return 2;
+ return 1;
+}
+
+int columnWidthUTF8(StringRef Text) {
+ unsigned ColumnWidth = 0;
+ unsigned Length;
+ for (size_t i = 0, e = Text.size(); i < e; i += Length) {
+ Length = getNumBytesForUTF8(Text[i]);
+ if (Length <= 0 || i + Length > Text.size())
+ return ErrorInvalidUTF8;
+ UTF32 buf[1];
+ const UTF8 *Start = reinterpret_cast<const UTF8 *>(Text.data() + i);
+ UTF32 *Target = &buf[0];
+ if (conversionOK != ConvertUTF8toUTF32(&Start, Start + Length, &Target,
+ Target + 1, strictConversion))
+ return ErrorInvalidUTF8;
+ int Width = charWidth(buf[0]);
+ if (Width < 0)
+ return ErrorNonPrintableCharacter;
+ ColumnWidth += Width;
+ }
+ return ColumnWidth;
+}
+
+} // namespace unicode
+} // namespace sys
+} // namespace llvm
+
diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc
index 2bb9bf1..dcfd76e 100644
--- a/contrib/llvm/lib/Support/Unix/Memory.inc
+++ b/contrib/llvm/lib/Support/Unix/Memory.inc
@@ -32,7 +32,11 @@
# endif
#endif
+#ifdef __APPLE__
extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
+#else
+extern "C" void __clear_cache(void *, void*);
+#endif
namespace {
@@ -267,6 +271,9 @@ bool Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) {
kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address,
(vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY);
return KERN_SUCCESS == kr;
+#elif defined(__arm__) || defined(__aarch64__)
+ Memory::InvalidateInstructionCache(M.Address, M.Size);
+ return true;
#else
return true;
#endif
diff --git a/contrib/llvm/lib/Support/Unix/Path.inc b/contrib/llvm/lib/Support/Unix/Path.inc
index 6a5ebb8..c9dc871 100644
--- a/contrib/llvm/lib/Support/Unix/Path.inc
+++ b/contrib/llvm/lib/Support/Unix/Path.inc
@@ -1,4 +1,4 @@
-//===- llvm/Support/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===//
+//===- llvm/Support/Unix/Path.inc - Unix Path Implementation ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the Unix specific portion of the Path class.
+// This file implements the Unix specific implementation of the Path API.
//
//===----------------------------------------------------------------------===//
@@ -17,6 +17,9 @@
//===----------------------------------------------------------------------===//
#include "Unix.h"
+#include "llvm/Support/Process.h"
+#include <limits.h>
+#include <stdio.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
@@ -26,15 +29,6 @@
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#if HAVE_UTIME_H
-#include <utime.h>
-#endif
-#if HAVE_TIME_H
-#include <time.h>
-#endif
#if HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
@@ -52,217 +46,143 @@
# endif
#endif
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
+// Both stdio.h and cstdio are included via different pathes and
+// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros
+// either.
+#undef ferror
+#undef feof
+
// For GNU Hurd
-#if defined(__GNU__) && !defined(MAXPATHLEN)
-# define MAXPATHLEN 4096
+#if defined(__GNU__) && !defined(PATH_MAX)
+# define PATH_MAX 4096
#endif
-// Put in a hack for Cygwin which falsely reports that the mkdtemp function
-// is available when it is not.
-#ifdef __CYGWIN__
-# undef HAVE_MKDTEMP
-#endif
+using namespace llvm;
namespace {
-inline bool lastIsSlash(const std::string& path) {
- return !path.empty() && path[path.length() - 1] == '/';
-}
-
-}
+ /// This class automatically closes the given file descriptor when it goes out
+ /// of scope. You can take back explicit ownership of the file descriptor by
+ /// calling take(). The destructor does not verify that close was successful.
+ /// Therefore, never allow this class to call close on a file descriptor that
+ /// has been read from or written to.
+ struct AutoFD {
+ int FileDescriptor;
+
+ AutoFD(int fd) : FileDescriptor(fd) {}
+ ~AutoFD() {
+ if (FileDescriptor >= 0)
+ ::close(FileDescriptor);
+ }
-namespace llvm {
-using namespace sys;
+ int take() {
+ int ret = FileDescriptor;
+ FileDescriptor = -1;
+ return ret;
+ }
-const char sys::PathSeparator = ':';
+ operator int() const {return FileDescriptor;}
+ };
+
+ error_code TempDir(SmallVectorImpl<char> &result) {
+ // FIXME: Don't use TMPDIR if program is SUID or SGID enabled.
+ const char *dir = 0;
+ (dir = std::getenv("TMPDIR" )) ||
+ (dir = std::getenv("TMP" )) ||
+ (dir = std::getenv("TEMP" )) ||
+ (dir = std::getenv("TEMPDIR")) ||
+#ifdef P_tmpdir
+ (dir = P_tmpdir) ||
+#endif
+ (dir = "/tmp");
-StringRef Path::GetEXESuffix() {
- return StringRef();
+ result.clear();
+ StringRef d(dir);
+ result.append(d.begin(), d.end());
+ return error_code::success();
+ }
}
-Path::Path(StringRef p)
- : path(p) {}
-
-Path::Path(const char *StrStart, unsigned StrLen)
- : path(StrStart, StrLen) {}
-
-Path&
-Path::operator=(StringRef that) {
- path.assign(that.data(), that.size());
- return *this;
-}
+static error_code createUniqueEntity(const Twine &Model, int &ResultFD,
+ SmallVectorImpl<char> &ResultPath,
+ bool MakeAbsolute, unsigned Mode,
+ FSEntity Type) {
+ SmallString<128> ModelStorage;
+ Model.toVector(ModelStorage);
+
+ if (MakeAbsolute) {
+ // Make model absolute by prepending a temp directory if it's not already.
+ bool absolute = sys::path::is_absolute(Twine(ModelStorage));
+ if (!absolute) {
+ SmallString<128> TDir;
+ if (error_code ec = TempDir(TDir)) return ec;
+ sys::path::append(TDir, Twine(ModelStorage));
+ ModelStorage.swap(TDir);
+ }
+ }
-bool
-Path::isValid() const {
- // Empty paths are considered invalid here.
- // This code doesn't check MAXPATHLEN because there's no need. Nothing in
- // LLVM manipulates Paths with fixed-sizes arrays, and if the OS can't
- // handle names longer than some limit, it'll report this on demand using
- // ENAMETOLONG.
- return !path.empty();
-}
+ // From here on, DO NOT modify model. It may be needed if the randomly chosen
+ // path already exists.
+ ResultPath = ModelStorage;
+ // Null terminate.
+ ResultPath.push_back(0);
+ ResultPath.pop_back();
+
+retry_random_path:
+ // Replace '%' with random chars.
+ for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) {
+ if (ModelStorage[i] == '%')
+ ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15];
+ }
-bool
-Path::isAbsolute(const char *NameStart, unsigned NameLen) {
- assert(NameStart);
- if (NameLen == 0)
- return false;
- return NameStart[0] == '/';
-}
+ // Try to open + create the file.
+ switch (Type) {
+ case FS_File: {
+ int RandomFD = ::open(ResultPath.begin(), O_RDWR | O_CREAT | O_EXCL, Mode);
+ if (RandomFD == -1) {
+ int SavedErrno = errno;
+ // If the file existed, try again, otherwise, error.
+ if (SavedErrno == errc::file_exists)
+ goto retry_random_path;
+ return error_code(SavedErrno, system_category());
+ }
-bool
-Path::isAbsolute() const {
- if (path.empty())
- return false;
- return path[0] == '/';
-}
-
-Path
-Path::GetRootDirectory() {
- Path result;
- result.set("/");
- return result;
-}
-
-Path
-Path::GetTemporaryDirectory(std::string *ErrMsg) {
-#if defined(HAVE_MKDTEMP)
- // The best way is with mkdtemp but that's not available on many systems,
- // Linux and FreeBSD have it. Others probably won't.
- char pathname[] = "/tmp/llvm_XXXXXX";
- if (0 == mkdtemp(pathname)) {
- MakeErrMsg(ErrMsg,
- std::string(pathname) + ": can't create temporary directory");
- return Path();
- }
- return Path(pathname);
-#elif defined(HAVE_MKSTEMP)
- // If no mkdtemp is available, mkstemp can be used to create a temporary file
- // which is then removed and created as a directory. We prefer this over
- // mktemp because of mktemp's inherent security and threading risks. We still
- // have a slight race condition from the time the temporary file is created to
- // the time it is re-created as a directoy.
- char pathname[] = "/tmp/llvm_XXXXXX";
- int fd = 0;
- if (-1 == (fd = mkstemp(pathname))) {
- MakeErrMsg(ErrMsg,
- std::string(pathname) + ": can't create temporary directory");
- return Path();
- }
- ::close(fd);
- ::unlink(pathname); // start race condition, ignore errors
- if (-1 == ::mkdir(pathname, S_IRWXU)) { // end race condition
- MakeErrMsg(ErrMsg,
- std::string(pathname) + ": can't create temporary directory");
- return Path();
- }
- return Path(pathname);
-#elif defined(HAVE_MKTEMP)
- // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have
- // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable
- // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing
- // the XXXXXX with the pid of the process and a letter. That leads to only
- // twenty six temporary files that can be generated.
- char pathname[] = "/tmp/llvm_XXXXXX";
- char *TmpName = ::mktemp(pathname);
- if (TmpName == 0) {
- MakeErrMsg(ErrMsg,
- std::string(TmpName) + ": can't create unique directory name");
- return Path();
- }
- if (-1 == ::mkdir(TmpName, S_IRWXU)) {
- MakeErrMsg(ErrMsg,
- std::string(TmpName) + ": can't create temporary directory");
- return Path();
+ ResultFD = RandomFD;
+ return error_code::success();
}
- return Path(TmpName);
-#else
- // This is the worst case implementation. tempnam(3) leaks memory unless its
- // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread
- // issues. The mktemp(3) function doesn't have enough variability in the
- // temporary name generated. So, we provide our own implementation that
- // increments an integer from a random number seeded by the current time. This
- // should be sufficiently unique that we don't have many collisions between
- // processes. Generally LLVM processes don't run very long and don't use very
- // many temporary files so this shouldn't be a big issue for LLVM.
- static time_t num = ::time(0);
- char pathname[MAXPATHLEN];
- do {
- num++;
- sprintf(pathname, "/tmp/llvm_%010u", unsigned(num));
- } while ( 0 == access(pathname, F_OK ) );
- if (-1 == ::mkdir(pathname, S_IRWXU)) {
- MakeErrMsg(ErrMsg,
- std::string(pathname) + ": can't create temporary directory");
- return Path();
- }
- return Path(pathname);
-#endif
-}
-void
-Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
-#ifdef LTDL_SHLIBPATH_VAR
- char* env_var = getenv(LTDL_SHLIBPATH_VAR);
- if (env_var != 0) {
- getPathList(env_var,Paths);
- }
-#endif
- // FIXME: Should this look at LD_LIBRARY_PATH too?
- Paths.push_back(sys::Path("/usr/local/lib/"));
- Paths.push_back(sys::Path("/usr/X11R6/lib/"));
- Paths.push_back(sys::Path("/usr/lib/"));
- Paths.push_back(sys::Path("/lib/"));
-}
-
-void
-Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) {
- char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
- if (env_var != 0) {
- getPathList(env_var,Paths);
- }
-#ifdef LLVM_LIBDIR
- {
- Path tmpPath;
- if (tmpPath.set(LLVM_LIBDIR))
- if (tmpPath.canRead())
- Paths.push_back(tmpPath);
+ case FS_Name: {
+ bool Exists;
+ error_code EC = sys::fs::exists(ResultPath.begin(), Exists);
+ if (EC)
+ return EC;
+ if (Exists)
+ goto retry_random_path;
+ return error_code::success();
}
-#endif
- GetSystemLibraryPaths(Paths);
-}
-Path
-Path::GetUserHomeDirectory() {
- const char* home = getenv("HOME");
- Path result;
- if (home && result.set(home))
- return result;
- result.set("/");
- return result;
-}
-
-Path
-Path::GetCurrentDirectory() {
- char pathname[MAXPATHLEN];
- if (!getcwd(pathname, MAXPATHLEN)) {
- assert(false && "Could not query current working directory.");
- return Path();
+ case FS_Dir: {
+ bool Existed;
+ error_code EC = sys::fs::create_directory(ResultPath.begin(), Existed);
+ if (EC)
+ return EC;
+ if (Existed)
+ goto retry_random_path;
+ return error_code::success();
}
-
- return Path(pathname);
+ }
+ llvm_unreachable("Invalid Type");
}
+namespace llvm {
+namespace sys {
+namespace fs {
#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \
- defined(__linux__) || defined(__CYGWIN__)
+ defined(__linux__) || defined(__CYGWIN__) || defined(__DragonFly__)
static int
test_dir(char buf[PATH_MAX], char ret[PATH_MAX],
const char *dir, const char *bin)
@@ -318,7 +238,7 @@ getprogpath(char ret[PATH_MAX], const char *bin)
/// GetMainExecutable - Return the path to the main executable, given the
/// value of argv[0] from program startup.
-Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
+std::string getMainExecutable(const char *argv0, void *MainAddr) {
#if defined(__APPLE__)
// On OS X the executable path is saved to the stack by dyld. Reading it
// from there is much faster than calling dladdr, especially for large
@@ -328,14 +248,15 @@ Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
if (_NSGetExecutablePath(exe_path, &size) == 0) {
char link_path[MAXPATHLEN];
if (realpath(exe_path, link_path))
- return Path(link_path);
+ return link_path;
}
#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \
- defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__)
+ defined(__OpenBSD__) || defined(__minix) || defined(__DragonFly__) || \
+ defined(__FreeBSD_kernel__)
char exe_path[PATH_MAX];
if (getprogpath(exe_path, argv0) != NULL)
- return Path(exe_path);
+ return exe_path;
#elif defined(__linux__) || defined(__CYGWIN__)
char exe_path[MAXPATHLEN];
StringRef aPath("/proc/self/exe");
@@ -343,558 +264,534 @@ Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
// /proc is not always mounted under Linux (chroot for example).
ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path));
if (len >= 0)
- return Path(StringRef(exe_path, len));
+ return StringRef(exe_path, len);
} else {
// Fall back to the classical detection.
if (getprogpath(exe_path, argv0) != NULL)
- return Path(exe_path);
+ return exe_path;
}
#elif defined(HAVE_DLFCN_H)
// Use dladdr to get executable path if available.
Dl_info DLInfo;
int err = dladdr(MainAddr, &DLInfo);
if (err == 0)
- return Path();
+ return "";
// If the filename is a symlink, we need to resolve and return the location of
// the actual executable.
char link_path[MAXPATHLEN];
if (realpath(DLInfo.dli_fname, link_path))
- return Path(link_path);
+ return link_path;
#else
#error GetMainExecutable is not implemented on this host yet.
#endif
- return Path();
+ return "";
}
+TimeValue file_status::getLastModificationTime() const {
+ TimeValue Ret;
+ Ret.fromEpochTime(fs_st_mtime);
+ return Ret;
+}
-StringRef Path::getDirname() const {
- return getDirnameCharSep(path, "/");
+UniqueID file_status::getUniqueID() const {
+ return UniqueID(fs_st_dev, fs_st_ino);
}
-StringRef
-Path::getBasename() const {
- // Find the last slash
- std::string::size_type slash = path.rfind('/');
- if (slash == std::string::npos)
- slash = 0;
- else
- slash++;
+error_code current_path(SmallVectorImpl<char> &result) {
+ result.clear();
- std::string::size_type dot = path.rfind('.');
- if (dot == std::string::npos || dot < slash)
- return StringRef(path).substr(slash);
- else
- return StringRef(path).substr(slash, dot - slash);
-}
+ const char *pwd = ::getenv("PWD");
+ llvm::sys::fs::file_status PWDStatus, DotStatus;
+ if (pwd && llvm::sys::path::is_absolute(pwd) &&
+ !llvm::sys::fs::status(pwd, PWDStatus) &&
+ !llvm::sys::fs::status(".", DotStatus) &&
+ PWDStatus.getUniqueID() == DotStatus.getUniqueID()) {
+ result.append(pwd, pwd + strlen(pwd));
+ return error_code::success();
+ }
-StringRef
-Path::getSuffix() const {
- // Find the last slash
- std::string::size_type slash = path.rfind('/');
- if (slash == std::string::npos)
- slash = 0;
- else
- slash++;
+#ifdef MAXPATHLEN
+ result.reserve(MAXPATHLEN);
+#else
+// For GNU Hurd
+ result.reserve(1024);
+#endif
- std::string::size_type dot = path.rfind('.');
- if (dot == std::string::npos || dot < slash)
- return StringRef();
- else
- return StringRef(path).substr(dot + 1);
-}
+ while (true) {
+ if (::getcwd(result.data(), result.capacity()) == 0) {
+ // See if there was a real error.
+ if (errno != errc::not_enough_memory)
+ return error_code(errno, system_category());
+ // Otherwise there just wasn't enough space.
+ result.reserve(result.capacity() * 2);
+ } else
+ break;
+ }
-bool Path::getMagicNumber(std::string &Magic, unsigned len) const {
- assert(len < 1024 && "Request for magic string too long");
- char Buf[1025];
- int fd = ::open(path.c_str(), O_RDONLY);
- if (fd < 0)
- return false;
- ssize_t bytes_read = ::read(fd, Buf, len);
- ::close(fd);
- if (ssize_t(len) != bytes_read)
- return false;
- Magic.assign(Buf, len);
- return true;
+ result.set_size(strlen(result.data()));
+ return error_code::success();
}
-bool
-Path::exists() const {
- return 0 == access(path.c_str(), F_OK );
-}
+error_code create_directory(const Twine &path, bool &existed) {
+ SmallString<128> path_storage;
+ StringRef p = path.toNullTerminatedStringRef(path_storage);
-bool
-Path::isDirectory() const {
- struct stat buf;
- if (0 != stat(path.c_str(), &buf))
- return false;
- return ((buf.st_mode & S_IFMT) == S_IFDIR) ? true : false;
-}
+ if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) {
+ if (errno != errc::file_exists)
+ return error_code(errno, system_category());
+ existed = true;
+ } else
+ existed = false;
-bool
-Path::isSymLink() const {
- struct stat buf;
- if (0 != lstat(path.c_str(), &buf))
- return false;
- return S_ISLNK(buf.st_mode);
+ return error_code::success();
}
+error_code create_hard_link(const Twine &to, const Twine &from) {
+ // Get arguments.
+ SmallString<128> from_storage;
+ SmallString<128> to_storage;
+ StringRef f = from.toNullTerminatedStringRef(from_storage);
+ StringRef t = to.toNullTerminatedStringRef(to_storage);
-bool
-Path::canRead() const {
- return 0 == access(path.c_str(), R_OK);
-}
+ if (::link(t.begin(), f.begin()) == -1)
+ return error_code(errno, system_category());
-bool
-Path::canWrite() const {
- return 0 == access(path.c_str(), W_OK);
+ return error_code::success();
}
-bool
-Path::isRegularFile() const {
- // Get the status so we can determine if it's a file or directory
- struct stat buf;
-
- if (0 != stat(path.c_str(), &buf))
- return false;
+error_code create_symlink(const Twine &to, const Twine &from) {
+ // Get arguments.
+ SmallString<128> from_storage;
+ SmallString<128> to_storage;
+ StringRef f = from.toNullTerminatedStringRef(from_storage);
+ StringRef t = to.toNullTerminatedStringRef(to_storage);
- if (S_ISREG(buf.st_mode))
- return true;
+ if (::symlink(t.begin(), f.begin()) == -1)
+ return error_code(errno, system_category());
- return false;
+ return error_code::success();
}
-bool
-Path::canExecute() const {
- if (0 != access(path.c_str(), R_OK | X_OK ))
- return false;
+error_code remove(const Twine &path, bool &existed) {
+ SmallString<128> path_storage;
+ StringRef p = path.toNullTerminatedStringRef(path_storage);
+
struct stat buf;
- if (0 != stat(path.c_str(), &buf))
- return false;
- if (!S_ISREG(buf.st_mode))
- return false;
- return true;
-}
+ if (stat(p.begin(), &buf) != 0) {
+ if (errno != errc::no_such_file_or_directory)
+ return error_code(errno, system_category());
+ existed = false;
+ return error_code::success();
+ }
-StringRef
-Path::getLast() const {
- // Find the last slash
- size_t pos = path.rfind('/');
+ // Note: this check catches strange situations. In all cases, LLVM should
+ // only be involved in the creation and deletion of regular files. This
+ // check ensures that what we're trying to erase is a regular file. It
+ // effectively prevents LLVM from erasing things like /dev/null, any block
+ // special file, or other things that aren't "regular" files.
+ if (!S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode))
+ return make_error_code(errc::operation_not_permitted);
- // Handle the corner cases
- if (pos == std::string::npos)
- return path;
+ if (::remove(p.begin()) == -1) {
+ if (errno != errc::no_such_file_or_directory)
+ return error_code(errno, system_category());
+ existed = false;
+ } else
+ existed = true;
- // If the last character is a slash
- if (pos == path.length()-1) {
- // Find the second to last slash
- size_t pos2 = path.rfind('/', pos-1);
- if (pos2 == std::string::npos)
- return StringRef(path).substr(0,pos);
- else
- return StringRef(path).substr(pos2+1,pos-pos2-1);
- }
- // Return everything after the last slash
- return StringRef(path).substr(pos+1);
+ return error_code::success();
}
-const FileStatus *
-PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
- if (!fsIsValid || update) {
- struct stat buf;
- if (0 != stat(path.c_str(), &buf)) {
- MakeErrMsg(ErrStr, path + ": can't get status of file");
- return 0;
- }
- status.fileSize = buf.st_size;
- status.modTime.fromEpochTime(buf.st_mtime);
- status.mode = buf.st_mode;
- status.user = buf.st_uid;
- status.group = buf.st_gid;
- status.uniqueID = uint64_t(buf.st_ino);
- status.isDir = S_ISDIR(buf.st_mode);
- status.isFile = S_ISREG(buf.st_mode);
- fsIsValid = true;
- }
- return &status;
-}
+error_code rename(const Twine &from, const Twine &to) {
+ // Get arguments.
+ SmallString<128> from_storage;
+ SmallString<128> to_storage;
+ StringRef f = from.toNullTerminatedStringRef(from_storage);
+ StringRef t = to.toNullTerminatedStringRef(to_storage);
-static bool AddPermissionBits(const Path &File, int bits) {
- // Get the umask value from the operating system. We want to use it
- // when changing the file's permissions. Since calling umask() sets
- // the umask and returns its old value, we must call it a second
- // time to reset it to the user's preference.
- int mask = umask(0777); // The arg. to umask is arbitrary.
- umask(mask); // Restore the umask.
+ if (::rename(f.begin(), t.begin()) == -1)
+ return error_code(errno, system_category());
- // Get the file's current mode.
- struct stat buf;
- if (0 != stat(File.c_str(), &buf))
- return false;
- // Change the file to have whichever permissions bits from 'bits'
- // that the umask would not disable.
- if ((chmod(File.c_str(), (buf.st_mode | (bits & ~mask)))) == -1)
- return false;
- return true;
+ return error_code::success();
}
-bool Path::makeReadableOnDisk(std::string* ErrMsg) {
- if (!AddPermissionBits(*this, 0444))
- return MakeErrMsg(ErrMsg, path + ": can't make file readable");
- return false;
-}
+error_code resize_file(const Twine &path, uint64_t size) {
+ SmallString<128> path_storage;
+ StringRef p = path.toNullTerminatedStringRef(path_storage);
-bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
- if (!AddPermissionBits(*this, 0222))
- return MakeErrMsg(ErrMsg, path + ": can't make file writable");
- return false;
-}
+ if (::truncate(p.begin(), size) == -1)
+ return error_code(errno, system_category());
-bool Path::makeExecutableOnDisk(std::string* ErrMsg) {
- if (!AddPermissionBits(*this, 0111))
- return MakeErrMsg(ErrMsg, path + ": can't make file executable");
- return false;
+ return error_code::success();
}
-bool
-Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
- DIR* direntries = ::opendir(path.c_str());
- if (direntries == 0)
- return MakeErrMsg(ErrMsg, path + ": can't open directory");
-
- std::string dirPath = path;
- if (!lastIsSlash(dirPath))
- dirPath += '/';
+error_code exists(const Twine &path, bool &result) {
+ SmallString<128> path_storage;
+ StringRef p = path.toNullTerminatedStringRef(path_storage);
- result.clear();
- struct dirent* de = ::readdir(direntries);
- for ( ; de != 0; de = ::readdir(direntries)) {
- if (de->d_name[0] != '.') {
- Path aPath(dirPath + (const char*)de->d_name);
- struct stat st;
- if (0 != lstat(aPath.path.c_str(), &st)) {
- if (S_ISLNK(st.st_mode))
- continue; // dangling symlink -- ignore
- return MakeErrMsg(ErrMsg,
- aPath.path + ": can't determine file object type");
- }
- result.insert(aPath);
- }
- }
+ if (::access(p.begin(), F_OK) == -1) {
+ if (errno != errc::no_such_file_or_directory)
+ return error_code(errno, system_category());
+ result = false;
+ } else
+ result = true;
- closedir(direntries);
- return false;
+ return error_code::success();
}
-bool
-Path::set(StringRef a_path) {
- if (a_path.empty())
- return false;
- path = a_path;
- return true;
+bool can_write(const Twine &Path) {
+ SmallString<128> PathStorage;
+ StringRef P = Path.toNullTerminatedStringRef(PathStorage);
+ return 0 == access(P.begin(), W_OK);
}
-bool
-Path::appendComponent(StringRef name) {
- if (name.empty())
+bool can_execute(const Twine &Path) {
+ SmallString<128> PathStorage;
+ StringRef P = Path.toNullTerminatedStringRef(PathStorage);
+
+ if (0 != access(P.begin(), R_OK | X_OK))
+ return false;
+ struct stat buf;
+ if (0 != stat(P.begin(), &buf))
+ return false;
+ if (!S_ISREG(buf.st_mode))
return false;
- if (!lastIsSlash(path))
- path += '/';
- path += name;
return true;
}
-bool
-Path::eraseComponent() {
- size_t slashpos = path.rfind('/',path.size());
- if (slashpos == 0 || slashpos == std::string::npos) {
- path.erase();
- return true;
- }
- if (slashpos == path.size() - 1)
- slashpos = path.rfind('/',slashpos-1);
- if (slashpos == std::string::npos) {
- path.erase();
- return true;
- }
- path.erase(slashpos);
- return true;
+bool equivalent(file_status A, file_status B) {
+ assert(status_known(A) && status_known(B));
+ return A.fs_st_dev == B.fs_st_dev &&
+ A.fs_st_ino == B.fs_st_ino;
}
-bool
-Path::eraseSuffix() {
- size_t dotpos = path.rfind('.',path.size());
- size_t slashpos = path.rfind('/',path.size());
- if (dotpos != std::string::npos) {
- if (slashpos == std::string::npos || dotpos > slashpos+1) {
- path.erase(dotpos, path.size()-dotpos);
- return true;
- }
- }
- return false;
+error_code equivalent(const Twine &A, const Twine &B, bool &result) {
+ file_status fsA, fsB;
+ if (error_code ec = status(A, fsA)) return ec;
+ if (error_code ec = status(B, fsB)) return ec;
+ result = equivalent(fsA, fsB);
+ return error_code::success();
}
-static bool createDirectoryHelper(char* beg, char* end, bool create_parents) {
+static error_code fillStatus(int StatRet, const struct stat &Status,
+ file_status &Result) {
+ if (StatRet != 0) {
+ error_code ec(errno, system_category());
+ if (ec == errc::no_such_file_or_directory)
+ Result = file_status(file_type::file_not_found);
+ else
+ Result = file_status(file_type::status_error);
+ return ec;
+ }
- if (access(beg, R_OK | W_OK) == 0)
- return false;
+ file_type Type = file_type::type_unknown;
+
+ if (S_ISDIR(Status.st_mode))
+ Type = file_type::directory_file;
+ else if (S_ISREG(Status.st_mode))
+ Type = file_type::regular_file;
+ else if (S_ISBLK(Status.st_mode))
+ Type = file_type::block_file;
+ else if (S_ISCHR(Status.st_mode))
+ Type = file_type::character_file;
+ else if (S_ISFIFO(Status.st_mode))
+ Type = file_type::fifo_file;
+ else if (S_ISSOCK(Status.st_mode))
+ Type = file_type::socket_file;
+
+ perms Perms = static_cast<perms>(Status.st_mode);
+ Result =
+ file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_mtime,
+ Status.st_uid, Status.st_gid, Status.st_size);
+
+ return error_code::success();
+}
+
+error_code status(const Twine &Path, file_status &Result) {
+ SmallString<128> PathStorage;
+ StringRef P = Path.toNullTerminatedStringRef(PathStorage);
+
+ struct stat Status;
+ int StatRet = ::stat(P.begin(), &Status);
+ return fillStatus(StatRet, Status, Result);
+}
+
+error_code status(int FD, file_status &Result) {
+ struct stat Status;
+ int StatRet = ::fstat(FD, &Status);
+ return fillStatus(StatRet, Status, Result);
+}
+
+error_code setLastModificationAndAccessTime(int FD, TimeValue Time) {
+#if defined(HAVE_FUTIMENS)
+ timespec Times[2];
+ Times[0].tv_sec = Time.toPosixTime();
+ Times[0].tv_nsec = 0;
+ Times[1] = Times[0];
+ if (::futimens(FD, Times))
+#elif defined(HAVE_FUTIMES)
+ timeval Times[2];
+ Times[0].tv_sec = Time.toPosixTime();
+ Times[0].tv_usec = 0;
+ Times[1] = Times[0];
+ if (::futimes(FD, Times))
+#else
+#error Missing futimes() and futimens()
+#endif
+ return error_code(errno, system_category());
+ return error_code::success();
+}
+
+error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) {
+ AutoFD ScopedFD(FD);
+ if (!CloseFD)
+ ScopedFD.take();
+
+ // Figure out how large the file is.
+ struct stat FileInfo;
+ if (fstat(FD, &FileInfo) == -1)
+ return error_code(errno, system_category());
+ uint64_t FileSize = FileInfo.st_size;
+
+ if (Size == 0)
+ Size = FileSize;
+ else if (FileSize < Size) {
+ // We need to grow the file.
+ if (ftruncate(FD, Size) == -1)
+ return error_code(errno, system_category());
+ }
- if (create_parents) {
+ int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE;
+ int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE);
+#ifdef MAP_FILE
+ flags |= MAP_FILE;
+#endif
+ Mapping = ::mmap(0, Size, prot, flags, FD, Offset);
+ if (Mapping == MAP_FAILED)
+ return error_code(errno, system_category());
+ return error_code::success();
+}
+
+mapped_file_region::mapped_file_region(const Twine &path,
+ mapmode mode,
+ uint64_t length,
+ uint64_t offset,
+ error_code &ec)
+ : Mode(mode)
+ , Size(length)
+ , Mapping() {
+ // Make sure that the requested size fits within SIZE_T.
+ if (length > std::numeric_limits<size_t>::max()) {
+ ec = make_error_code(errc::invalid_argument);
+ return;
+ }
- char* c = end;
+ SmallString<128> path_storage;
+ StringRef name = path.toNullTerminatedStringRef(path_storage);
+ int oflags = (mode == readonly) ? O_RDONLY : O_RDWR;
+ int ofd = ::open(name.begin(), oflags);
+ if (ofd == -1) {
+ ec = error_code(errno, system_category());
+ return;
+ }
- for (; c != beg; --c)
- if (*c == '/') {
+ ec = init(ofd, true, offset);
+ if (ec)
+ Mapping = 0;
+}
+
+mapped_file_region::mapped_file_region(int fd,
+ bool closefd,
+ mapmode mode,
+ uint64_t length,
+ uint64_t offset,
+ error_code &ec)
+ : Mode(mode)
+ , Size(length)
+ , Mapping() {
+ // Make sure that the requested size fits within SIZE_T.
+ if (length > std::numeric_limits<size_t>::max()) {
+ ec = make_error_code(errc::invalid_argument);
+ return;
+ }
- // Recurse to handling the parent directory.
- *c = '\0';
- bool x = createDirectoryHelper(beg, c, create_parents);
- *c = '/';
+ ec = init(fd, closefd, offset);
+ if (ec)
+ Mapping = 0;
+}
- // Return if we encountered an error.
- if (x)
- return true;
+mapped_file_region::~mapped_file_region() {
+ if (Mapping)
+ ::munmap(Mapping, Size);
+}
- break;
- }
- }
+#if LLVM_HAS_RVALUE_REFERENCES
+mapped_file_region::mapped_file_region(mapped_file_region &&other)
+ : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) {
+ other.Mapping = 0;
+}
+#endif
- return mkdir(beg, S_IRWXU | S_IRWXG) != 0;
+mapped_file_region::mapmode mapped_file_region::flags() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return Mode;
}
-bool
-Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) {
- // Get a writeable copy of the path name
- std::string pathname(path);
+uint64_t mapped_file_region::size() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return Size;
+}
- // Null-terminate the last component
- size_t lastchar = path.length() - 1 ;
+char *mapped_file_region::data() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ assert(Mode != readonly && "Cannot get non const data for readonly mapping!");
+ return reinterpret_cast<char*>(Mapping);
+}
- if (pathname[lastchar] != '/')
- ++lastchar;
+const char *mapped_file_region::const_data() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return reinterpret_cast<const char*>(Mapping);
+}
- pathname[lastchar] = '\0';
+int mapped_file_region::alignment() {
+ return process::get_self()->page_size();
+}
- if (createDirectoryHelper(&pathname[0], &pathname[lastchar], create_parents))
- return MakeErrMsg(ErrMsg, pathname + ": can't create directory");
+error_code detail::directory_iterator_construct(detail::DirIterState &it,
+ StringRef path){
+ SmallString<128> path_null(path);
+ DIR *directory = ::opendir(path_null.c_str());
+ if (directory == 0)
+ return error_code(errno, system_category());
- return false;
+ 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());
+ return directory_iterator_increment(it);
}
-bool
-Path::createFileOnDisk(std::string* ErrMsg) {
- // Create the file
- int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR);
- if (fd < 0)
- return MakeErrMsg(ErrMsg, path + ": can't create file");
- ::close(fd);
- return false;
+error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
+ if (it.IterationHandle)
+ ::closedir(reinterpret_cast<DIR *>(it.IterationHandle));
+ it.IterationHandle = 0;
+ it.CurrentEntry = directory_entry();
+ return error_code::success();
}
-bool
-Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
- // Make this into a unique file name
- if (makeUnique( reuse_current, ErrMsg ))
- return true;
+error_code detail::directory_iterator_increment(detail::DirIterState &it) {
+ errno = 0;
+ dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle));
+ if (cur_dir == 0 && errno != 0) {
+ return error_code(errno, system_category());
+ } else if (cur_dir != 0) {
+ StringRef name(cur_dir->d_name, NAMLEN(cur_dir));
+ if ((name.size() == 1 && name[0] == '.') ||
+ (name.size() == 2 && name[0] == '.' && name[1] == '.'))
+ return directory_iterator_increment(it);
+ it.CurrentEntry.replace_filename(name);
+ } else
+ return directory_iterator_destruct(it);
- // create the file
- int fd = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666);
- if (fd < 0)
- return MakeErrMsg(ErrMsg, path + ": can't create temporary file");
- ::close(fd);
- return false;
+ return error_code::success();
}
-bool
-Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
- // Get the status so we can determine if it's a file or directory.
- struct stat buf;
- if (0 != stat(path.c_str(), &buf)) {
- MakeErrMsg(ErrStr, path + ": can't get status of file");
- return true;
- }
+error_code get_magic(const Twine &path, uint32_t len,
+ SmallVectorImpl<char> &result) {
+ SmallString<128> PathStorage;
+ StringRef Path = path.toNullTerminatedStringRef(PathStorage);
+ result.set_size(0);
- // Note: this check catches strange situations. In all cases, LLVM should
- // only be involved in the creation and deletion of regular files. This
- // check ensures that what we're trying to erase is a regular file. It
- // effectively prevents LLVM from erasing things like /dev/null, any block
- // special file, or other things that aren't "regular" files.
- if (S_ISREG(buf.st_mode)) {
- if (unlink(path.c_str()) != 0)
- return MakeErrMsg(ErrStr, path + ": can't destroy file");
- return false;
- }
+ // Open path.
+ std::FILE *file = std::fopen(Path.data(), "rb");
+ if (file == 0)
+ return error_code(errno, system_category());
- if (!S_ISDIR(buf.st_mode)) {
- if (ErrStr) *ErrStr = "not a file or directory";
- return true;
- }
+ // Reserve storage.
+ result.reserve(len);
- if (remove_contents) {
- // Recursively descend the directory to remove its contents.
- std::string cmd = "/bin/rm -rf " + path;
- if (system(cmd.c_str()) != 0) {
- MakeErrMsg(ErrStr, path + ": failed to recursively remove directory.");
- return true;
+ // Read magic!
+ size_t size = std::fread(result.data(), 1, len, file);
+ if (std::ferror(file) != 0) {
+ std::fclose(file);
+ return error_code(errno, system_category());
+ } else if (size != len) {
+ if (std::feof(file) != 0) {
+ std::fclose(file);
+ result.set_size(size);
+ return make_error_code(errc::value_too_large);
}
- return false;
- }
-
- // Otherwise, try to just remove the one directory.
- std::string pathname(path);
- size_t lastchar = path.length() - 1;
- if (pathname[lastchar] == '/')
- pathname[lastchar] = '\0';
- else
- pathname[lastchar+1] = '\0';
-
- if (rmdir(pathname.c_str()) != 0)
- return MakeErrMsg(ErrStr, pathname + ": can't erase directory");
- return false;
-}
-
-bool
-Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
- if (0 != ::rename(path.c_str(), newName.c_str()))
- return MakeErrMsg(ErrMsg, std::string("can't rename '") + path + "' as '" +
- newName.str() + "'");
- return false;
-}
-
-bool
-Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const {
- struct utimbuf utb;
- utb.actime = si.modTime.toPosixTime();
- utb.modtime = utb.actime;
- if (0 != ::utime(path.c_str(),&utb))
- return MakeErrMsg(ErrStr, path + ": can't set file modification time");
- if (0 != ::chmod(path.c_str(),si.mode))
- return MakeErrMsg(ErrStr, path + ": can't set mode");
- return false;
-}
-
-bool
-sys::CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg){
- int inFile = -1;
- int outFile = -1;
- inFile = ::open(Src.c_str(), O_RDONLY);
- if (inFile == -1)
- return MakeErrMsg(ErrMsg, Src.str() +
- ": can't open source file to copy");
-
- outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666);
- if (outFile == -1) {
- ::close(inFile);
- return MakeErrMsg(ErrMsg, Dest.str() +
- ": can't create destination file for copy");
}
-
- char Buffer[16*1024];
- while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) {
- if (Amt == -1) {
- if (errno != EINTR && errno != EAGAIN) {
- ::close(inFile);
- ::close(outFile);
- return MakeErrMsg(ErrMsg, Src.str()+": can't read source file");
- }
- } else {
- char *BufPtr = Buffer;
- while (Amt) {
- ssize_t AmtWritten = ::write(outFile, BufPtr, Amt);
- if (AmtWritten == -1) {
- if (errno != EINTR && errno != EAGAIN) {
- ::close(inFile);
- ::close(outFile);
- return MakeErrMsg(ErrMsg, Dest.str() +
- ": can't write destination file");
- }
- } else {
- Amt -= AmtWritten;
- BufPtr += AmtWritten;
- }
- }
- }
+ std::fclose(file);
+ result.set_size(size);
+ return error_code::success();
+}
+
+error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
+ bool map_writable, void *&result) {
+ SmallString<128> path_storage;
+ StringRef name = path.toNullTerminatedStringRef(path_storage);
+ int oflags = map_writable ? O_RDWR : O_RDONLY;
+ int ofd = ::open(name.begin(), oflags);
+ if ( ofd == -1 )
+ return error_code(errno, system_category());
+ AutoFD fd(ofd);
+ int flags = map_writable ? MAP_SHARED : MAP_PRIVATE;
+ int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ;
+#ifdef MAP_FILE
+ flags |= MAP_FILE;
+#endif
+ result = ::mmap(0, size, prot, flags, fd, file_offset);
+ if (result == MAP_FAILED) {
+ return error_code(errno, system_category());
}
- ::close(inFile);
- ::close(outFile);
- return false;
-}
-
-bool
-Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
- bool Exists;
- if (reuse_current && (fs::exists(path, Exists) || !Exists))
- return false; // File doesn't exist already, just use it!
-
- // Append an XXXXXX pattern to the end of the file for use with mkstemp,
- // mktemp or our own implementation.
- // This uses std::vector instead of SmallVector to avoid a dependence on
- // libSupport. And performance isn't critical here.
- std::vector<char> Buf;
- Buf.resize(path.size()+8);
- char *FNBuffer = &Buf[0];
- path.copy(FNBuffer,path.size());
- bool isdir;
- if (!fs::is_directory(path, isdir) && isdir)
- strcpy(FNBuffer+path.size(), "/XXXXXX");
- else
- strcpy(FNBuffer+path.size(), "-XXXXXX");
+
+ return error_code::success();
+}
-#if defined(HAVE_MKSTEMP)
- int TempFD;
- if ((TempFD = mkstemp(FNBuffer)) == -1)
- return MakeErrMsg(ErrMsg, path + ": can't make unique filename");
+error_code unmap_file_pages(void *base, size_t size) {
+ if ( ::munmap(base, size) == -1 )
+ return error_code(errno, system_category());
+
+ return error_code::success();
+}
- // We don't need to hold the temp file descriptor... we will trust that no one
- // will overwrite/delete the file before we can open it again.
- close(TempFD);
+error_code openFileForRead(const Twine &Name, int &ResultFD) {
+ SmallString<128> Storage;
+ StringRef P = Name.toNullTerminatedStringRef(Storage);
+ while ((ResultFD = open(P.begin(), O_RDONLY)) < 0) {
+ if (errno != EINTR)
+ return error_code(errno, system_category());
+ }
+ return error_code::success();
+}
- // Save the name
- path = FNBuffer;
+error_code openFileForWrite(const Twine &Name, int &ResultFD,
+ sys::fs::OpenFlags Flags, unsigned Mode) {
+ // Verify that we don't have both "append" and "excl".
+ assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
+ "Cannot specify both 'excl' and 'append' file creation flags!");
- // By default mkstemp sets the mode to 0600, so update mode bits now.
- AddPermissionBits (*this, 0666);
-#elif defined(HAVE_MKTEMP)
- // If we don't have mkstemp, use the old and obsolete mktemp function.
- if (mktemp(FNBuffer) == 0)
- return MakeErrMsg(ErrMsg, path + ": can't make unique filename");
+ int OpenFlags = O_WRONLY | O_CREAT;
- // Save the name
- path = FNBuffer;
-#else
- // Okay, looks like we have to do it all by our lonesome.
- static unsigned FCounter = 0;
- // Try to initialize with unique value.
- if (FCounter == 0) FCounter = ((unsigned)getpid() & 0xFFFF) << 8;
- char* pos = strstr(FNBuffer, "XXXXXX");
- do {
- if (++FCounter > 0xFFFFFF) {
- return MakeErrMsg(ErrMsg,
- path + ": can't make unique filename: too many files");
- }
- sprintf(pos, "%06X", FCounter);
- path = FNBuffer;
- } while (exists());
- // POSSIBLE SECURITY BUG: An attacker can easily guess the name and exploit
- // LLVM.
-#endif
- return false;
-}
+ if (Flags & F_Append)
+ OpenFlags |= O_APPEND;
+ else
+ OpenFlags |= O_TRUNC;
-const char *Path::MapInFilePages(int FD, size_t FileSize, off_t Offset) {
- int Flags = MAP_PRIVATE;
-#ifdef MAP_FILE
- Flags |= MAP_FILE;
-#endif
- void *BasePtr = ::mmap(0, FileSize, PROT_READ, Flags, FD, Offset);
- if (BasePtr == MAP_FAILED)
- return 0;
- return (const char*)BasePtr;
-}
+ if (Flags & F_Excl)
+ OpenFlags |= O_EXCL;
-void Path::UnMapFilePages(const char *BasePtr, size_t FileSize) {
- const void *Addr = static_cast<const void *>(BasePtr);
- ::munmap(const_cast<void *>(Addr), FileSize);
+ SmallString<128> Storage;
+ StringRef P = Name.toNullTerminatedStringRef(Storage);
+ while ((ResultFD = open(P.begin(), OpenFlags, Mode)) < 0) {
+ if (errno != EINTR)
+ return error_code(errno, system_category());
+ }
+ return error_code::success();
}
-} // end llvm namespace
+} // end namespace fs
+} // end namespace sys
+} // end namespace llvm
diff --git a/contrib/llvm/lib/Support/Unix/PathV2.inc b/contrib/llvm/lib/Support/Unix/PathV2.inc
deleted file mode 100644
index 7e0aead..0000000
--- a/contrib/llvm/lib/Support/Unix/PathV2.inc
+++ /dev/null
@@ -1,693 +0,0 @@
-//===- llvm/Support/Unix/PathV2.cpp - Unix Path Implementation --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the Unix specific implementation of the PathV2 API.
-//
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only generic UNIX code that
-//=== is guaranteed to work on *all* UNIX variants.
-//===----------------------------------------------------------------------===//
-
-#include "Unix.h"
-#include "llvm/Support/Process.h"
-#if HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-#if HAVE_DIRENT_H
-# include <dirent.h>
-# define NAMLEN(dirent) strlen((dirent)->d_name)
-#else
-# define dirent direct
-# define NAMLEN(dirent) (dirent)->d_namlen
-# if HAVE_SYS_NDIR_H
-# include <sys/ndir.h>
-# endif
-# if HAVE_SYS_DIR_H
-# include <sys/dir.h>
-# endif
-# if HAVE_NDIR_H
-# include <ndir.h>
-# endif
-#endif
-#if HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#if HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
-// Both stdio.h and cstdio are included via different pathes and
-// stdcxx's cstdio doesn't include stdio.h, so it doesn't #undef the macros
-// either.
-#undef ferror
-#undef feof
-
-// For GNU Hurd
-#if defined(__GNU__) && !defined(PATH_MAX)
-# define PATH_MAX 4096
-#endif
-
-using namespace llvm;
-
-namespace {
- /// This class automatically closes the given file descriptor when it goes out
- /// of scope. You can take back explicit ownership of the file descriptor by
- /// calling take(). The destructor does not verify that close was successful.
- /// Therefore, never allow this class to call close on a file descriptor that
- /// has been read from or written to.
- struct AutoFD {
- int FileDescriptor;
-
- AutoFD(int fd) : FileDescriptor(fd) {}
- ~AutoFD() {
- if (FileDescriptor >= 0)
- ::close(FileDescriptor);
- }
-
- int take() {
- int ret = FileDescriptor;
- FileDescriptor = -1;
- return ret;
- }
-
- operator int() const {return FileDescriptor;}
- };
-
- error_code TempDir(SmallVectorImpl<char> &result) {
- // FIXME: Don't use TMPDIR if program is SUID or SGID enabled.
- const char *dir = 0;
- (dir = std::getenv("TMPDIR" )) ||
- (dir = std::getenv("TMP" )) ||
- (dir = std::getenv("TEMP" )) ||
- (dir = std::getenv("TEMPDIR")) ||
-#ifdef P_tmpdir
- (dir = P_tmpdir) ||
-#endif
- (dir = "/tmp");
-
- result.clear();
- StringRef d(dir);
- result.append(d.begin(), d.end());
- return error_code::success();
- }
-}
-
-namespace llvm {
-namespace sys {
-namespace fs {
-
-error_code current_path(SmallVectorImpl<char> &result) {
-#ifdef MAXPATHLEN
- result.reserve(MAXPATHLEN);
-#else
-// For GNU Hurd
- result.reserve(1024);
-#endif
-
- while (true) {
- if (::getcwd(result.data(), result.capacity()) == 0) {
- // See if there was a real error.
- if (errno != errc::not_enough_memory)
- return error_code(errno, system_category());
- // Otherwise there just wasn't enough space.
- result.reserve(result.capacity() * 2);
- } else
- break;
- }
-
- result.set_size(strlen(result.data()));
- return error_code::success();
-}
-
-error_code copy_file(const Twine &from, const Twine &to, copy_option copt) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toNullTerminatedStringRef(from_storage);
- StringRef t = to.toNullTerminatedStringRef(to_storage);
-
- const size_t buf_sz = 32768;
- char buffer[buf_sz];
- int from_file = -1, to_file = -1;
-
- // Open from.
- if ((from_file = ::open(f.begin(), O_RDONLY)) < 0)
- return error_code(errno, system_category());
- AutoFD from_fd(from_file);
-
- // Stat from.
- struct stat from_stat;
- if (::stat(f.begin(), &from_stat) != 0)
- return error_code(errno, system_category());
-
- // Setup to flags.
- int to_flags = O_CREAT | O_WRONLY;
- if (copt == copy_option::fail_if_exists)
- to_flags |= O_EXCL;
-
- // Open to.
- if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0)
- return error_code(errno, system_category());
- AutoFD to_fd(to_file);
-
- // Copy!
- ssize_t sz, sz_read = 1, sz_write;
- while (sz_read > 0 &&
- (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) {
- // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
- // Marc Rochkind, Addison-Wesley, 2004, page 94
- sz_write = 0;
- do {
- if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) {
- sz_read = sz; // cause read loop termination.
- break; // error.
- }
- sz_write += sz;
- } while (sz_write < sz_read);
- }
-
- // After all the file operations above the return value of close actually
- // matters.
- if (::close(from_fd.take()) < 0) sz_read = -1;
- if (::close(to_fd.take()) < 0) sz_read = -1;
-
- // Check for errors.
- if (sz_read < 0)
- return error_code(errno, system_category());
-
- return error_code::success();
-}
-
-error_code create_directory(const Twine &path, bool &existed) {
- SmallString<128> path_storage;
- StringRef p = path.toNullTerminatedStringRef(path_storage);
-
- if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) {
- if (errno != errc::file_exists)
- return error_code(errno, system_category());
- existed = true;
- } else
- existed = false;
-
- return error_code::success();
-}
-
-error_code create_hard_link(const Twine &to, const Twine &from) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toNullTerminatedStringRef(from_storage);
- StringRef t = to.toNullTerminatedStringRef(to_storage);
-
- if (::link(t.begin(), f.begin()) == -1)
- return error_code(errno, system_category());
-
- return error_code::success();
-}
-
-error_code create_symlink(const Twine &to, const Twine &from) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toNullTerminatedStringRef(from_storage);
- StringRef t = to.toNullTerminatedStringRef(to_storage);
-
- if (::symlink(t.begin(), f.begin()) == -1)
- return error_code(errno, system_category());
-
- return error_code::success();
-}
-
-error_code remove(const Twine &path, bool &existed) {
- SmallString<128> path_storage;
- StringRef p = path.toNullTerminatedStringRef(path_storage);
-
- if (::remove(p.begin()) == -1) {
- if (errno != errc::no_such_file_or_directory)
- return error_code(errno, system_category());
- existed = false;
- } else
- existed = true;
-
- return error_code::success();
-}
-
-error_code rename(const Twine &from, const Twine &to) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toNullTerminatedStringRef(from_storage);
- StringRef t = to.toNullTerminatedStringRef(to_storage);
-
- if (::rename(f.begin(), t.begin()) == -1) {
- // If it's a cross device link, copy then delete, otherwise return the error
- if (errno == EXDEV) {
- if (error_code ec = copy_file(from, to, copy_option::overwrite_if_exists))
- return ec;
- bool Existed;
- if (error_code ec = remove(from, Existed))
- return ec;
- } else
- return error_code(errno, system_category());
- }
-
- return error_code::success();
-}
-
-error_code resize_file(const Twine &path, uint64_t size) {
- SmallString<128> path_storage;
- StringRef p = path.toNullTerminatedStringRef(path_storage);
-
- if (::truncate(p.begin(), size) == -1)
- return error_code(errno, system_category());
-
- return error_code::success();
-}
-
-error_code exists(const Twine &path, bool &result) {
- SmallString<128> path_storage;
- StringRef p = path.toNullTerminatedStringRef(path_storage);
-
- if (::access(p.begin(), F_OK) == -1) {
- if (errno != errc::no_such_file_or_directory)
- return error_code(errno, system_category());
- result = false;
- } else
- result = true;
-
- return error_code::success();
-}
-
-bool equivalent(file_status A, file_status B) {
- assert(status_known(A) && status_known(B));
- return A.fs_st_dev == B.fs_st_dev &&
- A.fs_st_ino == B.fs_st_ino;
-}
-
-error_code equivalent(const Twine &A, const Twine &B, bool &result) {
- file_status fsA, fsB;
- if (error_code ec = status(A, fsA)) return ec;
- if (error_code ec = status(B, fsB)) return ec;
- result = equivalent(fsA, fsB);
- return error_code::success();
-}
-
-error_code file_size(const Twine &path, uint64_t &result) {
- SmallString<128> path_storage;
- StringRef p = path.toNullTerminatedStringRef(path_storage);
-
- struct stat status;
- if (::stat(p.begin(), &status) == -1)
- return error_code(errno, system_category());
- if (!S_ISREG(status.st_mode))
- return make_error_code(errc::operation_not_permitted);
-
- result = status.st_size;
- return error_code::success();
-}
-
-error_code status(const Twine &path, file_status &result) {
- SmallString<128> path_storage;
- StringRef p = path.toNullTerminatedStringRef(path_storage);
-
- struct stat status;
- if (::stat(p.begin(), &status) != 0) {
- error_code ec(errno, system_category());
- if (ec == errc::no_such_file_or_directory)
- result = file_status(file_type::file_not_found);
- else
- result = file_status(file_type::status_error);
- return ec;
- }
-
- perms prms = static_cast<perms>(status.st_mode & perms_mask);
-
- if (S_ISDIR(status.st_mode))
- result = file_status(file_type::directory_file, prms);
- else if (S_ISREG(status.st_mode))
- result = file_status(file_type::regular_file, prms);
- else if (S_ISBLK(status.st_mode))
- result = file_status(file_type::block_file, prms);
- else if (S_ISCHR(status.st_mode))
- result = file_status(file_type::character_file, prms);
- else if (S_ISFIFO(status.st_mode))
- result = file_status(file_type::fifo_file, prms);
- else if (S_ISSOCK(status.st_mode))
- result = file_status(file_type::socket_file, prms);
- else
- result = file_status(file_type::type_unknown, prms);
-
- result.fs_st_dev = status.st_dev;
- result.fs_st_ino = status.st_ino;
-
- return error_code::success();
-}
-
-// Modifies permissions on a file.
-error_code permissions(const Twine &path, perms prms) {
- if ((prms & add_perms) && (prms & remove_perms))
- llvm_unreachable("add_perms and remove_perms are mutually exclusive");
-
- // Get current permissions
- file_status info;
- if (error_code ec = status(path, info)) {
- return ec;
- }
-
- // Set updated permissions.
- SmallString<128> path_storage;
- StringRef p = path.toNullTerminatedStringRef(path_storage);
- perms permsToSet;
- if (prms & add_perms) {
- permsToSet = (info.permissions() | prms) & perms_mask;
- } else if (prms & remove_perms) {
- permsToSet = (info.permissions() & ~prms) & perms_mask;
- } else {
- permsToSet = prms & perms_mask;
- }
- if (::chmod(p.begin(), static_cast<mode_t>(permsToSet))) {
- return error_code(errno, system_category());
- }
-
- return error_code::success();
-}
-
-// Since this is most often used for temporary files, mode defaults to 0600.
-error_code unique_file(const Twine &model, int &result_fd,
- SmallVectorImpl<char> &result_path,
- bool makeAbsolute, unsigned mode) {
- SmallString<128> Model;
- model.toVector(Model);
- // Null terminate.
- Model.c_str();
-
- if (makeAbsolute) {
- // Make model absolute by prepending a temp directory if it's not already.
- bool absolute = path::is_absolute(Twine(Model));
- if (!absolute) {
- SmallString<128> TDir;
- if (error_code ec = TempDir(TDir)) return ec;
- path::append(TDir, Twine(Model));
- Model.swap(TDir);
- }
- }
-
- // From here on, DO NOT modify model. It may be needed if the randomly chosen
- // path already exists.
- SmallString<128> RandomPath = Model;
-
-retry_random_path:
- // Replace '%' with random chars.
- for (unsigned i = 0, e = Model.size(); i != e; ++i) {
- if (Model[i] == '%')
- RandomPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15];
- }
-
- // Make sure we don't fall into an infinite loop by constantly trying
- // to create the parent path.
- bool TriedToCreateParent = false;
-
- // Try to open + create the file.
-rety_open_create:
- int RandomFD = ::open(RandomPath.c_str(), O_RDWR | O_CREAT | O_EXCL, mode);
- if (RandomFD == -1) {
- int SavedErrno = errno;
- // If the file existed, try again, otherwise, error.
- if (SavedErrno == errc::file_exists)
- goto retry_random_path;
- // If path prefix doesn't exist, try to create it.
- if (SavedErrno == errc::no_such_file_or_directory && !TriedToCreateParent) {
- TriedToCreateParent = true;
- StringRef p(RandomPath);
- SmallString<64> dir_to_create;
- for (path::const_iterator i = path::begin(p),
- e = --path::end(p); i != e; ++i) {
- path::append(dir_to_create, *i);
- bool Exists;
- if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec;
- if (!Exists) {
- // Don't try to create network paths.
- if (i->size() > 2 && (*i)[0] == '/' &&
- (*i)[1] == '/' &&
- (*i)[2] != '/')
- return make_error_code(errc::no_such_file_or_directory);
- if (::mkdir(dir_to_create.c_str(), 0700) == -1 &&
- errno != errc::file_exists)
- return error_code(errno, system_category());
- }
- }
- goto rety_open_create;
- }
-
- return error_code(SavedErrno, system_category());
- }
-
- // Make the path absolute.
- char real_path_buff[PATH_MAX + 1];
- if (realpath(RandomPath.c_str(), real_path_buff) == NULL) {
- int error = errno;
- ::close(RandomFD);
- ::unlink(RandomPath.c_str());
- return error_code(error, system_category());
- }
-
- result_path.clear();
- StringRef d(real_path_buff);
- result_path.append(d.begin(), d.end());
-
- result_fd = RandomFD;
- return error_code::success();
-}
-
-error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) {
- AutoFD ScopedFD(FD);
- if (!CloseFD)
- ScopedFD.take();
-
- // Figure out how large the file is.
- struct stat FileInfo;
- if (fstat(FD, &FileInfo) == -1)
- return error_code(errno, system_category());
- uint64_t FileSize = FileInfo.st_size;
-
- if (Size == 0)
- Size = FileSize;
- else if (FileSize < Size) {
- // We need to grow the file.
- if (ftruncate(FD, Size) == -1)
- return error_code(errno, system_category());
- }
-
- int flags = (Mode == readwrite) ? MAP_SHARED : MAP_PRIVATE;
- int prot = (Mode == readonly) ? PROT_READ : (PROT_READ | PROT_WRITE);
-#ifdef MAP_FILE
- flags |= MAP_FILE;
-#endif
- Mapping = ::mmap(0, Size, prot, flags, FD, Offset);
- if (Mapping == MAP_FAILED)
- return error_code(errno, system_category());
- return error_code::success();
-}
-
-mapped_file_region::mapped_file_region(const Twine &path,
- mapmode mode,
- uint64_t length,
- uint64_t offset,
- error_code &ec)
- : Mode(mode)
- , Size(length)
- , Mapping() {
- // Make sure that the requested size fits within SIZE_T.
- if (length > std::numeric_limits<size_t>::max()) {
- ec = make_error_code(errc::invalid_argument);
- return;
- }
-
- SmallString<128> path_storage;
- StringRef name = path.toNullTerminatedStringRef(path_storage);
- int oflags = (mode == readonly) ? O_RDONLY : O_RDWR;
- int ofd = ::open(name.begin(), oflags);
- if (ofd == -1) {
- ec = error_code(errno, system_category());
- return;
- }
-
- ec = init(ofd, true, offset);
- if (ec)
- Mapping = 0;
-}
-
-mapped_file_region::mapped_file_region(int fd,
- bool closefd,
- mapmode mode,
- uint64_t length,
- uint64_t offset,
- error_code &ec)
- : Mode(mode)
- , Size(length)
- , Mapping() {
- // Make sure that the requested size fits within SIZE_T.
- if (length > std::numeric_limits<size_t>::max()) {
- ec = make_error_code(errc::invalid_argument);
- return;
- }
-
- ec = init(fd, closefd, offset);
- if (ec)
- Mapping = 0;
-}
-
-mapped_file_region::~mapped_file_region() {
- if (Mapping)
- ::munmap(Mapping, Size);
-}
-
-#if LLVM_HAS_RVALUE_REFERENCES
-mapped_file_region::mapped_file_region(mapped_file_region &&other)
- : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) {
- other.Mapping = 0;
-}
-#endif
-
-mapped_file_region::mapmode mapped_file_region::flags() const {
- assert(Mapping && "Mapping failed but used anyway!");
- return Mode;
-}
-
-uint64_t mapped_file_region::size() const {
- assert(Mapping && "Mapping failed but used anyway!");
- return Size;
-}
-
-char *mapped_file_region::data() const {
- assert(Mapping && "Mapping failed but used anyway!");
- assert(Mode != readonly && "Cannot get non const data for readonly mapping!");
- return reinterpret_cast<char*>(Mapping);
-}
-
-const char *mapped_file_region::const_data() const {
- assert(Mapping && "Mapping failed but used anyway!");
- return reinterpret_cast<const char*>(Mapping);
-}
-
-int mapped_file_region::alignment() {
- return process::get_self()->page_size();
-}
-
-error_code detail::directory_iterator_construct(detail::DirIterState &it,
- StringRef path){
- SmallString<128> path_null(path);
- DIR *directory = ::opendir(path_null.c_str());
- if (directory == 0)
- return error_code(errno, system_category());
-
- 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());
- return directory_iterator_increment(it);
-}
-
-error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
- if (it.IterationHandle)
- ::closedir(reinterpret_cast<DIR *>(it.IterationHandle));
- it.IterationHandle = 0;
- it.CurrentEntry = directory_entry();
- return error_code::success();
-}
-
-error_code detail::directory_iterator_increment(detail::DirIterState &it) {
- errno = 0;
- dirent *cur_dir = ::readdir(reinterpret_cast<DIR *>(it.IterationHandle));
- if (cur_dir == 0 && errno != 0) {
- return error_code(errno, system_category());
- } else if (cur_dir != 0) {
- StringRef name(cur_dir->d_name, NAMLEN(cur_dir));
- if ((name.size() == 1 && name[0] == '.') ||
- (name.size() == 2 && name[0] == '.' && name[1] == '.'))
- return directory_iterator_increment(it);
- it.CurrentEntry.replace_filename(name);
- } else
- return directory_iterator_destruct(it);
-
- return error_code::success();
-}
-
-error_code get_magic(const Twine &path, uint32_t len,
- SmallVectorImpl<char> &result) {
- SmallString<128> PathStorage;
- StringRef Path = path.toNullTerminatedStringRef(PathStorage);
- result.set_size(0);
-
- // Open path.
- std::FILE *file = std::fopen(Path.data(), "rb");
- if (file == 0)
- return error_code(errno, system_category());
-
- // Reserve storage.
- result.reserve(len);
-
- // Read magic!
- size_t size = std::fread(result.data(), 1, len, file);
- if (std::ferror(file) != 0) {
- std::fclose(file);
- return error_code(errno, system_category());
- } else if (size != result.size()) {
- if (std::feof(file) != 0) {
- std::fclose(file);
- result.set_size(size);
- return make_error_code(errc::value_too_large);
- }
- }
- std::fclose(file);
- result.set_size(len);
- return error_code::success();
-}
-
-error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
- bool map_writable, void *&result) {
- SmallString<128> path_storage;
- StringRef name = path.toNullTerminatedStringRef(path_storage);
- int oflags = map_writable ? O_RDWR : O_RDONLY;
- int ofd = ::open(name.begin(), oflags);
- if ( ofd == -1 )
- return error_code(errno, system_category());
- AutoFD fd(ofd);
- int flags = map_writable ? MAP_SHARED : MAP_PRIVATE;
- int prot = map_writable ? (PROT_READ|PROT_WRITE) : PROT_READ;
-#ifdef MAP_FILE
- flags |= MAP_FILE;
-#endif
- result = ::mmap(0, size, prot, flags, fd, file_offset);
- if (result == MAP_FAILED) {
- return error_code(errno, system_category());
- }
-
- return error_code::success();
-}
-
-error_code unmap_file_pages(void *base, size_t size) {
- if ( ::munmap(base, size) == -1 )
- return error_code(errno, system_category());
-
- return error_code::success();
-}
-
-
-} // end namespace fs
-} // end namespace sys
-} // end namespace llvm
diff --git a/contrib/llvm/lib/Support/Unix/Process.inc b/contrib/llvm/lib/Support/Unix/Process.inc
index 9a4454f..c5778e7 100644
--- a/contrib/llvm/lib/Support/Unix/Process.inc
+++ b/contrib/llvm/lib/Support/Unix/Process.inc
@@ -13,6 +13,9 @@
#include "Unix.h"
#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/MutexGuard.h"
#include "llvm/Support/TimeValue.h"
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
@@ -86,13 +89,10 @@ TimeValue self_process::get_system_time() const {
return getRUsageTimes().second;
}
+// On Cygwin, getpagesize() returns 64k(AllocationGranularity) and
+// offset in mmap(3) should be aligned to the AllocationGranularity.
static unsigned getPageSize() {
-#if defined(__CYGWIN__)
- // On Cygwin, getpagesize() returns 64k but the page size for the purposes of
- // memory protection and mmap() is 4k.
- // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492
- const int page_size = 0x1000;
-#elif defined(HAVE_GETPAGESIZE)
+#if defined(HAVE_GETPAGESIZE)
const int page_size = ::getpagesize();
#elif defined(HAVE_SYSCONF)
long page_size = ::sysconf(_SC_PAGE_SIZE);
@@ -138,14 +138,6 @@ void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
llvm::tie(user_time, sys_time) = getRUsageTimes();
}
-int Process::GetCurrentUserId() {
- return getuid();
-}
-
-int Process::GetCurrentGroupId() {
- return getgid();
-}
-
#if defined(HAVE_MACH_MACH_H) && !defined(__GNU__)
#include <mach/mach.h>
#endif
@@ -190,6 +182,22 @@ void Process::PreventCoreFiles() {
#endif
}
+Optional<std::string> Process::GetEnv(StringRef Name) {
+ std::string NameStr = Name.str();
+ const char *Val = ::getenv(NameStr.c_str());
+ if (!Val)
+ return None;
+ return std::string(Val);
+}
+
+error_code Process::GetArgumentVector(SmallVectorImpl<const char *> &ArgsOut,
+ ArrayRef<const char *> ArgsIn,
+ SpecificBumpPtrAllocator<char> &) {
+ ArgsOut.append(ArgsIn.begin(), ArgsIn.end());
+
+ return error_code::success();
+}
+
bool Process::StandardInIsUserInput() {
return FileDescriptorIsDisplayed(STDIN_FILENO);
}
@@ -224,8 +232,6 @@ static unsigned getColumns(int FileID) {
#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H)
// Try to determine the width of the terminal.
struct winsize ws;
- // Zero-fill ws to avoid a false positive from MemorySanitizer.
- memset(&ws, 0, sizeof(ws));
if (ioctl(FileID, TIOCGWINSZ, &ws) == 0)
Columns = ws.ws_col;
#endif
@@ -247,22 +253,61 @@ unsigned Process::StandardErrColumns() {
return getColumns(2);
}
-static bool terminalHasColors() {
- if (const char *term = std::getenv("TERM")) {
- // Most modern terminals support ANSI escape sequences for colors.
- // We could check terminfo, or have a list of known terms that support
- // colors, but that would be overkill.
- // The user can always ask for no colors by setting TERM to dumb, or
- // using a commandline flag.
- return strcmp(term, "dumb") != 0;
- }
+#ifdef HAVE_TERMINFO
+// We manually declare these extern functions because finding the correct
+// headers from various terminfo, curses, or other sources is harder than
+// writing their specs down.
+extern "C" int setupterm(char *term, int filedes, int *errret);
+extern "C" struct term *set_curterm(struct term *termp);
+extern "C" int del_curterm(struct term *termp);
+extern "C" int tigetnum(char *capname);
+#endif
+
+static bool terminalHasColors(int fd) {
+#ifdef HAVE_TERMINFO
+ // First, acquire a global lock because these C routines are thread hostile.
+ static sys::Mutex M;
+ MutexGuard G(M);
+
+ int errret = 0;
+ if (setupterm((char *)0, fd, &errret) != 0)
+ // Regardless of why, if we can't get terminfo, we shouldn't try to print
+ // colors.
+ return false;
+
+ // Test whether the terminal as set up supports color output. How to do this
+ // isn't entirely obvious. We can use the curses routine 'has_colors' but it
+ // would be nice to avoid a dependency on curses proper when we can make do
+ // with a minimal terminfo parsing library. Also, we don't really care whether
+ // the terminal supports the curses-specific color changing routines, merely
+ // if it will interpret ANSI color escape codes in a reasonable way. Thus, the
+ // strategy here is just to query the baseline colors capability and if it
+ // supports colors at all to assume it will translate the escape codes into
+ // whatever range of colors it does support. We can add more detailed tests
+ // here if users report them as necessary.
+ //
+ // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if
+ // the terminfo says that no colors are supported.
+ bool HasColors = tigetnum(const_cast<char *>("colors")) > 0;
+
+ // Now extract the structure allocated by setupterm and free its memory
+ // through a really silly dance.
+ struct term *termp = set_curterm((struct term *)0);
+ (void)del_curterm(termp); // Drop any errors here.
+
+ // Return true if we found a color capabilities for the current terminal.
+ if (HasColors)
+ return true;
+#endif
+
+ // Otherwise, be conservative.
return false;
}
bool Process::FileDescriptorHasColors(int fd) {
// A file descriptor has colors if it is displayed and the terminal has
// colors.
- return FileDescriptorIsDisplayed(fd) && terminalHasColors();
+ return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd);
}
bool Process::StandardOutHasColors() {
@@ -273,29 +318,15 @@ bool Process::StandardErrHasColors() {
return FileDescriptorHasColors(STDERR_FILENO);
}
+void Process::UseANSIEscapeCodes(bool /*enable*/) {
+ // No effect.
+}
+
bool Process::ColorNeedsFlush() {
// No, we use ANSI escape sequences.
return false;
}
-#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m"
-
-#define ALLCOLORS(FGBG,BOLD) {\
- COLOR(FGBG, "0", BOLD),\
- COLOR(FGBG, "1", BOLD),\
- COLOR(FGBG, "2", BOLD),\
- COLOR(FGBG, "3", BOLD),\
- COLOR(FGBG, "4", BOLD),\
- COLOR(FGBG, "5", BOLD),\
- COLOR(FGBG, "6", BOLD),\
- COLOR(FGBG, "7", BOLD)\
- }
-
-static const char colorcodes[2][2][8][10] = {
- { ALLCOLORS("3",""), ALLCOLORS("3","1;") },
- { ALLCOLORS("4",""), ALLCOLORS("4","1;") }
-};
-
const char *Process::OutputColor(char code, bool bold, bool bg) {
return colorcodes[bg?1:0][bold?1:0][code&7];
}
diff --git a/contrib/llvm/lib/Support/Unix/Program.inc b/contrib/llvm/lib/Support/Unix/Program.inc
index aa03d48..78b2971 100644
--- a/contrib/llvm/lib/Support/Unix/Program.inc
+++ b/contrib/llvm/lib/Support/Unix/Program.inc
@@ -36,6 +36,9 @@
#include <unistd.h>
#endif
#ifdef HAVE_POSIX_SPAWN
+#ifdef __sun__
+#define _RESTRICT_KYWD
+#endif
#include <spawn.h>
#if !defined(__APPLE__)
extern char **environ;
@@ -47,20 +50,16 @@
namespace llvm {
using namespace sys;
-Program::Program() : Data_(0) {}
-
-Program::~Program() {}
+ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {}
// This function just uses the PATH environment variable to find the program.
-Path
-Program::FindProgramByName(const std::string& progName) {
+std::string
+sys::FindProgramByName(const std::string& progName) {
// Check some degenerate cases
if (progName.length() == 0) // no program
- return Path();
- Path temp;
- if (!temp.set(progName)) // invalid name
- return Path();
+ return "";
+ std::string temp = progName;
// Use the given path verbatim if it contains any slashes; this matches
// the behavior of sh(1) and friends.
if (progName.find('/') != std::string::npos)
@@ -72,7 +71,7 @@ Program::FindProgramByName(const std::string& progName) {
// Get the path. If its empty, we can't do anything to find it.
const char *PathStr = getenv("PATH");
if (PathStr == 0)
- return Path();
+ return "";
// Now we have a colon separated list of directories to search; try them.
size_t PathLen = strlen(PathStr);
@@ -81,12 +80,10 @@ Program::FindProgramByName(const std::string& progName) {
const char *Colon = std::find(PathStr, PathStr+PathLen, ':');
// Check to see if this first directory contains the executable...
- Path FilePath;
- if (FilePath.set(std::string(PathStr,Colon))) {
- FilePath.appendComponent(progName);
- if (FilePath.canExecute())
- return FilePath; // Found the executable!
- }
+ SmallString<128> FilePath(PathStr,Colon);
+ sys::path::append(FilePath, progName);
+ if (sys::fs::can_execute(Twine(FilePath)))
+ return FilePath.str(); // Found the executable!
// Nope it wasn't in this directory, check the next path in the list!
PathLen -= Colon-PathStr;
@@ -98,23 +95,23 @@ Program::FindProgramByName(const std::string& progName) {
PathLen--;
}
}
- return Path();
+ return "";
}
-static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) {
+static bool RedirectIO(const StringRef *Path, int FD, std::string* ErrMsg) {
if (Path == 0) // Noop
return false;
- const char *File;
- if (Path->isEmpty())
+ std::string File;
+ if (Path->empty())
// Redirect empty paths to /dev/null
File = "/dev/null";
else
- File = Path->c_str();
+ File = *Path;
// Open the file
- int InFD = open(File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
+ int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
if (InFD == -1) {
- MakeErrMsg(ErrMsg, "Cannot open file '" + std::string(File) + "' for "
+ MakeErrMsg(ErrMsg, "Cannot open file '" + File + "' for "
+ (FD == 0 ? "input" : "output"));
return true;
}
@@ -130,19 +127,20 @@ static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) {
}
#ifdef HAVE_POSIX_SPAWN
-static bool RedirectIO_PS(const Path *Path, int FD, std::string *ErrMsg,
+static bool RedirectIO_PS(const std::string *Path, int FD, std::string *ErrMsg,
posix_spawn_file_actions_t *FileActions) {
if (Path == 0) // Noop
return false;
const char *File;
- if (Path->isEmpty())
+ if (Path->empty())
// Redirect empty paths to /dev/null
File = "/dev/null";
else
File = Path->c_str();
- if (int Err = posix_spawn_file_actions_addopen(FileActions, FD,
- File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666))
+ if (int Err = posix_spawn_file_actions_addopen(
+ FileActions, FD, File,
+ FD == 0 ? O_RDONLY : O_WRONLY | O_CREAT, 0666))
return MakeErrMsg(ErrMsg, "Cannot dup2", Err);
return false;
}
@@ -180,10 +178,18 @@ static void SetMemoryLimits (unsigned size)
#endif
}
-bool
-Program::Execute(const Path &path, const char **args, const char **envp,
- const Path **redirects, unsigned memoryLimit,
- std::string *ErrMsg) {
+}
+
+static bool Execute(ProcessInfo &PI, StringRef Program, const char **args,
+ const char **envp, const StringRef **redirects,
+ unsigned memoryLimit, std::string *ErrMsg) {
+ if (!llvm::sys::fs::exists(Program)) {
+ if (ErrMsg)
+ *ErrMsg = std::string("Executable \"") + Program.str() +
+ std::string("\" doesn't exist!");
+ return false;
+ }
+
// If this OS has posix_spawn and there is no memory limit being implied, use
// posix_spawn. It is more efficient than fork/exec.
#ifdef HAVE_POSIX_SPAWN
@@ -191,18 +197,32 @@ Program::Execute(const Path &path, const char **args, const char **envp,
posix_spawn_file_actions_t FileActionsStore;
posix_spawn_file_actions_t *FileActions = 0;
+ // If we call posix_spawn_file_actions_addopen we have to make sure the
+ // c strings we pass to it stay alive until the call to posix_spawn,
+ // so we copy any StringRefs into this variable.
+ std::string RedirectsStorage[3];
+
if (redirects) {
+ std::string *RedirectsStr[3] = {0, 0, 0};
+ for (int I = 0; I < 3; ++I) {
+ if (redirects[I]) {
+ RedirectsStorage[I] = *redirects[I];
+ RedirectsStr[I] = &RedirectsStorage[I];
+ }
+ }
+
FileActions = &FileActionsStore;
posix_spawn_file_actions_init(FileActions);
// Redirect stdin/stdout.
- if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) ||
- RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions))
+ if (RedirectIO_PS(RedirectsStr[0], 0, ErrMsg, FileActions) ||
+ RedirectIO_PS(RedirectsStr[1], 1, ErrMsg, FileActions))
return false;
if (redirects[1] == 0 || redirects[2] == 0 ||
*redirects[1] != *redirects[2]) {
// Just redirect stderr
- if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false;
+ if (RedirectIO_PS(RedirectsStr[2], 2, ErrMsg, FileActions))
+ return false;
} else {
// If stdout and stderr should go to the same place, redirect stderr
// to the FD already open for stdout.
@@ -222,7 +242,7 @@ Program::Execute(const Path &path, const char **args, const char **envp,
// Explicitly initialized to prevent what appears to be a valgrind false
// positive.
pid_t PID = 0;
- int Err = posix_spawn(&PID, path.c_str(), FileActions, /*attrp*/0,
+ int Err = posix_spawn(&PID, Program.str().c_str(), FileActions, /*attrp*/0,
const_cast<char **>(args), const_cast<char **>(envp));
if (FileActions)
@@ -231,7 +251,8 @@ Program::Execute(const Path &path, const char **args, const char **envp,
if (Err)
return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
- Data_ = reinterpret_cast<void*>(PID);
+ PI.Pid = PID;
+
return true;
}
#endif
@@ -272,12 +293,13 @@ Program::Execute(const Path &path, const char **args, const char **envp,
}
// Execute!
+ std::string PathStr = Program;
if (envp != 0)
- execve(path.c_str(),
+ execve(PathStr.c_str(),
const_cast<char **>(args),
const_cast<char **>(envp));
else
- execv(path.c_str(),
+ execv(PathStr.c_str(),
const_cast<char **>(args));
// If the execve() failed, we should exit. Follow Unix protocol and
// return 127 if the executable was not found, and 126 otherwise.
@@ -293,62 +315,71 @@ Program::Execute(const Path &path, const char **args, const char **envp,
break;
}
- Data_ = reinterpret_cast<void*>(child);
+ PI.Pid = child;
return true;
}
-int
-Program::Wait(const sys::Path &path,
- unsigned secondsToWait,
- std::string* ErrMsg)
-{
+namespace llvm {
+
+ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
+ bool WaitUntilTerminates, std::string *ErrMsg) {
#ifdef HAVE_SYS_WAIT_H
struct sigaction Act, Old;
-
- if (Data_ == 0) {
- MakeErrMsg(ErrMsg, "Process not started!");
- return -1;
- }
-
- // Install a timeout handler. The handler itself does nothing, but the simple
- // fact of having a handler at all causes the wait below to return with EINTR,
- // unlike if we used SIG_IGN.
- if (secondsToWait) {
+ assert(PI.Pid && "invalid pid to wait on, process not started?");
+
+ int WaitPidOptions = 0;
+ pid_t ChildPid = PI.Pid;
+ if (WaitUntilTerminates) {
+ SecondsToWait = 0;
+ ChildPid = -1; // mimic a wait() using waitpid()
+ } else if (SecondsToWait) {
+ // Install a timeout handler. The handler itself does nothing, but the
+ // simple fact of having a handler at all causes the wait below to return
+ // with EINTR, unlike if we used SIG_IGN.
memset(&Act, 0, sizeof(Act));
Act.sa_handler = TimeOutHandler;
sigemptyset(&Act.sa_mask);
sigaction(SIGALRM, &Act, &Old);
- alarm(secondsToWait);
- }
+ alarm(SecondsToWait);
+ } else if (SecondsToWait == 0)
+ WaitPidOptions = WNOHANG;
// Parent process: Wait for the child process to terminate.
int status;
- uint64_t pid = reinterpret_cast<uint64_t>(Data_);
- pid_t child = static_cast<pid_t>(pid);
- while (waitpid(pid, &status, 0) != child)
- if (secondsToWait && errno == EINTR) {
- // Kill the child.
- kill(child, SIGKILL);
-
- // Turn off the alarm and restore the signal handler
- alarm(0);
- sigaction(SIGALRM, &Old, 0);
-
- // Wait for child to die
- if (wait(&status) != child)
- MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
- else
- MakeErrMsg(ErrMsg, "Child timed out", 0);
-
- return -2; // Timeout detected
- } else if (errno != EINTR) {
- MakeErrMsg(ErrMsg, "Error waiting for child process");
- return -1;
+ ProcessInfo WaitResult;
+ WaitResult.Pid = waitpid(ChildPid, &status, WaitPidOptions);
+ if (WaitResult.Pid != PI.Pid) {
+ if (WaitResult.Pid == 0) {
+ // Non-blocking wait.
+ return WaitResult;
+ } else {
+ if (SecondsToWait && errno == EINTR) {
+ // Kill the child.
+ kill(PI.Pid, SIGKILL);
+
+ // Turn off the alarm and restore the signal handler
+ alarm(0);
+ sigaction(SIGALRM, &Old, 0);
+
+ // Wait for child to die
+ if (wait(&status) != ChildPid)
+ MakeErrMsg(ErrMsg, "Child timed out but wouldn't die");
+ else
+ MakeErrMsg(ErrMsg, "Child timed out", 0);
+
+ WaitResult.ReturnCode = -2; // Timeout detected
+ return WaitResult;
+ } else if (errno != EINTR) {
+ MakeErrMsg(ErrMsg, "Error waiting for child process");
+ WaitResult.ReturnCode = -1;
+ return WaitResult;
+ }
}
+ }
// We exited normally without timeout, so turn off the timer.
- if (secondsToWait) {
+ if (SecondsToWait && !WaitUntilTerminates) {
alarm(0);
sigaction(SIGALRM, &Old, 0);
}
@@ -358,24 +389,19 @@ Program::Wait(const sys::Path &path,
int result = 0;
if (WIFEXITED(status)) {
result = WEXITSTATUS(status);
-#ifdef HAVE_POSIX_SPAWN
- // The posix_spawn child process returns 127 on any kind of error.
- // Following the POSIX convention for command-line tools (which posix_spawn
- // itself apparently does not), check to see if the failure was due to some
- // reason other than the file not existing, and return 126 in this case.
- bool Exists;
- if (result == 127 && !llvm::sys::fs::exists(path.str(), Exists) && Exists)
- result = 126;
-#endif
+ WaitResult.ReturnCode = result;
+
if (result == 127) {
if (ErrMsg)
*ErrMsg = llvm::sys::StrError(ENOENT);
- return -1;
+ WaitResult.ReturnCode = -1;
+ return WaitResult;
}
if (result == 126) {
if (ErrMsg)
*ErrMsg = "Program could not be executed";
- return -1;
+ WaitResult.ReturnCode = -1;
+ return WaitResult;
}
} else if (WIFSIGNALED(status)) {
if (ErrMsg) {
@@ -387,27 +413,27 @@ Program::Wait(const sys::Path &path,
}
// Return a special value to indicate that the process received an unhandled
// signal during execution as opposed to failing to execute.
- return -2;
+ WaitResult.ReturnCode = -2;
}
- return result;
#else
if (ErrMsg)
*ErrMsg = "Program::Wait is not implemented on this platform yet!";
- return -1;
+ WaitResult.ReturnCode = -2;
#endif
+ return WaitResult;
}
-error_code Program::ChangeStdinToBinary(){
+error_code sys::ChangeStdinToBinary(){
// Do nothing, as Unix doesn't differentiate between text and binary.
return make_error_code(errc::success);
}
-error_code Program::ChangeStdoutToBinary(){
+error_code sys::ChangeStdoutToBinary(){
// Do nothing, as Unix doesn't differentiate between text and binary.
return make_error_code(errc::success);
}
-error_code Program::ChangeStderrToBinary(){
+error_code sys::ChangeStderrToBinary(){
// Do nothing, as Unix doesn't differentiate between text and binary.
return make_error_code(errc::success);
}
@@ -432,5 +458,4 @@ bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) {
}
return true;
}
-
}
diff --git a/contrib/llvm/lib/Support/Unix/Signals.inc b/contrib/llvm/lib/Support/Unix/Signals.inc
index 64d1fc1..b4c78d6 100644
--- a/contrib/llvm/lib/Support/Unix/Signals.inc
+++ b/contrib/llvm/lib/Support/Unix/Signals.inc
@@ -55,8 +55,7 @@ static std::vector<std::pair<void(*)(void*), void*> > CallBacksToRun;
static const int IntSigs[] = {
SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
};
-static const int *const IntSigsEnd =
- IntSigs + sizeof(IntSigs) / sizeof(IntSigs[0]);
+static const int *const IntSigsEnd = array_endof(IntSigs);
// KillSigs - Signals that represent that we have a bug, and our prompt
// termination has been ordered.
@@ -75,8 +74,7 @@ static const int KillSigs[] = {
, SIGEMT
#endif
};
-static const int *const KillSigsEnd =
- KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]);
+static const int *const KillSigsEnd = array_endof(KillSigs);
static unsigned NumRegisteredSignals = 0;
static struct {
@@ -211,11 +209,11 @@ void llvm::sys::SetInterruptFunction(void (*IF)()) {
}
// RemoveFileOnSignal - The public API
-bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename,
+bool llvm::sys::RemoveFileOnSignal(StringRef Filename,
std::string* ErrMsg) {
SignalsMutex.acquire();
std::string *OldPtr = FilesToRemove.empty() ? 0 : &FilesToRemove[0];
- FilesToRemove.push_back(Filename.str());
+ FilesToRemove.push_back(Filename);
// We want to call 'c_str()' on every std::string in this vector so that if
// the underlying implementation requires a re-allocation, it happens here
@@ -235,10 +233,10 @@ bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename,
}
// DontRemoveFileOnSignal - The public API
-void llvm::sys::DontRemoveFileOnSignal(const sys::Path &Filename) {
+void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) {
SignalsMutex.acquire();
std::vector<std::string>::reverse_iterator RI =
- std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename.str());
+ std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename);
std::vector<std::string>::iterator I = FilesToRemove.end();
if (RI != FilesToRemove.rend())
I = FilesToRemove.erase(RI.base()-1);
@@ -335,7 +333,7 @@ static void PrintStackTraceSignalHandler(void *) {
void llvm::sys::PrintStackTraceOnErrorSignal() {
AddSignalHandler(PrintStackTraceSignalHandler, 0);
-#if defined(__APPLE__)
+#if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES)
// Environment variable to disable any kind of crash dialog.
if (getenv("LLVM_DISABLE_CRASH_REPORT")) {
mach_port_t self = mach_task_self();
@@ -361,7 +359,7 @@ void llvm::sys::PrintStackTraceOnErrorSignal() {
// the same linkage unit by just defining our own versions of the assert handler
// and abort.
-#ifdef __APPLE__
+#if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES)
#include <signal.h>
#include <pthread.h>
diff --git a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc
index 2b4c901..f14d0fa 100644
--- a/contrib/llvm/lib/Support/Unix/ThreadLocal.inc
+++ b/contrib/llvm/lib/Support/Unix/ThreadLocal.inc
@@ -18,7 +18,7 @@
namespace llvm {
using namespace sys;
-ThreadLocalImpl::ThreadLocalImpl() { }
+ThreadLocalImpl::ThreadLocalImpl() : data() { }
ThreadLocalImpl::~ThreadLocalImpl() { }
void ThreadLocalImpl::setInstance(const void* d) { data = const_cast<void*>(d);}
const void* ThreadLocalImpl::getInstance() { return data; }
diff --git a/contrib/llvm/lib/Support/Unix/TimeValue.inc b/contrib/llvm/lib/Support/Unix/TimeValue.inc
index df8558b..80532b0 100644
--- a/contrib/llvm/lib/Support/Unix/TimeValue.inc
+++ b/contrib/llvm/lib/Support/Unix/TimeValue.inc
@@ -22,18 +22,13 @@ namespace llvm {
using namespace sys;
std::string TimeValue::str() const {
- char buffer[32];
-
- time_t ourTime = time_t(this->toEpochTime());
-#ifdef __hpux
-// note that the following line needs -D_REENTRANT on HP-UX to be picked up
- asctime_r(localtime(&ourTime), buffer);
-#else
- ::asctime_r(::localtime(&ourTime), buffer);
-#endif
-
- std::string result(buffer);
- return result.substr(0,24);
+ time_t OurTime = time_t(this->toEpochTime());
+ struct tm Storage;
+ struct tm *LT = ::localtime_r(&OurTime, &Storage);
+ assert(LT);
+ char Buffer[25];
+ strftime(Buffer, 25, "%b %e %H:%M %Y", LT);
+ return std::string(Buffer);
}
TimeValue TimeValue::now() {
diff --git a/contrib/llvm/lib/Support/Unix/Unix.h b/contrib/llvm/lib/Support/Unix/Unix.h
index 051f56f..ba688e3 100644
--- a/contrib/llvm/lib/Support/Unix/Unix.h
+++ b/contrib/llvm/lib/Support/Unix/Unix.h
@@ -22,28 +22,22 @@
#include "llvm/Config/config.h" // Get autoconf configuration settings
#include "llvm/Support/Errno.h"
#include <algorithm>
+#include <assert.h>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
+#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
-#ifdef HAVE_ASSERT_H
-#include <assert.h>
-#endif
-
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
@@ -53,6 +47,10 @@
# include <sys/wait.h>
#endif
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+#endif
+
#ifndef WEXITSTATUS
# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif
diff --git a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc
index 83da82a..5a7b219 100644
--- a/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc
+++ b/contrib/llvm/lib/Support/Windows/DynamicLibrary.inc
@@ -71,7 +71,7 @@ extern "C" {
DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
std::string *errMsg) {
- SmartScopedLock<true> lock(getMutex());
+ SmartScopedLock<true> lock(*SymbolsMutex);
if (!filename) {
// When no file is specified, enumerate all DLLs and EXEs in the process.
@@ -83,8 +83,15 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
// This is mostly to ensure that the return value still shows up as "valid".
return DynamicLibrary(&OpenedHandles);
}
+
+ SmallVector<wchar_t, MAX_PATH> filenameUnicode;
+ if (error_code ec = windows::UTF8ToUTF16(filename, filenameUnicode)) {
+ SetLastError(ec.value());
+ MakeErrMsg(errMsg, std::string(filename) + ": Can't convert to UTF-16: ");
+ return DynamicLibrary();
+ }
- HMODULE a_handle = LoadLibrary(filename);
+ HMODULE a_handle = LoadLibraryW(filenameUnicode.data());
if (a_handle == 0) {
MakeErrMsg(errMsg, std::string(filename) + ": Can't open : ");
@@ -114,10 +121,10 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
#undef EXPLICIT_SYMBOL2
void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) {
- SmartScopedLock<true> Lock(getMutex());
+ SmartScopedLock<true> Lock(*SymbolsMutex);
// First check symbols added via AddSymbol().
- if (ExplicitSymbols) {
+ if (ExplicitSymbols.isConstructed()) {
StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);
if (i != ExplicitSymbols->end())
diff --git a/contrib/llvm/lib/Support/Windows/Memory.inc b/contrib/llvm/lib/Support/Windows/Memory.inc
index 4c5aebd..1260452 100644
--- a/contrib/llvm/lib/Support/Windows/Memory.inc
+++ b/contrib/llvm/lib/Support/Windows/Memory.inc
@@ -82,7 +82,7 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes,
uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) +
NearBlock->size()
- : NULL;
+ : 0;
// If the requested address is not aligned to the allocation granularity,
// round up to get beyond NearBlock. VirtualAlloc would have rounded down.
@@ -106,7 +106,7 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes,
MemoryBlock Result;
Result.Address = PA;
Result.Size = NumBlocks*Granularity;
- ;
+
if (Flags & MF_EXEC)
Memory::InvalidateInstructionCache(Result.Address, Result.Size);
diff --git a/contrib/llvm/lib/Support/Windows/Path.inc b/contrib/llvm/lib/Support/Windows/Path.inc
index f4898e6..0b39198 100644
--- a/contrib/llvm/lib/Support/Windows/Path.inc
+++ b/contrib/llvm/lib/Support/Windows/Path.inc
@@ -1,4 +1,4 @@
-//===- llvm/Support/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===//
+//===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,920 +7,1116 @@
//
//===----------------------------------------------------------------------===//
//
-// This file provides the Win32 specific implementation of the Path class.
+// This file implements the Windows specific implementation of the Path API.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only generic Win32 code that
-//=== is guaranteed to work on *all* Win32 variants.
+//=== WARNING: Implementation here must contain only generic Windows code that
+//=== is guaranteed to work on *all* Windows variants.
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/STLExtras.h"
#include "Windows.h"
-#include <cstdio>
-#include <malloc.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <sys/types.h>
-// We need to undo a macro defined in Windows.h, otherwise we won't compile:
-#undef CopyFile
-#undef GetCurrentDirectory
+#undef max
-// Windows happily accepts either forward or backward slashes, though any path
-// returned by a Win32 API will have backward slashes. As LLVM code basically
-// assumes forward slashes are used, backward slashs are converted where they
-// can be introduced into a path.
-//
-// Another invariant is that a path ends with a slash if and only if the path
-// is a root directory. Any other use of a trailing slash is stripped. Unlike
-// in Unix, Windows has a rather complicated notion of a root path and this
-// invariant helps simply the code.
-
-static void FlipBackSlashes(std::string& s) {
- for (size_t i = 0; i < s.size(); i++)
- if (s[i] == '\\')
- s[i] = '/';
-}
+// MinGW doesn't define this.
+#ifndef _ERRNO_T_DEFINED
+#define _ERRNO_T_DEFINED
+typedef int errno_t;
+#endif
-namespace llvm {
-namespace sys {
+#ifdef _MSC_VER
+# pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW.
+#endif
-const char PathSeparator = ';';
+using namespace llvm;
-StringRef Path::GetEXESuffix() {
- return "exe";
-}
+using llvm::sys::windows::UTF8ToUTF16;
+using llvm::sys::windows::UTF16ToUTF8;
-Path::Path(llvm::StringRef p)
- : path(p) {
- FlipBackSlashes(path);
-}
+namespace {
+ typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
+ /*__in*/ LPCWSTR lpSymlinkFileName,
+ /*__in*/ LPCWSTR lpTargetFileName,
+ /*__in*/ DWORD dwFlags);
-Path::Path(const char *StrStart, unsigned StrLen)
- : path(StrStart, StrLen) {
- FlipBackSlashes(path);
-}
+ PtrCreateSymbolicLinkW create_symbolic_link_api =
+ PtrCreateSymbolicLinkW(::GetProcAddress(
+ ::GetModuleHandleW(L"Kernel32.dll"), "CreateSymbolicLinkW"));
-Path&
-Path::operator=(StringRef that) {
- path.assign(that.data(), that.size());
- FlipBackSlashes(path);
- return *this;
-}
+ error_code TempDir(SmallVectorImpl<wchar_t> &result) {
+ retry_temp_dir:
+ DWORD len = ::GetTempPathW(result.capacity(), result.begin());
-bool
-Path::isValid() const {
- if (path.empty())
- return false;
+ if (len == 0)
+ return windows_error(::GetLastError());
- size_t len = path.size();
- // If there is a null character, it and all its successors are ignored.
- size_t pos = path.find_first_of('\0');
- if (pos != std::string::npos)
- len = pos;
-
- // If there is a colon, it must be the second character, preceded by a letter
- // and followed by something.
- pos = path.rfind(':',len);
- size_t rootslash = 0;
- if (pos != std::string::npos) {
- if (pos != 1 || !isalpha(static_cast<unsigned char>(path[0])) || len < 3)
- return false;
- rootslash = 2;
- }
+ if (len > result.capacity()) {
+ result.reserve(len);
+ goto retry_temp_dir;
+ }
- // Look for a UNC path, and if found adjust our notion of the root slash.
- if (len > 3 && path[0] == '/' && path[1] == '/') {
- rootslash = path.find('/', 2);
- if (rootslash == std::string::npos)
- rootslash = 0;
+ result.set_size(len);
+ return error_code::success();
}
- // Check for illegal characters.
- if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012"
- "\013\014\015\016\017\020\021\022\023\024\025\026"
- "\027\030\031\032\033\034\035\036\037")
- != std::string::npos)
- return false;
-
- // Remove trailing slash, unless it's a root slash.
- if (len > rootslash+1 && path[len-1] == '/')
- path.erase(--len);
-
- // Check each component for legality.
- for (pos = 0; pos < len; ++pos) {
- // A component may not end in a space.
- if (path[pos] == ' ') {
- if (pos+1 == len || path[pos+1] == '/' || path[pos+1] == '\0')
- return false;
+ bool is_separator(const wchar_t value) {
+ switch (value) {
+ case L'\\':
+ case L'/':
+ return true;
+ default:
+ return false;
}
+ }
+}
- // A component may not end in a period.
- if (path[pos] == '.') {
- if (pos+1 == len || path[pos+1] == '/') {
- // Unless it is the pseudo-directory "."...
- if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':')
- return true;
- // or "..".
- if (pos > 0 && path[pos-1] == '.') {
- if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':')
- return true;
- }
- return false;
+// FIXME: mode should be used here and default to user r/w only,
+// it currently comes in as a UNIX mode.
+static error_code createUniqueEntity(const Twine &model, int &result_fd,
+ SmallVectorImpl<char> &result_path,
+ bool makeAbsolute, unsigned mode,
+ FSEntity Type) {
+ // Use result_path as temp storage.
+ result_path.set_size(0);
+ StringRef m = model.toStringRef(result_path);
+
+ SmallVector<wchar_t, 128> model_utf16;
+ if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec;
+
+ if (makeAbsolute) {
+ // Make model absolute by prepending a temp directory if it's not already.
+ bool absolute = sys::path::is_absolute(m);
+
+ if (!absolute) {
+ SmallVector<wchar_t, 64> temp_dir;
+ if (error_code ec = TempDir(temp_dir)) return ec;
+ // Handle c: by removing it.
+ if (model_utf16.size() > 2 && model_utf16[1] == L':') {
+ model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2);
}
+ model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end());
}
}
- return true;
-}
+ // Replace '%' with random chars. From here on, DO NOT modify model. It may be
+ // needed if the randomly chosen path already exists.
+ SmallVector<wchar_t, 128> random_path_utf16;
+
+ // Get a Crypto Provider for CryptGenRandom.
+ HCRYPTPROV HCPC;
+ if (!::CryptAcquireContextW(&HCPC,
+ NULL,
+ NULL,
+ PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT))
+ return windows_error(::GetLastError());
+ ScopedCryptContext CryptoProvider(HCPC);
+
+retry_random_path:
+ random_path_utf16.set_size(0);
+ for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(),
+ e = model_utf16.end();
+ i != e; ++i) {
+ if (*i == L'%') {
+ BYTE val = 0;
+ if (!::CryptGenRandom(CryptoProvider, 1, &val))
+ return windows_error(::GetLastError());
+ random_path_utf16.push_back(L"0123456789abcdef"[val & 15]);
+ }
+ else
+ random_path_utf16.push_back(*i);
+ }
+ // Make random_path_utf16 null terminated.
+ random_path_utf16.push_back(0);
+ random_path_utf16.pop_back();
+
+ HANDLE TempFileHandle = INVALID_HANDLE_VALUE;
+
+ switch (Type) {
+ case FS_File: {
+ // Try to create + open the path.
+ TempFileHandle =
+ ::CreateFileW(random_path_utf16.begin(), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ, NULL,
+ // Return ERROR_FILE_EXISTS if the file
+ // already exists.
+ CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL);
+ if (TempFileHandle == INVALID_HANDLE_VALUE) {
+ // If the file existed, try again, otherwise, error.
+ error_code ec = windows_error(::GetLastError());
+ if (ec == windows_error::file_exists)
+ goto retry_random_path;
+
+ return ec;
+ }
-void Path::makeAbsolute() {
- TCHAR FullPath[MAX_PATH + 1] = {0};
- LPTSTR FilePart = NULL;
+ // Convert the Windows API file handle into a C-runtime handle.
+ int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0);
+ if (fd == -1) {
+ ::CloseHandle(TempFileHandle);
+ ::DeleteFileW(random_path_utf16.begin());
+ // MSDN doesn't say anything about _open_osfhandle setting errno or
+ // GetLastError(), so just return invalid_handle.
+ return windows_error::invalid_handle;
+ }
- DWORD RetLength = ::GetFullPathNameA(path.c_str(),
- sizeof(FullPath)/sizeof(FullPath[0]),
- FullPath, &FilePart);
+ result_fd = fd;
+ break;
+ }
- if (0 == RetLength) {
- // FIXME: Report the error GetLastError()
- assert(0 && "Unable to make absolute path!");
- } else if (RetLength > MAX_PATH) {
- // FIXME: Report too small buffer (needed RetLength bytes).
- assert(0 && "Unable to make absolute path!");
- } else {
- path = FullPath;
+ case FS_Name: {
+ DWORD attributes = ::GetFileAttributesW(random_path_utf16.begin());
+ if (attributes != INVALID_FILE_ATTRIBUTES)
+ goto retry_random_path;
+ error_code EC = make_error_code(windows_error(::GetLastError()));
+ if (EC != windows_error::file_not_found &&
+ EC != windows_error::path_not_found)
+ return EC;
+ break;
}
-}
-bool
-Path::isAbsolute(const char *NameStart, unsigned NameLen) {
- assert(NameStart);
- // FIXME: This does not handle correctly an absolute path starting from
- // a drive letter or in UNC format.
- switch (NameLen) {
- case 0:
- return false;
- case 1:
- case 2:
- return NameStart[0] == '/';
- default:
- return
- (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) ||
- (NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\'));
+ case FS_Dir:
+ if (!::CreateDirectoryW(random_path_utf16.begin(), NULL)) {
+ error_code EC = windows_error(::GetLastError());
+ if (EC != windows_error::already_exists)
+ return EC;
+ goto retry_random_path;
+ }
+ break;
}
-}
-bool
-Path::isAbsolute() const {
- // FIXME: This does not handle correctly an absolute path starting from
- // a drive letter or in UNC format.
- switch (path.length()) {
- case 0:
- return false;
- case 1:
- case 2:
- return path[0] == '/';
- default:
- return path[0] == '/' || (path[1] == ':' && path[2] == '/');
+ // Set result_path to the utf-8 representation of the path.
+ if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
+ random_path_utf16.size(), result_path)) {
+ switch (Type) {
+ case FS_File:
+ ::CloseHandle(TempFileHandle);
+ ::DeleteFileW(random_path_utf16.begin());
+ case FS_Name:
+ break;
+ case FS_Dir:
+ ::RemoveDirectoryW(random_path_utf16.begin());
+ break;
+ }
+ return ec;
}
+
+ return error_code::success();
}
-static Path *TempDirectory;
+namespace llvm {
+namespace sys {
+namespace fs {
-Path
-Path::GetTemporaryDirectory(std::string* ErrMsg) {
- if (TempDirectory) {
-#if defined(_MSC_VER)
- // Visual Studio gets confused and emits a diagnostic about calling exists,
- // even though this is the implementation for PathV1. Temporarily
- // disable the deprecated warning message
- #pragma warning(push)
- #pragma warning(disable:4996)
-#endif
- assert(TempDirectory->exists() && "Who has removed TempDirectory?");
-#if defined(_MSC_VER)
- #pragma warning(pop)
-#endif
- return *TempDirectory;
- }
+std::string getMainExecutable(const char *argv0, void *MainExecAddr) {
+ SmallVector<wchar_t, MAX_PATH> PathName;
+ DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity());
- char pathname[MAX_PATH];
- if (!GetTempPath(MAX_PATH, pathname)) {
- if (ErrMsg)
- *ErrMsg = "Can't determine temporary directory";
- return Path();
- }
+ // A zero return value indicates a failure other than insufficient space.
+ if (Size == 0)
+ return "";
- Path result;
- result.set(pathname);
+ // Insufficient space is determined by a return value equal to the size of
+ // the buffer passed in.
+ if (Size == PathName.capacity())
+ return "";
- // Append a subdirectory based on our process id so multiple LLVMs don't
- // step on each other's toes.
-#ifdef __MINGW32__
- // Mingw's Win32 header files are broken.
- sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId()));
-#else
- sprintf(pathname, "LLVM_%u", GetCurrentProcessId());
-#endif
- result.appendComponent(pathname);
-
- // If there's a directory left over from a previous LLVM execution that
- // happened to have the same process id, get rid of it.
- result.eraseFromDisk(true);
-
- // And finally (re-)create the empty directory.
- result.createDirectoryOnDisk(false);
- TempDirectory = new Path(result);
- return *TempDirectory;
-}
-
-// FIXME: the following set of functions don't map to Windows very well.
-Path
-Path::GetRootDirectory() {
- // This is the only notion that that Windows has of a root directory. Nothing
- // is here except for drives.
- return Path("file:///");
-}
-
-void
-Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) {
- char buff[MAX_PATH];
- // Generic form of C:\Windows\System32
- HRESULT res = SHGetFolderPathA(NULL,
- CSIDL_FLAG_CREATE | CSIDL_SYSTEM,
- NULL,
- SHGFP_TYPE_CURRENT,
- buff);
- if (res != S_OK) {
- assert(0 && "Failed to get system directory");
- return;
- }
- Paths.push_back(sys::Path(buff));
-
- // Reset buff.
- buff[0] = 0;
- // Generic form of C:\Windows
- res = SHGetFolderPathA(NULL,
- CSIDL_FLAG_CREATE | CSIDL_WINDOWS,
- NULL,
- SHGFP_TYPE_CURRENT,
- buff);
- if (res != S_OK) {
- assert(0 && "Failed to get windows directory");
- return;
- }
- Paths.push_back(sys::Path(buff));
-}
+ // On success, GetModuleFileNameW returns the number of characters written to
+ // the buffer not including the NULL terminator.
+ PathName.set_size(Size);
-void
-Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) {
- char * env_var = getenv("LLVM_LIB_SEARCH_PATH");
- if (env_var != 0) {
- getPathList(env_var,Paths);
- }
-#ifdef LLVM_LIBDIR
- {
- Path tmpPath;
- if (tmpPath.set(LLVM_LIBDIR))
- if (tmpPath.canRead())
- Paths.push_back(tmpPath);
- }
-#endif
- GetSystemLibraryPaths(Paths);
-}
+ // Convert the result from UTF-16 to UTF-8.
+ SmallVector<char, MAX_PATH> PathNameUTF8;
+ if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8))
+ return "";
-Path
-Path::GetUserHomeDirectory() {
- char buff[MAX_PATH];
- HRESULT res = SHGetFolderPathA(NULL,
- CSIDL_FLAG_CREATE | CSIDL_APPDATA,
- NULL,
- SHGFP_TYPE_CURRENT,
- buff);
- if (res != S_OK)
- assert(0 && "Failed to get user home directory");
- return Path(buff);
+ return std::string(PathNameUTF8.data());
}
-Path
-Path::GetCurrentDirectory() {
- char pathname[MAX_PATH];
- ::GetCurrentDirectoryA(MAX_PATH,pathname);
- return Path(pathname);
+UniqueID file_status::getUniqueID() const {
+ // The file is uniquely identified by the volume serial number along
+ // with the 64-bit file identifier.
+ uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) |
+ static_cast<uint64_t>(FileIndexLow);
+
+ return UniqueID(VolumeSerialNumber, FileID);
}
-/// GetMainExecutable - Return the path to the main executable, given the
-/// value of argv[0] from program startup.
-Path Path::GetMainExecutable(const char *argv0, void *MainAddr) {
- char pathname[MAX_PATH];
- DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH);
- return ret != MAX_PATH ? Path(pathname) : Path();
+TimeValue file_status::getLastModificationTime() const {
+ ULARGE_INTEGER UI;
+ UI.LowPart = LastWriteTimeLow;
+ UI.HighPart = LastWriteTimeHigh;
+
+ TimeValue Ret;
+ Ret.fromWin32Time(UI.QuadPart);
+ return Ret;
}
+error_code current_path(SmallVectorImpl<char> &result) {
+ SmallVector<wchar_t, MAX_PATH> cur_path;
+ DWORD len = MAX_PATH;
-// FIXME: the above set of functions don't map to Windows very well.
+ do {
+ cur_path.reserve(len);
+ len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data());
+
+ // A zero return value indicates a failure other than insufficient space.
+ if (len == 0)
+ return windows_error(::GetLastError());
+ // If there's insufficient space, the len returned is larger than the len
+ // given.
+ } while (len > cur_path.capacity());
-StringRef Path::getDirname() const {
- return getDirnameCharSep(path, "/");
+ // On success, GetCurrentDirectoryW returns the number of characters not
+ // including the null-terminator.
+ cur_path.set_size(len);
+ return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result);
}
-StringRef
-Path::getBasename() const {
- // Find the last slash
- size_t slash = path.rfind('/');
- if (slash == std::string::npos)
- slash = 0;
- else
- slash++;
+error_code create_directory(const Twine &path, bool &existed) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
- size_t dot = path.rfind('.');
- if (dot == std::string::npos || dot < slash)
- return StringRef(path).substr(slash);
- else
- return StringRef(path).substr(slash, dot - slash);
-}
+ if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
+ path_utf16))
+ return ec;
-StringRef
-Path::getSuffix() const {
- // Find the last slash
- size_t slash = path.rfind('/');
- if (slash == std::string::npos)
- slash = 0;
- else
- slash++;
+ if (!::CreateDirectoryW(path_utf16.begin(), NULL)) {
+ error_code ec = windows_error(::GetLastError());
+ if (ec == windows_error::already_exists)
+ existed = true;
+ else
+ return ec;
+ } else
+ existed = false;
- size_t dot = path.rfind('.');
- if (dot == std::string::npos || dot < slash)
- return StringRef("");
- else
- return StringRef(path).substr(dot + 1);
+ return error_code::success();
}
-bool
-Path::exists() const {
- DWORD attr = GetFileAttributes(path.c_str());
- return attr != INVALID_FILE_ATTRIBUTES;
-}
+error_code create_hard_link(const Twine &to, const Twine &from) {
+ // Get arguments.
+ SmallString<128> from_storage;
+ SmallString<128> to_storage;
+ StringRef f = from.toStringRef(from_storage);
+ StringRef t = to.toStringRef(to_storage);
+
+ // Convert to utf-16.
+ SmallVector<wchar_t, 128> wide_from;
+ SmallVector<wchar_t, 128> wide_to;
+ if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
+ if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-bool
-Path::isDirectory() const {
- DWORD attr = GetFileAttributes(path.c_str());
- return (attr != INVALID_FILE_ATTRIBUTES) &&
- (attr & FILE_ATTRIBUTE_DIRECTORY);
+ if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL))
+ return windows_error(::GetLastError());
+
+ return error_code::success();
}
-bool
-Path::isSymLink() const {
- DWORD attributes = GetFileAttributes(path.c_str());
+error_code create_symlink(const Twine &to, const Twine &from) {
+ // Only do it if the function is available at runtime.
+ if (!create_symbolic_link_api)
+ return make_error_code(errc::function_not_supported);
- if (attributes == INVALID_FILE_ATTRIBUTES)
- // There's no sane way to report this :(.
- assert(0 && "GetFileAttributes returned INVALID_FILE_ATTRIBUTES");
+ // Get arguments.
+ SmallString<128> from_storage;
+ SmallString<128> to_storage;
+ StringRef f = from.toStringRef(from_storage);
+ StringRef t = to.toStringRef(to_storage);
- // This isn't exactly what defines a NTFS symlink, but it is only true for
- // paths that act like a symlink.
- return attributes & FILE_ATTRIBUTE_REPARSE_POINT;
-}
+ // Convert to utf-16.
+ SmallVector<wchar_t, 128> wide_from;
+ SmallVector<wchar_t, 128> wide_to;
+ if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
+ if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-bool
-Path::canRead() const {
- // FIXME: take security attributes into account.
- DWORD attr = GetFileAttributes(path.c_str());
- return attr != INVALID_FILE_ATTRIBUTES;
-}
+ if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0))
+ return windows_error(::GetLastError());
-bool
-Path::canWrite() const {
- // FIXME: take security attributes into account.
- DWORD attr = GetFileAttributes(path.c_str());
- return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY);
+ return error_code::success();
}
-bool
-Path::canExecute() const {
- // FIXME: take security attributes into account.
- DWORD attr = GetFileAttributes(path.c_str());
- return attr != INVALID_FILE_ATTRIBUTES;
+error_code remove(const Twine &path, bool &existed) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
+
+ file_status st;
+ error_code EC = status(path, st);
+ if (EC) {
+ if (EC == windows_error::file_not_found ||
+ EC == windows_error::path_not_found) {
+ existed = false;
+ return error_code::success();
+ }
+ return EC;
+ }
+
+ if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
+ path_utf16))
+ return ec;
+
+ if (st.type() == file_type::directory_file) {
+ if (!::RemoveDirectoryW(c_str(path_utf16))) {
+ error_code ec = windows_error(::GetLastError());
+ if (ec != windows_error::file_not_found)
+ return ec;
+ existed = false;
+ } else
+ existed = true;
+ } else {
+ if (!::DeleteFileW(c_str(path_utf16))) {
+ error_code ec = windows_error(::GetLastError());
+ if (ec != windows_error::file_not_found)
+ return ec;
+ existed = false;
+ } else
+ existed = true;
+ }
+
+ return error_code::success();
}
-bool
-Path::isRegularFile() const {
- bool res;
- if (fs::is_regular_file(path, res))
- return false;
- return res;
+error_code rename(const Twine &from, const Twine &to) {
+ // Get arguments.
+ SmallString<128> from_storage;
+ SmallString<128> to_storage;
+ StringRef f = from.toStringRef(from_storage);
+ StringRef t = to.toStringRef(to_storage);
+
+ // Convert to utf-16.
+ SmallVector<wchar_t, 128> wide_from;
+ SmallVector<wchar_t, 128> wide_to;
+ if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
+ if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
+
+ error_code ec = error_code::success();
+ for (int i = 0; i < 2000; i++) {
+ if (::MoveFileExW(wide_from.begin(), wide_to.begin(),
+ MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
+ return error_code::success();
+ ec = windows_error(::GetLastError());
+ if (ec != windows_error::access_denied)
+ break;
+ // Retry MoveFile() at ACCESS_DENIED.
+ // System scanners (eg. indexer) might open the source file when
+ // It is written and closed.
+ ::Sleep(1);
+ }
+
+ return ec;
}
-StringRef
-Path::getLast() const {
- // Find the last slash
- size_t pos = path.rfind('/');
+error_code resize_file(const Twine &path, uint64_t size) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
- // Handle the corner cases
- if (pos == std::string::npos)
- return path;
+ if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
+ path_utf16))
+ return ec;
- // If the last character is a slash, we have a root directory
- if (pos == path.length()-1)
- return path;
+ int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE);
+ if (fd == -1)
+ return error_code(errno, generic_category());
+#ifdef HAVE__CHSIZE_S
+ errno_t error = ::_chsize_s(fd, size);
+#else
+ errno_t error = ::_chsize(fd, size);
+#endif
+ ::close(fd);
+ return error_code(error, generic_category());
+}
- // Return everything after the last slash
- return StringRef(path).substr(pos+1);
+error_code exists(const Twine &path, bool &result) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
+
+ if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
+ path_utf16))
+ return ec;
+
+ DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
+
+ if (attributes == INVALID_FILE_ATTRIBUTES) {
+ // See if the file didn't actually exist.
+ error_code ec = make_error_code(windows_error(::GetLastError()));
+ if (ec != windows_error::file_not_found &&
+ ec != windows_error::path_not_found)
+ return ec;
+ result = false;
+ } else
+ result = true;
+ return error_code::success();
}
-const FileStatus *
-PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const {
- if (!fsIsValid || update) {
- WIN32_FILE_ATTRIBUTE_DATA fi;
- if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
- MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) +
- ": Can't get status: ");
- return 0;
- }
+bool can_write(const Twine &Path) {
+ // FIXME: take security attributes into account.
+ SmallString<128> PathStorage;
+ SmallVector<wchar_t, 128> PathUtf16;
- status.fileSize = fi.nFileSizeHigh;
- status.fileSize <<= sizeof(fi.nFileSizeHigh)*8;
- status.fileSize += fi.nFileSizeLow;
+ if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
+ return false;
- status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777;
- status.user = 9999; // Not applicable to Windows, so...
- status.group = 9999; // Not applicable to Windows, so...
+ DWORD Attr = ::GetFileAttributesW(PathUtf16.begin());
+ return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY);
+}
- // FIXME: this is only unique if the file is accessed by the same file path.
- // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode
- // numbers, but the concept doesn't exist in Windows.
- status.uniqueID = 0;
- for (unsigned i = 0; i < path.length(); ++i)
- status.uniqueID += path[i];
+bool can_execute(const Twine &Path) {
+ SmallString<128> PathStorage;
+ SmallVector<wchar_t, 128> PathUtf16;
- ULARGE_INTEGER ui;
- ui.LowPart = fi.ftLastWriteTime.dwLowDateTime;
- ui.HighPart = fi.ftLastWriteTime.dwHighDateTime;
- status.modTime.fromWin32Time(ui.QuadPart);
+ if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
+ return false;
- status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
- fsIsValid = true;
- }
- return &status;
+ DWORD Attr = ::GetFileAttributesW(PathUtf16.begin());
+ return Attr != INVALID_FILE_ATTRIBUTES;
}
-bool Path::makeReadableOnDisk(std::string* ErrMsg) {
- // All files are readable on Windows (ignoring security attributes).
- return false;
+bool equivalent(file_status A, file_status B) {
+ assert(status_known(A) && status_known(B));
+ return A.FileIndexHigh == B.FileIndexHigh &&
+ A.FileIndexLow == B.FileIndexLow &&
+ A.FileSizeHigh == B.FileSizeHigh &&
+ A.FileSizeLow == B.FileSizeLow &&
+ A.LastWriteTimeHigh == B.LastWriteTimeHigh &&
+ A.LastWriteTimeLow == B.LastWriteTimeLow &&
+ A.VolumeSerialNumber == B.VolumeSerialNumber;
}
-bool Path::makeWriteableOnDisk(std::string* ErrMsg) {
- DWORD attr = GetFileAttributes(path.c_str());
+error_code equivalent(const Twine &A, const Twine &B, bool &result) {
+ file_status fsA, fsB;
+ if (error_code ec = status(A, fsA)) return ec;
+ if (error_code ec = status(B, fsB)) return ec;
+ result = equivalent(fsA, fsB);
+ return error_code::success();
+}
- // If it doesn't exist, we're done.
- if (attr == INVALID_FILE_ATTRIBUTES)
- return false;
+static bool isReservedName(StringRef path) {
+ // This list of reserved names comes from MSDN, at:
+ // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
+ static const char *sReservedNames[] = { "nul", "con", "prn", "aux",
+ "com1", "com2", "com3", "com4", "com5", "com6",
+ "com7", "com8", "com9", "lpt1", "lpt2", "lpt3",
+ "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" };
+
+ // First, check to see if this is a device namespace, which always
+ // starts with \\.\, since device namespaces are not legal file paths.
+ if (path.startswith("\\\\.\\"))
+ return true;
- if (attr & FILE_ATTRIBUTE_READONLY) {
- if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) {
- MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: ");
+ // Then compare against the list of ancient reserved names
+ for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) {
+ if (path.equals_lower(sReservedNames[i]))
return true;
- }
}
- return false;
-}
-bool Path::makeExecutableOnDisk(std::string* ErrMsg) {
- // All files are executable on Windows (ignoring security attributes).
+ // The path isn't what we consider reserved.
return false;
}
-bool
-Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const {
- WIN32_FILE_ATTRIBUTE_DATA fi;
- if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
- MakeErrMsg(ErrMsg, path + ": can't get status of file");
- return true;
+static error_code getStatus(HANDLE FileHandle, file_status &Result) {
+ if (FileHandle == INVALID_HANDLE_VALUE)
+ goto handle_status_error;
+
+ switch (::GetFileType(FileHandle)) {
+ default:
+ llvm_unreachable("Don't know anything about this file type");
+ case FILE_TYPE_UNKNOWN: {
+ DWORD Err = ::GetLastError();
+ if (Err != NO_ERROR)
+ return windows_error(Err);
+ Result = file_status(file_type::type_unknown);
+ return error_code::success();
+ }
+ case FILE_TYPE_DISK:
+ break;
+ case FILE_TYPE_CHAR:
+ Result = file_status(file_type::character_file);
+ return error_code::success();
+ case FILE_TYPE_PIPE:
+ Result = file_status(file_type::fifo_file);
+ return error_code::success();
}
- if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
- if (ErrMsg)
- *ErrMsg = path + ": not a directory";
- return true;
+ BY_HANDLE_FILE_INFORMATION Info;
+ 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.ftLastWriteTime.dwHighDateTime,
+ Info.ftLastWriteTime.dwLowDateTime,
+ Info.dwVolumeSerialNumber, Info.nFileSizeHigh,
+ Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow);
+ return error_code::success();
}
- result.clear();
- WIN32_FIND_DATA fd;
- std::string searchpath = path;
- if (path.size() == 0 || searchpath[path.size()-1] == '/')
- searchpath += "*";
+handle_status_error:
+ error_code EC = windows_error(::GetLastError());
+ if (EC == windows_error::file_not_found ||
+ EC == windows_error::path_not_found)
+ Result = file_status(file_type::file_not_found);
+ else if (EC == windows_error::sharing_violation)
+ Result = file_status(file_type::type_unknown);
else
- searchpath += "/*";
+ Result = file_status(file_type::status_error);
+ return EC;
+}
- HANDLE h = FindFirstFile(searchpath.c_str(), &fd);
- if (h == INVALID_HANDLE_VALUE) {
- if (GetLastError() == ERROR_FILE_NOT_FOUND)
- return true; // not really an error, now is it?
- MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
- return true;
- }
+error_code status(const Twine &path, file_status &result) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
- do {
- if (fd.cFileName[0] == '.')
- continue;
- Path aPath(path);
- aPath.appendComponent(&fd.cFileName[0]);
- result.insert(aPath);
- } while (FindNextFile(h, &fd));
-
- DWORD err = GetLastError();
- FindClose(h);
- if (err != ERROR_NO_MORE_FILES) {
- SetLastError(err);
- MakeErrMsg(ErrMsg, path + ": Can't read directory: ");
- return true;
+ StringRef path8 = path.toStringRef(path_storage);
+ if (isReservedName(path8)) {
+ result = file_status(file_type::character_file);
+ return error_code::success();
}
- return false;
-}
-bool
-Path::set(StringRef a_path) {
- if (a_path.empty())
- return false;
- std::string save(path);
- path = a_path;
- FlipBackSlashes(path);
- if (!isValid()) {
- path = save;
- return false;
+ if (error_code ec = UTF8ToUTF16(path8, path_utf16))
+ return ec;
+
+ DWORD attr = ::GetFileAttributesW(path_utf16.begin());
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ return getStatus(INVALID_HANDLE_VALUE, result);
+
+ // 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);
}
- return true;
+
+ 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);
+
+ return getStatus(h, result);
}
-bool
-Path::appendComponent(StringRef name) {
- if (name.empty())
- return false;
- std::string save(path);
- if (!path.empty()) {
- size_t last = path.size() - 1;
- if (path[last] != '/')
- path += '/';
- }
- path += name;
- if (!isValid()) {
- path = save;
- return false;
- }
- return true;
+error_code status(int FD, file_status &Result) {
+ HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ return getStatus(FileHandle, Result);
}
-bool
-Path::eraseComponent() {
- size_t slashpos = path.rfind('/',path.size());
- if (slashpos == path.size() - 1 || slashpos == std::string::npos)
- return false;
- std::string save(path);
- path.erase(slashpos);
- if (!isValid()) {
- path = save;
- return false;
- }
- return true;
+error_code setLastModificationAndAccessTime(int FD, TimeValue Time) {
+ ULARGE_INTEGER UI;
+ UI.QuadPart = Time.toWin32Time();
+ FILETIME FT;
+ FT.dwLowDateTime = UI.LowPart;
+ FT.dwHighDateTime = UI.HighPart;
+ HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ if (!SetFileTime(FileHandle, NULL, &FT, &FT))
+ return windows_error(::GetLastError());
+ return error_code::success();
}
-bool
-Path::eraseSuffix() {
- size_t dotpos = path.rfind('.',path.size());
- size_t slashpos = path.rfind('/',path.size());
- if (dotpos != std::string::npos) {
- if (slashpos == std::string::npos || dotpos > slashpos+1) {
- std::string save(path);
- path.erase(dotpos, path.size()-dotpos);
- if (!isValid()) {
- path = save;
- return false;
- }
- return true;
- }
+error_code get_magic(const Twine &path, uint32_t len,
+ SmallVectorImpl<char> &result) {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
+ result.set_size(0);
+
+ // Convert path to UTF-16.
+ if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
+ path_utf16))
+ return ec;
+
+ // Open file.
+ HANDLE file = ::CreateFileW(c_str(path_utf16),
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_READONLY,
+ NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ return windows_error(::GetLastError());
+
+ // Allocate buffer.
+ result.reserve(len);
+
+ // Get magic!
+ DWORD bytes_read = 0;
+ BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL);
+ error_code ec = windows_error(::GetLastError());
+ ::CloseHandle(file);
+ if (!read_success || (bytes_read != len)) {
+ // Set result size to the number of bytes read if it's valid.
+ if (bytes_read <= len)
+ result.set_size(bytes_read);
+ // ERROR_HANDLE_EOF is mapped to errc::value_too_large.
+ return ec;
}
- return false;
-}
-inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) {
- if (ErrMsg)
- *ErrMsg = std::string(pathname) + ": " + std::string(msg);
- return true;
+ result.set_size(len);
+ return error_code::success();
}
-bool
-Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) {
- // Get a writeable copy of the path name
- size_t len = path.length();
- char *pathname = reinterpret_cast<char *>(_alloca(len+2));
- path.copy(pathname, len);
- pathname[len] = 0;
-
- // Make sure it ends with a slash.
- if (len == 0 || pathname[len - 1] != '/') {
- pathname[len] = '/';
- pathname[++len] = 0;
+error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) {
+ FileDescriptor = FD;
+ // Make sure that the requested size fits within SIZE_T.
+ if (Size > std::numeric_limits<SIZE_T>::max()) {
+ if (FileDescriptor) {
+ if (CloseFD)
+ _close(FileDescriptor);
+ } else
+ ::CloseHandle(FileHandle);
+ return make_error_code(errc::invalid_argument);
}
- // Determine starting point for initial / search.
- char *next = pathname;
- if (pathname[0] == '/' && pathname[1] == '/') {
- // Skip host name.
- next = strchr(pathname+2, '/');
- if (next == NULL)
- return PathMsg(ErrMsg, pathname, "badly formed remote directory");
+ DWORD flprotect;
+ switch (Mode) {
+ case readonly: flprotect = PAGE_READONLY; break;
+ case readwrite: flprotect = PAGE_READWRITE; break;
+ case priv: flprotect = PAGE_WRITECOPY; break;
+ }
- // Skip share name.
- next = strchr(next+1, '/');
- if (next == NULL)
- return PathMsg(ErrMsg, pathname,"badly formed remote directory");
+ FileMappingHandle =
+ ::CreateFileMappingW(FileHandle, 0, flprotect,
+ (Offset + Size) >> 32,
+ (Offset + Size) & 0xffffffff,
+ 0);
+ if (FileMappingHandle == NULL) {
+ error_code ec = windows_error(GetLastError());
+ if (FileDescriptor) {
+ if (CloseFD)
+ _close(FileDescriptor);
+ } else
+ ::CloseHandle(FileHandle);
+ return ec;
+ }
- next++;
- if (*next == 0)
- return PathMsg(ErrMsg, pathname, "badly formed remote directory");
+ DWORD dwDesiredAccess;
+ switch (Mode) {
+ case readonly: dwDesiredAccess = FILE_MAP_READ; break;
+ case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break;
+ case priv: dwDesiredAccess = FILE_MAP_COPY; break;
+ }
+ Mapping = ::MapViewOfFile(FileMappingHandle,
+ dwDesiredAccess,
+ Offset >> 32,
+ Offset & 0xffffffff,
+ Size);
+ if (Mapping == NULL) {
+ error_code ec = windows_error(GetLastError());
+ ::CloseHandle(FileMappingHandle);
+ if (FileDescriptor) {
+ if (CloseFD)
+ _close(FileDescriptor);
+ } else
+ ::CloseHandle(FileHandle);
+ return ec;
+ }
- } else {
- if (pathname[1] == ':')
- next += 2; // skip drive letter
- if (*next == '/')
- next++; // skip root directory
- }
-
- // If we're supposed to create intermediate directories
- if (create_parents) {
- // Loop through the directory components until we're done
- while (*next) {
- next = strchr(next, '/');
- *next = 0;
- if (!CreateDirectory(pathname, NULL) &&
- GetLastError() != ERROR_ALREADY_EXISTS)
- return MakeErrMsg(ErrMsg,
- std::string(pathname) + ": Can't create directory: ");
- *next++ = '/';
- }
- } else {
- // Drop trailing slash.
- pathname[len-1] = 0;
- if (!CreateDirectory(pathname, NULL) &&
- GetLastError() != ERROR_ALREADY_EXISTS) {
- return MakeErrMsg(ErrMsg, std::string(pathname) +
- ": Can't create directory: ");
+ if (Size == 0) {
+ MEMORY_BASIC_INFORMATION mbi;
+ SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi));
+ if (Result == 0) {
+ error_code ec = windows_error(GetLastError());
+ ::UnmapViewOfFile(Mapping);
+ ::CloseHandle(FileMappingHandle);
+ if (FileDescriptor) {
+ if (CloseFD)
+ _close(FileDescriptor);
+ } else
+ ::CloseHandle(FileHandle);
+ return ec;
}
+ Size = mbi.RegionSize;
}
- return false;
-}
-
-bool
-Path::createFileOnDisk(std::string* ErrMsg) {
- // Create the file
- HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (h == INVALID_HANDLE_VALUE)
- return MakeErrMsg(ErrMsg, path + ": Can't create file: ");
- CloseHandle(h);
- return false;
+ // Close all the handles except for the view. It will keep the other handles
+ // alive.
+ ::CloseHandle(FileMappingHandle);
+ if (FileDescriptor) {
+ if (CloseFD)
+ _close(FileDescriptor); // Also closes FileHandle.
+ } else
+ ::CloseHandle(FileHandle);
+ return error_code::success();
}
-bool
-Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const {
- WIN32_FILE_ATTRIBUTE_DATA fi;
- if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi))
- return true;
+mapped_file_region::mapped_file_region(const Twine &path,
+ mapmode mode,
+ uint64_t length,
+ uint64_t offset,
+ error_code &ec)
+ : Mode(mode)
+ , Size(length)
+ , Mapping()
+ , FileDescriptor()
+ , FileHandle(INVALID_HANDLE_VALUE)
+ , FileMappingHandle() {
+ SmallString<128> path_storage;
+ SmallVector<wchar_t, 128> path_utf16;
+
+ // Convert path to UTF-16.
+ if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)))
+ return;
- if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- // If it doesn't exist, we're done.
- bool Exists;
- if (fs::exists(path, Exists) || !Exists)
- return false;
+ // Get file handle for creating a file mapping.
+ FileHandle = ::CreateFileW(c_str(path_utf16),
+ Mode == readonly ? GENERIC_READ
+ : GENERIC_READ | GENERIC_WRITE,
+ Mode == readonly ? FILE_SHARE_READ
+ : 0,
+ 0,
+ Mode == readonly ? OPEN_EXISTING
+ : OPEN_ALWAYS,
+ Mode == readonly ? FILE_ATTRIBUTE_READONLY
+ : FILE_ATTRIBUTE_NORMAL,
+ 0);
+ if (FileHandle == INVALID_HANDLE_VALUE) {
+ ec = windows_error(::GetLastError());
+ return;
+ }
- char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3));
- int lastchar = path.length() - 1 ;
- path.copy(pathname, lastchar+1);
-
- // Make path end with '/*'.
- if (pathname[lastchar] != '/')
- pathname[++lastchar] = '/';
- pathname[lastchar+1] = '*';
- pathname[lastchar+2] = 0;
-
- if (remove_contents) {
- WIN32_FIND_DATA fd;
- HANDLE h = FindFirstFile(pathname, &fd);
-
- // It's a bad idea to alter the contents of a directory while enumerating
- // its contents. So build a list of its contents first, then destroy them.
-
- if (h != INVALID_HANDLE_VALUE) {
- std::vector<Path> list;
-
- do {
- if (strcmp(fd.cFileName, ".") == 0)
- continue;
- if (strcmp(fd.cFileName, "..") == 0)
- continue;
-
- Path aPath(path);
- aPath.appendComponent(&fd.cFileName[0]);
- list.push_back(aPath);
- } while (FindNextFile(h, &fd));
-
- DWORD err = GetLastError();
- FindClose(h);
- if (err != ERROR_NO_MORE_FILES) {
- SetLastError(err);
- return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
- }
-
- for (std::vector<Path>::iterator I = list.begin(); I != list.end();
- ++I) {
- Path &aPath = *I;
- aPath.eraseFromDisk(true);
- }
- } else {
- if (GetLastError() != ERROR_FILE_NOT_FOUND)
- return MakeErrMsg(ErrStr, path + ": Can't read directory: ");
- }
- }
+ FileDescriptor = 0;
+ ec = init(FileDescriptor, true, offset);
+ if (ec) {
+ Mapping = FileMappingHandle = 0;
+ FileHandle = INVALID_HANDLE_VALUE;
+ FileDescriptor = 0;
+ }
+}
- pathname[lastchar] = 0;
- if (!RemoveDirectory(pathname))
- return MakeErrMsg(ErrStr,
- std::string(pathname) + ": Can't destroy directory: ");
- return false;
- } else {
- // Read-only files cannot be deleted on Windows. Must remove the read-only
- // attribute first.
- if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
- if (!SetFileAttributes(path.c_str(),
- fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
- return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
- }
+mapped_file_region::mapped_file_region(int fd,
+ bool closefd,
+ mapmode mode,
+ uint64_t length,
+ uint64_t offset,
+ error_code &ec)
+ : Mode(mode)
+ , Size(length)
+ , Mapping()
+ , FileDescriptor(fd)
+ , FileHandle(INVALID_HANDLE_VALUE)
+ , FileMappingHandle() {
+ FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+ if (FileHandle == INVALID_HANDLE_VALUE) {
+ if (closefd)
+ _close(FileDescriptor);
+ FileDescriptor = 0;
+ ec = make_error_code(errc::bad_file_descriptor);
+ return;
+ }
- if (!DeleteFile(path.c_str()))
- return MakeErrMsg(ErrStr, path + ": Can't destroy file: ");
- return false;
+ ec = init(FileDescriptor, closefd, offset);
+ if (ec) {
+ Mapping = FileMappingHandle = 0;
+ FileHandle = INVALID_HANDLE_VALUE;
+ FileDescriptor = 0;
}
}
-bool Path::getMagicNumber(std::string& Magic, unsigned len) const {
- assert(len < 1024 && "Request for magic string too long");
- char* buf = reinterpret_cast<char*>(alloca(len));
+mapped_file_region::~mapped_file_region() {
+ if (Mapping)
+ ::UnmapViewOfFile(Mapping);
+}
+
+#if LLVM_HAS_RVALUE_REFERENCES
+mapped_file_region::mapped_file_region(mapped_file_region &&other)
+ : Mode(other.Mode)
+ , Size(other.Size)
+ , Mapping(other.Mapping)
+ , FileDescriptor(other.FileDescriptor)
+ , FileHandle(other.FileHandle)
+ , FileMappingHandle(other.FileMappingHandle) {
+ other.Mapping = other.FileMappingHandle = 0;
+ other.FileHandle = INVALID_HANDLE_VALUE;
+ other.FileDescriptor = 0;
+}
+#endif
- HANDLE h = CreateFile(path.c_str(),
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (h == INVALID_HANDLE_VALUE)
- return false;
+mapped_file_region::mapmode mapped_file_region::flags() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return Mode;
+}
- DWORD nRead = 0;
- BOOL ret = ReadFile(h, buf, len, &nRead, NULL);
- CloseHandle(h);
+uint64_t mapped_file_region::size() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return Size;
+}
- if (!ret || nRead != len)
- return false;
+char *mapped_file_region::data() const {
+ assert(Mode != readonly && "Cannot get non const data for readonly mapping!");
+ assert(Mapping && "Mapping failed but used anyway!");
+ return reinterpret_cast<char*>(Mapping);
+}
- Magic = std::string(buf, len);
- return true;
+const char *mapped_file_region::const_data() const {
+ assert(Mapping && "Mapping failed but used anyway!");
+ return reinterpret_cast<const char*>(Mapping);
}
-bool
-Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) {
- if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING))
- return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path
- + "': ");
- return false;
+int mapped_file_region::alignment() {
+ SYSTEM_INFO SysInfo;
+ ::GetSystemInfo(&SysInfo);
+ return SysInfo.dwAllocationGranularity;
}
-bool
-Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const {
- // FIXME: should work on directories also.
- if (!si.isFile) {
- return true;
- }
+error_code detail::directory_iterator_construct(detail::DirIterState &it,
+ StringRef path){
+ SmallVector<wchar_t, 128> path_utf16;
- HANDLE h = CreateFile(path.c_str(),
- FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (h == INVALID_HANDLE_VALUE)
- return true;
+ if (error_code ec = UTF8ToUTF16(path,
+ path_utf16))
+ return ec;
- BY_HANDLE_FILE_INFORMATION bhfi;
- if (!GetFileInformationByHandle(h, &bhfi)) {
- DWORD err = GetLastError();
- CloseHandle(h);
- SetLastError(err);
- return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: ");
- }
-
- ULARGE_INTEGER ui;
- ui.QuadPart = si.modTime.toWin32Time();
- FILETIME ft;
- ft.dwLowDateTime = ui.LowPart;
- ft.dwHighDateTime = ui.HighPart;
- BOOL ret = SetFileTime(h, NULL, &ft, &ft);
- DWORD err = GetLastError();
- CloseHandle(h);
- if (!ret) {
- SetLastError(err);
- return MakeErrMsg(ErrMsg, path + ": SetFileTime: ");
- }
-
- // Best we can do with Unix permission bits is to interpret the owner
- // writable bit.
- if (si.mode & 0200) {
- if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
- if (!SetFileAttributes(path.c_str(),
- bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
- return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
- }
+ // Convert path to the format that Windows is happy with.
+ if (path_utf16.size() > 0 &&
+ !is_separator(path_utf16[path.size() - 1]) &&
+ path_utf16[path.size() - 1] != L':') {
+ path_utf16.push_back(L'\\');
+ path_utf16.push_back(L'*');
} else {
- if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
- if (!SetFileAttributes(path.c_str(),
- bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
- return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: ");
- }
+ path_utf16.push_back(L'*');
}
- return false;
+ // Get the first directory entry.
+ WIN32_FIND_DATAW FirstFind;
+ ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
+ if (!FindHandle)
+ return windows_error(::GetLastError());
+
+ size_t FilenameLen = ::wcslen(FirstFind.cFileName);
+ while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') ||
+ (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' &&
+ FirstFind.cFileName[1] == L'.'))
+ if (!::FindNextFileW(FindHandle, &FirstFind)) {
+ error_code ec = windows_error(::GetLastError());
+ // Check for end.
+ if (ec == windows_error::no_more_files)
+ return detail::directory_iterator_destruct(it);
+ return ec;
+ } else
+ FilenameLen = ::wcslen(FirstFind.cFileName);
+
+ // Construct the current directory entry.
+ SmallString<128> directory_entry_name_utf8;
+ if (error_code ec = UTF16ToUTF8(FirstFind.cFileName,
+ ::wcslen(FirstFind.cFileName),
+ directory_entry_name_utf8))
+ return ec;
+
+ it.IterationHandle = intptr_t(FindHandle.take());
+ SmallString<128> directory_entry_path(path);
+ path::append(directory_entry_path, directory_entry_name_utf8.str());
+ it.CurrentEntry = directory_entry(directory_entry_path.str());
+
+ return error_code::success();
}
-bool
-CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) {
- // Can't use CopyFile macro defined in Windows.h because it would mess up the
- // above line. We use the expansion it would have in a non-UNICODE build.
- if (!::CopyFileA(Src.c_str(), Dest.c_str(), false))
- return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() +
- "' to '" + Dest.str() + "': ");
- return false;
+error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
+ if (it.IterationHandle != 0)
+ // Closes the handle if it's valid.
+ ScopedFindHandle close(HANDLE(it.IterationHandle));
+ it.IterationHandle = 0;
+ it.CurrentEntry = directory_entry();
+ return error_code::success();
}
-bool
-Path::makeUnique(bool reuse_current, std::string* ErrMsg) {
- bool Exists;
- if (reuse_current && (fs::exists(path, Exists) || !Exists))
- return false; // File doesn't exist already, just use it!
-
- // Reserve space for -XXXXXX at the end.
- char *FNBuffer = (char*) alloca(path.size()+8);
- unsigned offset = path.size();
- path.copy(FNBuffer, offset);
-
- // Find a numeric suffix that isn't used by an existing file. Assume there
- // won't be more than 1 million files with the same prefix. Probably a safe
- // bet.
- static int FCounter = -1;
- if (FCounter < 0) {
- // Give arbitrary initial seed.
- // FIXME: We should use sys::fs::unique_file() in future.
- LARGE_INTEGER cnt64;
- DWORD x = GetCurrentProcessId();
- x = (x << 16) | (x >> 16);
- if (QueryPerformanceCounter(&cnt64)) // RDTSC
- x ^= cnt64.HighPart ^ cnt64.LowPart;
- FCounter = x % 1000000;
+error_code detail::directory_iterator_increment(detail::DirIterState &it) {
+ WIN32_FIND_DATAW FindData;
+ if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
+ error_code ec = windows_error(::GetLastError());
+ // Check for end.
+ if (ec == windows_error::no_more_files)
+ return detail::directory_iterator_destruct(it);
+ return ec;
}
- do {
- sprintf(FNBuffer+offset, "-%06u", FCounter);
- if (++FCounter > 999999)
- FCounter = 0;
- path = FNBuffer;
- } while (!fs::exists(path, Exists) && Exists);
- return false;
-}
-bool
-Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) {
- // Make this into a unique file name
- makeUnique(reuse_current, ErrMsg);
+ size_t FilenameLen = ::wcslen(FindData.cFileName);
+ if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') ||
+ (FilenameLen == 2 && FindData.cFileName[0] == L'.' &&
+ FindData.cFileName[1] == L'.'))
+ return directory_iterator_increment(it);
- // Now go and create it
- HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (h == INVALID_HANDLE_VALUE)
- return MakeErrMsg(ErrMsg, path + ": can't create file");
+ SmallString<128> directory_entry_path_utf8;
+ if (error_code ec = UTF16ToUTF8(FindData.cFileName,
+ ::wcslen(FindData.cFileName),
+ directory_entry_path_utf8))
+ return ec;
- CloseHandle(h);
- return false;
+ it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
+ return error_code::success();
}
-/// MapInFilePages - Not yet implemented on win32.
-const char *Path::MapInFilePages(int FD, size_t FileSize, off_t Offset) {
- return 0;
+error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
+ bool map_writable, void *&result) {
+ assert(0 && "NOT IMPLEMENTED");
+ return windows_error::invalid_function;
}
-/// MapInFilePages - Not yet implemented on win32.
-void Path::UnMapFilePages(const char *Base, size_t FileSize) {
+error_code unmap_file_pages(void *base, size_t size) {
assert(0 && "NOT IMPLEMENTED");
+ return windows_error::invalid_function;
+}
+
+error_code openFileForRead(const Twine &Name, int &ResultFD) {
+ SmallString<128> PathStorage;
+ SmallVector<wchar_t, 128> PathUTF16;
+
+ if (error_code EC = UTF8ToUTF16(Name.toStringRef(PathStorage),
+ PathUTF16))
+ return EC;
+
+ HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (H == INVALID_HANDLE_VALUE) {
+ error_code EC = windows_error(::GetLastError());
+ // Provide a better error message when trying to open directories.
+ // This only runs if we failed to open the file, so there is probably
+ // no performances issues.
+ if (EC != windows_error::access_denied)
+ return EC;
+ if (is_directory(Name))
+ return error_code(errc::is_a_directory, posix_category());
+ return EC;
+ }
+
+ int FD = ::_open_osfhandle(intptr_t(H), 0);
+ if (FD == -1) {
+ ::CloseHandle(H);
+ return windows_error::invalid_handle;
+ }
+
+ ResultFD = FD;
+ return error_code::success();
+}
+
+error_code openFileForWrite(const Twine &Name, int &ResultFD,
+ sys::fs::OpenFlags Flags, unsigned Mode) {
+ // Verify that we don't have both "append" and "excl".
+ assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
+ "Cannot specify both 'excl' and 'append' file creation flags!");
+
+ SmallString<128> PathStorage;
+ SmallVector<wchar_t, 128> PathUTF16;
+
+ if (error_code EC = UTF8ToUTF16(Name.toStringRef(PathStorage),
+ PathUTF16))
+ return EC;
+
+ DWORD CreationDisposition;
+ if (Flags & F_Excl)
+ CreationDisposition = CREATE_NEW;
+ else if (Flags & F_Append)
+ CreationDisposition = OPEN_ALWAYS;
+ else
+ CreationDisposition = CREATE_ALWAYS;
+
+ HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (H == INVALID_HANDLE_VALUE) {
+ error_code EC = windows_error(::GetLastError());
+ // Provide a better error message when trying to open directories.
+ // This only runs if we failed to open the file, so there is probably
+ // no performances issues.
+ if (EC != windows_error::access_denied)
+ return EC;
+ if (is_directory(Name))
+ return error_code(errc::is_a_directory, posix_category());
+ return EC;
+ }
+
+ int OpenFlags = 0;
+ if (Flags & F_Append)
+ OpenFlags |= _O_APPEND;
+
+ if (!(Flags & F_Binary))
+ OpenFlags |= _O_TEXT;
+
+ int FD = ::_open_osfhandle(intptr_t(H), OpenFlags);
+ if (FD == -1) {
+ ::CloseHandle(H);
+ return windows_error::invalid_handle;
+ }
+
+ ResultFD = FD;
+ return error_code::success();
}
+} // end namespace fs
+namespace windows {
+llvm::error_code UTF8ToUTF16(llvm::StringRef utf8,
+ llvm::SmallVectorImpl<wchar_t> &utf16) {
+ int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+ utf8.begin(), utf8.size(),
+ utf16.begin(), 0);
+
+ if (len == 0)
+ return llvm::windows_error(::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());
+
+ if (len == 0)
+ return llvm::windows_error(::GetLastError());
+
+ // Make utf16 null terminated.
+ utf16.push_back(0);
+ utf16.pop_back();
+
+ return llvm::error_code::success();
}
+
+llvm::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
+ llvm::SmallVectorImpl<char> &utf8) {
+ // Get length.
+ int len = ::WideCharToMultiByte(CP_UTF8, 0,
+ utf16, utf16_len,
+ utf8.begin(), 0,
+ NULL, NULL);
+
+ if (len == 0)
+ return llvm::windows_error(::GetLastError());
+
+ utf8.reserve(len);
+ utf8.set_size(len);
+
+ // Now do the actual conversion.
+ len = ::WideCharToMultiByte(CP_UTF8, 0,
+ utf16, utf16_len,
+ utf8.data(), utf8.size(),
+ NULL, NULL);
+
+ if (len == 0)
+ return llvm::windows_error(::GetLastError());
+
+ // Make utf8 null terminated.
+ utf8.push_back(0);
+ utf8.pop_back();
+
+ return llvm::error_code::success();
}
+} // end namespace windows
+} // end namespace sys
+} // end namespace llvm
diff --git a/contrib/llvm/lib/Support/Windows/PathV2.inc b/contrib/llvm/lib/Support/Windows/PathV2.inc
deleted file mode 100644
index 23f3d14..0000000
--- a/contrib/llvm/lib/Support/Windows/PathV2.inc
+++ /dev/null
@@ -1,1022 +0,0 @@
-//===- llvm/Support/Windows/PathV2.inc - Windows Path Impl ------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the Windows specific implementation of the PathV2 API.
-//
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
-//=== WARNING: Implementation here must contain only generic Windows code that
-//=== is guaranteed to work on *all* Windows variants.
-//===----------------------------------------------------------------------===//
-
-#include "Windows.h"
-#include <fcntl.h>
-#include <io.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#undef max
-
-// MinGW doesn't define this.
-#ifndef _ERRNO_T_DEFINED
-#define _ERRNO_T_DEFINED
-typedef int errno_t;
-#endif
-
-using namespace llvm;
-
-namespace {
- typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
- /*__in*/ LPCWSTR lpSymlinkFileName,
- /*__in*/ LPCWSTR lpTargetFileName,
- /*__in*/ DWORD dwFlags);
-
- PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW(
- ::GetProcAddress(::GetModuleHandleA("kernel32.dll"),
- "CreateSymbolicLinkW"));
-
- error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16) {
- int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
- utf8.begin(), utf8.size(),
- utf16.begin(), 0);
-
- if (len == 0)
- return windows_error(::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());
-
- if (len == 0)
- return windows_error(::GetLastError());
-
- // Make utf16 null terminated.
- utf16.push_back(0);
- utf16.pop_back();
-
- return error_code::success();
- }
-
- error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
- SmallVectorImpl<char> &utf8) {
- // Get length.
- int len = ::WideCharToMultiByte(CP_UTF8, 0,
- utf16, utf16_len,
- utf8.begin(), 0,
- NULL, NULL);
-
- if (len == 0)
- return windows_error(::GetLastError());
-
- utf8.reserve(len);
- utf8.set_size(len);
-
- // Now do the actual conversion.
- len = ::WideCharToMultiByte(CP_UTF8, 0,
- utf16, utf16_len,
- utf8.data(), utf8.size(),
- NULL, NULL);
-
- if (len == 0)
- return windows_error(::GetLastError());
-
- // Make utf8 null terminated.
- utf8.push_back(0);
- utf8.pop_back();
-
- return error_code::success();
- }
-
- error_code TempDir(SmallVectorImpl<wchar_t> &result) {
- retry_temp_dir:
- DWORD len = ::GetTempPathW(result.capacity(), result.begin());
-
- if (len == 0)
- return windows_error(::GetLastError());
-
- if (len > result.capacity()) {
- result.reserve(len);
- goto retry_temp_dir;
- }
-
- result.set_size(len);
- return error_code::success();
- }
-
- bool is_separator(const wchar_t value) {
- switch (value) {
- case L'\\':
- case L'/':
- return true;
- default:
- return false;
- }
- }
-}
-
-namespace llvm {
-namespace sys {
-namespace fs {
-
-error_code current_path(SmallVectorImpl<char> &result) {
- SmallVector<wchar_t, 128> cur_path;
- cur_path.reserve(128);
-retry_cur_dir:
- DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data());
-
- // A zero return value indicates a failure other than insufficient space.
- if (len == 0)
- return windows_error(::GetLastError());
-
- // If there's insufficient space, the len returned is larger than the len
- // given.
- if (len > cur_path.capacity()) {
- cur_path.reserve(len);
- goto retry_cur_dir;
- }
-
- cur_path.set_size(len);
- // cur_path now holds the current directory in utf-16. Convert to utf-8.
-
- // Find out how much space we need. Sadly, this function doesn't return the
- // size needed unless you tell it the result size is 0, which means you
- // _always_ have to call it twice.
- len = ::WideCharToMultiByte(CP_UTF8, 0,
- cur_path.data(), cur_path.size(),
- result.data(), 0,
- NULL, NULL);
-
- if (len == 0)
- return make_error_code(windows_error(::GetLastError()));
-
- result.reserve(len);
- result.set_size(len);
- // Now do the actual conversion.
- len = ::WideCharToMultiByte(CP_UTF8, 0,
- cur_path.data(), cur_path.size(),
- result.data(), result.size(),
- NULL, NULL);
- if (len == 0)
- return windows_error(::GetLastError());
-
- return error_code::success();
-}
-
-error_code copy_file(const Twine &from, const Twine &to, copy_option copt) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toStringRef(from_storage);
- StringRef t = to.toStringRef(to_storage);
-
- // Convert to utf-16.
- SmallVector<wchar_t, 128> wide_from;
- SmallVector<wchar_t, 128> wide_to;
- if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
- if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-
- // Copy the file.
- BOOL res = ::CopyFileW(wide_from.begin(), wide_to.begin(),
- copt != copy_option::overwrite_if_exists);
-
- if (res == 0)
- return windows_error(::GetLastError());
-
- return error_code::success();
-}
-
-error_code create_directory(const Twine &path, bool &existed) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- if (!::CreateDirectoryW(path_utf16.begin(), NULL)) {
- error_code ec = windows_error(::GetLastError());
- if (ec == windows_error::already_exists)
- existed = true;
- else
- return ec;
- } else
- existed = false;
-
- return error_code::success();
-}
-
-error_code create_hard_link(const Twine &to, const Twine &from) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toStringRef(from_storage);
- StringRef t = to.toStringRef(to_storage);
-
- // Convert to utf-16.
- SmallVector<wchar_t, 128> wide_from;
- SmallVector<wchar_t, 128> wide_to;
- if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
- if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-
- if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL))
- return windows_error(::GetLastError());
-
- return error_code::success();
-}
-
-error_code create_symlink(const Twine &to, const Twine &from) {
- // Only do it if the function is available at runtime.
- if (!create_symbolic_link_api)
- return make_error_code(errc::function_not_supported);
-
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toStringRef(from_storage);
- StringRef t = to.toStringRef(to_storage);
-
- // Convert to utf-16.
- SmallVector<wchar_t, 128> wide_from;
- SmallVector<wchar_t, 128> wide_to;
- if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
- if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-
- if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0))
- return windows_error(::GetLastError());
-
- return error_code::success();
-}
-
-error_code remove(const Twine &path, bool &existed) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- file_status st;
- if (error_code ec = status(path, st))
- return ec;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- if (st.type() == file_type::directory_file) {
- if (!::RemoveDirectoryW(c_str(path_utf16))) {
- error_code ec = windows_error(::GetLastError());
- if (ec != windows_error::file_not_found)
- return ec;
- existed = false;
- } else
- existed = true;
- } else {
- if (!::DeleteFileW(c_str(path_utf16))) {
- error_code ec = windows_error(::GetLastError());
- if (ec != windows_error::file_not_found)
- return ec;
- existed = false;
- } else
- existed = true;
- }
-
- return error_code::success();
-}
-
-error_code rename(const Twine &from, const Twine &to) {
- // Get arguments.
- SmallString<128> from_storage;
- SmallString<128> to_storage;
- StringRef f = from.toStringRef(from_storage);
- StringRef t = to.toStringRef(to_storage);
-
- // Convert to utf-16.
- SmallVector<wchar_t, 128> wide_from;
- SmallVector<wchar_t, 128> wide_to;
- if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec;
- if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec;
-
- error_code ec = error_code::success();
- for (int i = 0; i < 2000; i++) {
- if (::MoveFileExW(wide_from.begin(), wide_to.begin(),
- MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
- return error_code::success();
- ec = windows_error(::GetLastError());
- if (ec != windows_error::access_denied)
- break;
- // Retry MoveFile() at ACCESS_DENIED.
- // System scanners (eg. indexer) might open the source file when
- // It is written and closed.
- ::Sleep(1);
- }
-
- return ec;
-}
-
-error_code resize_file(const Twine &path, uint64_t size) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE);
- if (fd == -1)
- return error_code(errno, generic_category());
-#ifdef HAVE__CHSIZE_S
- errno_t error = ::_chsize_s(fd, size);
-#else
- errno_t error = ::_chsize(fd, size);
-#endif
- ::close(fd);
- return error_code(error, generic_category());
-}
-
-error_code exists(const Twine &path, bool &result) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
-
- if (attributes == INVALID_FILE_ATTRIBUTES) {
- // See if the file didn't actually exist.
- error_code ec = make_error_code(windows_error(::GetLastError()));
- if (ec != windows_error::file_not_found &&
- ec != windows_error::path_not_found)
- return ec;
- result = false;
- } else
- result = true;
- return error_code::success();
-}
-
-bool equivalent(file_status A, file_status B) {
- assert(status_known(A) && status_known(B));
- return A.FileIndexHigh == B.FileIndexHigh &&
- A.FileIndexLow == B.FileIndexLow &&
- A.FileSizeHigh == B.FileSizeHigh &&
- A.FileSizeLow == B.FileSizeLow &&
- A.LastWriteTimeHigh == B.LastWriteTimeHigh &&
- A.LastWriteTimeLow == B.LastWriteTimeLow &&
- A.VolumeSerialNumber == B.VolumeSerialNumber;
-}
-
-error_code equivalent(const Twine &A, const Twine &B, bool &result) {
- file_status fsA, fsB;
- if (error_code ec = status(A, fsA)) return ec;
- if (error_code ec = status(B, fsB)) return ec;
- result = equivalent(fsA, fsB);
- return error_code::success();
-}
-
-error_code file_size(const Twine &path, uint64_t &result) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- WIN32_FILE_ATTRIBUTE_DATA FileData;
- if (!::GetFileAttributesExW(path_utf16.begin(),
- ::GetFileExInfoStandard,
- &FileData))
- return windows_error(::GetLastError());
-
- result =
- (uint64_t(FileData.nFileSizeHigh) << (sizeof(FileData.nFileSizeLow) * 8))
- + FileData.nFileSizeLow;
-
- return error_code::success();
-}
-
-static bool isReservedName(StringRef path) {
- // This list of reserved names comes from MSDN, at:
- // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
- static const char *sReservedNames[] = { "nul", "con", "prn", "aux",
- "com1", "com2", "com3", "com4", "com5", "com6",
- "com7", "com8", "com9", "lpt1", "lpt2", "lpt3",
- "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" };
-
- // First, check to see if this is a device namespace, which always
- // starts with \\.\, since device namespaces are not legal file paths.
- if (path.startswith("\\\\.\\"))
- return true;
-
- // Then compare against the list of ancient reserved names
- for (size_t i = 0; i < sizeof(sReservedNames) / sizeof(const char *); ++i) {
- if (path.equals_lower(sReservedNames[i]))
- return true;
- }
-
- // The path isn't what we consider reserved.
- return false;
-}
-
-error_code status(const Twine &path, file_status &result) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- StringRef path8 = path.toStringRef(path_storage);
- if (isReservedName(path8)) {
- result = file_status(file_type::character_file);
- return error_code::success();
- }
-
- if (error_code ec = UTF8ToUTF16(path8, path_utf16))
- return ec;
-
- DWORD attr = ::GetFileAttributesW(path_utf16.begin());
- if (attr == INVALID_FILE_ATTRIBUTES)
- goto handle_status_error;
-
- // 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)
- goto handle_status_error;
- }
-
- if (attr & FILE_ATTRIBUTE_DIRECTORY)
- result = file_status(file_type::directory_file);
- else {
- result = file_status(file_type::regular_file);
- 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)
- goto handle_status_error;
- BY_HANDLE_FILE_INFORMATION Info;
- if (!::GetFileInformationByHandle(h, &Info))
- goto handle_status_error;
- result.FileIndexHigh = Info.nFileIndexHigh;
- result.FileIndexLow = Info.nFileIndexLow;
- result.FileSizeHigh = Info.nFileSizeHigh;
- result.FileSizeLow = Info.nFileSizeLow;
- result.LastWriteTimeHigh = Info.ftLastWriteTime.dwHighDateTime;
- result.LastWriteTimeLow = Info.ftLastWriteTime.dwLowDateTime;
- result.VolumeSerialNumber = Info.dwVolumeSerialNumber;
- }
-
- return error_code::success();
-
-handle_status_error:
- error_code ec = windows_error(::GetLastError());
- if (ec == windows_error::file_not_found ||
- ec == windows_error::path_not_found)
- result = file_status(file_type::file_not_found);
- else if (ec == windows_error::sharing_violation)
- result = file_status(file_type::type_unknown);
- else {
- result = file_status(file_type::status_error);
- return ec;
- }
-
- return error_code::success();
-}
-
-
-// Modifies permissions on a file.
-error_code permissions(const Twine &path, perms prms) {
-#if 0 // verify code below before enabling:
- // If the permissions bits are not trying to modify
- // "write" permissions, there is nothing to do.
- if (!(prms & (owner_write|group_write|others_write)))
- return error_code::success();
-
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
-
- if (prms & add_perms) {
- attributes &= ~FILE_ATTRIBUTE_READONLY;
- }
- else if (prms & remove_perms) {
- attributes |= FILE_ATTRIBUTE_READONLY;
- }
- else {
- assert(0 && "neither add_perms or remove_perms is set");
- }
-
- if ( ! ::SetFileAttributesW(path_utf16.begin(), attributes))
- return windows_error(::GetLastError());
-#endif
- return error_code::success();
-}
-
-
-// FIXME: mode should be used here and default to user r/w only,
-// it currently comes in as a UNIX mode.
-error_code unique_file(const Twine &model, int &result_fd,
- SmallVectorImpl<char> &result_path,
- bool makeAbsolute, unsigned mode) {
- // Use result_path as temp storage.
- result_path.set_size(0);
- StringRef m = model.toStringRef(result_path);
-
- SmallVector<wchar_t, 128> model_utf16;
- if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec;
-
- if (makeAbsolute) {
- // Make model absolute by prepending a temp directory if it's not already.
- bool absolute = path::is_absolute(m);
-
- if (!absolute) {
- SmallVector<wchar_t, 64> temp_dir;
- if (error_code ec = TempDir(temp_dir)) return ec;
- // Handle c: by removing it.
- if (model_utf16.size() > 2 && model_utf16[1] == L':') {
- model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2);
- }
- model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end());
- }
- }
-
- // Replace '%' with random chars. From here on, DO NOT modify model. It may be
- // needed if the randomly chosen path already exists.
- SmallVector<wchar_t, 128> random_path_utf16;
-
- // Get a Crypto Provider for CryptGenRandom.
- HCRYPTPROV HCPC;
- if (!::CryptAcquireContextW(&HCPC,
- NULL,
- NULL,
- PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT))
- return windows_error(::GetLastError());
- ScopedCryptContext CryptoProvider(HCPC);
-
-retry_random_path:
- random_path_utf16.set_size(0);
- for (SmallVectorImpl<wchar_t>::const_iterator i = model_utf16.begin(),
- e = model_utf16.end();
- i != e; ++i) {
- if (*i == L'%') {
- BYTE val = 0;
- if (!::CryptGenRandom(CryptoProvider, 1, &val))
- return windows_error(::GetLastError());
- random_path_utf16.push_back("0123456789abcdef"[val & 15]);
- }
- else
- random_path_utf16.push_back(*i);
- }
- // Make random_path_utf16 null terminated.
- random_path_utf16.push_back(0);
- random_path_utf16.pop_back();
-
- // Make sure we don't fall into an infinite loop by constantly trying
- // to create the parent path.
- bool TriedToCreateParent = false;
-
- // Try to create + open the path.
-retry_create_file:
- HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ,
- NULL,
- // Return ERROR_FILE_EXISTS if the file
- // already exists.
- CREATE_NEW,
- FILE_ATTRIBUTE_TEMPORARY,
- NULL);
- if (TempFileHandle == INVALID_HANDLE_VALUE) {
- // If the file existed, try again, otherwise, error.
- error_code ec = windows_error(::GetLastError());
- if (ec == windows_error::file_exists)
- goto retry_random_path;
- // Check for non-existing parent directories.
- if (ec == windows_error::path_not_found && !TriedToCreateParent) {
- TriedToCreateParent = true;
-
- // Create the directories using result_path as temp storage.
- if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
- random_path_utf16.size(), result_path))
- return ec;
- StringRef p(result_path.begin(), result_path.size());
- SmallString<64> dir_to_create;
- for (path::const_iterator i = path::begin(p),
- e = --path::end(p); i != e; ++i) {
- path::append(dir_to_create, *i);
- bool Exists;
- if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec;
- if (!Exists) {
- // If c: doesn't exist, bail.
- if (i->endswith(":"))
- return ec;
-
- SmallVector<wchar_t, 64> dir_to_create_utf16;
- if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16))
- return ec;
-
- // Create the directory.
- if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL))
- return windows_error(::GetLastError());
- }
- }
- goto retry_create_file;
- }
- return ec;
- }
-
- // Set result_path to the utf-8 representation of the path.
- if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
- random_path_utf16.size(), result_path)) {
- ::CloseHandle(TempFileHandle);
- ::DeleteFileW(random_path_utf16.begin());
- return ec;
- }
-
- // Convert the Windows API file handle into a C-runtime handle.
- int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0);
- if (fd == -1) {
- ::CloseHandle(TempFileHandle);
- ::DeleteFileW(random_path_utf16.begin());
- // MSDN doesn't say anything about _open_osfhandle setting errno or
- // GetLastError(), so just return invalid_handle.
- return windows_error::invalid_handle;
- }
-
- result_fd = fd;
- return error_code::success();
-}
-
-error_code get_magic(const Twine &path, uint32_t len,
- SmallVectorImpl<char> &result) {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
- result.set_size(0);
-
- // Convert path to UTF-16.
- if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
- path_utf16))
- return ec;
-
- // Open file.
- HANDLE file = ::CreateFileW(c_str(path_utf16),
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_READONLY,
- NULL);
- if (file == INVALID_HANDLE_VALUE)
- return windows_error(::GetLastError());
-
- // Allocate buffer.
- result.reserve(len);
-
- // Get magic!
- DWORD bytes_read = 0;
- BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL);
- error_code ec = windows_error(::GetLastError());
- ::CloseHandle(file);
- if (!read_success || (bytes_read != len)) {
- // Set result size to the number of bytes read if it's valid.
- if (bytes_read <= len)
- result.set_size(bytes_read);
- // ERROR_HANDLE_EOF is mapped to errc::value_too_large.
- return ec;
- }
-
- result.set_size(len);
- return error_code::success();
-}
-
-error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) {
- FileDescriptor = FD;
- // Make sure that the requested size fits within SIZE_T.
- if (Size > std::numeric_limits<SIZE_T>::max()) {
- if (FileDescriptor) {
- if (CloseFD)
- _close(FileDescriptor);
- } else
- ::CloseHandle(FileHandle);
- return make_error_code(errc::invalid_argument);
- }
-
- DWORD flprotect;
- switch (Mode) {
- case readonly: flprotect = PAGE_READONLY; break;
- case readwrite: flprotect = PAGE_READWRITE; break;
- case priv: flprotect = PAGE_WRITECOPY; break;
- default: llvm_unreachable("invalid mapping mode");
- }
-
- FileMappingHandle = ::CreateFileMapping(FileHandle,
- 0,
- flprotect,
- Size >> 32,
- Size & 0xffffffff,
- 0);
- if (FileMappingHandle == NULL) {
- error_code ec = windows_error(GetLastError());
- if (FileDescriptor) {
- if (CloseFD)
- _close(FileDescriptor);
- } else
- ::CloseHandle(FileHandle);
- return ec;
- }
-
- DWORD dwDesiredAccess;
- switch (Mode) {
- case readonly: dwDesiredAccess = FILE_MAP_READ; break;
- case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break;
- case priv: dwDesiredAccess = FILE_MAP_COPY; break;
- default: llvm_unreachable("invalid mapping mode");
- }
- Mapping = ::MapViewOfFile(FileMappingHandle,
- dwDesiredAccess,
- Offset >> 32,
- Offset & 0xffffffff,
- Size);
- if (Mapping == NULL) {
- error_code ec = windows_error(GetLastError());
- ::CloseHandle(FileMappingHandle);
- if (FileDescriptor) {
- if (CloseFD)
- _close(FileDescriptor);
- } else
- ::CloseHandle(FileHandle);
- return ec;
- }
-
- if (Size == 0) {
- MEMORY_BASIC_INFORMATION mbi;
- SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi));
- if (Result == 0) {
- error_code ec = windows_error(GetLastError());
- ::UnmapViewOfFile(Mapping);
- ::CloseHandle(FileMappingHandle);
- if (FileDescriptor) {
- if (CloseFD)
- _close(FileDescriptor);
- } else
- ::CloseHandle(FileHandle);
- return ec;
- }
- Size = mbi.RegionSize;
- }
-
- // Close all the handles except for the view. It will keep the other handles
- // alive.
- ::CloseHandle(FileMappingHandle);
- if (FileDescriptor) {
- if (CloseFD)
- _close(FileDescriptor); // Also closes FileHandle.
- } else
- ::CloseHandle(FileHandle);
- return error_code::success();
-}
-
-mapped_file_region::mapped_file_region(const Twine &path,
- mapmode mode,
- uint64_t length,
- uint64_t offset,
- error_code &ec)
- : Mode(mode)
- , Size(length)
- , Mapping()
- , FileDescriptor()
- , FileHandle(INVALID_HANDLE_VALUE)
- , FileMappingHandle() {
- SmallString<128> path_storage;
- SmallVector<wchar_t, 128> path_utf16;
-
- // Convert path to UTF-16.
- if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)))
- return;
-
- // Get file handle for creating a file mapping.
- FileHandle = ::CreateFileW(c_str(path_utf16),
- Mode == readonly ? GENERIC_READ
- : GENERIC_READ | GENERIC_WRITE,
- Mode == readonly ? FILE_SHARE_READ
- : 0,
- 0,
- Mode == readonly ? OPEN_EXISTING
- : OPEN_ALWAYS,
- Mode == readonly ? FILE_ATTRIBUTE_READONLY
- : FILE_ATTRIBUTE_NORMAL,
- 0);
- if (FileHandle == INVALID_HANDLE_VALUE) {
- ec = windows_error(::GetLastError());
- return;
- }
-
- FileDescriptor = 0;
- ec = init(FileDescriptor, true, offset);
- if (ec) {
- Mapping = FileMappingHandle = 0;
- FileHandle = INVALID_HANDLE_VALUE;
- FileDescriptor = 0;
- }
-}
-
-mapped_file_region::mapped_file_region(int fd,
- bool closefd,
- mapmode mode,
- uint64_t length,
- uint64_t offset,
- error_code &ec)
- : Mode(mode)
- , Size(length)
- , Mapping()
- , FileDescriptor(fd)
- , FileHandle(INVALID_HANDLE_VALUE)
- , FileMappingHandle() {
- FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
- if (FileHandle == INVALID_HANDLE_VALUE) {
- if (closefd)
- _close(FileDescriptor);
- FileDescriptor = 0;
- ec = make_error_code(errc::bad_file_descriptor);
- return;
- }
-
- ec = init(FileDescriptor, closefd, offset);
- if (ec) {
- Mapping = FileMappingHandle = 0;
- FileHandle = INVALID_HANDLE_VALUE;
- FileDescriptor = 0;
- }
-}
-
-mapped_file_region::~mapped_file_region() {
- if (Mapping)
- ::UnmapViewOfFile(Mapping);
-}
-
-#if LLVM_HAS_RVALUE_REFERENCES
-mapped_file_region::mapped_file_region(mapped_file_region &&other)
- : Mode(other.Mode)
- , Size(other.Size)
- , Mapping(other.Mapping)
- , FileDescriptor(other.FileDescriptor)
- , FileHandle(other.FileHandle)
- , FileMappingHandle(other.FileMappingHandle) {
- other.Mapping = other.FileMappingHandle = 0;
- other.FileHandle = INVALID_HANDLE_VALUE;
- other.FileDescriptor = 0;
-}
-#endif
-
-mapped_file_region::mapmode mapped_file_region::flags() const {
- assert(Mapping && "Mapping failed but used anyway!");
- return Mode;
-}
-
-uint64_t mapped_file_region::size() const {
- assert(Mapping && "Mapping failed but used anyway!");
- return Size;
-}
-
-char *mapped_file_region::data() const {
- assert(Mode != readonly && "Cannot get non const data for readonly mapping!");
- assert(Mapping && "Mapping failed but used anyway!");
- return reinterpret_cast<char*>(Mapping);
-}
-
-const char *mapped_file_region::const_data() const {
- assert(Mapping && "Mapping failed but used anyway!");
- return reinterpret_cast<const char*>(Mapping);
-}
-
-int mapped_file_region::alignment() {
- SYSTEM_INFO SysInfo;
- ::GetSystemInfo(&SysInfo);
- return SysInfo.dwAllocationGranularity;
-}
-
-error_code detail::directory_iterator_construct(detail::DirIterState &it,
- StringRef path){
- SmallVector<wchar_t, 128> path_utf16;
-
- if (error_code ec = UTF8ToUTF16(path,
- path_utf16))
- return ec;
-
- // Convert path to the format that Windows is happy with.
- if (path_utf16.size() > 0 &&
- !is_separator(path_utf16[path.size() - 1]) &&
- path_utf16[path.size() - 1] != L':') {
- path_utf16.push_back(L'\\');
- path_utf16.push_back(L'*');
- } else {
- path_utf16.push_back(L'*');
- }
-
- // Get the first directory entry.
- WIN32_FIND_DATAW FirstFind;
- ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
- if (!FindHandle)
- return windows_error(::GetLastError());
-
- size_t FilenameLen = ::wcslen(FirstFind.cFileName);
- while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') ||
- (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' &&
- FirstFind.cFileName[1] == L'.'))
- if (!::FindNextFileW(FindHandle, &FirstFind)) {
- error_code ec = windows_error(::GetLastError());
- // Check for end.
- if (ec == windows_error::no_more_files)
- return detail::directory_iterator_destruct(it);
- return ec;
- } else
- FilenameLen = ::wcslen(FirstFind.cFileName);
-
- // Construct the current directory entry.
- SmallString<128> directory_entry_name_utf8;
- if (error_code ec = UTF16ToUTF8(FirstFind.cFileName,
- ::wcslen(FirstFind.cFileName),
- directory_entry_name_utf8))
- return ec;
-
- it.IterationHandle = intptr_t(FindHandle.take());
- SmallString<128> directory_entry_path(path);
- path::append(directory_entry_path, directory_entry_name_utf8.str());
- it.CurrentEntry = directory_entry(directory_entry_path.str());
-
- return error_code::success();
-}
-
-error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
- if (it.IterationHandle != 0)
- // Closes the handle if it's valid.
- ScopedFindHandle close(HANDLE(it.IterationHandle));
- it.IterationHandle = 0;
- it.CurrentEntry = directory_entry();
- return error_code::success();
-}
-
-error_code detail::directory_iterator_increment(detail::DirIterState &it) {
- WIN32_FIND_DATAW FindData;
- if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
- error_code ec = windows_error(::GetLastError());
- // Check for end.
- if (ec == windows_error::no_more_files)
- return detail::directory_iterator_destruct(it);
- return ec;
- }
-
- size_t FilenameLen = ::wcslen(FindData.cFileName);
- if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') ||
- (FilenameLen == 2 && FindData.cFileName[0] == L'.' &&
- FindData.cFileName[1] == L'.'))
- return directory_iterator_increment(it);
-
- SmallString<128> directory_entry_path_utf8;
- if (error_code ec = UTF16ToUTF8(FindData.cFileName,
- ::wcslen(FindData.cFileName),
- directory_entry_path_utf8))
- return ec;
-
- it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
- return error_code::success();
-}
-
-error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,
- bool map_writable, void *&result) {
- assert(0 && "NOT IMPLEMENTED");
- return windows_error::invalid_function;
-}
-
-error_code unmap_file_pages(void *base, size_t size) {
- assert(0 && "NOT IMPLEMENTED");
- return windows_error::invalid_function;
-}
-
-
-
-} // end namespace fs
-} // end namespace sys
-} // end namespace llvm
diff --git a/contrib/llvm/lib/Support/Windows/Process.inc b/contrib/llvm/lib/Support/Windows/Process.inc
index ad94128..f9a3db9 100644
--- a/contrib/llvm/lib/Support/Windows/Process.inc
+++ b/contrib/llvm/lib/Support/Windows/Process.inc
@@ -11,18 +11,25 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Support/Allocator.h"
+
#include "Windows.h"
#include <direct.h>
#include <io.h>
#include <malloc.h>
#include <psapi.h>
+#include <shellapi.h>
#ifdef __MINGW32__
#if (HAVE_LIBPSAPI != 1)
#error "libpsapi.a should be present"
#endif
+ #if (HAVE_LIBSHELL32 != 1)
+ #error "libshell32.a should be present"
+ #endif
#else
#pragma comment(lib, "psapi.lib")
+ #pragma comment(lib, "shell32.lib")
#endif
//===----------------------------------------------------------------------===//
@@ -40,7 +47,7 @@ using namespace sys;
process::id_type self_process::get_id() {
- return GetCurrentProcess();
+ return GetCurrentProcessId();
}
static TimeValue getTimeValueFromFILETIME(FILETIME Time) {
@@ -83,6 +90,8 @@ static unsigned getPageSize() {
// that LLVM ought to run as 64-bits on a 64-bit system, anyway.
SYSTEM_INFO info;
GetSystemInfo(&info);
+ // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize,
+ // but dwAllocationGranularity.
return static_cast<unsigned>(info.dwPageSize);
}
@@ -119,28 +128,89 @@ void Process::GetTimeUsage(TimeValue &elapsed, TimeValue &user_time,
sys_time = getTimeValueFromFILETIME(KernelTime);
}
-int Process::GetCurrentUserId()
-{
- return 65536;
-}
-
-int Process::GetCurrentGroupId()
-{
- return 65536;
-}
-
// Some LLVM programs such as bugpoint produce core files as a normal part of
-// their operation. To prevent the disk from filling up, this configuration item
-// does what's necessary to prevent their generation.
+// their operation. To prevent the disk from filling up, this configuration
+// item does what's necessary to prevent their generation.
void Process::PreventCoreFiles() {
- // Windows doesn't do core files, but it does do modal pop-up message
- // boxes. As this method is used by bugpoint, preventing these pop-ups
- // is the moral equivalent of suppressing core files.
+ // Windows does have the concept of core files, called minidumps. However,
+ // disabling minidumps for a particular application extends past the lifetime
+ // of that application, which is the incorrect behavior for this API.
+ // Additionally, the APIs require elevated privileges to disable and re-
+ // enable minidumps, which makes this untenable. For more information, see
+ // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and
+ // later).
+ //
+ // Windows also has modal pop-up message boxes. As this method is used by
+ // bugpoint, preventing these pop-ups is additionally important.
SetErrorMode(SEM_FAILCRITICALERRORS |
SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
}
+/// Returns the environment variable \arg Name's value as a string encoded in
+/// UTF-8. \arg Name is assumed to be in UTF-8 encoding.
+Optional<std::string> Process::GetEnv(StringRef Name) {
+ // Convert the argument to UTF-16 to pass it to _wgetenv().
+ SmallVector<wchar_t, 128> NameUTF16;
+ if (error_code ec = windows::UTF8ToUTF16(Name, NameUTF16))
+ return None;
+
+ // Environment variable can be encoded in non-UTF8 encoding, and there's no
+ // way to know what the encoding is. The only reliable way to look up
+ // multibyte environment variable is to use GetEnvironmentVariableW().
+ SmallVector<wchar_t, MAX_PATH> Buf;
+ size_t Size = MAX_PATH;
+ do {
+ Buf.reserve(Size);
+ Size =
+ GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity());
+ if (Size == 0)
+ return None;
+
+ // Try again with larger buffer.
+ } while (Size > Buf.capacity());
+ Buf.set_size(Size);
+
+ // Convert the result from UTF-16 to UTF-8.
+ SmallVector<char, MAX_PATH> Res;
+ if (error_code ec = windows::UTF16ToUTF8(Buf.data(), Size, Res))
+ return None;
+ return std::string(Res.data());
+}
+
+error_code
+Process::GetArgumentVector(SmallVectorImpl<const char *> &Args,
+ ArrayRef<const char *>,
+ SpecificBumpPtrAllocator<char> &ArgAllocator) {
+ int NewArgCount;
+ error_code ec;
+
+ wchar_t **UnicodeCommandLine = CommandLineToArgvW(GetCommandLineW(),
+ &NewArgCount);
+ if (!UnicodeCommandLine)
+ return windows_error(::GetLastError());
+
+ Args.reserve(NewArgCount);
+
+ for (int i = 0; i < NewArgCount; ++i) {
+ SmallVector<char, MAX_PATH> NewArgString;
+ ec = windows::UTF16ToUTF8(UnicodeCommandLine[i],
+ wcslen(UnicodeCommandLine[i]),
+ NewArgString);
+ if (ec)
+ break;
+
+ char *Buffer = ArgAllocator.Allocate(NewArgString.size() + 1);
+ ::memcpy(Buffer, NewArgString.data(), NewArgString.size() + 1);
+ Args.push_back(Buffer);
+ }
+ LocalFree(UnicodeCommandLine);
+ if (ec)
+ return ec;
+
+ return error_code::success();
+}
+
bool Process::StandardInIsUserInput() {
return FileDescriptorIsDisplayed(0);
}
@@ -187,6 +257,11 @@ bool Process::StandardErrHasColors() {
return FileDescriptorHasColors(2);
}
+static bool UseANSI = false;
+void Process::UseANSIEscapeCodes(bool enable) {
+ UseANSI = enable;
+}
+
namespace {
class DefaultColors
{
@@ -208,10 +283,12 @@ DefaultColors defaultColors;
}
bool Process::ColorNeedsFlush() {
- return true;
+ return !UseANSI;
}
const char *Process::OutputBold(bool bg) {
+ if (UseANSI) return "\033[1m";
+
WORD colors = DefaultColors::GetCurrentColor();
if (bg)
colors |= BACKGROUND_INTENSITY;
@@ -222,6 +299,8 @@ const char *Process::OutputBold(bool bg) {
}
const char *Process::OutputColor(char code, bool bold, bool bg) {
+ if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7];
+
WORD colors;
if (bg) {
colors = ((code&1) ? BACKGROUND_RED : 0) |
@@ -247,6 +326,8 @@ static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) {
}
const char *Process::OutputReverse() {
+ if (UseANSI) return "\033[7m";
+
const WORD attributes
= GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE));
@@ -273,6 +354,7 @@ const char *Process::OutputReverse() {
}
const char *Process::ResetColor() {
+ if (UseANSI) return "\033[0m";
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors());
return 0;
}
diff --git a/contrib/llvm/lib/Support/Windows/Program.inc b/contrib/llvm/lib/Support/Windows/Program.inc
index 619ae5d..dc09738 100644
--- a/contrib/llvm/lib/Support/Windows/Program.inc
+++ b/contrib/llvm/lib/Support/Windows/Program.inc
@@ -12,6 +12,8 @@
//===----------------------------------------------------------------------===//
#include "Windows.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/FileSystem.h"
#include <cstdio>
#include <fcntl.h>
#include <io.h>
@@ -22,37 +24,17 @@
//=== and must not be UNIX code
//===----------------------------------------------------------------------===//
-namespace {
- struct Win32ProcessInfo {
- HANDLE hProcess;
- DWORD dwProcessId;
- };
-}
-
namespace llvm {
using namespace sys;
-Program::Program() : Data_(0) {}
-
-Program::~Program() {
- if (Data_) {
- Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_);
- CloseHandle(wpi->hProcess);
- delete wpi;
- Data_ = 0;
- }
-}
+ProcessInfo::ProcessInfo() : ProcessHandle(0), Pid(0), ReturnCode(0) {}
// This function just uses the PATH environment variable to find the program.
-Path
-Program::FindProgramByName(const std::string& progName) {
-
+std::string sys::FindProgramByName(const std::string &progName) {
// Check some degenerate cases
if (progName.length() == 0) // no program
- return Path();
- Path temp;
- if (!temp.set(progName)) // invalid name
- return Path();
+ return "";
+ std::string temp = progName;
// Return paths with slashes verbatim.
if (progName.find('\\') != std::string::npos ||
progName.find('/') != std::string::npos)
@@ -60,58 +42,60 @@ Program::FindProgramByName(const std::string& progName) {
// At this point, the file name is valid and does not contain slashes.
// Let Windows search for it.
- char buffer[MAX_PATH];
- char *dummy = NULL;
- DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH,
- buffer, &dummy);
-
- // See if it wasn't found.
- if (len == 0)
- return Path();
-
- // See if we got the entire path.
- if (len < MAX_PATH)
- return Path(buffer);
-
- // Buffer was too small; grow and retry.
- while (true) {
- char *b = reinterpret_cast<char *>(_alloca(len+1));
- DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy);
-
- // It is unlikely the search failed, but it's always possible some file
- // was added or removed since the last search, so be paranoid...
- if (len2 == 0)
- return Path();
- else if (len2 <= len)
- return Path(b);
-
- len = len2;
- }
+ SmallVector<wchar_t, MAX_PATH> progNameUnicode;
+ if (windows::UTF8ToUTF16(progName, progNameUnicode))
+ return "";
+
+ SmallVector<wchar_t, MAX_PATH> buffer;
+ DWORD len = MAX_PATH;
+ do {
+ buffer.reserve(len);
+ len = ::SearchPathW(NULL, progNameUnicode.data(), L".exe",
+ buffer.capacity(), buffer.data(), NULL);
+
+ // See if it wasn't found.
+ if (len == 0)
+ return "";
+
+ // Buffer was too small; grow and retry.
+ } while (len > buffer.capacity());
+
+ buffer.set_size(len);
+ SmallVector<char, MAX_PATH> result;
+ if (windows::UTF16ToUTF8(buffer.begin(), buffer.size(), result))
+ return "";
+
+ return std::string(result.data(), result.size());
}
-static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) {
+static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) {
HANDLE h;
if (path == 0) {
- DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
- GetCurrentProcess(), &h,
- 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
+ GetCurrentProcess(), &h,
+ 0, TRUE, DUPLICATE_SAME_ACCESS))
+ return INVALID_HANDLE_VALUE;
return h;
}
- const char *fname;
- if (path->isEmpty())
+ std::string fname;
+ if (path->empty())
fname = "NUL";
else
- fname = path->c_str();
+ fname = *path;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = 0;
sa.bInheritHandle = TRUE;
- h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ,
- &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
+ SmallVector<wchar_t, 128> fnameUnicode;
+ if (windows::UTF8ToUTF16(fname, fnameUnicode))
+ return INVALID_HANDLE_VALUE;
+
+ h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ,
+ FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) {
MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " +
(fd ? "input: " : "output: "));
@@ -181,22 +165,12 @@ static unsigned int ArgLenWithQuotes(const char *Str) {
return len;
}
+}
-bool
-Program::Execute(const Path& path,
- const char** args,
- const char** envp,
- const Path** redirects,
- unsigned memoryLimit,
- std::string* ErrMsg) {
- if (Data_) {
- Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_);
- CloseHandle(wpi->hProcess);
- delete wpi;
- Data_ = 0;
- }
-
- if (!path.canExecute()) {
+static bool Execute(ProcessInfo &PI, StringRef Program, const char **args,
+ const char **envp, const StringRef **redirects,
+ unsigned memoryLimit, std::string *ErrMsg) {
+ if (!sys::fs::can_execute(Program)) {
if (ErrMsg)
*ErrMsg = "program not executable";
return false;
@@ -213,8 +187,8 @@ Program::Execute(const Path& path,
}
// Now build the command line.
- char *command = reinterpret_cast<char *>(_alloca(len+1));
- char *p = command;
+ OwningArrayPtr<char> command(new char[len+1]);
+ char *p = command.get();
for (unsigned i = 0; args[i]; i++) {
const char *arg = args[i];
@@ -245,34 +219,28 @@ Program::Execute(const Path& path,
*p = 0;
// The pointer to the environment block for the new process.
- char *envblock = 0;
+ std::vector<wchar_t> EnvBlock;
if (envp) {
// An environment block consists of a null-terminated block of
// null-terminated strings. Convert the array of environment variables to
// an environment block by concatenating them.
+ for (unsigned i = 0; envp[i]; ++i) {
+ SmallVector<wchar_t, MAX_PATH> EnvString;
+ if (error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) {
+ SetLastError(ec.value());
+ MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16");
+ return false;
+ }
- // First, determine the length of the environment block.
- len = 0;
- for (unsigned i = 0; envp[i]; i++)
- len += strlen(envp[i]) + 1;
-
- // Now build the environment block.
- envblock = reinterpret_cast<char *>(_alloca(len+1));
- p = envblock;
-
- for (unsigned i = 0; envp[i]; i++) {
- const char *ev = envp[i];
- size_t len = strlen(ev) + 1;
- memcpy(p, ev, len);
- p += len;
+ EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end());
+ EnvBlock.push_back(0);
}
-
- *p = 0;
+ EnvBlock.push_back(0);
}
// Create a child process.
- STARTUPINFO si;
+ STARTUPINFOW si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.hStdInput = INVALID_HANDLE_VALUE;
@@ -296,9 +264,14 @@ Program::Execute(const Path& path,
if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) {
// If stdout and stderr should go to the same place, redirect stderr
// to the handle already open for stdout.
- DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
- GetCurrentProcess(), &si.hStdError,
- 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
+ GetCurrentProcess(), &si.hStdError,
+ 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+ CloseHandle(si.hStdInput);
+ CloseHandle(si.hStdOutput);
+ MakeErrMsg(ErrMsg, "can't dup stderr to stdout");
+ return false;
+ }
} else {
// Just redirect stderr
si.hStdError = RedirectIO(redirects[2], 2, ErrMsg);
@@ -316,8 +289,27 @@ Program::Execute(const Path& path,
fflush(stdout);
fflush(stderr);
- BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0,
- envblock, NULL, &si, &pi);
+
+ SmallVector<wchar_t, MAX_PATH> ProgramUtf16;
+ if (error_code ec = windows::UTF8ToUTF16(Program, ProgramUtf16)) {
+ SetLastError(ec.value());
+ MakeErrMsg(ErrMsg,
+ std::string("Unable to convert application name to UTF-16"));
+ return false;
+ }
+
+ SmallVector<wchar_t, MAX_PATH> CommandUtf16;
+ if (error_code ec = windows::UTF8ToUTF16(command.get(), CommandUtf16)) {
+ SetLastError(ec.value());
+ MakeErrMsg(ErrMsg,
+ std::string("Unable to convert command-line to UTF-16"));
+ return false;
+ }
+
+ BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0,
+ TRUE, CREATE_UNICODE_ENVIRONMENT,
+ EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si,
+ &pi);
DWORD err = GetLastError();
// Regardless of whether the process got created or not, we are done with
@@ -330,13 +322,12 @@ Program::Execute(const Path& path,
if (!rc) {
SetLastError(err);
MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") +
- path.str() + "'");
+ Program.str() + "'");
return false;
}
- Win32ProcessInfo* wpi = new Win32ProcessInfo;
- wpi->hProcess = pi.hProcess;
- wpi->dwProcessId = pi.dwProcessId;
- Data_ = wpi;
+
+ PI.Pid = pi.dwProcessId;
+ PI.ProcessHandle = pi.hProcess;
// Make sure these get closed no matter what.
ScopedCommonHandle hThread(pi.hThread);
@@ -344,7 +335,7 @@ Program::Execute(const Path& path,
// Assign the process to a job if a memory limit is defined.
ScopedJobHandle hJob;
if (memoryLimit != 0) {
- hJob = CreateJobObject(0, 0);
+ hJob = CreateJobObjectW(0, 0);
bool success = false;
if (hJob) {
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
@@ -369,72 +360,84 @@ Program::Execute(const Path& path,
return true;
}
-int
-Program::Wait(const Path &path,
- unsigned secondsToWait,
- std::string* ErrMsg) {
- if (Data_ == 0) {
- MakeErrMsg(ErrMsg, "Process not started!");
- return -1;
- }
-
- Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_);
- HANDLE hProcess = wpi->hProcess;
-
- // Wait for the process to terminate.
- DWORD millisecondsToWait = INFINITE;
- if (secondsToWait > 0)
- millisecondsToWait = secondsToWait * 1000;
-
- if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) {
- if (!TerminateProcess(hProcess, 1)) {
- MakeErrMsg(ErrMsg, "Failed to terminate timed-out program.");
- // -2 indicates a crash or timeout as opposed to failure to execute.
- return -2;
+namespace llvm {
+ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
+ bool WaitUntilChildTerminates, std::string *ErrMsg) {
+ assert(PI.Pid && "invalid pid to wait on, process not started?");
+ assert(PI.ProcessHandle &&
+ "invalid process handle to wait on, process not started?");
+ DWORD milliSecondsToWait = 0;
+ if (WaitUntilChildTerminates)
+ milliSecondsToWait = INFINITE;
+ else if (SecondsToWait > 0)
+ milliSecondsToWait = SecondsToWait * 1000;
+
+ ProcessInfo WaitResult = PI;
+ DWORD WaitStatus = WaitForSingleObject(PI.ProcessHandle, milliSecondsToWait);
+ if (WaitStatus == WAIT_TIMEOUT) {
+ if (SecondsToWait) {
+ if (!TerminateProcess(PI.ProcessHandle, 1)) {
+ if (ErrMsg)
+ MakeErrMsg(ErrMsg, "Failed to terminate timed-out program.");
+
+ // -2 indicates a crash or timeout as opposed to failure to execute.
+ WaitResult.ReturnCode = -2;
+ CloseHandle(PI.ProcessHandle);
+ return WaitResult;
+ }
+ WaitForSingleObject(PI.ProcessHandle, INFINITE);
+ CloseHandle(PI.ProcessHandle);
+ } else {
+ // Non-blocking wait.
+ return ProcessInfo();
}
- WaitForSingleObject(hProcess, INFINITE);
}
// Get its exit status.
DWORD status;
- BOOL rc = GetExitCodeProcess(hProcess, &status);
+ BOOL rc = GetExitCodeProcess(PI.ProcessHandle, &status);
DWORD err = GetLastError();
+ CloseHandle(PI.ProcessHandle);
if (!rc) {
SetLastError(err);
- MakeErrMsg(ErrMsg, "Failed getting status for program.");
+ if (ErrMsg)
+ MakeErrMsg(ErrMsg, "Failed getting status for program.");
+
// -2 indicates a crash or timeout as opposed to failure to execute.
- return -2;
+ WaitResult.ReturnCode = -2;
+ return WaitResult;
}
if (!status)
- return 0;
+ return WaitResult;
// Pass 10(Warning) and 11(Error) to the callee as negative value.
if ((status & 0xBFFF0000U) == 0x80000000U)
- return (int)status;
-
- if (status & 0xFF)
- return status & 0x7FFFFFFF;
+ WaitResult.ReturnCode = static_cast<int>(status);
+ else if (status & 0xFF)
+ WaitResult.ReturnCode = status & 0x7FFFFFFF;
+ else
+ WaitResult.ReturnCode = 1;
- return 1;
+ return WaitResult;
}
-error_code Program::ChangeStdinToBinary(){
+error_code sys::ChangeStdinToBinary(){
int result = _setmode( _fileno(stdin), _O_BINARY );
if (result == -1)
return error_code(errno, generic_category());
return make_error_code(errc::success);
}
-error_code Program::ChangeStdoutToBinary(){
+error_code sys::ChangeStdoutToBinary(){
int result = _setmode( _fileno(stdout), _O_BINARY );
if (result == -1)
return error_code(errno, generic_category());
return make_error_code(errc::success);
}
-error_code Program::ChangeStderrToBinary(){
+error_code sys::ChangeStderrToBinary(){
int result = _setmode( _fileno(stderr), _O_BINARY );
if (result == -1)
return error_code(errno, generic_category());
@@ -456,5 +459,4 @@ bool llvm::sys::argumentsFitWithinSystemLimits(ArrayRef<const char*> Args) {
}
return true;
}
-
}
diff --git a/contrib/llvm/lib/Support/Windows/RWMutex.inc b/contrib/llvm/lib/Support/Windows/RWMutex.inc
index 9593923..c431844 100644
--- a/contrib/llvm/lib/Support/Windows/RWMutex.inc
+++ b/contrib/llvm/lib/Support/Windows/RWMutex.inc
@@ -48,8 +48,7 @@ static bool loadSRW() {
if (!sChecked) {
sChecked = true;
- HMODULE hLib = ::LoadLibrary(TEXT("Kernel32"));
- if (hLib) {
+ if (HMODULE hLib = ::GetModuleHandleW(L"Kernel32.dll")) {
fpInitializeSRWLock =
(VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
"InitializeSRWLock");
@@ -65,7 +64,6 @@ static bool loadSRW() {
fpReleaseSRWLockShared =
(VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
"ReleaseSRWLockShared");
- ::FreeLibrary(hLib);
if (fpInitializeSRWLock != NULL) {
sHasSRW = true;
diff --git a/contrib/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm/lib/Support/Windows/Signals.inc
index b18b4d1..4b40d51 100644
--- a/contrib/llvm/lib/Support/Windows/Signals.inc
+++ b/contrib/llvm/lib/Support/Windows/Signals.inc
@@ -11,6 +11,8 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Support/FileSystem.h"
+
#include "Windows.h"
#include <algorithm>
#include <stdio.h>
@@ -133,7 +135,7 @@ typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64);
static fpSymFunctionTableAccess64 SymFunctionTableAccess64;
static bool load64BitDebugHelp(void) {
- HMODULE hLib = ::LoadLibrary("Dbghelp.dll");
+ HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll");
if (hLib) {
StackWalk64 = (fpStackWalk64)
::GetProcAddress(hLib, "StackWalk64");
@@ -158,7 +160,7 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
// InterruptFunction - The function to call if ctrl-c is pressed.
static void (*InterruptFunction)() = 0;
-static std::vector<llvm::sys::Path> *FilesToRemove = NULL;
+static std::vector<std::string> *FilesToRemove = NULL;
static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0;
static bool RegisteredUnhandledExceptionFilter = false;
static bool CleanupExecuted = false;
@@ -191,34 +193,6 @@ static int AvoidMessageBoxHook(int ReportType, char *Message, int *Return) {
return TRUE;
}
-/// CRTReportHook - Function called on a CRT debugging event.
-static int CRTReportHook(int ReportType, char *Message, int *Return) {
- // Don't cause a DebugBreak() on return.
- if (Return)
- *Return = 0;
-
- switch (ReportType) {
- default:
- case _CRT_ASSERT:
- fprintf(stderr, "CRT assert: %s\n", Message);
- // FIXME: Is there a way to just crash? Perhaps throw to the unhandled
- // exception code? Perhaps SetErrorMode() handles this.
- _exit(3);
- break;
- case _CRT_ERROR:
- fprintf(stderr, "CRT error: %s\n", Message);
- // FIXME: Is there a way to just crash? Perhaps throw to the unhandled
- // exception code? Perhaps SetErrorMode() handles this.
- _exit(3);
- break;
- case _CRT_WARN:
- fprintf(stderr, "CRT warn: %s\n", Message);
- break;
- }
-
- // Don't call _CrtDbgReport.
- return TRUE;
-}
#endif
static void RegisterHandler() {
@@ -251,19 +225,10 @@ static void RegisterHandler() {
OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter);
SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE);
-#ifdef _MSC_VER
- const char *EnableMsgbox = getenv("LLVM_ENABLE_CRT_REPORT");
- if (!EnableMsgbox || strcmp("0", EnableMsgbox) == 0) {
- // Setting a report hook overrides the default behavior of popping an "abort,
- // retry, or ignore" dialog.
- _CrtSetReportHook(AvoidMessageBoxHook);
- }
-#endif
-
// Environment variable to disable any kind of crash dialog.
if (getenv("LLVM_DISABLE_CRASH_REPORT")) {
#ifdef _MSC_VER
- _CrtSetReportHook(CRTReportHook);
+ _CrtSetReportHook(AvoidMessageBoxHook);
#endif
SetErrorMode(SEM_FAILCRITICALERRORS |
SEM_NOGPFAULTERRORBOX |
@@ -276,7 +241,7 @@ static void RegisterHandler() {
}
// RemoveFileOnSignal - The public API
-bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
+bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) {
RegisterHandler();
if (CleanupExecuted) {
@@ -286,7 +251,7 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
}
if (FilesToRemove == NULL)
- FilesToRemove = new std::vector<sys::Path>;
+ FilesToRemove = new std::vector<std::string>;
FilesToRemove->push_back(Filename);
@@ -295,14 +260,14 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
}
// DontRemoveFileOnSignal - The public API
-void sys::DontRemoveFileOnSignal(const sys::Path &Filename) {
+void sys::DontRemoveFileOnSignal(StringRef Filename) {
if (FilesToRemove == NULL)
return;
RegisterHandler();
FilesToRemove->push_back(Filename);
- std::vector<sys::Path>::reverse_iterator I =
+ std::vector<std::string>::reverse_iterator I =
std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename);
if (I != FilesToRemove->rend())
FilesToRemove->erase(I.base()-1);
@@ -352,7 +317,8 @@ static void Cleanup() {
if (FilesToRemove != NULL)
while (!FilesToRemove->empty()) {
- FilesToRemove->back().eraseFromDisk();
+ bool Existed;
+ llvm::sys::fs::remove(FilesToRemove->back(), Existed);
FilesToRemove->pop_back();
}
diff --git a/contrib/llvm/lib/Support/Windows/TimeValue.inc b/contrib/llvm/lib/Support/Windows/TimeValue.inc
index 1227552..98b07d6 100644
--- a/contrib/llvm/lib/Support/Windows/TimeValue.inc
+++ b/contrib/llvm/lib/Support/Windows/TimeValue.inc
@@ -12,10 +12,11 @@
//===----------------------------------------------------------------------===//
#include "Windows.h"
+#include <cctype>
#include <time.h>
-namespace llvm {
-using namespace sys;
+using namespace llvm;
+using namespace llvm::sys;
//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only Win32 specific code.
@@ -31,21 +32,28 @@ TimeValue TimeValue::now() {
}
std::string TimeValue::str() const {
+ struct tm *LT;
#ifdef __MINGW32__
- // This ban may be lifted by either:
- // (i) a future MinGW version other than 1.0 inherents the __time64_t type, or
- // (ii) configure tests for either the time_t or __time64_t type.
- time_t ourTime = time_t(this->toEpochTime());
- struct tm *lt = ::localtime(&ourTime);
+ // Old versions of mingw don't have _localtime64_s. Remove this once we drop support
+ // for them.
+ time_t OurTime = time_t(this->toEpochTime());
+ LT = ::localtime(&OurTime);
+ assert(LT);
#else
- __time64_t ourTime = this->toEpochTime();
- struct tm *lt = ::_localtime64(&ourTime);
+ struct tm Storage;
+ __time64_t OurTime = this->toEpochTime();
+ int Error = ::_localtime64_s(&Storage, &OurTime);
+ assert(!Error);
+ LT = &Storage;
#endif
- char buffer[25];
- strftime(buffer, 25, "%a %b %d %H:%M:%S %Y", lt);
- return std::string(buffer);
-}
-
-
+ char Buffer[25];
+ // FIXME: the windows version of strftime doesn't support %e
+ strftime(Buffer, 25, "%b %d %H:%M %Y", LT);
+ assert((Buffer[3] == ' ' && isdigit(Buffer[5]) && Buffer[6] == ' ') &&
+ "Unexpected format in strftime()!");
+ // Emulate %e on %d to mute '0'.
+ if (Buffer[4] == '0')
+ Buffer[4] = ' ';
+ return std::string(Buffer);
}
diff --git a/contrib/llvm/lib/Support/Windows/Windows.h b/contrib/llvm/lib/Support/Windows/Windows.h
index 5c1da0d..1f3417d 100644
--- a/contrib/llvm/lib/Support/Windows/Windows.h
+++ b/contrib/llvm/lib/Support/Windows/Windows.h
@@ -24,22 +24,31 @@
#define _WIN32_IE 0x0600 // MinGW at it again.
#define WIN32_LEAN_AND_MEAN
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h" // Get build system configuration settings
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/system_error.h"
#include <windows.h>
#include <wincrypt.h>
-#include <shlobj.h>
#include <cassert>
#include <string>
+#include <vector>
inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) {
if (!ErrMsg)
return true;
char *buffer = NULL;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, GetLastError(), 0, (LPSTR)&buffer, 1, NULL);
- *ErrMsg = prefix + buffer;
+ DWORD R = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, GetLastError(), 0, (LPSTR)&buffer, 1, NULL);
+ if (R)
+ *ErrMsg = prefix + buffer;
+ else
+ *ErrMsg = prefix + "Unknown error";
+
LocalFree(buffer);
- return true;
+ return R != 0;
}
template <typename HandleTraits>
@@ -75,7 +84,7 @@ public:
}
// True if Handle is valid.
- operator bool() const {
+ LLVM_EXPLICIT operator bool() const {
return HandleTraits::IsValid(Handle) ? true : false;
}
@@ -147,4 +156,13 @@ c_str(SmallVectorImpl<T> &str) {
str.pop_back();
return str.data();
}
+
+namespace sys {
+namespace windows {
+error_code UTF8ToUTF16(StringRef utf8,
+ SmallVectorImpl<wchar_t> &utf16);
+error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
+ SmallVectorImpl<char> &utf8);
+} // end namespace windows
+} // end namespace sys
} // end namespace llvm.
diff --git a/contrib/llvm/lib/Support/YAMLParser.cpp b/contrib/llvm/lib/Support/YAMLParser.cpp
index 213f5e1..9495cd4 100644
--- a/contrib/llvm/lib/Support/YAMLParser.cpp
+++ b/contrib/llvm/lib/Support/YAMLParser.cpp
@@ -96,6 +96,15 @@ static EncodingInfo getUnicodeEncoding(StringRef Input) {
namespace llvm {
namespace yaml {
+/// Pin the vtables to this file.
+void Node::anchor() {}
+void NullNode::anchor() {}
+void ScalarNode::anchor() {}
+void KeyValueNode::anchor() {}
+void MappingNode::anchor() {}
+void SequenceNode::anchor() {}
+void AliasNode::anchor() {}
+
/// Token - A single YAML token.
struct Token : ilist_node<Token> {
enum TokenKind {
@@ -1070,14 +1079,22 @@ bool Scanner::scanDirective() {
Current = skip_while(&Scanner::skip_ns_char, Current);
StringRef Name(NameStart, Current - NameStart);
Current = skip_while(&Scanner::skip_s_white, Current);
-
+
+ Token T;
if (Name == "YAML") {
Current = skip_while(&Scanner::skip_ns_char, Current);
- Token T;
T.Kind = Token::TK_VersionDirective;
T.Range = StringRef(Start, Current - Start);
TokenQueue.push_back(T);
return true;
+ } else if(Name == "TAG") {
+ Current = skip_while(&Scanner::skip_ns_char, Current);
+ Current = skip_while(&Scanner::skip_s_white, Current);
+ Current = skip_while(&Scanner::skip_ns_char, Current);
+ T.Kind = Token::TK_TagDirective;
+ T.Range = StringRef(Start, Current - Start);
+ TokenQueue.push_back(T);
+ return true;
}
return false;
}
@@ -1564,10 +1581,6 @@ void Stream::printError(Node *N, const Twine &Msg) {
, Ranges);
}
-void Stream::handleYAMLDirective(const Token &t) {
- // TODO: Ensure version is 1.x.
-}
-
document_iterator Stream::begin() {
if (CurrentDoc)
report_fatal_error("Can only iterate over the stream once");
@@ -1588,14 +1601,59 @@ void Stream::skip() {
i->skip();
}
-Node::Node(unsigned int Type, OwningPtr<Document> &D, StringRef A)
+Node::Node(unsigned int Type, OwningPtr<Document> &D, StringRef A, StringRef T)
: Doc(D)
, TypeID(Type)
- , Anchor(A) {
+ , Anchor(A)
+ , Tag(T) {
SMLoc Start = SMLoc::getFromPointer(peekNext().Range.begin());
SourceRange = SMRange(Start, Start);
}
+std::string Node::getVerbatimTag() const {
+ StringRef Raw = getRawTag();
+ if (!Raw.empty() && Raw != "!") {
+ std::string Ret;
+ if (Raw.find_last_of('!') == 0) {
+ Ret = Doc->getTagMap().find("!")->second;
+ Ret += Raw.substr(1);
+ return llvm_move(Ret);
+ } else if (Raw.startswith("!!")) {
+ Ret = Doc->getTagMap().find("!!")->second;
+ Ret += Raw.substr(2);
+ return llvm_move(Ret);
+ } else {
+ StringRef TagHandle = Raw.substr(0, Raw.find_last_of('!') + 1);
+ std::map<StringRef, StringRef>::const_iterator It =
+ Doc->getTagMap().find(TagHandle);
+ if (It != Doc->getTagMap().end())
+ Ret = It->second;
+ else {
+ Token T;
+ T.Kind = Token::TK_Tag;
+ T.Range = TagHandle;
+ setError(Twine("Unknown tag handle ") + TagHandle, T);
+ }
+ Ret += Raw.substr(Raw.find_last_of('!') + 1);
+ return llvm_move(Ret);
+ }
+ }
+
+ switch (getType()) {
+ case NK_Null:
+ return "tag:yaml.org,2002:null";
+ case NK_Scalar:
+ // TODO: Tag resolution.
+ return "tag:yaml.org,2002:str";
+ case NK_Mapping:
+ return "tag:yaml.org,2002:map";
+ case NK_Sequence:
+ return "tag:yaml.org,2002:seq";
+ }
+
+ return "";
+}
+
Token &Node::peekNext() {
return Doc->peekNext();
}
@@ -1999,6 +2057,10 @@ void SequenceNode::increment() {
}
Document::Document(Stream &S) : stream(S), Root(0) {
+ // Tag maps starts with two default mappings.
+ TagMap["!"] = "!";
+ TagMap["!!"] = "tag:yaml.org,2002:";
+
if (parseDirectives())
expectToken(Token::TK_DocumentStart);
Token &T = peekNext();
@@ -2042,6 +2104,7 @@ Node *Document::parseBlockNode() {
Token T = peekNext();
// Handle properties.
Token AnchorInfo;
+ Token TagInfo;
parse_property:
switch (T.Kind) {
case Token::TK_Alias:
@@ -2056,7 +2119,11 @@ parse_property:
T = peekNext();
goto parse_property;
case Token::TK_Tag:
- getNext(); // Skip TK_Tag.
+ if (TagInfo.Kind == Token::TK_Tag) {
+ setError("Already encountered a tag for this node!", T);
+ return 0;
+ }
+ TagInfo = getNext(); // Consume TK_Tag.
T = peekNext();
goto parse_property;
default:
@@ -2070,42 +2137,49 @@ parse_property:
// Don't eat the TK_BlockEntry, SequenceNode needs it.
return new (NodeAllocator) SequenceNode( stream.CurrentDoc
, AnchorInfo.Range.substr(1)
+ , TagInfo.Range
, SequenceNode::ST_Indentless);
case Token::TK_BlockSequenceStart:
getNext();
return new (NodeAllocator)
SequenceNode( stream.CurrentDoc
, AnchorInfo.Range.substr(1)
+ , TagInfo.Range
, SequenceNode::ST_Block);
case Token::TK_BlockMappingStart:
getNext();
return new (NodeAllocator)
MappingNode( stream.CurrentDoc
, AnchorInfo.Range.substr(1)
+ , TagInfo.Range
, MappingNode::MT_Block);
case Token::TK_FlowSequenceStart:
getNext();
return new (NodeAllocator)
SequenceNode( stream.CurrentDoc
, AnchorInfo.Range.substr(1)
+ , TagInfo.Range
, SequenceNode::ST_Flow);
case Token::TK_FlowMappingStart:
getNext();
return new (NodeAllocator)
MappingNode( stream.CurrentDoc
, AnchorInfo.Range.substr(1)
+ , TagInfo.Range
, MappingNode::MT_Flow);
case Token::TK_Scalar:
getNext();
return new (NodeAllocator)
ScalarNode( stream.CurrentDoc
, AnchorInfo.Range.substr(1)
+ , TagInfo.Range
, T.Range);
case Token::TK_Key:
// Don't eat the TK_Key, KeyValueNode expects it.
return new (NodeAllocator)
MappingNode( stream.CurrentDoc
, AnchorInfo.Range.substr(1)
+ , TagInfo.Range
, MappingNode::MT_Inline);
case Token::TK_DocumentStart:
case Token::TK_DocumentEnd:
@@ -2126,10 +2200,10 @@ bool Document::parseDirectives() {
while (true) {
Token T = peekNext();
if (T.Kind == Token::TK_TagDirective) {
- handleTagDirective(getNext());
+ parseTAGDirective();
isDirective = true;
} else if (T.Kind == Token::TK_VersionDirective) {
- stream.handleYAMLDirective(getNext());
+ parseYAMLDirective();
isDirective = true;
} else
break;
@@ -2137,6 +2211,21 @@ bool Document::parseDirectives() {
return isDirective;
}
+void Document::parseYAMLDirective() {
+ getNext(); // Eat %YAML <version>
+}
+
+void Document::parseTAGDirective() {
+ Token Tag = getNext(); // %TAG <handle> <prefix>
+ StringRef T = Tag.Range;
+ // Strip %TAG
+ T = T.substr(T.find_first_of(" \t")).ltrim(" \t");
+ std::size_t HandleEnd = T.find_first_of(" \t");
+ StringRef TagHandle = T.substr(0, HandleEnd);
+ StringRef TagPrefix = T.substr(HandleEnd).ltrim(" \t");
+ TagMap[TagHandle] = TagPrefix;
+}
+
bool Document::expectToken(int TK) {
Token T = getNext();
if (T.Kind != TK) {
diff --git a/contrib/llvm/lib/Support/YAMLTraits.cpp b/contrib/llvm/lib/Support/YAMLTraits.cpp
index 9da2aa7..42bff96 100644
--- a/contrib/llvm/lib/Support/YAMLTraits.cpp
+++ b/contrib/llvm/lib/Support/YAMLTraits.cpp
@@ -15,6 +15,7 @@
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
+#include <cctype>
using namespace llvm;
using namespace yaml;
@@ -40,32 +41,43 @@ void IO::setContext(void *Context) {
// Input
//===----------------------------------------------------------------------===//
-Input::Input(StringRef InputContent, void *Ctxt)
- : IO(Ctxt),
+Input::Input(StringRef InputContent,
+ void *Ctxt,
+ SourceMgr::DiagHandlerTy DiagHandler,
+ void *DiagHandlerCtxt)
+ : IO(Ctxt),
Strm(new Stream(InputContent, SrcMgr)),
CurrentNode(NULL) {
+ if (DiagHandler)
+ SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt);
DocIterator = Strm->begin();
}
Input::~Input() {
-
}
error_code Input::error() {
return EC;
}
-void Input::setDiagHandler(SourceMgr::DiagHandlerTy Handler, void *Ctxt) {
- SrcMgr.setDiagHandler(Handler, Ctxt);
-}
+// Pin the vtables to this file.
+void Input::HNode::anchor() {}
+void Input::EmptyHNode::anchor() {}
+void Input::ScalarHNode::anchor() {}
-bool Input::outputting() {
+bool Input::outputting() const {
return false;
}
bool Input::setCurrentDocument() {
if (DocIterator != Strm->end()) {
Node *N = DocIterator->getRoot();
+ if (!N) {
+ assert(Strm->failed() && "Root is NULL iff parsing failed");
+ EC = make_error_code(errc::invalid_argument);
+ return false;
+ }
+
if (isa<NullNode>(N)) {
// Empty files are allowed and ignored
++DocIterator;
@@ -82,10 +94,21 @@ void Input::nextDocument() {
++DocIterator;
}
+bool Input::mapTag(StringRef Tag, bool Default) {
+ std::string foundTag = CurrentNode->_node->getVerbatimTag();
+ if (foundTag.empty()) {
+ // If no tag found and 'Tag' is the default, say it was found.
+ return Default;
+ }
+ // Return true iff found tag matches supplied tag.
+ return Tag.equals(foundTag);
+}
+
void Input::beginMapping() {
if (EC)
return;
- MapHNode *MN = dyn_cast<MapHNode>(CurrentNode);
+ // CurrentNode can be null if the document is empty.
+ MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode);
if (MN) {
MN->ValidKeys.clear();
}
@@ -96,6 +119,15 @@ bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault,
UseDefault = false;
if (EC)
return false;
+
+ // CurrentNode is null for empty documents, which is an error in case required
+ // nodes are present.
+ if (!CurrentNode) {
+ if (Required)
+ EC = make_error_code(errc::invalid_argument);
+ return false;
+ }
+
MapHNode *MN = dyn_cast<MapHNode>(CurrentNode);
if (!MN) {
setError(CurrentNode, "not a mapping");
@@ -122,13 +154,14 @@ void Input::postflightKey(void *saveInfo) {
void Input::endMapping() {
if (EC)
return;
- MapHNode *MN = dyn_cast<MapHNode>(CurrentNode);
+ // CurrentNode can be null if the document is empty.
+ MapHNode *MN = dyn_cast_or_null<MapHNode>(CurrentNode);
if (!MN)
return;
for (MapHNode::NameToNode::iterator i = MN->Mapping.begin(),
End = MN->Mapping.end(); i != End; ++i) {
- if (!MN->isValidKey(i->first)) {
- setError(i->second, Twine("unknown key '") + i->first + "'");
+ if (!MN->isValidKey(i->first())) {
+ setError(i->second, Twine("unknown key '") + i->first() + "'");
break;
}
}
@@ -263,6 +296,7 @@ void Input::scalarString(StringRef &S) {
}
void Input::setError(HNode *hnode, const Twine &message) {
+ assert(hnode && "HNode must not be NULL");
this->setError(hnode->_node, message);
}
@@ -322,7 +356,7 @@ Input::HNode *Input::createHNodes(Node *N) {
}
bool Input::MapHNode::isValidKey(StringRef Key) {
- for (SmallVector<const char *, 6>::iterator i = ValidKeys.begin(),
+ for (SmallVectorImpl<const char *>::iterator i = ValidKeys.begin(),
End = ValidKeys.end(); i != End; ++i) {
if (Key.equals(*i))
return true;
@@ -334,6 +368,10 @@ void Input::setError(const Twine &Message) {
this->setError(CurrentNode, Message);
}
+bool Input::canElideEmptySequence() {
+ return false;
+}
+
Input::MapHNode::~MapHNode() {
for (MapHNode::NameToNode::iterator i = Mapping.begin(), End = Mapping.end();
i != End; ++i) {
@@ -368,7 +406,7 @@ Output::Output(raw_ostream &yout, void *context)
Output::~Output() {
}
-bool Output::outputting() {
+bool Output::outputting() const {
return true;
}
@@ -377,6 +415,14 @@ void Output::beginMapping() {
NeedsNewLine = true;
}
+bool Output::mapTag(StringRef Tag, bool Use) {
+ if (Use) {
+ this->output(" ");
+ this->output(Tag);
+ }
+ return Use;
+}
+
void Output::endMapping() {
StateStack.pop_back();
}
@@ -505,9 +551,20 @@ void Output::endBitSetScalar() {
}
void Output::scalarString(StringRef &S) {
+ const char ScalarSafeChars[] = "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t";
+
this->newLineCheck();
- if (S.find('\n') == StringRef::npos) {
- // No embedded new-line chars, just print string.
+ if (S.empty()) {
+ // Print '' for the empty string because leaving the field empty is not
+ // allowed.
+ this->outputUpToEndOfLine("''");
+ return;
+ }
+ if (S.find_first_not_of(ScalarSafeChars) == StringRef::npos &&
+ !isspace(S.front()) && !isspace(S.back())) {
+ // If the string consists only of safe characters, print it out without
+ // quotes.
this->outputUpToEndOfLine(S);
return;
}
@@ -532,6 +589,19 @@ void Output::scalarString(StringRef &S) {
void Output::setError(const Twine &message) {
}
+bool Output::canElideEmptySequence() {
+ // Normally, with an optional key/value where the value is an empty sequence,
+ // the whole key/value can be not written. But, that produces wrong yaml
+ // if the key/value is the only thing in the map and the map is used in
+ // a sequence. This detects if the this sequence is the first key/value
+ // in map that itself is embedded in a sequnce.
+ if (StateStack.size() < 2)
+ return true;
+ if (StateStack.back() != inMapFirstKey)
+ return true;
+ return (StateStack[StateStack.size()-2] != inSeq);
+}
+
void Output::output(StringRef s) {
Column += s.size();
Out << s;
diff --git a/contrib/llvm/lib/Support/raw_ostream.cpp b/contrib/llvm/lib/Support/raw_ostream.cpp
index a433088..cb96489 100644
--- a/contrib/llvm/lib/Support/raw_ostream.cpp
+++ b/contrib/llvm/lib/Support/raw_ostream.cpp
@@ -18,6 +18,7 @@
#include "llvm/Config/config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
@@ -25,14 +26,15 @@
#include <cctype>
#include <cerrno>
#include <sys/stat.h>
-#include <sys/types.h>
-#if defined(HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
+// <fcntl.h> may provide O_BINARY.
#if defined(HAVE_FCNTL_H)
# include <fcntl.h>
#endif
+
+#if defined(HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
#if defined(HAVE_SYS_UIO_H) && defined(HAVE_WRITEV)
# include <sys/uio.h>
#endif
@@ -43,7 +45,6 @@
#if defined(_MSC_VER)
#include <io.h>
-#include <fcntl.h>
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
@@ -424,14 +425,9 @@ void format_object_base::home() {
/// stream should be immediately destroyed; the string will be empty
/// if no error occurred.
raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo,
- unsigned Flags)
- : Error(false), UseAtomicWrites(false), pos(0)
-{
+ sys::fs::OpenFlags Flags)
+ : Error(false), UseAtomicWrites(false), pos(0) {
assert(Filename != 0 && "Filename is null");
- // Verify that we don't have both "append" and "excl".
- assert((!(Flags & F_Excl) || !(Flags & F_Append)) &&
- "Cannot specify both 'excl' and 'append' file creation flags!");
-
ErrorInfo.clear();
// Handle "-" as stdout. Note that when we do this, we consider ourself
@@ -441,32 +437,20 @@ raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo,
FD = STDOUT_FILENO;
// If user requested binary then put stdout into binary mode if
// possible.
- if (Flags & F_Binary)
- sys::Program::ChangeStdoutToBinary();
+ if (Flags & sys::fs::F_Binary)
+ sys::ChangeStdoutToBinary();
// Close stdout when we're done, to detect any output errors.
ShouldClose = true;
return;
}
- int OpenFlags = O_WRONLY|O_CREAT;
-#ifdef O_BINARY
- if (Flags & F_Binary)
- OpenFlags |= O_BINARY;
-#endif
-
- if (Flags & F_Append)
- OpenFlags |= O_APPEND;
- else
- OpenFlags |= O_TRUNC;
- if (Flags & F_Excl)
- OpenFlags |= O_EXCL;
+ error_code EC = sys::fs::openFileForWrite(Filename, FD, Flags);
- while ((FD = open(Filename, OpenFlags, 0664)) < 0) {
- if (errno != EINTR) {
- ErrorInfo = "Error opening output file '" + std::string(Filename) + "'";
- ShouldClose = false;
- return;
- }
+ if (EC) {
+ ErrorInfo = "Error opening output file '" + std::string(Filename) + "': " +
+ EC.message();
+ ShouldClose = false;
+ return;
}
// Ok, we successfully opened the file, so it'll need to be closed.
OpenPOWER on IntegriCloud