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