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