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