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 *
logger_init()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
logger_destroy(logger_t * logger)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
logger_set_level(logger_t * logger,int level)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
logger_set_callback(logger_t * logger,logger_callback_t callback,void * cls)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 *
logger_utf8_to_local(const char * str)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
logger_log(logger_t * logger,int level,const char * fmt,...)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 
140