diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /solenv/gdb | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
27 files changed, 3981 insertions, 0 deletions
diff --git a/solenv/gdb/autoload.template b/solenv/gdb/autoload.template new file mode 100644 index 000000000..fdbcce200 --- /dev/null +++ b/solenv/gdb/autoload.template @@ -0,0 +1,32 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import importlib +import os.path +import sys + +import gdb + +PP_PATH = os.path.normpath('%PYTHONDIR%') + +if gdb.current_objfile(): + if PP_PATH not in sys.path: + sys.path.insert(0, PP_PATH) + +for mod in '%MODULES%'.split(): + module = importlib.import_module('libreoffice.' + mod) + module.register_pretty_printers(gdb.current_objfile()) + +try: + import boost + boost.register_pretty_printers(gdb) +except: + pass + +# vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/boost/__init__.py b/solenv/gdb/boost/__init__.py new file mode 100644 index 000000000..353ee3b09 --- /dev/null +++ b/solenv/gdb/boost/__init__.py @@ -0,0 +1,32 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# GDB pretty printers for Boost. +# +# Copyright (C) 2012 Red Hat, Inc., David Tardon <dtardon@redhat.com> +# +# This file is part of boost-gdb-printers. +# +# 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/>. + +import boost.optional +import boost.ptr_container +import boost.smart_ptr +import boost.unordered + +def register_pretty_printers(obj): + boost.optional.register_pretty_printers(obj) + boost.ptr_container.register_pretty_printers(obj) + boost.smart_ptr.register_pretty_printers(obj) + boost.unordered.register_pretty_printers(obj) + +# vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/boost/lib/__init__.py b/solenv/gdb/boost/lib/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/solenv/gdb/boost/lib/__init__.py diff --git a/solenv/gdb/boost/lib/unordered.py b/solenv/gdb/boost/lib/unordered.py new file mode 100644 index 000000000..ee58d0481 --- /dev/null +++ b/solenv/gdb/boost/lib/unordered.py @@ -0,0 +1,129 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# Helper classes for working with Boost.Unordered. +# +# Copyright (C) 2012 Red Hat, Inc., David Tardon <dtardon@redhat.com> +# +# This file is part of boost-gdb-printers. +# +# 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/>. + +import gdb +import six + +class Unordered(object): + '''Common representation of Boost.Unordered types''' + + def __init__(self, value, extractor): + self.value = value + self.extractor = extractor + self.node_type = self._node_type() + + def __len__(self): + table = self.value['table_'] + if table['buckets_']: + return int(table['size_']) + else: + return 0 + + def __iter__(self): + table = self.value['table_'] + buckets = table['buckets_'] + if buckets: + first = table['cached_begin_bucket_'] + last = buckets + table['bucket_count_'] + else: + first = last = None + return self._iterator(first, last, self.node_type, self.extractor) + + def empty(self): + return not self.value['table_']['buckets_'] + + def _node_type(self): + hash_table = self.value['table_'].type.fields()[0] + assert hash_table.is_base_class + hash_buckets = hash_table.type.fields()[0] + assert hash_buckets.is_base_class + node_type = gdb.lookup_type("%s::node" % hash_buckets.type) + assert node_type != None + return node_type + + class _iterator(six.Iterator): + '''Iterator for Boost.Unordered types''' + + def __init__(self, first_bucket, last_bucket, node_type, extractor): + self.bucket = first_bucket + self.last_bucket = last_bucket + self.node = self.bucket + self.node_type = node_type + self.value_type = self._value_type() + self.extractor = extractor + + def __iter__(self): + return self + + def __next__(self): + if self.node: + self.node = self.node.dereference()['next_'] + + # we finished the current bucket: go on to the next non-empty one + if not self.node: + while not self.node and self.bucket != self.last_bucket: + self.bucket += 1 + self.node = self.bucket.dereference()['next_'] + + # sorry, no node available + if not self.node or self.node == self.bucket: + raise StopIteration() + + mapped = self._value() + return (self.extractor.key(mapped), self.extractor.value(mapped)) + + def _value(self): + assert self.node != self.bucket # bucket node has no value + assert self.node != None + node = self.node.dereference().cast(self.node_type) + return node['data_'].cast(self.value_type) + + def _value_type(self): + value_base = self.node_type.fields()[1] + assert value_base.is_base_class + return value_base.type.template_argument(0) + +class Map(Unordered): + + def __init__(self, value): + super(Map, self).__init__(value, self._extractor()) + + class _extractor(object): + + def key(self, node): + return node['first'] + + def value(self, node): + return node['second'] + +class Set(Unordered): + + def __init__(self, value): + super(Set, self).__init__(value, self._extractor()) + + class _extractor(object): + + def key(self, node): + return None + + def value(self, node): + return node + +# vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/boost/optional.py b/solenv/gdb/boost/optional.py new file mode 100644 index 000000000..08297254e --- /dev/null +++ b/solenv/gdb/boost/optional.py @@ -0,0 +1,56 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# GDB pretty printers for Boost.Optional. +# +# Copyright (C) 2012 Red Hat, Inc., David Tardon <dtardon@redhat.com> +# +# This file is part of boost-gdb-printers. +# +# 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/>. + +import gdb + +import boost.util.printing as printing + +class OptionalPrinter: + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + if self.value['m_initialized']: + data = self.value['m_storage']['dummy_']['data'] + ptr_type = self.value.type.template_argument(0).pointer() + return "%s %s" % (self.typename, data.cast(ptr_type).dereference()) + else: + return "empty " + self.typename + +printer = None + +def build_pretty_printers(): + global printer + + if printer != None: + return + + printer = printing.Printer("boost.optional") + + printer.add('boost::optional', OptionalPrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/boost/ptr_container.py b/solenv/gdb/boost/ptr_container.py new file mode 100644 index 000000000..425d812f5 --- /dev/null +++ b/solenv/gdb/boost/ptr_container.py @@ -0,0 +1,248 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# GDB pretty printers for Boost.Pointer Container. +# +# Copyright (C) 2012 Red Hat, Inc., David Tardon <dtardon@redhat.com> +# +# This file is part of boost-gdb-printers. +# +# 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/>. + + +import gdb +import six + +from boost.lib.unordered import Map, Set + +import boost.util.printing as printing + +std = None + +class PtrStdPrinterBase(object): + + def __init__(self, typename, value, seq_tag): + self._import_std() + self.typename = typename + self.value = value + + # (try to) init printer of underlying std sequence and get elements + printer = self._get_sequence_printer(seq_tag) + if printer: + seq = value['c_'] + if str(seq.type.strip_typedefs()).startswith('std::__debug::'): + seq_typename = 'std::__debug::%s' % seq_tag + else: + seq_typename = 'std::%s' % seq_tag + self.sequence = list(printer(seq_typename, seq).children()) + else: + self.sequence = None + + def to_string(self): + if self.sequence != None: + length = len(self.sequence) + if length: + return "%s %s" % (self.typename, self.print_size(length)) + else: + return "empty %s" % self.typename + else: + return "opaque %s" % self.typename + + def children(self): + return self._iterator(self.sequence, self.value.type.template_argument(0)) + + class _iterator(six.Iterator): + + def __init__(self, sequence, type): + self.impl = iter(sequence) + self.type = type.pointer() + + def __iter__(self): + return self + + def __next__(self): + (index, value) = six.advance_iterator(self.impl) + return (index, value.cast(self.type).dereference()) + + def _import_std(self): + global std + if not std: + try: + import libstdcxx.v6.printers + std = libstdcxx.v6.printers + except: + pass + + def _get_sequence_printer(self, typename): + if typename == "deque": + return std.StdDequePrinter + if typename == "list": + return std.StdListPrinter + if typename == "map": + return std.StdMapPrinter + if typename == "set": + return std.StdSetPrinter + if typename == "vector": + return std.StdVectorPrinter + +class PtrSequencePrinter(PtrStdPrinterBase): + + def __init__(self, typename, value, seq_tag): + super(PtrSequencePrinter, self).__init__(typename, value, seq_tag) + + def print_size(self, size): + return "of length %s" % size + + def display_hint(self): + return 'array' + +class PtrSetPrinter(PtrStdPrinterBase): + + def __init__(self, typename, value): + super(PtrSetPrinter, self).__init__(typename, value, 'set') + + def print_size(self, size): + return "with %s elements" % size + + def display_hint(self): + return 'array' + +class PtrMapPrinter(PtrStdPrinterBase): + + def __init__(self, typename, value): + super(PtrMapPrinter, self).__init__(typename, value, 'map') + + def children(self): + type = self.value.type + return self._iterator(self.sequence, type.template_argument(0), type.template_argument(1)) + + class _iterator(six.Iterator): + + def __init__(self, sequence, key_type, value_type): + self.impl = iter(sequence) + self.key_type = key_type + self.value_type = value_type.pointer() + self.key = True + + def __iter__(self): + return self + + def __next__(self): + (index, value) = six.advance_iterator(self.impl) + if self.key: + value = value.cast(self.key_type) + else: + value = value.cast(self.value_type).dereference() + self.key = not self.key + return (index, value) + + def display_hint(self): + return 'map' + + def print_size(self, size): + return "with %s elements" % (size / 2) + +class PtrBoostPrinterBase(object): + + def __init__(self, typename, value, container, iterator, value_type): + self.typename = typename + self.impl = container(value['c_']) + self.iterator = iterator + self.value_type = value_type.pointer() + + def to_string(self): + if self.impl.empty(): + return "empty " + self.typename + else: + return "%s with %s elements" % (self.typename, len(self.impl)) + + def children(self): + return self.iterator(iter(self.impl), self.value_type) + +class PtrUnorderedMapPrinter(PtrBoostPrinterBase): + + def __init__(self, typename, value): + super(PtrUnorderedMapPrinter, self).__init__(typename, value, Map, self._iterator, + value.type.template_argument(1)) + + def display_hint(self): + return 'map' + + class _iterator(six.Iterator): + + def __init__(self, impl, value_type): + self.impl = impl + self.step = True + self.value = None + self.value_type = value_type + + def __iter__(self): + return self + + def __next__(self): + if self.step: + self.value = six.advance_iterator(self.impl) + value = self.value[0] + else: + value = self.value[1].cast(self.value_type).dereference() + self.step = not self.step + return ("", value) + +class PtrUnorderedSetPrinter(PtrBoostPrinterBase): + + def __init__(self, typename, value): + super(PtrUnorderedSetPrinter, self).__init__(typename, value, Set, self._iterator, + value.type.template_argument(0)) + + def display_hint(self): + return 'array' + + class _iterator(six.Iterator): + + def __init__(self, impl, value_type): + self.impl = impl + self.value_type = value_type + + def __iter__(self): + return self + + def __next__(self): + return ("", six.advance_iterator(self.impl)[1].cast(self.value_type).dereference()) + +printer = None + +def build_pretty_printers(): + global printer + + if printer != None: + return + + printer = printing.Printer("boost.ptr_container") + + printer.add('boost::ptr_deque', (lambda t, v: PtrSequencePrinter(t, v, "deque"))) + printer.add('boost::ptr_list', (lambda t, v: PtrSequencePrinter(t, v, "list"))) + printer.add('boost::ptr_map', PtrMapPrinter) + printer.add('boost::ptr_multimap', PtrMapPrinter) + printer.add('boost::ptr_multiset', PtrSetPrinter) + printer.add('boost::ptr_set', PtrSetPrinter) + printer.add('boost::ptr_unordered_map', PtrUnorderedMapPrinter) + printer.add('boost::ptr_unordered_multimap', PtrUnorderedMapPrinter) + printer.add('boost::ptr_unordered_multiset', PtrUnorderedSetPrinter) + printer.add('boost::ptr_unordered_set', PtrUnorderedSetPrinter) + printer.add('boost::ptr_vector', (lambda t, v: PtrSequencePrinter(t, v, "vector"))) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/boost/smart_ptr.py b/solenv/gdb/boost/smart_ptr.py new file mode 100644 index 000000000..60d88278a --- /dev/null +++ b/solenv/gdb/boost/smart_ptr.py @@ -0,0 +1,76 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# GDB pretty printers for Boost.Smart Ptr. +# +# Copyright (C) 2012 Red Hat, Inc., David Tardon <dtardon@redhat.com> +# +# This file is part of boost-gdb-printers. +# +# 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/>. + +import gdb + +import boost.util.printing as printing + + +class SmartPtrPrinter: + """Prints smart pointers based on Boost.SmartPtr""" + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + if self.value['px']: + print_object = gdb.parameter('print object') + value = self.value['px'].dereference() + if print_object: + dynamic_type = self.value['px'].dynamic_type + value = self.value['px'].cast(dynamic_type).dereference() + return "%s %s" % (self.typename, value) + else: + return "empty %s" % (self.typename) + +class WeakPtrPrinter: + """Prints boost::weak_ptr instances""" + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + value = self.value['px'] + return "%s %s" % (self.typename, value) + +printer = None + +def build_pretty_printers(): + global printer + + if printer != None: + return + + printer = printing.Printer("boost.smart_ptr") + + printer.add('boost::shared_ptr', SmartPtrPrinter) + # printer.add('boost::shared_array', SmartPtrPrinter) + printer.add('boost::weak_ptr', WeakPtrPrinter) + printer.add('boost::scoped_ptr', SmartPtrPrinter) + # printer.add('boost::scoped_array', SmartPtrPrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/boost/unordered.py b/solenv/gdb/boost/unordered.py new file mode 100644 index 000000000..2c5672185 --- /dev/null +++ b/solenv/gdb/boost/unordered.py @@ -0,0 +1,112 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# GDB pretty printers for Boost.Unordered. +# +# Copyright (C) 2012 Red Hat, Inc., David Tardon <dtardon@redhat.com> +# +# This file is part of boost-gdb-printers. +# +# 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/>. + + +import gdb +import six + +from boost.lib.unordered import Map, Set + +import boost.util.printing as printing + +class PrinterBase(object): + '''Contains common functionality for printing Boost.Unordered types''' + + def __init__(self, typename, value, container, iterator): + self.typename = typename + self.impl = container(value) + self.iterator = iterator + + def to_string(self): + if self.impl.empty(): + return "empty " + self.typename + else: + return "%s with %s elements" % (self.typename, len(self.impl)) + + def children(self): + return self.iterator(iter(self.impl)) + +class UnorderedMapPrinter(PrinterBase): + + def __init__(self, typename, value): + super(UnorderedMapPrinter, self).__init__(typename, value, Map, self._iterator) + + def display_hint(self): + return 'map' + + class _iterator(six.Iterator): + + def __init__(self, impl): + self.impl = impl + self.value = None + self.step = True + + def __iter__(self): + return self + + def __next__(self): + if self.step: + self.value = six.advance_iterator(self.impl) + value = self.value[0] + else: + value = self.value[1] + self.step = not self.step + return ("", value) + +class UnorderedSetPrinter(PrinterBase): + + def __init__(self, typename, value): + super(UnorderedSetPrinter, self).__init__(typename, value, Set, self._iterator) + + def display_hint(self): + return 'array' + + class _iterator(six.Iterator): + + def __init__(self, impl): + self.impl = impl + + def __iter__(self): + return self + + def __next__(self): + return ("", six.advance_iterator(self.impl)[1]) + +printer = None + +def build_pretty_printers(): + global printer + + if printer != None: + return + + printer = printing.Printer("boost.unordered") + + printer.add('boost::unordered_map', UnorderedMapPrinter) + printer.add('boost::unordered_multimap', UnorderedMapPrinter) + printer.add('boost::unordered_multiset', UnorderedSetPrinter) + printer.add('boost::unordered_set', UnorderedSetPrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/boost/util/__init__.py b/solenv/gdb/boost/util/__init__.py new file mode 100644 index 000000000..e7992304d --- /dev/null +++ b/solenv/gdb/boost/util/__init__.py @@ -0,0 +1,3 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- + +# vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/boost/util/compatibility.py b/solenv/gdb/boost/util/compatibility.py new file mode 100644 index 000000000..e704b1992 --- /dev/null +++ b/solenv/gdb/boost/util/compatibility.py @@ -0,0 +1,32 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# Compatibility with older versions of GDB. +# +# Copyright (C) 2012 Red Hat, Inc., David Tardon <dtardon@redhat.com> +# +# This file is part of boost-gdb-printers. +# +# 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/>. + + +import gdb + +use_gdb_printing = True +try: + import gdb.printing +except ImportError: + use_gdb_printing = False + +use_lazy_string = hasattr(gdb.Value, 'lazy_string') + +# vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/boost/util/printing.py b/solenv/gdb/boost/util/printing.py new file mode 100644 index 000000000..22bf29f80 --- /dev/null +++ b/solenv/gdb/boost/util/printing.py @@ -0,0 +1,137 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# Printer interface adaptor. +# +# Copyright (C) 2012 Red Hat, Inc., David Tardon <dtardon@redhat.com> +# +# This file is part of boost-gdb-printers. +# +# 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/>. + + +try: + from collections.abc import Mapping +except: + from collections import Mapping +import gdb +import re +import six + +from boost.util.compatibility import use_gdb_printing + +class SimplePrinter(object): + + def __init__(self, name, function): + self.name = name + self.function = function + self.enabled = True + + def invoke(self, val): + if not self.enabled: + return None + return self.function(self.name, val) + +class NameLookup(Mapping): + + def __init__(self): + self.map = {} + self.name_regex = re.compile(r'^([\w:]+)(<.*>)?') + + def add(self, name, printer): + self.map[name] = printer + + def __len__(self): + return len(self.map) + + def __getitem__(self, type): + typename = self._basic_type(type) + if typename and typename in self.map: + return self.map[typename] + return None + + def __iter__(self): + return self.map + + def _basic_type(self, type): + basic_type = self.basic_type(type) + if basic_type: + match = self.name_regex.match(basic_type) + if match: + return match.group(1) + return None + + @staticmethod + def basic_type(type): + if type.code == gdb.TYPE_CODE_REF: + type = type.target() + type = type.unqualified().strip_typedefs() + return type.tag + +class FunctionLookup(Mapping): + + def __init__(self): + self.map = {} + + def add(self, test, printer): + self.map[test] = printer + + def __len__(self): + return len(self.map) + + def __getitem__(self, type): + for (test, printer) in six.iteritems(self.map): + if test(type): + return printer + return None + + def __iter__(self): + return self.map + +class Printer(object): + + def __init__(self, name): + self.name = name + self.subprinters = [] + self.name_lookup = NameLookup() + self.func_lookup = FunctionLookup() + self.enabled = True + + def add(self, name, function, lookup = None): + printer = SimplePrinter(name, function) + self.subprinters.append(printer) + if not lookup: + self.name_lookup.add(name, printer) + else: + self.func_lookup.add(lookup, printer) + + + def __call__(self, val): + printer = self.name_lookup[val.type] + if not printer: + printer = self.func_lookup[val.type] + + if printer: + return printer.invoke(val) + return None + +def register_pretty_printer(printer, obj): + '''Registers printer with objfile''' + + if use_gdb_printing: + gdb.printing.register_pretty_printer(obj, printer) + else: + if obj is None: + obj = gdb + obj.pretty_printers.append(printer) + +# vim:set filetype=python shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/__init__.py b/solenv/gdb/libreoffice/__init__.py new file mode 100644 index 000000000..06b4ade34 --- /dev/null +++ b/solenv/gdb/libreoffice/__init__.py @@ -0,0 +1,10 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/basegfx.py b/solenv/gdb/libreoffice/basegfx.py new file mode 100644 index 000000000..c14968c91 --- /dev/null +++ b/solenv/gdb/libreoffice/basegfx.py @@ -0,0 +1,196 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import gdb +import six + +from libreoffice.util import printing + +class B2DRangePrinter(object): + '''Prints a B2DRange object.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + # inject children() func dynamically + if not self._isEmpty(): + self.children = self._children + + def to_string(self): + if self._isEmpty(): + return "empty %s" % (self.typename) + else: + return "%s" % (self.typename) + + def _isEmpty(self): + return (self.value['maRangeX']['mnMinimum'] > self.value['maRangeX']['mnMaximum'] + or self.value['maRangeY']['mnMinimum'] > self.value['maRangeY']['mnMaximum']) + + def _children(self): + left = self.value['maRangeX']['mnMinimum'] + top = self.value['maRangeY']['mnMinimum'] + right = self.value['maRangeX']['mnMaximum'] + bottom = self.value['maRangeY']['mnMaximum'] + children = [('left', left), ('top', top), ('right', right), ('bottom', bottom)] + return children.__iter__() + +class B2DPolygonPrinter(object): + '''Prints a B2DPolygon object.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + # inject children() func dynamically + if not self._isEmpty(): + self.children = self._children + + def to_string(self): + if self._isEmpty(): + return "empty %s" % (self.typename) + else: + return "%s %s" % ('bezier curve' if self._hasCurves() else 'straight line', + self.typename) + + def _count(self): + # It's a call into the inferior (being debugged) process. + # Will not work with core dumps and can cause a deadlock. + return int(gdb.parse_and_eval( + "(('basegfx::B2DPolygon' *) {})->count()".format(self.value.address))) + + def _isEmpty(self): + return self._count() == 0 + + def _hasCurves(self): + # It's a call into the inferior (being debugged) process. + # Will not work with core dumps and can cause a deadlock. + return int(gdb.parse_and_eval( + "(('basegfx::B2DPolygon' *) {})->areControlPointsUsed()".format(self.value.address))) != 0 + + def _children(self): + if self._hasCurves(): + return self._bezierIterator(self._count(), self.value) + else: + return self._plainIterator(self._count(), self.value) + + class _plainIterator(six.Iterator): + def __init__(self, count, value): + self.count = count + self.value = value + self.index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self.index >= self.count: + raise StopIteration() + points = self.value['mpPolygon']['m_pimpl'].dereference()['m_value']['maPoints']['maVector'] + currPoint = (points['_M_impl']['_M_start'] + self.index).dereference() + # doesn't work? + #currPoint = gdb.parse_and_eval( + # '((basegfx::B2DPolygon*)%d)->getB2DPoint(%d)' % ( + # self.value.address, self.index)) + self.index += 1 + return ('point %d' % (self.index-1), + '(%15f, %15f)' % (currPoint['mfX'], currPoint['mfY'])) + + class _bezierIterator(six.Iterator): + def __init__(self, count, value): + self.count = count + self.value = value + self.index = 0 + + def __iter__(self): + return self + + def __next__(self): + if self.index >= self.count: + raise StopIteration() + points = self.value['mpPolygon']['m_pimpl'].dereference()['m_value']['maPoints']['maVector'] + currPoint = (points['_M_impl']['_M_start'] + self.index).dereference() + #currPoint = gdb.parse_and_eval( + # '((basegfx::B2DPolygon*)%d)->getB2DPoint(%d)' % ( + # self.value.address, self.index)) + + # It's a call into the inferior (being debugged) process. + # Will not work with core dumps and can cause a deadlock. + prevControl = gdb.parse_and_eval( + "(('basegfx::B2DPolygon' *) {})->getPrevControlPoint({:d})".format(self.value.address, self.index)) + # It's a call into the inferior (being debugged) process. + # Will not work with core dumps and can cause a deadlock. + nextControl = gdb.parse_and_eval( + "(('basegfx::B2DPolygon' *) {})->getNextControlPoint({:d})".format(self.value.address, self.index)) + self.index += 1 + return ('point %d' % (self.index-1), + 'p: (%15f, %15f) c-1: (%15f, %15f) c1: (%15f, %15f)' % + (currPoint['mfX'], currPoint['mfY'], + prevControl['mfX'], prevControl['mfY'], + nextControl['mfX'], nextControl['mfY'])) + +class B2DPolyPolygonPrinter(object): + '''Prints a B2DPolyPolygon object.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + if self._isEmpty(): + return "empty %s" % (self.typename) + else: + return "%s %s with %d sub-polygon(s)" % ('closed' if self._isClosed() else 'open', + self.typename, + self._count()) + + def _count(self): + # It's a call into the inferior (being debugged) process. + # Will not work with core dumps and can cause a deadlock. + return int(gdb.parse_and_eval( + "(('basegfx::B2DPolyPolygon' *) {})->count()".format(self.value.address))) + + def _isClosed(self): + # It's a call into the inferior (being debugged) process. + # Will not work with core dumps and can cause a deadlock. + return int(gdb.parse_and_eval( + "(('basegfx::B2DPolyPolygon' *) {})->isClosed()".format(self.value.address))) != 0 + + def _isEmpty(self): + return self._count() == 0 + + def children(self): + if self.value['mpPolyPolygon']['m_pimpl'].type.code in (gdb.TYPE_CODE_PTR, gdb.TYPE_CODE_MEMBERPTR): + if self.value['mpPolyPolygon']['m_pimpl']: + try: + vector = self.value['mpPolyPolygon']['m_pimpl'].dereference()['m_value']['maPolygons'] + import libstdcxx.v6.printers as std + return std.StdVectorPrinter("std::vector", vector).children() + except RuntimeError: + gdb.write("Cannot access memory at address " + str(self.value['mpPolyPolygon']['m_pimpl'].address)) + + return None + +printer = None + +def build_pretty_printers(): + global printer + + printer = printing.Printer('libreoffice/basegfx') + + # basic types + printer.add('basegfx::B2DRange', B2DRangePrinter) + printer.add('basegfx::B2DPolygon', B2DPolygonPrinter) + printer.add('basegfx::B2DPolyPolygon', B2DPolyPolygonPrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: + diff --git a/solenv/gdb/libreoffice/cppu.py b/solenv/gdb/libreoffice/cppu.py new file mode 100644 index 000000000..5114dbe12 --- /dev/null +++ b/solenv/gdb/libreoffice/cppu.py @@ -0,0 +1,156 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import six + +from libreoffice.util import printing +from libreoffice.util.uno import TypeClass, make_uno_type, uno_cast + +class UnoAnyPrinter(object): + '''Prints UNO any''' + + def __init__(self, typename, value): + self.value = value + self.typename = typename.replace('com::sun::star::', '') + + def to_string(self): + type_desc = self.value['pType'] + assert type_desc + type = make_uno_type(type_desc.dereference()) + assert type + if type_desc.dereference()['eTypeClass'] == TypeClass.VOID: + return ('%s(%s)' % (self.typename, type.tag)) + else: + ptr = self.value['pData'] + assert ptr + return ('%s(%s: %s)' % (self.typename, type.tag, str(uno_cast(type, ptr).dereference()))) + +class UnoReferencePrinter(object): + '''Prints reference to a UNO interface''' + + def __init__(self, typename, value): + self.value = value + self.typename = typename.replace('com::sun::star::', '') + + def to_string(self): + iface = self.value['_pInterface'] + if iface: + try: + return '%s to (%s) %s' % (self.typename, str(iface.dynamic_type), str(iface)) + except: + # fallback for potential problem: + # base class 'com::sun::star::uno::XInterface' is ambiguous + return '%s to (XInterface) %s' % (self.typename, str(iface)) + + else: + return "empty %s" % self.typename + +class UnoSequencePrinter(object): + '''Prints UNO Sequence''' + + class iterator(six.Iterator): + '''Sequence iterator''' + + def __init__(self, first, size): + self.item = first + self.size = size + self.count = 0 + + def __iter__(self): + return self + + def __next__(self): + if self.count == self.size: + raise StopIteration + count = self.count + self.count = self.count + 1 + elem = self.item.dereference() + self.item = self.item + 1 + return ('[%d]' % count, elem) + + + def __init__(self, typename, value): + self.value = value + self.typename = typename.replace('com::sun::star::', '') + + def to_string(self): + pimpl = self.value['_pSequence'] + if pimpl: + impl = pimpl.dereference() + elems = impl['nElements'] + if elems == 0: + return "empty %s" % self.typename + else: + return "%s of length %d" % (self.typename, elems) + else: + return "uninitialized %s" % self.typename + + def children(self): + pimpl = self.value['_pSequence'] + if pimpl: + impl = pimpl.dereference() + elemtype = self.value.type.template_argument(0) + elements = impl['elements'].cast(elemtype.pointer()) + return self.iterator(elements, int(impl['nElements'])) + else: + # TODO is that the best thing to do here? + return None + + def display_hint(self): + if self.value['_pSequence']: + return 'array' + else: + return None + +class UnoTypePrinter(object): + '''Prints UNO Type''' + + def __init__(self, typename, value): + self.value = value + self.typename = typename.replace('com::sun::star::', '') + + def to_string(self): + uno = make_uno_type(self.value) + if uno: + return "%s %s" % (self.typename, uno.tag) + # return "%s %s" % (self.typename, uno.typename) + else: + return "invalid %s" % self.typename + +class CppuThreadpoolThreadPoolPrinter(object): + '''Prints cppu_threadpool::ThreadPool objects (a hack to avoid infinite recursion through sal.RtlReferencePrinter when printing an rtl::Reference<cppu_threadpool::ThreadPool> whose std::list<cppu_threadpool::WaitingThread*> m_lstThreads member, via rtl::Reference<cppu_threadpool::ORequestThread> thread member, via rtl::Reference<cppu_threadpool::ThreadPool> m_aThreadPool member, has a circular reference back)''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return '%s@%s' % (self.typename, self.value.address) + +printer = None + +def build_pretty_printers(): + global printer + + printer = printing.Printer("libreoffice/cppu") + + # basic UNO stuff + printer.add('_uno_Any', UnoAnyPrinter) + printer.add('com::sun::star::uno::Any', UnoAnyPrinter) + printer.add('com::sun::star::uno::Reference', UnoReferencePrinter) + printer.add('com::sun::star::uno::Sequence', UnoSequencePrinter) + printer.add('com::sun::star::uno::Type', UnoTypePrinter) + printer.add('cppu_threadpool::ThreadPool', CppuThreadpoolThreadPoolPrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/sal.py b/solenv/gdb/libreoffice/sal.py new file mode 100644 index 000000000..8dcfaebe6 --- /dev/null +++ b/solenv/gdb/libreoffice/sal.py @@ -0,0 +1,167 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import gdb +import gdb.types +import six + +from libreoffice.util import printing +from libreoffice.util.string import StringPrinterHelper + +class RtlStringPrinter(StringPrinterHelper): + '''Prints rtl_String or rtl_uString''' + + def __init__(self, typename, val, encoding = None): + super(RtlStringPrinter, self).__init__(typename, val, encoding) + + def data(self): + return self.val['buffer'].address + + def length(self): + return self.val['length'] + +class StringPrinter(StringPrinterHelper): + '''Prints rtl:: strings and string buffers''' + + def __init__(self, typename, val, encoding = None): + super(StringPrinter, self).__init__(typename, val, encoding) + + def valid(self): + return self.val['pData'] + + def data(self): + assert self.val['pData'] + return self.val['pData'].dereference()['buffer'].address + + def length(self): + assert self.val['pData'] + return self.val['pData'].dereference()['length'] + +class SalUnicodePrinter(StringPrinterHelper): + '''Prints a sal_Unicode*''' + + def __init__(self, typename, val): + super(SalUnicodePrinter, self).__init__(typename, val, 'utf-16') + + def data(self): + return self.val + + @staticmethod + def query(type): + type = type.unqualified() + if type.code != gdb.TYPE_CODE_PTR: + return False + return str(type.target()) == 'sal_Unicode' + +class RtlReferencePrinter(object): + '''Prints rtl::Reference''' + + def __init__(self, typename, val): + self.typename = typename + self.val = val + + def to_string(self): + pointee = self.val['m_pBody'] + if pointee: + return '%s to %s' % (self.typename, str(pointee)) + else: + return "empty %s" % self.typename + +class OslFileStatusPrinter(object): + '''Prints oslFileStatus''' + + def __init__(self, typename, val): + self.val = val + + def to_string(self): + osl_file_type = gdb.lookup_type('oslFileType').strip_typedefs() + fields_to_enum_val = gdb.types.make_enum_dict(osl_file_type) + + etype = self.field_val_if_valid('eType') + if etype is not None: + pretty_etype = '<unknown type>' # in case it's not one of the fields + + for field_name, field_val in six.iteritems(fields_to_enum_val): + if etype == field_val: + pretty_etype = self.pretty_file_type(field_name) + else: + pretty_etype = '<invalid type>' + + file_url = self.field_val_if_valid('ustrFileURL') + if file_url is not None: + pretty_file_url = str(file_url.dereference()) + else: + pretty_file_url = '<invalid file url>' + + pretty_file_status = pretty_etype + ': ' + pretty_file_url + + # for links append the link target if valid + if etype == fields_to_enum_val['osl_File_Type_Link']: + link_target = self.field_val_if_valid('ustrLinkTargetURL') + if link_target is None: + pretty_link_target = '<invalid link target>' + else: + pretty_link_target = str(link_target.dereference()) + + pretty_file_status += ' -> ' + pretty_link_target + + return pretty_file_status + + def pretty_file_type(self, file_type_name): + if file_type_name != 'osl_File_Type_Regular': + return file_type_name.replace('osl_File_Type_', '').lower() + else: + return 'file' # regular is not very descriptive, file is better + + def field_val_if_valid(self, field): + mask_for_field = {'eType': 0x00000001, + 'uAttributes': 0x00000002, + 'aCreationTime': 0x00000010, + 'aAccessTime': 0x00000020, + 'aModifyTime': 0x00000040, + 'uFileSize': 0x00000080, + 'ustrFileName': 0x00000100, + 'ustrFileURL': 0x00000200, + 'ustrLinkTargetURL': 0x00000400} + + valid_fields = self.val['uValidFields'] + if valid_fields & mask_for_field[field]: + return self.val[field] + else: + return None + +printer = None + +def build_pretty_printers(): + global printer + + printer = printing.Printer("libreoffice/sal") + + # strings and string buffers + printer.add('_rtl_String', RtlStringPrinter) + printer.add('_rtl_uString', lambda name, val: RtlStringPrinter(name, + val, 'utf-16le')) + printer.add('rtl::OString', StringPrinter) + printer.add('rtl::OUString', lambda name, val: StringPrinter(name, val, 'utf-16')) + printer.add('rtl::OStringBuffer', StringPrinter) + printer.add('rtl::OUStringBuffer', lambda name, val: StringPrinter(name, val, 'utf-16')) + printer.add('sal_Unicode', SalUnicodePrinter, SalUnicodePrinter.query) + + # other stuff + printer.add('rtl::Reference', RtlReferencePrinter) + printer.add('_oslFileStatus', OslFileStatusPrinter) + + return printer + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/svl.py b/solenv/gdb/libreoffice/svl.py new file mode 100644 index 000000000..f82b02a7b --- /dev/null +++ b/solenv/gdb/libreoffice/svl.py @@ -0,0 +1,93 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import gdb +import six + +from libreoffice.util import printing + +class ItemSetPrinter(object): + '''Prints SfxItemSets''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + whichranges = self.which_ranges() + return "SfxItemSet of pool %s with parent %s and Which ranges: %s" \ + % (self.value['m_pPool'], self.value['m_pParent'], whichranges) + + def which_ranges(self): + whichranges = self.value['m_pWhichRanges']['m_pairs'] + whichranges_cnt = self.value['m_pWhichRanges']['m_size'] + whiches = [] + for index in range(whichranges_cnt): + whiches.append((int(whichranges[index]['first']), int(whichranges[index]['second']))) + return whiches + + def children(self): + whichranges = self.which_ranges() + size = 0 + whichids = [] + for (whichfrom, whichto) in whichranges: + size += whichto - whichfrom + 1 + whichids += [which for which in range(whichfrom, whichto+1)] + return self._iterator(self.value['m_ppItems'], size, whichids) + + class _iterator(six.Iterator): + + def __init__(self, data, count, whichids): + self.data = data + self.whichids = whichids + self.count = count + self.pos = 0 + self._check_invariant() + + def __iter__(self): + return self + + def __next__(self): + if self.pos == self.count: + raise StopIteration() + + which = self.whichids[self.pos] + elem = self.data[self.pos] + self.pos = self.pos + 1 + + self._check_invariant() + if (elem == -1): + elem = "(Invalid)" + elif (elem != 0): + # let's try how well that works... + elem = elem.cast(elem.dynamic_type).dereference() + return (str(which), elem) + + def _check_invariant(self): + assert self.count >= 0 + assert self.data + assert self.pos >= 0 + assert self.pos <= self.count + assert len(self.whichids) == self.count + +printer = None + +def build_pretty_printers(): + global printer + + printer = printing.Printer("libreoffice/svl") + + printer.add('SfxItemSet', ItemSetPrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/sw.py b/solenv/gdb/libreoffice/sw.py new file mode 100644 index 000000000..707d0a425 --- /dev/null +++ b/solenv/gdb/libreoffice/sw.py @@ -0,0 +1,305 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import six +import gdb +from libreoffice.util import printing + +class SwPositionPrinter(object): + '''Prints SwPosition.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + node = self.value['nNode']['m_pNode'].dereference(); + block = node['m_pBlock'].dereference(); + nodeindex = block['nStart'] + node['m_nOffset'] + offset = self.value['nContent']['m_nIndex'] + return "%s (node %d, offset %d)" % (self.typename, nodeindex, offset) + +class SwNodeIndexPrinter(object): + '''Prints SwNodeIndex.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + node = self.value['m_pNode'].dereference(); + block = node['m_pBlock'].dereference(); + nodeindex = block['nStart'] + node['m_nOffset'] + return "%s (node %d)" % (self.typename, nodeindex) + +class SwIndexPrinter(object): + '''Prints SwIndex.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + offset = self.value['m_nIndex'] + return "%s (offset %d)" % (self.typename, offset) + +class SwPaMPrinter(object): + '''Prints SwPaM.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + + def children(self): + next_ = self.value['m_pNext'] + prev = self.value['m_pPrev'] + point = self.value['m_pPoint'].dereference() + mark = self.value['m_pMark'].dereference() + children = [ ( 'point', point), ( 'mark', mark ) ] + if next_ != self.value.address: + children.append(("next", next_)) + if prev != self.value.address: + children.append(("prev", prev)) + return children.__iter__() + +# apparently the purpose of this is to suppress printing all the extra members +# that SwCursor and SwUnoCursor add +class SwUnoCursorPrinter(SwPaMPrinter): + '''Prints SwUnoCursor.''' + +class SwRectPrinter(object): + '''Prints SwRect.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + + def children(self): + point = self.value['m_Point'] + size = self.value['m_Size'] + children = [ ( 'point', point), ( 'size', size ) ] + return children.__iter__() + +class MarkBasePrinter(object): + '''Prints sw::mark::MarkBase.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + + def children(self): + m = self.value.cast(self.value.dynamic_type) + return [ ( v, m[ v ] ) + for v in ( 'm_aName', 'm_pPos1', 'm_pPos2' ) ].__iter__() + +class SwXTextRangeImplPrinter(object): + '''Prints SwXTextRange::Impl.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + + def children(self): + mark = self.value['m_pMark'].dereference() + children = [('mark', mark)] + return children.__iter__() + +class SwXTextCursorPrinter(object): + '''Prints SwXTextCursor.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + + def children(self): + cursor = self.value['m_pUnoCursor']["m_pCursor"]["_M_ptr"] + registeredIn = cursor.dereference() + children = [('m_pUnoCursor', registeredIn)] + return children.__iter__() + +class SwUnoImplPtrPrinter(object): + """Prints sw::UnoImplPtr""" + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + if self.value['m_p']: + return "%s %s" % (self.typename, self.value['m_p'].dereference()) + else: + return "empty %s" % (self.typename,) + +class SwXTextRangePrinter(object): + '''Prints SwXTextRange.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s %s" % (self.typename, self.value['m_pImpl']) + +class BigPtrArrayPrinter(object): + '''Prints BigPtrArray.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + length = self.value['m_nSize'] + if length > 0: + return "%s of length %d" % (self.typename, length) + else: + return "empty %s" % self.typename + + def children(self): + return self._iterator(self.value) + + def display_hint(self): + return 'array' + + + class _iterator(six.Iterator): + + def __init__(self, array): + # libstdc++ unique_ptr is a std::tuple which contains multiple + # _M_head_impl members and gdb may pick the wrong one by default + # so have to manually cast it to the one that contains the array + self.blocks = array['m_ppInf']['_M_t']['_M_t'].cast(gdb.lookup_type("std::_Head_base<0, BlockInfo**, false>"))['_M_head_impl'] + self.count = array['m_nSize'] + self.pos = 0 + self.block_count = array['m_nBlock'] + self.block_pos = 0 + self.block = None + self.indent = "" + self.max_indent = " " + self._next_block(False) + self._check_invariant() + + def __iter__(self): + return self + + def _node_value(self, node): + cur_indent = self.indent + if str(node.dynamic_type.target()) == "SwTextNode": + # accessing this is completely non-obvious... + # also, node.dynamic_cast(node.dynamic_type) is null? + value = " TextNode " + \ + six.text_type(node.cast(node.dynamic_type).dereference()['m_Text']) + elif str(node.dynamic_type.target()) == "SwOLENode": + value = " OLENode " + elif str(node.dynamic_type.target()) == "SwGrfNode": + value = " GrfNode " + elif str(node.dynamic_type.target()) == "SwSectionNode": + value = " SectionNode " + self.indent += " " + elif str(node.dynamic_type.target()) == "SwTableNode": + value = " TableNode " + self.indent += " " + elif str(node.dynamic_type.target()) == "SwStartNode": + value = " StartNode " + self.indent += " " + elif str(node.dynamic_type.target()) == "SwEndNode": + value = " EndNode " + self.indent = self.indent[:-1] + cur_indent = self.indent + elif str(node.dynamic_type.target()) == "SwDummySectionNode": + value = "DummySctNode " + else: # must be currently being deleted, so has some abstract type + value = "~DeletedNode " +# return "\n[%s%4d%s] %s %s" % (cur_indent, self.pos, \ +# self.max_indent[len(cur_indent):], node, value) + return "\n[%4d] %s%s%s %s" % (self.pos, cur_indent, \ + node, self.max_indent[len(cur_indent):], value) + + def __next__(self): + if self.pos == self.count: + raise StopIteration() + + name = str(self.pos) + node = self.block['mvData']['_M_elems'][self.pos - self.block['nStart']] + value = self._node_value(node) + if self.pos == self.block['nEnd']: + self._next_block() + self.pos += 1 + + self._check_invariant() + return (name, value) + + def _next_block(self, advance = True): + if advance: + self.block_pos += 1 + + if self.block_pos == self.block_count: + return + + pblock = self.blocks[self.block_pos] + assert pblock + block = pblock.dereference() + start = block['nStart'] + end = block['nEnd'] + assert end - start + 1 == block['nElem'] + if self.block: + assert start == self.block['nEnd'] + 1 + assert end <= self.count + else: + assert start == 0 + self.block = block + + def _check_invariant(self): + assert self.pos <= self.count + assert self.block_pos <= self.block_count + if self.pos == 0 and self.pos < self.count: + assert self.block != None + +printer = None + +def build_pretty_printers(): + global printer + + printer = printing.Printer("libreoffice/sw") + printer.add('BigPtrArray', BigPtrArrayPrinter) + printer.add('SwPosition', SwPositionPrinter) + printer.add('SwNodeIndex', SwNodeIndexPrinter) + printer.add('SwIndex', SwIndexPrinter) + printer.add('SwPaM', SwPaMPrinter) + printer.add('SwUnoCursor', SwUnoCursorPrinter) + printer.add('SwRect', SwRectPrinter) + printer.add('sw::mark::Bookmark', MarkBasePrinter) + printer.add('sw::mark::MarkBase', MarkBasePrinter) + printer.add('sw::mark::UnoMark', MarkBasePrinter) + printer.add('sw::mark::IMark', MarkBasePrinter) + printer.add('SwXTextRange::Impl', SwXTextRangeImplPrinter) + printer.add('sw::UnoImplPtr', SwUnoImplPtrPrinter) + printer.add('SwXTextRange', SwXTextRangePrinter) + printer.add('SwXTextCursor', SwXTextCursorPrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/tl.py b/solenv/gdb/libreoffice/tl.py new file mode 100644 index 000000000..8e15bfd47 --- /dev/null +++ b/solenv/gdb/libreoffice/tl.py @@ -0,0 +1,220 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import gdb + +from libreoffice.util import printing + +class BigIntPrinter(object): + '''Prints big integer''' + + def __init__(self, typename, val): + self.val = val + + def to_string(self): + if self.val['bIsSet']: + if self.val['bIsBig']: + return self._value() + else: + return self.val['nVal'] + else: + return "unset %s" % self.typename + + def _value(self): + len = self.val['nLen'] + digits = self.val['nNum'] + dsize = digits.dereference().type.sizeof * 8 + num = 0 + # The least significant byte is on index 0 + for i in reversed(range(0, len)): + num <<= dsize + num += digits[i] + return num + +class ColorPrinter(object): + '''Prints color as rgb(r, g, b) or rgba(r, g, b, a)''' + + def __init__(self, typename, val): + self.val = val + + def to_string(self): + r = self.val['R'] + g = self.val['G'] + b = self.val['B'] + t = self.val['T'] + if t: + return "rgba(%d, %d, %d, %d)" % (r, g, b, 255 - t) + else: + return "rgb(%d, %d, %d)" % (r, g, b) + +class DateTimeImpl(object): + + def __init__(self, date, time): + self.date = date + self.time = time + + def __str__(self): + result = '' + if self.date: + result += str(self.date) + if self.time: + result += ' ' + if self.time: + result += str(self.time) + return result + + @staticmethod + def parse(val): + return DateTimeImpl(DateImpl.parse(val), TimeImpl.parse(val)) + +class DateTimePrinter(object): + '''Prints date and time''' + + def __init__(self, typename, val): + self.val = val + + def to_string(self): + return str(DateTimeImpl.parse(self.val)) + +class DateImpl(DateTimeImpl): + + def __init__(self, year, month, day): + super(DateImpl, self).__init__(self, None) + self.year = year + self.month = month + self.day = day + + def __str__(self): + return "%d-%d-%d" % (self.year, self.month, self.day) + + @staticmethod + def parse(val): + date = val['mnDate'] + y = date / 10000 + if date < 0: + date = -date + m = (date / 100) % 100 + d = date % 100 + return DateImpl(y, m, d) + +class DatePrinter(object): + '''Prints date''' + + def __init__(self, typename, val): + self.val = val + + def to_string(self): + return str(DateImpl.parse(self.val)) + +class TimeImpl(DateTimeImpl): + + def __init__(self, hour, minute, second, nanosecond = 0): + super(TimeImpl, self).__init__(None, self) + self.hour = hour + self.minute = minute + self.second = second + self.nanosecond = nanosecond + + def __str__(self): + decimal = '' + if self.nanosecond != 0: + decimal = '.%09d' % self.nanosecond + return "%02d:%02d:%02d%s" % (self.hour, self.minute, self.second, decimal) + + @staticmethod + def parse(val): + time = val['nTime'] + h = time / 10000000000000 + m = (time / 100000000000) % 100 + s = (time / 1000000000) % 100 + ns = time % 1000000000 + return TimeImpl(h, m, s, ns) + +class TimePrinter(object): + '''Prints time''' + + def __init__(self, typename, val): + self.val = val + + def to_string(self): + return str(TimeImpl.parse(self.val)) + +class PointPrinter(object): + '''Prints a Point.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + + def children(self): + x = self.value['nA'] + y = self.value['nB'] + children = [('x', x), ('y', y)] + return children.__iter__() + +class SizePrinter(object): + '''Prints a Size.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + + def children(self): + width = self.value['nA'] + height = self.value['nB'] + children = [('width', width), ('height', height)] + return children.__iter__() + +class RectanglePrinter(object): + '''Prints a Rectangle.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + + def children(self): + left = self.value['nLeft'] + top = self.value['nTop'] + right = self.value['nRight'] + bottom = self.value['nBottom'] + children = [('left', left), ('top', top), ('right', right), ('bottom', bottom)] + return children.__iter__() + +printer = None + +def build_pretty_printers(): + global printer + + printer = printing.Printer('libreoffice/tl') + + # various types + printer.add('BigInt', BigIntPrinter) + printer.add('Color', ColorPrinter) + printer.add('DateTime', DateTimePrinter) + printer.add('Date', DatePrinter) + printer.add('Time', TimePrinter) + printer.add('Point', PointPrinter) + printer.add('Size', SizePrinter) + printer.add('Rectangle', RectanglePrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/util/__init__.py b/solenv/gdb/libreoffice/util/__init__.py new file mode 100644 index 000000000..047763a18 --- /dev/null +++ b/solenv/gdb/libreoffice/util/__init__.py @@ -0,0 +1,11 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/util/compatibility.py b/solenv/gdb/libreoffice/util/compatibility.py new file mode 100644 index 000000000..6d8070997 --- /dev/null +++ b/solenv/gdb/libreoffice/util/compatibility.py @@ -0,0 +1,20 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import gdb + +use_gdb_printing = True +try: + import gdb.printing +except ImportError: + use_gdb_printing = False + +use_lazy_string = hasattr(gdb.Value, 'lazy_string') + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/util/printing.py b/solenv/gdb/libreoffice/util/printing.py new file mode 100644 index 000000000..a31e353cf --- /dev/null +++ b/solenv/gdb/libreoffice/util/printing.py @@ -0,0 +1,125 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +try: + from collections.abc import Mapping +except: + from collections import Mapping +import gdb +import re +import six + +from libreoffice.util.compatibility import use_gdb_printing + +class SimplePrinter(object): + + def __init__(self, name, function): + self.name = name + self.function = function + self.enabled = True + + def invoke(self, val): + if not self.enabled: + return None + return self.function(self.name, val) + +class NameLookup(Mapping): + + def __init__(self): + self.map = {} + self.name_regex = re.compile(r'^([\w:]+)(<.*>)?') + + def add(self, name, printer): + self.map[name] = printer + + def __len__(self): + return len(self.map) + + def __getitem__(self, type): + typename = self._basic_type(type) + if typename and typename in self.map: + return self.map[typename] + return None + + def __iter__(self): + return self.map + + def _basic_type(self, type): + basic_type = self.basic_type(type) + if basic_type: + match = self.name_regex.match(basic_type) + if match: + return match.group(1) + return None + + @staticmethod + def basic_type(type): + if type.code == gdb.TYPE_CODE_REF: + type = type.target() + type = type.unqualified().strip_typedefs() + return type.tag + +class FunctionLookup(Mapping): + + def __init__(self): + self.map = {} + + def add(self, test, printer): + self.map[test] = printer + + def __len__(self): + return len(self.map) + + def __getitem__(self, type): + for (test, printer) in six.iteritems(self.map): + if test(type): + return printer + return None + + def __iter__(self): + return self.map + +class Printer(object): + + def __init__(self, name): + self.name = name + self.subprinters = [] + self.name_lookup = NameLookup() + self.func_lookup = FunctionLookup() + self.enabled = True + + def add(self, name, function, lookup = None): + printer = SimplePrinter(name, function) + self.subprinters.append(printer) + if not lookup: + self.name_lookup.add(name, printer) + else: + self.func_lookup.add(lookup, printer) + + + def __call__(self, val): + printer = self.name_lookup[val.type] + if not printer: + printer = self.func_lookup[val.type] + + if printer: + return printer.invoke(val) + return None + +def register_pretty_printer(printer, obj): + '''Registers printer with objfile''' + + if use_gdb_printing: + gdb.printing.register_pretty_printer(obj, printer) + else: + if obj is None: + obj = gdb + obj.pretty_printers.append(printer) + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/util/string.py b/solenv/gdb/libreoffice/util/string.py new file mode 100644 index 000000000..742aabbac --- /dev/null +++ b/solenv/gdb/libreoffice/util/string.py @@ -0,0 +1,75 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import gdb + +from libreoffice.util.compatibility import use_lazy_string + +class StringPrinterHelper(object): + '''Base for all string pretty printers''' + + class MustBeImplemented(Exception): + pass + + def __init__(self, typename, val, encoding = None): + self.typename = typename + self.val = val + self.encoding = encoding + + def to_string(self): + if self.valid(): + data = self.data() + len = self.length() + return self.make_string(data, self.encoding, len) + else: + return "uninitialized %s" % self.typename + + def display_hint(self): + if self.valid(): + return 'string' + else: + return None + + def valid(self): + return True + + def data(self): + raise self.MustBeImplemented() + + def length(self): + return -1 + + @staticmethod + def make_string(data, encoding = None, length = -1): + '''Creates a new string from memory''' + + if not encoding: + encoding = '' + + # we need to determine length, if not given (for sal_Unicode*) + if length < 0: + length = 0 + while data[length] != 0 and length <= 512: # arbitrary limit + length += 1 + + if use_lazy_string: + return data.lazy_string(encoding, length) + + # The gdb.Value.string() conversion works on array of bytes, but + # the length we have is the length of the string. So we must + # multiply it by width of character if the string is Unicode. + width = data[0].type.sizeof + if width > 1: + length = length * width + + char = gdb.lookup_type('char') + bytes = data.cast(char.pointer()) + return bytes.string(encoding, length = length) + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/util/uno.py b/solenv/gdb/libreoffice/util/uno.py new file mode 100644 index 000000000..2f0d83a6b --- /dev/null +++ b/solenv/gdb/libreoffice/util/uno.py @@ -0,0 +1,516 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import gdb +import re +import six + +class UnsupportedType(Exception): + '''Represents exception thrown when an unsupported UNO type(like + array or union) is used.''' + + def __init__(self, type): + self.type = type + +class UnknownType(Exception): + '''Represents exception thrown when an unknown UNO type is used.''' + + def __init__(self, type): + self.type = type + +class TypeClass(object): + '''Represents type class of UNO type.''' + + # type class of void + VOID = 0 + # type class of char + CHAR = 1 + # type class of boolean + BOOLEAN = 2 + # type class of byte + BYTE = 3 + # type class of short + SHORT = 4 + # type class of unsigned short + UNSIGNED_SHORT = 5 + # type class of long + LONG = 6 + # type class of unsigned long + UNSIGNED_LONG = 7 + # type class of hyper + HYPER = 8 + # type class of unsigned hyper + UNSIGNED_HYPER = 9 + # type class of float + FLOAT = 10 + # type class of double + DOUBLE = 11 + # type class of string + STRING = 12 + # type class of type + TYPE = 13 + # type class of any + ANY = 14 + # type class of enum + ENUM = 15 + # type class of typedef + TYPEDEF = 16 + # type class of struct + STRUCT = 17 + + # type class of exception + EXCEPTION = 19 + # type class of sequence + SEQUENCE = 20 + + # type class of interface + INTERFACE = 22 + # type class of service (not implemented) + SERVICE = 23 + # type class of module (not implemented) + MODULE = 24 + # type class of interface method + INTERFACE_METHOD = 25 + # type class of interface attribute + INTERFACE_ATTRIBUTE = 26 + # type class of unknown type + UNKNOWN = 27 + # type class of properties + PROPERTY = 28 + # type class of constants + CONSTANT = 29 + # type class of constants groups + CONSTANTS = 30 + # type class of singletons + SINGLETON = 31 + +class TemplateType(object): + + def __init__(self, template, *args): + self.template = template + self.args = args + + def __str__(self): + argtypes = [str(gdb.lookup_type(str(arg)).strip_typedefs()) for arg in self.args] + return self.template + '<' + ', '.join(argtypes) + '>' + +class Type(object): + '''Describes a UNO type.''' + + def __init__(self, typeclass, tag): + '''Constructs a new Type. + @param[in] typeclass value of com::sun::star::uno::TypeClass + @param[in] tag UNO name of the type + ''' + self.typeclass = typeclass + self.tag = tag + # C++ name of the type + self.typename = None + + def type(self): + '''Gets gdb.Type for the type''' + if self.typename: + return gdb.lookup_type(str(self.typename)) + return None + + @staticmethod + def uno2cpp(typename): + return str(typename).replace('.', '::')[1:-1] + + def strip_typedefs(self): + copy = self.copy() + copy.typename = self._strip_typedefs(self.typename) + return copy + + def _strip_typedefs(self, typename): + template_args = re.compile('([^<]+)(<.*>)') + match = template_args.match(typename) + type = self._lookup_type(match.group(1)) + types = [] + if match.group(2): + list_delim = re.compile(', *') + # FIXME: this does not work with nested templates + for arg in match.group(2).split(list_delim): + types.append(self._lookup_type(arg)) + + typename = str(type) + if not types.empty(): + typename += '<' + types.join(', ') + '>' + + return typename + + def _lookup_type(self, typename): + if typename != '': + type = gdb.lookup_type(typename) + if type: + type = type.strip_typedefs() + return type + +def make_uno_type(val): + '''Creates a UNO type from gdb.Value of type + com::sun::star::uno::Type, typelib_TypeDescription, or + typelib_TypeDescriptionReference + ''' + + cssu_type = 'com::sun::star::uno::Type' + type_desc = '_typelib_TypeDescription' + type_descs =( + type_desc, + '_typelib_CompoundTypeDescription', + '_typelib_StructTypeDescription', + '_typelib_IndirectTypeDescription', + '_typelib_EnumTypeDescription', + '_typelib_InterfaceMemberTypeDescription', + '_typelib_InterfaceMethodTypeDescription', + '_typelib_InterfaceAttributeTypeDescription', + '_typelib_InterfaceTypeDescription' + ) + type_desc_ref = '_typelib_TypeDescriptionReference' + + type = val.type.strip_typedefs() + + if type.tag == cssu_type: + pvalue = val['_pType'] + assert pvalue + val = pvalue.dereference() + type = val.type.strip_typedefs() + + while type.tag == type_desc_ref: + pvalue = val['pType'] + assert pvalue + val = pvalue.dereference() + type = val.type.strip_typedefs() + + if type.tag not in type_descs: + return None + + # determination of the UNO type + full_val = val + if type.tag != type_desc: + while 'aBase' in val: + val = val['aBase'] + type_class = int(val['eTypeClass']) + name = val['pTypeName'].dereference() + uno_type = None + if type_class == TypeClass.VOID: + uno_type = VoidType() + elif type_class == TypeClass.CHAR: + uno_type = PrimitiveType(type_class, name, 'char') + elif type_class == TypeClass.BOOLEAN: + uno_type = PrimitiveType(type_class, name, 'sal_Bool') + elif type_class == TypeClass.BYTE: + uno_type = PrimitiveType(type_class, name, 'sal_Int8') + elif type_class == TypeClass.SHORT: + uno_type = PrimitiveType(type_class, name, 'sal_Int16') + elif type_class == TypeClass.UNSIGNED_SHORT: + uno_type = PrimitiveType(type_class, name, 'sal_uInt16') + elif type_class == TypeClass.LONG: + uno_type = PrimitiveType(type_class, name, 'sal_Int32') + elif type_class == TypeClass.UNSIGNED_LONG: + uno_type = PrimitiveType(type_class, name, 'sal_uInt32') + elif type_class == TypeClass.HYPER: + uno_type = PrimitiveType(type_class, name, 'sal_Int64') + elif type_class == TypeClass.UNSIGNED_HYPER: + uno_type = PrimitiveType(type_class, name, 'sal_uInt64') + elif type_class == TypeClass.FLOAT: + uno_type = PrimitiveType(type_class, name, 'float') + elif type_class == TypeClass.DOUBLE: + uno_type = PrimitiveType(type_class, name, 'double') + elif type_class == TypeClass.STRING: + uno_type = PrimitiveType(type_class, name, 'rtl::OUString') + elif type_class == TypeClass.TYPE: + uno_type = PrimitiveType(type_class, name, 'com::sun::star::uno::Type') + elif type_class == TypeClass.ANY: + uno_type = PrimitiveType(type_class, name, 'com::sun::star::uno::Any') + elif type_class == TypeClass.ENUM: + uno_type = EnumType(val, full_val) + elif type_class == TypeClass.TYPEDEF: + pass + elif type_class == TypeClass.STRUCT: + uno_type = StructType(val, full_val) + elif type_class == TypeClass.EXCEPTION: + uno_type = CompoundType(val, full_val) + elif type_class == TypeClass.SEQUENCE: + uno_type = IndirectType(val, full_val) + elif type_class == TypeClass.INTERFACE: + uno_type = InterfaceType(val, full_val) + elif type_class == TypeClass.SERVICE: + raise UnsupportedType('service') + elif type_class == TypeClass.MODULE: + raise UnsupportedType('module') + elif type_class == TypeClass.INTERFACE_METHOD: + uno_type = InterfaceMethodType(val, full_val) + elif type_class == TypeClass.INTERFACE_ATTRIBUTE: + uno_type = InterfaceAttributeType(val, full_val) + elif type_class == TypeClass.UNKNOWN: + raise UnknownType(type) + elif type_class == TypeClass.PROPERTY: + pass + elif type_class == TypeClass.CONSTANT: + pass + elif type_class == TypeClass.CONSTANTS: + pass + elif type_class == TypeClass.SINGLETON: + pass + else: + raise UnknownType(type) + + assert uno_type + return uno_type + +def uno_cast(type, val): + '''Casts val or pointer to UNO type represented by type''' + if val.type.code == gdb.TYPE_CODE_PTR: + return val.cast(type.type().pointer()) + else: + return val.cast(type.type()) + +class VoidType(Type): + + def __init__(self): + super(VoidType, self).__init__(TypeClass.VOID, "void") + self.typename = "void" + +class PrimitiveType(Type): + + def __init__(self, typeclass, typename_uno, typename_cpp): + super(PrimitiveType, self).__init__(typeclass, typename_uno) + self.typename = str(typename_cpp) + +class CompoundType(Type): + + def __init__(self, type, full_type): + super(CompoundType, self).__init__(type['eTypeClass'], type['pTypeName'].dereference()) + self.typename = self.uno2cpp(self.tag) + self._type = full_type + + class _iterator(six.Iterator): + + def __init__(self, count, types, names): + self.count = count + self.members = members + self.names = names + self.pos = 0 + + def __iter__(self): + return self + + def __next__(self): + assert self.pos >= 0 and self.pos <= self.count + if self.pos == self.count: + raise StopIteration + + pmember = self.members[self.pos] + assert pmember + pname = self.names[self.i] + assert pname + self.pos = self.pos + 1 + member = make_uno_type(pmember.dereference()) + assert member + name = str(pname.dereference()) + return (name, member) + + def attributes(self): + return _iterator(self._type['nMembers'], self._type['ppTypeRefs'], + self._type['ppMemberNames']) + +class StructType(CompoundType): + + def __init__(self, type, full_type): + full_type = full_type.cast(gdb.lookup_type('_typelib_StructTypeDescription')) + super(StructType, self).__init__(type, full_type['aBase']) + +class IndirectType(Type): + + def __init__(self, type, full_type): + super(IndirectType, self).__init__(type['eTypeClass'], type['pTypeName'].dereference()) + full_type = full_type.cast(gdb.lookup_type('_typelib_IndirectTypeDescription')) + pelem = full_type['pType'] + assert pelem + self.element = make_uno_type(pelem.dereference()) + assert self.element + self.typename = TemplateType('com::sun::star::uno::Sequence', self.element.typename) + +class EnumType(Type): + + def __init__(self, type, full_type): + super(EnumType, self).__init__(TypeClass.ENUM, type['pTypeName'].dereference()) + self.typename = self.uno2cpp(self.tag) + self._type = full_type.cast(gdb.lookup_type('_typelib_EnumTypeDescription')) + + class _iterator(six.Iterator): + + def __init__(self, count, values, names): + self.count = count + self.values = values + self.names = names + self.pos = 0 + + def __iter__(self): + return self + + def __next__(self): + assert self.pos >= 0 and self.pos <= self.count + if self.pos == self.count: + raise StopIteration + + pvalue = self.values[self.pos] + assert pvalue + pname = self.names[self.pos] + assert pname + self.pos = self.pos + 1 + val = int(pvalue.dereference()) + name = str(pname.dereference()) + return (name, val) + + def values(self): + return _iterator(self._type['nEnumValues'], + self._type['ppEnumNames'], self._type['pEnumValues']) + + def default_value(self): + return self._type['nDefaultEnumValue'] + +class InterfaceMemberType(Type): + + def __init__(self, type, full_type): + super(InterfaceMemberType, self).__init__(type['eTypeClass'], type['pTypeName'].dereference()) + (interface, delim, member) = self.tag.partition('::') + self.typename = self.uno2cpp(interface) + '::*' + member + full_type = full_type.cast(gdb.lookup_type('_typelib_InterfaceMemberTypeDescription')) + self.position = full_type['nPosition'] + pname = full_type['pMemberName'] + assert pname + self.name = pname.dereference() + +class InterfaceMethodType(InterfaceMemberType): + + def __init__(self, type, full_type): + full_type = full_type.cast(gdb.lookup_type('_typelib_InterfaceMethodTypeDescription')) + super(InterfaceMethodType, self).__init__(type, full_type['aBase']) + pret = full_type['pReturnTypeRef'] + assert pret + self.return_type = make_uno_type(pret.dereference()) + assert self.return_type + self.oneway = full_type['bOneWay'] + self._type = full_type + + class _iterator(six.Iterator): + + def __init__(self, count, values): + self.count = count + self.values = values + self.pos = 0 + assert values + + def __iter__(self): + return self + + def __next__(self): + assert self.pos >= 0 and self.pos <= self.count + if self.pos == self.count: + raise StopIteration + + val = self.values[self.pos] + self.pos = self.pos + 1 + return val + + class parameter(tuple): + + def __init__(self, type): + self.__init_tuple(type) + self.input = type['bIn'] + self.output = type['bOut'] + + def _init_tuple(self, type): + pname = self['pName'] + assert pname + ptype = self['pTypeRef'] + assert ptype + name = str(pname.dereference()) + type = make_uno_type(ptype.dereference()) + assert type + super(parameter, self).__init__(name, type) + + def parameters(self): + for param in _iterator(self._type['nParams'], self._type['pParams']): + yield parameter(param) + + def exceptions(self): + def make_exception(self, pex): + assert pex + ex = make_uno_type(pex.dereference()) + assert ex + return ex + + for ex in _iterator( + self._type['nExceptions'], self._type['ppExceptions']): + yield make_exception(ex) + +class InterfaceAttributeType(InterfaceMemberType): + + def __init__(self, type, full_type): + full_type = full_type.cast(gdb.lookup_type('_typelib_InterfaceAttributeTypeDescription')) + super(InterfaceAttributeType, self).__init__(type, full_type['aBase']) + self.readonly = full_type['bReadOnly'] + ptype = full_type['pAttributeTypeRef'] + assert ptype + self.type = make_uno_type(ptype.dereference()) + assert self.type + +class MembersNotInitialized(Exception): + '''Represents exception raised when interface type' members haven't + been initialized(i.e. just level 1 initialization has been + performed)''' + pass + +class InterfaceType(Type): + + def __init__(self, type, full_type): + super(InterfaceType, self).__init__(TypeClass.INTERFACE, type['pTypeName'].dereference()) + assert int(type['eTypeClass']) == TypeClass.INTERFACE + self.typename = self.uno2cpp(self.tag) + full_type = full_type.cast(gdb.lookup_type('_typelib_InterfaceTypeDescription')) + self.uik = full_type['aUik'] + self._type = full_type + + class _iterator(six.Iterator): + + def __init__(self, count, values): + assert values + self.count = count + self.values = values + self.pos = 0 + + def __iter__(self): + return self + + def __next__(self): + assert self.pos >= 0 and self.pos <= self.count + pvalue = self.values[self.pos] + assert pvalue + self.pos = self.pos + 1 + uno = make_uno_type(pvalue.dereference()) + assert uno + return uno + + def members(self): + return __members(self._type['nMembers'], self._type['ppMembers']) + + def all_members(self): + return __members(self._type['nAllMembers'], self._type['ppAllMembers']) + + def __members(count, values): + if values == 0: + raise MembersNotInitialized + return _iterator(count, values) + + def bases(self): + return _iterator(self._type['nBaseTypes'], self._type['ppBaseTypes']) + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/utl.py b/solenv/gdb/libreoffice/utl.py new file mode 100644 index 000000000..0e6de6ff9 --- /dev/null +++ b/solenv/gdb/libreoffice/utl.py @@ -0,0 +1,39 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import gdb + +from libreoffice.util import printing + +class TranslateIdPrinter(object): + '''Prints a TranslateId.''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return self.value['mpContext'].format_string(format='s') + " " + self.value['mpId'].format_string(format='s') + +printer = None + +def build_pretty_printers(): + global printer + + printer = printing.Printer('libreoffice/utl') + + # various types + printer.add('TranslateId', TranslateIdPrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/vcl.py b/solenv/gdb/libreoffice/vcl.py new file mode 100644 index 000000000..ce5957475 --- /dev/null +++ b/solenv/gdb/libreoffice/vcl.py @@ -0,0 +1,123 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import six +import gdb +from libreoffice.util import printing + +class ImplSchedulerDataPrinter(object): + '''Prints the ImplSchedulerData linked list. + + This can be used to dump the current state of the scheduler via: + p *ImplGetSVData()->maSchedCtx.mpFirstSchedulerData + + This doesn't include currently invoked tasks AKA the stack. + + To dump the scheduler stack of invoked tasks use: + p *ImplGetSVData()->maSchedCtx.mpSchedulerStack + ''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + self.timer_type_ptr = gdb.lookup_type("Timer").pointer() + self.idle_type_ptr = gdb.lookup_type("Idle").pointer() + + def as_string(self, gdbobj): + if gdbobj['mpTask']: + task = gdbobj['mpTask'].dereference() + timer = gdbobj['mpTask'].dynamic_cast( self.timer_type_ptr ) + idle = gdbobj['mpTask'].dynamic_cast( self.idle_type_ptr ) + if idle: + task_type = "Idle" + elif timer: + task_type = "Timer" + else: + task_type = "Task" + res = "{:7s}{:10s} active: {:6s}".format( task_type, str(task['mePriority']).replace('TaskPriority::',''), str(task['mbActive']) ) + name = task['mpDebugName'] + if not name: + res = res + " (task debug name not set)" + else: + res = "{} '{}' ({})".format(res, str(name.string()), str(task.dynamic_type)) + val_type = gdb.lookup_type(str( task.dynamic_type )).pointer() + timer = gdbobj['mpTask'].cast( val_type ) + if task_type == "Timer": + res = "{}: {}ms".format(res, timer['mnTimeout']) + elif task_type == "Idle": + assert 0 == timer['mnTimeout'], "Idle with timeout == {}".format( timer['mnTimeout'] ) + return res + else: + return "(no task)" + + def to_string(self): + return self.typename + + def children(self): + return self._iterator(self) + + def display_hint(self): + return 'array' + + class _iterator(six.Iterator): + + def __init__(self, printer): + self.pos = 0 + self.printer = printer + self.value = printer.value + + def __iter__(self): + return self + + def __next__(self): + if not self.value: + raise StopIteration() + + pos = str(self.pos) + name = "\n " + self.printer.as_string(self.value) + self.value = self.value['mpNext'] + self.pos += 1 + + return (pos, name) + +class ImplSchedulerContextPrinter(object): + + def __init__(self, typename, value): + self.typename = typename + self.value = value + self.prio = gdb.lookup_type('TaskPriority') + + def to_string(self): + res = "{\n" + if self.value['mnTimerPeriod']: + res = res + "mnTimerPeriod = " + str(self.value['mnTimerPeriod']) + "\n" + if self.value['mpSchedulerStack']: + res = res + "STACK, " + str(self.value['mpSchedulerStack'].dereference()) + if self.value['mpFirstSchedulerData']: + for key, value in self.prio.items(): + first = self.value['mpFirstSchedulerData'][value.enumval] + if first: + res = res + key.replace('TaskPriority::', '') + ", " + str(first.dereference()) + return res + "}" + +printer = None + +def build_pretty_printers(): + global printer + + printer = printing.Printer("libreoffice/vcl") + printer.add('ImplSchedulerData', ImplSchedulerDataPrinter) + printer.add('ImplSchedulerContext', ImplSchedulerContextPrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/libreoffice/writerfilter.py b/solenv/gdb/libreoffice/writerfilter.py new file mode 100644 index 000000000..487263e92 --- /dev/null +++ b/solenv/gdb/libreoffice/writerfilter.py @@ -0,0 +1,88 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +from libreoffice.util import printing + +class OOXMLPropertySetPrinter(object): + '''Prints writerfilter::ooxml::OOXMLPropertySet''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + + def children(self): + children = [ ( 'properties', self.value['mProperties'] ) ] + return children.__iter__() + +class OOXMLPropertyPrinter(object): + '''Prints writerfilter::ooxml::OOXMLProperty''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + + def children(self): + children = [ ( 'id', self.value['mId'] ), + ( 'type', self.value['meType'] ), + ( 'value', self.value['mpValue'] ) ] + return children.__iter__() + +class OOXMLPropertySetValuePrinter(object): + '''Prints writerfilter::ooxml::OOXMLPropertySetValue''' + + def __init__(self, typename, value): + self.typename = typename + self.value = value + + def to_string(self): + return "%s" % (self.typename) + +class OOXMLStringValuePrinter(object): + '''Prints writerfilter::ooxml::OOXMLStringValue''' + + def __init__(self, typename, value): + self.value = value + + def to_string(self): + return "%s" % (self.value['mStr']) + +class OOXMLIntegerValuePrinter(object): + '''Prints writerfilter::ooxml::OOXMLIntegerValue''' + + def __init__(self, typename, value): + self.value = value + + def to_string(self): + return "%d" % (self.value['mnValue']) + +printer = None + +def build_pretty_printers(): + global printer + + printer = printing.Printer("libreoffice/writerfilter") + printer.add('writerfilter::ooxml::OOXMLProperty', OOXMLPropertyPrinter) + printer.add('writerfilter::ooxml::OOXMLPropertySet', OOXMLPropertySetPrinter) + printer.add('writerfilter::ooxml::OOXMLPropertySetValue', OOXMLPropertySetValuePrinter) + printer.add('writerfilter::ooxml::OOXMLStringValue', OOXMLStringValuePrinter) + printer.add('writerfilter::ooxml::OOXMLIntegerValue', OOXMLIntegerValuePrinter) + printer.add('writerfilter::ooxml::OOXMLHexValue', OOXMLIntegerValuePrinter) + +def register_pretty_printers(obj): + printing.register_pretty_printer(printer, obj) + +build_pretty_printers() + +# vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/solenv/gdb/six.py b/solenv/gdb/six.py new file mode 100644 index 000000000..5fe9f8e14 --- /dev/null +++ b/solenv/gdb/six.py @@ -0,0 +1,980 @@ +# Copyright (c) 2010-2020 Benjamin Peterson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Utilities for writing code that runs on Python 2 and 3""" + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson <benjamin@python.org>" +__version__ = "1.14.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + get_source = get_code # same as get_code + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("getoutput", "commands", "subprocess"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("splitvalue", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", "moves.urllib.parse") + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", "moves.urllib.error") + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), + MovedAttribute("parse_http_list", "urllib2", "urllib.request"), + MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", "moves.urllib.request") + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", "moves.urllib.response") + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", "moves.urllib.robotparser") + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + +_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), + "moves.urllib") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") + + +if PY3: + def b(s): + return s.encode("latin-1") + + def u(s): + return s + unichr = chr + import struct + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + del io + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" + _assertNotRegex = "assertNotRegex" +else: + def b(s): + return s + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +def assertNotRegex(self, *args, **kwargs): + return getattr(self, _assertNotRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + try: + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + finally: + value = None + tb = None + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + exec_("""def reraise(tp, value, tb=None): + try: + raise tp, value, tb + finally: + tb = None +""") + + +if sys.version_info[:2] > (3,): + exec_("""def raise_from(value, from_value): + try: + raise value from from_value + finally: + value = None +""") +else: + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + # This does exactly the same what the :func:`py3:functools.update_wrapper` + # function does on Python versions after 3.2. It sets the ``__wrapped__`` + # attribute on ``wrapper`` object and it doesn't raise an error if any of + # the attributes mentioned in ``assigned`` and ``updated`` are missing on + # ``wrapped`` object. + def _update_wrapper(wrapper, wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + for attr in assigned: + try: + value = getattr(wrapped, attr) + except AttributeError: + continue + else: + setattr(wrapper, attr, value) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + wrapper.__wrapped__ = wrapped + return wrapper + _update_wrapper.__doc__ = functools.update_wrapper.__doc__ + + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + return functools.partial(_update_wrapper, wrapped=wrapped, + assigned=assigned, updated=updated) + wraps.__doc__ = functools.wraps.__doc__ + +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + + def __new__(cls, name, this_bases, d): + if sys.version_info[:2] >= (3, 7): + # This version introduced PEP 560 that requires a bit + # of extra care (we mimic what is done by __build_class__). + resolved_bases = types.resolve_bases(bases) + if resolved_bases is not bases: + d['__orig_bases__'] = bases + else: + resolved_bases = bases + return meta(name, resolved_bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + if hasattr(cls, '__qualname__'): + orig_vars['__qualname__'] = cls.__qualname__ + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def ensure_binary(s, encoding='utf-8', errors='strict'): + """Coerce **s** to six.binary_type. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> encoded to `bytes` + - `bytes` -> `bytes` + """ + if isinstance(s, text_type): + return s.encode(encoding, errors) + elif isinstance(s, binary_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def ensure_str(s, encoding='utf-8', errors='strict'): + """Coerce *s* to `str`. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if not isinstance(s, (text_type, binary_type)): + raise TypeError("not expecting type '%s'" % type(s)) + if PY2 and isinstance(s, text_type): + s = s.encode(encoding, errors) + elif PY3 and isinstance(s, binary_type): + s = s.decode(encoding, errors) + return s + + +def ensure_text(s, encoding='utf-8', errors='strict'): + """Coerce *s* to six.text_type. + + For Python 2: + - `unicode` -> `unicode` + - `str` -> `unicode` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if isinstance(s, binary_type): + return s.decode(encoding, errors) + elif isinstance(s, text_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def python_2_unicode_compatible(klass): + """ + A class decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if '__str__' not in klass.__dict__: + raise ValueError("@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % + klass.__name__) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if (type(importer).__name__ == "_SixMetaPathImporter" and + importer.name == __name__): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) |