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"
31 #include "grealpath.h"
36 #define WIN32_LEAN_AND_MEAN
41 #include <glib-object.h>
43 DL_EXPORT(void) init_giscanner(void);
45 #define NEW_CLASS(ctype, name, cname, num_methods) \
46 static const PyMethodDef _Py##cname##_methods[num_methods]; \
47 PyTypeObject Py##cname##_Type = { \
48 PyObject_HEAD_INIT(NULL) \
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
54 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, \
59 0, 0, NULL, NULL, 0, 0, \
63 #define REGISTER_TYPE(d, name, type) \
64 type.ob_type = &PyType_Type; \
65 type.tp_alloc = PyType_GenericAlloc; \
66 type.tp_new = PyType_GenericNew; \
67 if (PyType_Ready (&type)) \
69 PyDict_SetItemString (d, name, (PyObject *)&type); \
77 static PyObject * pygi_source_type_new (GISourceType *type);
81 GISourceSymbol *symbol;
86 GISourceScanner *scanner;
89 NEW_CLASS (PyGISourceSymbol, "SourceSymbol", GISourceSymbol, 10);
90 NEW_CLASS (PyGISourceType, "SourceType", GISourceType, 9);
91 NEW_CLASS (PyGISourceScanner, "SourceScanner", GISourceScanner, 8);
97 pygi_source_symbol_new (GISourceSymbol *symbol)
99 PyGISourceSymbol *self;
107 self = (PyGISourceSymbol *)PyObject_New (PyGISourceSymbol,
108 &PyGISourceSymbol_Type);
109 self->symbol = symbol;
110 return (PyObject*)self;
114 symbol_get_type (PyGISourceSymbol *self,
117 return PyInt_FromLong (self->symbol->type);
121 symbol_get_line (PyGISourceSymbol *self,
124 return PyInt_FromLong (self->symbol->line);
128 symbol_get_private (PyGISourceSymbol *self,
131 return PyBool_FromLong (self->symbol->private);
135 symbol_get_ident (PyGISourceSymbol *self,
139 if (!self->symbol->ident)
145 return PyString_FromString (self->symbol->ident);
149 symbol_get_base_type (PyGISourceSymbol *self,
152 return pygi_source_type_new (self->symbol->base_type);
156 symbol_get_const_int (PyGISourceSymbol *self,
159 if (!self->symbol->const_int_set)
165 if (self->symbol->const_int_is_unsigned)
166 return PyLong_FromUnsignedLongLong ((unsigned long long)self->symbol->const_int);
168 return PyLong_FromLongLong ((long long)self->symbol->const_int);
172 symbol_get_const_double (PyGISourceSymbol *self,
175 if (!self->symbol->const_double_set)
180 return PyFloat_FromDouble (self->symbol->const_double);
184 symbol_get_const_string (PyGISourceSymbol *self,
187 if (!self->symbol->const_string)
193 return PyString_FromString (self->symbol->const_string);
197 symbol_get_source_filename (PyGISourceSymbol *self,
200 if (!self->symbol->source_filename)
206 return PyString_FromString (self->symbol->source_filename);
209 static const PyGetSetDef _PyGISourceSymbol_getsets[] = {
211 { "type", (getter)symbol_get_type, NULL, NULL},
213 { "ident", (getter)symbol_get_ident, NULL, NULL},
214 { "base_type", (getter)symbol_get_base_type, NULL, NULL},
215 /* gboolean const_int_set; */
216 { "const_int", (getter)symbol_get_const_int, NULL, NULL},
217 /* gboolean const_double_set; */
218 { "const_double", (getter)symbol_get_const_double, NULL, NULL},
219 { "const_string", (getter)symbol_get_const_string, NULL, NULL},
220 { "source_filename", (getter)symbol_get_source_filename, NULL, NULL},
221 { "line", (getter)symbol_get_line, NULL, NULL},
222 { "private", (getter)symbol_get_private, NULL, NULL},
231 pygi_source_type_new (GISourceType *type)
233 PyGISourceType *self;
241 self = (PyGISourceType *)PyObject_New (PyGISourceType,
242 &PyGISourceType_Type);
244 return (PyObject*)self;
248 type_get_type (PyGISourceType *self,
251 return PyInt_FromLong (self->type->type);
255 type_get_storage_class_specifier (PyGISourceType *self,
258 return PyInt_FromLong (self->type->storage_class_specifier);
262 type_get_type_qualifier (PyGISourceType *self,
265 return PyInt_FromLong (self->type->type_qualifier);
269 type_get_function_specifier (PyGISourceType *self,
272 return PyInt_FromLong (self->type->function_specifier);
276 type_get_name (PyGISourceType *self,
279 if (!self->type->name)
285 return PyString_FromString (self->type->name);
289 type_get_base_type (PyGISourceType *self,
292 return pygi_source_type_new (self->type->base_type);
296 type_get_child_list (PyGISourceType *self,
304 return Py_BuildValue("[]");
306 list = PyList_New (g_list_length (self->type->child_list));
308 for (l = self->type->child_list; l; l = l->next)
310 PyObject *item = pygi_source_symbol_new (l->data);
311 PyList_SetItem (list, i++, item);
319 type_get_is_bitfield (PyGISourceType *self,
322 return PyInt_FromLong (self->type->is_bitfield);
325 static const PyGetSetDef _PyGISourceType_getsets[] = {
326 { "type", (getter)type_get_type, NULL, NULL},
327 { "storage_class_specifier", (getter)type_get_storage_class_specifier, NULL, NULL},
328 { "type_qualifier", (getter)type_get_type_qualifier, NULL, NULL},
329 { "function_specifier", (getter)type_get_function_specifier, NULL, NULL},
330 { "name", (getter)type_get_name, NULL, NULL},
331 { "base_type", (getter)type_get_base_type, NULL, NULL},
332 { "child_list", (getter)type_get_child_list, NULL, NULL},
333 { "is_bitfield", (getter)type_get_is_bitfield, NULL, NULL},
342 pygi_source_scanner_init (PyGISourceScanner *self,
346 if (!PyArg_ParseTuple (args, ":SourceScanner.__init__"))
349 self->scanner = gi_source_scanner_new ();
355 pygi_source_scanner_append_filename (PyGISourceScanner *self,
360 if (!PyArg_ParseTuple (args, "s:SourceScanner.append_filename", &filename))
363 self->scanner->filenames = g_list_append (self->scanner->filenames,
364 g_realpath (filename));
371 pygi_source_scanner_parse_macros (PyGISourceScanner *self,
378 list = PyTuple_GET_ITEM (args, 0);
380 if (!PyList_Check (list))
382 PyErr_SetString (PyExc_RuntimeError, "parse macro takes a list of filenames");
387 for (i = 0; i < PyList_Size (list); ++i)
392 obj = PyList_GetItem (list, i);
393 filename = PyString_AsString (obj);
395 filenames = g_list_append (filenames, filename);
398 gi_source_scanner_parse_macros (self->scanner, filenames);
399 g_list_free (filenames);
406 pygi_source_scanner_parse_file (PyGISourceScanner *self,
412 if (!PyArg_ParseTuple (args, "i:SourceScanner.parse_file", &fd))
416 /* The file descriptor passed to us is from the C library Python
417 * uses. That is msvcr71.dll for Python 2.5 and msvcr90.dll for
418 * Python 2.6, 2.7, 3.2 etc; and msvcr100.dll for Python 3.3 and later.
419 * This code, at least if compiled with mingw, uses
420 * msvcrt.dll, so we cannot use the file descriptor directly. So
421 * perform appropriate magic.
424 /* If we are using the following combinations,
425 * we can use the file descriptors directly
426 * (Not if a build using WDK is used):
427 * Python 2.6.x/2.7.x with Visual C++ 2008
428 * Python 3.1.x/3.2.x with Visual C++ 2008
429 * Python 3.3+ with Visual C++ 2010
432 #if (defined(_MSC_VER) && !defined(USE_WIN_DDK))
433 #if (PY_MAJOR_VERSION==2 && PY_MINOR_VERSION>=6 && (_MSC_VER >= 1500 && _MSC_VER < 1600))
434 #define MSVC_USE_FD_DIRECTLY 1
435 #elif (PY_MAJOR_VERSION==3 && PY_MINOR_VERSION<=2 && (_MSC_VER >= 1500 && _MSC_VER < 1600))
436 #define MSVC_USE_FD_DIRECTLY 1
437 #elif (PY_MAJOR_VERSION==3 && PY_MINOR_VERSION>=3 && (_MSC_VER >= 1600 && _MSC_VER < 1700))
438 #define MSVC_USE_FD_DIRECTLY 1
442 #ifndef MSVC_USE_FD_DIRECTLY
444 #if defined(PY_MAJOR_VERSION) && PY_MAJOR_VERSION==2 && PY_MINOR_VERSION==5
445 #define PYTHON_MSVCRXX_DLL "msvcr71.dll"
446 #elif defined(PY_MAJOR_VERSION) && PY_MAJOR_VERSION==2 && PY_MINOR_VERSION==6
447 #define PYTHON_MSVCRXX_DLL "msvcr90.dll"
448 #elif defined(PY_MAJOR_VERSION) && PY_MAJOR_VERSION==2 && PY_MINOR_VERSION==7
449 #define PYTHON_MSVCRXX_DLL "msvcr90.dll"
450 #elif defined(PY_MAJOR_VERSION) && PY_MAJOR_VERSION==3 && PY_MINOR_VERSION==2
451 #define PYTHON_MSVCRXX_DLL "msvcr90.dll"
452 #elif defined(PY_MAJOR_VERSION) && PY_MAJOR_VERSION==3 && PY_MINOR_VERSION>=3
453 #define PYTHON_MSVCRXX_DLL "msvcr100.dll"
455 #error This Python version not handled
458 intptr_t (*p__get_osfhandle) (int);
461 msvcrxx = GetModuleHandle (PYTHON_MSVCRXX_DLL);
464 g_print ("No " PYTHON_MSVCRXX_DLL " loaded.\n");
468 p__get_osfhandle = (intptr_t (*) (int)) GetProcAddress (msvcrxx, "_get_osfhandle");
469 if (!p__get_osfhandle)
471 g_print ("No _get_osfhandle found in " PYTHON_MSVCRXX_DLL ".\n");
475 handle = (HANDLE) p__get_osfhandle (fd);
476 if (!p__get_osfhandle)
478 g_print ("Could not get OS handle from " PYTHON_MSVCRXX_DLL " fd.\n");
482 fd = _open_osfhandle ((intptr_t) handle, _O_RDONLY);
485 g_print ("Could not open C fd from OS handle.\n");
492 fp = fdopen (fd, "r");
495 PyErr_SetFromErrno (PyExc_OSError);
499 if (!gi_source_scanner_parse_file (self->scanner, fp))
501 g_print ("Something went wrong during parsing.\n");
510 pygi_source_scanner_lex_filename (PyGISourceScanner *self,
515 if (!PyArg_ParseTuple (args, "s:SourceScanner.lex_filename", &filename))
518 self->scanner->current_filename = g_strdup (filename);
519 if (!gi_source_scanner_lex_filename (self->scanner, filename))
521 g_print ("Something went wrong during lexing.\n");
524 self->scanner->filenames =
525 g_list_append (self->scanner->filenames, g_strdup (filename));
532 pygi_source_scanner_set_macro_scan (PyGISourceScanner *self,
537 if (!PyArg_ParseTuple (args, "b:SourceScanner.set_macro_scan", ¯o_scan))
540 gi_source_scanner_set_macro_scan (self->scanner, macro_scan);
547 pygi_source_scanner_get_symbols (PyGISourceScanner *self)
553 symbols = gi_source_scanner_get_symbols (self->scanner);
554 list = PyList_New (g_slist_length (symbols));
556 for (l = symbols; l; l = l->next)
558 PyObject *item = pygi_source_symbol_new (l->data);
559 PyList_SetItem (list, i++, item);
567 pygi_source_scanner_get_comments (PyGISourceScanner *self)
569 GSList *l, *comments;
573 comments = gi_source_scanner_get_comments (self->scanner);
574 list = PyList_New (g_slist_length (comments));
576 for (l = comments; l; l = l->next)
578 GISourceComment *comment = l->data;
579 PyObject *item = Py_BuildValue ("(ssi)", comment->comment,
582 PyList_SetItem (list, i++, item);
589 static const PyMethodDef _PyGISourceScanner_methods[] = {
590 { "get_comments", (PyCFunction) pygi_source_scanner_get_comments, METH_NOARGS },
591 { "get_symbols", (PyCFunction) pygi_source_scanner_get_symbols, METH_NOARGS },
592 { "append_filename", (PyCFunction) pygi_source_scanner_append_filename, METH_VARARGS },
593 { "parse_file", (PyCFunction) pygi_source_scanner_parse_file, METH_VARARGS },
594 { "parse_macros", (PyCFunction) pygi_source_scanner_parse_macros, METH_VARARGS },
595 { "lex_filename", (PyCFunction) pygi_source_scanner_lex_filename, METH_VARARGS },
596 { "set_macro_scan", (PyCFunction) pygi_source_scanner_set_macro_scan, METH_VARARGS },
601 static int calc_attrs_length(PyObject *attributes, int indent,
610 for (i = 0; i < PyList_Size (attributes); ++i)
612 PyObject *tuple, *pyvalue;
617 tuple = PyList_GetItem (attributes, i);
618 if (PyTuple_GetItem(tuple, 1) == Py_None)
621 if (!PyArg_ParseTuple(tuple, "sO", &attr, &pyvalue))
624 if (PyUnicode_Check(pyvalue)) {
625 s = PyUnicode_AsUTF8String(pyvalue);
629 value = PyString_AsString(s);
630 } else if (PyString_Check(pyvalue)) {
631 value = PyString_AsString(pyvalue);
633 PyErr_SetString(PyExc_TypeError,
634 "value must be string or unicode");
638 escaped = g_markup_escape_text (value, -1);
639 attr_length += 2 + strlen(attr) + strlen(escaped) + 2;
644 return attr_length + indent + self_indent;
647 /* Hall of shame, wasted time debugging the code below
648 * 20min - Johan 2009-02-19
651 pygi_collect_attributes (PyObject *self,
655 PyObject *attributes;
656 int indent, indent_len, i, j, self_indent;
659 GString *attr_value = NULL;
661 PyObject *result = NULL;
663 if (!PyArg_ParseTuple(args, "sO!isi",
664 &tag_name, &PyList_Type, &attributes,
665 &self_indent, &indent_char,
669 if (attributes == Py_None || !PyList_Size(attributes))
670 return PyUnicode_DecodeUTF8("", 0, "strict");
672 len = calc_attrs_length(attributes, indent, self_indent);
676 indent_len = self_indent + strlen(tag_name) + 1;
681 attr_value = g_string_new ("");
683 for (i = 0; i < PyList_Size (attributes); ++i)
685 PyObject *tuple, *pyvalue;
687 char *attr, *value, *escaped;
689 tuple = PyList_GetItem (attributes, i);
691 if (!PyTuple_Check (tuple))
693 PyErr_SetString(PyExc_TypeError,
694 "attribute item must be a tuple");
698 if (!PyTuple_Size (tuple) == 2)
700 PyErr_SetString(PyExc_IndexError,
701 "attribute item must be a tuple of length 2");
705 if (PyTuple_GetItem(tuple, 1) == Py_None)
708 /* this leaks, but we exit after, so */
709 if (!PyArg_ParseTuple(tuple, "sO", &attr, &pyvalue))
712 if (PyUnicode_Check(pyvalue)) {
713 s = PyUnicode_AsUTF8String(pyvalue);
716 value = PyString_AsString(s);
717 } else if (PyString_Check(pyvalue)) {
718 value = PyString_AsString(pyvalue);
720 PyErr_SetString(PyExc_TypeError,
721 "value must be string or unicode");
725 if (indent_len && !first)
727 g_string_append_c (attr_value, '\n');
728 for (j = 0; j < indent_len; j++)
729 g_string_append_c (attr_value, ' ');
731 g_string_append_c (attr_value, ' ');
732 g_string_append (attr_value, attr);
733 g_string_append_c (attr_value, '=');
734 g_string_append_c (attr_value, '\"');
735 escaped = g_markup_escape_text (value, -1);
736 g_string_append (attr_value, escaped);
737 g_string_append_c (attr_value, '\"');
743 result = PyUnicode_DecodeUTF8 (attr_value->str, attr_value->len, "strict");
745 if (attr_value != NULL)
746 g_string_free (attr_value, TRUE);
752 static const PyMethodDef pyscanner_functions[] = {
753 { "collect_attributes",
754 (PyCFunction) pygi_collect_attributes, METH_VARARGS },
755 { NULL, NULL, 0, NULL }
762 gboolean is_uninstalled;
764 /* Hack to avoid having to create a fake directory structure; when
765 * running uninstalled, the module will be in the top builddir,
766 * with no _giscanner prefix.
768 is_uninstalled = g_getenv ("UNINSTALLED_INTROSPECTION_SRCDIR") != NULL;
769 m = Py_InitModule (is_uninstalled ? "_giscanner" : "giscanner._giscanner",
770 (PyMethodDef*)pyscanner_functions);
771 d = PyModule_GetDict (m);
773 PyGISourceScanner_Type.tp_init = (initproc)pygi_source_scanner_init;
774 PyGISourceScanner_Type.tp_methods = (PyMethodDef*)_PyGISourceScanner_methods;
775 REGISTER_TYPE (d, "SourceScanner", PyGISourceScanner_Type);
777 PyGISourceSymbol_Type.tp_getset = (PyGetSetDef*)_PyGISourceSymbol_getsets;
778 REGISTER_TYPE (d, "SourceSymbol", PyGISourceSymbol_Type);
780 PyGISourceType_Type.tp_getset = (PyGetSetDef*)_PyGISourceType_getsets;
781 REGISTER_TYPE (d, "SourceType", PyGISourceType_Type);