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
*, const 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
);
253 * Add a message to a queue
255 * This function provides basic functionnalities to other msg_* functions.
256 * It adds a message to a queue (after having printed all stored messages if it
257 * is full). If the message can't be converted to string in memory, it issues
260 void msg_GenericVa (vlc_object_t
*p_this
, int i_type
,
261 const char *psz_module
,
262 const char *psz_format
, va_list _args
)
264 char * psz_str
= NULL
; /* formatted message string */
269 if( p_this
->i_flags
& OBJECT_FLAGS_QUIET
||
270 (p_this
->i_flags
& OBJECT_FLAGS_NODBG
&& i_type
== VLC_MSG_DBG
) )
273 msg_bank_t
*bank
= libvlc_bank (p_this
->p_libvlc
);
274 locale_t locale
= uselocale (bank
->locale
);
277 /* Expand %m to strerror(errno) - only once */
278 char buf
[strlen( psz_format
) + 2001], *ptr
;
279 strcpy( buf
, psz_format
);
281 psz_format
= (const char*) buf
;
285 ptr
= strchr( ptr
, '%' );
295 strerror_r( errno
, errbuf
, 1001 );
297 int sockerr
= WSAGetLastError( );
300 strncpy( errbuf
, net_strerror( sockerr
), 1001 );
301 WSASetLastError( sockerr
);
304 || (strcmp ("Unknown network stack error", errbuf
) == 0))
305 strncpy( errbuf
, strerror( errno
), 1001 );
309 /* Escape '%' from the error string */
310 for( char *percent
= strchr( errbuf
, '%' );
312 percent
= strchr( percent
+ 2, '%' ) )
314 memmove( percent
+ 1, percent
, strlen( percent
) + 1 );
317 errlen
= strlen( errbuf
);
318 memmove( ptr
+ errlen
, ptr
+ 2, strlen( ptr
+ 2 ) + 1 );
319 memcpy( ptr
, errbuf
, errlen
);
320 break; /* Only once, so we don't overflow */
323 /* Looks for conversion specifier... */
326 while( *ptr
&& ( strchr( "diouxXeEfFgGaAcspn%", *ptr
) == NULL
) );
328 ptr
++; /* ...and skip it */
332 /* Convert message to string */
333 vlc_va_copy( args
, _args
);
334 if( vasprintf( &psz_str
, psz_format
, args
) == -1 )
338 if( psz_str
== NULL
)
340 int canc
= vlc_savecancel (); /* Do not print half of a message... */
342 fprintf( stderr
, "main warning: can't store message (%m): " );
346 /* we're not using GLIBC, so we are sure that the error description
347 * will be stored in the buffer we provide to strerror_r() */
348 strerror_r( errno
, psz_err
, 1001 );
350 strncpy( psz_err
, strerror( errno
), 1001 );
352 psz_err
[1000] = '\0';
353 fprintf( stderr
, "main warning: can't store message (%s): ", psz_err
);
355 vlc_va_copy( args
, _args
);
356 /* We should use utf8_vfprintf - but it calls malloc()... */
357 vfprintf( stderr
, psz_format
, args
);
359 fputs( "\n", stderr
);
360 vlc_restorecancel (canc
);
366 /* Fill message information fields */
370 msg
.i_object_id
= (uintptr_t)p_this
;
371 msg
.psz_object_type
= p_this
->psz_object_type
;
372 msg
.psz_module
= psz_module
;
373 msg
.psz_msg
= psz_str
;
374 msg
.psz_header
= NULL
;
376 for (vlc_object_t
*o
= p_this
; o
!= NULL
; o
= o
->p_parent
)
377 if (o
->psz_header
!= NULL
)
379 msg
.psz_header
= o
->psz_header
;
383 PrintMsg( p_this
, &msg
);
385 vlc_rwlock_rdlock (&bank
->lock
);
386 for (int i
= 0; i
< bank
->i_sub
; i
++)
388 msg_subscription_t
*sub
= bank
->pp_sub
[i
];
389 libvlc_priv_t
*priv
= libvlc_priv( sub
->instance
);
390 msg_bank_t
*bank
= priv
->msg_bank
;
391 void *val
= vlc_dictionary_value_for_key( &bank
->enabled_objects
,
393 if( val
== kObjectPrintingDisabled
) continue;
394 if( val
!= kObjectPrintingEnabled
) /*if not allowed */
396 val
= vlc_dictionary_value_for_key( &bank
->enabled_objects
,
397 msg
.psz_object_type
);
398 if( val
== kObjectPrintingDisabled
) continue;
399 if( val
== kObjectPrintingEnabled
); /* Allowed */
400 else if( !bank
->all_objects_enabled
) continue;
406 if( sub
->verbosity
< 0 ) continue;
409 if( sub
->verbosity
< 1 ) continue;
412 if( sub
->verbosity
< 2 ) continue;
416 sub
->func (sub
->opaque
, &msg
);
418 vlc_rwlock_unlock (&bank
->lock
);
422 /*****************************************************************************
423 * PrintMsg: output a standard message item to stderr
424 *****************************************************************************
425 * Print a message to stderr, with colour formatting if needed.
426 *****************************************************************************/
427 static void PrintMsg ( vlc_object_t
*p_this
, const msg_item_t
*p_item
)
429 # define COL(x,y) "\033[" #x ";" #y "m"
430 # define RED COL(31,1)
431 # define GREEN COL(32,1)
432 # define YELLOW COL(0,33)
433 # define WHITE COL(0,1)
434 # define GRAY "\033[0m"
435 static const char msgtype
[4][9] = { "", " error", " warning", " debug" };
436 static const char msgcolor
[4][8] = { WHITE
, RED
, YELLOW
, GRAY
};
438 libvlc_priv_t
*priv
= libvlc_priv (p_this
->p_libvlc
);
439 int type
= p_item
->i_type
;
441 if (priv
->i_verbose
< 0 || priv
->i_verbose
< (type
- VLC_MSG_ERR
))
444 const char *objtype
= p_item
->psz_object_type
;
445 msg_bank_t
*bank
= priv
->msg_bank
;
446 void * val
= vlc_dictionary_value_for_key (&bank
->enabled_objects
,
448 if( val
== kObjectPrintingDisabled
)
450 if( val
== kObjectPrintingEnabled
)
454 val
= vlc_dictionary_value_for_key (&bank
->enabled_objects
,
456 if( val
== kObjectPrintingDisabled
)
458 if( val
== kObjectPrintingEnabled
)
460 else if( !bank
->all_objects_enabled
)
464 /* Send the message to stderr */
465 FILE *stream
= stderr
;
466 int canc
= vlc_savecancel ();
469 fprintf (stream
, priv
->b_color
? "["GREEN
"%p"GRAY
"] " : "[%p] ",
470 (void *)p_item
->i_object_id
);
471 if (p_item
->psz_header
!= NULL
)
472 utf8_fprintf (stream
, "[%s] ", p_item
->psz_header
);
473 utf8_fprintf (stream
, "%s %s%s: ", p_item
->psz_module
, objtype
,
476 fputs (msgcolor
[type
], stream
);
477 fputs (p_item
->psz_msg
, stream
);
479 fputs (GRAY
, stream
);
480 putc_unlocked ('\n', stream
);
481 #if defined (WIN32) || defined (__OS2__)
484 funlockfile (stream
);
485 vlc_restorecancel (canc
);