summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY4
-rw-r--r--config.c79
-rw-r--r--config.h23
-rw-r--r--menu.c98
-rw-r--r--vdr.520
-rw-r--r--vdr.c6
6 files changed, 112 insertions, 118 deletions
diff --git a/HISTORY b/HISTORY
index 5f33e92e..df1bf609 100644
--- a/HISTORY
+++ b/HISTORY
@@ -6276,7 +6276,7 @@ Video Disk Recorder Revision History
- Fixed plugin arguments corruption with glibc 2.11 on x86_64 (thanks to
Anssi Hannula).
-2010-01-30: Version 1.7.12
+2010-01-31: Version 1.7.12
- Changed the EVCONTENTMASK_* macros to enums and changed "mask" to "group".
- Updated the Estonian OSD texts (thanks to Arthur Konovalov).
@@ -6306,3 +6306,5 @@ Video Disk Recorder Revision History
constructor of cReceiver is still available, but it is recommended to plugin authors
that they switch to the new interface as soon as possible.
When replaying such a recording, the PCR packets are sent to PlayTsVideo()
+- The files "commands.conf" and "reccmd.conf" can now contain nested lists of
+ commands. See vdr.5 for information about the new file format.
diff --git a/config.c b/config.c
index 494eb3dc..acdf4c4f 100644
--- a/config.c
+++ b/config.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.c 2.9 2010/01/17 15:08:32 kls Exp $
+ * $Id: config.c 2.10 2010/01/31 12:36:36 kls Exp $
*/
#include "config.h"
@@ -22,71 +22,6 @@
#define ChkDoublePlausibility(Variable, Default) { if (Variable < 0.00001) Variable = Default; }
-// --- cCommand --------------------------------------------------------------
-
-char *cCommand::result = NULL;
-
-cCommand::cCommand(void)
-{
- title = command = NULL;
- confirm = false;
-}
-
-cCommand::~cCommand()
-{
- free(title);
- free(command);
-}
-
-bool cCommand::Parse(const char *s)
-{
- const char *p = strchr(s, ':');
- if (p) {
- int l = p - s;
- if (l > 0) {
- title = MALLOC(char, l + 1);
- stripspace(strn0cpy(title, s, l + 1));
- if (!isempty(title)) {
- int l = strlen(title);
- if (l > 1 && title[l - 1] == '?') {
- confirm = true;
- title[l - 1] = 0;
- }
- command = stripspace(strdup(skipspace(p + 1)));
- return !isempty(command);
- }
- }
- }
- return false;
-}
-
-const char *cCommand::Execute(const char *Parameters)
-{
- free(result);
- result = NULL;
- cString cmdbuf;
- if (Parameters)
- cmdbuf = cString::sprintf("%s %s", command, Parameters);
- const char *cmd = *cmdbuf ? *cmdbuf : command;
- dsyslog("executing command '%s'", cmd);
- cPipe p;
- if (p.Open(cmd, "r")) {
- int l = 0;
- int c;
- while ((c = fgetc(p)) != EOF) {
- if (l % 20 == 0)
- result = (char *)realloc(result, l + 21);
- result[l++] = char(c);
- }
- if (result)
- result[l] = 0;
- p.Close();
- }
- else
- esyslog("ERROR: can't open pipe for command '%s'", cmd);
- return result;
-}
-
// --- cSVDRPhost ------------------------------------------------------------
cSVDRPhost::cSVDRPhost(void)
@@ -194,7 +129,8 @@ bool cNestedItemList::Parse(FILE *f, cList<cNestedItem> *List, int &Line)
*p = 0;
s = skipspace(stripspace(s));
if (!isempty(s)) {
- if ((p = strchr(s, '{')) != NULL) {
+ p = s + strlen(s) - 1;
+ if (*p == '{') {
*p = 0;
stripspace(s);
cNestedItem *Item = new cNestedItem(s, true);
@@ -270,12 +206,11 @@ bool cNestedItemList::Save(void)
return result;
}
-cNestedItemList Folders;
-
-// --- cCommands -------------------------------------------------------------
+// --- Folders and Commands --------------------------------------------------
-cCommands Commands;
-cCommands RecordingCommands;
+cNestedItemList Folders;
+cNestedItemList Commands;
+cNestedItemList RecordingCommands;
// --- cSVDRPhosts -----------------------------------------------------------
diff --git a/config.h b/config.h
index 37e11a41..be1d7bde 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.h 2.20 2010/01/17 15:08:32 kls Exp $
+ * $Id: config.h 2.21 2010/01/31 11:14:02 kls Exp $
*/
#ifndef __CONFIG_H
@@ -48,21 +48,6 @@
#define MaxSkinName 16
#define MaxThemeName 16
-class cCommand : public cListObject {
-private:
- char *title;
- char *command;
- bool confirm;
- static char *result;
-public:
- cCommand(void);
- virtual ~cCommand();
- bool Parse(const char *s);
- const char *Title(void) { return title; }
- bool Confirm(void) { return confirm; }
- const char *Execute(const char *Parameters = NULL);
- };
-
typedef uint32_t in_addr_t; //XXX from /usr/include/netinet/in.h (apparently this is not defined on systems with glibc < 2.2)
class cSVDRPhost : public cListObject {
@@ -187,8 +172,6 @@ public:
bool Save(void);
};
-class cCommands : public cConfig<cCommand> {};
-
class cSVDRPhosts : public cConfig<cSVDRPhost> {
public:
bool LocalhostOnly(void);
@@ -196,8 +179,8 @@ public:
};
extern cNestedItemList Folders;
-extern cCommands Commands;
-extern cCommands RecordingCommands;
+extern cNestedItemList Commands;
+extern cNestedItemList RecordingCommands;
extern cSVDRPhosts SVDRPhosts;
class cSetupLine : public cListObject {
diff --git a/menu.c b/menu.c
index 2f9d236c..7ddf0cff 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 2.13 2010/01/29 16:36:57 kls Exp $
+ * $Id: menu.c 2.14 2010/01/31 12:43:24 kls Exp $
*/
#include "menu.h"
@@ -1783,44 +1783,100 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
class cMenuCommands : public cOsdMenu {
private:
- cCommands *commands;
- char *parameters;
+ cList<cNestedItem> *commands;
+ cString parameters;
+ cString title;
+ cString command;
+ bool confirm;
+ char *result;
+ bool Parse(const char *s);
eOSState Execute(void);
public:
- cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters = NULL);
+ cMenuCommands(const char *Title, cList<cNestedItem> *Commands, const char *Parameters = NULL);
virtual ~cMenuCommands();
virtual eOSState ProcessKey(eKeys Key);
};
-cMenuCommands::cMenuCommands(const char *Title, cCommands *Commands, const char *Parameters)
+cMenuCommands::cMenuCommands(const char *Title, cList<cNestedItem> *Commands, const char *Parameters)
:cOsdMenu(Title)
{
+ result = NULL;
SetHasHotkeys();
commands = Commands;
- parameters = Parameters ? strdup(Parameters) : NULL;
- for (cCommand *command = commands->First(); command; command = commands->Next(command))
- Add(new cOsdItem(hk(command->Title())));
+ parameters = Parameters;
+ for (cNestedItem *Command = commands->First(); Command; Command = commands->Next(Command)) {
+ const char *s = Command->Text();
+ if (Command->SubItems())
+ Add(new cOsdItem(hk(cString::sprintf("%s...", s))));
+ else if (Parse(s))
+ Add(new cOsdItem(hk(title)));
+ }
}
cMenuCommands::~cMenuCommands()
{
- free(parameters);
+ free(result);
+}
+
+bool cMenuCommands::Parse(const char *s)
+{
+ const char *p = strchr(s, ':');
+ if (p) {
+ int l = p - s;
+ if (l > 0) {
+ char t[l + 1];
+ stripspace(strn0cpy(t, s, l + 1));
+ l = strlen(t);
+ if (l > 1 && t[l - 1] == '?') {
+ t[l - 1] = 0;
+ confirm = true;
+ }
+ else
+ confirm = false;
+ title = t;
+ command = skipspace(p + 1);
+ return true;
+ }
+ }
+ return false;
}
eOSState cMenuCommands::Execute(void)
{
- cCommand *command = commands->Get(Current());
- if (command) {
- bool confirmed = true;
- if (command->Confirm())
- confirmed = Interface->Confirm(cString::sprintf("%s?", command->Title()));
- if (confirmed) {
- Skins.Message(mtStatus, cString::sprintf("%s...", command->Title()));
- const char *Result = command->Execute(parameters);
- Skins.Message(mtStatus, NULL);
- if (Result)
- return AddSubMenu(new cMenuText(command->Title(), Result, fontFix));
- return osEnd;
+ cNestedItem *Command = commands->Get(Current());
+ if (Command) {
+ if (Command->SubItems())
+ return AddSubMenu(new cMenuCommands(Title(), Command->SubItems(), parameters));
+ if (Parse(Command->Text())) {
+ if (!confirm || Interface->Confirm(cString::sprintf("%s?", *title))) {
+ Skins.Message(mtStatus, cString::sprintf("%s...", *title));
+ free(result);
+ result = NULL;
+ cString cmdbuf;
+ if (!isempty(parameters))
+ cmdbuf = cString::sprintf("%s %s", *command, *parameters);
+ const char *cmd = *cmdbuf ? *cmdbuf : *command;
+ dsyslog("executing command '%s'", cmd);
+ cPipe p;
+ if (p.Open(cmd, "r")) {
+ int l = 0;
+ int c;
+ while ((c = fgetc(p)) != EOF) {
+ if (l % 20 == 0)
+ result = (char *)realloc(result, l + 21);
+ result[l++] = char(c);
+ }
+ if (result)
+ result[l] = 0;
+ p.Close();
+ }
+ else
+ esyslog("ERROR: can't open pipe for command '%s'", cmd);
+ Skins.Message(mtStatus, NULL);
+ if (result)
+ return AddSubMenu(new cMenuText(title, result, fontFix));
+ return osEnd;
+ }
}
}
return osContinue;
diff --git a/vdr.5 b/vdr.5
index f77ca7c9..4b2cb90b 100644
--- a/vdr.5
+++ b/vdr.5
@@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the
.\" vdr distribution.
.\"
-.\" $Id: vdr.5 2.12 2010/01/16 15:45:28 kls Exp $
+.\" $Id: vdr.5 2.13 2010/01/31 12:59:50 kls Exp $
.\"
.TH vdr 5 "10 Feb 2008" "1.6" "Video Disk Recorder Files"
.SH NAME
@@ -546,6 +546,24 @@ to make sure they are not executed inadvertently.
Everything following (and including) a '#' character is considered to be comment.
+You can have nested layers of command menus by surrounding a sequence of
+commands with '{'...'}' and giving it a title, as in
+
+My Commands {
+.br
+ First list {
+ Do something: some command
+ Do something else: another command
+ }
+ Second list {
+ Even more: yet another command
+ So much more: and yet another one
+ }
+.br
+ }
+
+Command lists can be nested to any depth.
+
By default the menu entries in the "Commands" menu will be numbered '1'...'9'
to make them selectable by pressing the corresponding number key. If you want
to use your own numbering scheme (maybe to skip certain numbers), just precede
diff --git a/vdr.c b/vdr.c
index 38a29544..e0773015 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.tvdr.de
*
- * $Id: vdr.c 2.15 2010/01/16 15:11:13 kls Exp $
+ * $Id: vdr.c 2.16 2010/01/31 11:14:40 kls Exp $
*/
#include <getopt.h>
@@ -582,8 +582,8 @@ int main(int argc, char *argv[])
Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC);
Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true);
Timers.Load(AddDirectory(ConfigDirectory, "timers.conf"));
- Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true);
- RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true);
+ Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));
+ RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"));
SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true);
Keys.Load(AddDirectory(ConfigDirectory, "remote.conf"));
KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true);