c79d4b87a6f7b7a3d4fda4f6266158330ebc2440
[strongswan.git] / src / libstrongswan / utils / printf_hook / printf_hook_builtin.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 /**
17 * Copyright (C) 2002-2006 H. Peter Anvin
18 *
19 * Permission is hereby granted, free of charge, to any person obtaining a copy
20 * of this software and associated documentation files (the "Software"), to deal
21 * in the Software without restriction, including without limitation the rights
22 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 * copies of the Software, and to permit persons to whom the Software is
24 * furnished to do so, subject to the following conditions:
25 *
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 * THE SOFTWARE.
36 */
37
38 #include "printf_hook.h"
39
40 #include <utils/utils.h>
41 #include <utils/debug.h>
42 #include <collections/hashtable.h>
43
44 #include <inttypes.h>
45 #include <limits.h>
46 #include <stdio.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #include <errno.h>
50 #include <math.h>
51
52 #define PRINTF_BUF_LEN 8192
53 #define ARGS_MAX 3
54
55 typedef struct private_printf_hook_t private_printf_hook_t;
56 typedef struct printf_hook_handler_t printf_hook_handler_t;
57
58 /**
59 * private data of printf_hook
60 */
61 struct private_printf_hook_t {
62
63 /**
64 * public functions
65 */
66 printf_hook_t public;
67 };
68
69 /**
70 * struct with information about a registered handler
71 */
72 struct printf_hook_handler_t {
73
74 /**
75 * callback function
76 */
77 printf_hook_function_t hook;
78
79 /**
80 * number of arguments
81 */
82 int numargs;
83
84 /**
85 * types of the arguments
86 */
87 int argtypes[ARGS_MAX];
88 };
89
90 /**
91 * Data to pass to a printf hook.
92 */
93 struct printf_hook_data_t {
94
95 /**
96 * Output buffer
97 */
98 char *q;
99
100 /**
101 * Remaining bytes in q
102 */
103 size_t n;
104 };
105
106 /**
107 * Registered hooks (char => printf_hook_handler_t)
108 */
109 static hashtable_t *hooks;
110
111 /**
112 * builtin-printf variant of print_in_hook()
113 */
114 size_t print_in_hook(printf_hook_data_t *data, char *fmt, ...)
115 {
116 int written;
117 va_list args;
118
119 va_start(args, fmt);
120 written = builtin_vsnprintf(data->q, data->n, fmt, args);
121 va_end(args);
122
123 if (written > data->n)
124 {
125 data->q += data->n;
126 data->n = 0;
127 }
128 else
129 {
130 data->q += written;
131 data->n -= written;
132 }
133 return written;
134 }
135
136 METHOD(printf_hook_t, add_handler, void,
137 private_printf_hook_t *this, char spec, printf_hook_function_t hook, ...)
138 {
139 int i = -1;
140 bool failed = FALSE;
141 printf_hook_handler_t *handler;
142 printf_hook_argtype_t argtype;
143 va_list args;
144
145 INIT(handler,
146 .hook = hook,
147 );
148
149 va_start(args, hook);
150 while (!failed)
151 {
152 argtype = va_arg(args, printf_hook_argtype_t);
153
154 if (argtype == PRINTF_HOOK_ARGTYPE_END)
155 {
156 break;
157 }
158 if (++i >= countof(handler->argtypes))
159 {
160 DBG1(DBG_LIB, "Too many arguments for printf hook with "
161 "specifier '%c', not registered!", spec);
162 failed = TRUE;
163 break;
164 }
165 handler->argtypes[i] = argtype;
166 }
167 va_end(args);
168
169 handler->numargs = i + 1;
170 if (!failed && handler->numargs > 0)
171 {
172 free(hooks->put(hooks, (void*)(uintptr_t)spec, handler));
173 }
174 else
175 {
176 free(handler);
177 }
178 }
179
180 /**
181 * Printf format modifier flags
182 */
183 typedef enum {
184 FL_ZERO = 0x01,
185 FL_MINUS = 0x02,
186 FL_PLUS = 0x04,
187 FL_TICK = 0x08,
188 FL_SPACE = 0x10,
189 FL_HASH = 0x20,
190 FL_SIGNED = 0x40,
191 FL_UPPER = 0x80,
192 } bpf_flag_t;
193
194 /**
195 * Size of format string arguments
196 */
197 typedef enum {
198 RNK_CHAR = -2,
199 RNK_SHORT = -1,
200 RNK_INT = 0,
201 RNK_LONG = 1,
202 RNK_LONGLONG = 2,
203
204 RNK_INTMAX = RNK_LONGLONG,
205 RNK_SIZE_T = RNK_LONG,
206 RNK_PTRDIFF_T = RNK_LONG,
207
208 RNK_MIN = RNK_CHAR,
209 RNK_MAX = RNK_LONGLONG,
210 } bpf_rank_t;
211
212 /**
213 * Printf specifier Parser state
214 */
215 typedef enum {
216 /* Ground state */
217 ST_NORMAL,
218 /* Special flags */
219 ST_FLAGS,
220 /* Field width */
221 ST_WIDTH,
222 /* Field precision */
223 ST_PREC,
224 /* Length or conversion modifiers */
225 ST_MODIFIERS,
226 } bpf_state_t;
227
228 #define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })
229
230 static const char lcdigits[] = "0123456789abcdef";
231 static const char ucdigits[] = "0123456789ABCDEF";
232
233 /**
234 * Write an integer argument to q, using flags, base, width and precision
235 */
236 static size_t format_int(char *q, size_t n, uintmax_t val, bpf_flag_t flags,
237 int base, int width, int prec)
238 {
239 char *qq;
240 size_t o = 0, oo;
241 const char *digits;
242 uintmax_t tmpval;
243 int minus = 0;
244 int ndigits = 0, nchars;
245 int tickskip, b4tick;
246
247 /* Select type of digits */
248 digits = (flags & FL_UPPER) ? ucdigits : lcdigits;
249
250 /* If signed, separate out the minus */
251 if (flags & FL_SIGNED && (intmax_t) val < 0)
252 {
253 minus = 1;
254 val = (uintmax_t) (-(intmax_t) val);
255 }
256
257 /* Count the number of digits needed. This returns zero for 0. */
258 tmpval = val;
259 while (tmpval)
260 {
261 tmpval /= base;
262 ndigits++;
263 }
264
265 /* Adjust ndigits for size of output */
266 if (flags & FL_HASH && base == 8)
267 {
268 if (prec < ndigits + 1)
269 {
270 prec = ndigits + 1;
271 }
272 }
273
274 if (ndigits < prec)
275 {
276 /* Mandatory number padding */
277 ndigits = prec;
278 }
279 else if (val == 0)
280 {
281 /* Zero still requires space */
282 ndigits = 1;
283 }
284
285 /* For ', figure out what the skip should be */
286 if (flags & FL_TICK)
287 {
288 if (base == 16)
289 {
290 tickskip = 4;
291 }
292 else
293 {
294 tickskip = 3;
295 }
296 }
297 else
298 {
299 /* No tick marks */
300 tickskip = ndigits;
301 }
302
303 /* Tick marks aren't digits, but generated by the number converter */
304 ndigits += (ndigits - 1) / tickskip;
305
306 /* Now compute the number of nondigits */
307 nchars = ndigits;
308
309 if (minus || (flags & (FL_PLUS | FL_SPACE)))
310 {
311 /* Need space for sign */
312 nchars++;
313 }
314 if ((flags & FL_HASH) && base == 16)
315 {
316 /* Add 0x for hex */
317 nchars += 2;
318 }
319
320 /* Emit early space padding */
321 if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars)
322 {
323 while (width > nchars)
324 {
325 EMIT(' ');
326 width--;
327 }
328 }
329
330 /* Emit nondigits */
331 if (minus)
332 {
333 EMIT('-');
334 }
335 else if (flags & FL_PLUS)
336 {
337 EMIT('+');
338 }
339 else if (flags & FL_SPACE)
340 {
341 EMIT(' ');
342 }
343
344 if ((flags & FL_HASH) && base == 16)
345 {
346 EMIT('0');
347 EMIT((flags & FL_UPPER) ? 'X' : 'x');
348 }
349
350 /* Emit zero padding */
351 if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits)
352 {
353 while (width > nchars)
354 {
355 EMIT('0');
356 width--;
357 }
358 }
359
360 /* Generate the number. This is done from right to left. */
361 /* Advance the pointer to end of number */
362 q += ndigits;
363 o += ndigits;
364 /* Temporary values */
365 qq = q;
366 oo = o;
367
368 b4tick = tickskip;
369 while (ndigits > 0)
370 {
371 if (!b4tick--)
372 {
373 qq--;
374 oo--;
375 ndigits--;
376 if (oo < n)
377 {
378 *qq = '_';
379 }
380 b4tick = tickskip - 1;
381 }
382 qq--;
383 oo--;
384 ndigits--;
385 if (oo < n)
386 {
387 *qq = digits[val % base];
388 }
389 val /= base;
390 }
391
392 /* Emit late space padding */
393 while ((flags & FL_MINUS) && width > nchars)
394 {
395 EMIT(' ');
396 width--;
397 }
398
399 return o;
400 }
401
402 /**
403 * Write an double argument to q, using flags, base, width and precision
404 */
405 static size_t format_double(char *q, size_t n, double val, bpf_flag_t flags,
406 int base, int width, int prec)
407 {
408 char *qq;
409 size_t o = 0, oo;
410 const char *digits;
411 uintmax_t tmpval;
412 int minus = 0;
413 int ndigits = 0, nchars;
414
415 /* Select type of digits */
416 digits = (flags & FL_UPPER) ? ucdigits : lcdigits;
417
418 if (prec < 0)
419 {
420 /* default precision */
421 prec = 6;
422 }
423 if (val < 0)
424 {
425 minus = 1;
426 }
427
428 tmpval = (uintmax_t)fabs(val);
429 while (tmpval)
430 {
431 tmpval /= base;
432 ndigits++;
433 }
434 if (val == 0)
435 {
436 ndigits++;
437 }
438
439 /* Now compute the number of nondigits */
440 nchars = ndigits;
441
442 if (prec)
443 {
444 /* Space for decimal-point and digits after that */
445 nchars += prec + 1;
446 }
447 if (minus || (flags & (FL_PLUS | FL_SPACE)))
448 {
449 /* Need space for sign */
450 nchars++;
451 }
452 if ((flags & FL_HASH) && base == 16)
453 {
454 /* Add 0x for hex */
455 nchars += 2;
456 }
457
458 /* Emit early space padding */
459 if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars)
460 {
461 while (width > nchars)
462 {
463 EMIT(' ');
464 width--;
465 }
466 }
467
468 /* Emit nondigits */
469 if (minus)
470 {
471 EMIT('-');
472 }
473 else if (flags & FL_PLUS)
474 {
475 EMIT('+');
476 }
477 else if (flags & FL_SPACE)
478 {
479 EMIT(' ');
480 }
481
482 if ((flags & FL_HASH) && base == 16)
483 {
484 EMIT('0');
485 EMIT((flags & FL_UPPER) ? 'X' : 'x');
486 }
487
488 /* Emit zero padding */
489 if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits)
490 {
491 while (width > nchars)
492 {
493 EMIT('0');
494 width--;
495 }
496 }
497
498 /* Generate the number. This is done from right to left. */
499 /* Advance the pointer to end of number */
500 q += ndigits;
501 o += ndigits;
502 /* Temporary values */
503 qq = q;
504 oo = o;
505
506 tmpval = (uintmax_t)fabs(val);
507 if (!prec)
508 {
509 /* round up if no additional digits */
510 if (fabs(val) - tmpval >= 0.5)
511 {
512 tmpval++;
513 }
514 }
515 while (ndigits > 0)
516 {
517 qq--;
518 oo--;
519 ndigits--;
520 if (oo < n)
521 {
522 *qq = digits[tmpval % base];
523 }
524 tmpval /= base;
525 }
526
527 if (prec)
528 {
529 EMIT('.');
530
531 q += prec;
532 o += prec;
533 qq = q;
534 oo = o;
535
536 tmpval = (uintmax_t)(fabs(val) * pow(base, prec));
537 /* round up if required */
538 if (fabs(val) * pow(base, prec) - tmpval >= 0.5)
539 {
540 tmpval++;
541 }
542 while (prec > 0)
543 {
544 qq--;
545 oo--;
546 prec--;
547 if (oo < n)
548 {
549 *qq = digits[tmpval % base];
550 }
551 tmpval /= base;
552 }
553 }
554
555 /* Emit late space padding */
556 while ((flags & FL_MINUS) && width > nchars)
557 {
558 EMIT(' ');
559 width--;
560 }
561
562 return o;
563 }
564
565 int builtin_vsnprintf(char *buffer, size_t n, const char *format, va_list ap)
566 {
567 const char *p = format;
568 char ch;
569 char *q = buffer;
570 /* Number of characters output */
571 size_t o = 0;
572 uintmax_t val = 0;
573 /* Default rank */
574 int rank = RNK_INT;
575 int width = 0;
576 int prec = -1;
577 int base;
578 size_t sz;
579 bpf_flag_t flags = 0;
580 bpf_state_t state = ST_NORMAL;
581 /* %s string argument */
582 const char *sarg;
583 /* %c char argument */
584 char carg;
585 /* String length */
586 int slen;
587
588 while ((ch = *p++))
589 {
590 switch (state)
591 {
592 case ST_NORMAL:
593 {
594 if (ch == '%')
595 {
596 state = ST_FLAGS;
597 flags = 0;
598 rank = RNK_INT;
599 width = 0;
600 prec = -1;
601 }
602 else
603 {
604 EMIT(ch);
605 }
606 break;
607 }
608 case ST_FLAGS:
609 {
610 switch (ch)
611 {
612 case '-':
613 flags |= FL_MINUS;
614 break;
615 case '+':
616 flags |= FL_PLUS;
617 break;
618 case '\'':
619 flags |= FL_TICK;
620 break;
621 case ' ':
622 flags |= FL_SPACE;
623 break;
624 case '#':
625 flags |= FL_HASH;
626 break;
627 case '0':
628 flags |= FL_ZERO;
629 break;
630 default:
631 state = ST_WIDTH;
632 /* Process this character again */
633 p--;
634 break;
635 }
636 break;
637 }
638 case ST_WIDTH:
639 {
640 if (ch >= '0' && ch <= '9')
641 {
642 width = width * 10 + (ch - '0');
643 }
644 else if (ch == '*')
645 {
646 width = va_arg(ap, int);
647 if (width < 0)
648 {
649 width = -width;
650 flags |= FL_MINUS;
651 }
652 }
653 else if (ch == '.')
654 {
655 /* Precision given */
656 prec = 0;
657 state = ST_PREC;
658 }
659 else
660 {
661 state = ST_MODIFIERS;
662 /* Process this character again */
663 p--;
664 }
665 break;
666 }
667 case ST_PREC:
668 {
669 if (ch >= '0' && ch <= '9')
670 {
671 prec = prec * 10 + (ch - '0');
672 }
673 else if (ch == '*')
674 {
675 prec = va_arg(ap, int);
676 if (prec < 0)
677 {
678 prec = -1;
679 }
680 }
681 else
682 {
683 state = ST_MODIFIERS;
684 /* Process this character again */
685 p--;
686 }
687 break;
688 }
689 case ST_MODIFIERS:
690 {
691 switch (ch)
692 {
693 /* Length modifiers - nonterminal sequences */
694 case 'h':
695 rank--;
696 break;
697 case 'l':
698 rank++;
699 break;
700 case 'j':
701 rank = RNK_INTMAX;
702 break;
703 case 'z':
704 rank = RNK_SIZE_T;
705 break;
706 case 't':
707 rank = RNK_PTRDIFF_T;
708 break;
709 case 'L':
710 case 'q':
711 rank += 2;
712 break;
713 default:
714 {
715 /* Output modifiers - terminal sequences */
716
717 /* Next state will be normal */
718 state = ST_NORMAL;
719
720 /* Canonicalize rank */
721 if (rank < RNK_MIN)
722 {
723 rank = RNK_MIN;
724 }
725 else if (rank > RNK_MAX)
726 {
727 rank = RNK_MAX;
728 }
729
730 switch (ch)
731 {
732 case 'p':
733 {
734 /* Pointer */
735 base = 16;
736 prec = (CHAR_BIT*sizeof(void *)+3)/4;
737 flags |= FL_HASH;
738 val = (uintmax_t)(uintptr_t)
739 va_arg(ap, void *);
740 goto is_integer;
741 }
742 case 'd':
743 case 'i':
744 {
745 /* Signed decimal output */
746 base = 10;
747 flags |= FL_SIGNED;
748 switch (rank)
749 {
750 case RNK_CHAR:
751 /* Yes, all these casts are
752 needed... */
753 val = (uintmax_t)(intmax_t)(signed char)
754 va_arg(ap, signed int);
755 break;
756 case RNK_SHORT:
757 val = (uintmax_t)(intmax_t)(signed short)
758 va_arg(ap, signed int);
759 break;
760 case RNK_INT:
761 val = (uintmax_t)(intmax_t)
762 va_arg(ap, signed int);
763 break;
764 case RNK_LONG:
765 val = (uintmax_t)(intmax_t)
766 va_arg(ap, signed long);
767 break;
768 case RNK_LONGLONG:
769 val = (uintmax_t)(intmax_t)
770 va_arg(ap, signed long long);
771 break;
772 }
773 goto is_integer;
774 }
775 case 'o':
776 {
777 /* Octal */
778 base = 8;
779 goto is_unsigned;
780 }
781 case 'u':
782 {
783 /* Unsigned decimal */
784 base = 10;
785 goto is_unsigned;
786 }
787 case 'X':
788 {
789 /* Upper case hexadecimal */
790 flags |= FL_UPPER;
791 /* fall through */
792 }
793 case 'x':
794 {
795 /* Hexadecimal */
796 base = 16;
797 goto is_unsigned;
798 }
799 is_unsigned:
800 {
801 switch (rank) {
802 case RNK_CHAR:
803 val = (uintmax_t)(unsigned char)
804 va_arg(ap, unsigned int);
805 break;
806 case RNK_SHORT:
807 val = (uintmax_t)(unsigned short)
808 va_arg(ap, unsigned int);
809 break;
810 case RNK_INT:
811 val = (uintmax_t)
812 va_arg(ap, unsigned int);
813 break;
814 case RNK_LONG:
815 val = (uintmax_t)
816 va_arg(ap, unsigned long);
817 break;
818 case RNK_LONGLONG:
819 val = (uintmax_t)
820 va_arg(ap, unsigned long long);
821 break;
822 }
823 goto is_integer;
824 }
825 is_integer:
826 {
827 sz = format_int(q, (o < n) ? n - o : 0,
828 val, flags, base, width, prec);
829 q += sz;
830 o += sz;
831 break;
832 }
833 case 'c':
834 {
835 /* Character */
836 carg = (char)va_arg(ap, int);
837 sarg = &carg;
838 slen = 1;
839 goto is_string;
840 }
841 case 's':
842 {
843 /* String */
844 sarg = va_arg(ap, const char *);
845 sarg = sarg ? sarg : "(null)";
846 slen = strlen(sarg);
847 goto is_string;
848 }
849 case 'm':
850 {
851 /* glibc error string */
852 sarg = strerror(errno);
853 slen = strlen(sarg);
854 goto is_string;
855 }
856 is_string:
857 {
858 char sch;
859 int i;
860
861 if (prec != -1 && slen > prec)
862 {
863 slen = prec;
864 }
865
866 if (width > slen && !(flags & FL_MINUS))
867 {
868 char pad = (flags & FL_ZERO) ? '0' : ' ';
869 while (width > slen)
870 {
871 EMIT(pad);
872 width--;
873 }
874 }
875 for (i = slen; i; i--)
876 {
877 sch = *sarg++;
878 EMIT(sch);
879 }
880 if (width > slen && (flags & FL_MINUS))
881 {
882 while (width > slen)
883 {
884 EMIT(' ');
885 width--;
886 }
887 }
888 break;
889 }
890 case 'A':
891 {
892 base = 16;
893 flags |= FL_UPPER;
894 goto is_double;
895 }
896 case 'E':
897 case 'G':
898 {
899 /* currently not supported, fall */
900 }
901 case 'F':
902 {
903 base = 10;
904 flags |= FL_UPPER;
905 goto is_double;
906 }
907 case 'a':
908 {
909 base = 16;
910 goto is_double;
911 }
912 case 'e':
913 case 'g':
914 {
915 /* currently not supported, fall */
916 }
917 case 'f':
918 {
919 base = 10;
920 goto is_double;
921 }
922 is_double:
923 {
924 double dval;
925
926 dval = va_arg(ap, double);
927 if (isinf(dval))
928 {
929 if (isgreater(dval, 0.0))
930 {
931 sarg = flags & FL_UPPER ? "INF" : "inf";
932 }
933 else
934 {
935 sarg = flags & FL_UPPER ? "-INF" : "-inf";
936 }
937 slen = strlen(sarg);
938 goto is_string;
939 }
940 if (isnan(dval))
941 {
942 sarg = flags & FL_UPPER ? "NAN" : "nan";
943 slen = strlen(sarg);
944 goto is_string;
945 }
946 sz = format_double(q, (o < n) ? n - o : 0,
947 dval, flags, base, width, prec);
948 q += sz;
949 o += sz;
950 break;
951 }
952 case 'n':
953 {
954 /* Output the number of characters written */
955 switch (rank)
956 {
957 case RNK_CHAR:
958 *va_arg(ap, signed char *) = o;
959 break;
960 case RNK_SHORT:
961 *va_arg(ap, signed short *) = o;
962 break;
963 case RNK_INT:
964 *va_arg(ap, signed int *) = o;
965 break;
966 case RNK_LONG:
967 *va_arg(ap, signed long *) = o;
968 break;
969 case RNK_LONGLONG:
970 *va_arg(ap, signed long long *) = o;
971 break;
972 }
973 break;
974 }
975 default:
976 {
977 printf_hook_handler_t *handler;
978
979 handler = hooks->get(hooks, (void*)(uintptr_t)ch);
980 if (handler)
981 {
982 const void *args[ARGS_MAX];
983 int i, iargs[ARGS_MAX];
984 void *pargs[ARGS_MAX];
985 printf_hook_spec_t spec = {
986 .hash = flags & FL_HASH,
987 .plus = flags & FL_PLUS,
988 .minus = flags & FL_MINUS,
989 .width = width,
990 };
991 printf_hook_data_t data = {
992 .q = q,
993 .n = (o < n) ? n - o : 0,
994 };
995
996 for (i = 0; i < handler->numargs; i++)
997 {
998 switch (handler->argtypes[i])
999 {
1000 case PRINTF_HOOK_ARGTYPE_INT:
1001 iargs[i] = va_arg(ap, int);
1002 args[i] = &iargs[i];
1003 break;
1004 case PRINTF_HOOK_ARGTYPE_POINTER:
1005 pargs[i] = va_arg(ap, void*);
1006 args[i] = &pargs[i];
1007 break;
1008 }
1009 }
1010 sz = handler->hook(&data, &spec, args);
1011 q += sz;
1012 o += sz;
1013 }
1014 else
1015 {
1016 /* Anything else, including % */
1017 EMIT(ch);
1018 }
1019 break;
1020 }
1021 }
1022 }
1023 }
1024 }
1025 }
1026 }
1027
1028 /* Null-terminate the string */
1029 if (o < n)
1030 {
1031 /* No overflow */
1032 *q = '\0';
1033 }
1034 else if (n > 0)
1035 {
1036 /* Overflow - terminate at end of buffer */
1037 buffer[n - 1] = '\0';
1038 }
1039 return o;
1040 }
1041
1042 int builtin_printf(const char *format, ...)
1043 {
1044 int written;
1045 va_list args;
1046
1047 va_start(args, format);
1048 written = builtin_vprintf(format, args);
1049 va_end(args);
1050
1051 return written;
1052 }
1053
1054 int builtin_fprintf(FILE *stream, const char *format, ...)
1055 {
1056 int written;
1057 va_list args;
1058
1059 va_start(args, format);
1060 written = builtin_vfprintf(stream, format, args);
1061 va_end(args);
1062
1063 return written;
1064 }
1065
1066 int builtin_sprintf(char *str, const char *format, ...)
1067 {
1068 int written;
1069 va_list args;
1070
1071 va_start(args, format);
1072 written = builtin_vsnprintf(str, ~(size_t)0, format, args);
1073 va_end(args);
1074
1075 return written;
1076 }
1077
1078 int builtin_snprintf(char *str, size_t size, const char *format, ...)
1079 {
1080 int written;
1081 va_list args;
1082
1083 va_start(args, format);
1084 written = builtin_vsnprintf(str, size, format, args);
1085 va_end(args);
1086
1087 return written;
1088 }
1089
1090 int builtin_asprintf(char **str, const char *format, ...)
1091 {
1092 int written;
1093 va_list args;
1094
1095 va_start(args, format);
1096 written = builtin_vasprintf(str, format, args);
1097 va_end(args);
1098
1099 return written;
1100 }
1101
1102 int builtin_vprintf(const char *format, va_list ap)
1103 {
1104 return builtin_vfprintf(stdout, format, ap);
1105 }
1106
1107 int builtin_vfprintf(FILE *stream, const char *format, va_list ap)
1108 {
1109 char buf[PRINTF_BUF_LEN];
1110 int len;
1111
1112 len = builtin_vsnprintf(buf, sizeof(buf), format, ap);
1113 return fwrite(buf, 1, len, stream);
1114 }
1115
1116 int builtin_vsprintf(char *str, const char *format, va_list ap)
1117 {
1118 return builtin_vsnprintf(str, ~(size_t)0, format, ap);
1119 }
1120
1121 int builtin_vasprintf(char **str, const char *format, va_list ap)
1122 {
1123 char buf[PRINTF_BUF_LEN];
1124 int len;
1125
1126 len = builtin_vsnprintf(buf, sizeof(buf), format, ap);
1127 *str = strdup(buf);
1128 return len;
1129 }
1130
1131 METHOD(printf_hook_t, destroy, void,
1132 private_printf_hook_t *this)
1133 {
1134 enumerator_t *enumerator;
1135 printf_hook_handler_t *handler;
1136
1137 enumerator = hooks->create_enumerator(hooks);
1138 while (enumerator->enumerate(enumerator, NULL, &handler))
1139 {
1140 free(handler);
1141 }
1142 enumerator->destroy(enumerator);
1143
1144 hooks->destroy(hooks);
1145
1146 free(this);
1147 }
1148
1149 /*
1150 * see header file
1151 */
1152 printf_hook_t *printf_hook_create()
1153 {
1154 private_printf_hook_t *this;
1155
1156 INIT(this,
1157 .public = {
1158 .add_handler = _add_handler,
1159 .destroy = _destroy,
1160 },
1161 );
1162
1163 hooks = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 8);
1164
1165 return &this->public;
1166 }