* ./src/interface/intf_msg.c, src/interface/intf_playlist.c: disabled
[vlc.git] / src / interface / intf_msg.c
blobbc912977bb72a4b133d1c8ecfad468e6866fd340
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 /*****************************************************************************
27 * Preamble
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>
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h> /* close(), write() */
40 #endif
42 #include "interface.h"
45 /*****************************************************************************
46 * intf_msg_t
47 *****************************************************************************
48 * Store all data requiered by messages interfaces. It has a single reference
49 * int p_main.
50 *****************************************************************************/
51 typedef struct msg_bank_s
53 /* Message queue lock */
54 vlc_mutex_t lock;
56 /* Message queue */
57 msg_item_t msg[INTF_MSG_QSIZE]; /* message queue */
58 int i_start;
59 int i_stop;
61 /* Subscribers */
62 int i_sub;
63 intf_subscription_t **pp_sub;
65 } msg_bank_t;
67 msg_bank_t msg_bank;
69 /*****************************************************************************
70 * Local prototypes
71 *****************************************************************************/
72 static void QueueMsg ( int, int, char *, va_list );
73 static void FlushMsg ( void );
75 #if defined( WIN32 )
76 static char *ConvertPrintfFormatString ( char *psz_format );
77 #endif
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 );
89 msg_bank.i_start = 0;
90 msg_bank.i_stop = 0;
92 msg_bank.i_sub = 0;
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 )
105 /* Destroy lock */
106 vlc_mutex_destroy( &msg_bank.lock );
108 if( msg_bank.i_sub )
110 fprintf( stderr, "intf error: stale interface subscribers\n" );
113 /* Free remaining messages */
114 FlushMsg( );
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 */
127 msg_bank.i_sub++;
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 );
141 return p_sub;
144 /*****************************************************************************
145 * intf_MsgUnsub: unsubscribe from the message queue.
146 *****************************************************************************/
147 void intf_MsgUnsub( intf_subscription_t *p_sub )
149 int i_index;
151 vlc_mutex_lock( &msg_bank.lock );
153 /* Sanity check */
154 if( !msg_bank.i_sub )
156 intf_ErrMsg( "intf error: no subscriber in the list" );
157 return;
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 )
165 break;
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 );
173 return;
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 ];
182 msg_bank.i_sub--;
183 if( msg_bank.i_sub )
185 msg_bank.pp_sub = realloc( msg_bank.pp_sub,
186 msg_bank.i_sub * sizeof( intf_subscription_t* ) );
188 else
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, ... )
205 va_list ap;
207 va_start( ap, psz_format );
208 QueueMsg( INTF_MSG_STD, 0, psz_format, ap );
209 va_end( 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
216 * on stderr.
217 *****************************************************************************/
218 void intf_ErrMsg( char *psz_format, ... )
220 va_list ap;
222 va_start( ap, psz_format );
223 QueueMsg( INTF_MSG_ERR, 0, psz_format, ap );
224 va_end( 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, ... )
235 va_list ap;
237 va_start( ap, psz_format );
238 QueueMsg( INTF_MSG_WARN, i_level, psz_format, ap );
239 va_end( 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, ... )
250 va_list ap;
252 if( p_main->b_stats )
254 va_start( ap, psz_format );
255 QueueMsg( INTF_MSG_STAT, 0, psz_format, ap );
256 va_end( 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 )
267 int i_index = 0;
268 int i_subindex;
269 char p_string[75];
270 u8 *p_area = (u8 *)p_data;
272 intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
273 i_size, p_data );
275 while( i_index < i_size )
277 i_subindex = 0;
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 ] );
284 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 );
291 i_index += 24;
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
305 * a warning.
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 */
311 #ifdef WIN32
312 char * psz_temp;
313 #endif
316 * Convert message to string
318 #ifdef HAVE_VASPRINTF
319 vasprintf( &psz_str, psz_format, ap );
320 #else
321 psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
322 #endif
324 if( psz_str == NULL )
326 fprintf(stderr, "intf warning: can't store following message (%s): ",
327 strerror(errno) );
328 vfprintf(stderr, psz_format, ap );
329 fprintf(stderr, "\n" );
330 return;
333 #ifndef HAVE_VASPRINTF
334 # ifdef WIN32
335 psz_temp = ConvertPrintfFormatString(psz_format);
336 if( !psz_temp )
338 fprintf(stderr, "intf warning: couldn't print message");
339 return;
341 vsprintf( psz_str, psz_temp, ap );
342 free( psz_temp );
343 # else
344 vsprintf( psz_str, psz_format, ap );
345 # endif
346 #endif
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 )
360 FlushMsg( );
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 );
366 return;
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 /*****************************************************************************
381 * FlushMsg
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) ) )
405 i_stop = i_start;
409 /* Free message data */
410 for( i_index = msg_bank.i_start;
411 i_index != i_stop;
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 *****************************************************************************/
432 #if defined( WIN32 )
433 static char *ConvertPrintfFormatString( char *psz_format )
435 int i, i_counter=0, i_pos=0;
436 char *psz_dest;
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 ) )
449 i_counter++;
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");
458 return NULL;
461 /* Now build the modified string */
462 i_counter = 0;
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';
471 i_pos = i+3;
472 i_counter++;
475 strcpy( psz_dest+i_pos+i_counter, psz_format+i_pos );
477 return psz_dest;
479 #endif