diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index a1b0c3545f8..b11698426b4 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,19 @@ +2015-09-17 François Dumont + + * 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 PR libstdc++/65913 diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h index 9fc23c828fc..72735bbf9e8 100644 --- a/libstdc++-v3/include/debug/formatter.h +++ b/libstdc++-v3/include/debug/formatter.h @@ -132,6 +132,13 @@ namespace __gnu_debug 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 enum _Constness { @@ -153,13 +160,6 @@ namespace __gnu_debug __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 struct _Parameter { @@ -375,15 +375,16 @@ namespace __gnu_debug void _M_print_field(const _Error_formatter* __formatter, - const char* __name) const; + const char* __name) const _GLIBCXX_DEPRECATED; void - _M_print_description(const _Error_formatter* __formatter) const; + _M_print_description(const _Error_formatter* __formatter) + const _GLIBCXX_DEPRECATED; }; template - const _Error_formatter& - _M_iterator(const _Iterator& __it, const char* __name = 0) const + _Error_formatter& + _M_iterator(const _Iterator& __it, const char* __name = 0) { if (_M_num_parameters < std::size_t(__max_parameters)) _M_parameters[_M_num_parameters++] = _Parameter(__it, __name, @@ -392,57 +393,59 @@ namespace __gnu_debug } template - const _Error_formatter& + _Error_formatter& _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++] = _Parameter(__it, __name, _Is_iterator_value_type()); return *this; } - const _Error_formatter& - _M_integer(long __value, const char* __name = 0) const + _Error_formatter& + _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); return *this; } - const _Error_formatter& - _M_string(const char* __value, const char* __name = 0) const + _Error_formatter& + _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); return *this; } template - const _Error_formatter& - _M_sequence(const _Sequence& __seq, const char* __name = 0) const + _Error_formatter& + _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, _Is_sequence()); return *this; } template - const _Error_formatter& - _M_instance(const _Type& __inst, const char* __name = 0) const + _Error_formatter& + _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, _Is_instance()); return *this; } - const _Error_formatter& - _M_message(const char* __text) const + _Error_formatter& + _M_message(const char* __text) { _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 (); _GLIBCXX_NORETURN void @@ -450,40 +453,38 @@ namespace __gnu_debug template void - _M_format_word(char*, int, const char*, _Tp) const throw (); + _M_format_word(char*, int, const char*, _Tp) + const throw () _GLIBCXX_DEPRECATED; void - _M_print_word(const char* __word) const; + _M_print_word(const char* __word) const _GLIBCXX_DEPRECATED; void - _M_print_string(const char* __string) const; + _M_print_string(const char* __string) const _GLIBCXX_DEPRECATED; private: - _Error_formatter(const char* __file, std::size_t __line) - : _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(); } + _Error_formatter(const char* __file, unsigned int __line) + : _M_file(__file), _M_line(__line), _M_num_parameters(0), _M_text(0) + { } void - _M_get_max_length() const throw (); + _M_get_max_length() const throw () _GLIBCXX_DEPRECATED; enum { __max_parameters = 9 }; const char* _M_file; - std::size_t _M_line; - mutable _Parameter _M_parameters[__max_parameters]; - mutable std::size_t _M_num_parameters; - mutable 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; + unsigned int _M_line; + _Parameter _M_parameters[__max_parameters]; + unsigned int _M_num_parameters; + const char* _M_text; public: - static _Error_formatter - _M_at(const char* __file, std::size_t __line) - { return _Error_formatter(__file, __line); } + static _Error_formatter& + _M_at(const char* __file, unsigned int __line) + { + static _Error_formatter __formatter(__file, __line); + return __formatter; + } }; } // namespace __gnu_debug diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc index ac3ac67b49e..ae56c30273f 100644 --- a/libstdc++-v3/src/c++11/debug.cc +++ b/libstdc++-v3/src/c++11/debug.cc @@ -22,18 +22,19 @@ // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . -#include +#include +#include + +#include #include #include #include #include -#include + #include -#include -#include -#include -#include -#include + +#include // for std::min +#include // for _Hash_impl #include // for __cxa_demangle @@ -524,37 +525,123 @@ namespace __gnu_debug namespace { + using _Error_formatter = __gnu_debug::_Error_formatter; + using _Parameter = __gnu_debug::_Error_formatter::_Parameter; + + template + int + format_word(char* buf, int n, const char* fmt, _Tp s) + { return std::min(__builtin_snprintf(buf, n, fmt, s), n - 1); } + void - print_type(const __gnu_debug::_Error_formatter* __formatter, - const type_info* __info, - const char* __unknown_name) + get_max_length(std::size_t& max_length) { - if (!__info) - __formatter->_M_print_word(__unknown_name); + 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') + max_length = ret; + } + } + + struct PrintContext + { + PrintContext() + : _M_max_length(78), _M_column(1), _M_first_line(true), _M_wordwrap(false) + { get_max_length(_M_max_length); } + + std::size_t _M_max_length; + enum { _M_indent = 4 } ; + std::size_t _M_column; + bool _M_first_line; + bool _M_wordwrap; + }; + + void + print_word(PrintContext& ctx, const char* word, + std::ptrdiff_t count = -1) + { + size_t length = count >= 0 ? count : __builtin_strlen(word); + if (length == 0) + return; + + // Consider first '\n' at begining cause it impacts column. + if (word[0] == '\n') + { + fprintf(stderr, "\n"); + ctx._M_column = 1; + ++word; + --length; + + if (length == 0) + return; + } + + size_t visual_length + = isspace(word[length - 1]) ? length - 1 : length; + if (visual_length == 0 + || !ctx._M_wordwrap + || (ctx._M_column + visual_length < ctx._M_max_length) + || (visual_length >= ctx._M_max_length && ctx._M_column == 1)) + { + // If this isn't the first line, indent + if (ctx._M_column == 1 && !ctx._M_first_line) + { + char spacing[ctx._M_indent + 1]; + 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; + } + + int written = fprintf(stderr, "%s", word); + + if (word[length - 1] == '\n') + { + ctx._M_first_line = false; + ctx._M_column = 1; + } + else + ctx._M_column += written; + } else { - int __status; - char* __demangled_name = - __cxxabiv1::__cxa_demangle(__info->name(), NULL, NULL, &__status); - __formatter->_M_print_word(__status == 0 - ? __demangled_name : __info->name()); - free(__demangled_name); + print_word(ctx, "\n", 1); + print_word(ctx, word, count); + } + } + + void + print_type(PrintContext& ctx, + const type_info* info, + const char* unknown_name) + { + if (!info) + 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); } } bool - print_field( - const __gnu_debug::_Error_formatter* __formatter, - const char* __name, - const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant) + print_field(PrintContext& ctx, + const char* name, const _Parameter::_Type& type) { - if (strcmp(__name, "name") == 0) + if (__builtin_strcmp(name, "name") == 0) { - assert(__variant._M_name); - __formatter->_M_print_word(__variant._M_name); + assert(type._M_name); + print_word(ctx, type._M_name); } - else if (strcmp(__name, "type") == 0) - print_type(__formatter, __variant._M_type, ""); + else if (__builtin_strcmp(name, "type") == 0) + print_type(ctx, type._M_type, ""); else return false; @@ -562,21 +649,17 @@ namespace } bool - print_field( - const __gnu_debug::_Error_formatter* __formatter, - const char* __name, - const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant) + print_field(PrintContext& ctx, + const char* name, const _Parameter::_Instance& inst) { - const __gnu_debug::_Error_formatter::_Parameter::_Type& __type = __variant; - if (print_field(__formatter, __name, __type)) + const _Parameter::_Type& type = inst; + if (print_field(ctx, name, type)) { } - else if (strcmp(__name, "address") == 0) + else if (__builtin_strcmp(name, "address") == 0) { - const int __bufsize = 64; - char __buf[__bufsize]; - __formatter->_M_format_word(__buf, __bufsize, "%p", - __variant._M_address); - __formatter->_M_print_word(__buf); + char buf[64]; + int ret = __builtin_sprintf(buf, "%p", inst._M_address); + print_word(ctx, buf, ret); } else return false; @@ -585,141 +668,93 @@ namespace } void - print_description( - const __gnu_debug::_Error_formatter* __formatter, - const __gnu_debug::_Error_formatter::_Parameter::_Type& __variant) + print_field(PrintContext& ctx, const _Parameter& param, const char* name) { - if (__variant._M_name) - { - const int __bufsize = 64; - char __buf[__bufsize]; - __formatter->_M_format_word(__buf, __bufsize, "\"%s\"", - __variant._M_name); - __formatter->_M_print_word(__buf); - } + assert(param._M_kind != _Parameter::__unused_param); + const int bufsize = 64; + char buf[bufsize]; - __formatter->_M_print_word(" {\n"); - - if (__variant._M_type) - { - __formatter->_M_print_word(" type = "); - print_type(__formatter, __variant._M_type, ""); - __formatter->_M_print_word(";\n"); - } - } - - - void - print_description( - const __gnu_debug::_Error_formatter* __formatter, - const __gnu_debug::_Error_formatter::_Parameter::_Instance& __variant) - { - const int __bufsize = 64; - char __buf[__bufsize]; - - if (__variant._M_name) - { - __formatter->_M_format_word(__buf, __bufsize, "\"%s\" ", - __variant._M_name); - __formatter->_M_print_word(__buf); - } - - __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p {\n", - __variant._M_address); - __formatter->_M_print_word(__buf); - - if (__variant._M_type) - { - __formatter->_M_print_word(" type = "); - print_type(__formatter, __variant._M_type, ""); - } - } -} - -namespace __gnu_debug -{ - void - _Error_formatter::_Parameter:: - _M_print_field(const _Error_formatter* __formatter, const char* __name) const - { - assert(this->_M_kind != _Parameter::__unused_param); - const int __bufsize = 64; - char __buf[__bufsize]; - - switch (_M_kind) + const auto& variant = param._M_variant; + switch (param._M_kind) { - case __iterator: - if (print_field(__formatter, __name, _M_variant._M_iterator)) - { } - else if (strcmp(__name, "constness") == 0) - { - static const char* __constness_names[__last_constness] = - { - "", - "constant", - "mutable" - }; - __formatter->_M_print_word(__constness_names[_M_variant. - _M_iterator. - _M_constness]); - } - else if (strcmp(__name, "state") == 0) - { - static const char* __state_names[__last_state] = - { - "", - "singular", - "dereferenceable (start-of-sequence)", - "dereferenceable", - "past-the-end", - "before-begin" - }; - __formatter->_M_print_word(__state_names[_M_variant. - _M_iterator._M_state]); - } - else if (strcmp(__name, "sequence") == 0) - { - assert(_M_variant._M_iterator._M_sequence); - __formatter->_M_format_word(__buf, __bufsize, "%p", - _M_variant._M_iterator._M_sequence); - __formatter->_M_print_word(__buf); - } - else if (strcmp(__name, "seq_type") == 0) - print_type(__formatter, _M_variant._M_iterator._M_seq_type, - ""); - else + case _Parameter::__iterator: + { + const auto& iterator = variant._M_iterator; + if (print_field(ctx, name, iterator)) + { } + else if (__builtin_strcmp(name, "constness") == 0) + { + static const char* + constness_names[_Error_formatter::__last_constness] = + { + "", + "constant", + "mutable" + }; + print_word(ctx, constness_names[iterator._M_constness]); + } + else if (__builtin_strcmp(name, "state") == 0) + { + static const char* + state_names[_Error_formatter::__last_state] = + { + "", + "singular", + "dereferenceable (start-of-sequence)", + "dereferenceable", + "past-the-end", + "before-begin" + }; + print_word(ctx, state_names[iterator._M_state]); + } + else if (__builtin_strcmp(name, "sequence") == 0) + { + assert(iterator._M_sequence); + int written = __builtin_sprintf(buf, "%p", iterator._M_sequence); + print_word(ctx, buf, written); + } + else if (__builtin_strcmp(name, "seq_type") == 0) + print_type(ctx, iterator._M_seq_type, ""); + else + assert(false); + } + break; + + case _Parameter::__sequence: + if (!print_field(ctx, name, variant._M_sequence)) assert(false); break; - case __sequence: - if (!print_field(__formatter, __name, _M_variant._M_sequence)) - assert(false); - break; - case __integer: - if (strcmp(__name, "name") == 0) + + case _Parameter::__integer: + if (__builtin_strcmp(name, "name") == 0) { - assert(_M_variant._M_integer._M_name); - __formatter->_M_print_word(_M_variant._M_integer._M_name); + assert(variant._M_integer._M_name); + print_word(ctx, variant._M_integer._M_name); } else assert(false); break; - case __string: - if (strcmp(__name, "name") == 0) + + case _Parameter::__string: + if (__builtin_strcmp(name, "name") == 0) { - assert(_M_variant._M_string._M_name); - __formatter->_M_print_word(_M_variant._M_string._M_name); + assert(variant._M_string._M_name); + print_word(ctx, variant._M_string._M_name); } else assert(false); 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); 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); break; + default: assert(false); break; @@ -727,136 +762,296 @@ namespace __gnu_debug } void - _Error_formatter::_Parameter:: - _M_print_description(const _Error_formatter* __formatter) const + print_description(PrintContext& ctx, const _Parameter::_Type& type) { - const int __bufsize = 128; - char __buf[__bufsize]; - - switch (_M_kind) + if (type._M_name) { - case __iterator: - __formatter->_M_print_word("iterator "); - print_description(__formatter, _M_variant._M_iterator); + const int bufsize = 64; + char buf[bufsize]; + int written + = format_word(buf, bufsize, "\"%s\"", type._M_name); + print_word(ctx, buf, written); + } - if (_M_variant._M_iterator._M_type) - { - if (_M_variant._M_iterator._M_constness != __unknown_constness) - { - __formatter->_M_print_word(" ("); - _M_print_field(__formatter, "constness"); - __formatter->_M_print_word(" iterator)"); - } - __formatter->_M_print_word(";\n"); - } + print_word(ctx, " {\n"); - if (_M_variant._M_iterator._M_state != __unknown_state) - { - __formatter->_M_print_word(" state = "); - _M_print_field(__formatter, "state"); - __formatter->_M_print_word(";\n"); - } + if (type._M_type) + { + print_word(ctx, " type = "); + print_type(ctx, type._M_type, ""); + print_word(ctx, ";\n"); + } + } - if (_M_variant._M_iterator._M_sequence) - { - __formatter->_M_print_word(" references sequence "); - if (_M_variant._M_iterator._M_seq_type) - { - __formatter->_M_print_word("with type `"); - _M_print_field(__formatter, "seq_type"); - __formatter->_M_print_word("' "); - } + void + print_description(PrintContext& ctx, const _Parameter::_Instance& inst) + { + const int bufsize = 64; + char buf[bufsize]; - __formatter->_M_format_word(__buf, __bufsize, "@ 0x%p\n", - _M_variant._M_iterator._M_sequence); - __formatter->_M_print_word(__buf); - } + if (inst._M_name) + { + int written + = format_word(buf, bufsize, "\"%s\" ", inst._M_name); + print_word(ctx, buf, written); + } - __formatter->_M_print_word("}\n"); + int written + = __builtin_sprintf(buf, "@ 0x%p {\n", inst._M_address); + print_word(ctx, buf, written); + + if (inst._M_type) + { + print_word(ctx, " type = "); + print_type(ctx, inst._M_type, ""); + } + } + + void + print_description(PrintContext& ctx, const _Parameter& param) + { + const int bufsize = 128; + char buf[bufsize]; + + const auto& variant = param._M_variant; + switch (param._M_kind) + { + case _Parameter::__iterator: + { + const auto& ite = variant._M_iterator; + + print_word(ctx, "iterator "); + print_description(ctx, ite); + + 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; - case __sequence: - __formatter->_M_print_word("sequence "); - print_description(__formatter, _M_variant._M_sequence); - if (_M_variant._M_sequence._M_type) - __formatter->_M_print_word(";\n"); + case _Parameter::__sequence: + 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; - case __instance: - __formatter->_M_print_word("instance "); - print_description(__formatter, _M_variant._M_instance); - if (_M_variant._M_instance._M_type) - __formatter->_M_print_word(";\n"); + case _Parameter::__instance: + print_word(ctx, "instance "); + print_description(ctx, variant._M_instance); - __formatter->_M_print_word("}\n"); + if (variant._M_instance._M_type) + print_word(ctx, ";\n", 2); + + print_word(ctx, "}\n", 2); break; - case __iterator_value_type: - __formatter->_M_print_word("iterator::value_type "); - print_description(__formatter, _M_variant._M_iterator_value_type); - __formatter->_M_print_word("}\n"); + + case _Parameter::__iterator_value_type: + print_word(ctx, "iterator::value_type "); + print_description(ctx, variant._M_iterator_value_type); + print_word(ctx, "}\n", 2); break; + default: 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 () - { return this->_M_message(_S_debug_messages[__id]); } + { + return const_cast<_Error_formatter*>(this) + ->_M_message(_S_debug_messages[__id]); + } void _Error_formatter::_M_error() const { - const int __bufsize = 128; - char __buf[__bufsize]; + const int bufsize = 128; + char buf[bufsize]; // Emit file & line number information - _M_column = 1; - _M_wordwrap = false; + bool go_to_next_line = false; + PrintContext ctx; if (_M_file) { - _M_format_word(__buf, __bufsize, "%s:", _M_file); - _M_print_word(__buf); - _M_column += strlen(__buf); + int written = format_word(buf, bufsize, "%s:", _M_file); + print_word(ctx, buf, written); + go_to_next_line = true; } if (_M_line > 0) { - _M_format_word(__buf, __bufsize, "%u:", _M_line); - _M_print_word(__buf); - _M_column += strlen(__buf); + int written = __builtin_sprintf(buf, "%u:", _M_line); + print_word(ctx, buf, written); + go_to_next_line = true; } - if (_M_max_length) - _M_wordwrap = true; - _M_print_word("error: "); + if (go_to_next_line) + print_word(ctx, "\n", 1); + + if (ctx._M_max_length) + ctx._M_wordwrap = true; + + print_word(ctx, "Error: "); // Print the error message assert(_M_text); - _M_print_string(_M_text); - _M_print_word(".\n"); + print_string(ctx, _M_text, _M_parameters, _M_num_parameters); + print_word(ctx, ".\n", 2); // Emit descriptions of the objects involved in the operation - _M_wordwrap = false; - bool __has_noninteger_parameters = false; - for (unsigned int __i = 0; __i < _M_num_parameters; ++__i) + ctx._M_first_line = true; + ctx._M_wordwrap = false; + 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::__sequence: case _Parameter::__instance: case _Parameter::__iterator_value_type: - if (!__has_noninteger_parameters) + if (!has_header) { - _M_first_line = true; - _M_print_word("\nObjects involved in the operation:\n"); - __has_noninteger_parameters = true; + print_word(ctx, "\nObjects involved in the operation:\n"); + has_header = true; } - _M_parameters[__i]._M_print_description(this); + print_description(ctx, _M_parameters[i]); break; + default: break; } @@ -865,172 +1060,39 @@ namespace __gnu_debug abort(); } + // Deprecated methods kept for backward compatibility. + void + _Error_formatter::_Parameter::_M_print_field( + const _Error_formatter*, const char*) const + { } + + void + _Error_formatter::_Parameter::_M_print_description(const _Error_formatter*) const + { } + template 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 - } + _Error_formatter::_M_format_word(char*, int, const char*, _Tp) + const throw () + { } void - _Error_formatter::_M_print_word(const char* __word) 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); - } - } + _Error_formatter::_M_print_word(const char*) const + { } void - _Error_formatter:: - _M_print_string(const char* __string) const - { - const char* __start = __string; - const char* __finish = __start; - const int __bufsize = 128; - char __buf[__bufsize]; - - while (*__start) - { - if (*__start != '%') - { - // [__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 - enum { __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; - - __param._M_print_field(this, __field); - } - } + _Error_formatter::_M_print_string(const char*) const + { } void _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. template void _Error_formatter::_M_format_word(char*, int, const char*, - const void*) const; + const void*) const; template void @@ -1039,10 +1101,10 @@ namespace __gnu_debug template void _Error_formatter::_M_format_word(char*, int, const char*, - std::size_t) const; + std::size_t) const; template void _Error_formatter::_M_format_word(char*, int, const char*, - const char*) const; + const char*) const; } // namespace __gnu_debug