Logo Search packages:      
Sourcecode: libgphoto2 version File versions  Download package

gphoto2-port-log.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-log.h>

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>

#include <gphoto2/gphoto2-port-result.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 _(String) (String)
#  define N_(String) (String)
#endif

#ifndef DISABLE_DEBUGGING
/** 
 * \brief Internal logging function entry.
 * 
 * Internal structure to remember the logging functions.
 * Use gp_log_add_func() and gp_log_remove_func() to access it.
 */
00055 typedef struct {
00056       unsigned int id;  /**< Internal id */
00057       GPLogLevel   level;     /**< Internal loglevel */
00058       GPLogFunc    func;      /**< Internal function pointer to call */
00059       void        *data;      /**< Private data supplied by caller */
} LogFunc;

static LogFunc *log_funcs = NULL;
static unsigned int log_funcs_count = 0;

/**
 * \brief Add a function to get logging information
 *
 * \param level the maximum level of logging it will get, up to and including the passed value
 * \param func a #GPLogFunc
 * \param data data
 *
 * Adds a log function that will be called for each log message that is flagged
 * with a log level that appears in given log level. This function returns
 * an id that you can use for removing the log function again (using
 * #gp_log_remove_func).
 *
 * \return an id or a gphoto2 error code
 **/
int
00080 gp_log_add_func (GPLogLevel level, GPLogFunc func, void *data)
{
      LogFunc *new_log_funcs;

      if (!func)
            return (GP_ERROR_BAD_PARAMETERS);

      if (!log_funcs)
            new_log_funcs = malloc (sizeof (LogFunc));
      else
            new_log_funcs = realloc (log_funcs, sizeof (LogFunc) * 
                               (log_funcs_count + 1));
      if (!new_log_funcs)
            return (GP_ERROR_NO_MEMORY);

      log_funcs = new_log_funcs;
      log_funcs_count++;

      log_funcs[log_funcs_count - 1].id = log_funcs_count;
      log_funcs[log_funcs_count - 1].level = level;
      log_funcs[log_funcs_count - 1].func = func;
      log_funcs[log_funcs_count - 1].data = data;

      return (log_funcs_count);
}

/**
 * \brief Remove a logging receiving function
 * \param id an id (return value of #gp_log_add_func)
 *
 * Removes the log function with given id.
 *
 * \return a gphoto2 error code
 **/
int
00115 gp_log_remove_func (int id)
{
      if (id < 1 || id > log_funcs_count)
            return (GP_ERROR_BAD_PARAMETERS);

      memmove (log_funcs + id - 1, log_funcs + id, log_funcs_count - id);
      log_funcs_count--;

      return (GP_OK);
}

/**
 * Width of offset field in characters. Note that HEXDUMP_COMPLETE_LINE 
 * needs to be changed when this value is changed.
 */
00130 #define HEXDUMP_OFFSET_WIDTH 4

/**
 * Distance between offset, hexdump and ascii blocks. Note that
 * HEXDUMP_COMPLETE_LINE needs to be changed when this value is changed.
 */
00136 #define HEXDUMP_BLOCK_DISTANCE 2

/** Initial value for x "pointer" (for hexdump) */
00139 #define HEXDUMP_INIT_X (HEXDUMP_OFFSET_WIDTH + HEXDUMP_BLOCK_DISTANCE)

/** Initial value for y "pointer" (for ascii values) */
00142 #define HEXDUMP_INIT_Y (HEXDUMP_INIT_X + 3 * 16 - 1 + HEXDUMP_BLOCK_DISTANCE)

/** Used to switch to next line */
00145 #define HEXDUMP_LINE_WIDTH (HEXDUMP_INIT_Y + 16)

/** Used to put the '-' character in the middle of the hexdumps */
00148 #define HEXDUMP_MIDDLE (HEXDUMP_INIT_X + 3 * 8 - 1)

/**
 * We are lazy and do our typing only once. Please note that you have
 * to add/remove some lines when increasing/decreasing the values of 
 * HEXDUMP_BLOCK_DISTANCE and/or HEXDUMP_OFFSET_WIDTH.
 */
00155 #define HEXDUMP_COMPLETE_LINE {\
        curline[HEXDUMP_OFFSET_WIDTH - 4] = hexchars[(index >> 12) & 0xf]; \
        curline[HEXDUMP_OFFSET_WIDTH - 3] = hexchars[(index >>  8) & 0xf]; \
        curline[HEXDUMP_OFFSET_WIDTH - 2] = hexchars[(index >>  4) & 0xf]; \
        curline[HEXDUMP_OFFSET_WIDTH - 1] = '0'; \
        curline[HEXDUMP_OFFSET_WIDTH + 0] = ' '; \
        curline[HEXDUMP_OFFSET_WIDTH + 1] = ' '; \
        curline[HEXDUMP_MIDDLE] = '-'; \
        curline[HEXDUMP_INIT_Y-2] = ' '; \
        curline[HEXDUMP_INIT_Y-1] = ' '; \
        curline[HEXDUMP_LINE_WIDTH] = '\n'; \
        curline = curline + (HEXDUMP_LINE_WIDTH + 1);}

/**
 * \brief Log data
 * \brief domain the domain
 * \brief data the data to be logged
 * \brief size the size of the data
 *
 * Takes the data and creates a formatted hexdump string. If you would like
 * to log text messages, use #gp_log instead.
 **/
void
00178 gp_log_data (const char *domain, const char *data, unsigned int size)
{
      static const char hexchars[16] = "0123456789abcdef";
      char *curline, *result;
      int x = HEXDUMP_INIT_X;
      int y = HEXDUMP_INIT_Y;
      int index;
      unsigned char value;

      if (!data) {
            gp_log (GP_LOG_DATA, domain, _("No hexdump (NULL buffer)"));
            return;
      }

      if (!size) {
            gp_log (GP_LOG_DATA, domain, _("Empty hexdump of empty buffer"));
            return;
      }

      if (size > 1024*1024) {
            /* Does not make sense for 200 MB movies */
            gp_log (GP_LOG_DATA, domain, _("Truncating dump from %d bytes to 1MB"), size);
            size = 1024*1024;
      }

      curline = result = malloc ((HEXDUMP_LINE_WIDTH+1)*(((size-1)/16)+1)+1);
      if (!result) {
            gp_log (GP_LOG_ERROR, "gphoto2-log", _("Malloc for %i bytes "
                  "failed"), (HEXDUMP_LINE_WIDTH+1)*(((size-1)/16)+1)+1);
            return;
      }

      for (index = 0; index < size; ++index) {
                value = (unsigned char)data[index];
                curline[x] = hexchars[value >> 4];
                curline[x+1] = hexchars[value & 0xf];
                curline[x+2] = ' ';
                curline[y++] = ((value>=32)&&(value<127))?value:'.';
                x += 3;
                if ((index & 0xf) == 0xf) { /* end of line */
                        x = HEXDUMP_INIT_X;
                        y = HEXDUMP_INIT_Y;
                        HEXDUMP_COMPLETE_LINE;
                }
        }
        if ((index & 0xf) != 0) { /* not at end of line yet? */
                /* if so, complete this line */
                while (y < HEXDUMP_INIT_Y + 16) {
                        curline[x+0] = ' ';
                        curline[x+1] = ' ';
                        curline[x+2] = ' ';
                        curline[y++] = ' ';
                        x += 3;
                }
                HEXDUMP_COMPLETE_LINE;
        }
        curline[0] = '\0';

      gp_log (GP_LOG_DATA, domain, _("Hexdump of %i = 0x%x bytes follows:\n%s"),
            size, size, result);
      free (result);
}

#undef HEXDUMP_COMPLETE_LINE
#undef HEXDUMP_MIDDLE
#undef HEXDUMP_LINE_WIDTH
#undef HEXDUMP_INIT_Y
#undef HEXDUMP_INIT_X
#undef HEXDUMP_BLOCK_DISTANCE
#undef HEXDUMP_OFFSET_WIDTH

/**
 * \brief Log a debug or error message with va_list
 * \param level gphoto2 log level
 * \param domain the domain
 * \param format the format
 * \param args the va_list corresponding to format
 *
 * Logs a message at the given log level. You would normally use this
 * function to log as yet unformatted strings. 
 **/
void
00260 gp_logv (GPLogLevel level, const char *domain, const char *format,
       va_list args)
{
      int i;
#ifdef HAVE_VA_COPY
      va_list xargs;
#endif

      for (i = 0; i < log_funcs_count; i++) {
            if (log_funcs[i].level >= level) {
#ifdef HAVE_VA_COPY
                  va_copy (xargs, args);
                  log_funcs[i].func (level, domain, format, xargs,
                                 log_funcs[i].data);
#else
                  log_funcs[i].func (level, domain, format, args,
                                 log_funcs[i].data);
#endif
            }
      }
}

/**
 * \brief Log a debug or error message
 * \param level gphoto2 log level
 * \param domain the log domain
 * \param format a printf style format string
 * \param ... the variable argumentlist for above format string
 *
 * Logs a message at the given log level. You would normally use this
 * function to log general debug output in a printf way.
 **/
void
00293 gp_log (GPLogLevel level, const char *domain, const char *format, ...)
{
      va_list args;

      va_start (args, format);
      gp_logv (level, domain, format, args);
      va_end (args);
}

#else /* DISABLE_DEBUGGING */

/*
 * Even if debugging is disabled, we must keep stubs to these functions
 * around so that programs dynamically linked to this library will still run.
 */

/* Remove these macros so we can compile functions with these names */
#ifdef gp_log_add_func
#undef gp_log_add_func
#endif
#ifdef gp_log_remove_func
#undef gp_log_remove_func
#endif
#ifdef gp_log_data
#undef gp_log_data
#endif
#ifdef gp_logv
#undef gp_logv
#endif
#ifdef gp_log
#undef gp_log
#endif

int
gp_log_add_func (GPLogLevel level, GPLogFunc func, void *data)
{
      return 0;
}

int
gp_log_remove_func (int id)
{
      return 0;
}

void
gp_log_data (const char *domain, const char *data, unsigned int size)
{
}

void
gp_logv (GPLogLevel level, const char *domain, const char *format,
       va_list args)
{
}

void
gp_log (GPLogLevel level, const char *domain, const char *format, ...)
{
}
#endif /* DISABLE_DEBUGGING */


#ifdef _GPHOTO2_INTERNAL_CODE

/** 
 * \brief (Internal) translate a enumeration code to a string
 */
const char *
gpi_enum_to_string(unsigned int _enum, 
               const StringFlagItem *map)
{
      int i;
      for (i=0; map[i].str != NULL; i++) {
            if (_enum == map[i].flag) {
                  return(map[i].str);
                  break;
            }
      }
      return NULL;
}

/** 
 * \brief (Internal) translate a string to an enumeration code
 */
int
gpi_string_to_enum(const char *str,
               unsigned int *result,
               const StringFlagItem *map)
{
      int i;
      for (i=0; map[i].str != NULL; i++) {
            if (0==strcmp(map[i].str, str)) {
                  (*result) = map[i].flag;
                  return 0;
            }
      }
      return 1;
}

void
gpi_flags_to_string_list(unsigned int flags, 
                   const StringFlagItem *map,
                   string_item_func func, void *data)
{
      int i;
      for (i=0; map[i].str != NULL; i++) {
            if ((flags == 0) && (map[i].flag == 0)) {
                  func(map[i].str, data);
                  break;
            } else if (0 != (flags & map[i].flag)) {
                  func(map[i].str, data);      
            }
      }
}

unsigned int 
gpi_string_to_flag(const char *str, 
             const StringFlagItem *map)
{
      int i;
      for (i=0; map[i].str != NULL; i++) {
            if (0==strcmp(map[i].str, str)) {
                  return map[i].flag;
            }
      }
  return 0;
}

int 
gpi_string_or_to_flags(const char *str, 
                   unsigned int *flags,
                   const StringFlagItem *map)
{
      int i;
      int found = 0;
      for (i=0; map[i].str != NULL; i++) {
            if (0==strcmp(map[i].str, str)) {
                  (*flags) |= map[i].flag;
                  found = 1;
            }
      }
      if (found) {
            return 0;
      } else {
            return 1;
      }
}

unsigned int
gpi_string_list_to_flags(const char *str[], 
                 const StringFlagItem *map)
{
      int i;
      unsigned int flags = 0;
      for (i=0; str[i] != NULL; i++) {
            flags |= gpi_string_to_flag(str[i], map);
      }
      return flags;
}

#endif /* _GPHOTO2_INTERNAL_CODE */


/*
 * Local Variables:
 * c-file-style:"linux"
 * indent-tabs-mode:t
 * End:
 */

Generated by  Doxygen 1.6.0   Back to index