1 /* GObject introspection: scanner
3 * Copyright (C) 2008 Johan Dahlin <johan@gnome.org>
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.
26 #include "sourcescanner.h"
35 #define WIN32_LEAN_AND_MEAN
40 #include <glib-object.h>
42 DL_EXPORT(void) init_giscanner(void);
44 #define NEW_CLASS(ctype, name, cname, num_methods) \
45 static const PyMethodDef _Py##cname##_methods[num_methods]; \
46 PyTypeObject Py##cname##_Type = { \
47 PyObject_HEAD_INIT(NULL) \
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
53 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, \
58 0, 0, NULL, NULL, 0, 0, \
62 #define REGISTER_TYPE(d, name, type) \
63 type.ob_type = &PyType_Type; \
64 type.tp_alloc = PyType_GenericAlloc; \
65 type.tp_new = PyType_GenericNew; \
66 if (PyType_Ready (&type)) \
68 PyDict_SetItemString (d, name, (PyObject *)&type); \
76 static PyObject * pygi_source_type_new (GISourceType *type);
80 GISourceSymbol *symbol;
85 GISourceScanner *scanner;
88 NEW_CLASS (PyGISourceSymbol, "SourceSymbol", GISourceSymbol, 10);
89 NEW_CLASS (PyGISourceType, "SourceType", GISourceType, 9);
90 NEW_CLASS (PyGISourceScanner, "SourceScanner", GISourceScanner, 8);
96 pygi_source_symbol_new (GISourceSymbol *symbol)
98 PyGISourceSymbol *self;
106 self = (PyGISourceSymbol *)PyObject_New (PyGISourceSymbol,
107 &PyGISourceSymbol_Type);
108 self->symbol = symbol;
109 return (PyObject*)self;
113 symbol_get_type (PyGISourceSymbol *self,
116 return PyInt_FromLong (self->symbol->type);
120 symbol_get_line (PyGISourceSymbol *self,
123 return PyInt_FromLong (self->symbol->line);
127 symbol_get_private (PyGISourceSymbol *self,
130 return PyBool_FromLong (self->symbol->private);
134 symbol_get_ident (PyGISourceSymbol *self,
138 if (!self->symbol->ident)
144 return PyString_FromString (self->symbol->ident);
148 symbol_get_base_type (PyGISourceSymbol *self,
151 return pygi_source_type_new (self->symbol->base_type);
155 symbol_get_const_int (PyGISourceSymbol *self,
158 if (!self->symbol->const_int_set)
164 if (self->symbol->const_int_is_unsigned)
165 return PyLong_FromUnsignedLongLong ((unsigned long long)self->symbol->const_int);
167 return PyLong_FromLongLong ((long long)self->symbol->const_int);
171 symbol_get_const_double (PyGISourceSymbol *self,
174 if (!self->symbol->const_double_set)
179 return PyFloat_FromDouble (self->symbol->const_double);
183 symbol_get_const_string (PyGISourceSymbol *self,
186 if (!self->symbol->const_string)
192 return PyString_FromString (self->symbol->const_string);
196 symbol_get_const_boolean (PyGISourceSymbol *self,
199 if (!self->symbol->const_boolean_set)
205 return PyBool_FromLong (self->symbol->const_boolean);
209 symbol_get_source_filename (PyGISourceSymbol *self,
212 if (!self->symbol->source_filename)
218 return PyString_FromString (self->symbol->source_filename);
221 static const PyGetSetDef _PyGISourceSymbol_getsets[] = {
223 { "type", (getter)symbol_get_type, NULL, NULL},
225 { "ident", (getter)symbol_get_ident, NULL, NULL},
226 { "base_type", (getter)symbol_get_base_type, NULL, NULL},
227 /* gboolean const_int_set; */
228 { "const_int", (getter)symbol_get_const_int, NULL, NULL},
229 /* gboolean const_double_set; */
230 { "const_double", (getter)symbol_get_const_double, NULL, NULL},
231 { "const_string", (getter)symbol_get_const_string, NULL, NULL},
232 /* gboolean const_boolean_set; */
233 { "const_boolean", (getter)symbol_get_const_boolean, NULL, NULL},
234 { "source_filename", (getter)symbol_get_source_filename, NULL, NULL},
235 { "line", (getter)symbol_get_line, NULL, NULL},
236 { "private", (getter)symbol_get_private, NULL, NULL},
245 pygi_source_type_new (GISourceType *type)
247 PyGISourceType *self;
255 self = (PyGISourceType *)PyObject_New (PyGISourceType,
256 &PyGISourceType_Type);
258 return (PyObject*)self;
262 type_get_type (PyGISourceType *self,
265 return PyInt_FromLong (self->type->type);
269 type_get_storage_class_specifier (PyGISourceType *self,
272 return PyInt_FromLong (self->type->storage_class_specifier);
276 type_get_type_qualifier (PyGISourceType *self,
279 return PyInt_FromLong (self->type->type_qualifier);
283 type_get_function_specifier (PyGISourceType *self,
286 return PyInt_FromLong (self->type->function_specifier);
290 type_get_name (PyGISourceType *self,
293 if (!self->type->name)
299 return PyString_FromString (self->type->name);
303 type_get_base_type (PyGISourceType *self,
306 return pygi_source_type_new (self->type->base_type);
310 type_get_child_list (PyGISourceType *self,
318 return Py_BuildValue("[]");
320 list = PyList_New (g_list_length (self->type->child_list));
322 for (l = self->type->child_list; l; l = l->next)
324 PyObject *item = pygi_source_symbol_new (l->data);
325 PyList_SetItem (list, i++, item);
333 type_get_is_bitfield (PyGISourceType *self,
336 return PyInt_FromLong (self->type->is_bitfield);
339 static const PyGetSetDef _PyGISourceType_getsets[] = {
340 { "type", (getter)type_get_type, NULL, NULL},
341 { "storage_class_specifier", (getter)type_get_storage_class_specifier, NULL, NULL},
342 { "type_qualifier", (getter)type_get_type_qualifier, NULL, NULL},
343 { "function_specifier", (getter)type_get_function_specifier, NULL, NULL},
344 { "name", (getter)type_get_name, NULL, NULL},
345 { "base_type", (getter)type_get_base_type, NULL, NULL},
346 { "child_list", (getter)type_get_child_list, NULL, NULL},
347 { "is_bitfield", (getter)type_get_is_bitfield, NULL, NULL},
356 pygi_source_scanner_init (PyGISourceScanner *self,
360 if (!PyArg_ParseTuple (args, ":SourceScanner.__init__"))
363 self->scanner = gi_source_scanner_new ();
369 pygi_source_scanner_append_filename (PyGISourceScanner *self,
375 if (!PyArg_ParseTuple (args, "s:SourceScanner.append_filename", &filename))
378 file = g_file_new_for_path (filename);
379 g_hash_table_add (self->scanner->files, file);
386 pygi_source_scanner_parse_macros (PyGISourceScanner *self,
393 list = PyTuple_GET_ITEM (args, 0);
395 if (!PyList_Check (list))
397 PyErr_SetString (PyExc_RuntimeError, "parse macro takes a list of filenames");
402 for (i = 0; i < PyList_Size (list); ++i)
407 obj = PyList_GetItem (list, i);
408 filename = PyString_AsString (obj);
410 filenames = g_list_append (filenames, filename);
413 gi_source_scanner_parse_macros (self->scanner, filenames);
414 g_list_free (filenames);
421 pygi_source_scanner_parse_file (PyGISourceScanner *self,
427 if (!PyArg_ParseTuple (args, "i:SourceScanner.parse_file", &fd))
431 /* The file descriptor passed to us is from the C library Python
432 * uses. That is msvcr71.dll for Python 2.5 and msvcr90.dll for
433 * Python 2.6, 2.7, 3.2 etc; and msvcr100.dll for Python 3.3 and later.
434 * This code, at least if compiled with mingw, uses
435 * msvcrt.dll, so we cannot use the file descriptor directly. So
436 * perform appropriate magic.
439 /* If we are using the following combinations,
440 * we can use the file descriptors directly
441 * (Not if a build using WDK is used):
442 * Python 2.6.x/2.7.x with Visual C++ 2008
443 * Python 3.1.x/3.2.x with Visual C++ 2008
444 * Python 3.3+ with Visual C++ 2010
447 #if (defined(_MSC_VER) && !defined(USE_WIN_DDK))
448 #if (PY_MAJOR_VERSION==2 && PY_MINOR_VERSION>=6 && (_MSC_VER >= 1500 && _MSC_VER < 1600))
449 #define MSVC_USE_FD_DIRECTLY 1
450 #elif (PY_MAJOR_VERSION==3 && PY_MINOR_VERSION<=2 && (_MSC_VER >= 1500 && _MSC_VER < 1600))
451 #define MSVC_USE_FD_DIRECTLY 1
452 #elif (PY_MAJOR_VERSION==3 && PY_MINOR_VERSION>=3 && (_MSC_VER >= 1600 && _MSC_VER < 1700))
453 #define MSVC_USE_FD_DIRECTLY 1
457 #ifndef MSVC_USE_FD_DIRECTLY
459 #if defined(PY_MAJOR_VERSION) && PY_MAJOR_VERSION==2 && PY_MINOR_VERSION==5
460 #define PYTHON_MSVCRXX_DLL "msvcr71.dll"
461 #elif defined(PY_MAJOR_VERSION) && PY_MAJOR_VERSION==2 && PY_MINOR_VERSION==6
462 #define PYTHON_MSVCRXX_DLL "msvcr90.dll"
463 #elif defined(PY_MAJOR_VERSION) && PY_MAJOR_VERSION==2 && PY_MINOR_VERSION==7
464 #define PYTHON_MSVCRXX_DLL "msvcr90.dll"
465 #elif defined(PY_MAJOR_VERSION) && PY_MAJOR_VERSION==3 && PY_MINOR_VERSION==2
466 #define PYTHON_MSVCRXX_DLL "msvcr90.dll"
467 #elif defined(PY_MAJOR_VERSION) && PY_MAJOR_VERSION==3 && PY_MINOR_VERSION>=3
468 #define PYTHON_MSVCRXX_DLL "msvcr100.dll"
470 #error This Python version not handled
473 intptr_t (*p__get_osfhandle) (int);
476 msvcrxx = GetModuleHandle (PYTHON_MSVCRXX_DLL);
479 g_print ("No " PYTHON_MSVCRXX_DLL " loaded.\n");
483 p__get_osfhandle = (intptr_t (*) (int)) GetProcAddress (msvcrxx, "_get_osfhandle");
484 if (!p__get_osfhandle)
486 g_print ("No _get_osfhandle found in " PYTHON_MSVCRXX_DLL ".\n");
490 handle = (HANDLE) p__get_osfhandle (fd);
491 if (!p__get_osfhandle)
493 g_print ("Could not get OS handle from " PYTHON_MSVCRXX_DLL " fd.\n");
497 fd = _open_osfhandle ((intptr_t) handle, _O_RDONLY);
500 g_print ("Could not open C fd from OS handle.\n");
507 fp = fdopen (fd, "r");
510 PyErr_SetFromErrno (PyExc_OSError);
514 if (!gi_source_scanner_parse_file (self->scanner, fp))
516 g_print ("Something went wrong during parsing.\n");
525 pygi_source_scanner_lex_filename (PyGISourceScanner *self,
531 if (!PyArg_ParseTuple (args, "s:SourceScanner.lex_filename", &filename))
534 self->scanner->current_file = g_file_new_for_path (filename);
535 if (!gi_source_scanner_lex_filename (self->scanner, filename))
537 g_print ("Something went wrong during lexing.\n");
540 file = g_file_new_for_path (filename);
541 g_hash_table_add (self->scanner->files, file);
548 pygi_source_scanner_set_macro_scan (PyGISourceScanner *self,
553 if (!PyArg_ParseTuple (args, "b:SourceScanner.set_macro_scan", ¯o_scan))
556 gi_source_scanner_set_macro_scan (self->scanner, macro_scan);
563 pygi_source_scanner_get_symbols (PyGISourceScanner *self)
569 symbols = gi_source_scanner_get_symbols (self->scanner);
570 list = PyList_New (g_slist_length (symbols));
572 for (l = symbols; l; l = l->next)
574 PyObject *item = pygi_source_symbol_new (l->data);
575 PyList_SetItem (list, i++, item);
578 g_slist_free (symbols);
584 pygi_source_scanner_get_comments (PyGISourceScanner *self)
586 GSList *l, *comments;
590 comments = gi_source_scanner_get_comments (self->scanner);
591 list = PyList_New (g_slist_length (comments));
593 for (l = comments; l; l = l->next)
595 GISourceComment *comment = l->data;
596 PyObject *item = Py_BuildValue ("(ssi)", comment->comment,
599 PyList_SetItem (list, i++, item);
602 g_slist_free (comments);
607 static const PyMethodDef _PyGISourceScanner_methods[] = {
608 { "get_comments", (PyCFunction) pygi_source_scanner_get_comments, METH_NOARGS },
609 { "get_symbols", (PyCFunction) pygi_source_scanner_get_symbols, METH_NOARGS },
610 { "append_filename", (PyCFunction) pygi_source_scanner_append_filename, METH_VARARGS },
611 { "parse_file", (PyCFunction) pygi_source_scanner_parse_file, METH_VARARGS },
612 { "parse_macros", (PyCFunction) pygi_source_scanner_parse_macros, METH_VARARGS },
613 { "lex_filename", (PyCFunction) pygi_source_scanner_lex_filename, METH_VARARGS },
614 { "set_macro_scan", (PyCFunction) pygi_source_scanner_set_macro_scan, METH_VARARGS },
619 static int calc_attrs_length(PyObject *attributes, int indent,
628 for (i = 0; i < PyList_Size (attributes); ++i)
630 PyObject *tuple, *pyvalue;
635 tuple = PyList_GetItem (attributes, i);
636 if (PyTuple_GetItem(tuple, 1) == Py_None)
639 if (!PyArg_ParseTuple(tuple, "sO", &attr, &pyvalue))
642 if (PyUnicode_Check(pyvalue)) {
643 s = PyUnicode_AsUTF8String(pyvalue);
647 value = PyString_AsString(s);
648 } else if (PyString_Check(pyvalue)) {
649 value = PyString_AsString(pyvalue);
651 PyErr_SetString(PyExc_TypeError,
652 "value must be string or unicode");
656 escaped = g_markup_escape_text (value, -1);
657 attr_length += 2 + strlen(attr) + strlen(escaped) + 2;
662 return attr_length + indent + self_indent;
665 /* Hall of shame, wasted time debugging the code below
666 * 20min - Johan 2009-02-19
669 pygi_collect_attributes (PyObject *self,
673 PyObject *attributes;
674 int indent, indent_len, i, j, self_indent;
677 GString *attr_value = NULL;
679 PyObject *result = NULL;
681 if (!PyArg_ParseTuple(args, "sO!isi",
682 &tag_name, &PyList_Type, &attributes,
683 &self_indent, &indent_char,
687 if (attributes == Py_None || !PyList_Size(attributes))
688 return PyUnicode_DecodeUTF8("", 0, "strict");
690 len = calc_attrs_length(attributes, indent, self_indent);
694 indent_len = self_indent + strlen(tag_name) + 1;
699 attr_value = g_string_new ("");
701 for (i = 0; i < PyList_Size (attributes); ++i)
703 PyObject *tuple, *pyvalue;
705 char *attr, *value, *escaped;
707 tuple = PyList_GetItem (attributes, i);
709 if (!PyTuple_Check (tuple))
711 PyErr_SetString(PyExc_TypeError,
712 "attribute item must be a tuple");
716 if (PyTuple_Size (tuple) != 2)
718 PyErr_SetString(PyExc_IndexError,
719 "attribute item must be a tuple of length 2");
723 if (PyTuple_GetItem(tuple, 1) == Py_None)
726 /* this leaks, but we exit after, so */
727 if (!PyArg_ParseTuple(tuple, "sO", &attr, &pyvalue))
730 if (PyUnicode_Check(pyvalue)) {
731 s = PyUnicode_AsUTF8String(pyvalue);
734 value = PyString_AsString(s);
735 } else if (PyString_Check(pyvalue)) {
736 value = PyString_AsString(pyvalue);
738 PyErr_SetString(PyExc_TypeError,
739 "value must be string or unicode");
743 if (indent_len && !first)
745 g_string_append_c (attr_value, '\n');
746 for (j = 0; j < indent_len; j++)
747 g_string_append_c (attr_value, ' ');
749 g_string_append_c (attr_value, ' ');
750 g_string_append (attr_value, attr);
751 g_string_append_c (attr_value, '=');
752 g_string_append_c (attr_value, '\"');
753 escaped = g_markup_escape_text (value, -1);
754 g_string_append (attr_value, escaped);
755 g_string_append_c (attr_value, '\"');
761 result = PyUnicode_DecodeUTF8 (attr_value->str, attr_value->len, "strict");
763 if (attr_value != NULL)
764 g_string_free (attr_value, TRUE);
770 static const PyMethodDef pyscanner_functions[] = {
771 { "collect_attributes",
772 (PyCFunction) pygi_collect_attributes, METH_VARARGS },
773 { NULL, NULL, 0, NULL }
780 gboolean is_uninstalled;
782 /* Hack to avoid having to create a fake directory structure; when
783 * running uninstalled, the module will be in the top builddir,
784 * with no _giscanner prefix.
786 is_uninstalled = g_getenv ("UNINSTALLED_INTROSPECTION_SRCDIR") != NULL;
787 m = Py_InitModule (is_uninstalled ? "_giscanner" : "giscanner._giscanner",
788 (PyMethodDef*)pyscanner_functions);
789 d = PyModule_GetDict (m);
791 PyGISourceScanner_Type.tp_init = (initproc)pygi_source_scanner_init;
792 PyGISourceScanner_Type.tp_methods = (PyMethodDef*)_PyGISourceScanner_methods;
793 REGISTER_TYPE (d, "SourceScanner", PyGISourceScanner_Type);
795 PyGISourceSymbol_Type.tp_getset = (PyGetSetDef*)_PyGISourceSymbol_getsets;
796 REGISTER_TYPE (d, "SourceSymbol", PyGISourceSymbol_Type);
798 PyGISourceType_Type.tp_getset = (PyGetSetDef*)_PyGISourceType_getsets;
799 REGISTER_TYPE (d, "SourceType", PyGISourceType_Type);