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 * $Id: intf_msg.c,v 1.28 2001/03/21 13:42:34 sam Exp $
9 * Authors: Vincent Seguin <seguin@via.ecp.fr>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
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() */
45 #include "interface.h"
46 #include "intf_console.h"
50 /*****************************************************************************
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 *****************************************************************************/
59 int i_type; /* message type, see below */
60 char * psz_msg; /* the message itself */
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 */
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 #define INTF_MSG_WARN 4 /* warning message*/
80 /*****************************************************************************
82 *****************************************************************************
83 * Store all data requiered by messages interfaces. It has a single reference
85 *****************************************************************************/
86 typedef struct intf_msg_s
90 vlc_mutex_t lock; /* message queue lock */
91 int i_count; /* number of messages stored */
92 intf_msg_item_t msg[INTF_MSG_QSIZE]; /* message queue */
97 FILE * p_log_file; /* log file */
100 #if !defined(INTF_MSG_QUEUE) && !defined(DEBUG_LOG)
101 /* If neither messages queue, neither log file is used, then the structure
102 * is empty. However, empty structures are not allowed in C. Therefore, a
103 * dummy integer is used to fill it. */
104 int i_dummy; /* unused filler */
108 /*****************************************************************************
110 *****************************************************************************/
112 static void QueueMsg ( intf_msg_t *p_msg, int i_type,
113 char *psz_format, va_list ap );
114 static void PrintMsg ( intf_msg_item_t *p_msg );
116 static void QueueDbgMsg ( intf_msg_t *p_msg, char *psz_file,
117 char *psz_function, int i_line,
118 char *psz_format, va_list ap );
120 #ifdef INTF_MSG_QUEUE
121 static void FlushLockedMsg ( intf_msg_t *p_msg );
125 /*****************************************************************************
126 * intf_MsgCreate: initialize messages interface (ok ?)
127 *****************************************************************************
128 * This functions has to be called before any call to other intf_*Msg functions.
129 * It set up the locks and the message queue if it is used.
130 *****************************************************************************/
131 p_intf_msg_t intf_MsgCreate( void )
135 /* Allocate structure */
136 p_msg = malloc( sizeof( intf_msg_t ) );
143 #ifdef INTF_MSG_QUEUE
144 /* Message queue initialization */
145 vlc_mutex_init( &p_msg->lock ); /* intialize lock */
146 p_msg->i_count = 0; /* queue is empty */
151 /* Log file initialization - on failure, file pointer will be null,
152 * and no log will be issued, but this is not considered as an
154 p_msg->p_log_file = fopen( DEBUG_LOG, "w" );
160 /*****************************************************************************
161 * intf_MsgDestroy: free resources allocated by intf_InitMsg (ok ?)
162 *****************************************************************************
163 * This functions prints all messages remaining in queue, then free all the
164 * resources allocated by intf_InitMsg.
165 * No other messages interface functions should be called after this one.
166 *****************************************************************************/
167 void intf_MsgDestroy( void )
169 intf_FlushMsg(); /* print all remaining messages */
172 /* Close log file if any */
173 if( p_main->p_msg->p_log_file != NULL )
175 fclose( p_main->p_msg->p_log_file );
179 #ifdef INTF_MSG_QUEUE
181 vlc_mutex_destroy( &p_main->p_msg->lock );
185 free( p_main->p_msg );
188 /*****************************************************************************
189 * intf_Msg: print a message (ok ?)
190 *****************************************************************************
191 * This function queue a message for later printing, or print it immediately
192 * if the queue isn't used.
193 *****************************************************************************/
194 void intf_Msg( char *psz_format, ... )
198 va_start( ap, psz_format );
199 QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
203 /*****************************************************************************
204 * intf_ErrMsg : print an error message (ok ?)
205 *****************************************************************************
206 * This function is the same as intf_Msg, except that it prints its messages
208 *****************************************************************************/
209 void intf_ErrMsg( char *psz_format, ... )
213 va_start( ap, psz_format );
214 QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
218 /*****************************************************************************
219 * intf_WarnMsg : print a warning message
220 *****************************************************************************
221 * This function is the same as intf_Msg, except that it concerns warning
222 * messages for testing purpose.
223 *****************************************************************************/
224 void intf_WarnMsg( int i_level, char *psz_format, ... )
228 if( i_level >= p_main->i_warning_level )
230 va_start( ap, psz_format );
231 QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
237 /*****************************************************************************
238 * intf_IntfMsg : print an interface message (ok ?)
239 *****************************************************************************
240 * In opposition to all other intf_*Msg function, this function does not print
241 * it's message on default terminal (stdout or stderr), but send it to
242 * interface (in fact to the X11 console). This means that the interface MUST
243 * be initialized and a X11 console openned before this function is used, and
244 * that once the console is closed, this call is vorbidden.
245 * Practically, only the interface thread itself should call this function, and
246 * flush all messages before intf_CloseX11Console() is called.
247 *****************************************************************************/
248 void intf_IntfMsg(char *psz_format, ...)
252 va_start( ap, psz_format );
253 QueueMsg( p_main->p_msg, INTF_MSG_INTF, psz_format, ap );
257 /*****************************************************************************
258 * _intf_DbgMsg: print a debugging message (ok ?)
259 *****************************************************************************
260 * This function prints a debugging message. Compared to other intf_*Msg
261 * functions, it is only defined if DEBUG is defined and require a file name,
262 * a function name and a line number as additionnal debugging informations. It
263 * also prints a debugging header for each received line.
264 *****************************************************************************/
266 void _intf_DbgMsg( char *psz_file, char *psz_function, int i_line,
267 char *psz_format, ...)
271 va_start( ap, psz_format );
272 QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
278 /*****************************************************************************
279 * intf_MsgImm: print a message (ok ?)
280 *****************************************************************************
281 * This function prints a message immediately. If the queue is used, all
282 * waiting messages are also printed.
283 *****************************************************************************/
284 void intf_MsgImm( char *psz_format, ... )
288 va_start( ap, psz_format );
289 QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
294 /*****************************************************************************
295 * intf_ErrMsgImm: print an error message immediately (ok ?)
296 *****************************************************************************
297 * This function is the same as intf_MsgImm, except that it prints its message
299 *****************************************************************************/
300 void intf_ErrMsgImm(char *psz_format, ...)
304 va_start( ap, psz_format );
305 QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
310 /*****************************************************************************
311 * intf_WarnMsgImm : print a warning message
312 *****************************************************************************
313 * This function is the same as intf_MsgImm, except that it concerns warning
314 * messages for testing purpose.
315 *****************************************************************************/
316 void intf_WarnMsgImm( int i_level, char *psz_format, ... )
320 if( i_level >= p_main->i_warning_level )
322 va_start( ap, psz_format );
323 QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
331 /*****************************************************************************
332 * _intf_DbgMsgImm: print a debugging message immediately (ok ?)
333 *****************************************************************************
334 * This function is the same as intf_DbgMsgImm, except that it prints its
335 * message immediately. It should only be called through the macro
337 *****************************************************************************/
339 void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
340 char *psz_format, ...)
344 va_start( ap, psz_format );
345 QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
352 /*****************************************************************************
353 * intf_WarnHexDump : print a hexadecimal dump of a memory area
354 *****************************************************************************
355 * This is convenient for debugging purposes.
356 *****************************************************************************/
357 void intf_WarnHexDump( int i_level, void *p_data, int i_size )
362 u8 *p_area = (u8 *)p_data;
364 intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
367 while( i_index < i_size )
371 while( ( i_subindex < 24 ) && ( i_index + i_subindex < i_size ) )
373 sprintf( p_string + 3 * i_subindex, "%.2x ",
374 p_area[ i_index + i_subindex ] );
379 /* -1 here is safe because we know we printed at least one */
380 p_string[ 3 * i_subindex - 1 ] = '\0';
381 intf_WarnMsg( i_level, "0x%.4x: %s", i_index, p_string );
386 intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
389 /*****************************************************************************
390 * intf_FlushMsg (ok ?)
391 *****************************************************************************
392 * Print all messages remaining in queue: get lock and call FlushLockedMsg.
393 * This function does nothing if the message queue isn't used.
394 * This function is only implemented if message queue is used. If not, it is
396 *****************************************************************************/
397 #ifdef INTF_MSG_QUEUE
398 void intf_FlushMsg( void )
400 vlc_mutex_lock( &p_main->p_msg->lock ); /* get lock */
401 FlushLockedMsg( p_main->p_msg ); /* flush messages */
402 vlc_mutex_unlock( &p_main->p_msg->lock ); /* give lock back */
406 /* following functions are local */
408 /*****************************************************************************
409 * QueueMsg: add a message to a queue
410 *****************************************************************************
411 * This function provide basic functionnalities to other intf_*Msg functions.
412 * It add a message to a queue (after having printed all stored messages if it
413 * is full. If the message can't be converted to string in memory, it exit the
414 * program. If the queue is not used, it prints the message immediately.
415 *****************************************************************************/
416 static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list ap )
418 char * psz_str; /* formatted message string */
419 intf_msg_item_t * p_msg_item; /* pointer to message */
421 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
422 intf_msg_item_t msg_item; /* message */
423 p_msg_item = &msg_item;
424 #endif /*....................................................................*/
427 * Convert message to string
429 #ifdef HAVE_VASPRINTF
430 vasprintf( &psz_str, psz_format, ap );
432 psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
434 if( psz_str == NULL )
436 fprintf(stderr, "warning: can't store following message (%s): ",
438 vfprintf(stderr, psz_format, ap );
439 fprintf(stderr, "\n" );
442 #ifdef HAVE_VASPRINTF
444 vsprintf( psz_str, psz_format, ap );
447 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
448 vlc_mutex_lock( &p_msg->lock ); /* get lock */
449 if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
451 #ifdef DEBUG /* in debug mode, queue overflow causes a warning */
452 fprintf(stderr, "warning: message queue overflow\n" );
454 FlushLockedMsg( p_msg );
456 p_msg_item = p_msg->msg + p_msg->i_count++; /* select message */
457 #endif /*.............................................. end of queue mode ...*/
460 * Fill message information fields
462 p_msg_item->i_type = i_type;
463 p_msg_item->psz_msg = psz_str;
465 p_msg_item->date = mdate();
468 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
469 vlc_mutex_unlock( &p_msg->lock ); /* give lock back */
470 #else /*....................................................... instant mode */
471 PrintMsg( p_msg_item ); /* print message */
472 free( psz_str ); /* free message data */
473 #endif /*....................................................................*/
476 /*****************************************************************************
477 * QueueDbgMsg: add a message to a queue with debugging informations
478 *****************************************************************************
479 * This function is the same as QueueMsg, except that it is only defined when
480 * DEBUG is define, and require additionnal debugging informations.
481 *****************************************************************************/
483 static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
484 int i_line, char *psz_format, va_list ap)
486 char * psz_str; /* formatted message string */
487 intf_msg_item_t * p_msg_item; /* pointer to message */
489 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
490 intf_msg_item_t msg_item; /* message */
491 p_msg_item = &msg_item;
492 #endif /*....................................................................*/
495 * Convert message to string
497 #ifdef HAVE_VASPRINTF
498 vasprintf( &psz_str, psz_format, ap );
500 psz_str = (char*) malloc( INTF_MAX_MSG_SIZE );
501 vsprintf( psz_str, psz_format, ap );
503 if( psz_str == NULL )
505 fprintf(stderr, "warning: can't store following message (%s): ",
507 fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
508 vfprintf(stderr, psz_format, ap );
509 fprintf(stderr, "\n" );
513 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
514 vlc_mutex_lock( &p_msg->lock ); /* get lock */
515 if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
517 fprintf(stderr, "warning: message queue overflow\n" );
518 FlushLockedMsg( p_msg );
520 p_msg_item = p_msg->msg + p_msg->i_count++; /* select message */
521 #endif /*.............................................. end of queue mode ...*/
524 * Fill message information fields
526 p_msg_item->i_type = INTF_MSG_DBG;
527 p_msg_item->psz_msg = psz_str;
528 p_msg_item->psz_file = psz_file;
529 p_msg_item->psz_function = psz_function;
530 p_msg_item->i_line = i_line;
531 p_msg_item->date = mdate();
533 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
534 vlc_mutex_unlock( &p_msg->lock ); /* give lock back */
535 #else /*....................................................... instant mode */
536 PrintMsg( p_msg_item ); /* print message */
537 free( psz_str ); /* free message data */
538 #endif /*....................................................................*/
542 /*****************************************************************************
543 * FlushLockedMsg (ok ?)
544 *****************************************************************************
545 * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
546 * this function does not check the lock. This function is only defined if
547 * INTF_MSG_QUEUE is defined.
548 *****************************************************************************/
549 #ifdef INTF_MSG_QUEUE
550 static void FlushLockedMsg ( intf_msg_t *p_msg )
554 for( i_index = 0; i_index < p_msg->i_count; i_index++ )
556 /* Print message and free message data */
557 PrintMsg( &p_msg->msg[i_index] );
558 free( p_msg->msg[i_index].psz_msg );
565 /*****************************************************************************
566 * PrintMsg: print a message (ok ?)
567 *****************************************************************************
568 * Print a single message. The message data is not freed. This function exists
569 * in two version. The DEBUG version prints a date with each message, and is
570 * able to log messages (if DEBUG_LOG is defined).
571 * The normal one just prints messages to the screen.
572 *****************************************************************************/
575 static void PrintMsg( intf_msg_item_t *p_msg )
577 char psz_date[MSTRTIME_MAX_SIZE]; /* formatted time buffer */
578 char * psz_msg; /* message buffer */
580 /* Format message - the message is formatted here because in case the log
581 * file is used, it avoids another format string parsing */
582 switch( p_msg->i_type )
584 case INTF_MSG_STD: /* regular messages */
586 asprintf( &psz_msg, "%s", p_msg->psz_msg );
589 case INTF_MSG_WARN: /* Warning message */
590 mstrtime( psz_date, p_msg->date );
591 asprintf( &psz_msg, "(%s) %s",
592 psz_date, p_msg->psz_msg );
596 case INTF_MSG_INTF: /* interface messages */
597 asprintf( &psz_msg, "%s", p_msg->psz_msg );
600 case INTF_MSG_DBG: /* debug messages */
601 mstrtime( psz_date, p_msg->date );
602 asprintf( &psz_msg, "(%s) " INTF_MSG_DBG_FORMAT "%s",
603 psz_date, p_msg->psz_file, p_msg->psz_function, p_msg->i_line,
608 /* Check if formatting function succeeded */
609 if( psz_msg == NULL )
611 fprintf( stderr, "error: can not format message (%s): %s\n",
612 strerror( errno ), p_msg->psz_msg );
619 switch( p_msg->i_type )
621 case INTF_MSG_STD: /* standard messages */
622 fprintf( stdout, "%s\n", psz_msg );
624 case INTF_MSG_ERR: /* error messages */
626 #ifndef DEBUG_LOG_ONLY
627 case INTF_MSG_DBG: /* debugging messages */
629 fprintf( stderr, "%s\n", psz_msg );
631 case INTF_MSG_INTF: /* interface messages */
632 intf_ConsolePrint( p_main->p_intf->p_console, psz_msg );
637 /* Append all messages to log file */
638 if( p_main->p_msg->p_log_file != NULL )
640 fwrite( psz_msg, strlen( psz_msg ), 1, p_main->p_msg->p_log_file );
641 fwrite( "\n", 1, 1, p_main->p_msg->p_log_file );
645 /* Free formatted message */
651 static void PrintMsg( intf_msg_item_t *p_msg )
654 * Print messages on screen
656 switch( p_msg->i_type )
658 case INTF_MSG_STD: /* standard messages */
659 case INTF_MSG_DBG: /* debug messages */
660 fprintf( stdout, "%s\n", p_msg->psz_msg );
662 case INTF_MSG_ERR: /* error messages */
664 fprintf( stderr, "%s\n", p_msg->psz_msg ); /* warning message */
666 case INTF_MSG_INTF: /* interface messages */
667 intf_ConsolePrint( p_main->p_intf->p_console, p_msg->psz_msg );