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
26 from .libtoolimporter import LibtoolImporter
27 from .message import Position
29 with LibtoolImporter(None, None):
30 if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ:
31 from _giscanner import SourceScanner as CSourceScanner
33 from giscanner._giscanner import SourceScanner as CSourceScanner
35 HEADER_EXTS = ['.h', '.hpp', '.hxx']
36 SOURCE_EXTS = ['.c', '.cpp', '.cc', '.cxx']
37 ALL_EXTS = SOURCE_EXTS + HEADER_EXTS
39 (CSYMBOL_TYPE_INVALID,
40 CSYMBOL_TYPE_ELLIPSIS,
43 CSYMBOL_TYPE_FUNCTION,
48 CSYMBOL_TYPE_MEMBER) = range(10)
59 CTYPE_FUNCTION) = range(10)
61 STORAGE_CLASS_NONE = 0
62 STORAGE_CLASS_TYPEDEF = 1 << 1
63 STORAGE_CLASS_EXTERN = 1 << 2
64 STORAGE_CLASS_STATIC = 1 << 3
65 STORAGE_CLASS_AUTO = 1 << 4
66 STORAGE_CLASS_REGISTER = 1 << 5
68 TYPE_QUALIFIER_NONE = 0
69 TYPE_QUALIFIER_CONST = 1 << 1
70 TYPE_QUALIFIER_RESTRICT = 1 << 2
71 TYPE_QUALIFIER_VOLATILE = 1 << 3
72 TYPE_QUALIFIER_EXTENSION = 1 << 4
75 FUNCTION_INLINE = 1 << 1
78 UNARY_POINTER_INDIRECTION,
81 UNARY_BITWISE_COMPLEMENT,
82 UNARY_LOGICAL_NEGATION) = range(6)
85 def symbol_type_name(symbol_type):
87 CSYMBOL_TYPE_INVALID: 'invalid',
88 CSYMBOL_TYPE_ELLIPSIS: 'ellipsis',
89 CSYMBOL_TYPE_CONST: 'const',
90 CSYMBOL_TYPE_OBJECT: 'object',
91 CSYMBOL_TYPE_FUNCTION: 'function',
92 CSYMBOL_TYPE_STRUCT: 'struct',
93 CSYMBOL_TYPE_UNION: 'union',
94 CSYMBOL_TYPE_ENUM: 'enum',
95 CSYMBOL_TYPE_TYPEDEF: 'typedef',
96 CSYMBOL_TYPE_MEMBER: 'member'}.get(symbol_type)
99 def ctype_name(ctype):
101 CTYPE_INVALID: 'invalid',
103 CTYPE_BASIC_TYPE: 'basic',
104 CTYPE_TYPEDEF: 'typedef',
105 CTYPE_STRUCT: 'struct',
106 CTYPE_UNION: 'union',
108 CTYPE_POINTER: 'pointer',
109 CTYPE_ARRAY: 'array',
110 CTYPE_FUNCTION: 'function'}.get(ctype)
113 class SourceType(object):
114 __members__ = ['type', 'base_type', 'name', 'type_qualifier',
115 'child_list', 'is_bitfield']
117 def __init__(self, scanner, stype):
118 self._scanner = scanner
122 return '<%s type=%r name=%r>' % (
123 self.__class__.__name__,
124 ctype_name(self.type),
129 return self._stype.type
133 if self._stype.base_type is not None:
134 return SourceType(self._scanner, self._stype.base_type)
138 return self._stype.name
141 def type_qualifier(self):
142 return self._stype.type_qualifier
145 def child_list(self):
146 for symbol in self._stype.child_list:
149 yield SourceSymbol(self._scanner, symbol)
152 def is_bitfield(self):
153 return self._stype.is_bitfield
156 class SourceSymbol(object):
157 __members__ = ['const_int', 'const_double', 'const_string', 'const_boolean',
158 'ident', 'type', 'base_type']
160 def __init__(self, scanner, symbol):
161 self._scanner = scanner
162 self._symbol = symbol
165 src = self.source_filename
169 src += ':%r' % (line, )
170 return '<%s type=%r ident=%r src=%r>' % (
171 self.__class__.__name__,
172 symbol_type_name(self.type),
178 return self._symbol.const_int
181 def const_double(self):
182 return self._symbol.const_double
185 def const_string(self):
186 return self._symbol.const_string
189 def const_boolean(self):
190 return self._symbol.const_boolean
194 return self._symbol.ident
198 return self._symbol.type
202 if self._symbol.base_type is not None:
203 return SourceType(self._scanner, self._symbol.base_type)
206 def source_filename(self):
207 return self._symbol.source_filename
211 return self._symbol.line
215 return self._symbol.private
219 return Position(self._symbol.source_filename,
223 class SourceScanner(object):
226 self._scanner = CSourceScanner()
228 self._cpp_options = []
232 def set_cpp_options(self, includes, defines, undefines, cflags=[]):
233 self._cpp_options.extend(cflags)
234 for prefix, args in [('-I', [os.path.realpath(f) for f in includes]),
237 for arg in (args or []):
239 if not opt in self._cpp_options:
240 self._cpp_options.append(opt)
242 def parse_files(self, filenames):
243 for filename in filenames:
244 # self._scanner expects file names to be canonicalized and symlinks to be resolved
245 filename = os.path.realpath(filename)
246 self._scanner.append_filename(filename)
247 self._filenames.append(filename)
250 for filename in self._filenames:
251 if os.path.splitext(filename)[1] in SOURCE_EXTS:
252 self._scanner.lex_filename(filename)
254 headers.append(filename)
258 def parse_macros(self, filenames):
259 self._scanner.set_macro_scan(True)
260 # self._scanner expects file names to be canonicalized and symlinks to be resolved
261 self._scanner.parse_macros([os.path.realpath(f) for f in filenames])
262 self._scanner.set_macro_scan(False)
264 def get_symbols(self):
265 for symbol in self._scanner.get_symbols():
266 yield SourceSymbol(self._scanner, symbol)
268 def get_comments(self):
269 return self._scanner.get_comments()
273 for symbol in self._scanner.get_symbols():
274 print symbol.ident, symbol.base_type.name, symbol.type
278 def _parse(self, filenames):
282 defines = ['__GI_SCANNER__']
284 cpp_args = os.environ.get('CC', 'cc').split() # support CC="ccache gcc"
286 # The Microsoft compiler/preprocessor (cl) does not accept
287 # source input from stdin (the '-' flag), so we need
288 # some help from gcc from MinGW/Cygwin or so.
289 # Note that the generated dumper program is
290 # still built and linked by Visual C++.
292 cpp_args += os.environ.get('CPPFLAGS', '').split()
293 cpp_args += os.environ.get('CFLAGS', '').split()
294 cpp_args += ['-E', '-C', '-I.', '-']
295 cpp_args += self._cpp_options
297 proc = subprocess.Popen(cpp_args,
298 stdin=subprocess.PIPE,
299 stdout=subprocess.PIPE)
301 for define in defines:
302 proc.stdin.write('#ifndef %s\n' % (define, ))
303 proc.stdin.write('# define %s\n' % (define, ))
304 proc.stdin.write('#endif\n')
306 proc.stdin.write('#undef %s\n' % (undef, ))
307 for filename in filenames:
308 proc.stdin.write('#include <%s>\n' % (filename, ))
311 tmp_fd, tmp_name = tempfile.mkstemp()
312 fp = os.fdopen(tmp_fd, 'w+b')
314 data = proc.stdout.read(4096)
322 assert proc, 'Proc was none'
324 if proc.returncode != 0:
325 raise SystemExit('Error while processing the source.')
327 self._scanner.parse_file(fp.fileno())