/* * tools.c: Tools for handling configuration files and strings * * See the README file for copyright information and how to reach the author. * */ #include "tools.h" #include // // HTML conversion code taken from RSS Reader plugin for VDR // http://www.saunalahti.fi/~rahrenbe/vdr/rssreader/ // by Rolf Ahrenberg // // --- Static ----------------------------------------------------------- #define ELEMENTS(x) (sizeof(x) / sizeof(x[0])) struct conv_table { const char *from; const char *to; }; static struct conv_table pre_conv_table[] = { // 'to' field must be smaller than 'from' {"
", "\n"} }; // Conversion page: http://www.ltg.ed.ac.uk/~richard/utf-8.cgi static struct conv_table post_conv_table[] = { // 'to' field must be smaller than 'from' {""", "\x22"}, {""", "\x22"}, {"&", "\x26"}, {"&", "\x26"}, {"&", "\x26"}, {"'", "\x27"}, {"(", "\x28"}, {")", "\x29"}, {":", "\x3a"}, {"<", "\x3c"}, {"<", "\x3c"}, {">", "\x3e"}, {">", "\x3e"}, {"[", "\x5b"}, {"]", "\x5d"}, {" ", "\xc2\xa0"}, {" ", "\xc2\xa0"}, {"°", "\xc2\xb0"}, {"°", "\xc2\xb0"}, {"´", "\xc2\xb4"}, {"´", "\xc2\xb4"}, {"Ä", "\xc3\x84"}, {"Ä", "\xc3\x84"}, {"Å", "\xc3\x85"}, {"Å", "\xc3\x85"}, {"Ö", "\xc3\x96"}, {"Ö", "\xc3\x96"}, {"Ü", "\xc3\x9c"}, {"Ü", "\xc3\x9c"}, {"ß", "\xc3\x9f"}, {"ß", "\xc3\x9f"}, {"â", "\xc3\xa2"}, {"â", "\xc3\xa2"}, {"ä", "\xc3\xa4"}, {"ä", "\xc3\xa4"}, {"å", "\xc3\xa5"}, {"å", "\xc3\xa5"}, {"ç", "\xc3\xa7"}, {"ç", "\xc3\xa7"}, {"é", "\xc3\xa9"}, {"é", "\xc3\xa9"}, {"ê", "\xc3\xaa"}, {"ê", "\xc3\xaa"}, {"ö", "\xc3\xb6"}, {"ö", "\xc3\xb6"}, {"ü", "\xc3\xbc"}, {"ü", "\xc3\xbc"}, {"–", "\xe2\x80\x93"}, {"–", "\xe2\x80\x93"}, {"—", "\xe2\x80\x94"}, {"—", "\xe2\x80\x94"}, {"‘", "\xe2\x80\x98"}, {"‘", "\xe2\x80\x98"}, {"’", "\xe2\x80\x99"}, {"’", "\xe2\x80\x99"}, {"‚", "\xe2\x80\x9a"}, {"‚", "\xe2\x80\x9a"}, {"“", "\xe2\x80\x9c"}, {"“", "\xe2\x80\x9c"}, {"”", "\xe2\x80\x9d"}, {"”", "\xe2\x80\x9d"}, {"„", "\xe2\x80\x9e"}, {"„", "\xe2\x80\x9e"}, {"′", "\xe2\x80\xb3"}, {"″", "\xe2\x80\xb3"}, {"€", "\xe2\x82\xac"}, {"€", "\xe2\x82\xac"}, {"\n\n", "\n"}, // let's also strip multiple linefeeds }; static char *htmlcharconv(char *str, struct conv_table *conv, unsigned int elem) { if (str && conv) { for (unsigned int i = 0; i < elem; ++i) { char *ptr = strstr(str, conv[i].from); while (ptr) { long of = ptr - str; size_t l = strlen(str); size_t l1 = strlen(conv[i].from); size_t l2 = strlen(conv[i].to); if (l2 > l1) { error("htmlcharconv(): cannot reallocate string"); return str; } if (l2 != l1) memmove(str + of + l2, str + of + l1, l - of - l1 + 1); strncpy(str + of, conv[i].to, l2); ptr = strstr(str, conv[i].from); } } return str; } return NULL; } // --- General functions ------------------------------------------------ char *striphtml(char *str) { if (str) { char *c, t = 0, *r; str = htmlcharconv(str, pre_conv_table, ELEMENTS(pre_conv_table)); c = str; r = str; while (*str != '\0') { if (*str == '<') t++; else if (*str == '>') t--; else if (t < 1) *(c++) = *str; str++; } *c = '\0'; return htmlcharconv(r, post_conv_table, ELEMENTS(post_conv_table)); } return NULL; } // --- cAddEventThread ---------------------------------------- class cAddEventListItem : public cListObject { protected: cEvent *event; tChannelID channelID; public: cAddEventListItem(cEvent *Event, tChannelID ChannelID) { event = Event; channelID = ChannelID; } tChannelID GetChannelID() { return channelID; } cEvent *GetEvent() { return event; } ~cAddEventListItem() { } }; class cAddEventThread : public cThread { private: cTimeMs LastHandleEvent; cList *list; enum { INSERT_TIMEOUT_IN_MS = 10000 }; protected: virtual void Action(void); public: cAddEventThread(void); ~cAddEventThread(void); void AddEvent(cEvent *Event, tChannelID ChannelID); }; cAddEventThread::cAddEventThread(void) :cThread("add events to schedule") { LastHandleEvent = time(NULL); list = new cList; } cAddEventThread::~cAddEventThread(void) { LOCK_THREAD; list->cList::Clear(); Cancel(3); } void cAddEventThread::Action(void) { SetPriority(19); while (Running() && !LastHandleEvent.TimedOut()) { cAddEventListItem *e = NULL; cSchedulesLock SchedulesLock(true, 10); cSchedules *schedules = (cSchedules *)cSchedules::Schedules(SchedulesLock); Lock(); while (schedules && (e = list->First()) != NULL) { cSchedule *schedule = (cSchedule *)schedules->GetSchedule(Channels.GetByChannelID(e->GetChannelID()), true); schedule->AddEvent(e->GetEvent()); EpgHandlers.SortSchedule(schedule); EpgHandlers.DropOutdated(schedule, e->GetEvent()->StartTime(), e->GetEvent()->EndTime(), e->GetEvent()->TableID(), e->GetEvent()->Version()); list->Del(e); } Unlock(); cCondWait::SleepMs(10); } } void cAddEventThread::AddEvent(cEvent *Event, tChannelID ChannelID) { LOCK_THREAD; LastHandleEvent.Set(INSERT_TIMEOUT_IN_MS); list->Add(new cAddEventListItem(Event, ChannelID)); } static cAddEventThread AddEventThread; // --- void AddEvent(cEvent *Event, tChannelID ChannelID) { if (!AddEventThread.Active()) AddEventThread.Start(); AddEventThread.AddEvent(Event, ChannelID); } // --- Listitem ---------------------------------------- cListItem::cListItem() { enabled = false; string = NULL; numchannels = 0; channels_num = NULL; channels_str = NULL; } cListItem::~cListItem(void) { Free(); } void cListItem::Free(void) { if (channels_str) { int i = 0; while (i < numchannels) { free(channels_str[i]); ++i; } } FREE(channels_num); FREE(channels_str); FREE(string); numchannels = 0; enabled = false; } const char *cListItem::GetChannelID(int index) { if (channels_str && index >= 0 && index < numchannels) return channels_str[index]; else return NULL; } int cListItem::GetChannelNum(int index) { if (channels_num && index >= 0 && index < numchannels) return channels_num[index]; else return 0; } bool cListItem::IsActive(tChannelID ChannelID) { bool active = true; if (numchannels > 0) { bool found = false; int i = 0; while (i < numchannels) { if ((Channels.GetByChannelID(ChannelID)->Number() == GetChannelNum(i)) || (GetChannelID(i) && strcmp(*(ChannelID.ToString()), GetChannelID(i)) == 0)) { found = true; break; } ++i; } if (!found) active = false; } return active; } int cListItem::LoadChannelsFromString(const char *string) { numchannels = 0; char *tmpstring = strdup(string); char *c = tmpstring; while (c) { ++numchannels; c = strchr(c+1, ','); } if (numchannels > 0) { char *c = tmpstring; // Use channel numbers if (atoi(string)) channels_num = (int *)malloc(sizeof(int)*numchannels); else// use channel IDs channels_str = (char **)malloc(sizeof(char *)*numchannels); int i = 0; char *pc = strtok(c, ","); while (i < numchannels) { // Use channel numbers if (atoi(string)) channels_num[i] = atoi(pc); else// use channel IDs channels_str[i] = strdup(pc); pc = strtok(NULL, ","); ++i; } } free(tmpstring); return numchannels; } void cListItem::ToggleEnabled(void) { enabled = !enabled; } void cListItem::PrintConfigLineToFile(FILE *f) { if (f) fprintf(f, "%s%s\n", (!enabled && string && *string != '#') ? "!" : "", string); }