mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	The files "commands.conf" and "reccmd.conf" can now contain nested lists of commands
This commit is contained in:
		
							
								
								
									
										4
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								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. | ||||
|   | ||||
							
								
								
									
										79
									
								
								config.c
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								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; | ||||
| } | ||||
|  | ||||
| // --- Folders and Commands -------------------------------------------------- | ||||
|  | ||||
| cNestedItemList Folders; | ||||
|  | ||||
| // --- cCommands ------------------------------------------------------------- | ||||
|  | ||||
| cCommands Commands; | ||||
| cCommands RecordingCommands; | ||||
| cNestedItemList Commands; | ||||
| cNestedItemList RecordingCommands; | ||||
|  | ||||
| // --- cSVDRPhosts ----------------------------------------------------------- | ||||
|  | ||||
|   | ||||
							
								
								
									
										23
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								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 { | ||||
|   | ||||
							
								
								
									
										98
									
								
								menu.c
									
									
									
									
									
								
							
							
						
						
									
										98
									
								
								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; | ||||
|   | ||||
							
								
								
									
										20
									
								
								vdr.5
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								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 | ||||
|   | ||||
							
								
								
									
										6
									
								
								vdr.c
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user