asx: remove useless test
[vlc.git] / src / misc / messages.c
blob8dda0641f5f7164d717b8f64ada4770df8621c7a
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$
9 * Authors: Vincent Seguin <seguin@via.ecp.fr>
10 * Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
27 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
35 #include <stdlib.h>
36 #include <stdarg.h> /* va_list for BSD */
37 #include <unistd.h>
38 #include <assert.h>
40 #include <vlc_common.h>
41 #include <vlc_interface.h>
42 #include <vlc_charset.h>
43 #include <vlc_modules.h>
44 #include "../libvlc.h"
46 struct vlc_logger_t
48 struct vlc_common_members obj;
49 vlc_rwlock_t lock;
50 vlc_log_cb log;
51 void *sys;
52 module_t *module;
55 static void vlc_vaLogCallback(libvlc_int_t *vlc, int type,
56 const vlc_log_t *item, const char *format,
57 va_list ap)
59 vlc_logger_t *logger = libvlc_priv(vlc)->logger;
60 int canc;
62 assert(logger != NULL);
63 canc = vlc_savecancel();
64 vlc_rwlock_rdlock(&logger->lock);
65 logger->log(logger->sys, type, item, format, ap);
66 vlc_rwlock_unlock(&logger->lock);
67 vlc_restorecancel(canc);
70 static void vlc_LogCallback(libvlc_int_t *vlc, int type, const vlc_log_t *item,
71 const char *format, ...)
73 va_list ap;
75 va_start(ap, format);
76 vlc_vaLogCallback(vlc, type, item, format, ap);
77 va_end(ap);
80 #ifdef _WIN32
81 static void Win32DebugOutputMsg (void *, int , const vlc_log_t *,
82 const char *, va_list);
83 #endif
85 /**
86 * Emit a log message. This function is the variable argument list equivalent
87 * to vlc_Log().
89 void vlc_vaLog (vlc_object_t *obj, int type, const char *module,
90 const char *file, unsigned line, const char *func,
91 const char *format, va_list args)
93 if (obj != NULL && obj->obj.flags & OBJECT_FLAGS_QUIET)
94 return;
96 /* Get basename from the module filename */
97 char *p = strrchr(module, '/');
98 if (p != NULL)
99 module = p + 1;
100 p = strchr(module, '.');
102 size_t modlen = (p != NULL) ? (p - module) : 0;
103 char modulebuf[modlen + 1];
104 if (p != NULL)
106 memcpy(modulebuf, module, modlen);
107 modulebuf[modlen] = '\0';
108 module = modulebuf;
111 /* Fill message information fields */
112 vlc_log_t msg;
114 msg.i_object_id = (uintptr_t)obj;
115 msg.psz_object_type = (obj != NULL) ? obj->obj.object_type : "generic";
116 msg.psz_module = module;
117 msg.psz_header = NULL;
118 msg.file = file;
119 msg.line = line;
120 msg.func = func;
121 msg.tid = vlc_thread_id();
123 for (vlc_object_t *o = obj; o != NULL; o = o->obj.parent)
124 if (o->obj.header != NULL)
126 msg.psz_header = o->obj.header;
127 break;
130 #ifdef _WIN32
131 va_list ap;
133 va_copy (ap, args);
134 Win32DebugOutputMsg (NULL, type, &msg, format, ap);
135 va_end (ap);
136 #endif
138 /* Pass message to the callback */
139 if (obj != NULL)
140 vlc_vaLogCallback(obj->obj.libvlc, type, &msg, format, args);
144 * Emit a log message.
145 * \param obj VLC object emitting the message or NULL
146 * \param type VLC_MSG_* message type (info, error, warning or debug)
147 * \param module name of module from which the message come
148 * (normally vlc_module_name)
149 * \param file source module file name (normally __FILE__) or NULL
150 * \param line function call source line number (normally __LINE__) or 0
151 * \param func calling function name (normally __func__) or NULL
152 * \param format printf-like message format
154 void vlc_Log(vlc_object_t *obj, int type, const char *module,
155 const char *file, unsigned line, const char *func,
156 const char *format, ... )
158 va_list ap;
160 va_start(ap, format);
161 vlc_vaLog(obj, type, module, file, line, func, format, ap);
162 va_end(ap);
165 #ifdef _WIN32
166 static const char msg_type[4][9] = { "", " error", " warning", " debug" };
168 static void Win32DebugOutputMsg (void* d, int type, const vlc_log_t *p_item,
169 const char *format, va_list dol)
171 VLC_UNUSED(p_item);
173 const signed char *pverbose = d;
174 if (pverbose && (*pverbose < 0 || *pverbose < (type - VLC_MSG_ERR)))
175 return;
177 va_list dol2;
178 va_copy (dol2, dol);
179 int msg_len = vsnprintf(NULL, 0, format, dol2);
180 va_end (dol2);
182 if (msg_len <= 0)
183 return;
185 char *msg = malloc(msg_len + 1 + 1);
186 if (!msg)
187 return;
189 msg_len = vsnprintf(msg, msg_len+1, format, dol);
190 if (msg_len > 0){
191 if (msg[msg_len-1] != '\n') {
192 msg[msg_len] = '\n';
193 msg[msg_len + 1] = '\0';
195 char* psz_msg = NULL;
196 if (asprintf(&psz_msg, "%s %s%s: %s", p_item->psz_module,
197 p_item->psz_object_type, msg_type[type], msg) > 0) {
198 wchar_t* wmsg = ToWide(psz_msg);
199 OutputDebugStringW(wmsg);
200 free(wmsg);
201 free(psz_msg);
204 free(msg);
206 #endif
208 typedef struct vlc_log_early_t
210 struct vlc_log_early_t *next;
211 int type;
212 vlc_log_t meta;
213 char *msg;
214 } vlc_log_early_t;
216 typedef struct
218 vlc_mutex_t lock;
219 vlc_log_early_t *head;
220 vlc_log_early_t **tailp;
221 } vlc_logger_early_t;
223 static void vlc_vaLogEarly(void *d, int type, const vlc_log_t *item,
224 const char *format, va_list ap)
226 vlc_logger_early_t *sys = d;
228 vlc_log_early_t *log = malloc(sizeof (*log));
229 if (unlikely(log == NULL))
230 return;
232 log->next = NULL;
233 log->type = type;
234 log->meta.i_object_id = item->i_object_id;
235 /* NOTE: Object types MUST be static constant - no need to copy them. */
236 log->meta.psz_object_type = item->psz_object_type;
237 log->meta.psz_module = item->psz_module; /* Ditto. */
238 log->meta.psz_header = item->psz_header ? strdup(item->psz_header) : NULL;
239 log->meta.file = item->file;
240 log->meta.line = item->line;
241 log->meta.func = item->func;
243 if (vasprintf(&log->msg, format, ap) == -1)
244 log->msg = NULL;
246 vlc_mutex_lock(&sys->lock);
247 assert(sys->tailp != NULL);
248 assert(*(sys->tailp) == NULL);
249 *(sys->tailp) = log;
250 sys->tailp = &log->next;
251 vlc_mutex_unlock(&sys->lock);
254 static int vlc_LogEarlyOpen(vlc_logger_t *logger)
256 vlc_logger_early_t *sys = malloc(sizeof (*sys));
258 if (unlikely(sys == NULL))
259 return -1;
261 vlc_mutex_init(&sys->lock);
262 sys->head = NULL;
263 sys->tailp = &sys->head;
265 logger->log = vlc_vaLogEarly;
266 logger->sys = sys;
267 return 0;
270 static void vlc_LogEarlyClose(vlc_logger_t *logger, void *d)
272 libvlc_int_t *vlc = logger->obj.libvlc;
273 vlc_logger_early_t *sys = d;
275 /* Drain early log messages */
276 for (vlc_log_early_t *log = sys->head, *next; log != NULL; log = next)
278 vlc_LogCallback(vlc, log->type, &log->meta, "%s",
279 (log->msg != NULL) ? log->msg : "message lost");
280 free(log->msg);
281 next = log->next;
282 free(log);
285 vlc_mutex_destroy(&sys->lock);
286 free(sys);
289 static void vlc_vaLogDiscard(void *d, int type, const vlc_log_t *item,
290 const char *format, va_list ap)
292 (void) d; (void) type; (void) item; (void) format; (void) ap;
295 static int vlc_logger_load(void *func, va_list ap)
297 vlc_log_cb (*activate)(vlc_object_t *, void **) = func;
298 vlc_logger_t *logger = va_arg(ap, vlc_logger_t *);
299 vlc_log_cb *cb = va_arg(ap, vlc_log_cb *);
300 void **sys = va_arg(ap, void **);
302 *cb = activate(VLC_OBJECT(logger), sys);
303 return (*cb != NULL) ? VLC_SUCCESS : VLC_EGENERIC;
306 static void vlc_logger_unload(void *func, va_list ap)
308 void (*deactivate)(vlc_logger_t *) = func;
309 void *sys = va_arg(ap, void *);
311 deactivate(sys);
315 * Performs preinitialization of the messages logging subsystem.
317 * Early log messages will be stored in memory until the subsystem is fully
318 * initialized with vlc_LogInit(). This enables logging before the
319 * configuration and modules bank are ready.
321 * \return 0 on success, -1 on error.
323 int vlc_LogPreinit(libvlc_int_t *vlc)
325 vlc_logger_t *logger = vlc_custom_create(vlc, sizeof (*logger), "logger");
327 libvlc_priv(vlc)->logger = logger;
329 if (unlikely(logger == NULL))
330 return -1;
332 vlc_rwlock_init(&logger->lock);
334 if (vlc_LogEarlyOpen(logger))
336 logger->log = vlc_vaLogDiscard;
337 return -1;
340 /* Announce who we are */
341 msg_Dbg(vlc, "VLC media player - %s", VERSION_MESSAGE);
342 msg_Dbg(vlc, "%s", COPYRIGHT_MESSAGE);
343 msg_Dbg(vlc, "revision %s", psz_vlc_changeset);
344 msg_Dbg(vlc, "configured with %s", CONFIGURE_LINE);
345 return 0;
349 * Initializes the messages logging subsystem and drain the early messages to
350 * the configured log.
352 * \return 0 on success, -1 on error.
354 int vlc_LogInit(libvlc_int_t *vlc)
356 vlc_logger_t *logger = libvlc_priv(vlc)->logger;
357 if (unlikely(logger == NULL))
358 return -1;
360 vlc_log_cb cb;
361 void *sys, *early_sys = NULL;
363 /* TODO: module configuration item */
364 module_t *module = vlc_module_load(logger, "logger", NULL, false,
365 vlc_logger_load, logger, &cb, &sys);
366 if (module == NULL)
367 cb = vlc_vaLogDiscard;
369 vlc_rwlock_wrlock(&logger->lock);
370 if (logger->log == vlc_vaLogEarly)
371 early_sys = logger->sys;
373 logger->log = cb;
374 logger->sys = sys;
375 assert(logger->module == NULL); /* Only one call to vlc_LogInit()! */
376 logger->module = module;
377 vlc_rwlock_unlock(&logger->lock);
379 if (early_sys != NULL)
380 vlc_LogEarlyClose(logger, early_sys);
382 return 0;
386 * Sets the message logging callback.
387 * \param cb message callback, or NULL to clear
388 * \param data data pointer for the message callback
390 void vlc_LogSet(libvlc_int_t *vlc, vlc_log_cb cb, void *opaque)
392 vlc_logger_t *logger = libvlc_priv(vlc)->logger;
394 if (unlikely(logger == NULL))
395 return;
397 module_t *module;
398 void *sys;
400 if (cb == NULL)
401 cb = vlc_vaLogDiscard;
403 vlc_rwlock_wrlock(&logger->lock);
404 sys = logger->sys;
405 module = logger->module;
407 logger->log = cb;
408 logger->sys = opaque;
409 logger->module = NULL;
410 vlc_rwlock_unlock(&logger->lock);
412 if (module != NULL)
413 vlc_module_unload(vlc, module, vlc_logger_unload, sys);
415 /* Announce who we are */
416 msg_Dbg (vlc, "VLC media player - %s", VERSION_MESSAGE);
417 msg_Dbg (vlc, "%s", COPYRIGHT_MESSAGE);
418 msg_Dbg (vlc, "revision %s", psz_vlc_changeset);
419 msg_Dbg (vlc, "configured with %s", CONFIGURE_LINE);
422 void vlc_LogDeinit(libvlc_int_t *vlc)
424 vlc_logger_t *logger = libvlc_priv(vlc)->logger;
426 if (unlikely(logger == NULL))
427 return;
429 if (logger->module != NULL)
430 vlc_module_unload(vlc, logger->module, vlc_logger_unload, logger->sys);
431 else
432 /* Flush early log messages (corner case: no call to vlc_LogInit()) */
433 if (logger->log == vlc_vaLogEarly)
435 logger->log = vlc_vaLogDiscard;
436 vlc_LogEarlyClose(logger, logger->sys);
439 vlc_rwlock_destroy(&logger->lock);
440 vlc_object_release(logger);
441 libvlc_priv(vlc)->logger = NULL;