--- /dev/null
+## llvm-ar should be able to consume response files.
+
+# RUN: echo 'contents' > %t.txt
+# RUN: echo 'rc %t1.a %t.txt' > %t.response1.txt
+# RUN: llvm-ar @%t.response1.txt
+# RUN: llvm-ar p %t1.a | FileCheck %s --check-prefix=CONTENTS
+
+## Quotes and Spaces.
+# RUN: echo 'contents' > '%t space.txt'
+## Python is used here to ensure the quotes are written to the response file
+# RUN: %python -c "import os; open(r'%t.response2.txt', 'w').write(r'%t2.a \"%t space.txt\"'+ '\n')"
+# RUN: llvm-ar rc @%t.response2.txt
+# RUN: llvm-ar p %t2.a | FileCheck %s --check-prefix=CONTENTS
+
+## Arguments after the response file.
+# RUN: echo 'rc %t3.a' > %t.response3.txt
+# RUN: llvm-ar @%t.response3.txt %t.txt
+# RUN: llvm-ar p %t3.a | FileCheck %s --check-prefix=CONTENTS
+
+# CONTENTS: contents
+
+## rsp-quoting
+# RUN: not llvm-ar --rsp-quoting=foobar @%t.response1.txt 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERROR
+# ERROR: Invalid response file quoting style foobar
+
+# RUN: echo -e 'rc %/t.a blah\\foo' > %t-rsp.txt
+# RUN: not llvm-ar --rsp-quoting=windows @%t-rsp.txt 2>&1 | \
+# RUN: FileCheck %s --check-prefix=WIN
+# WIN: error: blah\foo: {{[Nn]}}o such file or directory
+
+# RUN: not llvm-ar -rsp-quoting posix @%t-rsp.txt 2>&1 | \
+# RUN: FileCheck %s --check-prefix=POSIX
+# POSIX: error: blahfoo: {{[Nn]}}o such file or directory
=bsd - bsd
--plugin=<string> - ignored for compatibility
-h --help - display this help and exit
+ --rsp-quoting - quoting style for response files
+ =posix - posix
+ =windows - windows
--version - print the version and exit
@<file> - read options from <file>
return false;
}
+static const char *matchFlagWithArg(StringRef Expected,
+ ArrayRef<const char *>::iterator &ArgIt,
+ ArrayRef<const char *> Args) {
+ StringRef Arg = *ArgIt;
+
+ if (Arg.startswith("--"))
+ Arg = Arg.substr(2);
+ else if (Arg.startswith("-"))
+ Arg = Arg.substr(1);
+
+ size_t len = Expected.size();
+ if (Arg == Expected) {
+ if (++ArgIt == Args.end())
+ fail(std::string(Expected) + " requires an argument");
+
+ return *ArgIt;
+ }
+ if (Arg.startswith(Expected) && Arg.size() > len && Arg[len] == '=')
+ return Arg.data() + len + 1;
+
+ return nullptr;
+}
+
+static cl::TokenizerCallback getRspQuoting(ArrayRef<const char *> ArgsArr) {
+ cl::TokenizerCallback Ret =
+ Triple(sys::getProcessTriple()).getOS() == Triple::Win32
+ ? cl::TokenizeWindowsCommandLine
+ : cl::TokenizeGNUCommandLine;
+
+ for (ArrayRef<const char *>::iterator ArgIt = ArgsArr.begin();
+ ArgIt != ArgsArr.end(); ++ArgIt) {
+ if (const char *Match = matchFlagWithArg("rsp-quoting", ArgIt, ArgsArr)) {
+ StringRef MatchRef = Match;
+ if (MatchRef == "posix")
+ Ret = cl::TokenizeGNUCommandLine;
+ else if (MatchRef == "windows")
+ Ret = cl::TokenizeWindowsCommandLine;
+ else
+ fail(std::string("Invalid response file quoting style ") + Match);
+ }
+ }
+
+ return Ret;
+}
+
static int ar_main(int argc, char **argv) {
- SmallVector<const char *, 0> Argv(argv, argv + argc);
+ SmallVector<const char *, 0> Argv(argv + 1, argv + argc);
StringSaver Saver(Alloc);
- cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);
- for (size_t i = 1; i < Argv.size(); ++i) {
- StringRef Arg = Argv[i];
- const char *match = nullptr;
- auto MatchFlagWithArg = [&](const char *expected) {
- size_t len = strlen(expected);
- if (Arg == expected) {
- if (++i >= Argv.size())
- fail(std::string(expected) + " requires an argument");
- match = Argv[i];
- return true;
- }
- if (Arg.startswith(expected) && Arg.size() > len && Arg[len] == '=') {
- match = Arg.data() + len + 1;
- return true;
- }
- return false;
- };
- if (handleGenericOption(Argv[i]))
+
+ cl::ExpandResponseFiles(Saver, getRspQuoting(makeArrayRef(argv, argc)), Argv);
+
+ ArrayRef<const char *> ArgsArr = makeArrayRef(argv, argc);
+
+ for (ArrayRef<const char *>::iterator ArgIt = Argv.begin();
+ ArgIt != Argv.end(); ++ArgIt) {
+ const char *Match = nullptr;
+
+ if (handleGenericOption(*ArgIt))
return 0;
- if (Arg == "--") {
- for (; i < Argv.size(); ++i)
- PositionalArgs.push_back(Argv[i]);
+ if (strcmp(*ArgIt, "--") == 0) {
+ ++ArgIt;
+ for (; ArgIt != Argv.end(); ++ArgIt)
+ PositionalArgs.push_back(*ArgIt);
break;
}
- if (Arg[0] == '-') {
- if (Arg.startswith("--"))
- Arg = Argv[i] + 2;
+
+ if (*ArgIt[0] != '-') {
+ if (Options.empty())
+ Options += *ArgIt;
else
- Arg = Argv[i] + 1;
- if (Arg == "M") {
- MRI = true;
- } else if (MatchFlagWithArg("format")) {
- FormatType = StringSwitch<Format>(match)
- .Case("default", Default)
- .Case("gnu", GNU)
- .Case("darwin", DARWIN)
- .Case("bsd", BSD)
- .Default(Unknown);
- if (FormatType == Unknown)
- fail(std::string("Invalid format ") + match);
- } else if (MatchFlagWithArg("plugin")) {
- // Ignored.
- } else {
- Options += Argv[i] + 1;
- }
- } else if (Options.empty()) {
- Options += Argv[i];
- } else {
- PositionalArgs.push_back(Argv[i]);
+ PositionalArgs.push_back(*ArgIt);
+ continue;
}
+
+ if (strcmp(*ArgIt, "-M") == 0) {
+ MRI = true;
+ continue;
+ }
+
+ Match = matchFlagWithArg("format", ArgIt, Argv);
+ if (Match) {
+ FormatType = StringSwitch<Format>(Match)
+ .Case("default", Default)
+ .Case("gnu", GNU)
+ .Case("darwin", DARWIN)
+ .Case("bsd", BSD)
+ .Default(Unknown);
+ if (FormatType == Unknown)
+ fail(std::string("Invalid format ") + Match);
+ continue;
+ }
+
+ if (matchFlagWithArg("plugin", ArgIt, Argv) ||
+ matchFlagWithArg("rsp-quoting", ArgIt, Argv))
+ continue;
+
+ Options += *ArgIt + 1;
}
+
ArchiveOperation Operation = parseCommandLine();
return performOperation(Operation, nullptr);
}