/* Copyright (C) 2004-2011 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include #include #include #include #define MINAPPEARANCE 100 // the minimum appearance of a category #define MAXVALUES 60 // the maximum of values for a category #define MAXNAMELENGTH 30 // the maximum length of a category name or value // some helping stuff copied from VDR sources #define KILOBYTE(n) ((n) * 1024) #define MAXPARSEBUFFER KILOBYTE(10) #ifdef __FreeBSD__ #ifdef isnumber #undef isnumber #endif #endif bool isnumber(const char *s) { if (!*s) return false; while (*s) { if (!isdigit(*s)) return false; s++; } return true; } // --- cReadLine ------------------------------------------------------------- class cReadLine { private: char buffer[MAXPARSEBUFFER]; public: char *Read(FILE *f); }; char *cReadLine::Read(FILE *f) { if (fgets(buffer, sizeof(buffer), f) > 0) { int l = strlen(buffer) - 1; if (l >= 0 && buffer[l] == '\n') buffer[l] = 0; return buffer; } return NULL; } char *skipspace(const char *s) { while (*s && isspace(*s)) s++; return (char *)s; } int comparevalue( const void *arg1, const void *arg2 ) { char* value1 = *(char**) arg1; char* value2 = *(char**) arg2; return strcmp(value1, value2); } // --- cCat ------------------------------------------------------------- class cCat { public: int appeared; char name[MAXPARSEBUFFER]; int numvalues; char** values; cCat(char* n) :appeared(0), numvalues(0), values(NULL) { strcpy(name, n); } void addvalue(char* value) { if (valueexists(value)) return; char* newvalue = (char*) malloc(sizeof(char) * (strlen(value)+1)); strcpy(newvalue, value); values = (char**) realloc(values, sizeof(char*)*(numvalues+1)); values[numvalues++] = newvalue; } bool valueexists(char* value) { for(int i=0; iappeared == cat2->appeared) return 0; if (cat1->appeared < cat2->appeared) return 1; else return -1; } // --- cCats ------------------------------------------------------------- class cCats { private: int numcats; cCat** cats; public: cCats():numcats(0), cats(NULL) {} int num() {return numcats;} cCat* add(char* name) { cCat* newCat = new cCat(name); cats = (cCat**) realloc(cats, sizeof(cCat*)*(numcats+1)); cats[numcats++] = newCat; return newCat; } cCat* get(int i) { if (i>=0 && iname, name) == 0) return cats[i]; return NULL; } void sort() { for(int i=0; isort(); qsort(cats, numcats, sizeof( cCat* ), comparecat ); } }; int main(int argc, char *argv[]) { FILE* f = NULL; cCats catlist; unsigned int minappearance = MINAPPEARANCE; unsigned int maxvalues = MAXVALUES; unsigned int maxlength = MAXNAMELENGTH; static const struct option long_options[] = { { "minappearance", required_argument, NULL, 'm' }, { "maxvalues", required_argument, NULL, 'v' }, { "maxlength", required_argument, NULL, 'l' }, { "help", no_argument, NULL, 'h' }, { NULL, no_argument, NULL, 0 } }; int c; while ((c = getopt_long(argc, argv, "m:v:l:h", long_options, NULL)) != -1) { switch (c) { case 'm': if (isnumber(optarg)) { minappearance = atoi(optarg); break; } fprintf(stderr, "invalid parameter minappearance: %s\n", optarg); return 2; break; case 'v': if (isnumber(optarg)) { maxvalues = atoi(optarg); break; } fprintf(stderr, "invalid parameter maxvalues: %s\n", optarg); return 2; break; case 'l': if (isnumber(optarg)) { maxlength = atoi(optarg); break; } fprintf(stderr, "invalid parameter maxlength: %s\n", optarg); return 2; break; case 'h': printf("usage: createcats [OPTIONS] /path_to/epg.data\n\n"); printf("-m N, --minappearance=N the minimum number a category has to appear\n"); printf(" to be used\n"); printf("-v N, --maxvalues=N values of a category are omitted if they exceed\n"); printf(" this number\n"); printf("-l N, --maxlength=N the maximum length of a text to be accepted\n"); printf(" as a category value\n"); printf("-h, --help this help\n\n"); return 0; default: break; } } if (argc < 2) { fprintf(stderr, "ERROR: please pass your epg.data\nusage: createcats epg.data\n"); return 1; } f = fopen(argv[argc-1], "r"); if (f == NULL) { fprintf(stderr, "ERROR: could not open: %s\n", argv[1]); return 1; } char *s; cReadLine ReadLine; while ((s = ReadLine.Read(f)) != NULL) { if (*s == 'D') { s = strchr(s,'|'); // jump to possibly first category if (!s) continue; s++; char *pstrSearchToken; char *pstrSearch=strdup(s); pstrSearchToken=strtok(pstrSearch, "|"); while(pstrSearchToken) { // must have a ':' char* szPos = NULL; if ((szPos = strchr(pstrSearchToken, ':')) == NULL) { pstrSearchToken=strtok(NULL, "|"); continue; } char catname[MAXPARSEBUFFER] = ""; char catvalue[MAXPARSEBUFFER] = ""; strncpy(catname, pstrSearchToken, szPos - pstrSearchToken); catname[szPos - pstrSearchToken] = 0; strcpy(catvalue, skipspace(szPos+1)); cCat* cat = catlist.exists(catname); if (!cat && strlen(catname) < maxlength) // accept only names up to 30 chars cat = catlist.add(catname); if (cat) { cat->appeared++; if (strlen(catvalue) < maxlength) // accept only values up to 30 chars cat->addvalue(catvalue); } pstrSearchToken=strtok(NULL, "|"); } free(pstrSearch); } } fclose(f); catlist.sort(); f = fopen("epgsearchcats.conf", "w"); if (f == NULL) { fprintf(stderr, "ERROR: could not open outputfile\n"); return 1; } fprintf(f, "# -----------------------------------------------------------------------------\n"); fprintf(f, "# This is just a template based on your current epg.data. Please edit!\n"); fprintf(f, "# Perhaps a category or its value list should be removed. Also the\n"); fprintf(f, "# 'name in menu' should be adjusted to your language.\n"); fprintf(f, "# The order of items determines the order listed in epgsearch. It does not\n"); fprintf(f, "# depend on the ID, which is used by epgsearch.\n"); fprintf(f, "# Format:\n"); fprintf(f, "# ID|category name|name in menu|values separated by ',' (option)|searchmode(option)\n"); fprintf(f, "# - 'ID' should be a unique positive integer\n"); fprintf(f, "# (changing the id later on will force you to reedit your search timers!)\n"); fprintf(f, "# - 'category name' is the name in your epg.data\n"); fprintf(f, "# - 'name in menu' is the name displayed in epgsearch.\n"); fprintf(f, "# - 'values' is an optional list of possible values\n"); fprintf(f, "# if you omit the list, the entry turns to an edit field in epgsearch,\n"); fprintf(f, "# else it's an list of items to select from\n"); fprintf(f, "# - 'searchmode' is an optional parameter specifying the mode of search:\n"); fprintf(f, "# text comparison:\n"); fprintf(f, "# 0 - the whole term must appear as substring\n"); fprintf(f, "# 1 - all single words (delimiters are ',', ';', '|' or '~')\n"); fprintf(f, "# must exist as substrings. This is the default search mode.\n"); fprintf(f, "# 2 - at least one word (delimiters are ',', ';', '|' or '~')\n"); fprintf(f, "# must exist as substring.\n"); fprintf(f, "# 3 - matches exactly\n"); fprintf(f, "# 4 - regular expression\n"); fprintf(f, "# numerical comparison:\n"); fprintf(f, "# 10 - less\n"); fprintf(f, "# 11 - less or equal\n"); fprintf(f, "# 12 - greater\n"); fprintf(f, "# 13 - greater or equal\n"); fprintf(f, "# 14 - equal\n"); fprintf(f, "# 15 - not equal\n"); fprintf(f, "# -----------------------------------------------------------------------------\n\n"); int id = 1; for(int i=0; iappeared > (int)minappearance && cat->numvalues > 1) // accept only category, that have at least 2 values and appear more than MINAPPEARANCE timers { 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)":""); fprintf(f, "%d|%s|%s|", id++, cat->name, cat->name); for(int j=0; cat->numvalues < (int)maxvalues && jnumvalues; j++) fprintf(f, "%s%s", cat->values[j], (j == cat->numvalues-1?"":",")); fprintf(f, "|1\n\n"); } } fclose(f); printf("epgsearchcats.conf created!\n"); return 0; }