]> git.sesse.net Git - vlc/blob - src/interface/intf_msg.c
.Impl�mentation de intf_WarnMsg( int i_level, char *psz_format, ... ) et
[vlc] / src / interface / intf_msg.c
1 /*****************************************************************************
2  * intf_msg.c: messages interface
3  * This library provides basic functions for threads to interact with user
4  * interface, such as message output. See config.h for output configuration.
5  *****************************************************************************
6  * Copyright (C) 1998, 1999, 2000 VideoLAN
7  *
8  * Authors:
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include "defs.h"
29
30 #include <errno.h>                                                  /* errno */
31 #include <fcntl.h>                     /* O_CREAT, O_TRUNC, O_WRONLY, O_SYNC */
32 #include <stdio.h>                                               /* required */
33 #include <stdarg.h>                                       /* va_list for BSD */
34 #include <stdlib.h>                                              /* malloc() */
35 #include <string.h>                                            /* strerror() */
36 #include <unistd.h>                                      /* close(), write() */
37
38 #include "config.h"
39 #include "common.h"
40 #include "threads.h"
41 #include "mtime.h"
42 #include "plugins.h"
43 #include "intf_msg.h"
44 #include "interface.h"
45 #include "intf_console.h"
46
47 #include "main.h"
48
49 /*****************************************************************************
50  * intf_msg_item_t
51  *****************************************************************************
52  * Store a single message. Messages have a maximal size of INTF_MSG_MSGSIZE.
53  * If DEBUG is defined, messages have a date field and debug messages are
54  * printed with a date to allow more precise profiling.
55  *****************************************************************************/
56 typedef struct
57 {
58     int     i_type;                               /* message type, see below */
59     char *  psz_msg;                                   /* the message itself */
60
61 #ifdef DEBUG
62     /* Debugging informations - in DEBUG mode, debug messages have calling
63      * location informations printed */
64     mtime_t date;                                     /* date of the message */
65     char *  psz_file;               /* file in which the function was called */
66     char *  psz_function;     /* function from which the function was called */
67     int     i_line;                 /* line at which the function was called */
68 #endif
69 } intf_msg_item_t;
70
71 /* Message types */
72 #define INTF_MSG_STD    0                                /* standard message */
73 #define INTF_MSG_ERR    1                                   /* error message */
74 #define INTF_MSG_INTF   2                               /* interface message */
75 #define INTF_MSG_DBG    3                                   /* debug message */
76 #define INTF_MSG_WARN   4                                  /* warning message*/
77
78
79 /*****************************************************************************
80  * intf_msg_t
81  *****************************************************************************
82  * Store all data requiered by messages interfaces. It has a single reference
83  * int p_main.
84  *****************************************************************************/
85 typedef struct intf_msg_s
86 {
87 #ifdef INTF_MSG_QUEUE
88     /* Message queue */
89     vlc_mutex_t             lock;                      /* message queue lock */
90     int                     i_count;            /* number of messages stored */
91     intf_msg_item_t         msg[INTF_MSG_QSIZE];            /* message queue */
92 #endif
93
94 #ifdef DEBUG_LOG
95     /* Log file */
96     int                     i_log_file;                          /* log file */
97 #endif
98
99 //#if 0
100 #if !defined(INTF_MSG_QUEUE) && !defined(DEBUG_LOG)
101     /* If neither messages queue, neither log file is used, then the structure
102      * is empty. However, empty structures are not allowed in C. Therefore, a
103      * dummy integer is used to fill it. */
104     int                     i_dummy;                        /* unused filler */
105 #endif
106 //    int                     i_warning_level;
107 } intf_msg_t;
108
109 /*****************************************************************************
110  * Local prototypes
111  *****************************************************************************/
112
113 static void QueueMsg        ( intf_msg_t *p_msg, int i_type,
114                               char *psz_format, va_list ap );
115 static void PrintMsg        ( intf_msg_item_t *p_msg );
116 #ifdef DEBUG
117 static void QueueDbgMsg     ( intf_msg_t *p_msg, char *psz_file,
118                               char *psz_function, int i_line,
119                               char *psz_format, va_list ap );
120 #endif
121 #ifdef INTF_MSG_QUEUE
122 static void FlushLockedMsg  ( intf_msg_t *p_msg );
123 #endif
124
125
126 /*****************************************************************************
127  * intf_MsgCreate: initialize messages interface                         (ok ?)
128  *****************************************************************************
129  * This functions has to be called before any call to other intf_*Msg functions.
130  * It set up the locks and the message queue if it is used.
131  *****************************************************************************/
132 p_intf_msg_t intf_MsgCreate( void )
133 {
134     p_intf_msg_t p_msg;
135
136     /* Allocate structure */
137     p_msg = malloc( sizeof( intf_msg_t ) );
138     if( p_msg == NULL )
139     {
140         errno = ENOMEM;
141     }
142     else
143     {
144 #ifdef INTF_MSG_QUEUE
145     /* Message queue initialization */
146     vlc_mutex_init( &p_msg->lock );                        /* intialize lock */
147     p_msg->i_count = 0;                                    /* queue is empty */
148 #endif
149
150     
151 #ifdef DEBUG_LOG
152         /* Log file initialization - on failure, file pointer will be null,
153          * and no log will be issued, but this is not considered as an
154          * error */
155         p_msg->i_log_file = open( DEBUG_LOG, O_CREAT | O_TRUNC |
156 #ifndef SYS_BSD
157                                   O_SYNC |
158 #else
159                                   O_ASYNC |
160 #endif /* SYS_BSD */
161                                   O_WRONLY, 0666 );
162
163 #endif
164     }
165     return( p_msg );
166 }
167
168 /*****************************************************************************
169  * intf_MsgDestroy: free resources allocated by intf_InitMsg            (ok ?)
170  *****************************************************************************
171  * This functions prints all messages remaining in queue, then free all the
172  * resources allocated by intf_InitMsg.
173  * No other messages interface functions should be called after this one.
174  *****************************************************************************/
175 void intf_MsgDestroy( void )
176 {
177     intf_FlushMsg();                         /* print all remaining messages */
178
179 #ifdef DEBUG_LOG
180     /* Close log file if any */
181     if( p_main->p_msg->i_log_file >= 0 )
182     {
183         close( p_main->p_msg->i_log_file );
184     }
185 #endif
186
187     /* Free structure */
188     free( p_main->p_msg );
189 }
190
191 /*****************************************************************************
192  * intf_Msg: print a message                                             (ok ?)
193  *****************************************************************************
194  * This function queue a message for later printing, or print it immediately
195  * if the queue isn't used.
196  *****************************************************************************/
197 void intf_Msg( char *psz_format, ... )
198 {
199     va_list ap;
200
201     va_start( ap, psz_format );
202     QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
203     va_end( ap );
204 }
205
206 /*****************************************************************************
207  * intf_ErrMsg : print an error message                                  (ok ?)
208  *****************************************************************************
209  * This function is the same as intf_Msg, except that it prints its messages
210  * on stderr.
211  *****************************************************************************/
212 void intf_ErrMsg( char *psz_format, ... )
213 {
214     va_list ap;
215
216     va_start( ap, psz_format );
217     QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
218     va_end( ap );
219 }
220
221 /*****************************************************************************
222  * intf_WarnMsg : print a warning message
223  *****************************************************************************
224  * This function is the same as intf_Msg, except that it concerns warning
225  * messages for testing purpose.
226  *****************************************************************************/
227 void intf_WarnMsg( int i_level, char *psz_format, ... )
228 {
229     va_list ap;
230     
231     if( i_level >= p_main->p_intf->i_warning_level )
232     {
233         va_start( ap, psz_format );
234         QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
235         va_end( ap );
236     }
237 }
238
239
240 /*****************************************************************************
241  * intf_IntfMsg : print an interface message                             (ok ?)
242  *****************************************************************************
243  * In opposition to all other intf_*Msg function, this function does not print
244  * it's message on default terminal (stdout or stderr), but send it to
245  * interface (in fact to the X11 console). This means that the interface MUST
246  * be initialized and a X11 console openned before this function is used, and
247  * that once the console is closed, this call is vorbidden.
248  * Practically, only the interface thread itself should call this function, and
249  * flush all messages before intf_CloseX11Console() is called.
250  *****************************************************************************/
251 void intf_IntfMsg(char *psz_format, ...)
252 {
253     va_list ap;
254
255     va_start( ap, psz_format );
256     QueueMsg( p_main->p_msg, INTF_MSG_INTF, psz_format, ap );
257     va_end( ap );
258 }
259
260 /*****************************************************************************
261  * _intf_DbgMsg: print a debugging message                               (ok ?)
262  *****************************************************************************
263  * This function prints a debugging message. Compared to other intf_*Msg
264  * functions, it is only defined if DEBUG is defined and require a file name,
265  * a function name and a line number as additionnal debugging informations. It
266  * also prints a debugging header for each received line.
267  *****************************************************************************/
268 #ifdef DEBUG
269 void _intf_DbgMsg( char *psz_file, char *psz_function, int i_line,
270                    char *psz_format, ...)
271 {
272     va_list ap;
273
274     va_start( ap, psz_format );
275     QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
276                  psz_format, ap );
277     va_end( ap );
278 }
279 #endif
280
281 /*****************************************************************************
282  * intf_MsgImm: print a message                                          (ok ?)
283  *****************************************************************************
284  * This function prints a message immediately. If the queue is used, all
285  * waiting messages are also printed.
286  *****************************************************************************/
287 void intf_MsgImm( char *psz_format, ... )
288 {
289     va_list ap;
290
291     va_start( ap, psz_format );
292     QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
293     va_end( ap );
294     intf_FlushMsg();
295 }
296
297 /*****************************************************************************
298  * intf_ErrMsgImm: print an error message immediately                    (ok ?)
299  *****************************************************************************
300  * This function is the same as intf_MsgImm, except that it prints its message
301  * on stderr.
302  *****************************************************************************/
303 void intf_ErrMsgImm(char *psz_format, ...)
304 {
305     va_list ap;
306
307     va_start( ap, psz_format );
308     QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
309     va_end( ap );
310     intf_FlushMsg();
311 }
312
313 /*****************************************************************************
314  * intf_WarnMsgImm : print a warning message
315  *****************************************************************************
316  * This function is the same as intf_MsgImm, except that it concerns warning
317  * messages for testing purpose.
318  *****************************************************************************/
319 void intf_WarnMsgImm( int i_level, char *psz_format, ... )
320 {
321     va_list ap;
322
323     if( i_level >= p_main->p_intf->i_warning_level )
324     {
325         va_start( ap, psz_format );
326         QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
327         va_end( ap );
328     }
329     intf_FlushMsg();
330 }
331
332
333
334 /*****************************************************************************
335  * _intf_DbgMsgImm: print a debugging message immediately                (ok ?)
336  *****************************************************************************
337  * This function is the same as intf_DbgMsgImm, except that it prints its
338  * message immediately. It should only be called through the macro
339  * intf_DbgMsgImm().
340  *****************************************************************************/
341 #ifdef DEBUG
342 void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
343                       char *psz_format, ...)
344 {
345     va_list ap;
346
347     va_start( ap, psz_format );
348     QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
349                  psz_format, ap );
350     va_end( ap );
351     intf_FlushMsg();
352 }
353 #endif
354
355 /*****************************************************************************
356  * intf_FlushMsg                                                        (ok ?)
357  *****************************************************************************
358  * Print all messages remaining in queue: get lock and call FlushLockedMsg.
359  * This function does nothing if the message queue isn't used.
360  * This function is only implemented if message queue is used. If not, it is
361  * an empty macro.
362  *****************************************************************************/
363 #ifdef INTF_MSG_QUEUE
364 void intf_FlushMsg( void )
365 {
366     vlc_mutex_lock( &p_main->p_msg->lock );                      /* get lock */
367     FlushLockedMsg( p_main->p_msg );                       /* flush messages */
368     vlc_mutex_unlock( &p_main->p_msg->lock );              /* give lock back */
369 }
370 #endif
371
372 /* following functions are local */
373
374 /*****************************************************************************
375  * QueueMsg: add a message to a queue
376  *****************************************************************************
377  * This function provide basic functionnalities to other intf_*Msg functions.
378  * It add a message to a queue (after having printed all stored messages if it
379  * is full. If the message can't be converted to string in memory, it exit the
380  * program. If the queue is not used, it prints the message immediately.
381  *****************************************************************************/
382 static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list ap )
383 {
384     char *                  psz_str;             /* formatted message string */
385     intf_msg_item_t *       p_msg_item;                /* pointer to message */
386
387 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
388     intf_msg_item_t         msg_item;                             /* message */
389     p_msg_item =           &msg_item;
390 #endif /*....................................................................*/
391
392     /*
393      * Convert message to string
394      */
395 #ifdef SYS_BEOS
396     psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
397     vsprintf( psz_str, psz_format, ap );
398 #else
399     vasprintf( &psz_str, psz_format, ap );
400 #endif
401     if( psz_str == NULL )
402     {
403         fprintf(stderr, "warning: can't store following message (%s): ",
404                 strerror(errno) );
405         vfprintf(stderr, psz_format, ap );
406         exit( errno );
407     }
408
409 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
410     vlc_mutex_lock( &p_msg->lock );                              /* get lock */
411     if( p_msg->i_count == INTF_MSG_QSIZE )          /* flush queue if needed */
412     {
413 #ifdef DEBUG               /* in debug mode, queue overflow causes a warning */
414         fprintf(stderr, "warning: message queue overflow\n" );
415 #endif
416         FlushLockedMsg( p_msg );
417     }
418     p_msg_item = p_msg->msg + p_msg->i_count++;            /* select message */
419 #endif /*.............................................. end of queue mode ...*/
420
421     /*
422      * Fill message information fields
423      */
424     p_msg_item->i_type =     i_type;
425     p_msg_item->psz_msg =    psz_str;
426
427 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
428     vlc_mutex_unlock( &p_msg->lock );                      /* give lock back */
429 #else /*....................................................... instant mode */
430     PrintMsg( p_msg_item );                                 /* print message */
431     free( psz_str );                                    /* free message data */
432 #endif /*....................................................................*/
433 }
434
435 /*****************************************************************************
436  * QueueDbgMsg: add a message to a queue with debugging informations
437  *****************************************************************************
438  * This function is the same as QueueMsg, except that it is only defined when
439  * DEBUG is define, and require additionnal debugging informations.
440  *****************************************************************************/
441 #ifdef DEBUG
442 static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
443                         int i_line, char *psz_format, va_list ap)
444 {
445     char *                  psz_str;             /* formatted message string */
446     intf_msg_item_t *       p_msg_item;                /* pointer to message */
447
448 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
449     intf_msg_item_t         msg_item;                             /* message */
450     p_msg_item =           &msg_item;
451 #endif /*....................................................................*/
452
453     /*
454      * Convert message to string
455      */
456 #ifdef SYS_BEOS
457     psz_str = (char*) malloc( INTF_MAX_MSG_SIZE );
458     vsprintf( psz_str, psz_format, ap );
459 #else
460     vasprintf( &psz_str, psz_format, ap );
461 #endif
462     if( psz_str == NULL )
463     {
464         fprintf(stderr, "warning: can't store following message (%s): ",
465                 strerror(errno) );
466         fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
467         vfprintf(stderr, psz_format, ap );
468         exit( errno );
469     }
470
471 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
472     vlc_mutex_lock( &p_msg->lock );                              /* get lock */
473     if( p_msg->i_count == INTF_MSG_QSIZE )          /* flush queue if needed */
474     {
475 #ifdef DEBUG               /* in debug mode, queue overflow causes a warning */
476         fprintf(stderr, "warning: message queue overflow\n" );
477 #endif
478         FlushLockedMsg( p_msg );
479     }
480     p_msg_item = p_msg->msg + p_msg->i_count++;            /* select message */
481 #endif /*.............................................. end of queue mode ...*/
482
483     /*
484      * Fill message information fields
485      */
486     p_msg_item->i_type =       INTF_MSG_DBG;
487     p_msg_item->psz_msg =      psz_str;
488     p_msg_item->psz_file =     psz_file;
489     p_msg_item->psz_function = psz_function;
490     p_msg_item->i_line =       i_line;
491     p_msg_item->date =         mdate();
492
493 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
494     vlc_mutex_unlock( &p_msg->lock );                      /* give lock back */
495 #else /*....................................................... instant mode */
496     PrintMsg( p_msg_item );                                 /* print message */
497     free( psz_str );                                    /* free message data */
498 #endif /*....................................................................*/
499 }
500 #endif
501
502 /*****************************************************************************
503  * FlushLockedMsg                                                       (ok ?)
504  *****************************************************************************
505  * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
506  * this function does not check the lock. This function is only defined if
507  * INTF_MSG_QUEUE is defined.
508  *****************************************************************************/
509 #ifdef INTF_MSG_QUEUE
510 static void FlushLockedMsg ( intf_msg_t *p_msg )
511 {
512     int i_index;
513
514     for( i_index = 0; i_index < p_msg->i_count; i_index++ )
515     {
516         /* Print message and free message data */
517         PrintMsg( &p_msg->msg[i_index] );
518         free( p_msg->msg[i_index].psz_msg );
519     }
520
521     p_msg->i_count = 0;
522 }
523 #endif
524
525 /*****************************************************************************
526  * PrintMsg: print a message                                             (ok ?)
527  *****************************************************************************
528  * Print a single message. The message data is not freed. This function exists
529  * in two version. The DEBUG version prints a date with each message, and is
530  * able to log messages (if DEBUG_LOG is defined).
531  * The normal one just prints messages to the screen.
532  *****************************************************************************/
533 #ifdef DEBUG
534
535 static void PrintMsg( intf_msg_item_t *p_msg )
536 {
537     char    psz_date[MSTRTIME_MAX_SIZE];            /* formatted time buffer */
538     char *  psz_msg;                                       /* message buffer */
539
540     /* Format message - the message is formatted here because in case the log
541      * file is used, it avoids another format string parsing */
542     switch( p_msg->i_type )
543     {
544     case INTF_MSG_STD:                                   /* regular messages */
545     case INTF_MSG_ERR:
546         asprintf( &psz_msg, "%s", p_msg->psz_msg );
547         break;
548
549     case INTF_MSG_WARN:                                   /* Warning message */
550         asprintf( &psz_msg, "%s", p_msg->psz_msg );
551         break;
552         
553     case INTF_MSG_INTF:                                /* interface messages */
554         asprintf( &psz_msg, "%s", p_msg->psz_msg );
555         break;
556
557     case INTF_MSG_DBG:                                     /* debug messages */
558         mstrtime( psz_date, p_msg->date );
559         asprintf( &psz_msg, "(%s) " INTF_MSG_DBG_FORMAT "%s",
560                   psz_date, p_msg->psz_file, p_msg->psz_function, p_msg->i_line,
561                   p_msg->psz_msg );
562         break;
563     }
564
565     /* Check if formatting function succeeded */
566     if( psz_msg == NULL )
567     {
568         fprintf( stderr, "error: can not format message (%s): %s\n",
569                  strerror( errno ), p_msg->psz_msg );
570         return;
571     }
572
573     /*
574      * Print messages
575      */
576     switch( p_msg->i_type )
577     {
578     case INTF_MSG_STD:                                  /* standard messages */
579         fprintf( stdout, psz_msg );
580         break;
581     case INTF_MSG_ERR:                                     /* error messages */
582     case INTF_MSG_WARN:
583 #ifndef DEBUG_LOG_ONLY
584     case INTF_MSG_DBG:                                 /* debugging messages */
585 #endif
586         fprintf( stderr, psz_msg );
587         break;
588     case INTF_MSG_INTF:                                /* interface messages */
589         intf_ConsolePrint( p_main->p_intf->p_console, psz_msg );
590         break;
591     }
592
593 #ifdef DEBUG_LOG
594     /* Append all messages to log file */
595     if( p_main->p_msg->i_log_file >= 0 )
596     {
597         write( p_main->p_msg->i_log_file, psz_msg, strlen( psz_msg ) );
598     }
599 #endif
600
601     /* Free formatted message */
602     free( psz_msg );
603 }
604
605 #else
606
607 static void PrintMsg( intf_msg_item_t *p_msg )
608 {
609     /*
610      * Print messages on screen
611      */
612     switch( p_msg->i_type )
613     {
614     case INTF_MSG_STD:                                  /* standard messages */
615     case INTF_MSG_DBG:                                     /* debug messages */
616         fprintf( stdout, p_msg->psz_msg );
617         break;
618     case INTF_MSG_ERR:                                     /* error messages */
619     case INTF_MSG_WARN:
620         fprintf( stderr, p_msg->psz_msg );                /* warning message */
621         break;
622     case INTF_MSG_INTF:                                /* interface messages */
623         intf_ConsolePrint( p_main->p_intf->p_console, p_msg->psz_msg );
624         break;
625     }
626 }
627
628 #endif