Add a wrapper around vstr_add_fmt() to avoid having to link libcharon against libvstr
[strongswan.git] / src / libstrongswan / printf_hook.c
1 /*
2 * Copyright (C) 2009 Tobias Brunner
3 * Copyright (C) 2006-2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "printf_hook.h"
18
19 #include "utils.h"
20 #include "debug.h"
21
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <string.h>
25
26 typedef struct private_printf_hook_t private_printf_hook_t;
27 typedef struct printf_hook_handler_t printf_hook_handler_t;
28
29 #define PRINTF_BUF_LEN 8192
30 #define ARGS_MAX 3
31
32 /**
33 * private data of printf_hook
34 */
35 struct private_printf_hook_t {
36
37 /**
38 * public functions
39 */
40 printf_hook_t public;
41 };
42
43 /**
44 * struct with information about a registered handler
45 */
46 struct printf_hook_handler_t {
47
48 /**
49 * callback function
50 */
51 printf_hook_function_t hook;
52
53 /**
54 * number of arguments
55 */
56 int numargs;
57
58 /**
59 * types of the arguments
60 */
61 int argtypes[ARGS_MAX];
62
63 #ifdef USE_VSTR
64 /**
65 * name required for Vstr
66 */
67 char *name;
68 #endif
69 };
70
71 /* A-Z | 6 other chars | a-z */
72 #define NUM_HANDLERS 58
73 static printf_hook_handler_t *printf_hooks[NUM_HANDLERS];
74
75 #define SPEC_TO_INDEX(spec) ((int)(spec) - (int)'A')
76 #define IS_VALID_SPEC(spec) (SPEC_TO_INDEX(spec) > -1 && SPEC_TO_INDEX(spec) < NUM_HANDLERS)
77
78 #if !defined(USE_VSTR) && \
79 (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER))
80
81 /**
82 * Printf hook print function. This is actually of type "printf_function",
83 * however glibc does it typedef to function, but uclibc to a pointer.
84 * So we redefine it here.
85 */
86 static int custom_print(FILE *stream, const struct printf_info *info,
87 const void *const *args)
88 {
89 printf_hook_spec_t spec;
90 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)];
91 printf_hook_data_t data = {
92 .stream = stream,
93 };
94
95 spec.hash = info->alt;
96 spec.plus = info->showsign;
97 spec.minus = info->left;
98 spec.width = info->width;
99
100 return handler->hook(&data, &spec, args);
101 }
102
103 /**
104 * Printf hook arginfo function, which is actually of type
105 * "printf_arginfo_[size_]function".
106 */
107 static int custom_arginfo(const struct printf_info *info, size_t n, int *argtypes
108 #ifdef HAVE_PRINTF_SPECIFIER
109 , int *size
110 #endif
111 )
112 {
113 int i;
114 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)];
115
116 if (handler->numargs <= n)
117 {
118 for (i = 0; i < handler->numargs; ++i)
119 {
120 argtypes[i] = handler->argtypes[i];
121 }
122 }
123 /* we never set "size", as we have no user defined types */
124 return handler->numargs;
125 }
126
127 #else
128
129 #include <errno.h>
130 #include <unistd.h> /* for STDOUT_FILENO */
131
132 /**
133 * These are used below, whenever the public wrapper functions are called before
134 * initialization or after destruction.
135 */
136 #undef vprintf
137 #undef vfprintf
138 #undef vsnprintf
139
140 /**
141 * Vstr custom format specifier callback function.
142 */
143 static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec)
144 {
145 int i;
146 const void *args[ARGS_MAX];
147 printf_hook_spec_t spec;
148 printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(fmt_spec->name[0])];
149 printf_hook_data_t data = {
150 .base = base,
151 .pos = pos,
152 };
153
154 for (i = 0; i < handler->numargs; i++)
155 {
156 switch(handler->argtypes[i])
157 {
158 case PRINTF_HOOK_ARGTYPE_INT:
159 args[i] = VSTR_FMT_CB_ARG_PTR(fmt_spec, i);
160 break;
161 case PRINTF_HOOK_ARGTYPE_POINTER:
162 args[i] = &VSTR_FMT_CB_ARG_PTR(fmt_spec, i);
163 break;
164 }
165 }
166
167 spec.hash = fmt_spec->fmt_hash;
168 spec.plus = fmt_spec->fmt_plus;
169 spec.minus = fmt_spec->fmt_minus;
170 spec.width = fmt_spec->fmt_field_width;
171
172 handler->hook(&data, &spec, args);
173 return 1;
174 }
175
176 /**
177 * Add a custom format handler to the given Vstr_conf object
178 */
179 static void vstr_fmt_add_handler(Vstr_conf *conf, printf_hook_handler_t *handler)
180 {
181 int *at = handler->argtypes;
182 switch(handler->numargs)
183 {
184 case 1:
185 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
186 VSTR_TYPE_FMT_END);
187 break;
188 case 2:
189 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
190 at[1], VSTR_TYPE_FMT_END);
191 break;
192 case 3:
193 vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
194 at[1], at[2], VSTR_TYPE_FMT_END);
195 break;
196 }
197 }
198
199 /**
200 * Management of thread-specific Vstr_conf objects
201 */
202 #include <threading/thread_value.h>
203
204 static thread_value_t *vstr_conf = NULL;
205
206 static Vstr_conf *create_vstr_conf()
207 {
208 int i;
209 Vstr_conf *conf = vstr_make_conf();
210 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '%');
211 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_TYPE_GRPALLOC_CACHE,
212 VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR);
213 vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, PRINTF_BUF_LEN);
214 for (i = 0; i < NUM_HANDLERS; ++i)
215 {
216 printf_hook_handler_t *handler = printf_hooks[i];
217 if (handler)
218 {
219 vstr_fmt_add_handler(conf, handler);
220 }
221 }
222 return conf;
223 }
224
225 static inline Vstr_conf *get_vstr_conf()
226 {
227 Vstr_conf *conf = NULL;
228 if (vstr_conf)
229 {
230 conf = (Vstr_conf*)vstr_conf->get(vstr_conf);
231 if (!conf)
232 {
233 conf = create_vstr_conf();
234 vstr_conf->set(vstr_conf, conf);
235 }
236 }
237 return conf;
238 }
239
240 /**
241 * Described in header
242 */
243 size_t vstr_print_in_hook(struct Vstr_base *base, size_t pos, const char *fmt,
244 ...)
245 {
246 va_list args;
247 int written;
248
249 va_start(args, fmt);
250 written = vstr_add_vfmt(base, pos, fmt, args);
251 va_end(args);
252 return written;
253 }
254
255 /**
256 * Wrapper functions for printf and alike
257 */
258 int vstr_wrapper_printf(const char *format, ...)
259 {
260 int written;
261 va_list args;
262 va_start(args, format);
263 written = vstr_wrapper_vprintf(format, args);
264 va_end(args);
265 return written;
266 }
267 int vstr_wrapper_fprintf(FILE *stream, const char *format, ...)
268 {
269 int written;
270 va_list args;
271 va_start(args, format);
272 written = vstr_wrapper_vfprintf(stream, format, args);
273 va_end(args);
274 return written;
275 }
276 int vstr_wrapper_sprintf(char *str, const char *format, ...)
277 {
278 int written;
279 va_list args;
280 va_start(args, format);
281 written = vstr_wrapper_vsprintf(str, format, args);
282 va_end(args);
283 return written;
284 }
285 int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...)
286 {
287 int written;
288 va_list args;
289 va_start(args, format);
290 written = vstr_wrapper_vsnprintf(str, size, format, args);
291 va_end(args);
292 return written;
293 }
294 int vstr_wrapper_asprintf(char **str, const char *format, ...)
295 {
296 int written;
297 va_list args;
298 va_start(args, format);
299 written = vstr_wrapper_vasprintf(str, format, args);
300 va_end(args);
301 return written;
302 }
303 static inline int vstr_wrapper_vprintf_internal(Vstr_conf *conf, int fd,
304 const char *format,
305 va_list args)
306 {
307 int written;
308 Vstr_base *s = vstr_make_base(conf);
309 vstr_add_vfmt(s, 0, format, args);
310 written = s->len;
311 while (s->len)
312 {
313 if (!vstr_sc_write_fd(s, 1, s->len, fd, NULL))
314 {
315 if (errno != EAGAIN && errno != EINTR)
316 {
317 written -= s->len;
318 break;
319 }
320 }
321 }
322 vstr_free_base(s);
323 return written;
324 }
325 int vstr_wrapper_vprintf(const char *format, va_list args)
326 {
327 Vstr_conf *conf = get_vstr_conf();
328 if (conf)
329 {
330 return vstr_wrapper_vprintf_internal(conf, STDOUT_FILENO, format, args);
331 }
332 return vprintf(format, args);
333 }
334 int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list args)
335 {
336 Vstr_conf *conf = get_vstr_conf();
337 if (conf)
338 {
339 return vstr_wrapper_vprintf_internal(conf, fileno(stream), format,
340 args);
341 }
342 return vfprintf(stream, format, args);
343 }
344 static inline int vstr_wrapper_vsnprintf_internal(char *str, size_t size,
345 const char *format,
346 va_list args)
347 {
348 Vstr_conf *conf = get_vstr_conf();
349 if (conf)
350 {
351 int written;
352 Vstr_base *s = vstr_make_base(conf);
353 vstr_add_vfmt(s, 0, format, args);
354 written = s->len;
355 vstr_export_cstr_buf(s, 1, s->len, str, (size > 0) ? size : s->len + 1);
356 vstr_free_base(s);
357 return written;
358 }
359 return vsnprintf(str, size, format, args);
360 }
361 int vstr_wrapper_vsprintf(char *str, const char *format, va_list args)
362 {
363 return vstr_wrapper_vsnprintf_internal(str, 0, format, args);
364 }
365 int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format,
366 va_list args)
367 {
368 return (size > 0) ? vstr_wrapper_vsnprintf_internal(str, size, format, args) : 0;
369 }
370 int vstr_wrapper_vasprintf(char **str, const char *format, va_list args)
371 {
372 size_t len = 100;
373 int written;
374 *str = malloc(len);
375 while (TRUE)
376 {
377 va_list ac;
378 va_copy(ac, args);
379 written = vstr_wrapper_vsnprintf_internal(*str, len, format, ac);
380 va_end(ac);
381 if (written < len)
382 {
383 break;
384 }
385 len = written + 1;
386 *str = realloc(*str, len);
387 }
388 return written;
389 }
390 #endif
391
392 METHOD(printf_hook_t, add_handler, void,
393 private_printf_hook_t *this, char spec,
394 printf_hook_function_t hook, ...)
395 {
396 int i = -1;
397 printf_hook_handler_t *handler;
398 printf_hook_argtype_t argtype;
399 va_list args;
400
401 if (!IS_VALID_SPEC(spec))
402 {
403 DBG1(DBG_LIB, "'%c' is not a valid printf hook specifier, "
404 "not registered!", spec);
405 return;
406 }
407
408 handler = malloc_thing(printf_hook_handler_t);
409 handler->hook = hook;
410
411 va_start(args, hook);
412 while ((argtype = va_arg(args, printf_hook_argtype_t)) != PRINTF_HOOK_ARGTYPE_END)
413 {
414 if (++i >= ARGS_MAX)
415 {
416 DBG1(DBG_LIB, "Too many arguments for printf hook with "
417 "specifier '%c', not registered!", spec);
418 va_end(args);
419 free(handler);
420 return;
421 }
422 handler->argtypes[i] = argtype;
423 }
424 va_end(args);
425
426 handler->numargs = i + 1;
427
428 if (handler->numargs > 0)
429 {
430 #if !defined(USE_VSTR) && \
431 (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER))
432 # ifdef HAVE_PRINTF_SPECIFIER
433 register_printf_specifier(spec, custom_print, custom_arginfo);
434 # else
435 register_printf_function(spec, custom_print, custom_arginfo);
436 # endif
437 #else
438 Vstr_conf *conf = get_vstr_conf();
439 handler->name = malloc(2);
440 handler->name[0] = spec;
441 handler->name[1] = '\0';
442 vstr_fmt_add_handler(conf, handler);
443 #endif
444 printf_hooks[SPEC_TO_INDEX(spec)] = handler;
445 }
446 else
447 {
448 free(handler);
449 }
450 }
451
452 METHOD(printf_hook_t, destroy, void,
453 private_printf_hook_t *this)
454 {
455 int i;
456 #ifdef USE_VSTR
457 Vstr_conf *conf = get_vstr_conf();
458 #endif
459
460 for (i = 0; i < NUM_HANDLERS; ++i)
461 {
462 printf_hook_handler_t *handler = printf_hooks[i];
463 if (handler)
464 {
465 #ifdef USE_VSTR
466 vstr_fmt_del(conf, handler->name);
467 free(handler->name);
468 #endif
469 free(handler);
470 }
471 }
472
473 #ifdef USE_VSTR
474 /* freeing the Vstr_conf of the main thread */
475 vstr_conf->destroy(vstr_conf);
476 vstr_conf = NULL;
477 vstr_free_conf(conf);
478 vstr_exit();
479 #endif
480 free(this);
481 }
482
483 /*
484 * see header file
485 */
486 printf_hook_t *printf_hook_create()
487 {
488 private_printf_hook_t *this;
489
490 INIT(this,
491 .public = {
492 .add_handler = _add_handler,
493 .destroy = _destroy,
494 },
495 );
496
497 memset(printf_hooks, 0, sizeof(printf_hooks));
498
499 #ifdef USE_VSTR
500 if (!vstr_init())
501 {
502 DBG1(DBG_LIB, "failed to initialize Vstr library!");
503 free(this);
504 return NULL;
505 }
506 vstr_conf = thread_value_create((thread_cleanup_t)vstr_free_conf);
507 #endif
508
509 return &this->public;
510 }
511