libgphoto2 photo camera library (libgphoto2) Internals  2.5.23
gphoto2-port-log.c
Go to the documentation of this file.
1 
24 #define _DEFAULT_SOURCE
25 
26 #include "config.h"
28 
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <stdio.h>
33 
35 
36 #ifdef ENABLE_NLS
37 # include <libintl.h>
38 # undef _
39 # define _(String) dgettext (GETTEXT_PACKAGE, String)
40 # ifdef gettext_noop
41 # define N_(String) gettext_noop (String)
42 # else
43 # define N_(String) (String)
44 # endif
45 #else
46 # define _(String) (String)
47 # define N_(String) (String)
48 #endif
49 
50 #ifndef DISABLE_DEBUGGING
51 
57 typedef struct {
58  unsigned int id;
61  void *data;
62 } LogFunc;
63 
64 static LogFunc *log_funcs = NULL;
65 static unsigned int log_funcs_count = 0;
66 
81 int
83 {
84  static int logfuncid = 0;
85 
86  C_PARAMS (func);
87  C_MEM (log_funcs = realloc (log_funcs, sizeof (LogFunc) *
88  (log_funcs_count + 1)));
90 
91  log_funcs[log_funcs_count - 1].id = ++logfuncid;
93  log_funcs[log_funcs_count - 1].func = func;
94  log_funcs[log_funcs_count - 1].data = data;
95 
96  return logfuncid;
97 }
98 
99 
100 char*
101 gpi_vsnprintf (const char* format, va_list args)
102 {
103  va_list xargs;
104  int strsize;
105  char *str;
106 
107 #ifdef HAVE_VA_COPY
108  va_copy (xargs, args);
109 #else
110  /* according to 'the web', the only interesting compiler without va_copy is MSVC
111  * and there a simple assignment is the way to go */
112  xargs = args;
113 #endif
114 
115  /* query the size necessary for the string, add the terminating '\0' */
116  strsize = vsnprintf (NULL, 0, format, xargs) + 1;
117  va_end (xargs);
118 
119  str = malloc(strsize);
120  if (!str)
121  return NULL;
122 
123  /* actually print the string into the buffer */
124  vsnprintf (str, strsize, format, args);
125 
126  return str;
127 }
128 
137 int
139 {
140  int i;
141 
142  for (i=0;i<log_funcs_count;i++) {
143  if (log_funcs[i].id == id) {
144  memmove (log_funcs + i, log_funcs + i + 1, sizeof(LogFunc) * (log_funcs_count - i - 1));
145  log_funcs_count--;
146  return GP_OK;
147  }
148  }
150 }
151 
156 #define HEXDUMP_OFFSET_WIDTH 4
157 
162 #define HEXDUMP_BLOCK_DISTANCE 2
163 
165 #define HEXDUMP_INIT_X (HEXDUMP_OFFSET_WIDTH + HEXDUMP_BLOCK_DISTANCE)
166 
168 #define HEXDUMP_INIT_Y (HEXDUMP_INIT_X + 3 * 16 - 1 + HEXDUMP_BLOCK_DISTANCE)
169 
171 #define HEXDUMP_LINE_WIDTH (HEXDUMP_INIT_Y + 16)
172 
174 #define HEXDUMP_MIDDLE (HEXDUMP_INIT_X + 3 * 8 - 1)
175 
181 #define HEXDUMP_COMPLETE_LINE {\
182  curline[HEXDUMP_OFFSET_WIDTH - 4] = hexchars[(index >> 12) & 0xf]; \
183  curline[HEXDUMP_OFFSET_WIDTH - 3] = hexchars[(index >> 8) & 0xf]; \
184  curline[HEXDUMP_OFFSET_WIDTH - 2] = hexchars[(index >> 4) & 0xf]; \
185  curline[HEXDUMP_OFFSET_WIDTH - 1] = '0'; \
186  curline[HEXDUMP_OFFSET_WIDTH + 0] = ' '; \
187  curline[HEXDUMP_OFFSET_WIDTH + 1] = ' '; \
188  curline[HEXDUMP_MIDDLE] = '-'; \
189  curline[HEXDUMP_INIT_Y-2] = ' '; \
190  curline[HEXDUMP_INIT_Y-1] = ' '; \
191  curline[HEXDUMP_LINE_WIDTH] = '\n'; \
192  curline = curline + (HEXDUMP_LINE_WIDTH + 1);}
193 
203 /* coverity[-tainted_sink] */
204 void
205 gp_log_data (const char *domain, const char *data, unsigned int size, const char *format, ...)
206 {
207  va_list args;
208  static const char hexchars[16] = "0123456789abcdef";
209  char *curline, *result = 0, *msg = 0;
210  int x = HEXDUMP_INIT_X;
211  int y = HEXDUMP_INIT_Y;
212  unsigned int index, original_size = size;
213  unsigned char value;
214 
215  va_start (args, format);
216  msg = gpi_vsnprintf(format, args);
217  va_end (args);
218  if (!msg) {
219  GP_LOG_E ("Malloc for expanding format string '%s' failed.", format);
220  goto exit;
221  }
222 
223  if (!data) {
224  gp_log (GP_LOG_DATA, domain, "%s (no hexdump, NULL buffer)", msg);
225  goto exit;
226  }
227 
228  if (!size) {
229  gp_log (GP_LOG_DATA, domain, "%s (empty hexdump of empty buffer)", msg);
230  goto exit;
231  }
232 
233  if (size > 1024*1024) {
234  /* Does not make sense for 200 MB movies */
235  size = 1024*1024;
236  }
237 
238  curline = result = malloc ((HEXDUMP_LINE_WIDTH+1)*(((size-1)/16)+1)+1);
239  if (!result) {
240  GP_LOG_E ("Malloc for %i bytes failed", (HEXDUMP_LINE_WIDTH+1)*(((size-1)/16)+1)+1);
241  goto exit;
242  }
243 
244  for (index = 0; index < size; ++index) {
245  value = (unsigned char)data[index];
246  curline[x] = hexchars[value >> 4];
247  curline[x+1] = hexchars[value & 0xf];
248  curline[x+2] = ' ';
249  curline[y++] = ((value>=32)&&(value<127))?value:'.';
250  x += 3;
251  if ((index & 0xf) == 0xf) { /* end of line */
252  x = HEXDUMP_INIT_X;
253  y = HEXDUMP_INIT_Y;
255  }
256  }
257  if ((index & 0xf) != 0) { /* not at end of line yet? */
258  /* if so, complete this line */
259  while (y < HEXDUMP_INIT_Y + 16) {
260  curline[x+0] = ' ';
261  curline[x+1] = ' ';
262  curline[x+2] = ' ';
263  curline[y++] = ' ';
264  x += 3;
265  }
267  }
268  curline[0] = '\0';
269 
270  if (size == original_size)
271  gp_log (GP_LOG_DATA, domain, "%s (hexdump of %d bytes)\n%s", msg, size, result);
272  else
273  gp_log (GP_LOG_DATA, domain, "%s (hexdump of the first %d of %d bytes)\n%s", msg, size, original_size, result);
274 
275 exit:
276  free (msg);
277  free (result);
278 }
279 
280 #undef HEXDUMP_COMPLETE_LINE
281 #undef HEXDUMP_MIDDLE
282 #undef HEXDUMP_LINE_WIDTH
283 #undef HEXDUMP_INIT_Y
284 #undef HEXDUMP_INIT_X
285 #undef HEXDUMP_BLOCK_DISTANCE
286 #undef HEXDUMP_OFFSET_WIDTH
287 
298 void
299 gp_logv (GPLogLevel level, const char *domain, const char *format,
300  va_list args)
301 {
302  unsigned int i;
303  char *str = 0;
304 
305  if (!log_funcs_count)
306  return;
307 
308  str = gpi_vsnprintf(format, args);
309  if (!str) {
310  GP_LOG_E ("Malloc for expanding format string '%s' failed.", format);
311  return;
312  }
313 
314  for (i = 0; i < log_funcs_count; i++)
315  if (log_funcs[i].level >= level)
316  log_funcs[i].func (level, domain, str, log_funcs[i].data);
317  free (str);
318 }
319 
330 void
331 gp_log (GPLogLevel level, const char *domain, const char *format, ...)
332 {
333  va_list args;
334 
335  va_start (args, format);
336  gp_logv (level, domain, format, args);
337  va_end (args);
338 }
339 
340 void
341 gp_log_with_source_location(GPLogLevel level, const char *file, int line, const char *func, const char *format, ...)
342 {
343  va_list args;
344  char domain[100];
345 
346  /* Only display filename without any path/directory part */
347  file = strrchr(file, '/') ? strrchr(file, '/') + 1 : file;
348  snprintf(domain, sizeof(domain), "%s [%s:%d]", func, file, line);
349 
350  va_start (args, format);
351  gp_logv (level, domain, format, args);
352  va_end (args);
353 }
354 
355 #else /* DISABLE_DEBUGGING */
356 
357 /*
358  * Even if debugging is disabled, we must keep stubs to these functions
359  * around so that programs dynamically linked to this library will still run.
360  */
361 
362 /* Remove these macros so we can compile functions with these names */
363 #ifdef gp_log_add_func
364 #undef gp_log_add_func
365 #endif
366 #ifdef gp_log_remove_func
367 #undef gp_log_remove_func
368 #endif
369 #ifdef gp_log_data
370 #undef gp_log_data
371 #endif
372 #ifdef gp_logv
373 #undef gp_logv
374 #endif
375 #ifdef gp_log
376 #undef gp_log
377 #endif
378 #ifdef gp_log_with_source_location
379 #undef gp_log_with_source_location
380 #endif
381 
382 int
383 gp_log_add_func (GPLogLevel level, GPLogFunc func, void *data)
384 {
385  return 0;
386 }
387 
388 int
389 gp_log_remove_func (int id)
390 {
391  return 0;
392 }
393 
394 void
395 gp_log_data (const char *domain, const char *data, unsigned int size, const char *format, ...)
396 {
397 }
398 
399 void
400 gp_logv (GPLogLevel level, const char *domain, const char *format,
401  va_list args)
402 {
403 }
404 
405 void
406 gp_log (GPLogLevel level, const char *domain, const char *format, ...)
407 {
408 }
409 
410 void
411 gp_log_with_source_location(GPLogLevel level, const char *file, int line, const char *func, const char *format, ...)
412 {
413 }
414 #endif /* DISABLE_DEBUGGING */
415 
416 
417 #ifdef _GPHOTO2_INTERNAL_CODE
418 
422 const char *
423 gpi_enum_to_string(unsigned int _enum,
424  const StringFlagItem *map)
425 {
426  int i;
427  for (i=0; map[i].str != NULL; i++) {
428  if (_enum == map[i].flag) {
429  return(map[i].str);
430  break;
431  }
432  }
433  return NULL;
434 }
435 
439 int
440 gpi_string_to_enum(const char *str,
441  unsigned int *result,
442  const StringFlagItem *map)
443 {
444  int i;
445  for (i=0; map[i].str != NULL; i++) {
446  if (0==strcmp(map[i].str, str)) {
447  (*result) = map[i].flag;
448  return 0;
449  }
450  }
451  return 1;
452 }
453 
454 void
455 gpi_flags_to_string_list(unsigned int flags,
456  const StringFlagItem *map,
457  string_item_func func, void *data)
458 {
459  int i;
460  for (i=0; map[i].str != NULL; i++) {
461  if ((flags == 0) && (map[i].flag == 0)) {
462  func(map[i].str, data);
463  break;
464  } else if (0 != (flags & map[i].flag)) {
465  func(map[i].str, data);
466  }
467  }
468 }
469 
470 unsigned int
471 gpi_string_to_flag(const char *str,
472  const StringFlagItem *map)
473 {
474  int i;
475  for (i=0; map[i].str != NULL; i++) {
476  if (0==strcmp(map[i].str, str)) {
477  return map[i].flag;
478  }
479  }
480  return 0;
481 }
482 
483 int
484 gpi_string_or_to_flags(const char *str,
485  unsigned int *flags,
486  const StringFlagItem *map)
487 {
488  int i;
489  int found = 0;
490  for (i=0; map[i].str != NULL; i++) {
491  if (0==strcmp(map[i].str, str)) {
492  (*flags) |= map[i].flag;
493  found = 1;
494  }
495  }
496  if (found) {
497  return 0;
498  } else {
499  return 1;
500  }
501 }
502 
503 unsigned int
504 gpi_string_list_to_flags(const char *str[],
505  const StringFlagItem *map)
506 {
507  int i;
508  unsigned int flags = 0;
509  for (i=0; str[i] != NULL; i++) {
510  flags |= gpi_string_to_flag(str[i], map);
511  }
512  return flags;
513 }
514 
515 #endif /* _GPHOTO2_INTERNAL_CODE */
516 
517 
518 /*
519  * Local Variables:
520  * c-file-style:"linux"
521  * indent-tabs-mode:t
522  * End:
523  */
LogFunc
Internal logging function entry.
Definition: gphoto2-port-log.c:57
gp_log
void gp_log(GPLogLevel level, const char *domain, const char *format,...)
Log a debug or error message.
Definition: gphoto2-port-log.c:331
gp_logv
void gp_logv(GPLogLevel level, const char *domain, const char *format, va_list args)
Log a debug or error message with va_list.
Definition: gphoto2-port-log.c:299
gp_log_data
void gp_log_data(const char *domain, const char *data, unsigned int size, const char *format,...)
Log data.
Definition: gphoto2-port-log.c:205
HEXDUMP_INIT_Y
#define HEXDUMP_INIT_Y
Definition: gphoto2-port-log.c:168
GP_LOG_DATA
@ GP_LOG_DATA
Log message is a data hex dump.
Definition: gphoto2-port-log.h:34
level
GPLevel level
Definition: gphoto2-port.c:683
log_funcs
static LogFunc * log_funcs
Definition: gphoto2-port-log.c:64
LogFunc::level
GPLogLevel level
Definition: gphoto2-port-log.c:59
HEXDUMP_COMPLETE_LINE
#define HEXDUMP_COMPLETE_LINE
Definition: gphoto2-port-log.c:181
HEXDUMP_LINE_WIDTH
#define HEXDUMP_LINE_WIDTH
Definition: gphoto2-port-log.c:171
gphoto2-port-result.h
result
int result
Definition: gphoto2-result.c:44
GP_ERROR_BAD_PARAMETERS
#define GP_ERROR_BAD_PARAMETERS
Bad parameters passed.
Definition: gphoto2-port-result.h:38
GP_OK
#define GP_OK
Everything is OK.
Definition: gphoto2-port-result.h:30
LogFunc::id
unsigned int id
Definition: gphoto2-port-log.c:58
HEXDUMP_INIT_X
#define HEXDUMP_INIT_X
Definition: gphoto2-port-log.c:165
LogFunc::data
void * data
Definition: gphoto2-port-log.c:61
GPLogLevel
GPLogLevel
Logging level Specifies the logging severity level.
Definition: gphoto2-port-log.h:30
LogFunc::func
GPLogFunc func
Definition: gphoto2-port-log.c:60
gphoto2-port-log.h
gp_log_add_func
int gp_log_add_func(GPLogLevel level, GPLogFunc func, void *data)
Add a function to get logging information.
Definition: gphoto2-port-log.c:82
log_funcs_count
static unsigned int log_funcs_count
Definition: gphoto2-port-log.c:65
gpi_vsnprintf
char * gpi_vsnprintf(const char *format, va_list args)
Definition: gphoto2-port-log.c:101
gp_log_remove_func
int gp_log_remove_func(int id)
Remove a logging receiving function.
Definition: gphoto2-port-log.c:138
GPLogFunc
void(* GPLogFunc)(GPLogLevel level, const char *domain, const char *str, void *data)
Logging function hook.
Definition: gphoto2-port-log.h:61
gp_log_with_source_location
void gp_log_with_source_location(GPLogLevel level, const char *file, int line, const char *func, const char *format,...)
Definition: gphoto2-port-log.c:341