2008-08-17 03:35:29 +02:00
|
|
|
//===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2008-08-17 03:35:29 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This implements support for bulk buffered stream output.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2008-08-22 17:45:00 +02:00
|
|
|
#include "llvm/Config/config.h"
|
2009-03-17 22:15:18 +01:00
|
|
|
#include "llvm/Support/Compiler.h"
|
2009-07-15 10:11:46 +02:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2013-07-16 21:44:17 +02:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/Support/Format.h"
|
2016-11-12 00:57:40 +01:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
2014-09-25 22:30:58 +02:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2016-10-11 21:24:45 +02:00
|
|
|
#include "llvm/Support/NativeFormatting.h"
|
2012-12-03 17:50:05 +01:00
|
|
|
#include "llvm/Support/Process.h"
|
|
|
|
#include "llvm/Support/Program.h"
|
2016-08-23 19:14:32 +02:00
|
|
|
#include <algorithm>
|
2010-01-29 16:19:06 +01:00
|
|
|
#include <cctype>
|
2010-05-05 17:17:47 +02:00
|
|
|
#include <cerrno>
|
2016-08-23 19:14:32 +02:00
|
|
|
#include <cstdio>
|
|
|
|
#include <iterator>
|
|
|
|
#include <sys/stat.h>
|
2008-08-17 03:35:29 +02:00
|
|
|
|
2013-07-17 04:21:10 +02:00
|
|
|
// <fcntl.h> may provide O_BINARY.
|
|
|
|
#if defined(HAVE_FCNTL_H)
|
|
|
|
# include <fcntl.h>
|
|
|
|
#endif
|
|
|
|
|
2008-08-22 17:45:00 +02:00
|
|
|
#if defined(HAVE_UNISTD_H)
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
2008-08-17 11:25:21 +02:00
|
|
|
|
2010-10-19 03:21:55 +02:00
|
|
|
#if defined(__CYGWIN__)
|
|
|
|
#include <io.h>
|
|
|
|
#endif
|
|
|
|
|
2008-08-17 11:25:21 +02:00
|
|
|
#if defined(_MSC_VER)
|
2008-08-17 03:35:29 +02:00
|
|
|
#include <io.h>
|
2008-08-21 02:14:44 +02:00
|
|
|
#ifndef STDIN_FILENO
|
|
|
|
# define STDIN_FILENO 0
|
|
|
|
#endif
|
|
|
|
#ifndef STDOUT_FILENO
|
|
|
|
# define STDOUT_FILENO 1
|
|
|
|
#endif
|
|
|
|
#ifndef STDERR_FILENO
|
|
|
|
# define STDERR_FILENO 2
|
|
|
|
#endif
|
2008-08-17 03:35:29 +02:00
|
|
|
#endif
|
|
|
|
|
2018-04-29 02:45:03 +02:00
|
|
|
#ifdef _WIN32
|
[Windows] Convert from UTF-8 to UTF-16 when writing to a Windows console
Summary:
Calling WriteConsoleW is the most reliable way to print Unicode
characters to a Windows console.
If binary data gets printed to the console, attempting to re-encode it
shouldn't be a problem, since garbage in can produce garbage out.
This breaks printing strings in the local codepage, which WriteConsoleA
knows how to handle. For example, this can happen when user source code
is encoded with the local codepage, and an LLVM tool quotes it while
emitting a caret diagnostic. This is unfortunate, but well-behaved tools
should validate that their input is UTF-8 and escape non-UTF-8
characters before sending them to raw_fd_ostream. Clang already does
this, but not all LLVM tools do this.
One drawback to the current implementation is printing a string a byte
at a time doesn't work. Consider this LLVM code:
for (char C : MyStr) outs() << C;
Because outs() is now unbuffered, we wil try to convert each byte to
UTF-16, which will fail. However, this already didn't work, so I think
we may as well update callers that do that as we find them to print
complete portions of strings. You can see a real example of this in my
patch to SourceMgr.cpp
Fixes PR38669 and PR36267.
Reviewers: zturner, efriedma
Subscribers: llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D51558
llvm-svn: 341433
2018-09-05 02:08:56 +02:00
|
|
|
#include "llvm/Support/ConvertUTF.h"
|
2020-02-28 09:59:24 +01:00
|
|
|
#include "llvm/Support/Windows/WindowsSupport.h"
|
2016-01-06 01:50:06 +01:00
|
|
|
#endif
|
|
|
|
|
2008-08-22 17:45:00 +02:00
|
|
|
using namespace llvm;
|
|
|
|
|
2020-04-22 12:09:37 +02:00
|
|
|
constexpr raw_ostream::Colors raw_ostream::BLACK;
|
|
|
|
constexpr raw_ostream::Colors raw_ostream::RED;
|
|
|
|
constexpr raw_ostream::Colors raw_ostream::GREEN;
|
|
|
|
constexpr raw_ostream::Colors raw_ostream::YELLOW;
|
|
|
|
constexpr raw_ostream::Colors raw_ostream::BLUE;
|
|
|
|
constexpr raw_ostream::Colors raw_ostream::MAGENTA;
|
|
|
|
constexpr raw_ostream::Colors raw_ostream::CYAN;
|
|
|
|
constexpr raw_ostream::Colors raw_ostream::WHITE;
|
|
|
|
constexpr raw_ostream::Colors raw_ostream::SAVEDCOLOR;
|
|
|
|
constexpr raw_ostream::Colors raw_ostream::RESET;
|
2019-08-07 10:08:17 +02:00
|
|
|
|
2009-07-16 01:25:33 +02:00
|
|
|
raw_ostream::~raw_ostream() {
|
2009-07-27 22:49:44 +02:00
|
|
|
// raw_ostream's subclasses should take care to flush the buffer
|
|
|
|
// in their destructors.
|
|
|
|
assert(OutBufCur == OutBufStart &&
|
|
|
|
"raw_ostream destructor called with non-empty buffer!");
|
|
|
|
|
2019-11-08 16:06:33 +01:00
|
|
|
if (BufferMode == BufferKind::InternalBuffer)
|
2009-08-19 01:42:36 +02:00
|
|
|
delete [] OutBufStart;
|
2009-07-16 01:25:33 +02:00
|
|
|
}
|
2008-08-22 17:45:00 +02:00
|
|
|
|
2009-12-19 02:38:42 +01:00
|
|
|
size_t raw_ostream::preferred_buffer_size() const {
|
2009-08-13 19:27:29 +02:00
|
|
|
// BUFSIZ is intended to be a reasonable default.
|
|
|
|
return BUFSIZ;
|
|
|
|
}
|
|
|
|
|
|
|
|
void raw_ostream::SetBuffered() {
|
|
|
|
// Ask the subclass to determine an appropriate buffer size.
|
2009-08-15 04:05:19 +02:00
|
|
|
if (size_t Size = preferred_buffer_size())
|
|
|
|
SetBufferSize(Size);
|
|
|
|
else
|
|
|
|
// It may return 0, meaning this stream should be unbuffered.
|
|
|
|
SetUnbuffered();
|
2009-08-13 19:27:29 +02:00
|
|
|
}
|
|
|
|
|
2010-03-24 20:38:02 +01:00
|
|
|
void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
|
2011-08-28 05:30:02 +02:00
|
|
|
BufferKind Mode) {
|
2019-11-08 16:06:33 +01:00
|
|
|
assert(((Mode == BufferKind::Unbuffered && !BufferStart && Size == 0) ||
|
|
|
|
(Mode != BufferKind::Unbuffered && BufferStart && Size != 0)) &&
|
2009-09-15 22:31:46 +02:00
|
|
|
"stream must be unbuffered or have at least one byte");
|
2009-08-19 01:42:36 +02:00
|
|
|
// Make sure the current buffer is free of content (we can't flush here; the
|
|
|
|
// child buffer management logic will be in write_impl).
|
|
|
|
assert(GetNumBytesInBuffer() == 0 && "Current buffer is non-empty!");
|
2009-08-13 17:58:55 +02:00
|
|
|
|
2019-11-08 16:06:33 +01:00
|
|
|
if (BufferMode == BufferKind::InternalBuffer)
|
2009-08-19 01:42:36 +02:00
|
|
|
delete [] OutBufStart;
|
|
|
|
OutBufStart = BufferStart;
|
2009-08-13 17:58:55 +02:00
|
|
|
OutBufEnd = OutBufStart+Size;
|
|
|
|
OutBufCur = OutBufStart;
|
2009-08-19 01:42:36 +02:00
|
|
|
BufferMode = Mode;
|
2009-08-19 19:54:29 +02:00
|
|
|
|
|
|
|
assert(OutBufStart <= OutBufEnd && "Invalid size!");
|
2009-08-13 17:58:55 +02:00
|
|
|
}
|
|
|
|
|
2008-08-21 22:58:52 +02:00
|
|
|
raw_ostream &raw_ostream::operator<<(unsigned long N) {
|
2016-11-12 00:57:40 +01:00
|
|
|
write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
|
2016-10-11 21:24:45 +02:00
|
|
|
return *this;
|
2008-08-21 22:58:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &raw_ostream::operator<<(long N) {
|
2016-11-12 00:57:40 +01:00
|
|
|
write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
|
2016-10-11 21:24:45 +02:00
|
|
|
return *this;
|
2008-08-21 22:58:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &raw_ostream::operator<<(unsigned long long N) {
|
2016-11-12 00:57:40 +01:00
|
|
|
write_integer(*this, static_cast<uint64_t>(N), 0, IntegerStyle::Integer);
|
2016-10-11 21:24:45 +02:00
|
|
|
return *this;
|
2008-08-21 22:58:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &raw_ostream::operator<<(long long N) {
|
2016-11-12 00:57:40 +01:00
|
|
|
write_integer(*this, static_cast<int64_t>(N), 0, IntegerStyle::Integer);
|
2016-10-11 21:24:45 +02:00
|
|
|
return *this;
|
2008-08-21 22:58:52 +02:00
|
|
|
}
|
|
|
|
|
2009-07-30 20:21:23 +02:00
|
|
|
raw_ostream &raw_ostream::write_hex(unsigned long long N) {
|
2016-10-29 02:27:22 +02:00
|
|
|
llvm::write_hex(*this, N, HexPrintStyle::Lower);
|
2016-10-11 21:24:45 +02:00
|
|
|
return *this;
|
2008-08-24 00:23:09 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 10:08:17 +02:00
|
|
|
raw_ostream &raw_ostream::operator<<(Colors C) {
|
|
|
|
if (C == Colors::RESET)
|
|
|
|
resetColor();
|
|
|
|
else
|
|
|
|
changeColor(C);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-09-13 20:22:59 +02:00
|
|
|
raw_ostream &raw_ostream::write_uuid(const uuid_t UUID) {
|
|
|
|
for (int Idx = 0; Idx < 16; ++Idx) {
|
|
|
|
*this << format("%02" PRIX32, UUID[Idx]);
|
|
|
|
if (Idx == 3 || Idx == 5 || Idx == 7 || Idx == 9)
|
|
|
|
*this << "-";
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-27 08:59:50 +01:00
|
|
|
raw_ostream &raw_ostream::write_escaped(StringRef Str,
|
|
|
|
bool UseHexEscapes) {
|
2016-02-04 07:51:41 +01:00
|
|
|
for (unsigned char c : Str) {
|
2009-10-17 22:43:08 +02:00
|
|
|
switch (c) {
|
|
|
|
case '\\':
|
|
|
|
*this << '\\' << '\\';
|
|
|
|
break;
|
|
|
|
case '\t':
|
|
|
|
*this << '\\' << 't';
|
|
|
|
break;
|
|
|
|
case '\n':
|
|
|
|
*this << '\\' << 'n';
|
|
|
|
break;
|
|
|
|
case '"':
|
|
|
|
*this << '\\' << '"';
|
|
|
|
break;
|
|
|
|
default:
|
2018-07-26 17:31:41 +02:00
|
|
|
if (isPrint(c)) {
|
2009-10-17 22:43:08 +02:00
|
|
|
*this << c;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-11-27 08:59:50 +01:00
|
|
|
// Write out the escaped representation.
|
|
|
|
if (UseHexEscapes) {
|
|
|
|
*this << '\\' << 'x';
|
|
|
|
*this << hexdigit((c >> 4 & 0xF));
|
|
|
|
*this << hexdigit((c >> 0) & 0xF);
|
|
|
|
} else {
|
|
|
|
// Always use a full 3-character octal escape.
|
|
|
|
*this << '\\';
|
|
|
|
*this << char('0' + ((c >> 6) & 7));
|
|
|
|
*this << char('0' + ((c >> 3) & 7));
|
|
|
|
*this << char('0' + ((c >> 0) & 7));
|
|
|
|
}
|
2009-10-17 22:43:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2009-07-30 20:21:23 +02:00
|
|
|
raw_ostream &raw_ostream::operator<<(const void *P) {
|
2016-10-29 02:27:22 +02:00
|
|
|
llvm::write_hex(*this, (uintptr_t)P, HexPrintStyle::PrefixLower);
|
2016-10-11 21:24:45 +02:00
|
|
|
return *this;
|
2009-07-30 20:21:23 +02:00
|
|
|
}
|
|
|
|
|
2009-08-24 05:52:50 +02:00
|
|
|
raw_ostream &raw_ostream::operator<<(double N) {
|
2016-10-29 02:27:22 +02:00
|
|
|
llvm::write_double(*this, N, FloatStyle::Exponent);
|
2016-10-11 21:24:45 +02:00
|
|
|
return *this;
|
2009-08-24 05:52:50 +02:00
|
|
|
}
|
|
|
|
|
2009-03-16 23:55:06 +01:00
|
|
|
void raw_ostream::flush_nonempty() {
|
|
|
|
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
|
2009-08-19 01:42:36 +02:00
|
|
|
size_t Length = OutBufCur - OutBufStart;
|
|
|
|
OutBufCur = OutBufStart;
|
2020-06-08 13:58:04 +02:00
|
|
|
flush_tied_then_write(OutBufStart, Length);
|
2009-03-16 23:55:06 +01:00
|
|
|
}
|
|
|
|
|
2009-03-16 23:00:17 +01:00
|
|
|
raw_ostream &raw_ostream::write(unsigned char C) {
|
2009-03-17 02:36:56 +01:00
|
|
|
// Group exceptional cases into a single branch.
|
2012-08-30 00:57:00 +02:00
|
|
|
if (LLVM_UNLIKELY(OutBufCur >= OutBufEnd)) {
|
|
|
|
if (LLVM_UNLIKELY(!OutBufStart)) {
|
2019-11-08 16:06:33 +01:00
|
|
|
if (BufferMode == BufferKind::Unbuffered) {
|
2020-06-08 13:58:04 +02:00
|
|
|
flush_tied_then_write(reinterpret_cast<char *>(&C), 1);
|
2009-08-18 22:09:59 +02:00
|
|
|
return *this;
|
|
|
|
}
|
2009-08-19 02:23:39 +02:00
|
|
|
// Set up a buffer and start over.
|
|
|
|
SetBuffered();
|
|
|
|
return write(C);
|
2009-08-18 22:09:59 +02:00
|
|
|
}
|
2009-08-19 02:23:39 +02:00
|
|
|
|
|
|
|
flush_nonempty();
|
2009-03-17 02:13:35 +01:00
|
|
|
}
|
|
|
|
|
2009-03-16 23:00:17 +01:00
|
|
|
*OutBufCur++ = C;
|
2009-03-16 23:08:44 +01:00
|
|
|
return *this;
|
2009-03-16 23:00:17 +01:00
|
|
|
}
|
2008-08-24 00:23:09 +02:00
|
|
|
|
2009-07-16 17:24:40 +02:00
|
|
|
raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) {
|
2009-03-17 02:36:56 +01:00
|
|
|
// Group exceptional cases into a single branch.
|
2012-08-30 00:57:00 +02:00
|
|
|
if (LLVM_UNLIKELY(size_t(OutBufEnd - OutBufCur) < Size)) {
|
|
|
|
if (LLVM_UNLIKELY(!OutBufStart)) {
|
2019-11-08 16:06:33 +01:00
|
|
|
if (BufferMode == BufferKind::Unbuffered) {
|
2020-06-08 13:58:04 +02:00
|
|
|
flush_tied_then_write(Ptr, Size);
|
2009-08-13 17:44:52 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
// Set up a buffer and start over.
|
2009-08-13 19:27:29 +02:00
|
|
|
SetBuffered();
|
2009-08-13 17:44:52 +02:00
|
|
|
return write(Ptr, Size);
|
|
|
|
}
|
2009-08-19 02:23:39 +02:00
|
|
|
|
2011-03-04 20:49:30 +01:00
|
|
|
size_t NumBytes = OutBufEnd - OutBufCur;
|
|
|
|
|
2011-03-04 19:18:16 +01:00
|
|
|
// If the buffer is empty at this point we have a string that is larger
|
2011-03-04 20:49:30 +01:00
|
|
|
// than the buffer. Directly write the chunk that is a multiple of the
|
|
|
|
// preferred buffer size and put the remainder in the buffer.
|
2012-08-30 00:57:00 +02:00
|
|
|
if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) {
|
2014-12-12 22:48:03 +01:00
|
|
|
assert(NumBytes != 0 && "undefined behavior");
|
2011-03-04 20:49:30 +01:00
|
|
|
size_t BytesToWrite = Size - (Size % NumBytes);
|
2020-06-08 13:58:04 +02:00
|
|
|
flush_tied_then_write(Ptr, BytesToWrite);
|
2013-03-13 00:55:24 +01:00
|
|
|
size_t BytesRemaining = Size - BytesToWrite;
|
|
|
|
if (BytesRemaining > size_t(OutBufEnd - OutBufCur)) {
|
|
|
|
// Too much left over to copy into our buffer.
|
|
|
|
return write(Ptr + BytesToWrite, BytesRemaining);
|
|
|
|
}
|
|
|
|
copy_to_buffer(Ptr + BytesToWrite, BytesRemaining);
|
2011-03-04 19:18:16 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't have enough space in the buffer to fit the string in. Insert as
|
|
|
|
// much as possible, flush and start over with the remainder.
|
|
|
|
copy_to_buffer(Ptr, NumBytes);
|
|
|
|
flush_nonempty();
|
|
|
|
return write(Ptr + NumBytes, Size - NumBytes);
|
2009-03-17 02:36:56 +01:00
|
|
|
}
|
2009-08-13 17:44:52 +02:00
|
|
|
|
|
|
|
copy_to_buffer(Ptr, Size);
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) {
|
2009-08-13 22:32:03 +02:00
|
|
|
assert(Size <= size_t(OutBufEnd - OutBufCur) && "Buffer overrun!");
|
2009-08-13 20:38:15 +02:00
|
|
|
|
2008-08-21 22:58:52 +02:00
|
|
|
// Handle short strings specially, memcpy isn't very good at very short
|
|
|
|
// strings.
|
|
|
|
switch (Size) {
|
2016-08-17 22:30:52 +02:00
|
|
|
case 4: OutBufCur[3] = Ptr[3]; LLVM_FALLTHROUGH;
|
|
|
|
case 3: OutBufCur[2] = Ptr[2]; LLVM_FALLTHROUGH;
|
|
|
|
case 2: OutBufCur[1] = Ptr[1]; LLVM_FALLTHROUGH;
|
|
|
|
case 1: OutBufCur[0] = Ptr[0]; LLVM_FALLTHROUGH;
|
2008-08-21 22:58:52 +02:00
|
|
|
case 0: break;
|
|
|
|
default:
|
2009-08-13 17:44:52 +02:00
|
|
|
memcpy(OutBufCur, Ptr, Size);
|
2008-08-21 22:58:52 +02:00
|
|
|
break;
|
|
|
|
}
|
2009-03-10 17:21:55 +01:00
|
|
|
|
2009-08-13 17:44:52 +02:00
|
|
|
OutBufCur += Size;
|
2008-08-21 22:58:52 +02:00
|
|
|
}
|
|
|
|
|
2020-06-08 13:58:04 +02:00
|
|
|
void raw_ostream::flush_tied_then_write(const char *Ptr, size_t Size) {
|
|
|
|
if (TiedStream)
|
|
|
|
TiedStream->flush();
|
|
|
|
write_impl(Ptr, Size);
|
|
|
|
}
|
|
|
|
|
2008-08-23 21:23:10 +02:00
|
|
|
// Formatted output.
|
|
|
|
raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) {
|
2009-03-17 02:36:56 +01:00
|
|
|
// If we have more than a few bytes left in our output buffer, try
|
|
|
|
// formatting directly onto its end.
|
2009-07-16 17:24:40 +02:00
|
|
|
size_t NextBufferSize = 127;
|
2009-08-23 22:31:39 +02:00
|
|
|
size_t BufferBytesLeft = OutBufEnd - OutBufCur;
|
|
|
|
if (BufferBytesLeft > 3) {
|
2009-07-16 17:24:40 +02:00
|
|
|
size_t BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft);
|
2010-03-24 20:38:02 +01:00
|
|
|
|
2008-08-23 21:23:10 +02:00
|
|
|
// Common case is that we have plenty of space.
|
2009-08-23 22:31:39 +02:00
|
|
|
if (BytesUsed <= BufferBytesLeft) {
|
2008-08-23 21:23:10 +02:00
|
|
|
OutBufCur += BytesUsed;
|
|
|
|
return *this;
|
|
|
|
}
|
2010-03-24 20:38:02 +01:00
|
|
|
|
2008-08-23 21:23:10 +02:00
|
|
|
// Otherwise, we overflowed and the return value tells us the size to try
|
|
|
|
// again with.
|
|
|
|
NextBufferSize = BytesUsed;
|
|
|
|
}
|
2010-03-24 20:38:02 +01:00
|
|
|
|
2008-08-23 21:23:10 +02:00
|
|
|
// If we got here, we didn't have enough space in the output buffer for the
|
|
|
|
// string. Try printing into a SmallVector that is resized to have enough
|
|
|
|
// space. Iterate until we win.
|
|
|
|
SmallVector<char, 128> V;
|
2010-03-24 20:38:02 +01:00
|
|
|
|
2016-08-23 19:14:32 +02:00
|
|
|
while (true) {
|
2008-08-23 21:23:10 +02:00
|
|
|
V.resize(NextBufferSize);
|
2010-03-24 20:38:02 +01:00
|
|
|
|
2008-08-23 21:23:10 +02:00
|
|
|
// Try formatting into the SmallVector.
|
2009-08-23 22:31:39 +02:00
|
|
|
size_t BytesUsed = Fmt.print(V.data(), NextBufferSize);
|
2010-03-24 20:38:02 +01:00
|
|
|
|
2008-08-23 21:23:10 +02:00
|
|
|
// If BytesUsed fit into the vector, we win.
|
2008-10-26 20:20:47 +01:00
|
|
|
if (BytesUsed <= NextBufferSize)
|
2009-08-23 22:31:39 +02:00
|
|
|
return write(V.data(), BytesUsed);
|
2010-03-24 20:38:02 +01:00
|
|
|
|
2008-08-23 21:23:10 +02:00
|
|
|
// Otherwise, try again with a new size.
|
|
|
|
assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?");
|
|
|
|
NextBufferSize = BytesUsed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-12 00:57:40 +01:00
|
|
|
raw_ostream &raw_ostream::operator<<(const formatv_object_base &Obj) {
|
|
|
|
Obj.format(*this);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2014-09-25 22:30:58 +02:00
|
|
|
raw_ostream &raw_ostream::operator<<(const FormattedString &FS) {
|
2020-04-26 14:05:55 +02:00
|
|
|
unsigned LeftIndent = 0;
|
|
|
|
unsigned RightIndent = 0;
|
|
|
|
const ssize_t Difference = FS.Width - FS.Str.size();
|
|
|
|
if (Difference > 0) {
|
|
|
|
switch (FS.Justify) {
|
|
|
|
case FormattedString::JustifyNone:
|
|
|
|
break;
|
|
|
|
case FormattedString::JustifyLeft:
|
|
|
|
RightIndent = Difference;
|
|
|
|
break;
|
|
|
|
case FormattedString::JustifyRight:
|
|
|
|
LeftIndent = Difference;
|
|
|
|
break;
|
|
|
|
case FormattedString::JustifyCenter:
|
|
|
|
LeftIndent = Difference / 2;
|
|
|
|
RightIndent = Difference - LeftIndent;
|
|
|
|
break;
|
|
|
|
}
|
2017-07-13 18:11:08 +02:00
|
|
|
}
|
2020-04-26 14:05:55 +02:00
|
|
|
indent(LeftIndent);
|
|
|
|
(*this) << FS.Str;
|
|
|
|
indent(RightIndent);
|
2014-09-25 22:30:58 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) {
|
|
|
|
if (FN.Hex) {
|
2016-10-29 02:27:22 +02:00
|
|
|
HexPrintStyle Style;
|
|
|
|
if (FN.Upper && FN.HexPrefix)
|
|
|
|
Style = HexPrintStyle::PrefixUpper;
|
|
|
|
else if (FN.Upper && !FN.HexPrefix)
|
|
|
|
Style = HexPrintStyle::Upper;
|
|
|
|
else if (!FN.Upper && FN.HexPrefix)
|
|
|
|
Style = HexPrintStyle::PrefixLower;
|
|
|
|
else
|
|
|
|
Style = HexPrintStyle::Lower;
|
|
|
|
llvm::write_hex(*this, FN.HexValue, Style, FN.Width);
|
2014-09-25 22:30:58 +02:00
|
|
|
} else {
|
2016-10-29 02:27:22 +02:00
|
|
|
llvm::SmallString<16> Buffer;
|
|
|
|
llvm::raw_svector_ostream Stream(Buffer);
|
2016-11-12 00:57:40 +01:00
|
|
|
llvm::write_integer(Stream, FN.DecValue, 0, IntegerStyle::Integer);
|
2016-10-29 02:27:22 +02:00
|
|
|
if (Buffer.size() < FN.Width)
|
|
|
|
indent(FN.Width - Buffer.size());
|
|
|
|
(*this) << Buffer;
|
2014-09-25 22:30:58 +02:00
|
|
|
}
|
2016-10-11 21:24:45 +02:00
|
|
|
return *this;
|
2014-09-25 22:30:58 +02:00
|
|
|
}
|
|
|
|
|
2016-11-10 21:16:45 +01:00
|
|
|
raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) {
|
|
|
|
if (FB.Bytes.empty())
|
|
|
|
return *this;
|
|
|
|
|
Added the ability to dump hex bytes easily into a raw_ostream.
Unit tests were added to verify this functionality keeps working correctly.
Example output for raw hex bytes:
llvm::ArrayRef<uint8_t> Bytes = ...;
llvm::outs() << format_hex_bytes(Bytes);
554889e5 4881ec70 04000048 8d051002
00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with offsets:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with ASCII with offsets:
llvm::outs() << format_hex_bytes_with_ascii(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002 |UH.?H.?p...H....|
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000 |..L..?...L..?...|
The default groups bytes into 4 byte groups, but this can be changed to 1 byte:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00 00 4c 8b 0d d0 02 00 00
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 2 /*ByteGroupSize*/);
0x0000000100000d10: 5548 89e5 4881 ec70 0400 0048 8d05 1002
0x0000000100000d20: 0000 4c8d 05fd 0100 004c 8b0d d002 0000
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 8 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70
0x0000000100000d18: 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00
0x0000000100000d28: 00 4c 8b 0d d0 02 00 00
https://reviews.llvm.org/D26405
llvm-svn: 286316
2016-11-09 01:15:54 +01:00
|
|
|
size_t LineIndex = 0;
|
2016-11-10 21:16:45 +01:00
|
|
|
auto Bytes = FB.Bytes;
|
|
|
|
const size_t Size = Bytes.size();
|
|
|
|
HexPrintStyle HPS = FB.Upper ? HexPrintStyle::Upper : HexPrintStyle::Lower;
|
|
|
|
uint64_t OffsetWidth = 0;
|
|
|
|
if (FB.FirstByteOffset.hasValue()) {
|
|
|
|
// Figure out how many nibbles are needed to print the largest offset
|
|
|
|
// represented by this data set, so that we can align the offset field
|
|
|
|
// to the right width.
|
|
|
|
size_t Lines = Size / FB.NumPerLine;
|
|
|
|
uint64_t MaxOffset = *FB.FirstByteOffset + Lines * FB.NumPerLine;
|
|
|
|
unsigned Power = 0;
|
|
|
|
if (MaxOffset > 0)
|
|
|
|
Power = llvm::Log2_64_Ceil(MaxOffset);
|
2016-11-10 21:35:21 +01:00
|
|
|
OffsetWidth = std::max<uint64_t>(4, llvm::alignTo(Power, 4) / 4);
|
2016-11-10 21:16:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// The width of a block of data including all spaces for group separators.
|
|
|
|
unsigned NumByteGroups =
|
|
|
|
alignTo(FB.NumPerLine, FB.ByteGroupSize) / FB.ByteGroupSize;
|
|
|
|
unsigned BlockCharWidth = FB.NumPerLine * 2 + NumByteGroups - 1;
|
|
|
|
|
|
|
|
while (!Bytes.empty()) {
|
|
|
|
indent(FB.IndentLevel);
|
|
|
|
|
Added the ability to dump hex bytes easily into a raw_ostream.
Unit tests were added to verify this functionality keeps working correctly.
Example output for raw hex bytes:
llvm::ArrayRef<uint8_t> Bytes = ...;
llvm::outs() << format_hex_bytes(Bytes);
554889e5 4881ec70 04000048 8d051002
00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with offsets:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with ASCII with offsets:
llvm::outs() << format_hex_bytes_with_ascii(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002 |UH.?H.?p...H....|
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000 |..L..?...L..?...|
The default groups bytes into 4 byte groups, but this can be changed to 1 byte:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00 00 4c 8b 0d d0 02 00 00
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 2 /*ByteGroupSize*/);
0x0000000100000d10: 5548 89e5 4881 ec70 0400 0048 8d05 1002
0x0000000100000d20: 0000 4c8d 05fd 0100 004c 8b0d d002 0000
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 8 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70
0x0000000100000d18: 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00
0x0000000100000d28: 00 4c 8b 0d d0 02 00 00
https://reviews.llvm.org/D26405
llvm-svn: 286316
2016-11-09 01:15:54 +01:00
|
|
|
if (FB.FirstByteOffset.hasValue()) {
|
|
|
|
uint64_t Offset = FB.FirstByteOffset.getValue();
|
2016-11-10 21:16:45 +01:00
|
|
|
llvm::write_hex(*this, Offset + LineIndex, HPS, OffsetWidth);
|
Added the ability to dump hex bytes easily into a raw_ostream.
Unit tests were added to verify this functionality keeps working correctly.
Example output for raw hex bytes:
llvm::ArrayRef<uint8_t> Bytes = ...;
llvm::outs() << format_hex_bytes(Bytes);
554889e5 4881ec70 04000048 8d051002
00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with offsets:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with ASCII with offsets:
llvm::outs() << format_hex_bytes_with_ascii(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002 |UH.?H.?p...H....|
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000 |..L..?...L..?...|
The default groups bytes into 4 byte groups, but this can be changed to 1 byte:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00 00 4c 8b 0d d0 02 00 00
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 2 /*ByteGroupSize*/);
0x0000000100000d10: 5548 89e5 4881 ec70 0400 0048 8d05 1002
0x0000000100000d20: 0000 4c8d 05fd 0100 004c 8b0d d002 0000
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 8 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70
0x0000000100000d18: 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00
0x0000000100000d28: 00 4c 8b 0d d0 02 00 00
https://reviews.llvm.org/D26405
llvm-svn: 286316
2016-11-09 01:15:54 +01:00
|
|
|
*this << ": ";
|
|
|
|
}
|
2016-11-10 21:16:45 +01:00
|
|
|
|
|
|
|
auto Line = Bytes.take_front(FB.NumPerLine);
|
|
|
|
|
|
|
|
size_t CharsPrinted = 0;
|
|
|
|
// Print the hex bytes for this line in groups
|
|
|
|
for (size_t I = 0; I < Line.size(); ++I, CharsPrinted += 2) {
|
|
|
|
if (I && (I % FB.ByteGroupSize) == 0) {
|
|
|
|
++CharsPrinted;
|
Added the ability to dump hex bytes easily into a raw_ostream.
Unit tests were added to verify this functionality keeps working correctly.
Example output for raw hex bytes:
llvm::ArrayRef<uint8_t> Bytes = ...;
llvm::outs() << format_hex_bytes(Bytes);
554889e5 4881ec70 04000048 8d051002
00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with offsets:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with ASCII with offsets:
llvm::outs() << format_hex_bytes_with_ascii(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002 |UH.?H.?p...H....|
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000 |..L..?...L..?...|
The default groups bytes into 4 byte groups, but this can be changed to 1 byte:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00 00 4c 8b 0d d0 02 00 00
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 2 /*ByteGroupSize*/);
0x0000000100000d10: 5548 89e5 4881 ec70 0400 0048 8d05 1002
0x0000000100000d20: 0000 4c8d 05fd 0100 004c 8b0d d002 0000
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 8 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70
0x0000000100000d18: 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00
0x0000000100000d28: 00 4c 8b 0d d0 02 00 00
https://reviews.llvm.org/D26405
llvm-svn: 286316
2016-11-09 01:15:54 +01:00
|
|
|
*this << " ";
|
2016-11-10 21:16:45 +01:00
|
|
|
}
|
|
|
|
llvm::write_hex(*this, Line[I], HPS, 2);
|
Added the ability to dump hex bytes easily into a raw_ostream.
Unit tests were added to verify this functionality keeps working correctly.
Example output for raw hex bytes:
llvm::ArrayRef<uint8_t> Bytes = ...;
llvm::outs() << format_hex_bytes(Bytes);
554889e5 4881ec70 04000048 8d051002
00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with offsets:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with ASCII with offsets:
llvm::outs() << format_hex_bytes_with_ascii(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002 |UH.?H.?p...H....|
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000 |..L..?...L..?...|
The default groups bytes into 4 byte groups, but this can be changed to 1 byte:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00 00 4c 8b 0d d0 02 00 00
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 2 /*ByteGroupSize*/);
0x0000000100000d10: 5548 89e5 4881 ec70 0400 0048 8d05 1002
0x0000000100000d20: 0000 4c8d 05fd 0100 004c 8b0d d002 0000
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 8 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70
0x0000000100000d18: 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00
0x0000000100000d28: 00 4c 8b 0d d0 02 00 00
https://reviews.llvm.org/D26405
llvm-svn: 286316
2016-11-09 01:15:54 +01:00
|
|
|
}
|
2016-11-10 21:16:45 +01:00
|
|
|
|
Added the ability to dump hex bytes easily into a raw_ostream.
Unit tests were added to verify this functionality keeps working correctly.
Example output for raw hex bytes:
llvm::ArrayRef<uint8_t> Bytes = ...;
llvm::outs() << format_hex_bytes(Bytes);
554889e5 4881ec70 04000048 8d051002
00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with offsets:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with ASCII with offsets:
llvm::outs() << format_hex_bytes_with_ascii(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002 |UH.?H.?p...H....|
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000 |..L..?...L..?...|
The default groups bytes into 4 byte groups, but this can be changed to 1 byte:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00 00 4c 8b 0d d0 02 00 00
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 2 /*ByteGroupSize*/);
0x0000000100000d10: 5548 89e5 4881 ec70 0400 0048 8d05 1002
0x0000000100000d20: 0000 4c8d 05fd 0100 004c 8b0d d002 0000
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 8 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70
0x0000000100000d18: 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00
0x0000000100000d28: 00 4c 8b 0d d0 02 00 00
https://reviews.llvm.org/D26405
llvm-svn: 286316
2016-11-09 01:15:54 +01:00
|
|
|
if (FB.ASCII) {
|
|
|
|
// Print any spaces needed for any bytes that we didn't print on this
|
|
|
|
// line so that the ASCII bytes are correctly aligned.
|
2016-11-10 21:16:45 +01:00
|
|
|
assert(BlockCharWidth >= CharsPrinted);
|
|
|
|
indent(BlockCharWidth - CharsPrinted + 2);
|
|
|
|
*this << "|";
|
|
|
|
|
Added the ability to dump hex bytes easily into a raw_ostream.
Unit tests were added to verify this functionality keeps working correctly.
Example output for raw hex bytes:
llvm::ArrayRef<uint8_t> Bytes = ...;
llvm::outs() << format_hex_bytes(Bytes);
554889e5 4881ec70 04000048 8d051002
00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with offsets:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with ASCII with offsets:
llvm::outs() << format_hex_bytes_with_ascii(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002 |UH.?H.?p...H....|
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000 |..L..?...L..?...|
The default groups bytes into 4 byte groups, but this can be changed to 1 byte:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00 00 4c 8b 0d d0 02 00 00
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 2 /*ByteGroupSize*/);
0x0000000100000d10: 5548 89e5 4881 ec70 0400 0048 8d05 1002
0x0000000100000d20: 0000 4c8d 05fd 0100 004c 8b0d d002 0000
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 8 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70
0x0000000100000d18: 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00
0x0000000100000d28: 00 4c 8b 0d d0 02 00 00
https://reviews.llvm.org/D26405
llvm-svn: 286316
2016-11-09 01:15:54 +01:00
|
|
|
// Print the ASCII char values for each byte on this line
|
2016-11-10 21:16:45 +01:00
|
|
|
for (uint8_t Byte : Line) {
|
2018-07-26 17:31:41 +02:00
|
|
|
if (isPrint(Byte))
|
2016-11-10 21:16:45 +01:00
|
|
|
*this << static_cast<char>(Byte);
|
Added the ability to dump hex bytes easily into a raw_ostream.
Unit tests were added to verify this functionality keeps working correctly.
Example output for raw hex bytes:
llvm::ArrayRef<uint8_t> Bytes = ...;
llvm::outs() << format_hex_bytes(Bytes);
554889e5 4881ec70 04000048 8d051002
00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with offsets:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with ASCII with offsets:
llvm::outs() << format_hex_bytes_with_ascii(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002 |UH.?H.?p...H....|
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000 |..L..?...L..?...|
The default groups bytes into 4 byte groups, but this can be changed to 1 byte:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00 00 4c 8b 0d d0 02 00 00
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 2 /*ByteGroupSize*/);
0x0000000100000d10: 5548 89e5 4881 ec70 0400 0048 8d05 1002
0x0000000100000d20: 0000 4c8d 05fd 0100 004c 8b0d d002 0000
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 8 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70
0x0000000100000d18: 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00
0x0000000100000d28: 00 4c 8b 0d d0 02 00 00
https://reviews.llvm.org/D26405
llvm-svn: 286316
2016-11-09 01:15:54 +01:00
|
|
|
else
|
|
|
|
*this << '.';
|
|
|
|
}
|
|
|
|
*this << '|';
|
|
|
|
}
|
2016-11-10 21:16:45 +01:00
|
|
|
|
|
|
|
Bytes = Bytes.drop_front(Line.size());
|
|
|
|
LineIndex += Line.size();
|
Added the ability to dump hex bytes easily into a raw_ostream.
Unit tests were added to verify this functionality keeps working correctly.
Example output for raw hex bytes:
llvm::ArrayRef<uint8_t> Bytes = ...;
llvm::outs() << format_hex_bytes(Bytes);
554889e5 4881ec70 04000048 8d051002
00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with offsets:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000
Example output for raw hex bytes with ASCII with offsets:
llvm::outs() << format_hex_bytes_with_ascii(Bytes, 0x100000d10);
0x0000000100000d10: 554889e5 4881ec70 04000048 8d051002 |UH.?H.?p...H....|
0x0000000100000d20: 00004c8d 05fd0100 004c8b0d d0020000 |..L..?...L..?...|
The default groups bytes into 4 byte groups, but this can be changed to 1 byte:
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00 00 4c 8b 0d d0 02 00 00
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 16 /*NumPerLine*/, 2 /*ByteGroupSize*/);
0x0000000100000d10: 5548 89e5 4881 ec70 0400 0048 8d05 1002
0x0000000100000d20: 0000 4c8d 05fd 0100 004c 8b0d d002 0000
llvm::outs() << format_hex_bytes(Bytes, 0x100000d10, 8 /*NumPerLine*/, 1 /*ByteGroupSize*/);
0x0000000100000d10: 55 48 89 e5 48 81 ec 70
0x0000000100000d18: 04 00 00 48 8d 05 10 02
0x0000000100000d20: 00 00 4c 8d 05 fd 01 00
0x0000000100000d28: 00 4c 8b 0d d0 02 00 00
https://reviews.llvm.org/D26405
llvm-svn: 286316
2016-11-09 01:15:54 +01:00
|
|
|
if (LineIndex < Size)
|
|
|
|
*this << '\n';
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-05-18 00:11:43 +02:00
|
|
|
template <char C>
|
|
|
|
static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) {
|
|
|
|
static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
|
|
|
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
|
|
|
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
|
|
|
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C,
|
|
|
|
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C};
|
2009-08-23 01:10:29 +02:00
|
|
|
|
|
|
|
// Usually the indentation is small, handle it with a fastpath.
|
2018-05-18 00:11:43 +02:00
|
|
|
if (NumChars < array_lengthof(Chars))
|
|
|
|
return OS.write(Chars, NumChars);
|
|
|
|
|
|
|
|
while (NumChars) {
|
|
|
|
unsigned NumToWrite = std::min(NumChars,
|
|
|
|
(unsigned)array_lengthof(Chars)-1);
|
|
|
|
OS.write(Chars, NumToWrite);
|
|
|
|
NumChars -= NumToWrite;
|
2009-08-23 01:10:29 +02:00
|
|
|
}
|
2018-05-18 00:11:43 +02:00
|
|
|
return OS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// indent - Insert 'NumSpaces' spaces.
|
|
|
|
raw_ostream &raw_ostream::indent(unsigned NumSpaces) {
|
|
|
|
return write_padding<' '>(*this, NumSpaces);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// write_zeros - Insert 'NumZeros' nulls.
|
|
|
|
raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) {
|
|
|
|
return write_padding<'\0'>(*this, NumZeros);
|
2009-08-23 01:10:29 +02:00
|
|
|
}
|
|
|
|
|
2020-06-08 17:47:55 +02:00
|
|
|
bool raw_ostream::prepare_colors() {
|
|
|
|
// Colors were explicitly disabled.
|
|
|
|
if (!ColorEnabled)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Colors require changing the terminal but this stream is not going to a
|
|
|
|
// terminal.
|
|
|
|
if (sys::Process::ColorNeedsFlush() && !is_displayed())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (sys::Process::ColorNeedsFlush())
|
|
|
|
flush();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &raw_ostream::changeColor(enum Colors colors, bool bold, bool bg) {
|
|
|
|
if (!prepare_colors())
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
const char *colorcode =
|
|
|
|
(colors == SAVEDCOLOR)
|
|
|
|
? sys::Process::OutputBold(bg)
|
|
|
|
: sys::Process::OutputColor(static_cast<char>(colors), bold, bg);
|
|
|
|
if (colorcode)
|
|
|
|
write(colorcode, strlen(colorcode));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &raw_ostream::resetColor() {
|
|
|
|
if (!prepare_colors())
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
if (const char *colorcode = sys::Process::ResetColor())
|
|
|
|
write(colorcode, strlen(colorcode));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &raw_ostream::reverseColor() {
|
|
|
|
if (!prepare_colors())
|
|
|
|
return *this;
|
|
|
|
|
|
|
|
if (const char *colorcode = sys::Process::OutputReverse())
|
|
|
|
write(colorcode, strlen(colorcode));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
Add missing vtable anchors
Summary: This patch adds anchor() for MemoryBuffer, raw_fd_ostream, RTDyldMemoryManager, SectionMemoryManager, etc.
Reviewers: jlebar, eli.friedman, dblaikie
Reviewed By: dblaikie
Subscribers: mehdi_amini, mgorny, dblaikie, weimingz, llvm-commits
Differential Revision: https://reviews.llvm.org/D45244
llvm-svn: 329861
2018-04-12 01:09:20 +02:00
|
|
|
void raw_ostream::anchor() {}
|
|
|
|
|
2008-08-23 21:23:10 +02:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Formatted Output
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
// Out of line virtual method.
|
|
|
|
void format_object_base::home() {
|
|
|
|
}
|
|
|
|
|
2008-08-17 03:35:29 +02:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// raw_fd_ostream
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-04-13 12:28:56 +02:00
|
|
|
static int getFD(StringRef Filename, std::error_code &EC,
|
2018-06-07 21:58:58 +02:00
|
|
|
sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access,
|
2015-04-13 12:28:56 +02:00
|
|
|
sys::fs::OpenFlags Flags) {
|
2018-06-07 21:58:58 +02:00
|
|
|
assert((Access & sys::fs::FA_Write) &&
|
|
|
|
"Cannot make a raw_ostream from a read-only descriptor!");
|
|
|
|
|
2010-08-19 00:26:19 +02:00
|
|
|
// Handle "-" as stdout. Note that when we do this, we consider ourself
|
2017-03-31 14:08:45 +02:00
|
|
|
// the owner of stdout and may set the "binary" flag globally based on Flags.
|
2014-08-25 20:16:47 +02:00
|
|
|
if (Filename == "-") {
|
2015-04-13 12:28:56 +02:00
|
|
|
EC = std::error_code();
|
2021-04-16 14:06:35 +02:00
|
|
|
// Change stdout's text/binary mode based on the Flags.
|
|
|
|
sys::ChangeStdoutMode(Flags);
|
2017-03-30 21:30:51 +02:00
|
|
|
return STDOUT_FILENO;
|
2008-08-17 05:53:23 +02:00
|
|
|
}
|
2010-03-24 20:38:02 +01:00
|
|
|
|
2015-04-13 12:28:56 +02:00
|
|
|
int FD;
|
2018-06-07 21:58:58 +02:00
|
|
|
if (Access & sys::fs::FA_Read)
|
|
|
|
EC = sys::fs::openFileForReadWrite(Filename, FD, Disp, Flags);
|
|
|
|
else
|
|
|
|
EC = sys::fs::openFileForWrite(Filename, FD, Disp, Flags);
|
2015-04-13 12:28:56 +02:00
|
|
|
if (EC)
|
|
|
|
return -1;
|
2010-03-24 20:38:02 +01:00
|
|
|
|
2015-04-13 12:28:56 +02:00
|
|
|
return FD;
|
2015-04-13 06:54:19 +02:00
|
|
|
}
|
2015-04-10 19:52:22 +02:00
|
|
|
|
2018-06-07 21:58:58 +02:00
|
|
|
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC)
|
|
|
|
: raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write,
|
|
|
|
sys::fs::OF_None) {}
|
|
|
|
|
|
|
|
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
|
|
|
sys::fs::CreationDisposition Disp)
|
|
|
|
: raw_fd_ostream(Filename, EC, Disp, sys::fs::FA_Write, sys::fs::OF_None) {}
|
|
|
|
|
|
|
|
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
|
|
|
sys::fs::FileAccess Access)
|
|
|
|
: raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, Access,
|
|
|
|
sys::fs::OF_None) {}
|
|
|
|
|
|
|
|
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
|
|
|
sys::fs::OpenFlags Flags)
|
|
|
|
: raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write,
|
|
|
|
Flags) {}
|
|
|
|
|
2015-04-13 12:28:56 +02:00
|
|
|
raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
|
2018-06-07 21:58:58 +02:00
|
|
|
sys::fs::CreationDisposition Disp,
|
|
|
|
sys::fs::FileAccess Access,
|
2015-04-13 12:28:56 +02:00
|
|
|
sys::fs::OpenFlags Flags)
|
2018-06-07 21:58:58 +02:00
|
|
|
: raw_fd_ostream(getFD(Filename, EC, Disp, Access, Flags), true) {}
|
2015-04-13 12:28:56 +02:00
|
|
|
|
2015-04-09 18:59:07 +02:00
|
|
|
/// FD is the file descriptor that this writes to. If ShouldClose is true, this
|
|
|
|
/// closes the file when the stream is destroyed.
|
2020-09-01 09:16:07 +02:00
|
|
|
raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered,
|
|
|
|
OStreamKind K)
|
|
|
|
: raw_pwrite_stream(unbuffered, K), FD(fd), ShouldClose(shouldClose) {
|
2019-08-02 09:22:34 +02:00
|
|
|
if (FD < 0 ) {
|
2015-04-13 12:28:56 +02:00
|
|
|
ShouldClose = false;
|
|
|
|
return;
|
|
|
|
}
|
2017-08-04 03:39:23 +02:00
|
|
|
|
2020-06-08 17:47:55 +02:00
|
|
|
enable_colors(true);
|
|
|
|
|
2017-08-04 03:39:23 +02:00
|
|
|
// Do not attempt to close stdout or stderr. We used to try to maintain the
|
|
|
|
// property that tools that support writing file to stdout should not also
|
|
|
|
// write informational output to stdout, but in practice we were never able to
|
|
|
|
// maintain this invariant. Many features have been added to LLVM and clang
|
|
|
|
// (-fdump-record-layouts, optimization remarks, etc) that print to stdout, so
|
|
|
|
// users must simply be aware that mixed output and remarks is a possibility.
|
2017-03-30 21:30:51 +02:00
|
|
|
if (FD <= STDERR_FILENO)
|
|
|
|
ShouldClose = false;
|
2011-01-17 16:53:12 +01:00
|
|
|
|
[Windows] Convert from UTF-8 to UTF-16 when writing to a Windows console
Summary:
Calling WriteConsoleW is the most reliable way to print Unicode
characters to a Windows console.
If binary data gets printed to the console, attempting to re-encode it
shouldn't be a problem, since garbage in can produce garbage out.
This breaks printing strings in the local codepage, which WriteConsoleA
knows how to handle. For example, this can happen when user source code
is encoded with the local codepage, and an LLVM tool quotes it while
emitting a caret diagnostic. This is unfortunate, but well-behaved tools
should validate that their input is UTF-8 and escape non-UTF-8
characters before sending them to raw_fd_ostream. Clang already does
this, but not all LLVM tools do this.
One drawback to the current implementation is printing a string a byte
at a time doesn't work. Consider this LLVM code:
for (char C : MyStr) outs() << C;
Because outs() is now unbuffered, we wil try to convert each byte to
UTF-16, which will fail. However, this already didn't work, so I think
we may as well update callers that do that as we find them to print
complete portions of strings. You can see a real example of this in my
patch to SourceMgr.cpp
Fixes PR38669 and PR36267.
Reviewers: zturner, efriedma
Subscribers: llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D51558
llvm-svn: 341433
2018-09-05 02:08:56 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
// Check if this is a console device. This is not equivalent to isatty.
|
|
|
|
IsWindowsConsole =
|
|
|
|
::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR;
|
|
|
|
#endif
|
|
|
|
|
2011-01-17 16:53:12 +01:00
|
|
|
// Get the starting position.
|
|
|
|
off_t loc = ::lseek(FD, 0, SEEK_CUR);
|
2018-04-29 02:45:03 +02:00
|
|
|
#ifdef _WIN32
|
2015-04-13 13:09:48 +02:00
|
|
|
// MSVCRT's _lseek(SEEK_CUR) doesn't return -1 for pipes.
|
|
|
|
sys::fs::file_status Status;
|
|
|
|
std::error_code EC = status(FD, Status);
|
|
|
|
SupportsSeeking = !EC && Status.type() == sys::fs::file_type::regular_file;
|
|
|
|
#else
|
2015-04-10 20:15:51 +02:00
|
|
|
SupportsSeeking = loc != (off_t)-1;
|
2015-04-13 13:09:48 +02:00
|
|
|
#endif
|
2015-04-10 20:15:51 +02:00
|
|
|
if (!SupportsSeeking)
|
2011-01-17 16:53:12 +01:00
|
|
|
pos = 0;
|
|
|
|
else
|
|
|
|
pos = static_cast<uint64_t>(loc);
|
2010-10-14 22:30:58 +02:00
|
|
|
}
|
|
|
|
|
2008-08-17 03:35:29 +02:00
|
|
|
raw_fd_ostream::~raw_fd_ostream() {
|
2010-08-20 18:34:20 +02:00
|
|
|
if (FD >= 0) {
|
|
|
|
flush();
|
2017-10-24 03:26:22 +02:00
|
|
|
if (ShouldClose) {
|
|
|
|
if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
|
|
|
|
error_detected(EC);
|
|
|
|
}
|
2010-08-20 18:34:20 +02:00
|
|
|
}
|
|
|
|
|
2011-03-16 03:53:39 +01:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
// On mingw, global dtors should not call exit().
|
|
|
|
// report_fatal_error() invokes exit(). We know report_fatal_error()
|
|
|
|
// might not write messages to stderr when any errors were detected
|
|
|
|
// on FD == 2.
|
|
|
|
if (FD == 2) return;
|
|
|
|
#endif
|
|
|
|
|
2010-08-20 18:34:20 +02:00
|
|
|
// If there are any pending errors, report them now. Clients wishing
|
|
|
|
// to avoid report_fatal_error calls should check for errors with
|
|
|
|
// has_error() and clear the error flag with clear_error() before
|
|
|
|
// destructing raw_ostream objects which may have errors.
|
|
|
|
if (has_error())
|
2017-10-24 03:26:22 +02:00
|
|
|
report_fatal_error("IO failure on output stream: " + error().message(),
|
2019-07-16 06:46:31 +02:00
|
|
|
/*gen_crash_diag=*/false);
|
2010-08-18 01:11:56 +02:00
|
|
|
}
|
2009-08-23 04:51:22 +02:00
|
|
|
|
[Windows] Convert from UTF-8 to UTF-16 when writing to a Windows console
Summary:
Calling WriteConsoleW is the most reliable way to print Unicode
characters to a Windows console.
If binary data gets printed to the console, attempting to re-encode it
shouldn't be a problem, since garbage in can produce garbage out.
This breaks printing strings in the local codepage, which WriteConsoleA
knows how to handle. For example, this can happen when user source code
is encoded with the local codepage, and an LLVM tool quotes it while
emitting a caret diagnostic. This is unfortunate, but well-behaved tools
should validate that their input is UTF-8 and escape non-UTF-8
characters before sending them to raw_fd_ostream. Clang already does
this, but not all LLVM tools do this.
One drawback to the current implementation is printing a string a byte
at a time doesn't work. Consider this LLVM code:
for (char C : MyStr) outs() << C;
Because outs() is now unbuffered, we wil try to convert each byte to
UTF-16, which will fail. However, this already didn't work, so I think
we may as well update callers that do that as we find them to print
complete portions of strings. You can see a real example of this in my
patch to SourceMgr.cpp
Fixes PR38669 and PR36267.
Reviewers: zturner, efriedma
Subscribers: llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D51558
llvm-svn: 341433
2018-09-05 02:08:56 +02:00
|
|
|
#if defined(_WIN32)
|
|
|
|
// The most reliable way to print unicode in a Windows console is with
|
|
|
|
// WriteConsoleW. To use that, first transcode from UTF-8 to UTF-16. This
|
|
|
|
// assumes that LLVM programs always print valid UTF-8 to the console. The data
|
|
|
|
// might not be UTF-8 for two major reasons:
|
|
|
|
// 1. The program is printing binary (-filetype=obj -o -), in which case it
|
|
|
|
// would have been gibberish anyway.
|
|
|
|
// 2. The program is printing text in a semi-ascii compatible codepage like
|
|
|
|
// shift-jis or cp1252.
|
|
|
|
//
|
|
|
|
// Most LLVM programs don't produce non-ascii text unless they are quoting
|
|
|
|
// user source input. A well-behaved LLVM program should either validate that
|
|
|
|
// the input is UTF-8 or transcode from the local codepage to UTF-8 before
|
|
|
|
// quoting it. If they don't, this may mess up the encoding, but this is still
|
|
|
|
// probably the best compromise we can make.
|
|
|
|
static bool write_console_impl(int FD, StringRef Data) {
|
|
|
|
SmallVector<wchar_t, 256> WideText;
|
|
|
|
|
|
|
|
// Fall back to ::write if it wasn't valid UTF-8.
|
|
|
|
if (auto EC = sys::windows::UTF8ToUTF16(Data, WideText))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// On Windows 7 and earlier, WriteConsoleW has a low maximum amount of data
|
|
|
|
// that can be written to the console at a time.
|
|
|
|
size_t MaxWriteSize = WideText.size();
|
|
|
|
if (!RunningWindows8OrGreater())
|
|
|
|
MaxWriteSize = 32767;
|
|
|
|
|
|
|
|
size_t WCharsWritten = 0;
|
|
|
|
do {
|
|
|
|
size_t WCharsToWrite =
|
|
|
|
std::min(MaxWriteSize, WideText.size() - WCharsWritten);
|
|
|
|
DWORD ActuallyWritten;
|
|
|
|
bool Success =
|
|
|
|
::WriteConsoleW((HANDLE)::_get_osfhandle(FD), &WideText[WCharsWritten],
|
|
|
|
WCharsToWrite, &ActuallyWritten,
|
|
|
|
/*Reserved=*/nullptr);
|
|
|
|
|
|
|
|
// The most likely reason for WriteConsoleW to fail is that FD no longer
|
|
|
|
// points to a console. Fall back to ::write. If this isn't the first loop
|
|
|
|
// iteration, something is truly wrong.
|
|
|
|
if (!Success)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
WCharsWritten += ActuallyWritten;
|
|
|
|
} while (WCharsWritten != WideText.size());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-07-16 17:24:40 +02:00
|
|
|
void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) {
|
2010-03-24 20:38:02 +01:00
|
|
|
assert(FD >= 0 && "File already closed.");
|
2009-03-17 00:29:31 +01:00
|
|
|
pos += Size;
|
2010-05-06 03:27:36 +02:00
|
|
|
|
[Windows] Convert from UTF-8 to UTF-16 when writing to a Windows console
Summary:
Calling WriteConsoleW is the most reliable way to print Unicode
characters to a Windows console.
If binary data gets printed to the console, attempting to re-encode it
shouldn't be a problem, since garbage in can produce garbage out.
This breaks printing strings in the local codepage, which WriteConsoleA
knows how to handle. For example, this can happen when user source code
is encoded with the local codepage, and an LLVM tool quotes it while
emitting a caret diagnostic. This is unfortunate, but well-behaved tools
should validate that their input is UTF-8 and escape non-UTF-8
characters before sending them to raw_fd_ostream. Clang already does
this, but not all LLVM tools do this.
One drawback to the current implementation is printing a string a byte
at a time doesn't work. Consider this LLVM code:
for (char C : MyStr) outs() << C;
Because outs() is now unbuffered, we wil try to convert each byte to
UTF-16, which will fail. However, this already didn't work, so I think
we may as well update callers that do that as we find them to print
complete portions of strings. You can see a real example of this in my
patch to SourceMgr.cpp
Fixes PR38669 and PR36267.
Reviewers: zturner, efriedma
Subscribers: llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D51558
llvm-svn: 341433
2018-09-05 02:08:56 +02:00
|
|
|
#if defined(_WIN32)
|
|
|
|
// If this is a Windows console device, try re-encoding from UTF-8 to UTF-16
|
|
|
|
// and using WriteConsoleW. If that fails, fall back to plain write().
|
|
|
|
if (IsWindowsConsole)
|
|
|
|
if (write_console_impl(FD, StringRef(Ptr, Size)))
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
2018-08-06 18:21:41 +02:00
|
|
|
// The maximum write size is limited to INT32_MAX. A write
|
|
|
|
// greater than SSIZE_MAX is implementation-defined in POSIX,
|
|
|
|
// and Windows _write requires 32 bit input.
|
|
|
|
size_t MaxWriteSize = INT32_MAX;
|
2017-10-31 18:37:20 +01:00
|
|
|
|
2017-06-20 22:51:51 +02:00
|
|
|
#if defined(__linux__)
|
2017-10-31 18:37:20 +01:00
|
|
|
// It is observed that Linux returns EINVAL for a very large write (>2G).
|
|
|
|
// Make it a reasonably small value.
|
|
|
|
MaxWriteSize = 1024 * 1024 * 1024;
|
2016-01-06 01:50:06 +01:00
|
|
|
#endif
|
|
|
|
|
2010-05-05 17:17:47 +02:00
|
|
|
do {
|
2017-10-31 18:37:20 +01:00
|
|
|
size_t ChunkSize = std::min(Size, MaxWriteSize);
|
2016-01-06 01:50:06 +01:00
|
|
|
ssize_t ret = ::write(FD, Ptr, ChunkSize);
|
2010-05-06 03:27:36 +02:00
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
// If it's a recoverable error, swallow it and retry the write.
|
2010-05-18 17:25:14 +02:00
|
|
|
//
|
|
|
|
// Ideally we wouldn't ever see EAGAIN or EWOULDBLOCK here, since
|
|
|
|
// raw_ostream isn't designed to do non-blocking I/O. However, some
|
|
|
|
// programs, such as old versions of bjam, have mistakenly used
|
|
|
|
// O_NONBLOCK. For compatibility, emulate blocking semantics by
|
|
|
|
// spinning until the write succeeds. If you don't want spinning,
|
|
|
|
// don't use O_NONBLOCK file descriptors with raw_ostream.
|
2010-05-06 04:06:20 +02:00
|
|
|
if (errno == EINTR || errno == EAGAIN
|
|
|
|
#ifdef EWOULDBLOCK
|
|
|
|
|| errno == EWOULDBLOCK
|
|
|
|
#endif
|
|
|
|
)
|
2010-05-06 03:27:36 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Otherwise it's a non-recoverable error. Note it and quit.
|
2017-10-24 03:26:22 +02:00
|
|
|
error_detected(std::error_code(errno, std::generic_category()));
|
2010-05-06 03:27:36 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The write may have written some or all of the data. Update the
|
|
|
|
// size and buffer pointer to reflect the remainder that needs
|
|
|
|
// to be written. If there are no bytes left, we're done.
|
|
|
|
Ptr += ret;
|
|
|
|
Size -= ret;
|
|
|
|
} while (Size > 0);
|
2008-08-17 03:35:29 +02:00
|
|
|
}
|
|
|
|
|
2010-08-18 03:34:52 +02:00
|
|
|
void raw_fd_ostream::close() {
|
|
|
|
assert(ShouldClose);
|
|
|
|
ShouldClose = false;
|
|
|
|
flush();
|
2017-10-24 03:26:22 +02:00
|
|
|
if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
|
|
|
|
error_detected(EC);
|
2010-08-18 03:34:52 +02:00
|
|
|
FD = -1;
|
|
|
|
}
|
|
|
|
|
2009-01-26 22:42:04 +01:00
|
|
|
uint64_t raw_fd_ostream::seek(uint64_t off) {
|
2016-02-23 08:17:58 +01:00
|
|
|
assert(SupportsSeeking && "Stream does not support seeking!");
|
2009-01-26 22:42:04 +01:00
|
|
|
flush();
|
2018-04-29 02:45:03 +02:00
|
|
|
#ifdef _WIN32
|
2016-12-09 06:20:43 +01:00
|
|
|
pos = ::_lseeki64(FD, off, SEEK_SET);
|
|
|
|
#elif defined(HAVE_LSEEK64)
|
|
|
|
pos = ::lseek64(FD, off, SEEK_SET);
|
|
|
|
#else
|
2016-12-09 06:04:30 +01:00
|
|
|
pos = ::lseek(FD, off, SEEK_SET);
|
2016-12-09 06:20:43 +01:00
|
|
|
#endif
|
2015-04-15 00:54:16 +02:00
|
|
|
if (pos == (uint64_t)-1)
|
2017-10-24 03:26:22 +02:00
|
|
|
error_detected(std::error_code(errno, std::generic_category()));
|
2010-03-24 20:38:02 +01:00
|
|
|
return pos;
|
2009-01-26 22:42:04 +01:00
|
|
|
}
|
|
|
|
|
2015-04-20 15:04:30 +02:00
|
|
|
void raw_fd_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
|
|
|
uint64_t Offset) {
|
2015-04-14 17:00:34 +02:00
|
|
|
uint64_t Pos = tell();
|
|
|
|
seek(Offset);
|
|
|
|
write(Ptr, Size);
|
|
|
|
seek(Pos);
|
|
|
|
}
|
|
|
|
|
2009-12-19 02:38:42 +01:00
|
|
|
size_t raw_fd_ostream::preferred_buffer_size() const {
|
[Windows] Convert from UTF-8 to UTF-16 when writing to a Windows console
Summary:
Calling WriteConsoleW is the most reliable way to print Unicode
characters to a Windows console.
If binary data gets printed to the console, attempting to re-encode it
shouldn't be a problem, since garbage in can produce garbage out.
This breaks printing strings in the local codepage, which WriteConsoleA
knows how to handle. For example, this can happen when user source code
is encoded with the local codepage, and an LLVM tool quotes it while
emitting a caret diagnostic. This is unfortunate, but well-behaved tools
should validate that their input is UTF-8 and escape non-UTF-8
characters before sending them to raw_fd_ostream. Clang already does
this, but not all LLVM tools do this.
One drawback to the current implementation is printing a string a byte
at a time doesn't work. Consider this LLVM code:
for (char C : MyStr) outs() << C;
Because outs() is now unbuffered, we wil try to convert each byte to
UTF-16, which will fail. However, this already didn't work, so I think
we may as well update callers that do that as we find them to print
complete portions of strings. You can see a real example of this in my
patch to SourceMgr.cpp
Fixes PR38669 and PR36267.
Reviewers: zturner, efriedma
Subscribers: llvm-commits, hiraditya
Differential Revision: https://reviews.llvm.org/D51558
llvm-svn: 341433
2018-09-05 02:08:56 +02:00
|
|
|
#if defined(_WIN32)
|
|
|
|
// Disable buffering for console devices. Console output is re-encoded from
|
|
|
|
// UTF-8 to UTF-16 on Windows, and buffering it would require us to split the
|
|
|
|
// buffer on a valid UTF-8 codepoint boundary. Terminal buffering is disabled
|
|
|
|
// below on most other OSs, so do the same thing on Windows and avoid that
|
|
|
|
// complexity.
|
|
|
|
if (IsWindowsConsole)
|
|
|
|
return 0;
|
|
|
|
return raw_ostream::preferred_buffer_size();
|
|
|
|
#elif !defined(__minix)
|
|
|
|
// Minix has no st_blksize.
|
2009-08-13 19:27:29 +02:00
|
|
|
assert(FD >= 0 && "File not yet open!");
|
|
|
|
struct stat statbuf;
|
2009-12-19 02:38:42 +01:00
|
|
|
if (fstat(FD, &statbuf) != 0)
|
|
|
|
return 0;
|
2010-03-24 20:38:02 +01:00
|
|
|
|
2009-12-19 02:38:42 +01:00
|
|
|
// If this is a terminal, don't use buffering. Line buffering
|
|
|
|
// would be a more traditional thing to do, but it's not worth
|
|
|
|
// the complexity.
|
2020-03-17 02:20:58 +01:00
|
|
|
if (S_ISCHR(statbuf.st_mode) && is_displayed())
|
2009-12-19 02:38:42 +01:00
|
|
|
return 0;
|
|
|
|
// Return the preferred block size.
|
|
|
|
return statbuf.st_blksize;
|
2010-05-28 18:50:01 +02:00
|
|
|
#else
|
2009-08-13 19:27:29 +02:00
|
|
|
return raw_ostream::preferred_buffer_size();
|
2010-05-28 18:50:01 +02:00
|
|
|
#endif
|
2009-08-13 19:27:29 +02:00
|
|
|
}
|
|
|
|
|
2009-09-11 22:46:33 +02:00
|
|
|
bool raw_fd_ostream::is_displayed() const {
|
|
|
|
return sys::Process::FileDescriptorIsDisplayed(FD);
|
|
|
|
}
|
|
|
|
|
2012-07-20 20:29:41 +02:00
|
|
|
bool raw_fd_ostream::has_colors() const {
|
[Support] Speedup llvm-dwarfdump 3.9x
Currently `strace llvm-dwarfdump x.debug >/tmp/file`:
ioctl(1, TCGETS, 0x7ffd64d7f340) = -1 ENOTTY (Inappropriate ioctl for device)
write(1, " DW_AT_decl_line\t(89)\n"..., 4096) = 4096
ioctl(1, TCGETS, 0x7ffd64d7f400) = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(1, TCGETS, 0x7ffd64d7f410) = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(1, TCGETS, 0x7ffd64d7f400) = -1 ENOTTY (Inappropriate ioctl for device)
After this patch:
write(1, "0000000000001102 \"strlen\")\n "..., 4096) = 4096
write(1, "site\n DW_AT_low"..., 4096) = 4096
write(1, "d53)\n\n0x000e4d4d: DW_TAG_G"..., 4096) = 4096
The same speedup can be achieved by `--color=0` but that is not much convenient.
This implementation has been suggested by Joerg Sonnenberger.
Differential Revision: https://reviews.llvm.org/D86406
2020-08-26 09:57:53 +02:00
|
|
|
if (!HasColors)
|
|
|
|
HasColors = sys::Process::FileDescriptorHasColors(FD);
|
|
|
|
return *HasColors;
|
2012-07-20 20:29:41 +02:00
|
|
|
}
|
|
|
|
|
2020-04-29 06:26:19 +02:00
|
|
|
Expected<sys::fs::FileLocker> raw_fd_ostream::lock() {
|
|
|
|
std::error_code EC = sys::fs::lockFile(FD);
|
|
|
|
if (!EC)
|
|
|
|
return sys::fs::FileLocker(FD);
|
|
|
|
return errorCodeToError(EC);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expected<sys::fs::FileLocker>
|
|
|
|
raw_fd_ostream::tryLockFor(std::chrono::milliseconds Timeout) {
|
|
|
|
std::error_code EC = sys::fs::tryLockFile(FD, Timeout);
|
|
|
|
if (!EC)
|
|
|
|
return sys::fs::FileLocker(FD);
|
|
|
|
return errorCodeToError(EC);
|
|
|
|
}
|
|
|
|
|
Add missing vtable anchors
Summary: This patch adds anchor() for MemoryBuffer, raw_fd_ostream, RTDyldMemoryManager, SectionMemoryManager, etc.
Reviewers: jlebar, eli.friedman, dblaikie
Reviewed By: dblaikie
Subscribers: mehdi_amini, mgorny, dblaikie, weimingz, llvm-commits
Differential Revision: https://reviews.llvm.org/D45244
llvm-svn: 329861
2018-04-12 01:09:20 +02:00
|
|
|
void raw_fd_ostream::anchor() {}
|
|
|
|
|
2008-08-17 06:13:37 +02:00
|
|
|
//===----------------------------------------------------------------------===//
|
2010-08-20 18:44:56 +02:00
|
|
|
// outs(), errs(), nulls()
|
2008-08-17 06:13:37 +02:00
|
|
|
//===----------------------------------------------------------------------===//
|
2008-08-17 03:35:29 +02:00
|
|
|
|
[Support] Use outs() in ToolOutputFile
Summary:
If the output filename was specified as "-", the ToolOutputFile class
would create a brand new raw_ostream object referring to the stdout.
This patch changes it to reuse the llvm::outs() singleton.
At the moment, this change should be "NFC", but it does enable other
enhancements, like the automatic stdout/stderr synchronization as
discussed on D80803.
I've checked the history, and I did not find any indication that this
class *has* to use a brand new stream object instead of outs() --
indeed, it is special-casing "-" in a number of places already, so this
change fits the pattern pretty well. I suspect the main reason for the
current state of affairs is that the class was originally introduced
(r111595, in 2010) as a raw_fd_ostream subclass, which made any other
solution impossible.
Another potential benefit of this patch is that it makes it possible to
move the raw_ostream class out of the business of special-casing "-" for
stdout handling. That state of affairs does not seem appropriate because
"-" is a valid filename (albeit hard to access with a lot of command
line tools) on most systems. Handling "-" in ToolOutputFile seems more
appropriate.
To make this possible, this patch changes the return type of
llvm::outs() and errs() to raw_fd_ostream&. Previously the functions
were constructing objects of that type, but returning a generic
raw_ostream reference. This makes it possible for new ToolOutputFile and
other code to use raw_fd_ostream methods like error() on the outs()
object. This does not seem like a bad thing (since stdout is a file
descriptor which can be redirected to anywhere, it makes sense to ask it
whether the writing was successful or if it supports seeking), and
indeed a lot of code was already depending on this fact via the
ToolOutputFile "back door".
Reviewers: dblaikie, JDevlieghere, MaskRay, jhenderson
Subscribers: hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81078
2020-06-03 12:08:45 +02:00
|
|
|
raw_fd_ostream &llvm::outs() {
|
2017-08-04 03:39:23 +02:00
|
|
|
// Set buffer settings to model stdout behavior.
|
2015-04-13 12:28:56 +02:00
|
|
|
std::error_code EC;
|
2019-08-05 07:43:48 +02:00
|
|
|
static raw_fd_ostream S("-", EC, sys::fs::OF_None);
|
2015-04-13 12:28:56 +02:00
|
|
|
assert(!EC);
|
2008-08-17 06:13:37 +02:00
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
[Support] Use outs() in ToolOutputFile
Summary:
If the output filename was specified as "-", the ToolOutputFile class
would create a brand new raw_ostream object referring to the stdout.
This patch changes it to reuse the llvm::outs() singleton.
At the moment, this change should be "NFC", but it does enable other
enhancements, like the automatic stdout/stderr synchronization as
discussed on D80803.
I've checked the history, and I did not find any indication that this
class *has* to use a brand new stream object instead of outs() --
indeed, it is special-casing "-" in a number of places already, so this
change fits the pattern pretty well. I suspect the main reason for the
current state of affairs is that the class was originally introduced
(r111595, in 2010) as a raw_fd_ostream subclass, which made any other
solution impossible.
Another potential benefit of this patch is that it makes it possible to
move the raw_ostream class out of the business of special-casing "-" for
stdout handling. That state of affairs does not seem appropriate because
"-" is a valid filename (albeit hard to access with a lot of command
line tools) on most systems. Handling "-" in ToolOutputFile seems more
appropriate.
To make this possible, this patch changes the return type of
llvm::outs() and errs() to raw_fd_ostream&. Previously the functions
were constructing objects of that type, but returning a generic
raw_ostream reference. This makes it possible for new ToolOutputFile and
other code to use raw_fd_ostream methods like error() on the outs()
object. This does not seem like a bad thing (since stdout is a file
descriptor which can be redirected to anywhere, it makes sense to ask it
whether the writing was successful or if it supports seeking), and
indeed a lot of code was already depending on this fact via the
ToolOutputFile "back door".
Reviewers: dblaikie, JDevlieghere, MaskRay, jhenderson
Subscribers: hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D81078
2020-06-03 12:08:45 +02:00
|
|
|
raw_fd_ostream &llvm::errs() {
|
2020-06-08 13:58:04 +02:00
|
|
|
// Set standard error to be unbuffered and tied to outs() by default.
|
2010-08-20 18:39:41 +02:00
|
|
|
static raw_fd_ostream S(STDERR_FILENO, false, true);
|
2008-08-17 06:13:37 +02:00
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2009-07-16 23:17:53 +02:00
|
|
|
/// nulls() - This returns a reference to a raw_ostream which discards output.
|
|
|
|
raw_ostream &llvm::nulls() {
|
|
|
|
static raw_null_ostream S;
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2020-09-01 09:16:07 +02:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// File Streams
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
raw_fd_stream::raw_fd_stream(StringRef Filename, std::error_code &EC)
|
|
|
|
: raw_fd_ostream(getFD(Filename, EC, sys::fs::CD_CreateAlways,
|
|
|
|
sys::fs::FA_Write | sys::fs::FA_Read,
|
|
|
|
sys::fs::OF_None),
|
|
|
|
true, false, OStreamKind::OK_FDStream) {
|
|
|
|
if (EC)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Do not support non-seekable files.
|
|
|
|
if (!supportsSeeking())
|
|
|
|
EC = std::make_error_code(std::errc::invalid_argument);
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t raw_fd_stream::read(char *Ptr, size_t Size) {
|
|
|
|
assert(get_fd() >= 0 && "File already closed.");
|
|
|
|
ssize_t Ret = ::read(get_fd(), (void *)Ptr, Size);
|
|
|
|
if (Ret >= 0)
|
|
|
|
inc_pos(Ret);
|
|
|
|
else
|
|
|
|
error_detected(std::error_code(errno, std::generic_category()));
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool raw_fd_stream::classof(const raw_ostream *OS) {
|
|
|
|
return OS->get_kind() == OStreamKind::OK_FDStream;
|
|
|
|
}
|
|
|
|
|
2008-08-24 00:43:04 +02:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// raw_string_ostream
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-08-18 22:07:36 +02:00
|
|
|
raw_string_ostream::~raw_string_ostream() {
|
|
|
|
flush();
|
|
|
|
}
|
|
|
|
|
2009-07-16 17:24:40 +02:00
|
|
|
void raw_string_ostream::write_impl(const char *Ptr, size_t Size) {
|
2009-03-17 00:29:31 +01:00
|
|
|
OS.append(Ptr, Size);
|
2008-08-24 00:43:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// raw_svector_ostream
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-08-13 08:19:52 +02:00
|
|
|
uint64_t raw_svector_ostream::current_pos() const { return OS.size(); }
|
2009-08-19 19:54:29 +02:00
|
|
|
|
2015-08-13 08:19:52 +02:00
|
|
|
void raw_svector_ostream::write_impl(const char *Ptr, size_t Size) {
|
|
|
|
OS.append(Ptr, Ptr + Size);
|
2015-08-13 20:10:19 +02:00
|
|
|
}
|
2009-08-18 22:07:36 +02:00
|
|
|
|
2015-04-20 15:04:30 +02:00
|
|
|
void raw_svector_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
|
|
|
uint64_t Offset) {
|
2015-08-13 08:19:52 +02:00
|
|
|
memcpy(OS.data() + Offset, Ptr, Size);
|
2009-08-19 20:40:58 +02:00
|
|
|
}
|
|
|
|
|
2009-07-16 23:17:53 +02:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// raw_null_ostream
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-07-27 23:46:02 +02:00
|
|
|
raw_null_ostream::~raw_null_ostream() {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
// ~raw_ostream asserts that the buffer is empty. This isn't necessary
|
|
|
|
// with raw_null_ostream, but it's better to have raw_null_ostream follow
|
|
|
|
// the rules than to change the rules just for raw_null_ostream.
|
|
|
|
flush();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-07-16 23:17:53 +02:00
|
|
|
void raw_null_ostream::write_impl(const char *Ptr, size_t Size) {
|
|
|
|
}
|
|
|
|
|
2009-12-19 02:38:42 +01:00
|
|
|
uint64_t raw_null_ostream::current_pos() const {
|
2009-07-16 23:17:53 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2015-04-14 17:00:34 +02:00
|
|
|
|
2015-04-20 15:04:30 +02:00
|
|
|
void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size,
|
|
|
|
uint64_t Offset) {}
|
Add missing vtable anchors
Summary: This patch adds anchor() for MemoryBuffer, raw_fd_ostream, RTDyldMemoryManager, SectionMemoryManager, etc.
Reviewers: jlebar, eli.friedman, dblaikie
Reviewed By: dblaikie
Subscribers: mehdi_amini, mgorny, dblaikie, weimingz, llvm-commits
Differential Revision: https://reviews.llvm.org/D45244
llvm-svn: 329861
2018-04-12 01:09:20 +02:00
|
|
|
|
|
|
|
void raw_pwrite_stream::anchor() {}
|
2018-12-29 03:02:13 +01:00
|
|
|
|
|
|
|
void buffer_ostream::anchor() {}
|
2020-12-15 02:46:11 +01:00
|
|
|
|
|
|
|
void buffer_unique_ostream::anchor() {}
|
2021-03-04 10:51:30 +01:00
|
|
|
|
|
|
|
Error llvm::writeToOutput(StringRef OutputFileName,
|
|
|
|
std::function<Error(raw_ostream &)> Write) {
|
|
|
|
if (OutputFileName == "-")
|
|
|
|
return Write(outs());
|
|
|
|
|
|
|
|
if (OutputFileName == "/dev/null") {
|
|
|
|
raw_null_ostream Out;
|
|
|
|
return Write(Out);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Mode = sys::fs::all_read | sys::fs::all_write | sys::fs::all_exe;
|
|
|
|
Expected<sys::fs::TempFile> Temp =
|
|
|
|
sys::fs::TempFile::create(OutputFileName + ".temp-stream-%%%%%%", Mode);
|
|
|
|
if (!Temp)
|
|
|
|
return createFileError(OutputFileName, Temp.takeError());
|
|
|
|
|
|
|
|
raw_fd_ostream Out(Temp->FD, false);
|
|
|
|
|
|
|
|
if (Error E = Write(Out)) {
|
|
|
|
if (Error DiscardError = Temp->discard())
|
|
|
|
return joinErrors(std::move(E), std::move(DiscardError));
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
Out.flush();
|
|
|
|
|
|
|
|
return Temp->keep(OutputFileName);
|
|
|
|
}
|