~ubuntu-branches/debian/wheezy/vlc/wheezy

« back to all changes in this revision

Viewing changes to src/misc/messages.c

Tags: upstream-0.7.2.final
ImportĀ upstreamĀ versionĀ 0.7.2.final

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 * messages.c: messages interface
 
3
 * This library provides an interface to the message queue to be used by other
 
4
 * modules, especially intf modules. See config.h for output configuration.
 
5
 *****************************************************************************
 
6
 * Copyright (C) 1998-2004 VideoLAN
 
7
 * $Id: messages.c 7553 2004-04-29 15:30:00Z zorglub $
 
8
 *
 
9
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
 
10
 *          Samuel Hocevar <sam@zoy.org>
 
11
 *
 
12
 * This program is free software; you can redistribute it and/or modify
 
13
 * it under the terms of the GNU General Public License as published by
 
14
 * the Free Software Foundation; either version 2 of the License, or
 
15
 * (at your option) any later version.
 
16
 *
 
17
 * This program is distributed in the hope that it will be useful,
 
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
20
 * GNU General Public License for more details.
 
21
 *
 
22
 * You should have received a copy of the GNU General Public License
 
23
 * along with this program; if not, write to the Free Software
 
24
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 
25
 *****************************************************************************/
 
26
 
 
27
/*****************************************************************************
 
28
 * Preamble
 
29
 *****************************************************************************/
 
30
#include <stdio.h>                                               /* required */
 
31
#include <stdarg.h>                                       /* va_list for BSD */
 
32
#include <stdlib.h>                                              /* malloc() */
 
33
#include <string.h>                                            /* strerror() */
 
34
 
 
35
#include <vlc/vlc.h>
 
36
 
 
37
#ifdef HAVE_FCNTL_H
 
38
#   include <fcntl.h>                  /* O_CREAT, O_TRUNC, O_WRONLY, O_SYNC */
 
39
#endif
 
40
 
 
41
#ifdef HAVE_ERRNO_H
 
42
#   include <errno.h>                                               /* errno */
 
43
#endif
 
44
 
 
45
#ifdef HAVE_UNISTD_H
 
46
#   include <unistd.h>                                   /* close(), write() */
 
47
#endif
 
48
 
 
49
#include "vlc_interface.h"
 
50
 
 
51
/*****************************************************************************
 
52
 * Local macros
 
53
 *****************************************************************************/
 
54
#if defined(HAVE_VA_COPY)
 
55
#   define vlc_va_copy(dest,src) va_copy(dest,src)
 
56
#elif defined(HAVE___VA_COPY)
 
57
#   define vlc_va_copy(dest,src) __va_copy(dest,src)
 
58
#else
 
59
#   define vlc_va_copy(dest,src) (dest)=(src)
 
60
#endif
 
61
 
 
62
/*****************************************************************************
 
63
 * Local prototypes
 
64
 *****************************************************************************/
 
65
static void QueueMsg ( vlc_object_t *, int , const char *,
 
66
                       const char *, va_list );
 
67
static void FlushMsg ( msg_bank_t * );
 
68
static void PrintMsg ( vlc_object_t *, msg_item_t * );
 
69
 
 
70
/**
 
71
 * Initialize messages interface
 
72
 *
 
73
 * This functions has to be called before any call to other msg_* functions.
 
74
 * It set up the locks and the message queue if it is used.
 
75
 */
 
76
void __msg_Create( vlc_object_t *p_this )
 
77
{
 
78
    /* Message queue initialization */
 
79
    vlc_mutex_init( p_this, &p_this->p_libvlc->msg_bank.lock );
 
80
 
 
81
    p_this->p_libvlc->msg_bank.b_configured = VLC_FALSE;
 
82
    p_this->p_libvlc->msg_bank.b_overflow = VLC_FALSE;
 
83
 
 
84
    p_this->p_libvlc->msg_bank.i_start = 0;
 
85
    p_this->p_libvlc->msg_bank.i_stop = 0;
 
86
 
 
87
    p_this->p_libvlc->msg_bank.i_sub = 0;
 
88
    p_this->p_libvlc->msg_bank.pp_sub = NULL;
 
89
 
 
90
#ifdef UNDER_CE
 
91
    p_this->p_libvlc->msg_bank.logfile =
 
92
        CreateFile( L"vlc-log.txt", GENERIC_WRITE,
 
93
                    FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
 
94
                    CREATE_ALWAYS, 0, NULL );
 
95
    SetFilePointer( p_this->p_libvlc->msg_bank.logfile, 0, NULL, FILE_END );
 
96
#endif
 
97
}
 
98
 
 
99
/**
 
100
 * Flush the message queue
 
101
 */
 
102
void __msg_Flush( vlc_object_t *p_this )
 
103
{
 
104
    int i_index;
 
105
 
 
106
    vlc_mutex_lock( &p_this->p_libvlc->msg_bank.lock );
 
107
 
 
108
    p_this->p_libvlc->msg_bank.b_configured = VLC_TRUE;
 
109
 
 
110
    for( i_index = p_this->p_libvlc->msg_bank.i_start;
 
111
         i_index != p_this->p_libvlc->msg_bank.i_stop;
 
112
         i_index = (i_index+1) % VLC_MSG_QSIZE )
 
113
    {
 
114
        PrintMsg( p_this, &p_this->p_libvlc->msg_bank.msg[i_index] );
 
115
    }
 
116
 
 
117
    FlushMsg( &p_this->p_libvlc->msg_bank );
 
118
 
 
119
    vlc_mutex_unlock( &p_this->p_libvlc->msg_bank.lock );
 
120
}
 
121
 
 
122
/**
 
123
 * Free resources allocated by msg_Create
 
124
 *
 
125
 * This functions prints all messages remaining in queue, then free all the
 
126
 * resources allocated by msg_Create.
 
127
 * No other messages interface functions should be called after this one.
 
128
 */
 
129
void __msg_Destroy( vlc_object_t *p_this )
 
130
{
 
131
    if( p_this->p_libvlc->msg_bank.i_sub )
 
132
    {
 
133
        msg_Err( p_this, "stale interface subscribers" );
 
134
    }
 
135
 
 
136
    /* Flush the queue */
 
137
    if( !p_this->p_libvlc->msg_bank.b_configured )
 
138
    {
 
139
        msg_Flush( p_this );
 
140
    }
 
141
    else
 
142
    {
 
143
        FlushMsg( &p_this->p_libvlc->msg_bank );
 
144
    }
 
145
 
 
146
#ifdef UNDER_CE
 
147
    CloseHandle( p_this->p_libvlc->msg_bank.logfile );
 
148
#endif
 
149
 
 
150
    /* Destroy lock */
 
151
    vlc_mutex_destroy( &p_this->p_libvlc->msg_bank.lock );
 
152
}
 
153
 
 
154
/**
 
155
 * Subscribe to the message queue.
 
156
 */
 
157
msg_subscription_t *__msg_Subscribe( vlc_object_t *p_this )
 
158
{
 
159
    msg_bank_t *p_bank = &p_this->p_libvlc->msg_bank;
 
160
    msg_subscription_t *p_sub = malloc( sizeof( msg_subscription_t ) );
 
161
 
 
162
    vlc_mutex_lock( &p_bank->lock );
 
163
 
 
164
    /* Add subscription to the list */
 
165
    INSERT_ELEM( p_bank->pp_sub, p_bank->i_sub, p_bank->i_sub, p_sub );
 
166
 
 
167
    p_sub->i_start = p_bank->i_start;
 
168
    p_sub->pi_stop = &p_bank->i_stop;
 
169
 
 
170
    p_sub->p_msg   = p_bank->msg;
 
171
    p_sub->p_lock  = &p_bank->lock;
 
172
 
 
173
    vlc_mutex_unlock( &p_bank->lock );
 
174
 
 
175
    return p_sub;
 
176
}
 
177
 
 
178
/**
 
179
 * Unsubscribe from the message queue.
 
180
 */
 
181
void __msg_Unsubscribe( vlc_object_t *p_this, msg_subscription_t *p_sub )
 
182
{
 
183
    msg_bank_t *p_bank = &p_this->p_libvlc->msg_bank;
 
184
    int i_index;
 
185
 
 
186
    vlc_mutex_lock( &p_bank->lock );
 
187
 
 
188
    /* Sanity check */
 
189
    if( !p_bank->i_sub )
 
190
    {
 
191
        msg_Err( p_this, "no subscriber in the list" );
 
192
        return;
 
193
    }
 
194
 
 
195
    /* Look for the appropriate subscription */
 
196
    for( i_index = 0; i_index < p_bank->i_sub; i_index++ )
 
197
    {
 
198
        if( p_bank->pp_sub[ i_index ] == p_sub )
 
199
        {
 
200
            break;
 
201
        }
 
202
    }
 
203
 
 
204
    if( p_bank->pp_sub[ i_index ] != p_sub )
 
205
    {
 
206
        msg_Err( p_this, "subscriber not found" );
 
207
        vlc_mutex_unlock( &p_bank->lock );
 
208
        return;
 
209
    }
 
210
 
 
211
    /* Remove this subscription */
 
212
    REMOVE_ELEM( p_bank->pp_sub, p_bank->i_sub, i_index );
 
213
 
 
214
    vlc_mutex_unlock( &p_bank->lock );
 
215
}
 
216
 
 
217
/*****************************************************************************
 
218
 * __msg_*: print a message
 
219
 *****************************************************************************
 
220
 * These functions queue a message for later printing.
 
221
 *****************************************************************************/
 
222
void __msg_Generic( vlc_object_t *p_this, int i_type, const char *psz_module,
 
223
                    const char *psz_format, ... )
 
224
{
 
225
    va_list args;
 
226
 
 
227
    va_start( args, psz_format );
 
228
    QueueMsg( p_this, i_type, psz_module, psz_format, args );
 
229
    va_end( args );
 
230
}
 
231
 
 
232
void __msg_GenericVa( vlc_object_t *p_this, int i_type, const char *psz_module,
 
233
                      const char *psz_format, va_list args )
 
234
{
 
235
    QueueMsg( p_this, i_type, psz_module, psz_format, args );
 
236
}
 
237
 
 
238
/* Generic functions used when variadic macros are not available. */
 
239
#define DECLARE_MSG_FN( FN_NAME, FN_TYPE ) \
 
240
    void FN_NAME( vlc_object_t *p_this, const char *psz_format, ... ) \
 
241
    { \
 
242
        va_list args; \
 
243
        va_start( args, psz_format ); \
 
244
        QueueMsg( (vlc_object_t *)p_this, FN_TYPE, "unknown", \
 
245
                  psz_format, args ); \
 
246
        va_end( args ); \
 
247
    } \
 
248
    struct _
 
249
/**
 
250
 * Output an informational message.
 
251
 * \note Do not use this for debug messages
 
252
 * \see input_AddInfo
 
253
 */
 
254
DECLARE_MSG_FN( __msg_Info, VLC_MSG_INFO );
 
255
/**
 
256
 * Output an error message.
 
257
 */
 
258
DECLARE_MSG_FN( __msg_Err,  VLC_MSG_ERR );
 
259
/**
 
260
 * Output a waring message
 
261
 */
 
262
DECLARE_MSG_FN( __msg_Warn, VLC_MSG_WARN );
 
263
/**
 
264
 * Output a debug message
 
265
 */
 
266
DECLARE_MSG_FN( __msg_Dbg,  VLC_MSG_DBG );
 
267
 
 
268
/**
 
269
 * Add a message to a queue
 
270
 *
 
271
 * This function provides basic functionnalities to other msg_* functions.
 
272
 * It adds a message to a queue (after having printed all stored messages if it
 
273
 * is full). If the message can't be converted to string in memory, it issues
 
274
 * a warning.
 
275
 */
 
276
static void QueueMsg( vlc_object_t *p_this, int i_type, const char *psz_module,
 
277
                      const char *psz_format, va_list _args )
 
278
{
 
279
    msg_bank_t * p_bank = &p_this->p_libvlc->msg_bank;       /* message bank */
 
280
    char *       psz_str = NULL;                 /* formatted message string */
 
281
    va_list      args;
 
282
    msg_item_t * p_item = NULL;                        /* pointer to message */
 
283
    msg_item_t   item;                    /* message in case of a full queue */
 
284
 
 
285
#if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN) || defined(SYS_BEOS)
 
286
    int          i_size = strlen(psz_format) + INTF_MAX_MSG_SIZE;
 
287
#endif
 
288
 
 
289
    /*
 
290
     * Convert message to string
 
291
     */
 
292
#if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN) && !defined( SYS_BEOS )
 
293
    vlc_va_copy( args, _args );
 
294
    vasprintf( &psz_str, psz_format, args );
 
295
    va_end( args );
 
296
#else
 
297
    psz_str = (char*) malloc( i_size * sizeof(char) );
 
298
#endif
 
299
 
 
300
    if( psz_str == NULL )
 
301
    {
 
302
#ifdef HAVE_ERRNO_H
 
303
        fprintf( stderr, "main warning: can't store message (%s): ",
 
304
                 strerror(errno) );
 
305
#else
 
306
        fprintf( stderr, "main warning: can't store message: " );
 
307
#endif
 
308
        vlc_va_copy( args, _args );
 
309
        vfprintf( stderr, psz_format, args );
 
310
        va_end( args );
 
311
        fprintf( stderr, "\n" );
 
312
        return;
 
313
    }
 
314
 
 
315
#if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN) || defined(SYS_BEOS)
 
316
    vlc_va_copy( args, _args );
 
317
    vsnprintf( psz_str, i_size, psz_format, args );
 
318
    va_end( args );
 
319
    psz_str[ i_size - 1 ] = 0; /* Just in case */
 
320
#endif
 
321
 
 
322
    /* Put message in queue */
 
323
    vlc_mutex_lock( &p_bank->lock );
 
324
 
 
325
    /* Check there is room in the queue for our message */
 
326
    if( p_bank->b_overflow )
 
327
    {
 
328
        FlushMsg( p_bank );
 
329
 
 
330
        if( ((p_bank->i_stop - p_bank->i_start + 1) % VLC_MSG_QSIZE) == 0 )
 
331
        {
 
332
            /* Still in overflow mode, print from a dummy item */
 
333
            p_item = &item;
 
334
        }
 
335
        else
 
336
        {
 
337
            /* Pheeew, at last, there is room in the queue! */
 
338
            p_bank->b_overflow = VLC_FALSE;
 
339
        }
 
340
    }
 
341
    else if( ((p_bank->i_stop - p_bank->i_start + 2) % VLC_MSG_QSIZE) == 0 )
 
342
    {
 
343
        FlushMsg( p_bank );
 
344
 
 
345
        if( ((p_bank->i_stop - p_bank->i_start + 2) % VLC_MSG_QSIZE) == 0 )
 
346
        {
 
347
            p_bank->b_overflow = VLC_TRUE;
 
348
 
 
349
            /* Put the overflow message in the queue */
 
350
            p_item = p_bank->msg + p_bank->i_stop;
 
351
            p_bank->i_stop = (p_bank->i_stop + 1) % VLC_MSG_QSIZE;
 
352
 
 
353
            p_item->i_type =        VLC_MSG_WARN;
 
354
            p_item->i_object_id =   p_this->i_object_id;
 
355
            p_item->i_object_type = p_this->i_object_type;
 
356
            p_item->psz_module =    strdup( "message" );
 
357
            p_item->psz_msg =       strdup( "message queue overflowed" );
 
358
 
 
359
            PrintMsg( p_this, p_item );
 
360
 
 
361
            /* We print from a dummy item */
 
362
            p_item = &item;
 
363
        }
 
364
    }
 
365
 
 
366
    if( !p_bank->b_overflow )
 
367
    {
 
368
        /* Put the message in the queue */
 
369
        p_item = p_bank->msg + p_bank->i_stop;
 
370
        p_bank->i_stop = (p_bank->i_stop + 1) % VLC_MSG_QSIZE;
 
371
    }
 
372
 
 
373
    /* Fill message information fields */
 
374
    p_item->i_type =        i_type;
 
375
    p_item->i_object_id =   p_this->i_object_id;
 
376
    p_item->i_object_type = p_this->i_object_type;
 
377
    p_item->psz_module =    strdup( psz_module );
 
378
    p_item->psz_msg =       psz_str;
 
379
 
 
380
    PrintMsg( p_this, p_item );
 
381
 
 
382
    if( p_bank->b_overflow )
 
383
    {
 
384
        free( p_item->psz_module );
 
385
        free( p_item->psz_msg );
 
386
    }
 
387
 
 
388
    vlc_mutex_unlock( &p_bank->lock );
 
389
}
 
390
 
 
391
/* following functions are local */
 
392
 
 
393
/*****************************************************************************
 
394
 * FlushMsg
 
395
 *****************************************************************************
 
396
 * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
 
397
 * this function does not check the lock.
 
398
 *****************************************************************************/
 
399
static void FlushMsg ( msg_bank_t *p_bank )
 
400
{
 
401
    int i_index, i_start, i_stop;
 
402
 
 
403
    /* Only flush the queue if it has been properly configured */
 
404
    if( !p_bank->b_configured )
 
405
    {
 
406
        return;
 
407
    }
 
408
 
 
409
    /* Get the maximum message index that can be freed */
 
410
    i_stop = p_bank->i_stop;
 
411
 
 
412
    /* Check until which value we can free messages */
 
413
    for( i_index = 0; i_index < p_bank->i_sub; i_index++ )
 
414
    {
 
415
        i_start = p_bank->pp_sub[ i_index ]->i_start;
 
416
 
 
417
        /* If this subscriber is late, we don't free messages before
 
418
         * his i_start value, otherwise he'll miss messages */
 
419
        if(   ( i_start < i_stop
 
420
               && (p_bank->i_stop <= i_start || i_stop <= p_bank->i_stop) )
 
421
           || ( i_stop < i_start
 
422
               && (i_stop <= p_bank->i_stop && p_bank->i_stop <= i_start) ) )
 
423
        {
 
424
            i_stop = i_start;
 
425
        }
 
426
    }
 
427
 
 
428
    /* Free message data */
 
429
    for( i_index = p_bank->i_start;
 
430
         i_index != i_stop;
 
431
         i_index = (i_index+1) % VLC_MSG_QSIZE )
 
432
    {
 
433
        free( p_bank->msg[i_index].psz_msg );
 
434
        free( p_bank->msg[i_index].psz_module );
 
435
    }
 
436
 
 
437
    /* Update the new start value */
 
438
    p_bank->i_start = i_index;
 
439
}
 
440
 
 
441
/*****************************************************************************
 
442
 * PrintMsg: output a message item to stderr
 
443
 *****************************************************************************
 
444
 * Print a message to stderr, with colour formatting if needed.
 
445
 *****************************************************************************/
 
446
static void PrintMsg ( vlc_object_t * p_this, msg_item_t * p_item )
 
447
{
 
448
#   define COL(x)  "\033[" #x ";1m"
 
449
#   define RED     COL(31)
 
450
#   define GREEN   COL(32)
 
451
#   define YELLOW  COL(33)
 
452
#   define WHITE   COL(37)
 
453
#   define GRAY    "\033[0m"
 
454
 
 
455
#ifdef UNDER_CE
 
456
    int i_dummy;
 
457
#endif
 
458
    static const char * ppsz_type[4] = { "", " error", " warning", " debug" };
 
459
    static const char *ppsz_color[4] = { WHITE, RED, YELLOW, GRAY };
 
460
    char *psz_object = "private";
 
461
    int i_type = p_item->i_type;
 
462
 
 
463
    switch( i_type )
 
464
    {
 
465
        case VLC_MSG_ERR:
 
466
            if( p_this->p_libvlc->i_verbose < 0 ) return;
 
467
            break;
 
468
        case VLC_MSG_INFO:
 
469
            if( p_this->p_libvlc->i_verbose < 0 ) return;
 
470
            break;
 
471
        case VLC_MSG_WARN:
 
472
            if( p_this->p_libvlc->i_verbose < 1 ) return;
 
473
            break;
 
474
        case VLC_MSG_DBG:
 
475
            if( p_this->p_libvlc->i_verbose < 2 ) return;
 
476
            break;
 
477
    }
 
478
 
 
479
    switch( p_item->i_object_type )
 
480
    {
 
481
        case VLC_OBJECT_ROOT: psz_object = "root"; break;
 
482
        case VLC_OBJECT_VLC: psz_object = "vlc"; break;
 
483
        case VLC_OBJECT_MODULE: psz_object = "module"; break;
 
484
        case VLC_OBJECT_INTF: psz_object = "interface"; break;
 
485
        case VLC_OBJECT_PLAYLIST: psz_object = "playlist"; break;
 
486
        case VLC_OBJECT_ITEM: psz_object = "item"; break;
 
487
        case VLC_OBJECT_INPUT: psz_object = "input"; break;
 
488
        case VLC_OBJECT_DECODER: psz_object = "decoder"; break;
 
489
        case VLC_OBJECT_PACKETIZER: psz_object = "packetizer"; break;
 
490
        case VLC_OBJECT_ENCODER: psz_object = "encoder"; break;
 
491
        case VLC_OBJECT_VOUT: psz_object = "video output"; break;
 
492
        case VLC_OBJECT_AOUT: psz_object = "audio output"; break;
 
493
        case VLC_OBJECT_SOUT: psz_object = "stream output"; break;
 
494
        case VLC_OBJECT_HTTPD: psz_object = "http daemon"; break;
 
495
        case VLC_OBJECT_DIALOGS: psz_object = "dialogs provider"; break;
 
496
        case VLC_OBJECT_VLM: psz_object = "vlm"; break;
 
497
        case VLC_OBJECT_ANNOUNCE: psz_object = "announce handler"; break;
 
498
        case VLC_OBJECT_DEMUX: psz_object = "demuxer"; break;
 
499
    }
 
500
 
 
501
#ifdef UNDER_CE
 
502
#   define CE_WRITE(str) WriteFile( p_this->p_libvlc->msg_bank.logfile, \
 
503
                                    str, strlen(str), &i_dummy, NULL );
 
504
    CE_WRITE( p_item->psz_module );
 
505
    CE_WRITE( " " );
 
506
    CE_WRITE( psz_object );
 
507
    CE_WRITE( ppsz_type[i_type] );
 
508
    CE_WRITE( ": " );
 
509
    CE_WRITE( p_item->psz_msg );
 
510
    CE_WRITE( "\r\n" );
 
511
    FlushFileBuffers( p_this->p_libvlc->msg_bank.logfile );
 
512
 
 
513
#else
 
514
    /* Send the message to stderr */
 
515
    if( p_this->p_libvlc->b_color )
 
516
    {
 
517
        fprintf( stderr, "[" GREEN "%.8i" GRAY "] %s %s%s: %s%s" GRAY "\n",
 
518
                         p_item->i_object_id, p_item->psz_module, psz_object,
 
519
                         ppsz_type[i_type], ppsz_color[i_type],
 
520
                         p_item->psz_msg );
 
521
    }
 
522
    else
 
523
    {
 
524
        fprintf( stderr, "[%.8i] %s %s%s: %s\n", p_item->i_object_id,
 
525
                         p_item->psz_module, psz_object, ppsz_type[i_type],
 
526
                         p_item->psz_msg );
 
527
    }
 
528
 
 
529
#   if defined(WIN32)
 
530
    fflush( stderr );
 
531
#   endif
 
532
#endif
 
533
}