2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
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>.
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
17 * Copyright (C) 2002-2006 H. Peter Anvin
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:
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
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
38 #include "printf_hook.h"
40 #include <utils/utils.h>
41 #include <utils/debug.h>
42 #include <collections/hashtable.h>
52 #define PRINTF_BUF_LEN 8192
55 typedef struct private_printf_hook_t private_printf_hook_t
;
56 typedef struct printf_hook_handler_t printf_hook_handler_t
;
59 * private data of printf_hook
61 struct private_printf_hook_t
{
70 * struct with information about a registered handler
72 struct printf_hook_handler_t
{
77 printf_hook_function_t hook
;
85 * types of the arguments
87 int argtypes
[ARGS_MAX
];
91 * Data to pass to a printf hook.
93 struct printf_hook_data_t
{
101 * Remaining bytes in q
107 * Registered hooks (char => printf_hook_handler_t)
109 static hashtable_t
*hooks
;
112 * builtin-printf variant of print_in_hook()
114 size_t print_in_hook(printf_hook_data_t
*data
, char *fmt
, ...)
120 written
= builtin_vsnprintf(data
->q
, data
->n
, fmt
, args
);
123 if (written
> data
->n
)
136 METHOD(printf_hook_t
, add_handler
, void,
137 private_printf_hook_t
*this, char spec
, printf_hook_function_t hook
, ...)
141 printf_hook_handler_t
*handler
;
142 printf_hook_argtype_t argtype
;
149 va_start(args
, hook
);
152 argtype
= va_arg(args
, printf_hook_argtype_t
);
154 if (argtype
== PRINTF_HOOK_ARGTYPE_END
)
158 if (++i
>= countof(handler
->argtypes
))
160 DBG1(DBG_LIB
, "Too many arguments for printf hook with "
161 "specifier '%c', not registered!", spec
);
165 handler
->argtypes
[i
] = argtype
;
169 handler
->numargs
= i
+ 1;
170 if (!failed
&& handler
->numargs
> 0)
172 free(hooks
->put(hooks
, (void*)(uintptr_t)spec
, handler
));
181 * Printf format modifier flags
195 * Size of format string arguments
204 RNK_INTMAX
= RNK_LONGLONG
,
205 RNK_SIZE_T
= RNK_LONG
,
206 RNK_PTRDIFF_T
= RNK_LONG
,
209 RNK_MAX
= RNK_LONGLONG
,
213 * Printf specifier Parser state
222 /* Field precision */
224 /* Length or conversion modifiers */
228 #define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })
230 static const char lcdigits
[] = "0123456789abcdef";
231 static const char ucdigits
[] = "0123456789ABCDEF";
234 * Write an integer argument to q, using flags, base, width and precision
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
)
244 int ndigits
= 0, nchars
;
245 int tickskip
, b4tick
;
247 /* Select type of digits */
248 digits
= (flags
& FL_UPPER
) ? ucdigits
: lcdigits
;
250 /* If signed, separate out the minus */
251 if (flags
& FL_SIGNED
&& (intmax_t) val
< 0)
254 val
= (uintmax_t) (-(intmax_t) val
);
257 /* Count the number of digits needed. This returns zero for 0. */
265 /* Adjust ndigits for size of output */
266 if (flags
& FL_HASH
&& base
== 8)
268 if (prec
< ndigits
+ 1)
276 /* Mandatory number padding */
281 /* Zero still requires space */
285 /* For ', figure out what the skip should be */
303 /* Tick marks aren't digits, but generated by the number converter */
304 ndigits
+= (ndigits
- 1) / tickskip
;
306 /* Now compute the number of nondigits */
309 if (minus
|| (flags
& (FL_PLUS
| FL_SPACE
)))
311 /* Need space for sign */
314 if ((flags
& FL_HASH
) && base
== 16)
320 /* Emit early space padding */
321 if (!(flags
& (FL_MINUS
| FL_ZERO
)) && width
> nchars
)
323 while (width
> nchars
)
335 else if (flags
& FL_PLUS
)
339 else if (flags
& FL_SPACE
)
344 if ((flags
& FL_HASH
) && base
== 16)
347 EMIT((flags
& FL_UPPER
) ?
'X' : 'x');
350 /* Emit zero padding */
351 if ((flags
& (FL_MINUS
| FL_ZERO
)) == FL_ZERO
&& width
> ndigits
)
353 while (width
> nchars
)
360 /* Generate the number. This is done from right to left. */
361 /* Advance the pointer to end of number */
364 /* Temporary values */
380 b4tick
= tickskip
- 1;
387 *qq
= digits
[val
% base
];
392 /* Emit late space padding */
393 while ((flags
& FL_MINUS
) && width
> nchars
)
403 * Write an double argument to q, using flags, base, width and precision
405 static size_t format_double(char *q
, size_t n
, double val
, bpf_flag_t flags
,
406 int base
, int width
, int prec
)
413 int ndigits
= 0, nchars
;
415 /* Select type of digits */
416 digits
= (flags
& FL_UPPER
) ? ucdigits
: lcdigits
;
420 /* default precision */
428 tmpval
= (uintmax_t)fabs(val
);
439 /* Now compute the number of nondigits */
444 /* Space for decimal-point and digits after that */
447 if (minus
|| (flags
& (FL_PLUS
| FL_SPACE
)))
449 /* Need space for sign */
452 if ((flags
& FL_HASH
) && base
== 16)
458 /* Emit early space padding */
459 if (!(flags
& (FL_MINUS
| FL_ZERO
)) && width
> nchars
)
461 while (width
> nchars
)
473 else if (flags
& FL_PLUS
)
477 else if (flags
& FL_SPACE
)
482 if ((flags
& FL_HASH
) && base
== 16)
485 EMIT((flags
& FL_UPPER
) ?
'X' : 'x');
488 /* Emit zero padding */
489 if ((flags
& (FL_MINUS
| FL_ZERO
)) == FL_ZERO
&& width
> ndigits
)
491 while (width
> nchars
)
498 /* Generate the number. This is done from right to left. */
499 /* Advance the pointer to end of number */
502 /* Temporary values */
506 tmpval
= (uintmax_t)fabs(val
);
509 /* round up if no additional digits */
510 if (fabs(val
) - tmpval
>= 0.5)
522 *qq
= digits
[tmpval
% base
];
536 tmpval
= (uintmax_t)(fabs(val
) * pow(base
, prec
));
537 /* round up if required */
538 if (fabs(val
) * pow(base
, prec
) - tmpval
>= 0.5)
549 *qq
= digits
[tmpval
% base
];
555 /* Emit late space padding */
556 while ((flags
& FL_MINUS
) && width
> nchars
)
565 int builtin_vsnprintf(char *buffer
, size_t n
, const char *format
, va_list ap
)
567 const char *p
= format
;
570 /* Number of characters output */
579 bpf_flag_t flags
= 0;
580 bpf_state_t state
= ST_NORMAL
;
581 /* %s string argument */
583 /* %c char argument */
632 /* Process this character again */
640 if (ch
>= '0' && ch
<= '9')
642 width
= width
* 10 + (ch
- '0');
646 width
= va_arg(ap
, int);
655 /* Precision given */
661 state
= ST_MODIFIERS
;
662 /* Process this character again */
669 if (ch
>= '0' && ch
<= '9')
671 prec
= prec
* 10 + (ch
- '0');
675 prec
= va_arg(ap
, int);
683 state
= ST_MODIFIERS
;
684 /* Process this character again */
693 /* Length modifiers - nonterminal sequences */
707 rank
= RNK_PTRDIFF_T
;
715 /* Output modifiers - terminal sequences */
717 /* Next state will be normal */
720 /* Canonicalize rank */
725 else if (rank
> RNK_MAX
)
736 prec
= (CHAR_BIT
*sizeof(void *)+3)/4;
738 val
= (uintmax_t)(uintptr_t)
745 /* Signed decimal output */
751 /* Yes, all these casts are
753 val
= (uintmax_t)(intmax_t)(signed char)
754 va_arg(ap
, signed int);
757 val
= (uintmax_t)(intmax_t)(signed short)
758 va_arg(ap
, signed int);
761 val
= (uintmax_t)(intmax_t)
762 va_arg(ap
, signed int);
765 val
= (uintmax_t)(intmax_t)
766 va_arg(ap
, signed long);
769 val
= (uintmax_t)(intmax_t)
770 va_arg(ap
, signed long long);
783 /* Unsigned decimal */
789 /* Upper case hexadecimal */
803 val
= (uintmax_t)(unsigned char)
804 va_arg(ap
, unsigned int);
807 val
= (uintmax_t)(unsigned short)
808 va_arg(ap
, unsigned int);
812 va_arg(ap
, unsigned int);
816 va_arg(ap
, unsigned long);
820 va_arg(ap
, unsigned long long);
827 sz
= format_int(q
, (o
< n
) ? n
- o
: 0,
828 val
, flags
, base
, width
, prec
);
836 carg
= (char)va_arg(ap
, int);
844 sarg
= va_arg(ap
, const char *);
845 sarg
= sarg ? sarg
: "(null)";
851 /* glibc error string */
852 sarg
= strerror(errno
);
861 if (prec
!= -1 && slen
> prec
)
866 if (width
> slen
&& !(flags
& FL_MINUS
))
868 char pad
= (flags
& FL_ZERO
) ?
'0' : ' ';
875 for (i
= slen
; i
; i
--)
880 if (width
> slen
&& (flags
& FL_MINUS
))
899 /* currently not supported, fall */
915 /* currently not supported, fall */
926 dval
= va_arg(ap
, double);
929 if (isgreater(dval
, 0.0))
931 sarg
= flags
& FL_UPPER ?
"INF" : "inf";
935 sarg
= flags
& FL_UPPER ?
"-INF" : "-inf";
942 sarg
= flags
& FL_UPPER ?
"NAN" : "nan";
946 sz
= format_double(q
, (o
< n
) ? n
- o
: 0,
947 dval
, flags
, base
, width
, prec
);
954 /* Output the number of characters written */
958 *va_arg(ap
, signed char *) = o
;
961 *va_arg(ap
, signed short *) = o
;
964 *va_arg(ap
, signed int *) = o
;
967 *va_arg(ap
, signed long *) = o
;
970 *va_arg(ap
, signed long long *) = o
;
977 printf_hook_handler_t
*handler
;
979 handler
= hooks
->get(hooks
, (void*)(uintptr_t)ch
);
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
,
991 printf_hook_data_t data
= {
993 .n
= (o
< n
) ? n
- o
: 0,
996 for (i
= 0; i
< handler
->numargs
; i
++)
998 switch (handler
->argtypes
[i
])
1000 case PRINTF_HOOK_ARGTYPE_INT
:
1001 iargs
[i
] = va_arg(ap
, int);
1002 args
[i
] = &iargs
[i
];
1004 case PRINTF_HOOK_ARGTYPE_POINTER
:
1005 pargs
[i
] = va_arg(ap
, void*);
1006 args
[i
] = &pargs
[i
];
1010 sz
= handler
->hook(&data
, &spec
, args
);
1016 /* Anything else, including % */
1028 /* Null-terminate the string */
1036 /* Overflow - terminate at end of buffer */
1037 buffer
[n
- 1] = '\0';
1042 int builtin_printf(const char *format
, ...)
1047 va_start(args
, format
);
1048 written
= builtin_vprintf(format
, args
);
1054 int builtin_fprintf(FILE *stream
, const char *format
, ...)
1059 va_start(args
, format
);
1060 written
= builtin_vfprintf(stream
, format
, args
);
1066 int builtin_sprintf(char *str
, const char *format
, ...)
1071 va_start(args
, format
);
1072 written
= builtin_vsnprintf(str
, ~(size_t)0, format
, args
);
1078 int builtin_snprintf(char *str
, size_t size
, const char *format
, ...)
1083 va_start(args
, format
);
1084 written
= builtin_vsnprintf(str
, size
, format
, args
);
1090 int builtin_asprintf(char **str
, const char *format
, ...)
1095 va_start(args
, format
);
1096 written
= builtin_vasprintf(str
, format
, args
);
1102 int builtin_vprintf(const char *format
, va_list ap
)
1104 return builtin_vfprintf(stdout
, format
, ap
);
1107 int builtin_vfprintf(FILE *stream
, const char *format
, va_list ap
)
1109 char buf
[PRINTF_BUF_LEN
];
1112 len
= builtin_vsnprintf(buf
, sizeof(buf
), format
, ap
);
1113 return fwrite(buf
, 1, len
, stream
);
1116 int builtin_vsprintf(char *str
, const char *format
, va_list ap
)
1118 return builtin_vsnprintf(str
, ~(size_t)0, format
, ap
);
1121 int builtin_vasprintf(char **str
, const char *format
, va_list ap
)
1123 char buf
[PRINTF_BUF_LEN
];
1126 len
= builtin_vsnprintf(buf
, sizeof(buf
), format
, ap
);
1131 METHOD(printf_hook_t
, destroy
, void,
1132 private_printf_hook_t
*this)
1134 enumerator_t
*enumerator
;
1135 printf_hook_handler_t
*handler
;
1137 enumerator
= hooks
->create_enumerator(hooks
);
1138 while (enumerator
->enumerate(enumerator
, NULL
, &handler
))
1142 enumerator
->destroy(enumerator
);
1144 hooks
->destroy(hooks
);
1152 printf_hook_t
*printf_hook_create()
1154 private_printf_hook_t
*this;
1158 .add_handler
= _add_handler
,
1159 .destroy
= _destroy
,
1163 hooks
= hashtable_create(hashtable_hash_ptr
, hashtable_equals_ptr
, 8);
1165 return &this->public;