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