diff options
-rw-r--r-- | include/mysql/service_my_snprintf.h | 2 | ||||
-rw-r--r-- | strings/my_vsnprintf.c | 60 | ||||
-rw-r--r-- | unittest/mysys/Makefile.am | 2 | ||||
-rw-r--r-- | unittest/mysys/my_vsnprintf-t.c | 155 |
4 files changed, 166 insertions, 53 deletions
diff --git a/include/mysql/service_my_snprintf.h b/include/mysql/service_my_snprintf.h index a9f205fc4de..ad344864c34 100644 --- a/include/mysql/service_my_snprintf.h +++ b/include/mysql/service_my_snprintf.h @@ -42,7 +42,7 @@ % <flag> <width> <precision> <length modifier> <format> where everithing but the format is optional. - Three one-character flags are regognized: + Three one-character flags are recognized: '0' has the standard zero-padding semantics; '-' is parsed, but silently ignored; '`' (backtick) is only supported for strings (%s) and means that the diff --git a/strings/my_vsnprintf.c b/strings/my_vsnprintf.c index 46961058eea..ad8e7c8c776 100644 --- a/strings/my_vsnprintf.c +++ b/strings/my_vsnprintf.c @@ -260,6 +260,14 @@ static char *process_int_arg(char *to, char *end, size_t length, { size_t diff= (length- res_length); bfill(to, diff, (print_type & PREZERO_ARG) ? '0' : ' '); + if (arg_type == 'p' && print_type & PREZERO_ARG) + { + if (diff > 1) + to[1]= 'x'; + else + store_start[0]= 'x'; + store_start[1]= '0'; + } to+= diff; } bmove(to, store_start, res_length); @@ -323,6 +331,7 @@ start: /* Get print width */ if (*fmt == '*') { + fmt++; fmt= get_width(fmt, &print_arr[idx].width); print_arr[idx].width--; DBUG_ASSERT(*fmt == '$' && print_arr[idx].width < MAX_ARGS); @@ -623,54 +632,3 @@ size_t my_snprintf(char* to, size_t n, const char* fmt, ...) return result; } -#ifdef MAIN -#define OVERRUN_SENTRY 250 -static void my_printf(const char * fmt, ...) -{ - char buf[33]; - int n; - va_list ar; - va_start(ar, fmt); - buf[sizeof(buf)-1]=OVERRUN_SENTRY; - n = my_vsnprintf(buf, sizeof(buf)-1,fmt, ar); - printf(buf); - printf("n=%d, strlen=%d\n", n, strlen(buf)); - if ((uchar) buf[sizeof(buf)-1] != OVERRUN_SENTRY) - { - fprintf(stderr, "Buffer overrun\n"); - abort(); - } - va_end(ar); -} - - -int main() -{ - - my_printf("Hello\n"); - my_printf("Hello int, %d\n", 1); - my_printf("Hello string '%s'\n", "I am a string"); - my_printf("Hello hack hack hack hack hack hack hack %d\n", 1); - my_printf("Hello %d hack %d\n", 1, 4); - my_printf("Hello %d hack hack hack hack hack %d\n", 1, 4); - my_printf("Hello '%s' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n", "hack"); - my_printf("Hello hhhhhhhhhhhhhh %d sssssssssssssss\n", 1); - my_printf("Hello %u\n", 1); - my_printf("Hex: %lx '%6lx'\n", 32, 65); - my_printf("conn %ld to: '%-.64s' user: '%-.32s' host:\ - `%-.64s' (%-.64s)", 1, 0,0,0,0); - - my_printf("Hello string %`s\n", "I am a string"); - my_printf("Hello %05s\n", "TEST"); - my_printf("My %1$`-.1s test\n", "QQQQ"); - my_printf("My %1$s test done %2$s\n", "DDDD", "AAAA"); - my_printf("My %1$s test %2$s, %1$-.3s\n", "DDDD", "CCCC"); - my_printf("My %1$`-.4b test\n", "QQQQ"); - my_printf("My %1$c test\n", 'X'); - my_printf("My `%010d` test1 %4x test2 %4X\n", 10, 10, 10); - my_printf("My `%1$010d` test1 %2$4x test2 %2$4x\n", 10, 10); - my_printf("My %1$*02$d test\n", 10, 5); - my_printf("My %1$`s test %2$s, %1$`-.3s\n", "DDDD", "CCCC"); - return 0; -} -#endif diff --git a/unittest/mysys/Makefile.am b/unittest/mysys/Makefile.am index f0ffc7a6720..56c65d71396 100644 --- a/unittest/mysys/Makefile.am +++ b/unittest/mysys/Makefile.am @@ -21,7 +21,7 @@ LDADD = $(top_builddir)/unittest/mytap/libmytap.a \ $(top_builddir)/dbug/libdbug.a \ $(top_builddir)/strings/libmystrings.a -noinst_PROGRAMS = bitmap-t base64-t +noinst_PROGRAMS = bitmap-t base64-t my_vsnprintf-t if NEED_THREAD # my_atomic-t is used to check thread functions, so it is safe to diff --git a/unittest/mysys/my_vsnprintf-t.c b/unittest/mysys/my_vsnprintf-t.c new file mode 100644 index 00000000000..f3a6b5700da --- /dev/null +++ b/unittest/mysys/my_vsnprintf-t.c @@ -0,0 +1,155 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <my_global.h> +#include <m_string.h> +#include <tap.h> + +char buf[1024]; /* let's hope that's enough */ + +void test1(const char *res, const char *fmt, ...) +{ + va_list args; + size_t len; + va_start(args,fmt); + len= my_vsnprintf(buf, sizeof(buf)-1, fmt, args); + va_end(args); + ok(strlen(res) == len && strcmp(buf, res) == 0, "\"%s\"", buf); +} + +int main(void) +{ + plan(47); + + test1("Constant string", + "Constant string"); + + test1("Format specifier s works", + "Format specifier s %s", "works"); + test1("Format specifier b works (mysql extension)", + "Format specifier b %.5b (mysql extension)", "works!!!"); + test1("Format specifier c !", + "Format specifier c %c", '!'); + test1("Format specifier d 1", + "Format specifier d %d", 1); + test1("Format specifier u 2", + "Format specifier u %u", 2); + test1("Format specifier x a", + "Format specifier x %x", 10); + test1("Format specifier X B", + "Format specifier X %X", 11); + test1("Format specifier p 0x5", + "Format specifier p %p", 5); + + test1("Flag '-' is ignored < 1>", + "Flag '-' is ignored <%-4d>", 1); + test1("Flag '0' works <0006>", + "Flag '0' works <%04d>", 6); + + test1("Width is ignored for strings <x> <y>", + "Width is ignored for strings <%04s> <%5s>", "x", "y"); + + test1("Precision works for strings <abcde>", + "Precision works for strings <%.5s>", "abcdef!"); + + test1("Flag '`' (backtick) works: `abcd` `op``q` (mysql extension)", + "Flag '`' (backtick) works: %`s %`.4s (mysql extension)", + "abcd", "op`qrst"); + + test1("Length modifiers work: 1 * -1 * 2 * 3", + "Length modifiers work: %d * %ld * %lld * %zd", 1, -1L, 2LL, (size_t)3); + + test1("(null) pointer is fine", + "%s pointer is fine", NULL); + + test1("Positional arguments work: on the dark side they are", + "Positional arguments work: %3$s %1$s %2$s", + "they", "are", "on the dark side"); + + test1("Asterisk '*' as a width works: < 4>", + "Asterisk '*' as a width works: <%*d>", 5, 4); + + test1("Asterisk '*' as a precision works: <qwerty>", + "Asterisk '*' as a precision works: <%.*s>", 6, "qwertyuiop"); + + test1("Positional arguments for a width: < 4>", + "Positional arguments for a width: <%1$*2$d>", 4, 5); + + test1("Positional arguments for a precision: <qwerty>", + "Positional arguments for a precision: <%1$.*2$s>", "qwertyuiop", 6); + + test1("Positional arguments and a width: <0000ab>", + "Positional arguments and a width: <%1$06x>", 0xab); + + test1("Padding and %p <0x12> <0x034> <0x0000ab> < 0xcd>", + "Padding and %%p <%04p> <%05p> <%08p> <%8p>", 0x12, 0x34, 0xab, 0xcd); + +#if MYSQL_VERSION_ID > 60000 +#error %f/%g tests go here +#endif + + test1("Hello", + "Hello"); + test1("Hello int, 1", + "Hello int, %d", 1); + test1("Hello int, -1", + "Hello int, %d", -1); + test1("Hello string 'I am a string'", + "Hello string '%s'", "I am a string"); + test1("Hello hack hack hack hack hack hack hack 1", + "Hello hack hack hack hack hack hack hack %d", 1); + test1("Hello 1 hack 4", + "Hello %d hack %d", 1, 4); + test1("Hello 1 hack hack hack hack hack 4", + "Hello %d hack hack hack hack hack %d", 1, 4); + test1("Hello 'hack' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", + "Hello '%s' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh", "hack"); + test1("Hello hhhhhhhhhhhhhh 1 sssssssssssssss", + "Hello hhhhhhhhhhhhhh %d sssssssssssssss", 1); + test1("Hello 1", + "Hello %u", 1); + test1("Hello 4294967295", + "Hello %u", -1); + test1("Hex: 20 ' 41'", + "Hex: %lx '%6lx'", 32, 65); + test1("conn 1 to: '(null)' user: '(null)' host: '(null)' ((null))", + "conn %ld to: '%-.64s' user: '%-.32s' host: '%-.64s' (%-.64s)", + 1L, NULL, NULL, NULL, NULL); + test1("Hello string `I am a string`", + "Hello string %`s", "I am a string"); + test1("Hello TEST", + "Hello %05s", "TEST"); + test1("My `Q` test", + "My %1$`-.1s test", "QQQQ"); + test1("My AAAA test done DDDD", + "My %2$s test done %1$s", "DDDD", "AAAA"); + test1("My DDDD test CCCC, DDD", + "My %1$s test %2$s, %1$-.3s", "DDDD", "CCCC"); + test1("My QQQQ test", + "My %1$`-.4b test", "QQQQ"); + test1("My X test", + "My %1$c test", 'X'); + test1("My <0000000010> test1 < a> test2 < A>", + "My <%010d> test1 <%4x> test2 <%4X>", 10, 10, 10); + test1("My <0000000010> test1 < a> test2 < a>", + "My <%1$010d> test1 <%2$4x> test2 <%2$4x>", 10, 10); + test1("My 00010 test", + "My %1$*02$d test", 10, 5); + test1("My `DDDD` test CCCC, `DDD`", + "My %1$`s test %2$s, %1$`-.3s", "DDDD", "CCCC"); + + return exit_status(); +} + |