1 /*
2 colortail -- output last part of file(s) in color.
3 Copyright (C) 2009 Joakim Andersson <ja@joakimandersson.se>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "Colorizer.h"
21 #include "CfgFileParser.h"
22 #include "TailFile.h"
23
24 #include <assert.h>
25 #include <iostream>
26 #include <string.h>
27
28 using namespace std;
29
Colorizer()30 Colorizer::Colorizer()
31 {
32 // default constructor
33
34 m_items_list = NULL;
35 }
36
free_items()37 void Colorizer::free_items()
38 {
39 // frees the memory that the items uses
40
41 // check if there is a list
42 if (m_items_list)
43 {
44 SearchData *tmp;
45
46 // go through all the elements in the list,
47 // and free each SearchData instance
48 while (!m_items_list->is_empty())
49 {
50 tmp = m_items_list->first_element();
51 m_items_list->remove_first();
52 delete tmp;
53 }
54
55 // delete the list
56 delete m_items_list;
57 m_items_list = NULL;
58 }
59 }
60
61
Colorizer(const char * cfg_file)62 Colorizer::Colorizer(const char *cfg_file)
63 {
64 // other constructor
65
66 // sends the cfg_file to the CfgFileParser
67 // gets the items_list from the CfgFileParser and saves it
68
69 // check that cfg_file isn't NULL
70 assert (cfg_file != NULL);
71
72 CfgFileParser parser;
73
74 // parse the cfg file
75 int n = parser.parse(cfg_file);
76
77 // get the items list
78 m_items_list = parser.get_items_list();
79 }
80
~Colorizer()81 Colorizer::~Colorizer()
82 {
83 // destructor
84
85 // free the memory the search data items use
86 free_items();
87 }
88
colorize(const char * str)89 string Colorizer::colorize(const char *str)
90 {
91 // colorize the string, returns a new string containing
92 // the colorized version of str
93 // RETURN: new string with result
94
95 // check that a list exists
96 assert (m_items_list != NULL);
97
98 regmatch_t pmatch[10];
99 int found = 0, submatch = 0, j;
100 char color[MAX_CHARS_READ][20];
101
102 // set all the color strings to empty strings
103 for (int f = 0 ; f < MAX_CHARS_READ ; f++)
104 {
105 color[f][0] = '\0';
106 }
107
108 // make an iterator
109 ListIterator<SearchData*> itr(*m_items_list);
110
111 // will contain the new string
112 ostringstream newstr;
113
114 SearchData *current;
115 int i = 0;
116 // go through all the elements in the list
117 for (itr.init() ; !itr ; ++itr, i++)
118 {
119 current = itr();
120
121 // check for match
122 if (regexec(current->m_preg, str, 10, pmatch, 0) == 0)
123 {
124 // TODO: check for callback function
125 // TODO: call callback function
126
127 found = 1;
128
129 // Check to see if this is a substring match
130 if (pmatch[1].rm_so != -1)
131 {
132 submatch = 1;
133 // Note: start at offset 1 to get only submatches
134
135 for (j = 1 ; pmatch[j].rm_so != -1 && j <= 10 ; j++)
136 {
137 // go through all the character positions
138 // that the submatch is for
139 for (int k = pmatch[j].rm_so ; k < (pmatch[j].rm_eo) ; k++)
140 {
141
142 // set the color in the color string array
143 strcpy(color[k], current->m_ansi_color_code);
144 }
145 }
146 }
147 else
148 {
149 // not a substring match, colorize whole string.
150 // stop looking for other matches as well
151
152 submatch = 0;
153
154 // write ansi color code
155 newstr << current->m_ansi_color_code;
156
157 // check if str ends in '\n'
158 int len = strlen(str);
159 if (str[len-1] == '\n')
160 {
161 for (int a = 0 ; a < len-1 ; a++)
162 {
163 newstr.put(str[a]);
164 }
165 }
166 else
167 {
168 // doesn't end in '\n'
169 newstr << str;
170 }
171
172 // write ansi reset str and a newline
173 newstr << ANSI_RESET_STR << endl << ends;
174 // return the new string
175 return newstr.str();
176 }
177 }
178 }
179
180 // did we get a match
181 if (found == 0)
182 {
183 // no we didn't
184 // print without color
185 // check if str ends in '\n'
186 if (str[strlen(str)-1] == '\n')
187 {
188 newstr << str << ends;
189 }
190 else
191 {
192 // doesn't end in '\n'
193 newstr << str << endl << ends;
194 }
195
196 // return the new string
197 return newstr.str();
198 }
199
200 // did we find submatches?
201 if (submatch == 1)
202 {
203 int last_was_reset_str = 1;
204 // iiterate through all the characters
205 int l = strlen(str);
206 for (i = 0 ; i < l ; i++)
207 {
208 if (color[i][0] == '\0')
209 {
210 // no color for this position
211 if (last_was_reset_str != 1)
212 {
213 // write reset string
214 newstr << ANSI_RESET_STR;
215 // remeber that we wrote it
216 last_was_reset_str = 1;
217 }
218 }
219 else
220 {
221 // a color for this position
222 // reset ansi reset string checker
223 last_was_reset_str = 0;
224 // write color
225 newstr << color[i];
226 }
227
228 // write current character
229 newstr.put(str[i]);
230 }
231
232 // check if last wasn't the ansi reset string
233 if (last_was_reset_str != 1)
234 {
235 // write reset string
236 newstr << ANSI_RESET_STR;
237 }
238
239 // write newline and null
240 //newstr << endl << ends;
241 newstr << ends;
242
243 return newstr.str();
244
245 }
246
247
248 // should never get here
249 string empty = "";
250 return empty;
251 }
252