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 \
\f
/* 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)
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)
{
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);
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);
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)
fprintf_unfiltered (stream, "%s=", fldname);
fprintf_unfiltered (stream, "\"");
if (string)
- fputstr_unfiltered (string, '"', stream);
+ stream->putstr (string, '"');
fprintf_unfiltered (stream, "\"");
}
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
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);
+}
+
\f
void
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);
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;
--- /dev/null
+/* 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);
+}
return target_char;
}
\f
-/* 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);
-}
-\f
/* Number of lines per page or UINT_MAX if paging is disabled. */
static unsigned int lines_per_page;
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);