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.42 2002/01/04 14:01:35 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 *****************************************************************************/
29 #include <errno.h> /* errno */
30 #include <fcntl.h> /* O_CREAT, O_TRUNC, O_WRONLY, O_SYNC */
31 #include <stdio.h> /* required */
32 #include <stdarg.h> /* va_list for BSD */
33 #include <stdlib.h> /* malloc() */
34 #include <string.h> /* strerror() */
36 #include <videolan/vlc.h>
39 #include <unistd.h> /* close(), write() */
42 #include "interface.h"
44 /*****************************************************************************
46 *****************************************************************************
47 * Store a single message. Messages have a maximal size of INTF_MSG_MSGSIZE.
48 * If TRACE is defined, messages have a date field and debug messages are
49 * printed with a date to allow more precise profiling.
50 *****************************************************************************/
53 int i_type; /* message type, see below */
54 char * psz_msg; /* the message itself */
57 /* Debugging informations - in TRACE mode, debug messages have calling
58 * location information printed */
59 mtime_t date; /* date of the message */
60 char * psz_file; /* file in which the function was called */
61 char * psz_function; /* function from which the function was called */
62 int i_line; /* line at which the function was called */
67 #define INTF_MSG_STD 0 /* standard message */
68 #define INTF_MSG_ERR 1 /* error message */
69 #define INTF_MSG_DBG 3 /* debug message */
70 #define INTF_MSG_WARN 4 /* warning message */
71 #define INTF_MSG_STAT 5 /* statistic message */
74 /*****************************************************************************
76 *****************************************************************************
77 * Store all data requiered by messages interfaces. It has a single reference
79 *****************************************************************************/
80 typedef struct intf_msg_s
84 vlc_mutex_t lock; /* message queue lock */
85 int i_count; /* number of messages stored */
86 intf_msg_item_t msg[INTF_MSG_QSIZE]; /* message queue */
91 FILE * p_log_file; /* log file */
94 #if !defined(INTF_MSG_QUEUE) && !defined(TRACE_LOG)
95 /* If neither messages queue, neither log file is used, then the structure
96 * is empty. However, empty structures are not allowed in C. Therefore, a
97 * dummy integer is used to fill it. */
98 int i_dummy; /* unused filler */
102 /*****************************************************************************
104 *****************************************************************************/
106 static void QueueMsg ( intf_msg_t *p_msg, int i_type,
107 char *psz_format, va_list ap );
108 static void PrintMsg ( intf_msg_item_t *p_msg );
110 static void QueueDbgMsg ( intf_msg_t *p_msg, char *psz_file,
111 char *psz_function, int i_line,
112 char *psz_format, va_list ap );
114 #ifdef INTF_MSG_QUEUE
115 static void FlushLockedMsg ( intf_msg_t *p_msg );
119 static char *ConvertPrintfFormatString ( char *psz_format );
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 )
132 /* Allocate structure */
133 p_msg = malloc( sizeof( intf_msg_t ) );
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 */
148 /* Log file initialization - on failure, file pointer will be null,
149 * and no log will be issued, but this is not considered as an
151 p_msg->p_log_file = fopen( TRACE_LOG, "w" );
157 /*****************************************************************************
158 * intf_MsgDestroy: free resources allocated by intf_InitMsg (ok ?)
159 *****************************************************************************
160 * This functions prints all messages remaining in queue, then free all the
161 * resources allocated by intf_InitMsg.
162 * No other messages interface functions should be called after this one.
163 *****************************************************************************/
164 void intf_MsgDestroy( void )
166 intf_FlushMsg(); /* print all remaining messages */
169 /* Close log file if any */
170 if( p_main->p_msg->p_log_file != NULL )
172 fclose( p_main->p_msg->p_log_file );
176 #ifdef INTF_MSG_QUEUE
178 vlc_mutex_destroy( &p_main->p_msg->lock );
182 free( p_main->p_msg );
185 /*****************************************************************************
186 * intf_Msg: print a message (ok ?)
187 *****************************************************************************
188 * This function queue a message for later printing, or print it immediately
189 * if the queue isn't used.
190 *****************************************************************************/
191 void intf_Msg( char *psz_format, ... )
195 va_start( ap, psz_format );
196 QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
200 /*****************************************************************************
201 * intf_ErrMsg : print an error message (ok ?)
202 *****************************************************************************
203 * This function is the same as intf_Msg, except that it prints its messages
205 *****************************************************************************/
206 void intf_ErrMsg( char *psz_format, ... )
210 va_start( ap, psz_format );
211 QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
215 /*****************************************************************************
216 * intf_WarnMsg : print a warning message
217 *****************************************************************************
218 * This function is the same as intf_Msg, except that it concerns warning
219 * messages for testing purpose.
220 *****************************************************************************/
221 void intf_WarnMsg( int i_level, char *psz_format, ... )
225 if( i_level <= p_main->i_warning_level )
227 va_start( ap, psz_format );
228 QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
233 /*****************************************************************************
234 * intf_StatMsg : print a statistic message
235 *****************************************************************************
236 * This function is the same as intf_Msg, except that it concerns statistic
237 * messages for testing purpose.
238 *****************************************************************************/
239 void intf_StatMsg( char *psz_format, ... )
243 if( p_main->b_stats )
245 va_start( ap, psz_format );
246 QueueMsg( p_main->p_msg, INTF_MSG_STAT, psz_format, ap );
251 /*****************************************************************************
252 * _intf_DbgMsg: print a debugging message (ok ?)
253 *****************************************************************************
254 * This function prints a debugging message. Compared to other intf_*Msg
255 * functions, it is only defined if TRACE is defined and require a file name,
256 * a function name and a line number as additionnal debugging informations. It
257 * also prints a debugging header for each received line.
258 *****************************************************************************/
260 void _intf_DbgMsg( char *psz_file, char *psz_function, int i_line,
261 char *psz_format, ...)
265 va_start( ap, psz_format );
266 QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
272 /*****************************************************************************
273 * intf_MsgImm: print a message (ok ?)
274 *****************************************************************************
275 * This function prints a message immediately. If the queue is used, all
276 * waiting messages are also printed.
277 *****************************************************************************/
278 void intf_MsgImm( char *psz_format, ... )
282 va_start( ap, psz_format );
283 QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
288 /*****************************************************************************
289 * intf_ErrMsgImm: print an error message immediately (ok ?)
290 *****************************************************************************
291 * This function is the same as intf_MsgImm, except that it prints its message
293 *****************************************************************************/
294 void intf_ErrMsgImm(char *psz_format, ...)
298 va_start( ap, psz_format );
299 QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
304 /*****************************************************************************
305 * intf_WarnMsgImm : print a warning message
306 *****************************************************************************
307 * This function is the same as intf_MsgImm, except that it concerns warning
308 * messages for testing purpose.
309 *****************************************************************************/
310 void intf_WarnMsgImm( int i_level, char *psz_format, ... )
314 if( i_level <= p_main->i_warning_level )
316 va_start( ap, psz_format );
317 QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
325 /*****************************************************************************
326 * _intf_DbgMsgImm: print a debugging message immediately (ok ?)
327 *****************************************************************************
328 * This function is the same as intf_DbgMsgImm, except that it prints its
329 * message immediately. It should only be called through the macro
331 *****************************************************************************/
333 void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
334 char *psz_format, ...)
338 va_start( ap, psz_format );
339 QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
346 /*****************************************************************************
347 * intf_WarnHexDump : print a hexadecimal dump of a memory area
348 *****************************************************************************
349 * This is convenient for debugging purposes.
350 *****************************************************************************/
351 void intf_WarnHexDump( int i_level, void *p_data, int i_size )
356 u8 *p_area = (u8 *)p_data;
358 intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
361 while( i_index < i_size )
365 while( ( i_subindex < 24 ) && ( i_index + i_subindex < i_size ) )
367 sprintf( p_string + 3 * i_subindex, "%.2x ",
368 p_area[ i_index + i_subindex ] );
373 /* -1 here is safe because we know we printed at least one */
374 p_string[ 3 * i_subindex - 1 ] = '\0';
375 intf_WarnMsg( i_level, "0x%.4x: %s", i_index, p_string );
380 intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
383 /*****************************************************************************
384 * intf_FlushMsg (ok ?)
385 *****************************************************************************
386 * Print all messages remaining in queue: get lock and call FlushLockedMsg.
387 * This function does nothing if the message queue isn't used.
388 * This function is only implemented if message queue is used. If not, it is
390 *****************************************************************************/
391 #ifdef INTF_MSG_QUEUE
392 void intf_FlushMsg( void )
394 vlc_mutex_lock( &p_main->p_msg->lock ); /* get lock */
395 FlushLockedMsg( p_main->p_msg ); /* flush messages */
396 vlc_mutex_unlock( &p_main->p_msg->lock ); /* give lock back */
400 /* following functions are local */
402 /*****************************************************************************
403 * QueueMsg: add a message to a queue
404 *****************************************************************************
405 * This function provide basic functionnalities to other intf_*Msg functions.
406 * It add a message to a queue (after having printed all stored messages if it
407 * is full. If the message can't be converted to string in memory, it exit the
408 * program. If the queue is not used, it prints the message immediately.
409 *****************************************************************************/
410 static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list ap )
412 char * psz_str; /* formatted message string */
413 intf_msg_item_t * p_msg_item; /* pointer to message */
418 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
419 intf_msg_item_t msg_item; /* message */
420 p_msg_item = &msg_item;
421 #endif /*....................................................................*/
424 * Convert message to string
427 #ifdef HAVE_VASPRINTF
428 vasprintf( &psz_str, psz_format, ap );
430 psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
432 if( psz_str == NULL )
434 fprintf(stderr, "warning: can't store following message (%s): ",
436 vfprintf(stderr, psz_format, ap );
437 fprintf(stderr, "\n" );
440 #ifndef HAVE_VASPRINTF
442 psz_temp = ConvertPrintfFormatString(psz_format);
443 vsprintf( psz_str, psz_temp, ap );
446 vsprintf( psz_str, psz_format, ap );
448 #endif /* HAVE_VASPRINTF */
450 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
451 vlc_mutex_lock( &p_msg->lock ); /* get lock */
452 if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
454 #ifdef DEBUG /* in debug mode, queue overflow causes a warning */
455 fprintf(stderr, "warning: message queue overflow\n" );
457 FlushLockedMsg( p_msg );
459 p_msg_item = p_msg->msg + p_msg->i_count++; /* select message */
460 #endif /*.............................................. end of queue mode ...*/
463 * Fill message information fields
465 p_msg_item->i_type = i_type;
466 p_msg_item->psz_msg = psz_str;
468 p_msg_item->date = mdate();
471 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
472 vlc_mutex_unlock( &p_msg->lock ); /* give lock back */
473 #else /*....................................................... instant mode */
474 PrintMsg( p_msg_item ); /* print message */
475 free( psz_str ); /* free message data */
476 #endif /*....................................................................*/
479 /*****************************************************************************
480 * QueueDbgMsg: add a message to a queue with debugging informations
481 *****************************************************************************
482 * This function is the same as QueueMsg, except that it is only defined when
483 * TRACE is define, and require additionnal debugging informations.
484 *****************************************************************************/
486 static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
487 int i_line, char *psz_format, va_list ap)
489 char * psz_str; /* formatted message string */
490 intf_msg_item_t * p_msg_item; /* pointer to message */
495 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
496 intf_msg_item_t msg_item; /* message */
497 p_msg_item = &msg_item;
498 #endif /*....................................................................*/
501 * Convert message to string
503 #ifdef HAVE_VASPRINTF
504 vasprintf( &psz_str, psz_format, ap );
506 psz_str = (char*) malloc( INTF_MAX_MSG_SIZE );
508 if( psz_str == NULL )
510 fprintf(stderr, "warning: can't store following message (%s): ",
512 fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
513 vfprintf(stderr, psz_format, ap );
514 fprintf(stderr, "\n" );
517 #ifndef HAVE_VASPRINTF
519 psz_temp = ConvertPrintfFormatString(psz_format);
520 vsprintf( psz_str, psz_temp, ap );
523 vsprintf( psz_str, psz_format, ap );
525 #endif /* HAVE_VASPRINTF */
527 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
528 vlc_mutex_lock( &p_msg->lock ); /* get lock */
529 if( p_msg->i_count == INTF_MSG_QSIZE ) /* flush queue if needed */
531 fprintf(stderr, "warning: message queue overflow\n" );
532 FlushLockedMsg( p_msg );
534 p_msg_item = p_msg->msg + p_msg->i_count++; /* select message */
535 #endif /*.............................................. end of queue mode ...*/
538 * Fill message information fields
540 p_msg_item->i_type = INTF_MSG_DBG;
541 p_msg_item->psz_msg = psz_str;
542 p_msg_item->psz_file = psz_file;
543 p_msg_item->psz_function = psz_function;
544 p_msg_item->i_line = i_line;
545 p_msg_item->date = mdate();
547 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
548 vlc_mutex_unlock( &p_msg->lock ); /* give lock back */
549 #else /*....................................................... instant mode */
550 PrintMsg( p_msg_item ); /* print message */
551 free( psz_str ); /* free message data */
552 #endif /*....................................................................*/
556 /*****************************************************************************
557 * FlushLockedMsg (ok ?)
558 *****************************************************************************
559 * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
560 * this function does not check the lock. This function is only defined if
561 * INTF_MSG_QUEUE is defined.
562 *****************************************************************************/
563 #ifdef INTF_MSG_QUEUE
564 static void FlushLockedMsg ( intf_msg_t *p_msg )
568 for( i_index = 0; i_index < p_msg->i_count; i_index++ )
570 /* Print message and free message data */
571 PrintMsg( &p_msg->msg[i_index] );
572 free( p_msg->msg[i_index].psz_msg );
579 /*****************************************************************************
580 * PrintMsg: print a message (ok ?)
581 *****************************************************************************
582 * Print a single message. The message data is not freed. This function exists
583 * in two version. The TRACE version prints a date with each message, and is
584 * able to log messages (if TRACE_LOG is defined).
585 * The normal one just prints messages to the screen.
586 *****************************************************************************/
589 static void PrintMsg( intf_msg_item_t *p_msg )
591 char psz_date[MSTRTIME_MAX_SIZE]; /* formatted time buffer */
592 int i_msg_len = MSTRTIME_MAX_SIZE + strlen(p_msg->psz_msg) + 200;
593 char *psz_msg; /* message buffer */
595 psz_msg = malloc( sizeof( char ) * i_msg_len );
597 /* Check if allocation succeeded */
598 if( psz_msg == NULL )
600 fprintf( stderr, "error: not enough memory for message %s\n",
605 /* Format message - the message is formatted here because in case the log
606 * file is used, it avoids another format string parsing */
607 switch( p_msg->i_type )
609 case INTF_MSG_STD: /* regular messages */
612 snprintf( psz_msg, i_msg_len, "%s", p_msg->psz_msg );
615 case INTF_MSG_WARN: /* Warning message */
616 mstrtime( psz_date, p_msg->date );
617 snprintf( psz_msg, i_msg_len, "(%s) %s",
618 psz_date, p_msg->psz_msg );
622 case INTF_MSG_DBG: /* debug messages */
623 mstrtime( psz_date, p_msg->date );
624 snprintf( psz_msg, i_msg_len, "(%s) " INTF_MSG_DBG_FORMAT "%s",
625 psz_date, p_msg->psz_file, p_msg->psz_function, p_msg->i_line,
633 switch( p_msg->i_type )
635 case INTF_MSG_STD: /* standard messages */
637 fprintf( stdout, "%s\n", psz_msg );
639 case INTF_MSG_ERR: /* error messages */
641 #ifndef TRACE_LOG_ONLY
642 case INTF_MSG_DBG: /* debugging messages */
644 fprintf( stderr, "%s\n", psz_msg );
649 /* Append all messages to log file */
650 if( p_main->p_msg->p_log_file != NULL )
652 fwrite( psz_msg, strlen( psz_msg ), 1, p_main->p_msg->p_log_file );
653 fwrite( "\n", 1, 1, p_main->p_msg->p_log_file );
657 /* Free the message */
663 static void PrintMsg( intf_msg_item_t *p_msg )
666 * Print messages on screen
668 switch( p_msg->i_type )
670 case INTF_MSG_STD: /* standard messages */
672 case INTF_MSG_DBG: /* debug messages */
673 fprintf( stdout, "%s\n", p_msg->psz_msg );
675 case INTF_MSG_ERR: /* error messages */
677 fprintf( stderr, "%s\n", p_msg->psz_msg ); /* warning message */
686 /*****************************************************************************
687 * ConvertPrintfFormatString: replace all occurrences of %ll with %I64 in the
688 * printf format string.
689 *****************************************************************************
690 * Win32 doesn't recognize the "%lld" format in a printf string, so we have
691 * to convert this string to something that win32 can handle.
692 * This is a REALLY UGLY HACK which won't even work in every situation,
693 * but hey I don't want to put an ifdef WIN32 each time I use printf with
694 * a "long long" type!!!
695 * By the way, if we don't do this we can sometimes end up with segfaults.
696 *****************************************************************************/
697 static char *ConvertPrintfFormatString( char *psz_format )
699 int i, i_counter=0, i_pos=0;
702 /* We first need to check how many occurences of %ll there are in the
703 * psz_format string. Once we'll know that we'll be able to malloc the
704 * destination string */
706 for( i=0; i <= (strlen(psz_format) - 4); i++ )
708 if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
714 /* malloc the destination string */
715 psz_dest = malloc( strlen(psz_format) + i_counter + 1 );
716 if( psz_dest == NULL )
718 fprintf(stderr, "warning: malloc failed in ConvertPrintfFormatString\n");
722 /* Now build the modified string */
724 for( i=0; i <= (strlen(psz_format) - 4); i++ )
726 if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
728 memcpy( psz_dest+i_pos+i_counter, psz_format+i_pos, i-i_pos+1);
729 *(psz_dest+i+i_counter+1)='I';
730 *(psz_dest+i+i_counter+2)='6';
731 *(psz_dest+i+i_counter+3)='4';
736 strcpy( psz_dest+i_pos+i_counter, psz_format+i_pos );