]> git.sesse.net Git - vlc/blob - src/interface/intf_msg.c
* The Gtk+ interface is now built as a Debian package as well. The Gnome
[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: Vincent Seguin <seguin@via.ecp.fr>
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
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     FILE *                  p_log_file;                          /* log file */
97 #endif
98
99 #if !defined(INTF_MSG_QUEUE) && !defined(DEBUG_LOG)
100     /* If neither messages queue, neither log file is used, then the structure
101      * is empty. However, empty structures are not allowed in C. Therefore, a
102      * dummy integer is used to fill it. */
103     int                     i_dummy;                        /* unused filler */
104 #endif
105 } intf_msg_t;
106
107 /*****************************************************************************
108  * Local prototypes
109  *****************************************************************************/
110
111 static void QueueMsg        ( intf_msg_t *p_msg, int i_type,
112                               char *psz_format, va_list ap );
113 static void PrintMsg        ( intf_msg_item_t *p_msg );
114 #ifdef DEBUG
115 static void QueueDbgMsg     ( intf_msg_t *p_msg, char *psz_file,
116                               char *psz_function, int i_line,
117                               char *psz_format, va_list ap );
118 #endif
119 #ifdef INTF_MSG_QUEUE
120 static void FlushLockedMsg  ( intf_msg_t *p_msg );
121 #endif
122
123
124 /*****************************************************************************
125  * intf_MsgCreate: initialize messages interface                         (ok ?)
126  *****************************************************************************
127  * This functions has to be called before any call to other intf_*Msg functions.
128  * It set up the locks and the message queue if it is used.
129  *****************************************************************************/
130 p_intf_msg_t intf_MsgCreate( void )
131 {
132     p_intf_msg_t p_msg;
133
134     /* Allocate structure */
135     p_msg = malloc( sizeof( intf_msg_t ) );
136     if( p_msg == NULL )
137     {
138         errno = ENOMEM;
139     }
140     else
141     {
142 #ifdef INTF_MSG_QUEUE
143     /* Message queue initialization */
144     vlc_mutex_init( &p_msg->lock );                        /* intialize lock */
145     p_msg->i_count = 0;                                    /* queue is empty */
146 #endif
147
148     
149 #ifdef DEBUG_LOG
150         /* Log file initialization - on failure, file pointer will be null,
151          * and no log will be issued, but this is not considered as an
152          * error */
153         p_msg->p_log_file = fopen( DEBUG_LOG, "w" );
154 #endif
155     }
156     return( p_msg );
157 }
158
159 /*****************************************************************************
160  * intf_MsgDestroy: free resources allocated by intf_InitMsg            (ok ?)
161  *****************************************************************************
162  * This functions prints all messages remaining in queue, then free all the
163  * resources allocated by intf_InitMsg.
164  * No other messages interface functions should be called after this one.
165  *****************************************************************************/
166 void intf_MsgDestroy( void )
167 {
168     intf_FlushMsg();                         /* print all remaining messages */
169
170 #ifdef DEBUG_LOG
171     /* Close log file if any */
172     if( p_main->p_msg->p_log_file != NULL )
173     {
174         fclose( p_main->p_msg->p_log_file );
175     }
176 #endif
177
178 #ifdef INTF_MSG_QUEUE
179     /* destroy lock */
180     vlc_mutex_destroy( &p_main->p_msg->lock );
181 #endif
182     
183     /* Free structure */
184     free( p_main->p_msg );
185 }
186
187 /*****************************************************************************
188  * intf_Msg: print a message                                             (ok ?)
189  *****************************************************************************
190  * This function queue a message for later printing, or print it immediately
191  * if the queue isn't used.
192  *****************************************************************************/
193 void intf_Msg( char *psz_format, ... )
194 {
195     va_list ap;
196
197     va_start( ap, psz_format );
198     QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
199     va_end( ap );
200 }
201
202 /*****************************************************************************
203  * intf_ErrMsg : print an error message                                  (ok ?)
204  *****************************************************************************
205  * This function is the same as intf_Msg, except that it prints its messages
206  * on stderr.
207  *****************************************************************************/
208 void intf_ErrMsg( char *psz_format, ... )
209 {
210     va_list ap;
211
212     va_start( ap, psz_format );
213     QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
214     va_end( ap );
215 }
216
217 /*****************************************************************************
218  * intf_WarnMsg : print a warning message
219  *****************************************************************************
220  * This function is the same as intf_Msg, except that it concerns warning
221  * messages for testing purpose.
222  *****************************************************************************/
223 void intf_WarnMsg( int i_level, char *psz_format, ... )
224 {
225     va_list ap;
226     
227     if( i_level >= p_main->i_warning_level )
228     {
229         va_start( ap, psz_format );
230         QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
231         va_end( ap );
232     }
233 }
234
235
236 /*****************************************************************************
237  * intf_IntfMsg : print an interface message                             (ok ?)
238  *****************************************************************************
239  * In opposition to all other intf_*Msg function, this function does not print
240  * it's message on default terminal (stdout or stderr), but send it to
241  * interface (in fact to the X11 console). This means that the interface MUST
242  * be initialized and a X11 console openned before this function is used, and
243  * that once the console is closed, this call is vorbidden.
244  * Practically, only the interface thread itself should call this function, and
245  * flush all messages before intf_CloseX11Console() is called.
246  *****************************************************************************/
247 void intf_IntfMsg(char *psz_format, ...)
248 {
249     va_list ap;
250
251     va_start( ap, psz_format );
252     QueueMsg( p_main->p_msg, INTF_MSG_INTF, psz_format, ap );
253     va_end( ap );
254 }
255
256 /*****************************************************************************
257  * _intf_DbgMsg: print a debugging message                               (ok ?)
258  *****************************************************************************
259  * This function prints a debugging message. Compared to other intf_*Msg
260  * functions, it is only defined if DEBUG is defined and require a file name,
261  * a function name and a line number as additionnal debugging informations. It
262  * also prints a debugging header for each received line.
263  *****************************************************************************/
264 #ifdef DEBUG
265 void _intf_DbgMsg( char *psz_file, char *psz_function, int i_line,
266                    char *psz_format, ...)
267 {
268     va_list ap;
269
270     va_start( ap, psz_format );
271     QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
272                  psz_format, ap );
273     va_end( ap );
274 }
275 #endif
276
277 /*****************************************************************************
278  * intf_MsgImm: print a message                                          (ok ?)
279  *****************************************************************************
280  * This function prints a message immediately. If the queue is used, all
281  * waiting messages are also printed.
282  *****************************************************************************/
283 void intf_MsgImm( char *psz_format, ... )
284 {
285     va_list ap;
286
287     va_start( ap, psz_format );
288     QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
289     va_end( ap );
290     intf_FlushMsg();
291 }
292
293 /*****************************************************************************
294  * intf_ErrMsgImm: print an error message immediately                    (ok ?)
295  *****************************************************************************
296  * This function is the same as intf_MsgImm, except that it prints its message
297  * on stderr.
298  *****************************************************************************/
299 void intf_ErrMsgImm(char *psz_format, ...)
300 {
301     va_list ap;
302
303     va_start( ap, psz_format );
304     QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
305     va_end( ap );
306     intf_FlushMsg();
307 }
308
309 /*****************************************************************************
310  * intf_WarnMsgImm : print a warning message
311  *****************************************************************************
312  * This function is the same as intf_MsgImm, except that it concerns warning
313  * messages for testing purpose.
314  *****************************************************************************/
315 void intf_WarnMsgImm( int i_level, char *psz_format, ... )
316 {
317     va_list ap;
318
319     if( i_level >= p_main->i_warning_level )
320     {
321         va_start( ap, psz_format );
322         QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
323         va_end( ap );
324     }
325     intf_FlushMsg();
326 }
327
328
329
330 /*****************************************************************************
331  * _intf_DbgMsgImm: print a debugging message immediately                (ok ?)
332  *****************************************************************************
333  * This function is the same as intf_DbgMsgImm, except that it prints its
334  * message immediately. It should only be called through the macro
335  * intf_DbgMsgImm().
336  *****************************************************************************/
337 #ifdef DEBUG
338 void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
339                       char *psz_format, ...)
340 {
341     va_list ap;
342
343     va_start( ap, psz_format );
344     QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
345                  psz_format, ap );
346     va_end( ap );
347     intf_FlushMsg();
348 }
349 #endif
350
351 /*****************************************************************************
352  * intf_WarnHexDump : print a hexadecimal dump of a memory area
353  *****************************************************************************
354  * This is convenient for debugging purposes.
355  *****************************************************************************/
356 void intf_WarnHexDump( int i_level, void *p_data, int i_size )
357 {
358     int   i_index = 0;
359     int   i_subindex;
360     char  p_string[75];
361     u8   *p_area = (u8 *)p_data;
362
363     intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
364                            i_size, p_data );
365
366     while( i_index < i_size )
367     {
368         i_subindex = 0;
369
370         while( ( i_subindex < 24 ) && ( i_index + i_subindex < i_size ) )
371         {
372             sprintf( p_string + 3 * i_subindex, "%.2x ",
373                      p_area[ i_index + i_subindex ] );
374
375             i_subindex++;
376         }
377
378         /* -1 here is safe because we know we printed at least one */
379         p_string[ 3 * i_subindex - 1 ] = '\0';
380         intf_WarnMsg( i_level, "0x%.4x: %s", i_index, p_string );
381
382         i_index += 24;
383     }
384
385     intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
386 }
387
388 /*****************************************************************************
389  * intf_FlushMsg                                                        (ok ?)
390  *****************************************************************************
391  * Print all messages remaining in queue: get lock and call FlushLockedMsg.
392  * This function does nothing if the message queue isn't used.
393  * This function is only implemented if message queue is used. If not, it is
394  * an empty macro.
395  *****************************************************************************/
396 #ifdef INTF_MSG_QUEUE
397 void intf_FlushMsg( void )
398 {
399     vlc_mutex_lock( &p_main->p_msg->lock );                      /* get lock */
400     FlushLockedMsg( p_main->p_msg );                       /* flush messages */
401     vlc_mutex_unlock( &p_main->p_msg->lock );              /* give lock back */
402 }
403 #endif
404
405 /* following functions are local */
406
407 /*****************************************************************************
408  * QueueMsg: add a message to a queue
409  *****************************************************************************
410  * This function provide basic functionnalities to other intf_*Msg functions.
411  * It add a message to a queue (after having printed all stored messages if it
412  * is full. If the message can't be converted to string in memory, it exit the
413  * program. If the queue is not used, it prints the message immediately.
414  *****************************************************************************/
415 static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list ap )
416 {
417     char *                  psz_str;             /* formatted message string */
418     intf_msg_item_t *       p_msg_item;                /* pointer to message */
419
420 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
421     intf_msg_item_t         msg_item;                             /* message */
422     p_msg_item =           &msg_item;
423 #endif /*....................................................................*/
424
425     /*
426      * Convert message to string
427      */
428 #ifdef HAVE_VASPRINTF
429     vasprintf( &psz_str, psz_format, ap );
430 #else
431     psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
432 #endif
433     if( psz_str == NULL )
434     {
435         fprintf(stderr, "warning: can't store following message (%s): ",
436                 strerror(errno) );
437         vfprintf(stderr, psz_format, ap );
438         fprintf(stderr, "\n" );
439         exit( errno );
440     }
441 #ifdef HAVE_VASPRINTF
442 #else
443     vsprintf( psz_str, psz_format, ap );
444 #endif
445
446 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
447     vlc_mutex_lock( &p_msg->lock );                              /* get lock */
448     if( p_msg->i_count == INTF_MSG_QSIZE )          /* flush queue if needed */
449     {
450 #ifdef DEBUG               /* in debug mode, queue overflow causes a warning */
451         fprintf(stderr, "warning: message queue overflow\n" );
452 #endif
453         FlushLockedMsg( p_msg );
454     }
455     p_msg_item = p_msg->msg + p_msg->i_count++;            /* select message */
456 #endif /*.............................................. end of queue mode ...*/
457
458     /*
459      * Fill message information fields
460      */
461     p_msg_item->i_type =     i_type;
462     p_msg_item->psz_msg =    psz_str;
463 #ifdef DEBUG    
464     p_msg_item->date =       mdate();
465 #endif
466
467 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
468     vlc_mutex_unlock( &p_msg->lock );                      /* give lock back */
469 #else /*....................................................... instant mode */
470     PrintMsg( p_msg_item );                                 /* print message */
471     free( psz_str );                                    /* free message data */
472 #endif /*....................................................................*/
473 }
474
475 /*****************************************************************************
476  * QueueDbgMsg: add a message to a queue with debugging informations
477  *****************************************************************************
478  * This function is the same as QueueMsg, except that it is only defined when
479  * DEBUG is define, and require additionnal debugging informations.
480  *****************************************************************************/
481 #ifdef DEBUG
482 static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
483                         int i_line, char *psz_format, va_list ap)
484 {
485     char *                  psz_str;             /* formatted message string */
486     intf_msg_item_t *       p_msg_item;                /* pointer to message */
487
488 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
489     intf_msg_item_t         msg_item;                             /* message */
490     p_msg_item =           &msg_item;
491 #endif /*....................................................................*/
492
493     /*
494      * Convert message to string
495      */
496 #ifdef HAVE_VASPRINTF
497     vasprintf( &psz_str, psz_format, ap );
498 #else
499     psz_str = (char*) malloc( INTF_MAX_MSG_SIZE );
500     vsprintf( psz_str, psz_format, ap );
501 #endif
502     if( psz_str == NULL )
503     {
504         fprintf(stderr, "warning: can't store following message (%s): ",
505                 strerror(errno) );
506         fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
507         vfprintf(stderr, psz_format, ap );
508         fprintf(stderr, "\n" );
509         exit( errno );
510     }
511
512 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
513     vlc_mutex_lock( &p_msg->lock );                              /* get lock */
514     if( p_msg->i_count == INTF_MSG_QSIZE )          /* flush queue if needed */
515     {
516         fprintf(stderr, "warning: message queue overflow\n" );
517         FlushLockedMsg( p_msg );
518     }
519     p_msg_item = p_msg->msg + p_msg->i_count++;            /* select message */
520 #endif /*.............................................. end of queue mode ...*/
521
522     /*
523      * Fill message information fields
524      */
525     p_msg_item->i_type =       INTF_MSG_DBG;
526     p_msg_item->psz_msg =      psz_str;
527     p_msg_item->psz_file =     psz_file;
528     p_msg_item->psz_function = psz_function;
529     p_msg_item->i_line =       i_line;
530     p_msg_item->date =         mdate();
531
532 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
533     vlc_mutex_unlock( &p_msg->lock );                      /* give lock back */
534 #else /*....................................................... instant mode */
535     PrintMsg( p_msg_item );                                 /* print message */
536     free( psz_str );                                    /* free message data */
537 #endif /*....................................................................*/
538 }
539 #endif
540
541 /*****************************************************************************
542  * FlushLockedMsg                                                       (ok ?)
543  *****************************************************************************
544  * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
545  * this function does not check the lock. This function is only defined if
546  * INTF_MSG_QUEUE is defined.
547  *****************************************************************************/
548 #ifdef INTF_MSG_QUEUE
549 static void FlushLockedMsg ( intf_msg_t *p_msg )
550 {
551     int i_index;
552
553     for( i_index = 0; i_index < p_msg->i_count; i_index++ )
554     {
555         /* Print message and free message data */
556         PrintMsg( &p_msg->msg[i_index] );
557         free( p_msg->msg[i_index].psz_msg );
558     }
559
560     p_msg->i_count = 0;
561 }
562 #endif
563
564 /*****************************************************************************
565  * PrintMsg: print a message                                             (ok ?)
566  *****************************************************************************
567  * Print a single message. The message data is not freed. This function exists
568  * in two version. The DEBUG version prints a date with each message, and is
569  * able to log messages (if DEBUG_LOG is defined).
570  * The normal one just prints messages to the screen.
571  *****************************************************************************/
572 #ifdef DEBUG
573
574 static void PrintMsg( intf_msg_item_t *p_msg )
575 {
576     char    psz_date[MSTRTIME_MAX_SIZE];            /* formatted time buffer */
577     char *  psz_msg;                                       /* message buffer */
578
579     /* Format message - the message is formatted here because in case the log
580      * file is used, it avoids another format string parsing */
581     switch( p_msg->i_type )
582     {
583     case INTF_MSG_STD:                                   /* regular messages */
584     case INTF_MSG_ERR:
585         asprintf( &psz_msg, "%s", p_msg->psz_msg );
586         break;
587
588     case INTF_MSG_WARN:                                   /* Warning message */
589         mstrtime( psz_date, p_msg->date );
590         asprintf( &psz_msg, "(%s) %s",
591                   psz_date, p_msg->psz_msg );
592
593         break;
594         
595     case INTF_MSG_INTF:                                /* interface messages */
596         asprintf( &psz_msg, "%s", p_msg->psz_msg );
597         break;
598
599     case INTF_MSG_DBG:                                     /* debug messages */
600         mstrtime( psz_date, p_msg->date );
601         asprintf( &psz_msg, "(%s) " INTF_MSG_DBG_FORMAT "%s",
602                   psz_date, p_msg->psz_file, p_msg->psz_function, p_msg->i_line,
603                   p_msg->psz_msg );
604         break;
605     }
606
607     /* Check if formatting function succeeded */
608     if( psz_msg == NULL )
609     {
610         fprintf( stderr, "error: can not format message (%s): %s\n",
611                  strerror( errno ), p_msg->psz_msg );
612         return;
613     }
614
615     /*
616      * Print messages
617      */
618     switch( p_msg->i_type )
619     {
620     case INTF_MSG_STD:                                  /* standard messages */
621         fprintf( stdout, "%s\n", psz_msg );
622         break;
623     case INTF_MSG_ERR:                                     /* error messages */
624     case INTF_MSG_WARN:
625 #ifndef DEBUG_LOG_ONLY
626     case INTF_MSG_DBG:                                 /* debugging messages */
627 #endif
628         fprintf( stderr, "%s\n", psz_msg );
629         break;
630     case INTF_MSG_INTF:                                /* interface messages */
631         intf_ConsolePrint( p_main->p_intf->p_console, psz_msg );
632         break;
633     }
634
635 #ifdef DEBUG_LOG
636     /* Append all messages to log file */
637     if( p_main->p_msg->p_log_file != NULL )
638     {
639         fwrite( psz_msg, strlen( psz_msg ), 1, p_main->p_msg->p_log_file );
640         fwrite( "\n", 1, 1, p_main->p_msg->p_log_file );
641     }
642 #endif
643
644     /* Free formatted message */
645     free( psz_msg );
646 }
647
648 #else
649
650 static void PrintMsg( intf_msg_item_t *p_msg )
651 {
652     /*
653      * Print messages on screen
654      */
655     switch( p_msg->i_type )
656     {
657     case INTF_MSG_STD:                                  /* standard messages */
658     case INTF_MSG_DBG:                                     /* debug messages */
659         fprintf( stdout, "%s\n", p_msg->psz_msg );
660         break;
661     case INTF_MSG_ERR:                                     /* error messages */
662     case INTF_MSG_WARN:
663         fprintf( stderr, "%s\n", p_msg->psz_msg );        /* warning message */
664         break;
665     case INTF_MSG_INTF:                                /* interface messages */
666         intf_ConsolePrint( p_main->p_intf->p_console, p_msg->psz_msg );
667         break;
668     }
669 }
670
671 #endif
672