]> git.sesse.net Git - vlc/blob - src/misc/messages.c
core: gather message initialization code
[vlc] / src / misc / messages.c
1 /*****************************************************************************
2  * messages.c: messages interface
3  * This library provides an interface to the message queue to be used by other
4  * modules, especially intf modules. See vlc_config.h for output configuration.
5  *****************************************************************************
6  * Copyright (C) 1998-2005 VLC authors and VideoLAN
7  * $Id$
8  *
9  * Authors: Vincent Seguin <seguin@via.ecp.fr>
10  *          Samuel Hocevar <sam@zoy.org>
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU Lesser General Public License as published by
14  * the Free Software Foundation; either version 2.1 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * along with this program; if not, write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <stdlib.h>
36 #include <stdarg.h>                                       /* va_list for BSD */
37 #ifdef __APPLE__
38 # include <xlocale.h>
39 #elif defined(HAVE_LOCALE_H)
40 # include <locale.h>
41 #endif
42 #include <errno.h>                                                  /* errno */
43 #include <assert.h>
44 #include <unistd.h>
45
46 #include <vlc_common.h>
47 #include <vlc_interface.h>
48 #ifdef WIN32
49 #   include <vlc_network.h>          /* 'net_strerror' and 'WSAGetLastError' */
50 #endif
51 #include <vlc_charset.h>
52 #include "../libvlc.h"
53
54 /**
55  * Emit a log message.
56  * \param obj VLC object emitting the message or NULL
57  * \param type VLC_MSG_* message type (info, error, warning or debug)
58  * \param module name of module from which the message come
59  *               (normally MODULE_STRING)
60  * \param format printf-like message format
61  */
62 void vlc_Log (vlc_object_t *obj, int type, const char *module,
63               const char *format, ... )
64 {
65     va_list args;
66
67     va_start (args, format);
68     vlc_vaLog (obj, type, module, format, args);
69     va_end (args);
70 }
71
72 #ifdef WIN32
73 static void Win32DebugOutputMsg (void *, int , const vlc_log_t *,
74                                  const char *, va_list);
75 #endif
76
77 /**
78  * Emit a log message. This function is the variable argument list equivalent
79  * to vlc_Log().
80  */
81 void vlc_vaLog (vlc_object_t *obj, int type, const char *module,
82                 const char *format, va_list args)
83 {
84     if (obj != NULL && obj->i_flags & OBJECT_FLAGS_QUIET)
85         return;
86
87     /* C locale to get error messages in English in the logs */
88     locale_t c = newlocale (LC_MESSAGES_MASK, "C", (locale_t)0);
89     locale_t locale = uselocale (c);
90
91 #ifndef __GLIBC__
92     /* Expand %m to strerror(errno) - only once */
93     char buf[strlen(format) + 2001], *ptr;
94     strcpy (buf, format);
95     ptr = (char*)buf;
96     format = (const char*) buf;
97
98     for( ;; )
99     {
100         ptr = strchr( ptr, '%' );
101         if( ptr == NULL )
102             break;
103
104         if( ptr[1] == 'm' )
105         {
106             char errbuf[2001];
107             size_t errlen;
108
109 #ifndef WIN32
110             strerror_r( errno, errbuf, 1001 );
111 #else
112             int sockerr = WSAGetLastError( );
113             if( sockerr )
114             {
115                 strncpy( errbuf, net_strerror( sockerr ), 1001 );
116                 WSASetLastError( sockerr );
117             }
118             if ((sockerr == 0)
119              || (strcmp ("Unknown network stack error", errbuf) == 0))
120                 strncpy( errbuf, strerror( errno ), 1001 );
121 #endif
122             errbuf[1000] = 0;
123
124             /* Escape '%' from the error string */
125             for( char *percent = strchr( errbuf, '%' );
126                  percent != NULL;
127                  percent = strchr( percent + 2, '%' ) )
128             {
129                 memmove( percent + 1, percent, strlen( percent ) + 1 );
130             }
131
132             errlen = strlen( errbuf );
133             memmove( ptr + errlen, ptr + 2, strlen( ptr + 2 ) + 1 );
134             memcpy( ptr, errbuf, errlen );
135             break; /* Only once, so we don't overflow */
136         }
137
138         /* Looks for conversion specifier... */
139         do
140             ptr++;
141         while( *ptr && ( strchr( "diouxXeEfFgGaAcspn%", *ptr ) == NULL ) );
142         if( *ptr )
143             ptr++; /* ...and skip it */
144     }
145 #endif
146
147     /* Fill message information fields */
148     vlc_log_t msg;
149
150     msg.i_object_id = (uintptr_t)obj;
151     msg.psz_object_type = (obj != NULL) ? obj->psz_object_type : "generic";
152     msg.psz_module = module;
153     msg.psz_header = NULL;
154
155     for (vlc_object_t *o = obj; o != NULL; o = o->p_parent)
156         if (o->psz_header != NULL)
157         {
158             msg.psz_header = o->psz_header;
159             break;
160         }
161
162     /* Pass message to the callback */
163     libvlc_priv_t *priv = libvlc_priv (obj->p_libvlc);
164
165 #ifdef WIN32
166     va_list ap;
167
168     va_copy (ap, args);
169     Win32DebugOutputMsg (&priv->log.verbose, type, &msg, format, ap);
170     va_end (ap);
171 #endif
172
173     vlc_rwlock_rdlock (&priv->log.lock);
174     priv->log.cb (priv->log.opaque, type, &msg, format, args);
175     vlc_rwlock_unlock (&priv->log.lock);
176
177     uselocale (locale);
178     freelocale (c);
179 }
180
181 static const char msg_type[4][9] = { "", " error", " warning", " debug" };
182 #define COL(x,y)  "\033[" #x ";" #y "m"
183 #define RED     COL(31,1)
184 #define GREEN   COL(32,1)
185 #define YELLOW  COL(0,33)
186 #define WHITE   COL(0,1)
187 #define GRAY    "\033[0m"
188 static const char msg_color[4][8] = { WHITE, RED, YELLOW, GRAY };
189
190 static void PrintColorMsg (void *d, int type, const vlc_log_t *p_item,
191                            const char *format, va_list ap)
192 {
193     FILE *stream = stderr;
194     int verbose = (intptr_t)d;
195
196     if (verbose < 0 || verbose < (type - VLC_MSG_ERR))
197         return;
198
199     int canc = vlc_savecancel ();
200
201     flockfile (stream);
202     fprintf (stream, "["GREEN"%p"GRAY"] ", (void *)p_item->i_object_id);
203     if (p_item->psz_header != NULL)
204         utf8_fprintf (stream, "[%s] ", p_item->psz_header);
205     utf8_fprintf (stream, "%s %s%s: %s", p_item->psz_module,
206                   p_item->psz_object_type, msg_type[type], msg_color[type]);
207     utf8_vfprintf (stream, format, ap);
208     fputs (GRAY"\n", stream);
209 #if defined (WIN32) || defined (__OS2__)
210     fflush (stream);
211 #endif
212     funlockfile (stream);
213     vlc_restorecancel (canc);
214 }
215
216 static void PrintMsg (void *d, int type, const vlc_log_t *p_item,
217                       const char *format, va_list ap)
218 {
219     FILE *stream = stderr;
220     int verbose = (intptr_t)d;
221
222     if (verbose < 0 || verbose < (type - VLC_MSG_ERR))
223         return;
224
225     int canc = vlc_savecancel ();
226
227     flockfile (stream);
228     fprintf (stream, "[%p] ", (void *)p_item->i_object_id);
229     if (p_item->psz_header != NULL)
230         utf8_fprintf (stream, "[%s] ", p_item->psz_header);
231     utf8_fprintf (stream, "%s %s%s: ", p_item->psz_module,
232                   p_item->psz_object_type, msg_type[type]);
233     utf8_vfprintf (stream, format, ap);
234     putc_unlocked ('\n', stream);
235 #if defined (WIN32) || defined (__OS2__)
236     fflush (stream);
237 #endif
238     funlockfile (stream);
239     vlc_restorecancel (canc);
240 }
241
242 #ifdef WIN32
243 static void Win32DebugOutputMsg (void* d, int type, const vlc_log_t *p_item,
244                                  const char *format, va_list dol)
245 {
246     VLC_UNUSED(p_item);
247
248     const signed char *pverbose = d;
249     if (pverbose && (*pverbose < 0 || *pverbose < (type - VLC_MSG_ERR)))
250         return;
251
252     va_list dol2;
253     va_copy (dol2, dol);
254     int msg_len = vsnprintf(NULL, 0, format, dol2);
255     va_end (dol2);
256
257     if(msg_len <= 0)
258         return;
259
260     char *msg = malloc(msg_len + 1 + 1);
261     if (!msg)
262         return;
263
264     msg_len = vsnprintf(msg, msg_len+1, format, dol);
265     if (msg_len > 0){
266         if(msg[msg_len-1] != '\n'){
267             msg[msg_len] = '\n';
268             msg[msg_len + 1] = '\0';
269         }
270         char* psz_msg = NULL;
271         if(asprintf(&psz_msg, "%s %s%s: %s", p_item->psz_module,
272                     p_item->psz_object_type, msg_type[type], msg) > 0) {
273             wchar_t* wmsg = ToWide(psz_msg);
274             OutputDebugStringW(wmsg);
275             free(wmsg);
276             free(psz_msg);
277         }
278     }
279     free(msg);
280 }
281 #endif
282
283 /**
284  * Sets the message logging callback.
285  * \param cb message callback, or NULL to reset
286  * \param data data pointer for the message callback
287  */
288 void vlc_LogSet (libvlc_int_t *vlc, vlc_log_cb cb, void *opaque)
289 {
290     libvlc_priv_t *priv = libvlc_priv (vlc);
291
292     if (cb == NULL)
293     {
294 #if defined (HAVE_ISATTY) && !defined (WIN32)
295         if (isatty (STDERR_FILENO) && var_InheritBool (vlc, "color"))
296             cb = PrintColorMsg;
297         else
298 #endif
299             cb = PrintMsg;
300         opaque = (void *)(intptr_t)priv->log.verbose;
301     }
302
303     vlc_rwlock_wrlock (&priv->log.lock);
304     priv->log.cb = cb;
305     priv->log.opaque = opaque;
306     vlc_rwlock_unlock (&priv->log.lock);
307
308     /* Announce who we are */
309     msg_Dbg (vlc, "VLC media player - %s", VERSION_MESSAGE);
310     msg_Dbg (vlc, "%s", COPYRIGHT_MESSAGE);
311     msg_Dbg (vlc, "revision %s", psz_vlc_changeset);
312     msg_Dbg (vlc, "configured with %s", CONFIGURE_LINE);
313 }
314
315 void vlc_LogInit (libvlc_int_t *vlc)
316 {
317     libvlc_priv_t *priv = libvlc_priv (vlc);
318     const char *str;
319
320     if (var_InheritBool (vlc, "quiet"))
321         priv->log.verbose = -1;
322     else
323     if ((str = getenv ("VLC_VERBOSE")) != NULL)
324         priv->log.verbose = atoi (str);
325     else
326         priv->log.verbose = var_InheritInteger (vlc, "verbose");
327
328     vlc_rwlock_init (&priv->log.lock);
329     vlc_LogSet (vlc, NULL, NULL);
330 }
331
332 void vlc_LogDeinit (libvlc_int_t *vlc)
333 {
334     libvlc_priv_t *priv = libvlc_priv (vlc);
335
336     vlc_rwlock_destroy (&priv->log.lock);
337 }