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
8 * Authors: Vincent Seguin <seguin@via.ecp.fr>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
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() */
44 #include "interface.h"
45 #include "intf_console.h"
49 /*****************************************************************************
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 *****************************************************************************/
58 int i_type; /* message type, see below */
59 char * psz_msg; /* the message itself */
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 */
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*/
79 /*****************************************************************************
81 *****************************************************************************
82 * Store all data requiered by messages interfaces. It has a single reference
84 *****************************************************************************/
85 typedef struct intf_msg_s
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 */
96 FILE * p_log_file; /* log file */
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 */
107 /*****************************************************************************
109 *****************************************************************************/
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 );
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 );
119 #ifdef INTF_MSG_QUEUE
120 static void FlushLockedMsg ( intf_msg_t *p_msg );
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 )
134 /* Allocate structure */
135 p_msg = malloc( sizeof( intf_msg_t ) );
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 */
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
153 p_msg->p_log_file = fopen( DEBUG_LOG, "w" );
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 )
168 intf_FlushMsg(); /* print all remaining messages */
171 /* Close log file if any */
172 if( p_main->p_msg->p_log_file != NULL )
174 fclose( p_main->p_msg->p_log_file );
178 #ifdef INTF_MSG_QUEUE
180 vlc_mutex_destroy( &p_main->p_msg->lock );
184 free( p_main->p_msg );
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, ... )
197 va_start( ap, psz_format );
198 QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
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
207 *****************************************************************************/
208 void intf_ErrMsg( char *psz_format, ... )
212 va_start( ap, psz_format );
213 QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
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, ... )
227 if( i_level >= p_main->i_warning_level )
229 va_start( ap, psz_format );
230 QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
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, ...)
251 va_start( ap, psz_format );
252 QueueMsg( p_main->p_msg, INTF_MSG_INTF, psz_format, ap );
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 *****************************************************************************/
265 void _intf_DbgMsg( char *psz_file, char *psz_function, int i_line,
266 char *psz_format, ...)
270 va_start( ap, psz_format );
271 QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
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, ... )
287 va_start( ap, psz_format );
288 QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
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
298 *****************************************************************************/
299 void intf_ErrMsgImm(char *psz_format, ...)
303 va_start( ap, psz_format );
304 QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
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, ... )
319 if( i_level >= p_main->i_warning_level )
321 va_start( ap, psz_format );
322 QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
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
336 *****************************************************************************/
338 void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
339 char *psz_format, ...)
343 va_start( ap, psz_format );
344 QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
351 /*****************************************************************************
352 * intf_FlushMsg (ok ?)
353 *****************************************************************************
354 * Print all messages remaining in queue: get lock and call FlushLockedMsg.
355 * This function does nothing if the message queue isn't used.
356 * This function is only implemented if message queue is used. If not, it is
358 *****************************************************************************/
359 #ifdef INTF_MSG_QUEUE
360 void intf_FlushMsg( void )
362 vlc_mutex_lock( &p_main->p_msg->lock ); /* get lock */
363 FlushLockedMsg( p_main->p_msg ); /* flush messages */
364 vlc_mutex_unlock( &p_main->p_msg->lock ); /* give lock back */
368 /* following functions are local */
370 /*****************************************************************************
371 * QueueMsg: add a message to a queue
372 *****************************************************************************
373 * This function provide basic functionnalities to other intf_*Msg functions.
374 * It add a message to a queue (after having printed all stored messages if it
375 * is full. If the message can't be converted to string in memory, it exit the
376 * program. If the queue is not used, it prints the message immediately.
377 *****************************************************************************/
378 static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list ap )
380 char * psz_str; /* formatted message string */
381 intf_msg_item_t * p_msg_item; /* pointer to message */
383 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
384 intf_msg_item_t msg_item; /* message */
385 p_msg_item = &msg_item;
386 #endif /*....................................................................*/
389 * Convert message to string
391 #ifdef HAVE_VASPRINTF
392 vasprintf( &psz_str, psz_format, ap );
394 psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
396 if( psz_str == NULL )
398 fprintf(stderr, "warning: can't store following message (%s): ",
400 vfprintf(stderr, psz_format, ap );
401 fprintf(stderr, "\n" );
404 #ifdef HAVE_VASPRINTF
406 vsprintf( psz_str, psz_format, ap );
409 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
410 vlc_mutex_lock( &p_msg->lock ); /* get lock */
411 if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
413 #ifdef DEBUG /* in debug mode, queue overflow causes a warning */
414 fprintf(stderr, "warning: message queue overflow\n" );
416 FlushLockedMsg( p_msg );
418 p_msg_item = p_msg->msg + p_msg->i_count++; /* select message */
419 #endif /*.............................................. end of queue mode ...*/
422 * Fill message information fields
424 p_msg_item->i_type = i_type;
425 p_msg_item->psz_msg = psz_str;
427 p_msg_item->date = mdate();
430 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
431 vlc_mutex_unlock( &p_msg->lock ); /* give lock back */
432 #else /*....................................................... instant mode */
433 PrintMsg( p_msg_item ); /* print message */
434 free( psz_str ); /* free message data */
435 #endif /*....................................................................*/
438 /*****************************************************************************
439 * QueueDbgMsg: add a message to a queue with debugging informations
440 *****************************************************************************
441 * This function is the same as QueueMsg, except that it is only defined when
442 * DEBUG is define, and require additionnal debugging informations.
443 *****************************************************************************/
445 static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
446 int i_line, char *psz_format, va_list ap)
448 char * psz_str; /* formatted message string */
449 intf_msg_item_t * p_msg_item; /* pointer to message */
451 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
452 intf_msg_item_t msg_item; /* message */
453 p_msg_item = &msg_item;
454 #endif /*....................................................................*/
457 * Convert message to string
459 #ifdef HAVE_VASPRINTF
460 vasprintf( &psz_str, psz_format, ap );
462 psz_str = (char*) malloc( INTF_MAX_MSG_SIZE );
463 vsprintf( psz_str, psz_format, ap );
465 if( psz_str == NULL )
467 fprintf(stderr, "warning: can't store following message (%s): ",
469 fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
470 vfprintf(stderr, psz_format, ap );
471 fprintf(stderr, "\n" );
475 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
476 vlc_mutex_lock( &p_msg->lock ); /* get lock */
477 if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
479 fprintf(stderr, "warning: message queue overflow\n" );
480 FlushLockedMsg( p_msg );
482 p_msg_item = p_msg->msg + p_msg->i_count++; /* select message */
483 #endif /*.............................................. end of queue mode ...*/
486 * Fill message information fields
488 p_msg_item->i_type = INTF_MSG_DBG;
489 p_msg_item->psz_msg = psz_str;
490 p_msg_item->psz_file = psz_file;
491 p_msg_item->psz_function = psz_function;
492 p_msg_item->i_line = i_line;
493 p_msg_item->date = mdate();
495 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
496 vlc_mutex_unlock( &p_msg->lock ); /* give lock back */
497 #else /*....................................................... instant mode */
498 PrintMsg( p_msg_item ); /* print message */
499 free( psz_str ); /* free message data */
500 #endif /*....................................................................*/
504 /*****************************************************************************
505 * FlushLockedMsg (ok ?)
506 *****************************************************************************
507 * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
508 * this function does not check the lock. This function is only defined if
509 * INTF_MSG_QUEUE is defined.
510 *****************************************************************************/
511 #ifdef INTF_MSG_QUEUE
512 static void FlushLockedMsg ( intf_msg_t *p_msg )
516 for( i_index = 0; i_index < p_msg->i_count; i_index++ )
518 /* Print message and free message data */
519 PrintMsg( &p_msg->msg[i_index] );
520 free( p_msg->msg[i_index].psz_msg );
527 /*****************************************************************************
528 * PrintMsg: print a message (ok ?)
529 *****************************************************************************
530 * Print a single message. The message data is not freed. This function exists
531 * in two version. The DEBUG version prints a date with each message, and is
532 * able to log messages (if DEBUG_LOG is defined).
533 * The normal one just prints messages to the screen.
534 *****************************************************************************/
537 static void PrintMsg( intf_msg_item_t *p_msg )
539 char psz_date[MSTRTIME_MAX_SIZE]; /* formatted time buffer */
540 char * psz_msg; /* message buffer */
542 /* Format message - the message is formatted here because in case the log
543 * file is used, it avoids another format string parsing */
544 switch( p_msg->i_type )
546 case INTF_MSG_STD: /* regular messages */
548 asprintf( &psz_msg, "%s", p_msg->psz_msg );
551 case INTF_MSG_WARN: /* Warning message */
552 mstrtime( psz_date, p_msg->date );
553 asprintf( &psz_msg, "(%s) %s",
554 psz_date, p_msg->psz_msg );
558 case INTF_MSG_INTF: /* interface messages */
559 asprintf( &psz_msg, "%s", p_msg->psz_msg );
562 case INTF_MSG_DBG: /* debug messages */
563 mstrtime( psz_date, p_msg->date );
564 asprintf( &psz_msg, "(%s) " INTF_MSG_DBG_FORMAT "%s",
565 psz_date, p_msg->psz_file, p_msg->psz_function, p_msg->i_line,
570 /* Check if formatting function succeeded */
571 if( psz_msg == NULL )
573 fprintf( stderr, "error: can not format message (%s): %s\n",
574 strerror( errno ), p_msg->psz_msg );
581 switch( p_msg->i_type )
583 case INTF_MSG_STD: /* standard messages */
584 fprintf( stdout, "%s\n", psz_msg );
586 case INTF_MSG_ERR: /* error messages */
588 #ifndef DEBUG_LOG_ONLY
589 case INTF_MSG_DBG: /* debugging messages */
591 fprintf( stderr, "%s\n", psz_msg );
593 case INTF_MSG_INTF: /* interface messages */
594 intf_ConsolePrint( p_main->p_intf->p_console, psz_msg );
599 /* Append all messages to log file */
600 if( p_main->p_msg->p_log_file != NULL )
602 fwrite( psz_msg, strlen( psz_msg ), 1, p_main->p_msg->p_log_file );
603 fwrite( "\n", 1, 1, p_main->p_msg->p_log_file );
607 /* Free formatted message */
613 static void PrintMsg( intf_msg_item_t *p_msg )
616 * Print messages on screen
618 switch( p_msg->i_type )
620 case INTF_MSG_STD: /* standard messages */
621 case INTF_MSG_DBG: /* debug messages */
622 fprintf( stdout, "%s\n", p_msg->psz_msg );
624 case INTF_MSG_ERR: /* error messages */
626 fprintf( stderr, "%s\n", p_msg->psz_msg ); /* warning message */
628 case INTF_MSG_INTF: /* interface messages */
629 intf_ConsolePrint( p_main->p_intf->p_console, p_msg->psz_msg );