Q=$(if $(quiet),@)
non_third_party_sources = \
+ src/Args.cpp \
src/ArgsInfo.cpp \
src/AtomicFile.cpp \
src/CacheEntryReader.cpp \
src/Util.cpp \
src/ZstdCompressor.cpp \
src/ZstdDecompressor.cpp \
- src/args.cpp \
src/ccache.cpp \
src/cleanup.cpp \
src/compopt.cpp \
ccache_sources = src/main.cpp $(base_sources)
ccache_objs = $(patsubst %.c, %.o, $(patsubst %.cpp, %.o, $(ccache_sources)))
+test_suites += unittest/test_Args.cpp
test_suites += unittest/test_AtomicFile.cpp
test_suites += unittest/test_Checksum.cpp
test_suites += unittest/test_Compression.cpp
test_suites += unittest/test_Stat.cpp
test_suites += unittest/test_Util.cpp
test_suites += unittest/test_ZstdCompression.cpp
-test_suites += unittest/test_args.cpp
test_suites += unittest/test_argument_processing.cpp
test_suites += unittest/test_compopt.cpp
test_suites += unittest/test_hash.cpp
test_suites += unittest/test_hashutil.cpp
+test_suites += unittest/test_legacy_args.cpp
test_suites += unittest/test_legacy_util.cpp
test_sources += unittest/catch2_tests.cpp
AX_CHECK_COMPILE_FLAG([-Wno-global-constructors], [extra_warnings="$extra_warnings -Wno-global-constructors"],, [-Werror])
AX_CHECK_COMPILE_FLAG([-Wno-implicit-fallthrough], [extra_warnings="$extra_warnings -Wno-implicit-fallthrough"],, [-Werror])
AX_CHECK_COMPILE_FLAG([-Wno-padded], [extra_warnings="$extra_warnings -Wno-padded"],, [-Werror])
+ AX_CHECK_COMPILE_FLAG([-Wno-return-std-move-in-c++11], [extra_warnings="$extra_warnings -Wno-return-std-move-in-c++11"],, [-Werror])
AX_CHECK_COMPILE_FLAG([-Wno-shadow-field-in-constructor], [extra_warnings="$extra_warnings -Wno-shadow-field-in-constructor"],, [-Werror])
AX_CHECK_COMPILE_FLAG([-Wno-shorten-64-to-32], [extra_warnings="$extra_warnings -Wno-shorten-64-to-32"],, [-Werror])
AX_CHECK_COMPILE_FLAG([-Wno-sign-conversion], [extra_warnings="$extra_warnings -Wno-sign-conversion"],, [-Werror])
--- /dev/null
+// Copyright (C) 2020 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "Args.hpp"
+
+Args::Args() : argv(m_args)
+{
+}
+
+Args::Args(const Args& other) : m_args(other.m_args), argv(m_args)
+{
+}
+
+Args::Args(Args&& other) : m_args(std::move(other.m_args)), argv(m_args)
+{
+}
+
+Args
+Args::from_argv(int argc, const char* const* argv)
+{
+ Args args;
+ args.m_args.assign(argv, argv + argc);
+ return args;
+}
+
+Args
+Args::from_string(const std::string& command)
+{
+ char* p = x_strdup(command.c_str());
+ char* q = p;
+ char* word;
+ char* saveptr = NULL;
+ Args args;
+ while ((word = strtok_r(q, " \t\r\n", &saveptr))) {
+ args.push_back(word);
+ q = NULL;
+ }
+
+ free(p);
+ return args;
+}
+
+nonstd::optional<Args>
+Args::from_gcc_atfile(const std::string& filename)
+{
+ std::string argtext;
+ try {
+ argtext = Util::read_file(filename);
+ } catch (Error&) {
+ return nonstd::nullopt;
+ }
+
+ Args args;
+ auto pos = argtext.cbegin();
+ std::string argbuf;
+ argbuf.resize(argtext.length() + 1);
+ auto argpos = argbuf.begin();
+
+ // Used to track quoting state; if \0 we are not inside quotes. Otherwise
+ // stores the quoting character that started it for matching the end quote.
+ char quoting = '\0';
+
+ while (true) {
+ switch (*pos) {
+ case '\\':
+ pos++;
+ if (*pos == '\0') {
+ continue;
+ }
+ break;
+
+ case '"':
+ case '\'':
+ if (quoting != '\0') {
+ if (quoting == *pos) {
+ quoting = '\0';
+ pos++;
+ continue;
+ } else {
+ break;
+ }
+ } else {
+ quoting = *pos;
+ pos++;
+ continue;
+ }
+
+ case '\n':
+ case '\r':
+ case '\t':
+ case ' ':
+ if (quoting) {
+ break;
+ }
+ // Fall through.
+
+ case '\0':
+ // End of token
+ *argpos = '\0';
+ if (argbuf[0] != '\0') {
+ args_add(args, argbuf);
+ }
+ argpos = argbuf.begin();
+ if (*pos == '\0') {
+ return args;
+ } else {
+ pos++;
+ continue;
+ }
+ }
+
+ *argpos = *pos;
+ pos++;
+ argpos++;
+ }
+}
+
+Args&
+Args::operator=(const Args& other)
+{
+ m_args = other.m_args;
+ argv.m_args = &m_args;
+ return *this;
+}
+
+Args&
+Args::operator=(Args&& other)
+{
+ m_args = std::move(other.m_args);
+ argv.m_args = &m_args;
+ return *this;
+}
+
+std::vector<const char*>
+Args::to_argv() const
+{
+ std::vector<const char*> result;
+ result.reserve(m_args.size() + 1);
+ for (const auto& arg : m_args) {
+ result.push_back(arg.c_str());
+ }
+ result.push_back(nullptr);
+ return result;
+}
+
+std::string
+Args::to_string() const
+{
+ std::string result;
+ for (const auto& arg : m_args) {
+ if (!result.empty()) {
+ result += ' ';
+ }
+ result += arg;
+ }
+ return result;
+}
+
+void
+Args::erase_with_prefix(nonstd::string_view prefix)
+{
+ m_args.erase(std::remove_if(m_args.begin(),
+ m_args.end(),
+ [&prefix](const std::string& s) {
+ return Util::starts_with(s, prefix);
+ }),
+ m_args.end());
+}
+
+void
+Args::insert(size_t index, const Args& args)
+{
+ if (args.size() == 0) {
+ return;
+ }
+ m_args.insert(m_args.begin() + index, args.m_args.begin(), args.m_args.end());
+}
+
+void
+Args::pop_back(size_t count)
+{
+ m_args.erase(m_args.end() - count, m_args.end());
+}
+
+void
+Args::pop_front(size_t count)
+{
+ m_args.erase(m_args.begin(), m_args.begin() + count);
+}
+
+void
+Args::push_back(const std::string& arg)
+{
+ m_args.push_back(arg);
+}
+
+void
+Args::push_back(const Args& args)
+{
+ m_args.insert(m_args.end(), args.m_args.begin(), args.m_args.end());
+}
+
+void
+Args::push_front(const std::string& arg)
+{
+ m_args.push_front(arg);
+}
+
+void
+Args::replace(size_t index, const Args& args)
+{
+ if (args.size() == 1) {
+ // Trivial case; replace with 1 element.
+ m_args[index] = args[0];
+ } else {
+ m_args.erase(m_args.begin() + index);
+ insert(index, args);
+ }
+}
+
+Args::ArgvAccessWrapper::ArgvAccessWrapper(const std::deque<std::string>& args)
+ : m_args(&args)
+{
+}
+
+const char* Args::ArgvAccessWrapper::operator[](size_t i) const
+{
+ return i == m_args->size() ? nullptr : m_args->at(i).c_str();
+}
+
+// === Wrapper functions for the legacy API: ===
+
+void
+args_add(Args& args, const std::string& arg)
+{
+ args.push_back(arg);
+}
+
+void
+args_add_prefix(Args& args, const std::string& arg)
+{
+ args.push_front(arg);
+}
+
+Args
+args_copy(const Args& args)
+{
+ return args;
+}
+
+void
+args_extend(Args& args, const Args& to_append)
+{
+ args.push_back(to_append);
+}
+
+Args
+args_init(int argc, const char* const* argv)
+{
+ return Args::from_argv(argc, argv);
+}
+
+nonstd::optional<Args>
+args_init_from_gcc_atfile(const std::string& filename)
+{
+ return Args::from_gcc_atfile(filename);
+}
+
+Args
+args_init_from_string(const std::string& s)
+{
+ return Args::from_string(s);
+}
+
+void
+args_insert(Args& args, size_t index, const Args& to_insert, bool replace)
+{
+ if (replace) {
+ args.replace(index, to_insert);
+ } else {
+ args.insert(index, to_insert);
+ }
+}
+
+void
+args_pop(Args& args, size_t count)
+{
+ args.pop_back(count);
+}
+
+void
+args_remove_first(Args& args)
+{
+ args.pop_front(1);
+}
+
+void
+args_set(Args& args, size_t index, const std::string& value)
+{
+ args[index] = value;
+}
+
+void
+args_strip(Args& args, nonstd::string_view prefix)
+{
+ args.erase_with_prefix(prefix);
+}
--- /dev/null
+// Copyright (C) 2020 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#pragma once
+
+#include "system.hpp"
+
+#include "NonCopyable.hpp"
+#include "Util.hpp"
+
+#include "third_party/nonstd/optional.hpp"
+#include "third_party/nonstd/string_view.hpp"
+
+#include <deque>
+#include <string>
+
+class Args
+{
+public:
+ Args();
+ Args(const Args& other);
+ Args(Args&& other);
+
+ static Args from_argv(int argc, const char* const* argv);
+ static Args from_string(const std::string& command);
+ static nonstd::optional<Args> from_gcc_atfile(const std::string& filename);
+
+ Args& operator=(const Args& other);
+ Args& operator=(Args&& other);
+
+ bool operator==(const Args& other) const;
+ bool operator!=(const Args& other) const;
+
+ size_t size() const;
+ const std::string& operator[](size_t i) const;
+ std::string& operator[](size_t i);
+
+ // Accessor functions for the legacy API:
+ Args& operator*();
+ const Args* operator->() const;
+
+ // Return the argument list as a vector of raw string pointers. Callers can
+ // use `const_cast<char* const*>(args.to_argv().data())` to get an array
+ // suitable to pass to e.g. execv(2).
+ std::vector<const char*> to_argv() const;
+
+ // Return a space-delimited argument list in string form. No quoting of spaces
+ // in arguments is performed.
+ std::string to_string() const;
+
+ // Remove all arguments with prefix `prefix`.
+ void erase_with_prefix(nonstd::string_view prefix);
+
+ // Insert arguments in `args` at position `index`.
+ void insert(size_t index, const Args& args);
+
+ // Remove the last `count` arguments.
+ void pop_back(size_t count = 1);
+
+ // Remove the first `count` arguments.
+ void pop_front(size_t count = 1);
+
+ // Add `arg` to the end.
+ void push_back(const std::string& arg);
+
+ // Add `args` to the end.
+ void push_back(const Args& args);
+
+ // Add `arg` to the front.
+ void push_front(const std::string& arg);
+
+ // Replace the argument at `index` with all arguments in `args`.
+ void replace(size_t index, const Args& args);
+
+private:
+ std::deque<std::string> m_args;
+
+public:
+ // Wrapper for legacy API:
+ class ArgvAccessWrapper
+ {
+ public:
+ friend Args;
+
+ ArgvAccessWrapper(const std::deque<std::string>& args);
+
+ const char* operator[](size_t i) const;
+
+ private:
+ const std::deque<std::string>* m_args;
+ };
+
+ ArgvAccessWrapper argv;
+};
+
+inline bool
+Args::operator==(const Args& other) const
+{
+ return m_args == other.m_args;
+}
+
+inline bool
+Args::operator!=(const Args& other) const
+{
+ return m_args != other.m_args;
+}
+
+inline size_t
+Args::size() const
+{
+ return m_args.size();
+}
+
+inline const std::string& Args::operator[](size_t i) const
+{
+ return m_args[i];
+}
+
+inline std::string& Args::operator[](size_t i)
+{
+ return m_args[i];
+}
+
+inline Args& Args::operator*()
+{
+ return *this;
+}
+
+inline const Args* Args::operator->() const
+{
+ return this;
+}
+
+// Wrapper functions for the legacy API:
+void args_add(Args& args, const std::string& arg);
+void args_add_prefix(Args& args, const std::string& arg);
+Args args_copy(const Args& args);
+void args_extend(Args& args, const Args& to_append);
+Args args_init(int argc, const char* const* argv);
+nonstd::optional<Args> args_init_from_gcc_atfile(const std::string& filename);
+Args args_init_from_string(const std::string& s);
+void args_insert(Args& args, size_t index, const Args& to_insert, bool replace);
+void args_pop(Args& args, size_t count);
+void args_remove_first(Args& args);
+void args_set(Args& args, size_t index, const std::string& value);
+void args_strip(Args& args, nonstd::string_view prefix);
#include "ArgsInfo.hpp"
-#include "args.hpp"
-
ArgsInfo::~ArgsInfo()
{
for (size_t i = 0; i < debug_prefix_maps_len; i++) {
free(debug_prefix_maps[i]);
}
free(debug_prefix_maps);
-
- args_free(depend_extra_args);
}
#include "system.hpp"
+#include "Args.hpp"
+
#include <string>
// This class holds meta-information derived from the compiler arguments.
size_t debug_prefix_maps_len = 0;
// Argument list to add to compiler invocation in depend mode.
- struct args* depend_extra_args = nullptr;
+ Args depend_extra_args;
ArgsInfo() = default;
~ArgsInfo();
#include "Counters.hpp"
#include "Util.hpp"
-#include "args.hpp"
Context::Context()
: actual_cwd(Util::get_actual_cwd()),
Context::~Context()
{
- args_free(orig_args);
-
free(result_name);
for (size_t i = 0; i < ignore_headers_len; i++) {
#include "system.hpp"
+#include "Args.hpp"
#include "ArgsInfo.hpp"
#include "Config.hpp"
#include "NonCopyable.hpp"
#include <unordered_map>
-struct args;
-
struct Context : NonCopyable
{
Context();
std::string apparent_cwd;
// The original argument list.
- struct args* orig_args = nullptr;
+ Args orig_args;
// Name (represented as a struct digest) of the file containing the cached
// result.
+++ /dev/null
-// Copyright (C) 2002 Andrew Tridgell
-// Copyright (C) 2009-2020 Joel Rosdahl and other contributors
-//
-// See doc/AUTHORS.adoc for a complete list of contributors.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3 of the License, or (at your option)
-// any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program; if not, write to the Free Software Foundation, Inc., 51
-// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-#include "args.hpp"
-
-#include "legacy_util.hpp"
-
-struct args*
-args_init(int init_argc, const char* const* init_args)
-{
- struct args* args = (struct args*)x_malloc(sizeof(struct args));
- args->argc = 0;
- args->argv = (char**)x_malloc(sizeof(char*));
- args->argv[0] = nullptr;
- for (int i = 0; i < init_argc; i++) {
- args_add(args, init_args[i]);
- }
- return args;
-}
-
-struct args*
-args_init_from_string(const char* command)
-{
- char* p = x_strdup(command);
- char* q = p;
- char *word, *saveptr = nullptr;
- struct args* args = args_init(0, nullptr);
- while ((word = strtok_r(q, " \t\r\n", &saveptr))) {
- args_add(args, word);
- q = nullptr;
- }
-
- free(p);
- return args;
-}
-
-struct args*
-args_init_from_gcc_atfile(const char* filename)
-{
- char* argtext;
- if (!(argtext = read_text_file(filename, 0))) {
- return nullptr;
- }
-
- struct args* args = args_init(0, nullptr);
- char* pos = argtext;
- char* argbuf = static_cast<char*>(x_malloc(strlen(argtext) + 1));
- char* argpos = argbuf;
-
- // Used to track quoting state; if \0, we are not inside quotes. Otherwise
- // stores the quoting character that started it, for matching the end quote.
- char quoting = '\0';
-
- while (1) {
- switch (*pos) {
- case '\\':
- pos++;
- if (*pos == '\0') {
- continue;
- }
- break;
-
- case '\"':
- case '\'':
- if (quoting != '\0') {
- if (quoting == *pos) {
- quoting = '\0';
- pos++;
- continue;
- } else {
- break;
- }
- } else {
- quoting = *pos;
- pos++;
- continue;
- }
-
- case '\n':
- case '\r':
- case '\t':
- case ' ':
- if (quoting) {
- break;
- }
- // Fall through.
-
- case '\0':
- // End of token
- *argpos = '\0';
- if (argbuf[0] != '\0') {
- args_add(args, argbuf);
- }
- argpos = argbuf;
- if (*pos == '\0') {
- goto out;
- } else {
- pos++;
- continue;
- }
- }
-
- *argpos = *pos;
- pos++;
- argpos++;
- }
-
-out:
- free(argbuf);
- free(argtext);
- return args;
-}
-
-struct args*
-args_copy(struct args* args)
-{
- return args_init(args->argc, args->argv);
-}
-
-// Insert all arguments in src into dest at position index. If replace is true,
-// the element at dest->argv[index] is replaced with the contents of src and
-// everything past it is shifted. Otherwise, dest->argv[index] is also shifted.
-//
-// src is consumed by this operation and should not be freed or used again by
-// the caller.
-void
-args_insert(struct args* dest, int index, struct args* src, bool replace)
-{
- // Adjustments made if we are replacing or shifting the element currently at
- // dest->argv[index].
- int offset = replace ? 1 : 0;
-
- if (replace) {
- free(dest->argv[index]);
- }
-
- if (src->argc == 0) {
- if (replace) {
- // Have to shift everything down by 1 since we replaced with an empty
- // list.
- for (int i = index; i < dest->argc; i++) {
- dest->argv[i] = dest->argv[i + 1];
- }
- dest->argc--;
- }
- args_free(src);
- return;
- }
-
- if (src->argc == 1 && replace) {
- // Trivial case; replace with 1 element.
- dest->argv[index] = src->argv[0];
- src->argc = 0;
- args_free(src);
- return;
- }
-
- dest->argv = (char**)x_realloc(
- dest->argv, (src->argc + dest->argc + 1 - offset) * sizeof(char*));
-
- // Shift arguments over.
- for (int i = dest->argc; i >= index + offset; i--) {
- dest->argv[i + src->argc - offset] = dest->argv[i];
- }
-
- // Copy the new arguments into place.
- for (int i = 0; i < src->argc; i++) {
- dest->argv[i + index] = src->argv[i];
- }
-
- dest->argc += src->argc - offset;
- src->argc = 0;
- args_free(src);
-}
-
-void
-args_free(struct args* args)
-{
- if (!args) {
- return;
- }
- for (int i = 0; i < args->argc; ++i) {
- if (args->argv[i]) {
- free(args->argv[i]);
- }
- }
- free(args->argv);
- free(args);
-}
-
-void
-args_add(struct args* args, const char* s)
-{
- args->argv = (char**)x_realloc(args->argv, (args->argc + 2) * sizeof(char*));
- args->argv[args->argc] = x_strdup(s);
- args->argc++;
- args->argv[args->argc] = nullptr;
-}
-
-// Add all arguments in to_append to args.
-void
-args_extend(struct args* args, struct args* to_append)
-{
- for (int i = 0; i < to_append->argc; i++) {
- args_add(args, to_append->argv[i]);
- }
-}
-
-// Pop the last element off the args list.
-void
-args_pop(struct args* args, int n)
-{
- while (n--) {
- args->argc--;
- free(args->argv[args->argc]);
- args->argv[args->argc] = nullptr;
- }
-}
-
-// Set argument at given index.
-void
-args_set(struct args* args, int index, const char* value)
-{
- assert(index < args->argc);
- free(args->argv[index]);
- args->argv[index] = x_strdup(value);
-}
-
-// Remove the first element of the argument list.
-void
-args_remove_first(struct args* args)
-{
- free(args->argv[0]);
- memmove(&args->argv[0], &args->argv[1], args->argc * sizeof(args->argv[0]));
- args->argc--;
-}
-
-// Add an argument into the front of the argument list.
-void
-args_add_prefix(struct args* args, const char* s)
-{
- args->argv = (char**)x_realloc(args->argv, (args->argc + 2) * sizeof(char*));
- memmove(
- &args->argv[1], &args->argv[0], (args->argc + 1) * sizeof(args->argv[0]));
- args->argv[0] = x_strdup(s);
- args->argc++;
-}
-
-// Strip any arguments beginning with the specified prefix.
-void
-args_strip(struct args* args, const char* prefix)
-{
- for (int i = 0; i < args->argc;) {
- if (str_startswith(args->argv[i], prefix)) {
- free(args->argv[i]);
- memmove(&args->argv[i],
- &args->argv[i + 1],
- (args->argc - i) * sizeof(args->argv[i]));
- args->argc--;
- } else {
- i++;
- }
- }
-}
-
-// Format args to a space-separated string. Does not quote spaces. Caller
-// frees.
-char*
-args_to_string(const struct args* args)
-{
- unsigned size = 0;
- for (char** p = args->argv; *p; p++) {
- size += strlen(*p) + 1;
- }
-
- char* result = static_cast<char*>(x_malloc(size + 1));
- int pos = 0;
- for (char** p = args->argv; *p; p++) {
- pos += sprintf(&result[pos], "%s ", *p);
- }
- result[pos - 1] = '\0';
- return result;
-}
-
-// Returns true if args1 equals args2, else false.
-bool
-args_equal(const struct args* args1, const struct args* args2)
-{
- if (args1->argc != args2->argc) {
- return false;
- }
- for (int i = 0; i < args1->argc; i++) {
- if (!str_eq(args1->argv[i], args2->argv[i])) {
- return false;
- }
- }
- return true;
-}
-
-void
-args_deleter::operator()(struct args*& arg)
-{
- args_free(arg);
- arg = nullptr;
-}
+++ /dev/null
-// Copyright (C) 2020 Joel Rosdahl and other contributors
-//
-// See doc/AUTHORS.adoc for a complete list of contributors.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3 of the License, or (at your option)
-// any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program; if not, write to the Free Software Foundation, Inc., 51
-// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-#pragma once
-
-#include "ScopeGuard.hpp"
-
-struct args
-{
- char** argv;
- int argc;
-};
-
-struct args* args_init(int, const char* const*);
-struct args* args_init_from_string(const char*);
-struct args* args_init_from_gcc_atfile(const char* filename);
-struct args* args_copy(struct args* args);
-void args_free(struct args* args);
-void args_add(struct args* args, const char* s);
-void args_add_prefix(struct args* args, const char* s);
-void args_extend(struct args* args, struct args* to_append);
-void args_insert(struct args* dest, int index, struct args* src, bool replace);
-void args_pop(struct args* args, int n);
-void args_set(struct args* args, int index, const char* value);
-void args_strip(struct args* args, const char* prefix);
-void args_remove_first(struct args* args);
-char* args_to_string(const struct args* args);
-bool args_equal(const struct args* args1, const struct args* args2);
-
-struct args_deleter
-{
- void operator()(struct args*& arg);
-};
-using ArgsScopeGuard = ScopeGuard<args_deleter, struct args*>;
#include "ccache.hpp"
+#include "Args.hpp"
#include "ArgsInfo.hpp"
#include "Context.hpp"
#include "File.hpp"
#include "ProgressBar.hpp"
#include "ScopeGuard.hpp"
#include "Util.hpp"
-#include "args.hpp"
#include "cleanup.hpp"
#include "compopt.hpp"
#include "compress.hpp"
static const char HASH_PREFIX[] = "3";
static void
-add_prefix(const Context& ctx, struct args* args, const char* prefix_command)
+add_prefix(const Context& ctx, Args& args, const char* prefix_command)
{
if (str_eq(prefix_command, "")) {
return;
}
- struct args* prefix = args_init(0, nullptr);
+ Args prefix;
char* e = x_strdup(prefix_command);
char* saveptr = nullptr;
for (char* tok = strtok_r(e, " ", &saveptr); tok;
free(e);
cc_log("Using command-line prefix %s", prefix_command);
- for (int i = prefix->argc; i != 0; i--) {
+ for (size_t i = prefix.size(); i != 0; i--) {
args_add_prefix(args, prefix->argv[i - 1]);
}
- args_free(prefix);
}
// If `exit_code` is set, just exit with that code directly, otherwise execute
// Run the real compiler and put the result in cache.
static void
to_cache(Context& ctx,
- struct args* args,
- struct args* depend_extra_args,
+ Args& args,
+ Args& depend_extra_args,
struct hash* depend_mode_hash)
{
args_add(args, "-o");
tmp_stdout_fd = create_tmp_fd(&tmp_stdout);
tmp_stderr = format("%s/tmp.stderr", temp_dir(ctx));
tmp_stderr_fd = create_tmp_fd(&tmp_stderr);
- status = execute(args->argv, tmp_stdout_fd, tmp_stderr_fd, &compiler_pid);
+ status = execute(
+ args.to_argv().data(), tmp_stdout_fd, tmp_stderr_fd, &compiler_pid);
args_pop(args, 3);
} else {
// The cached result path is not known yet, use temporary files.
// Use the original arguments (including dependency options) in depend
// mode.
- assert(ctx.orig_args);
- struct args* depend_mode_args = args_copy(ctx.orig_args);
+ Args depend_mode_args = ctx.orig_args;
args_strip(depend_mode_args, "--ccache-");
- if (depend_extra_args) {
- args_extend(depend_mode_args, depend_extra_args);
- }
+ args_extend(depend_mode_args, depend_extra_args);
add_prefix(ctx, depend_mode_args, ctx.config.prefix_command().c_str());
ctx.time_of_compilation = time(nullptr);
- status = execute(
- depend_mode_args->argv, tmp_stdout_fd, tmp_stderr_fd, &compiler_pid);
- args_free(depend_mode_args);
+ status = execute(depend_mode_args.to_argv().data(),
+ tmp_stdout_fd,
+ tmp_stderr_fd,
+ &compiler_pid);
}
MTR_END("execute", "compiler");
// Find the result name by running the compiler in preprocessor mode and
// hashing the result.
static struct digest*
-get_result_name_from_cpp(Context& ctx, struct args* args, struct hash* hash)
+get_result_name_from_cpp(Context& ctx, Args& args, struct hash* hash)
{
ctx.time_of_compilation = time(nullptr);
add_prefix(ctx, args, ctx.config.prefix_command_cpp().c_str());
cc_log("Running preprocessor");
MTR_BEGIN("execute", "preprocessor");
- status = execute(args->argv, path_stdout_fd, path_stderr_fd, &compiler_pid);
+ status = execute(
+ args.to_argv().data(), path_stdout_fd, path_stderr_fd, &compiler_pid);
MTR_END("execute", "preprocessor");
args_pop(args, args_added);
}
// Update a hash with information common for the direct and preprocessor modes.
static void
hash_common_info(const Context& ctx,
- struct args* args,
+ const Args& args,
struct hash* hash,
const ArgsInfo& args_info)
{
// otherwise NULL. Caller frees.
static struct digest*
calculate_result_name(Context& ctx,
- struct args* args,
- struct args* preprocessor_args,
+ const Args& args,
+ Args& preprocessor_args,
struct hash* hash,
bool direct_mode)
{
|| ctx.guessed_compiler == GuessedCompiler::unknown;
// First the arguments.
- for (int i = 1; i < args->argc; i++) {
+ for (size_t i = 1; i < args.size(); i++) {
// -L doesn't affect compilation (except for clang).
- if (i < args->argc - 1 && str_eq(args->argv[i], "-L") && !is_clang) {
+ if (i < args.size() - 1 && str_eq(args->argv[i], "-L") && !is_clang) {
i++;
continue;
}
}
}
- char* p = nullptr;
+ const char* p = nullptr;
if (str_startswith(args->argv[i], "-specs=")) {
p = args->argv[i] + 7;
} else if (str_startswith(args->argv[i], "--specs=")) {
}
}
- if (str_eq(args->argv[i], "-Xclang") && i + 3 < args->argc
+ if (str_eq(args->argv[i], "-Xclang") && i + 3 < args.size()
&& str_eq(args->argv[i + 1], "-load")
&& str_eq(args->argv[i + 2], "-Xclang")) {
auto st = Stat::stat(args->argv[i + 3], Stat::OnError::log);
if ((str_eq(args->argv[i], "-ccbin")
|| str_eq(args->argv[i], "--compiler-bindir"))
- && i + 1 < args->argc) {
+ && i + 1 < args.size()) {
auto st = Stat::stat(args->argv[i + 1], Stat::OnError::log);
if (st) {
found_ccbin = true;
// All other arguments are included in the hash.
hash_delimiter(hash, "arg");
hash_string(hash, args->argv[i]);
- if (i + 1 < args->argc && compopt_takes_arg(args->argv[i])) {
+ if (i + 1 < args.size() && compopt_takes_arg(args->argv[i])) {
i++;
hash_delimiter(hash, "arg");
hash_string(hash, args->argv[i]);
cc_log("Did not find result name in manifest");
}
} else {
- assert(preprocessor_args);
if (ctx.args_info.arch_args_size == 0) {
result_name = get_result_name_from_cpp(ctx, preprocessor_args, hash);
cc_log("Got result name from preprocessor");
// Find the real compiler. We just search the PATH to find an executable of the
// same name that isn't a link to ourselves.
static void
-find_compiler(const Context& ctx, const char* const* argv)
+find_compiler(Context& ctx, const char* const* argv)
{
// We might be being invoked like "ccache gcc -c foo.c".
std::string base(Util::base_name(argv[0]));
fatal("Recursive invocation (the name of the ccache binary must be \"%s\")",
MYNAME);
}
- ctx.orig_args->argv[0] = compiler;
+ ctx.orig_args[0] = compiler;
}
bool
// incremented.
optional<enum stats>
process_args(Context& ctx,
- struct args* args,
- struct args** preprocessor_args,
- struct args** extra_args_to_hash,
- struct args** compiler_args)
+ const Args& args,
+ Args& preprocessor_args,
+ Args& extra_args_to_hash,
+ Args& compiler_args)
{
ArgsInfo& args_info = ctx.args_info;
Config& config = ctx.config;
// expanded_args is a copy of the original arguments given to the compiler
// but with arguments from @file and similar constructs expanded. It's only
// used as a temporary data structure to loop over.
- struct args* expanded_args = args_copy(args);
- ArgsScopeGuard expanded_args_guard(expanded_args);
+ Args expanded_args = args;
// common_args contains all original arguments except:
// * those that never should be passed to the preprocessor,
// * those that only should be passed to the preprocessor (if run_second_cpp
// is false), and
// * dependency options (like -MD and friends).
- struct args* common_args = args_init(0, nullptr);
- ArgsScopeGuard common_args_guard(common_args);
+ Args common_args;
// cpp_args contains arguments that were not added to common_args, i.e. those
// that should only be passed to the preprocessor if run_second_cpp is false.
// If run_second_cpp is true, they will be passed to the compiler as well.
- struct args* cpp_args = args_init(0, nullptr);
- ArgsScopeGuard cpp_args_guard(cpp_args);
+ Args cpp_args;
// dep_args contains dependency options like -MD. They are only passed to the
// preprocessor, never to the compiler.
- struct args* dep_args = args_init(0, nullptr);
- ArgsScopeGuard dep_args_guard(dep_args);
+ Args dep_args;
// compiler_only_args contains arguments that should only be passed to the
// compiler, not the preprocessor.
- struct args* compiler_only_args =
- args_init(0, nullptr); // will leak on failure
+ Args compiler_only_args;
bool found_color_diagnostics = false;
bool found_directives_only = false;
// Collect extra arguments that should be added.
auto add_extra_arg = [&args_info, &config](const char* arg) {
if (config.depend_mode()) {
- if (args_info.depend_extra_args == nullptr) {
- args_info.depend_extra_args = args_init(0, nullptr);
- }
args_add(args_info.depend_extra_args, arg);
}
};
- int argc = expanded_args->argc;
- char** argv = expanded_args->argv;
+ auto& argv = expanded_args->argv;
args_add(common_args, argv[0]);
- for (int i = 1; i < argc; i++) {
+ for (size_t i = 1; i < expanded_args.size(); i++) {
+ size_t argc = expanded_args.size();
+
// The user knows best: just swallow the next arg.
if (str_eq(argv[i], "--ccache-skip")) {
i++;
// Handle "@file" argument.
if (str_startswith(argv[i], "@") || str_startswith(argv[i], "-@")) {
- char* argpath = argv[i] + 1;
+ const char* argpath = argv[i] + 1;
if (argpath[-1] == '-') {
++argpath;
}
- struct args* file_args = args_init_from_gcc_atfile(argpath);
+ auto file_args = args_init_from_gcc_atfile(argpath);
if (!file_args) {
cc_log("Couldn't read arg file %s", argpath);
return STATS_ARGS;
}
- args_insert(expanded_args, i, file_args, true);
- argc = expanded_args->argc;
- argv = expanded_args->argv;
+ args_insert(expanded_args, i, *file_args, true);
i--;
continue;
}
++i;
// Argument is a comma-separated list of files.
- char* str_start = argv[i];
- char* str_end = strchr(str_start, ',');
- int index = i + 1;
+ const char* str_start = argv[i];
+ const char* str_end = strchr(str_start, ',');
+ size_t index = i + 1;
if (!str_end) {
str_end = str_start + strlen(str_start);
}
while (str_end) {
- *str_end = '\0';
- struct args* file_args = args_init_from_gcc_atfile(str_start);
+ std::string path(str_start, str_end - str_start);
+ auto file_args = args_init_from_gcc_atfile(path);
if (!file_args) {
- cc_log("Couldn't read cuda options file %s", str_start);
+ cc_log("Couldn't read cuda options file %s", path.c_str());
return STATS_ARGS;
}
- int new_index = file_args->argc + index;
- args_insert(expanded_args, index, file_args, false);
+ size_t new_index = file_args->size() + index;
+ args_insert(expanded_args, index, *file_args, false);
index = new_index;
str_start = str_end;
str_end = strchr(str_start, ',');
}
- argc = expanded_args->argc;
- argv = expanded_args->argv;
continue;
}
if (str_startswith(argv[i], "-MF")) {
dependency_filename_specified = true;
- char* arg;
+ const char* arg;
bool separate_argument = (strlen(argv[i]) == 3);
if (separate_argument) {
// -MF arg
// Same as above but options with concatenated argument beginning with a
// slash.
if (argv[i][0] == '-') {
- char* slash_pos = strchr(argv[i], '/');
+ const char* slash_pos = strchr(argv[i], '/');
if (slash_pos) {
char* option = x_strndup(argv[i], slash_pos - argv[i]);
if (compopt_takes_concat_arg(option) && compopt_takes_path(option)) {
}
// Else: Fall back to running the real compiler.
- assert(ctx.orig_args);
+ assert(ctx.orig_args.size() > 0);
args_strip(ctx.orig_args, "--ccache-");
add_prefix(ctx, ctx.orig_args, ctx.config.prefix_command().c_str());
cc_log("Failed; falling back to running the real compiler");
- cc_log_argv("Executing ", ctx.orig_args->argv);
- struct args* orig_args_for_execv = ctx.orig_args;
- ctx.orig_args = nullptr; // Take over ownership.
+
+ // exitfn_call deletes ctx and thereby ctx.orig_orgs, so save it.
+ Args saved_orig_args(std::move(ctx.orig_args));
+ auto execv_argv = saved_orig_args.to_argv();
+
+ cc_log_argv("Executing ", execv_argv.data());
exitfn_call();
- execv(orig_args_for_execv->argv[0], orig_args_for_execv->argv);
- fatal(
- "execv of %s failed: %s", orig_args_for_execv->argv[0], strerror(errno));
+ execv(execv_argv[0], const_cast<char* const*>(execv_argv.data()));
+ fatal("execv of %s failed: %s", execv_argv[0], strerror(errno));
}
}
MTR_END("main", "guess_compiler");
// Arguments (except -E) to send to the preprocessor.
- struct args* preprocessor_args;
+ Args preprocessor_args;
// Arguments not sent to the preprocessor but that should be part of the
// hash.
- struct args* extra_args_to_hash;
+ Args extra_args_to_hash;
// Arguments to send to the real compiler.
- struct args* compiler_args;
+ Args compiler_args;
MTR_BEGIN("main", "process_args");
- auto error = process_args(ctx,
- ctx.orig_args,
- &preprocessor_args,
- &extra_args_to_hash,
- &compiler_args);
+ auto error = process_args(
+ ctx, ctx.orig_args, preprocessor_args, extra_args_to_hash, compiler_args);
if (error) {
failed(*error);
}
"DIRECT MODE",
debug_text_file);
- struct args* args_to_hash = args_copy(preprocessor_args);
+ Args args_to_hash = preprocessor_args;
args_extend(args_to_hash, extra_args_to_hash);
bool put_result_in_manifest = false;
if (ctx.config.direct_mode()) {
cc_log("Trying direct lookup");
MTR_BEGIN("hash", "direct_hash");
+ Args dummy_args;
result_name =
- calculate_result_name(ctx, args_to_hash, nullptr, direct_hash, true);
+ calculate_result_name(ctx, args_to_hash, dummy_args, direct_hash, true);
MTR_END("hash", "direct_hash");
if (result_name) {
update_cached_result_globals(ctx, result_name);
#include "system.hpp"
+#include "Args.hpp"
#include "Counters.hpp"
#include "stats.hpp"
void block_signals();
void unblock_signals();
nonstd::optional<enum stats> process_args(Context& ctx,
- struct args* args,
- struct args** preprocessor_args,
- struct args** extra_args_to_hash,
- struct args** compiler_args);
+ const Args& args,
+ Args& preprocessor_args,
+ Args& extra_args_to_hash,
+ Args& compiler_args);
bool is_precompiled_header(const char* path);
#include "hashutil.hpp"
+#include "Args.hpp"
#include "Config.hpp"
#include "Context.hpp"
#include "Stat.hpp"
-#include "args.hpp"
#include "ccache.hpp"
#include "execute.hpp"
#include "logging.hpp"
}
#endif
- struct args* args = args_init_from_string(command);
- for (int i = 0; i < args->argc; i++) {
+ Args args = Args::from_string(command);
+
+ for (size_t i = 0; i < args.size(); i++) {
if (str_eq(args->argv[i], "%compiler%")) {
args_set(args, i, compiler);
}
}
- cc_log_argv("Executing compiler check command ", args->argv);
+
+ auto argv = args.to_argv();
+ cc_log_argv("Executing compiler check command ", argv.data());
#ifdef _WIN32
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si, 0x00, sizeof(si));
- char* path = find_executable_in_path(args->argv[0], nullptr, getenv("PATH"));
+ char* path =
+ find_executable_in_path(args[0].c_str(), nullptr, getenv("PATH"));
if (!path) {
- path = args->argv[0];
+ path = x_strdup(args[0].c_str());
}
char* sh = win32getshell(path);
if (sh) {
char* win32args;
if (!cmd) {
int length;
- win32args = win32argvtos(sh, args->argv, &length);
+ win32args = win32argvtos(sh, argv.data(), &length);
} else {
win32args = (char*)command; // quoted
}
BOOL ret =
CreateProcess(path, win32args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
+ free(path);
CloseHandle(pipe_out[1]);
- args_free(args);
free(win32args);
if (!cmd) {
free((char*)command); // Original argument was replaced above.
close(0);
dup2(pipefd[1], 1);
dup2(pipefd[1], 2);
- _exit(execvp(args->argv[0], args->argv));
+ _exit(execvp(argv[0], const_cast<char* const*>(argv.data())));
// Never reached.
} else {
// Parent.
- args_free(args);
close(pipefd[1]);
bool ok = hash_fd(hash, pipefd[0]);
if (!ok) {
#include "framework.hpp"
+#include "../src/Args.hpp"
#include "../src/Config.hpp"
#include "../src/Util.hpp"
-#include "../src/args.hpp"
#include "../src/ccache.hpp"
#include "util.hpp"
cct_check_args_eq(const char* file,
int line,
const char* expression,
- const struct args* expected,
- const struct args* actual,
- bool free1,
- bool free2)
+ const Args& expected,
+ const Args& actual)
{
- bool result;
-
- if (expected && actual && args_equal(actual, expected)) {
+ if (actual == expected) {
cct_check_passed(file, line, expression);
- result = true;
+ return true;
} else {
- char* exp_str = expected ? args_to_string(expected) : x_strdup("(null)");
- char* act_str = actual ? args_to_string(actual) : x_strdup("(null)");
- cct_check_failed(file, line, expression, exp_str, act_str);
- free(exp_str);
- free(act_str);
- result = false;
- }
-
- if (free1) {
- args_free(const_cast<struct args*>(expected));
- }
- if (free2) {
- args_free(const_cast<struct args*>(actual));
+ cct_check_failed(file,
+ line,
+ expression,
+ expected.to_string().c_str(),
+ actual.to_string().c_str());
+ return false;
}
- return result;
}
void
-// Copyright (C) 2010-2019 Joel Rosdahl and other contributors
+// Copyright (C) 2010-2020 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
#include "../src/system.hpp"
+class Args;
+
// ============================================================================
#define TEST_SUITE(name) \
// ============================================================================
-#define CHECK_ARGS_EQ(expected, actual) \
- CHECK_POINTER_EQ_BASE(args, expected, actual, false, false)
-
-#define CHECK_ARGS_EQ_FREE1(expected, actual) \
- CHECK_POINTER_EQ_BASE(args, expected, actual, true, false)
-
-#define CHECK_ARGS_EQ_FREE2(expected, actual) \
- CHECK_POINTER_EQ_BASE(args, expected, actual, false, true)
-
-#define CHECK_ARGS_EQ_FREE12(expected, actual) \
- CHECK_POINTER_EQ_BASE(args, expected, actual, true, true)
+#define CHECK_ARGS_EQ_FREE12(e, a) \
+ do { \
+ if (!cct_check_args_eq(__FILE__, __LINE__, #a, (e), (a))) { \
+ cct_test_end(); \
+ cct_suite_end(); \
+ return _test_counter; \
+ } \
+ } while (false)
// ============================================================================
bool cct_check_args_eq(const char* file,
int line,
const char* expression,
- const struct args* expected,
- const struct args* actual,
- bool free1,
- bool free2);
+ const Args& expected,
+ const Args& actual);
void cct_chdir(const char* path);
void cct_wipe(const char* path);
void cct_create_fresh_dir(const char* path);
--- /dev/null
+// Copyright (C) 2020 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "../src/Args.hpp"
+
+#include "third_party/catch.hpp"
+
+TEST_CASE("Args default constructor")
+{
+ Args args;
+ CHECK(args.size() == 0);
+}
+
+TEST_CASE("Args copy constructor")
+{
+ Args args1;
+ args1.push_back("foo");
+ args1.push_back("bar");
+
+ Args args2(args1);
+ CHECK(args1 == args2);
+}
+
+TEST_CASE("Args move constructor")
+{
+ Args args1;
+ args1.push_back("foo");
+ args1.push_back("bar");
+ const char* foo_pointer = args1[0].c_str();
+ const char* bar_pointer = args1[1].c_str();
+
+ Args args2(std::move(args1));
+ CHECK(args1.size() == 0);
+ CHECK(args2.size() == 2);
+ CHECK(args2[0].c_str() == foo_pointer);
+ CHECK(args2[1].c_str() == bar_pointer);
+}
+
+TEST_CASE("Args::from_argv")
+{
+ int argc = 2;
+ const char* argv[] = {"a", "b"};
+ Args args = Args::from_argv(argc, argv);
+ CHECK(args.size() == 2);
+ CHECK(args[0] == "a");
+ CHECK(args[1] == "b");
+}
+
+TEST_CASE("Args::from_string")
+{
+ Args args = Args::from_string(" c d\te\r\nf ");
+ CHECK(args.size() == 4);
+ CHECK(args[0] == "c");
+ CHECK(args[1] == "d");
+ CHECK(args[2] == "e");
+ CHECK(args[3] == "f");
+}
+
+TEST_CASE("Args copy assignment operator")
+{
+ Args args1 = Args::from_string("x y");
+ Args args2;
+ args2 = args1;
+ CHECK(args2.size() == 2);
+ CHECK(args2[0] == "x");
+ CHECK(args2[1] == "y");
+}
+
+TEST_CASE("Args move assignment operator")
+{
+ Args args1 = Args::from_string("x y");
+ const char* x_pointer = args1[0].c_str();
+ const char* y_pointer = args1[1].c_str();
+
+ Args args2;
+ args2 = std::move(args1);
+ CHECK(args1.size() == 0);
+ CHECK(args2.size() == 2);
+ CHECK(args2[0].c_str() == x_pointer);
+ CHECK(args2[1] == y_pointer);
+}
+
+TEST_CASE("Args equality operators")
+{
+ Args args1 = Args::from_string("x y");
+ Args args2 = Args::from_string("x y");
+ Args args3 = Args::from_string("y x");
+ CHECK(args1 == args1);
+ CHECK(args1 == args2);
+ CHECK(args2 == args1);
+ CHECK(args1 != args3);
+ CHECK(args3 != args1);
+}
+
+TEST_CASE("Args::size")
+{
+ Args args;
+ CHECK(args.size() == 0);
+ args.push_back("1");
+ CHECK(args.size() == 1);
+ args.push_back("2");
+ CHECK(args.size() == 2);
+}
+
+TEST_CASE("Args indexing")
+{
+ const Args args1 = Args::from_string("1 2 3");
+ CHECK(args1[0] == "1");
+ CHECK(args1[1] == "2");
+ CHECK(args1[2] == "3");
+
+ Args args2 = Args::from_string("1 2 3");
+ CHECK(args2[0] == "1");
+ CHECK(args2[1] == "2");
+ CHECK(args2[2] == "3");
+}
+
+TEST_CASE("Args::to_argv")
+{
+ Args args = Args::from_string("1 2 3");
+ auto argv = args.to_argv();
+ CHECK(std::string(argv[0]) == "1");
+ CHECK(std::string(argv[1]) == "2");
+ CHECK(std::string(argv[2]) == "3");
+ CHECK(argv[3] == nullptr);
+}
+
+TEST_CASE("Args::to_string")
+{
+ CHECK(Args::from_string("a little string").to_string() == "a little string");
+}
+
+TEST_CASE("Args operations")
+{
+ Args args = Args::from_string("eeny meeny miny moe");
+ Args more_args = Args::from_string("x y");
+ Args no_args;
+
+ SECTION("erase_with_prefix")
+ {
+ args.erase_with_prefix("m");
+ CHECK(args == Args::from_string("eeny"));
+ }
+
+ SECTION("insert empty args")
+ {
+ args.insert(2, no_args);
+ CHECK(args == Args::from_string("eeny meeny miny moe"));
+ }
+
+ SECTION("insert non-empty args")
+ {
+ args.insert(4, more_args);
+ args.insert(2, more_args);
+ args.insert(0, more_args);
+ CHECK(args == Args::from_string("x y eeny meeny x y miny moe x y"));
+ }
+
+ SECTION("pop_back")
+ {
+ args.pop_back();
+ CHECK(args == Args::from_string("eeny meeny miny"));
+
+ args.pop_back(2);
+ CHECK(args == Args::from_string("eeny"));
+ }
+
+ SECTION("pop_front")
+ {
+ args.pop_front();
+ CHECK(args == Args::from_string("meeny miny moe"));
+
+ args.pop_front(2);
+ CHECK(args == Args::from_string("moe"));
+ }
+
+ SECTION("push_back string")
+ {
+ args.push_back("foo");
+ CHECK(args == Args::from_string("eeny meeny miny moe foo"));
+ }
+
+ SECTION("push_back args")
+ {
+ args.push_back(more_args);
+ CHECK(args == Args::from_string("eeny meeny miny moe x y"));
+ }
+
+ SECTION("push_front string")
+ {
+ args.push_front("foo");
+ CHECK(args == Args::from_string("foo eeny meeny miny moe"));
+ }
+
+ SECTION("replace")
+ {
+ args.replace(3, more_args);
+ args.replace(2, no_args);
+ args.replace(0, more_args);
+ CHECK(args == Args::from_string("x y meeny x y"));
+ }
+}
+++ /dev/null
-// Copyright (C) 2010-2020 Joel Rosdahl and other contributors
-//
-// See doc/AUTHORS.adoc for a complete list of contributors.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License as published by the Free
-// Software Foundation; either version 3 of the License, or (at your option)
-// any later version.
-//
-// This program is distributed in the hope that it will be useful, but WITHOUT
-// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-// more details.
-//
-// You should have received a copy of the GNU General Public License along with
-// this program; if not, write to the Free Software Foundation, Inc., 51
-// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-// This file contains tests for the functions operating on struct args.
-
-#include "../src/args.hpp"
-#include "framework.hpp"
-#include "util.hpp"
-
-TEST_SUITE(args)
-
-TEST(args_init_empty)
-{
- struct args* args = args_init(0, nullptr);
- CHECK(args);
- CHECK_INT_EQ(0, args->argc);
- CHECK(!args->argv[0]);
- args_free(args);
-}
-
-TEST(args_init_populated)
-{
- const char* argv[] = {"first", "second"};
- struct args* args = args_init(2, argv);
- CHECK(args);
- CHECK_INT_EQ(2, args->argc);
- CHECK_STR_EQ("first", args->argv[0]);
- CHECK_STR_EQ("second", args->argv[1]);
- CHECK(!args->argv[2]);
- args_free(args);
-}
-
-TEST(args_init_from_string)
-{
- struct args* args = args_init_from_string("first second\tthird\nfourth");
- CHECK(args);
- CHECK_INT_EQ(4, args->argc);
- CHECK_STR_EQ("first", args->argv[0]);
- CHECK_STR_EQ("second", args->argv[1]);
- CHECK_STR_EQ("third", args->argv[2]);
- CHECK_STR_EQ("fourth", args->argv[3]);
- CHECK(!args->argv[4]);
- args_free(args);
-}
-
-TEST(args_init_from_gcc_atfile)
-{
- struct args* args;
- const char* argtext =
- "first\rsec\\\tond\tthi\\\\rd\nfourth \tfif\\ th \"si'x\\\" th\""
- " 'seve\nth'\\";
-
- create_file("gcc_atfile", argtext);
-
- args = args_init_from_gcc_atfile("gcc_atfile");
- CHECK(args);
- CHECK_INT_EQ(7, args->argc);
- CHECK_STR_EQ("first", args->argv[0]);
- CHECK_STR_EQ("sec\tond", args->argv[1]);
- CHECK_STR_EQ("thi\\rd", args->argv[2]);
- CHECK_STR_EQ("fourth", args->argv[3]);
- CHECK_STR_EQ("fif th", args->argv[4]);
- CHECK_STR_EQ("si'x\" th", args->argv[5]);
-#ifndef _WIN32
- CHECK_STR_EQ("seve\nth", args->argv[6]);
-#else
- CHECK_STR_EQ("seve\r\nth", args->argv[6]);
-#endif
- CHECK(!args->argv[7]);
- args_free(args);
-}
-
-TEST(args_copy)
-{
- struct args* args1 = args_init_from_string("foo");
- struct args* args2 = args_copy(args1);
- CHECK_ARGS_EQ_FREE12(args1, args2);
-}
-
-TEST(args_add)
-{
- struct args* args = args_init_from_string("first");
- CHECK_INT_EQ(1, args->argc);
- args_add(args, "second");
- CHECK_INT_EQ(2, args->argc);
- CHECK_STR_EQ("second", args->argv[1]);
- CHECK(!args->argv[2]);
- args_free(args);
-}
-
-TEST(args_extend)
-{
- struct args* args1 = args_init_from_string("first");
- struct args* args2 = args_init_from_string("second third");
- CHECK_INT_EQ(1, args1->argc);
- args_extend(args1, args2);
- CHECK_INT_EQ(3, args1->argc);
- CHECK_STR_EQ("second", args1->argv[1]);
- CHECK_STR_EQ("third", args1->argv[2]);
- CHECK(!args1->argv[3]);
- args_free(args1);
- args_free(args2);
-}
-
-TEST(args_pop)
-{
- struct args* args = args_init_from_string("first second third");
- args_pop(args, 2);
- CHECK_INT_EQ(1, args->argc);
- CHECK_STR_EQ("first", args->argv[0]);
- CHECK(!args->argv[1]);
- args_free(args);
-}
-
-TEST(args_set)
-{
- struct args* args = args_init_from_string("first second third");
- args_set(args, 1, "2nd");
- CHECK_INT_EQ(3, args->argc);
- CHECK_STR_EQ("first", args->argv[0]);
- CHECK_STR_EQ("2nd", args->argv[1]);
- CHECK_STR_EQ("third", args->argv[2]);
- CHECK(!args->argv[3]);
- args_free(args);
-}
-
-TEST(args_remove_first)
-{
- struct args* args1 = args_init_from_string("first second third");
- struct args* args2 = args_init_from_string("second third");
- args_remove_first(args1);
- CHECK_ARGS_EQ_FREE12(args1, args2);
-}
-
-TEST(args_add_prefix)
-{
- struct args* args1 = args_init_from_string("second third");
- struct args* args2 = args_init_from_string("first second third");
- args_add_prefix(args1, "first");
- CHECK_ARGS_EQ_FREE12(args1, args2);
-}
-
-TEST(args_strip)
-{
- struct args* args1 = args_init_from_string("first xsecond third xfourth");
- struct args* args2 = args_init_from_string("first third");
- args_strip(args1, "x");
- CHECK_ARGS_EQ_FREE12(args1, args2);
-}
-
-TEST(args_to_string)
-{
- struct args* args = args_init_from_string("first second");
- CHECK_STR_EQ_FREE2("first second", args_to_string(args));
- args_free(args);
-}
-
-TEST(args_insert)
-{
- struct args* args = args_init_from_string("first second third fourth fifth");
-
- struct args* src1 = args_init_from_string("alpha beta gamma");
- struct args* src2 = args_init_from_string("one");
- struct args* src3 = args_init_from_string("");
- struct args* src4 = args_init_from_string("alpha beta gamma");
- struct args* src5 = args_init_from_string("one");
- struct args* src6 = args_init_from_string("");
-
- args_insert(args, 2, src1, true);
- CHECK_STR_EQ_FREE2("first second alpha beta gamma fourth fifth",
- args_to_string(args));
- CHECK_INT_EQ(7, args->argc);
- args_insert(args, 2, src2, true);
- CHECK_STR_EQ_FREE2("first second one beta gamma fourth fifth",
- args_to_string(args));
- CHECK_INT_EQ(7, args->argc);
- args_insert(args, 2, src3, true);
- CHECK_STR_EQ_FREE2("first second beta gamma fourth fifth",
- args_to_string(args));
- CHECK_INT_EQ(6, args->argc);
-
- args_insert(args, 1, src4, false);
- CHECK_STR_EQ_FREE2("first alpha beta gamma second beta gamma fourth fifth",
- args_to_string(args));
- CHECK_INT_EQ(9, args->argc);
- args_insert(args, 1, src5, false);
- CHECK_STR_EQ_FREE2(
- "first one alpha beta gamma second beta gamma fourth fifth",
- args_to_string(args));
- CHECK_INT_EQ(10, args->argc);
- args_insert(args, 1, src6, false);
- CHECK_STR_EQ_FREE2(
- "first one alpha beta gamma second beta gamma fourth fifth",
- args_to_string(args));
- CHECK_INT_EQ(10, args->argc);
-
- args_free(args);
-}
-
-TEST_SUITE_END
// This file contains tests for the processing of compiler arguments.
+#include "../src/Args.hpp"
#include "../src/Config.hpp"
#include "../src/Context.hpp"
#include "../src/Util.hpp"
-#include "../src/args.hpp"
#include "../src/ccache.hpp"
#include "../src/stats.hpp"
#include "framework.hpp"
{
Context ctx;
- struct args* orig = args_init_from_string("cc -c foo.c -E");
- struct args *preprocessed, *compiler;
+ Args orig = args_init_from_string("cc -c foo.c -E");
+ Args preprocessed;
+ Args extra;
+ Args compiler;
create_file("foo.c", "");
- CHECK(process_args(ctx, orig, &preprocessed, nullptr, &compiler)
+ CHECK(process_args(ctx, orig, preprocessed, extra, compiler)
== STATS_PREPROCESSING);
-
- args_free(orig);
}
TEST(dash_M_should_be_unsupported)
{
Context ctx;
- struct args* orig = args_init_from_string("cc -c foo.c -M");
- struct args *preprocessed, *compiler;
+ Args orig = args_init_from_string("cc -c foo.c -M");
+ Args preprocessed;
+ Args extra;
+ Args compiler;
create_file("foo.c", "");
- CHECK(process_args(ctx, orig, &preprocessed, nullptr, &compiler)
+ CHECK(process_args(ctx, orig, preprocessed, extra, compiler)
== STATS_UNSUPPORTED_OPTION);
-
- args_free(orig);
}
TEST(dependency_args_to_preprocessor_if_run_second_cpp_is_false)
#define DEP_ARGS \
"-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd" \
" -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf"
- struct args* orig =
- args_init_from_string("cc " DEP_ARGS " -c foo.c -o foo.o");
- struct args* exp_cpp = args_init_from_string("cc " DEP_ARGS);
- struct args* exp_extra = args_init(0, nullptr);
- struct args* exp_cc = args_init_from_string("cc -c");
+ Args orig = args_init_from_string("cc " DEP_ARGS " -c foo.c -o foo.o");
+ Args exp_cpp = args_init_from_string("cc " DEP_ARGS);
+ Args exp_extra = args_init(0, NULL);
+ Args exp_cc = args_init_from_string("cc -c");
#undef DEP_ARGS
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
ctx.config.set_run_second_cpp(false);
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(dependency_args_to_compiler_if_run_second_cpp_is_true)
#define DEP_ARGS \
"-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd" \
" -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf"
- struct args* orig =
- args_init_from_string("cc " DEP_ARGS " -c foo.c -o foo.o");
- struct args* exp_cpp = args_init_from_string("cc");
- struct args* exp_extra = args_init_from_string(DEP_ARGS);
- struct args* exp_cc = args_init_from_string("cc -c " DEP_ARGS);
+ Args orig = args_init_from_string("cc " DEP_ARGS " -c foo.c -o foo.o");
+ Args exp_cpp = args_init_from_string("cc");
+ Args exp_extra = args_init_from_string(DEP_ARGS);
+ Args exp_cc = args_init_from_string("cc -c " DEP_ARGS);
#undef DEP_ARGS
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(cpp_only_args_to_preprocessor_if_run_second_cpp_is_false)
#define DEP_ARGS \
"-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd" \
" -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf"
- struct args* orig =
+ Args orig =
args_init_from_string("cc " CPP_ARGS " " DEP_ARGS " -c foo.c -o foo.o");
- struct args* exp_cpp = args_init_from_string("cc " CPP_ARGS " " DEP_ARGS);
- struct args* exp_extra = args_init(0, nullptr);
- struct args* exp_cc = args_init_from_string("cc -c");
+ Args exp_cpp = args_init_from_string("cc " CPP_ARGS " " DEP_ARGS);
+ Args exp_extra = args_init(0, NULL);
+ Args exp_cc = args_init_from_string("cc -c");
#undef DEP_ARGS
#undef CPP_ARGS
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
ctx.config.set_run_second_cpp(false);
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(cpp_only_args_to_preprocessor_and_compiler_if_run_second_cpp_is_true)
#define DEP_ARGS \
" -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd" \
" -Wp,-MMD,wpmmd"
- struct args* orig =
+ Args orig =
args_init_from_string("cc " CPP_ARGS " " DEP_ARGS " -c foo.c -o foo.o");
- struct args* exp_cpp = args_init_from_string("cc " CPP_ARGS);
- struct args* exp_extra = args_init_from_string(DEP_ARGS);
- struct args* exp_cc = args_init_from_string("cc " CPP_ARGS " -c " DEP_ARGS);
+ Args exp_cpp = args_init_from_string("cc " CPP_ARGS);
+ Args exp_extra = args_init_from_string(DEP_ARGS);
+ Args exp_cc = args_init_from_string("cc " CPP_ARGS " -c " DEP_ARGS);
#undef DEP_ARGS
#undef CPP_ARGS
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(dependency_args_that_take_an_argument_should_not_require_space_delimiter)
Context ctx;
#define DEP_ARGS "-MMD -MFfoo.d -MT mt -MTmt -MQmq"
- struct args* orig =
- args_init_from_string("cc -c " DEP_ARGS " foo.c -o foo.o");
- struct args* exp_cpp = args_init_from_string("cc");
- struct args* exp_extra = args_init_from_string(DEP_ARGS);
- struct args* exp_cc = args_init_from_string("cc -c " DEP_ARGS);
+ Args orig = args_init_from_string("cc -c " DEP_ARGS " foo.c -o foo.o");
+ Args exp_cpp = args_init_from_string("cc");
+ Args exp_extra = args_init_from_string(DEP_ARGS);
+ Args exp_cc = args_init_from_string("cc -c " DEP_ARGS);
#undef DEP_ARGS
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(MQ_flag_should_not_be_added_if_run_second_cpp_is_true)
{
Context ctx;
- struct args* orig =
- args_init_from_string("cc -c -MD foo.c -MF foo.d -o foo.o");
- struct args* exp_cpp = args_init_from_string("cc");
- struct args* exp_extra = args_init_from_string("-MD -MF foo.d");
- struct args* exp_cc = args_init_from_string("cc -c -MD -MF foo.d");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("cc -c -MD foo.c -MF foo.d -o foo.o");
+ Args exp_cpp = args_init_from_string("cc");
+ Args exp_extra = args_init_from_string("-MD -MF foo.d");
+ Args exp_cc = args_init_from_string("cc -c -MD -MF foo.d");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(MQ_flag_should_be_added_if_run_second_cpp_is_false)
{
Context ctx;
- struct args* orig =
- args_init_from_string("cc -c -MD foo.c -MF foo.d -o foo.o");
- struct args* exp_cpp = args_init_from_string("cc -MD -MF foo.d -MQ foo.o");
- struct args* exp_extra = args_init(0, nullptr);
- struct args* exp_cc = args_init_from_string("cc -c");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("cc -c -MD foo.c -MF foo.d -o foo.o");
+ Args exp_cpp = args_init_from_string("cc -MD -MF foo.d -MQ foo.o");
+ Args exp_extra = args_init(0, NULL);
+ Args exp_cc = args_init_from_string("cc -c");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
ctx.config.set_run_second_cpp(false);
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(MF_should_be_added_if_run_second_cpp_is_false)
{
Context ctx;
- struct args* orig = args_init_from_string("cc -c -MD foo.c -o foo.o");
- struct args* exp_cpp = args_init_from_string("cc -MD -MF foo.d -MQ foo.o");
- struct args* exp_extra = args_init(0, nullptr);
- struct args* exp_cc = args_init_from_string("cc -c");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("cc -c -MD foo.c -o foo.o");
+ Args exp_cpp = args_init_from_string("cc -MD -MF foo.d -MQ foo.o");
+ Args exp_extra = args_init(0, NULL);
+ Args exp_cc = args_init_from_string("cc -c");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
ctx.config.set_run_second_cpp(false);
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(MF_should_not_be_added_if_run_second_cpp_is_true)
{
Context ctx;
- struct args* orig = args_init_from_string("cc -c -MD foo.c -o foo.o");
- struct args* exp_cpp = args_init_from_string("cc");
- struct args* exp_extra = args_init_from_string("-MD");
- struct args* exp_cc = args_init_from_string("cc -c -MD");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("cc -c -MD foo.c -o foo.o");
+ Args exp_cpp = args_init_from_string("cc");
+ Args exp_extra = args_init_from_string("-MD");
+ Args exp_cc = args_init_from_string("cc -c -MD");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(equal_sign_after_MF_should_be_removed)
{
Context ctx;
- struct args* orig = args_init_from_string("cc -c -MF=path foo.c -o foo.o");
- struct args* exp_cpp = args_init_from_string("cc");
- struct args* exp_extra = args_init_from_string("-MFpath");
- struct args* exp_cc = args_init_from_string("cc -c -MFpath");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("cc -c -MF=path foo.c -o foo.o");
+ Args exp_cpp = args_init_from_string("cc");
+ Args exp_extra = args_init_from_string("-MFpath");
+ Args exp_cc = args_init_from_string("cc -c -MFpath");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(sysroot_should_be_rewritten_if_basedir_is_used)
Context ctx;
char* arg_string;
- struct args* orig;
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
ctx.config.set_base_dir(get_root());
orig = args_init_from_string(arg_string);
free(arg_string);
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_STR_EQ(act_cpp->argv[1], "--sysroot=./foo/bar");
-
- args_free(orig);
- args_free(act_cpp);
- args_free(act_cc);
}
TEST(sysroot_with_separate_argument_should_be_rewritten_if_basedir_is_used)
Context ctx;
char* arg_string;
- struct args* orig;
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
ctx.config.set_base_dir(get_root());
orig = args_init_from_string(arg_string);
free(arg_string);
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_STR_EQ(act_cpp->argv[1], "--sysroot");
CHECK_STR_EQ(act_cpp->argv[2], "./foo");
-
- args_free(orig);
- args_free(act_cpp);
- args_free(act_cc);
}
TEST(MF_flag_with_immediate_argument_should_work_as_last_argument)
{
Context ctx;
- struct args* orig =
+ Args orig =
args_init_from_string("cc -c foo.c -o foo.o -MMD -MT bar -MFfoo.d");
- struct args* exp_cpp = args_init_from_string("cc");
- struct args* exp_extra = args_init_from_string("-MMD -MT bar -MFfoo.d");
- struct args* exp_cc = args_init_from_string("cc -c -MMD -MT bar -MFfoo.d");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args exp_cpp = args_init_from_string("cc");
+ Args exp_extra = args_init_from_string("-MMD -MT bar -MFfoo.d");
+ Args exp_cc = args_init_from_string("cc -c -MMD -MT bar -MFfoo.d");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(MT_flag_with_immediate_argument_should_work_as_last_argument)
{
Context ctx;
- struct args* orig =
+ Args orig =
args_init_from_string("cc -c foo.c -o foo.o -MMD -MFfoo.d -MT foo -MTbar");
- struct args* exp_cpp = args_init_from_string("cc");
- struct args* exp_extra =
- args_init_from_string("-MMD -MFfoo.d -MT foo -MTbar");
- struct args* exp_cc =
- args_init_from_string("cc -c -MMD -MFfoo.d -MT foo -MTbar");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args exp_cpp = args_init_from_string("cc");
+ Args exp_extra = args_init_from_string("-MMD -MFfoo.d -MT foo -MTbar");
+ Args exp_cc = args_init_from_string("cc -c -MMD -MFfoo.d -MT foo -MTbar");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(MQ_flag_with_immediate_argument_should_work_as_last_argument)
{
Context ctx;
- struct args* orig =
+ Args orig =
args_init_from_string("cc -c foo.c -o foo.o -MMD -MFfoo.d -MQ foo -MQbar");
- struct args* exp_cpp = args_init_from_string("cc");
- struct args* exp_extra =
- args_init_from_string("-MMD -MFfoo.d -MQ foo -MQbar");
- struct args* exp_cc =
- args_init_from_string("cc -c -MMD -MFfoo.d -MQ foo -MQbar");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args exp_cpp = args_init_from_string("cc");
+ Args exp_extra = args_init_from_string("-MMD -MFfoo.d -MQ foo -MQbar");
+ Args exp_cc = args_init_from_string("cc -c -MMD -MFfoo.d -MQ foo -MQbar");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(MQ_flag_without_immediate_argument_should_not_add_MQobj)
{
Context ctx;
- struct args* orig =
- args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQ foo.d foo.c");
- struct args* exp_cpp = args_init_from_string("gcc");
- struct args* exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MQ foo.d");
- struct args* exp_cc =
- args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQ foo.d");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQ foo.d foo.c");
+ Args exp_cpp = args_init_from_string("gcc");
+ Args exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MQ foo.d");
+ Args exp_cc = args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQ foo.d");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(MT_flag_without_immediate_argument_should_not_add_MTobj)
{
Context ctx;
- struct args* orig =
- args_init_from_string("gcc -c -MD -MP -MFfoo.d -MT foo.d foo.c");
- struct args* exp_cpp = args_init_from_string("gcc");
- struct args* exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MT foo.d");
- struct args* exp_cc =
- args_init_from_string("gcc -c -MD -MP -MFfoo.d -MT foo.d");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("gcc -c -MD -MP -MFfoo.d -MT foo.d foo.c");
+ Args exp_cpp = args_init_from_string("gcc");
+ Args exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MT foo.d");
+ Args exp_cc = args_init_from_string("gcc -c -MD -MP -MFfoo.d -MT foo.d");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(MQ_flag_with_immediate_argument_should_not_add_MQobj)
{
Context ctx;
- struct args* orig =
- args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQfoo.d foo.c");
- struct args* exp_cpp = args_init_from_string("gcc");
- struct args* exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MQfoo.d");
- struct args* exp_cc =
- args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQfoo.d");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQfoo.d foo.c");
+ Args exp_cpp = args_init_from_string("gcc");
+ Args exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MQfoo.d");
+ Args exp_cc = args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQfoo.d");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(MT_flag_with_immediate_argument_should_not_add_MQobj)
{
Context ctx;
- struct args* orig =
- args_init_from_string("gcc -c -MD -MP -MFfoo.d -MTfoo.d foo.c");
- struct args* exp_cpp = args_init_from_string("gcc");
- struct args* exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MTfoo.d");
- struct args* exp_cc =
- args_init_from_string("gcc -c -MD -MP -MFfoo.d -MTfoo.d");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("gcc -c -MD -MP -MFfoo.d -MTfoo.d foo.c");
+ Args exp_cpp = args_init_from_string("gcc");
+ Args exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MTfoo.d");
+ Args exp_cc = args_init_from_string("gcc -c -MD -MP -MFfoo.d -MTfoo.d");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(fprofile_flag_with_existing_dir_should_be_rewritten_to_real_path)
{
Context ctx;
- struct args* orig =
- args_init_from_string("gcc -c -fprofile-generate=some/dir foo.c");
- struct args* exp_cpp = args_init_from_string("gcc");
- struct args* exp_extra = args_init(0, nullptr);
- struct args* exp_cc = args_init_from_string("gcc");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("gcc -c -fprofile-generate=some/dir foo.c");
+ Args exp_cpp = args_init_from_string("gcc");
+ Args exp_extra = args_init(0, NULL);
+ Args exp_cc = args_init_from_string("gcc");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
char* s;
args_add(exp_cc, "-c");
free(s);
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(fprofile_flag_with_nonexistent_dir_should_not_be_rewritten)
{
Context ctx;
- struct args* orig =
- args_init_from_string("gcc -c -fprofile-generate=some/dir foo.c");
- struct args* exp_cpp =
- args_init_from_string("gcc -fprofile-generate=some/dir");
- struct args* exp_extra = args_init(0, nullptr);
- struct args* exp_cc =
- args_init_from_string("gcc -fprofile-generate=some/dir -c");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("gcc -c -fprofile-generate=some/dir foo.c");
+ Args exp_cpp = args_init_from_string("gcc -fprofile-generate=some/dir");
+ Args exp_extra = args_init(0, NULL);
+ Args exp_cc = args_init_from_string("gcc -fprofile-generate=some/dir -c");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(isystem_flag_with_separate_arg_should_be_rewritten_if_basedir_is_used)
Context ctx;
char* arg_string;
- struct args* orig;
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
ctx.config.set_base_dir(get_root());
orig = args_init_from_string(arg_string);
free(arg_string);
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_STR_EQ("./foo", act_cpp->argv[2]);
-
- args_free(orig);
- args_free(act_cpp);
- args_free(act_cc);
}
TEST(isystem_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used)
char* cwd;
char* arg_string;
- struct args* orig;
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
ctx.config.set_base_dir("/"); // posix
orig = args_init_from_string(arg_string);
free(arg_string);
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_STR_EQ("-isystem./foo", act_cpp->argv[1]);
free(cwd);
- args_free(orig);
- args_free(act_cpp);
- args_free(act_cc);
}
TEST(I_flag_with_concat_arg_should_be_rewritten_if_basedir_is_used)
char* cwd;
char* arg_string;
- struct args* orig;
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
ctx.config.set_base_dir(x_strdup("/")); // posix
orig = args_init_from_string(arg_string);
free(arg_string);
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_STR_EQ("-I./foo", act_cpp->argv[1]);
free(cwd);
- args_free(orig);
- args_free(act_cpp);
- args_free(act_cc);
}
TEST(debug_flag_order_with_known_option_first)
{
Context ctx;
- struct args* orig = args_init_from_string("cc -g1 -gsplit-dwarf foo.c -c");
- struct args* exp_cpp = args_init_from_string("cc -g1 -gsplit-dwarf");
- struct args* exp_extra = args_init(0, nullptr);
- struct args* exp_cc = args_init_from_string("cc -g1 -gsplit-dwarf -c");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("cc -g1 -gsplit-dwarf foo.c -c");
+ Args exp_cpp = args_init_from_string("cc -g1 -gsplit-dwarf");
+ Args exp_extra = args_init(0, NULL);
+ Args exp_cc = args_init_from_string("cc -g1 -gsplit-dwarf -c");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(debug_flag_order_with_known_option_last)
{
Context ctx;
- struct args* orig = args_init_from_string("cc -gsplit-dwarf -g1 foo.c -c");
- struct args* exp_cpp = args_init_from_string("cc -gsplit-dwarf -g1");
- struct args* exp_extra = args_init(0, nullptr);
- struct args* exp_cc = args_init_from_string("cc -gsplit-dwarf -g1 -c");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args orig = args_init_from_string("cc -gsplit-dwarf -g1 foo.c -c");
+ Args exp_cpp = args_init_from_string("cc -gsplit-dwarf -g1");
+ Args exp_extra = args_init(0, NULL);
+ Args exp_cc = args_init_from_string("cc -gsplit-dwarf -g1 -c");
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST(options_not_to_be_passed_to_the_preprocesor)
{
Context ctx;
- struct args* orig = args_init_from_string(
+ Args orig = args_init_from_string(
"cc -Wa,foo foo.c -g -c -DX -Werror -Xlinker fie -Xlinker,fum -Wno-error");
- struct args* exp_cpp = args_init_from_string("cc -g -DX");
- struct args* exp_extra = args_init_from_string(
+ Args exp_cpp = args_init_from_string("cc -g -DX");
+ Args exp_extra = args_init_from_string(
" -Wa,foo -Werror -Xlinker fie -Xlinker,fum -Wno-error");
- struct args* exp_cc = args_init_from_string(
+ Args exp_cc = args_init_from_string(
"cc -g -Wa,foo -Werror -Xlinker fie -Xlinker,fum -Wno-error -DX -c");
- struct args* act_cpp = nullptr;
- struct args* act_extra = nullptr;
- struct args* act_cc = nullptr;
+ Args act_cpp;
+ Args act_extra;
+ Args act_cc;
create_file("foo.c", "");
- CHECK(!process_args(ctx, orig, &act_cpp, &act_extra, &act_cc));
+ CHECK(!process_args(ctx, orig, act_cpp, act_extra, act_cc));
CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
- args_free(orig);
}
TEST_SUITE_END
--- /dev/null
+// Copyright (C) 2010-2020 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+// This file contains tests for the functions operating on struct args.
+
+#include "../src/Args.hpp"
+#include "framework.hpp"
+#include "util.hpp"
+
+TEST_SUITE(args)
+
+TEST(args_init_empty)
+{
+ Args args;
+ CHECK_INT_EQ(0, args.size());
+ CHECK(!args->argv[0]);
+}
+
+TEST(args_init_populated)
+{
+ const char* argv[] = {"first", "second", nullptr};
+ Args args = Args::from_argv(2, argv);
+ CHECK_INT_EQ(2, args.size());
+ CHECK_STR_EQ("first", args->argv[0]);
+ CHECK_STR_EQ("second", args->argv[1]);
+ CHECK(!args->argv[2]);
+}
+
+TEST(args_init_from_string)
+{
+ Args args = args_init_from_string("first second\tthird\nfourth");
+ CHECK_INT_EQ(4, args.size());
+ CHECK_STR_EQ("first", args->argv[0]);
+ CHECK_STR_EQ("second", args->argv[1]);
+ CHECK_STR_EQ("third", args->argv[2]);
+ CHECK_STR_EQ("fourth", args->argv[3]);
+ CHECK(!args->argv[4]);
+}
+
+TEST(args_init_from_gcc_atfile)
+{
+ const char* argtext =
+ "first\rsec\\\tond\tthi\\\\rd\nfourth \tfif\\ th \"si'x\\\" th\""
+ " 'seve\nth'\\";
+
+ create_file("gcc_atfile", argtext);
+
+ Args args = *args_init_from_gcc_atfile("gcc_atfile");
+ CHECK_INT_EQ(7, args->size());
+ CHECK_STR_EQ("first", args->argv[0]);
+ CHECK_STR_EQ("sec\tond", args->argv[1]);
+ CHECK_STR_EQ("thi\\rd", args->argv[2]);
+ CHECK_STR_EQ("fourth", args->argv[3]);
+ CHECK_STR_EQ("fif th", args->argv[4]);
+ CHECK_STR_EQ("si'x\" th", args->argv[5]);
+ CHECK_STR_EQ("seve\nth", args->argv[6]);
+ CHECK(!args->argv[7]);
+}
+
+TEST(args_copy)
+{
+ Args args1 = args_init_from_string("foo");
+ Args args2 = args1;
+ CHECK_ARGS_EQ_FREE12(args1, args2);
+}
+
+TEST(args_add)
+{
+ Args args = args_init_from_string("first");
+ CHECK_INT_EQ(1, args.size());
+ args_add(args, "second");
+ CHECK_INT_EQ(2, args.size());
+ CHECK_STR_EQ("second", args->argv[1]);
+ CHECK(!args->argv[2]);
+}
+
+TEST(args_extend)
+{
+ Args args1 = args_init_from_string("first");
+ Args args2 = args_init_from_string("second third");
+ CHECK_INT_EQ(1, args1.size());
+ args_extend(args1, args2);
+ CHECK_INT_EQ(3, args1.size());
+ CHECK_STR_EQ("second", args1->argv[1]);
+ CHECK_STR_EQ("third", args1->argv[2]);
+ CHECK(!args1->argv[3]);
+}
+
+TEST(args_pop)
+{
+ Args args = args_init_from_string("first second third");
+ args_pop(args, 2);
+ CHECK_INT_EQ(1, args.size());
+ CHECK_STR_EQ("first", args->argv[0]);
+ CHECK(!args->argv[1]);
+}
+
+TEST(args_set)
+{
+ Args args = args_init_from_string("first second third");
+ args_set(args, 1, "2nd");
+ CHECK_INT_EQ(3, args.size());
+ CHECK_STR_EQ("first", args->argv[0]);
+ CHECK_STR_EQ("2nd", args->argv[1]);
+ CHECK_STR_EQ("third", args->argv[2]);
+ CHECK(!args->argv[3]);
+}
+
+TEST(args_remove_first)
+{
+ Args args1 = args_init_from_string("first second third");
+ Args args2 = args_init_from_string("second third");
+ args_remove_first(args1);
+ CHECK_ARGS_EQ_FREE12(args1, args2);
+}
+
+TEST(args_add_prefix)
+{
+ Args args1 = args_init_from_string("second third");
+ Args args2 = args_init_from_string("first second third");
+ args_add_prefix(args1, "first");
+ CHECK_ARGS_EQ_FREE12(args1, args2);
+}
+
+TEST(args_strip)
+{
+ Args args1 = args_init_from_string("first xsecond third xfourth");
+ Args args2 = args_init_from_string("first third");
+ args_strip(args1, "x");
+ CHECK_ARGS_EQ_FREE12(args1, args2);
+}
+
+TEST(args_to_string)
+{
+ Args args = args_init_from_string("first second");
+ CHECK_STR_EQ("first second", args.to_string().c_str());
+}
+
+TEST(args_insert)
+{
+ Args args = args_init_from_string("first second third fourth fifth");
+
+ Args src1 = args_init_from_string("alpha beta gamma");
+ Args src2 = args_init_from_string("one");
+ Args src3 = args_init_from_string("");
+ Args src4 = args_init_from_string("alpha beta gamma");
+ Args src5 = args_init_from_string("one");
+ Args src6 = args_init_from_string("");
+
+ args_insert(args, 2, src1, true);
+ CHECK_STR_EQ("first second alpha beta gamma fourth fifth",
+ args.to_string().c_str());
+ CHECK_INT_EQ(7, args.size());
+ args_insert(args, 2, src2, true);
+ CHECK_STR_EQ("first second one beta gamma fourth fifth",
+ args.to_string().c_str());
+ CHECK_INT_EQ(7, args.size());
+ args_insert(args, 2, src3, true);
+ CHECK_STR_EQ("first second beta gamma fourth fifth",
+ args.to_string().c_str());
+ CHECK_INT_EQ(6, args.size());
+
+ args_insert(args, 1, src4, false);
+ CHECK_STR_EQ("first alpha beta gamma second beta gamma fourth fifth",
+ args.to_string().c_str());
+ CHECK_INT_EQ(9, args.size());
+ args_insert(args, 1, src5, false);
+ CHECK_STR_EQ("first one alpha beta gamma second beta gamma fourth fifth",
+ args.to_string().c_str());
+ CHECK_INT_EQ(10, args.size());
+ args_insert(args, 1, src6, false);
+ CHECK_STR_EQ("first one alpha beta gamma second beta gamma fourth fifth",
+ args.to_string().c_str());
+ CHECK_INT_EQ(10, args.size());
+}
+
+TEST_SUITE_END