2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
21 from __future__ import with_statement
24 from contextlib import contextmanager
25 from cStringIO import StringIO
26 from xml.sax.saxutils import escape, quoteattr
27 from .libtoolimporter import LibtoolImporter
30 def _calc_attrs_length(attributes, indent, self_indent):
34 for attr, value in attributes:
35 # FIXME: actually, if we have attributes with None as value this
36 # should be considered a bug and raise an error. We are just
37 # ignoring them here while we fix GIRParser to create the right
38 # ast with the correct attributes.
41 attr_length += 2 + len(attr) + len(quoteattr(value))
42 return attr_length + indent + self_indent
45 def collect_attributes(tag_name, attributes, self_indent,
46 self_indent_char, indent=-1):
49 if _calc_attrs_length(attributes, indent, self_indent) > 79:
50 indent_len = self_indent + len(tag_name) + 1
55 for attr, value in attributes:
56 # FIXME: actually, if we have attributes with None as value this
57 # should be considered a bug and raise an error. We are just
58 # ignoring them here while we fix GIRParser to create the right
59 # ast with the correct attributes.
62 if indent_len and not first:
63 attr_value += '\n%s' % (self_indent_char * indent_len)
64 attr_value += ' %s=%s' % (attr, quoteattr(value))
70 with LibtoolImporter(None, None):
71 if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ:
72 from _giscanner import collect_attributes
74 from giscanner._giscanner import collect_attributes
77 class XMLWriter(object):
80 self._data = StringIO()
81 self._data.write('<?xml version="1.0"?>\n')
85 self.enable_whitespace()
89 def _open_tag(self, tag_name, attributes=None):
90 if attributes is None:
92 attrs = collect_attributes(
93 tag_name, attributes, self._indent,
96 self.write_line(u'<%s%s>' % (tag_name, attrs))
98 def _close_tag(self, tag_name):
99 self.write_line(u'</%s>' % (tag_name, ))
103 def enable_whitespace(self):
104 self._indent_char = ' '
105 self._newline_char = '\n'
107 def disable_whitespace(self):
108 self._indent_char = ''
109 self._newline_char = ''
112 return self._data.getvalue()
114 def write_line(self, line=u'', indent=True, do_escape=False):
115 if isinstance(line, str):
116 line = line.decode('utf-8')
117 assert isinstance(line, unicode)
119 line = escape(line.encode('utf-8')).decode('utf-8')
121 self._data.write('%s%s%s' % (
122 self._indent_char * self._indent,
123 line.encode('utf-8'),
126 self._data.write('%s%s' % (line.encode('utf-8'), self._newline_char))
128 def write_comment(self, text):
129 self.write_line('<!-- %s -->' % (text, ))
131 def write_tag(self, tag_name, attributes, data=None):
132 if attributes is None:
134 prefix = u'<%s' % (tag_name, )
136 if isinstance(data, str):
137 data = data.decode('UTF-8')
138 suffix = u'>%s</%s>' % (escape(data), tag_name)
141 attrs = collect_attributes(
142 tag_name, attributes,
145 len(prefix) + len(suffix))
146 self.write_line(prefix + attrs + suffix)
148 def push_tag(self, tag_name, attributes=None):
149 if attributes is None:
151 self._open_tag(tag_name, attributes)
152 self._tag_stack.append(tag_name)
153 self._indent += self._indent_unit
156 self._indent -= self._indent_unit
157 tag_name = self._tag_stack.pop()
158 self._close_tag(tag_name)
162 def tagcontext(self, tag_name, attributes=None):
163 self.push_tag(tag_name, attributes)
172 w.push_tag('repository')
173 w.push_tag('namespace')
174 w.push_tag('enumeration')
178 ('c:identifier', 'GTK_ANCHOR_WEST'),
179 ('glib:nick', 'west')])
185 lines = x.split('\n')
188 assert len(lines[3]) < 80, len(lines[3])
190 if __name__ == '__main__':