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 "CfgFileParser.h"
21
22 #include <iostream>
23 #include <assert.h>
24 #include <cstring>
25 #include <stdlib.h>
26
27 using namespace std;
28
29 // ## class SearchData ##
30
SearchData()31 SearchData::SearchData()
32 {
33 // default constructor
34 m_preg = NULL;
35 m_ansi_color_code = NULL;
36 m_pf = NULL;
37 m_param_to_callback_fkn = NULL;
38 }
39
~SearchData()40 SearchData::~SearchData()
41 {
42 if (m_preg)
43 {
44 // is allocated with malloc
45 free(m_preg);
46 }
47
48 if (m_ansi_color_code)
49 {
50 delete m_ansi_color_code;
51 }
52
53 if (m_param_to_callback_fkn)
54 {
55 delete m_param_to_callback_fkn;
56 }
57 }
58
set_color(char * color)59 void SearchData::set_color(char *color)
60 {
61 // allocates memory and sets the m_ansi_color_code string to color
62
63 if (m_ansi_color_code)
64 {
65 delete m_ansi_color_code;
66 }
67
68 m_ansi_color_code = new char[strlen(color)+1];
69 strcpy(m_ansi_color_code, color);
70 }
71
CfgFileParser()72 CfgFileParser::CfgFileParser()
73 {
74 m_items_list = NULL;
75 m_filename = NULL;
76 m_line = 0;
77 }
78
~CfgFileParser()79 CfgFileParser::~CfgFileParser()
80 {
81 free_items();
82 if (m_filename)
83 {
84 delete m_filename;
85 }
86 }
87
free_items()88 void CfgFileParser::free_items()
89 {
90 // frees the memory that the items uses
91
92 // check if there is a list
93 if (m_items_list)
94 {
95 SearchData *tmp;
96
97 // go through all the elements in the list,
98 // and free each SearchData instance
99 while (!m_items_list->is_empty())
100 {
101 tmp = m_items_list->first_element();
102 m_items_list->remove_first();
103 delete tmp;
104 }
105
106 // delete the list
107 delete m_items_list;
108 m_items_list = NULL;
109 }
110 }
111
read_line()112 char* CfgFileParser::read_line()
113 {
114 // reads the next line from the file and increases the line counter
115 // prints error message if no characters were read.
116 // returns: string or NULL if error.
117
118 char *str = new char[MAX_CFG_LINE_LENGTH];
119 assert (str != NULL);
120
121 // read next line
122 m_infile.getline(str, MAX_CFG_LINE_LENGTH);
123
124 // increase line counter
125 m_line++;
126
127 // read less than zero chars?
128 if (m_infile.gcount() <= 0)
129 {
130 // found EOF
131 delete str;
132 return NULL;
133 }
134
135 return str;
136 }
137
read_item()138 int CfgFileParser::read_item()
139 {
140 // reads the color for the reg exps, then eads the reg exps and makes
141 // SearchData instances for them and adds to the m_items_list
142 // only reads and processes ONE item
143 // returns number of SearchData instances added to the list
144
145 int nr_items_added = 0;
146
147 // is there a list?
148 assert (m_items_list != NULL);
149
150 // is there a open file?
151 assert (m_infile);
152
153 // read color
154 char *color = read_color();
155
156 if (color == NULL)
157 {
158 // didn't get a color
159
160 // quit, return 0
161 return 0;
162 }
163
164 // TODO: add action reading
165 // read action
166
167 if (read_left() == 0)
168 {
169 // found '{'
170
171 // loop until '}'
172 while (1)
173 {
174 // read string
175 char *regexp = read_regexp();
176 if (regexp)
177 {
178 // check if it's a '}'
179 if (regexp[0] == '}')
180 {
181 // free mem
182 delete regexp;
183 // stop looping
184 break;
185 }
186
187 // has a regexp.. make a SearchData item
188
189 SearchData *searchdata = new SearchData();
190 // check allocation
191 assert (searchdata != NULL);
192
193 // set color
194 searchdata->set_color(color);
195
196 // allocate memory to the pattern storage buffer
197 searchdata->m_preg = (regex_t*) malloc(sizeof(regex_t));
198 // check allocation
199 assert (searchdata->m_preg != NULL);
200
201 // make compiled pattern buffer
202 if (regcomp(searchdata->m_preg, regexp, REG_EXTENDED) != 0)
203 {
204 // failed to make compiled reg exp pattern
205 cout << "colortail: Failed to make compiled reg exp pattern for "
206 << "reg exp in config file " << m_filename << " at line "
207 << m_line << ". Skipping this line." << endl;
208
209 // free mem
210 delete searchdata;
211 }
212 else
213 {
214 // TODO: set callback fkn
215 // TODO: set param to callback fkn
216
217 // add the search data item to the items list
218 m_items_list->add(searchdata);
219 // increase items added counter
220 nr_items_added++;
221 }
222 // free mem
223 delete regexp;
224 }
225 else
226 {
227 // error reading string, eof maybe..
228 // stop looping
229 break;
230 }
231 }
232 }
233 return nr_items_added;
234 }
235
read_color()236 char* CfgFileParser::read_color()
237 {
238 // reads and skips lines until a 'COLOR' statement is found,
239 // it then extracts the color after 'COLOR' and returns a new string
240 // containing the ANSI color code for that string.
241 // RETURNS: the new string, NULL on error.
242
243 // is there a open file?
244 assert (m_infile);
245
246 while (1)
247 {
248 // read line
249 char *tmp = read_line();
250 if (!tmp)
251 {
252 // found EOF
253 return NULL;
254 }
255
256 // got a line to look at
257
258 // process line if it's not empty or doesn't starts with a '#'
259 if (tmp[0] != '\0' && tmp[0] != '#')
260 {
261 if (strncmp(tmp, "COLOR", 5) != 0)
262 {
263 cout << "colortail: Error in config file: " << m_filename
264 << " at line " << m_line << ". Skipping this line." << endl;
265 }
266 else
267 {
268 int linepos = 5;
269 char *color = new char[20];
270
271 // skip all spaces
272 while (tmp[linepos] == ' ')
273 {
274 linepos++;
275 }
276
277 // read which color it is
278 int found_color = 0;
279
280 if (strncmp(&tmp[linepos], "black", 5) == 0) {
281 strcpy(color, BLACK);
282 found_color = 1;
283 }
284
285 if (strncmp(&tmp[linepos], "red", 3) == 0) {
286 strcpy(color, RED);
287 found_color = 1;
288 }
289
290 if (strncmp(&tmp[linepos], "green", 5) == 0) {
291 strcpy(color, GREEN);
292 found_color = 1;
293 }
294
295 if (strncmp(&tmp[linepos], "yellow", 6) == 0) {
296 strcpy(color, YELLOW);
297 found_color = 1;
298 }
299
300 if (strncmp(&tmp[linepos], "blue", 4) == 0) {
301 strcpy(color, BLUE);
302 found_color = 1;
303 }
304
305 if (strncmp(&tmp[linepos], "magenta", 7) == 0) {
306 strcpy(color, MAGENTA);
307 found_color = 1;
308 }
309
310 if (strncmp(&tmp[linepos], "cyan", 4) == 0) {
311 strcpy(color, CYAN);
312 found_color = 1;
313 }
314
315 if (strncmp(&tmp[linepos], "white", 6) == 0) {
316 strcpy(color, WHITE);
317 found_color = 1;
318 }
319
320 if (strncmp(&tmp[linepos], "brightblack", 6+5) == 0) {
321 strcpy(color, BRIGHTBLACK);
322 found_color = 1;
323 }
324
325 if (strncmp(&tmp[linepos], "brightred", 6+3) == 0) {
326 strcpy(color, BRIGHTRED);
327 found_color = 1;
328 }
329
330 if (strncmp(&tmp[linepos], "brightgreen", 6+5) == 0) {
331 strcpy(color, BRIGHTGREEN);
332 found_color = 1;
333 }
334
335 if (strncmp(&tmp[linepos], "brightyellow", 6+6) == 0) {
336 strcpy(color, BRIGHTYELLOW);
337 found_color = 1;
338 }
339
340 if (strncmp(&tmp[linepos], "brightblue", 6+4) == 0) {
341 strcpy(color, BRIGHTBLUE);
342 found_color = 1;
343 }
344
345 if (strncmp(&tmp[linepos], "brightmagenta", 6+7) == 0) {
346 strcpy(color, BRIGHTMAGENTA);
347 found_color = 1;
348 }
349
350 if (strncmp(&tmp[linepos], "brightcyan", 6+4) == 0) {
351 strcpy(color, BRIGHTCYAN);
352 found_color = 1;
353 }
354
355 if (strncmp(&tmp[linepos], "brightwhite", 6+5) == 0) {
356 strcpy(color, BRIGHTWHITE);
357 found_color = 1;
358 }
359
360 if (found_color == 0)
361 {
362 // didn't found color
363 cout << "colortail: Don't recognize color in config file: "
364 << m_filename << " at line " << m_line << endl;
365
366 // free mem
367 delete tmp;
368 delete color;
369 // error, return NULL
370 return NULL;
371 }
372 else
373 {
374 // free mem
375 delete tmp;
376 // found color
377 return color;
378 }
379 }
380 // free memory for read line
381 delete tmp;
382 }
383 }
384 // should never execute this
385 return NULL;
386 }
387
read_left()388 int CfgFileParser::read_left()
389 {
390 // reads lines (skips empty and comments lines) until a '{' is found
391 // RETURNS: 0 if a '{' is found, 1 if not found, 2 if error
392
393 // is there a open file?
394 assert (m_infile);
395
396 while (1)
397 {
398 // read line
399 char *tmp = read_line();
400 if (!tmp)
401 {
402 // error reading line
403 cout << "colortail: Error reading line in config file: "
404 << m_filename << " at line " << m_line << "." << endl;
405 // error, return 2
406 return 2;
407 }
408
409 // got a line to look at
410
411 // process line if it's not empty or doesn't starts with a '#'
412 if (tmp[0] != '\n' && tmp[0] != '#')
413 {
414 if (tmp[0] == '{')
415 {
416 // free mem
417 delete tmp;
418
419 return 0;
420 }
421 else
422 {
423 // not a '{'
424 cout << "colortail: Error, expected '{' but found '"
425 << tmp[0] << "' in config file: " << m_filename
426 << " at line " << m_line << "." << endl;
427 // free mem
428 delete tmp;
429
430 return 1;
431 }
432 }
433
434 // free mem
435 delete tmp;
436 }
437
438 // should never get this far
439 return 1;
440 }
441
read_regexp()442 char* CfgFileParser::read_regexp()
443 {
444 // reads and skips empty and comments lines until a regexp is found
445 // RETURNS: a new string containing the reg exp, NULL on error
446
447 // is there a open file?
448 assert (m_infile);
449
450 while (1)
451 {
452 // read line
453 char *tmp = read_line();
454
455 if (!tmp)
456 {
457 // error reading line
458 cout << "colortail: Error reading line in config file: "
459 << m_filename << " at line " << m_line << "." << endl;
460
461 // error, return NULL
462 return NULL;
463 }
464
465 // got a line
466
467 // process line if it's not empty or doesn't starts with a '#'
468 if (tmp[0] != '\n' && tmp[0] != '#')
469 {
470 // found a string, return it
471 return tmp;
472 }
473
474 // this is a empty line or a comment, skip it
475
476 // free mem
477 delete tmp;
478 }
479
480 // should never get this far
481 return NULL;
482 }
483
484
parse(const char * filename)485 int CfgFileParser::parse(const char *filename)
486 {
487 // parses the cfg file and sets up the list of SearchData elements
488 // returns number of SearchData items created
489
490 // is there a list?
491 if (m_items_list)
492 {
493 // delete it
494 free_items();
495 }
496
497 // make a new list
498 m_items_list = new List<SearchData*>;
499
500 // check the allocation
501 assert (m_items_list != NULL);
502
503 // try to open the file
504 m_infile.open(filename, ios::in);
505
506 if (!m_infile)
507 {
508 // open failed
509 cout << "colortail: Failed to open config file: " << filename << endl;
510 return 0;
511 }
512
513 // save filename of config file
514 if (m_filename)
515 {
516 delete m_filename;
517 }
518
519 m_filename = new char[strlen(filename) + 1];
520 strcpy(m_filename, filename);
521
522
523 int items_counter = 0;
524
525 // read the items
526 while (!m_infile.eof())
527 {
528 // read in a item
529 int n = read_item();
530
531 items_counter += n;
532 }
533
534 return items_counter;
535 }
536
get_items_list()537 List<SearchData*>* CfgFileParser::get_items_list()
538 {
539 // returns the items list, and sets this class item list to NULL
540
541 List<SearchData*>* tmp = m_items_list;
542 m_items_list = NULL;
543
544 return tmp;
545 }
546
547
548
549
550
551
552
553
554