Logo Search packages:      
Sourcecode: libgphoto2 version File versions

gphoto2-port-info-list.c

Go to the documentation of this file.
/** \file
 *
 * \author Copyright 2001 Lutz Müller <lutz@users.sf.net>
 *
 * \par License
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * \par
 * This library 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
 * Lesser General Public License for more details. 
 *
 * \par
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "config.h"
#include <gphoto2/gphoto2-port-info-list.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_REGEX
#include <regex.h>
#else
#error We need regex.h, but it has not been detected.
#endif

#include <ltdl.h>

#include <gphoto2/gphoto2-port-result.h>
#include <gphoto2/gphoto2-port-library.h>
#include <gphoto2/gphoto2-port-log.h>

#ifdef ENABLE_NLS
#  include <libintl.h>
#  undef _
#  define _(String) dgettext (GETTEXT_PACKAGE, String)
#  ifdef gettext_noop
#    define N_(String) gettext_noop (String)
#  else
#    define N_(String) (String)
#  endif 
#else
#  define textdomain(String) (String)
#  define gettext(String) (String)
#  define dgettext(Domain,Message) (Message)
#  define dcgettext(Domain,Message,Type) (Message)
#  define bindtextdomain(Domain,Directory) (Domain)
#  define bind_textdomain_codeset(Domain,codeset) (codeset)
#  define _(String) (String)
#  define N_(String) (String)
#endif

/**
 * \internal GPPortInfoList:
 *
 * The internals of this list are private.
 **/
00067 struct _GPPortInfoList {
      GPPortInfo *info;
      unsigned int count;
};

#define CHECK_NULL(x) {if (!(x)) return (GP_ERROR_BAD_PARAMETERS);}
#define CR(x)         {int r=(x);if (r<0) return (r);}

/**
 * IOLIBDIR_ENV:
 *
 * Name of the environment variable which may contain the path where
 * to look for the IO libs. If this environment variable is not defined,
 * use the compiled-in default constant.
 **/
00082 #define IOLIBDIR_ENV "IOLIBS"

/**
 * \brief Specify codeset for translations
 *
 * This function specifies the codeset that are used for the translated
 * strings that are passed back by the libgphoto2_port functions.
 *
 * This function is called by the gp_message_codeset() function, there is
 * no need to call it yourself.
 * 
 * \param codeset new codeset to use
 * \return the previous codeset
 */
const char*
00097 gp_port_message_codeset (const char *codeset) {
      return bind_textdomain_codeset (GETTEXT_PACKAGE, codeset);
}

/**
 * \brief Create a new GPPortInfoList
 *
 * \param list pointer to a GPPortInfoList* which is allocated
 *
 * Creates a new list which can later be filled with port infos (#GPPortInfo)
 * using #gp_port_info_list_load.
 *
 * \return a gphoto2 error code
 **/
int
00112 gp_port_info_list_new (GPPortInfoList **list)
{
      CHECK_NULL (list);

      /*
       * We put this in here because everybody needs to call this function
       * before accessing ports...
       */
      bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);

      *list = malloc (sizeof (GPPortInfoList));
      if (!*list)
            return (GP_ERROR_NO_MEMORY);
      memset (*list, 0, sizeof (GPPortInfoList));

      return (GP_OK);
}

/**
 * \brief Free a GPPortInfo list
 * \param list a #GPPortInfoList
 *
 * Frees a GPPortInfoList structure and its internal data structures.
 *
 * \return a gphoto2 error code
 **/
int
00139 gp_port_info_list_free (GPPortInfoList *list)
{
      CHECK_NULL (list);

      if (list->info) {
            free (list->info);
            list->info = NULL;
      }
      list->count = 0;

      free (list);

      return (GP_OK);
}

/**
 * \brief Append a portinfo to the port information list
 *
 * \param list a #GPPortInfoList
 * \param info the info to append
 *
 * Appends an entry to the list. This function is typically called by
 * an io-driver during #gp_port_library_list. If you leave info.name blank,
 * #gp_port_info_list_lookup_path will try to match non-existent paths
 * against info.path and - if successfull - will append this entry to the 
 * list.
 *
 * \note This returns index - number of generic entries, not the correct index.
 *
 * \return A non-negative number or a gphoto2 error code
 **/
int
00171 gp_port_info_list_append (GPPortInfoList *list, GPPortInfo info)
{
      int generic, i;
      GPPortInfo *new_info;

      CHECK_NULL (list);

      if (!list->info)
            new_info = malloc (sizeof (GPPortInfo));
      else
            new_info = realloc (list->info, sizeof (GPPortInfo) *
                                          (list->count + 1));
      if (!new_info)
            return (GP_ERROR_NO_MEMORY);

      list->info = new_info;
      list->count++;

      memcpy (&(list->info[list->count - 1]), &info, sizeof (GPPortInfo));

      /* Ignore generic entries */
      for (generic = i = 0; i < list->count; i++)
            if (!strlen (list->info[i].name))
                  generic++;
      return (list->count - 1 - generic);
}


static int
foreach_func (const char *filename, lt_ptr data)
{
      GPPortInfoList *list = data;
      lt_dlhandle lh;
      GPPortLibraryType lib_type;
      GPPortLibraryList lib_list;
      GPPortType type;
      unsigned int j, old_size = list->count;
      int result;

      gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
            _("Called for filename '%s'."), filename );

      lh = lt_dlopenext (filename);
      if (!lh) {
            gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
                  _("Could not load '%s': '%s'."), filename, lt_dlerror ());
            return (0);
      }

      lib_type = lt_dlsym (lh, "gp_port_library_type");
      lib_list = lt_dlsym (lh, "gp_port_library_list");
      if (!lib_type || !lib_list) {
            gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
                  _("Could not find some functions in '%s': '%s'."),
                  filename, lt_dlerror ());
            lt_dlclose (lh);
            return (0);
      }

      type = lib_type ();
      for (j = 0; j < list->count; j++)
            if (list->info[j].type == type)
                  break;
      if (j != list->count) {
            gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
                  _("'%s' already loaded"), filename);
            lt_dlclose (lh);
            return (0);
      }

      result = lib_list (list);
      lt_dlclose (lh);
      if (result < 0) {
            gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
                  _("Could not load port driver list: '%s'."),
                  gp_port_result_as_string (result));
            return (0);
      }

      for (j = old_size; j < list->count; j++){
            gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
                  _("Loaded '%s' ('%s') from '%s'."),
                  list->info[j].name, list->info[j].path,
                  filename);
            strcpy (list->info[j].library_filename, filename);
      }

      return (0);
}


/**
 * \brief Load system ports
 * 
 * \param list a #GPPortInfoList
 *
 * Searches the system for io-drivers and appends them to the list. You would
 * normally call this function once after #gp_port_info_list_new and then
 * use this list in order to supply #gp_port_set_info with parameters or to do
 * autodetection.
 *
 * \return a gphoto2 error code
 **/
int
00275 gp_port_info_list_load (GPPortInfoList *list)
{
      const char *iolibs_env = getenv(IOLIBDIR_ENV);
      const char *iolibs = (iolibs_env != NULL)?iolibs_env:IOLIBS;
      int result;

      CHECK_NULL (list);

      gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
            _("Using ltdl to load io-drivers from '%s'..."),
            iolibs);
      lt_dlinit ();
      lt_dladdsearchdir (iolibs);
      result = lt_dlforeachfile (iolibs, foreach_func, list);
      lt_dlexit ();
      if (result < 0)
            return (result);
        return (GP_OK);
}

/**
 * \brief Number of ports in the list
 * \param list a #GPPortInfoList
 *
 * Returns the number of entries in the passed list.
 *
 * \return The number of entries or a gphoto2 error code
 **/
int
00304 gp_port_info_list_count (GPPortInfoList *list)
{
      int count, i;

      CHECK_NULL (list);

      gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Counting entries "
            "(%i available)..."), list->count);

      /* Ignore generic entries */
      count = list->count;
      for (i = 0; i < list->count; i++)
            if (!strlen (list->info[i].name))
                  count--;

      gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("%i regular entries "
            "available."), count);
      return (count);
}

/**
 * \brief Lookup a specific path in the list
 *
 * \param list a #GPPortInfoList
 * \param path a path
 *
 * Looks for an entry in the list with the supplied path. If no exact match
 * can be found, a regex search will be performed in the hope some driver
 * claimed ports like "serial:*".
 *
 * \return The index of the entry or a gphoto2 error code
 **/
int
00337 gp_port_info_list_lookup_path (GPPortInfoList *list, const char *path)
{
      int i, result, generic;
      regex_t pattern;
#ifdef HAVE_GNU_REGEX
      const char *rv;
#else
      regmatch_t match;
#endif

      CHECK_NULL (list && path);

      gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Looking for "
            "path '%s' (%i entries available)..."), path, list->count);

      /* Exact match? */
      for (generic = i = 0; i < list->count; i++)
            if (!strlen (list->info[i].name))
                  generic++;
            else if (!strcmp (list->info[i].path, path))
                  return (i - generic);

      /* Regex match? */
      gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
            _("Starting regex search for '%s'..."), path);
      for (i = 0; i < list->count; i++) {
            GPPortInfo newinfo;

            if (strlen (list->info[i].name))
                  continue;

            gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
                  _("Trying '%s'..."), list->info[i].path);

            /* Compile the pattern */
#ifdef HAVE_GNU_REGEX
            memset (&pattern, 0, sizeof (pattern));
            rv = re_compile_pattern (list->info[i].path,
                               strlen (list->info[i].path), &pattern);
            if (rv) {
                  gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
                        "%s", rv);
                  continue;
            }
#else
            result = regcomp (&pattern, list->info[i].path, REG_ICASE);
            if (result) {
                  char buf[1024];
                  if (regerror (result, &pattern, buf, sizeof (buf)))
                        gp_log (GP_LOG_ERROR, "gphoto2-port-info-list",
                              "%s", buf);
                  else
                        gp_log (GP_LOG_ERROR, "gphoto2-port-info-list",
                              _("regcomp failed"));
                  return (GP_ERROR_UNKNOWN_PORT);
            }
#endif

            /* Try to match */
#ifdef HAVE_GNU_REGEX
            result = re_match (&pattern, path, strlen (path), 0, NULL);
            regfree (&pattern);
            if (result < 0) {
                  gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
                        _("re_match failed (%i)"), result);
                  continue;
            }
#else
            result = regexec (&pattern, path, 1, &match, 0);
            regfree (&pattern);
            if (result) {
                  gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list",
                        _("regexec failed"));
                  continue;
            }
#endif
            memcpy (&newinfo, &list->info[i], sizeof(newinfo));
            strncpy (newinfo.path, path, sizeof (newinfo.path));
            strncpy (newinfo.name, _("Generic Port"), sizeof (newinfo.name));
            CR (result = gp_port_info_list_append (list, newinfo));
            return result;
      }

      return (GP_ERROR_UNKNOWN_PORT);
}

/**
 * \brief Look up a name in the list
 * \param list a #GPPortInfoList
 * \param name a name
 *
 * Looks for an entry in the list with the exact given name.
 *
 * \return The index of the entry or a gphoto2 error code
 **/
int
00433 gp_port_info_list_lookup_name (GPPortInfoList *list, const char *name)
{
      int i, generic;

      CHECK_NULL (list && name);

      gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Looking up entry "
            "'%s'..."), name);

      /* Ignore generic entries */
      for (generic = i = 0; i < list->count; i++)
            if (!strlen (list->info[i].name))
                  generic++;
            else if (!strcmp (list->info[i].name, name))
                  return (i - generic);

      return (GP_ERROR_UNKNOWN_PORT);
}

/**
 * \brief Get port information of specific entry
 * \param list a #GPPortInfoList
 * \param n the index of the entry
 * \param info the returned information
 *
 * Retreives an entry from the list and stores it into info.
 *
 * \return a gphoto2 error code
 **/
int
00463 gp_port_info_list_get_info (GPPortInfoList *list, int n, GPPortInfo *info)
{
      int i;

      CHECK_NULL (list && info);

      gp_log (GP_LOG_DEBUG, "gphoto2-port-info-list", _("Getting info of "
            "entry %i (%i available)..."), n, list->count);

      if (n < 0 || n >= list->count)
            return (GP_ERROR_BAD_PARAMETERS);

      /* Ignore generic entries */
      for (i = 0; i <= n; i++)
            if (!strlen (list->info[i].name))
                  n++;

      if (n >= list->count)
            return (GP_ERROR_BAD_PARAMETERS);

      memcpy (info, &(list->info[n]), sizeof (GPPortInfo));

      return (GP_OK);
}


#ifdef _GPHOTO2_INTERNAL_CODE
/**
 * \brief Internal map between GP_PORT and name
 * 
 * Internal map between the GP_PORT_xxx enumeration and
 * string names (usb,serial,disk,ptpip,...).
 */
const StringFlagItem gpi_gphoto_port_type_map[] = {
      { "none",   GP_PORT_NONE },
      { "serial", GP_PORT_SERIAL },
      { "usb",    GP_PORT_USB },
      { "disk",   GP_PORT_DISK },
      { "ptpip",  GP_PORT_PTPIP },
      { NULL, 0 },
};
#endif /* _GPHOTO2_INTERNAL_CODE */

Generated by  Doxygen 1.6.0   Back to index