summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2005-08-27 16:42:28 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2005-08-27 16:42:28 +0200
commit6445b9a0864a945d50e5ea4744f3bfa4ee8622dd (patch)
tree3b1759d7d98226656ee52bddab007e1c48847dc3
parent110c64f56db10405446cafb17a1c18308fff0b96 (diff)
downloadvdr-6445b9a0864a945d50e5ea4744f3bfa4ee8622dd.tar.gz
vdr-6445b9a0864a945d50e5ea4744f3bfa4ee8622dd.tar.bz2
Implemented SVDRP command for plugins
-rw-r--r--CONTRIBUTORS3
-rw-r--r--HISTORY5
-rw-r--r--PLUGINS.html122
-rw-r--r--PLUGINS/src/svdrpdemo/COPYING340
-rw-r--r--PLUGINS/src/svdrpdemo/HISTORY6
-rw-r--r--PLUGINS/src/svdrpdemo/Makefile82
-rw-r--r--PLUGINS/src/svdrpdemo/README13
-rw-r--r--PLUGINS/src/svdrpdemo/svdrpdemo.c60
-rwxr-xr-xnewplugin16
-rw-r--r--plugin.c12
-rw-r--r--plugin.h4
-rw-r--r--svdrp.c157
-rw-r--r--svdrp.h4
-rw-r--r--tools.c12
-rw-r--r--tools.h3
15 files changed, 785 insertions, 54 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 803c3be4..aa4a861c 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1449,3 +1449,6 @@ David Woodhouse <dwmw2@infradead.org>
Marcus Hilbrich <s4440288@mail.inf.tu-dresden.de>
for a bug report that lead to fixing the EPG scan, so that it doesn't use the
primary device if that is currently in Transfer-Mode from itself
+
+Hardy Flor <HFlor@web.de>
+ for a patch that was used as a base to implement SVDRP commands for plugins
diff --git a/HISTORY b/HISTORY
index b9a840b9..cb6fa780 100644
--- a/HISTORY
+++ b/HISTORY
@@ -3736,3 +3736,8 @@ Video Disk Recorder Revision History
as delimiter (thanks to Marco Schlüßler).
- Moved cMenuEditTimer and cMenuEvent to menu.h so that plugins can use it (suggested
by Thomas Günther).
+- The new static function cString::sprintf() can be used to easily create a formatted
+ string.
+- Plugins can now implement their own SVDRP commands (based on a patch from Hardy
+ Flor). See PLUGINS.html, section "SVDRP commands" for details. The SVDRP commands
+ of a plugin are accessed through the new SVDRP command PLUG.
diff --git a/PLUGINS.html b/PLUGINS.html
index bcd6e581..7123f74c 100644
--- a/PLUGINS.html
+++ b/PLUGINS.html
@@ -14,18 +14,18 @@ Copyright &copy; 2005 Klaus Schmidinger<br>
<a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
</center>
<p>
-<!--X1.3.19--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
-Important modifications introduced in version 1.3.19 are marked like this.
-<!--X1.3.19--></td></tr></table>
-<!--X1.3.20--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
+<!--X1.3.20--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.20 are marked like this.
<!--X1.3.20--></td></tr></table>
-<!--X1.3.21--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
+<!--X1.3.21--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.21 are marked like this.
<!--X1.3.21--></td></tr></table>
-<!--X1.3.30--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+<!--X1.3.30--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.3.30 are marked like this.
<!--X1.3.30--></td></tr></table>
+<!--X1.3.31--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+Important modifications introduced in version 1.3.31 are marked like this.
+<!--X1.3.31--></td></tr></table>
<p>
VDR provides an easy to use plugin interface that allows additional functionality
to be added to the program by implementing a dynamically loadable library file.
@@ -58,7 +58,7 @@ structures and allows it to hook itself into specific areas to perform special a
<li><a href="#Command line arguments">Command line arguments</a>
<li><a href="#Command line help">Command line help</a>
<li><a href="#Getting started">Getting started</a>
-<!--X1.3.20--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
+<!--X1.3.20--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<li><a href="#Shutting down">Shutting down</a>
<!--X1.3.20--></td></tr></table>
<li><a href="#Main menu entry">Main menu entry</a>
@@ -68,9 +68,12 @@ structures and allows it to hook itself into specific areas to perform special a
<li><a href="#The Setup menu">The Setup menu</a>
<li><a href="#Configuration files">Configuration files</a>
<li><a href="#Internationalization">Internationalization</a>
-<!--X1.3.30--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+<!--X1.3.30--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
<li><a href="#Custom services">Custom services</a>
<!--X1.3.30--></td></tr></table>
+<!--X1.3.31--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+<li><a href="#SVDRP commands">SVDRP commands</a>
+<!--X1.3.31--></td></tr></table>
<li><a href="#Loading plugins into VDR">Loading plugins into VDR</a>
<li><a href="#Building the distribution package">Building the distribution package</a>
</ul>
@@ -84,7 +87,7 @@ structures and allows it to hook itself into specific areas to perform special a
<li><a href="#Skins">Skins</a>
<li><a href="#Themes">Themes</a>
<li><a href="#Devices">Devices</a>
-<!--X1.3.21--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
+<!--X1.3.21--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
<li><a href="#Audio">Audio</a>
<!--X1.3.21--></td></tr></table>
<li><a href="#Remote Control">Remote Control</a>
@@ -311,7 +314,7 @@ since VDR, for instance, has to create the plugin objects in order to get their
command line help - and after that immediately destroys them again.
<p>
The <b>destructor</b> has to clean up any data created by the plugin.
-<!--X1.3.20--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
+<!--X1.3.20--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
Any threads the plugin may have created shall be stopped in the
<a href="#Shutting down"><tt>Stop()</tt></a> function.
<!--X1.3.20--></td></tr></table>
@@ -509,7 +512,7 @@ VDR to exit.
If the plugin doesn't implement any background functionality or internationalized
texts, it doesn't need to implement either of these functions.
-<!--X1.3.20--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
+<!--X1.3.20--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
<a name="Shutting down"><hr><h2>Shutting down</h2>
<center><i><b>Stop it, right there!</b></i></center><p>
@@ -869,7 +872,7 @@ Texts are first searched for in the <i>Phrases</i> registered for this plugin (i
and then in the global VDR texts. So a plugin can make use of texts defined by the
core VDR code.
-<!--X1.3.30--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+<!--X1.3.30--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
<a name="Custom services"><hr><h2>Custom services</h2>
<center><i><b>What can I do for you?</b></i></center><p>
@@ -940,6 +943,97 @@ any plugin handled the request, or <tt>false</tt> if no plugin handled the reque
<!--X1.3.30--></td></tr></table>
+<!--X1.3.31--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+<a name="SVDRP commands"><hr><h2>SVDRP commands</h2>
+
+<center><i><b>Infinite Diversity in Infinite Combinations</b></i></center><p>
+
+A plugin can implement its own SVDRP commands through the two functions
+
+<p><table><tr><td bgcolor=#F0F0F0><pre>
+virtual const char **SVDRPHelpPages(void);
+virtual cString SVDRPCommand(const char *Cmd, const char *Option, int &ReplyCode);
+</pre></td></tr></table><p>
+
+The <tt>SVDRPHelpPages()</tt> function must return a pointer to a list of help
+strings for all of the plugin's SVDRP commands, like this
+
+<p><table><tr><td bgcolor=#F0F0F0><pre>
+const char **cPluginSvdrpdemo::SVDRPHelpPages(void)
+{
+ static const char *HelpPages[] = {
+ "DATE\n"
+ " Print the current date.",
+ "TIME [ raw ]\n"
+ " Print the current time.\n"
+ " If the optional keyword 'raw' is given, the result will be the\n"
+ " raw time_t data.",
+ NULL
+ };
+ return HelpPages;
+}
+</pre></td></tr></table><p>
+
+Note that the first line of each entry contains the actual command and its
+parameters, while the following lines explain what the command does and what
+the parameters (if any) mean. All lines of the explanation shall be indented
+by exactly 4 blanks (no tabs), and none of them shall be longer than 79 characters
+(to avoid messy output on 80 character wide terminals). The last entry in the
+list must be NULL.
+<p>
+The actual processing of SVDRP commands for a plugin is done in its
+<tt>SVDRPCommand()</tt> function.
+Here's an example of such a function, which implements the commands advertised in
+the above help texts:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre>
+cString cPluginSvdrpdemo::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
+{
+ if (strcasecmp(Command, "DATE") == 0) {
+ // we use the default reply code here
+ return DateString(time(NULL));
+ }
+ else if (strcasecmp(Command, "TIME") == 0) {
+ ReplyCode = 901;
+ if (*Option) {
+ if (strcasecmp(Option, "RAW") == 0)
+ return cString::sprintf("%ld\nThis is the number of seconds since the epoch\n"
+ "and a demo of a multi-line reply", time(NULL));
+ else {
+ ReplyCode = 504;
+ return cString::sprintf("Unknown option: \"%s\"", Option);
+ }
+ }
+ return TimeString(time(NULL));
+ }
+ return NULL;
+}
+</pre></td></tr></table><p>
+
+The command is given to this function in the <tt>Command</tt> parameter, and any optional parameters
+are given in the <tt>Option</tt> string. <tt>Command</tt> always points to an actual, non-empty string, while
+<tt>Option</tt> may point to an empty string (it is never NULL, though).
+<p>
+If a plugin doesn't implement the given command, it shall return NULL, and VDR will
+automatically issue a proper error message. If it encounters an unknown or invalid
+option, it shall set the <tt>ReplyCode</tt> to one of the codes defined in <tt>VDR/svdrp.c</tt>
+and return a proper error message.
+<p>
+The default <tt>ReplyCode</tt> is 900, and if the plugin doesn't care about reply
+codes, it doesn't have to set it to anything else (unless there is an error, of
+course). The codes in the range 901..999 are reserved for plugins that want
+to use special reply codes. Any plugin can use any of these values and doesn't
+have to coordinate this with any other plugin, since the caller knows which
+plugin was called, and will therefore process the values according to the
+particular plugin's definitions.
+<p>
+The returned string may consist of several lines, separated by the newline character
+('<tt>\n</tt>'). Each of these lines will be preceeded with the <tt>ReplyCode</tt>
+when presenting them to the caller, and the continuation character ('<tt>-</tt>')
+will be set for all but the last one.
+
+<!--X1.3.31--></td></tr></table>
+
<a name="Loading plugins into VDR"><hr><h2>Loading plugins into VDR</h2>
<center><i><b>Saddling up!</b></i></center><p>
@@ -1276,9 +1370,7 @@ public:
};
cMyReceiver::cMyReceiver(int Pid)
-<!--X1.3.19--><table width=100%><tr><td bgcolor=#0000AA>&nbsp;</td><td width=100%>
:cReceiver(0, -1, Pid)
-<!--X1.3.19--></td></tr></table>
{
}
@@ -1735,7 +1827,7 @@ private:
virtual void Action(void);
public:
cMyAudio(void);
-<!--X1.3.21--><table width=100%><tr><td bgcolor=#AA0000>&nbsp;</td><td width=100%>
+<!--X1.3.21--><table width=100%><tr><td bgcolor=#00AA00>&nbsp;</td><td width=100%>
virtual void Play(const uchar *Data, int Length, uchar Id);
<!--X1.3.21--></td></tr></table>
virtual void Mute(bool On);
diff --git a/PLUGINS/src/svdrpdemo/COPYING b/PLUGINS/src/svdrpdemo/COPYING
new file mode 100644
index 00000000..5b6e7c66
--- /dev/null
+++ b/PLUGINS/src/svdrpdemo/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/PLUGINS/src/svdrpdemo/HISTORY b/PLUGINS/src/svdrpdemo/HISTORY
new file mode 100644
index 00000000..78014f20
--- /dev/null
+++ b/PLUGINS/src/svdrpdemo/HISTORY
@@ -0,0 +1,6 @@
+VDR Plugin 'svdrpdemo' Revision History
+---------------------------------------
+
+2005-08-27: Version 0.0.1
+
+- Initial revision.
diff --git a/PLUGINS/src/svdrpdemo/Makefile b/PLUGINS/src/svdrpdemo/Makefile
new file mode 100644
index 00000000..5714bdc6
--- /dev/null
+++ b/PLUGINS/src/svdrpdemo/Makefile
@@ -0,0 +1,82 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id: Makefile 1.1 2005/08/27 11:26:49 kls Exp $
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+#
+PLUGIN = svdrpdemo
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The C++ compiler and options:
+
+CXX ?= g++
+CXXFLAGS ?= -O2 -Wall -Woverloaded-virtual
+
+### The directory environment:
+
+DVBDIR = ../../../../DVB
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
+### The version number of VDR (taken from VDR's "config.h"):
+
+VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
+
+DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: libvdr-$(PLUGIN).so
+
+libvdr-$(PLUGIN).so: $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
+ @cp $@ $(LIBDIR)/$@.$(VDRVERSION)
+
+dist: clean
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @mkdir $(TMPDIR)/$(ARCHIVE)
+ @cp -a * $(TMPDIR)/$(ARCHIVE)
+ @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE)
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @echo Distribution package created as $(PACKAGE).tgz
+
+clean:
+ @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
diff --git a/PLUGINS/src/svdrpdemo/README b/PLUGINS/src/svdrpdemo/README
new file mode 100644
index 00000000..27b767a5
--- /dev/null
+++ b/PLUGINS/src/svdrpdemo/README
@@ -0,0 +1,13 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Klaus Schmidinger <Klaus.Schmidinger@cadsoft.de>
+
+Project's homepage: http://www.cadsoft.de/vdr
+
+Latest version available at: http://www.cadsoft.de/vdr
+
+See the file COPYING for license information.
+
+Description:
+
+This plugin shows how to add SVDRP support to a plugin.
diff --git a/PLUGINS/src/svdrpdemo/svdrpdemo.c b/PLUGINS/src/svdrpdemo/svdrpdemo.c
new file mode 100644
index 00000000..b6ee9a70
--- /dev/null
+++ b/PLUGINS/src/svdrpdemo/svdrpdemo.c
@@ -0,0 +1,60 @@
+/*
+ * svdrpdemo.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: svdrpdemo.c 1.1 2005/08/27 16:28:58 kls Exp $
+ */
+
+#include <vdr/plugin.h>
+
+static const char *VERSION = "0.0.1";
+static const char *DESCRIPTION = "How to add SVDRP support to a plugin";
+static const char *MAINMENUENTRY = NULL;
+
+class cPluginSvdrpdemo : public cPlugin {
+private:
+ // Add any member variables or functions you may need here.
+public:
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void) { return DESCRIPTION; }
+ virtual const char **SVDRPHelpPages(void);
+ virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
+ };
+
+const char **cPluginSvdrpdemo::SVDRPHelpPages(void)
+{
+ static const char *HelpPages[] = {
+ "DATE\n"
+ " Print the current date.",
+ "TIME [ raw ]\n"
+ " Print the current time.\n"
+ " If the optional keyword 'raw' is given, the result will be the\n"
+ " raw time_t data.",
+ NULL
+ };
+ return HelpPages;
+}
+
+cString cPluginSvdrpdemo::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
+{
+ if (strcasecmp(Command, "DATE") == 0) {
+ // we use the default reply code here
+ return DateString(time(NULL));
+ }
+ else if (strcasecmp(Command, "TIME") == 0) {
+ ReplyCode = 901;
+ if (*Option) {
+ if (strcasecmp(Option, "RAW") == 0)
+ return cString::sprintf("%ld\nThis is the number of seconds since the epoch\nand a demo of a multi-line reply", time(NULL));
+ else {
+ ReplyCode = 504;
+ return cString::sprintf("Unknown option: \"%s\"", Option);
+ }
+ }
+ return TimeString(time(NULL));
+ }
+ return NULL;
+}
+
+VDRPLUGINCREATOR(cPluginSvdrpdemo); // Don't touch this!
diff --git a/newplugin b/newplugin
index 8badddfb..90d6113a 100755
--- a/newplugin
+++ b/newplugin
@@ -12,7 +12,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: newplugin 1.19 2005/08/21 09:32:08 kls Exp $
+# $Id: newplugin 1.20 2005/08/27 16:13:29 kls Exp $
$PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin <name>\n";
@@ -171,6 +171,8 @@ public:
virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value);
virtual bool Service(const char *Id, void *Data = NULL);
+ virtual const char **SVDRPHelpPages(void);
+ virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
};
cPlugin${PLUGIN_CLASS}::cPlugin$PLUGIN_CLASS(void)
@@ -243,6 +245,18 @@ bool cPlugin${PLUGIN_CLASS}::Service(const char *Id, void *Data)
return false;
}
+const char **cPlugin${PLUGIN_CLASS}::SVDRPHelpPages(vo<F3>id)
+{
+ // Return help text for SVDRP commands this plugin implements
+ return NULL;
+}
+
+const char *cPlugin${PLUGIN_CLASS}::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
+{
+ // Process SVDRP commands this plugin implements
+ return NULL;
+}
+
VDRPLUGINCREATOR(cPlugin$PLUGIN_CLASS); // Don't touch this!
};
diff --git a/plugin.c b/plugin.c
index 8a316cc0..99163134 100644
--- a/plugin.c
+++ b/plugin.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: plugin.c 1.14 2005/08/21 09:35:28 kls Exp $
+ * $Id: plugin.c 1.15 2005/08/27 16:13:24 kls Exp $
*/
#include "plugin.h"
@@ -104,6 +104,16 @@ bool cPlugin::Service(const char *Id, void *Data)
return false;
}
+const char **cPlugin::SVDRPHelpPages(void)
+{
+ return NULL;
+}
+
+cString cPlugin::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
+{
+ return NULL;
+}
+
void cPlugin::RegisterI18n(const tI18nPhrase * const Phrases)
{
I18nRegister(Phrases, Name());
diff --git a/plugin.h b/plugin.h
index 3befbbba..2d9f9833 100644
--- a/plugin.h
+++ b/plugin.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: plugin.h 1.9 2005/08/21 09:32:08 kls Exp $
+ * $Id: plugin.h 1.10 2005/08/27 16:13:17 kls Exp $
*/
#ifndef __PLUGIN_H
@@ -51,6 +51,8 @@ public:
void RegisterI18n(const tI18nPhrase * const Phrases);
virtual bool Service(const char *Id, void *Data = NULL);
+ virtual const char **SVDRPHelpPages(void);
+ virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
static void SetConfigDirectory(const char *Dir);
static const char *ConfigDirectory(const char *PluginName = NULL);
diff --git a/svdrp.c b/svdrp.c
index 093bd997..4d1b5abd 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.74 2005/08/07 14:20:41 kls Exp $
+ * $Id: svdrp.c 1.75 2005/08/27 16:18:32 kls Exp $
*/
#include "svdrp.h"
@@ -32,6 +32,7 @@
#include "eitscan.h"
#include "keys.h"
#include "menu.h"
+#include "plugin.h"
#include "remote.h"
#include "timers.h"
#include "tools.h"
@@ -253,6 +254,12 @@ const char *HelpPages[] = {
" zero, this means that the timer is currently recording and has started\n"
" at the given time. The first value in the resulting line is the number\n"
" of the timer.",
+ "PLUG <name> [ <command> [ <options> ]]\n"
+ " Send a command to a plugin.\n"
+ " The PLUG command without any parameters lists all plugins.\n"
+ " If only a name is given, all commands known to that plugin are listed.\n"
+ " If a command is given (optionally followed by parameters), that command\n"
+ " is sent to the plugin, and the result will be displayed.",
"PUTE\n"
" Put data into the EPG list. The data entered has to strictly follow the\n"
" format defined in vdr(5) for the 'epg.data' file. A '.' on a line\n"
@@ -294,6 +301,8 @@ const char *HelpPages[] = {
504 Command parameter not implemented
550 Requested action not taken
554 Transaction failed
+ 900 Default plugin reply code
+ 901..999 Plugin specific reply codes
*/
@@ -315,15 +324,16 @@ const char *GetHelpTopic(const char *HelpPage)
return NULL;
}
-const char *GetHelpPage(const char *Cmd)
+const char *GetHelpPage(const char *Cmd, const char **p)
{
- const char **p = HelpPages;
- while (*p) {
- const char *t = GetHelpTopic(*p);
- if (strcasecmp(Cmd, t) == 0)
- return *p;
- p++;
- }
+ if (p) {
+ while (*p) {
+ const char *t = GetHelpTopic(*p);
+ if (strcasecmp(Cmd, t) == 0)
+ return *p;
+ p++;
+ }
+ }
return NULL;
}
@@ -376,14 +386,14 @@ void cSVDRP::Reply(int Code, const char *fmt, ...)
va_start(ap, fmt);
char *buffer;
vasprintf(&buffer, fmt, ap);
- char *nl = strchr(buffer, '\n');
- if (Code > 0 && nl && *(nl + 1)) // trailing newlines don't count!
- Code = -Code;
- char number[16];
- sprintf(number, "%03d%c", abs(Code), Code < 0 ? '-' : ' ');
const char *s = buffer;
while (s && *s) {
const char *n = strchr(s, '\n');
+ char cont = ' ';
+ if (Code < 0 || n && *(n + 1)) // trailing newlines don't count!
+ cont = '-';
+ char number[16];
+ sprintf(number, "%03d%c", abs(Code), cont);
if (!(Send(number) && Send(s, n ? n - s : -1) && Send("\r\n"))) {
Close();
break;
@@ -400,6 +410,32 @@ void cSVDRP::Reply(int Code, const char *fmt, ...)
}
}
+void cSVDRP::PrintHelpTopics(const char **hp)
+{
+ int NumPages = 0;
+ if (hp) {
+ while (*hp) {
+ NumPages++;
+ hp++;
+ }
+ hp -= NumPages;
+ }
+ const int TopicsPerLine = 5;
+ int x = 0;
+ for (int y = 0; (y * TopicsPerLine + x) < NumPages; y++) {
+ char buffer[TopicsPerLine * MAXHELPTOPIC + 5];
+ char *q = buffer;
+ q += sprintf(q, " ");
+ for (x = 0; x < TopicsPerLine && (y * TopicsPerLine + x) < NumPages; x++) {
+ const char *topic = GetHelpTopic(hp[(y * TopicsPerLine + x)]);
+ if (topic)
+ q += sprintf(q, "%*s", -MAXHELPTOPIC, topic);
+ }
+ x = 0;
+ Reply(-214, buffer);
+ }
+}
+
void cSVDRP::CmdCHAN(const char *Option)
{
if (*Option) {
@@ -626,7 +662,7 @@ void cSVDRP::CmdGRAB(const char *Option)
void cSVDRP::CmdHELP(const char *Option)
{
if (*Option) {
- const char *hp = GetHelpPage(Option);
+ const char *hp = GetHelpPage(Option, HelpPages);
if (hp)
Reply(214, hp);
else {
@@ -637,24 +673,13 @@ void cSVDRP::CmdHELP(const char *Option)
else {
Reply(-214, "This is VDR version %s", VDRVERSION);
Reply(-214, "Topics:");
- const char **hp = HelpPages;
- int NumPages = 0;
- while (*hp) {
- NumPages++;
- hp++;
- }
- const int TopicsPerLine = 5;
- int x = 0;
- for (int y = 0; (y * TopicsPerLine + x) < NumPages; y++) {
- char buffer[TopicsPerLine * (MAXHELPTOPIC + 5)];
- char *q = buffer;
- for (x = 0; x < TopicsPerLine && (y * TopicsPerLine + x) < NumPages; x++) {
- const char *topic = GetHelpTopic(HelpPages[(y * TopicsPerLine + x)]);
- if (topic)
- q += sprintf(q, " %s", topic);
- }
- x = 0;
- Reply(-214, buffer);
+ PrintHelpTopics(HelpPages);
+ cPlugin *plugin;
+ for (int i = 0; (plugin = cPluginManager::GetPlugin(i)) != NULL; i++) {
+ const char **hp = plugin->SVDRPHelpPages();
+ if (hp)
+ Reply(-214, "Plugin %s v%s - %s", plugin->Name(), plugin->Version(), plugin->Description());
+ PrintHelpTopics(hp);
}
Reply(-214, "To report bugs in the implementation send email to");
Reply(-214, " vdr-bugs@cadsoft.de");
@@ -1042,6 +1067,71 @@ void cSVDRP::CmdNEXT(const char *Option)
Reply(550, "No active timers");
}
+void cSVDRP::CmdPLUG(const char *Option)
+{
+ if (*Option) {
+ char *opt = strdup(Option);
+ char *name = skipspace(opt);
+ char *option = name;
+ while (*option && !isspace(*option))
+ option++;
+ char c = *option;
+ *option = 0;
+ cPlugin *plugin = cPluginManager::GetPlugin(name);
+ if (plugin) {
+ if (c)
+ option = skipspace(++option);
+ char *cmd = option;
+ while (*option && !isspace(*option))
+ option++;
+ if (*option) {
+ *option++ = 0;
+ option = skipspace(option);
+ }
+ if (!*cmd || strcasecmp(cmd, "HELP") == 0) {
+ if (*cmd && *option) {
+ const char *hp = GetHelpPage(option, plugin->SVDRPHelpPages());
+ if (hp) {
+ Reply(-214, hp);
+ Reply(214, "End of HELP info");
+ }
+ else
+ Reply(504, "HELP topic \"%s\" for plugin \"%s\" unknown", option, plugin->Name());
+ }
+ else {
+ Reply(-214, "Plugin %s v%s - %s", plugin->Name(), plugin->Version(), plugin->Description());
+ const char **hp = plugin->SVDRPHelpPages();
+ if (hp) {
+ Reply(-214, "SVDRP commands:");
+ PrintHelpTopics(hp);
+ Reply(214, "End of HELP info");
+ }
+ else
+ Reply(214, "This plugin has no SVDRP commands");
+ }
+ }
+ else {
+ int ReplyCode = 900;
+ cString s = plugin->SVDRPCommand(cmd, option, ReplyCode);
+ if (s)
+ Reply(abs(ReplyCode), *s);
+ else
+ Reply(500, "Command unrecognized: \"%s\"", cmd);
+ }
+ }
+ else
+ Reply(550, "Plugin \"%s\" not found (use PLUG for a list of plugins)", name);
+ free(opt);
+ }
+ else {
+ Reply(-214, "Available plugins:");
+ cPlugin *plugin;
+ for (int i = 0; (plugin = cPluginManager::GetPlugin(i)) != NULL; i++)
+ Reply(-214, "%s v%s - %s", plugin->Name(), plugin->Version(), plugin->Description());
+ Reply(214, "End of plugin list");
+ }
+}
+
void cSVDRP::CmdPUTE(const char *Option)
{
delete PUTEhandler;
@@ -1167,6 +1257,7 @@ void cSVDRP::Execute(char *Cmd)
else if (CMD("NEWC")) CmdNEWC(s);
else if (CMD("NEWT")) CmdNEWT(s);
else if (CMD("NEXT")) CmdNEXT(s);
+ else if (CMD("PLUG")) CmdPLUG(s);
else if (CMD("PUTE")) CmdPUTE(s);
else if (CMD("SCAN")) CmdSCAN(s);
else if (CMD("STAT")) CmdSTAT(s);
diff --git a/svdrp.h b/svdrp.h
index 8df86156..a27201ba 100644
--- a/svdrp.h
+++ b/svdrp.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: svdrp.h 1.20 2004/01/17 15:41:52 kls Exp $
+ * $Id: svdrp.h 1.21 2005/08/27 12:37:49 kls Exp $
*/
#ifndef __SVDRP_H
@@ -52,6 +52,7 @@ private:
void Close(bool Timeout = false);
bool Send(const char *s, int length = -1);
void Reply(int Code, const char *fmt, ...);
+ void PrintHelpTopics(const char **hp);
void CmdCHAN(const char *Option);
void CmdCLRE(const char *Option);
void CmdDELC(const char *Option);
@@ -72,6 +73,7 @@ private:
void CmdNEWC(const char *Option);
void CmdNEWT(const char *Option);
void CmdNEXT(const char *Option);
+ void CmdPLUG(const char *Option);
void CmdPUTE(const char *Option);
void CmdSCAN(const char *Option);
void CmdSTAT(const char *Option);
diff --git a/tools.c b/tools.c
index ca4b0b80..46d3ce26 100644
--- a/tools.c
+++ b/tools.c
@@ -4,13 +4,14 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 1.96 2005/08/06 09:53:21 kls Exp $
+ * $Id: tools.c 1.97 2005/08/27 14:43:55 kls Exp $
*/
#include "tools.h"
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
+#include <stdarg.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/vfs.h>
@@ -530,6 +531,15 @@ cString &cString::operator=(const cString &String)
return *this;
}
+cString cString::sprintf(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ char *buffer;
+ vasprintf(&buffer, fmt, ap);
+ return cString(buffer, true);
+}
+
cString WeekDayName(int WeekDay)
{
char buffer[4];
diff --git a/tools.h b/tools.h
index 0a8ee8b6..41a00498 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.74 2005/08/21 14:06:38 kls Exp $
+ * $Id: tools.h 1.75 2005/08/27 14:40:08 kls Exp $
*/
#ifndef __TOOLS_H
@@ -81,6 +81,7 @@ public:
operator const char * () const { return s; } // for use in (const char *) context
const char * operator*() const { return s; } // for use in (const void *) context (printf() etc.)
cString &operator=(const cString &String);
+ static cString sprintf(const char *fmt, ...);
};
ssize_t safe_read(int filedes, void *buffer, size_t size);