From 9873ce28d0dd486c65d17c8913a736e5ca46b2ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Thu, 28 Feb 2013 08:41:51 -0500 Subject: [PATCH] libwinpr-utils: experiment with printf replacement --- libfreerdp/primitives/CMakeLists.txt | 2 +- winpr/libwinpr/utils/test/CMakeLists.txt | 1 + winpr/libwinpr/utils/test/TestPrint.c | 359 +++++++++++++++++++++++ 3 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 winpr/libwinpr/utils/test/TestPrint.c diff --git a/libfreerdp/primitives/CMakeLists.txt b/libfreerdp/primitives/CMakeLists.txt index e8d1a7bfb..807a46835 100644 --- a/libfreerdp/primitives/CMakeLists.txt +++ b/libfreerdp/primitives/CMakeLists.txt @@ -101,6 +101,6 @@ endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") if(BUILD_TESTING AND ((NOT WIN32) AND (NOT APPLE))) - add_subdirectory(test) +# add_subdirectory(test) endif() diff --git a/winpr/libwinpr/utils/test/CMakeLists.txt b/winpr/libwinpr/utils/test/CMakeLists.txt index 07f7e589e..cf967be4b 100644 --- a/winpr/libwinpr/utils/test/CMakeLists.txt +++ b/winpr/libwinpr/utils/test/CMakeLists.txt @@ -6,6 +6,7 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS TestQueue.c + TestPrint.c TestArrayList.c TestCmdLine.c TestMessageQueue.c diff --git a/winpr/libwinpr/utils/test/TestPrint.c b/winpr/libwinpr/utils/test/TestPrint.c new file mode 100644 index 000000000..e27a46b2b --- /dev/null +++ b/winpr/libwinpr/utils/test/TestPrint.c @@ -0,0 +1,359 @@ + +#include +#include +#include + +#include +#include +#include + +int wprintfx(const char *fmt, ...); + +int TestPrint(int argc, char* argv[]) +{ + wprintfx("this %s a test: %d\n", "is", 65); + + return 0; +} + +/*---------------------------------------------------------------------------- +Stripped-down printf() +Chris Giese http://my.execpc.com/~geezer +Release date: Feb 3, 2008 +This code is public domain (no copyright). +You can do whatever you want with it. + +%[flag][width][.prec][mod][conv] +flag: - left justify, pad right w/ blanks DONE + 0 pad left w/ 0 for numerics DONE + + always print sign, + or - no + ' ' (blank) no + # (???) no + +width: (field width) DONE + +prec: (precision) no + +conv: d,i decimal int DONE + u decimal unsigned DONE + o octal DONE + x,X hex DONE + f,e,g,E,G float no + c char DONE + s string DONE + p ptr DONE + +mod: N near ptr DONE + F far ptr no + h short (16-bit) int DONE + l long (32-bit) int DONE + L long long (64-bit) int no +----------------------------------------------------------------------------*/ +#include /* strlen() */ + +/* flags used in processing format string */ +#define PR_LJ 0x01 /* left justify */ +#define PR_CA 0x02 /* use A-F instead of a-f for hex */ +#define PR_SG 0x04 /* signed numeric conversion (%d vs. %u) */ +#define PR_32 0x08 /* long (32-bit) numeric conversion */ +#define PR_16 0x10 /* short (16-bit) numeric conversion */ +#define PR_WS 0x20 /* PR_SG set and num was < 0 */ +#define PR_LZ 0x40 /* pad left with '0' instead of ' ' */ +#define PR_FP 0x80 /* pointers are far */ + +/* largest number handled is 2^32-1, lowest radix handled is 8. +2^32-1 in base 8 has 11 digits (add 5 for trailing NUL and for slop) */ +#define PR_BUFLEN 16 + +typedef int (*fnptr_t)(unsigned c, void **helper); +/***************************************************************************** +name: do_printf +action: minimal subfunction for ?printf, calls function + 'fn' with arg 'ptr' for each character to be output +returns:total number of characters output +*****************************************************************************/ +int do_printf(const char *fmt, va_list args, fnptr_t fn, void *ptr) +{ + unsigned flags, actual_wd, count, given_wd; + unsigned char *where, buf[PR_BUFLEN]; + unsigned char state, radix; + long num; + + state = flags = count = given_wd = 0; +/* begin scanning format specifier list */ + for (; *fmt; fmt++) + { + switch (state) + { +/* STATE 0: AWAITING % */ + case 0: + if (*fmt != '%') /* not %... */ + { + fn(*fmt, &ptr); /* ...just echo it */ + count++; + break; + } +/* found %, get next char and advance state to check if next char is a flag */ + state++; + fmt++; + /* FALL THROUGH */ +/* STATE 1: AWAITING FLAGS (%-0) */ + case 1: + if (*fmt == '%') /* %% */ + { + fn(*fmt, &ptr); + count++; + state = flags = given_wd = 0; + break; + } + if (*fmt == '-') + { + if (flags & PR_LJ)/* %-- is illegal */ + state = flags = given_wd = 0; + else + flags |= PR_LJ; + break; + } +/* not a flag char: advance state to check if it's field width */ + state++; +/* check now for '%0...' */ + if (*fmt == '0') + { + flags |= PR_LZ; + fmt++; + } + /* FALL THROUGH */ +/* STATE 2: AWAITING (NUMERIC) FIELD WIDTH */ + case 2: + if (*fmt >= '0' && *fmt <= '9') + { + given_wd = 10 * given_wd + (*fmt - '0'); + break; + } +/* not field width: advance state to check if it's a modifier */ + state++; + /* FALL THROUGH */ +/* STATE 3: AWAITING MODIFIER CHARS (FNlh) */ + case 3: + if (*fmt == 'F') + { + flags |= PR_FP; + break; + } + if (*fmt == 'N') + break; + if (*fmt == 'l') + { + flags |= PR_32; + break; + } + if (*fmt == 'h') + { + flags |= PR_16; + break; + } +/* not modifier: advance state to check if it's a conversion char */ + state++; + /* FALL THROUGH */ +/* STATE 4: AWAITING CONVERSION CHARS (Xxpndiuocs) */ + case 4: + where = buf + PR_BUFLEN - 1; + *where = '\0'; + switch (*fmt) + { + case 'X': + flags |= PR_CA; + /* FALL THROUGH */ +/* xxx - far pointers (%Fp, %Fn) not yet supported */ + case 'x': + case 'p': + case 'n': + radix = 16; + goto DO_NUM; + case 'd': + case 'i': + flags |= PR_SG; + /* FALL THROUGH */ + case 'u': + radix = 10; + goto DO_NUM; + case 'o': + radix = 8; +/* load the value to be printed. l=long=32 bits: */ +DO_NUM: if (flags & PR_32) + num = va_arg(args, unsigned long); +/* h=short=16 bits (signed or unsigned) */ + else if (flags & PR_16) + { + if (flags & PR_SG) + num = (short) va_arg(args, int); + else + num = (unsigned short) va_arg(args, int); + } +/* no h nor l: sizeof(int) bits (signed or unsigned) */ + else + { + if (flags & PR_SG) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + } +/* take care of sign */ + if (flags & PR_SG) + { + if (num < 0) + { + flags |= PR_WS; + num = -num; + } + } +/* convert binary to octal/decimal/hex ASCII +OK, I found my mistake. The math here is _always_ unsigned */ + do + { + unsigned long temp; + + temp = (unsigned long)num % radix; + where--; + if (temp < 10) + *where = temp + '0'; + else if (flags & PR_CA) + *where = temp - 10 + 'A'; + else + *where = temp - 10 + 'a'; + num = (unsigned long)num / radix; + } + while (num != 0); + goto EMIT; + case 'c': +/* disallow pad-left-with-zeroes for %c */ + flags &= ~PR_LZ; + where--; + *where = (unsigned char) va_arg(args, int); + actual_wd = 1; + goto EMIT2; + case 's': +/* disallow pad-left-with-zeroes for %s */ + flags &= ~PR_LZ; + where = va_arg(args, unsigned char*); +EMIT: + actual_wd = strlen((char*) where); + if (flags & PR_WS) + actual_wd++; +/* if we pad left with ZEROES, do the sign now */ + if ((flags & (PR_WS | PR_LZ)) == (PR_WS | PR_LZ)) + { + fn('-', &ptr); + count++; + } +/* pad on left with spaces or zeroes (for right justify) */ +EMIT2: if ((flags & PR_LJ) == 0) + { + while (given_wd > actual_wd) + { + fn((flags & PR_LZ) ? '0' : ' ', &ptr); + count++; + given_wd--; + } + } +/* if we pad left with SPACES, do the sign now */ + if ((flags & (PR_WS | PR_LZ)) == PR_WS) + { + fn('-', &ptr); + count++; + } +/* emit string/char/converted number */ + while (*where != '\0') + { + fn(*where++, &ptr); + count++; + } +/* pad on right with spaces (for left justify) */ + if (given_wd < actual_wd) + given_wd = 0; + else given_wd -= actual_wd; + for (; given_wd; given_wd--) + { + fn(' ', &ptr); + count++; + } + break; + default: + break; + } + default: + state = flags = given_wd = 0; + break; + } + } + return count; +} + +/***************************************************************************** +SPRINTF +*****************************************************************************/ +static int vsprintf_help(unsigned c, void **ptr) +{ + char *dst; + + dst = *ptr; + *dst++ = (char) c; + *ptr = dst; + + return 0; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int status; + + status = do_printf(fmt, args, vsprintf_help, (void*) buf); + buf[status] = '\0'; + + return status; +} + +static int discard(unsigned c_UNUSED, void **ptr_UNUSED) +{ + return 0; +} + +int sprintf(char *buf, const char *fmt, ...) +{ + va_list args; + int status; + + va_start(args, fmt); + + if (!buf) + status = do_printf(fmt, args, discard, NULL); + else + status = vsprintf(buf, fmt, args); + + va_end(args); + + return status; +} + +int vprintf_help(unsigned c, void **ptr_UNUSED) +{ + putchar(c); + return 0; +} + +int vprintf(const char *fmt, va_list args) +{ + return do_printf(fmt, args, vprintf_help, NULL); +} + +int wprintfx(const char *fmt, ...) +{ + va_list args; + int status; + + va_start(args, fmt); + status = vprintf(fmt, args); + va_end(args); + + return status; +}