libstdc++: Add pretty printer for std::locale

Print the locale's name, except when it uses the same named C locale for
all categories except one, in which case print something like:
std::locale = "en_GB.UTF-8" with "LC_CTYPE=en_US.UTF-8"

libstdc++-v3/ChangeLog:

	* python/libstdcxx/v6/printers.py (StdLocalePrinter): New
	printer class.
	* testsuite/libstdc++-prettyprinters/locale.cc: New test.
This commit is contained in:
Jonathan Wakely 2023-08-23 12:10:16 +01:00
parent 701ce3c723
commit 3d2e240af7
2 changed files with 81 additions and 0 deletions

View file

@ -2131,6 +2131,50 @@ class StdChronoTimeZoneRulePrinter:
return 'time_zone rule {} from {} to {} starting on {}'.format(
self.val['name'], self.val['from'], self.val['to'], start)
class StdLocalePrinter:
"Print a std::locale"
def __init__(self, typename, val):
self.val = val
self.typename = typename
def to_string(self):
names = self.val['_M_impl']['_M_names']
mod = ''
if names[0] == 0:
name = '*'
else:
cats = gdb.parse_and_eval(self.typename + '::_S_categories')
ncat = gdb.parse_and_eval(self.typename + '::_S_categories_size')
n = names[0].string();
cat = cats[0].string()
name = '{}={}'.format(cat, n)
cat_names = {cat: n}
i = 1
while i < ncat and names[i] != 0:
n = names[i].string()
cat = cats[i].string()
name = '{};{}={}'.format(name, cat, n)
cat_names[cat] = n
i = i + 1
uniq_names = set(cat_names.values())
if len(uniq_names) == 1:
name = n
elif len(uniq_names) == 2:
n1, n2 = (uniq_names)
name_list = list(cat_names.values())
other = None
if name_list.count(n1) == 1:
name = n2
other = n1
elif name_list.count(n2) == 1:
name = n1
other = n2
if other is not None:
cat = next(c for c,n in cat_names.items() if n == other)
mod = ' with "{}={}"'.format(cat, other)
return 'std::locale = "{}"{}'.format(name, mod)
# A "regular expression" printer which conforms to the
# "SubPrettyPrinter" protocol from gdb.printing.
@ -2585,6 +2629,7 @@ def build_libstdcxx_dictionary ():
libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter)
libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter)
# vector<bool>
libstdcxx_printer.add_version('std::', 'locale', StdLocalePrinter)
if hasattr(gdb.Value, 'dynamic_type'):
libstdcxx_printer.add_version('std::', 'error_code',

View file

@ -0,0 +1,36 @@
// { dg-do run }
// { dg-options "-g -O0" }
// { dg-require-namedlocale "fr_FR.ISO8859-15" }
// { dg-require-namedlocale "de_DE.ISO8859-15" }
// { dg-require-namedlocale "en_US.ISO8859-1" }
#include <locale>
#include <testsuite_hooks.h> // for ISO_8859 macro
int main()
{
std::locale l1 = std::locale::classic();
// { dg-final { note-test l1 {std::locale = "C"} } }
std::locale l2(ISO_8859(15,fr_FR));
// { dg-final { regexp-test l2 {std::locale = "fr_FR.ISO8859-15(@euro)?"} } }
std::locale l3(l2, ISO_8859(15,de_DE), std::locale::time);
// { dg-final { regexp-test l3 {std::locale = "fr_FR.ISO8859-15(@euro)?" with "LC_TIME=de_DE.ISO8859-15(@euro)?"} } }
std::locale l4(l3, ISO_8859(1,en_US), std::locale::monetary);
// We don't know which order the categories will occur in the string,
// so test three times, checking for the required substring each time:
// { dg-final { regexp-test l4 {std::locale = "(.*;)?LC_CTYPE=fr_FR.ISO8859-15(@euro)?(;.*)?"} } }
std::locale l5 = l4;
// { dg-final { regexp-test l5 {std::locale = "(.*;)?LC_TIME=de_DE.ISO8859-15(@euro)?(;.*)?"} } }
std::locale l6 = l5;
// { dg-final { regexp-test l6 {std::locale = "(.*;)?LC_MONETARY=en_US.ISO8859-1(;.*)?"} } }
std::locale l7(l1, &std::use_facet<std::ctype<char> >(l1));
// { dg-final { regexp-test l7 {std::locale = "\*"} } }
return 0; // Mark SPOT
}
// { dg-final { gdb-test SPOT } }