Simplify the set_log_callback, it is better for thread safety
[deb_shairplay.git] / src / lib / logger.c
1 /**
2 * Copyright (C) 2011-2012 Juho Vähä-Herttua
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <stdarg.h>
18 #include <assert.h>
19
20 #include "logger.h"
21 #include "compat.h"
22
23 struct logger_s {
24 mutex_handle_t lvl_mutex;
25 mutex_handle_t cb_mutex;
26
27 int level;
28 logger_callback_t callback;
29 };
30
31 logger_t *
32 logger_init()
33 {
34 logger_t *logger = calloc(1, sizeof(logger_t));
35 assert(logger);
36
37 MUTEX_CREATE(logger->lvl_mutex);
38 MUTEX_CREATE(logger->cb_mutex);
39
40 logger->level = LOGGER_WARNING;
41 logger->callback = NULL;
42 return logger;
43 }
44
45 void
46 logger_destroy(logger_t *logger)
47 {
48 MUTEX_DESTROY(logger->lvl_mutex);
49 MUTEX_DESTROY(logger->cb_mutex);
50 free(logger);
51 }
52
53 void
54 logger_set_level(logger_t *logger, int level)
55 {
56 assert(logger);
57
58 MUTEX_LOCK(logger->lvl_mutex);
59 logger->level = level;
60 MUTEX_UNLOCK(logger->lvl_mutex);
61 }
62
63 void
64 logger_set_callback(logger_t *logger, logger_callback_t callback)
65 {
66 assert(logger);
67
68 MUTEX_LOCK(logger->cb_mutex);
69 logger->callback = callback;
70 MUTEX_UNLOCK(logger->cb_mutex);
71 }
72
73 static char *
74 logger_utf8_to_local(const char *str)
75 {
76 char *ret = NULL;
77
78 /* FIXME: This is only implemented on Windows for now */
79 #if defined(_WIN32) || defined(_WIN64)
80 int wclen, mblen;
81 WCHAR *wcstr;
82 BOOL failed;
83
84 wclen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
85 wcstr = malloc(sizeof(WCHAR) * wclen);
86 MultiByteToWideChar(CP_UTF8, 0, str, -1, wcstr, wclen);
87
88 mblen = WideCharToMultiByte(CP_ACP, 0, wcstr, wclen, NULL, 0, NULL, &failed);
89 if (failed) {
90 /* Invalid characters in input, conversion failed */
91 free(wcstr);
92 return NULL;
93 }
94
95 ret = malloc(sizeof(CHAR) * mblen);
96 WideCharToMultiByte(CP_ACP, 0, wcstr, wclen, ret, mblen, NULL, NULL);
97 free(wcstr);
98 #endif
99
100 return ret;
101 }
102
103 void
104 logger_log(logger_t *logger, int level, const char *fmt, ...)
105 {
106 char buffer[4096];
107 va_list ap;
108
109 MUTEX_LOCK(logger->lvl_mutex);
110 if (level > logger->level) {
111 MUTEX_UNLOCK(logger->lvl_mutex);
112 return;
113 }
114 MUTEX_UNLOCK(logger->lvl_mutex);
115
116 buffer[sizeof(buffer)-1] = '\0';
117 va_start(ap, fmt);
118 vsnprintf(buffer, sizeof(buffer)-1, fmt, ap);
119 va_end(ap);
120
121 MUTEX_LOCK(logger->cb_mutex);
122 if (logger->callback) {
123 logger->callback(level, buffer);
124 MUTEX_UNLOCK(logger->cb_mutex);
125 } else {
126 char *local;
127 MUTEX_UNLOCK(logger->cb_mutex);
128 local = logger_utf8_to_local(buffer);
129 if (local) {
130 fprintf(stderr, "%s\n", local);
131 free(local);
132 } else {
133 fprintf(stderr, "%s\n", buffer);
134 }
135 }
136 }
137