diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2002-10-20 12:28:55 +0200 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2002-10-20 12:28:55 +0200 |
commit | ac9622bb8ad8d660fca4e77460c970f72c344afa (patch) | |
tree | 9738265846abf2c1a491cfec77a4e55f434297be | |
parent | ab4ceb29a033f8a3cc051d5ea9a6f20ca6e75f8a (diff) | |
download | vdr-ac9622bb8ad8d660fca4e77460c970f72c344afa.tar.gz vdr-ac9622bb8ad8d660fca4e77460c970f72c344afa.tar.bz2 |
Timers now internally have a pointer to their channel
-rw-r--r-- | HISTORY | 4 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | channels.c | 8 | ||||
-rw-r--r-- | channels.h | 3 | ||||
-rw-r--r-- | config.c | 377 | ||||
-rw-r--r-- | config.h | 61 | ||||
-rw-r--r-- | menu.c | 172 | ||||
-rw-r--r-- | recording.c | 20 | ||||
-rw-r--r-- | recording.h | 3 | ||||
-rw-r--r-- | svdrp.c | 11 | ||||
-rw-r--r-- | timers.c | 408 | ||||
-rw-r--r-- | timers.h | 91 | ||||
-rw-r--r-- | vdr.c | 7 |
13 files changed, 596 insertions, 573 deletions
@@ -1611,7 +1611,7 @@ Video Disk Recorder Revision History shall be executed from the "Recordings" menu; see MANUAL and 'man vdr(5)' for details (suggested by Gerhard Steiner). -2002-10-19: Version 1.1.14 +2002-10-20: Version 1.1.14 - Fixed some faulty default parameter initializations (thanks to Robert Schiele). - Added further satellites to 'sources.conf' (thanks to Reinhard Walter Buchner). @@ -1624,3 +1624,5 @@ Video Disk Recorder Revision History used to create 'gaps' in the channel numbering (see 'man 5 vdr'). BE CAREFUL TO UPDATE YOUR 'timers.conf' ACCORDINGLY IF INSERTING THIS NEW FEATURE INTO YOUR 'channels.conf' FILE! +- Timers now internally have a pointer to their channel (this is necessary to + handle gaps in channel numbers, and in preparation for unique channel ids). @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.48 2002/10/04 14:29:14 kls Exp $ +# $Id: Makefile 1.49 2002/10/19 15:46:08 kls Exp $ .DELETE_ON_ERROR: @@ -36,7 +36,7 @@ OBJS = audio.o channels.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd dvbplayer.o dvbspu.o eit.o eitscan.o font.o i18n.o interface.o keys.o\ lirc.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o rcu.o\ receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sources.o\ - spu.o status.o svdrp.o thread.o tools.o transfer.o vdr.o videodir.o + spu.o status.o svdrp.o thread.o timers.o tools.o transfer.o vdr.o videodir.o OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1 FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1 @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: channels.c 1.4 2002/10/19 14:46:05 kls Exp $ + * $Id: channels.c 1.5 2002/10/20 11:50:47 kls Exp $ */ #include "channels.h" @@ -450,9 +450,3 @@ bool cChannels::SwitchTo(int Number) cChannel *channel = GetByNumber(Number); return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true); } - -const char *cChannels::GetChannelNameByNumber(int Number) -{ - cChannel *channel = GetByNumber(Number); - return channel ? channel->Name() : NULL; -} @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: channels.h 1.2 2002/10/19 11:48:02 kls Exp $ + * $Id: channels.h 1.3 2002/10/20 11:50:36 kls Exp $ */ #ifndef __CHANNELS_H @@ -114,7 +114,6 @@ public: void ReNumber(void); // Recalculate 'number' based on channel type cChannel *GetByNumber(int Number, int SkipGap = 0); cChannel *GetByServiceID(unsigned short ServiceId); - const char *GetChannelNameByNumber(int Number); bool SwitchTo(int Number); int MaxNumber(void) { return maxNumber; } }; @@ -4,13 +4,12 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.110 2002/10/19 11:34:01 kls Exp $ + * $Id: config.c 1.111 2002/10/19 15:49:51 kls Exp $ */ #include "config.h" #include <ctype.h> #include <stdlib.h> -#include "channels.h" //XXX timers! #include "i18n.h" #include "interface.h" #include "plugin.h" @@ -20,339 +19,6 @@ // format characters in order to allow any number of blanks after a numeric // value! -// -- cTimer ----------------------------------------------------------------- - -char *cTimer::buffer = NULL; - -cTimer::cTimer(bool Instant) -{ - startTime = stopTime = 0; - recording = pending = false; - active = Instant ? taActInst : taInactive; - cChannel *ch = Channels.GetByNumber(cDevice::CurrentChannel()); - channel = ch ? ch->Number() : 0; - time_t t = time(NULL); - struct tm tm_r; - struct tm *now = localtime_r(&t, &tm_r); - day = now->tm_mday; - start = now->tm_hour * 100 + now->tm_min; - stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime; - stop = (stop / 60) * 100 + (stop % 60); - if (stop >= 2400) - stop -= 2400; -//TODO VPS??? - priority = Setup.DefaultPriority; - lifetime = Setup.DefaultLifetime; - *file = 0; - firstday = 0; - summary = NULL; - if (Instant && ch) - snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : ch->Name()); -} - -cTimer::cTimer(const cEventInfo *EventInfo) -{ - startTime = stopTime = 0; - recording = pending = false; - active = true; - cChannel *ch = Channels.GetByServiceID(EventInfo->GetServiceID()); - channel = ch ? ch->Number() : 0; - time_t tstart = EventInfo->GetTime(); - time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60; - tstart -= Setup.MarginStart * 60; - struct tm tm_r; - struct tm *time = localtime_r(&tstart, &tm_r); - day = time->tm_mday; - start = time->tm_hour * 100 + time->tm_min; - time = localtime_r(&tstop, &tm_r); - stop = time->tm_hour * 100 + time->tm_min; - if (stop >= 2400) - stop -= 2400; - priority = Setup.DefaultPriority; - lifetime = Setup.DefaultLifetime; - *file = 0; - const char *Title = EventInfo->GetTitle(); - if (!isempty(Title)) - strn0cpy(file, EventInfo->GetTitle(), sizeof(file)); - firstday = 0; - summary = NULL; -} - -cTimer::~cTimer() -{ - free(summary); -} - -cTimer& cTimer::operator= (const cTimer &Timer) -{ - memcpy(this, &Timer, sizeof(*this)); - if (summary) - summary = strdup(summary); - return *this; -} - -bool cTimer::operator< (const cListObject &ListObject) -{ - cTimer *ti = (cTimer *)&ListObject; - time_t t1 = StartTime(); - time_t t2 = ti->StartTime(); - return t1 < t2 || (t1 == t2 && priority > ti->priority); -} - -const char *cTimer::ToText(cTimer *Timer) -{ - free(buffer); - strreplace(Timer->file, ':', '|'); - strreplace(Timer->summary, '\n', '|'); - asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day, Timer->firstday), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); - strreplace(Timer->summary, '|', '\n'); - strreplace(Timer->file, '|', ':'); - return buffer; -} - -const char *cTimer::ToText(void) -{ - return ToText(this); -} - -int cTimer::TimeToInt(int t) -{ - return (t / 100 * 60 + t % 100) * 60; -} - -int cTimer::ParseDay(const char *s, time_t *FirstDay) -{ - char *tail; - int d = strtol(s, &tail, 10); - if (FirstDay) - *FirstDay = 0; - if (tail && *tail) { - d = 0; - if (tail == s) { - const char *first = strchr(s, '@'); - int l = first ? first - s : strlen(s); - if (l == 7) { - for (const char *p = s + 6; p >= s; p--) { - d <<= 1; - d |= (*p != '-'); - } - d |= 0x80000000; - } - if (FirstDay && first) { - ++first; - if (strlen(first) == 10) { - struct tm tm_r; - if (3 == sscanf(first, "%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) { - tm_r.tm_year -= 1900; - tm_r.tm_mon--; - tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0; - tm_r.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting - *FirstDay = mktime(&tm_r); - } - } - else - d = 0; - } - } - } - else if (d < 1 || d > 31) - d = 0; - return d; -} - -const char *cTimer::PrintDay(int d, time_t FirstDay) -{ -#define DAYBUFFERSIZE 32 - static char buffer[DAYBUFFERSIZE]; - if ((d & 0x80000000) != 0) { - char *b = buffer; - const char *w = tr("MTWTFSS"); - while (*w) { - *b++ = (d & 1) ? *w : '-'; - d >>= 1; - w++; - } - if (FirstDay) { - struct tm tm_r; - localtime_r(&FirstDay, &tm_r); - b += strftime(b, DAYBUFFERSIZE - (b - buffer), "@%Y-%m-%d", &tm_r); - } - *b = 0; - } - else - sprintf(buffer, "%d", d); - return buffer; -} - -const char *cTimer::PrintFirstDay(void) -{ - if (firstday) { - const char *s = PrintDay(day, firstday); - if (strlen(s) == 18) - return s + 8; - } - return ""; // not NULL, so the caller can always use the result -} - -bool cTimer::Parse(const char *s) -{ - char *buffer1 = NULL; - char *buffer2 = NULL; - free(summary); - summary = NULL; - //XXX Apparently sscanf() doesn't work correctly if the last %a argument - //XXX results in an empty string (this first occured when the EIT gathering - //XXX was put into a separate thread - don't know why this happens... - //XXX As a cure we copy the original string and add a blank. - //XXX If anybody can shed some light on why sscanf() failes here, I'd love - //XXX to hear about that! - char *s2 = NULL; - int l2 = strlen(s); - while (l2 > 0 && isspace(s[l2 - 1])) - l2--; - if (s[l2 - 1] == ':') { - s2 = MALLOC(char, l2 + 3); - strcat(strn0cpy(s2, s, l2 + 1), " \n"); - s = s2; - } - if (8 <= sscanf(s, "%d :%d :%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) { - if (summary && !*skipspace(summary)) { - free(summary); - summary = NULL; - } - //TODO add more plausibility checks - day = ParseDay(buffer1, &firstday); - strn0cpy(file, buffer2, MaxFileName); - strreplace(file, '|', ':'); - strreplace(summary, '|', '\n'); - free(buffer1); - free(buffer2); - free(s2); - return day != 0; - } - free(s2); - return false; -} - -bool cTimer::Save(FILE *f) -{ - return fprintf(f, ToText()) > 0; -} - -bool cTimer::IsSingleEvent(void) -{ - return (day & 0x80000000) == 0; -} - -int cTimer::GetMDay(time_t t) -{ - struct tm tm_r; - return localtime_r(&t, &tm_r)->tm_mday; -} - -int cTimer::GetWDay(time_t t) -{ - struct tm tm_r; - int weekday = localtime_r(&t, &tm_r)->tm_wday; - return weekday == 0 ? 6 : weekday - 1; // we start with monday==0! -} - -bool cTimer::DayMatches(time_t t) -{ - return IsSingleEvent() ? GetMDay(t) == day : (day & (1 << GetWDay(t))) != 0; -} - -time_t cTimer::IncDay(time_t t, int Days) -{ - struct tm tm_r; - tm tm = *localtime_r(&t, &tm_r); - tm.tm_mday += Days; // now tm_mday may be out of its valid range - int h = tm.tm_hour; // save original hour to compensate for DST change - tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting - t = mktime(&tm); // normalize all values - tm.tm_hour = h; // compensate for DST change - return mktime(&tm); // calculate final result -} - -time_t cTimer::SetTime(time_t t, int SecondsFromMidnight) -{ - struct tm tm_r; - tm tm = *localtime_r(&t, &tm_r); - tm.tm_hour = SecondsFromMidnight / 3600; - tm.tm_min = (SecondsFromMidnight % 3600) / 60; - tm.tm_sec = SecondsFromMidnight % 60; - tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting - return mktime(&tm); -} - -char *cTimer::SetFile(const char *File) -{ - if (!isempty(File)) - strn0cpy(file, File, sizeof(file)); - return file; -} - -bool cTimer::Matches(time_t t) -{ - startTime = stopTime = 0; - if (t == 0) - t = time(NULL); - - int begin = TimeToInt(start); // seconds from midnight - int length = TimeToInt(stop) - begin; - if (length < 0) - length += SECSINDAY; - - int DaysToCheck = IsSingleEvent() ? 61 : 7; // 61 to handle months with 31/30/31 - for (int i = -1; i <= DaysToCheck; i++) { - time_t t0 = IncDay(t, i); - if (DayMatches(t0)) { - time_t a = SetTime(t0, begin); - time_t b = a + length; - if ((!firstday || a >= firstday) && t <= b) { - startTime = a; - stopTime = b; - break; - } - } - } - if (!startTime) - startTime = firstday; // just to have something that's more than a week in the future - else if (t > startTime || t > firstday + SECSINDAY + 3600) // +3600 in case of DST change - firstday = 0; - return active && startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers -} - -time_t cTimer::StartTime(void) -{ - if (!startTime) - Matches(); - return startTime; -} - -time_t cTimer::StopTime(void) -{ - if (!stopTime) - Matches(); - return stopTime; -} - -void cTimer::SetRecording(bool Recording) -{ - recording = Recording; - isyslog("timer %d %s", Index() + 1, recording ? "start" : "stop"); -} - -void cTimer::SetPending(bool Pending) -{ - pending = Pending; -} - -void cTimer::Skip(void) -{ - firstday = IncDay(SetTime(StartTime(), 0), 1); -} - // --- cCommand ------------------------------------------------------------- char *cCommand::result = NULL; @@ -476,47 +142,6 @@ bool cCaDefinition::Parse(const char *s) cCommands Commands; cCommands RecordingCommands; -// -- cTimers ---------------------------------------------------------------- - -cTimers Timers; - -cTimer *cTimers::GetTimer(cTimer *Timer) -{ - cTimer *ti = (cTimer *)First(); - while (ti) { - if (ti->channel == Timer->channel && ti->day == Timer->day && ti->start == Timer->start && ti->stop == Timer->stop) - return ti; - ti = (cTimer *)ti->Next(); - } - return NULL; -} - -cTimer *cTimers::GetMatch(time_t t) -{ - cTimer *t0 = NULL; - cTimer *ti = First(); - while (ti) { - if (!ti->recording && ti->Matches(t)) { - if (!t0 || ti->priority > t0->priority) - t0 = ti; - } - ti = (cTimer *)ti->Next(); - } - return t0; -} - -cTimer *cTimers::GetNextActiveTimer(void) -{ - cTimer *t0 = NULL; - cTimer *ti = First(); - while (ti) { - if (ti->active && (!t0 || *ti < *t0)) - t0 = ti; - ti = (cTimer *)ti->Next(); - } - return t0; -} - // -- cSVDRPhosts ------------------------------------------------------------ cSVDRPhosts SVDRPhosts; @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.136 2002/10/19 11:29:46 kls Exp $ + * $Id: config.h 1.137 2002/10/19 15:43:31 kls Exp $ */ #ifndef __CONFIG_H @@ -32,57 +32,6 @@ #define MaxFileName 256 -enum eTimerActive { taInactive = 0, - taActive = 1, - taInstant = 2, - taActInst = (taActive | taInstant) - }; - -class cTimer : public cListObject { -private: - time_t startTime, stopTime; - static char *buffer; - static const char *ToText(cTimer *Timer); -public: - bool recording, pending; - int active; - int channel; - int day; - int start; - int stop; -//TODO VPS??? - int priority; - int lifetime; - char file[MaxFileName]; - time_t firstday; - char *summary; - cTimer(bool Instant = false); - cTimer(const cEventInfo *EventInfo); - virtual ~cTimer(); - cTimer& operator= (const cTimer &Timer); - virtual bool operator< (const cListObject &ListObject); - const char *ToText(void); - bool Parse(const char *s); - bool Save(FILE *f); - bool IsSingleEvent(void); - int GetMDay(time_t t); - int GetWDay(time_t t); - bool DayMatches(time_t t); - static time_t IncDay(time_t t, int Days); - static time_t SetTime(time_t t, int SecondsFromMidnight); - char *SetFile(const char *File); - bool Matches(time_t t = 0); - time_t StartTime(void); - time_t StopTime(void); - void SetRecording(bool Recording); - void SetPending(bool Pending); - void Skip(void); - const char *PrintFirstDay(void); - static int TimeToInt(int t); - static int ParseDay(const char *s, time_t *FirstDay = NULL); - static const char *PrintDay(int d, time_t FirstDay = 0); - }; - class cCommand : public cListObject { private: char *title; @@ -203,13 +152,6 @@ public: } }; -class cTimers : public cConfig<cTimer> { -public: - cTimer *GetTimer(cTimer *Timer); - cTimer *GetMatch(time_t t); - cTimer *GetNextActiveTimer(void); - }; - class cCommands : public cConfig<cCommand> {}; class cSVDRPhosts : public cConfig<cSVDRPhost> { @@ -222,7 +164,6 @@ public: const cCaDefinition *Get(int Number); }; -extern cTimers Timers; extern cCommands Commands; extern cCommands RecordingCommands; extern cSVDRPhosts SVDRPhosts; @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.218 2002/10/19 15:33:37 kls Exp $ + * $Id: menu.c 1.219 2002/10/20 12:03:13 kls Exp $ */ #include "menu.h" @@ -24,6 +24,7 @@ #include "remote.h" #include "sources.h" #include "status.h" +#include "timers.h" #include "videodir.h" #define MENUTIMEOUT 120 // seconds @@ -617,17 +618,14 @@ eOSState cMenuEditChannel::ProcessKey(eKeys Key) class cMenuChannelItem : public cOsdItem { private: - int index; cChannel *channel; public: - cMenuChannelItem(int Index, cChannel *Channel); + cMenuChannelItem(cChannel *Channel); virtual void Set(void); - void SetIndex(int Index); }; -cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel) +cMenuChannelItem::cMenuChannelItem(cChannel *Channel) { - index = Index; channel = Channel; if (channel->GroupSep()) SetColor(clrCyan, clrBackground); @@ -644,15 +642,11 @@ void cMenuChannelItem::Set(void) SetText(buffer, false); } -void cMenuChannelItem::SetIndex(int Index) -{ - index = Index; - Set(); -} - // --- cMenuChannels --------------------------------------------------------- class cMenuChannels : public cOsdMenu { +private: + void Propagate(void); protected: eOSState Switch(void); eOSState Edit(void); @@ -673,12 +667,22 @@ cMenuChannels::cMenuChannels(void) int curr = ((channel = Channels.GetByNumber(cDevice::CurrentChannel())) != NULL) ? channel->Index() : -1; while ((channel = Channels.Get(i)) != NULL) { - Add(new cMenuChannelItem(i, channel), i == curr); + Add(new cMenuChannelItem(channel), i == curr); i++; } SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("Mark")); } +void cMenuChannels::Propagate(void) +{ + Channels.ReNumber(); + Channels.Save(); + for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) + ci->Set(); + Timers.Save(); // channel numbering has changed! + Display(); +} + eOSState cMenuChannels::Switch(void) { cChannel *ch = Channels.Get(Current()); @@ -702,7 +706,7 @@ eOSState cMenuChannels::New(void) cChannel *channel = new cChannel(Channels.Get(Current())); Channels.Add(channel); Channels.ReNumber(); - Add(new cMenuChannelItem(channel->Index()/*XXX*/, channel), true); + Add(new cMenuChannelItem(channel), true); Channels.Save(); isyslog("channel %d added", channel->Number()); return AddSubMenu(new cMenuEditChannel(Current())); @@ -715,36 +719,17 @@ eOSState cMenuChannels::Del(void) cChannel *channel = Channels.Get(Index); int DeletedChannel = channel->Number(); // Check if there is a timer using this channel: - for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { - if (ti->channel == DeletedChannel) { + for (cTimer *ti = Timers.First(); ti; ti = Timers.Next(ti)) { + if (ti->Channel() == channel) { Interface->Error(tr("Channel is being used by a timer!")); return osContinue; } } if (Interface->Confirm(tr("Delete channel?"))) { - // Move and renumber the channels: Channels.Del(channel); - Channels.ReNumber(); cOsdMenu::Del(Index); - int i = 0; - for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) - ci->SetIndex(i++); - Channels.Save(); + Propagate(); isyslog("channel %d deleted", DeletedChannel); - // Fix the timers: - bool TimersModified = false; - for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { - int OldChannel = ti->channel; - if (ti->channel > DeletedChannel) - ti->channel--; - if (ti->channel != OldChannel) { - TimersModified = true; - isyslog("timer %d: channel changed from %d to %d", ti->Index() + 1, OldChannel, ti->channel); - } - } - if (TimersModified) - Timers.Save(); - Display(); } } return osContinue; @@ -754,35 +739,10 @@ void cMenuChannels::Move(int From, int To) { int FromNumber = Channels.Get(From)->Number(); int ToNumber = Channels.Get(To)->Number(); - // Move and renumber the channels: Channels.Move(From, To); - Channels.ReNumber(); cOsdMenu::Move(From, To); - int i = 0; - for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) - ci->SetIndex(i++); - Channels.Save(); + Propagate(); isyslog("channel %d moved to %d", FromNumber, ToNumber); - // Fix the timers: - bool TimersModified = false; - From++; // user visible channel numbers start with '1' - To++; - for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { - int OldChannel = ti->channel; - if (ti->channel == FromNumber) - ti->channel = ToNumber; - else if (ti->channel > FromNumber && ti->channel <= ToNumber) - ti->channel--; - else if (ti->channel < FromNumber && ti->channel >= ToNumber) - ti->channel++; - if (ti->channel != OldChannel) { - TimersModified = true; - isyslog("timer %d: channel changed from %d to %d", ti->Index() + 1, OldChannel, ti->channel); - } - } - if (TimersModified) - Timers.Save(); - Display(); } eOSState cMenuChannels::ProcessKey(eKeys Key) @@ -835,6 +795,7 @@ class cMenuEditTimer : public cOsdMenu { private: cTimer *timer; cTimer data; + int channel; cMenuEditDateItem *firstday; void SetFirstDayItem(void); public: @@ -851,12 +812,12 @@ cMenuEditTimer::cMenuEditTimer(int Index, bool New) data = *timer; if (New) data.active = 1; + channel = data.Channel()->Number(); Add(new cMenuEditBoolItem(tr("Active"), &data.active)); - Add(new cMenuEditChanItem(tr("Channel"), &data.channel)); + Add(new cMenuEditChanItem(tr("Channel"), &channel)); Add(new cMenuEditDayItem( tr("Day"), &data.day)); Add(new cMenuEditTimeItem(tr("Start"), &data.start)); Add(new cMenuEditTimeItem(tr("Stop"), &data.stop)); -//TODO VPS??? Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file), tr(FileNameChars))); @@ -884,15 +845,24 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key) if (state == osUnknown) { switch (Key) { - case kOk: if (!*data.file) - strcpy(data.file, Channels.GetChannelNameByNumber(data.channel)); - if (timer && memcmp(timer, &data, sizeof(data)) != 0) { - *timer = data; - if (timer->active) - timer->active = 1; // allows external programs to mark active timers with values > 1 and recognize if the user has modified them - Timers.Save(); - isyslog("timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive"); - } + case kOk: { + cChannel *ch = Channels.GetByNumber(channel); + if (ch) + data.channel = ch; + else { + Interface->Error(tr("*** Invalid Channel ***")); + break; + } + if (!*data.file) + strcpy(data.file, data.Channel()->Name()); + if (timer && memcmp(timer, &data, sizeof(data)) != 0) { + *timer = data; + if (timer->active) + timer->active = 1; // allows external programs to mark active timers with values > 1 and recognize if the user has modified them + Timers.Save(); + isyslog("timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive"); + } + } return osBack; case kRed: case kGreen: @@ -933,14 +903,14 @@ void cMenuTimerItem::Set(void) { char *buffer = NULL; asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s", - !timer->active ? ' ' : timer->firstday ? '!' : timer->recording ? '#' : '>', - timer->channel, - timer->PrintDay(timer->day), - timer->start / 100, - timer->start % 100, - timer->stop / 100, - timer->stop % 100, - timer->file); + !timer->Active() ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>', + timer->Channel()->Number(), + timer->PrintDay(timer->Day()), + timer->Start() / 100, + timer->Start() % 100, + timer->Stop() / 100, + timer->Stop() % 100, + timer->File()); SetText(buffer, false); } @@ -985,23 +955,13 @@ eOSState cMenuTimers::OnOff(void) { cTimer *timer = CurrentTimer(); if (timer) { - if (timer->IsSingleEvent()) - timer->active = !timer->active; - else if (timer->firstday) { - timer->firstday = 0; - timer->active = false; - } - else if (timer->active) - timer->Skip(); - else - timer->active = true; - timer->Matches(); // refresh start and end time + timer->OnOff(); RefreshCurrent(); DisplayCurrent(true); - if (timer->firstday) + if (timer->FirstDay()) isyslog("timer %d first day set to %s", timer->Index() + 1, timer->PrintFirstDay()); else - isyslog("timer %d %sactivated", timer->Index() + 1, timer->active ? "" : "de"); + isyslog("timer %d %sactivated", timer->Index() + 1, timer->Active() ? "" : "de"); Timers.Save(); } return osContinue; @@ -1032,7 +992,7 @@ eOSState cMenuTimers::Del(void) // Check if this timer is active: cTimer *ti = CurrentTimer(); if (ti) { - if (!ti->recording) { + if (!ti->Recording()) { if (Interface->Confirm(tr("Delete timer?"))) { int Index = ti->Index(); Timers.Del(ti); @@ -1062,8 +1022,8 @@ eOSState cMenuTimers::Summary(void) if (HasSubMenu() || Count() == 0) return osContinue; cTimer *ti = CurrentTimer(); - if (ti && ti->summary && *ti->summary) - return AddSubMenu(new cMenuText(tr("Summary"), ti->summary)); + if (ti && !isempty(ti->Summary())) + return AddSubMenu(new cMenuText(tr("Summary"), ti->Summary())); return Edit(); // convenience for people not using the Summary feature ;-) } @@ -2675,7 +2635,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer) timer = new cTimer(true); Timers.Add(timer); Timers.Save(); - asprintf(&instantId, cDevice::NumDevices() > 1 ? "%s - %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), device->CardIndex() + 1); + asprintf(&instantId, cDevice::NumDevices() > 1 ? "%s - %d" : "%s", timer->Channel()->Name(), device->CardIndex() + 1); } timer->SetPending(true); timer->SetRecording(true); @@ -2692,8 +2652,8 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer) cRecording Recording(timer, Title, Subtitle, Summary); fileName = strdup(Recording.FileName()); cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); - cChannel *ch = Channels.GetByNumber(timer->channel); - recorder = new cRecorder(fileName, ch->Ca(), timer->priority, ch->Vpid(), ch->Apid1(), ch->Apid2(), ch->Dpid1(), ch->Dpid2()); + const cChannel *ch = timer->Channel(); + recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apid1(), ch->Apid2(), ch->Dpid1(), ch->Dpid2()); if (device->AttachReceiver(recorder)) { Recording.WriteSummary(); cStatus::MsgRecording(device, Recording.Name()); @@ -2713,8 +2673,8 @@ cRecordControl::~cRecordControl() bool cRecordControl::GetEventInfo(void) { - cChannel *channel = Channels.GetByNumber(timer->channel); - time_t Time = timer->active == taActInst ? timer->StartTime() + INSTANT_REC_EPG_LOOKAHEAD : timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2; + const cChannel *channel = timer->Channel(); + time_t Time = timer->Active() == taActInst ? timer->StartTime() + INSTANT_REC_EPG_LOOKAHEAD : timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2; for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) { { cMutexLock MutexLock; @@ -2759,7 +2719,7 @@ bool cRecordControl::Process(time_t t) { if (!recorder || !timer || !timer->Matches(t)) return false; - AssertFreeDiskSpace(timer->priority); + AssertFreeDiskSpace(timer->Priority()); return true; } @@ -2769,12 +2729,12 @@ cRecordControl *cRecordControls::RecordControls[MAXRECORDCONTROLS] = { NULL }; bool cRecordControls::Start(cTimer *Timer) { - int ch = Timer ? Timer->channel : cDevice::CurrentChannel(); + int ch = Timer ? Timer->Channel()->Number() : cDevice::CurrentChannel(); cChannel *channel = Channels.GetByNumber(ch); if (channel) { bool NeedsDetachReceivers = false; - cDevice *device = cDevice::GetDevice(channel, Timer ? Timer->priority : Setup.DefaultPriority, &NeedsDetachReceivers); + cDevice *device = cDevice::GetDevice(channel, Timer ? Timer->Priority() : Setup.DefaultPriority, &NeedsDetachReceivers); if (device) { if (NeedsDetachReceivers) Stop(device); @@ -2789,7 +2749,7 @@ bool cRecordControls::Start(cTimer *Timer) } } } - else if (!Timer || (Timer->priority >= Setup.PrimaryLimit && !Timer->pending)) + else if (!Timer || (Timer->Priority() >= Setup.PrimaryLimit && !Timer->Pending())) isyslog("no free DVB device to record channel %d!", ch); } else diff --git a/recording.c b/recording.c index 1be6623b..ba85ded1 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.69 2002/10/13 09:08:45 kls Exp $ + * $Id: recording.c 1.70 2002/10/20 11:54:29 kls Exp $ */ #include "recording.h" @@ -307,13 +307,13 @@ cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, c name = NULL; // set up the actual name: if (isempty(Title)) - Title = Channels.GetChannelNameByNumber(Timer->channel); + Title = Timer->Channel()->Name(); if (isempty(Subtitle)) Subtitle = " "; - char *macroTITLE = strstr(Timer->file, TIMERMACRO_TITLE); - char *macroEPISODE = strstr(Timer->file, TIMERMACRO_EPISODE); + char *macroTITLE = strstr(Timer->File(), TIMERMACRO_TITLE); + char *macroEPISODE = strstr(Timer->File(), TIMERMACRO_EPISODE); if (macroTITLE || macroEPISODE) { - name = strdup(Timer->file); + name = strdup(Timer->File()); name = strreplace(name, TIMERMACRO_TITLE, Title); name = strreplace(name, TIMERMACRO_EPISODE, Subtitle); if (Timer->IsSingleEvent()) { @@ -322,16 +322,16 @@ cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, c } } else if (Timer->IsSingleEvent() || !Setup.UseSubtitle) - name = strdup(Timer->file); + name = strdup(Timer->File()); else - asprintf(&name, "%s~%s", Timer->file, Subtitle); + asprintf(&name, "%s~%s", Timer->File(), Subtitle); // substitute characters that would cause problems in file names: strreplace(name, '\n', ' '); start = Timer->StartTime(); - priority = Timer->priority; - lifetime = Timer->lifetime; + priority = Timer->Priority(); + lifetime = Timer->Lifetime(); // handle summary: - summary = !isempty(Timer->summary) ? strdup(Timer->summary) : NULL; + summary = !isempty(Timer->Summary()) ? strdup(Timer->Summary()) : NULL; if (!summary) { if (isempty(Subtitle)) Subtitle = ""; diff --git a/recording.h b/recording.h index 2fae49ee..82f2fcca 100644 --- a/recording.h +++ b/recording.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.h 1.24 2002/06/22 10:09:27 kls Exp $ + * $Id: recording.h 1.25 2002/10/19 15:48:52 kls Exp $ */ #ifndef __RECORDING_H @@ -12,6 +12,7 @@ #include <time.h> #include "config.h" +#include "timers.h" #include "tools.h" void RemoveDeletedRecordings(void); @@ -10,7 +10,7 @@ * and interact with the Video Disk Recorder - or write a full featured * graphical interface that sits on top of an SVDRP connection. * - * $Id: svdrp.c 1.46 2002/10/19 11:48:02 kls Exp $ + * $Id: svdrp.c 1.47 2002/10/20 10:24:20 kls Exp $ */ #include "svdrp.h" @@ -31,6 +31,7 @@ #include "device.h" #include "keys.h" #include "remote.h" +#include "timers.h" #include "tools.h" // --- cSocket --------------------------------------------------------------- @@ -487,7 +488,7 @@ void cSVDRP::CmdDELT(const char *Option) if (isnumber(Option)) { cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1); if (timer) { - if (!timer->recording) { + if (!timer->Recording()) { Timers.Del(timer); Timers.Save(); isyslog("timer %s deleted", Option); @@ -806,16 +807,16 @@ void cSVDRP::CmdMODT(const char *Option) if (timer) { cTimer t = *timer; if (strcasecmp(tail, "ON") == 0) - t.active = 1; + t.SetActive(taActive); else if (strcasecmp(tail, "OFF") == 0) - t.active = 0; + t.SetActive(taInactive); else if (!t.Parse(tail)) { Reply(501, "Error in timer settings"); return; } *timer = t; Timers.Save(); - isyslog("timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive"); + isyslog("timer %d modified (%s)", timer->Index() + 1, timer->Active() ? "active" : "inactive"); Reply(250, "%d %s", timer->Index() + 1, timer->ToText()); } else diff --git a/timers.c b/timers.c new file mode 100644 index 00000000..76f86a5e --- /dev/null +++ b/timers.c @@ -0,0 +1,408 @@ +/* + * timers.c: Timer handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: timers.c 1.1 2002/10/20 12:28:55 kls Exp $ + */ + +#include "timers.h" +#include <ctype.h> +#include "channels.h" +#include "i18n.h" + +// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' +// format characters in order to allow any number of blanks after a numeric +// value! + +// -- cTimer ----------------------------------------------------------------- + +char *cTimer::buffer = NULL; + +cTimer::cTimer(bool Instant) +{ + startTime = stopTime = 0; + recording = pending = false; + active = Instant ? taActInst : taInactive; + channel = Channels.GetByNumber(cDevice::CurrentChannel()); + time_t t = time(NULL); + struct tm tm_r; + struct tm *now = localtime_r(&t, &tm_r); + day = now->tm_mday; + start = now->tm_hour * 100 + now->tm_min; + stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime; + stop = (stop / 60) * 100 + (stop % 60); + if (stop >= 2400) + stop -= 2400; + priority = Setup.DefaultPriority; + lifetime = Setup.DefaultLifetime; + *file = 0; + firstday = 0; + summary = NULL; + if (Instant && channel) + snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : channel->Name()); +} + +cTimer::cTimer(const cEventInfo *EventInfo) +{ + startTime = stopTime = 0; + recording = pending = false; + active = true; + channel = Channels.GetByServiceID(EventInfo->GetServiceID()); + time_t tstart = EventInfo->GetTime(); + time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60; + tstart -= Setup.MarginStart * 60; + struct tm tm_r; + struct tm *time = localtime_r(&tstart, &tm_r); + day = time->tm_mday; + start = time->tm_hour * 100 + time->tm_min; + time = localtime_r(&tstop, &tm_r); + stop = time->tm_hour * 100 + time->tm_min; + if (stop >= 2400) + stop -= 2400; + priority = Setup.DefaultPriority; + lifetime = Setup.DefaultLifetime; + *file = 0; + const char *Title = EventInfo->GetTitle(); + if (!isempty(Title)) + strn0cpy(file, EventInfo->GetTitle(), sizeof(file)); + firstday = 0; + summary = NULL; +} + +cTimer::~cTimer() +{ + free(summary); +} + +cTimer& cTimer::operator= (const cTimer &Timer) +{ + memcpy(this, &Timer, sizeof(*this)); + if (summary) + summary = strdup(summary); + return *this; +} + +bool cTimer::operator< (const cListObject &ListObject) +{ + cTimer *ti = (cTimer *)&ListObject; + time_t t1 = StartTime(); + time_t t2 = ti->StartTime(); + return t1 < t2 || (t1 == t2 && priority > ti->priority); +} + +const char *cTimer::ToText(cTimer *Timer) +{ + free(buffer); + strreplace(Timer->file, ':', '|'); + strreplace(Timer->summary, '\n', '|'); + asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->Channel()->Number(), PrintDay(Timer->day, Timer->firstday), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); + strreplace(Timer->summary, '|', '\n'); + strreplace(Timer->file, '|', ':'); + return buffer; +} + +const char *cTimer::ToText(void) +{ + return ToText(this); +} + +int cTimer::TimeToInt(int t) +{ + return (t / 100 * 60 + t % 100) * 60; +} + +int cTimer::ParseDay(const char *s, time_t *FirstDay) +{ + char *tail; + int d = strtol(s, &tail, 10); + if (FirstDay) + *FirstDay = 0; + if (tail && *tail) { + d = 0; + if (tail == s) { + const char *first = strchr(s, '@'); + int l = first ? first - s : strlen(s); + if (l == 7) { + for (const char *p = s + 6; p >= s; p--) { + d <<= 1; + d |= (*p != '-'); + } + d |= 0x80000000; + } + if (FirstDay && first) { + ++first; + if (strlen(first) == 10) { + struct tm tm_r; + if (3 == sscanf(first, "%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) { + tm_r.tm_year -= 1900; + tm_r.tm_mon--; + tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0; + tm_r.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting + *FirstDay = mktime(&tm_r); + } + } + else + d = 0; + } + } + } + else if (d < 1 || d > 31) + d = 0; + return d; +} + +const char *cTimer::PrintDay(int d, time_t FirstDay) +{ +#define DAYBUFFERSIZE 32 + static char buffer[DAYBUFFERSIZE]; + if ((d & 0x80000000) != 0) { + char *b = buffer; + const char *w = tr("MTWTFSS"); + while (*w) { + *b++ = (d & 1) ? *w : '-'; + d >>= 1; + w++; + } + if (FirstDay) { + struct tm tm_r; + localtime_r(&FirstDay, &tm_r); + b += strftime(b, DAYBUFFERSIZE - (b - buffer), "@%Y-%m-%d", &tm_r); + } + *b = 0; + } + else + sprintf(buffer, "%d", d); + return buffer; +} + +const char *cTimer::PrintFirstDay(void) +{ + if (firstday) { + const char *s = PrintDay(day, firstday); + if (strlen(s) == 18) + return s + 8; + } + return ""; // not NULL, so the caller can always use the result +} + +bool cTimer::Parse(const char *s) +{ + char *buffer1 = NULL; + char *buffer2 = NULL; + free(summary); + summary = NULL; + //XXX Apparently sscanf() doesn't work correctly if the last %a argument + //XXX results in an empty string (this first occured when the EIT gathering + //XXX was put into a separate thread - don't know why this happens... + //XXX As a cure we copy the original string and add a blank. + //XXX If anybody can shed some light on why sscanf() failes here, I'd love + //XXX to hear about that! + char *s2 = NULL; + int l2 = strlen(s); + while (l2 > 0 && isspace(s[l2 - 1])) + l2--; + if (s[l2 - 1] == ':') { + s2 = MALLOC(char, l2 + 3); + strcat(strn0cpy(s2, s, l2 + 1), " \n"); + s = s2; + } + int ch = 0; + if (8 <= sscanf(s, "%d :%d :%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &active, &ch, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) { + if (summary && !*skipspace(summary)) { + free(summary); + summary = NULL; + } + //TODO add more plausibility checks + day = ParseDay(buffer1, &firstday); + strn0cpy(file, buffer2, MaxFileName); + strreplace(file, '|', ':'); + strreplace(summary, '|', '\n'); + free(buffer1); + free(buffer2); + free(s2); + channel = Channels.GetByNumber(ch); + if (!channel) { + esyslog("ERROR: channel %d not defined", ch); + return false; + } + return day != 0; + } + free(s2); + return false; +} + +bool cTimer::Save(FILE *f) +{ + return fprintf(f, ToText()) > 0; +} + +bool cTimer::IsSingleEvent(void) +{ + return (day & 0x80000000) == 0; +} + +int cTimer::GetMDay(time_t t) +{ + struct tm tm_r; + return localtime_r(&t, &tm_r)->tm_mday; +} + +int cTimer::GetWDay(time_t t) +{ + struct tm tm_r; + int weekday = localtime_r(&t, &tm_r)->tm_wday; + return weekday == 0 ? 6 : weekday - 1; // we start with monday==0! +} + +bool cTimer::DayMatches(time_t t) +{ + return IsSingleEvent() ? GetMDay(t) == day : (day & (1 << GetWDay(t))) != 0; +} + +time_t cTimer::IncDay(time_t t, int Days) +{ + struct tm tm_r; + tm tm = *localtime_r(&t, &tm_r); + tm.tm_mday += Days; // now tm_mday may be out of its valid range + int h = tm.tm_hour; // save original hour to compensate for DST change + tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting + t = mktime(&tm); // normalize all values + tm.tm_hour = h; // compensate for DST change + return mktime(&tm); // calculate final result +} + +time_t cTimer::SetTime(time_t t, int SecondsFromMidnight) +{ + struct tm tm_r; + tm tm = *localtime_r(&t, &tm_r); + tm.tm_hour = SecondsFromMidnight / 3600; + tm.tm_min = (SecondsFromMidnight % 3600) / 60; + tm.tm_sec = SecondsFromMidnight % 60; + tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting + return mktime(&tm); +} + +char *cTimer::SetFile(const char *File) +{ + if (!isempty(File)) + strn0cpy(file, File, sizeof(file)); + return file; +} + +bool cTimer::Matches(time_t t) +{ + startTime = stopTime = 0; + if (t == 0) + t = time(NULL); + + int begin = TimeToInt(start); // seconds from midnight + int length = TimeToInt(stop) - begin; + if (length < 0) + length += SECSINDAY; + + int DaysToCheck = IsSingleEvent() ? 61 : 7; // 61 to handle months with 31/30/31 + for (int i = -1; i <= DaysToCheck; i++) { + time_t t0 = IncDay(t, i); + if (DayMatches(t0)) { + time_t a = SetTime(t0, begin); + time_t b = a + length; + if ((!firstday || a >= firstday) && t <= b) { + startTime = a; + stopTime = b; + break; + } + } + } + if (!startTime) + startTime = firstday; // just to have something that's more than a week in the future + else if (t > startTime || t > firstday + SECSINDAY + 3600) // +3600 in case of DST change + firstday = 0; + return active && startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers +} + +time_t cTimer::StartTime(void) +{ + if (!startTime) + Matches(); + return startTime; +} + +time_t cTimer::StopTime(void) +{ + if (!stopTime) + Matches(); + return stopTime; +} + +void cTimer::SetRecording(bool Recording) +{ + recording = Recording; + isyslog("timer %d %s", Index() + 1, recording ? "start" : "stop"); +} + +void cTimer::SetPending(bool Pending) +{ + pending = Pending; +} + +void cTimer::SetActive(int Active) +{ + active = Active; +} + +void cTimer::Skip(void) +{ + firstday = IncDay(SetTime(StartTime(), 0), 1); +} + +void cTimer::OnOff(void) +{ + if (IsSingleEvent()) + active = !active; + else if (firstday) { + firstday = 0; + active = false; + } + else if (active) + Skip(); + else + active = true; + Matches(); // refresh start and end time +} + +// -- cTimers ---------------------------------------------------------------- + +cTimers Timers; + +cTimer *cTimers::GetTimer(cTimer *Timer) +{ + for (cTimer *ti = First(); ti; ti = Next(ti)) { + if (ti->Channel() == Timer->Channel() && ti->Day() == Timer->Day() && ti->Start() == Timer->Start() && ti->Stop() == Timer->Stop()) + return ti; + } + return NULL; +} + +cTimer *cTimers::GetMatch(time_t t) +{ + cTimer *t0 = NULL; + for (cTimer *ti = First(); ti; ti = Next(ti)) { + if (!ti->Recording() && ti->Matches(t)) { + if (!t0 || ti->Priority() > t0->Priority()) + t0 = ti; + } + } + return t0; +} + +cTimer *cTimers::GetNextActiveTimer(void) +{ + cTimer *t0 = NULL; + for (cTimer *ti = First(); ti; ti = Next(ti)) { + if (ti->Active() && (!t0 || *ti < *t0)) + t0 = ti; + } + return t0; +} diff --git a/timers.h b/timers.h new file mode 100644 index 00000000..8dc762e3 --- /dev/null +++ b/timers.h @@ -0,0 +1,91 @@ +/* + * timers.h: Timer handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: timers.h 1.1 2002/10/20 11:52:23 kls Exp $ + */ + +#ifndef __TIMERS_H +#define __TIMERS_H + +#include "channels.h" +#include "config.h" +#include "tools.h" + +enum eTimerActive { taInactive = 0, + taActive = 1, + taInstant = 2, + taActInst = (taActive | taInstant) + }; + +class cTimer : public cListObject { + friend class cMenuEditTimer; +private: + time_t startTime, stopTime; + static char *buffer; + bool recording, pending; + int active; + cChannel *channel; + int day; + int start; + int stop; + int priority; + int lifetime; + char file[MaxFileName]; + time_t firstday; + char *summary; + static const char *ToText(cTimer *Timer); +public: + cTimer(bool Instant = false); + cTimer(const cEventInfo *EventInfo); + virtual ~cTimer(); + cTimer& operator= (const cTimer &Timer); + virtual bool operator< (const cListObject &ListObject); + bool Recording(void) { return recording; } + bool Pending(void) { return pending; } + int Active(void) { return active; } + const cChannel *Channel(void) { return channel; } + int Day(void) { return day; } + int Start(void) { return start; } + int Stop(void) { return stop; } + int Priority(void) { return priority; } + int Lifetime(void) { return lifetime; } + const char *File(void) { return file; } + time_t FirstDay(void) { return firstday; } + const char *Summary(void) { return summary; } + const char *ToText(void); + bool Parse(const char *s); + bool Save(FILE *f); + bool IsSingleEvent(void); + int GetMDay(time_t t); + int GetWDay(time_t t); + bool DayMatches(time_t t); + static time_t IncDay(time_t t, int Days); + static time_t SetTime(time_t t, int SecondsFromMidnight); + char *SetFile(const char *File); + bool Matches(time_t t = 0); + time_t StartTime(void); + time_t StopTime(void); + void SetRecording(bool Recording); + void SetPending(bool Pending); + void SetActive(int Active); + void Skip(void); + void OnOff(void); + const char *PrintFirstDay(void); + static int TimeToInt(int t); + static int ParseDay(const char *s, time_t *FirstDay = NULL); + static const char *PrintDay(int d, time_t FirstDay = 0); + }; + +class cTimers : public cConfig<cTimer> { +public: + cTimer *GetTimer(cTimer *Timer); + cTimer *GetMatch(time_t t); + cTimer *GetNextActiveTimer(void); + }; + +extern cTimers Timers; + +#endif //__TIMERS_H @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.127 2002/10/13 12:13:19 kls Exp $ + * $Id: vdr.c 1.128 2002/10/20 12:09:45 kls Exp $ */ #include <getopt.h> @@ -47,6 +47,7 @@ #include "rcu.h" #include "recording.h" #include "sources.h" +#include "timers.h" #include "tools.h" #include "videodir.h" @@ -603,8 +604,8 @@ int main(int argc, char *argv[]) if (WatchdogTimeout > 0) signal(SIGALRM, SIG_IGN); if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) { - int Channel = timer ? timer->channel : 0; - const char *File = timer ? timer->file : ""; + int Channel = timer ? timer->Channel()->Number() : 0; + const char *File = timer ? timer->File() : ""; char *cmd; asprintf(&cmd, "%s %ld %ld %d \"%s\" %d", Shutdown, Next, Delta, Channel, strescape(File, "\"$"), UserShutdown); isyslog("executing '%s'", cmd); |