2 * Copyright (C) 2013 Martin Willi
4 * Copyright (C) secunet Security Networks AG
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>.
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
18 * Copyright (C) 2002-2006 H. Peter Anvin
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:
27 * The above copyright notice and this permission notice shall be included in
28 * all copies or substantial portions of the Software.
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
39 #include "printf_hook.h"
41 #include <utils/utils.h>
42 #include <utils/debug.h>
43 #include <collections/hashtable.h>
53 #define PRINTF_BUF_LEN 8192
56 typedef struct private_printf_hook_t private_printf_hook_t
;
57 typedef struct printf_hook_handler_t printf_hook_handler_t
;
60 * private data of printf_hook
62 struct private_printf_hook_t
{
71 * struct with information about a registered handler
73 struct printf_hook_handler_t
{
78 printf_hook_function_t hook
;
86 * types of the arguments
88 int argtypes
[ARGS_MAX
];
92 * Data to pass to a printf hook.
94 struct printf_hook_data_t
{
102 * Remaining bytes in q
108 * Registered hooks (char => printf_hook_handler_t)
110 static hashtable_t
*hooks
;
113 * builtin-printf variant of print_in_hook()
115 size_t print_in_hook(printf_hook_data_t
*data
, char *fmt
, ...)
121 written
= builtin_vsnprintf(data
->q
, data
->n
, fmt
, args
);
124 if (written
> data
->n
)
137 METHOD(printf_hook_t
, add_handler
, void,
138 private_printf_hook_t
*this, char spec
, printf_hook_function_t hook
, ...)
142 printf_hook_handler_t
*handler
;
143 printf_hook_argtype_t argtype
;
150 va_start(args
, hook
);
153 argtype
= va_arg(args
, printf_hook_argtype_t
);
155 if (argtype
== PRINTF_HOOK_ARGTYPE_END
)
159 if (++i
>= countof(handler
->argtypes
))
161 DBG1(DBG_LIB
, "Too many arguments for printf hook with "
162 "specifier '%c', not registered!", spec
);
166 handler
->argtypes
[i
] = argtype
;
170 handler
->numargs
= i
+ 1;
171 if (!failed
&& handler
->numargs
> 0)
173 free(hooks
->put(hooks
, (void*)(uintptr_t)spec
, handler
));
182 * Printf format modifier flags
196 * Size of format string arguments
205 RNK_INTMAX
= RNK_LONGLONG
,
206 RNK_SIZE_T
= RNK_LONG
,
207 RNK_PTRDIFF_T
= RNK_LONG
,
210 RNK_MAX
= RNK_LONGLONG
,
214 * Printf specifier Parser state
223 /* Field precision */
225 /* Length or conversion modifiers */
229 #define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })
231 static const char lcdigits
[] = "0123456789abcdef";
232 static const char ucdigits
[] = "0123456789ABCDEF";
235 * Write an integer argument to q, using flags, base, width and precision
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
)
245 int ndigits
= 0, nchars
;
246 int tickskip
, b4tick
;
248 /* Select type of digits */
249 digits
= (flags
& FL_UPPER
) ? ucdigits
: lcdigits
;
251 /* If signed, separate out the minus */
252 if (flags
& FL_SIGNED
&& (intmax_t) val
< 0)
255 val
= (uintmax_t) (-(intmax_t) val
);
258 /* Count the number of digits needed. This returns zero for 0. */
266 /* Adjust ndigits for size of output */
267 if (flags
& FL_HASH
&& base
== 8)
269 if (prec
< ndigits
+ 1)
277 /* Mandatory number padding */
282 /* Zero still requires space */
286 /* For ', figure out what the skip should be */
304 /* Tick marks aren't digits, but generated by the number converter */
305 ndigits
+= (ndigits
- 1) / tickskip
;
307 /* Now compute the number of nondigits */
310 if (minus
|| (flags
& (FL_PLUS
| FL_SPACE
)))
312 /* Need space for sign */
315 if ((flags
& FL_HASH
) && base
== 16)
321 /* Emit early space padding */
322 if (!(flags
& (FL_MINUS
| FL_ZERO
)) && width
> nchars
)
324 while (width
> nchars
)
336 else if (flags
& FL_PLUS
)
340 else if (flags
& FL_SPACE
)
345 if ((flags
& FL_HASH
) && base
== 16)
348 EMIT((flags
& FL_UPPER
) ? 'X' : 'x');
351 /* Emit zero padding */
352 if ((flags
& (FL_MINUS
| FL_ZERO
)) == FL_ZERO
&& width
> ndigits
)
354 while (width
> nchars
)
361 /* Generate the number. This is done from right to left. */
362 /* Advance the pointer to end of number */
365 /* Temporary values */
381 b4tick
= tickskip
- 1;
388 *qq
= digits
[val
% base
];
393 /* Emit late space padding */
394 while ((flags
& FL_MINUS
) && width
> nchars
)
404 * Write an double argument to q, using flags, base, width and precision
406 static size_t format_double(char *q
, size_t n
, double val
, bpf_flag_t flags
,
407 int base
, int width
, int prec
)
414 int ndigits
= 0, nchars
;
416 /* Select type of digits */
417 digits
= (flags
& FL_UPPER
) ? ucdigits
: lcdigits
;
421 /* default precision */
429 tmpval
= (uintmax_t)fabs(val
);
440 /* Now compute the number of nondigits */
445 /* Space for decimal-point and digits after that */
448 if (minus
|| (flags
& (FL_PLUS
| FL_SPACE
)))
450 /* Need space for sign */
453 if ((flags
& FL_HASH
) && base
== 16)
459 /* Emit early space padding */
460 if (!(flags
& (FL_MINUS
| FL_ZERO
)) && width
> nchars
)
462 while (width
> nchars
)
474 else if (flags
& FL_PLUS
)
478 else if (flags
& FL_SPACE
)
483 if ((flags
& FL_HASH
) && base
== 16)
486 EMIT((flags
& FL_UPPER
) ? 'X' : 'x');
489 /* Emit zero padding */
490 if ((flags
& (FL_MINUS
| FL_ZERO
)) == FL_ZERO
&& width
> ndigits
)
492 while (width
> nchars
)
499 /* Generate the number. This is done from right to left. */
500 /* Advance the pointer to end of number */
503 /* Temporary values */
507 tmpval
= (uintmax_t)fabs(val
);
510 /* round up if no additional digits */
511 if (fabs(val
) - tmpval
>= 0.5)
523 *qq
= digits
[tmpval
% base
];
537 tmpval
= (uintmax_t)(fabs(val
) * pow(base
, prec
));
538 /* round up if required */
539 if (fabs(val
) * pow(base
, prec
) - tmpval
>= 0.5)
550 *qq
= digits
[tmpval
% base
];
556 /* Emit late space padding */
557 while ((flags
& FL_MINUS
) && width
> nchars
)
566 int builtin_vsnprintf(char *buffer
, size_t n
, const char *format
, va_list ap
)
568 const char *p
= format
;
571 /* Number of characters output */
580 bpf_flag_t flags
= 0;
581 bpf_state_t state
= ST_NORMAL
;
582 /* %s string argument */
584 /* %c char argument */
633 /* Process this character again */
641 if (ch
>= '0' && ch
<= '9')
643 width
= width
* 10 + (ch
- '0');
647 width
= va_arg(ap
, int);
656 /* Precision given */
662 state
= ST_MODIFIERS
;
663 /* Process this character again */
670 if (ch
>= '0' && ch
<= '9')
672 prec
= prec
* 10 + (ch
- '0');
676 prec
= va_arg(ap
, int);
684 state
= ST_MODIFIERS
;
685 /* Process this character again */
694 /* Length modifiers - nonterminal sequences */
708 rank
= RNK_PTRDIFF_T
;
716 /* Output modifiers - terminal sequences */
718 /* Next state will be normal */
721 /* Canonicalize rank */
726 else if (rank
> RNK_MAX
)
737 prec
= (CHAR_BIT
*sizeof(void *)+3)/4;
739 val
= (uintmax_t)(uintptr_t)
746 /* Signed decimal output */
752 /* Yes, all these casts are
754 val
= (uintmax_t)(intmax_t)(signed char)
755 va_arg(ap
, signed int);
758 val
= (uintmax_t)(intmax_t)(signed short)
759 va_arg(ap
, signed int);
762 val
= (uintmax_t)(intmax_t)
763 va_arg(ap
, signed int);
766 val
= (uintmax_t)(intmax_t)
767 va_arg(ap
, signed long);
770 val
= (uintmax_t)(intmax_t)
771 va_arg(ap
, signed long long);
784 /* Unsigned decimal */
790 /* Upper case hexadecimal */
804 val
= (uintmax_t)(unsigned char)
805 va_arg(ap
, unsigned int);
808 val
= (uintmax_t)(unsigned short)
809 va_arg(ap
, unsigned int);
813 va_arg(ap
, unsigned int);
817 va_arg(ap
, unsigned long);
821 va_arg(ap
, unsigned long long);
828 sz
= format_int(q
, (o
< n
) ? n
- o
: 0,
829 val
, flags
, base
, width
, prec
);
837 carg
= (char)va_arg(ap
, int);
845 sarg
= va_arg(ap
, const char *);
846 sarg
= sarg
? sarg
: "(null)";
847 slen
= prec
!= -1 ? strnlen(sarg
, prec
)
853 /* glibc error string */
854 sarg
= strerror(errno
);
863 if (prec
!= -1 && slen
> prec
)
868 if (width
> slen
&& !(flags
& FL_MINUS
))
870 char pad
= (flags
& FL_ZERO
) ? '0' : ' ';
877 for (i
= slen
; i
; i
--)
882 if (width
> slen
&& (flags
& FL_MINUS
))
901 /* currently not supported, fall */
917 /* currently not supported, fall */
928 dval
= va_arg(ap
, double);
931 if (isgreater(dval
, 0.0))
933 sarg
= flags
& FL_UPPER
? "INF" : "inf";
937 sarg
= flags
& FL_UPPER
? "-INF" : "-inf";
944 sarg
= flags
& FL_UPPER
? "NAN" : "nan";
948 sz
= format_double(q
, (o
< n
) ? n
- o
: 0,
949 dval
, flags
, base
, width
, prec
);
956 /* Output the number of characters written */
960 *va_arg(ap
, signed char *) = o
;
963 *va_arg(ap
, signed short *) = o
;
966 *va_arg(ap
, signed int *) = o
;
969 *va_arg(ap
, signed long *) = o
;
972 *va_arg(ap
, signed long long *) = o
;
979 printf_hook_handler_t
*handler
;
981 handler
= hooks
->get(hooks
, (void*)(uintptr_t)ch
);
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
,
993 printf_hook_data_t data
= {
995 .n
= (o
< n
) ? n
- o
: 0,
998 for (i
= 0; i
< handler
->numargs
; i
++)
1000 switch (handler
->argtypes
[i
])
1002 case PRINTF_HOOK_ARGTYPE_INT
:
1003 iargs
[i
] = va_arg(ap
, int);
1004 args
[i
] = &iargs
[i
];
1006 case PRINTF_HOOK_ARGTYPE_POINTER
:
1007 pargs
[i
] = va_arg(ap
, void*);
1008 args
[i
] = &pargs
[i
];
1012 sz
= handler
->hook(&data
, &spec
, args
);
1018 /* Anything else, including % */
1030 /* Null-terminate the string */
1038 /* Overflow - terminate at end of buffer */
1039 buffer
[n
- 1] = '\0';
1044 int builtin_printf(const char *format
, ...)
1049 va_start(args
, format
);
1050 written
= builtin_vprintf(format
, args
);
1056 int builtin_fprintf(FILE *stream
, const char *format
, ...)
1061 va_start(args
, format
);
1062 written
= builtin_vfprintf(stream
, format
, args
);
1068 int builtin_sprintf(char *str
, const char *format
, ...)
1073 va_start(args
, format
);
1074 written
= builtin_vsnprintf(str
, ~(size_t)0, format
, args
);
1080 int builtin_snprintf(char *str
, size_t size
, const char *format
, ...)
1085 va_start(args
, format
);
1086 written
= builtin_vsnprintf(str
, size
, format
, args
);
1092 int builtin_asprintf(char **str
, const char *format
, ...)
1097 va_start(args
, format
);
1098 written
= builtin_vasprintf(str
, format
, args
);
1104 int builtin_vprintf(const char *format
, va_list ap
)
1106 return builtin_vfprintf(stdout
, format
, ap
);
1111 * Set TTY color on Windows consoles
1113 static void set_console_color(HANDLE handle
, int color
)
1115 CONSOLE_SCREEN_BUFFER_INFO info
;
1119 /* windows console color combination */
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
},
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
},
1143 if (GetConsoleScreenBufferInfo(handle
, &info
))
1147 info
.wAttributes
&= ~(FOREGROUND_BLUE
| FOREGROUND_GREEN
|
1148 FOREGROUND_RED
| FOREGROUND_INTENSITY
);
1152 info
.wAttributes
&= ~(BACKGROUND_BLUE
| BACKGROUND_GREEN
|
1153 BACKGROUND_RED
| BACKGROUND_INTENSITY
);
1155 for (i
= 0; i
< countof(maps
); i
++)
1157 if (maps
[i
].color
== color
)
1159 info
.wAttributes
|= maps
[i
].attributes
;
1160 SetConsoleTextAttribute(handle
, info
.wAttributes
);
1167 int builtin_vfprintf(FILE *stream
, const char *format
, va_list ap
)
1169 char buf
[PRINTF_BUF_LEN
], *pos
, *stop
;
1174 total
= len
= builtin_vsnprintf(buf
, sizeof(buf
), format
, ap
);
1175 switch (fileno(stream
))
1178 handle
= GetStdHandle(STD_OUTPUT_HANDLE
);
1181 handle
= GetStdHandle(STD_ERROR_HANDLE
);
1184 handle
= INVALID_HANDLE_VALUE
;
1187 /* GetConsoleMode fails if output redirected */
1188 if (handle
== INVALID_HANDLE_VALUE
|| !GetConsoleMode(handle
, &mode
))
1190 return fwrite(buf
, 1, len
, stream
);
1194 pos
= &buf
[total
- len
];
1197 if (pos
[0] == '\e' && pos
[1] == '[' && pos
[4] == 'm')
1199 if (isdigit(pos
[3]))
1201 if (pos
[2] == '3' || pos
[2] == '4')
1203 set_console_color(handle
,
1204 (pos
[2] - '0') * 10 + pos
[3] - '0');
1211 stop
= memchr(pos
+ 1, '\e', len
);
1220 if (clen
&& !WriteConsole(handle
, pos
, clen
, &clen
, NULL
))
1231 int builtin_vfprintf(FILE *stream
, const char *format
, va_list ap
)
1233 char buf
[PRINTF_BUF_LEN
];
1236 len
= builtin_vsnprintf(buf
, sizeof(buf
), format
, ap
);
1237 return fwrite(buf
, 1, len
, stream
);
1242 int builtin_vsprintf(char *str
, const char *format
, va_list ap
)
1244 return builtin_vsnprintf(str
, ~(size_t)0, format
, ap
);
1247 int builtin_vasprintf(char **str
, const char *format
, va_list ap
)
1249 char buf
[PRINTF_BUF_LEN
];
1252 len
= builtin_vsnprintf(buf
, sizeof(buf
), format
, ap
);
1257 METHOD(printf_hook_t
, destroy
, void,
1258 private_printf_hook_t
*this)
1260 enumerator_t
*enumerator
;
1261 printf_hook_handler_t
*handler
;
1263 enumerator
= hooks
->create_enumerator(hooks
);
1264 while (enumerator
->enumerate(enumerator
, NULL
, &handler
))
1268 enumerator
->destroy(enumerator
);
1270 hooks
->destroy(hooks
);
1278 printf_hook_t
*printf_hook_create()
1280 private_printf_hook_t
*this;
1284 .add_handler
= _add_handler
,
1285 .destroy
= _destroy
,
1289 hooks
= hashtable_create(hashtable_hash_ptr
, hashtable_equals_ptr
, 8);
1291 return &this->public;