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