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.49 2002/05/17 00:58:13 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"
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 ];
185 msg_bank.pp_sub = realloc( msg_bank.pp_sub,
186 msg_bank.i_sub * sizeof( intf_subscription_t* ) );
190 free( msg_bank.pp_sub );
191 msg_bank.pp_sub = NULL;
194 vlc_mutex_unlock( &msg_bank.lock );
197 /*****************************************************************************
198 * intf_Msg: print a message (ok ?)
199 *****************************************************************************
200 * This function queue a message for later printing, or print it immediately
201 * if the queue isn't used.
202 *****************************************************************************/
203 void intf_Msg( char *psz_format, ... )
207 va_start( ap, psz_format );
208 QueueMsg( INTF_MSG_STD, 0, psz_format, ap );
212 /*****************************************************************************
213 * intf_ErrMsg : print an error message (ok ?)
214 *****************************************************************************
215 * This function is the same as intf_Msg, except that it prints its messages
217 *****************************************************************************/
218 void intf_ErrMsg( char *psz_format, ... )
222 va_start( ap, psz_format );
223 QueueMsg( INTF_MSG_ERR, 0, psz_format, ap );
227 /*****************************************************************************
228 * intf_WarnMsg : print a warning message
229 *****************************************************************************
230 * This function is the same as intf_Msg, except that it concerns warning
231 * messages for testing purpose.
232 *****************************************************************************/
233 void intf_WarnMsg( int i_level, char *psz_format, ... )
237 va_start( ap, psz_format );
238 QueueMsg( INTF_MSG_WARN, i_level, psz_format, ap );
242 /*****************************************************************************
243 * intf_StatMsg : print a statistic message
244 *****************************************************************************
245 * This function is the same as intf_Msg, except that it concerns statistic
246 * messages for testing purpose.
247 *****************************************************************************/
248 void intf_StatMsg( char *psz_format, ... )
252 if( p_main->b_stats )
254 va_start( ap, psz_format );
255 QueueMsg( INTF_MSG_STAT, 0, psz_format, ap );
260 /*****************************************************************************
261 * intf_WarnHexDump : print a hexadecimal dump of a memory area
262 *****************************************************************************
263 * This is convenient for debugging purposes.
264 *****************************************************************************/
265 void intf_WarnHexDump( int i_level, void *p_data, int i_size )
270 u8 *p_area = (u8 *)p_data;
272 intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
275 while( i_index < i_size )
279 while( ( i_subindex < 24 ) && ( i_index + i_subindex < i_size ) )
281 sprintf( p_string + 3 * i_subindex, "%.2x ",
282 p_area[ i_index + i_subindex ] );
287 /* -1 here is safe because we know we printed at least one */
288 p_string[ 3 * i_subindex - 1 ] = '\0';
289 intf_WarnMsg( i_level, "0x%.4x: %s", i_index, p_string );
294 intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
297 /* following functions are local */
299 /*****************************************************************************
300 * QueueMsg: add a message to a queue
301 *****************************************************************************
302 * This function provides basic functionnalities to other intf_*Msg functions.
303 * It adds a message to a queue (after having printed all stored messages if it
304 * is full). If the message can't be converted to string in memory, it issues
306 *****************************************************************************/
307 static void QueueMsg( int i_type, int i_level, char *psz_format, va_list ap )
309 char * psz_str; /* formatted message string */
310 msg_item_t * p_item; /* pointer to message */
316 * Convert message to string
318 #ifdef HAVE_VASPRINTF
319 vasprintf( &psz_str, psz_format, ap );
321 psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
324 if( psz_str == NULL )
326 fprintf(stderr, "intf warning: can't store following message (%s): ",
328 vfprintf(stderr, psz_format, ap );
329 fprintf(stderr, "\n" );
333 #ifndef HAVE_VASPRINTF
335 psz_temp = ConvertPrintfFormatString(psz_format);
338 fprintf(stderr, "intf warning: couldn't print message");
341 vsprintf( psz_str, psz_temp, ap );
344 vsprintf( psz_str, psz_format, ap );
348 /* Put message in queue */
349 vlc_mutex_lock( &msg_bank.lock );
351 /* Send the message to stderr */
352 if( i_level <= p_main->i_warning_level )
354 fprintf( stderr, "%s\n", psz_str );
357 /* Put the message in the queue if there is room for it */
358 if( ((msg_bank.i_stop - msg_bank.i_start + 1) % INTF_MSG_QSIZE) == 0 )
362 if( ((msg_bank.i_stop - msg_bank.i_start + 1) % INTF_MSG_QSIZE) == 0 )
364 fprintf( stderr, "intf warning: message queue overflow\n" );
365 vlc_mutex_unlock( &msg_bank.lock );
370 p_item = msg_bank.msg + msg_bank.i_stop;
371 msg_bank.i_stop = (msg_bank.i_stop + 1) % INTF_MSG_QSIZE;
373 /* Fill message information fields */
374 p_item->i_type = i_type;
375 p_item->psz_msg = psz_str;
377 vlc_mutex_unlock( &msg_bank.lock );
380 /*****************************************************************************
382 *****************************************************************************
383 * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
384 * this function does not check the lock.
385 *****************************************************************************/
386 static void FlushMsg ( void )
388 int i_index, i_start, i_stop;
390 /* Get the maximum message index that can be freed */
391 i_stop = msg_bank.i_stop;
393 /* Check until which value we can free messages */
394 for( i_index = 0; i_index < msg_bank.i_sub; i_index++ )
396 i_start = msg_bank.pp_sub[ i_index ]->i_start;
398 /* If this subscriber is late, we don't free messages before
399 * his i_start value, otherwise he'll miss messages */
400 if( ( i_start < i_stop
401 && (msg_bank.i_stop <= i_start || i_stop <= msg_bank.i_stop) )
402 || ( i_stop < i_start
403 && (i_stop <= msg_bank.i_stop && msg_bank.i_stop <= i_start) ) )
409 /* Free message data */
410 for( i_index = msg_bank.i_start;
412 i_index = (i_index+1) % INTF_MSG_QSIZE )
414 free( msg_bank.msg[i_index].psz_msg );
417 /* Update the new start value */
418 msg_bank.i_start = i_index;
421 /*****************************************************************************
422 * ConvertPrintfFormatString: replace all occurrences of %ll with %I64 in the
423 * printf format string.
424 *****************************************************************************
425 * Win32 doesn't recognize the "%ll" format in a printf string, so we have
426 * to convert this string to something that win32 can handle.
427 * This is a REALLY UGLY HACK which won't even work in every situation,
428 * but hey I don't want to put an ifdef WIN32 each time I use printf with
429 * a "long long" type!!!
430 * By the way, if we don't do this we can sometimes end up with segfaults.
431 *****************************************************************************/
433 static char *ConvertPrintfFormatString( char *psz_format )
435 int i, i_counter=0, i_pos=0;
438 /* We first need to check how many occurences of %ll there are in the
439 * psz_format string. Once we'll know that we'll be able to malloc the
440 * destination string */
442 if( strlen( psz_format ) <= 3 )
443 return strdup( psz_format );
445 for( i=0; i <= (strlen(psz_format) - 3); i++ )
447 if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
453 /* malloc the destination string */
454 psz_dest = malloc( strlen(psz_format) + i_counter + 1 );
455 if( psz_dest == NULL )
457 fprintf( stderr, "intf warning: ConvertPrintfFormatString failed\n");
461 /* Now build the modified string */
463 for( i=0; i <= (strlen(psz_format) - 3); i++ )
465 if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
467 memcpy( psz_dest+i_pos+i_counter, psz_format+i_pos, i-i_pos+1);
468 *(psz_dest+i+i_counter+1)='I';
469 *(psz_dest+i+i_counter+2)='6';
470 *(psz_dest+i+i_counter+3)='4';
475 strcpy( psz_dest+i_pos+i_counter, psz_format+i_pos );