changeset 119:b39573fc066e

Irccd: improve util::format to disable some features, #408
author David Demelier <markand@malikania.fr>
date Mon, 02 May 2016 13:28:28 +0200
parents 2a63c8ec45cd
children 4cb417fd4e18
files lib/irccd/util.cpp lib/irccd/util.hpp tests/util/main.cpp
diffstat 3 files changed, 89 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/lib/irccd/util.cpp	Fri Apr 29 14:19:30 2016 +0200
+++ b/lib/irccd/util.cpp	Mon May 02 13:28:28 2016 +0200
@@ -17,6 +17,7 @@
  */
 
 #include <algorithm>
+#include <cassert>
 #include <cctype>
 #include <cstdlib>
 #include <ctime>
@@ -119,41 +120,39 @@
 
 	/* @{} means reset */
 	if (list.empty()) {
-		oss << attributesTable.at("reset");
-	} else {
-		/* Remove useless spaces */
-		for (auto &a : list) {
-			a = strip(a);
+		return std::string(1, attributesTable.at("reset"));
+	}
+
+	/* Remove useless spaces */
+	std::transform(list.begin(), list.end(), list.begin(), strip);
+
+	/*
+	 * 0: foreground
+	 * 1: background
+	 * 2-n: attributes
+	 */
+	auto foreground = list[0];
+	if (!foreground.empty() || list.size() >= 2) {
+		/* Color sequence */
+		oss << '\x03';
+
+		/* Foreground */
+		auto it = colorTable.find(foreground);
+		if (it != colorTable.end()) {
+			oss << it->second;
 		}
 
-		/*
-		 * 0: foreground
-		 * 1: background
-		 * 2-n: attributes
-		 */
-		auto foreground = list[0];
-		if (!foreground.empty() || list.size() >= 2) {
-			/* Color sequence */
-			oss << '\x03';
+		/* Background */
+		if (list.size() >= 2 && (it = colorTable.find(list[1])) != colorTable.end()) {
+			oss << "," << it->second;
+		}
 
-			/* Foreground */
-			auto it = colorTable.find(foreground);
-			if (it != colorTable.end()) {
-				oss << it->second;
-			}
+		/* Attributes */
+		for (std::size_t i = 2; i < list.size(); ++i) {
+			auto attribute = attributesTable.find(list[i]);
 
-			/* Background */
-			if (list.size() >= 2 && (it = colorTable.find(list[1])) != colorTable.end()) {
-				oss << "," << it->second;
-			}
-
-			/* Attributes */
-			for (std::size_t i = 2; i < list.size(); ++i) {
-				auto attribute = attributesTable.find(list[i]);
-
-				if (attribute != attributesTable.end()) {
-					oss << attribute->second;
-				}
+			if (attribute != attributesTable.end()) {
+				oss << attribute->second;
 			}
 		}
 	}
@@ -163,6 +162,8 @@
 
 std::string substitute(std::string::const_iterator &it, std::string::const_iterator &end, char token, const Substitution &params)
 {
+	assert(isReserved(token));
+
 	std::string content, value;
 
 	if (it == end) {
@@ -173,24 +174,33 @@
 		content += *it++;
 	}
 
-	if (*it != '}' || it == end) {
+	if (it == end || *it != '}') {
 		throw std::invalid_argument("unclosed "s + token + " construct"s);
 	}
 
 	it++;
 
+	/* Create default original value if flag is disabled */
+	value = std::string(1, token) + "{"s + content + "}"s;
+
 	switch (token) {
 	case '#':
-		value = substituteKeywords(content, params);
+		if (params.flags & Substitution::Keywords) {
+			value = substituteKeywords(content, params);
+		}
 		break;
 	case '$':
-		value = substituteEnv(content);
+		if (params.flags & Substitution::Env) {
+			value = substituteEnv(content);
+		}
 		break;
 	case '@':
-		value = substituteAttributes(content);
+		if (params.flags & Substitution::IrcAttrs) {
+			substituteAttributes(content);
+		}
 		break;
 	default:
-		throw std::invalid_argument("unknown "s + token + " construct");
+		break;
 	}
 
 	return value;
@@ -204,7 +214,9 @@
 	 * Change the date format before anything else to avoid interpolation with keywords and
 	 * user input.
 	 */
-	text = substituteDate(text, params);
+	if (params.flags & Substitution::Date) {
+		text = substituteDate(text, params);
+	}
 
 	std::ostringstream oss;
 
--- a/lib/irccd/util.hpp	Fri Apr 29 14:19:30 2016 +0200
+++ b/lib/irccd/util.hpp	Mon May 02 13:28:28 2016 +0200
@@ -65,6 +65,18 @@
 class Substitution {
 public:
 	/**
+	 * \brief Disable or enable some features.
+	 */
+	enum Flags {
+		Date		= (1 << 0),	//!< date templates
+		Keywords	= (1 << 1),	//!< keywords
+		Env		= (1 << 2),	//!< environment variables
+		IrcAttrs	= (1 << 3),	//!< IRC escape codes
+	};
+
+	std::uint8_t flags{Date | Keywords | Env | IrcAttrs};
+
+	/**
 	 * Fill that field if you want a date.
 	 */
 	std::time_t time{std::time(nullptr)};
--- a/tests/util/main.cpp	Fri Apr 29 14:19:30 2016 +0200
+++ b/tests/util/main.cpp	Mon May 02 13:28:28 2016 +0200
@@ -56,6 +56,34 @@
 	ASSERT_ANY_THROW(util::format("#{failure"));
 }
 
+TEST(Format, disableDate)
+{
+	util::Substitution params;
+
+	params.flags &= ~(util::Substitution::Date);
+
+	ASSERT_EQ("%H:%M", util::format("%H:%M", params));
+}
+
+TEST(Format, disableKeywords)
+{
+	util::Substitution params;
+
+	params.keywords.emplace("target", "hello");
+	params.flags &= ~(util::Substitution::Keywords);
+
+	ASSERT_EQ("#{target}", util::format("#{target}", params));
+}
+
+TEST(Format, disableEnv)
+{
+	util::Substitution params;
+
+	params.flags &= ~(util::Substitution::Env);
+
+	ASSERT_EQ("${HOME}", util::format("${HOME}", params));
+}
+
 TEST(Format, keywordSimple)
 {
 	util::Substitution params;