1 /*****************************************************************************
2 * messages.c: messages interface
3 * This library provides an interface to the message queue to be used by other
4 * modules, especially intf modules. See vlc_config.h for output configuration.
5 *****************************************************************************
6 * Copyright (C) 1998-2005 the VideoLAN team
9 * Authors: Vincent Seguin <seguin@via.ecp.fr>
10 * Samuel Hocevar <sam@zoy.org>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
35 #include <vlc_common.h>
37 #include <stdarg.h> /* va_list for BSD */
40 #elif defined(HAVE_LOCALE_H)
43 #include <errno.h> /* errno */
46 # include <vlc_network.h> /* 'net_strerror' and 'WSAGetLastError' */
50 # include <unistd.h> /* close(), write() */
55 #include <vlc_charset.h>
56 #include "../libvlc.h"
58 /*****************************************************************************
60 *****************************************************************************/
61 #if defined(HAVE_VA_COPY)
62 # define vlc_va_copy(dest,src) va_copy(dest,src)
63 #elif defined(HAVE___VA_COPY)
64 # define vlc_va_copy(dest,src) __va_copy(dest,src)
66 # define vlc_va_copy(dest,src) (dest)=(src)
69 static inline msg_bank_t
*libvlc_bank (libvlc_int_t
*inst
)
71 return (libvlc_priv (inst
))->msg_bank
;
74 /*****************************************************************************
76 *****************************************************************************/
77 static void PrintMsg ( vlc_object_t
*, msg_item_t
* );
80 * Store all data required by messages interfaces.
84 /** Message queue lock */
89 msg_subscription_t
**pp_sub
;
91 locale_t locale
; /**< C locale for error messages */
92 vlc_dictionary_t enabled_objects
; ///< Enabled objects
93 bool all_objects_enabled
; ///< Should we print all objects?
97 * Initialize messages queues
98 * This function initializes all message queues
100 msg_bank_t
*msg_Create (void)
102 msg_bank_t
*bank
= malloc (sizeof (*bank
));
104 vlc_rwlock_init (&bank
->lock
);
105 vlc_dictionary_init (&bank
->enabled_objects
, 0);
106 bank
->all_objects_enabled
= true;
111 /* C locale to get error messages in English in the logs */
112 bank
->locale
= newlocale (LC_MESSAGES_MASK
, "C", (locale_t
)0);
117 * Object Printing selection
119 static void const * kObjectPrintingEnabled
= &kObjectPrintingEnabled
;
120 static void const * kObjectPrintingDisabled
= &kObjectPrintingDisabled
;
123 #undef msg_EnableObjectPrinting
124 void msg_EnableObjectPrinting (vlc_object_t
*obj
, const char * psz_object
)
126 msg_bank_t
*bank
= libvlc_bank (obj
->p_libvlc
);
128 vlc_rwlock_wrlock (&bank
->lock
);
129 if( !strcmp(psz_object
, "all") )
130 bank
->all_objects_enabled
= true;
132 vlc_dictionary_insert (&bank
->enabled_objects
, psz_object
,
133 (void *)kObjectPrintingEnabled
);
134 vlc_rwlock_unlock (&bank
->lock
);
137 #undef msg_DisableObjectPrinting
138 void msg_DisableObjectPrinting (vlc_object_t
*obj
, const char * psz_object
)
140 msg_bank_t
*bank
= libvlc_bank (obj
->p_libvlc
);
142 vlc_rwlock_wrlock (&bank
->lock
);
143 if( !strcmp(psz_object
, "all") )
144 bank
->all_objects_enabled
= false;
146 vlc_dictionary_insert (&bank
->enabled_objects
, psz_object
,
147 (void *)kObjectPrintingDisabled
);
148 vlc_rwlock_unlock (&bank
->lock
);
152 * Destroy the message queues
154 * This functions prints all messages remaining in the queues,
155 * then frees all the allocated resources
156 * No other messages interface functions should be called after this one.
158 void msg_Destroy (msg_bank_t
*bank
)
160 if (unlikely(bank
->i_sub
!= 0))
161 fputs ("stale interface subscribers (LibVLC might crash)\n", stderr
);
163 if (bank
->locale
!= (locale_t
)0)
164 freelocale (bank
->locale
);
166 vlc_dictionary_clear (&bank
->enabled_objects
, NULL
, NULL
);
168 vlc_rwlock_destroy (&bank
->lock
);
172 struct msg_subscription_t
174 libvlc_int_t
*instance
;
176 msg_cb_data_t
*opaque
;
181 * Subscribe to the message queue.
182 * Whenever a message is emitted, a callback will be called.
183 * Callback invocation are serialized within a subscription.
185 * @param instance LibVLC instance to get messages from
186 * @param cb callback function
187 * @param opaque data for the callback function
188 * @return a subscription pointer, or NULL in case of failure
190 msg_subscription_t
*msg_Subscribe (libvlc_int_t
*instance
, msg_callback_t cb
,
191 msg_cb_data_t
*opaque
)
193 msg_subscription_t
*sub
= malloc (sizeof (*sub
));
197 sub
->instance
= instance
;
199 sub
->opaque
= opaque
;
200 sub
->verbosity
= 2; /* by default, give all the messages */
202 msg_bank_t
*bank
= libvlc_bank (instance
);
203 vlc_rwlock_wrlock (&bank
->lock
);
204 TAB_APPEND (bank
->i_sub
, bank
->pp_sub
, sub
);
205 vlc_rwlock_unlock (&bank
->lock
);
211 * Unsubscribe from the message queue.
212 * This function waits for the message callback to return if needed.
214 void msg_Unsubscribe (msg_subscription_t
*sub
)
216 msg_bank_t
*bank
= libvlc_bank (sub
->instance
);
218 vlc_rwlock_wrlock (&bank
->lock
);
219 TAB_REMOVE (bank
->i_sub
, bank
->pp_sub
, sub
);
220 vlc_rwlock_unlock (&bank
->lock
);
224 void msg_SubscriptionSetVerbosity( msg_subscription_t
*sub
, const int i_verbosity
)
226 if( i_verbosity
< 0 || i_verbosity
> 2 ) return;
228 msg_bank_t
*bank
= libvlc_bank ( sub
->instance
);
230 vlc_rwlock_wrlock (&bank
->lock
);
232 sub
->verbosity
= i_verbosity
;
234 vlc_rwlock_unlock (&bank
->lock
);
236 /*****************************************************************************
237 * msg_*: print a message
238 *****************************************************************************
239 * These functions queue a message for later printing.
240 *****************************************************************************/
241 void msg_Generic( vlc_object_t
*p_this
, int i_type
, const char *psz_module
,
242 const char *psz_format
, ... )
246 va_start( args
, psz_format
);
247 msg_GenericVa (p_this
, i_type
, psz_module
, psz_format
, args
);
252 * Destroys a message.
254 static void msg_Free (gc_object_t
*gc
)
256 msg_item_t
*msg
= vlc_priv (gc
, msg_item_t
);
258 free (msg
->psz_module
);
260 free (msg
->psz_header
);
266 * Add a message to a queue
268 * This function provides basic functionnalities to other msg_* functions.
269 * It adds a message to a queue (after having printed all stored messages if it
270 * is full). If the message can't be converted to string in memory, it issues
273 void msg_GenericVa (vlc_object_t
*p_this
, int i_type
,
274 const char *psz_module
,
275 const char *psz_format
, va_list _args
)
277 size_t i_header_size
; /* Size of the additionnal header */
279 char * psz_str
= NULL
; /* formatted message string */
280 char * psz_header
= NULL
;
285 if( p_this
->i_flags
& OBJECT_FLAGS_QUIET
||
286 (p_this
->i_flags
& OBJECT_FLAGS_NODBG
&& i_type
== VLC_MSG_DBG
) )
289 msg_bank_t
*bank
= libvlc_bank (p_this
->p_libvlc
);
290 locale_t locale
= uselocale (bank
->locale
);
293 /* Expand %m to strerror(errno) - only once */
294 char buf
[strlen( psz_format
) + 2001], *ptr
;
295 strcpy( buf
, psz_format
);
297 psz_format
= (const char*) buf
;
301 ptr
= strchr( ptr
, '%' );
311 strerror_r( errno
, errbuf
, 1001 );
313 int sockerr
= WSAGetLastError( );
316 strncpy( errbuf
, net_strerror( sockerr
), 1001 );
317 WSASetLastError( sockerr
);
320 || (strcmp ("Unknown network stack error", errbuf
) == 0))
321 strncpy( errbuf
, strerror( errno
), 1001 );
325 /* Escape '%' from the error string */
326 for( char *percent
= strchr( errbuf
, '%' );
328 percent
= strchr( percent
+ 2, '%' ) )
330 memmove( percent
+ 1, percent
, strlen( percent
) + 1 );
333 errlen
= strlen( errbuf
);
334 memmove( ptr
+ errlen
, ptr
+ 2, strlen( ptr
+ 2 ) + 1 );
335 memcpy( ptr
, errbuf
, errlen
);
336 break; /* Only once, so we don't overflow */
339 /* Looks for conversion specifier... */
342 while( *ptr
&& ( strchr( "diouxXeEfFgGaAcspn%", *ptr
) == NULL
) );
344 ptr
++; /* ...and skip it */
348 /* Convert message to string */
349 vlc_va_copy( args
, _args
);
350 if( vasprintf( &psz_str
, psz_format
, args
) == -1 )
354 if( psz_str
== NULL
)
356 int canc
= vlc_savecancel (); /* Do not print half of a message... */
358 fprintf( stderr
, "main warning: can't store message (%m): " );
362 /* we're not using GLIBC, so we are sure that the error description
363 * will be stored in the buffer we provide to strerror_r() */
364 strerror_r( errno
, psz_err
, 1001 );
366 strncpy( psz_err
, strerror( errno
), 1001 );
368 psz_err
[1000] = '\0';
369 fprintf( stderr
, "main warning: can't store message (%s): ", psz_err
);
371 vlc_va_copy( args
, _args
);
372 /* We should use utf8_vfprintf - but it calls malloc()... */
373 vfprintf( stderr
, psz_format
, args
);
375 fputs( "\n", stderr
);
376 vlc_restorecancel (canc
);
382 msg_item_t
* p_item
= malloc (sizeof (*p_item
));
386 vlc_gc_init (p_item
, msg_Free
);
387 p_item
->psz_module
= p_item
->psz_msg
= p_item
->psz_header
= NULL
;
393 while( p_obj
!= NULL
)
395 char *psz_old
= NULL
;
396 if( p_obj
->psz_header
)
398 i_header_size
+= strlen( p_obj
->psz_header
) + 4;
401 psz_old
= strdup( psz_header
);
402 psz_header
= xrealloc( psz_header
, i_header_size
);
403 snprintf( psz_header
, i_header_size
, "[%s] %s",
404 p_obj
->psz_header
, psz_old
);
408 psz_header
= xmalloc( i_header_size
);
409 snprintf( psz_header
, i_header_size
, "[%s]",
414 p_obj
= p_obj
->p_parent
;
417 /* Fill message information fields */
418 p_item
->i_type
= i_type
;
419 p_item
->i_object_id
= (uintptr_t)p_this
;
420 p_item
->psz_object_type
= p_this
->psz_object_type
;
421 p_item
->psz_module
= strdup( psz_module
);
422 p_item
->psz_msg
= psz_str
;
423 p_item
->psz_header
= psz_header
;
425 PrintMsg( p_this
, p_item
);
427 vlc_rwlock_rdlock (&bank
->lock
);
428 for (int i
= 0; i
< bank
->i_sub
; i
++)
430 msg_subscription_t
*sub
= bank
->pp_sub
[i
];
431 libvlc_priv_t
*priv
= libvlc_priv( sub
->instance
);
432 msg_bank_t
*bank
= priv
->msg_bank
;
433 void *val
= vlc_dictionary_value_for_key( &bank
->enabled_objects
,
434 p_item
->psz_module
);
435 if( val
== kObjectPrintingDisabled
) continue;
436 if( val
!= kObjectPrintingEnabled
) /*if not allowed */
438 val
= vlc_dictionary_value_for_key( &bank
->enabled_objects
,
439 p_item
->psz_object_type
);
440 if( val
== kObjectPrintingDisabled
) continue;
441 if( val
== kObjectPrintingEnabled
); /* Allowed */
442 else if( !bank
->all_objects_enabled
) continue;
444 switch( p_item
->i_type
)
448 if( sub
->verbosity
< 0 ) continue;
451 if( sub
->verbosity
< 1 ) continue;
454 if( sub
->verbosity
< 2 ) continue;
458 sub
->func (sub
->opaque
, p_item
, 0);
460 vlc_rwlock_unlock (&bank
->lock
);
461 msg_Release (p_item
);
464 /*****************************************************************************
465 * PrintMsg: output a standard message item to stderr
466 *****************************************************************************
467 * Print a message to stderr, with colour formatting if needed.
468 *****************************************************************************/
469 static void PrintMsg ( vlc_object_t
* p_this
, msg_item_t
* p_item
)
471 # define COL(x,y) "\033[" #x ";" #y "m"
472 # define RED COL(31,1)
473 # define GREEN COL(32,1)
474 # define YELLOW COL(0,33)
475 # define WHITE COL(0,1)
476 # define GRAY "\033[0m"
478 static const char ppsz_type
[4][9] = { "", " error", " warning", " debug" };
479 static const char ppsz_color
[4][8] = { WHITE
, RED
, YELLOW
, GRAY
};
480 const char *psz_object
;
481 libvlc_priv_t
*priv
= libvlc_priv (p_this
->p_libvlc
);
482 msg_bank_t
*bank
= priv
->msg_bank
;
483 int i_type
= p_item
->i_type
;
488 if( priv
->i_verbose
< 0 ) return;
491 if( priv
->i_verbose
< 0 ) return;
494 if( priv
->i_verbose
< 1 ) return;
497 if( priv
->i_verbose
< 2 ) return;
501 psz_object
= p_item
->psz_object_type
;
502 void * val
= vlc_dictionary_value_for_key (&bank
->enabled_objects
,
504 if( val
== kObjectPrintingDisabled
)
506 if( val
== kObjectPrintingEnabled
)
510 val
= vlc_dictionary_value_for_key (&bank
->enabled_objects
,
512 if( val
== kObjectPrintingDisabled
)
514 if( val
== kObjectPrintingEnabled
)
516 else if( !bank
->all_objects_enabled
)
520 int canc
= vlc_savecancel ();
521 /* Send the message to stderr */
522 utf8_fprintf( stderr
, "[%s%p%s] %s%s%s %s%s: %s%s%s\n",
523 priv
->b_color
? GREEN
: "",
524 (void *)p_item
->i_object_id
,
525 priv
->b_color
? GRAY
: "",
526 p_item
->psz_header
? p_item
->psz_header
: "",
527 p_item
->psz_header
? " " : "",
528 p_item
->psz_module
, psz_object
,
530 priv
->b_color
? ppsz_color
[i_type
] : "",
532 priv
->b_color
? GRAY
: "" );
537 vlc_restorecancel (canc
);