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