Fixed and documented example.c
[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 void *cls;
29 logger_callback_t callback;
30 };
31
32 logger_t *
33 logger_init()
34 {
35 logger_t *logger = calloc(1, sizeof(logger_t));
36 assert(logger);
37
38 MUTEX_CREATE(logger->lvl_mutex);
39 MUTEX_CREATE(logger->cb_mutex);
40
41 logger->level = LOGGER_WARNING;
42 logger->callback = NULL;
43 return logger;
44 }
45
46 void
47 logger_destroy(logger_t *logger)
48 {
49 MUTEX_DESTROY(logger->lvl_mutex);
50 MUTEX_DESTROY(logger->cb_mutex);
51 free(logger);
52 }
53
54 void
55 logger_set_level(logger_t *logger, int level)
56 {
57 assert(logger);
58
59 MUTEX_LOCK(logger->lvl_mutex);
60 logger->level = level;
61 MUTEX_UNLOCK(logger->lvl_mutex);
62 }
63
64 void
65 logger_set_callback(logger_t *logger, logger_callback_t callback, void *cls)
66 {
67 assert(logger);
68
69 MUTEX_LOCK(logger->cb_mutex);
70 logger->cls = cls;
71 logger->callback = callback;
72 MUTEX_UNLOCK(logger->cb_mutex);
73 }
74
75 static char *
76 logger_utf8_to_local(const char *str)
77 {
78 char *ret = NULL;
79
80 /* FIXME: This is only implemented on Windows for now */
81 #if defined(_WIN32) || defined(_WIN64)
82 int wclen, mblen;
83 WCHAR *wcstr;
84 BOOL failed;
85
86 wclen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
87 wcstr = malloc(sizeof(WCHAR) * wclen);
88 MultiByteToWideChar(CP_UTF8, 0, str, -1, wcstr, wclen);
89
90 mblen = WideCharToMultiByte(CP_ACP, 0, wcstr, wclen, NULL, 0, NULL, &failed);
91 if (failed) {
92 /* Invalid characters in input, conversion failed */
93 free(wcstr);
94 return NULL;
95 }
96
97 ret = malloc(sizeof(CHAR) * mblen);
98 WideCharToMultiByte(CP_ACP, 0, wcstr, wclen, ret, mblen, NULL, NULL);
99 free(wcstr);
100 #endif
101
102 return ret;
103 }
104
105 void
106 logger_log(logger_t *logger, int level, const char *fmt, ...)
107 {
108 char buffer[4096];
109 va_list ap;
110
111 MUTEX_LOCK(logger->lvl_mutex);
112 if (level > logger->level) {
113 MUTEX_UNLOCK(logger->lvl_mutex);
114 return;
115 }
116 MUTEX_UNLOCK(logger->lvl_mutex);
117
118 buffer[sizeof(buffer)-1] = '\0';
119 va_start(ap, fmt);
120 vsnprintf(buffer, sizeof(buffer)-1, fmt, ap);
121 va_end(ap);
122
123 MUTEX_LOCK(logger->cb_mutex);
124 if (logger->callback) {
125 logger->callback(logger->cls, level, buffer);
126 MUTEX_UNLOCK(logger->cb_mutex);
127 } else {
128 char *local;
129 MUTEX_UNLOCK(logger->cb_mutex);
130 local = logger_utf8_to_local(buffer);
131 if (local) {
132 fprintf(stderr, "%s\n", local);
133 free(local);
134 } else {
135 fprintf(stderr, "%s\n", buffer);
136 }
137 }
138 }
139