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 <sstream>
22 #include <cstring>
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 
27 #include "OptionsParser.h"
28 #include "Info.h"
29 #include "Usage.h"
30 
31 using namespace std;
32 // methods for class Options
33 
Options()34 Options::Options()
35 {
36    // sets default values for attributes
37 
38    // don't follow by default
39    follow = 0;
40    // color output by default
41    color = 1;
42    // 10 rows by default
43    rows = 10;
44    // verbose by default
45    verbose = 1;
46    // no cfg files by default
47    nr_cfg_files = 0;
48    for (int i = 0 ; i < MAX_FILES ; i++)
49    {
50       cfg_filenames[i] = NULL;
51    }
52    // individual cfg files as default
53    global_cfg_file = 0;
54 
55 }
56 
~Options()57 Options::~Options()
58 {
59    // destructor, frees memory allocated for filenames
60 
61    for (int i = 0 ; i < MAX_FILES ; i++)
62    {
63       if (cfg_filenames[i])
64       {
65 	 delete[] cfg_filenames[i];
66       }
67    }
68 }
69 
70 // methods for class OptionsParser
OptionsParser()71 OptionsParser::OptionsParser()
72 {
73    // constructor
74 
75    // set default error msg
76    sprintf(m_error, "No error");
77 }
78 
~OptionsParser()79 OptionsParser::~OptionsParser()
80 {
81    // destructor
82 }
83 
parse(int argc,char ** argv)84 Options* OptionsParser::parse(int argc, char **argv)
85 {
86    // parses options and sets the attributes in the Options class
87    // which is then returned. Returns NULL on error and m_error is set
88 
89    // make Options instance
90    Options *o = new Options();
91 
92    // prevent error messages from getopt_long
93    opterr = 0;
94 
95    int c;
96    Info info;
97    Usage usage;
98 
99    while (1)
100    {
101       c = getopt_long(argc, argv, "qvn:fk:l", long_options, NULL);
102       if (c == -1)
103       {
104 	 break;
105       }
106 
107       switch (c)
108       {
109 	 case 'v':
110 	    // version
111 	    info.print();
112 	    break;
113 
114 	 case 'h':
115 	    // help
116 	    usage.print();
117 	    break;
118 
119 	 case 'f':
120 	    // follow
121 	    o->follow = 1;
122 	    break;
123 
124 	 case 'k':
125 	    // color config file
126 
127 	 {
128 
129 	    int pos = 0; // position in optarg
130 	    int loop = 1;
131 	    while (loop)
132 	    {
133 	       ostringstream filename;
134 
135 	       while (1)
136 	       {
137 		  if (optarg[pos] == ',')
138 		  {
139 		     // found seperator
140 		     // set filename in options class
141 			string str = filename.str();
142 			 char* cs = new char[str.length()+1];
143 			std::strcpy(cs, str.c_str());
144 
145 			o->cfg_filenames[o->nr_cfg_files] = cs;
146 
147 		     // increase the nr_cfg_files counter
148 		     (o->nr_cfg_files)++;
149 
150 		     // increase the position
151 		     pos++;
152 
153 		     // break the inner loop
154 		     break;
155 		  }
156 
157 		  if (optarg[pos] == '\0')
158 		  {
159 		     // found end of string
160 		     // set filename in options class
161 			string str = filename.str();
162 			 char* cs = new char[str.length()+1];
163   			 std::strcpy(cs, str.c_str());
164 
165 		     o->cfg_filenames[o->nr_cfg_files] = cs;
166 
167 		     // increase the nr_cfg_files counter
168 		     (o->nr_cfg_files)++;
169 
170 		     // check if only one cfg file
171 		     if (o->nr_cfg_files == 1)
172 		     {
173 			// only one cfg file
174 			o->global_cfg_file = 1;
175 		     }
176 
177 		     // stop the big loop
178 		     loop = 0;
179 
180 		     // break the inner loop
181 		     break;
182 		  }
183 
184 		  // insert the current character into the filename string
185 		  filename.put(optarg[pos]);
186 
187 		  // increase the position
188 		  pos++;
189 	       }
190 	    }
191 	 }
192 	 break;
193 
194 	 case 'l':
195 	    // no colors
196 	    o->color = 0;
197 	    break;
198 
199 	 case 'n':
200 	    // numberg of lines
201 
202 	    // check if only digits
203 	    if (check_digits(optarg) == 0)
204 	    {
205 	       o->rows = atoi(optarg);
206 	    }
207 	    else
208 	    {
209 	       sprintf(m_error,
210 		       "One or more non-digits were given as number of rows");
211 	       // free memory for options class
212 	       delete o;
213 	       // return NULL to show that an error occured
214 	       return NULL;
215 	    }
216 	    break;
217 
218 	 case 'q':
219 	    // quiet mode
220 	    o->verbose = 0;
221 	    break;
222 
223 	 case '?':
224 	    // unrecognized option
225 
226 	    // TODO: fix to handle -45 that means -n 45
227 
228 	    cout << "colortail: invalid option -- " << (char)c << endl;
229 	    cout << "Try 'colortail --help' for more information." << endl;
230 
231 	    break;
232 
233 	 default:
234 
235 	    cout << "Unrecognized option " << (char)c << endl;
236 
237 	    // print usage
238 	    usage.print();
239 	    break;
240       }
241    }
242 
243    return o;
244 }
245 
246 
check_digits(char * str)247 int OptionsParser::check_digits(char *str)
248 {
249    // checks if str only contains digits
250 
251    int i = 0, len = strlen(str);
252 
253    for (i = 0 ; i < len ; i++)
254    {
255       if (str[i] < '0' || str[i] > '9')
256       {
257 	 // not a digit
258 	 return 1;
259       }
260    }
261    return 0;
262 }
263 
get_error_msg()264 char* OptionsParser::get_error_msg()
265 {
266    // returns the current set error msg
267 
268    return m_error;
269 }
270 
271 
272 
273 
274 
275 
276