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
)
132 METHOD(printf_hook_t
, add_handler
, void,
133 private_printf_hook_t
*this, char spec
, printf_hook_function_t hook
, ...)
137 printf_hook_handler_t
*handler
;
138 printf_hook_argtype_t argtype
;
145 va_start(args
, hook
);
148 argtype
= va_arg(args
, printf_hook_argtype_t
);
150 if (argtype
== PRINTF_HOOK_ARGTYPE_END
)
154 if (++i
>= countof(handler
->argtypes
))
156 DBG1(DBG_LIB
, "Too many arguments for printf hook with "
157 "specifier '%c', not registered!", spec
);
161 handler
->argtypes
[i
] = argtype
;
165 handler
->numargs
= i
+ 1;
166 if (!failed
&& handler
->numargs
> 0)
168 free(hooks
->put(hooks
, (void*)(uintptr_t)spec
, handler
));
177 * Printf format modifier flags
191 * Size of format string arguments
200 RNK_INTMAX
= RNK_LONGLONG
,
201 RNK_SIZE_T
= RNK_LONG
,
202 RNK_PTRDIFF_T
= RNK_LONG
,
205 RNK_MAX
= RNK_LONGLONG
,
209 * Printf specifier Parser state
218 /* Field precision */
220 /* Length or conversion modifiers */
224 #define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })
226 static const char lcdigits
[] = "0123456789abcdef";
227 static const char ucdigits
[] = "0123456789ABCDEF";
230 * Write an integer argument to q, using flags, base, width and precision
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
)
240 int ndigits
= 0, nchars
;
241 int tickskip
, b4tick
;
243 /* Select type of digits */
244 digits
= (flags
& FL_UPPER
) ? ucdigits
: lcdigits
;
246 /* If signed, separate out the minus */
247 if (flags
& FL_SIGNED
&& (intmax_t) val
< 0)
250 val
= (uintmax_t) (-(intmax_t) val
);
253 /* Count the number of digits needed. This returns zero for 0. */
261 /* Adjust ndigits for size of output */
262 if (flags
& FL_HASH
&& base
== 8)
264 if (prec
< ndigits
+ 1)
272 /* Mandatory number padding */
277 /* Zero still requires space */
281 /* For ', figure out what the skip should be */
299 /* Tick marks aren't digits, but generated by the number converter */
300 ndigits
+= (ndigits
- 1) / tickskip
;
302 /* Now compute the number of nondigits */
305 if (minus
|| (flags
& (FL_PLUS
| FL_SPACE
)))
307 /* Need space for sign */
310 if ((flags
& FL_HASH
) && base
== 16)
316 /* Emit early space padding */
317 if (!(flags
& (FL_MINUS
| FL_ZERO
)) && width
> nchars
)
319 while (width
> nchars
)
331 else if (flags
& FL_PLUS
)
335 else if (flags
& FL_SPACE
)
340 if ((flags
& FL_HASH
) && base
== 16)
343 EMIT((flags
& FL_UPPER
) ?
'X' : 'x');
346 /* Emit zero padding */
347 if ((flags
& (FL_MINUS
| FL_ZERO
)) == FL_ZERO
&& width
> ndigits
)
349 while (width
> nchars
)
356 /* Generate the number. This is done from right to left. */
357 /* Advance the pointer to end of number */
360 /* Temporary values */
376 b4tick
= tickskip
- 1;
383 *qq
= digits
[val
% base
];
388 /* Emit late space padding */
389 while ((flags
& FL_MINUS
) && width
> nchars
)
399 * Write an double argument to q, using flags, base, width and precision
401 static size_t format_double(char *q
, size_t n
, double val
, bpf_flag_t flags
,
402 int base
, int width
, int prec
)
409 int ndigits
= 0, nchars
;
411 /* Select type of digits */
412 digits
= (flags
& FL_UPPER
) ? ucdigits
: lcdigits
;
416 /* default precision */
424 tmpval
= (uintmax_t)fabs(val
);
435 /* Now compute the number of nondigits */
440 /* Space for decimal-point and digits after that */
443 if (minus
|| (flags
& (FL_PLUS
| FL_SPACE
)))
445 /* Need space for sign */
448 if ((flags
& FL_HASH
) && base
== 16)
454 /* Emit early space padding */
455 if (!(flags
& (FL_MINUS
| FL_ZERO
)) && width
> nchars
)
457 while (width
> nchars
)
469 else if (flags
& FL_PLUS
)
473 else if (flags
& FL_SPACE
)
478 if ((flags
& FL_HASH
) && base
== 16)
481 EMIT((flags
& FL_UPPER
) ?
'X' : 'x');
484 /* Emit zero padding */
485 if ((flags
& (FL_MINUS
| FL_ZERO
)) == FL_ZERO
&& width
> ndigits
)
487 while (width
> nchars
)
494 /* Generate the number. This is done from right to left. */
495 /* Advance the pointer to end of number */
498 /* Temporary values */
502 tmpval
= (uintmax_t)fabs(val
);
505 /* round up if no additional digits */
506 if (fabs(val
) - tmpval
>= 0.5)
518 *qq
= digits
[tmpval
% base
];
532 tmpval
= (uintmax_t)(fabs(val
) * pow(base
, prec
));
533 /* round up if required */
534 if (fabs(val
) * pow(base
, prec
) - tmpval
>= 0.5)
545 *qq
= digits
[tmpval
% base
];
551 /* Emit late space padding */
552 while ((flags
& FL_MINUS
) && width
> nchars
)
561 int builtin_vsnprintf(char *buffer
, size_t n
, const char *format
, va_list ap
)
563 const char *p
= format
;
566 /* Number of characters output */
575 bpf_flag_t flags
= 0;
576 bpf_state_t state
= ST_NORMAL
;
577 /* %s string argument */
579 /* %c char argument */
628 /* Process this character again */
636 if (ch
>= '0' && ch
<= '9')
638 width
= width
* 10 + (ch
- '0');
642 width
= va_arg(ap
, int);
651 /* Precision given */
657 state
= ST_MODIFIERS
;
658 /* Process this character again */
665 if (ch
>= '0' && ch
<= '9')
667 prec
= prec
* 10 + (ch
- '0');
671 prec
= va_arg(ap
, int);
679 state
= ST_MODIFIERS
;
680 /* Process this character again */
689 /* Length modifiers - nonterminal sequences */
703 rank
= RNK_PTRDIFF_T
;
711 /* Output modifiers - terminal sequences */
713 /* Next state will be normal */
716 /* Canonicalize rank */
721 else if (rank
> RNK_MAX
)
732 prec
= (CHAR_BIT
*sizeof(void *)+3)/4;
734 val
= (uintmax_t)(uintptr_t)
741 /* Signed decimal output */
747 /* Yes, all these casts are
749 val
= (uintmax_t)(intmax_t)(signed char)
750 va_arg(ap
, signed int);
753 val
= (uintmax_t)(intmax_t)(signed short)
754 va_arg(ap
, signed int);
757 val
= (uintmax_t)(intmax_t)
758 va_arg(ap
, signed int);
761 val
= (uintmax_t)(intmax_t)
762 va_arg(ap
, signed long);
765 val
= (uintmax_t)(intmax_t)
766 va_arg(ap
, signed long long);
779 /* Unsigned decimal */
785 /* Upper case hexadecimal */
799 val
= (uintmax_t)(unsigned char)
800 va_arg(ap
, unsigned int);
803 val
= (uintmax_t)(unsigned short)
804 va_arg(ap
, unsigned int);
808 va_arg(ap
, unsigned int);
812 va_arg(ap
, unsigned long);
816 va_arg(ap
, unsigned long long);
823 sz
= format_int(q
, (o
< n
) ? n
- o
: 0,
824 val
, flags
, base
, width
, prec
);
832 carg
= (char)va_arg(ap
, int);
840 sarg
= va_arg(ap
, const char *);
841 sarg
= sarg ? sarg
: "(null)";
847 /* glibc error string */
848 sarg
= strerror(errno
);
857 if (prec
!= -1 && slen
> prec
)
862 if (width
> slen
&& !(flags
& FL_MINUS
))
864 char pad
= (flags
& FL_ZERO
) ?
'0' : ' ';
871 for (i
= slen
; i
; i
--)
876 if (width
> slen
&& (flags
& FL_MINUS
))
895 /* currently not supported, fall */
911 /* currently not supported, fall */
922 dval
= va_arg(ap
, double);
925 if (isgreater(dval
, 0.0))
927 sarg
= flags
& FL_UPPER ?
"INF" : "inf";
931 sarg
= flags
& FL_UPPER ?
"-INF" : "-inf";
938 sarg
= flags
& FL_UPPER ?
"NAN" : "nan";
942 sz
= format_double(q
, (o
< n
) ? n
- o
: 0,
943 dval
, flags
, base
, width
, prec
);
950 /* Output the number of characters written */
954 *va_arg(ap
, signed char *) = o
;
957 *va_arg(ap
, signed short *) = o
;
960 *va_arg(ap
, signed int *) = o
;
963 *va_arg(ap
, signed long *) = o
;
966 *va_arg(ap
, signed long long *) = o
;
973 printf_hook_handler_t
*handler
;
975 handler
= hooks
->get(hooks
, (void*)(uintptr_t)ch
);
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
,
987 printf_hook_data_t data
= {
989 .n
= (o
< n
) ? n
- o
: 0,
992 for (i
= 0; i
< handler
->numargs
; i
++)
994 switch (handler
->argtypes
[i
])
996 case PRINTF_HOOK_ARGTYPE_INT
:
997 iargs
[i
] = va_arg(ap
, int);
1000 case PRINTF_HOOK_ARGTYPE_POINTER
:
1001 pargs
[i
] = va_arg(ap
, void*);
1002 args
[i
] = &pargs
[i
];
1006 sz
= handler
->hook(&data
, &spec
, args
);
1012 /* Anything else, including % */
1024 /* Null-terminate the string */
1032 /* Overflow - terminate at end of buffer */
1033 buffer
[n
- 1] = '\0';
1038 int builtin_printf(const char *format
, ...)
1043 va_start(args
, format
);
1044 written
= builtin_vprintf(format
, args
);
1050 int builtin_fprintf(FILE *stream
, const char *format
, ...)
1055 va_start(args
, format
);
1056 written
= builtin_vfprintf(stream
, format
, args
);
1062 int builtin_sprintf(char *str
, const char *format
, ...)
1067 va_start(args
, format
);
1068 written
= builtin_vsnprintf(str
, ~(size_t)0, format
, args
);
1074 int builtin_snprintf(char *str
, size_t size
, const char *format
, ...)
1079 va_start(args
, format
);
1080 written
= builtin_vsnprintf(str
, size
, format
, args
);
1086 int builtin_asprintf(char **str
, const char *format
, ...)
1091 va_start(args
, format
);
1092 written
= builtin_vasprintf(str
, format
, args
);
1098 int builtin_vprintf(const char *format
, va_list ap
)
1100 return builtin_vfprintf(stdout
, format
, ap
);
1103 int builtin_vfprintf(FILE *stream
, const char *format
, va_list ap
)
1105 char buf
[PRINTF_BUF_LEN
];
1108 len
= builtin_vsnprintf(buf
, sizeof(buf
), format
, ap
);
1109 return fwrite(buf
, 1, len
, stream
);
1112 int builtin_vsprintf(char *str
, const char *format
, va_list ap
)
1114 return builtin_vsnprintf(str
, ~(size_t)0, format
, ap
);
1117 int builtin_vasprintf(char **str
, const char *format
, va_list ap
)
1119 char buf
[PRINTF_BUF_LEN
];
1122 len
= builtin_vsnprintf(buf
, sizeof(buf
), format
, ap
);
1127 METHOD(printf_hook_t
, destroy
, void,
1128 private_printf_hook_t
*this)
1130 enumerator_t
*enumerator
;
1131 printf_hook_handler_t
*handler
;
1133 enumerator
= hooks
->create_enumerator(hooks
);
1134 while (enumerator
->enumerate(enumerator
, NULL
, &handler
))
1138 enumerator
->destroy(enumerator
);
1140 hooks
->destroy(hooks
);
1148 printf_hook_t
*printf_hook_create()
1150 private_printf_hook_t
*this;
1154 .add_handler
= _add_handler
,
1155 .destroy
= _destroy
,
1159 hooks
= hashtable_create(hashtable_hash_ptr
, hashtable_equals_ptr
, 8);
1161 return &this->public;