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) \
46 static const PyMethodDef _Py##cname##_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);
90 NEW_CLASS (PyGISourceType, "SourceType", GISourceType);
91 NEW_CLASS (PyGISourceScanner, "SourceScanner", GISourceScanner);
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 return PyLong_FromLongLong ((long long)self->symbol->const_int);
169 symbol_get_const_double (PyGISourceSymbol *self,
172 if (!self->symbol->const_double_set)
177 return PyFloat_FromDouble (self->symbol->const_double);
181 symbol_get_const_string (PyGISourceSymbol *self,
184 if (!self->symbol->const_string)
190 return PyString_FromString (self->symbol->const_string);
194 symbol_get_source_filename (PyGISourceSymbol *self,
197 if (!self->symbol->source_filename)
203 return PyString_FromString (self->symbol->source_filename);
206 static const PyGetSetDef _PyGISourceSymbol_getsets[] = {
208 { "type", (getter)symbol_get_type, NULL, NULL},
210 { "ident", (getter)symbol_get_ident, NULL, NULL},
211 { "base_type", (getter)symbol_get_base_type, NULL, NULL},
212 /* gboolean const_int_set; */
213 { "const_int", (getter)symbol_get_const_int, NULL, NULL},
214 /* gboolean const_double_set; */
215 { "const_double", (getter)symbol_get_const_double, NULL, NULL},
216 { "const_string", (getter)symbol_get_const_string, NULL, NULL},
217 { "source_filename", (getter)symbol_get_source_filename, NULL, NULL},
218 { "line", (getter)symbol_get_line, NULL, NULL},
219 { "private", (getter)symbol_get_private, NULL, NULL},
228 pygi_source_type_new (GISourceType *type)
230 PyGISourceType *self;
238 self = (PyGISourceType *)PyObject_New (PyGISourceType,
239 &PyGISourceType_Type);
241 return (PyObject*)self;
245 type_get_type (PyGISourceType *self,
248 return PyInt_FromLong (self->type->type);
252 type_get_storage_class_specifier (PyGISourceType *self,
255 return PyInt_FromLong (self->type->storage_class_specifier);
259 type_get_type_qualifier (PyGISourceType *self,
262 return PyInt_FromLong (self->type->type_qualifier);
266 type_get_function_specifier (PyGISourceType *self,
269 return PyInt_FromLong (self->type->function_specifier);
273 type_get_name (PyGISourceType *self,
276 if (!self->type->name)
282 return PyString_FromString (self->type->name);
286 type_get_base_type (PyGISourceType *self,
289 return pygi_source_type_new (self->type->base_type);
293 type_get_child_list (PyGISourceType *self,
301 return Py_BuildValue("[]");
303 list = PyList_New (g_list_length (self->type->child_list));
305 for (l = self->type->child_list; l; l = l->next)
307 PyObject *item = pygi_source_symbol_new (l->data);
308 PyList_SetItem (list, i++, item);
316 type_get_is_bitfield (PyGISourceType *self,
319 return PyInt_FromLong (self->type->is_bitfield);
322 static const PyGetSetDef _PyGISourceType_getsets[] = {
323 { "type", (getter)type_get_type, NULL, NULL},
324 { "storage_class_specifier", (getter)type_get_storage_class_specifier, NULL, NULL},
325 { "type_qualifier", (getter)type_get_type_qualifier, NULL, NULL},
326 { "function_specifier", (getter)type_get_function_specifier, NULL, NULL},
327 { "name", (getter)type_get_name, NULL, NULL},
328 { "base_type", (getter)type_get_base_type, NULL, NULL},
329 { "child_list", (getter)type_get_child_list, NULL, NULL},
330 { "is_bitfield", (getter)type_get_is_bitfield, NULL, NULL},
339 pygi_source_scanner_init (PyGISourceScanner *self,
343 if (!PyArg_ParseTuple (args, ":SourceScanner.__init__"))
346 self->scanner = gi_source_scanner_new ();
352 pygi_source_scanner_append_filename (PyGISourceScanner *self,
357 if (!PyArg_ParseTuple (args, "s:SourceScanner.append_filename", &filename))
360 self->scanner->filenames = g_list_append (self->scanner->filenames,
361 g_realpath (filename));
368 pygi_source_scanner_parse_macros (PyGISourceScanner *self,
375 list = PyTuple_GET_ITEM (args, 0);
377 if (!PyList_Check (list))
379 PyErr_SetString (PyExc_RuntimeError, "parse macro takes a list of filenames");
384 for (i = 0; i < PyList_Size (list); ++i)
389 obj = PyList_GetItem (list, i);
390 filename = PyString_AsString (obj);
392 filenames = g_list_append (filenames, filename);
395 gi_source_scanner_parse_macros (self->scanner, filenames);
396 g_list_free (filenames);
403 pygi_source_scanner_parse_file (PyGISourceScanner *self,
409 if (!PyArg_ParseTuple (args, "i:SourceScanner.parse_file", &fd))
413 /* The file descriptor passed to us is from the C library Python
414 * uses. That is msvcr71.dll at least for Python 2.5. This code, at
415 * least if compiled with mingw, uses msvcrt.dll, so we cannot use
416 * the file descriptor directly. So perform appropriate magic.
420 int (*p__get_osfhandle) (int);
423 msvcr71 = GetModuleHandle ("msvcr71.dll");
426 g_print ("No msvcr71.dll loaded.\n");
430 p__get_osfhandle = GetProcAddress (msvcr71, "_get_osfhandle");
431 if (!p__get_osfhandle)
433 g_print ("No _get_osfhandle found in msvcr71.dll.\n");
437 handle = p__get_osfhandle (fd);
438 if (!p__get_osfhandle)
440 g_print ("Could not get OS handle from msvcr71 fd.\n");
444 fd = _open_osfhandle (handle, _O_RDONLY);
447 g_print ("Could not open C fd from OS handle.\n");
453 fp = fdopen (fd, "r");
456 PyErr_SetFromErrno (PyExc_OSError);
460 if (!gi_source_scanner_parse_file (self->scanner, fp))
462 g_print ("Something went wrong during parsing.\n");
471 pygi_source_scanner_lex_filename (PyGISourceScanner *self,
476 if (!PyArg_ParseTuple (args, "s:SourceScanner.lex_filename", &filename))
479 self->scanner->current_filename = g_strdup (filename);
480 if (!gi_source_scanner_lex_filename (self->scanner, filename))
482 g_print ("Something went wrong during lexing.\n");
485 self->scanner->filenames =
486 g_list_append (self->scanner->filenames, g_strdup (filename));
493 pygi_source_scanner_set_macro_scan (PyGISourceScanner *self,
498 if (!PyArg_ParseTuple (args, "b:SourceScanner.set_macro_scan", ¯o_scan))
501 gi_source_scanner_set_macro_scan (self->scanner, macro_scan);
508 pygi_source_scanner_get_symbols (PyGISourceScanner *self)
514 symbols = gi_source_scanner_get_symbols (self->scanner);
515 list = PyList_New (g_slist_length (symbols));
517 for (l = symbols; l; l = l->next)
519 PyObject *item = pygi_source_symbol_new (l->data);
520 PyList_SetItem (list, i++, item);
528 pygi_source_scanner_get_comments (PyGISourceScanner *self)
530 GSList *l, *comments;
534 comments = gi_source_scanner_get_comments (self->scanner);
535 list = PyList_New (g_slist_length (comments));
537 for (l = comments; l; l = l->next)
539 GISourceComment *comment = l->data;
540 PyObject *item = Py_BuildValue ("(ssi)", comment->comment,
543 PyList_SetItem (list, i++, item);
550 static const PyMethodDef _PyGISourceScanner_methods[] = {
551 { "get_comments", (PyCFunction) pygi_source_scanner_get_comments, METH_NOARGS },
552 { "get_symbols", (PyCFunction) pygi_source_scanner_get_symbols, METH_NOARGS },
553 { "append_filename", (PyCFunction) pygi_source_scanner_append_filename, METH_VARARGS },
554 { "parse_file", (PyCFunction) pygi_source_scanner_parse_file, METH_VARARGS },
555 { "parse_macros", (PyCFunction) pygi_source_scanner_parse_macros, METH_VARARGS },
556 { "lex_filename", (PyCFunction) pygi_source_scanner_lex_filename, METH_VARARGS },
557 { "set_macro_scan", (PyCFunction) pygi_source_scanner_set_macro_scan, METH_VARARGS },
562 static int calc_attrs_length(PyObject *attributes, int indent,
571 for (i = 0; i < PyList_Size (attributes); ++i)
573 PyObject *tuple, *pyvalue;
578 tuple = PyList_GetItem (attributes, i);
579 if (PyTuple_GetItem(tuple, 1) == Py_None)
582 if (!PyArg_ParseTuple(tuple, "sO", &attr, &pyvalue))
585 if (PyUnicode_Check(pyvalue)) {
586 s = PyUnicode_AsUTF8String(pyvalue);
590 value = PyString_AsString(s);
591 } else if (PyString_Check(pyvalue)) {
592 value = PyString_AsString(pyvalue);
594 PyErr_SetString(PyExc_TypeError,
595 "value must be string or unicode");
599 escaped = g_markup_escape_text (value, -1);
600 attr_length += 2 + strlen(attr) + strlen(escaped) + 2;
605 return attr_length + indent + self_indent;
608 /* Hall of shame, wasted time debugging the code below
609 * 20min - Johan 2009-02-19
612 pygi_collect_attributes (PyObject *self,
616 PyObject *attributes;
617 int indent, indent_len, i, j, self_indent;
620 GString *attr_value = NULL;
622 PyObject *result = NULL;
624 if (!PyArg_ParseTuple(args, "sO!isi",
625 &tag_name, &PyList_Type, &attributes,
626 &self_indent, &indent_char,
630 if (attributes == Py_None || !PyList_Size(attributes))
631 return PyUnicode_DecodeUTF8("", 0, "strict");
633 len = calc_attrs_length(attributes, indent, self_indent);
637 indent_len = self_indent + strlen(tag_name) + 1;
642 attr_value = g_string_new ("");
644 for (i = 0; i < PyList_Size (attributes); ++i)
646 PyObject *tuple, *pyvalue;
648 char *attr, *value, *escaped;
650 tuple = PyList_GetItem (attributes, i);
652 if (!PyTuple_Check (tuple))
654 PyErr_SetString(PyExc_TypeError,
655 "attribute item must be a tuple");
659 if (!PyTuple_Size (tuple) == 2)
661 PyErr_SetString(PyExc_IndexError,
662 "attribute item must be a tuple of length 2");
666 if (PyTuple_GetItem(tuple, 1) == Py_None)
669 /* this leaks, but we exit after, so */
670 if (!PyArg_ParseTuple(tuple, "sO", &attr, &pyvalue))
673 if (PyUnicode_Check(pyvalue)) {
674 s = PyUnicode_AsUTF8String(pyvalue);
677 value = PyString_AsString(s);
678 } else if (PyString_Check(pyvalue)) {
679 value = PyString_AsString(pyvalue);
681 PyErr_SetString(PyExc_TypeError,
682 "value must be string or unicode");
686 if (indent_len && !first)
688 g_string_append_c (attr_value, '\n');
689 for (j = 0; j < indent_len; j++)
690 g_string_append_c (attr_value, ' ');
692 g_string_append_c (attr_value, ' ');
693 g_string_append (attr_value, attr);
694 g_string_append_c (attr_value, '=');
695 g_string_append_c (attr_value, '\"');
696 escaped = g_markup_escape_text (value, -1);
697 g_string_append (attr_value, escaped);
698 g_string_append_c (attr_value, '\"');
704 result = PyUnicode_DecodeUTF8 (attr_value->str, attr_value->len, "strict");
706 if (attr_value != NULL)
707 g_string_free (attr_value, TRUE);
713 static const PyMethodDef pyscanner_functions[] = {
714 { "collect_attributes",
715 (PyCFunction) pygi_collect_attributes, METH_VARARGS },
716 { NULL, NULL, 0, NULL }
723 gboolean is_uninstalled;
725 /* Hack to avoid having to create a fake directory structure; when
726 * running uninstalled, the module will be in the top builddir,
727 * with no _giscanner prefix.
729 is_uninstalled = g_getenv ("UNINSTALLED_INTROSPECTION_SRCDIR") != NULL;
730 m = Py_InitModule (is_uninstalled ? "_giscanner" : "giscanner._giscanner",
731 (PyMethodDef*)pyscanner_functions);
732 d = PyModule_GetDict (m);
734 PyGISourceScanner_Type.tp_init = (initproc)pygi_source_scanner_init;
735 PyGISourceScanner_Type.tp_methods = (PyMethodDef*)_PyGISourceScanner_methods;
736 REGISTER_TYPE (d, "SourceScanner", PyGISourceScanner_Type);
738 PyGISourceSymbol_Type.tp_getset = (PyGetSetDef*)_PyGISourceSymbol_getsets;
739 REGISTER_TYPE (d, "SourceSymbol", PyGISourceSymbol_Type);
741 PyGISourceType_Type.tp_getset = (PyGetSetDef*)_PyGISourceType_getsets;
742 REGISTER_TYPE (d, "SourceType", PyGISourceType_Type);