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 <iostream>
21 #include <assert.h>
22 #include <unistd.h>
23 
24 #include "ColorTail.h"
25 #include "TailFile.h"
26 #include "OptionsParser.h"
27 #include "Colorizer.h"
28 
29 using namespace std;
30 
31 // the constructor
ColorTail()32 ColorTail::ColorTail()
33 {
34    // nothing yet
35 }
36 
37 // the destructor
~ColorTail()38 ColorTail::~ColorTail()
39 {
40    // free the memory for the TailFile objects in the list
41    free_list_items();
42 }
43 
free_list_items()44 void ColorTail::free_list_items()
45 {
46    // removes all the elements from the list and frees the memory the objects
47    // uses
48 
49    TailFile *tmp;
50 
51    // go through all the elements in the list,
52    // and free each TailFile object
53    while (!m_tailfiles.is_empty())
54    {
55       tmp = m_tailfiles.first_element();
56       m_tailfiles.remove_first();
57       delete tmp;
58    }
59 }
60 
61 // the starting method
start(int argc,char ** argv)62 int ColorTail::start(int argc, char **argv)
63 {
64    // parse options
65    OptionsParser optParser;
66    Options *options = optParser.parse(argc, argv);
67 
68    assert (options != NULL);
69 
70    // the options has been stripped from argc and argv, just the
71    // files to tail and the program namn left
72 
73    // tailfile counter
74    int tailfile_counter = 0;
75 
76    // iterate through all the files to tail
77    for (int i = optind ; i < argc ; i++)
78    {
79       // new TailFile object
80       TailFile *new_tailfile = new TailFile();
81 
82       Colorizer *colorizer = NULL;
83 
84       // check if colors
85       if (options->color)
86       {
87 	 // color output
88 	 // check if global config file
89 	 if (options->global_cfg_file)
90 	 {
91 	    // global config file
92 	    // check if there is a config file
93 	    if (options->nr_cfg_files > 0)
94 	    {
95 	       // yes there is a first config file
96 	       colorizer = new Colorizer(options->cfg_filenames[0]);
97 
98 	       // open the tailfile
99 	       new_tailfile->open(argv[i], colorizer);
100 	    }
101 	    else
102 	    {
103 	       // no config file
104 	       // print error
105 	       cout << "colortail: Couldn't open global color config file. Skipping colors for the " << argv[i] << " file." << endl;
106                // open the tailfile without colorizer
107 	       new_tailfile->open(argv[i], NULL);
108 	    }
109 	 }
110 	 else
111 	 {
112 	    // individual config files
113 	    // check if there is a config file
114 	    if (options->nr_cfg_files > tailfile_counter
115 		&& options->cfg_filenames[tailfile_counter] != NULL)
116 	    {
117 	       // there is a config file
118 	       colorizer = new Colorizer
119 		  (options->cfg_filenames[tailfile_counter]);
120 
121 	       // open the tailfile
122 	       new_tailfile->open(argv[i], colorizer);
123 	    }
124 	    else
125 	    {
126 	       // no config file
127 	       // no error message because it can be cfgfile1,,cfgfile2
128 	       // open the tailfile without colorizer
129 	       new_tailfile->open(argv[i], NULL);
130 	    }
131 	 }
132       }
133       else
134       {
135 	 // no colors
136 
137 	 // open the tailfile without colorizer
138 	 new_tailfile->open(argv[i], NULL);
139       }
140 
141       // add the tailfile to the end of the tailfile list
142       m_tailfiles.add_last(new_tailfile);
143 
144       // increase the tailfile counter
145       tailfile_counter++;
146    }
147 
148    // check if not follow-mode
149    if (options->follow == 0)
150    {
151       // not follow-mode, just print the tails of the files in the list
152 
153       // make an iterator
154       ListIterator<TailFile*> itr(m_tailfiles);
155       TailFile *current_file;
156 
157       // iterate through the file list
158       for (itr.init() ; !itr ; ++itr)
159       {
160 	 current_file = itr();
161 
162 	 // check if verbose mode
163 	 if (options->verbose)
164 	 {
165 	    // print filename
166 	    current_file->printFilename();
167 	 }
168 
169 	 // print the specified number of rows
170 	 current_file->print(options->rows);
171       }
172    }
173    else
174    {
175       // follow mode
176 
177       // make an iterator
178       ListIterator<TailFile*> itr(m_tailfiles);
179       TailFile *current_file;
180 
181       // iterate through the file list and print the no of rows wanted
182       for (itr.init() ; !itr ; ++itr)
183       {
184 	 current_file = itr();
185 
186 	 // check if more than zero rows
187 	 if (options->rows > 0)
188 	 {
189 	    // check if verbose mode
190 	    if (options->verbose)
191 	    {
192 	       // print filename
193 	       current_file->printFilename();
194 	    }
195 	 }
196 
197 	 // print the specified number of rows
198 	 current_file->print(options->rows);
199       }
200 
201       // the "forever" part
202 
203       // keeps track of the last file a line was printed from
204       char *last_filename = NULL;
205       int changed = 0;
206       while (1)
207       {
208 	 // iterate through the file list and check if the
209 	 // file size has changed.
210 
211 	 for (itr.init() ; !itr ; ++itr)
212 	 {
213 	    current_file = itr();
214 
215 	    int n = current_file->more_to_read();
216 	    if (n != 0)
217 	    {
218 	       // file size has changed
219 	       // print the change, if there is a '\n'
220 	       current_file->follow_print(n, options->verbose,last_filename);
221 
222 	       // get the filename of this file
223 	       last_filename = current_file->get_filename();
224 
225 	       // set the changed boolean
226 	       changed = 1;
227 	    }
228 	 }
229 
230 	 // check if changed
231 	 if (changed)
232 	 {
233 	    // something changed
234 
235 	    // clear the flag
236 	    changed = 0;
237 	 }
238 	 else
239 	 {
240 	    // nothing changed
241 
242 	    // sleep one second
243 	    sleep(1);
244 	 }
245       }
246    }
247    return 0;
248 }
249