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-2001 VideoLAN
7 * $Id: intf_msg.c,v 1.39 2001/11/28 15:08:06 massiot 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"
52 /*****************************************************************************
54 *****************************************************************************
55 * Store a single message. Messages have a maximal size of INTF_MSG_MSGSIZE.
56 * If TRACE is defined, messages have a date field and debug messages are
57 * printed with a date to allow more precise profiling.
58 *****************************************************************************/
61 int i_type; /* message type, see below */
62 char * psz_msg; /* the message itself */
65 /* Debugging informations - in TRACE mode, debug messages have calling
66 * location information printed */
67 mtime_t date; /* date of the message */
68 char * psz_file; /* file in which the function was called */
69 char * psz_function; /* function from which the function was called */
70 int i_line; /* line at which the function was called */
75 #define INTF_MSG_STD 0 /* standard message */
76 #define INTF_MSG_ERR 1 /* error message */
77 #define INTF_MSG_DBG 3 /* debug message */
78 #define INTF_MSG_WARN 4 /* warning message */
79 #define INTF_MSG_STAT 5 /* statistic message */
82 /*****************************************************************************
84 *****************************************************************************
85 * Store all data requiered by messages interfaces. It has a single reference
87 *****************************************************************************/
88 typedef struct intf_msg_s
92 vlc_mutex_t lock; /* message queue lock */
93 int i_count; /* number of messages stored */
94 intf_msg_item_t msg[INTF_MSG_QSIZE]; /* message queue */
99 FILE * p_log_file; /* log file */
102 #if !defined(INTF_MSG_QUEUE) && !defined(TRACE_LOG)
103 /* If neither messages queue, neither log file is used, then the structure
104 * is empty. However, empty structures are not allowed in C. Therefore, a
105 * dummy integer is used to fill it. */
106 int i_dummy; /* unused filler */
110 /*****************************************************************************
112 *****************************************************************************/
114 static void QueueMsg ( intf_msg_t *p_msg, int i_type,
115 char *psz_format, va_list ap );
116 static void PrintMsg ( intf_msg_item_t *p_msg );
118 static void QueueDbgMsg ( intf_msg_t *p_msg, char *psz_file,
119 char *psz_function, int i_line,
120 char *psz_format, va_list ap );
122 #ifdef INTF_MSG_QUEUE
123 static void FlushLockedMsg ( intf_msg_t *p_msg );
127 static char *ConvertPrintfFormatString ( char *psz_format );
130 /*****************************************************************************
131 * intf_MsgCreate: initialize messages interface (ok ?)
132 *****************************************************************************
133 * This functions has to be called before any call to other intf_*Msg functions.
134 * It set up the locks and the message queue if it is used.
135 *****************************************************************************/
136 p_intf_msg_t intf_MsgCreate( void )
140 /* Allocate structure */
141 p_msg = malloc( sizeof( intf_msg_t ) );
148 #ifdef INTF_MSG_QUEUE
149 /* Message queue initialization */
150 vlc_mutex_init( &p_msg->lock ); /* intialize lock */
151 p_msg->i_count = 0; /* queue is empty */
156 /* Log file initialization - on failure, file pointer will be null,
157 * and no log will be issued, but this is not considered as an
159 p_msg->p_log_file = fopen( TRACE_LOG, "w" );
165 /*****************************************************************************
166 * intf_MsgDestroy: free resources allocated by intf_InitMsg (ok ?)
167 *****************************************************************************
168 * This functions prints all messages remaining in queue, then free all the
169 * resources allocated by intf_InitMsg.
170 * No other messages interface functions should be called after this one.
171 *****************************************************************************/
172 void intf_MsgDestroy( void )
174 intf_FlushMsg(); /* print all remaining messages */
177 /* Close log file if any */
178 if( p_main->p_msg->p_log_file != NULL )
180 fclose( p_main->p_msg->p_log_file );
184 #ifdef INTF_MSG_QUEUE
186 vlc_mutex_destroy( &p_main->p_msg->lock );
190 free( p_main->p_msg );
193 /*****************************************************************************
194 * intf_Msg: print a message (ok ?)
195 *****************************************************************************
196 * This function queue a message for later printing, or print it immediately
197 * if the queue isn't used.
198 *****************************************************************************/
199 void intf_Msg( char *psz_format, ... )
203 va_start( ap, psz_format );
204 QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
208 /*****************************************************************************
209 * intf_ErrMsg : print an error message (ok ?)
210 *****************************************************************************
211 * This function is the same as intf_Msg, except that it prints its messages
213 *****************************************************************************/
214 void intf_ErrMsg( char *psz_format, ... )
218 va_start( ap, psz_format );
219 QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
223 /*****************************************************************************
224 * intf_WarnMsg : print a warning message
225 *****************************************************************************
226 * This function is the same as intf_Msg, except that it concerns warning
227 * messages for testing purpose.
228 *****************************************************************************/
229 void intf_WarnMsg( int i_level, char *psz_format, ... )
233 if( i_level <= p_main->i_warning_level )
235 va_start( ap, psz_format );
236 QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
241 /*****************************************************************************
242 * intf_StatMsg : print a statistic message
243 *****************************************************************************
244 * This function is the same as intf_Msg, except that it concerns statistic
245 * messages for testing purpose.
246 *****************************************************************************/
247 void intf_StatMsg( char *psz_format, ... )
251 if( p_main->b_stats )
253 va_start( ap, psz_format );
254 QueueMsg( p_main->p_msg, INTF_MSG_STAT, psz_format, ap );
259 /*****************************************************************************
260 * _intf_DbgMsg: print a debugging message (ok ?)
261 *****************************************************************************
262 * This function prints a debugging message. Compared to other intf_*Msg
263 * functions, it is only defined if TRACE is defined and require a file name,
264 * a function name and a line number as additionnal debugging informations. It
265 * also prints a debugging header for each received line.
266 *****************************************************************************/
268 void _intf_DbgMsg( char *psz_file, char *psz_function, int i_line,
269 char *psz_format, ...)
273 va_start( ap, psz_format );
274 QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
280 /*****************************************************************************
281 * intf_MsgImm: print a message (ok ?)
282 *****************************************************************************
283 * This function prints a message immediately. If the queue is used, all
284 * waiting messages are also printed.
285 *****************************************************************************/
286 void intf_MsgImm( char *psz_format, ... )
290 va_start( ap, psz_format );
291 QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
296 /*****************************************************************************
297 * intf_ErrMsgImm: print an error message immediately (ok ?)
298 *****************************************************************************
299 * This function is the same as intf_MsgImm, except that it prints its message
301 *****************************************************************************/
302 void intf_ErrMsgImm(char *psz_format, ...)
306 va_start( ap, psz_format );
307 QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
312 /*****************************************************************************
313 * intf_WarnMsgImm : print a warning message
314 *****************************************************************************
315 * This function is the same as intf_MsgImm, except that it concerns warning
316 * messages for testing purpose.
317 *****************************************************************************/
318 void intf_WarnMsgImm( int i_level, char *psz_format, ... )
322 if( i_level <= p_main->i_warning_level )
324 va_start( ap, psz_format );
325 QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
333 /*****************************************************************************
334 * _intf_DbgMsgImm: print a debugging message immediately (ok ?)
335 *****************************************************************************
336 * This function is the same as intf_DbgMsgImm, except that it prints its
337 * message immediately. It should only be called through the macro
339 *****************************************************************************/
341 void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
342 char *psz_format, ...)
346 va_start( ap, psz_format );
347 QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
354 /*****************************************************************************
355 * intf_WarnHexDump : print a hexadecimal dump of a memory area
356 *****************************************************************************
357 * This is convenient for debugging purposes.
358 *****************************************************************************/
359 void intf_WarnHexDump( int i_level, void *p_data, int i_size )
364 u8 *p_area = (u8 *)p_data;
366 intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
369 while( i_index < i_size )
373 while( ( i_subindex < 24 ) && ( i_index + i_subindex < i_size ) )
375 sprintf( p_string + 3 * i_subindex, "%.2x ",
376 p_area[ i_index + i_subindex ] );
381 /* -1 here is safe because we know we printed at least one */
382 p_string[ 3 * i_subindex - 1 ] = '\0';
383 intf_WarnMsg( i_level, "0x%.4x: %s", i_index, p_string );
388 intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
391 /*****************************************************************************
392 * intf_FlushMsg (ok ?)
393 *****************************************************************************
394 * Print all messages remaining in queue: get lock and call FlushLockedMsg.
395 * This function does nothing if the message queue isn't used.
396 * This function is only implemented if message queue is used. If not, it is
398 *****************************************************************************/
399 #ifdef INTF_MSG_QUEUE
400 void intf_FlushMsg( void )
402 vlc_mutex_lock( &p_main->p_msg->lock ); /* get lock */
403 FlushLockedMsg( p_main->p_msg ); /* flush messages */
404 vlc_mutex_unlock( &p_main->p_msg->lock ); /* give lock back */
408 /* following functions are local */
410 /*****************************************************************************
411 * QueueMsg: add a message to a queue
412 *****************************************************************************
413 * This function provide basic functionnalities to other intf_*Msg functions.
414 * It add a message to a queue (after having printed all stored messages if it
415 * is full. If the message can't be converted to string in memory, it exit the
416 * program. If the queue is not used, it prints the message immediately.
417 *****************************************************************************/
418 static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list ap )
420 char * psz_str; /* formatted message string */
421 intf_msg_item_t * p_msg_item; /* pointer to message */
426 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
427 intf_msg_item_t msg_item; /* message */
428 p_msg_item = &msg_item;
429 #endif /*....................................................................*/
432 * Convert message to string
435 #ifdef HAVE_VASPRINTF
436 vasprintf( &psz_str, psz_format, ap );
438 psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
440 if( psz_str == NULL )
442 fprintf(stderr, "warning: can't store following message (%s): ",
444 vfprintf(stderr, psz_format, ap );
445 fprintf(stderr, "\n" );
448 #ifndef HAVE_VASPRINTF
450 psz_temp = ConvertPrintfFormatString(psz_format);
451 vsprintf( psz_str, psz_temp, ap );
454 vsprintf( psz_str, psz_format, ap );
456 #endif /* HAVE_VASPRINTF */
458 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
459 vlc_mutex_lock( &p_msg->lock ); /* get lock */
460 if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
462 #ifdef DEBUG /* in debug mode, queue overflow causes a warning */
463 fprintf(stderr, "warning: message queue overflow\n" );
465 FlushLockedMsg( p_msg );
467 p_msg_item = p_msg->msg + p_msg->i_count++; /* select message */
468 #endif /*.............................................. end of queue mode ...*/
471 * Fill message information fields
473 p_msg_item->i_type = i_type;
474 p_msg_item->psz_msg = psz_str;
476 p_msg_item->date = mdate();
479 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
480 vlc_mutex_unlock( &p_msg->lock ); /* give lock back */
481 #else /*....................................................... instant mode */
482 PrintMsg( p_msg_item ); /* print message */
483 free( psz_str ); /* free message data */
484 #endif /*....................................................................*/
487 /*****************************************************************************
488 * QueueDbgMsg: add a message to a queue with debugging informations
489 *****************************************************************************
490 * This function is the same as QueueMsg, except that it is only defined when
491 * TRACE is define, and require additionnal debugging informations.
492 *****************************************************************************/
494 static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
495 int i_line, char *psz_format, va_list ap)
497 char * psz_str; /* formatted message string */
498 intf_msg_item_t * p_msg_item; /* pointer to message */
503 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
504 intf_msg_item_t msg_item; /* message */
505 p_msg_item = &msg_item;
506 #endif /*....................................................................*/
509 * Convert message to string
511 #ifdef HAVE_VASPRINTF
512 vasprintf( &psz_str, psz_format, ap );
514 psz_str = (char*) malloc( INTF_MAX_MSG_SIZE );
516 if( psz_str == NULL )
518 fprintf(stderr, "warning: can't store following message (%s): ",
520 fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
521 vfprintf(stderr, psz_format, ap );
522 fprintf(stderr, "\n" );
525 #ifndef HAVE_VASPRINTF
527 psz_temp = ConvertPrintfFormatString(psz_format);
528 vsprintf( psz_str, psz_temp, ap );
531 vsprintf( psz_str, psz_format, ap );
533 #endif /* HAVE_VASPRINTF */
535 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
536 vlc_mutex_lock( &p_msg->lock ); /* get lock */
537 if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
539 fprintf(stderr, "warning: message queue overflow\n" );
540 FlushLockedMsg( p_msg );
542 p_msg_item = p_msg->msg + p_msg->i_count++; /* select message */
543 #endif /*.............................................. end of queue mode ...*/
546 * Fill message information fields
548 p_msg_item->i_type = INTF_MSG_DBG;
549 p_msg_item->psz_msg = psz_str;
550 p_msg_item->psz_file = psz_file;
551 p_msg_item->psz_function = psz_function;
552 p_msg_item->i_line = i_line;
553 p_msg_item->date = mdate();
555 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
556 vlc_mutex_unlock( &p_msg->lock ); /* give lock back */
557 #else /*....................................................... instant mode */
558 PrintMsg( p_msg_item ); /* print message */
559 free( psz_str ); /* free message data */
560 #endif /*....................................................................*/
564 /*****************************************************************************
565 * FlushLockedMsg (ok ?)
566 *****************************************************************************
567 * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
568 * this function does not check the lock. This function is only defined if
569 * INTF_MSG_QUEUE is defined.
570 *****************************************************************************/
571 #ifdef INTF_MSG_QUEUE
572 static void FlushLockedMsg ( intf_msg_t *p_msg )
576 for( i_index = 0; i_index < p_msg->i_count; i_index++ )
578 /* Print message and free message data */
579 PrintMsg( &p_msg->msg[i_index] );
580 free( p_msg->msg[i_index].psz_msg );
587 /*****************************************************************************
588 * PrintMsg: print a message (ok ?)
589 *****************************************************************************
590 * Print a single message. The message data is not freed. This function exists
591 * in two version. The TRACE version prints a date with each message, and is
592 * able to log messages (if TRACE_LOG is defined).
593 * The normal one just prints messages to the screen.
594 *****************************************************************************/
597 static void PrintMsg( intf_msg_item_t *p_msg )
599 char psz_date[MSTRTIME_MAX_SIZE]; /* formatted time buffer */
600 int i_msg_len = MSTRTIME_MAX_SIZE + strlen(p_msg->psz_msg) + 200;
601 char *psz_msg; /* message buffer */
603 psz_msg = malloc( sizeof( char ) * i_msg_len );
605 /* Check if allocation succeeded */
606 if( psz_msg == NULL )
608 fprintf( stderr, "error: not enough memory for message %s\n",
613 /* Format message - the message is formatted here because in case the log
614 * file is used, it avoids another format string parsing */
615 switch( p_msg->i_type )
617 case INTF_MSG_STD: /* regular messages */
620 snprintf( psz_msg, i_msg_len, "%s", p_msg->psz_msg );
623 case INTF_MSG_WARN: /* Warning message */
624 mstrtime( psz_date, p_msg->date );
625 snprintf( psz_msg, i_msg_len, "(%s) %s",
626 psz_date, p_msg->psz_msg );
630 case INTF_MSG_DBG: /* debug messages */
631 mstrtime( psz_date, p_msg->date );
632 snprintf( psz_msg, i_msg_len, "(%s) " INTF_MSG_DBG_FORMAT "%s",
633 psz_date, p_msg->psz_file, p_msg->psz_function, p_msg->i_line,
641 switch( p_msg->i_type )
643 case INTF_MSG_STD: /* standard messages */
645 fprintf( stdout, "%s\n", psz_msg );
647 case INTF_MSG_ERR: /* error messages */
649 #ifndef TRACE_LOG_ONLY
650 case INTF_MSG_DBG: /* debugging messages */
652 fprintf( stderr, "%s\n", psz_msg );
657 /* Append all messages to log file */
658 if( p_main->p_msg->p_log_file != NULL )
660 fwrite( psz_msg, strlen( psz_msg ), 1, p_main->p_msg->p_log_file );
661 fwrite( "\n", 1, 1, p_main->p_msg->p_log_file );
665 /* Free the message */
671 static void PrintMsg( intf_msg_item_t *p_msg )
674 * Print messages on screen
676 switch( p_msg->i_type )
678 case INTF_MSG_STD: /* standard messages */
680 case INTF_MSG_DBG: /* debug messages */
681 fprintf( stdout, "%s\n", p_msg->psz_msg );
683 case INTF_MSG_ERR: /* error messages */
685 fprintf( stderr, "%s\n", p_msg->psz_msg ); /* warning message */
694 /*****************************************************************************
695 * ConvertPrintfFormatString: replace all occurrences of %ll with %I64 in the
696 * printf format string.
697 *****************************************************************************
698 * Win32 doesn't recognize the "%lld" format in a printf string, so we have
699 * to convert this string to something that win32 can handle.
700 * This is a REALLY UGLY HACK which won't even work in every situation,
701 * but hey I don't want to put an ifdef WIN32 each time I use printf with
702 * a "long long" type!!!
703 * By the way, if we don't do this we can sometimes end up with segfaults.
704 *****************************************************************************/
705 static char *ConvertPrintfFormatString( char *psz_format )
707 int i, i_counter=0, i_pos=0;
710 /* We first need to check how many occurences of %ll there are in the
711 * psz_format string. Once we'll know that we'll be able to malloc the
712 * destination string */
714 for( i=0; i <= (strlen(psz_format) - 4); i++ )
716 if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
720 /* malloc the destination string */
721 psz_dest = malloc( strlen(psz_format) + i_counter + 1 );
722 if( psz_dest == NULL )
724 fprintf(stderr, "warning: malloc failed in ConvertPrintfFormatString\n");
728 /* Now build the modified string */
730 for( i=0; i <= (strlen(psz_format) - 4); i++ )
732 if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
734 memcpy( psz_dest+i_pos+i_counter, psz_format+i_pos, i-i_pos+1);
735 *(psz_dest+i+i_counter+1)='I';
736 *(psz_dest+i+i_counter+2)='6';
737 *(psz_dest+i+i_counter+3)='4';
742 strcpy( psz_dest+i_pos+i_counter, psz_format+i_pos );