diff --git a/strings/my_vsnprintf.c b/strings/my_vsnprintf.c index c38cd91e807..408931ee930 100644 --- a/strings/my_vsnprintf.c +++ b/strings/my_vsnprintf.c @@ -153,7 +153,7 @@ static const char *check_longlong(const char *fmt, uint *have_longlong) position in buffer which points on the end of escaped string */ -static char *backtick_string(CHARSET_INFO *cs, char *to, char *end, +static char *backtick_string(CHARSET_INFO *cs, char *to, const char *end, char *par, size_t par_len, char quote_char) { uint char_len; @@ -196,7 +196,7 @@ err: Prints string argument */ -static char *process_str_arg(CHARSET_INFO *cs, char *to, char *end, +static char *process_str_arg(CHARSET_INFO *cs, char *to, const char *end, size_t width, char *par, uint print_type) { int well_formed_error; @@ -257,7 +257,7 @@ static char *process_dbl_arg(char *to, char *end, size_t width, Prints integer argument */ -static char *process_int_arg(char *to, char *end, size_t length, +static char *process_int_arg(char *to, const char *end, size_t length, longlong par, char arg_type, uint print_type) { size_t res_length, to_length; @@ -482,24 +482,26 @@ start: case 'M': { longlong larg; - char *org_to= to; - char errmsg_buff[MYSYS_STRERROR_SIZE]; + const char *real_end; - length= (print_arr[i].flags & WIDTH_ARG) + width= (print_arr[i].flags & WIDTH_ARG) ? (size_t)args_arr[print_arr[i].width].longlong_arg : print_arr[i].width; + real_end= MY_MIN(to + width, end); + larg = args_arr[print_arr[i].arg_idx].longlong_arg; - to= process_int_arg(to, end, 0, larg, 'd', print_arr[i].flags); - width-= (to - org_to); - if (width <= 4) - break; - *to++= ' '; - *to++= '"'; - my_strerror(errmsg_buff, sizeof(errmsg_buff), (int) larg); - to= process_str_arg(cs, to, end, width-3, errmsg_buff, - print_arr[i].flags); - *to++= '"'; + to= process_int_arg(to, real_end, 0, larg, 'd', print_arr[i].flags); + if (real_end - to >= 3) + { + char errmsg_buff[MYSYS_STRERROR_SIZE]; + *to++= ' '; + *to++= '"'; + my_strerror(errmsg_buff, sizeof(errmsg_buff), larg); + to= process_str_arg(cs, to, real_end, width, errmsg_buff, + print_arr[i].flags); + if (real_end > to) *to++= '"'; + } break; } default: @@ -666,18 +668,18 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n, } else if (*fmt == 'M') { - const char *org_to= to; int larg= va_arg(ap, int); - to= process_int_arg(to, end, 0, larg, 'd', print_type); - width-= (to - org_to); - if ((end - to) >= 4 && (int) width >= 4) + const char *real_end= MY_MIN(to + width, end); + + to= process_int_arg(to, real_end, 0, larg, 'd', print_type); + if (real_end - to >= 3) { char errmsg_buff[MYSYS_STRERROR_SIZE]; *to++= ' '; *to++= '"'; my_strerror(errmsg_buff, sizeof(errmsg_buff), larg); - to= process_str_arg(cs, to, end, width-3, errmsg_buff, print_type); - *to++= '"'; + to= process_str_arg(cs, to, real_end, width, errmsg_buff, print_type); + if (real_end > to) *to++= '"'; } continue; } diff --git a/unittest/mysys/my_vsnprintf-t.c b/unittest/mysys/my_vsnprintf-t.c index 5809d6144cc..45df97fbecd 100644 --- a/unittest/mysys/my_vsnprintf-t.c +++ b/unittest/mysys/my_vsnprintf-t.c @@ -19,6 +19,16 @@ char buf[1024]; /* let's hope that's enough */ +static void test_w_len(const char *res, size_t buflen, const char *fmt, ...) +{ + va_list args; + size_t len; + va_start(args,fmt); + len= my_vsnprintf(buf, buflen, fmt, args); + va_end(args); + ok(strlen(res) == len && strcmp(buf, res) == 0, "\"%s\"", buf); +} + static void test1(const char *res, const char *fmt, ...) { va_list args; @@ -51,7 +61,7 @@ static void test_many(const char **res, const char *fmt, ...) int main(void) { - plan(59); + plan(39); test1("Constant string", "Constant string"); @@ -141,62 +151,6 @@ int main(void) test1("G with a width (ignored) and precision: <12.35>", "G with a width (ignored) and precision: <%10.5g>", 12.3456789); - diag("================================================================"); - - test1("Hello", - "Hello"); - test1("Hello int, 1", - "Hello int, %d", 1); - test1("Hello int, -1", - "Hello int, %d", -1); - test1("Hello int, 1", - "Hello int, %i", 1); - test1("Hello int, -1", - "Hello int, %i", -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"); - { /* Test that %M works */ const char *results[]= @@ -208,6 +162,22 @@ int main(void) test_many(results, "Error %M", 1); } + test1("M with 0 error code: 0 \"Internal error/check (Not system error)\"", + "M with 0 error code: %M", 0); + + test1("M with positional: 0 \"Internal error/check (Not system error)\"", + "M with positional: %1$M", 0); + + test1("M with width: 0 \"Internal error/ch", + "M with width: %.20M", 0); + test1("M with width positional: 0 \"Internal error/ch", + "M with width positional: %2$.*1$M", 20, 0); + + test_w_len("M small buf: 0 \"In", + 19, "M small buf: %M", 0); + test_w_len("M small buf positional: 0 \"In", + 30, "M small buf positional: %1$M", 0); + return exit_status(); }