Logo Search packages:      
Sourcecode: beryl-core version File versions

plugin.c

/*
 * Copyright © 2005 Novell, Inc.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Author: David Reveman <davidr@novell.com>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <malloc.h>
#include <dirent.h>

#include <beryl.h>
#include <beryl-private.h>

#define HOME_PLUGINDIR ".beryl/plugins"

CompPlugin *plugins = 0;

#if 0
#define pr_debug(a, b...) do { fprintf(stderr, a, ##b); } while(0)
#else
#define pr_debug(a, b...) do { } while(0)
#endif

#if 0
#define pr_debug_verbose(a, b...) do { fprintf(stderr, a, ##b); } while(0)
#else
#define pr_debug_verbose(a, b...) do { } while(0)
#endif

static Bool loaderLoadPlugin(CompPlugin * p, CompDisplay * d, char *name)
{
      char *file;
      void *dlhand;

      BerylSettingsPlugin * plg = beryl_settings_context_find_plugin(d->context, name);

      if (!plg)
      {
            fprintf(stderr,"Could not find a plugin named %s.\n",name);
            return FALSE;
      }

      file = beryl_settings_plugin_get_filename(plg);
      if (!file)
            return FALSE;

      dlhand = dlopen(file, RTLD_LAZY);
      if (dlhand)
      {
            PluginGetInfoProc getInfo;
            char *error;

            dlerror();

            getInfo = (PluginGetInfoProc) dlsym(dlhand, "getCompPluginInfo");

            error = dlerror();
            if (error)
            {
                  fprintf(stderr, "%s: dlsym: %s\n", programName, error);

                  getInfo = 0;
            }

            if (getInfo)
            {
                  p->vTable = (*getInfo) ();
                  if (!p->vTable)
                  {
                        fprintf(stderr,
                                    _
                                    ("%s: Couldn't get vtable from '%s' plugin\n"),
                                    programName, file);

                        dlclose(dlhand);

                        return FALSE;
                  }
                  if (p->vTable->version != BERYL_VERSION ||
                        p->vTable->struct_plugin_size !=
                        sizeof(CompPlugin)
                        || p->vTable->struct_display_size !=
                        sizeof(CompDisplay)
                        || p->vTable->struct_screen_size !=
                        sizeof(CompScreen)
                        || p->vTable->struct_window_size !=
                        sizeof(CompWindow)
                        || p->vTable->struct_texture_size !=
                        sizeof(CompTexture)
                        || p->vTable->struct_icon_size != sizeof(CompIcon))
                  {

                        fprintf(stderr,
                                    _
                                    ("%s: '%s' plugin version does not match beryl version.\n"),
                                    programName, file);
                        if (p->vTable->version == BERYL_VERSION)
                        {
                              fprintf(stderr,
                                          _
                                          ("%s: '%s' plugin has some sizeof() mismatch.\n"),
                                          programName, file);
                        }
                        else
                        {
                              fprintf(stderr,
                                          _
                                          ("%s is of version %d, but plugin '%s' has version %d.\n"),
                                          programName, BERYL_VERSION,
                                          file, p->vTable->version);
                        }

                        dlclose(dlhand);

                        return FALSE;
                  }
            }
            else
            {
                  fprintf(stderr,
                              _
                              ("%s: Failed to lookup getCompPluginInfo in '%s' ")
                              "plugin\n", programName, file);

                  dlclose(dlhand);

                  return FALSE;
            }
      }
      else
            return FALSE;

      p->devPrivate.ptr = dlhand;
      p->devType = "dlloader";

      return TRUE;
}

static void loaderUnloadPlugin(CompPlugin * p)
{
      dlclose(p->devPrivate.ptr);
}

Bool initPluginForDisplay(CompPlugin * p, CompDisplay * d)
{
      CompScreen *s, *failedScreen = d->screens;
      Bool status = TRUE;

      if (!(*p->vTable->initDisplay) (p, d))
            return FALSE;

      for (s = d->screens; s; s = s->next)
      {
            if (!(*s->initPluginForScreen) (p, s))
            {
                  fprintf(stderr,
                              _("%s: Plugin '%s':initScreen failed\n"),
                              programName, p->vTable->name);
                  failedScreen = s;
                  status = FALSE;
                  break;
            }
      }

      for (s = d->screens; s != failedScreen; s = s->next)
            (*s->finiPluginForScreen) (p, s);
      
      if (p->vTable->getDisplayOptions)
      {
            CompOption *option;
            CompOptionValue value;
            int nOption;
            
            option=(*p->vTable->getDisplayOptions) (d, &nOption);
            while (nOption--)
            {
                  memcpy(&value,&option->value,sizeof(CompOptionValue));
                  if (beryl_settings_context_comp_get_option_value(d->context,p->vTable->name,option->name,FALSE,&value))
                  {
                        if (p->vTable->setDisplayOption)
                              p->vTable->setDisplayOption(d,option->name,&value);
                  }
                  option++;
            }
      }
      return status;
}

void finiPluginForDisplay(CompPlugin * p, CompDisplay * d)
{
      CompScreen *s;

      for (s = d->screens; s; s = s->next)
            (*s->finiPluginForScreen) (p, s);

      (*p->vTable->finiDisplay) (p, d);
}

Bool initPluginForScreen(CompPlugin * p, CompScreen * s)
{
      Bool status = TRUE;
      CompDisplay *d = s->display;
      if (p->vTable->initScreen)
      {
            if (!(*p->vTable->initScreen) (p, s))
                  return FALSE;
      }

      if (p->vTable->initWindow)
      {
            CompWindow *w, *failedWindow = s->windows;

            for (w = s->windows; w; w = w->next)
            {
                  if (!(*p->vTable->initWindow) (p, w))
                  {
                        fprintf(stderr,
                                    _("%s: Plugin '%s':initWindow "
                                      "failed\n"), programName, p->vTable->name);
                        failedWindow = w;
                        status = FALSE;
                        break;
                  }
            }

            if (p->vTable->finiWindow)
            {
                  for (w = s->windows; w != failedWindow; w = w->next)
                        (*p->vTable->finiWindow) (p, w);
            }
      }

      if (p->vTable->getScreenOptions)
      {
            CompOption *option;
            CompOptionValue value;
            int nOption;
            nOption=0;
            option=(*p->vTable->getScreenOptions) (s, &nOption);
            while (nOption--)
            {           
                  memcpy(&value,&option->value,sizeof(CompOptionValue));
                  if (beryl_settings_context_comp_get_option_value(d->context,p->vTable->name,option->name,TRUE,&value))
                  {
                        if (p->vTable->setScreenOption)
                              p->vTable->setScreenOption(s,option->name,&value);
                  }
                  option++;
            }
      }

      return status;
}

void finiPluginForScreen(CompPlugin * p, CompScreen * s)
{
      if (p->vTable->finiWindow)
      {
            CompWindow *w = s->windows;

            for (w = s->windows; w; w = w->next)
                  (*p->vTable->finiWindow) (p, w);
      }

      if (p->vTable->finiScreen)
            (*p->vTable->finiScreen) (p, s);
}

static Bool initPlugin(CompPlugin * p)
{
      CompDisplay *d = compDisplays;

      if (!(*p->vTable->init) (p))
      {
            fprintf(stderr, _("%s: InitPlugin '%s' failed\n"),
                        programName, p->vTable->name);
            return FALSE;
      }

      if (d)
      {
            if (!(*d->initPluginForDisplay) (p, d))
            {
                  fprintf(stderr,
                              _("%s: Plugin '%s':initDisplay failed\n"),
                              programName, p->vTable->name);

                  (*p->vTable->fini) (p);

                  return FALSE;
            }
      }

      return TRUE;
}

static void finiPlugin(CompPlugin * p)
{
      CompDisplay *d = compDisplays;

      if (d)
            (*d->finiPluginForDisplay) (p, d);

      (*p->vTable->fini) (p);
}

void screenInitPlugins(CompScreen * s)
{
      CompPlugin *p;
      int i, j = 0;

      for (p = plugins; p; p = p->next)
            j++;

      while (j--)
      {
            i = 0;
            for (p = plugins; i < j; p = p->next)
                  i++;

            if (p->vTable->initScreen)
                  (*s->initPluginForScreen) (p, s);
      }
}

void screenFiniPlugins(CompScreen * s)
{
      CompPlugin *p;

      for (p = plugins; p; p = p->next)
      {
            if (p->vTable->finiScreen)
                  (*s->finiPluginForScreen) (p, s);
      }
}

void windowInitPlugins(CompWindow * w)
{
      CompPlugin *p;

      for (p = plugins; p; p = p->next)
      {
            if (p->vTable->initWindow)
                  (*p->vTable->initWindow) (p, w);
      }
}

void windowFiniPlugins(CompWindow * w)
{
      CompPlugin *p;

      for (p = plugins; p; p = p->next)
      {
            if (p->vTable->finiWindow)
                  (*p->vTable->finiWindow) (p, w);
      }
}

int findActivePluginIndex(char *name)
{
      CompPlugin *p;
      int i = 0;

      for (p = plugins; p; p = p->next)
      {
            if (!strcmp(p->vTable->name, name))
                  return (p->state == BerylPluginReady) ? i : -1;
            i++;
      }
      return -1;
}

CompPlugin *findActivePlugin(char *name)
{
      CompPlugin *p;

      for (p = plugins; p; p = p->next)
            if (!strcmp(p->vTable->name, name))
                  return (p->state == BerylPluginReady) ? p : 0;

      return 0;
}

static CompPlugin *findActivePluginWithFeature(char *name,
                                                                     CompPluginFeature ** feature)
{
      CompPlugin *p;
      int i;

      for (p = plugins; p; p = p->next)
      {
            if (p->state != BerylPluginReady)
                  continue;

            for (i = 0; i < p->vTable->nFeatures; i++)
            {
                  if (!strcmp(p->vTable->features[i].name, name))
                  {
                        if (feature)
                              *feature = &p->vTable->features[i];

                        return p;
                  }
            }
      }

      return 0;
}

CompPluginFeature *findActiveFeature(char *name)
{
      CompPluginFeature *feature;

      if (findActivePluginWithFeature(name, &feature))
            return feature;
      return 0;
}

void unloadPlugin(CompPlugin * p, CompDisplay * d)
{
      int i, index = -1;
      CompOptionValue *value;

      for (i = 0; i < d->plugin.list.nValue; i++)
            if (!strcmp(p->vTable->name, d->plugin.list.value[i].s))
            {
                  index = i;
                  break;
            }

      if (index == -1)
            fprintf(stderr,
                        "Argh. Can't find plugin name when trying to unload %s.\n",
                        p->vTable->name);

      /* finiPlugin done at start of update plugins */
      loaderUnloadPlugin(p);
      free(p);

      /* Shift down later items in the list */
      for (i = index; i < d->plugin.list.nValue; i++)
      {
            if ((index + 1) < d->plugin.list.nValue)
                  d->plugin.list.value[i].s = d->plugin.list.value[i + 1].s;
      }
      d->plugin.list.nValue--;

      /* Shrink list allocation if possible */
      value = realloc(d->plugin.list.value, sizeof(CompOption) *
                              (d->plugin.list.nValue));
      if (value)
            d->plugin.list.value = value;
}

CompPlugin *loadPlugin(const char *name, CompDisplay * d)
{
      CompPlugin *p;
      Bool status;
      CompOptionValue *value;

      value = realloc(d->plugin.list.value, sizeof(CompOption) *
                              (d->plugin.list.nValue + 1));
      if (!value)
            return 0;

      value[d->plugin.list.nValue].s = strdup(name);
      d->plugin.list.value = value;

      /* Don't increase count until loaded okay */

      p = malloc(sizeof(CompPlugin));
      if (!p)
            return 0;
      p->next = 0;
      p->devPrivate.uval = 0;
      p->devType = NULL;
      p->vTable = 0;
      p->state = BerylPluginNeedsInit;

      status = loaderLoadPlugin(p, d, (char *)name);
      if (!status)
      {
            fprintf(stderr, _("%s: Couldn't load plugin '%s'\n"), programName, name);
            free(p);

            return 0;
      }

      d->plugin.list.nValue++;
      return p;
}

static int comparePluginDeps(CompPlugin * new, CompPlugin * existing)
{
      CompPluginDep *deps;
      int nDeps;

      deps = new->vTable->deps;
      nDeps = new->vTable->nDeps;

      while (nDeps--)
      {
            switch (deps->rule)
            {
            case CompPluginRuleBefore:
                  if (!strcmp(deps->name, existing->vTable->name))
                  {
                        pr_debug_verbose("%s: '%s' plugin must be loaded before '%s' "
                                                  "plugin\n", programName,
                                                 new->vTable->name, deps->name);

                        return -1;
                  }
                  break;
            case CompPluginRuleAfterCategory:
                  if (!strcmp(deps->name, existing->vTable->category))
                  {
                        pr_debug_verbose("%s: '%s' plugin must be loaded after category '%s'"
                                                  " which contains '%s' plugin", programName,
                                                 new->vTable->name, deps->name,
                                                 existing->vTable->name);
                        return 1;
                  }
            case CompPluginRuleAfter:
                  if (!strcmp(deps->name, existing->vTable->name))
                  {
                        pr_debug_verbose("%s: '%s' plugin must be loaded after '%s' "
                                                  "plugin\n", programName,
                                                 new->vTable->name, deps->name);

                        return 1;
                  }
                  break;
            case CompPluginRuleEnd:
                  /* plugins with this rule should be loaded at the end of the list */
                  pr_debug_verbose("%s: '%s' plugin must be loaded at the end of the list\n",
                        programName, new->vTable->name);
                  return 1;
                  break;
            case CompPluginRuleRequire:
                  if (!findActiveFeature(deps->name))
                  {
                        pr_debug_verbose("%s: '%s' plugin needs feature '%s' which "
                                                 "is currently not provided by any plugin\n",
                                                 programName, new->vTable->name, deps->name);
                        /* check if the existing plugin has the "End" rule set 
                           if it has, load the new plugin before */
                        CompPluginDep *oldDeps = existing->vTable->deps;
                        int i;

                        for (i=0;i < existing->vTable->nDeps; i++) {
                              if (oldDeps->rule == CompPluginRuleEnd)
                                    return 0;
                              oldDeps++;
                        }

                        return 1;
                  }
                  break;
            }

            deps++;
      }

      return 0;
}

static Bool checkPluginDeps(CompPlugin * p)
{
      CompPluginDep *deps;
      int nDeps;

      deps = p->vTable->deps;
      nDeps = p->vTable->nDeps;

      while (nDeps--)
      {
            switch (deps->rule)
            {
            case CompPluginRuleRequire:
                  if (!findActiveFeature(deps->name))
                  {
                        fprintf(stderr,
                                    "%s: '%s' plugin needs feature '%s' which "
                                    "is currently not provided by any plugin\n",
                                    programName, p->vTable->name, deps->name);

                        return FALSE;
                  }
                  break;
            default:
                  break;
            }

            deps++;
      }

      return TRUE;
}

static Bool splashWasActive = FALSE;

static void splashActivate(CompPlugin * p)
{
      CompDisplay *d = compDisplays;

      if (splashWasActive || strcmp(p->vTable->name, "splash") != 0)
            return;
      splashWasActive = TRUE;

      int i, nOpts = 0;
      CompOption *o = p->vTable->getDisplayOptions(d, &nOpts);
      CompScreen *s;

      for (s = d->screens; s; s = s->next)
      {
            for (i = 0; i < nOpts; i++)
            {
                  if (strcmp(o[i].name, "initiate") == 0)
                  {
                        CompOption root;

                        root.type = CompOptionTypeInt;
                        root.name = "root";
                        root.value.i = s->root;
                        printf("Initiating splash\n");
                        (*o[i].value.action.initiate) (d,
                                                                     &(o[i].
                                                                         value.action), 0, &root, 1);
                  }
            }
      }
}

static Bool tryInitPlugin(CompPlugin * p)
{
      CompPlugin *plugin;
      int i;

      for (i = 0; i < p->vTable->nFeatures; i++)
      {
            plugin = findActivePluginWithFeature(p->vTable->features[i].name, 0);

            if (plugin)
            {
                  fprintf(stderr,
                              "%s: Plugin '%s' can't be activated because "
                              "plugin '%s' is already providing feature '%s'\n",
                              programName, p->vTable->name,
                              plugin->vTable->name, p->vTable->features[i].name);
                  return FALSE;
            }
      }

      if (!checkPluginDeps(p))
      {
            fprintf(stderr,
                        _
                        ("%s: Can't activate '%s' plugin due to dependency "
                         "problems\n"), programName, p->vTable->name);

            return FALSE;
      }

      if (!initPlugin(p))
      {
            fprintf(stderr, _("%s: Couldn't activate plugin '%s'\n"),
                        programName, p->vTable->name);

            return FALSE;
      }

      splashActivate(p);

      p->state = BerylPluginReady;

      return TRUE;
}

CompPlugin *getPlugins(void)
{
      return plugins;
}

static void depth_first_plugin(CompPlugin * p, int cnt, CompPlugin ** list)
{
      if (p->state)
            return; // already visited
      p->state = 1; // visited this one now
      int i;
      for (i=0;i<cnt;i++)
      {
            if (p!=list[i])
            {
                  //depth-first into any plugin that this one must come after...first
                  if (comparePluginDeps(p,list[i])==1)
                        depth_first_plugin(list[i],cnt,list);
            }
      }
      p->next=plugins;
      plugins=p;
}

static void sort_plugin_list(void)
{
      CompPlugin * pl = NULL;
      //DAG Depth-First sorting:
      CompPlugin * p[256];
      int pState[256];
      //backing array of plugins, simple and succinct
      //now, we'll abuse state to store if a plugin has been visited in depth-first
      int cnt=0;
      for (pl=plugins;pl;pl=pl->next)
      {
            pState[cnt]=pl->state;
            p[cnt++]=pl;
            pl->state=0; // not visited
      }
      plugins = NULL;
      int i;
      for (i=0;i<cnt;i++)
            depth_first_plugin(p[i],cnt,p);
      for (i=0;i<cnt;i++)
            p[i]->state=pState[i]; // restore state

      CompPlugin * new_list = plugins;
      pr_debug("New list: ");
      while (new_list)
      {
            pr_debug("%s ", new_list->vTable->name);
            new_list = new_list->next;
      }
      pr_debug("\n");
}

void updatePlugins(CompDisplay * d)
{
      CompPlugin *p, *prev = NULL;
      int i, j, old_num = 0, new_num = 0;

      for (i = 0; i < d->nRequestFlags; i++)
      {
            for (j = 0; j < 8; j++)
            {
                  d->requestFlags[i].data[j] = 0;
            }
      }

      /* Unload by default. */
      pr_debug("Pop: ");
      p = plugins;
      while (p)
      {
            old_num++;
            pr_debug("%s ", p->vTable->name);
            
            
                  finiPlugin(p);
                  p->state = BerylPluginNeedsUnload;
            
            p = p->next;
      }
      pr_debug("\n");

      pr_debug("Old number of plugins is %d.\n", old_num);

      /* first load settings plugin (unconditionally) upon
       * first startup to get the list of plugins to be
       * activated
       */


      GSList * active_plugins;
      GSList * iter;
      //o = &d->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS];
      active_plugins=beryl_settings_context_get_active_plugins(d->context);

      /*
       * Now mark names still in the list as ok, and
       * find how many plugins we'll have in the new
       * list. Don't load new plugins yet though,
       * because we want to make sure we can allocate
       * the new list first.
       */

      for (iter=active_plugins;iter;iter=iter->next)
      {
            pr_debug("Plugin %s ", beryl_settings_plugin_get_name(iter->data));
            p = plugins;
            while (p)
            {
                  if (!strcmp(beryl_settings_plugin_get_name(iter->data), p->vTable->name))
                  {
                        pr_debug("matches an existing plugin name.\n");
                        if (p->state == BerylPluginNeedsUnload)
                        {
                              p->state = BerylPluginNeedsInit;
                              new_num++;
                        }
                        break;
                  }
                  p = p->next;
            }

            /* New plugin? */
            if (!p)
            {
                  pr_debug("is a new plugin.\n");
            }
      }

      pr_debug("New number of plugins is %d.\n", new_num);
      pr_debug("Checking for new plugins.\n");

      /*
       * Now mark names still in the list as ok, and
       * seek to load plugins with new names.
       */
      for (iter = active_plugins; iter; iter=iter->next)
      {
            p = plugins;
            while (p)
            {
                  if (!strcmp(beryl_settings_plugin_get_name(iter->data), p->vTable->name))
                  {
                        break;
                  }
                  p = p->next;
            }

            /* New plugin? */
            if (!p)
            {
                  pr_debug("Seeking to load %s.\n", beryl_settings_plugin_get_name(iter->data));
                  p = loadPlugin(beryl_settings_plugin_get_name(iter->data), d);
                  if (p)
                  {
                        p->next = plugins;
                        plugins = p;
                        new_num++;
                  }
            }
      }

      /* Unload old plugins before sorting! */
      p = plugins;
      while (p)
      {
            CompPlugin *next = p->next;

            if (p->state == BerylPluginNeedsUnload)
            {
                  pr_debug("Unloading %s...", p->vTable->name);
                  if (p == plugins)
                        plugins = next;
                  else
                        prev->next = next;
                  unloadPlugin(p, d);
                  pr_debug("done.\n");
            }
            else
                  prev = p;
            p = next;
      }

      pr_debug_verbose("Seeking to arrange new plugin list.\n");

      sort_plugin_list();

      pr_debug_verbose("Initialising new plugins.\n");

      /*
       * Ok. Now we know what needs initialising and in.
       * what order.
       *
       * This could be done more efficiently (O(n^2/2) at the mo),
       * but n will normally be small, it isn't run often,
       * and I decided the extra complexity of a doubly linked list
       * wasn't worth it. - NC
       */

      i = new_num;
      while (i)
      {
            CompPlugin *prev = NULL;

            p = plugins;
            for (j = 1; j < i; j++)
            {
                  prev = p;
                  p = p->next;
            }
            pr_debug("Trying to initialise %s... ", p->vTable->name);
            if (p->state == BerylPluginNeedsInit)
            {
                  if (!tryInitPlugin(p))
                  {
                        fprintf(stderr,
                                    "Couldn't initialise %s. This should not happen!\n",
                                    p->vTable->name);
                        if (prev)
                              prev->next = p->next;
                        else
                              plugins = p->next;
                  }
                  else
                        pr_debug("Done.\n");
            }
            i--;
      }

      pr_debug_verbose("Initialisation done.\n");

      pr_debug("Indirect routine.\n");
      //(*d->setDisplayOption) (d, o->name, &d->plugin);

      d->dirtyPluginList = FALSE;

      pr_debug("Leaving.\n");
}

void finiPlugins(CompDisplay * d)
{
      while (plugins)
      {
            CompPlugin *next = plugins->next;

            finiPlugin(plugins);
            unloadPlugin(plugins, d);
            plugins = next;
      }
}

static int
dlloaderFilter (const struct dirent *name)
{
    int length = strlen (name->d_name);

    if (length < 7)
      return 0;

    if (strncmp (name->d_name, "lib", 3) ||
      strncmp (name->d_name + length - 3, ".so", 3))
      return 0;

    return 1;
}

static char **
dlloaderListPlugins (char *path,
                 int  *n)
{
    struct dirent **nameList;
    char      **list;
    char      *name;
    int             length, nFile, i, j = 0;

    if (!path)
      path = ".";

    nFile = scandir (path, &nameList, dlloaderFilter, alphasort);
    if (!nFile)
      return 0;

    list = malloc (nFile * sizeof (char *));
    if (!list)
      return 0;

    for (i = 0; i < nFile; i++)
    {
      length = strlen (nameList[i]->d_name);

      name = malloc ((length - 5) * sizeof (char));
      if (name)
      {
          strncpy (name, nameList[i]->d_name + 3, length - 6);
          name[length - 6] = '\0';

          list[j++] = name;
      }
    }

    if (j)
    {
      *n = j;

      return list;
    }

    free (list);

    return NULL;
}

static Bool
stringExist (char **list,
           int  nList,
           char *s)
{
    int i;

    for (i = 0; i < nList; i++)
      if (strcmp (list[i], s) == 0)
          return TRUE;

    return FALSE;
}

char **
availablePlugins (int *n)
{
    char *home, *plugindir;
    char **list, **currentList, **pluginList, **homeList = NULL;
    int  nCurrentList, nPluginList, nHomeList;
    int  count, i, j;

    home = getenv ("HOME");
    if (home)
    {
      plugindir = malloc (strlen (home) + strlen (HOME_PLUGINDIR) + 3);
      if (plugindir)
      {
          sprintf (plugindir, "%s/%s", home, HOME_PLUGINDIR);
          homeList = (dlloaderListPlugins) (plugindir, &nHomeList);
          free (plugindir);
      }
    }

    pluginList  = (dlloaderListPlugins) (PLUGINDIR, &nPluginList);
    currentList = (dlloaderListPlugins) (".", &nCurrentList);

    count = 0;
    if (homeList)
      count += nHomeList;
    if (pluginList)
      count += nPluginList;
    if (currentList)
      count += nCurrentList;

    if (!count)
      return NULL;

    list = malloc (count * sizeof (char *));
    if (!list)
      return NULL;

    j = 0;
    if (homeList)
    {
      for (i = 0; i < nHomeList; i++)
          if (!stringExist (list, j, homeList[i]))
            list[j++] = homeList[i];

      free (homeList);
    }

    if (pluginList)
    {
      for (i = 0; i < nPluginList; i++)
          if (!stringExist (list, j, pluginList[i]))
            list[j++] = pluginList[i];

      free (pluginList);
    }

    if (currentList)
    {
      for (i = 0; i < nCurrentList; i++)
          if (!stringExist (list, j, currentList[i]))
            list[j++] = currentList[i];

      free (currentList);
    }

    *n = j;

    return list;
}

Generated by  Doxygen 1.6.0   Back to index