1 static const char version[] = "$Id: category.c,v 1.13 2013/09/29 17:37:04 valtri Exp $";
2 
3 /*
4 * category.c
5 *
6 * Copyright 2001-2003, Meiosys (www.meiosys.com). All rights reserved.
7 *
8 * See the COPYING file for the terms of usage and distribution.
9 */
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13 
14 #include <stdlib.h>
15 #include <string.h>
16 #if defined(HAVE_ALLOCA_H)
17 #include <alloca.h>
18 #elif defined(HAVE_MALLOC_H)
19 #include <malloc.h>
20 #endif
21 #include <sd/sprintf.h>
22 #include <sd/malloc.h>
23 #include <sd/factory.h>
24 #include <log4c/appender.h>
25 #include <log4c/priority.h>
26 #include <log4c/logging_event.h>
27 #include <log4c/category.h>
28 #include <log4c/rc.h>
29 #include <sd/error.h>
30 #include <sd/sd_xplatform.h>
31 
32 struct __log4c_category {
33   char*			cat_name;
34   int				cat_priority;
35   int				cat_additive;
36   const log4c_category_t*	cat_parent;
37   log4c_appender_t*		cat_appender;
38 };
39 
40 sd_factory_t* log4c_category_factory = NULL;
41 
42 static const char LOG4C_CATEGORY_DEFAULT[] = "root";
43 
44 
45 /**
46 * @bug the root category name should be "" not "root". *
47 */
48 
49 /*******************************************************************************/
log4c_category_get(const char * a_name)50 extern log4c_category_t* log4c_category_get(const char* a_name)
51 {
52   static const sd_factory_ops_t log4c_category_factory_ops = {
53     (void*) log4c_category_new,
54     (void*) log4c_category_delete,
55     (void*) log4c_category_print,
56   };
57 
58   if (!log4c_category_factory) {
59     log4c_category_factory = sd_factory_new("log4c_category_factory",
60       &log4c_category_factory_ops);
61   }
62 
63   return sd_factory_get(log4c_category_factory, a_name);
64 }
65 
66 /*******************************************************************************/
log4c_category_list(log4c_category_t ** a_cats,int a_ncats)67 extern int log4c_category_list(log4c_category_t** a_cats, int a_ncats)
68 {
69   return sd_factory_list(log4c_category_factory, (void**) a_cats, a_ncats);
70 }
71 
72 /*******************************************************************************/
73 static const char* dot_dirname(char* a_string);
74 
log4c_category_new(const char * a_name)75 extern log4c_category_t* log4c_category_new(const char* a_name)
76 {
77   log4c_category_t* this;
78 
79   if (!a_name)
80     return NULL;
81 
82   this		= sd_calloc(1, sizeof(log4c_category_t));
83   this->cat_name	= sd_strdup(a_name);
84   this->cat_priority	= LOG4C_PRIORITY_NOTSET;
85   this->cat_additive	= 1;
86   this->cat_appender	= NULL;
87   this->cat_parent	= NULL;
88 
89   /* skip root category because it has a NULL parent */
90   if (strcmp(LOG4C_CATEGORY_DEFAULT, a_name)) {
91     char* tmp = sd_strdup(this->cat_name);
92 
93     this->cat_parent = log4c_category_get(dot_dirname(tmp));
94     free(tmp);
95   }
96   return this;
97 }
98 
99 /*******************************************************************************/
log4c_category_delete(log4c_category_t * this)100 extern void log4c_category_delete(log4c_category_t* this)
101 {
102   if (!this)
103     return;
104 
105   free(this->cat_name);
106   free(this);
107 }
108 
109 /*******************************************************************************/
log4c_category_get_name(const log4c_category_t * this)110 extern const char* log4c_category_get_name(const log4c_category_t* this)
111 {
112   return (this ? this->cat_name : "(nil)");
113 }
114 
115 /*******************************************************************************/
log4c_category_get_priority(const log4c_category_t * this)116 extern int log4c_category_get_priority(const log4c_category_t* this)
117 {
118   return (this ? this->cat_priority : LOG4C_PRIORITY_UNKNOWN);
119 }
120 
121 /*******************************************************************************/
log4c_category_get_chainedpriority(const log4c_category_t * this)122 extern int log4c_category_get_chainedpriority(const log4c_category_t* this)
123 {
124   const log4c_category_t* cat = this;
125 
126   if (!this)
127     return LOG4C_PRIORITY_UNKNOWN;
128 
129   while (cat->cat_priority == LOG4C_PRIORITY_NOTSET && cat->cat_parent)
130     cat = cat->cat_parent;
131 
132   return cat->cat_priority;
133 }
134 
135 /*******************************************************************************/
log4c_category_get_appender(const log4c_category_t * this)136 extern const log4c_appender_t* log4c_category_get_appender(const log4c_category_t* this)
137 {
138   return (this ? this->cat_appender : NULL);
139 }
140 
141 /*******************************************************************************/
log4c_category_get_additivity(const log4c_category_t * this)142 extern int log4c_category_get_additivity(const log4c_category_t* this)
143 {
144   return (this ? this->cat_additive : -1);
145 }
146 
147 /*******************************************************************************/
log4c_category_set_priority(log4c_category_t * this,int a_priority)148 extern int log4c_category_set_priority(log4c_category_t* this, int a_priority)
149 {
150   int previous;
151 
152   if (!this)
153     return LOG4C_PRIORITY_UNKNOWN;
154 
155   previous = this->cat_priority;
156   this->cat_priority = a_priority;
157   return previous;
158 }
159 
160 /**
161 * @todo need multiple appenders per category
162 */
163 
164 /*******************************************************************************/
log4c_category_set_appender(log4c_category_t * this,log4c_appender_t * a_appender)165 extern const log4c_appender_t* log4c_category_set_appender(
166   log4c_category_t* this,
167   log4c_appender_t* a_appender)
168 {
169   log4c_appender_t* previous;
170 
171   if (!this)
172     return NULL;
173 
174   previous = this->cat_appender;
175   this->cat_appender = a_appender;
176   return previous;
177 }
178 
179 /*******************************************************************************/
log4c_category_set_additivity(log4c_category_t * this,int a_additivity)180 extern int log4c_category_set_additivity(log4c_category_t* this, int a_additivity)
181 {
182   int previous;
183 
184   if (!this)
185     return -1;
186 
187   previous = this->cat_additive;
188   this->cat_additive = a_additivity;
189   return previous;
190 }
191 
192 /*******************************************************************************/
log4c_category_print(const log4c_category_t * this,FILE * a_stream)193 extern void log4c_category_print(const log4c_category_t* this, FILE* a_stream)
194 {
195   if (!this)
196     return;
197 
198     fprintf(a_stream, "{ name:'%s' priority:%s additive:%d appender:'%s' parent:'%s' }",
199 	    this->cat_name,
200 	    log4c_priority_to_string(this->cat_priority),
201 	    this->cat_additive,
202 	    log4c_appender_get_name(this->cat_appender),
203 	    log4c_category_get_name(this->cat_parent)
204       );
205 }
206 
207 /*******************************************************************************/
__log4c_category_vlog(const log4c_category_t * this,const log4c_location_info_t * a_locinfo,int a_priority,const char * a_format,va_list a_args)208 extern void __log4c_category_vlog(const log4c_category_t* this,
209   const log4c_location_info_t* a_locinfo,
210   int a_priority,
211   const char* a_format,
212   va_list a_args)
213 {
214   char* message;
215   log4c_logging_event_t evt;
216   const log4c_category_t* cat;
217   int yes = 0;
218 
219   if (!this)
220     return;
221 
222   /* check if an appender is defined in the category hierarchy */
223   for (cat = this; cat; cat = cat->cat_parent) {
224     if (cat->cat_appender)
225 	    yes++;
226   }
227 
228   if (!yes)
229     return;
230 
231   log4c_reread();
232 
233   /* when there is no limit on the buffer size, we use malloc() to
234   * give the user the possiblity to reallocate if necessary. When
235   * the buffer is limited in size, we use alloca() for more
236   * efficiency.
237   */
238   evt.evt_buffer.buf_maxsize = log4c_rc->config.bufsize;
239 
240   if (!evt.evt_buffer.buf_maxsize) {
241     evt.evt_buffer.buf_size = LOG4C_BUFFER_SIZE_DEFAULT;
242     evt.evt_buffer.buf_data = sd_malloc(evt.evt_buffer.buf_size);
243     message = sd_vsprintf(a_format, a_args);
244   }
245   else {
246     size_t n;
247 
248     evt.evt_buffer.buf_size = evt.evt_buffer.buf_maxsize;
249     evt.evt_buffer.buf_data = alloca(evt.evt_buffer.buf_size);
250     message = alloca(evt.evt_buffer.buf_size);
251 
252     if ( (n = (size_t)vsnprintf(message, evt.evt_buffer.buf_size, a_format, a_args))
253       >= evt.evt_buffer.buf_size)
254     sd_error("truncating message of %d bytes (bufsize = %d)", n,
255       evt.evt_buffer.buf_size);
256   }
257 
258   evt.evt_category	= this->cat_name;
259   evt.evt_priority	= a_priority;
260   evt.evt_msg	        = message;
261   evt.evt_loc	        = a_locinfo;
262   SD_GETTIMEOFDAY(&evt.evt_timestamp, NULL);
263 
264   for (cat = this; cat; cat = cat->cat_parent) {
265     if (cat->cat_appender)
266 	    log4c_appender_append(cat->cat_appender, &evt);
267 
268     if (!cat->cat_additive) break;
269   }
270 
271   if (!evt.evt_buffer.buf_maxsize) {
272     free(message);
273     free(evt.evt_buffer.buf_data);
274   }
275 }
276 
277 /*******************************************************************************/
dot_dirname(char * a_string)278 static const char* dot_dirname(char* a_string)
279 {
280   char* p;
281 
282   if (!a_string)
283     return NULL;
284 
285   if ( (p = strrchr(a_string, '.')) == NULL)
286     return LOG4C_CATEGORY_DEFAULT;
287 
288   *p = '\0';
289   return a_string;
290 }
291 
292