summaryrefslogtreecommitdiff
path: root/src/regexmanager.cpp
blob: 299264d22c0cb7f41496c1949f9e2363aa53b14f (plain) (blame)
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
#include <regexmanager.h>
#include <logger.h>
#include <utils.h>
#include <cstring>

namespace newsbeuter {

regexmanager::regexmanager() {
	// this creates the entries in the map. we need them there to have the "all" location work.
	locations["article"];
	locations["articlelist"];
	locations["feedlist"];
}

regexmanager::~regexmanager() {
	for (std::map<std::string, rc_pair>::iterator jt=locations.begin();jt!=locations.end();jt++) {
		std::vector<regex_t *>& regexes(jt->second.first);
		if (regexes.size() > 0) {
			for (std::vector<regex_t *>::iterator it=regexes.begin();it!=regexes.end();++it) {
				delete *it;
			}
		}
	}
}

action_handler_status regexmanager::handle_action(const std::string& action, const std::vector<std::string>& params) {
	if (action == "highlight") {
		if (params.size() < 3)
			return AHS_TOO_FEW_PARAMS;

		std::string location = params[0];
		if (location != "all" && location != "article" && location != "articlelist" && location != "feedlist")
			return AHS_INVALID_PARAMS;

		regex_t * rx = new regex_t;
		if (regcomp(rx, params[1].c_str(), REG_EXTENDED | REG_ICASE) != 0) {
			delete rx;
			return AHS_INVALID_PARAMS;
		}
		std::string colorstr;
		if (params[2] != "default") {
			colorstr.append("fg=");
			if (!utils::is_valid_color(params[2]))
				return AHS_INVALID_PARAMS;
			colorstr.append(params[2]);
		}
		if (params.size() > 2) {
			if (params[3] != "default") {
				if (colorstr.length() > 0)
					colorstr.append(",");
				colorstr.append("bg=");
				if (!utils::is_valid_color(params[3]))
					return AHS_INVALID_PARAMS;
				colorstr.append(params[3]);
			}
			for (unsigned int i=4;i<params.size();++i) {
				if (params[i] != "default") {
					if (colorstr.length() > 0)
						colorstr.append(",");
					colorstr.append("attr=");
					if (!utils::is_valid_attribute(params[i]))
						return AHS_INVALID_PARAMS;
					colorstr.append(params[i]);
				}
			}
		}
		if (location != "all") {
			GetLogger().log(LOG_DEBUG, "regexmanager::handle_action: adding rx = %s colorstr = %s to location %s",
				params[1].c_str(), colorstr.c_str(), location.c_str());
			locations[location].first.push_back(rx);
			locations[location].second.push_back(colorstr);
		} else {
			delete rx;
			for (std::map<std::string, rc_pair>::iterator it=locations.begin();it!=locations.end();it++) {
				GetLogger().log(LOG_DEBUG, "regexmanager::handle_action: adding rx = %s colorstr = %s to location %s",
					params[1].c_str(), colorstr.c_str(), it->first.c_str());
				rx = new regex_t;
 				// we need to create a new one for each push_back, otherwise we'd have double frees.
				regcomp(rx, params[1].c_str(), REG_EXTENDED | REG_ICASE);
				it->second.first.push_back(rx);
				it->second.second.push_back(colorstr);
			}
		}
		return AHS_OK;
	} else
		return AHS_INVALID_COMMAND;
}

void regexmanager::quote_and_highlight(std::string& str, const std::string& location) {
	std::vector<regex_t *>& regexes = locations[location].first;

	unsigned int len = str.length();
	for (unsigned int i=0;i<len;++i) {
		if (str[i] == '<') {
			str.insert(i+1, ">");
			++len;
		}
	}
	unsigned int i = 0;
	for (std::vector<regex_t *>::iterator it=regexes.begin();it!=regexes.end();++it, ++i) {
		regmatch_t pmatch;
		unsigned int offset = 0;
		int err = regexec(*it, str.c_str(), 1, &pmatch, 0);
		while (err == 0) {
			// GetLogger().log(LOG_DEBUG, "regexmanager::quote_and_highlight: matched %s rm_so = %u rm_eo = %u", str.c_str() + offset, pmatch.rm_so, pmatch.rm_eo);
			std::string marker = utils::strprintf("<%u>", i);
			str.insert(offset + pmatch.rm_eo, "</>");
			// GetLogger().log(LOG_DEBUG, "after first insert: %s", str.c_str());
			str.insert(offset + pmatch.rm_so, marker);
			// GetLogger().log(LOG_DEBUG, "after second insert: %s", str.c_str());
			offset += pmatch.rm_eo + marker.length() + strlen("</>");
			err = regexec(*it, str.c_str() + offset, 1, &pmatch, 0);
		}
	}
}

}