Commit 814e52ca by François Dumont

2015-09-17 François Dumont <fdumont@gcc.gnu.org>

	* include/debug/formatter.h
	(_Error_formatter::_Parameter::_M_print_field): Deprecate.
	(_Error_formatter::_Parameter::_M_print_description): Likewise.
	(_Error_formatter::_M_format_word): Likewise.
	(_Error_formatter::_M_print_word): Likewise.
	(_Error_formatter::_M_print_string): Likewise.
	(_Error_formatter::_M_get_max_length): Likewise.
	(_Error_formatter::_M_max_length): Delete.
	(_Error_formatter::_M_indent): Likewise.
	(_Error_formatter::_M_column): Likewise.
	(_Error_formatter::_M_first_line): Likewise.
	(_Error_formatter::_M_wordwrap): Likewise.
	* src/c++11/debug.cc: Adapt.

From-SVN: r227885
parent 378b307d
2015-09-17 François Dumont <fdumont@gcc.gnu.org>
* include/debug/formatter.h
(_Error_formatter::_Parameter::_M_print_field): Deprecate.
(_Error_formatter::_Parameter::_M_print_description): Likewise.
(_Error_formatter::_M_format_word): Likewise.
(_Error_formatter::_M_print_word): Likewise.
(_Error_formatter::_M_print_string): Likewise.
(_Error_formatter::_M_get_max_length): Likewise.
(_Error_formatter::_M_max_length): Delete.
(_Error_formatter::_M_indent): Likewise.
(_Error_formatter::_M_column): Likewise.
(_Error_formatter::_M_first_line): Likewise.
(_Error_formatter::_M_wordwrap): Likewise.
* src/c++11/debug.cc: Adapt.
2015-09-17 Jonathan Wakely <jwakely@redhat.com> 2015-09-17 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/65913 PR libstdc++/65913
......
...@@ -132,6 +132,13 @@ namespace __gnu_debug ...@@ -132,6 +132,13 @@ namespace __gnu_debug
class _Error_formatter class _Error_formatter
{ {
// Tags denoting the type of parameter for construction
struct _Is_iterator { };
struct _Is_iterator_value_type { };
struct _Is_sequence { };
struct _Is_instance { };
public:
/// Whether an iterator is constant, mutable, or unknown /// Whether an iterator is constant, mutable, or unknown
enum _Constness enum _Constness
{ {
...@@ -153,13 +160,6 @@ namespace __gnu_debug ...@@ -153,13 +160,6 @@ namespace __gnu_debug
__last_state __last_state
}; };
// Tags denoting the type of parameter for construction
struct _Is_iterator { };
struct _Is_iterator_value_type { };
struct _Is_sequence { };
struct _Is_instance { };
public:
// A parameter that may be referenced by an error message // A parameter that may be referenced by an error message
struct _Parameter struct _Parameter
{ {
...@@ -375,15 +375,16 @@ namespace __gnu_debug ...@@ -375,15 +375,16 @@ namespace __gnu_debug
void void
_M_print_field(const _Error_formatter* __formatter, _M_print_field(const _Error_formatter* __formatter,
const char* __name) const; const char* __name) const _GLIBCXX_DEPRECATED;
void void
_M_print_description(const _Error_formatter* __formatter) const; _M_print_description(const _Error_formatter* __formatter)
const _GLIBCXX_DEPRECATED;
}; };
template<typename _Iterator> template<typename _Iterator>
const _Error_formatter& _Error_formatter&
_M_iterator(const _Iterator& __it, const char* __name = 0) const _M_iterator(const _Iterator& __it, const char* __name = 0)
{ {
if (_M_num_parameters < std::size_t(__max_parameters)) if (_M_num_parameters < std::size_t(__max_parameters))
_M_parameters[_M_num_parameters++] = _Parameter(__it, __name, _M_parameters[_M_num_parameters++] = _Parameter(__it, __name,
...@@ -392,57 +393,59 @@ namespace __gnu_debug ...@@ -392,57 +393,59 @@ namespace __gnu_debug
} }
template<typename _Iterator> template<typename _Iterator>
const _Error_formatter& _Error_formatter&
_M_iterator_value_type(const _Iterator& __it, _M_iterator_value_type(const _Iterator& __it,
const char* __name = 0) const const char* __name = 0)
{ {
if (_M_num_parameters < std::size_t(__max_parameters)) if (_M_num_parameters < __max_parameters)
_M_parameters[_M_num_parameters++] = _M_parameters[_M_num_parameters++] =
_Parameter(__it, __name, _Is_iterator_value_type()); _Parameter(__it, __name, _Is_iterator_value_type());
return *this; return *this;
} }
const _Error_formatter& _Error_formatter&
_M_integer(long __value, const char* __name = 0) const _M_integer(long __value, const char* __name = 0)
{ {
if (_M_num_parameters < std::size_t(__max_parameters)) if (_M_num_parameters < __max_parameters)
_M_parameters[_M_num_parameters++] = _Parameter(__value, __name); _M_parameters[_M_num_parameters++] = _Parameter(__value, __name);
return *this; return *this;
} }
const _Error_formatter& _Error_formatter&
_M_string(const char* __value, const char* __name = 0) const _M_string(const char* __value, const char* __name = 0)
{ {
if (_M_num_parameters < std::size_t(__max_parameters)) if (_M_num_parameters < __max_parameters)
_M_parameters[_M_num_parameters++] = _Parameter(__value, __name); _M_parameters[_M_num_parameters++] = _Parameter(__value, __name);
return *this; return *this;
} }
template<typename _Sequence> template<typename _Sequence>
const _Error_formatter& _Error_formatter&
_M_sequence(const _Sequence& __seq, const char* __name = 0) const _M_sequence(const _Sequence& __seq, const char* __name = 0)
{ {
if (_M_num_parameters < std::size_t(__max_parameters)) if (_M_num_parameters < __max_parameters)
_M_parameters[_M_num_parameters++] = _Parameter(__seq, __name, _M_parameters[_M_num_parameters++] = _Parameter(__seq, __name,
_Is_sequence()); _Is_sequence());
return *this; return *this;
} }
template<typename _Type> template<typename _Type>
const _Error_formatter& _Error_formatter&
_M_instance(const _Type& __inst, const char* __name = 0) const _M_instance(const _Type& __inst, const char* __name = 0)
{ {
if (_M_num_parameters < std::size_t(__max_parameters)) if (_M_num_parameters < __max_parameters)
_M_parameters[_M_num_parameters++] = _Parameter(__inst, __name, _M_parameters[_M_num_parameters++] = _Parameter(__inst, __name,
_Is_instance()); _Is_instance());
return *this; return *this;
} }
const _Error_formatter& _Error_formatter&
_M_message(const char* __text) const _M_message(const char* __text)
{ _M_text = __text; return *this; } { _M_text = __text; return *this; }
const _Error_formatter& // Kept const qualifier for backward compatibility, to keep the same
// exported symbol.
_Error_formatter&
_M_message(_Debug_msg_id __id) const throw (); _M_message(_Debug_msg_id __id) const throw ();
_GLIBCXX_NORETURN void _GLIBCXX_NORETURN void
...@@ -450,40 +453,38 @@ namespace __gnu_debug ...@@ -450,40 +453,38 @@ namespace __gnu_debug
template<typename _Tp> template<typename _Tp>
void void
_M_format_word(char*, int, const char*, _Tp) const throw (); _M_format_word(char*, int, const char*, _Tp)
const throw () _GLIBCXX_DEPRECATED;
void void
_M_print_word(const char* __word) const; _M_print_word(const char* __word) const _GLIBCXX_DEPRECATED;
void void
_M_print_string(const char* __string) const; _M_print_string(const char* __string) const _GLIBCXX_DEPRECATED;
private: private:
_Error_formatter(const char* __file, std::size_t __line) _Error_formatter(const char* __file, unsigned int __line)
: _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0), : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0)
_M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false) { }
{ _M_get_max_length(); }
void void
_M_get_max_length() const throw (); _M_get_max_length() const throw () _GLIBCXX_DEPRECATED;
enum { __max_parameters = 9 }; enum { __max_parameters = 9 };
const char* _M_file; const char* _M_file;
std::size_t _M_line; unsigned int _M_line;
mutable _Parameter _M_parameters[__max_parameters]; _Parameter _M_parameters[__max_parameters];
mutable std::size_t _M_num_parameters; unsigned int _M_num_parameters;
mutable const char* _M_text; const char* _M_text;
mutable std::size_t _M_max_length;
enum { _M_indent = 4 } ;
mutable std::size_t _M_column;
mutable bool _M_first_line;
mutable bool _M_wordwrap;
public: public:
static _Error_formatter static _Error_formatter&
_M_at(const char* __file, std::size_t __line) _M_at(const char* __file, unsigned int __line)
{ return _Error_formatter(__file, __line); } {
static _Error_formatter __formatter(__file, __line);
return __formatter;
}
}; };
} // namespace __gnu_debug } // namespace __gnu_debug
......
...@@ -22,18 +22,19 @@ ...@@ -22,18 +22,19 @@
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>. // <http://www.gnu.org/licenses/>.
#include <debug/debug.h> #include <bits/move.h>
#include <bits/stl_iterator_base_types.h>
#include <debug/formatter.h>
#include <debug/safe_base.h> #include <debug/safe_base.h>
#include <debug/safe_unordered_base.h> #include <debug/safe_unordered_base.h>
#include <debug/safe_iterator.h> #include <debug/safe_iterator.h>
#include <debug/safe_local_iterator.h> #include <debug/safe_local_iterator.h>
#include <algorithm>
#include <cassert> #include <cassert>
#include <cstring>
#include <cctype> #include <algorithm> // for std::min
#include <cstdio> #include <functional> // for _Hash_impl
#include <cstdlib>
#include <functional>
#include <cxxabi.h> // for __cxa_demangle #include <cxxabi.h> // for __cxa_demangle
...@@ -524,202 +525,236 @@ namespace __gnu_debug ...@@ -524,202 +525,236 @@ namespace __gnu_debug
namespace namespace
{ {
using _Error_formatter = __gnu_debug::_Error_formatter;
using _Parameter = __gnu_debug::_Error_formatter::_Parameter;
template<typename _Tp>
int
format_word(char* buf, int n, const char* fmt, _Tp s)
{ return std::min(__builtin_snprintf(buf, n, fmt, s), n - 1); }
void void
print_type(const __gnu_debug::_Error_formatter* __formatter, get_max_length(std::size_t& max_length)
const type_info* __info,
const char* __unknown_name)
{ {
if (!__info) const char* nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
__formatter->_M_print_word(__unknown_name); if (nptr)
else
{ {
int __status; char* endptr;
char* __demangled_name = const unsigned long ret = std::strtoul(nptr, &endptr, 0);
__cxxabiv1::__cxa_demangle(__info->name(), NULL, NULL, &__status); if (*nptr != '\0' && *endptr == '\0')
__formatter->_M_print_word(__status == 0 max_length = ret;
? __demangled_name : __info->name());
free(__demangled_name);
} }
} }
bool struct PrintContext
print_field(
const __gnu_debug::_Error_formatter* __formatter,
const char* __name,
const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant)
{ {
if (strcmp(__name, "name") == 0) PrintContext()
{ : _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false)
assert(__variant._M_name); { get_max_length(_M_max_length); }
__formatter->_M_print_word(__variant._M_name);
} std::size_t _M_max_length;
else if (strcmp(__name, "type") == 0) enum { _M_indent = 4 } ;
print_type(__formatter, __variant._M_type, "<unknown type>"); std::size_t _M_column;
else bool _M_first_line;
return false; bool _M_wordwrap;
};
return true;
}
bool void
print_field( print_word(PrintContext& ctx, const char* word,
const __gnu_debug::_Error_formatter* __formatter, std::ptrdiff_t count = -1)
const char* __name,
const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant)
{ {
const __gnu_debug::_Error_formatter::_Parameter::_Type& __type = __variant; size_t length = count >= 0 ? count : __builtin_strlen(word);
if (print_field(__formatter, __name, __type)) if (length == 0)
{ } return;
else if (strcmp(__name, "address") == 0)
// Consider first '\n' at begining cause it impacts column.
if (word[0] == '\n')
{ {
const int __bufsize = 64; fprintf(stderr, "\n");
char __buf[__bufsize]; ctx._M_column = 1;
__formatter->_M_format_word(__buf, __bufsize, "%p", ++word;
__variant._M_address); --length;
__formatter->_M_print_word(__buf);
}
else
return false;
return true; if (length == 0)
} return;
}
void size_t visual_length
print_description( = isspace(word[length - 1]) ? length - 1 : length;
const __gnu_debug::_Error_formatter* __formatter, if (visual_length == 0
const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant) || !ctx._M_wordwrap
{ || (ctx._M_column + visual_length < ctx._M_max_length)
if (__variant._M_name) || (visual_length >= ctx._M_max_length && ctx._M_column == 1))
{ {
const int __bufsize = 64; // If this isn't the first line, indent
char __buf[__bufsize]; if (ctx._M_column == 1 && !ctx._M_first_line)
__formatter->_M_format_word(__buf, __bufsize, "\"%s\"", {
__variant._M_name); char spacing[ctx._M_indent + 1];
__formatter->_M_print_word(__buf); for (int i = 0; i < ctx._M_indent; ++i)
} spacing[i] = ' ';
spacing[ctx._M_indent] = '\0';
fprintf(stderr, "%s", spacing);
ctx._M_column += ctx._M_indent;
}
__formatter->_M_print_word(" {\n"); int written = fprintf(stderr, "%s", word);
if (__variant._M_type) if (word[length - 1] == '\n')
{
ctx._M_first_line = false;
ctx._M_column = 1;
}
else
ctx._M_column += written;
}
else
{ {
__formatter->_M_print_word(" type = "); print_word(ctx, "\n", 1);
print_type(__formatter, __variant._M_type, "<unknown type>"); print_word(ctx, word, count);
__formatter->_M_print_word(";\n");
} }
} }
void void
print_description( print_type(PrintContext& ctx,
const __gnu_debug::_Error_formatter* __formatter, const type_info* info,
const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant) const char* unknown_name)
{ {
const int __bufsize = 64; if (!info)
char __buf[__bufsize]; print_word(ctx, unknown_name);
else
{
int status;
char* demangled_name =
__cxxabiv1::__cxa_demangle(info->name(), NULL, NULL, &status);
print_word(ctx, status == 0 ? demangled_name : info->name());
free(demangled_name);
}
}
if (__variant._M_name) bool
print_field(PrintContext& ctx,
const char* name, const _Parameter::_Type& type)
{
if (__builtin_strcmp(name, "name") == 0)
{ {
__formatter->_M_format_word(__buf, __bufsize, "\"%s\" ", assert(type._M_name);
__variant._M_name); print_word(ctx, type._M_name);
__formatter->_M_print_word(__buf);
} }
else if (__builtin_strcmp(name, "type") == 0)
print_type(ctx, type._M_type, "<unknown type>");
else
return false;
__formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n", return true;
__variant._M_address); }
__formatter->_M_print_word(__buf);
if (__variant._M_type) bool
print_field(PrintContext& ctx,
const char* name, const _Parameter::_Instance& inst)
{
const _Parameter::_Type& type = inst;
if (print_field(ctx, name, type))
{ }
else if (__builtin_strcmp(name, "address") == 0)
{ {
__formatter->_M_print_word(" type = "); char buf[64];
print_type(__formatter, __variant._M_type, "<unknown type>"); int ret = __builtin_sprintf(buf, "%p", inst._M_address);
print_word(ctx, buf, ret);
} }
else
return false;
return true;
} }
}
namespace __gnu_debug
{
void void
_Error_formatter::_Parameter:: print_field(PrintContext& ctx, const _Parameter& param, const char* name)
_M_print_field(const _Error_formatter* __formatter, const char* __name) const
{ {
assert(this->_M_kind != _Parameter::__unused_param); assert(param._M_kind != _Parameter::__unused_param);
const int __bufsize = 64; const int bufsize = 64;
char __buf[__bufsize]; char buf[bufsize];
switch (_M_kind) const auto& variant = param._M_variant;
switch (param._M_kind)
{ {
case __iterator: case _Parameter::__iterator:
if (print_field(__formatter, __name, _M_variant._M_iterator)) {
{ } const auto& iterator = variant._M_iterator;
else if (strcmp(__name, "constness") == 0) if (print_field(ctx, name, iterator))
{ { }
static const char* __constness_names[__last_constness] = else if (__builtin_strcmp(name, "constness") == 0)
{ {
"<unknown>", static const char*
"constant", constness_names[_Error_formatter::__last_constness] =
"mutable" {
}; "<unknown>",
__formatter->_M_print_word(__constness_names[_M_variant. "constant",
_M_iterator. "mutable"
_M_constness]); };
} print_word(ctx, constness_names[iterator._M_constness]);
else if (strcmp(__name, "state") == 0) }
{ else if (__builtin_strcmp(name, "state") == 0)
static const char* __state_names[__last_state] = {
{ static const char*
"<unknown>", state_names[_Error_formatter::__last_state] =
"singular", {
"dereferenceable (start-of-sequence)", "<unknown>",
"dereferenceable", "singular",
"past-the-end", "dereferenceable (start-of-sequence)",
"before-begin" "dereferenceable",
}; "past-the-end",
__formatter->_M_print_word(__state_names[_M_variant. "before-begin"
_M_iterator._M_state]); };
} print_word(ctx, state_names[iterator._M_state]);
else if (strcmp(__name, "sequence") == 0) }
{ else if (__builtin_strcmp(name, "sequence") == 0)
assert(_M_variant._M_iterator._M_sequence); {
__formatter->_M_format_word(__buf, __bufsize, "%p", assert(iterator._M_sequence);
_M_variant._M_iterator._M_sequence); int written = __builtin_sprintf(buf, "%p", iterator._M_sequence);
__formatter->_M_print_word(__buf); print_word(ctx, buf, written);
} }
else if (strcmp(__name, "seq_type") == 0) else if (__builtin_strcmp(name, "seq_type") == 0)
print_type(__formatter, _M_variant._M_iterator._M_seq_type, print_type(ctx, iterator._M_seq_type, "<unknown seq_type>");
"<unknown seq_type>"); else
else assert(false);
assert(false); }
break; break;
case __sequence:
if (!print_field(__formatter, __name, _M_variant._M_sequence)) case _Parameter::__sequence:
if (!print_field(ctx, name, variant._M_sequence))
assert(false); assert(false);
break; break;
case __integer:
if (strcmp(__name, "name") == 0) case _Parameter::__integer:
if (__builtin_strcmp(name, "name") == 0)
{ {
assert(_M_variant._M_integer._M_name); assert(variant._M_integer._M_name);
__formatter->_M_print_word(_M_variant._M_integer._M_name); print_word(ctx, variant._M_integer._M_name);
} }
else else
assert(false); assert(false);
break; break;
case __string:
if (strcmp(__name, "name") == 0) case _Parameter::__string:
if (__builtin_strcmp(name, "name") == 0)
{ {
assert(_M_variant._M_string._M_name); assert(variant._M_string._M_name);
__formatter->_M_print_word(_M_variant._M_string._M_name); print_word(ctx, variant._M_string._M_name);
} }
else else
assert(false); assert(false);
break; break;
case __instance:
if (!print_field(__formatter, __name, _M_variant._M_instance)) case _Parameter::__instance:
if (!print_field(ctx, name, variant._M_instance))
assert(false); assert(false);
break; break;
case __iterator_value_type:
if (!print_field(__formatter, __name, _M_variant._M_iterator_value_type)) case _Parameter::__iterator_value_type:
if (!print_field(ctx, name, variant._M_iterator_value_type))
assert(false); assert(false);
break; break;
default: default:
assert(false); assert(false);
break; break;
...@@ -727,136 +762,296 @@ namespace __gnu_debug ...@@ -727,136 +762,296 @@ namespace __gnu_debug
} }
void void
_Error_formatter::_Parameter:: print_description(PrintContext& ctx, const _Parameter::_Type& type)
_M_print_description(const _Error_formatter* __formatter) const {
if (type._M_name)
{
const int bufsize = 64;
char buf[bufsize];
int written
= format_word(buf, bufsize, "\"%s\"", type._M_name);
print_word(ctx, buf, written);
}
print_word(ctx, " {\n");
if (type._M_type)
{
print_word(ctx, " type = ");
print_type(ctx, type._M_type, "<unknown type>");
print_word(ctx, ";\n");
}
}
void
print_description(PrintContext& ctx, const _Parameter::_Instance& inst)
{ {
const int __bufsize = 128; const int bufsize = 64;
char __buf[__bufsize]; char buf[bufsize];
switch (_M_kind) if (inst._M_name)
{ {
case __iterator: int written
__formatter->_M_print_word("iterator "); = format_word(buf, bufsize, "\"%s\" ", inst._M_name);
print_description(__formatter, _M_variant._M_iterator); print_word(ctx, buf, written);
}
if (_M_variant._M_iterator._M_type) int written
{ = __builtin_sprintf(buf, "@ 0x%p {\n", inst._M_address);
if (_M_variant._M_iterator._M_constness != __unknown_constness) print_word(ctx, buf, written);
{
__formatter->_M_print_word(" (");
_M_print_field(__formatter, "constness");
__formatter->_M_print_word(" iterator)");
}
__formatter->_M_print_word(";\n");
}
if (_M_variant._M_iterator._M_state != __unknown_state) if (inst._M_type)
{ {
__formatter->_M_print_word(" state = "); print_word(ctx, " type = ");
_M_print_field(__formatter, "state"); print_type(ctx, inst._M_type, "<unknown type>");
__formatter->_M_print_word(";\n"); }
} }
if (_M_variant._M_iterator._M_sequence) void
{ print_description(PrintContext& ctx, const _Parameter& param)
__formatter->_M_print_word(" references sequence "); {
if (_M_variant._M_iterator._M_seq_type) const int bufsize = 128;
{ char buf[bufsize];
__formatter->_M_print_word("with type `");
_M_print_field(__formatter, "seq_type");
__formatter->_M_print_word("' ");
}
__formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n", const auto& variant = param._M_variant;
_M_variant._M_iterator._M_sequence); switch (param._M_kind)
__formatter->_M_print_word(__buf); {
} case _Parameter::__iterator:
{
const auto& ite = variant._M_iterator;
print_word(ctx, "iterator ");
print_description(ctx, ite);
__formatter->_M_print_word("}\n"); if (ite._M_type)
{
if (ite._M_constness != _Error_formatter::__unknown_constness)
{
print_word(ctx, " (");
print_field(ctx, param, "constness");
print_word(ctx, " iterator)");
}
print_word(ctx, ";\n");
}
if (ite._M_state != _Error_formatter::__unknown_state)
{
print_word(ctx, " state = ");
print_field(ctx, param, "state");
print_word(ctx, ";\n");
}
if (ite._M_sequence)
{
print_word(ctx, " references sequence ");
if (ite._M_seq_type)
{
print_word(ctx, "with type '");
print_field(ctx, param, "seq_type");
print_word(ctx, "' ");
}
int written
= __builtin_sprintf(buf, "@ 0x%p\n", ite._M_sequence);
print_word(ctx, buf, written);
}
print_word(ctx, "}\n", 2);
}
break; break;
case __sequence:
__formatter->_M_print_word("sequence ");
print_description(__formatter, _M_variant._M_sequence);
if (_M_variant._M_sequence._M_type) case _Parameter::__sequence:
__formatter->_M_print_word(";\n"); print_word(ctx, "sequence ");
print_description(ctx, variant._M_sequence);
__formatter->_M_print_word("}\n"); if (variant._M_sequence._M_type)
print_word(ctx, ";\n", 2);
print_word(ctx, "}\n", 2);
break; break;
case __instance:
__formatter->_M_print_word("instance ");
print_description(__formatter, _M_variant._M_instance);
if (_M_variant._M_instance._M_type) case _Parameter::__instance:
__formatter->_M_print_word(";\n"); print_word(ctx, "instance ");
print_description(ctx, variant._M_instance);
if (variant._M_instance._M_type)
print_word(ctx, ";\n", 2);
__formatter->_M_print_word("}\n"); print_word(ctx, "}\n", 2);
break; break;
case __iterator_value_type:
__formatter->_M_print_word("iterator::value_type "); case _Parameter::__iterator_value_type:
print_description(__formatter, _M_variant._M_iterator_value_type); print_word(ctx, "iterator::value_type ");
__formatter->_M_print_word("}\n"); print_description(ctx, variant._M_iterator_value_type);
print_word(ctx, "}\n", 2);
break; break;
default: default:
break; break;
} }
} }
const _Error_formatter& void
print_string(PrintContext& ctx, const char* string,
const _Parameter* parameters, std::size_t num_parameters)
{
const char* start = string;
const int bufsize = 128;
char buf[bufsize];
int bufindex = 0;
while (*start)
{
if (isspace(*start))
{
buf[bufindex++] = *start++;
buf[bufindex] = '\0';
print_word(ctx, buf, bufindex);
bufindex = 0;
continue;
}
if (*start != '%')
{
// Normal char.
buf[bufindex++] = *start++;
continue;
}
if (*++start == '%')
{
// Escaped '%'
buf[bufindex++] = *start++;
continue;
}
// We are on a parameter property reference, we need to flush buffer
// first.
if (bufindex != 0)
{
buf[bufindex] = '\0';
print_word(ctx, buf, bufindex);
bufindex = 0;
}
// Get the parameter number
assert(*start >= '1' && *start <= '9');
size_t param_index = *start - '0' - 1;
assert(param_index < num_parameters);
const auto& param = parameters[param_index];
// '.' separates the parameter number from the field
// name, if there is one.
++start;
if (*start != '.')
{
assert(*start == ';');
++start;
if (param._M_kind == _Parameter::__integer)
{
int written
= __builtin_sprintf(buf, "%ld",
param._M_variant._M_integer._M_value);
print_word(ctx, buf, written);
}
else if (param._M_kind == _Parameter::__string)
print_string(ctx, param._M_variant._M_string._M_value,
parameters, num_parameters);
continue;
}
// Extract the field name we want
const int max_field_len = 16;
char field[max_field_len];
int field_idx = 0;
++start;
while (*start != ';')
{
assert(*start);
assert(field_idx < max_field_len - 1);
field[field_idx++] = *start++;
}
++start;
field[field_idx] = '\0';
print_field(ctx, param, field);
}
// Might need to flush.
if (bufindex)
{
buf[bufindex] = '\0';
print_word(ctx, buf, bufindex);
}
}
}
namespace __gnu_debug
{
_Error_formatter&
_Error_formatter::_M_message(_Debug_msg_id __id) const throw () _Error_formatter::_M_message(_Debug_msg_id __id) const throw ()
{ return this->_M_message(_S_debug_messages[__id]); } {
return const_cast<_Error_formatter*>(this)
->_M_message(_S_debug_messages[__id]);
}
void void
_Error_formatter::_M_error() const _Error_formatter::_M_error() const
{ {
const int __bufsize = 128; const int bufsize = 128;
char __buf[__bufsize]; char buf[bufsize];
// Emit file & line number information // Emit file & line number information
_M_column = 1; bool go_to_next_line = false;
_M_wordwrap = false; PrintContext ctx;
if (_M_file) if (_M_file)
{ {
_M_format_word(__buf, __bufsize, "%s:", _M_file); int written = format_word(buf, bufsize, "%s:", _M_file);
_M_print_word(__buf); print_word(ctx, buf, written);
_M_column += strlen(__buf); go_to_next_line = true;
} }
if (_M_line > 0) if (_M_line > 0)
{ {
_M_format_word(__buf, __bufsize, "%u:", _M_line); int written = __builtin_sprintf(buf, "%u:", _M_line);
_M_print_word(__buf); print_word(ctx, buf, written);
_M_column += strlen(__buf); go_to_next_line = true;
} }
if (_M_max_length) if (go_to_next_line)
_M_wordwrap = true; print_word(ctx, "\n", 1);
_M_print_word("error: ");
if (ctx._M_max_length)
ctx._M_wordwrap = true;
print_word(ctx, "Error: ");
// Print the error message // Print the error message
assert(_M_text); assert(_M_text);
_M_print_string(_M_text); print_string(ctx, _M_text, _M_parameters, _M_num_parameters);
_M_print_word(".\n"); print_word(ctx, ".\n", 2);
// Emit descriptions of the objects involved in the operation // Emit descriptions of the objects involved in the operation
_M_wordwrap = false; ctx._M_first_line = true;
bool __has_noninteger_parameters = false; ctx._M_wordwrap = false;
for (unsigned int __i = 0; __i < _M_num_parameters; ++__i) bool has_header = false;
for (unsigned int i = 0; i < _M_num_parameters; ++i)
{ {
switch (_M_parameters[__i]._M_kind) switch (_M_parameters[i]._M_kind)
{ {
case _Parameter::__iterator: case _Parameter::__iterator:
case _Parameter::__sequence: case _Parameter::__sequence:
case _Parameter::__instance: case _Parameter::__instance:
case _Parameter::__iterator_value_type: case _Parameter::__iterator_value_type:
if (!__has_noninteger_parameters) if (!has_header)
{ {
_M_first_line = true; print_word(ctx, "\nObjects involved in the operation:\n");
_M_print_word("\nObjects involved in the operation:\n"); has_header = true;
__has_noninteger_parameters = true;
} }
_M_parameters[__i]._M_print_description(this); print_description(ctx, _M_parameters[i]);
break; break;
default: default:
break; break;
} }
...@@ -865,172 +1060,39 @@ namespace __gnu_debug ...@@ -865,172 +1060,39 @@ namespace __gnu_debug
abort(); abort();
} }
template<typename _Tp> // Deprecated methods kept for backward compatibility.
void
_Error_formatter::_M_format_word(char* __buf,
int __n __attribute__ ((__unused__)),
const char* __fmt, _Tp __s) const throw ()
{
#ifdef _GLIBCXX_USE_C99
std::snprintf(__buf, __n, __fmt, __s);
#else
std::sprintf(__buf, __fmt, __s);
#endif
}
void void
_Error_formatter::_M_print_word(const char* __word) const _Error_formatter::_Parameter::_M_print_field(
{ const _Error_formatter*, const char*) const
if (!_M_wordwrap) { }
{
fprintf(stderr, "%s", __word);
return;
}
size_t __length = strlen(__word);
if (__length == 0)
return;
size_t __visual_length
= __word[__length - 1] == '\n' ? __length - 1 : __length;
if (__visual_length == 0
|| (_M_column + __visual_length < _M_max_length)
|| (__visual_length >= _M_max_length && _M_column == 1))
{
// If this isn't the first line, indent
if (_M_column == 1 && !_M_first_line)
{
char __spacing[_M_indent + 1];
for (int i = 0; i < _M_indent; ++i)
__spacing[i] = ' ';
__spacing[_M_indent] = '\0';
fprintf(stderr, "%s", __spacing);
_M_column += _M_indent;
}
fprintf(stderr, "%s", __word);
if (__word[__length - 1] == '\n')
{
_M_first_line = false;
_M_column = 1;
}
else
_M_column += __length;
}
else
{
_M_print_word("\n");
_M_print_word(__word);
}
}
void void
_Error_formatter:: _Error_formatter::_Parameter::_M_print_description(const _Error_formatter*) const
_M_print_string(const char* __string) const { }
{
const char* __start = __string;
const char* __finish = __start;
const int __bufsize = 128;
char __buf[__bufsize];
while (*__start) template<typename _Tp>
{ void
if (*__start != '%') _Error_formatter::_M_format_word(char*, int, const char*, _Tp)
{ const throw ()
// [__start, __finish) denotes the next word { }
__finish = __start;
while (isalnum(*__finish))
++__finish;
if (__start == __finish)
++__finish;
if (isspace(*__finish))
++__finish;
const ptrdiff_t __len = __finish - __start;
assert(__len < __bufsize);
memcpy(__buf, __start, __len);
__buf[__len] = '\0';
_M_print_word(__buf);
__start = __finish;
// Skip extra whitespace
while (*__start == ' ')
++__start;
continue;
}
++__start;
assert(*__start);
if (*__start == '%')
{
_M_print_word("%");
++__start;
continue;
}
// Get the parameter number
assert(*__start >= '1' && *__start <= '9');
size_t __param_index = *__start - '0' - 1;
assert(__param_index < _M_num_parameters);
const auto& __param = _M_parameters[__param_index];
// '.' separates the parameter number from the field
// name, if there is one.
++__start;
if (*__start != '.')
{
assert(*__start == ';');
++__start;
__buf[0] = '\0';
if (__param._M_kind == _Parameter::__integer)
{
_M_format_word(__buf, __bufsize, "%ld",
__param._M_variant._M_integer._M_value);
_M_print_word(__buf);
}
else if (__param._M_kind == _Parameter::__string)
_M_print_string(__param._M_variant._M_string._M_value);
continue;
}
// Extract the field name we want void
enum { __max_field_len = 16 }; _Error_formatter::_M_print_word(const char*) const
char __field[__max_field_len]; { }
int __field_idx = 0;
++__start;
while (*__start != ';')
{
assert(*__start);
assert(__field_idx < __max_field_len-1);
__field[__field_idx++] = *__start++;
}
++__start;
__field[__field_idx] = 0;
__param._M_print_field(this, __field); void
} _Error_formatter::_M_print_string(const char*) const
} { }
void void
_Error_formatter::_M_get_max_length() const throw () _Error_formatter::_M_get_max_length() const throw ()
{ { }
const char* __nptr = std::getenv("GLIBCXX_DEBUG_MESSAGE_LENGTH");
if (__nptr)
{
char* __endptr;
const unsigned long __ret = std::strtoul(__nptr, &__endptr, 0);
if (*__nptr != '\0' && *__endptr == '\0')
_M_max_length = __ret;
}
}
// Instantiations. // Instantiations.
template template
void void
_Error_formatter::_M_format_word(char*, int, const char*, _Error_formatter::_M_format_word(char*, int, const char*,
const void*) const; const void*) const;
template template
void void
...@@ -1039,10 +1101,10 @@ namespace __gnu_debug ...@@ -1039,10 +1101,10 @@ namespace __gnu_debug
template template
void void
_Error_formatter::_M_format_word(char*, int, const char*, _Error_formatter::_M_format_word(char*, int, const char*,
std::size_t) const; std::size_t) const;
template template
void void
_Error_formatter::_M_format_word(char*, int, const char*, _Error_formatter::_M_format_word(char*, int, const char*,
const char*) const; const char*) const;
} // namespace __gnu_debug } // namespace __gnu_debug
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment