Add generated file warning comment
[platform/upstream/gobject-introspection.git] / giscanner / xmlwriter.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
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.
9 #
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.
14 #
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.
19 #
20
21 from __future__ import with_statement
22
23 from contextlib import contextmanager
24 from cStringIO import StringIO
25 from xml.sax.saxutils import quoteattr
26
27 from .libtoolimporter import LibtoolImporter
28
29
30 def _calc_attrs_length(attributes, indent, self_indent):
31     if indent == -1:
32         return -1
33     attr_length = 0
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.
39         if value is None:
40             continue
41         attr_length += 2 + len(attr) + len(quoteattr(value))
42     return attr_length + indent + self_indent
43
44
45 def collect_attributes(tag_name, attributes, self_indent,
46                        self_indent_char, indent=-1):
47     if not attributes:
48         return ''
49     if _calc_attrs_length(attributes, indent, self_indent) > 79:
50         indent_len = self_indent + len(tag_name) + 1
51     else:
52         indent_len = 0
53     first = True
54     attr_value = ''
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.
60         if value is None:
61             continue
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))
65         if first:
66             first = False
67     return attr_value
68
69
70 with LibtoolImporter:
71     from giscanner._giscanner import collect_attributes
72
73
74 class XMLWriter(object):
75
76     def __init__(self):
77         self._data = StringIO()
78         self._data.write('<?xml version="1.0"?>\n')
79         self._tag_stack = []
80         self._indent = 0
81         self._indent_unit = 2
82         self._indent_char = ' '
83
84     # Private
85
86     def _open_tag(self, tag_name, attributes=None):
87         attrs = collect_attributes(
88             tag_name, attributes, self._indent,
89             self._indent_char,
90             len(tag_name) + 2)
91         self.write_line('<%s%s>' % (tag_name, attrs))
92
93     def _close_tag(self, tag_name):
94         self.write_line('</%s>' % (tag_name, ))
95
96     # Public API
97
98     def get_xml(self):
99         return self._data.getvalue()
100
101     def write_line(self, line=''):
102         self._data.write('%s%s\n' % (self._indent_char * self._indent, line))
103
104     def write_comment(self, text):
105         self.write_line('<!-- %s -->' % (text, ))
106
107     def write_tag(self, tag_name, attributes, data=None):
108         if attributes is None:
109             attributes = []
110         prefix = '<%s' % (tag_name, )
111         if data is not None:
112             suffix = '>%s</%s>' % (data, tag_name)
113         else:
114             suffix = '/>'
115         attrs = collect_attributes(
116             tag_name, attributes,
117             self._indent,
118             self._indent_char,
119             len(prefix) + len(suffix))
120         self.write_line(prefix + attrs + suffix)
121
122     def push_tag(self, tag_name, attributes=None):
123         self._open_tag(tag_name, attributes)
124         self._tag_stack.append(tag_name)
125         self._indent += self._indent_unit
126
127     def pop_tag(self):
128         self._indent -= self._indent_unit
129         tag_name = self._tag_stack.pop()
130         self._close_tag(tag_name)
131         return tag_name
132
133     @contextmanager
134     def tagcontext(self, tag_name, attributes=None):
135         self.push_tag(tag_name, attributes)
136         try:
137             yield
138         finally:
139             self.pop_tag()
140
141
142 def test():
143     w = XMLWriter()
144     w.push_tag('repository')
145     w.push_tag('namespace')
146     w.push_tag('enumeration')
147     w.push_tag('member',
148                [('name', 'west'),
149                 ('value', '7'),
150                 ('c:identifier', 'GTK_ANCHOR_WEST'),
151                 ('glib:nick', 'west')])
152
153     w.pop_tag()
154     w.pop_tag()
155     w.pop_tag()
156     x = w.get_xml()
157     lines = x.split('\n')
158     import pprint
159     pprint.pprint(lines)
160     assert len(lines[3]) < 80, len(lines[3])
161
162 if __name__ == '__main__':
163     test()