1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
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 | |
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 | |
45 | bool 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 | |
58 | class cReadLine { |
59 | private: |
60 | char buffer[MAXPARSEBUFFER((10) * 1024)]; |
61 | public: |
62 | cReadLine() { buffer[0]=0; } |
63 | char *Read(FILE *f); |
64 | }; |
65 | |
66 | char *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 | |
77 | char *skipspace(const char *s) |
78 | { |
79 | while (*s && isspace(*s)) |
80 | s++; |
81 | return (char *)s; |
82 | } |
83 | |
84 | int 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 | |
92 | class 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 | |
131 | int 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 | |
140 | class 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 | |
187 | int 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) |
| |
| |
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) |
| |
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,'|'); |
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 | |
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) |
296 | cat = catlist.add(catname); |
297 | |
298 | if (cat) |
299 | { |
300 | cat->appeared++; |
301 | if (strlen(catvalue) < maxlength) |
302 | cat->addvalue(catvalue); |
303 | } |
304 | |
305 | pstrSearchToken=strtok(NULL__null, "|"); |
306 | } |
307 | free(pstrSearch); |
308 | } |
309 | } |
310 | fclose(f); |
311 | |
312 | catlist.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) |
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 | } |