contrib: Bump libmicrodns to 0.1.2
[vlc.git] / src / misc / messages.c
blob898e4be56f835c6f461e2261bfcf7f2a6950bc39
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
8 * Authors: Vincent Seguin <seguin@via.ecp.fr>
9 * Samuel Hocevar <sam@zoy.org>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
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 Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
27 * Preamble
28 *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
34 #include <stdlib.h>
35 #include <stdarg.h> /* va_list for BSD */
36 #include <unistd.h>
37 #include <assert.h>
39 #include <vlc_common.h>
40 #include <vlc_interface.h>
41 #include <vlc_charset.h>
42 #include <vlc_modules.h>
43 #include "../libvlc.h"
45 static void vlc_LogSpam(vlc_object_t *obj)
47 /* Announce who we are */
48 msg_Dbg(obj, "VLC media player - %s", VERSION_MESSAGE);
49 msg_Dbg(obj, "%s", COPYRIGHT_MESSAGE);
50 msg_Dbg(obj, "revision %s", psz_vlc_changeset);
51 msg_Dbg(obj, "configured with %s", CONFIGURE_LINE);
54 struct vlc_logger {
55 const struct vlc_logger_operations *ops;
58 static void vlc_vaLogCallback(vlc_logger_t *logger, int type,
59 const vlc_log_t *item, const char *format,
60 va_list ap)
62 if (logger != NULL) {
63 int canc = vlc_savecancel();
65 logger->ops->log(logger, type, item, format, ap);
66 vlc_restorecancel(canc);
70 static void vlc_LogCallback(vlc_logger_t *logger, int type,
71 const vlc_log_t *item, const char *format, ...)
73 va_list ap;
75 va_start(ap, format);
76 vlc_vaLogCallback(logger, 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 void vlc_vaLog(struct vlc_logger *const *loggerp, int type,
86 const char *typename, const char *module,
87 const char *file, unsigned line, const char *func,
88 const char *format, va_list args)
90 struct vlc_logger *logger = *loggerp;
91 /* Get basename from the module filename */
92 char *p = strrchr(module, '/');
93 if (p != NULL)
94 module = p + 1;
95 p = strchr(module, '.');
97 size_t modlen = (p != NULL) ? (p - module) : 0;
98 char modulebuf[modlen + 1];
99 if (p != NULL)
101 memcpy(modulebuf, module, modlen);
102 modulebuf[modlen] = '\0';
103 module = modulebuf;
106 /* Fill message information fields */
107 vlc_log_t msg;
109 msg.i_object_id = (uintptr_t)(void *)loggerp;
110 msg.psz_object_type = typename;
111 msg.psz_module = module;
112 msg.psz_header = NULL;
113 msg.file = file;
114 msg.line = line;
115 msg.func = func;
116 msg.tid = vlc_thread_id();
118 #ifdef _WIN32
119 va_list ap;
121 va_copy (ap, args);
122 Win32DebugOutputMsg (NULL, type, &msg, format, ap);
123 va_end (ap);
124 #endif
126 /* Pass message to the callback */
127 if (logger != NULL)
128 vlc_vaLogCallback(logger, type, &msg, format, args);
131 void vlc_Log(struct vlc_logger *const *logger, int type,
132 const char *typename, const char *module,
133 const char *file, unsigned line, const char *func,
134 const char *format, ... )
136 va_list ap;
138 va_start(ap, format);
139 vlc_vaLog(logger, type, typename, module, file, line, func, format, ap);
140 va_end(ap);
143 #ifdef _WIN32
144 static const char msg_type[4][9] = { "", " error", " warning", " debug" };
146 static void Win32DebugOutputMsg (void* d, int type, const vlc_log_t *p_item,
147 const char *format, va_list dol)
149 VLC_UNUSED(p_item);
151 const signed char *pverbose = d;
152 if (pverbose && (*pverbose < 0 || *pverbose < (type - VLC_MSG_ERR)))
153 return;
155 va_list dol2;
156 va_copy (dol2, dol);
157 int msg_len = vsnprintf(NULL, 0, format, dol2);
158 va_end (dol2);
160 if (msg_len <= 0)
161 return;
163 char *msg = malloc(msg_len + 1 + 1);
164 if (!msg)
165 return;
167 msg_len = vsnprintf(msg, msg_len+1, format, dol);
168 if (msg_len > 0){
169 if (msg[msg_len-1] != '\n') {
170 msg[msg_len] = '\n';
171 msg[msg_len + 1] = '\0';
173 char* psz_msg = NULL;
174 if (asprintf(&psz_msg, "%s %s%s: %s", p_item->psz_module,
175 p_item->psz_object_type, msg_type[type], msg) > 0) {
176 wchar_t* wmsg = ToWide(psz_msg);
177 if (likely(wmsg != NULL))
179 OutputDebugStringW(wmsg);
180 free(wmsg);
182 free(psz_msg);
185 free(msg);
187 #endif
190 * Early (latched) message log.
192 * A message log that stores messages in memory until another log is available.
194 typedef struct vlc_log_early_t
196 struct vlc_log_early_t *next;
197 int type;
198 vlc_log_t meta;
199 char *msg;
200 } vlc_log_early_t;
202 typedef struct vlc_logger_early {
203 vlc_mutex_t lock;
204 vlc_log_early_t *head;
205 vlc_log_early_t **tailp;
206 vlc_logger_t *sink;
207 struct vlc_logger logger;
208 } vlc_logger_early_t;
210 static void vlc_vaLogEarly(void *d, int type, const vlc_log_t *item,
211 const char *format, va_list ap)
213 struct vlc_logger *logger = d;
214 struct vlc_logger_early *early =
215 container_of(logger, struct vlc_logger_early, logger);
217 vlc_log_early_t *log = malloc(sizeof (*log));
218 if (unlikely(log == NULL))
219 return;
221 log->next = NULL;
222 log->type = type;
223 log->meta.i_object_id = item->i_object_id;
224 /* NOTE: Object types MUST be static constant - no need to copy them. */
225 log->meta.psz_object_type = item->psz_object_type;
226 log->meta.psz_module = item->psz_module; /* Ditto. */
227 log->meta.psz_header = item->psz_header ? strdup(item->psz_header) : NULL;
228 log->meta.file = item->file;
229 log->meta.line = item->line;
230 log->meta.func = item->func;
232 if (vasprintf(&log->msg, format, ap) == -1)
233 log->msg = NULL;
235 vlc_mutex_lock(&early->lock);
236 assert(early->tailp != NULL);
237 assert(*(early->tailp) == NULL);
238 *(early->tailp) = log;
239 early->tailp = &log->next;
240 vlc_mutex_unlock(&early->lock);
243 static void vlc_LogEarlyClose(void *d)
245 struct vlc_logger *logger = d;
246 struct vlc_logger_early *early =
247 container_of(logger, struct vlc_logger_early, logger);
248 vlc_logger_t *sink = early->sink;
250 /* Drain early log messages */
251 for (vlc_log_early_t *log = early->head, *next; log != NULL; log = next)
253 vlc_LogCallback(sink, log->type, &log->meta, "%s",
254 (log->msg != NULL) ? log->msg : "message lost");
255 free(log->msg);
256 next = log->next;
257 free(log);
260 free(early);
263 static const struct vlc_logger_operations early_ops = {
264 vlc_vaLogEarly,
265 vlc_LogEarlyClose,
268 static struct vlc_logger *vlc_LogEarlyOpen(struct vlc_logger *logger)
270 vlc_logger_early_t *early = malloc(sizeof (*early));
271 if (unlikely(early == NULL))
272 return NULL;
274 early->logger.ops = &early_ops;
275 vlc_mutex_init(&early->lock);
276 early->head = NULL;
277 early->tailp = &early->head;
278 early->sink = logger;
279 return &early->logger;
282 static void vlc_vaLogDiscard(void *d, int type, const vlc_log_t *item,
283 const char *format, va_list ap)
285 (void) d; (void) type; (void) item; (void) format; (void) ap;
288 static void vlc_LogDiscardClose(void *d)
290 (void) d;
293 static const struct vlc_logger_operations discard_ops = {
294 vlc_vaLogDiscard,
295 vlc_LogDiscardClose,
298 static struct vlc_logger discard_log = { &discard_ops };
301 * Switchable message log.
303 * A message log that can be redirected live.
305 struct vlc_logger_switch {
306 struct vlc_logger *backend;
307 struct vlc_logger frontend;
308 vlc_rwlock_t lock;
311 static void vlc_vaLogSwitch(void *d, int type, const vlc_log_t *item,
312 const char *format, va_list ap)
314 struct vlc_logger *logger = d;
315 struct vlc_logger_switch *logswitch =
316 container_of(logger, struct vlc_logger_switch, frontend);
317 struct vlc_logger *backend;
319 vlc_rwlock_rdlock(&logswitch->lock);
320 backend = logswitch->backend;
321 backend->ops->log(backend, type, item, format, ap);
322 vlc_rwlock_unlock(&logswitch->lock);
325 static void vlc_LogSwitchClose(void *d)
327 struct vlc_logger *logger = d;
328 struct vlc_logger_switch *logswitch =
329 container_of(logger, struct vlc_logger_switch, frontend);
330 struct vlc_logger *backend = logswitch->backend;
332 logswitch->backend = &discard_log;
333 backend->ops->destroy(backend);
335 vlc_rwlock_destroy(&logswitch->lock);
336 free(logswitch);
339 static const struct vlc_logger_operations switch_ops = {
340 vlc_vaLogSwitch,
341 vlc_LogSwitchClose,
344 static void vlc_LogSwitch(vlc_logger_t *logger, vlc_logger_t *new_logger)
346 struct vlc_logger_switch *logswitch =
347 container_of(logger, struct vlc_logger_switch, frontend);
348 struct vlc_logger *old_logger;
350 assert(logger->ops == &switch_ops);
352 if (new_logger == NULL)
353 new_logger = &discard_log;
355 vlc_rwlock_wrlock(&logswitch->lock);
356 old_logger = logswitch->backend;
357 logswitch->backend = new_logger;
358 vlc_rwlock_unlock(&logswitch->lock);
360 old_logger->ops->destroy(old_logger);
363 static struct vlc_logger *vlc_LogSwitchCreate(void)
365 struct vlc_logger_switch *logswitch = malloc(sizeof (*logswitch));
366 if (unlikely(logswitch == NULL))
367 return NULL;
369 logswitch->frontend.ops = &switch_ops;
370 logswitch->backend = &discard_log;
371 vlc_rwlock_init(&logswitch->lock);
372 return &logswitch->frontend;
376 * Module-based message log.
378 struct vlc_logger_module {
379 struct vlc_object_t obj;
380 struct vlc_logger frontend;
381 const struct vlc_logger_operations *ops;
382 void *opaque;
385 static int vlc_logger_load(void *func, bool forced, va_list ap)
387 const struct vlc_logger_operations *(*activate)(vlc_object_t *,
388 void **) = func;
389 struct vlc_logger_module *module = va_arg(ap, struct vlc_logger_module *);
391 (void) forced;
392 module->ops = activate(VLC_OBJECT(module), &module->opaque);
393 return (module->ops != NULL) ? VLC_SUCCESS : VLC_EGENERIC;
396 static void vlc_vaLogModule(void *d, int type, const vlc_log_t *item,
397 const char *format, va_list ap)
399 struct vlc_logger *logger = d;
400 struct vlc_logger_module *module =
401 container_of(logger, struct vlc_logger_module, frontend);
403 module->ops->log(module->opaque, type, item, format, ap);
406 static void vlc_LogModuleClose(void *d)
408 struct vlc_logger *logger = d;
409 struct vlc_logger_module *module =
410 container_of(logger, struct vlc_logger_module, frontend);
412 if (module->ops->destroy != NULL)
413 module->ops->destroy(module->opaque);
415 vlc_object_delete(VLC_OBJECT(module));
418 static const struct vlc_logger_operations module_ops = {
419 vlc_vaLogModule,
420 vlc_LogModuleClose,
423 static struct vlc_logger *vlc_LogModuleCreate(vlc_object_t *parent)
425 struct vlc_logger_module *module;
427 module = vlc_custom_create(parent, sizeof (*module), "logger");
428 if (unlikely(module == NULL))
429 return NULL;
431 /* TODO: module configuration item */
432 if (vlc_module_load(VLC_OBJECT(module), "logger", NULL, false,
433 vlc_logger_load, module) == NULL) {
434 vlc_object_delete(VLC_OBJECT(module));
435 return NULL;
438 module->frontend.ops = &module_ops;
439 return &module->frontend;
443 * Initializes the messages logging subsystem and drain the early messages to
444 * the configured log.
446 void vlc_LogInit(libvlc_int_t *vlc)
448 struct vlc_logger *logger = vlc_LogModuleCreate(VLC_OBJECT(vlc));
449 if (logger == NULL)
450 logger = &discard_log;
452 vlc_LogSwitch(vlc->obj.logger, logger);
456 * Performs preinitialization of the messages logging subsystem.
458 * Early log messages will be stored in memory until the subsystem is fully
459 * initialized with vlc_LogInit(). This enables logging before the
460 * configuration and modules bank are ready.
462 * \return 0 on success, -1 on error.
464 int vlc_LogPreinit(libvlc_int_t *vlc)
466 vlc_logger_t *logger = vlc_LogSwitchCreate();
467 if (unlikely(logger == NULL))
468 return -1;
469 vlc->obj.logger = logger;
471 struct vlc_logger *early = vlc_LogEarlyOpen(logger);
472 if (early != NULL) {
473 vlc_LogSwitch(logger, early);
474 vlc_LogSpam(VLC_OBJECT(vlc));
476 return 0;
480 * Message log with "header".
482 struct vlc_logger_header {
483 struct vlc_logger logger;
484 struct vlc_logger *parent;
485 char header[];
488 static void vlc_vaLogHeader(void *d, int type, const vlc_log_t *item,
489 const char *format, va_list ap)
491 struct vlc_logger *logger = d;
492 struct vlc_logger_header *header =
493 container_of(logger, struct vlc_logger_header, logger);
494 struct vlc_logger *parent = header->parent;
495 vlc_log_t hitem = *item;
497 hitem.psz_header = header->header;
498 parent->ops->log(parent, type, &hitem, format, ap);
501 static const struct vlc_logger_operations header_ops = {
502 vlc_vaLogHeader,
503 free,
506 struct vlc_logger *vlc_LogHeaderCreate(struct vlc_logger *parent,
507 const char *str)
509 size_t len = strlen(str) + 1;
510 struct vlc_logger_header *header = malloc(sizeof (*header) + len);
511 if (unlikely(header == NULL))
512 return NULL;
514 header->logger.ops = &header_ops;
515 header->parent = parent;
516 memcpy(header->header, str, len);
517 return &header->logger;
521 * External custom log callback
523 struct vlc_logger_external {
524 struct vlc_logger logger;
525 const struct vlc_logger_operations *ops;
526 void *opaque;
529 static void vlc_vaLogExternal(void *d, int type, const vlc_log_t *item,
530 const char *format, va_list ap)
532 struct vlc_logger_external *ext = d;
534 ext->ops->log(ext->opaque, type, item, format, ap);
537 static void vlc_LogExternalClose(void *d)
539 struct vlc_logger_external *ext = d;
541 if (ext->ops->destroy != NULL)
542 ext->ops->destroy(ext->opaque);
543 free(ext);
546 static const struct vlc_logger_operations external_ops = {
547 vlc_vaLogExternal,
548 vlc_LogExternalClose,
551 static struct vlc_logger *
552 vlc_LogExternalCreate(const struct vlc_logger_operations *ops, void *opaque)
554 struct vlc_logger_external *ext = malloc(sizeof (*ext));
555 if (unlikely(ext == NULL))
556 return NULL;
558 ext->logger.ops = &external_ops;
559 ext->ops = ops;
560 ext->opaque = opaque;
561 return &ext->logger;
565 * Sets the message logging callback.
566 * \param ops message callback, or NULL to clear
567 * \param data data pointer for the message callback
569 void vlc_LogSet(libvlc_int_t *vlc, const struct vlc_logger_operations *ops,
570 void *opaque)
572 struct vlc_logger *logger;
574 if (ops != NULL)
575 logger = vlc_LogExternalCreate(ops, opaque);
576 else
577 logger = NULL;
579 if (logger == NULL)
580 logger = &discard_log;
582 vlc_LogSwitch(vlc->obj.logger, logger);
583 vlc_LogSpam(VLC_OBJECT(vlc));
586 void vlc_LogDestroy(vlc_logger_t *logger)
588 logger->ops->destroy(logger);