diff options
| -rw-r--r-- | src/ctor.h | 2 | ||||
| -rw-r--r-- | src/tools.cc | 10 | ||||
| -rw-r--r-- | src/util.cc | 93 | ||||
| -rw-r--r-- | src/util.h | 3 | ||||
| -rw-r--r-- | test/argsplit_test.cc | 203 | ||||
| -rw-r--r-- | test/ctor.cc | 17 | 
6 files changed, 322 insertions, 6 deletions
| @@ -191,7 +191,7 @@ using asm_flag = ctor::flag<ctor::asm_opt>;  using c_flags = std::vector<ctor::c_flag>;  using cxx_flags = std::vector<ctor::cxx_flag>; -using ld_flags= std::vector<ctor::ld_flag>; +using ld_flags = std::vector<ctor::ld_flag>;  using ar_flags = std::vector<ctor::ar_flag>;  using asm_flags = std::vector<ctor::asm_flag>; diff --git a/src/tools.cc b/src/tools.cc index f6cb437..dfabdff 100644 --- a/src/tools.cc +++ b/src/tools.cc @@ -441,7 +441,7 @@ std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg,  		}  		return {"-D" + arg};  	case ctor::cxx_opt::custom: -		return {arg}; +		return argsplit(arg);  	}  	std::cerr << "Unsupported compiler option.\n"; @@ -488,7 +488,7 @@ std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg,  		}  		return {"-D" + arg};  	case ctor::c_opt::custom: -		return {arg}; +		return argsplit(arg);  	}  	std::cerr << "Unsupported compiler option.\n"; @@ -521,7 +521,7 @@ std::vector<std::string> ld_option(ctor::ld_opt opt, const std::string& arg,  	case ctor::ld_opt::position_independent_executable:  		return {"-fPIE"};  	case ctor::ld_opt::custom: -		return {arg}; +		return argsplit(arg);  	}  	std::cerr << "Unsupported compiler option.\n"; @@ -542,7 +542,7 @@ std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg,  	case ctor::ar_opt::output:  		return {arg};  	case ctor::ar_opt::custom: -		return {arg}; +		return argsplit(arg);  	}  	std::cerr << "Unsupported compiler option.\n"; @@ -555,7 +555,7 @@ std::vector<std::string> asm_option(ctor::asm_opt opt, const std::string& arg,  	switch(opt)  	{  	case ctor::asm_opt::custom: -		return {arg}; +		return argsplit(arg);  	}  	std::cerr << "Unsupported compiler option.\n"; diff --git a/src/util.cc b/src/util.cc index dbd4c3c..6fc650a 100644 --- a/src/util.cc +++ b/src/util.cc @@ -6,6 +6,7 @@  #include <iostream>  #include <fstream>  #include <algorithm> +#include <sstream>  std::string to_lower(const std::string& str)  { @@ -184,3 +185,95 @@ std::string locate(const std::string& prog,  	return {};  } + +std::vector<std::string> argsplit(const std::string& str) +{ +	enum class state +	{ +		normal, +		in_quot, +		in_apotrophe, +	} state{state::normal}; +	bool esc{false}; + +	std::string token; +	std::vector<std::string> tokens; +	for(auto c : str) +	{ +		switch(state) +		{ +		case state::normal: +			if(esc) +			{ +				esc = false; +			} +			else +			{ +				if(c == ' ') +				{ +					tokens.push_back(token); +					token.clear(); +					continue; +				} +				if(c == '\\') +				{ +					esc = true; +				} +				if(c == '"') +				{ +					state = state::in_quot; +				} +				if(c == '\'') +				{ +					state = state::in_apotrophe; +				} +			} + +			token += c; +			break; +		case state::in_quot: +			if(esc) +			{ +				esc = false; +			} +			else +			{ +				if(c == '\\') +				{ +					esc = true; +				} +				if(c == '"') +				{ +					state = state::normal; +				} +			} + +			token += c; +			break; +		case state::in_apotrophe: +			if(esc) +			{ +				esc = false; +			} +			else +			{ +				if(c == '\\') +				{ +					esc = true; +				} +				if(c == '\'') +				{ +					state = state::normal; +				} +			} + +			token += c; +			break; +		} +	} +	if(!token.empty()) +	{ +		tokens.push_back(token); +	} +	return tokens; +} @@ -28,3 +28,6 @@ std::vector<std::string> get_paths(const std::string& path_env = std::getenv("PA  std::string locate(const std::string& app,                     const std::vector<std::string>& paths,                     const std::string& arch = {}); + +//! Splits string into tokens adhering to quotations " and ' +std::vector<std::string> argsplit(const std::string& str); diff --git a/test/argsplit_test.cc b/test/argsplit_test.cc new file mode 100644 index 0000000..7dce561 --- /dev/null +++ b/test/argsplit_test.cc @@ -0,0 +1,203 @@ +#include <uunit.h> + +#include <util.h> + +class ArgSplitTest +	: public uUnit +{ +public: +	using fs = std::filesystem::path; + +	ArgSplitTest() +	{ +		uTEST(ArgSplitTest::plain_test); +		uTEST(ArgSplitTest::quot_test); +		uTEST(ArgSplitTest::apotrophe_test); +		uTEST(ArgSplitTest::mixed_test); +		uTEST(ArgSplitTest::escape_test); +	} + +	void plain_test() +	{ +		using namespace std::string_literals; + +		{ // zero +			auto res = argsplit({}); +			uASSERT_EQUAL(0u, res.size()); +		} + +		{ // one +			auto res = argsplit("hello"s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("hello"s, res[0]); +		} + +		{ // many +			auto res = argsplit("hello world"s); +			uASSERT_EQUAL(2u, res.size()); +			uASSERT_EQUAL("hello"s, res[0]); +			uASSERT_EQUAL("world"s, res[1]); +		} +	} + +	void quot_test() +	{ +		using namespace std::string_literals; + +		{ // zero +			auto res = argsplit("\"\""); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\"\""s, res[0]); +		} + +		{ // one +			auto res = argsplit("\"hello\""s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\"hello\""s, res[0]); +		} + +		{ // one with space +			auto res = argsplit("\"hel lo\""s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\"hel lo\""s, res[0]); +		} + +		{ // many +			auto res = argsplit("\"hello\" \"world\""s); +			uASSERT_EQUAL(2u, res.size()); +			uASSERT_EQUAL("\"hello\""s, res[0]); +			uASSERT_EQUAL("\"world\""s, res[1]); +		} + +		{ // many with spaces +			auto res = argsplit("\"hel lo\" \"wor ld\""s); +			uASSERT_EQUAL(2u, res.size()); +			uASSERT_EQUAL("\"hel lo\""s, res[0]); +			uASSERT_EQUAL("\"wor ld\""s, res[1]); +		} +	} + +	void apotrophe_test() +	{ +		using namespace std::string_literals; + +		{ // zero +			auto res = argsplit("\'\'"); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\'\'"s, res[0]); +		} + +		{ // one +			auto res = argsplit("\'hello\'"s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\'hello\'"s, res[0]); +		} + +		{ // one with space +			auto res = argsplit("\'hel lo\'"s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\'hel lo\'"s, res[0]); +		} + +		{ // many +			auto res = argsplit("\'hello\' \'world\'"s); +			uASSERT_EQUAL(2u, res.size()); +			uASSERT_EQUAL("\'hello\'"s, res[0]); +			uASSERT_EQUAL("\'world\'"s, res[1]); +		} + +		{ // many with spaces +			auto res = argsplit("\'hel lo\' \'wor ld\'"s); +			uASSERT_EQUAL(2u, res.size()); +			uASSERT_EQUAL("\'hel lo\'"s, res[0]); +			uASSERT_EQUAL("\'wor ld\'"s, res[1]); +		} +	} + +	void mixed_test() +	{ +		using namespace std::string_literals; + +		{ // zero +			auto res = argsplit("\'\'"); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\'\'"s, res[0]); +		} + +		{ // one +			auto res = argsplit("\'he\"llo\'"s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\'he\"llo\'"s, res[0]); +		} + +		{ // one +			auto res = argsplit("\"he\'llo\""s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\"he\'llo\""s, res[0]); +		} + +		{ // one with space +			auto res = argsplit("\'he\"l lo\'\""s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\'he\"l lo\'\""s, res[0]); +		} + +		{ // one with space +			auto res = argsplit("\"he\'l lo\"\'"s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\"he\'l lo\"\'"s, res[0]); +		} + +		{ // many +			auto res = argsplit("\"he\'llo\" \"wor\'ld\""s); +			uASSERT_EQUAL(2u, res.size()); +			uASSERT_EQUAL("\"he\'llo\""s, res[0]); +			uASSERT_EQUAL("\"wor\'ld\""s, res[1]); +		} + +		{ // many with spaces +			auto res = argsplit("\'hel\"lo\' \'wor\"ld\'"s); +			uASSERT_EQUAL(2u, res.size()); +			uASSERT_EQUAL("\'hel\"lo\'"s, res[0]); +			uASSERT_EQUAL("\'wor\"ld\'"s, res[1]); +		} +	} + +	void escape_test() +	{ +		using namespace std::string_literals; + +		{ // zero +			auto res = argsplit("\\"); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\\"s, res[0]); +		} + +		{ // one +			auto res = argsplit("\\\'"s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\\\'"s, res[0]); +		} + +		{ // one +			auto res = argsplit("\\\""s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\\\""s, res[0]); +		} + +		{ // one +			auto res = argsplit("\\\\"s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("\\\\"s, res[0]); +		} + +		{ // one +			auto res = argsplit("a\\ b"s); +			uASSERT_EQUAL(1u, res.size()); +			uASSERT_EQUAL("a\\ b"s, res[0]); +		} +	} +}; + +// Registers the fixture into the 'registry' +static ArgSplitTest test; diff --git a/test/ctor.cc b/test/ctor.cc index 31c63ab..b7bcc6d 100644 --- a/test/ctor.cc +++ b/test/ctor.cc @@ -12,6 +12,23 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)  		{  			.type = ctor::target_type::unit_test,  			.system = ctor::output_system::build, +			.target = "argsplit_test", +			.sources = { +				"argsplit_test.cc", +				"testmain.cc", +				"../src/util.cc", +			}, +			.flags = { +				.cxxflags = { +					"-std=c++20", "-O3", "-Wall", "-Werror", +					"-I../src", "-Iuunit", +					"-DOUTPUT=\"argsplit\"", +				}, +			}, +		}, +		{ +			.type = ctor::target_type::unit_test, +			.system = ctor::output_system::build,  			.target = "pointerlist_test",  			.sources = {  				"pointerlist_test.cc", | 
