]> git.sesse.net Git - vlc/blob - src/interface/intf_msg.c
eb0ff2d85dea230e8486626a535a8a035eaac775
[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.40 2001/12/07 18:33:08 sam 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 "common.h"
43 #include "intf_msg.h"
44 #include "threads.h"
45 #include "mtime.h"
46
47 #include "interface.h"
48
49 /*****************************************************************************
50  * intf_msg_item_t
51  *****************************************************************************
52  * Store a single message. Messages have a maximal size of INTF_MSG_MSGSIZE.
53  * If TRACE is defined, messages have a date field and debug messages are
54  * printed with a date to allow more precise profiling.
55  *****************************************************************************/
56 typedef struct
57 {
58     int     i_type;                               /* message type, see below */
59     char *  psz_msg;                                   /* the message itself */
60
61 #ifdef TRACE
62     /* Debugging informations - in TRACE mode, debug messages have calling
63      * location information printed */
64     mtime_t date;                                     /* date of the message */
65     char *  psz_file;               /* file in which the function was called */
66     char *  psz_function;     /* function from which the function was called */
67     int     i_line;                 /* line at which the function was called */
68 #endif
69 } intf_msg_item_t;
70
71 /* Message types */
72 #define INTF_MSG_STD    0                                /* standard message */
73 #define INTF_MSG_ERR    1                                   /* error message */
74 #define INTF_MSG_DBG    3                                   /* debug message */
75 #define INTF_MSG_WARN   4                                 /* warning message */
76 #define INTF_MSG_STAT   5                               /* statistic message */
77
78
79 /*****************************************************************************
80  * intf_msg_t
81  *****************************************************************************
82  * Store all data requiered by messages interfaces. It has a single reference
83  * int p_main.
84  *****************************************************************************/
85 typedef struct intf_msg_s
86 {
87 #ifdef INTF_MSG_QUEUE
88     /* Message queue */
89     vlc_mutex_t             lock;                      /* message queue lock */
90     int                     i_count;            /* number of messages stored */
91     intf_msg_item_t         msg[INTF_MSG_QSIZE];            /* message queue */
92 #endif
93
94 #ifdef TRACE_LOG
95     /* Log file */
96     FILE *                  p_log_file;                          /* log file */
97 #endif
98
99 #if !defined(INTF_MSG_QUEUE) && !defined(TRACE_LOG)
100     /* If neither messages queue, neither log file is used, then the structure
101      * is empty. However, empty structures are not allowed in C. Therefore, a
102      * dummy integer is used to fill it. */
103     int                     i_dummy;                        /* unused filler */
104 #endif
105 } intf_msg_t;
106
107 /*****************************************************************************
108  * Local prototypes
109  *****************************************************************************/
110
111 static void QueueMsg        ( intf_msg_t *p_msg, int i_type,
112                               char *psz_format, va_list ap );
113 static void PrintMsg        ( intf_msg_item_t *p_msg );
114 #ifdef TRACE
115 static void QueueDbgMsg     ( intf_msg_t *p_msg, char *psz_file,
116                               char *psz_function, int i_line,
117                               char *psz_format, va_list ap );
118 #endif
119 #ifdef INTF_MSG_QUEUE
120 static void FlushLockedMsg  ( intf_msg_t *p_msg );
121 #endif
122
123 #if defined( WIN32 )
124 static char *ConvertPrintfFormatString ( char *psz_format );
125 #endif
126
127 /*****************************************************************************
128  * intf_MsgCreate: initialize messages interface                         (ok ?)
129  *****************************************************************************
130  * This functions has to be called before any call to other intf_*Msg functions.
131  * It set up the locks and the message queue if it is used.
132  *****************************************************************************/
133 p_intf_msg_t intf_MsgCreate( void )
134 {
135     p_intf_msg_t p_msg;
136
137     /* Allocate structure */
138     p_msg = malloc( sizeof( intf_msg_t ) );
139     if( p_msg == NULL )
140     {
141         errno = ENOMEM;
142     }
143     else
144     {
145 #ifdef INTF_MSG_QUEUE
146     /* Message queue initialization */
147     vlc_mutex_init( &p_msg->lock );                        /* intialize lock */
148     p_msg->i_count = 0;                                    /* queue is empty */
149 #endif
150
151     
152 #ifdef TRACE_LOG
153         /* Log file initialization - on failure, file pointer will be null,
154          * and no log will be issued, but this is not considered as an
155          * error */
156         p_msg->p_log_file = fopen( TRACE_LOG, "w" );
157 #endif
158     }
159     return( p_msg );
160 }
161
162 /*****************************************************************************
163  * intf_MsgDestroy: free resources allocated by intf_InitMsg            (ok ?)
164  *****************************************************************************
165  * This functions prints all messages remaining in queue, then free all the
166  * resources allocated by intf_InitMsg.
167  * No other messages interface functions should be called after this one.
168  *****************************************************************************/
169 void intf_MsgDestroy( void )
170 {
171     intf_FlushMsg();                         /* print all remaining messages */
172
173 #ifdef TRACE_LOG
174     /* Close log file if any */
175     if( p_main->p_msg->p_log_file != NULL )
176     {
177         fclose( p_main->p_msg->p_log_file );
178     }
179 #endif
180
181 #ifdef INTF_MSG_QUEUE
182     /* destroy lock */
183     vlc_mutex_destroy( &p_main->p_msg->lock );
184 #endif
185     
186     /* Free structure */
187     free( p_main->p_msg );
188 }
189
190 /*****************************************************************************
191  * intf_Msg: print a message                                             (ok ?)
192  *****************************************************************************
193  * This function queue a message for later printing, or print it immediately
194  * if the queue isn't used.
195  *****************************************************************************/
196 void intf_Msg( char *psz_format, ... )
197 {
198     va_list ap;
199
200     va_start( ap, psz_format );
201     QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
202     va_end( ap );
203 }
204
205 /*****************************************************************************
206  * intf_ErrMsg : print an error message                                  (ok ?)
207  *****************************************************************************
208  * This function is the same as intf_Msg, except that it prints its messages
209  * on stderr.
210  *****************************************************************************/
211 void intf_ErrMsg( char *psz_format, ... )
212 {
213     va_list ap;
214
215     va_start( ap, psz_format );
216     QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
217     va_end( ap );
218 }
219
220 /*****************************************************************************
221  * intf_WarnMsg : print a warning message
222  *****************************************************************************
223  * This function is the same as intf_Msg, except that it concerns warning
224  * messages for testing purpose.
225  *****************************************************************************/
226 void intf_WarnMsg( int i_level, char *psz_format, ... )
227 {
228     va_list ap;
229     
230     if( i_level <= p_main->i_warning_level )
231     {
232         va_start( ap, psz_format );
233         QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
234         va_end( ap );
235     }
236 }
237
238 /*****************************************************************************
239  * intf_StatMsg : print a statistic message
240  *****************************************************************************
241  * This function is the same as intf_Msg, except that it concerns statistic
242  * messages for testing purpose.
243  *****************************************************************************/
244 void intf_StatMsg( char *psz_format, ... )
245 {
246     va_list ap;
247     
248     if( p_main->b_stats )
249     {
250         va_start( ap, psz_format );
251         QueueMsg( p_main->p_msg, INTF_MSG_STAT, psz_format, ap );
252         va_end( ap );
253     }
254 }
255
256 /*****************************************************************************
257  * _intf_DbgMsg: print a debugging message                               (ok ?)
258  *****************************************************************************
259  * This function prints a debugging message. Compared to other intf_*Msg
260  * functions, it is only defined if TRACE is defined and require a file name,
261  * a function name and a line number as additionnal debugging informations. It
262  * also prints a debugging header for each received line.
263  *****************************************************************************/
264 #ifdef TRACE
265 void _intf_DbgMsg( char *psz_file, char *psz_function, int i_line,
266                    char *psz_format, ...)
267 {
268     va_list ap;
269
270     va_start( ap, psz_format );
271     QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
272                  psz_format, ap );
273     va_end( ap );
274 }
275 #endif
276
277 /*****************************************************************************
278  * intf_MsgImm: print a message                                          (ok ?)
279  *****************************************************************************
280  * This function prints a message immediately. If the queue is used, all
281  * waiting messages are also printed.
282  *****************************************************************************/
283 void intf_MsgImm( char *psz_format, ... )
284 {
285     va_list ap;
286
287     va_start( ap, psz_format );
288     QueueMsg( p_main->p_msg, INTF_MSG_STD, psz_format, ap );
289     va_end( ap );
290     intf_FlushMsg();
291 }
292
293 /*****************************************************************************
294  * intf_ErrMsgImm: print an error message immediately                    (ok ?)
295  *****************************************************************************
296  * This function is the same as intf_MsgImm, except that it prints its message
297  * on stderr.
298  *****************************************************************************/
299 void intf_ErrMsgImm(char *psz_format, ...)
300 {
301     va_list ap;
302
303     va_start( ap, psz_format );
304     QueueMsg( p_main->p_msg, INTF_MSG_ERR, psz_format, ap );
305     va_end( ap );
306     intf_FlushMsg();
307 }
308
309 /*****************************************************************************
310  * intf_WarnMsgImm : print a warning message
311  *****************************************************************************
312  * This function is the same as intf_MsgImm, except that it concerns warning
313  * messages for testing purpose.
314  *****************************************************************************/
315 void intf_WarnMsgImm( int i_level, char *psz_format, ... )
316 {
317     va_list ap;
318
319     if( i_level <= p_main->i_warning_level )
320     {
321         va_start( ap, psz_format );
322         QueueMsg( p_main->p_msg, INTF_MSG_WARN, psz_format, ap );
323         va_end( ap );
324     }
325     intf_FlushMsg();
326 }
327
328
329
330 /*****************************************************************************
331  * _intf_DbgMsgImm: print a debugging message immediately                (ok ?)
332  *****************************************************************************
333  * This function is the same as intf_DbgMsgImm, except that it prints its
334  * message immediately. It should only be called through the macro
335  * intf_DbgMsgImm().
336  *****************************************************************************/
337 #ifdef TRACE
338 void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
339                       char *psz_format, ...)
340 {
341     va_list ap;
342
343     va_start( ap, psz_format );
344     QueueDbgMsg( p_main->p_msg, psz_file, psz_function, i_line,
345                  psz_format, ap );
346     va_end( ap );
347     intf_FlushMsg();
348 }
349 #endif
350
351 /*****************************************************************************
352  * intf_WarnHexDump : print a hexadecimal dump of a memory area
353  *****************************************************************************
354  * This is convenient for debugging purposes.
355  *****************************************************************************/
356 void intf_WarnHexDump( int i_level, void *p_data, int i_size )
357 {
358     int   i_index = 0;
359     int   i_subindex;
360     char  p_string[75];
361     u8   *p_area = (u8 *)p_data;
362
363     intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
364                            i_size, p_data );
365
366     while( i_index < i_size )
367     {
368         i_subindex = 0;
369
370         while( ( i_subindex < 24 ) && ( i_index + i_subindex < i_size ) )
371         {
372             sprintf( p_string + 3 * i_subindex, "%.2x ",
373                      p_area[ i_index + i_subindex ] );
374
375             i_subindex++;
376         }
377
378         /* -1 here is safe because we know we printed at least one */
379         p_string[ 3 * i_subindex - 1 ] = '\0';
380         intf_WarnMsg( i_level, "0x%.4x: %s", i_index, p_string );
381
382         i_index += 24;
383     }
384
385     intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
386 }
387
388 /*****************************************************************************
389  * intf_FlushMsg                                                        (ok ?)
390  *****************************************************************************
391  * Print all messages remaining in queue: get lock and call FlushLockedMsg.
392  * This function does nothing if the message queue isn't used.
393  * This function is only implemented if message queue is used. If not, it is
394  * an empty macro.
395  *****************************************************************************/
396 #ifdef INTF_MSG_QUEUE
397 void intf_FlushMsg( void )
398 {
399     vlc_mutex_lock( &p_main->p_msg->lock );                      /* get lock */
400     FlushLockedMsg( p_main->p_msg );                       /* flush messages */
401     vlc_mutex_unlock( &p_main->p_msg->lock );              /* give lock back */
402 }
403 #endif
404
405 /* following functions are local */
406
407 /*****************************************************************************
408  * QueueMsg: add a message to a queue
409  *****************************************************************************
410  * This function provide basic functionnalities to other intf_*Msg functions.
411  * It add a message to a queue (after having printed all stored messages if it
412  * is full. If the message can't be converted to string in memory, it exit the
413  * program. If the queue is not used, it prints the message immediately.
414  *****************************************************************************/
415 static void QueueMsg( intf_msg_t *p_msg, int i_type, char *psz_format, va_list ap )
416 {
417     char *                  psz_str;             /* formatted message string */
418     intf_msg_item_t *       p_msg_item;                /* pointer to message */
419 #ifdef WIN32
420     char *                  psz_temp;
421 #endif
422
423 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
424     intf_msg_item_t         msg_item;                             /* message */
425     p_msg_item =           &msg_item;
426 #endif /*....................................................................*/
427
428     /*
429      * Convert message to string
430      */
431
432 #ifdef HAVE_VASPRINTF
433     vasprintf( &psz_str, psz_format, ap );
434 #else
435     psz_str = (char*) malloc( strlen(psz_format) + INTF_MAX_MSG_SIZE );
436 #endif
437     if( psz_str == NULL )
438     {
439         fprintf(stderr, "warning: can't store following message (%s): ",
440                 strerror(errno) );
441         vfprintf(stderr, psz_format, ap );
442         fprintf(stderr, "\n" );
443         exit( errno );
444     }
445 #ifndef HAVE_VASPRINTF
446 #ifdef WIN32
447     psz_temp = ConvertPrintfFormatString(psz_format);
448     vsprintf( psz_str, psz_temp, ap );
449     free( psz_temp );
450 #else
451     vsprintf( psz_str, psz_format, ap );
452 #endif /* WIN32 */
453 #endif /* HAVE_VASPRINTF */
454
455 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
456     vlc_mutex_lock( &p_msg->lock );                              /* get lock */
457     if( p_msg->i_count == INTF_MSG_QSIZE )          /* flush queue if needed */
458     {
459 #ifdef DEBUG               /* in debug mode, queue overflow causes a warning */
460         fprintf(stderr, "warning: message queue overflow\n" );
461 #endif
462         FlushLockedMsg( p_msg );
463     }
464     p_msg_item = p_msg->msg + p_msg->i_count++;            /* select message */
465 #endif /*.............................................. end of queue mode ...*/
466
467     /*
468      * Fill message information fields
469      */
470     p_msg_item->i_type =     i_type;
471     p_msg_item->psz_msg =    psz_str;
472 #ifdef TRACE    
473     p_msg_item->date =       mdate();
474 #endif
475
476 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
477     vlc_mutex_unlock( &p_msg->lock );                      /* give lock back */
478 #else /*....................................................... instant mode */
479     PrintMsg( p_msg_item );                                 /* print message */
480     free( psz_str );                                    /* free message data */
481 #endif /*....................................................................*/
482 }
483
484 /*****************************************************************************
485  * QueueDbgMsg: add a message to a queue with debugging informations
486  *****************************************************************************
487  * This function is the same as QueueMsg, except that it is only defined when
488  * TRACE is define, and require additionnal debugging informations.
489  *****************************************************************************/
490 #ifdef TRACE
491 static void QueueDbgMsg(intf_msg_t *p_msg, char *psz_file, char *psz_function,
492                         int i_line, char *psz_format, va_list ap)
493 {
494     char *                  psz_str;             /* formatted message string */
495     intf_msg_item_t *       p_msg_item;                /* pointer to message */
496 #ifdef WIN32
497     char *                  psz_temp;
498 #endif
499
500 #ifndef INTF_MSG_QUEUE /*................................... instant mode ...*/
501     intf_msg_item_t         msg_item;                             /* message */
502     p_msg_item =           &msg_item;
503 #endif /*....................................................................*/
504
505     /*
506      * Convert message to string
507      */
508 #ifdef HAVE_VASPRINTF
509     vasprintf( &psz_str, psz_format, ap );
510 #else
511     psz_str = (char*) malloc( INTF_MAX_MSG_SIZE );
512 #endif
513     if( psz_str == NULL )
514     {
515         fprintf(stderr, "warning: can't store following message (%s): ",
516                 strerror(errno) );
517         fprintf(stderr, INTF_MSG_DBG_FORMAT, psz_file, psz_function, i_line );
518         vfprintf(stderr, psz_format, ap );
519         fprintf(stderr, "\n" );
520         exit( errno );
521     }
522 #ifndef HAVE_VASPRINTF
523 #ifdef WIN32
524     psz_temp = ConvertPrintfFormatString(psz_format);
525     vsprintf( psz_str, psz_temp, ap );
526     free( psz_temp );
527 #else
528     vsprintf( psz_str, psz_format, ap );
529 #endif /* WIN32 */
530 #endif /* HAVE_VASPRINTF */
531
532 #ifdef INTF_MSG_QUEUE /*...................................... queue mode ...*/
533     vlc_mutex_lock( &p_msg->lock );                              /* get lock */
534     if( p_msg->i_count == INTF_MSG_QSIZE )          /* flush queue if needed */
535     {
536         fprintf(stderr, "warning: message queue overflow\n" );
537         FlushLockedMsg( p_msg );
538     }
539     p_msg_item = p_msg->msg + p_msg->i_count++;            /* select message */
540 #endif /*.............................................. end of queue mode ...*/
541
542     /*
543      * Fill message information fields
544      */
545     p_msg_item->i_type =       INTF_MSG_DBG;
546     p_msg_item->psz_msg =      psz_str;
547     p_msg_item->psz_file =     psz_file;
548     p_msg_item->psz_function = psz_function;
549     p_msg_item->i_line =       i_line;
550     p_msg_item->date =         mdate();
551
552 #ifdef INTF_MSG_QUEUE /*......................................... queue mode */
553     vlc_mutex_unlock( &p_msg->lock );                      /* give lock back */
554 #else /*....................................................... instant mode */
555     PrintMsg( p_msg_item );                                 /* print message */
556     free( psz_str );                                    /* free message data */
557 #endif /*....................................................................*/
558 }
559 #endif
560
561 /*****************************************************************************
562  * FlushLockedMsg                                                       (ok ?)
563  *****************************************************************************
564  * Print all messages remaining in queue. MESSAGE QUEUE MUST BE LOCKED, since
565  * this function does not check the lock. This function is only defined if
566  * INTF_MSG_QUEUE is defined.
567  *****************************************************************************/
568 #ifdef INTF_MSG_QUEUE
569 static void FlushLockedMsg ( intf_msg_t *p_msg )
570 {
571     int i_index;
572
573     for( i_index = 0; i_index < p_msg->i_count; i_index++ )
574     {
575         /* Print message and free message data */
576         PrintMsg( &p_msg->msg[i_index] );
577         free( p_msg->msg[i_index].psz_msg );
578     }
579
580     p_msg->i_count = 0;
581 }
582 #endif
583
584 /*****************************************************************************
585  * PrintMsg: print a message                                             (ok ?)
586  *****************************************************************************
587  * Print a single message. The message data is not freed. This function exists
588  * in two version. The TRACE version prints a date with each message, and is
589  * able to log messages (if TRACE_LOG is defined).
590  * The normal one just prints messages to the screen.
591  *****************************************************************************/
592 #ifdef TRACE
593
594 static void PrintMsg( intf_msg_item_t *p_msg )
595 {
596     char    psz_date[MSTRTIME_MAX_SIZE];            /* formatted time buffer */
597     int     i_msg_len = MSTRTIME_MAX_SIZE + strlen(p_msg->psz_msg) + 200;
598     char   *psz_msg;                                       /* message buffer */
599
600     psz_msg = malloc( sizeof( char ) * i_msg_len );
601
602     /* Check if allocation succeeded */
603     if( psz_msg == NULL )
604     {
605         fprintf( stderr, "error: not enough memory for message %s\n",
606                  p_msg->psz_msg );
607         return;
608     }
609
610     /* Format message - the message is formatted here because in case the log
611      * file is used, it avoids another format string parsing */
612     switch( p_msg->i_type )
613     {
614     case INTF_MSG_STD:                                   /* regular messages */
615     case INTF_MSG_STAT:
616     case INTF_MSG_ERR:
617         snprintf( psz_msg, i_msg_len, "%s", p_msg->psz_msg );
618         break;
619
620     case INTF_MSG_WARN:                                   /* Warning message */
621         mstrtime( psz_date, p_msg->date );
622         snprintf( psz_msg, i_msg_len, "(%s) %s",
623                   psz_date, p_msg->psz_msg );
624
625         break;
626         
627     case INTF_MSG_DBG:                                     /* debug messages */
628         mstrtime( psz_date, p_msg->date );
629         snprintf( psz_msg, i_msg_len, "(%s) " INTF_MSG_DBG_FORMAT "%s",
630                   psz_date, p_msg->psz_file, p_msg->psz_function, p_msg->i_line,
631                   p_msg->psz_msg );
632         break;
633     }
634
635     /*
636      * Print messages
637      */
638     switch( p_msg->i_type )
639     {
640     case INTF_MSG_STD:                                  /* standard messages */
641     case INTF_MSG_STAT:
642         fprintf( stdout, "%s\n", psz_msg );
643         break;
644     case INTF_MSG_ERR:                                     /* error messages */
645     case INTF_MSG_WARN:
646 #ifndef TRACE_LOG_ONLY
647     case INTF_MSG_DBG:                                 /* debugging messages */
648 #endif
649         fprintf( stderr, "%s\n", psz_msg );
650         break;
651     }
652
653 #ifdef TRACE_LOG
654     /* Append all messages to log file */
655     if( p_main->p_msg->p_log_file != NULL )
656     {
657         fwrite( psz_msg, strlen( psz_msg ), 1, p_main->p_msg->p_log_file );
658         fwrite( "\n", 1, 1, p_main->p_msg->p_log_file );
659     }
660 #endif
661
662     /* Free the message */
663     free( psz_msg );
664 }
665
666 #else
667
668 static void PrintMsg( intf_msg_item_t *p_msg )
669 {
670     /*
671      * Print messages on screen
672      */
673     switch( p_msg->i_type )
674     {
675     case INTF_MSG_STD:                                  /* standard messages */
676     case INTF_MSG_STAT:
677     case INTF_MSG_DBG:                                     /* debug messages */
678         fprintf( stdout, "%s\n", p_msg->psz_msg );
679         break;
680     case INTF_MSG_ERR:                                     /* error messages */
681     case INTF_MSG_WARN:
682         fprintf( stderr, "%s\n", p_msg->psz_msg );        /* warning message */
683         break;
684     }
685 }
686
687 #endif
688
689
690 #if defined( WIN32 )
691 /*****************************************************************************
692  * ConvertPrintfFormatString: replace all occurrences of %ll with %I64 in the
693  *                            printf format string.
694  *****************************************************************************
695  * Win32 doesn't recognize the "%lld" format in a printf string, so we have
696  * to convert this string to something that win32 can handle.
697  * This is a REALLY UGLY HACK which won't even work in every situation,
698  * but hey I don't want to put an ifdef WIN32 each time I use printf with
699  * a "long long" type!!!
700  * By the way, if we don't do this we can sometimes end up with segfaults.
701  *****************************************************************************/
702 static char *ConvertPrintfFormatString( char *psz_format )
703 {
704   int i, i_counter=0, i_pos=0;
705   char *psz_dest;
706
707   /* We first need to check how many occurences of %ll there are in the
708    * psz_format string. Once we'll know that we'll be able to malloc the
709    * destination string */
710
711   for( i=0; i <= (strlen(psz_format) - 4); i++ )
712   {
713       if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
714           i_counter++;
715   }
716
717   /* malloc the destination string */
718   psz_dest = malloc( strlen(psz_format) + i_counter + 1 );
719   if( psz_dest == NULL )
720   {
721       fprintf(stderr, "warning: malloc failed in ConvertPrintfFormatString\n");
722       exit (errno);
723   }
724
725   /* Now build the modified string */
726   i_counter = 0;
727   for( i=0; i <= (strlen(psz_format) - 4); i++ )
728   {
729       if( !strncmp( (char *)(psz_format + i), "%ll", 3 ) )
730       {
731           memcpy( psz_dest+i_pos+i_counter, psz_format+i_pos, i-i_pos+1);
732           *(psz_dest+i+i_counter+1)='I';
733           *(psz_dest+i+i_counter+2)='6';
734           *(psz_dest+i+i_counter+3)='4';
735           i_pos = i+3;
736           i_counter++;
737       }
738   }
739   strcpy( psz_dest+i_pos+i_counter, psz_format+i_pos );
740
741   return psz_dest;
742 }
743 #endif