Return to printf_hook_builtin.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / utils / printf_hook |
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: }