From ab4ceb29a033f8a3cc051d5ea9a6f20ca6e75f8a Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sat, 19 Oct 2002 15:33:37 +0200 Subject: [PATCH] Implemented gaps in channel numbering --- HISTORY | 5 ++++ channels.c | 73 ++++++++++++++++++++++++++++++++---------------------- channels.h | 4 +-- device.c | 6 ++--- eitscan.c | 6 ++--- menu.c | 59 ++++++++++++++++++++++++++++++++----------- svdrp.c | 26 ++++++++++--------- tools.c | 9 ++++++- tools.h | 3 ++- vdr.5 | 16 +++++++++--- 10 files changed, 137 insertions(+), 70 deletions(-) diff --git a/HISTORY b/HISTORY index e55ff53b..df92d6b4 100644 --- a/HISTORY +++ b/HISTORY @@ -1619,3 +1619,8 @@ Video Disk Recorder Revision History - Fixed a small glitch when switching channels (thanks to Dennis Noordsij for reporting this one). - Fixed handling multiple 'CaCaps' entries in 'setup.conf'. +- Group separators in 'channels.conf' may now be given like ':@201 My Channels', + where '@201' indicates the number to be given to the next channel. This can be + 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! diff --git a/channels.c b/channels.c index f86f8efb..5dd4b742 100644 --- a/channels.c +++ b/channels.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: channels.c 1.3 2002/10/06 12:41:49 kls Exp $ + * $Id: channels.c 1.4 2002/10/19 14:46:05 kls Exp $ */ #include "channels.h" @@ -158,6 +158,7 @@ cChannel::cChannel(void) tpid = 0; ca = 0; sid = 0; + number = 0; groupSep = false; //XXX polarization = 'v'; @@ -282,8 +283,12 @@ const char *cChannel::ToText(cChannel *Channel) strreplace(s, ':', '|'); } free(buffer); - if (Channel->groupSep) - asprintf(&buffer, ":%s\n", s); + if (Channel->groupSep) { + if (Channel->number) + asprintf(&buffer, ":@%d %s\n", Channel->number, s); + else + asprintf(&buffer, ":%s\n", s); + } else { char apidbuf[32]; char *q = apidbuf; @@ -308,13 +313,17 @@ const char *cChannel::ToText(void) bool cChannel::Parse(const char *s) { if (*s == ':') { - if (*++s) { - strn0cpy(name, s, MaxChannelName); - groupSep = true; - number = 0; + groupSep = true; + if (*++s == '@' && *++s) { + char *p = NULL; + errno = 0; + int n = strtol(s, &p, 10); + if (!errno && p != s && n > 0) { + number = n; + s = p; + } } - else - return false; + strn0cpy(name, skipspace(s), MaxChannelName); } else { groupSep = false; @@ -400,35 +409,39 @@ int cChannels::GetNextNormal(int Idx) void cChannels::ReNumber( void ) { - int Number = 0; - cChannel *ch = (cChannel *)First(); - while (ch) { - if (!ch->GroupSep()) - ch->SetNumber(++Number); - ch = (cChannel *)ch->Next(); - } - maxNumber = Number; + int Number = 1; + for (cChannel *channel = First(); channel; channel = Next(channel)) { + if (channel->GroupSep()) { + if (channel->Number() > Number) + Number = channel->Number(); + } + else + channel->SetNumber(Number++); + } + maxNumber = Number - 1; } -cChannel *cChannels::GetByNumber(int Number) +cChannel *cChannels::GetByNumber(int Number, int SkipGap) { - cChannel *channel = (cChannel *)First(); - while (channel) { - if (!channel->GroupSep() && channel->Number() == Number) - return channel; - channel = (cChannel *)channel->Next(); - } + cChannel *previous = NULL; + for (cChannel *channel = First(); channel; channel = Next(channel)) { + if (!channel->GroupSep()) { + if (channel->Number() == Number) + return channel; + else if (SkipGap && channel->Number() > Number) + return SkipGap > 0 ? channel : previous; + previous = channel; + } + } return NULL; } cChannel *cChannels::GetByServiceID(unsigned short ServiceId) { - cChannel *channel = (cChannel *)First(); - while (channel) { - if (!channel->GroupSep() && channel->Sid() == ServiceId) - return channel; - channel = (cChannel *)channel->Next(); - } + for (cChannel *channel = First(); channel; channel = Next(channel)) { + if (!channel->GroupSep() && channel->Sid() == ServiceId) + return channel; + } return NULL; } diff --git a/channels.h b/channels.h index 8a784f75..d014cf3a 100644 --- a/channels.h +++ b/channels.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: channels.h 1.1 2002/10/05 13:53:15 kls Exp $ + * $Id: channels.h 1.2 2002/10/19 11:48:02 kls Exp $ */ #ifndef __CHANNELS_H @@ -112,7 +112,7 @@ public: int GetPrevGroup(int Idx); // Get previous channel group int GetNextNormal(int Idx); // Get next normal channel (not group) void ReNumber(void); // Recalculate 'number' based on channel type - cChannel *GetByNumber(int Number); + cChannel *GetByNumber(int Number, int SkipGap = 0); cChannel *GetByServiceID(unsigned short ServiceId); const char *GetChannelNameByNumber(int Number); bool SwitchTo(int Number); diff --git a/device.c b/device.c index 637632b4..bfe4edbc 100644 --- a/device.c +++ b/device.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.c 1.27 2002/10/12 13:24:37 kls Exp $ + * $Id: device.c 1.28 2002/10/19 11:48:02 kls Exp $ */ #include "device.h" @@ -324,11 +324,11 @@ bool cDevice::SwitchChannel(int Direction) int first = n; PrimaryDevice()->StopReplay(); // otherwise a running Transfer Mode would block channels cChannel *channel; - while ((channel = Channels.GetByNumber(n)) != NULL) { + while ((channel = Channels.GetByNumber(n, Direction)) != NULL) { // try only channels which are currently available if (PrimaryDevice()->ProvidesChannel(channel, Setup.PrimaryLimit) || GetDevice(channel, 0)) break; - n += Direction; + n = channel->Number() + 1; } if (channel) { int d = n - first; diff --git a/eitscan.c b/eitscan.c index c29b6b57..2a89cec9 100644 --- a/eitscan.c +++ b/eitscan.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: eitscan.c 1.8 2002/10/05 13:44:35 kls Exp $ + * $Id: eitscan.c 1.9 2002/10/19 11:48:02 kls Exp $ */ #include "eitscan.h" @@ -63,7 +63,7 @@ void cEITScanner::Process(void) ch = 1; numTransponders = 0; } - cChannel *Channel = Channels.GetByNumber(ch); + cChannel *Channel = Channels.GetByNumber(ch, 1); if (Channel) { if (!Device->ProvidesChannel(Channel)) break; @@ -75,7 +75,7 @@ void cEITScanner::Process(void) break; } } - ch++; + ch = Channel->Number() + 1; } } } diff --git a/menu.c b/menu.c index 077922a1..286820ef 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.217 2002/10/13 12:10:54 kls Exp $ + * $Id: menu.c 1.218 2002/10/19 15:33:37 kls Exp $ */ #include "menu.h" @@ -33,7 +33,7 @@ #define MAXRECORDCONTROLS (MAXDEVICES * MAXRECEIVERS) #define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours -#define CHNUMWIDTH (Channels.Count() > 999 ? 5 : 4) // there are people with more than 999 channels... +#define CHNUMWIDTH (numdigits(Channels.MaxNumber()) + 1) // --- cMenuEditChanItem ----------------------------------------------------- @@ -42,6 +42,7 @@ protected: virtual void Set(void); public: cMenuEditChanItem(const char *Name, int *Value); + virtual eOSState ProcessKey(eKeys Key); }; cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value) @@ -54,13 +55,32 @@ void cMenuEditChanItem::Set(void) { char buf[255]; cChannel *channel = Channels.GetByNumber(*value); - if (channel) - snprintf(buf, sizeof(buf), "%d %s", *value, channel->Name()); - else - *buf = 0; + snprintf(buf, sizeof(buf), "%d %s", *value, channel ? channel->Name() : ""); SetValue(buf); } +eOSState cMenuEditChanItem::ProcessKey(eKeys Key) +{ + int delta = 1; + + switch (Key) { + case kLeft|k_Repeat: + case kLeft: delta = -1; + case kRight|k_Repeat: + case kRight: + { + cChannel *channel = Channels.GetByNumber(*value + delta, delta); + if (channel) { + *value = channel->Number(); + Set(); + } + } + break; + default : return cMenuEditIntItem::ProcessKey(Key); + } + return osContinue; +} + // --- cMenuEditTranItem ----------------------------------------------------- class cMenuEditTranItem : public cMenuEditChanItem { @@ -2383,10 +2403,17 @@ void cDisplayChannel::DisplayChannel(const cChannel *Channel) { int BufSize = Width() + 1; char buffer[BufSize]; - if (Channel && Channel->Number() > 0) - snprintf(buffer, BufSize, "%d%s %s", Channel->Number(), number ? "-" : "", Channel->Name()); + *buffer = 0; + if (Channel) { + if (Channel->Number() > 0) + snprintf(buffer, BufSize, "%d%s %s", Channel->Number(), number ? "-" : "", Channel->Name()); + else if (Channel->Name()) + snprintf(buffer, BufSize, "%s", Channel->Name()); + } + else if (number) + snprintf(buffer, BufSize, "%d-", number); else - snprintf(buffer, BufSize, "%s", Channel ? Channel->Name() : tr("*** Invalid Channel ***")); + snprintf(buffer, BufSize, "%s", tr("*** Invalid Channel ***")); Interface->Fill(0, 0, Setup.OSDwidth, 1, clrBackground); Interface->Write(0, 0, buffer); const char *date = DayDateTime(); @@ -2468,10 +2495,6 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) cChannel *channel = Channels.GetByNumber(number); DisplayChannel(channel); lastTime = time_ms(); - if (!channel) { - number = -1; - lastTime += 1000; - } } } break; @@ -2505,8 +2528,14 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) break; case kNone: if (number && time_ms() - lastTime > DIRECTCHANNELTIMEOUT) { - if (number > 0 && !Channels.SwitchTo(number)) - number = -1; + if (Channels.GetByNumber(number)) + Channels.SwitchTo(number); + else { + number = 0; + DisplayChannel(NULL); + lastTime = time_ms(); + return osContinue; + } return osEnd; } break; diff --git a/svdrp.c b/svdrp.c index 41171493..114be09a 100644 --- a/svdrp.c +++ b/svdrp.c @@ -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.45 2002/10/13 09:31:31 kls Exp $ + * $Id: svdrp.c 1.46 2002/10/19 11:48:02 kls Exp $ */ #include "svdrp.h" @@ -413,12 +413,12 @@ void cSVDRP::CmdCHAN(const char *Option) else { int i = 1; cChannel *channel; - while ((channel = Channels.GetByNumber(i)) != NULL) { + while ((channel = Channels.GetByNumber(i, 1)) != NULL) { if (strcasecmp(channel->Name(), Option) == 0) { n = i; break; } - i++; + i = channel->Number() + 1; } } if (n < 0) { @@ -640,7 +640,7 @@ void cSVDRP::CmdLSTC(const char *Option) int i = 1; cChannel *next = NULL; while (i <= Channels.MaxNumber()) { - cChannel *channel = Channels.GetByNumber(i); + cChannel *channel = Channels.GetByNumber(i, 1); if (channel) { if (strcasestr(channel->Name(), Option)) { if (next) @@ -652,7 +652,7 @@ void cSVDRP::CmdLSTC(const char *Option) Reply(501, "Channel \"%d\" not found", i); return; } - i++; + i = channel->Number() + 1; } if (next) Reply(250, "%d %s", next->Number(), next->ToText()); @@ -661,13 +661,15 @@ void cSVDRP::CmdLSTC(const char *Option) } } else if (Channels.MaxNumber() >= 1) { - for (int i = 1; i <= Channels.MaxNumber(); i++) { - cChannel *channel = Channels.GetByNumber(i); - if (channel) - Reply(i < Channels.MaxNumber() ? -250 : 250, "%d %s", channel->Number(), channel->ToText()); - else - Reply(501, "Channel \"%d\" not found", i); - } + int i = 1; + while (i <= Channels.MaxNumber()) { + cChannel *channel = Channels.GetByNumber(i, 1); + if (channel) + Reply(channel->Number() < Channels.MaxNumber() ? -250 : 250, "%d %s", channel->Number(), channel->ToText()); + else + Reply(501, "Channel \"%d\" not found", i); + i = channel->Number() + 1; + } } else Reply(550, "No channels defined"); diff --git a/tools.c b/tools.c index b3b64fc9..df2d5705 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.71 2002/09/09 21:35:49 kls Exp $ + * $Id: tools.c 1.72 2002/10/19 12:32:53 kls Exp $ */ #include "tools.h" @@ -207,6 +207,13 @@ bool isempty(const char *s) return !(s && *skipspace(s)); } +int numdigits(int n) +{ + char buf[16]; + snprintf(buf, sizeof(buf), "%d", n); + return strlen(buf); +} + int time_ms(void) { static time_t t0 = 0; diff --git a/tools.h b/tools.h index f8bf43f2..08f2429b 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.50 2002/09/08 10:22:29 kls Exp $ + * $Id: tools.h 1.51 2002/10/19 12:31:50 kls Exp $ */ #ifndef __TOOLS_H @@ -64,6 +64,7 @@ const char *strescape(const char *s, const char *chars); // returns a statically bool startswith(const char *s, const char *p); bool endswith(const char *s, const char *p); bool isempty(const char *s); +int numdigits(int n); int time_ms(void); void delay_ms(int ms); bool isnumber(const char *s); diff --git a/vdr.5 b/vdr.5 index ccb7b924..1d4e25ad 100644 --- a/vdr.5 +++ b/vdr.5 @@ -8,9 +8,9 @@ .\" License as specified in the file COPYING that comes with the .\" vdr distribution. .\" -.\" $Id: vdr.5 1.8 2002/10/13 12:14:49 kls Exp $ +.\" $Id: vdr.5 1.9 2002/10/19 12:45:23 kls Exp $ .\" -.TH vdr 5 "7 Sep 2002" "1.2.0" "Video Disk Recorder Files" +.TH vdr 5 "7 Oct 2002" "1.2.0" "Video Disk Recorder Files" .SH NAME vdr file formats - the Video Disk Recorder Files .SH DESCRIPTION @@ -26,12 +26,22 @@ character, followed by arbitrary text. Example: \fB:First group\fR +Group delimiters may also be used to specify the number of the next channel. +To do this, the character '@' and a number must immediately follow the ':', +as in + +\fB:@201 First group\fR + +The given number must be larger than the number of any previous channel +(otherwise it is silently ignored). + A \fBchannel definition\fR is a line with channel data, where the fields are separated by ':' characters. Example: \fBRTL:12188:h:S19.2E:27500:163:104:105:0:12003\fR -The line number of a channel definition (not counting group separators!) +The line number of a channel definition (not counting group separators, +and based on a possible previous '@...' parameter) defines the channel's number in OSD menus and the \fItimers.conf\fR file. The fields in a channel definition have the following meaning (from left