#!/usr/bin/perl -w # newplugin: Initializing a new plugin source directory # # Creates a new plugin source directory from which to start implementing # a plugin for VDR. # See the file PLUGINS.html for detailed instructions on how to # write a plugin. # # Usage: newplugin # # See the main source file 'vdr.c' for copyright information and # how to reach the author. # # $Id: newplugin 5.1 2021/01/02 14:32:20 kls Exp $ $PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin \n"; die "Please use only lowercase letters and digits in the plugin name\n" if ($PLUGIN_NAME =~ tr/a-z0-9//c); $PLUGIN_CLASS = ucfirst($PLUGIN_NAME); $PLUGIN_VERSION = "0.0.1"; $PLUGIN_DESCRIPTION = "Enter description for '$PLUGIN_NAME' plugin"; $PLUGIN_MAINENTRY = $PLUGIN_CLASS; $PLUGINS_SRC = "PLUGINS/src"; $README = qq {This is a "plugin" for the Video Disk Recorder (VDR). Written by: Your Name Project's homepage: URL Latest version available at: URL 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. See the file COPYING for more information. Description: }; $HISTORY_TITLE = "VDR Plugin '$PLUGIN_NAME' Revision History"; $HISTORY_LINE = '-' x length($HISTORY_TITLE); $HISTORY_DATE = sprintf("%4d-%02d-%02d", (localtime)[5] + 1900, (localtime)[4] + 1, (localtime)[3]); $HISTORY = qq {$HISTORY_TITLE $HISTORY_LINE $HISTORY_DATE: Version $PLUGIN_VERSION - Initial revision. }; $MAKEFILE = qq {# # Makefile for a Video Disk Recorder plugin # # \$Id\$ # 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 = $PLUGIN_NAME ### 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 directory environment: # Use package data if installed...otherwise assume we're under the VDR source directory: PKG_CONFIG ?= pkg-config PKGCFG = \$(if \$(VDRDIR),\$(shell \$(PKG_CONFIG) --variable=\$(1) \$(VDRDIR)/vdr.pc),\$(shell PKG_CONFIG_PATH="\$\$PKG_CONFIG_PATH:../../.." \$(PKG_CONFIG) --variable=\$(1) vdr)) LIBDIR = \$(call PKGCFG,libdir) LOCDIR = \$(call PKGCFG,locdir) PLGCFG = \$(call PKGCFG,plgcfg) # TMPDIR ?= /tmp ### The compiler options: export CFLAGS = \$(call PKGCFG,cflags) export CXXFLAGS = \$(call PKGCFG,cxxflags) ### The version number of VDR's plugin API: APIVERSION = \$(call PKGCFG,apiversion) ### Allow user defined options to overwrite defaults: -include \$(PLGCFG) ### The name of the distribution archive: ARCHIVE = \$(PLUGIN)-\$(VERSION) PACKAGE = vdr-\$(ARCHIVE) ### The name of the shared object file: SOFILE = libvdr-\$(PLUGIN).so ### Includes and Defines (add further entries here): INCLUDES += DEFINES += -DPLUGIN_NAME_I18N='"\$(PLUGIN)"' ### The object files (add further files here): OBJS = \$(PLUGIN).o ### The main target: all: \$(SOFILE) i18n ### Implicit rules: %.o: %.c \@echo CC \$\@ \$(Q)\$(CXX) \$(CXXFLAGS) -c \$(DEFINES) \$(INCLUDES) -o \$\@ \$< ### Dependencies: MAKEDEP = \$(CXX) -MM -MG DEPFILE = .dependencies \$(DEPFILE): Makefile \@\$(MAKEDEP) \$(CXXFLAGS) \$(DEFINES) \$(INCLUDES) \$(OBJS:%.o=%.c) > \$\@ -include \$(DEPFILE) ### Internationalization (I18N): PODIR = po I18Npo = \$(wildcard \$(PODIR)/*.po) I18Nmo = \$(addsuffix .mo, \$(foreach file, \$(I18Npo), \$(basename \$(file)))) I18Nmsgs = \$(addprefix \$(DESTDIR)\$(LOCDIR)/, \$(addsuffix /LC_MESSAGES/vdr-\$(PLUGIN).mo, \$(notdir \$(foreach file, \$(I18Npo), \$(basename \$(file)))))) I18Npot = \$(PODIR)/\$(PLUGIN).pot %.mo: %.po \@echo MO \$\@ \$(Q)msgfmt -c -o \$\@ \$< \$(I18Npot): \$(wildcard *.c) \@echo GT \$\@ \$(Q)xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-\$(PLUGIN) --package-version=\$(VERSION) --msgid-bugs-address='' -o \$\@ `ls \$^` %.po: \$(I18Npot) \@echo PO \$\@ \$(Q)msgmerge -U --no-wrap --no-location --backup=none -q -N \$\@ \$< \@touch \$\@ \$(I18Nmsgs): \$(DESTDIR)\$(LOCDIR)/%/LC_MESSAGES/vdr-\$(PLUGIN).mo: \$(PODIR)/%.mo install -D -m644 \$< \$\@ .PHONY: i18n i18n: \$(I18Nmo) \$(I18Npot) install-i18n: \$(I18Nmsgs) ### Targets: \$(SOFILE): \$(OBJS) \@echo LD \$\@ \$(Q)\$(CXX) \$(CXXFLAGS) \$(LDFLAGS) -shared \$(OBJS) -o \$\@ install-lib: \$(SOFILE) install -D \$^ \$(DESTDIR)\$(LIBDIR)/\$^.\$(APIVERSION) install: install-lib install-i18n dist: \$(I18Npo) 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 \$(PODIR)/*.mo \$(PODIR)/*.pot \@-rm -f \$(OBJS) \$(DEPFILE) *.so *.tgz core* *~ }; $MAIN = qq {/* * $PLUGIN_NAME.c: A plugin for the Video Disk Recorder * * See the README file for copyright information and how to reach the author. * * \$Id\$ */ #include static const char *VERSION = "$PLUGIN_VERSION"; static const char *DESCRIPTION = "$PLUGIN_DESCRIPTION"; static const char *MAINMENUENTRY = "$PLUGIN_MAINENTRY"; class cPlugin$PLUGIN_CLASS : public cPlugin { private: // Add any member variables or functions you may need here. public: cPlugin$PLUGIN_CLASS(void); virtual ~cPlugin$PLUGIN_CLASS(); virtual const char *Version(void) { return VERSION; } virtual const char *Description(void) { return DESCRIPTION; } virtual const char *CommandLineHelp(void); virtual bool ProcessArgs(int argc, char *argv[]); virtual bool Initialize(void); virtual bool Start(void); virtual void Stop(void); virtual void Housekeeping(void); virtual void MainThreadHook(void); virtual cString Active(void); virtual time_t WakeupTime(void); virtual const char *MainMenuEntry(void) { return MAINMENUENTRY; } virtual cOsdObject *MainMenuAction(void); 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) { // Initialize any member variables here. // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! } cPlugin${PLUGIN_CLASS}::~cPlugin$PLUGIN_CLASS() { // Clean up after yourself! } const char *cPlugin${PLUGIN_CLASS}::CommandLineHelp(void) { // Return a string that describes all known command line options. return NULL; } bool cPlugin${PLUGIN_CLASS}::ProcessArgs(int argc, char *argv[]) { // Implement command line argument processing here if applicable. return true; } bool cPlugin${PLUGIN_CLASS}::Initialize(void) { // Initialize any background activities the plugin shall perform. return true; } bool cPlugin${PLUGIN_CLASS}::Start(void) { // Start any background activities the plugin shall perform. return true; } void cPlugin${PLUGIN_CLASS}::Stop(void) { // Stop any background activities the plugin is performing. } void cPlugin${PLUGIN_CLASS}::Housekeeping(void) { // Perform any cleanup or other regular tasks. } void cPlugin${PLUGIN_CLASS}::MainThreadHook(void) { // Perform actions in the context of the main program thread. // WARNING: Use with great care - see PLUGINS.html! } cString cPlugin${PLUGIN_CLASS}::Active(void) { // Return a message string if shutdown should be postponed return NULL; } time_t cPlugin${PLUGIN_CLASS}::WakeupTime(void) { // Return custom wakeup time for shutdown script return 0; } cOsdObject *cPlugin${PLUGIN_CLASS}::MainMenuAction(void) { // Perform the action when selected from the main VDR menu. return NULL; } cMenuSetupPage *cPlugin${PLUGIN_CLASS}::SetupMenu(void) { // Return a setup menu in case the plugin supports one. return NULL; } bool cPlugin${PLUGIN_CLASS}::SetupParse(const char *Name, const char *Value) { // Parse your own setup parameters and store their values. return false; } bool cPlugin${PLUGIN_CLASS}::Service(const char *Id, void *Data) { // Handle custom service requests from other plugins return false; } const char **cPlugin${PLUGIN_CLASS}::SVDRPHelpPages(void) { // Return help text for SVDRP commands this plugin implements return NULL; } cString 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! }; $PLUGINDIR = "$PLUGINS_SRC/$PLUGIN_NAME"; die "The directory $PLUGINS_SRC doesn't exist!\n" unless (-d "$PLUGINS_SRC"); die "A plugin named '$PLUGIN_NAME' already exists in $PLUGINS_SRC!\n" if (-e "$PLUGINDIR"); mkdir("$PLUGINDIR") || die "$!"; mkdir("$PLUGINDIR/po") || die "$!"; CreateFile("README", $README); CreateFile("HISTORY", $HISTORY); CreateFile("Makefile", $MAKEFILE); CreateFile("$PLUGIN_NAME.c", $MAIN); `cp COPYING "$PLUGINDIR"` if (-e "COPYING"); print qq{ The new plugin source directory has been created in "$PLUGINDIR". The next steps you should perform now are: * edit the file "README" to adjust it to your specific implementation * fill in the code skeleton in "$PLUGIN_NAME.c" to implement your plugin function * add further source files if necessary * adapt the "Makefile" if necessary * do "make plugins" from the VDR source directory to build your plugin }; sub CreateFile { my ($FileName, $Content) = @_; open(FILE, ">$PLUGINDIR/$FileName") || die "$FileName: $!\n"; print FILE $Content; close(FILE); }