Implement putstr and putstrn in ui_file
In my tour of the ui_file subsystem, I found that fputstr and fputstrn can be simplified. The _filtered forms are never used (and IMO unlikely to ever be used) and so can be removed. And, the interface can be simplified by removing a callback function and moving the implementation directly to ui_file. A new self-test is included. Previously, I think nothing was testing this code. Regression tested on x86-64 Fedora 34.
This commit is contained in:
parent
28a4e64dd1
commit
d53fd721a1
10 changed files with 158 additions and 139 deletions
|
@ -477,6 +477,7 @@ SELFTESTS_SRCS = \
|
|||
unittests/style-selftests.c \
|
||||
unittests/tracepoint-selftests.c \
|
||||
unittests/tui-selftests.c \
|
||||
unittests/ui-file-selftests.c \
|
||||
unittests/unpack-selftests.c \
|
||||
unittests/utils-selftests.c \
|
||||
unittests/vec-utils-selftests.c \
|
||||
|
|
|
@ -191,8 +191,8 @@ ioscm_open_port (scm_t_port_type *port_type, long mode_bits, scm_t_bits stream)
|
|||
|
||||
/* Support for connecting Guile's stdio ports to GDB's stdio ports. */
|
||||
|
||||
/* Like fputstrn_filtered, but don't escape characters, except nul.
|
||||
Also like fputs_filtered, but a length is specified. */
|
||||
/* Print a string S, length SIZE, but don't escape characters, except
|
||||
nul. */
|
||||
|
||||
static void
|
||||
fputsn_filtered (const char *s, size_t size, struct ui_file *stream)
|
||||
|
|
|
@ -48,16 +48,6 @@ mi_console_file::write (const char *buf, long length_buf)
|
|||
this->flush ();
|
||||
}
|
||||
|
||||
/* Write C to STREAM's in an async-safe way. */
|
||||
|
||||
static int
|
||||
do_fputc_async_safe (int c, ui_file *stream)
|
||||
{
|
||||
char ch = c;
|
||||
stream->write_async_safe (&ch, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
mi_console_file::write_async_safe (const char *buf, long length_buf)
|
||||
{
|
||||
|
@ -65,12 +55,11 @@ mi_console_file::write_async_safe (const char *buf, long length_buf)
|
|||
if (m_quote)
|
||||
{
|
||||
m_raw->write_async_safe (&m_quote, 1);
|
||||
fputstrn_unfiltered (buf, length_buf, m_quote, do_fputc_async_safe,
|
||||
m_raw);
|
||||
m_raw->putstrn (buf, length_buf, m_quote, true);
|
||||
m_raw->write_async_safe (&m_quote, 1);
|
||||
}
|
||||
else
|
||||
fputstrn_unfiltered (buf, length_buf, 0, do_fputc_async_safe, m_raw);
|
||||
m_raw->putstrn (buf, length_buf, 0, true);
|
||||
|
||||
char nl = '\n';
|
||||
m_raw->write_async_safe (&nl, 1);
|
||||
|
@ -91,14 +80,13 @@ mi_console_file::flush ()
|
|||
if (m_quote)
|
||||
{
|
||||
fputc_unfiltered (m_quote, m_raw);
|
||||
fputstrn_unfiltered (buf, length_buf, m_quote, fputc_unfiltered,
|
||||
m_raw);
|
||||
m_raw->putstrn (buf, length_buf, m_quote);
|
||||
fputc_unfiltered (m_quote, m_raw);
|
||||
fputc_unfiltered ('\n', m_raw);
|
||||
}
|
||||
else
|
||||
{
|
||||
fputstrn_unfiltered (buf, length_buf, 0, fputc_unfiltered, m_raw);
|
||||
m_raw->putstrn (buf, length_buf, 0);
|
||||
fputc_unfiltered ('\n', m_raw);
|
||||
}
|
||||
gdb_flush (m_raw);
|
||||
|
|
|
@ -1866,7 +1866,7 @@ mi_print_exception (const char *token, const struct gdb_exception &exception)
|
|||
if (exception.message == NULL)
|
||||
fputs_unfiltered ("unknown error", mi->raw_stdout);
|
||||
else
|
||||
fputstr_unfiltered (exception.what (), '"', mi->raw_stdout);
|
||||
mi->raw_stdout->putstr (exception.what (), '"');
|
||||
fputs_unfiltered ("\"", mi->raw_stdout);
|
||||
|
||||
switch (exception.error)
|
||||
|
|
|
@ -135,7 +135,7 @@ mi_ui_out::do_field_string (int fldno, int width, ui_align align,
|
|||
fprintf_unfiltered (stream, "%s=", fldname);
|
||||
fprintf_unfiltered (stream, "\"");
|
||||
if (string)
|
||||
fputstr_unfiltered (string, '"', stream);
|
||||
stream->putstr (string, '"');
|
||||
fprintf_unfiltered (stream, "\"");
|
||||
}
|
||||
|
||||
|
|
|
@ -47,13 +47,15 @@ ui_file::printf (const char *format, ...)
|
|||
void
|
||||
ui_file::putstr (const char *str, int quoter)
|
||||
{
|
||||
fputstr_unfiltered (str, quoter, this);
|
||||
while (*str)
|
||||
printchar (*str++, quoter, false);
|
||||
}
|
||||
|
||||
void
|
||||
ui_file::putstrn (const char *str, int n, int quoter)
|
||||
ui_file::putstrn (const char *str, int n, int quoter, bool async_safe)
|
||||
{
|
||||
fputstrn_unfiltered (str, n, quoter, fputc_unfiltered, this);
|
||||
for (int i = 0; i < n; i++)
|
||||
printchar (str[i], quoter, async_safe);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -68,6 +70,67 @@ ui_file::vprintf (const char *format, va_list args)
|
|||
vfprintf_unfiltered (this, format, args);
|
||||
}
|
||||
|
||||
/* See ui-file.h. */
|
||||
|
||||
void
|
||||
ui_file::printchar (int c, int quoter, bool async_safe)
|
||||
{
|
||||
char buf[4];
|
||||
int out = 0;
|
||||
|
||||
c &= 0xFF; /* Avoid sign bit follies */
|
||||
|
||||
if (c < 0x20 /* Low control chars */
|
||||
|| (c >= 0x7F && c < 0xA0) /* DEL, High controls */
|
||||
|| (sevenbit_strings && c >= 0x80))
|
||||
{ /* high order bit set */
|
||||
buf[out++] = '\\';
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
buf[out++] = 'n';
|
||||
break;
|
||||
case '\b':
|
||||
buf[out++] = 'b';
|
||||
break;
|
||||
case '\t':
|
||||
buf[out++] = 't';
|
||||
break;
|
||||
case '\f':
|
||||
buf[out++] = 'f';
|
||||
break;
|
||||
case '\r':
|
||||
buf[out++] = 'r';
|
||||
break;
|
||||
case '\033':
|
||||
buf[out++] = 'e';
|
||||
break;
|
||||
case '\007':
|
||||
buf[out++] = 'a';
|
||||
break;
|
||||
default:
|
||||
{
|
||||
buf[out++] = '0' + ((c >> 6) & 0x7);
|
||||
buf[out++] = '0' + ((c >> 3) & 0x7);
|
||||
buf[out++] = '0' + ((c >> 0) & 0x7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (quoter != 0 && (c == '\\' || c == quoter))
|
||||
buf[out++] = '\\';
|
||||
buf[out++] = c;
|
||||
}
|
||||
|
||||
if (async_safe)
|
||||
this->write_async_safe (buf, out);
|
||||
else
|
||||
this->write (buf, out);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
|
|
|
@ -34,12 +34,22 @@ public:
|
|||
|
||||
void printf (const char *, ...) ATTRIBUTE_PRINTF (2, 3);
|
||||
|
||||
/* Print a string whose delimiter is QUOTER. Note that these
|
||||
routines should only be called for printing things which are
|
||||
independent of the language of the program being debugged. */
|
||||
/* Print a NUL-terminated string whose delimiter is QUOTER. Note
|
||||
that these routines should only be called for printing things
|
||||
which are independent of the language of the program being
|
||||
debugged.
|
||||
|
||||
This will normally escape backslashes and instances of QUOTER.
|
||||
If QUOTER is 0, it won't escape backslashes or any quoting
|
||||
character. As a side effect, if you pass the backslash character
|
||||
as the QUOTER, this will escape backslashes as usual, but not any
|
||||
other quoting character. */
|
||||
void putstr (const char *str, int quoter);
|
||||
|
||||
void putstrn (const char *str, int n, int quoter);
|
||||
/* Like putstr, but only print the first N characters of STR. If
|
||||
ASYNC_SAFE is true, then the output is done via the
|
||||
write_async_safe method. */
|
||||
void putstrn (const char *str, int n, int quoter, bool async_safe = false);
|
||||
|
||||
int putc (int c);
|
||||
|
||||
|
@ -96,6 +106,13 @@ public:
|
|||
default. */
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/* Helper function for putstr and putstrn. Print the character C on
|
||||
this stream as part of the contents of a literal string whose
|
||||
delimiter is QUOTER. */
|
||||
void printchar (int c, int quoter, bool async_safe);
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<ui_file> ui_file_up;
|
||||
|
|
62
gdb/unittests/ui-file-selftests.c
Normal file
62
gdb/unittests/ui-file-selftests.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
/* Self tests for ui_file
|
||||
|
||||
Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "gdbsupport/selftest.h"
|
||||
#include "ui-file.h"
|
||||
|
||||
namespace selftests {
|
||||
namespace file {
|
||||
|
||||
static void
|
||||
check_one (const char *str, int quoter, const char *result)
|
||||
{
|
||||
string_file out;
|
||||
out.putstr (str, quoter);
|
||||
SELF_CHECK (out.string () == result);
|
||||
}
|
||||
|
||||
static void
|
||||
run_tests ()
|
||||
{
|
||||
check_one ("basic stuff: \\", '\\',
|
||||
"basic stuff: \\\\");
|
||||
check_one ("more basic stuff: \\Q", 'Q',
|
||||
"more basic stuff: \\\\\\Q");
|
||||
check_one ("more basic stuff: \\Q", '\0',
|
||||
"more basic stuff: \\Q");
|
||||
|
||||
check_one ("weird stuff: \x1f\x90\n\b\t\f\r\033\007", '\\',
|
||||
"weird stuff: \\037\\220\\n\\b\\t\\f\\r\\e\\a");
|
||||
|
||||
scoped_restore save_7 = make_scoped_restore (&sevenbit_strings, true);
|
||||
check_one ("more weird stuff: \xa5", '\\',
|
||||
"more weird stuff: \\245");
|
||||
}
|
||||
|
||||
} /* namespace file*/
|
||||
} /* namespace selftests */
|
||||
|
||||
void _initialize_ui_file_selftest ();
|
||||
void
|
||||
_initialize_ui_file_selftest ()
|
||||
{
|
||||
selftests::register_test ("ui-file",
|
||||
selftests::file::run_tests);
|
||||
}
|
97
gdb/utils.c
97
gdb/utils.c
|
@ -1129,103 +1129,6 @@ parse_escape (struct gdbarch *gdbarch, const char **string_ptr)
|
|||
return target_char;
|
||||
}
|
||||
|
||||
/* Print the character C on STREAM as part of the contents of a literal
|
||||
string whose delimiter is QUOTER. Note that this routine should only
|
||||
be called for printing things which are independent of the language
|
||||
of the program being debugged.
|
||||
|
||||
printchar will normally escape backslashes and instances of QUOTER. If
|
||||
QUOTER is 0, printchar won't escape backslashes or any quoting character.
|
||||
As a side effect, if you pass the backslash character as the QUOTER,
|
||||
printchar will escape backslashes as usual, but not any other quoting
|
||||
character. */
|
||||
|
||||
static void
|
||||
printchar (int c, do_fputc_ftype do_fputc, ui_file *stream, int quoter)
|
||||
{
|
||||
c &= 0xFF; /* Avoid sign bit follies */
|
||||
|
||||
if (c < 0x20 || /* Low control chars */
|
||||
(c >= 0x7F && c < 0xA0) || /* DEL, High controls */
|
||||
(sevenbit_strings && c >= 0x80))
|
||||
{ /* high order bit set */
|
||||
do_fputc ('\\', stream);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
do_fputc ('n', stream);
|
||||
break;
|
||||
case '\b':
|
||||
do_fputc ('b', stream);
|
||||
break;
|
||||
case '\t':
|
||||
do_fputc ('t', stream);
|
||||
break;
|
||||
case '\f':
|
||||
do_fputc ('f', stream);
|
||||
break;
|
||||
case '\r':
|
||||
do_fputc ('r', stream);
|
||||
break;
|
||||
case '\033':
|
||||
do_fputc ('e', stream);
|
||||
break;
|
||||
case '\007':
|
||||
do_fputc ('a', stream);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
do_fputc ('0' + ((c >> 6) & 0x7), stream);
|
||||
do_fputc ('0' + ((c >> 3) & 0x7), stream);
|
||||
do_fputc ('0' + ((c >> 0) & 0x7), stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (quoter != 0 && (c == '\\' || c == quoter))
|
||||
do_fputc ('\\', stream);
|
||||
do_fputc (c, stream);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the character C on STREAM as part of the contents of a
|
||||
literal string whose delimiter is QUOTER. Note that these routines
|
||||
should only be call for printing things which are independent of
|
||||
the language of the program being debugged. */
|
||||
|
||||
void
|
||||
fputstr_filtered (const char *str, int quoter, struct ui_file *stream)
|
||||
{
|
||||
while (*str)
|
||||
printchar (*str++, fputc_filtered, stream, quoter);
|
||||
}
|
||||
|
||||
void
|
||||
fputstr_unfiltered (const char *str, int quoter, struct ui_file *stream)
|
||||
{
|
||||
while (*str)
|
||||
printchar (*str++, fputc_unfiltered, stream, quoter);
|
||||
}
|
||||
|
||||
void
|
||||
fputstrn_filtered (const char *str, int n, int quoter,
|
||||
struct ui_file *stream)
|
||||
{
|
||||
for (int i = 0; i < n; i++)
|
||||
printchar (str[i], fputc_filtered, stream, quoter);
|
||||
}
|
||||
|
||||
void
|
||||
fputstrn_unfiltered (const char *str, int n, int quoter,
|
||||
do_fputc_ftype do_fputc, struct ui_file *stream)
|
||||
{
|
||||
for (int i = 0; i < n; i++)
|
||||
printchar (str[i], do_fputc, stream, quoter);
|
||||
}
|
||||
|
||||
|
||||
/* Number of lines per page or UINT_MAX if paging is disabled. */
|
||||
static unsigned int lines_per_page;
|
||||
|
|
15
gdb/utils.h
15
gdb/utils.h
|
@ -464,21 +464,6 @@ extern void print_spaces_filtered (int, struct ui_file *);
|
|||
|
||||
extern const char *n_spaces (int);
|
||||
|
||||
extern void fputstr_filtered (const char *str, int quotr,
|
||||
struct ui_file * stream);
|
||||
|
||||
extern void fputstr_unfiltered (const char *str, int quotr,
|
||||
struct ui_file * stream);
|
||||
|
||||
extern void fputstrn_filtered (const char *str, int n, int quotr,
|
||||
struct ui_file * stream);
|
||||
|
||||
typedef int (*do_fputc_ftype) (int c, ui_file *stream);
|
||||
|
||||
extern void fputstrn_unfiltered (const char *str, int n, int quotr,
|
||||
do_fputc_ftype do_fputc,
|
||||
struct ui_file * stream);
|
||||
|
||||
/* Return nonzero if filtered printing is initialized. */
|
||||
extern int filtered_printing_initialized (void);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue