1 /*-------------------------------------------------------------------------
2 * C-Pluff, a plug-in framework for C
3 * Copyright 2007 Johannes Lehtinen
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *-----------------------------------------------------------------------*/
39 /* ------------------------------------------------------------------------
41 * ----------------------------------------------------------------------*/
43 /// Contains information about installed loggers
44 typedef struct logger_t {
47 cp_logger_func_t logger;
49 /// Pointer to registering plug-in or NULL for the main program
56 cp_log_severity_t min_severity;
58 /// Selected environment or NULL
59 cp_plugin_env_t *env_selection;
63 /* ------------------------------------------------------------------------
64 * Function definitions
65 * ----------------------------------------------------------------------*/
68 * Updates the context logging limits. The caller must have locked the
71 static void update_logging_limits(cp_context_t *context) {
73 int nms = CP_LOG_NONE;
75 node = list_first(context->env->loggers);
76 while (node != NULL) {
77 logger_t *lh = lnode_get(node);
78 if (lh->min_severity < nms) {
79 nms = lh->min_severity;
81 node = list_next(context->env->loggers, node);
83 context->env->log_min_severity = nms;
86 static int comp_logger(const void *p1, const void *p2) {
87 const logger_t *l1 = p1;
88 const logger_t *l2 = p2;
89 return l1->logger != l2->logger;
92 CP_C_API cp_status_t cp_register_logger(cp_context_t *context, cp_logger_func_t logger, void *user_data, cp_log_severity_t min_severity) {
96 cp_status_t status = CP_OK;
98 CHECK_NOT_NULL(context);
99 CHECK_NOT_NULL(logger);
100 cpi_lock_context(context);
101 cpi_check_invocation(context, CPI_CF_LOGGER, __func__);
104 // Check if logger already exists and allocate new holder if necessary
106 if ((node = list_find(context->env->loggers, &l, comp_logger)) == NULL) {
107 lh = malloc(sizeof(logger_t));
108 node = lnode_create(lh);
109 if (lh == NULL || node == NULL) {
110 status = CP_ERR_RESOURCE;
114 lh->plugin = context->plugin;
115 list_append(context->env->loggers, node);
117 lh = lnode_get(node);
120 // Initialize or update the logger holder
121 lh->user_data = user_data;
122 lh->min_severity = min_severity;
124 // Update global limits
125 update_logging_limits(context);
130 if (status == CP_ERR_RESOURCE) {
131 cpi_error(context, N_("Logger could not be registered due to insufficient memory."));
132 } else if (cpi_is_logged(context, CP_LOG_DEBUG)) {
134 /* TRANSLATORS: %s is the context owner */
135 cpi_debugf(context, N_("%s registered a logger."), cpi_context_owner(context, owner, sizeof(owner)));
137 cpi_unlock_context(context);
139 // Release resources on error
140 if (status != CP_OK) {
152 CP_C_API void cp_unregister_logger(cp_context_t *context, cp_logger_func_t logger) {
156 CHECK_NOT_NULL(context);
157 CHECK_NOT_NULL(logger);
158 cpi_lock_context(context);
159 cpi_check_invocation(context, CPI_CF_LOGGER, __func__);
162 if ((node = list_find(context->env->loggers, &l, comp_logger)) != NULL) {
163 logger_t *lh = lnode_get(node);
164 list_delete(context->env->loggers, node);
167 update_logging_limits(context);
169 if (cpi_is_logged(context, CP_LOG_DEBUG)) {
171 /* TRANSLATORS: %s is the context owner */
172 cpi_debugf(context, N_("%s unregistered a logger."), cpi_context_owner(context, owner, sizeof(owner)));
174 cpi_unlock_context(context);
177 static void do_log(cp_context_t *context, cp_log_severity_t severity, const char *msg) {
179 const char *apid = NULL;
181 assert(cpi_is_context_locked(context));
182 if (context->env->in_logger_invocation) {
183 cpi_fatalf(_("Encountered a recursive logging request within a logger invocation."));
185 if (context->plugin != NULL) {
186 apid = context->plugin->plugin->identifier;
188 context->env->in_logger_invocation++;
189 node = list_first(context->env->loggers);
190 while (node != NULL) {
191 logger_t *lh = lnode_get(node);
192 if (severity >= lh->min_severity) {
193 lh->logger(severity, msg, apid, lh->user_data);
195 node = list_next(context->env->loggers, node);
197 context->env->in_logger_invocation--;
200 CP_HIDDEN void cpi_log(cp_context_t *context, cp_log_severity_t severity, const char *msg) {
201 assert(context != NULL);
203 assert(severity >= CP_LOG_DEBUG && severity <= CP_LOG_ERROR);
204 do_log(context, severity, _(msg));
207 CP_HIDDEN void cpi_logf(cp_context_t *context, cp_log_severity_t severity, const char *msg, ...) {
211 assert(context != NULL);
213 assert(severity >= CP_LOG_DEBUG && severity <= CP_LOG_ERROR);
216 vsnprintf(buffer, sizeof(buffer), _(msg), va);
218 strcpy(buffer + sizeof(buffer)/sizeof(char) - 4, "...");
219 do_log(context, severity, buffer);
222 static void process_unregister_logger(list_t *list, lnode_t *node, void *plugin) {
223 logger_t *lh = lnode_get(node);
224 if (plugin == NULL || lh->plugin == plugin) {
225 list_delete(list, node);
231 CP_HIDDEN void cpi_unregister_loggers(list_t *loggers, cp_plugin_t *plugin) {
232 list_process(loggers, plugin, process_unregister_logger);
235 CP_C_API void cp_log(cp_context_t *context, cp_log_severity_t severity, const char *msg) {
236 CHECK_NOT_NULL(context);
238 cpi_lock_context(context);
239 cpi_check_invocation(context, CPI_CF_LOGGER, __func__);
240 if (severity < CP_LOG_DEBUG || severity > CP_LOG_ERROR) {
241 cpi_fatalf(_("Illegal severity value in call to %s."), __func__);
243 if (cpi_is_logged(context, severity)) {
244 do_log(context, severity, msg);
246 cpi_unlock_context(context);
249 CP_C_API int cp_is_logged(cp_context_t *context, cp_log_severity_t severity) {
252 CHECK_NOT_NULL(context);
253 cpi_lock_context(context);
254 cpi_check_invocation(context, CPI_CF_LOGGER, __func__);
255 is_logged = cpi_is_logged(context, severity);
256 cpi_unlock_context(context);