File: ArgumentsParser.cpp

package info (click to toggle)
dyssol 1.5.0-1.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 18,204 kB
  • sloc: cpp: 53,870; sh: 85; python: 59; makefile: 11
file content (158 lines) | stat: -rw-r--r-- 4,364 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* Copyright (c) 2021, Dyssol Development Team. All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */

#include "ArgumentsParser.h"
#include "ContainerFunctions.h"
#include "StringFunctions.h"

namespace SF = StringFunctions;

CArgumentsParser::CArgumentsParser(int _argc, const char** _argv)
	: CArgumentsParser{ _argc, _argv, {} }
{
}

CArgumentsParser::CArgumentsParser(int _argc, const char** _argv, std::vector<SKey> _allowedKeys)
	: m_allowedKeys{ std::move(_allowedKeys) }
{
	// parse all keys
	for (int i = 1; i < _argc; ++i)
		m_tokens.push_back(ParseArgument(std::string{ _argv[i] }));

	// handle allowed keys
	if (!m_allowedKeys.empty())
	{
		// remove possible signs in allowed keys
		for (auto& allowed : m_allowedKeys)
		{
			for (auto& k : allowed.keysL) k = RemoveSignL(k);
			for (auto& k : allowed.keysS) k = RemoveSignS(k);
		}
		// remove not allowed tokens
		FilterTokens();
	}
}

std::vector<CArgumentsParser::SKey> CArgumentsParser::AllAllowedKeys() const
{
	return m_allowedKeys;
}

size_t CArgumentsParser::TokensCount() const
{
	return m_tokens.size();
}

bool CArgumentsParser::HasKey(const std::string& _key) const
{
	const auto aliases = KeyAliases(_key);
	return std::any_of(aliases.begin(), aliases.end(), [&](const std::string& a)
		{ return VectorContains(m_tokens, [&](const SToken& t) { return RemoveSigns(t.key) == a; }); });
}

std::string CArgumentsParser::GetValue(const std::string& _key) const
{
	for (const auto& alias : KeyAliases(_key))
	{
		const size_t i = VectorFind(m_tokens, [&](const SToken& t) { return RemoveSigns(t.key) == alias; });
		if (i != static_cast<size_t>(-1))
			return m_tokens[i].value;
	}
	return {};
}

std::vector<std::string> CArgumentsParser::GetValues(const std::string& _key) const
{
	std::vector<std::string> res;
	for (const auto& alias : KeyAliases(_key))
		for (const auto& token : m_tokens)
			if (RemoveSigns(token.key) == alias)
				res.push_back(token.value);
	return res;
}

CArgumentsParser::SToken CArgumentsParser::ParseArgument(const std::string& _argument) const
{
	const auto parts = SF::SplitString(_argument, m_separator);
	if (parts.empty()) return {};
	// only a key or only a value
	if (parts.size() == 1)
	{
		// a key without value
		if (IsKey(parts[0]))
			return { parts[0], {} };
		// a value without key
		else
			return { {}, SF::RemoveQuotes(parts.front()) };
	}
	// key=value
	if (IsKey(parts[0]))
		return { parts[0], SF::RemoveQuotes(parts[1]) };
	// wrong format
	return {};
}

void CArgumentsParser::FilterTokens()
{
	// gather all allowed long keys
	std::vector<std::string> keysL;
	for (const auto& v : m_allowedKeys)
		keysL.insert(keysL.end(), v.keysL.begin(), v.keysL.end());
	// gather all allowed short keys
	std::vector<std::string> keysS;
	for (const auto& v : m_allowedKeys)
		keysS.insert(keysS.end(), v.keysS.begin(), v.keysS.end());

	// remove tokens with not allowed keys
	m_tokens.erase(std::remove_if(m_tokens.begin(), m_tokens.end(), [&](const SToken& t)
		{ return !VectorContains(keysL, RemoveSignL(t.key)) && !VectorContains(keysS, RemoveSignS(t.key)); }), m_tokens.end());
}

bool CArgumentsParser::IsKeyL(const std::string& _str) const
{
	return _str.rfind(m_keySignL, 0) == 0;
}

bool CArgumentsParser::IsKeyS(const std::string& _str) const
{
	return _str.rfind(m_keySignS, 0) == 0;
}

bool CArgumentsParser::IsKey(const std::string& _str) const
{
	return IsKeyL(_str) || IsKeyS(_str);
}

std::string CArgumentsParser::RemoveSignL(std::string _str) const
{
	if (IsKeyL(_str))
		_str.erase(0, m_keySignL.size());
	return _str;
}

std::string CArgumentsParser::RemoveSignS(std::string _str) const
{
	if (IsKeyS(_str))
		_str.erase(0, m_keySignS.size());
	return _str;
}

std::string CArgumentsParser::RemoveSigns(const std::string& _str) const
{
	return RemoveSignS(RemoveSignL(_str));
}

std::vector<std::string> CArgumentsParser::KeyAliases(const std::string& _key) const
{
	for (const auto& allowed : m_allowedKeys)
	{
		const auto cleanKey = RemoveSigns(_key);
		if (VectorContains(allowed.keysL, cleanKey) || VectorContains(allowed.keysS, cleanKey))
		{
			std::vector<std::string> res;
			res.insert(res.end(), allowed.keysL.begin(), allowed.keysL.end());
			res.insert(res.end(), allowed.keysS.begin(), allowed.keysS.end());
			return res;
		}
	}
	return{ _key }; // no aliases defined
}