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
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 /*****************************************************************************
29 *****************************************************************************/
36 #include <stdarg.h> /* va_list for BSD */
40 #include <vlc_common.h>
41 #include <vlc_interface.h>
42 #include <vlc_charset.h>
43 #include <vlc_modules.h>
44 #include "../libvlc.h"
55 static void vlc_vaLogCallback(libvlc_int_t
*vlc
, int type
,
56 const vlc_log_t
*item
, const char *format
,
59 vlc_logger_t
*logger
= libvlc_priv(vlc
)->logger
;
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
, ...)
76 vlc_vaLogCallback(vlc
, type
, item
, format
, ap
);
81 static void Win32DebugOutputMsg (void *, int , const vlc_log_t
*,
82 const char *, va_list);
86 * Emit a log message. This function is the variable argument list equivalent
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
)
96 /* Get basename from the module filename */
97 char *p
= strrchr(module
, '/');
100 p
= strchr(module
, '.');
102 size_t modlen
= (p
!= NULL
) ? (p
- module
) : 0;
103 char modulebuf
[modlen
+ 1];
106 memcpy(modulebuf
, module
, modlen
);
107 modulebuf
[modlen
] = '\0';
111 /* Fill message information fields */
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
;
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
;
134 Win32DebugOutputMsg (NULL
, type
, &msg
, format
, ap
);
138 /* Pass message to the callback */
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 MODULE_STRING)
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
, ... )
160 va_start(ap
, format
);
161 vlc_vaLog(obj
, type
, module
, file
, line
, func
, format
, ap
);
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
)
173 const signed char *pverbose
= d
;
174 if (pverbose
&& (*pverbose
< 0 || *pverbose
< (type
- VLC_MSG_ERR
)))
179 int msg_len
= vsnprintf(NULL
, 0, format
, dol2
);
185 char *msg
= malloc(msg_len
+ 1 + 1);
189 msg_len
= vsnprintf(msg
, msg_len
+1, format
, dol
);
191 if (msg
[msg_len
-1] != '\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
);
208 typedef struct vlc_log_early_t
210 struct vlc_log_early_t
*next
;
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
))
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)
246 vlc_mutex_lock(&sys
->lock
);
247 assert(sys
->tailp
!= NULL
);
248 assert(*(sys
->tailp
) == NULL
);
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
))
261 vlc_mutex_init(&sys
->lock
);
263 sys
->tailp
= &sys
->head
;
265 logger
->log
= vlc_vaLogEarly
;
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");
285 vlc_mutex_destroy(&sys
->lock
);
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 *);
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
))
332 vlc_rwlock_init(&logger
->lock
);
334 if (vlc_LogEarlyOpen(logger
))
336 logger
->log
= vlc_vaLogDiscard
;
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
);
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
))
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
);
367 cb
= vlc_vaLogDiscard
;
369 vlc_rwlock_wrlock(&logger
->lock
);
370 if (logger
->log
== vlc_vaLogEarly
)
371 early_sys
= logger
->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
);
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
))
401 cb
= vlc_vaLogDiscard
;
403 vlc_rwlock_wrlock(&logger
->lock
);
405 module
= logger
->module
;
408 logger
->sys
= opaque
;
409 logger
->module
= NULL
;
410 vlc_rwlock_unlock(&logger
->lock
);
413 vlc_module_unload(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
))
429 if (logger
->module
!= NULL
)
430 vlc_module_unload(logger
->module
, vlc_logger_unload
, logger
->sys
);
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
;