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