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.36 2001/06/02 01:09:03 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() */
39 #include <unistd.h> /* close(), write() */
48 #include "interface.h"
54 #define snprintf _snprintf /* snprintf not defined in mingw32 (bug?) */
58 /*****************************************************************************
60 *****************************************************************************
61 * Store a single message. Messages have a maximal size of INTF_MSG_MSGSIZE.
62 * If TRACE is defined, messages have a date field and debug messages are
63 * printed with a date to allow more precise profiling.
64 *****************************************************************************/
67 int i_type; /* message type, see below */
68 char * psz_msg; /* the message itself */
71 /* Debugging informations - in TRACE mode, debug messages have calling
72 * location informations printed */
73 mtime_t date; /* date of the message */
74 char * psz_file; /* file in which the function was called */
75 char * psz_function; /* function from which the function was called */
76 int i_line; /* line at which the function was called */
81 #define INTF_MSG_STD 0 /* standard message */
82 #define INTF_MSG_ERR 1 /* error message */
83 #define INTF_MSG_DBG 3 /* debug message */
84 #define INTF_MSG_WARN 4 /* warning message*/
87 /*****************************************************************************
89 *****************************************************************************
90 * Store all data requiered by messages interfaces. It has a single reference
92 *****************************************************************************/
93 typedef struct intf_msg_s
97 vlc_mutex_t lock; /* message queue lock */
98 int i_count; /* number of messages stored */
99 intf_msg_item_t msg[INTF_MSG_QSIZE]; /* message queue */
104 FILE * p_log_file; /* log file */
107 #if !defined(INTF_MSG_QUEUE) && !defined(TRACE_LOG)
108 /* If neither messages queue, neither log file is used, then the structure
109 * is empty. However, empty structures are not allowed in C. Therefore, a
110 * dummy integer is used to fill it. */
111 int i_dummy; /* unused filler */
115 /*****************************************************************************
117 *****************************************************************************/
119 static void QueueMsg ( intf_msg_t *p_msg, int i_type,
120 char *psz_format, va_list ap );
121 static void PrintMsg ( intf_msg_item_t *p_msg );
123 static void QueueDbgMsg ( intf_msg_t *p_msg, char *psz_file,
124 char *psz_function, int i_line,
125 char *psz_format, va_list ap );
127 #ifdef INTF_MSG_QUEUE
128 static void FlushLockedMsg ( intf_msg_t *p_msg );
132 /*****************************************************************************
133 * intf_MsgCreate: initialize messages interface (ok ?)
134 *****************************************************************************
135 * This functions has to be called before any call to other intf_*Msg functions.
136 * It set up the locks and the message queue if it is used.
137 *****************************************************************************/
138 p_intf_msg_t intf_MsgCreate( void )
142 /* Allocate structure */
143 p_msg = malloc( sizeof( intf_msg_t ) );
150 #ifdef INTF_MSG_QUEUE
151 /* Message queue initialization */
152 vlc_mutex_init( &p_msg->lock ); /* intialize lock */
153 p_msg->i_count = 0; /* queue is empty */
158 /* Log file initialization - on failure, file pointer will be null,
159 * and no log will be issued, but this is not considered as an
161 p_msg->p_log_file = fopen( TRACE_LOG, "w" );
167 /*****************************************************************************
168 * intf_MsgDestroy: free resources allocated by intf_InitMsg (ok ?)
169 *****************************************************************************
170 * This functions prints all messages remaining in queue, then free all the
171 * resources allocated by intf_InitMsg.
172 * No other messages interface functions should be called after this one.
173 *****************************************************************************/
174 void intf_MsgDestroy( void )
176 intf_FlushMsg(); /* print all remaining messages */
179 /* Close log file if any */
180 if( p_main->p_msg->p_log_file != NULL )
182 fclose( p_main->p_msg->p_log_file );
186 #ifdef INTF_MSG_QUEUE
188 vlc_mutex_destroy( &p_main->p_msg->lock );
192 free( p_main->p_msg );
195 /*****************************************************************************
196 * intf_Msg: print a message (ok ?)
197 *****************************************************************************
198 * This function queue a message for later printing, or print it immediately
199 * if the queue isn't used.
200 *****************************************************************************/
201 void intf_Msg( char *psz_format, ... )
205 va_start( ap, psz_format );
206 QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
210 /*****************************************************************************
211 * intf_ErrMsg : print an error message (ok ?)
212 *****************************************************************************
213 * This function is the same as intf_Msg, except that it prints its messages
215 *****************************************************************************/
216 void intf_ErrMsg( char *psz_format, ... )
220 va_start( ap, psz_format );
221 QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
225 /*****************************************************************************
226 * intf_WarnMsg : print a warning message
227 *****************************************************************************
228 * This function is the same as intf_Msg, except that it concerns warning
229 * messages for testing purpose.
230 *****************************************************************************/
231 void intf_WarnMsg( int i_level, char *psz_format, ... )
235 if( i_level <= p_main->i_warning_level )
237 va_start( ap, psz_format );
238 QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
244 /*****************************************************************************
245 * _intf_DbgMsg: print a debugging message (ok ?)
246 *****************************************************************************
247 * This function prints a debugging message. Compared to other intf_*Msg
248 * functions, it is only defined if TRACE is defined and require a file name,
249 * a function name and a line number as additionnal debugging informations. It
250 * also prints a debugging header for each received line.
251 *****************************************************************************/
253 void _intf_DbgMsg( char *psz_file, char *psz_function, int i_line,
254 char *psz_format, ...)
258 va_start( ap, psz_format );
259 QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
265 /*****************************************************************************
266 * intf_MsgImm: print a message (ok ?)
267 *****************************************************************************
268 * This function prints a message immediately. If the queue is used, all
269 * waiting messages are also printed.
270 *****************************************************************************/
271 void intf_MsgImm( char *psz_format, ... )
275 va_start( ap, psz_format );
276 QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
281 /*****************************************************************************
282 * intf_ErrMsgImm: print an error message immediately (ok ?)
283 *****************************************************************************
284 * This function is the same as intf_MsgImm, except that it prints its message
286 *****************************************************************************/
287 void intf_ErrMsgImm(char *psz_format, ...)
291 va_start( ap, psz_format );
292 QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
297 /*****************************************************************************
298 * intf_WarnMsgImm : print a warning message
299 *****************************************************************************
300 * This function is the same as intf_MsgImm, except that it concerns warning
301 * messages for testing purpose.
302 *****************************************************************************/
303 void intf_WarnMsgImm( int i_level, char *psz_format, ... )
307 if( i_level <= p_main->i_warning_level )
309 va_start( ap, psz_format );
310 QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
318 /*****************************************************************************
319 * _intf_DbgMsgImm: print a debugging message immediately (ok ?)
320 *****************************************************************************
321 * This function is the same as intf_DbgMsgImm, except that it prints its
322 * message immediately. It should only be called through the macro
324 *****************************************************************************/
326 void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
327 char *psz_format, ...)
331 va_start( ap, psz_format );
332 QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
339 /*****************************************************************************
340 * intf_WarnHexDump : print a hexadecimal dump of a memory area
341 *****************************************************************************
342 * This is convenient for debugging purposes.
343 *****************************************************************************/
344 void intf_WarnHexDump( int i_level, void *p_data, int i_size )
349 u8 *p_area = (u8 *)p_data;
351 intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
354 while( i_index < i_size )
358 while( ( i_subindex < 24 ) && ( i_index + i_subindex < i_size ) )
360 sprintf( p_string + 3 * i_subindex, "%.2x ",
361 p_area[ i_index + i_subindex ] );
366 /* -1 here is safe because we know we printed at least one */
367 p_string[ 3 * i_subindex - 1 ] = '\0';
368 intf_WarnMsg( i_level, "0x%.4x: %s", i_index, p_string );
373 intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
376 /*****************************************************************************
377 * intf_FlushMsg (ok ?)
378 *****************************************************************************
379 * Print all messages remaining in queue: get lock and call FlushLockedMsg.
380 * This function does nothing if the message queue isn't used.
381 * This function is only implemented if message queue is used. If not, it is
383 *****************************************************************************/
384 #ifdef INTF_MSG_QUEUE
385 void intf_FlushMsg( void )
387 vlc_mutex_lock( &p_main->p_msg->lock ); /* get lock */
388 FlushLockedMsg( p_main->p_msg ); /* flush messages */
389 vlc_mutex_unlock( &p_main->p_msg->lock ); /* give lock back */
393 /* following functions are local */
395 /*****************************************************************************
396 * QueueMsg: add a message to a queue
397 *****************************************************************************
398 * This function provide basic functionnalities to other intf_*Msg functions.
399 * It add a message to a queue (after having printed all stored messages if it
400 * is full. If the message can't be converted to string in memory, it exit the
401 * program. If the queue is not used, it prints the message immediately.
402 *****************************************************************************/
403 static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list ap )
405 char * psz_str; /* formatted message string */
406 intf_msg_item_t * p_msg_item; /* pointer to message */
408 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
409 intf_msg_item_t msg_item; /* message */
410 p_msg_item = &msg_item;
411 #endif /*....................................................................*/
414 * Convert message to string
416 #ifdef HAVE_VASPRINTF
417 vasprintf( &psz_str, psz_format, ap );
419 psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
421 if( psz_str == NULL )
423 fprintf(stderr, "warning: can't store following message (%s): ",
425 vfprintf(stderr, psz_format, ap );
426 fprintf(stderr, "\n" );
429 #ifdef HAVE_VASPRINTF
431 vsprintf( psz_str, psz_format, ap );
434 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
435 vlc_mutex_lock( &p_msg->lock ); /* get lock */
436 if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
438 #ifdef DEBUG /* in debug mode, queue overflow causes a warning */
439 fprintf(stderr, "warning: message queue overflow\n" );
441 FlushLockedMsg( p_msg );
443 p_msg_item = p_msg->msg + p_msg->i_count++; /* select message */
444 #endif /*.............................................. end of queue mode ...*/
447 * Fill message information fields
449 p_msg_item->i_type = i_type;
450 p_msg_item->psz_msg = psz_str;
452 p_msg_item->date = mdate();
455 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
456 vlc_mutex_unlock( &p_msg->lock ); /* give lock back */
457 #else /*....................................................... instant mode */
458 PrintMsg( p_msg_item ); /* print message */
459 free( psz_str ); /* free message data */
460 #endif /*....................................................................*/
463 /*****************************************************************************
464 * QueueDbgMsg: add a message to a queue with debugging informations
465 *****************************************************************************
466 * This function is the same as QueueMsg, except that it is only defined when
467 * TRACE is define, and require additionnal debugging informations.
468 *****************************************************************************/
470 static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
471 int i_line, char *psz_format, va_list ap)
473 char * psz_str; /* formatted message string */
474 intf_msg_item_t * p_msg_item; /* pointer to message */
476 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
477 intf_msg_item_t msg_item; /* message */
478 p_msg_item = &msg_item;
479 #endif /*....................................................................*/
482 * Convert message to string
484 #ifdef HAVE_VASPRINTF
485 vasprintf( &psz_str, psz_format, ap );
487 psz_str = (char*) malloc( INTF_MAX_MSG_SIZE );
488 vsprintf( psz_str, psz_format, ap );
490 if( psz_str == NULL )
492 fprintf(stderr, "warning: can't store following message (%s): ",
494 fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
495 vfprintf(stderr, psz_format, ap );
496 fprintf(stderr, "\n" );
500 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
501 vlc_mutex_lock( &p_msg->lock ); /* get lock */
502 if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
504 fprintf(stderr, "warning: message queue overflow\n" );
505 FlushLockedMsg( p_msg );
507 p_msg_item = p_msg->msg + p_msg->i_count++; /* select message */
508 #endif /*.............................................. end of queue mode ...*/
511 * Fill message information fields
513 p_msg_item->i_type = INTF_MSG_DBG;
514 p_msg_item->psz_msg = psz_str;
515 p_msg_item->psz_file = psz_file;
516 p_msg_item->psz_function = psz_function;
517 p_msg_item->i_line = i_line;
518 p_msg_item->date = mdate();
520 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
521 vlc_mutex_unlock( &p_msg->lock ); /* give lock back */
522 #else /*....................................................... instant mode */
523 PrintMsg( p_msg_item ); /* print message */
524 free( psz_str ); /* free message data */
525 #endif /*....................................................................*/
529 /*****************************************************************************
530 * FlushLockedMsg (ok ?)
531 *****************************************************************************
532 * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
533 * this function does not check the lock. This function is only defined if
534 * INTF_MSG_QUEUE is defined.
535 *****************************************************************************/
536 #ifdef INTF_MSG_QUEUE
537 static void FlushLockedMsg ( intf_msg_t *p_msg )
541 for( i_index = 0; i_index < p_msg->i_count; i_index++ )
543 /* Print message and free message data */
544 PrintMsg( &p_msg->msg[i_index] );
545 free( p_msg->msg[i_index].psz_msg );
552 /*****************************************************************************
553 * PrintMsg: print a message (ok ?)
554 *****************************************************************************
555 * Print a single message. The message data is not freed. This function exists
556 * in two version. The TRACE version prints a date with each message, and is
557 * able to log messages (if TRACE_LOG is defined).
558 * The normal one just prints messages to the screen.
559 *****************************************************************************/
562 static void PrintMsg( intf_msg_item_t *p_msg )
564 char psz_date[MSTRTIME_MAX_SIZE]; /* formatted time buffer */
565 int i_msg_len = MSTRTIME_MAX_SIZE + strlen(p_msg->psz_msg) + 200;
566 char *psz_msg; /* message buffer */
568 psz_msg = malloc( sizeof( char ) * i_msg_len );
570 /* Check if allocation succeeded */
571 if( psz_msg == NULL )
573 fprintf( stderr, "error: not enough memory for message %s\n",
578 /* Format message - the message is formatted here because in case the log
579 * file is used, it avoids another format string parsing */
580 switch( p_msg->i_type )
582 case INTF_MSG_STD: /* regular messages */
584 snprintf( psz_msg, i_msg_len, "%s", p_msg->psz_msg );
587 case INTF_MSG_WARN: /* Warning message */
588 mstrtime( psz_date, p_msg->date );
589 snprintf( psz_msg, i_msg_len, "(%s) %s",
590 psz_date, p_msg->psz_msg );
594 case INTF_MSG_DBG: /* debug messages */
595 mstrtime( psz_date, p_msg->date );
596 snprintf( psz_msg, i_msg_len, "(%s) " INTF_MSG_DBG_FORMAT "%s",
597 psz_date, p_msg->psz_file, p_msg->psz_function, p_msg->i_line,
605 switch( p_msg->i_type )
607 case INTF_MSG_STD: /* standard messages */
608 fprintf( stdout, "%s\n", psz_msg );
610 case INTF_MSG_ERR: /* error messages */
612 #ifndef TRACE_LOG_ONLY
613 case INTF_MSG_DBG: /* debugging messages */
615 fprintf( stderr, "%s\n", psz_msg );
620 /* Append all messages to log file */
621 if( p_main->p_msg->p_log_file != NULL )
623 fwrite( psz_msg, strlen( psz_msg ), 1, p_main->p_msg->p_log_file );
624 fwrite( "\n", 1, 1, p_main->p_msg->p_log_file );
628 /* Free the message */
634 static void PrintMsg( intf_msg_item_t *p_msg )
637 * Print messages on screen
639 switch( p_msg->i_type )
641 case INTF_MSG_STD: /* standard messages */
642 case INTF_MSG_DBG: /* debug messages */
643 fprintf( stdout, "%s\n", p_msg->psz_msg );
645 case INTF_MSG_ERR: /* error messages */
647 fprintf( stderr, "%s\n", p_msg->psz_msg ); /* warning message */