X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fmessages.c;h=8452a5a99d12badd17d259300a0489f65cdbe94a;hb=987349d7c90cacca2f8383bfb64cdc2a4551b1b1;hp=188d7632bbab8e9168b0d18fd10f002bb732ac70;hpb=9f1762006cc9f790267d3692f17ee7b0db7e3f76;p=vlc diff --git a/src/misc/messages.c b/src/misc/messages.c index 188d7632bb..8452a5a99d 100644 --- a/src/misc/messages.c +++ b/src/misc/messages.c @@ -3,25 +3,25 @@ * This library provides an interface to the message queue to be used by other * modules, especially intf modules. See vlc_config.h for output configuration. ***************************************************************************** - * Copyright (C) 1998-2005 the VideoLAN team + * Copyright (C) 1998-2005 VLC authors and VideoLAN * $Id$ * * Authors: Vincent Seguin * Samuel Hocevar * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program 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.1 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -32,455 +32,253 @@ # include "config.h" #endif -#include - +#include #include /* va_list for BSD */ -#ifdef __APPLE__ -# include -#elif defined(HAVE_LOCALE_H) -# include -#endif -#include /* errno */ - -#ifdef WIN32 -# include /* 'net_strerror' and 'WSAGetLastError' */ -#endif - -#ifdef HAVE_UNISTD_H -# include /* close(), write() */ -#endif - -#include +#include +#include +#include #include #include "../libvlc.h" -/***************************************************************************** - * Local macros - *****************************************************************************/ -#if defined(HAVE_VA_COPY) -# define vlc_va_copy(dest,src) va_copy(dest,src) -#elif defined(HAVE___VA_COPY) -# define vlc_va_copy(dest,src) __va_copy(dest,src) -#else -# define vlc_va_copy(dest,src) (dest)=(src) -#endif - -static inline msg_bank_t *libvlc_bank (libvlc_int_t *inst) -{ - return (libvlc_priv (inst))->msg_bank; -} - -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static void PrintMsg ( vlc_object_t *, const msg_item_t * ); - /** - * Store all data required by messages interfaces. + * Emit a log message. + * \param obj VLC object emitting the message or NULL + * \param type VLC_MSG_* message type (info, error, warning or debug) + * \param module name of module from which the message come + * (normally MODULE_STRING) + * \param format printf-like message format */ -struct msg_bank_t +void vlc_Log (vlc_object_t *obj, int type, const char *module, + const char *format, ... ) { - /** Message queue lock */ - vlc_rwlock_t lock; + va_list args; - /* Subscribers */ - int i_sub; - msg_subscription_t **pp_sub; + va_start (args, format); + vlc_vaLog (obj, type, module, format, args); + va_end (args); +} - locale_t locale; /**< C locale for error messages */ - vlc_dictionary_t enabled_objects; ///< Enabled objects - bool all_objects_enabled; ///< Should we print all objects? -}; +#ifdef _WIN32 +static void Win32DebugOutputMsg (void *, int , const vlc_log_t *, + const char *, va_list); +#endif /** - * Initialize messages queues - * This function initializes all message queues + * Emit a log message. This function is the variable argument list equivalent + * to vlc_Log(). */ -msg_bank_t *msg_Create (void) +void vlc_vaLog (vlc_object_t *obj, int type, const char *module, + const char *format, va_list args) { - msg_bank_t *bank = malloc (sizeof (*bank)); + if (obj != NULL && obj->i_flags & OBJECT_FLAGS_QUIET) + return; - vlc_rwlock_init (&bank->lock); - vlc_dictionary_init (&bank->enabled_objects, 0); - bank->all_objects_enabled = true; + /* Get basename from the module filename */ + char *p = strrchr(module, '/'); + if (p != NULL) + module = p; + p = strchr(module, '.'); - bank->i_sub = 0; - bank->pp_sub = NULL; + size_t modlen = (p != NULL) ? (p - module) : 1; + char modulebuf[modlen + 1]; + if (p != NULL) + { + memcpy(modulebuf, module, modlen); + modulebuf[modlen] = '\0'; + module = modulebuf; + } - /* C locale to get error messages in English in the logs */ - bank->locale = newlocale (LC_MESSAGES_MASK, "C", (locale_t)0); - return bank; -} + /* Fill message information fields */ + vlc_log_t msg; -/** - * Object Printing selection - */ -static void const * kObjectPrintingEnabled = &kObjectPrintingEnabled; -static void const * kObjectPrintingDisabled = &kObjectPrintingDisabled; + msg.i_object_id = (uintptr_t)obj; + msg.psz_object_type = (obj != NULL) ? obj->psz_object_type : "generic"; + msg.psz_module = module; + msg.psz_header = NULL; + for (vlc_object_t *o = obj; o != NULL; o = o->p_parent) + if (o->psz_header != NULL) + { + msg.psz_header = o->psz_header; + break; + } -#undef msg_EnableObjectPrinting -void msg_EnableObjectPrinting (vlc_object_t *obj, const char * psz_object) -{ - msg_bank_t *bank = libvlc_bank (obj->p_libvlc); + /* Pass message to the callback */ + libvlc_priv_t *priv = obj ? libvlc_priv (obj->p_libvlc) : NULL; - vlc_rwlock_wrlock (&bank->lock); - if( !strcmp(psz_object, "all") ) - bank->all_objects_enabled = true; - else - vlc_dictionary_insert (&bank->enabled_objects, psz_object, - (void *)kObjectPrintingEnabled); - vlc_rwlock_unlock (&bank->lock); -} +#ifdef _WIN32 + va_list ap; -#undef msg_DisableObjectPrinting -void msg_DisableObjectPrinting (vlc_object_t *obj, const char * psz_object) -{ - msg_bank_t *bank = libvlc_bank (obj->p_libvlc); + va_copy (ap, args); + Win32DebugOutputMsg (priv ? &priv->log.verbose : NULL, type, &msg, format, ap); + va_end (ap); +#endif - vlc_rwlock_wrlock (&bank->lock); - if( !strcmp(psz_object, "all") ) - bank->all_objects_enabled = false; - else - vlc_dictionary_insert (&bank->enabled_objects, psz_object, - (void *)kObjectPrintingDisabled); - vlc_rwlock_unlock (&bank->lock); + if (priv) { + vlc_rwlock_rdlock (&priv->log.lock); + priv->log.cb (priv->log.opaque, type, &msg, format, args); + vlc_rwlock_unlock (&priv->log.lock); + } } -/** - * Destroy the message queues - * - * This functions prints all messages remaining in the queues, - * then frees all the allocated resources - * No other messages interface functions should be called after this one. - */ -void msg_Destroy (msg_bank_t *bank) -{ - if (unlikely(bank->i_sub != 0)) - fputs ("stale interface subscribers (LibVLC might crash)\n", stderr); - - if (bank->locale != (locale_t)0) - freelocale (bank->locale); - - vlc_dictionary_clear (&bank->enabled_objects, NULL, NULL); +static const char msg_type[4][9] = { "", " error", " warning", " debug" }; +#define COL(x,y) "\033[" #x ";" #y "m" +#define RED COL(31,1) +#define GREEN COL(32,1) +#define YELLOW COL(0,33) +#define WHITE COL(0,1) +#define GRAY "\033[0m" +static const char msg_color[4][8] = { WHITE, RED, YELLOW, GRAY }; - vlc_rwlock_destroy (&bank->lock); - free (bank); -} +/* Display size of a pointer */ +static const int ptr_width = 2 * /* hex digits */ sizeof(uintptr_t); -struct msg_subscription_t +static void PrintColorMsg (void *d, int type, const vlc_log_t *p_item, + const char *format, va_list ap) { - libvlc_int_t *instance; - msg_callback_t func; - msg_cb_data_t *opaque; - int verbosity; -}; - -/** - * Subscribe to the message queue. - * Whenever a message is emitted, a callback will be called. - * Callback invocation are serialized within a subscription. - * - * @param instance LibVLC instance to get messages from - * @param cb callback function - * @param opaque data for the callback function - * @return a subscription pointer, or NULL in case of failure - */ -msg_subscription_t *msg_Subscribe (libvlc_int_t *instance, msg_callback_t cb, - msg_cb_data_t *opaque) -{ - msg_subscription_t *sub = malloc (sizeof (*sub)); - if (sub == NULL) - return NULL; - - sub->instance = instance; - sub->func = cb; - sub->opaque = opaque; - sub->verbosity = 2; /* by default, give all the messages */ - - msg_bank_t *bank = libvlc_bank (instance); - vlc_rwlock_wrlock (&bank->lock); - TAB_APPEND (bank->i_sub, bank->pp_sub, sub); - vlc_rwlock_unlock (&bank->lock); + FILE *stream = stderr; + int verbose = (intptr_t)d; - return sub; -} + if (verbose < 0 || verbose < (type - VLC_MSG_ERR)) + return; -/** - * Unsubscribe from the message queue. - * This function waits for the message callback to return if needed. - */ -void msg_Unsubscribe (msg_subscription_t *sub) -{ - msg_bank_t *bank = libvlc_bank (sub->instance); + int canc = vlc_savecancel (); - vlc_rwlock_wrlock (&bank->lock); - TAB_REMOVE (bank->i_sub, bank->pp_sub, sub); - vlc_rwlock_unlock (&bank->lock); - free (sub); + flockfile (stream); + utf8_fprintf (stream, "["GREEN"%0*"PRIxPTR""GRAY"] ", ptr_width, p_item->i_object_id); + if (p_item->psz_header != NULL) + utf8_fprintf (stream, "[%s] ", p_item->psz_header); + utf8_fprintf (stream, "%s %s%s: %s", p_item->psz_module, + p_item->psz_object_type, msg_type[type], msg_color[type]); + utf8_vfprintf (stream, format, ap); + fputs (GRAY"\n", stream); +#if defined (_WIN32) || defined (__OS2__) + fflush (stream); +#endif + funlockfile (stream); + vlc_restorecancel (canc); } -void msg_SubscriptionSetVerbosity( msg_subscription_t *sub, const int i_verbosity ) +static void PrintMsg (void *d, int type, const vlc_log_t *p_item, + const char *format, va_list ap) { - if( i_verbosity < 0 || i_verbosity > 2 ) return; - - msg_bank_t *bank = libvlc_bank ( sub->instance ); - - vlc_rwlock_wrlock (&bank->lock); + FILE *stream = stderr; + int verbose = (intptr_t)d; - sub->verbosity = i_verbosity; + if (verbose < 0 || verbose < (type - VLC_MSG_ERR)) + return; - vlc_rwlock_unlock (&bank->lock); -} -/***************************************************************************** - * msg_*: print a message - ***************************************************************************** - * These functions queue a message for later printing. - *****************************************************************************/ -void msg_Generic( vlc_object_t *p_this, int i_type, const char *psz_module, - const char *psz_format, ... ) -{ - va_list args; + int canc = vlc_savecancel (); - va_start( args, psz_format ); - msg_GenericVa (p_this, i_type, psz_module, psz_format, args); - va_end( args ); + flockfile (stream); + utf8_fprintf (stream, "[%0*"PRIxPTR"] ", ptr_width, p_item->i_object_id); + if (p_item->psz_header != NULL) + utf8_fprintf (stream, "[%s] ", p_item->psz_header); + utf8_fprintf (stream, "%s %s%s: ", p_item->psz_module, + p_item->psz_object_type, msg_type[type]); + utf8_vfprintf (stream, format, ap); + putc_unlocked ('\n', stream); +#if defined (_WIN32) || defined (__OS2__) + fflush (stream); +#endif + funlockfile (stream); + vlc_restorecancel (canc); } -#undef msg_GenericVa -/** - * Add a message to a queue - * - * This function provides basic functionnalities to other msg_* functions. - * It adds a message to a queue (after having printed all stored messages if it - * is full). If the message can't be converted to string in memory, it issues - * a warning. - */ -void msg_GenericVa (vlc_object_t *p_this, int i_type, - const char *psz_module, - const char *psz_format, va_list _args) +#ifdef _WIN32 +static void Win32DebugOutputMsg (void* d, int type, const vlc_log_t *p_item, + const char *format, va_list dol) { - char * psz_str = NULL; /* formatted message string */ - va_list args; - - assert (p_this); + VLC_UNUSED(p_item); - if( p_this->i_flags & OBJECT_FLAGS_QUIET || - (p_this->i_flags & OBJECT_FLAGS_NODBG && i_type == VLC_MSG_DBG) ) + const signed char *pverbose = d; + if (pverbose && (*pverbose < 0 || *pverbose < (type - VLC_MSG_ERR))) return; - msg_bank_t *bank = libvlc_bank (p_this->p_libvlc); - locale_t locale = uselocale (bank->locale); + va_list dol2; + va_copy (dol2, dol); + int msg_len = vsnprintf(NULL, 0, format, dol2); + va_end (dol2); -#ifndef __GLIBC__ - /* Expand %m to strerror(errno) - only once */ - char buf[strlen( psz_format ) + 2001], *ptr; - strcpy( buf, psz_format ); - ptr = (char*)buf; - psz_format = (const char*) buf; + if(msg_len <= 0) + return; - for( ;; ) - { - ptr = strchr( ptr, '%' ); - if( ptr == NULL ) - break; + char *msg = malloc(msg_len + 1 + 1); + if (!msg) + return; - if( ptr[1] == 'm' ) - { - char errbuf[2001]; - size_t errlen; - -#ifndef WIN32 - strerror_r( errno, errbuf, 1001 ); -#else - int sockerr = WSAGetLastError( ); - if( sockerr ) - { - strncpy( errbuf, net_strerror( sockerr ), 1001 ); - WSASetLastError( sockerr ); - } - if ((sockerr == 0) - || (strcmp ("Unknown network stack error", errbuf) == 0)) - strncpy( errbuf, strerror( errno ), 1001 ); -#endif - errbuf[1000] = 0; - - /* Escape '%' from the error string */ - for( char *percent = strchr( errbuf, '%' ); - percent != NULL; - percent = strchr( percent + 2, '%' ) ) - { - memmove( percent + 1, percent, strlen( percent ) + 1 ); - } - - errlen = strlen( errbuf ); - memmove( ptr + errlen, ptr + 2, strlen( ptr + 2 ) + 1 ); - memcpy( ptr, errbuf, errlen ); - break; /* Only once, so we don't overflow */ + msg_len = vsnprintf(msg, msg_len+1, format, dol); + if (msg_len > 0){ + if(msg[msg_len-1] != '\n'){ + msg[msg_len] = '\n'; + msg[msg_len + 1] = '\0'; + } + char* psz_msg = NULL; + if(asprintf(&psz_msg, "%s %s%s: %s", p_item->psz_module, + p_item->psz_object_type, msg_type[type], msg) > 0) { + wchar_t* wmsg = ToWide(psz_msg); + OutputDebugStringW(wmsg); + free(wmsg); + free(psz_msg); } - - /* Looks for conversion specifier... */ - do - ptr++; - while( *ptr && ( strchr( "diouxXeEfFgGaAcspn%", *ptr ) == NULL ) ); - if( *ptr ) - ptr++; /* ...and skip it */ } + free(msg); +} #endif - /* Convert message to string */ - vlc_va_copy( args, _args ); - if( vasprintf( &psz_str, psz_format, args ) == -1 ) - psz_str = NULL; - va_end( args ); +/** + * Sets the message logging callback. + * \param cb message callback, or NULL to reset + * \param data data pointer for the message callback + */ +void vlc_LogSet (libvlc_int_t *vlc, vlc_log_cb cb, void *opaque) +{ + libvlc_priv_t *priv = libvlc_priv (vlc); - if( psz_str == NULL ) + if (cb == NULL) { - int canc = vlc_savecancel (); /* Do not print half of a message... */ -#ifdef __GLIBC__ - fprintf( stderr, "main warning: can't store message (%m): " ); -#else - char psz_err[1001]; -#ifndef WIN32 - /* we're not using GLIBC, so we are sure that the error description - * will be stored in the buffer we provide to strerror_r() */ - strerror_r( errno, psz_err, 1001 ); -#else - strncpy( psz_err, strerror( errno ), 1001 ); +#if defined (HAVE_ISATTY) && !defined (_WIN32) + if (isatty (STDERR_FILENO) && var_InheritBool (vlc, "color")) + cb = PrintColorMsg; + else #endif - psz_err[1000] = '\0'; - fprintf( stderr, "main warning: can't store message (%s): ", psz_err ); -#endif - vlc_va_copy( args, _args ); - /* We should use utf8_vfprintf - but it calls malloc()... */ - vfprintf( stderr, psz_format, args ); - va_end( args ); - fputs( "\n", stderr ); - vlc_restorecancel (canc); - uselocale (locale); - return; + cb = PrintMsg; + opaque = (void *)(intptr_t)priv->log.verbose; } - uselocale (locale); - - /* Fill message information fields */ - msg_item_t msg; - msg.i_type = i_type; - msg.i_object_id = (uintptr_t)p_this; - msg.psz_object_type = p_this->psz_object_type; - msg.psz_module = psz_module; - msg.psz_msg = psz_str; - msg.psz_header = NULL; - - for (vlc_object_t *o = p_this; o != NULL; o = o->p_parent) - if (o->psz_header != NULL) - { - msg.psz_header = o->psz_header; - break; - } - - PrintMsg( p_this, &msg ); - - vlc_rwlock_rdlock (&bank->lock); - for (int i = 0; i < bank->i_sub; i++) - { - msg_subscription_t *sub = bank->pp_sub[i]; - libvlc_priv_t *priv = libvlc_priv( sub->instance ); - msg_bank_t *bank = priv->msg_bank; - void *val = vlc_dictionary_value_for_key( &bank->enabled_objects, - msg.psz_module ); - if( val == kObjectPrintingDisabled ) continue; - if( val != kObjectPrintingEnabled ) /*if not allowed */ - { - val = vlc_dictionary_value_for_key( &bank->enabled_objects, - msg.psz_object_type ); - if( val == kObjectPrintingDisabled ) continue; - if( val == kObjectPrintingEnabled ); /* Allowed */ - else if( !bank->all_objects_enabled ) continue; - } - switch( msg.i_type ) - { - case VLC_MSG_INFO: - case VLC_MSG_ERR: - if( sub->verbosity < 0 ) continue; - break; - case VLC_MSG_WARN: - if( sub->verbosity < 1 ) continue; - break; - case VLC_MSG_DBG: - if( sub->verbosity < 2 ) continue; - break; - } + vlc_rwlock_wrlock (&priv->log.lock); + priv->log.cb = cb; + priv->log.opaque = opaque; + vlc_rwlock_unlock (&priv->log.lock); - sub->func (sub->opaque, &msg); - } - vlc_rwlock_unlock (&bank->lock); - free (msg.psz_msg); + /* Announce who we are */ + msg_Dbg (vlc, "VLC media player - %s", VERSION_MESSAGE); + msg_Dbg (vlc, "%s", COPYRIGHT_MESSAGE); + msg_Dbg (vlc, "revision %s", psz_vlc_changeset); + msg_Dbg (vlc, "configured with %s", CONFIGURE_LINE); } -/***************************************************************************** - * PrintMsg: output a standard message item to stderr - ***************************************************************************** - * Print a message to stderr, with colour formatting if needed. - *****************************************************************************/ -static void PrintMsg ( vlc_object_t *p_this, const msg_item_t *p_item ) +void vlc_LogInit (libvlc_int_t *vlc) { -# define COL(x,y) "\033[" #x ";" #y "m" -# define RED COL(31,1) -# define GREEN COL(32,1) -# define YELLOW COL(0,33) -# define WHITE COL(0,1) -# define GRAY "\033[0m" - static const char msgtype[4][9] = { "", " error", " warning", " debug" }; - static const char msgcolor[4][8] = { WHITE, RED, YELLOW, GRAY }; - - libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc); - int type = p_item->i_type; - - if (priv->i_verbose < 0 || priv->i_verbose < (type - VLC_MSG_ERR)) - return; + libvlc_priv_t *priv = libvlc_priv (vlc); + const char *str; - const char *objtype = p_item->psz_object_type; - msg_bank_t *bank = priv->msg_bank; - void * val = vlc_dictionary_value_for_key (&bank->enabled_objects, - p_item->psz_module); - if( val == kObjectPrintingDisabled ) - return; - if( val == kObjectPrintingEnabled ) - /* Allowed */; + if (var_InheritBool (vlc, "quiet")) + priv->log.verbose = -1; else - { - val = vlc_dictionary_value_for_key (&bank->enabled_objects, - objtype); - if( val == kObjectPrintingDisabled ) - return; - if( val == kObjectPrintingEnabled ) - /* Allowed */; - else if( !bank->all_objects_enabled ) - return; - } + if ((str = getenv ("VLC_VERBOSE")) != NULL) + priv->log.verbose = atoi (str); + else + priv->log.verbose = var_InheritInteger (vlc, "verbose"); - /* Send the message to stderr */ - FILE *stream = stderr; - int canc = vlc_savecancel (); + vlc_rwlock_init (&priv->log.lock); + vlc_LogSet (vlc, NULL, NULL); +} - flockfile (stream); - fprintf (stream, priv->b_color ? "["GREEN"%p"GRAY"] " : "[%p] ", - (void *)p_item->i_object_id); - if (p_item->psz_header != NULL) - utf8_fprintf (stream, "[%s] ", p_item->psz_header); - utf8_fprintf (stream, "%s %s%s: ", p_item->psz_module, objtype, - msgtype[type]); - if (priv->b_color) - fputs (msgcolor[type], stream); - fputs (p_item->psz_msg, stream); - if (priv->b_color) - fputs (GRAY, stream); - putc_unlocked ('\n', stream); -#if defined (WIN32) || defined (__OS2__) - fflush (stream); -#endif - funlockfile (stream); - vlc_restorecancel (canc); +void vlc_LogDeinit (libvlc_int_t *vlc) +{ + libvlc_priv_t *priv = libvlc_priv (vlc); + + vlc_rwlock_destroy (&priv->log.lock); }