diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index ac25c59b904..fdd901200fe 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -24,7 +24,6 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/StringSaver.h" #include #include #include @@ -1773,6 +1772,15 @@ void getRegisteredOptions(StringMap &Map); // Standalone command line processing utilities. // +/// \brief Saves strings in the inheritor's stable storage and returns a stable +/// raw character pointer. +class StringSaver { + virtual void anchor(); +public: + virtual const char *SaveString(const char *Str) = 0; + virtual ~StringSaver() {}; // Pacify -Wnon-virtual-dtor. +}; + /// \brief Tokenizes a command line that can contain escapes and quotes. // /// The quoting rules match those used by GCC and other tools that use diff --git a/include/llvm/Support/StringSaver.h b/include/llvm/Support/StringSaver.h deleted file mode 100644 index 8d3dc129edc..00000000000 --- a/include/llvm/Support/StringSaver.h +++ /dev/null @@ -1,33 +0,0 @@ -//===- llvm/Support/StringSaver.h - Stable storage for strings --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_STRINGSAVER_H -#define LLVM_SUPPORT_STRINGSAVER_H - -#include "llvm/Support/Allocator.h" -#include - -namespace llvm { - -/// \brief Saves strings in stable storage that it owns. -class StringSaver { - BumpPtrAllocator Alloc; - -public: - const char *saveCStr(const char *CStr) { - auto Len = std::strlen(CStr) + 1; // Don't forget the NUL! - char *Buf = Alloc.Allocate(Len); - std::memcpy(Buf, CStr, Len); - return Buf; - } -}; - -} // end namespace llvm - -#endif diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index dddcbf3f3d7..4c1df5c47dd 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -76,6 +76,7 @@ void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} void parser::anchor() {} +void StringSaver::anchor() {} //===----------------------------------------------------------------------===// @@ -508,7 +509,7 @@ void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver, // End the token if this is whitespace. if (isWhitespace(Src[I])) { if (!Token.empty()) - NewArgv.push_back(Saver.saveCStr(Token.c_str())); + NewArgv.push_back(Saver.SaveString(Token.c_str())); Token.clear(); continue; } @@ -519,7 +520,7 @@ void cl::TokenizeGNUCommandLine(StringRef Src, StringSaver &Saver, // Append the last token after hitting EOF with no whitespace. if (!Token.empty()) - NewArgv.push_back(Saver.saveCStr(Token.c_str())); + NewArgv.push_back(Saver.SaveString(Token.c_str())); } /// Backslashes are interpreted in a rather complicated way in the Windows-style @@ -592,7 +593,7 @@ void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver, if (State == UNQUOTED) { // Whitespace means the end of the token. if (isWhitespace(Src[I])) { - NewArgv.push_back(Saver.saveCStr(Token.c_str())); + NewArgv.push_back(Saver.SaveString(Token.c_str())); Token.clear(); State = INIT; continue; @@ -624,7 +625,7 @@ void cl::TokenizeWindowsCommandLine(StringRef Src, StringSaver &Saver, } // Append the last token after hitting EOF with no whitespace. if (!Token.empty()) - NewArgv.push_back(Saver.saveCStr(Token.c_str())); + NewArgv.push_back(Saver.SaveString(Token.c_str())); } static bool ExpandResponseFile(const char *FName, StringSaver &Saver, @@ -690,6 +691,25 @@ bool cl::ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer, return AllExpanded; } +namespace { + class StrDupSaver : public StringSaver { + std::vector Dups; + public: + ~StrDupSaver() { + for (std::vector::iterator I = Dups.begin(), E = Dups.end(); + I != E; ++I) { + char *Dup = *I; + free(Dup); + } + } + const char *SaveString(const char *Str) override { + char *Dup = strdup(Str); + Dups.push_back(Dup); + return Dup; + } + }; +} + /// ParseEnvironmentOptions - An alternative entry point to the /// CommandLine library, which allows you to read the program's name /// from the caller (as PROGNAME) and its command-line arguments from @@ -709,8 +729,8 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, // Get program's "name", which we wouldn't know without the caller // telling us. SmallVector newArgv; - StringSaver Saver; - newArgv.push_back(Saver.saveCStr(progName)); + 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(). @@ -734,7 +754,7 @@ void cl::ParseCommandLineOptions(int argc, const char * const *argv, SmallVector newArgv; for (int i = 0; i != argc; ++i) newArgv.push_back(argv[i]); - StringSaver Saver; + StrDupSaver Saver; ExpandResponseFiles(Saver, TokenizeGNUCommandLine, newArgv); argv = &newArgv[0]; argc = static_cast(newArgv.size()); diff --git a/unittests/Support/CommandLineTest.cpp b/unittests/Support/CommandLineTest.cpp index ffabaca4610..e4a1b67c47e 100644 --- a/unittests/Support/CommandLineTest.cpp +++ b/unittests/Support/CommandLineTest.cpp @@ -146,19 +146,26 @@ TEST(CommandLineTest, UseOptionCategory) { "Category."; } -typedef void ParserFunction(StringRef Source, StringSaver &Saver, +class StrDupSaver : public cl::StringSaver { + const char *SaveString(const char *Str) override { + return strdup(Str); + } +}; + +typedef void ParserFunction(StringRef Source, llvm::cl::StringSaver &Saver, SmallVectorImpl &NewArgv); void testCommandLineTokenizer(ParserFunction *parse, const char *Input, const char *const Output[], size_t OutputSize) { SmallVector Actual; - StringSaver Saver; + StrDupSaver Saver; parse(Input, Saver, Actual); EXPECT_EQ(OutputSize, Actual.size()); for (unsigned I = 0, E = Actual.size(); I != E; ++I) { if (I < OutputSize) EXPECT_STREQ(Output[I], Actual[I]); + free(const_cast(Actual[I])); } }