Implemented 'channel grouping'

This commit is contained in:
Klaus Schmidinger 2000-09-09 14:57:43 +02:00
parent d4eb96f725
commit c00d4ea326
17 changed files with 437 additions and 168 deletions

View File

@ -10,6 +10,8 @@ Carsten Koch <Carsten.Koch@icem.de>
Plamen Ganev <pganev@com-it.net> Plamen Ganev <pganev@com-it.net>
for fixing the frequency offset for Hotbird channels for fixing the frequency offset for Hotbird channels
for adding the 'xtvrc2vdr' tool (see Tools/xtvrc2vdr) for adding the 'xtvrc2vdr' tool (see Tools/xtvrc2vdr)
for adding the 'dvbrc2vdr' tool (see Tools/dvbrc2vdr)
for implementing "channel grouping"
Heino Goldenstein <heino.goldenstein@microplex.de> Heino Goldenstein <heino.goldenstein@microplex.de>
for modifying scrolling through lists to make it page up and down for modifying scrolling through lists to make it page up and down
@ -19,3 +21,6 @@ Guido Fiala <gfiala@s.netic.de>
Robert Schneider <Robert.Schneider@lotus.com> Robert Schneider <Robert.Schneider@lotus.com>
for implementing EIT support for displaying the current/next info for implementing EIT support for displaying the current/next info
Niels de Carpentier <niels@casema.net>
for adding a workaround for a driver timing problem in cDvbApi::Cmd().

35
FORMATS Normal file
View File

@ -0,0 +1,35 @@
Video Disk Recorder File Formats
--------------------------------
* channels.conf
This file contains the channel setup.
It consists of two types of lines: "group delimiters" and "channel
definitions".
A "group delimiter" is a line starting with a ':' as the very first
character, followed by arbitrary text.
Example: ":First group"
A "channel definition" is a line with channel data, where the fields
are separated by ':' characters:
Example: "RTL:12188:h:1:27500:163:104:0:12003"
The fields in a channel definition have the following meaning (from left
to right):
- Name: the channel's name (if the name originally contains a ':' character
it has to be replaced by '|')
- Frequency in MHz (as an integer)
- Polarization (one of 'h', 'H', 'v', 'V')
- Diseqc number
- Symbol rate
- Video PID
- Audio PID
- Conditional Access (0 = Free To Air, 1 = can be decrypted by the first
DVB card, 2 = can be decrypted by the second DVB card)
- Program Number
* timers.conf
TODO

20
HISTORY
View File

@ -138,3 +138,23 @@ Video Disk Recorder Revision History
done for some of the channels in the default 'channels.conf'. Some other done for some of the channels in the default 'channels.conf'. Some other
parameters in the default 'channels.conf' have also been updated, so please parameters in the default 'channels.conf' have also been updated, so please
make sure your timers still use the correct channels! make sure your timers still use the correct channels!
2000-09-09: Version 0.63
- Workaround for a driver timing problem in cDvbApi::Cmd(), which sometimes caused
the OSD to no longer be displayed (thanks to Niels de Carpentier).
- Added the '-m486' option to the compiler call.
- If a channel name contains a colon (':') it is now replaced with a '|' in
channels.conf.
- Not everybody appears to like the "page scrolling" mechanism introduced by
Heino Goldenstein in version 0.61, so the Makefile now reacts on NO_PAGE_SCROLL=1
to suppress that.
- The new 'dvbrc2vdr' tool (thanks to Plamen Ganev!) can be used to convert
'dvbrc' channel files into 'vdr' format.
- Channels can now be "grouped" (thanks to Plamen Ganev!). See MANUAL for details.
There is currently no mechanism to define and maintain "Channel groups" via
the menu, so you'll have to insert "Channel group" control lines into your
'channels.conf' file manually (for example with a text editor).
XXX additional fields for 'preferred' etc???
- Started a new file named FORMATS with a description of the various file
formats used by VDR.

16
MANUAL
View File

@ -12,8 +12,8 @@ Video Disk Recorder User's Manual
Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Play
Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause
Left - - - Disable Decrement - Search back Left Prev group - - Disable Decrement - Search back
Right - - - Enable Increment - Search forward Right Next group - - Enable Increment - Search forward
Ok Ch display Select Switch Edit Accept Play Progress disp. Ok Ch display Select Switch Edit Accept Play Progress disp.
Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on
Back - Menu off Main menu Main menu Discard Main menu - Back - Menu off Main menu Main menu Discard Main menu -
@ -72,6 +72,18 @@ Video Disk Recorder User's Manual
To bring up the channel display without switching channels you can press To bring up the channel display without switching channels you can press
the "Ok" button. the "Ok" button.
* Switching through channel groups
If the 'channels.conf' file contains "group separators" you can switch
through these groups by pressing the "Left" and "Right" key while no
menu is being displayed. The channel display will show the name of the
group, and if you press the "Ok" button while the group name is being
displayed, you will switch to the first channel of that group.
Channel groups can be whatever you decide them to be. You can either
group your channels by "Bouquet", by language, genre or whatever your
preferences may be.
* Instant Recording * Instant Recording
You can start recording the current channel by pressing the "Red" button You can start recording the current channel by pressing the "Red" button

View File

@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and # See the main source file 'vdr.c' for copyright information and
# how to reach the author. # how to reach the author.
# #
# $Id: Makefile 1.7 2000/09/03 09:26:24 kls Exp $ # $Id: Makefile 1.8 2000/09/03 15:38:18 kls Exp $
DVBDIR = ../DVB DVBDIR = ../DVB
@ -21,8 +21,12 @@ ifdef DEBUG_OSD
DEFINES += -DDEBUG_OSD DEFINES += -DDEBUG_OSD
endif endif
ifdef NO_PAGE_SCROLL
DEFINES += -DNO_PAGE_SCROLL
endif
%.o: %.c %.o: %.c
g++ -g -O2 -Wall -c $(DEFINES) $(INCLUDES) $< g++ -g -O2 -Wall -m486 -c $(DEFINES) $(INCLUDES) $<
all: vdr all: vdr

152
config.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.c 1.18 2000/09/03 09:20:22 kls Exp $ * $Id: config.c 1.19 2000/09/09 14:50:58 kls Exp $
*/ */
#include "config.h" #include "config.h"
@ -196,11 +196,23 @@ cChannel::cChannel(const cChannel *Channel)
apid = Channel ? Channel->apid : 256; apid = Channel ? Channel->apid : 256;
ca = Channel ? Channel->ca : 0; ca = Channel ? Channel->ca : 0;
pnr = Channel ? Channel->pnr : 0; pnr = Channel ? Channel->pnr : 0;
preferred = Channel ? Channel->preferred : 0;
groupSep = Channel ? Channel->groupSep : false;
} }
const char *cChannel::ToText(cChannel *Channel) const char *cChannel::ToText(cChannel *Channel)
{ {
asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", Channel->name, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->ca, Channel->pnr); char buf[MaxChannelName * 2];
char *s = Channel->name;
if (strchr(s, ':')) {
s = strcpy(buf, s);
strreplace(s, ':', '|');
}
delete buffer;
if (Channel->groupSep)
asprintf(&buffer, ":%s\n", s);
else
asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%d:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, Channel->apid, Channel->ca, Channel->pnr, Channel->preferred);
return buffer; return buffer;
} }
@ -212,13 +224,32 @@ const char *cChannel::ToText(void)
bool cChannel::Parse(const char *s) bool cChannel::Parse(const char *s)
{ {
char *buffer = NULL; char *buffer = NULL;
if (9 == sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &ca, &pnr)) { if (*s == ':') {
strncpy(name, buffer, MaxChannelName - 1); if (*++s) {
name[strlen(buffer)] = 0; strn0cpy(name, s, MaxChannelName);
delete buffer; name[strlen(name) - 1] = 0; // strip the '\n'
return true; groupSep = true;
}
else
return false;
} }
return false; else {
groupSep = false;
int fields = sscanf(s, "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d:%d", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apid, &ca, &pnr, &preferred);
#define VER062_FIELDS 9
#define VER063_FIELDS 10
if (fields == VER062_FIELDS || fields == VER063_FIELDS) {
strn0cpy(name, buffer, MaxChannelName);
delete buffer;
if (fields == VER062_FIELDS) {
preferred = 0;
}
}
else
return false;
}
strreplace(name, '|', ':');
return true;
} }
bool cChannel::Save(FILE *f) bool cChannel::Save(FILE *f)
@ -230,9 +261,9 @@ bool cChannel::Switch(cDvbApi *DvbApi)
{ {
if (!DvbApi) if (!DvbApi)
DvbApi = cDvbApi::PrimaryDvbApi; DvbApi = cDvbApi::PrimaryDvbApi;
if (!DvbApi->Recording()) { if (!DvbApi->Recording() && !groupSep) {
isyslog(LOG_INFO, "switching to channel %d", Index() + 1); isyslog(LOG_INFO, "switching to channel %d", number);
CurrentChannel = Index(); CurrentChannel = number;
for (int i = 3; i--;) { for (int i = 3; i--;) {
if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) { if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) {
EIT.SetProgramNumber(pnr); EIT.SetProgramNumber(pnr);
@ -242,22 +273,10 @@ bool cChannel::Switch(cDvbApi *DvbApi)
} }
return false; return false;
} }
Interface.Info("Channel locked (recording)!"); Interface.Info(DvbApi->Recording() ? "Channel locked (recording)!" : name);
return false; return false;
} }
bool cChannel::SwitchTo(int i, cDvbApi *DvbApi)
{
cChannel *channel = Channels.Get(i);
return channel && channel->Switch(DvbApi);
}
const char *cChannel::GetChannelName(int i)
{
cChannel *channel = Channels.Get(i);
return channel ? channel->name : NULL;
}
// -- cTimer ----------------------------------------------------------------- // -- cTimer -----------------------------------------------------------------
char *cTimer::buffer = NULL; char *cTimer::buffer = NULL;
@ -267,7 +286,8 @@ cTimer::cTimer(bool Instant)
startTime = stopTime = 0; startTime = stopTime = 0;
recording = false; recording = false;
active = Instant; active = Instant;
channel = CurrentChannel + 1; cChannel *ch = Channels.GetByNumber(CurrentChannel);
channel = ch ? ch->number : 0;
time_t t = time(NULL); time_t t = time(NULL);
struct tm *now = localtime(&t); struct tm *now = localtime(&t);
day = now->tm_mday; day = now->tm_mday;
@ -280,8 +300,8 @@ cTimer::cTimer(bool Instant)
lifetime = 99; lifetime = 99;
*file = 0; *file = 0;
summary = NULL; summary = NULL;
if (Instant) if (Instant && ch)
snprintf(file, sizeof(file), "@%s", cChannel::GetChannelName(CurrentChannel)); snprintf(file, sizeof(file), "@%s", ch->name);
} }
cTimer::~cTimer() cTimer::~cTimer()
@ -299,6 +319,7 @@ cTimer& cTimer::operator= (const cTimer &Timer)
const char *cTimer::ToText(cTimer *Timer) const char *cTimer::ToText(cTimer *Timer)
{ {
delete buffer;
asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : ""); asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : "");
return buffer; return buffer;
} }
@ -368,11 +389,7 @@ bool cTimer::Parse(const char *s)
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 (8 <= sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) {
//TODO add more plausibility checks //TODO add more plausibility checks
day = ParseDay(buffer1); day = ParseDay(buffer1);
int l = strlen(buffer2); strn0cpy(file, buffer2, MaxFileName);
if (l >= MaxFileName)
l = MaxFileName - 1;
strncpy(file, buffer2, l);
file[l] = 0;
delete buffer1; delete buffer1;
delete buffer2; delete buffer2;
return day != 0; return day != 0;
@ -470,10 +487,79 @@ cKeys Keys;
// -- cChannels -------------------------------------------------------------- // -- cChannels --------------------------------------------------------------
int CurrentChannel = 0; int CurrentChannel = 1;
int CurrentGroup = -1;
cChannels Channels; cChannels Channels;
bool cChannels::Load(const char *FileName)
{
if (cConfig<cChannel>::Load(FileName)) {
ReNumber();
return true;
}
return false;
}
int cChannels::GetNextGroup(int Idx)
{
cChannel *channel = Get(++Idx);
while (channel && !channel->groupSep)
channel = Get(++Idx);
return channel ? Idx : -1;
}
int cChannels::GetPrevGroup(int Idx)
{
cChannel *channel = Get(--Idx);
while (channel && !channel->groupSep)
channel = Get(--Idx);
return channel ? Idx : -1;
}
int cChannels::GetNextNormal(int Idx)
{
cChannel *channel = Get(++Idx);
while (channel && channel->groupSep)
channel = Get(++Idx);
return channel ? Idx : -1;
}
void cChannels::ReNumber( void )
{
int Number = 0;
cChannel *ch = (cChannel *)First();
while (ch) {
if (!ch->groupSep)
ch->number = ++Number;
ch = (cChannel *)ch->Next();
}
maxNumber = Number;
}
cChannel *cChannels::GetByNumber(int Number)
{
cChannel *channel = (cChannel *)First();
while (channel) {
if (channel->number == Number)
return channel;
channel = (cChannel *)channel->Next();
}
return NULL;
}
bool cChannels::SwitchTo(int Number, cDvbApi *DvbApi)
{
cChannel *channel = GetByNumber(Number);
return channel && channel->Switch(DvbApi);
}
const char *cChannels::GetChannelNameByNumber(int Number)
{
cChannel *channel = GetByNumber(Number);
return channel ? channel->name : NULL;
}
// -- cTimers ---------------------------------------------------------------- // -- cTimers ----------------------------------------------------------------
cTimers Timers; cTimers Timers;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.h 1.15 2000/09/03 09:37:30 kls Exp $ * $Id: config.h 1.16 2000/09/09 14:21:35 kls Exp $
*/ */
#ifndef __CONFIG_H #ifndef __CONFIG_H
@ -17,7 +17,7 @@
#include "dvbapi.h" #include "dvbapi.h"
#include "tools.h" #include "tools.h"
#define VDRVERSION "0.62" #define VDRVERSION "0.63"
#define MaxBuffer 10000 #define MaxBuffer 10000
@ -75,14 +75,15 @@ public:
int apid; int apid;
int ca; int ca;
int pnr; int pnr;
int preferred; //TODO implement "preferred channel" mechanism
int number; // Sequence number assigned on load
bool groupSep;
cChannel(void); cChannel(void);
cChannel(const cChannel *Channel); cChannel(const cChannel *Channel);
const char *ToText(void); const char *ToText(void);
bool Parse(const char *s); bool Parse(const char *s);
bool Save(FILE *f); bool Save(FILE *f);
bool Switch(cDvbApi *DvbApi = NULL); bool Switch(cDvbApi *DvbApi = NULL);
static bool SwitchTo(int i, cDvbApi *DvbApi = NULL);
static const char *GetChannelName(int i);
}; };
class cTimer : public cListObject { class cTimer : public cListObject {
@ -130,7 +131,7 @@ private:
cList<T>::Clear(); cList<T>::Clear();
} }
public: public:
bool Load(const char *FileName) virtual bool Load(const char *FileName)
{ {
isyslog(LOG_INFO, "loading %s", FileName); isyslog(LOG_INFO, "loading %s", FileName);
bool result = true; bool result = true;
@ -182,14 +183,29 @@ public:
} }
}; };
class cChannels : public cConfig<cChannel> {}; class cChannels : public cConfig<cChannel> {
protected:
int maxNumber;
public:
cChannels(void) { maxNumber = 0; }
virtual bool Load(const char *FileName);
int GetNextGroup(int Idx); // Get next channel group
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);
const char *GetChannelNameByNumber(int Number);
bool SwitchTo(int Number, cDvbApi *DvbApi = NULL);
int MaxNumber(void) { return maxNumber; }
};
class cTimers : public cConfig<cTimer> { class cTimers : public cConfig<cTimer> {
public: public:
cTimer *GetTimer(cTimer *Timer); cTimer *GetTimer(cTimer *Timer);
}; };
extern int CurrentChannel; extern int CurrentChannel;
extern int CurrentGroup;
extern cChannels Channels; extern cChannels Channels;
extern cTimers Timers; extern cTimers Timers;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbapi.c 1.22 2000/08/06 14:06:14 kls Exp $ * $Id: dvbapi.c 1.23 2000/09/09 12:13:55 kls Exp $
*/ */
#include "dvbapi.h" #include "dvbapi.h"
@ -1199,6 +1199,10 @@ void cDvbApi::Cmd(OSD_Command cmd, int color, int x0, int y0, int x1, int y1, co
dc.y1 = y1; dc.y1 = y1;
dc.data = (void *)data; dc.data = (void *)data;
ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc); ioctl(videoDev, VIDIOCSOSDCOMMAND, &dc);
usleep(10); // XXX Workaround for a driver bug (cInterface::DisplayChannel() displayed texts at wrong places
// XXX and sometimes the OSD was no longer displayed).
// XXX Increase the value if the problem still persists on your particular system.
// TODO Check if this is still necessary with driver versions after 0.6.
} }
} }
#endif #endif

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: interface.c 1.11 2000/09/03 10:17:21 kls Exp $ * $Id: interface.c 1.12 2000/09/09 14:17:48 kls Exp $
*/ */
#include "interface.h" #include "interface.h"
@ -72,10 +72,10 @@ eKeys cInterface::GetKey(bool Wait)
eKeys cInterface::Wait(int Seconds, bool KeepChar) eKeys cInterface::Wait(int Seconds, bool KeepChar)
{ {
int t0 = time_ms(); int t0 = time_ms() + Seconds * 1000;
eKeys Key = kNone; eKeys Key = kNone;
while (time_ms() - t0 < Seconds * 1000) { while (time_ms() < t0) {
Key = GetKey(); Key = GetKey();
if (Key != kNone) if (Key != kNone)
break; break;
@ -112,11 +112,9 @@ void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor
cDvbApi::PrimaryDvbApi->Text(x, y, s, FgColor, BgColor); cDvbApi::PrimaryDvbApi->Text(x, y, s, FgColor, BgColor);
} }
void cInterface::WriteText(int x, int y, const char *s, bool Current) void cInterface::WriteText(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor)
{ {
if (open) { if (open) {
eDvbColor FgColor = Current ? clrBlack : clrWhite;
eDvbColor BgColor = Current ? clrCyan : clrBackground;
ClearEol(x, y, BgColor); ClearEol(x, y, BgColor);
int col = 0; int col = 0;
for (;;) { for (;;) {
@ -315,36 +313,42 @@ void cInterface::LearnKeys(void)
} }
} }
void cInterface::DisplayChannel(int Number, const char *Name) eKeys cInterface::DisplayChannel(int Number, const char *Name)
{ {
RcIo.Number(Number); // Number = 0 is used for channel group display and no EIT
if (Number)
RcIo.Number(Number);
if (Name && !Recording()) { if (Name && !Recording()) {
Open(MenuColumns, EIT.IsValid() ? 5 : 1); //XXX Maybe show only those lines that have actual information???
char buffer[MenuColumns + 1]; Open(MenuColumns, Number && EIT.IsValid() ? 5 : 1);
snprintf(buffer, sizeof(buffer), "%d %s", Number, Name ? Name : ""); int BufSize = MenuColumns + 1;
char buffer[BufSize];
if (Number)
snprintf(buffer, BufSize, "%d %s", Number, Name ? Name : "");
else
snprintf(buffer, BufSize, "%s", Name ? Name : "");
Write(0, 0, buffer); Write(0, 0, buffer);
time_t t = time(NULL); time_t t = time(NULL);
struct tm *now = localtime(&t); struct tm *now = localtime(&t);
snprintf(buffer, sizeof(buffer), "%02d:%02d", now->tm_hour, now->tm_min); snprintf(buffer, BufSize, "%02d:%02d", now->tm_hour, now->tm_min);
Write(-5, 0, buffer); Write(-5, 0, buffer);
if (EIT.IsValid()) { if (Number && EIT.IsValid()) {
const int t = 7; const int t = 6;
int w = MenuColumns - t; int w = MenuColumns - t;
Write(0, 1, EIT.GetRunningTime(), clrYellow, clrBackground); Write(0, 1, EIT.GetRunningTime(), clrYellow, clrBackground);
snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetRunningTitle()); snprintf(buffer, BufSize, "%.*s", w, EIT.GetRunningTitle()); Write(t, 1, buffer, clrCyan, clrBackground);
Write(t, 1, buffer, clrCyan, clrBackground); snprintf(buffer, BufSize, "%.*s", w, EIT.GetRunningSubtitle()); Write(t, 2, buffer, clrCyan, clrBackground);
snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetRunningSubtitle());
Write(t, 2, buffer, clrCyan, clrBackground);
Write(0, 3, EIT.GetNextTime(), clrYellow, clrBackground); Write(0, 3, EIT.GetNextTime(), clrYellow, clrBackground);
snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetNextTitle()); snprintf(buffer, BufSize, "%.*s", w, EIT.GetNextTitle()); Write(t, 3, buffer, clrCyan, clrBackground);
Write(t, 3, buffer, clrCyan, clrBackground); snprintf(buffer, BufSize, "%.*s", w, EIT.GetNextSubtitle()); Write(t, 4, buffer, clrCyan, clrBackground);
snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetNextSubtitle());
Write(t, 4, buffer, clrCyan, clrBackground);
} }
if (Wait(5, true) == kOk) eKeys Key = Wait(5, true);
if (Key == kOk)
GetKey(); GetKey();
Close(); Close();
return Key;
} }
return kNone;
} }
void cInterface::DisplayRecording(int Index, bool On) void cInterface::DisplayRecording(int Index, bool On)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: interface.h 1.9 2000/05/06 15:39:23 kls Exp $ * $Id: interface.h 1.10 2000/09/03 14:34:24 kls Exp $
*/ */
#ifndef __INTERFACE_H #ifndef __INTERFACE_H
@ -34,7 +34,7 @@ public:
void ClearEol(int x, int y, eDvbColor Color = clrBackground); void ClearEol(int x, int y, eDvbColor Color = clrBackground);
void SetCols(int *c); void SetCols(int *c);
void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground);
void WriteText(int x, int y, const char *s, bool Current = false); void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBlack);
void Title(const char *s); void Title(const char *s);
void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan); void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan);
void Info(const char *s); void Info(const char *s);
@ -42,7 +42,7 @@ public:
bool Confirm(const char *s); bool Confirm(const char *s);
void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
void LearnKeys(void); void LearnKeys(void);
void DisplayChannel(int Number, const char *Name = NULL); eKeys DisplayChannel(int Number, const char *Name = NULL);
void DisplayRecording(int Index, bool On); void DisplayRecording(int Index, bool On);
bool Recording(void); bool Recording(void);
}; };

59
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.22 2000/08/06 07:02:52 kls Exp $ * $Id: menu.c 1.23 2000/09/09 14:43:37 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -145,7 +145,7 @@ public:
}; };
cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value) cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value)
:cMenuEditIntItem(Name, Value, 1, Channels.Count()) :cMenuEditIntItem(Name, Value, 1, Channels.MaxNumber())
{ {
Set(); Set();
} }
@ -153,7 +153,7 @@ cMenuEditChanItem::cMenuEditChanItem(const char *Name, int *Value)
void cMenuEditChanItem::Set(void) void cMenuEditChanItem::Set(void)
{ {
char buf[255]; char buf[255];
cChannel *channel = Channels.Get(*value - 1); cChannel *channel = Channels.GetByNumber(*value);
if (channel) if (channel)
snprintf(buf, sizeof(buf), "%d %s", *value, channel->name); snprintf(buf, sizeof(buf), "%d %s", *value, channel->name);
else else
@ -513,6 +513,7 @@ cMenuEditChannel::cMenuEditChannel(int Index)
Add(new cMenuEditIntItem( "Apid", &data.apid, 0, 10000)); //TODO exact limits??? Add(new cMenuEditIntItem( "Apid", &data.apid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditIntItem( "CA", &data.ca, 0, cDvbApi::NumDvbApis)); Add(new cMenuEditIntItem( "CA", &data.ca, 0, cDvbApi::NumDvbApis));
Add(new cMenuEditIntItem( "Pnr", &data.pnr, 0)); Add(new cMenuEditIntItem( "Pnr", &data.pnr, 0));
Add(new cMenuEditIntItem( "Preferred", &data.preferred, 0, 1)); //TODO implement "preferred channel" mechanism
} }
} }
@ -547,13 +548,18 @@ cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel)
{ {
index = Index; index = Index;
channel = Channel; channel = Channel;
if (channel->groupSep)
SetColor(clrWhite, clrBlue);
Set(); Set();
} }
void cMenuChannelItem::Set(void) void cMenuChannelItem::Set(void)
{ {
char *buffer = NULL; char *buffer = NULL;
asprintf(&buffer, "%d\t%s", index + 1, channel->name); // user visible channel numbers start with '1' if (!channel->groupSep)
asprintf(&buffer, "%d\t%s", channel->number, channel->name );
else
asprintf(&buffer, "\t%s", channel->name);
SetText(buffer, false); SetText(buffer, false);
} }
@ -583,9 +589,10 @@ cMenuChannels::cMenuChannels(void)
//TODO //TODO
int i = 0; int i = 0;
cChannel *channel; cChannel *channel;
int curr = ((channel = Channels.GetByNumber(CurrentChannel)) != NULL) ? channel->Index() : -1;
while ((channel = Channels.Get(i)) != NULL) { while ((channel = Channels.Get(i)) != NULL) {
Add(new cMenuChannelItem(i, channel), i == CurrentChannel); Add(new cMenuChannelItem(i, channel), i == curr);
i++; i++;
} }
SetHelp("Edit", "New", "Delete", "Mark"); SetHelp("Edit", "New", "Delete", "Mark");
@ -613,9 +620,10 @@ eOSState cMenuChannels::New(void)
return osContinue; return osContinue;
cChannel *channel = new cChannel(Channels.Get(Current())); cChannel *channel = new cChannel(Channels.Get(Current()));
Channels.Add(channel); Channels.Add(channel);
Channels.ReNumber();
Add(new cMenuChannelItem(channel->Index()/*XXX*/, channel), true); Add(new cMenuChannelItem(channel->Index()/*XXX*/, channel), true);
Channels.Save(); Channels.Save();
isyslog(LOG_INFO, "channel %d added", channel->Index() + 1); isyslog(LOG_INFO, "channel %d added", channel->number);
return AddSubMenu(new cMenuEditChannel(Current())); return AddSubMenu(new cMenuEditChannel(Current()));
} }
@ -623,28 +631,30 @@ eOSState cMenuChannels::Del(void)
{ {
if (Count() > 0) { if (Count() > 0) {
int Index = Current(); int Index = Current();
cChannel *channel = Channels.Get(Index);
int DeletedChannel = channel->number;
// Check if there is a timer using this channel: // Check if there is a timer using this channel:
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
if (ti->channel == Index + 1) { if (ti->channel == DeletedChannel) {
Interface.Error("Channel is being used by a timer!"); Interface.Error("Channel is being used by a timer!");
return osContinue; return osContinue;
} }
} }
if (Interface.Confirm("Delete Channel?")) { if (Interface.Confirm("Delete Channel?")) {
// Move and renumber the channels: // Move and renumber the channels:
Channels.Del(Channels.Get(Index)); Channels.Del(channel);
Channels.ReNumber();
cOsdMenu::Del(Index); cOsdMenu::Del(Index);
int i = 0; int i = 0;
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
ci->SetIndex(i++); ci->SetIndex(i++);
Channels.Save(); Channels.Save();
isyslog(LOG_INFO, "channel %d deleted", Index + 1); isyslog(LOG_INFO, "channel %d deleted", DeletedChannel);
// Fix the timers: // Fix the timers:
bool TimersModified = false; bool TimersModified = false;
Index++; // user visible channel numbers start with '1'
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
int OldChannel = ti->channel; int OldChannel = ti->channel;
if (ti->channel > Index) if (ti->channel > DeletedChannel)
ti->channel--; ti->channel--;
if (ti->channel != OldChannel) { if (ti->channel != OldChannel) {
TimersModified = true; TimersModified = true;
@ -661,25 +671,28 @@ eOSState cMenuChannels::Del(void)
void cMenuChannels::Move(int From, int To) void cMenuChannels::Move(int From, int To)
{ {
int FromNumber = Channels.Get(From)->number;
int ToNumber = Channels.Get(To)->number;
// Move and renumber the channels: // Move and renumber the channels:
Channels.Move(From, To); Channels.Move(From, To);
Channels.ReNumber();
cOsdMenu::Move(From, To); cOsdMenu::Move(From, To);
int i = 0; int i = 0;
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next()) for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
ci->SetIndex(i++); ci->SetIndex(i++);
Channels.Save(); Channels.Save();
isyslog(LOG_INFO, "channel %d moved to %d", From + 1, To + 1); isyslog(LOG_INFO, "channel %d moved to %d", FromNumber, ToNumber);
// Fix the timers: // Fix the timers:
bool TimersModified = false; bool TimersModified = false;
From++; // user visible channel numbers start with '1' From++; // user visible channel numbers start with '1'
To++; To++;
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
int OldChannel = ti->channel; int OldChannel = ti->channel;
if (ti->channel == From) if (ti->channel == FromNumber)
ti->channel = To; ti->channel = ToNumber;
else if (ti->channel > From && ti->channel <= To) else if (ti->channel > FromNumber && ti->channel <= ToNumber)
ti->channel--; ti->channel--;
else if (ti->channel < From && ti->channel >= To) else if (ti->channel < FromNumber && ti->channel >= ToNumber)
ti->channel++; ti->channel++;
if (ti->channel != OldChannel) { if (ti->channel != OldChannel) {
TimersModified = true; TimersModified = true;
@ -791,7 +804,7 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key)
if (state == osUnknown) { if (state == osUnknown) {
if (Key == kOk) { if (Key == kOk) {
if (!*data.file) if (!*data.file)
strcpy(data.file, cChannel::GetChannelName(data.channel - 1)); strcpy(data.file, Channels.GetChannelNameByNumber(data.channel));
if (timer && memcmp(timer, &data, sizeof(data)) != 0) { if (timer && memcmp(timer, &data, sizeof(data)) != 0) {
*timer = data; *timer = data;
Timers.Save(); Timers.Save();
@ -1125,10 +1138,10 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer)
timer = new cTimer(true); timer = new cTimer(true);
Timers.Add(timer); Timers.Add(timer);
Timers.Save(); Timers.Save();
asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s on %d" : "%s", cChannel::GetChannelName(timer->channel - 1), dvbApi->Index() + 1); asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s on %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), dvbApi->Index() + 1);
} }
timer->SetRecording(true); timer->SetRecording(true);
cChannel::SwitchTo(timer->channel - 1, dvbApi); Channels.SwitchTo(timer->channel, dvbApi);
cRecording Recording(timer); cRecording Recording(timer);
if (dvbApi->StartRecord(Recording.FileName())) if (dvbApi->StartRecord(Recording.FileName()))
Recording.WriteSummary(); Recording.WriteSummary();
@ -1172,8 +1185,8 @@ cRecordControl *cRecordControls::RecordControls[MAXDVBAPI] = { NULL };
bool cRecordControls::Start(cTimer *Timer) bool cRecordControls::Start(cTimer *Timer)
{ {
int ch = Timer ? Timer->channel - 1 : CurrentChannel; int ch = Timer ? Timer->channel : CurrentChannel;
cChannel *channel = Channels.Get(ch); cChannel *channel = Channels.GetByNumber(ch);
if (channel) { if (channel) {
cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca); cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca);
@ -1186,10 +1199,10 @@ bool cRecordControls::Start(cTimer *Timer)
} }
} }
else else
esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch + 1); esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch);
} }
else else
esyslog(LOG_ERR, "ERROR: channel %d not defined!", ch + 1); esyslog(LOG_ERR, "ERROR: channel %d not defined!", ch);
return false; return false;
} }

100
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osd.c 1.5 2000/07/26 17:35:09 kls Exp $ * $Id: osd.c 1.6 2000/09/09 14:28:57 kls Exp $
*/ */
#include "osd.h" #include "osd.h"
@ -19,6 +19,9 @@ cOsdItem::cOsdItem(eOSState State)
offset = -1; offset = -1;
state = State; state = State;
fresh = false; fresh = false;
userColor = false;
fgColor = clrWhite;
bgColor = clrBackground;
} }
cOsdItem::cOsdItem(char *Text, eOSState State) cOsdItem::cOsdItem(char *Text, eOSState State)
@ -27,6 +30,9 @@ cOsdItem::cOsdItem(char *Text, eOSState State)
offset = -1; offset = -1;
state = State; state = State;
fresh = false; fresh = false;
userColor = false;
fgColor = clrWhite;
bgColor = clrBackground;
SetText(Text); SetText(Text);
} }
@ -41,15 +47,24 @@ void cOsdItem::SetText(const char *Text, bool Copy)
text = Copy ? strdup(Text) : Text; text = Copy ? strdup(Text) : Text;
} }
void cOsdItem::Display(int Offset, bool Current) void cOsdItem::SetColor(eDvbColor FgColor, eDvbColor BgColor)
{ {
userColor = true;
fgColor = FgColor;
bgColor = BgColor;
}
void cOsdItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor)
{
if (Offset < 0) {
FgColor = clrBlack;
BgColor = clrCyan;
}
fresh |= Offset >= 0; fresh |= Offset >= 0;
Current |= Offset < 0;
if (Offset >= 0) if (Offset >= 0)
offset = Offset; offset = Offset;
//TODO current if Offset == -1 ???
if (offset >= 0) if (offset >= 0)
Interface.WriteText(0, offset + 2, text, Current); Interface.WriteText(0, offset + 2, text, userColor ? fgColor : FgColor, userColor ? bgColor : BgColor);
} }
eOSState cOsdItem::ProcessKey(eKeys Key) eOSState cOsdItem::ProcessKey(eKeys Key)
@ -100,6 +115,10 @@ void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, c
helpGreen = Green; helpGreen = Green;
helpYellow = Yellow; helpYellow = Yellow;
helpBlue = Blue; helpBlue = Blue;
if (visible)
Display();
//XXX Interface.Help(helpRed, helpGreen, helpYellow, helpBlue);
//XXX must clear unused button areas!
} }
void cOsdMenu::Del(int Index) void cOsdMenu::Del(int Index)
@ -140,7 +159,7 @@ void cOsdMenu::Display(void)
for (int i = first; i < count; i++) { for (int i = first; i < count; i++) {
cOsdItem *item = Get(i); cOsdItem *item = Get(i);
if (item) if (item)
item->Display(i - first, i == current); item->Display(i - first, i == current ? clrBlack : clrWhite, i == current ? clrCyan : clrBackground);
if (++n == MAXOSDITEMS) //TODO get this from Interface!!! if (++n == MAXOSDITEMS) //TODO get this from Interface!!!
break; break;
} }
@ -159,49 +178,64 @@ void cOsdMenu::DisplayCurrent(bool Current)
{ {
cOsdItem *item = Get(current); cOsdItem *item = Get(current);
if (item) if (item)
item->Display(current - first, Current); item->Display(current - first, Current ? clrBlack : clrWhite, Current ? clrCyan : clrBackground);
}
bool cOsdMenu::SpecialItem(int idx)
{
cOsdItem *item = Get(idx);
return item && item->HasUserColor();
} }
void cOsdMenu::CursorUp(void) void cOsdMenu::CursorUp(void)
{ {
if (current > 0) { if (current > 0) {
DisplayCurrent(false); int tmpCurrent = current;
if (current == first) { while (--tmpCurrent >= 0 && SpecialItem(tmpCurrent));
first -= MAXOSDITEMS; if (tmpCurrent < 0)
if (first < 0) return;
first = 0; if (tmpCurrent >= first)
if (current - MAXOSDITEMS > 0) DisplayCurrent(false);
current -= MAXOSDITEMS; current = tmpCurrent;
else if (current < first) {
current--; first = first > MAXOSDITEMS - 1 ? first - (MAXOSDITEMS - 1) : 0;
#ifndef NO_PAGE_SCROLL
current = SpecialItem(first) ? first + 1 : first;
#endif
Display(); Display();
} }
else { else
current--;
DisplayCurrent(true); DisplayCurrent(true);
}
} }
} }
void cOsdMenu::CursorDown(void) void cOsdMenu::CursorDown(void)
{ {
int count = Count(); int last = Count() - 1;
if (current < count - 1) { int lastOnScreen = first + MAXOSDITEMS - 1;
DisplayCurrent(false);
if (current == first + MAXOSDITEMS - 1) { if (current < last) {
first += MAXOSDITEMS; int tmpCurrent = current;
if (first > count - MAXOSDITEMS) while (++tmpCurrent <= last && SpecialItem(tmpCurrent));
first = count - MAXOSDITEMS; if (tmpCurrent > last)
if (current + MAXOSDITEMS < count) return;
current += MAXOSDITEMS; if (tmpCurrent <= lastOnScreen)
else DisplayCurrent(false);
current++; current = tmpCurrent;
if (current > lastOnScreen) {
first += MAXOSDITEMS - 1;
lastOnScreen = first + MAXOSDITEMS - 1;
if (lastOnScreen > last) {
first = last - (MAXOSDITEMS - 1);
lastOnScreen = last;
}
#ifndef NO_PAGE_SCROLL
current = SpecialItem(lastOnScreen) ? lastOnScreen - 1 : lastOnScreen;
#endif
Display(); Display();
} }
else { else
current++;
DisplayCurrent(true); DisplayCurrent(true);
}
} }
} }

9
osd.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osd.h 1.9 2000/05/27 15:35:41 kls Exp $ * $Id: osd.h 1.10 2000/09/03 14:50:22 kls Exp $
*/ */
#ifndef __OSD_H #ifndef __OSD_H
@ -37,13 +37,17 @@ private:
eOSState state; eOSState state;
protected: protected:
bool fresh; bool fresh;
bool userColor;
eDvbColor fgColor, bgColor;
public: public:
cOsdItem(eOSState State = osUnknown); cOsdItem(eOSState State = osUnknown);
cOsdItem(char *Text, eOSState State = osUnknown); cOsdItem(char *Text, eOSState State = osUnknown);
virtual ~cOsdItem(); virtual ~cOsdItem();
bool HasUserColor(void) { return userColor; }
void SetText(const char *Text, bool Copy = true); void SetText(const char *Text, bool Copy = true);
void SetColor(eDvbColor FgColor, eDvbColor BgColor = clrBackground);
const char *Text(void) { return text; } const char *Text(void) { return text; }
void Display(int Offset = -1, bool Current = false); void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground);
virtual void Set(void) {} virtual void Set(void) {}
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
@ -68,6 +72,7 @@ private:
const char *status; const char *status;
protected: protected:
bool visible; bool visible;
bool SpecialItem(int idx);
void RefreshCurrent(void); void RefreshCurrent(void);
void DisplayCurrent(bool Current); void DisplayCurrent(bool Current);
void CursorUp(void); void CursorUp(void);

57
svdrp.c
View File

@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured * and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection. * graphical interface that sits on top of an SVDRP connection.
* *
* $Id: svdrp.c 1.5 2000/08/26 12:51:51 kls Exp $ * $Id: svdrp.c 1.6 2000/09/09 10:51:21 kls Exp $
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
@ -279,24 +279,24 @@ void cSVDRP::CmdChan(const char *Option)
if (*Option) { if (*Option) {
int n = -1; int n = -1;
if (isnumber(Option)) { if (isnumber(Option)) {
int o = strtol(Option, NULL, 10) - 1; int o = strtol(Option, NULL, 10);
if (o >= 0 && o < Channels.Count()) if (o >= 1 && o <= Channels.MaxNumber())
n = o; n = o;
} }
else if (strcmp(Option, "-") == 0) { else if (strcmp(Option, "-") == 0) {
n = CurrentChannel; n = CurrentChannel;
if (CurrentChannel > 0) if (CurrentChannel > 1)
n--; n--;
} }
else if (strcmp(Option, "+") == 0) { else if (strcmp(Option, "+") == 0) {
n = CurrentChannel; n = CurrentChannel;
if (CurrentChannel < Channels.Count() - 1) if (CurrentChannel < Channels.MaxNumber())
n++; n++;
} }
else { else {
int i = 0; int i = 1;
cChannel *channel; cChannel *channel;
while ((channel = Channels.Get(i)) != NULL) { while ((channel = Channels.GetByNumber(i)) != NULL) {
if (strcasecmp(channel->name, Option) == 0) { if (strcasecmp(channel->name, Option) == 0) {
n = i; n = i;
break; break;
@ -312,10 +312,10 @@ void cSVDRP::CmdChan(const char *Option)
Reply(550, "Can't switch channel, interface is recording"); Reply(550, "Can't switch channel, interface is recording");
return; return;
} }
cChannel *channel = Channels.Get(n); cChannel *channel = Channels.GetByNumber(n);
if (channel) { if (channel) {
if (!channel->Switch()) { if (!channel->Switch()) {
Reply(554, "Error switching to channel \"%d\"", channel->Index() + 1); Reply(554, "Error switching to channel \"%d\"", channel->number);
return; return;
} }
} }
@ -324,9 +324,9 @@ void cSVDRP::CmdChan(const char *Option)
return; return;
} }
} }
cChannel *channel = Channels.Get(CurrentChannel); cChannel *channel = Channels.GetByNumber(CurrentChannel);
if (channel) if (channel)
Reply(250, "%d %s", CurrentChannel + 1, channel->name); Reply(250, "%d %s", CurrentChannel, channel->name);
else else
Reply(550, "Unable to find channel \"%d\"", CurrentChannel); Reply(550, "Unable to find channel \"%d\"", CurrentChannel);
} }
@ -394,41 +394,41 @@ void cSVDRP::CmdLstc(const char *Option)
{ {
if (*Option) { if (*Option) {
if (isnumber(Option)) { if (isnumber(Option)) {
cChannel *channel = Channels.Get(strtol(Option, NULL, 10) - 1); cChannel *channel = Channels.GetByNumber(strtol(Option, NULL, 10));
if (channel) if (channel)
Reply(250, "%d %s", channel->Index() + 1, channel->ToText()); Reply(250, "%d %s", channel->number, channel->ToText());
else else
Reply(501, "Channel \"%s\" not defined", Option); Reply(501, "Channel \"%s\" not defined", Option);
} }
else { else {
int i = 0; int i = 1;
cChannel *next = NULL; cChannel *next = NULL;
while (i < Channels.Count()) { while (i <= Channels.MaxNumber()) {
cChannel *channel = Channels.Get(i); cChannel *channel = Channels.GetByNumber(i);
if (channel) { if (channel) {
if (strcasestr(channel->name, Option)) { if (strcasestr(channel->name, Option)) {
if (next) if (next)
Reply(-250, "%d %s", next->Index() + 1, next->ToText()); Reply(-250, "%d %s", next->number, next->ToText());
next = channel; next = channel;
} }
} }
else { else {
Reply(501, "Channel \"%d\" not found", i + 1); Reply(501, "Channel \"%d\" not found", i);
return; return;
} }
i++; i++;
} }
if (next) if (next)
Reply(250, "%d %s", next->Index() + 1, next->ToText()); Reply(250, "%d %s", next->number, next->ToText());
} }
} }
else { else {
for (int i = 0; i < Channels.Count(); i++) { for (int i = 1; i <= Channels.MaxNumber(); i++) {
cChannel *channel = Channels.Get(i); cChannel *channel = Channels.GetByNumber(i);
if (channel) if (channel)
Reply(i < Channels.Count() - 1 ? -250 : 250, "%d %s", channel->Index() + 1, channel->ToText()); Reply(i < Channels.MaxNumber() ? -250 : 250, "%d %s", channel->number, channel->ToText());
else else
Reply(501, "Channel \"%d\" not found", i + 1); Reply(501, "Channel \"%d\" not found", i);
} }
} }
} }
@ -464,7 +464,7 @@ void cSVDRP::CmdModc(const char *Option)
int n = strtol(Option, &tail, 10); int n = strtol(Option, &tail, 10);
if (tail && tail != Option) { if (tail && tail != Option) {
tail = skipspace(tail); tail = skipspace(tail);
cChannel *channel = Channels.Get(n - 1); cChannel *channel = Channels.GetByNumber(n);
if (channel) { if (channel) {
cChannel c = *channel; cChannel c = *channel;
if (!c.Parse(tail)) { if (!c.Parse(tail)) {
@ -473,8 +473,8 @@ void cSVDRP::CmdModc(const char *Option)
} }
*channel = c; *channel = c;
Channels.Save(); Channels.Save();
isyslog(LOG_INFO, "channel %d modified", channel->Index() + 1); isyslog(LOG_INFO, "channel %d modified", channel->number);
Reply(250, "%d %s", channel->Index() + 1, channel->ToText()); Reply(250, "%d %s", channel->number, channel->ToText());
} }
else else
Reply(501, "Channel \"%d\" not defined", n); Reply(501, "Channel \"%d\" not defined", n);
@ -537,9 +537,10 @@ void cSVDRP::CmdNewc(const char *Option)
cChannel *channel = new cChannel; cChannel *channel = new cChannel;
if (channel->Parse(Option)) { if (channel->Parse(Option)) {
Channels.Add(channel); Channels.Add(channel);
Channels.ReNumber();
Channels.Save(); Channels.Save();
isyslog(LOG_INFO, "channel %d added", channel->Index() + 1); isyslog(LOG_INFO, "channel %d added", channel->number);
Reply(250, "%d %s", channel->Index() + 1, channel->ToText()); Reply(250, "%d %s", channel->number, channel->ToText());
} }
else else
Reply(501, "Error in channel settings"); Reply(501, "Error in channel settings");

12
tools.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.c 1.13 2000/07/29 18:41:45 kls Exp $ * $Id: tools.c 1.14 2000/09/09 12:53:34 kls Exp $
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
@ -97,6 +97,14 @@ char *readline(FILE *f)
return NULL; return NULL;
} }
char *strn0cpy(char *dest, const char *src, size_t n)
{
char *s = dest;
for ( ; --n && (*dest = *src) != 0; dest++, src++) ;
*dest = 0;
return s;
}
char *strreplace(char *s, char c1, char c2) char *strreplace(char *s, char c1, char c2)
{ {
char *p = s; char *p = s;
@ -418,6 +426,8 @@ void cListBase::Clear(void)
cListObject *cListBase::Get(int Index) cListObject *cListBase::Get(int Index)
{ {
if (Index < 0)
return NULL;
cListObject *object = objects; cListObject *object = objects;
while (object && Index-- > 0) while (object && Index-- > 0)
object = object->Next(); object = object->Next();

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: tools.h 1.12 2000/07/29 10:56:00 kls Exp $ * $Id: tools.h 1.13 2000/09/09 12:53:10 kls Exp $
*/ */
#ifndef __TOOLS_H #ifndef __TOOLS_H
@ -38,6 +38,7 @@ bool readint(int filedes, int &n);
int readstring(int filedes, char *buffer, int size, bool wait = false); int readstring(int filedes, char *buffer, int size, bool wait = false);
void purge(int filedes); void purge(int filedes);
char *readline(FILE *f); char *readline(FILE *f);
char *strn0cpy(char *dest, const char *src, size_t n);
char *strreplace(char *s, char c1, char c2); char *strreplace(char *s, char c1, char c2);
char *skipspace(char *s); char *skipspace(char *s);
int time_ms(void); int time_ms(void);

37
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.cadsoft.de/people/kls/vdr * The project's page is at http://www.cadsoft.de/people/kls/vdr
* *
* $Id: vdr.c 1.27 2000/07/29 19:01:57 kls Exp $ * $Id: vdr.c 1.28 2000/09/09 14:18:25 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
@ -53,6 +53,14 @@ void SignalHandler(int signum)
Interrupted = signum; Interrupted = signum;
} }
static eKeys ShowChannel(int Number, bool Group = false)
{
cChannel *channel = Group ? Channels.Get(Number) : Channels.GetByNumber(Number);
if (channel)
return Interface.DisplayChannel(channel->number, channel->name);
return kNone;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
// Command line options: // Command line options:
@ -166,7 +174,7 @@ int main(int argc, char *argv[])
#endif #endif
Interface.Init(); Interface.Init();
cChannel::SwitchTo(CurrentChannel); Channels.SwitchTo(CurrentChannel);
// Signal handlers: // Signal handlers:
@ -185,16 +193,13 @@ int main(int argc, char *argv[])
while (!Interrupted) { while (!Interrupted) {
// Channel display: // Channel display:
if (CurrentChannel != LastChannel) { if (CurrentChannel != LastChannel) {
if (!Menu) { if (!Menu)
cChannel *channel = Channels.Get(CurrentChannel); ShowChannel(CurrentChannel);
if (channel)
Interface.DisplayChannel(CurrentChannel + 1, channel->name);
}
LastChannel = CurrentChannel; LastChannel = CurrentChannel;
} }
// Direct Channel Select (action): // Direct Channel Select (action):
if (dcNumber && time_ms() - dcTime > DIRECTCHANNELTIMEOUT) { if (dcNumber && time_ms() - dcTime > DIRECTCHANNELTIMEOUT) {
cChannel::SwitchTo(dcNumber - 1); Channels.SwitchTo(dcNumber);
dcNumber = 0; dcNumber = 0;
LastChannel = -1; // in case an invalid channel number was entered! LastChannel = -1; // in case an invalid channel number was entered!
} }
@ -246,11 +251,25 @@ int main(int argc, char *argv[])
} }
} }
break; break;
// Left/Right rotates trough channel groups:
case kLeft:
case kRight: if (!Interface.Recording()) {
int SaveGroup = CurrentGroup;
if (key == kRight)
CurrentGroup = Channels.GetNextGroup(CurrentGroup) ;
else
CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup);
if (CurrentGroup < 0)
CurrentGroup = SaveGroup;
if (ShowChannel(CurrentGroup, true) == kOk)
Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(CurrentGroup))->number);
}
break;
// Up/Down Channel Select: // Up/Down Channel Select:
case kUp: case kUp:
case kDown: if (!Interface.Recording()) { case kDown: if (!Interface.Recording()) {
int n = CurrentChannel + (key == kUp ? 1 : -1); int n = CurrentChannel + (key == kUp ? 1 : -1);
cChannel *channel = Channels.Get(n); cChannel *channel = Channels.GetByNumber(n);
if (channel) if (channel)
channel->Switch(); channel->Switch();
} }