Index: llvm/include/llvm/Support/MemoryBuffer.h =================================================================== --- llvm/include/llvm/Support/MemoryBuffer.h +++ llvm/include/llvm/Support/MemoryBuffer.h @@ -22,6 +22,7 @@ #include "llvm/Support/FileSystem.h" #include #include +#include #include namespace llvm { @@ -126,6 +127,15 @@ getFileOrSTDIN(const Twine &Filename, int64_t FileSize = -1, bool RequiresNullTerminator = true); + /// If Filename is "-" and stdin refers to a terminal, i.e. input has not been + /// redirected in, call NotRedirectedInput and return its MemoryBuffer. + /// Otherwise acts the same as + /// MemoryBuffer::getFileOrSTDIN(const Twine &, int64_t, bool). + static ErrorOr> getFileOrSTDIN( + const Twine &Filename, + std::function(void)> NotRedirectedInput, + int64_t FileSize = -1, bool RequiresNullTerminator = true); + /// Map a subrange of the specified file as a MemoryBuffer. static ErrorOr> getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset, Index: llvm/lib/Support/MemoryBuffer.cpp =================================================================== --- llvm/lib/Support/MemoryBuffer.cpp +++ llvm/lib/Support/MemoryBuffer.cpp @@ -150,6 +150,21 @@ return getFile(Filename, FileSize, RequiresNullTerminator); } +ErrorOr> MemoryBuffer::getFileOrSTDIN( + const Twine &Filename, + std::function(void)> NotRedirectedInput, + int64_t FileSize, bool RequiresNullTerminator) { + SmallString<256> NameBuf; + StringRef NameRef = Filename.toStringRef(NameBuf); + + if (NameRef == "-") { + if (sys::fs::is_tty(0)) + return NotRedirectedInput(); + return getSTDIN(); + } + return getFile(Filename, FileSize, RequiresNullTerminator); +} + ErrorOr> MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, uint64_t Offset, bool IsVolatile) { Index: llvm/unittests/Support/MemoryBufferTest.cpp =================================================================== --- llvm/unittests/Support/MemoryBufferTest.cpp +++ llvm/unittests/Support/MemoryBufferTest.cpp @@ -16,6 +16,14 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" +#include +#include +#ifdef _WIN32 +#include +#define dup2 _dup2; +#else +#include +#endif using namespace llvm; @@ -288,4 +296,40 @@ ASSERT_EQ(16u, MB.getBufferSize()); EXPECT_EQ("xxxxxxxxxxxxxxxx", MB.getBuffer()); } + +TEST_F(MemoryBufferTest, getFileOrSTDIN) { + int TestForChange = 0; + auto ChangeFunc = [&TestForChange]() -> std::unique_ptr { + errs() << "message"; + // TestForChange = 1; + std::exit(1); + return nullptr; + }; + // See if stdin is a tty, otherwise skip this test. + if (sys::fs::is_tty(0)) { + EXPECT_EXIT(MemoryBuffer::getFileOrSTDIN("-", ChangeFunc), + ::testing::ExitedWithCode(1), "message") + << "Reading from tty should have exited with exit code 1"; + // Currently the ChangeFunc isn't chaning TestForChange, I don't know why + // ASSERT_EQ(TestForChange, 1) << "Callback not called"; + TestForChange = 0; + } + + auto TempFile = sys::fs::TempFile::create("%%%%%%%%"); + if (!TempFile) + return; + + if (::dup2(TempFile->FD, 0)) + return; + + if (sys::fs::is_tty(0)) + return; + + MemoryBuffer::getFileOrSTDIN("-", ChangeFunc); + ASSERT_EQ(TestForChange, 0) << "Callback should not have been called"; + + // Need to check Error, also need to do something in if or compiler will warn. + if (Error E = TempFile->discard()) + return; +} }