messages.c 21.6 KB
Newer Older
1
/*****************************************************************************
2
3
 * messages.c: messages interface
 * 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
 *****************************************************************************
Jean-Paul Saman's avatar
Jean-Paul Saman committed
6
 * Copyright (C) 1998-2005 the VideoLAN team
zorglub's avatar
zorglub committed
7
 * $Id$
8
 *
Sam Hocevar's avatar
   
Sam Hocevar committed
9
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
10
 *          Samuel Hocevar <sam@zoy.org>
11
12
13
14
15
 *
 * 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
 * (at your option) any later version.
16
 *
17
18
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
21
 *
22
23
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
26

27
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
28
 * Preamble
29
 *****************************************************************************/
30
31
32

#include <vlc/vlc.h>

33
#include <stdarg.h>                                       /* va_list for BSD */
Sam Hocevar's avatar
   
Sam Hocevar committed
34

35
36
37
38
#ifdef HAVE_FCNTL_H
#   include <fcntl.h>                  /* O_CREAT, O_TRUNC, O_WRONLY, O_SYNC */
#endif

39
#include <errno.h>                                                  /* errno */
40

Sam Hocevar's avatar
   
Sam Hocevar committed
41
#ifdef HAVE_UNISTD_H
42
#   include <unistd.h>                                   /* close(), write() */
Sam Hocevar's avatar
   
Sam Hocevar committed
43
#endif
Michel Kaempf's avatar
Michel Kaempf committed
44

45
46
#include <assert.h>

zorglub's avatar
zorglub committed
47
#include <vlc_charset.h>
48

49
50
51
52
53
54
55
56
57
58
59
/*****************************************************************************
 * 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

60
61
62
#define QUEUE(i) p_this->p_libvlc->msg_bank.queues[i]
#define LOCK_BANK vlc_mutex_lock( &p_this->p_libvlc->msg_bank.lock );
#define UNLOCK_BANK vlc_mutex_unlock( &p_this->p_libvlc->msg_bank.lock );
63

Vincent Seguin's avatar
Vincent Seguin committed
64
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
65
 * Local prototypes
Vincent Seguin's avatar
Vincent Seguin committed
66
 *****************************************************************************/
67
static void QueueMsg ( vlc_object_t *, int, int , const char *,
68
                       const char *, va_list );
69
static void FlushMsg ( msg_queue_t * );
70
static void PrintMsg ( vlc_object_t *, msg_item_t * );
Michel Kaempf's avatar
Michel Kaempf committed
71

sigmunau's avatar
all:    
sigmunau committed
72
/**
73
74
 * Initialize messages queues
 * This function initializes all message queues
sigmunau's avatar
all:    
sigmunau committed
75
 */
76
void __msg_Create( vlc_object_t *p_this )
Michel Kaempf's avatar
Michel Kaempf committed
77
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
78
    int i;
79
    vlc_mutex_init( p_this, &(p_this->p_libvlc->msg_bank.lock) );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
80

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
81
82
83
84
85
86
87
88
89
90
    for( i = 0; i < 2; i++ )
    {
         vlc_mutex_init( p_this, &QUEUE(i).lock );
         QUEUE(i).b_overflow = VLC_FALSE;
         QUEUE(i).i_id = i;
         QUEUE(i).i_start = 0;
         QUEUE(i).i_stop = 0;
         QUEUE(i).i_sub = 0;
         QUEUE(i).pp_sub = 0;
    }
91
92

#ifdef UNDER_CE
93
    QUEUE(MSG_QUEUE_NORMAL).logfile =
94
95
        CreateFile( L"vlc-log.txt", GENERIC_WRITE,
                    FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
96
                    CREATE_ALWAYS, 0, NULL );
97
    SetFilePointer( QUEUE(MSG_QUEUE_NORMAL).logfile, 0, NULL, FILE_END );
98
#endif
Michel Kaempf's avatar
Michel Kaempf committed
99
100
}

sigmunau's avatar
all:    
sigmunau committed
101
/**
102
 * Flush all message queues
sigmunau's avatar
all:    
sigmunau committed
103
 */
104
105
void __msg_Flush( vlc_object_t *p_this )
{
106
    int i;
107
    for( i = 0 ; i < NB_QUEUES ; i++ )
108
    {
109
110
111
        vlc_mutex_lock( &QUEUE(i).lock );
        FlushMsg( &QUEUE(i) );
        vlc_mutex_unlock( &QUEUE(i).lock );
112
113
114
    }
}

sigmunau's avatar
all:    
sigmunau committed
115
/**
116
 * Destroy the message queues
sigmunau's avatar
all:    
sigmunau committed
117
 *
118
 * This functions prints all messages remaining in the queues,
119
 * then frees all the allocated ressources
Michel Kaempf's avatar
Michel Kaempf committed
120
 * No other messages interface functions should be called after this one.
sigmunau's avatar
all:    
sigmunau committed
121
 */
122
void __msg_Destroy( vlc_object_t *p_this )
Michel Kaempf's avatar
Michel Kaempf committed
123
{
124
    int i;
125
    for( i = NB_QUEUES -1 ; i >= 0;  i-- )
126
    {
127
        if( QUEUE(i).i_sub )
128
            msg_Err( p_this, "stale interface subscribers" );
129
130

        FlushMsg( &QUEUE(i) );
131

132
#ifdef UNDER_CE
hartman's avatar
hartman committed
133
        if( i == MSG_QUEUE_NORMAL )
134
            CloseHandle( QUEUE(MSG_QUEUE_NORMAL).logfile );
135
#endif
136
        /* Destroy lock */
137
        vlc_mutex_destroy( &QUEUE(i).lock );
138
    }
139
    vlc_mutex_destroy( &(p_this->p_libvlc->msg_bank.lock) );
Sam Hocevar's avatar
   
Sam Hocevar committed
140
141
}

sigmunau's avatar
all:    
sigmunau committed
142
/**
143
 * Subscribe to a message queue.
sigmunau's avatar
all:    
sigmunau committed
144
 */
145
msg_subscription_t *__msg_Subscribe( vlc_object_t *p_this, int i )
Sam Hocevar's avatar
   
Sam Hocevar committed
146
{
147
    msg_subscription_t *p_sub = malloc( sizeof( msg_subscription_t ) );
148

149
    assert( i < NB_QUEUES );
150

151
152
    LOCK_BANK;
    vlc_mutex_lock( &QUEUE(i).lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
153

154
    TAB_APPEND( QUEUE(i).i_sub, QUEUE(i).pp_sub, p_sub );
Sam Hocevar's avatar
   
Sam Hocevar committed
155

156
157
158
159
    p_sub->i_start = QUEUE(i).i_start;
    p_sub->pi_stop = &QUEUE(i).i_stop;
    p_sub->p_msg   = QUEUE(i).msg;
    p_sub->p_lock  = &QUEUE(i).lock;
Sam Hocevar's avatar
   
Sam Hocevar committed
160

161
162
    vlc_mutex_unlock( &QUEUE(i).lock );
    UNLOCK_BANK;
Sam Hocevar's avatar
   
Sam Hocevar committed
163
164
165
166

    return p_sub;
}

sigmunau's avatar
all:    
sigmunau committed
167
/**
168
 * Unsubscribe from a message queue.
sigmunau's avatar
all:    
sigmunau committed
169
 */
170
void __msg_Unsubscribe( vlc_object_t *p_this, msg_subscription_t *p_sub )
Sam Hocevar's avatar
   
Sam Hocevar committed
171
{
172
    int i,j;
Sam Hocevar's avatar
   
Sam Hocevar committed
173

174
175
    LOCK_BANK;
    for( i = 0 ; i< NB_QUEUES ; i++ )
Sam Hocevar's avatar
   
Sam Hocevar committed
176
    {
177
178
        vlc_mutex_lock( &QUEUE(i).lock );
        for( j = 0 ; j< QUEUE(i).i_sub ; j++ )
Sam Hocevar's avatar
   
Sam Hocevar committed
179
        {
180
            if( QUEUE(i).pp_sub[j] == p_sub )
181
            {
182
                REMOVE_ELEM( QUEUE(i).pp_sub, QUEUE(i).i_sub, j );
183
184
                if( p_sub ) free( p_sub );
            }
Sam Hocevar's avatar
   
Sam Hocevar committed
185
        }
186
        vlc_mutex_unlock( & QUEUE(i).lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
187
    }
188
    UNLOCK_BANK;
Michel Kaempf's avatar
Michel Kaempf committed
189
190
}

191
192
193
194
const char *msg_GetObjectTypeName(int i_object_type )
{
    switch( i_object_type )
    {
195
        case VLC_OBJECT_GLOBAL: return "global";
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
        case VLC_OBJECT_LIBVLC: return "libvlc";
        case VLC_OBJECT_MODULE: return "module";
        case VLC_OBJECT_INTF: return "interface";
        case VLC_OBJECT_PLAYLIST: return "playlist";
        case VLC_OBJECT_ITEM: return "item";
        case VLC_OBJECT_INPUT: return "input";
        case VLC_OBJECT_DECODER: return "decoder";
        case VLC_OBJECT_PACKETIZER: return "packetizer";
        case VLC_OBJECT_ENCODER: return "encoder";
        case VLC_OBJECT_VOUT: return "video output";
        case VLC_OBJECT_AOUT: return "audio output";
        case VLC_OBJECT_SOUT: return "stream output";
        case VLC_OBJECT_HTTPD: return "http server";
        case VLC_OBJECT_HTTPD_HOST: return "http server";
        case VLC_OBJECT_DIALOGS: return "dialogs provider";
        case VLC_OBJECT_VLM: return "vlm";
        case VLC_OBJECT_ANNOUNCE: return "announce handler";
        case VLC_OBJECT_DEMUX: return "demuxer";
        case VLC_OBJECT_ACCESS: return "access";
        case VLC_OBJECT_META_ENGINE: return "meta engine";
        default: return "private";
    }
}

220
/*****************************************************************************
221
 * __msg_*: print a message
222
 *****************************************************************************
223
 * These functions queue a message for later printing.
224
 *****************************************************************************/
225
void __msg_Generic( vlc_object_t *p_this, int i_queue, int i_type,
226
                    const char *psz_module,
227
                    const char *psz_format, ... )
Michel Kaempf's avatar
Michel Kaempf committed
228
{
229
    va_list args;
Michel Kaempf's avatar
Michel Kaempf committed
230

231
    va_start( args, psz_format );
232
    QueueMsg( p_this, i_queue, i_type, psz_module, psz_format, args );
233
    va_end( args );
Michel Kaempf's avatar
Michel Kaempf committed
234
}
235

236
void __msg_GenericVa( vlc_object_t *p_this, int i_queue,
237
                      int i_type, const char *psz_module,
238
239
                      const char *psz_format, va_list args )
{
240
    QueueMsg( p_this, i_queue, i_type, psz_module, psz_format, args );
241
242
}

243
244
/* Generic functions used when variadic macros are not available. */
#define DECLARE_MSG_FN( FN_NAME, FN_TYPE ) \
sigmunau's avatar
all:    
sigmunau committed
245
    void FN_NAME( vlc_object_t *p_this, const char *psz_format, ... ) \
246
247
248
    { \
        va_list args; \
        va_start( args, psz_format ); \
249
        QueueMsg( (vlc_object_t *)p_this,MSG_QUEUE_NORMAL, FN_TYPE, "unknown", \
250
251
                  psz_format, args ); \
        va_end( args ); \
252
253
    } \
    struct _
sigmunau's avatar
all:    
sigmunau committed
254
255
256
257
258
/**
 * Output an informational message.
 * \note Do not use this for debug messages
 * \see input_AddInfo
 */
259
DECLARE_MSG_FN( __msg_Info, VLC_MSG_INFO );
sigmunau's avatar
all:    
sigmunau committed
260
261
262
/**
 * Output an error message.
 */
263
DECLARE_MSG_FN( __msg_Err,  VLC_MSG_ERR );
sigmunau's avatar
all:    
sigmunau committed
264
265
266
/**
 * Output a waring message
 */
267
DECLARE_MSG_FN( __msg_Warn, VLC_MSG_WARN );
sigmunau's avatar
all:    
sigmunau committed
268
269
270
/**
 * Output a debug message
 */
271
DECLARE_MSG_FN( __msg_Dbg,  VLC_MSG_DBG );
Michel Kaempf's avatar
Michel Kaempf committed
272

sigmunau's avatar
all:    
sigmunau committed
273
274
275
/**
 * Add a message to a queue
 *
276
 * This function provides basic functionnalities to other msg_* functions.
277
278
279
 * 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.
sigmunau's avatar
all:    
sigmunau committed
280
 */
281
static void QueueMsg( vlc_object_t *p_this, int i_queue, int i_type,
282
                      const char *psz_module,
283
                      const char *psz_format, va_list _args )
Michel Kaempf's avatar
Michel Kaempf committed
284
{
285
    int         i_header_size;             /* Size of the additionnal header */
286
    vlc_object_t *p_obj;
287
    char *       psz_str = NULL;                 /* formatted message string */
288
    char *       psz_header = NULL;
289
    va_list      args;
290
291
    msg_item_t * p_item = NULL;                        /* pointer to message */
    msg_item_t   item;                    /* message in case of a full queue */
292
    msg_queue_t *p_queue;
gbazin's avatar
   
gbazin committed
293

294
#if !defined(HAVE_VASPRINTF) || defined(__APPLE__) || defined(SYS_BEOS)
295
    int          i_size = strlen(psz_format) + INTF_MAX_MSG_SIZE;
296
#endif
Vincent Seguin's avatar
Vincent Seguin committed
297

298
    if( p_this == NULL || p_this->i_flags & OBJECT_FLAGS_QUIET ||
299
        (p_this->i_flags & OBJECT_FLAGS_NODBG && i_type == VLC_MSG_DBG) )
300
301
302
303
    {
        return;
    }

304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
#ifndef __GLIBC__
    /* Expand %m to strerror(errno) - only once */
    char buf[strlen( psz_format ) + 2001], *ptr;
    strcpy( buf, psz_format );
    ptr = psz_format = buf;

    for( ;; )
    {
        ptr = strchr( ptr, '%' );
        if( ptr == NULL )
            break;

        if( ptr[1] == 'm' )
        {
            char errbuf[2001];
            size_t errlen;

321
#ifndef WIN32
322
            strerror_r( errno, errbuf, 1001 );
323
324
325
326
327
328
329
330
331
332
#else
            int sockerr = WSAGetLastError( );
            if( sockerr )
            {
                strncpy( errbuf, net_strerror( sockerr ), 1001 );
                WSASetLastError( sockerr );
            }
            else
                strncpy( errbuf, strerror( errno ), 1001 );
#endif
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
            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 */
        }

        /* Looks for conversion specifier... */
        do
            ptr++;
        while( *ptr && ( strchr( "diouxXeEfFgGaAcspn%", *ptr ) == NULL ) );
        if( *ptr )
            ptr++; /* ...and skip it */
    }
#endif

358
    /* Convert message to string  */
359
#if defined(HAVE_VASPRINTF) && !defined(__APPLE__) && !defined( SYS_BEOS )
360
    vlc_va_copy( args, _args );
361
362
    if( vasprintf( &psz_str, psz_format, args ) == -1 )
        psz_str = NULL;
363
    va_end( args );
Sam Hocevar's avatar
   
Sam Hocevar committed
364
#else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
365
    psz_str = (char*) malloc( i_size );
366
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
367

Michel Kaempf's avatar
Michel Kaempf committed
368
369
    if( psz_str == NULL )
    {
370
        fputs( "main warning: no memory to store message): ", stderr );
371
        vlc_va_copy( args, _args );
372
        /* We should use utf8_vfprintf - but it calls malloc()... */
373
        vfprintf( stderr, psz_format, args );
374
        va_end( args );
375
        fputs( "\n", stderr );
376
        return;
Michel Kaempf's avatar
Michel Kaempf committed
377
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
378

379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
    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 = (char*)realloc( psz_header, i_header_size );
                snprintf( psz_header, i_header_size , "[%s] %s",
                          p_obj->psz_header, psz_old );
            }
            else
            {
                psz_header = (char *)malloc( i_header_size );
                snprintf( psz_header, i_header_size, "[%s]",
                          p_obj->psz_header );
            }
        }
        if( psz_old ) free( psz_old );
        p_obj = p_obj->p_parent;
    }

405
#if !defined(HAVE_VASPRINTF) || defined(__APPLE__) || defined(SYS_BEOS)
406
    vlc_va_copy( args, _args );
407
    vsnprintf( psz_str, i_size, psz_format, args );
408
    va_end( args );
409
    psz_str[ i_size - 1 ] = 0; /* Just in case */
410
#endif
Vincent Seguin's avatar
Vincent Seguin committed
411

412
413
414
    assert( i_queue < NB_QUEUES );
    LOCK_BANK;
    p_queue = &QUEUE(i_queue) ;
415
    vlc_mutex_lock( &p_queue->lock );
Vincent Seguin's avatar
Vincent Seguin committed
416

417
    /* Check there is room in the queue for our message */
418
    if( p_queue->b_overflow )
419
    {
420
        FlushMsg( p_queue );
421

422
        if( ((p_queue->i_stop - p_queue->i_start + 1) % VLC_MSG_QSIZE) == 0 )
423
424
425
426
427
428
429
        {
            /* Still in overflow mode, print from a dummy item */
            p_item = &item;
        }
        else
        {
            /* Pheeew, at last, there is room in the queue! */
430
            p_queue->b_overflow = VLC_FALSE;
431
432
        }
    }
433
    else if( ((p_queue->i_stop - p_queue->i_start + 2) % VLC_MSG_QSIZE) == 0 )
Vincent Seguin's avatar
Vincent Seguin committed
434
    {
435
        FlushMsg( p_queue );
Michel Kaempf's avatar
Michel Kaempf committed
436

437
        if( ((p_queue->i_stop - p_queue->i_start + 2) % VLC_MSG_QSIZE) == 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
438
        {
439
440
441
442
443
444
445
446
447
448
449
450
451
            p_queue->b_overflow = VLC_TRUE;

            if( p_queue->i_id == MSG_QUEUE_NORMAL )
            {
               /* Put the overflow message in the queue */
                p_item = p_queue->msg + p_queue->i_stop;
                p_queue->i_stop = (p_queue->i_stop + 1) % VLC_MSG_QSIZE;

                p_item->i_type =        VLC_MSG_WARN;
                p_item->i_object_id =   p_this->i_object_id;
                p_item->i_object_type = p_this->i_object_type;
                p_item->psz_module =    strdup( "message" );
                p_item->psz_msg =       strdup( "message queue overflowed" );
452
                p_item->psz_header =    NULL;
453
454
455
456
457

               PrintMsg( p_this, p_item );
               /* We print from a dummy item */
               p_item = &item;
            }
Sam Hocevar's avatar
   
Sam Hocevar committed
458
        }
Michel Kaempf's avatar
Michel Kaempf committed
459
460
    }

461
    if( !p_queue->b_overflow )
462
463
    {
        /* Put the message in the queue */
464
465
        p_item = p_queue->msg + p_queue->i_stop;
        p_queue->i_stop = (p_queue->i_stop + 1) % VLC_MSG_QSIZE;
466
    }
Michel Kaempf's avatar
Michel Kaempf committed
467

Sam Hocevar's avatar
   
Sam Hocevar committed
468
    /* Fill message information fields */
469
470
471
472
473
    p_item->i_type =        i_type;
    p_item->i_object_id =   p_this->i_object_id;
    p_item->i_object_type = p_this->i_object_type;
    p_item->psz_module =    strdup( psz_module );
    p_item->psz_msg =       psz_str;
474
    p_item->psz_header =    psz_header;
475

476
477
    if( p_queue->i_id == MSG_QUEUE_NORMAL )
        PrintMsg( p_this, p_item );
Michel Kaempf's avatar
Michel Kaempf committed
478

479
    if( p_queue->b_overflow )
480
    {
Jean-Paul Saman's avatar
Jean-Paul Saman committed
481
482
483
484
        if( p_item->psz_module )
            free( p_item->psz_module );
        if( p_item->psz_msg )
            free( p_item->psz_msg );
485
486
        if( p_item->psz_header )
            free( p_item->psz_header );
487
488
    }

489
    vlc_mutex_unlock ( &p_queue->lock );
490
    UNLOCK_BANK;
Michel Kaempf's avatar
Michel Kaempf committed
491
492
}

493
494
/* following functions are local */

495
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
496
 * FlushMsg
497
 *****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
498
499
 * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
 * this function does not check the lock.
500
 *****************************************************************************/
501
static void FlushMsg ( msg_queue_t *p_queue )
Michel Kaempf's avatar
Michel Kaempf committed
502
{
Sam Hocevar's avatar
   
Sam Hocevar committed
503
    int i_index, i_start, i_stop;
Sam Hocevar's avatar
   
Sam Hocevar committed
504

Sam Hocevar's avatar
   
Sam Hocevar committed
505
    /* Get the maximum message index that can be freed */
506
    i_stop = p_queue->i_stop;
Sam Hocevar's avatar
   
Sam Hocevar committed
507

Sam Hocevar's avatar
   
Sam Hocevar committed
508
    /* Check until which value we can free messages */
509
    for( i_index = 0; i_index < p_queue->i_sub; i_index++ )
Sam Hocevar's avatar
   
Sam Hocevar committed
510
    {
511
        i_start = p_queue->pp_sub[ i_index ]->i_start;
Sam Hocevar's avatar
   
Sam Hocevar committed
512
513
514
515

        /* 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
516
               && (p_queue->i_stop <= i_start || i_stop <= p_queue->i_stop) )
Sam Hocevar's avatar
   
Sam Hocevar committed
517
           || ( i_stop < i_start
518
               && (i_stop <= p_queue->i_stop && p_queue->i_stop <= i_start) ) )
Sam Hocevar's avatar
   
Sam Hocevar committed
519
520
521
        {
            i_stop = i_start;
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
522
    }
523

Sam Hocevar's avatar
   
Sam Hocevar committed
524
    /* Free message data */
525
    for( i_index = p_queue->i_start;
Sam Hocevar's avatar
   
Sam Hocevar committed
526
         i_index != i_stop;
527
         i_index = (i_index+1) % VLC_MSG_QSIZE )
Michel Kaempf's avatar
Michel Kaempf committed
528
    {
529
530
531
532
        if( p_queue->msg[i_index].psz_msg )
            free( p_queue->msg[i_index].psz_msg );
        if( p_queue->msg[i_index].psz_module )
            free( p_queue->msg[i_index].psz_module );
533
534
        if( p_queue->msg[i_index].psz_header )
            free( p_queue->msg[i_index].psz_header );
535
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
536

Sam Hocevar's avatar
   
Sam Hocevar committed
537
    /* Update the new start value */
538
    p_queue->i_start = i_index;
Sam Hocevar's avatar
   
Sam Hocevar committed
539
}
gbazin's avatar
   
gbazin committed
540

541
/*****************************************************************************
542
 * PrintMsg: output a standard message item to stderr
543
544
545
546
547
548
549
550
551
552
553
554
 *****************************************************************************
 * Print a message to stderr, with colour formatting if needed.
 *****************************************************************************/
static void PrintMsg ( vlc_object_t * p_this, msg_item_t * p_item )
{
#   define COL(x)  "\033[" #x ";1m"
#   define RED     COL(31)
#   define GREEN   COL(32)
#   define YELLOW  COL(33)
#   define WHITE   COL(37)
#   define GRAY    "\033[0m"

555
556
557
#ifdef UNDER_CE
    int i_dummy;
#endif
558
    static const char * ppsz_type[4] = { "", " error", " warning", " debug" };
zorglub's avatar
zorglub committed
559
    static const char *ppsz_color[4] = { WHITE, RED, YELLOW, GRAY };
560
    const char *psz_object;
561
562
    int i_type = p_item->i_type;

563
    switch( i_type )
564
    {
565
        case VLC_MSG_ERR:
566
            if( p_this->p_libvlc->i_verbose < 0 ) return;
567
568
            break;
        case VLC_MSG_INFO:
569
            if( p_this->p_libvlc->i_verbose < 0 ) return;
570
571
            break;
        case VLC_MSG_WARN:
572
            if( p_this->p_libvlc->i_verbose < 1 ) return;
573
574
            break;
        case VLC_MSG_DBG:
575
            if( p_this->p_libvlc->i_verbose < 2 ) return;
576
            break;
577
578
    }

579
    psz_object = msg_GetObjectTypeName(p_item->i_object_type);
580

581
#ifdef UNDER_CE
582
#   define CE_WRITE(str) WriteFile( QUEUE(MSG_QUEUE_NORMAL).logfile, \
583
584
585
586
587
588
589
                                    str, strlen(str), &i_dummy, NULL );
    CE_WRITE( p_item->psz_module );
    CE_WRITE( " " );
    CE_WRITE( psz_object );
    CE_WRITE( ppsz_type[i_type] );
    CE_WRITE( ": " );
    CE_WRITE( p_item->psz_msg );
590
    CE_WRITE( "\r\n" );
591
    FlushFileBuffers( QUEUE(MSG_QUEUE_NORMAL).logfile );
592
593

#else
594
    /* Send the message to stderr */
595
    if( p_this->p_libvlc->b_color )
596
    {
597
598
        if( p_item->psz_header )
        {
599
            utf8_fprintf( stderr, "[" GREEN "%.8i" GRAY "] %s %s %s%s: %s%s" GRAY
600
601
602
603
604
605
606
607
                              "\n",
                         p_item->i_object_id, p_item->psz_header,
                         p_item->psz_module, psz_object,
                         ppsz_type[i_type], ppsz_color[i_type],
                         p_item->psz_msg );
        }
        else
        {
608
             utf8_fprintf( stderr, "[" GREEN "%.8i" GRAY "] %s %s%s: %s%s" GRAY "\n",
609
                         p_item->i_object_id, p_item->psz_module, psz_object,
610
                         ppsz_type[i_type], ppsz_color[i_type],
zorglub's avatar
zorglub committed
611
                         p_item->psz_msg );
612
        }
613
614
615
    }
    else
    {
616
617
        if( p_item->psz_header )
        {
618
            utf8_fprintf( stderr, "[%.8i] %s %s %s%s: %s\n", p_item->i_object_id,
619
620
621
622
623
                         p_item->psz_header, p_item->psz_module,
                         psz_object, ppsz_type[i_type], p_item->psz_msg );
        }
        else
        {
624
            utf8_fprintf( stderr, "[%.8i] %s %s%s: %s\n", p_item->i_object_id,
625
                         p_item->psz_module, psz_object, ppsz_type[i_type],
626
                         p_item->psz_msg );
627
        }
628
    }
629

630
#   if defined(WIN32)
631
    fflush( stderr );
632
#   endif
633
#endif
634
}
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652

static msg_context_t* GetContext(void)
{
    msg_context_t *p_ctx = vlc_threadvar_get( &msg_context_global_key );
    if( p_ctx == NULL )
    {
        MALLOC_NULL( p_ctx, msg_context_t );
        p_ctx->psz_message = NULL;
        vlc_threadvar_set( &msg_context_global_key, p_ctx );
    }
    return p_ctx;
}

void msg_StackSet( int i_code, const char *psz_message, ... )
{
    va_list ap;
    msg_context_t *p_ctx = GetContext();
    assert( p_ctx );
653

654
    va_start( ap, psz_message );
655
    free( p_ctx->psz_message );
656

657
658
    if( vasprintf( &p_ctx->psz_message, psz_message, ap ) == -1 )
        p_ctx->psz_message = NULL;
659
    va_end( ap );
660

661
662
663
664
665
666
667
668
669
670
671
    p_ctx->i_code = i_code;
}

void msg_StackAdd( const char *psz_message, ... )
{
    char *psz_tmp;
    va_list ap;
    msg_context_t *p_ctx = GetContext();
    assert( p_ctx );

    va_start( ap, psz_message );
672
673
    if( vasprintf( &psz_tmp, psz_message, ap ) == -1 )
        psz_tmp = NULL;
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
    va_end( ap );

    if( !p_ctx->psz_message )
        p_ctx->psz_message = psz_tmp;
    else
    {
        char *psz_old = malloc( strlen( p_ctx->psz_message ) + 1 );
        memcpy( psz_old, p_ctx->psz_message, strlen( p_ctx->psz_message ) + 1 );
        p_ctx->psz_message = realloc( p_ctx->psz_message,
                                      strlen( p_ctx->psz_message ) +
                                      /* ':', ' ', '0' */
                                      strlen( psz_tmp ) + 3 );
        sprintf( p_ctx->psz_message, "%s: %s", psz_tmp, psz_old );
        free( psz_tmp ); free( psz_old );
    }
}

const char* msg_StackMsg( void )
{
    msg_context_t *p_ctx = GetContext();
    assert( p_ctx );
    return p_ctx->psz_message;
}