X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fmessages.c;h=45666108e1ab4e727d59162a3c01fd9aea63574a;hb=add015beb93e65ac290bf3c5275226d27885b00d;hp=906b489cb6e66eeea7022ad140fd049dd4799b1c;hpb=69d7fdea2da6f773fd7993f78c2bea494eb2d819;p=vlc diff --git a/src/misc/messages.c b/src/misc/messages.c index 906b489cb6..45666108e1 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,560 +32,476 @@ # 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" -typedef struct -{ - int i_code; - char * psz_message; -} msg_context_t; +#ifdef __ANDROID__ +#include +#endif -static void cleanup_msg_context (void *data) +struct vlc_logger_t { - msg_context_t *ctx = data; - free (ctx->psz_message); - free (ctx); -} + VLC_COMMON_MEMBERS + vlc_rwlock_t lock; + vlc_log_cb log; + void *sys; +}; -static vlc_threadvar_t msg_context; -static uintptr_t banks = 0; +static void vlc_vaLogCallback(libvlc_int_t *vlc, int type, + const vlc_log_t *item, const char *format, + va_list ap) +{ + vlc_logger_t *logger = libvlc_priv(vlc)->logger; -/***************************************************************************** - * 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 + assert(logger != NULL); + vlc_rwlock_rdlock(&logger->lock); + logger->log(logger->sys, type, item, format, ap); + vlc_rwlock_unlock(&logger->lock); +} -static inline msg_bank_t *libvlc_bank (libvlc_int_t *inst) +static void vlc_LogCallback(libvlc_int_t *vlc, int type, const vlc_log_t *item, + const char *format, ...) { - return (libvlc_priv (inst))->msg_bank; -} + va_list ap; -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static void PrintMsg ( vlc_object_t *, msg_item_t * ); + va_start(ap, format); + vlc_vaLogCallback(vlc, type, item, format, ap); + va_end(ap); +} -static vlc_mutex_t msg_stack_lock = VLC_STATIC_MUTEX; +#ifdef _WIN32 +static void Win32DebugOutputMsg (void *, int , const vlc_log_t *, + const char *, va_list); +#endif /** - * Store all data required by messages interfaces. + * Emit a log message. This function is the variable argument list equivalent + * to vlc_Log(). */ -struct msg_bank_t +void vlc_vaLog (vlc_object_t *obj, int type, const char *module, + const char *format, va_list args) { - /** Message queue lock */ - vlc_rwlock_t lock; + if (obj != NULL && obj->i_flags & OBJECT_FLAGS_QUIET) + return; - /* Subscribers */ - int i_sub; - msg_subscription_t **pp_sub; + /* Get basename from the module filename */ + char *p = strrchr(module, '/'); + if (p != NULL) + module = p; + p = strchr(module, '.'); - locale_t locale; /**< C locale for error messages */ - vlc_dictionary_t enabled_objects; ///< Enabled objects - bool all_objects_enabled; ///< Should we print all objects? -}; + size_t modlen = (p != NULL) ? (p - module) : 0; + char modulebuf[modlen + 1]; + if (p != NULL) + { + memcpy(modulebuf, module, modlen); + modulebuf[modlen] = '\0'; + module = modulebuf; + } -/** - * Initialize messages queues - * This function initializes all message queues - */ -msg_bank_t *msg_Create (void) -{ - msg_bank_t *bank = malloc (sizeof (*bank)); + /* Fill message information fields */ + vlc_log_t msg; + + 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; - vlc_rwlock_init (&bank->lock); - vlc_dictionary_init (&bank->enabled_objects, 0); - bank->all_objects_enabled = true; + for (vlc_object_t *o = obj; o != NULL; o = o->p_parent) + if (o->psz_header != NULL) + { + msg.psz_header = o->psz_header; + break; + } - bank->i_sub = 0; - bank->pp_sub = NULL; +#ifdef _WIN32 + va_list ap; - /* C locale to get error messages in English in the logs */ - bank->locale = newlocale (LC_MESSAGES_MASK, "C", (locale_t)0); + va_copy (ap, args); + Win32DebugOutputMsg (NULL, type, &msg, format, ap); + va_end (ap); +#endif - vlc_mutex_lock( &msg_stack_lock ); - if( banks++ == 0 ) - vlc_threadvar_create( &msg_context, cleanup_msg_context ); - vlc_mutex_unlock( &msg_stack_lock ); - return bank; + /* Pass message to the callback */ + if (obj != NULL) + vlc_vaLogCallback(obj->p_libvlc, type, &msg, format, args); } /** - * Object Printing selection + * 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 */ -static void const * kObjectPrintingEnabled = &kObjectPrintingEnabled; -static void const * kObjectPrintingDisabled = &kObjectPrintingDisabled; - -#undef msg_EnableObjectPrinting -void msg_EnableObjectPrinting (vlc_object_t *obj, const char * psz_object) +void vlc_Log(vlc_object_t *obj, int type, const char *module, + const char *format, ... ) { - msg_bank_t *bank = libvlc_bank (obj->p_libvlc); + va_list ap; - 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); + va_start(ap, format); + vlc_vaLog(obj, type, module, format, ap); + va_end(ap); } -#undef msg_DisableObjectPrinting -void msg_DisableObjectPrinting (vlc_object_t *obj, const char * psz_object) +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 }; + +/* Display size of a pointer */ +static const int ptr_width = 2 * /* hex digits */ sizeof(uintptr_t); + +static void PrintColorMsg (void *d, int type, const vlc_log_t *p_item, + const char *format, va_list ap) { - msg_bank_t *bank = libvlc_bank (obj->p_libvlc); + FILE *stream = stderr; + int verbose = (intptr_t)d; - 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 (verbose < 0 || verbose < (type - VLC_MSG_ERR)) + return; + + int canc = vlc_savecancel (); + + 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); } -/** - * 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) +static void PrintMsg (void *d, int type, const vlc_log_t *p_item, + const char *format, va_list ap) { - if (unlikely(bank->i_sub != 0)) - fputs ("stale interface subscribers (LibVLC might crash)\n", stderr); - - vlc_mutex_lock( &msg_stack_lock ); - assert(banks > 0); - if( --banks == 0 ) - vlc_threadvar_delete( &msg_context ); - vlc_mutex_unlock( &msg_stack_lock ); + FILE *stream = stderr; + int verbose = (intptr_t)d; - if (bank->locale != (locale_t)0) - freelocale (bank->locale); + if (verbose < 0 || verbose < (type - VLC_MSG_ERR)) + return; - vlc_dictionary_clear (&bank->enabled_objects, NULL, NULL); + int canc = vlc_savecancel (); - vlc_rwlock_destroy (&bank->lock); - free (bank); + 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); } -struct msg_subscription_t +#ifdef _WIN32 +static void Win32DebugOutputMsg (void* d, int type, const vlc_log_t *p_item, + const char *format, va_list dol) { - libvlc_int_t *instance; - msg_callback_t func; - msg_cb_data_t *opaque; -}; + VLC_UNUSED(p_item); -/** - * 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; + const signed char *pverbose = d; + if (pverbose && (*pverbose < 0 || *pverbose < (type - VLC_MSG_ERR))) + return; + + va_list dol2; + va_copy (dol2, dol); + int msg_len = vsnprintf(NULL, 0, format, dol2); + va_end (dol2); - sub->instance = instance; - sub->func = cb; - sub->opaque = opaque; + if(msg_len <= 0) + return; - 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); + char *msg = malloc(msg_len + 1 + 1); + if (!msg) + return; - return sub; + 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); + } + } + free(msg); } +#endif -/** - * Unsubscribe from the message queue. - * This function waits for the message callback to return if needed. - */ -void msg_Unsubscribe (msg_subscription_t *sub) +#ifdef __ANDROID__ +static void AndroidPrintMsg (void *d, int type, const vlc_log_t *p_item, + const char *format, va_list ap) { - msg_bank_t *bank = libvlc_bank (sub->instance); + int verbose = (intptr_t)d; + int prio; - vlc_rwlock_wrlock (&bank->lock); - TAB_REMOVE (bank->i_sub, bank->pp_sub, sub); - vlc_rwlock_unlock (&bank->lock); - free (sub); -} + if (verbose < 0 || verbose < (type - VLC_MSG_ERR)) + return; -/***************************************************************************** - * 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 ); + char *format2; + if (asprintf (&format2, "[%0*"PRIxPTR"] %s %s: %s", + ptr_width, p_item->i_object_id, p_item->psz_module, + p_item->psz_object_type, format) < 0) + return; + switch (type) { + case VLC_MSG_INFO: + prio = ANDROID_LOG_INFO; + break; + case VLC_MSG_ERR: + prio = ANDROID_LOG_ERROR; + break; + case VLC_MSG_WARN: + prio = ANDROID_LOG_WARN; + break; + default: + case VLC_MSG_DBG: + prio = ANDROID_LOG_DEBUG; + } + __android_log_vprint (prio, "VLC", format2, ap); + free (format2); + vlc_restorecancel (canc); } +#endif -/** - * Destroys a message. - */ -static void msg_Free (gc_object_t *gc) +typedef struct vlc_log_early_t { - msg_item_t *msg = vlc_priv (gc, msg_item_t); - - free (msg->psz_module); - free (msg->psz_msg); - free (msg->psz_header); - free (msg); -} + struct vlc_log_early_t *next; + int type; + vlc_log_t meta; + char *msg; +} vlc_log_early_t; -#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) +typedef struct { - size_t i_header_size; /* Size of the additionnal header */ - vlc_object_t *p_obj; - char * psz_str = NULL; /* formatted message string */ - char * psz_header = NULL; - va_list args; + vlc_mutex_t lock; + vlc_log_early_t *head; + vlc_log_early_t **tailp; +} vlc_logger_early_t; - assert (p_this); +static void vlc_vaLogEarly(void *d, int type, const vlc_log_t *item, + const char *format, va_list ap) +{ + vlc_logger_early_t *sys = d; - if( p_this->i_flags & OBJECT_FLAGS_QUIET || - (p_this->i_flags & OBJECT_FLAGS_NODBG && i_type == VLC_MSG_DBG) ) + vlc_log_early_t *log = malloc(sizeof (*log)); + if (unlikely(log == NULL)) return; - msg_bank_t *bank = libvlc_bank (p_this->p_libvlc); - locale_t locale = uselocale (bank->locale); + log->next = NULL; + log->type = type; + log->meta.i_object_id = item->i_object_id; + /* NOTE: Object types MUST be static constant - no need to copy them. */ + log->meta.psz_object_type = item->psz_object_type; + log->meta.psz_module = item->psz_module; /* Ditto. */ + log->meta.psz_header = item->psz_header ? strdup(item->psz_header) : NULL; + + int canc = vlc_savecancel(); /* XXX: needed for vasprintf() ? */ + if (vasprintf(&log->msg, format, ap) == -1) + log->msg = NULL; + vlc_restorecancel(canc); + + vlc_mutex_lock(&sys->lock); + assert(sys->tailp != NULL); + assert(*(sys->tailp) == NULL); + *(sys->tailp) = log; + sys->tailp = &log->next; + vlc_mutex_unlock(&sys->lock); +} -#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; +static int vlc_LogEarlyOpen(vlc_logger_t *logger) +{ + vlc_logger_early_t *sys = malloc(sizeof (*sys)); - for( ;; ) - { - ptr = strchr( ptr, '%' ); - if( ptr == NULL ) - break; + if (unlikely(sys == NULL)) + return -1; - 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 */ - } + vlc_mutex_init(&sys->lock); + sys->head = NULL; + sys->tailp = &sys->head; - /* Looks for conversion specifier... */ - do - ptr++; - while( *ptr && ( strchr( "diouxXeEfFgGaAcspn%", *ptr ) == NULL ) ); - if( *ptr ) - ptr++; /* ...and skip it */ - } -#endif + logger->log = vlc_vaLogEarly; + logger->sys = sys; + return 0; +} - /* Convert message to string */ - vlc_va_copy( args, _args ); - if( vasprintf( &psz_str, psz_format, args ) == -1 ) - psz_str = NULL; - va_end( args ); +static void vlc_LogEarlyClose(libvlc_int_t *vlc, void *d) +{ + vlc_logger_early_t *sys = d; - if( psz_str == NULL ) + /* Drain early log messages */ + for (vlc_log_early_t *log = sys->head, *next; log != NULL; log = next) { - 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 ); -#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; + vlc_LogCallback(vlc, log->type, &log->meta, "%s", + (log->msg != NULL) ? log->msg : "message lost"); + free(log->msg); + next = log->next; + free(log); } - uselocale (locale); - msg_item_t * p_item = malloc (sizeof (*p_item)); - if (p_item == NULL) - return; /* Uho! */ + vlc_mutex_destroy(&sys->lock); + free(sys); +} - vlc_gc_init (p_item, msg_Free); - p_item->psz_module = p_item->psz_msg = p_item->psz_header = NULL; +static void vlc_vaLogDiscard(void *d, int type, const vlc_log_t *item, + const char *format, va_list ap) +{ + (void) d; (void) type; (void) item; (void) format; (void) ap; +} +/** + * Performs preinitialization of the messages logging subsystem. + * + * Early log messages will be stored in memory until the subsystem is fully + * initialized with vlc_LogInit(). This enables logging before the + * configuration and modules bank are ready. + * + * \return 0 on success, -1 on error. + */ +int vlc_LogPreinit(libvlc_int_t *vlc) +{ + vlc_logger_t *logger = vlc_custom_create(vlc, sizeof (*logger), "logger"); + libvlc_priv(vlc)->logger = logger; - i_header_size = 0; - p_obj = p_this; - while( p_obj != NULL ) - { - char *psz_old = NULL; - if( p_obj->psz_header ) - { - i_header_size += strlen( p_obj->psz_header ) + 4; - if( psz_header ) - { - psz_old = strdup( psz_header ); - psz_header = xrealloc( psz_header, i_header_size ); - snprintf( psz_header, i_header_size , "[%s] %s", - p_obj->psz_header, psz_old ); - } - else - { - psz_header = xmalloc( i_header_size ); - snprintf( psz_header, i_header_size, "[%s]", - p_obj->psz_header ); - } - } - free( psz_old ); - p_obj = p_obj->p_parent; - } + if (unlikely(logger == NULL)) + return -1; - /* Fill message information fields */ - p_item->i_type = i_type; - p_item->i_object_id = (uintptr_t)p_this; - p_item->psz_object_type = p_this->psz_object_type; - p_item->psz_module = strdup( psz_module ); - p_item->psz_msg = psz_str; - p_item->psz_header = psz_header; - - PrintMsg( p_this, p_item ); + vlc_rwlock_init(&logger->lock); - vlc_rwlock_rdlock (&bank->lock); - for (int i = 0; i < bank->i_sub; i++) + if (vlc_LogEarlyOpen(logger)) { - msg_subscription_t *sub = bank->pp_sub[i]; - sub->func (sub->opaque, p_item, 0); + logger->log = vlc_vaLogDiscard; + return -1; } - vlc_rwlock_unlock (&bank->lock); - msg_Release (p_item); + + /* 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); + return 0; } -/***************************************************************************** - * 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, msg_item_t * p_item ) +/** + * Initializes the messages logging subsystem and drain the early messages to + * the configured log. + * + * \return 0 on success, -1 on error. + */ +int vlc_LogInit(libvlc_int_t *vlc) { -# define COL(x) "\033[" #x ";1m" -# define RED COL(31) -# define GREEN COL(32) -# define YELLOW COL(33) -# define WHITE COL(0) -# define GRAY "\033[0m" - - static const char ppsz_type[4][9] = { "", " error", " warning", " debug" }; - static const char ppsz_color[4][8] = { WHITE, RED, YELLOW, GRAY }; - const char *psz_object; - libvlc_priv_t *priv = libvlc_priv (p_this->p_libvlc); - msg_bank_t *bank = priv->msg_bank; - int i_type = p_item->i_type; - - switch( i_type ) - { - case VLC_MSG_ERR: - if( priv->i_verbose < 0 ) return; - break; - case VLC_MSG_INFO: - if( priv->i_verbose < 0 ) return; - break; - case VLC_MSG_WARN: - if( priv->i_verbose < 1 ) return; - break; - case VLC_MSG_DBG: - if( priv->i_verbose < 2 ) return; - break; - } + vlc_logger_t *logger = libvlc_priv(vlc)->logger; + void *early_sys = NULL; + vlc_log_cb cb = PrintMsg; + signed char verbosity; + + if (unlikely(logger == NULL)) + return -1; + +#ifdef __ANDROID__ + cb = AndroidPrintMsg; +#elif defined (HAVE_ISATTY) && !defined (_WIN32) + if (isatty(STDERR_FILENO) && var_InheritBool(vlc, "color")) + cb = PrintColorMsg; +#endif - psz_object = p_item->psz_object_type; - 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")) + verbosity = -1; else { - val = vlc_dictionary_value_for_key (&bank->enabled_objects, - psz_object); - if( val == kObjectPrintingDisabled ) - return; - if( val == kObjectPrintingEnabled ) - /* Allowed */; - else if( !bank->all_objects_enabled ) - return; + const char *str = getenv("VLC_VERBOSE"); + + if (str == NULL || sscanf(str, "%hhd", &verbosity) < 1) + verbosity = var_InheritInteger(vlc, "verbose"); } - int canc = vlc_savecancel (); - /* Send the message to stderr */ - utf8_fprintf( stderr, "[%s%p%s] %s%s%s %s%s: %s%s%s\n", - priv->b_color ? GREEN : "", - (void *)p_item->i_object_id, - priv->b_color ? GRAY : "", - p_item->psz_header ? p_item->psz_header : "", - p_item->psz_header ? " " : "", - p_item->psz_module, psz_object, - ppsz_type[i_type], - priv->b_color ? ppsz_color[i_type] : "", - p_item->psz_msg, - priv->b_color ? GRAY : "" ); - -#ifdef WIN32 - fflush( stderr ); -#endif - vlc_restorecancel (canc); -} + vlc_rwlock_wrlock(&logger->lock); -static msg_context_t* GetContext(void) -{ - msg_context_t *p_ctx = vlc_threadvar_get( msg_context ); - if( p_ctx == NULL ) - { - p_ctx = malloc( sizeof( msg_context_t ) ); - if( !p_ctx ) - return NULL; - p_ctx->psz_message = NULL; - vlc_threadvar_set( msg_context, p_ctx ); - } - return p_ctx; + if (logger->log == vlc_vaLogEarly) + early_sys = logger->sys; + + logger->log = cb; + logger->sys = (void *)(intptr_t)verbosity; + vlc_rwlock_unlock(&logger->lock); + + if (early_sys != NULL) + vlc_LogEarlyClose(vlc, early_sys); + + return 0; } -void msg_StackSet( int i_code, const char *psz_message, ... ) +/** + * Sets the message logging callback. + * \param cb message callback, or NULL to clear + * \param data data pointer for the message callback + */ +void vlc_LogSet(libvlc_int_t *vlc, vlc_log_cb cb, void *opaque) { - va_list ap; - msg_context_t *p_ctx = GetContext(); + vlc_logger_t *logger = libvlc_priv(vlc)->logger; - if( p_ctx == NULL ) + if (unlikely(logger == NULL)) return; - free( p_ctx->psz_message ); - va_start( ap, psz_message ); - if( vasprintf( &p_ctx->psz_message, psz_message, ap ) == -1 ) - p_ctx->psz_message = NULL; - va_end( ap ); + if (cb == NULL) + cb = vlc_vaLogDiscard; - p_ctx->i_code = i_code; + vlc_rwlock_wrlock(&logger->lock); + logger->log = cb; + logger->sys = opaque; + vlc_rwlock_unlock(&logger->lock); + + /* 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); } -void msg_StackAdd( const char *psz_message, ... ) +void vlc_LogDeinit(libvlc_int_t *vlc) { - char *psz_tmp; - va_list ap; - msg_context_t *p_ctx = GetContext(); + vlc_logger_t *logger = libvlc_priv(vlc)->logger; - if( p_ctx == NULL ) + if (unlikely(logger == NULL)) return; - va_start( ap, psz_message ); - if( vasprintf( &psz_tmp, psz_message, ap ) == -1 ) - psz_tmp = NULL; - va_end( ap ); - - if( !p_ctx->psz_message ) - p_ctx->psz_message = psz_tmp; - else + /* Flush early log messages (corner case: no call to vlc_LogInit()) */ + if (logger->log == vlc_vaLogEarly) { - char *psz_new; - if( asprintf( &psz_new, "%s: %s", psz_tmp, p_ctx->psz_message ) == -1 ) - psz_new = NULL; - - free( p_ctx->psz_message ); - p_ctx->psz_message = psz_new; - free( psz_tmp ); + logger->log = vlc_vaLogDiscard; + vlc_LogEarlyClose(vlc, logger->sys); } -} -const char* msg_StackMsg( void ) -{ - msg_context_t *p_ctx = GetContext(); - assert( p_ctx ); - return p_ctx->psz_message; + vlc_rwlock_destroy(&logger->lock); + vlc_object_release(logger); }