mirror of
https://github.com/holub/mame
synced 2025-06-08 13:53:52 +03:00
emu/debug/debugcmd.cpp: Add NUL-terminated string argument support to printf/logerror. (#12124)
* Use %s to read NUL-terminated strings from emulated memory. Precision sets maximum length. * Also added left-justification option for numeric and string formats. * Made documentation more consistent and removed duplication.
This commit is contained in:
parent
80e9125a5b
commit
f93a04010a
@ -190,18 +190,22 @@ available:
|
|||||||
|
|
||||||
%c
|
%c
|
||||||
Prints the corresponding argument as an 8-bit character.
|
Prints the corresponding argument as an 8-bit character.
|
||||||
%[0][<n>]d
|
%[-][0][<n>]d
|
||||||
Prints the corresponding argument as a decimal number with optional
|
Prints the corresponding argument as a decimal number with optional
|
||||||
minimum field width and zero fill.
|
left justification, zero fill and minimum field width.
|
||||||
%[0][<n>]o
|
%[-][0][<n>]o
|
||||||
Prints the corresponding argument as an octal number with optional
|
Prints the corresponding argument as an octal number with optional
|
||||||
minimum field width and zero fill using lowercase letters.
|
left justification, zero fill and minimum field width.
|
||||||
%[0][<n>]x
|
%[-][0][<n>]x
|
||||||
Prints the corresponding argument as a hexadecimal number with
|
Prints the corresponding argument as a lowercase hexadecimal number
|
||||||
optional minimum field width and zero fill using lowercase letters.
|
with optional left justification, zero fill and minimum field width.
|
||||||
%[0][<n>]X
|
%[-][0][<n>]X
|
||||||
Prints the corresponding argument as a hexadecimal number with
|
Prints the corresponding argument as an uppercase hexadecimal number
|
||||||
optional minimum field width and zero fill using uppercase letters.
|
with optional left justification, zero fill and minimum field width.
|
||||||
|
%[-][<n>][.[<n>]]s
|
||||||
|
Prints a null-terminated string of 8-bit characters from the address
|
||||||
|
and address space given by the corresponding argument, with optional
|
||||||
|
left justification, minimum and maximum field widths.
|
||||||
\%%
|
\%%
|
||||||
Prints a literal percent symbol.
|
Prints a literal percent symbol.
|
||||||
\\n
|
\\n
|
||||||
|
@ -471,7 +471,7 @@ void debugger_commands::execute_print(const std::vector<std::string_view> ¶m
|
|||||||
|
|
||||||
bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std::string_view> ¶ms)
|
bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std::string_view> ¶ms)
|
||||||
{
|
{
|
||||||
std::string_view format(params[0]);
|
std::string_view const format(params[0]);
|
||||||
auto f = format.begin();
|
auto f = format.begin();
|
||||||
|
|
||||||
int param = 1;
|
int param = 1;
|
||||||
@ -499,21 +499,48 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
|
|||||||
// formatting
|
// formatting
|
||||||
else if (c == '%')
|
else if (c == '%')
|
||||||
{
|
{
|
||||||
|
bool left_justify = false;
|
||||||
|
bool zero_fill = false;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
int zerofill = 0;
|
int precision = 0;
|
||||||
|
|
||||||
// parse out the width
|
// parse optional left justification flag
|
||||||
while (f != format.end() && *f >= '0' && *f <= '9')
|
if (f != format.end() && *f == '-')
|
||||||
{
|
{
|
||||||
c = *f++;
|
left_justify = true;
|
||||||
if (c == '0' && width == 0)
|
f++;
|
||||||
zerofill = 1;
|
}
|
||||||
width = width * 10 + (c - '0');
|
|
||||||
|
// parse optional zero fill flag
|
||||||
|
if (f != format.end() && *f == '0')
|
||||||
|
{
|
||||||
|
zero_fill = true;
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse optional width
|
||||||
|
while (f != format.end() && isdigit(*f))
|
||||||
|
width = width * 10 + (*f++ - '0');
|
||||||
|
if (f == format.end())
|
||||||
|
break;
|
||||||
|
|
||||||
|
// apply left justification
|
||||||
|
if (left_justify)
|
||||||
|
width = -width;
|
||||||
|
|
||||||
|
if ((c = *f++) == '.')
|
||||||
|
{
|
||||||
|
// parse optional precision
|
||||||
|
while (f != format.end() && isdigit(*f))
|
||||||
|
precision = precision * 10 + (*f++ - '0');
|
||||||
|
|
||||||
|
// get the format
|
||||||
|
if (f != format.end())
|
||||||
|
c = *f++;
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (f == format.end()) break;
|
|
||||||
|
|
||||||
// get the format
|
|
||||||
c = *f++;
|
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case '%':
|
case '%':
|
||||||
@ -522,7 +549,7 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
|
|||||||
|
|
||||||
case 'X':
|
case 'X':
|
||||||
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
|
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
|
||||||
util::stream_format(stream, zerofill ? "%0*X" : "%*X", width, number);
|
util::stream_format(stream, zero_fill ? "%0*X" : "%*X", width, number);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_console.printf("Not enough parameters for format!\n");
|
m_console.printf("Not enough parameters for format!\n");
|
||||||
@ -531,7 +558,7 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
|
|||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
|
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
|
||||||
util::stream_format(stream, zerofill ? "%0*x" : "%*x", width, number);
|
util::stream_format(stream, zero_fill ? "%0*x" : "%*x", width, number);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_console.printf("Not enough parameters for format!\n");
|
m_console.printf("Not enough parameters for format!\n");
|
||||||
@ -542,7 +569,7 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
|
|||||||
case 'O':
|
case 'O':
|
||||||
case 'o':
|
case 'o':
|
||||||
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
|
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
|
||||||
util::stream_format(stream, zerofill ? "%0*o" : "%*o", width, number);
|
util::stream_format(stream, zero_fill ? "%0*o" : "%*o", width, number);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_console.printf("Not enough parameters for format!\n");
|
m_console.printf("Not enough parameters for format!\n");
|
||||||
@ -553,7 +580,7 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
|
|||||||
case 'D':
|
case 'D':
|
||||||
case 'd':
|
case 'd':
|
||||||
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
|
if (param < params.size() && m_console.validate_number_parameter(params[param++], number))
|
||||||
util::stream_format(stream, zerofill ? "%0*d" : "%*d", width, number);
|
util::stream_format(stream, zero_fill ? "%0*d" : "%*d", width, number);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_console.printf("Not enough parameters for format!\n");
|
m_console.printf("Not enough parameters for format!\n");
|
||||||
@ -572,6 +599,38 @@ bool debugger_commands::mini_printf(std::ostream &stream, const std::vector<std:
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
{
|
||||||
|
address_space *space;
|
||||||
|
if (param < params.size() && m_console.validate_target_address_parameter(params[param++], -1, space, number))
|
||||||
|
{
|
||||||
|
address_space *tspace;
|
||||||
|
std::string s;
|
||||||
|
|
||||||
|
for (u32 address = u32(number), taddress; space->device().memory().translate(space->spacenum(), device_memory_interface::TR_READ, taddress = address, tspace); address++)
|
||||||
|
{
|
||||||
|
u8 const data = tspace->read_byte(taddress);
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
break;
|
||||||
|
|
||||||
|
s += data;
|
||||||
|
|
||||||
|
if (precision == 1)
|
||||||
|
break;
|
||||||
|
else if (precision)
|
||||||
|
precision--;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::stream_format(stream, "%*s", width, s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_console.printf("Not enough parameters for format!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,11 +359,12 @@ const help_item f_static_help_list[] =
|
|||||||
"The printf command performs a C-style printf to the debugger console. Only a very limited set of "
|
"The printf command performs a C-style printf to the debugger console. Only a very limited set of "
|
||||||
"formatting options are available:\n"
|
"formatting options are available:\n"
|
||||||
"\n"
|
"\n"
|
||||||
" %c -- 8-bit character\n"
|
" %c -- 8-bit character\n"
|
||||||
" %[0][<n>]d -- decimal number with optional digit count and zero-fill\n"
|
" %[-][0][<n>]d -- decimal number with optional left justification, zero fill and minimum width\n"
|
||||||
" %[0][<n>]o -- octal number with optional digit count and zero-fill\n"
|
" %[-][0][<n>]o -- octal number with optional left justification, zero fill and minimum width\n"
|
||||||
" %[0][<n>]x -- hexadecimal number with optional digit count and zero-fill (lowercase digits)\n"
|
" %[-][0][<n>]x -- lowercase hexadecimal number with optional left justification, zero fill and minimum width\n"
|
||||||
" %[0][<n>]X -- hexadecimal number with optional digit count and zero-fill (uppercase digits)\n"
|
" %[-][0][<n>]X -- uppercase hexadecimal number with optional left justification, zero fill and minimum width\n"
|
||||||
|
" %[-][<n>][.[<n>]]s -- null-terminated string of 8-bit characters with optional left justification, minimum and maximum width\n"
|
||||||
"\n"
|
"\n"
|
||||||
"All remaining formatting options are ignored. Use %% to output a % character. Multiple lines can be "
|
"All remaining formatting options are ignored. Use %% to output a % character. Multiple lines can be "
|
||||||
"printed by embedding a \\n in the text.\n"
|
"printed by embedding a \\n in the text.\n"
|
||||||
@ -371,7 +372,7 @@ const help_item f_static_help_list[] =
|
|||||||
"Examples:\n"
|
"Examples:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"printf \"PC=%04X\",pc\n"
|
"printf \"PC=%04X\",pc\n"
|
||||||
" Prints PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
|
" Prints PC=<pcval> where <pcval> is displayed in uppercase hexadecimal with 4 digits and zero fill.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"printf \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
|
"printf \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
|
||||||
" Prints A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
|
" Prints A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
|
||||||
@ -382,21 +383,12 @@ const help_item f_static_help_list[] =
|
|||||||
" logerror <format>[,<item>[,...]]\n"
|
" logerror <format>[,<item>[,...]]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The logerror command performs a C-style printf to the error log. Only a very limited set of "
|
"The logerror command performs a C-style printf to the error log. Only a very limited set of "
|
||||||
"formatting options are available:\n"
|
"formatting options are available. See the 'printf' help for details.\n"
|
||||||
"\n"
|
|
||||||
" %c -- 8-bit character\n"
|
|
||||||
" %[0][<n>]d -- decimal number with optional digit count and zero-fill\n"
|
|
||||||
" %[0][<n>]o -- octal number with optional digit count and zero-fill\n"
|
|
||||||
" %[0][<n>]x -- hexadecimal number with optional digit count and zero-fill (lowercase digits)\n"
|
|
||||||
" %[0][<n>]X -- hexadecimal number with optional digit count and zero-fill (uppercase digits)\n"
|
|
||||||
"\n"
|
|
||||||
"All remaining formatting options are ignored. Use %% to output a % character. Multiple lines can be "
|
|
||||||
"printed by embedding a \\n in the text.\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
"Examples:\n"
|
"Examples:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"logerror \"PC=%04X\",pc\n"
|
"logerror \"PC=%04x\",pc\n"
|
||||||
" Logs PC=<pcval> where <pcval> is displayed in hexadecimal with 4 digits with zero-fill.\n"
|
" Logs PC=<pcval> where <pcval> is displayed in lowercase hexadecimal with 4 digits and zero fill.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"logerror \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
|
"logerror \"A=%d, B=%d\\nC=%d\",a,b,a+b\n"
|
||||||
" Logs A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
|
" Logs A=<aval>, B=<bval> on one line, and C=<a+bval> on a second line.\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user