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