Home

Dokumentation

Impressum

Dokumentation VDR
 

Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

plugin.c

Go to the documentation of this file.
00001 /*
00002  * plugin.c: The VDR plugin interface
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: plugin.c 1.8 2002/11/16 14:22:37 kls Exp $
00008  */
00009 
00010 #include "plugin.h"
00011 #include <ctype.h>
00012 #include <dirent.h>
00013 #include <dlfcn.h>
00014 #include <stdlib.h>
00015 #include <time.h>
00016 #include "config.h"
00017 
00018 #define LIBVDR_PREFIX  "libvdr-"
00019 #define SO_INDICATOR   ".so."
00020 
00021 #define MAXPLUGINARGS  1024
00022 #define HOUSEKEEPINGDELTA 10 // seconds
00023 
00024 // --- cPlugin ---------------------------------------------------------------
00025 
00026 char *cPlugin::configDirectory = NULL;
00027 
00028 cPlugin::cPlugin(void) 
00029 {
00030   name = NULL;
00031 }
00032 
00033 cPlugin::~cPlugin()
00034 {
00035   I18nRegister(NULL, Name());
00036 }
00037 
00038 void cPlugin::SetName(const char *s)
00039 {
00040   name = s;
00041 }
00042 
00043 const char *cPlugin::CommandLineHelp(void)
00044 {
00045   return NULL;
00046 }
00047 
00048 bool cPlugin::ProcessArgs(int argc, char *argv[])
00049 {
00050   return true;
00051 }
00052 
00053 bool cPlugin::Start(void)
00054 {
00055   return true;
00056 }
00057 
00058 void cPlugin::Housekeeping(void)
00059 {
00060 }
00061 
00062 const char *cPlugin::MainMenuEntry(void)
00063 {
00064   return NULL;
00065 }
00066 
00067 cOsdObject *cPlugin::MainMenuAction(void)
00068 {
00069   return NULL;
00070 }
00071 
00072 cMenuSetupPage *cPlugin::SetupMenu(void)
00073 {
00074   return NULL;
00075 }
00076 
00077 bool cPlugin::SetupParse(const char *Name, const char *Value)
00078 {
00079   return false;
00080 }
00081 
00082 void cPlugin::SetupStore(const char *Name, const char *Value)
00083 {
00084   Setup.Store(Name, Value, this->Name());
00085 }
00086 
00087 void cPlugin::SetupStore(const char *Name, int Value)
00088 {
00089   Setup.Store(Name, Value, this->Name());
00090 }
00091 
00092 void cPlugin::RegisterI18n(const tI18nPhrase * const Phrases)
00093 {
00094   I18nRegister(Phrases, Name());
00095 }
00096 
00097 void cPlugin::SetConfigDirectory(const char *Dir)
00098 {
00099   configDirectory = strdup(Dir);
00100 }
00101 
00102 const char *cPlugin::ConfigDirectory(const char *PluginName)
00103 {
00104   static char *buffer = NULL;
00105   free(buffer);
00106   asprintf(&buffer, "%s/plugins%s%s", configDirectory, PluginName ? "/" : "", PluginName ? PluginName : "");
00107   return MakeDirs(buffer, true) ? buffer : NULL;
00108 }
00109 
00110 // --- cDll ------------------------------------------------------------------
00111 
00112 cDll::cDll(const char *FileName, const char *Args)
00113 {
00114   fileName = strdup(FileName);
00115   args = Args ? strdup(Args) : NULL;
00116   handle = NULL;
00117   plugin = NULL;
00118 }
00119 
00120 cDll::~cDll()
00121 {
00122   delete plugin;
00123   if (handle)
00124      dlclose(handle);
00125   free(args);
00126   free(fileName);
00127 }
00128 
00129 static char *SkipQuote(char *s)
00130 {
00131   char c = *s;
00132   strcpy(s, s + 1);
00133   while (*s && *s != c) {
00134         if (*s == '\\')
00135            strcpy(s, s + 1);
00136         if (*s)
00137            s++;
00138         }
00139   if (*s) {
00140      strcpy(s, s + 1);
00141      return s;
00142      }
00143   esyslog("ERROR: missing closing %c", c);
00144   fprintf(stderr, "vdr: missing closing %c\n", c);
00145   return NULL;
00146 }
00147 
00148 bool cDll::Load(bool Log)
00149 {
00150   if (Log)
00151      isyslog("loading plugin: %s", fileName);
00152   if (handle) {
00153      esyslog("attempt to load plugin '%s' twice!", fileName);
00154      return false;
00155      }
00156   handle = dlopen(fileName, RTLD_NOW);
00157   const char *error = dlerror();
00158   if (!error) {
00159      void *(*creator)(void);
00160      (void *)creator = dlsym(handle, "VDRPluginCreator");
00161      if (!(error = dlerror()))
00162         plugin = (cPlugin *)creator();
00163      }
00164   if (!error) {
00165      if (plugin && args) {
00166         int argc = 0;
00167         char *argv[MAXPLUGINARGS];
00168         char *p = args;
00169         char *q = NULL;
00170         bool done = false;
00171         while (!done) {
00172               if (!q)
00173                  q = p;
00174               switch (*p) {
00175                 case '\\': strcpy(p, p + 1);
00176                            if (*p)
00177                               p++;
00178                            else {
00179                               esyslog("ERROR: missing character after \\");
00180                               fprintf(stderr, "vdr: missing character after \\\n");
00181                               return false;
00182                               }
00183                            break;
00184                 case '"':
00185                 case '\'': if ((p = SkipQuote(p)) == NULL)
00186                               return false;
00187                            break;
00188                 default: if (!*p || isspace(*p)) {
00189                             done = !*p;
00190                             *p = 0;
00191                             if (q) {
00192                                if (argc < MAXPLUGINARGS - 1)
00193                                   argv[argc++] = q;
00194                                else {
00195                                   esyslog("ERROR: plugin argument list too long");
00196                                   fprintf(stderr, "vdr: plugin argument list too long\n");
00197                                   return false;
00198                                   }
00199                                q = NULL;
00200                                }
00201                             }
00202                          if (!done)
00203                             p++;
00204                 }
00205               }
00206         argv[argc] = NULL;
00207         if (argc)
00208            plugin->SetName(argv[0]);
00209         optind = 0; // to reset the getopt() data
00210         return !argc || plugin->ProcessArgs(argc, argv);
00211         }
00212      }
00213   else {
00214      esyslog("ERROR: %s", error);
00215      fprintf(stderr, "vdr: %s\n", error);
00216      }
00217   return !error && plugin;
00218 }
00219 
00220 // --- cPluginManager --------------------------------------------------------
00221 
00222 cPluginManager *cPluginManager::pluginManager = NULL;
00223 
00224 cPluginManager::cPluginManager(const char *Directory)
00225 {
00226   directory = NULL;
00227   lastHousekeeping = time(NULL);
00228   nextHousekeeping = -1;
00229   if (pluginManager) {
00230      fprintf(stderr, "vdr: attempt to create more than one plugin manager - exiting!\n");
00231      exit(2);
00232      }
00233   SetDirectory(Directory);
00234   pluginManager = this;
00235 }
00236 
00237 cPluginManager::~cPluginManager()
00238 {
00239   Shutdown();
00240   free(directory);
00241   if (pluginManager == this)
00242      pluginManager = NULL;
00243 }
00244 
00245 void cPluginManager::SetDirectory(const char *Directory)
00246 {
00247   free(directory);
00248   directory = Directory ? strdup(Directory) : NULL;
00249 }
00250 
00251 void cPluginManager::AddPlugin(const char *Args)
00252 {
00253   if (strcmp(Args, "*") == 0) {
00254      DIR *d = opendir(directory);
00255      if (d) {
00256         struct dirent *e;
00257         while ((e = readdir(d)) != NULL) {
00258               if (strstr(e->d_name, LIBVDR_PREFIX) == e->d_name) {
00259                  char *p = strstr(e->d_name, SO_INDICATOR);
00260                  if (p) {
00261                     *p = 0;
00262                     p += strlen(SO_INDICATOR);
00263                     if (strcmp(p, VDRVERSION) == 0) {
00264                        char *name = e->d_name + strlen(LIBVDR_PREFIX);
00265                        if (strcmp(name, "*") != 0) { // let's not get into a loop!
00266                           AddPlugin(e->d_name + strlen(LIBVDR_PREFIX));
00267                           }
00268                        }
00269                     }
00270                  }
00271               }
00272         closedir(d);
00273         }
00274      return;
00275      }
00276   char *s = strdup(Args);
00277   char *p = strchr(s, ' ');
00278   if (p)
00279      *p = 0;
00280   char *buffer = NULL;
00281   asprintf(&buffer, "%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, VDRVERSION);
00282   dlls.Add(new cDll(buffer, Args));
00283   free(buffer);
00284   free(s);
00285 }
00286 
00287 bool cPluginManager::LoadPlugins(bool Log)
00288 {
00289   for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) {
00290       if (!dll->Load(Log))
00291          return false;
00292       }
00293   return true;
00294 }
00295 
00296 bool cPluginManager::StartPlugins(void)
00297 {
00298   for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) {
00299       cPlugin *p = dll->Plugin();
00300       if (p) {
00301          int Language = Setup.OSDLanguage;
00302          Setup.OSDLanguage = 0; // the i18n texts are only available _after_ Start()
00303          isyslog("starting plugin: %s (%s): %s", p->Name(), p->Version(), p->Description());
00304          Setup.OSDLanguage = Language;
00305          if (!p->Start())
00306             return false;
00307          }
00308       }
00309   return true;
00310 }
00311 
00312 void cPluginManager::Housekeeping(void)
00313 {
00314   if (time(NULL) - lastHousekeeping > HOUSEKEEPINGDELTA) {
00315      if (++nextHousekeeping >= dlls.Count())
00316         nextHousekeeping = 0;
00317      cDll *dll = dlls.Get(nextHousekeeping);
00318      if (dll) {
00319         cPlugin *p = dll->Plugin();
00320         if (p) {
00321            p->Housekeeping();
00322            }
00323         }
00324      lastHousekeeping = time(NULL);
00325      }
00326 }
00327 
00328 bool cPluginManager::HasPlugins(void)
00329 {
00330   return pluginManager && pluginManager->dlls.Count();
00331 }
00332 
00333 cPlugin *cPluginManager::GetPlugin(int Index)
00334 {
00335   cDll *dll = pluginManager ? pluginManager->dlls.Get(Index) : NULL;
00336   return dll ? dll->Plugin() : NULL;
00337 }
00338 
00339 cPlugin *cPluginManager::GetPlugin(const char *Name)
00340 {
00341   if (pluginManager) {
00342      for (cDll *dll = pluginManager->dlls.First(); dll; dll = pluginManager->dlls.Next(dll)) {
00343          cPlugin *p = dll->Plugin();
00344          if (p && strcmp(p->Name(), Name) == 0)
00345             return p;
00346          }
00347      }
00348   return NULL;
00349 }
00350 
00351 void cPluginManager::Shutdown(bool Log)
00352 {
00353   cDll *dll;
00354   while ((dll = dlls.Last()) != NULL) {
00355         if (Log) {
00356            cPlugin *p = dll->Plugin();
00357            if (p)
00358               isyslog("stopping plugin: %s", p->Name());
00359            }
00360         dlls.Del(dll);
00361         }
00362 }

Generated on Wed Feb 5 23:30:11 2003 for VDR by doxygen1.3-rc2