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.46 2002/02/23 21:31:44 gbazin 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"
45 /*****************************************************************************
47 *****************************************************************************
48 * Store all data requiered by messages interfaces. It has a single reference
50 *****************************************************************************/
51 typedef struct msg_bank_s
53 /* Message queue lock */
57 msg_item_t msg[INTF_MSG_QSIZE]; /* message queue */
63 intf_subscription_t **pp_sub;
69 /*****************************************************************************
71 *****************************************************************************/
72 static void QueueMsg ( int, int, char *, va_list );
73 static void FlushMsg ( void );
76 static char *ConvertPrintfFormatString ( char *psz_format );
79 /*****************************************************************************
80 * intf_MsgCreate: initialize messages interface (ok ?)
81 *****************************************************************************
82 * This functions has to be called before any call to other intf_*Msg functions.
83 * It set up the locks and the message queue if it is used.
84 *****************************************************************************/
85 void intf_MsgCreate( void )
87 /* Message queue initialization */
88 vlc_mutex_init( &msg_bank.lock );
93 msg_bank.pp_sub = NULL;
96 /*****************************************************************************
97 * intf_MsgDestroy: free resources allocated by intf_InitMsg (ok ?)
98 *****************************************************************************
99 * This functions prints all messages remaining in queue, then free all the
100 * resources allocated by intf_InitMsg.
101 * No other messages interface functions should be called after this one.
102 *****************************************************************************/
103 void intf_MsgDestroy( void )
106 vlc_mutex_destroy( &msg_bank.lock );
110 fprintf( stderr, "intf error: stale interface subscribers\n" );
113 /* Free remaining messages */
117 /*****************************************************************************
118 * intf_MsgSub: subscribe to the message queue.
119 *****************************************************************************/
120 intf_subscription_t *intf_MsgSub( void )
122 intf_subscription_t *p_sub = malloc( sizeof( intf_subscription_t ) );
124 vlc_mutex_lock( &msg_bank.lock );
126 /* Add subscription to the list */
128 msg_bank.pp_sub = realloc( msg_bank.pp_sub,
129 msg_bank.i_sub * sizeof( intf_subscription_t* ) );
131 msg_bank.pp_sub[ msg_bank.i_sub - 1 ] = p_sub;
133 p_sub->i_start = msg_bank.i_start;
134 p_sub->pi_stop = &msg_bank.i_stop;
136 p_sub->p_msg = msg_bank.msg;
137 p_sub->p_lock = &msg_bank.lock;
139 vlc_mutex_unlock( &msg_bank.lock );
144 /*****************************************************************************
145 * intf_MsgUnsub: unsubscribe from the message queue.
146 *****************************************************************************/
147 void intf_MsgUnsub( intf_subscription_t *p_sub )
151 vlc_mutex_lock( &msg_bank.lock );
154 if( !msg_bank.i_sub )
156 intf_ErrMsg( "intf error: no subscriber in the list" );
160 /* Look for the appropriate subscription */
161 for( i_index = 0; i_index < msg_bank.i_sub; i_index++ )
163 if( msg_bank.pp_sub[ i_index ] == p_sub )
169 if( msg_bank.pp_sub[ i_index ] != p_sub )
171 intf_ErrMsg( "intf error: subscriber not found" );
172 vlc_mutex_unlock( &msg_bank.lock );
176 /* Remove this subscription */
177 for( ; i_index < (msg_bank.i_sub - 1); i_index++ )
179 msg_bank.pp_sub[ i_index ] = msg_bank.pp_sub[ i_index+1 ];
183 msg_bank.pp_sub = realloc( msg_bank.pp_sub,
184 msg_bank.i_sub * sizeof( intf_subscription_t* ) );
186 vlc_mutex_unlock( &msg_bank.lock );
189 /*****************************************************************************
190 * intf_Msg: print a message (ok ?)
191 *****************************************************************************
192 * This function queue a message for later printing, or print it immediately
193 * if the queue isn't used.
194 *****************************************************************************/
195 void intf_Msg( char *psz_format, ... )
199 va_start( ap, psz_format );
200 QueueMsg( INTF_MSG_STD, 0, psz_format, ap );
204 /*****************************************************************************
205 * intf_ErrMsg : print an error message (ok ?)
206 *****************************************************************************
207 * This function is the same as intf_Msg, except that it prints its messages
209 *****************************************************************************/
210 void intf_ErrMsg( char *psz_format, ... )
214 va_start( ap, psz_format );
215 QueueMsg( INTF_MSG_ERR, 0, psz_format, ap );
219 /*****************************************************************************
220 * intf_WarnMsg : print a warning message
221 *****************************************************************************
222 * This function is the same as intf_Msg, except that it concerns warning
223 * messages for testing purpose.
224 *****************************************************************************/
225 void intf_WarnMsg( int i_level, char *psz_format, ... )
229 va_start( ap, psz_format );
230 QueueMsg( INTF_MSG_WARN, i_level, psz_format, ap );
234 /*****************************************************************************
235 * intf_StatMsg : print a statistic message
236 *****************************************************************************
237 * This function is the same as intf_Msg, except that it concerns statistic
238 * messages for testing purpose.
239 *****************************************************************************/
240 void intf_StatMsg( char *psz_format, ... )
244 if( p_main->b_stats )
246 va_start( ap, psz_format );
247 QueueMsg( INTF_MSG_STAT, 0, psz_format, ap );
252 /*****************************************************************************
253 * intf_WarnHexDump : print a hexadecimal dump of a memory area
254 *****************************************************************************
255 * This is convenient for debugging purposes.
256 *****************************************************************************/
257 void intf_WarnHexDump( int i_level, void *p_data, int i_size )
262 u8 *p_area = (u8 *)p_data;
264 intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
267 while( i_index < i_size )
271 while( ( i_subindex < 24 ) && ( i_index + i_subindex < i_size ) )
273 sprintf( p_string + 3 * i_subindex, "%.2x ",
274 p_area[ i_index + i_subindex ] );
279 /* -1 here is safe because we know we printed at least one */
280 p_string[ 3 * i_subindex - 1 ] = '\0';
281 intf_WarnMsg( i_level, "0x%.4x: %s", i_index, p_string );
286 intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
289 /* following functions are local */
291 /*****************************************************************************
292 * QueueMsg: add a message to a queue
293 *****************************************************************************
294 * This function provide basic functionnalities to other intf_*Msg functions.
295 * It add a message to a queue (after having printed all stored messages if it
296 * is full. If the message can't be converted to string in memory, it exit the
297 * program. If the queue is not used, it prints the message immediately.
298 *****************************************************************************/
299 static void QueueMsg( int i_type, int i_level, char *psz_format, va_list ap )
301 char * psz_str; /* formatted message string */
302 msg_item_t * p_item; /* pointer to message */
308 * Convert message to string
310 #ifdef HAVE_VASPRINTF
311 vasprintf( &psz_str, psz_format, ap );
313 psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
316 if( psz_str == NULL )
318 fprintf(stderr, "intf warning: can't store following message (%s): ",
320 vfprintf(stderr, psz_format, ap );
321 fprintf(stderr, "\n" );
325 #ifndef HAVE_VASPRINTF
327 psz_temp = ConvertPrintfFormatString(psz_format);
328 vsprintf( psz_str, psz_temp, ap );
331 vsprintf( psz_str, psz_format, ap );
335 /* Put message in queue */
336 vlc_mutex_lock( &msg_bank.lock );
338 /* Send the message to stderr */
339 if( i_level <= p_main->i_warning_level )
341 fprintf( stderr, "%s\n", psz_str );
344 /* Put the message in the queue if there is room for it */
345 if( ((msg_bank.i_stop - msg_bank.i_start + 1) % INTF_MSG_QSIZE) == 0 )
349 if( ((msg_bank.i_stop - msg_bank.i_start + 1) % INTF_MSG_QSIZE) == 0 )
351 fprintf( stderr, "intf warning: message queue overflow\n" );
352 vlc_mutex_unlock( &msg_bank.lock );
357 p_item = msg_bank.msg + msg_bank.i_stop;
358 msg_bank.i_stop = (msg_bank.i_stop + 1) % INTF_MSG_QSIZE;
360 /* Fill message information fields */
361 p_item->i_type = i_type;
362 p_item->psz_msg = psz_str;
364 vlc_mutex_unlock( &msg_bank.lock );
367 /*****************************************************************************
369 *****************************************************************************
370 * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
371 * this function does not check the lock.
372 *****************************************************************************/
373 static void FlushMsg ( void )
375 int i_index, i_start, i_stop;
377 /* Get the maximum message index that can be freed */
378 i_stop = msg_bank.i_stop;
380 /* Check until which value we can free messages */
381 for( i_index = 0; i_index < msg_bank.i_sub; i_index++ )
383 i_start = msg_bank.pp_sub[ i_index ]->i_start;
385 /* If this subscriber is late, we don't free messages before
386 * his i_start value, otherwise he'll miss messages */
387 if( ( i_start < i_stop
388 && (msg_bank.i_stop <= i_start || i_stop <= msg_bank.i_stop) )
389 || ( i_stop < i_start
390 && (i_stop <= msg_bank.i_stop && msg_bank.i_stop <= i_start) ) )
396 /* Free message data */
397 for( i_index = msg_bank.i_start;
399 i_index = (i_index+1) % INTF_MSG_QSIZE )
401 free( msg_bank.msg[i_index].psz_msg );
404 /* Update the new start value */
405 msg_bank.i_start = i_index;
408 /*****************************************************************************
409 * ConvertPrintfFormatString: replace all occurrences of %ll with %I64 in the
410 * printf format string.
411 *****************************************************************************
412 * Win32 doesn't recognize the "%lld" format in a printf string, so we have
413 * to convert this string to something that win32 can handle.
414 * This is a REALLY UGLY HACK which won't even work in every situation,
415 * but hey I don't want to put an ifdef WIN32 each time I use printf with
416 * a "long long" type!!!
417 * By the way, if we don't do this we can sometimes end up with segfaults.
418 *****************************************************************************/
420 static char *ConvertPrintfFormatString( char *psz_format )
422 int i, i_counter=0, i_pos=0;
425 /* We first need to check how many occurences of %ll there are in the
426 * psz_format string. Once we'll know that we'll be able to malloc the
427 * destination string */
429 for( i=0; i <= (strlen(psz_format) - 4); i++ )
431 if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
437 /* malloc the destination string */
438 psz_dest = malloc( strlen(psz_format) + i_counter + 1 );
439 if( psz_dest == NULL )
441 fprintf( stderr, "intf warning: ConvertPrintfFormatString failed\n");
445 /* Now build the modified string */
447 for( i=0; i <= (strlen(psz_format) - 4); i++ )
449 if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
451 memcpy( psz_dest+i_pos+i_counter, psz_format+i_pos, i-i_pos+1);
452 *(psz_dest+i+i_counter+1)='I';
453 *(psz_dest+i+i_counter+2)='6';
454 *(psz_dest+i+i_counter+3)='4';
459 strcpy( psz_dest+i_pos+i_counter, psz_format+i_pos );