| 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 | } |