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