Bug Summary

File:createcats.c
Location:line 183, column 6
Description:Null pointer passed as an argument to a 'nonnull' parameter

Annotated Source Code

1/* -*- c++ -*-
2Copyright (C) 2004-2013 Christian Wieninger
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
18
19The author can be reached at cwieninger@gmx.de
20
21The project's page is at http://winni.vdr-developer.org/epgsearch
22*/
23
24#include <stdio.h>
25#include <string.h>
26#include <ctype.h>
27#include <stdlib.h>
28#include <getopt.h>
29
30#define MINAPPEARANCE100 100 // the minimum appearance of a category
31#define MAXVALUES60 60 // the maximum of values for a category
32#define MAXNAMELENGTH30 30 // the maximum length of a category name or value
33
34
35// some helping stuff copied from VDR sources
36#define KILOBYTE(n)((n) * 1024) ((n) * 1024)
37#define MAXPARSEBUFFER((10) * 1024) KILOBYTE(10)((10) * 1024)
38
39#ifdef __FreeBSD__
40#ifdef isnumber
41#undef isnumber
42#endif
43#endif
44
45bool isnumber(const char *s)
46{
47 if (!*s)
48 return false;
49 while (*s) {
50 if (!isdigit(*s))
51 return false;
52 s++;
53 }
54 return true;
55}
56
57// --- cReadLine -------------------------------------------------------------
58class cReadLine {
59 private:
60 char buffer[MAXPARSEBUFFER((10) * 1024)];
61 public:
62 cReadLine() { buffer[0]=0; }
63 char *Read(FILE *f);
64};
65
66char *cReadLine::Read(FILE *f)
67{
68 if (fgets(buffer, sizeof(buffer), f) > 0) {
69 int l = strlen(buffer) - 1;
70 if (l >= 0 && buffer[l] == '\n')
71 buffer[l] = 0;
72 return buffer;
73 }
74 return NULL__null;
75}
76
77char *skipspace(const char *s)
78{
79 while (*s && isspace(*s))
80 s++;
81 return (char *)s;
82}
83
84int comparevalue( const void *arg1, const void *arg2 )
85{
86 char* value1 = *(char**) arg1;
87 char* value2 = *(char**) arg2;
88 return strcmp(value1, value2);
89}
90
91// --- cCat -------------------------------------------------------------
92class cCat {
93 public:
94 int appeared;
95 char name[MAXPARSEBUFFER((10) * 1024)];
96 int numvalues;
97 char** values;
98
99 cCat(char* n)
100 :appeared(0), numvalues(0), values(NULL__null)
101 {
102 strcpy(name, n);
103 }
104 void addvalue(char* value)
105 {
106 if (valueexists(value))
107 return;
108 char* newvalue = (char*) malloc(sizeof(char) * (strlen(value)+1));
109 strcpy(newvalue, value);
110 char **tmp = (char**) realloc(values, sizeof(char*)*(numvalues+1));
111 if (tmp) {
112 values=tmp;
113 values[numvalues++] = newvalue;
114 } else {
115 free(newvalue);
116 }
117 }
118 bool valueexists(char* value)
119 {
120 for(int i=0; i<numvalues; i++)
121 if (strcmp(values[i], value) == 0)
122 return true;
123 return false;
124 }
125 void sort()
126 {
127 qsort(values, numvalues, sizeof(char*), comparevalue );
128 }
129};
130
131int comparecat( const void *arg1, const void *arg2 )
132{
133 cCat* cat1 = *(cCat**) arg1;
134 cCat* cat2 = *(cCat**) arg2;
135 if (cat1->appeared == cat2->appeared) return 0;
136 if (cat1->appeared < cat2->appeared) return 1; else return -1;
137}
138
139// --- cCats -------------------------------------------------------------
140class cCats {
141 private:
142 int numcats;
143 cCat** cats;
144 public:
145 cCats():numcats(0), cats(NULL__null) {}
2
Null pointer value stored to 'catlist.cats'
146
147 int num() {return numcats;}
148
149 cCat* add(char* name)
150 {
151 cCat* newCat = new cCat(name);
152 cCat **tmp = (cCat**) realloc(cats, sizeof(cCat*)*(numcats+1));
153 if (tmp)
154 {
155 cats=tmp;
156 cats[numcats++] = newCat;
157 return newCat;
158 } else {
159 delete newCat;
160 return NULL__null;
161 }
162 }
163
164 cCat* get(int i)
165 {
166 if (i>=0 && i<numcats)
167 return cats[i];
168 else
169 return NULL__null;
170 }
171
172 cCat* exists(char* name)
173 {
174 for(int i=0; i<numcats; i++)
175 if (strcmp(cats[i]->name, name) == 0)
176 return cats[i];
177 return NULL__null;
178 }
179 void sort()
180 {
181 for(int i=0; i<numcats; i++)
10
Loop condition is false. Execution continues on line 183
182 cats[i]->sort();
183 qsort(cats, numcats, sizeof( cCat* ), comparecat );
11
Null pointer passed as an argument to a 'nonnull' parameter
184 }
185};
186
187int main(int argc, char *argv[])
188{
189 FILE* f = NULL__null;
190 cCats catlist;
1
Calling default constructor for 'cCats'
3
Returning from default constructor for 'cCats'
191 unsigned int minappearance = MINAPPEARANCE100;
192 unsigned int maxvalues = MAXVALUES60;
193 unsigned int maxlength = MAXNAMELENGTH30;
194
195 static const struct option long_options[] = {
196 { "minappearance", required_argument1, NULL__null, 'm' },
197 { "maxvalues", required_argument1, NULL__null, 'v' },
198 { "maxlength", required_argument1, NULL__null, 'l' },
199 { "help", no_argument0, NULL__null, 'h' },
200 { NULL__null, no_argument0, NULL__null, 0 }
201 };
202
203 int c;
204 while ((c = getopt_long(argc, argv, "m:v:l:h", long_options, NULL__null)) != -1)
4
Loop condition is false. Execution continues on line 250
205 {
206 switch (c)
207 {
208 case 'm':
209 if (isnumber(optarg))
210 {
211 minappearance = atoi(optarg);
212 break;
213 }
214 fprintf(stderrstderr, "invalid parameter minappearance: %s\n", optarg);
215 return 2;
216 break;
217 case 'v':
218 if (isnumber(optarg))
219 {
220 maxvalues = atoi(optarg);
221 break;
222 }
223 fprintf(stderrstderr, "invalid parameter maxvalues: %s\n", optarg);
224 return 2;
225 break;
226 case 'l':
227 if (isnumber(optarg))
228 {
229 maxlength = atoi(optarg);
230 break;
231 }
232 fprintf(stderrstderr, "invalid parameter maxlength: %s\n", optarg);
233 return 2;
234 break;
235 case 'h':
236 printf("usage: createcats [OPTIONS] /path_to/epg.data\n\n");
237 printf("-m N, --minappearance=N the minimum number a category has to appear\n");
238 printf(" to be used\n");
239 printf("-v N, --maxvalues=N values of a category are omitted if they exceed\n");
240 printf(" this number\n");
241 printf("-l N, --maxlength=N the maximum length of a text to be accepted\n");
242 printf(" as a category value\n");
243 printf("-h, --help this help\n\n");
244 return 0;
245 default:
246 break;
247 }
248 }
249
250 if (argc < 2)
5
Assuming 'argc' is >= 2
6
Taking false branch
251 {
252 fprintf(stderrstderr, "ERROR: please pass your epg.data\nusage: createcats epg.data\n");
253 return 1;
254 }
255
256 f = fopen(argv[argc-1], "r");
257 if (f == NULL__null)
7
Taking false branch
258 {
259 fprintf(stderrstderr, "ERROR: could not open: %s\n", argv[1]);
260 return 1;
261 }
262
263 char *s;
264 cReadLine ReadLine;
265 while ((s = ReadLine.Read(f)) != NULL__null)
8
Loop condition is false. Execution continues on line 310
266 {
267 if (*s == 'D')
268 {
269 s = strchr(s,'|'); // jump to possibly first category
270 if (!s)
271 continue;
272 s++;
273 char *pstrSearchToken;
274 char *pstrSearch=strdup(s);
275 pstrSearchToken=strtok(pstrSearch, "|");
276
277 while(pstrSearchToken)
278 {
279 // must have a ':'
280 char* szPos = NULL__null;
281 if ((szPos = strchr(pstrSearchToken, ':')) == NULL__null)
282 {
283 pstrSearchToken=strtok(NULL__null, "|");
284 continue;
285 }
286
287 char catname[MAXPARSEBUFFER((10) * 1024)] = "";
288 char catvalue[MAXPARSEBUFFER((10) * 1024)] = "";
289
290 strncpy(catname, pstrSearchToken, szPos - pstrSearchToken);
291 catname[szPos - pstrSearchToken] = 0;
292 strcpy(catvalue, skipspace(szPos+1));
293
294 cCat* cat = catlist.exists(catname);
295 if (!cat && strlen(catname) < maxlength) // accept only names up to 30 chars
296 cat = catlist.add(catname);
297
298 if (cat)
299 {
300 cat->appeared++;
301 if (strlen(catvalue) < maxlength) // accept only values up to 30 chars
302 cat->addvalue(catvalue);
303 }
304
305 pstrSearchToken=strtok(NULL__null, "|");
306 }
307 free(pstrSearch);
308 }
309 }
310 fclose(f);
311
312 catlist.sort();
9
Calling 'cCats::sort'
313
314 f = fopen("epgsearchcats.conf", "w");
315 if (f == NULL__null)
316 {
317 fprintf(stderrstderr, "ERROR: could not open outputfile\n");
318 return 1;
319 }
320 fprintf(f, "# -----------------------------------------------------------------------------\n");
321 fprintf(f, "# This is just a template based on your current epg.data. Please edit!\n");
322 fprintf(f, "# Perhaps a category or its value list should be removed. Also the\n");
323 fprintf(f, "# 'name in menu' should be adjusted to your language.\n");
324 fprintf(f, "# The order of items determines the order listed in epgsearch. It does not\n");
325 fprintf(f, "# depend on the ID, which is used by epgsearch.\n");
326 fprintf(f, "# Format:\n");
327 fprintf(f, "# ID|category name|name in menu|values separated by ',' (option)|searchmode(option)\n");
328 fprintf(f, "# - 'ID' should be a unique positive integer\n");
329 fprintf(f, "# (changing the id later on will force you to reedit your search timers!)\n");
330 fprintf(f, "# - 'category name' is the name in your epg.data\n");
331 fprintf(f, "# - 'name in menu' is the name displayed in epgsearch.\n");
332 fprintf(f, "# - 'values' is an optional list of possible values\n");
333 fprintf(f, "# if you omit the list, the entry turns to an edit field in epgsearch,\n");
334 fprintf(f, "# else it's a list of items to select from\n");
335 fprintf(f, "# - 'searchmode' is an optional parameter specifying the mode of search:\n");
336 fprintf(f, "# text comparison:\n");
337 fprintf(f, "# 0 - the whole term must appear as substring\n");
338 fprintf(f, "# 1 - all single words (delimiters are ',', ';', '|' or '~')\n");
339 fprintf(f, "# must exist as substrings. This is the default search mode.\n");
340 fprintf(f, "# 2 - at least one word (delimiters are ',', ';', '|' or '~')\n");
341 fprintf(f, "# must exist as substring.\n");
342 fprintf(f, "# 3 - matches exactly\n");
343 fprintf(f, "# 4 - regular expression\n");
344 fprintf(f, "# numerical comparison:\n");
345 fprintf(f, "# 10 - less\n");
346 fprintf(f, "# 11 - less or equal\n");
347 fprintf(f, "# 12 - greater\n");
348 fprintf(f, "# 13 - greater or equal\n");
349 fprintf(f, "# 14 - equal\n");
350 fprintf(f, "# 15 - not equal\n");
351 fprintf(f, "# -----------------------------------------------------------------------------\n\n");
352 int id = 1;
353 for(int i=0; i<catlist.num(); i++)
354 {
355 cCat* cat = catlist.get(i);
356 if (cat->appeared > (int)minappearance && cat->numvalues > 1) // accept only category, that have at least 2 values and appear more than MINAPPEARANCE timers
357 {
358 fprintf(f, "# '%s' found %d times with %d different values %s\n", cat->name, cat->appeared, cat->numvalues, cat->numvalues>=(int)maxvalues?"(values omitted, too much)":"");
359 fprintf(f, "%d|%s|%s|", id++, cat->name, cat->name);
360 for(int j=0; cat->numvalues < (int)maxvalues && j<cat->numvalues; j++)
361 fprintf(f, "%s%s", cat->values[j], (j == cat->numvalues-1?"":","));
362 fprintf(f, "|1\n\n");
363 }
364 }
365 fclose(f);
366
367 printf("epgsearchcats.conf created!\n");
368 return 0;
369}