]> git.sesse.net Git - vlc/blob - src/interface/intf_msg.c
* Added error checking in pthread wrapper ; as a result, intf_msg.h must
[vlc] / src / interface / intf_msg.c
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 $
8  *
9  * Authors: Vincent Seguin <seguin@via.ecp.fr>
10  *
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.
15  * 
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.
20  *
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  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include "defs.h"
30
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() */
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>                                      /* close(), write() */
40 #endif
41
42 #include "config.h"
43 #include "common.h"
44 #include "intf_msg.h"
45 #include "threads.h"
46 #include "mtime.h"
47
48 #include "interface.h"
49
50 #include "main.h"
51
52 /*****************************************************************************
53  * intf_msg_item_t
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  *****************************************************************************/
59 typedef struct
60 {
61     int     i_type;                               /* message type, see below */
62     char *  psz_msg;                                   /* the message itself */
63
64 #ifdef TRACE
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 */
71 #endif
72 } intf_msg_item_t;
73
74 /* Message types */
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 */
80
81
82 /*****************************************************************************
83  * intf_msg_t
84  *****************************************************************************
85  * Store all data requiered by messages interfaces. It has a single reference
86  * int p_main.
87  *****************************************************************************/
88 typedef struct intf_msg_s
89 {
90 #ifdef INTF_MSG_QUEUE
91     /* Message queue */
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 */
95 #endif
96
97 #ifdef TRACE_LOG
98     /* Log file */
99     FILE *                  p_log_file;                          /* log file */
100 #endif
101
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 */
107 #endif
108 } intf_msg_t;
109
110 /*****************************************************************************
111  * Local prototypes
112  *****************************************************************************/
113
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 );
117 #ifdef TRACE
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 );
121 #endif
122 #ifdef INTF_MSG_QUEUE
123 static void FlushLockedMsg  ( intf_msg_t *p_msg );
124 #endif
125
126 #if defined( WIN32 )
127 static char *ConvertPrintfFormatString ( char *psz_format );
128 #endif
129
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 )
137 {
138     p_intf_msg_t p_msg;
139
140     /* Allocate structure */
141     p_msg = malloc( sizeof( intf_msg_t ) );
142     if( p_msg == NULL )
143     {
144         errno = ENOMEM;
145     }
146     else
147     {
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 */
152 #endif
153
154     
155 #ifdef TRACE_LOG
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
158          * error */
159         p_msg->p_log_file = fopen( TRACE_LOG, "w" );
160 #endif
161     }
162     return( p_msg );
163 }
164
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 )
173 {
174     intf_FlushMsg();                         /* print all remaining messages */
175
176 #ifdef TRACE_LOG
177     /* Close log file if any */
178     if( p_main->p_msg->p_log_file != NULL )
179     {
180         fclose( p_main->p_msg->p_log_file );
181     }
182 #endif
183
184 #ifdef INTF_MSG_QUEUE
185     /* destroy lock */
186     vlc_mutex_destroy( &p_main->p_msg->lock );
187 #endif
188     
189     /* Free structure */
190     free( p_main->p_msg );
191 }
192
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, ... )
200 {
201     va_list ap;
202
203     va_start( ap, psz_format );
204     QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
205     va_end( ap );
206 }
207
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
212  * on stderr.
213  *****************************************************************************/
214 void intf_ErrMsg( char *psz_format, ... )
215 {
216     va_list ap;
217
218     va_start( ap, psz_format );
219     QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
220     va_end( ap );
221 }
222
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, ... )
230 {
231     va_list ap;
232     
233     if( i_level <= p_main->i_warning_level )
234     {
235         va_start( ap, psz_format );
236         QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
237         va_end( ap );
238     }
239 }
240
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, ... )
248 {
249     va_list ap;
250     
251     if( p_main->b_stats )
252     {
253         va_start( ap, psz_format );
254         QueueMsg( p_main->p_msg, INTF_MSG_STAT, psz_format, ap );
255         va_end( ap );
256     }
257 }
258
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  *****************************************************************************/
267 #ifdef TRACE
268 void _intf_DbgMsg( char *psz_file, char *psz_function, int i_line,
269                    char *psz_format, ...)
270 {
271     va_list ap;
272
273     va_start( ap, psz_format );
274     QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
275                  psz_format, ap );
276     va_end( ap );
277 }
278 #endif
279
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, ... )
287 {
288     va_list ap;
289
290     va_start( ap, psz_format );
291     QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
292     va_end( ap );
293     intf_FlushMsg();
294 }
295
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
300  * on stderr.
301  *****************************************************************************/
302 void intf_ErrMsgImm(char *psz_format, ...)
303 {
304     va_list ap;
305
306     va_start( ap, psz_format );
307     QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
308     va_end( ap );
309     intf_FlushMsg();
310 }
311
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, ... )
319 {
320     va_list ap;
321
322     if( i_level <= p_main->i_warning_level )
323     {
324         va_start( ap, psz_format );
325         QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
326         va_end( ap );
327     }
328     intf_FlushMsg();
329 }
330
331
332
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
338  * intf_DbgMsgImm().
339  *****************************************************************************/
340 #ifdef TRACE
341 void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
342                       char *psz_format, ...)
343 {
344     va_list ap;
345
346     va_start( ap, psz_format );
347     QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
348                  psz_format, ap );
349     va_end( ap );
350     intf_FlushMsg();
351 }
352 #endif
353
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 )
360 {
361     int   i_index = 0;
362     int   i_subindex;
363     char  p_string[75];
364     u8   *p_area = (u8 *)p_data;
365
366     intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
367                            i_size, p_data );
368
369     while( i_index < i_size )
370     {
371         i_subindex = 0;
372
373         while( ( i_subindex < 24 ) && ( i_index + i_subindex < i_size ) )
374         {
375             sprintf( p_string + 3 * i_subindex, "%.2x ",
376                      p_area[ i_index + i_subindex ] );
377
378             i_subindex++;
379         }
380
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 );
384
385         i_index += 24;
386     }
387
388     intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
389 }
390
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
397  * an empty macro.
398  *****************************************************************************/
399 #ifdef INTF_MSG_QUEUE
400 void intf_FlushMsg( void )
401 {
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 */
405 }
406 #endif
407
408 /* following functions are local */
409
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 )
419 {
420     char *                  psz_str;             /* formatted message string */
421     intf_msg_item_t *       p_msg_item;                /* pointer to message */
422 #ifdef WIN32
423     char *                  psz_temp;
424 #endif
425
426 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
427     intf_msg_item_t         msg_item;                             /* message */
428     p_msg_item =           &msg_item;
429 #endif /*....................................................................*/
430
431     /*
432      * Convert message to string
433      */
434
435 #ifdef HAVE_VASPRINTF
436     vasprintf( &psz_str, psz_format, ap );
437 #else
438     psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
439 #endif
440     if( psz_str == NULL )
441     {
442         fprintf(stderr, "warning: can't store following message (%s): ",
443                 strerror(errno) );
444         vfprintf(stderr, psz_format, ap );
445         fprintf(stderr, "\n" );
446         exit( errno );
447     }
448 #ifndef HAVE_VASPRINTF
449 #ifdef WIN32
450     psz_temp = ConvertPrintfFormatString(psz_format);
451     vsprintf( psz_str, psz_temp, ap );
452     free( psz_temp );
453 #else
454     vsprintf( psz_str, psz_format, ap );
455 #endif /* WIN32 */
456 #endif /* HAVE_VASPRINTF */
457
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 */
461     {
462 #ifdef DEBUG               /* in debug mode, queue overflow causes a warning */
463         fprintf(stderr, "warning: message queue overflow\n" );
464 #endif
465         FlushLockedMsg( p_msg );
466     }
467     p_msg_item = p_msg->msg + p_msg->i_count++;            /* select message */
468 #endif /*.............................................. end of queue mode ...*/
469
470     /*
471      * Fill message information fields
472      */
473     p_msg_item->i_type =     i_type;
474     p_msg_item->psz_msg =    psz_str;
475 #ifdef TRACE    
476     p_msg_item->date =       mdate();
477 #endif
478
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 /*....................................................................*/
485 }
486
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  *****************************************************************************/
493 #ifdef TRACE
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)
496 {
497     char *                  psz_str;             /* formatted message string */
498     intf_msg_item_t *       p_msg_item;                /* pointer to message */
499 #ifdef WIN32
500     char *                  psz_temp;
501 #endif
502
503 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
504     intf_msg_item_t         msg_item;                             /* message */
505     p_msg_item =           &msg_item;
506 #endif /*....................................................................*/
507
508     /*
509      * Convert message to string
510      */
511 #ifdef HAVE_VASPRINTF
512     vasprintf( &psz_str, psz_format, ap );
513 #else
514     psz_str = (char*) malloc( INTF_MAX_MSG_SIZE );
515 #endif
516     if( psz_str == NULL )
517     {
518         fprintf(stderr, "warning: can't store following message (%s): ",
519                 strerror(errno) );
520         fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
521         vfprintf(stderr, psz_format, ap );
522         fprintf(stderr, "\n" );
523         exit( errno );
524     }
525 #ifndef HAVE_VASPRINTF
526 #ifdef WIN32
527     psz_temp = ConvertPrintfFormatString(psz_format);
528     vsprintf( psz_str, psz_temp, ap );
529     free( psz_temp );
530 #else
531     vsprintf( psz_str, psz_format, ap );
532 #endif /* WIN32 */
533 #endif /* HAVE_VASPRINTF */
534
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 */
538     {
539         fprintf(stderr, "warning: message queue overflow\n" );
540         FlushLockedMsg( p_msg );
541     }
542     p_msg_item = p_msg->msg + p_msg->i_count++;            /* select message */
543 #endif /*.............................................. end of queue mode ...*/
544
545     /*
546      * Fill message information fields
547      */
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();
554
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 /*....................................................................*/
561 }
562 #endif
563
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 )
573 {
574     int i_index;
575
576     for( i_index = 0; i_index < p_msg->i_count; i_index++ )
577     {
578         /* Print message and free message data */
579         PrintMsg( &p_msg->msg[i_index] );
580         free( p_msg->msg[i_index].psz_msg );
581     }
582
583     p_msg->i_count = 0;
584 }
585 #endif
586
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  *****************************************************************************/
595 #ifdef TRACE
596
597 static void PrintMsg( intf_msg_item_t *p_msg )
598 {
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 */
602
603     psz_msg = malloc( sizeof( char ) * i_msg_len );
604
605     /* Check if allocation succeeded */
606     if( psz_msg == NULL )
607     {
608         fprintf( stderr, "error: not enough memory for message %s\n",
609                  p_msg->psz_msg );
610         return;
611     }
612
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 )
616     {
617     case INTF_MSG_STD:                                   /* regular messages */
618     case INTF_MSG_STAT:
619     case INTF_MSG_ERR:
620         snprintf( psz_msg, i_msg_len, "%s", p_msg->psz_msg );
621         break;
622
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 );
627
628         break;
629         
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,
634                   p_msg->psz_msg );
635         break;
636     }
637
638     /*
639      * Print messages
640      */
641     switch( p_msg->i_type )
642     {
643     case INTF_MSG_STD:                                  /* standard messages */
644     case INTF_MSG_STAT:
645         fprintf( stdout, "%s\n", psz_msg );
646         break;
647     case INTF_MSG_ERR:                                     /* error messages */
648     case INTF_MSG_WARN:
649 #ifndef TRACE_LOG_ONLY
650     case INTF_MSG_DBG:                                 /* debugging messages */
651 #endif
652         fprintf( stderr, "%s\n", psz_msg );
653         break;
654     }
655
656 #ifdef TRACE_LOG
657     /* Append all messages to log file */
658     if( p_main->p_msg->p_log_file != NULL )
659     {
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 );
662     }
663 #endif
664
665     /* Free the message */
666     free( psz_msg );
667 }
668
669 #else
670
671 static void PrintMsg( intf_msg_item_t *p_msg )
672 {
673     /*
674      * Print messages on screen
675      */
676     switch( p_msg->i_type )
677     {
678     case INTF_MSG_STD:                                  /* standard messages */
679     case INTF_MSG_STAT:
680     case INTF_MSG_DBG:                                     /* debug messages */
681         fprintf( stdout, "%s\n", p_msg->psz_msg );
682         break;
683     case INTF_MSG_ERR:                                     /* error messages */
684     case INTF_MSG_WARN:
685         fprintf( stderr, "%s\n", p_msg->psz_msg );        /* warning message */
686         break;
687     }
688 }
689
690 #endif
691
692
693 #if defined( WIN32 )
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 )
706 {
707   int i, i_counter=0, i_pos=0;
708   char *psz_dest;
709
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 */
713
714   for( i=0; i <= (strlen(psz_format) - 4); i++ )
715   {
716       if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
717           i_counter++;
718   }
719
720   /* malloc the destination string */
721   psz_dest = malloc( strlen(psz_format) + i_counter + 1 );
722   if( psz_dest == NULL )
723   {
724       fprintf(stderr, "warning: malloc failed in ConvertPrintfFormatString\n");
725       exit (errno);
726   }
727
728   /* Now build the modified string */
729   i_counter = 0;
730   for( i=0; i <= (strlen(psz_format) - 4); i++ )
731   {
732       if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
733       {
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';
738           i_pos = i+3;
739           i_counter++;
740       }
741   }
742   strcpy( psz_dest+i_pos+i_counter, psz_format+i_pos );
743
744   return psz_dest;
745 }
746 #endif