summaryrefslogtreecommitdiff
path: root/src/regexmanager.cpp
blob: e9559039f0f6f6ad2f94cc9a70f1892628c2e3e5 (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <regexmanager.h>
#include <logger.h>
#include <utils.h>
#include <cstring>
#include <exceptions.h>
#include <config.h>

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;
			}
		}
	}
}

void regexmanager::dump_config(std::vector<std::string>& config_output) {
	for (std::vector<std::string>::iterator it=cheat_store_for_dump_config.begin();it!=cheat_store_for_dump_config.end();it++) {
		config_output.push_back(*it);
	}
}

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

		std::string location = params[0];
		if (location != "all" && location != "article" && location != "articlelist" && location != "feedlist")
			throw confighandlerexception(utils::strprintf(_("`%s' is an invalid dialog type"), location.c_str()));

		regex_t * rx = new regex_t;
		int err;
		if ((err = regcomp(rx, params[1].c_str(), REG_EXTENDED | REG_ICASE)) != 0) {
			delete rx;
			char buf[1024];
			regerror(err, rx, buf, sizeof(buf));
			throw confighandlerexception(utils::strprintf(_("`%s' is not a valid regular expression: %s"), params[1].c_str(), buf));
		}
		std::string colorstr;
		if (params[2] != "default") {
			colorstr.append("fg=");
			if (!utils::is_valid_color(params[2]))
				throw confighandlerexception(utils::strprintf(_("`%s' is not a valid color"), params[2].c_str()));
			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]))
					throw confighandlerexception(utils::strprintf(_("`%s' is not a valid color"), params[3].c_str()));
				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]))
						throw confighandlerexception(utils::strprintf(_("`%s' is not a valid attribute"), params[i].c_str()));
					colorstr.append(params[i]);
				}
			}
		}
		if (location != "all") {
			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++) {
				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);
			}
		}
		std::string line = "highlight";
		for (std::vector<std::string>::const_iterator it=params.begin();it!=params.end();it++) {
			line.append(" ");
			line.append(utils::quote(*it));
		}
		cheat_store_for_dump_config.push_back(line);
	} else
		throw confighandlerexception(AHS_INVALID_COMMAND);
}

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

	std::vector<regex_t *>::iterator it=regexes.begin();
	for (unsigned int i=0;i<regexes.size()-1;i++) {
		it++;
	}
	delete *it;
	regexes.erase(it);
}



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

	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) {
			// 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, "</>");
			// LOG(LOG_DEBUG, "after first insert: %s", str.c_str());
			str.insert(offset + pmatch.rm_so, marker);
			// 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);
		}
	}
}

}