1
0
mirror of https://github.com/MariaDB/server.git synced 2025-04-18 21:44:20 +03:00

Remove `%s` %b %M %T from my_vsnprintf`

MDEV-21978 introduces more preferrable alternatives to those extensions.
This commit removes the above old and deprecated syntax.

With the code for the old extension formats gone,
this commit also improves the code around the new extension suffixes:
* Remove code for formatting ``%`T``
  * Those code are now dead,
    for the new suffix-based syntax does not recognize `%sQT`/`%sTQ`.
  * `suffix_q= TRUE` now additionally replaces `…|= ESCAPED_ARG`.
* Flatten `flag= true if /%iE/` and `do_iE if flag` code together

[Breaking] This commit removes obsolete features. Although my earlier
work (should have) migrated every usages direct or indirect in the
entire MariaDB/server, other codebases might still be using them. This
final change will break *everything* in those outdated foreign lands.
This commit is contained in:
ParadoxV5 2024-08-15 22:56:39 -06:00 committed by Sergei Golubchik
parent 6a182553ce
commit ab50aad15d
2 changed files with 16 additions and 133 deletions

View File

@ -28,7 +28,6 @@
#define LENGTH_ARG 1
#define WIDTH_ARG 2
#define PREZERO_ARG 4
#define ESCAPED_ARG 8
typedef struct pos_arg_info ARGS_INFO;
typedef struct print_info PRINT_INFO;
@ -153,15 +152,12 @@ static const char *check_longlong(const char *fmt, uint *have_longlong)
*/
static char *backtick_string(CHARSET_INFO *cs, char *to, const char *end,
char *par, size_t par_len, char quote_char,
my_bool cut)
char *par, size_t par_len, char quote_char)
{
char *last[3]= {0,0,0};
uint char_len;
char *start= to;
char *par_end= par + par_len;
size_t buff_length= (size_t) (end - to);
uint index= 0;
if (buff_length <= par_len)
goto err;
@ -170,11 +166,6 @@ static char *backtick_string(CHARSET_INFO *cs, char *to, const char *end,
for ( ; par < par_end; par+= char_len)
{
uchar c= *(uchar *) par;
if (cut)
{
last[index]= start;
index= (index + 1) % 3;
}
char_len= my_ci_charlen_fix(cs, (const uchar *) par, (const uchar *) par_end);
if (char_len == 1 && c == (uchar) quote_char )
{
@ -190,26 +181,6 @@ static char *backtick_string(CHARSET_INFO *cs, char *to, const char *end,
if (start + 1 >= end)
goto err;
if (cut)
{
uint dots= 0;
start= NULL;
for (; dots < 3; dots++)
{
if (index == 0)
index= 2;
else
index--;
if (!last[index])
break;
start= last[index];
}
if (start == NULL)
goto err; // there was no characters at all
for (; dots; dots--)
*start++= '.';
}
*start++= quote_char;
return start;
@ -225,7 +196,7 @@ err:
static char *process_str_arg(CHARSET_INFO *cs, char *to, const char *end,
longlong length_arg, size_t width, char *par,
uint print_type, my_bool nice_cut)
my_bool escaped_arg, my_bool nice_cut)
{
int well_formed_error;
uint dots= 0;
@ -284,10 +255,10 @@ static char *process_str_arg(CHARSET_INFO *cs, char *to, const char *end,
}
plen= my_well_formed_length(cs, par, par + plen, width, &well_formed_error);
if (print_type & ESCAPED_ARG)
if (escaped_arg)
{
const char *org_to= to;
to= backtick_string(cs, to, end, par, plen + dots, '`', MY_TEST(dots));
to= backtick_string(cs, to, end, par, plen + dots, '`');
plen= (size_t) (to - org_to);
dots= 0;
}
@ -431,11 +402,6 @@ start:
/* Here we are at the beginning of positional argument, right after $ */
arg_index--;
print_arr[idx].flags= 0;
if (*fmt == '`')
{
print_arr[idx].flags|= ESCAPED_ARG;
fmt++;
}
if (*fmt == '-')
fmt++;
print_arr[idx].length= print_arr[idx].width= 0;
@ -485,8 +451,6 @@ start:
{
switch (arg_type= args_arr[i].arg_type) {
case 's':
case 'b':
case 'T':
args_arr[i].str_arg= va_arg(ap, char *);
break;
case 'f':
@ -507,7 +471,6 @@ start:
else
args_arr[i].longlong_arg= va_arg(ap, uint);
break;
case 'M':
case 'c':
args_arr[i].longlong_arg= va_arg(ap, int);
break;
@ -521,15 +484,13 @@ start:
size_t width= 0, length= 0;
switch (arg_type= print_arr[i].arg_type) {
case 's':
case 'T':
case 'b':
{
char *par= args_arr[print_arr[i].arg_idx].str_arg;
my_bool suffix_b= arg_type == 'b', suffix_t= arg_type == 'T';
my_bool suffix_q= FALSE, suffix_b= FALSE, suffix_t= FALSE;
switch (*print_arr[i].begin) // look at the start of the next chunk
{
case 'Q':
print_arr[i].flags|= ESCAPED_ARG;
suffix_q= TRUE;
++print_arr[i].begin;
break;
case 'B':
@ -554,7 +515,7 @@ start:
? args_arr[print_arr[i].length].longlong_arg
: (longlong) print_arr[i].length;
to= process_str_arg(cs, to, end, min_field_width, width, par,
print_arr[i].flags, suffix_t);
suffix_q, suffix_t);
}
break;
}
@ -581,20 +542,14 @@ start:
case 'X':
case 'o':
case 'p':
case 'M':
{
/* Integer parameter */
longlong larg= args_arr[print_arr[i].arg_idx].longlong_arg;
my_bool suffix_e= arg_type == 'M';
// look at the start of the next chunk
if (arg_type == 'i' && *print_arr[i].begin == 'E')
{
suffix_e= TRUE;
++print_arr[i].begin; // roll forward to consume the char
}
if (suffix_e)
{
const char *real_end;
++print_arr[i].begin; // roll forward to consume the char
width= (print_arr[i].flags & WIDTH_ARG)
? (size_t)args_arr[print_arr[i].width].longlong_arg
: print_arr[i].width;
@ -607,7 +562,7 @@ start:
*to++= '"';
my_strerror(errmsg_buff, sizeof(errmsg_buff), (int) larg);
to= process_str_arg(cs, to, real_end, 0, width, errmsg_buff,
print_arr[i].flags, 1);
FALSE, TRUE);
if (real_end > to)
*to++= '"';
}
@ -707,11 +662,6 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
}
else
{
if (*fmt == '`')
{
print_type|= ESCAPED_ARG;
fmt++;
}
if (*fmt == '-')
fmt++;
if (*fmt == '*')
@ -742,16 +692,14 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
switch (arg_type= *fmt) {
case 's':
case 'T':
case 'b':
{
/* String parameter */
reg2 char *par= va_arg(ap, char *);
my_bool suffix_b= arg_type == 'b', suffix_t= arg_type == 'T';
my_bool suffix_q= FALSE, suffix_b= FALSE, suffix_t= FALSE;
switch (fmt[1]) // look-ahead (will at most land on the terminating `\0`)
{
case 'Q':
print_type|= ESCAPED_ARG;
suffix_q= TRUE;
++fmt;
break;
case 'B':
@ -768,7 +716,7 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
to= (suffix_b)
? process_bin_arg(to, end, width, par)
: process_str_arg(cs, to, end, (longlong) length, width, par,
print_type, suffix_t);
suffix_q, suffix_t);
continue;
}
case 'f':
@ -792,25 +740,19 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
case 'X':
case 'o':
case 'p':
case 'M':
{
/* Integer parameter */
longlong larg;
my_bool suffix_e= arg_type == 'M';
if (have_longlong)
larg= va_arg(ap,longlong);
else if (arg_type == 'd' || arg_type == 'i' || suffix_e)
else if (arg_type == 'd' || arg_type == 'i')
larg= va_arg(ap, int);
else
larg= va_arg(ap, uint);
if (arg_type == 'i' && fmt[1] == 'E') // look-ahead
{
suffix_e= TRUE;
++fmt;
}
if (suffix_e)
{
const char *real_end= MY_MIN(to + width, end);
++fmt;
to= process_int_arg(to, real_end, 0, larg, 'd', print_type);
if (real_end - to >= 3)
{
@ -819,7 +761,7 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
*to++= '"';
my_strerror(errmsg_buff, sizeof(errmsg_buff), (int) larg);
to= process_str_arg(cs, to, real_end, 0, width, errmsg_buff,
print_type, 1);
FALSE, TRUE);
if (real_end > to)
*to++= '"';
}

View File

@ -61,7 +61,7 @@ static void test_many(const char **res, const char *fmt, ...)
int main(void)
{
plan(62);
plan(45);
test1("Constant string",
"Constant string");
@ -70,8 +70,6 @@ int main(void)
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",
@ -106,8 +104,6 @@ int main(void)
test1("Precision works for strings <abcde>",
"Precision works for strings <%.5s>", "abcdef!");
test1("Precision works for strings <ab...>",
"Precision works for strings <%.5T>", "abcdef!");
// MDEV-21978, tests based on those for their previous incarnations
@ -152,30 +148,6 @@ int main(void)
test1("sT with small width: <.> <...>",
"sT with small width: <%.1sT> <%.3sT>", "abcd", "opqrst");
test1("Flag '`' (backtick) works: `abcd` `op``q` (mysql extension)",
"Flag '`' (backtick) works: %`s %`.4s (mysql extension)",
"abcd", "op`qrst");
test1("Flag '`' (backtick) works: `abcd` `op``q...` (mysql extension)",
"Flag '`' (backtick) works: %`T %`.7T (mysql extension)",
"abcd", "op`qrstuuuuuuuuu");
test1("Flag '`' (backtick) works: `abcd` `.` (mysql extension)",
"Flag '`' (backtick) works: %`T %`.1T (mysql extension)",
"abcd", "op`qrstuuuuuuuuu");
test1("Flag '`' (backtick) works: `abcd` `...` (mysql extension)",
"Flag '`' (backtick) works: %`T %`.3T (mysql extension)",
"abcd", "op`qrstuuuuuuuuu");
test1("Flag '`' (backtick) works: `abcd` `op...` (mysql extension)",
"Flag '`' (backtick) works: %`T %`.5T (mysql extension)",
"abcd", "op`qrstuuuuuuuuu");
test1("Flag '`' (backtick) works: `abcd` `op``...` (mysql extension)",
"Flag '`' (backtick) works: %`T %`.6T (mysql extension)",
"abcd", "op`qrstuuuuuuuuu");
test1("Length modifiers work: 1 * -1 * 2 * 3",
"Length modifiers work: %d * %ld * %lld * %zd", 1, -1L, 2LL, (size_t)3);
@ -202,8 +174,6 @@ int main(void)
"Asterisk '*' as a precision works: <%.*s>", 6, "qwertyuiop");
test1("Asterisk '*' as a precision works: <qwe...>",
"Asterisk '*' as a precision works: <%.*sT>", 6, "qwertyuiop");
test1("Asterisk '*' as a precision works: <qwe...>",
"Asterisk '*' as a precision works: <%.*T>", 6, "qwertyuiop");
test1("Positional arguments for a width: < 4>",
"Positional arguments for a width: <%1$*2$d>", 4, 5);
@ -212,8 +182,6 @@ int main(void)
"Positional arguments for a precision: <%1$.*2$s>", "qwertyuiop", 6);
test1("Positional arguments for a precision: <qwe...>",
"Positional arguments for a precision: <%1$.*2$sT>", "qwertyuiop", 6);
test1("Positional arguments for a precision: <qwe...>",
"Positional arguments for a precision: <%1$.*2$T>", "qwertyuiop", 6);
test1("Positional arguments and a width: <0000ab>",
"Positional arguments and a width: <%1$06x>", 0xab);
@ -231,32 +199,5 @@ int main(void)
test1("G with a width (ignored) and precision: <12.35>",
"G with a width (ignored) and precision: <%10.5g>", 12.3456789);
{
/* Test that %M works */
const char *results[]=
{
"Error 1 \"Operation not permitted\"", /* Linux */
"Error 1 \"Not owner\"", /* Solaris */
NullS
};
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...",
"M with width: %.20M", 0);
test1("M with width positional: 0 \"Internal error...",
"M with width positional: %2$.*1$M", 20, 0);
test_w_len("M small buf: 0 \"..",
19, "M small buf: %M", 0);
test_w_len("M small buf positional: 0 \"..",
30, "M small buf positional: %1$M", 0);
return exit_status();
}