]> git.sesse.net Git - vlc/blobdiff - src/interface/intf_msg.c
* ./src/interface/main.c: we no longer segfault if argc == 0.
[vlc] / src / interface / intf_msg.c
index 9d7539b80e76f5405edf1aa3897e4e1ddf1fa136..d17fa554d6bc9054beb6dea151c047218a5cb1fe 100644 (file)
@@ -3,8 +3,8 @@
  * This library provides basic functions for threads to interact with user
  * interface, such as message output. See config.h for output configuration.
  *****************************************************************************
- * Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: intf_msg.c,v 1.29 2001/04/25 06:56:47 benny Exp $
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: intf_msg.c,v 1.48 2002/04/24 00:36:24 sam Exp $
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
-#include "defs.h"
-
 #include <errno.h>                                                  /* errno */
 #include <fcntl.h>                     /* O_CREAT, O_TRUNC, O_WRONLY, O_SYNC */
 #include <stdio.h>                                               /* required */
 #include <stdarg.h>                                       /* va_list for BSD */
 #include <stdlib.h>                                              /* malloc() */
 #include <string.h>                                            /* strerror() */
-#include <unistd.h>                                      /* close(), write() */
 
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h"
-
-#include "intf_msg.h"
-#include "interface.h"
-#include "intf_console.h"
+#include <videolan/vlc.h>
 
-#include "main.h"
-
-/*****************************************************************************
- * intf_msg_item_t
- *****************************************************************************
- * Store a single message. Messages have a maximal size of INTF_MSG_MSGSIZE.
- * If DEBUG is defined, messages have a date field and debug messages are
- * printed with a date to allow more precise profiling.
- *****************************************************************************/
-typedef struct
-{
-    int     i_type;                               /* message type, see below */
-    char *  psz_msg;                                   /* the message itself */
-
-#ifdef DEBUG
-    /* Debugging informations - in DEBUG mode, debug messages have calling
-     * location informations printed */
-    mtime_t date;                                     /* date of the message */
-    char *  psz_file;               /* file in which the function was called */
-    char *  psz_function;     /* function from which the function was called */
-    int     i_line;                 /* line at which the function was called */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>                                      /* close(), write() */
 #endif
-} intf_msg_item_t;
 
-/* Message types */
-#define INTF_MSG_STD    0                                /* standard message */
-#define INTF_MSG_ERR    1                                   /* error message */
-#define INTF_MSG_INTF   2                               /* interface message */
-#define INTF_MSG_DBG    3                                   /* debug message */
-#define INTF_MSG_WARN   4                                  /* warning message*/
+#include "interface.h"
 
 
 /*****************************************************************************
@@ -83,44 +48,33 @@ typedef struct
  * Store all data requiered by messages interfaces. It has a single reference
  * int p_main.
  *****************************************************************************/
-typedef struct intf_msg_s
+typedef struct msg_bank_s
 {
-#ifdef INTF_MSG_QUEUE
+    /* Message queue lock */
+    vlc_mutex_t             lock;
+
     /* Message queue */
-    vlc_mutex_t             lock;                      /* message queue lock */
-    int                     i_count;            /* number of messages stored */
-    intf_msg_item_t         msg[INTF_MSG_QSIZE];            /* message queue */
-#endif
+    msg_item_t              msg[INTF_MSG_QSIZE];            /* message queue */
+    int i_start;
+    int i_stop;
 
-#ifdef DEBUG_LOG
-    /* Log file */
-    FILE *                  p_log_file;                          /* log file */
-#endif
+    /* Subscribers */
+    int i_sub;
+    intf_subscription_t **pp_sub;
 
-#if !defined(INTF_MSG_QUEUE) && !defined(DEBUG_LOG)
-    /* If neither messages queue, neither log file is used, then the structure
-     * is empty. However, empty structures are not allowed in C. Therefore, a
-     * dummy integer is used to fill it. */
-    int                     i_dummy;                        /* unused filler */
-#endif
-} intf_msg_t;
+} msg_bank_t;
+
+msg_bank_t msg_bank;
 
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
+static void QueueMsg ( int, int, char *, va_list );
+static void FlushMsg ( void );
 
-static void QueueMsg        ( intf_msg_t *p_msg, int i_type,
-                              char *psz_format, va_list ap );
-static void PrintMsg        ( intf_msg_item_t *p_msg );
-#ifdef DEBUG
-static void QueueDbgMsg     ( intf_msg_t *p_msg, char *psz_file,
-                              char *psz_function, int i_line,
-                              char *psz_format, va_list ap );
+#if defined( WIN32 )
+static char *ConvertPrintfFormatString ( char *psz_format );
 #endif
-#ifdef INTF_MSG_QUEUE
-static void FlushLockedMsg  ( intf_msg_t *p_msg );
-#endif
-
 
 /*****************************************************************************
  * intf_MsgCreate: initialize messages interface                         (ok ?)
@@ -128,33 +82,15 @@ static void FlushLockedMsg  ( intf_msg_t *p_msg );
  * This functions has to be called before any call to other intf_*Msg functions.
  * It set up the locks and the message queue if it is used.
  *****************************************************************************/
-p_intf_msg_t intf_MsgCreate( void )
+void intf_MsgCreate( void )
 {
-    p_intf_msg_t p_msg;
-
-    /* Allocate structure */
-    p_msg = malloc( sizeof( intf_msg_t ) );
-    if( p_msg == NULL )
-    {
-        errno = ENOMEM;
-    }
-    else
-    {
-#ifdef INTF_MSG_QUEUE
     /* Message queue initialization */
-    vlc_mutex_init( &p_msg->lock );                        /* intialize lock */
-    p_msg->i_count = 0;                                    /* queue is empty */
-#endif
+    vlc_mutex_init( &msg_bank.lock );
+    msg_bank.i_start = 0;
+    msg_bank.i_stop = 0;
 
-    
-#ifdef DEBUG_LOG
-        /* Log file initialization - on failure, file pointer will be null,
-         * and no log will be issued, but this is not considered as an
-         * error */
-        p_msg->p_log_file = fopen( DEBUG_LOG, "w" );
-#endif
-    }
-    return( p_msg );
+    msg_bank.i_sub = 0;
+    msg_bank.pp_sub = NULL;
 }
 
 /*****************************************************************************
@@ -166,189 +102,153 @@ p_intf_msg_t intf_MsgCreate( void )
  *****************************************************************************/
 void intf_MsgDestroy( void )
 {
-    intf_FlushMsg();                         /* print all remaining messages */
+    /* Destroy lock */
+    vlc_mutex_destroy( &msg_bank.lock );
 
-#ifdef DEBUG_LOG
-    /* Close log file if any */
-    if( p_main->p_msg->p_log_file != NULL )
+    if( msg_bank.i_sub )
     {
-        fclose( p_main->p_msg->p_log_file );
+        fprintf( stderr, "intf error: stale interface subscribers\n" );
     }
-#endif
 
-#ifdef INTF_MSG_QUEUE
-    /* destroy lock */
-    vlc_mutex_destroy( &p_main->p_msg->lock );
-#endif
-    
-    /* Free structure */
-    free( p_main->p_msg );
+    /* Free remaining messages */
+    FlushMsg( );
 }
 
 /*****************************************************************************
- * intf_Msg: print a message                                             (ok ?)
- *****************************************************************************
- * This function queue a message for later printing, or print it immediately
- * if the queue isn't used.
+ * intf_MsgSub: subscribe to the message queue.
  *****************************************************************************/
-void intf_Msg( char *psz_format, ... )
+intf_subscription_t *intf_MsgSub( void )
 {
-    va_list ap;
+    intf_subscription_t *p_sub = malloc( sizeof( intf_subscription_t ) );
 
-    va_start( ap, psz_format );
-    QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
-    va_end( ap );
-}
+    vlc_mutex_lock( &msg_bank.lock );
 
-/*****************************************************************************
- * intf_ErrMsg : print an error message                                  (ok ?)
- *****************************************************************************
- * This function is the same as intf_Msg, except that it prints its messages
- * on stderr.
- *****************************************************************************/
-void intf_ErrMsg( char *psz_format, ... )
-{
-    va_list ap;
+    /* Add subscription to the list */
+    msg_bank.i_sub++;
+    msg_bank.pp_sub = realloc( msg_bank.pp_sub,
+        msg_bank.i_sub * sizeof( intf_subscription_t* ) );
 
-    va_start( ap, psz_format );
-    QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
-    va_end( ap );
+    msg_bank.pp_sub[ msg_bank.i_sub - 1 ] = p_sub;
+
+    p_sub->i_start = msg_bank.i_start;
+    p_sub->pi_stop = &msg_bank.i_stop;
+
+    p_sub->p_msg   = msg_bank.msg;
+    p_sub->p_lock  = &msg_bank.lock;
+
+    vlc_mutex_unlock( &msg_bank.lock );
+
+    return p_sub;
 }
 
 /*****************************************************************************
- * intf_WarnMsg : print a warning message
- *****************************************************************************
- * This function is the same as intf_Msg, except that it concerns warning
- * messages for testing purpose.
+ * intf_MsgUnsub: unsubscribe from the message queue.
  *****************************************************************************/
-void intf_WarnMsg( int i_level, char *psz_format, ... )
+void intf_MsgUnsub( intf_subscription_t *p_sub )
 {
-    va_list ap;
-    
-    if( i_level >= p_main->i_warning_level )
+    int i_index;
+
+    vlc_mutex_lock( &msg_bank.lock );
+
+    /* Sanity check */
+    if( !msg_bank.i_sub )
     {
-        va_start( ap, psz_format );
-        QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
-        va_end( ap );
+        intf_ErrMsg( "intf error: no subscriber in the list" );
+        return;
     }
-}
 
+    /* Look for the appropriate subscription */
+    for( i_index = 0; i_index < msg_bank.i_sub; i_index++ )
+    {
+        if( msg_bank.pp_sub[ i_index ] == p_sub )
+        {
+            break;
+        }
+    }
 
-/*****************************************************************************
- * intf_IntfMsg : print an interface message                             (ok ?)
- *****************************************************************************
- * In opposition to all other intf_*Msg function, this function does not print
- * it's message on default terminal (stdout or stderr), but send it to
- * interface (in fact to the X11 console). This means that the interface MUST
- * be initialized and a X11 console openned before this function is used, and
- * that once the console is closed, this call is vorbidden.
- * Practically, only the interface thread itself should call this function, and
- * flush all messages before intf_CloseX11Console() is called.
- *****************************************************************************/
-void intf_IntfMsg(char *psz_format, ...)
-{
-    va_list ap;
+    if( msg_bank.pp_sub[ i_index ] != p_sub )
+    {
+        intf_ErrMsg( "intf error: subscriber not found" );
+        vlc_mutex_unlock( &msg_bank.lock );
+        return;
+    }
 
-    va_start( ap, psz_format );
-    QueueMsg( p_main->p_msg, INTF_MSG_INTF, psz_format, ap );
-    va_end( ap );
+    /* Remove this subscription */
+    for( ; i_index < (msg_bank.i_sub - 1); i_index++ )
+    {
+        msg_bank.pp_sub[ i_index ] = msg_bank.pp_sub[ i_index+1 ];
+    }
+
+    msg_bank.i_sub--;
+    msg_bank.pp_sub = realloc( msg_bank.pp_sub,
+        msg_bank.i_sub * sizeof( intf_subscription_t* ) );
+
+    vlc_mutex_unlock( &msg_bank.lock );
 }
 
 /*****************************************************************************
- * _intf_DbgMsg: print a debugging message                               (ok ?)
+ * intf_Msg: print a message                                             (ok ?)
  *****************************************************************************
- * This function prints a debugging message. Compared to other intf_*Msg
- * functions, it is only defined if DEBUG is defined and require a file name,
- * a function name and a line number as additionnal debugging informations. It
- * also prints a debugging header for each received line.
+ * This function queue a message for later printing, or print it immediately
+ * if the queue isn't used.
  *****************************************************************************/
-#ifdef DEBUG
-void _intf_DbgMsg( char *psz_file, char *psz_function, int i_line,
-                   char *psz_format, ...)
+void intf_Msg( char *psz_format, ... )
 {
     va_list ap;
 
     va_start( ap, psz_format );
-    QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
-                 psz_format, ap );
+    QueueMsg( INTF_MSG_STD, 0, psz_format, ap );
     va_end( ap );
 }
-#endif
 
 /*****************************************************************************
- * intf_MsgImm: print a message                                          (ok ?)
+ * intf_ErrMsg : print an error message                                  (ok ?)
  *****************************************************************************
- * This function prints a message immediately. If the queue is used, all
- * waiting messages are also printed.
+ * This function is the same as intf_Msg, except that it prints its messages
+ * on stderr.
  *****************************************************************************/
-void intf_MsgImm( char *psz_format, ... )
+void intf_ErrMsg( char *psz_format, ... )
 {
     va_list ap;
 
     va_start( ap, psz_format );
-    QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
+    QueueMsg( INTF_MSG_ERR, 0, psz_format, ap );
     va_end( ap );
-    intf_FlushMsg();
 }
 
 /*****************************************************************************
- * intf_ErrMsgImm: print an error message immediately                    (ok ?)
+ * intf_WarnMsg : print a warning message
  *****************************************************************************
- * This function is the same as intf_MsgImm, except that it prints its message
- * on stderr.
+ * This function is the same as intf_Msg, except that it concerns warning
+ * messages for testing purpose.
  *****************************************************************************/
-void intf_ErrMsgImm(char *psz_format, ...)
+void intf_WarnMsg( int i_level, char *psz_format, ... )
 {
     va_list ap;
-
+    
     va_start( ap, psz_format );
-    QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
+    QueueMsg( INTF_MSG_WARN, i_level, psz_format, ap );
     va_end( ap );
-    intf_FlushMsg();
 }
 
 /*****************************************************************************
- * intf_WarnMsgImm : print a warning message
+ * intf_StatMsg : print a statistic message
  *****************************************************************************
- * This function is the same as intf_MsgImm, except that it concerns warning
+ * This function is the same as intf_Msg, except that it concerns statistic
  * messages for testing purpose.
  *****************************************************************************/
-void intf_WarnMsgImm( int i_level, char *psz_format, ... )
+void intf_StatMsg( char *psz_format, ... )
 {
     va_list ap;
-
-    if( i_level >= p_main->i_warning_level )
+    
+    if( p_main->b_stats )
     {
         va_start( ap, psz_format );
-        QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
+        QueueMsg( INTF_MSG_STAT, 0, psz_format, ap );
         va_end( ap );
     }
-    intf_FlushMsg();
 }
 
-
-
-/*****************************************************************************
- * _intf_DbgMsgImm: print a debugging message immediately                (ok ?)
- *****************************************************************************
- * This function is the same as intf_DbgMsgImm, except that it prints its
- * message immediately. It should only be called through the macro
- * intf_DbgMsgImm().
- *****************************************************************************/
-#ifdef DEBUG
-void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
-                      char *psz_format, ...)
-{
-    va_list ap;
-
-    va_start( ap, psz_format );
-    QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
-                 psz_format, ap );
-    va_end( ap );
-    intf_FlushMsg();
-}
-#endif
-
 /*****************************************************************************
  * intf_WarnHexDump : print a hexadecimal dump of a memory area
  *****************************************************************************
@@ -386,42 +286,23 @@ void intf_WarnHexDump( int i_level, void *p_data, int i_size )
     intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
 }
 
-/*****************************************************************************
- * intf_FlushMsg                                                        (ok ?)
- *****************************************************************************
- * Print all messages remaining in queue: get lock and call FlushLockedMsg.
- * This function does nothing if the message queue isn't used.
- * This function is only implemented if message queue is used. If not, it is
- * an empty macro.
- *****************************************************************************/
-#ifdef INTF_MSG_QUEUE
-void intf_FlushMsg( void )
-{
-    vlc_mutex_lock( &p_main->p_msg->lock );                      /* get lock */
-    FlushLockedMsg( p_main->p_msg );                       /* flush messages */
-    vlc_mutex_unlock( &p_main->p_msg->lock );              /* give lock back */
-}
-#endif
-
 /* following functions are local */
 
 /*****************************************************************************
  * QueueMsg: add a message to a queue
  *****************************************************************************
- * This function provide basic functionnalities to other intf_*Msg functions.
- * It add 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 exit the
- * program. If the queue is not used, it prints the message immediately.
+ * This function provides basic functionnalities to other intf_*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.
  *****************************************************************************/
-static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list ap )
+static void QueueMsg( int i_type, int i_level, char *psz_format, va_list ap )
 {
     char *                  psz_str;             /* formatted message string */
-    intf_msg_item_t *       p_msg_item;                /* pointer to message */
-
-#ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
-    intf_msg_item_t         msg_item;                             /* message */
-    p_msg_item =           &msg_item;
-#endif /*....................................................................*/
+    msg_item_t *            p_item;                /* pointer to message */
+#ifdef WIN32
+    char *                  psz_temp;
+#endif
 
     /*
      * Convert message to string
@@ -431,241 +312,160 @@ static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list a
 #else
     psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
 #endif
+
     if( psz_str == NULL )
     {
-        fprintf(stderr, "warning: can't store following message (%s): ",
+        fprintf(stderr, "intf warning: can't store following message (%s): ",
                 strerror(errno) );
         vfprintf(stderr, psz_format, ap );
         fprintf(stderr, "\n" );
-        exit( errno );
+        return;
     }
-#ifdef HAVE_VASPRINTF
-#else
-    vsprintf( psz_str, psz_format, ap );
-#endif
 
-#ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
-    vlc_mutex_lock( &p_msg->lock );                              /* get lock */
-    if( p_msg->i_count == INTF_MSG_QSIZE )          /* flush queue if needed */
+#ifndef HAVE_VASPRINTF
+#   ifdef WIN32
+    psz_temp = ConvertPrintfFormatString(psz_format);
+    if( !psz_temp )
     {
-#ifdef DEBUG               /* in debug mode, queue overflow causes a warning */
-        fprintf(stderr, "warning: message queue overflow\n" );
-#endif
-        FlushLockedMsg( p_msg );
+        fprintf(stderr, "intf warning: couldn't print message");
+        return;
     }
-    p_msg_item = p_msg->msg + p_msg->i_count++;            /* select message */
-#endif /*.............................................. end of queue mode ...*/
-
-    /*
-     * Fill message information fields
-     */
-    p_msg_item->i_type =     i_type;
-    p_msg_item->psz_msg =    psz_str;
-#ifdef DEBUG    
-    p_msg_item->date =       mdate();
+    vsprintf( psz_str, psz_temp, ap );
+    free( psz_temp );
+#   else
+    vsprintf( psz_str, psz_format, ap );
+#   endif
 #endif
 
-#ifdef INTF_MSG_QUEUE /*......................................... queue mode */
-    vlc_mutex_unlock( &p_msg->lock );                      /* give lock back */
-#else /*....................................................... instant mode */
-    PrintMsg( p_msg_item );                                 /* print message */
-    free( psz_str );                                    /* free message data */
-#endif /*....................................................................*/
-}
-
-/*****************************************************************************
- * QueueDbgMsg: add a message to a queue with debugging informations
- *****************************************************************************
- * This function is the same as QueueMsg, except that it is only defined when
- * DEBUG is define, and require additionnal debugging informations.
- *****************************************************************************/
-#ifdef DEBUG
-static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
-                        int i_line, char *psz_format, va_list ap)
-{
-    char *                  psz_str;             /* formatted message string */
-    intf_msg_item_t *       p_msg_item;                /* pointer to message */
-
-#ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
-    intf_msg_item_t         msg_item;                             /* message */
-    p_msg_item =           &msg_item;
-#endif /*....................................................................*/
+    /* Put message in queue */
+    vlc_mutex_lock( &msg_bank.lock );
 
-    /*
-     * Convert message to string
-     */
-#ifdef HAVE_VASPRINTF
-    vasprintf( &psz_str, psz_format, ap );
-#else
-    psz_str = (char*) malloc( INTF_MAX_MSG_SIZE );
-    vsprintf( psz_str, psz_format, ap );
-#endif
-    if( psz_str == NULL )
+    /* Send the message to stderr */
+    if( i_level <= p_main->i_warning_level )
     {
-        fprintf(stderr, "warning: can't store following message (%s): ",
-                strerror(errno) );
-        fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
-        vfprintf(stderr, psz_format, ap );
-        fprintf(stderr, "\n" );
-        exit( errno );
+        fprintf( stderr, "%s\n", psz_str );
     }
 
-#ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
-    vlc_mutex_lock( &p_msg->lock );                              /* get lock */
-    if( p_msg->i_count == INTF_MSG_QSIZE )          /* flush queue if needed */
+    /* Put the message in the queue if there is room for it */
+    if( ((msg_bank.i_stop - msg_bank.i_start + 1) % INTF_MSG_QSIZE) == 0 )
     {
-        fprintf(stderr, "warning: message queue overflow\n" );
-        FlushLockedMsg( p_msg );
-    }
-    p_msg_item = p_msg->msg + p_msg->i_count++;            /* select message */
-#endif /*.............................................. end of queue mode ...*/
+        FlushMsg( );
 
-    /*
-     * Fill message information fields
-     */
-    p_msg_item->i_type =       INTF_MSG_DBG;
-    p_msg_item->psz_msg =      psz_str;
-    p_msg_item->psz_file =     psz_file;
-    p_msg_item->psz_function = psz_function;
-    p_msg_item->i_line =       i_line;
-    p_msg_item->date =         mdate();
-
-#ifdef INTF_MSG_QUEUE /*......................................... queue mode */
-    vlc_mutex_unlock( &p_msg->lock );                      /* give lock back */
-#else /*....................................................... instant mode */
-    PrintMsg( p_msg_item );                                 /* print message */
-    free( psz_str );                                    /* free message data */
-#endif /*....................................................................*/
-}
-#endif
+        if( ((msg_bank.i_stop - msg_bank.i_start + 1) % INTF_MSG_QSIZE) == 0 )
+        {
+            fprintf( stderr, "intf warning: message queue overflow\n" );
+            vlc_mutex_unlock( &msg_bank.lock );
+            return;
+        }
+    }
 
-/*****************************************************************************
- * FlushLockedMsg                                                       (ok ?)
- *****************************************************************************
- * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
- * this function does not check the lock. This function is only defined if
- * INTF_MSG_QUEUE is defined.
- *****************************************************************************/
-#ifdef INTF_MSG_QUEUE
-static void FlushLockedMsg ( intf_msg_t *p_msg )
-{
-    int i_index;
+    p_item = msg_bank.msg + msg_bank.i_stop;
+    msg_bank.i_stop = (msg_bank.i_stop + 1) % INTF_MSG_QSIZE;
 
-    for( i_index = 0; i_index < p_msg->i_count; i_index++ )
-    {
-        /* Print message and free message data */
-        PrintMsg( &p_msg->msg[i_index] );
-        free( p_msg->msg[i_index].psz_msg );
-    }
+    /* Fill message information fields */
+    p_item->i_type =     i_type;
+    p_item->psz_msg =    psz_str;
 
-    p_msg->i_count = 0;
+    vlc_mutex_unlock( &msg_bank.lock );
 }
-#endif
 
 /*****************************************************************************
- * PrintMsg: print a message                                             (ok ?)
+ * FlushMsg
  *****************************************************************************
- * Print a single message. The message data is not freed. This function exists
- * in two version. The DEBUG version prints a date with each message, and is
- * able to log messages (if DEBUG_LOG is defined).
- * The normal one just prints messages to the screen.
+ * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
+ * this function does not check the lock.
  *****************************************************************************/
-#ifdef DEBUG
-
-static void PrintMsg( intf_msg_item_t *p_msg )
+static void FlushMsg ( void )
 {
-    char    psz_date[MSTRTIME_MAX_SIZE];            /* formatted time buffer */
-    int     i_msg_len = MSTRTIME_MAX_SIZE + strlen(p_msg->psz_msg) + 200;
-    char    psz_msg[i_msg_len];                            /* message buffer */
+    int i_index, i_start, i_stop;
 
-    /* Format message - the message is formatted here because in case the log
-     * file is used, it avoids another format string parsing */
-    switch( p_msg->i_type )
-    {
-    case INTF_MSG_STD:                                   /* regular messages */
-    case INTF_MSG_ERR:
-        snprintf( psz_msg, i_msg_len, "%s", p_msg->psz_msg );
-        break;
-
-    case INTF_MSG_WARN:                                   /* Warning message */
-        mstrtime( psz_date, p_msg->date );
-        snprintf( psz_msg, i_msg_len, "(%s) %s",
-                  psz_date, p_msg->psz_msg );
-
-        break;
-        
-    case INTF_MSG_INTF:                                /* interface messages */
-        snprintf( psz_msg, i_msg_len, "%s", p_msg->psz_msg );
-        break;
-
-    case INTF_MSG_DBG:                                     /* debug messages */
-        mstrtime( psz_date, p_msg->date );
-        snprintf( psz_msg, i_msg_len, "(%s) " INTF_MSG_DBG_FORMAT "%s",
-                  psz_date, p_msg->psz_file, p_msg->psz_function, p_msg->i_line,
-                  p_msg->psz_msg );
-        break;
-    }
+    /* Get the maximum message index that can be freed */
+    i_stop = msg_bank.i_stop;
 
-    /* Check if formatting function succeeded */
-    if( psz_msg == NULL )
+    /* Check until which value we can free messages */
+    for( i_index = 0; i_index < msg_bank.i_sub; i_index++ )
     {
-        fprintf( stderr, "error: can not format message (%s): %s\n",
-                 strerror( errno ), p_msg->psz_msg );
-        return;
+        i_start = msg_bank.pp_sub[ i_index ]->i_start;
+
+        /* If this subscriber is late, we don't free messages before
+         * his i_start value, otherwise he'll miss messages */
+        if(   ( i_start < i_stop
+               && (msg_bank.i_stop <= i_start || i_stop <= msg_bank.i_stop) )
+           || ( i_stop < i_start
+               && (i_stop <= msg_bank.i_stop && msg_bank.i_stop <= i_start) ) )
+        {
+            i_stop = i_start;
+        }
     }
 
-    /*
-     * Print messages
-     */
-    switch( p_msg->i_type )
+    /* Free message data */
+    for( i_index = msg_bank.i_start;
+         i_index != i_stop;
+         i_index = (i_index+1) % INTF_MSG_QSIZE )
     {
-    case INTF_MSG_STD:                                  /* standard messages */
-        fprintf( stdout, "%s\n", psz_msg );
-        break;
-    case INTF_MSG_ERR:                                     /* error messages */
-    case INTF_MSG_WARN:
-#ifndef DEBUG_LOG_ONLY
-    case INTF_MSG_DBG:                                 /* debugging messages */
-#endif
-        fprintf( stderr, "%s\n", psz_msg );
-        break;
-    case INTF_MSG_INTF:                                /* interface messages */
-        intf_ConsolePrint( p_main->p_intf->p_console, psz_msg );
-        break;
+        free( msg_bank.msg[i_index].psz_msg );
     }
 
-#ifdef DEBUG_LOG
-    /* Append all messages to log file */
-    if( p_main->p_msg->p_log_file != NULL )
-    {
-        fwrite( psz_msg, strlen( psz_msg ), 1, p_main->p_msg->p_log_file );
-        fwrite( "\n", 1, 1, p_main->p_msg->p_log_file );
-    }
-#endif
+    /* Update the new start value */
+    msg_bank.i_start = i_index;
 }
 
-#else
-
-static void PrintMsg( intf_msg_item_t *p_msg )
+/*****************************************************************************
+ * ConvertPrintfFormatString: replace all occurrences of %ll with %I64 in the
+ *                            printf format string.
+ *****************************************************************************
+ * Win32 doesn't recognize the "%ll" format in a printf string, so we have
+ * to convert this string to something that win32 can handle.
+ * This is a REALLY UGLY HACK which won't even work in every situation,
+ * but hey I don't want to put an ifdef WIN32 each time I use printf with
+ * a "long long" type!!!
+ * By the way, if we don't do this we can sometimes end up with segfaults.
+ *****************************************************************************/
+#if defined( WIN32 )
+static char *ConvertPrintfFormatString( char *psz_format )
 {
-    /*
-     * Print messages on screen
-     */
-    switch( p_msg->i_type )
-    {
-    case INTF_MSG_STD:                                  /* standard messages */
-    case INTF_MSG_DBG:                                     /* debug messages */
-        fprintf( stdout, "%s\n", p_msg->psz_msg );
-        break;
-    case INTF_MSG_ERR:                                     /* error messages */
-    case INTF_MSG_WARN:
-        fprintf( stderr, "%s\n", p_msg->psz_msg );        /* warning message */
-        break;
-    case INTF_MSG_INTF:                                /* interface messages */
-        intf_ConsolePrint( p_main->p_intf->p_console, p_msg->psz_msg );
-        break;
-    }
+  int i, i_counter=0, i_pos=0;
+  char *psz_dest;
+
+  /* We first need to check how many occurences of %ll there are in the
+   * psz_format string. Once we'll know that we'll be able to malloc the
+   * destination string */
+
+  if( strlen( psz_format ) <= 3 )
+      return strdup( psz_format );
+
+  for( i=0; i <= (strlen(psz_format) - 3); i++ )
+  {
+      if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
+      {
+          i_counter++;
+      }
+  }
+
+  /* malloc the destination string */
+  psz_dest = malloc( strlen(psz_format) + i_counter + 1 );
+  if( psz_dest == NULL )
+  {
+      fprintf( stderr, "intf warning: ConvertPrintfFormatString failed\n");
+      return NULL;
+  }
+
+  /* Now build the modified string */
+  i_counter = 0;
+  for( i=0; i <= (strlen(psz_format) - 3); i++ )
+  {
+      if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
+      {
+          memcpy( psz_dest+i_pos+i_counter, psz_format+i_pos, i-i_pos+1);
+          *(psz_dest+i+i_counter+1)='I';
+          *(psz_dest+i+i_counter+2)='6';
+          *(psz_dest+i+i_counter+3)='4';
+          i_pos = i+3;
+          i_counter++;
+      }
+  }
+  strcpy( psz_dest+i_pos+i_counter, psz_format+i_pos );
+
+  return psz_dest;
 }
-
 #endif
-