/* GObject introspection: scanner * * Copyright (C) 2008 Johan Dahlin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #define PY_SSIZE_T_CLEAN #include #include "sourcescanner.h" #include #if PY_MAJOR_VERSION >= 3 #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) #define MOD_ERROR_RETURN NULL #define PyInt_FromLong PyLong_FromLong #else #define MOD_INIT(name) DL_EXPORT(void) init##name(void) #define MOD_ERROR_RETURN #endif /* forward declaration */ _GI_EXTERN MOD_INIT(_giscanner); #define NEW_CLASS(ctype, name, cname, num_methods) \ static const PyMethodDef _Py##cname##_methods[num_methods] G_GNUC_UNUSED; \ PyTypeObject Py##cname##_Type = { \ PyVarObject_HEAD_INIT(NULL, 0) \ "scanner." name, \ sizeof(ctype), \ 0 \ } #if PY_VERSION_HEX < 0x030900A4 # define Py_SET_TYPE(obj, type) ((Py_TYPE(obj) = (type)), (void)0) #endif #define REGISTER_TYPE(d, name, type) \ Py_SET_TYPE(&type, &PyType_Type); \ type.tp_alloc = PyType_GenericAlloc; \ type.tp_new = PyType_GenericNew; \ type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; \ if (PyType_Ready (&type)) \ return MOD_ERROR_RETURN; \ PyDict_SetItemString (d, name, (PyObject *)&type); \ Py_INCREF (&type); typedef struct { PyObject_HEAD GISourceType *type; } PyGISourceType; static PyObject * pygi_source_type_new (GISourceType *type); typedef struct { PyObject_HEAD GISourceSymbol *symbol; } PyGISourceSymbol; typedef struct { PyObject_HEAD GISourceScanner *scanner; } PyGISourceScanner; NEW_CLASS (PyGISourceSymbol, "SourceSymbol", GISourceSymbol, 10); NEW_CLASS (PyGISourceType, "SourceType", GISourceType, 9); NEW_CLASS (PyGISourceScanner, "SourceScanner", GISourceScanner, 9); /* Symbol */ static PyObject * pygi_source_symbol_new (GISourceSymbol *symbol) { PyGISourceSymbol *self; if (symbol == NULL) { Py_INCREF (Py_None); return Py_None; } self = (PyGISourceSymbol *)PyObject_New (PyGISourceSymbol, &PyGISourceSymbol_Type); self->symbol = symbol; return (PyObject*)self; } static PyObject * symbol_get_type (PyGISourceSymbol *self, void *context) { return PyInt_FromLong (self->symbol->type); } static PyObject * symbol_get_line (PyGISourceSymbol *self, void *context) { return PyInt_FromLong (self->symbol->line); } static PyObject * symbol_get_private (PyGISourceSymbol *self, void *context) { return PyBool_FromLong (self->symbol->private); } static PyObject * symbol_get_ident (PyGISourceSymbol *self, void *context) { if (!self->symbol->ident) { Py_INCREF(Py_None); return Py_None; } return PyUnicode_FromString (self->symbol->ident); } static PyObject * symbol_get_base_type (PyGISourceSymbol *self, void *context) { return pygi_source_type_new (self->symbol->base_type); } static PyObject * symbol_get_const_int (PyGISourceSymbol *self, void *context) { if (!self->symbol->const_int_set) { Py_INCREF(Py_None); return Py_None; } if (self->symbol->const_int_is_unsigned) return PyLong_FromUnsignedLongLong ((unsigned long long)self->symbol->const_int); else return PyLong_FromLongLong ((long long)self->symbol->const_int); } static PyObject * symbol_get_const_double (PyGISourceSymbol *self, void *context) { if (!self->symbol->const_double_set) { Py_INCREF(Py_None); return Py_None; } return PyFloat_FromDouble (self->symbol->const_double); } static PyObject * symbol_get_const_string (PyGISourceSymbol *self, void *context) { if (!self->symbol->const_string) { Py_INCREF(Py_None); return Py_None; } return PyUnicode_FromString (self->symbol->const_string); } static PyObject * symbol_get_const_boolean (PyGISourceSymbol *self, void *context) { if (!self->symbol->const_boolean_set) { Py_INCREF(Py_None); return Py_None; } return PyBool_FromLong (self->symbol->const_boolean); } static PyObject * symbol_get_source_filename (PyGISourceSymbol *self, void *context) { if (!self->symbol->source_filename) { Py_INCREF(Py_None); return Py_None; } return PyUnicode_FromString (self->symbol->source_filename); } static const PyGetSetDef _PyGISourceSymbol_getsets[] = { /* int ref_count; */ { "type", (getter)symbol_get_type, NULL, NULL}, /* int id; */ { "ident", (getter)symbol_get_ident, NULL, NULL}, { "base_type", (getter)symbol_get_base_type, NULL, NULL}, /* gboolean const_int_set; */ { "const_int", (getter)symbol_get_const_int, NULL, NULL}, /* gboolean const_double_set; */ { "const_double", (getter)symbol_get_const_double, NULL, NULL}, { "const_string", (getter)symbol_get_const_string, NULL, NULL}, /* gboolean const_boolean_set; */ { "const_boolean", (getter)symbol_get_const_boolean, NULL, NULL}, { "source_filename", (getter)symbol_get_source_filename, NULL, NULL}, { "line", (getter)symbol_get_line, NULL, NULL}, { "private", (getter)symbol_get_private, NULL, NULL}, { 0 } }; /* Type */ static PyObject * pygi_source_type_new (GISourceType *type) { PyGISourceType *self; if (type == NULL) { Py_INCREF (Py_None); return Py_None; } self = (PyGISourceType *)PyObject_New (PyGISourceType, &PyGISourceType_Type); self->type = type; return (PyObject*)self; } static PyObject * type_get_type (PyGISourceType *self, void *context) { return PyInt_FromLong (self->type->type); } static PyObject * type_get_storage_class_specifier (PyGISourceType *self, void *context) { return PyInt_FromLong (self->type->storage_class_specifier); } static PyObject * type_get_type_qualifier (PyGISourceType *self, void *context) { return PyInt_FromLong (self->type->type_qualifier); } static PyObject * type_get_function_specifier (PyGISourceType *self, void *context) { return PyInt_FromLong (self->type->function_specifier); } static PyObject * type_get_name (PyGISourceType *self, void *context) { if (!self->type->name) { Py_INCREF (Py_None); return Py_None; } return PyUnicode_FromString (self->type->name); } static PyObject * type_get_base_type (PyGISourceType *self, void *context) { return pygi_source_type_new (self->type->base_type); } static PyObject * type_get_child_list (PyGISourceType *self, void *context) { GList *l; PyObject *list; int i = 0; if (!self->type) return Py_BuildValue("[]"); list = PyList_New (g_list_length (self->type->child_list)); for (l = self->type->child_list; l; l = l->next) { PyObject *item = pygi_source_symbol_new (l->data); PyList_SetItem (list, i++, item); } Py_INCREF (list); return list; } static PyObject * type_get_is_bitfield (PyGISourceType *self, void *context) { return PyInt_FromLong (self->type->is_bitfield); } static const PyGetSetDef _PyGISourceType_getsets[] = { { "type", (getter)type_get_type, NULL, NULL}, { "storage_class_specifier", (getter)type_get_storage_class_specifier, NULL, NULL}, { "type_qualifier", (getter)type_get_type_qualifier, NULL, NULL}, { "function_specifier", (getter)type_get_function_specifier, NULL, NULL}, { "name", (getter)type_get_name, NULL, NULL}, { "base_type", (getter)type_get_base_type, NULL, NULL}, { "child_list", (getter)type_get_child_list, NULL, NULL}, { "is_bitfield", (getter)type_get_is_bitfield, NULL, NULL}, { 0 } }; /* Scanner */ static int pygi_source_scanner_init (PyGISourceScanner *self, PyObject *args, PyObject *kwargs) { if (!PyArg_ParseTuple (args, ":SourceScanner.__init__")) return -1; self->scanner = gi_source_scanner_new (); return 0; } static PyObject * pygi_source_scanner_append_filename (PyGISourceScanner *self, PyObject *args) { char *filename; GFile *file; if (!PyArg_ParseTuple (args, "s:SourceScanner.append_filename", &filename)) return NULL; file = g_file_new_for_path (filename); g_hash_table_add (self->scanner->files, file); Py_INCREF (Py_None); return Py_None; } static PyObject * pygi_source_scanner_parse_macros (PyGISourceScanner *self, PyObject *args) { GList *filenames; int i; PyObject *list; list = PyTuple_GET_ITEM (args, 0); if (!PyList_Check (list)) { PyErr_SetString (PyExc_RuntimeError, "parse macro takes a list of filenames"); return NULL; } filenames = NULL; for (i = 0; i < PyList_Size (list); ++i) { PyObject *obj; char *filename = NULL; obj = PyList_GetItem (list, i); if (PyUnicode_Check (obj)) { PyObject *s = PyUnicode_AsUTF8String (obj); filename = g_strdup (PyBytes_AsString (s)); Py_DECREF (s); } else if (PyBytes_Check (obj)) { filename = g_strdup (PyBytes_AsString (obj)); } if (filename == NULL) { PyErr_Format (PyExc_RuntimeError, "Expected string but got %s", (Py_TYPE(obj))->tp_name); g_list_free_full (filenames, g_free); return NULL; } filenames = g_list_append (filenames, filename); } gi_source_scanner_parse_macros (self->scanner, filenames); g_list_free_full (filenames, g_free); Py_INCREF (Py_None); return Py_None; } static PyObject * pygi_source_scanner_parse_file (PyGISourceScanner *self, PyObject *args) { char *filename; if (!PyArg_ParseTuple (args, "s:SourceScanner.parse_file", &filename)) return NULL; if (!gi_source_scanner_parse_file (self->scanner, filename)) { g_print ("Something went wrong during parsing.\n"); return NULL; } Py_INCREF (Py_None); return Py_None; } static PyObject * pygi_source_scanner_lex_filename (PyGISourceScanner *self, PyObject *args) { char *filename; GFile *file; if (!PyArg_ParseTuple (args, "s:SourceScanner.lex_filename", &filename)) return NULL; self->scanner->current_file = g_file_new_for_path (filename); if (!gi_source_scanner_lex_filename (self->scanner, filename)) { g_print ("Something went wrong during lexing.\n"); return NULL; } file = g_file_new_for_path (filename); g_hash_table_add (self->scanner->files, file); Py_INCREF (Py_None); return Py_None; } static PyObject * pygi_source_scanner_set_macro_scan (PyGISourceScanner *self, PyObject *args) { int macro_scan; if (!PyArg_ParseTuple (args, "b:SourceScanner.set_macro_scan", ¯o_scan)) return NULL; gi_source_scanner_set_macro_scan (self->scanner, macro_scan); Py_INCREF (Py_None); return Py_None; } static PyObject * pygi_source_scanner_get_symbols (PyGISourceScanner *self, G_GNUC_UNUSED PyObject *unused) { GPtrArray *symbols; PyObject *list; guint i = 0; symbols = gi_source_scanner_get_symbols (self->scanner); list = PyList_New (symbols->len); for (i = 0; i != symbols->len; ++i) { PyObject *item = pygi_source_symbol_new (g_ptr_array_index (symbols, i)); PyList_SetItem (list, i, item); } return list; } static PyObject * pygi_source_scanner_get_errors (PyGISourceScanner *self, G_GNUC_UNUSED PyObject *unused) { GPtrArray *errors; PyObject *list; guint i = 0; errors = gi_source_scanner_get_errors (self->scanner); list = PyList_New (errors->len); for (i = 0; i != errors->len; ++i) { PyObject *item = PyUnicode_FromString (g_ptr_array_index (errors, i)); PyList_SetItem (list, i, item); } return list; } static PyObject * pygi_source_scanner_get_comments (PyGISourceScanner *self, G_GNUC_UNUSED PyObject *unused) { GPtrArray *comments; PyObject *list; guint i = 0; comments = gi_source_scanner_get_comments (self->scanner); list = PyList_New (comments->len); for (i = 0; i != comments->len; ++i) { GISourceComment *comment = g_ptr_array_index (comments, i); PyObject *comment_obj; PyObject *filename_obj; PyObject *item; if (comment->comment) { comment_obj = PyUnicode_FromString (comment->comment); if (!comment_obj) { g_print ("Comment is not valid Unicode in %s line %d\n", comment->filename, comment->line); Py_INCREF (Py_None); comment_obj = Py_None; } } else { Py_INCREF (Py_None); comment_obj = Py_None; } if (comment->filename) { filename_obj = PyUnicode_FromString (comment->filename); } else { Py_INCREF (Py_None); filename_obj = Py_None; } item = Py_BuildValue ("(OOi)", comment_obj, filename_obj, comment->line); PyList_SetItem (list, i, item); Py_DECREF (comment_obj); Py_DECREF (filename_obj); } return list; } static const PyMethodDef _PyGISourceScanner_methods[] = { { "get_errors", (PyCFunction) pygi_source_scanner_get_errors, METH_NOARGS }, { "get_comments", (PyCFunction) pygi_source_scanner_get_comments, METH_NOARGS }, { "get_symbols", (PyCFunction) pygi_source_scanner_get_symbols, METH_NOARGS }, { "append_filename", (PyCFunction) pygi_source_scanner_append_filename, METH_VARARGS }, { "parse_file", (PyCFunction) pygi_source_scanner_parse_file, METH_VARARGS }, { "parse_macros", (PyCFunction) pygi_source_scanner_parse_macros, METH_VARARGS }, { "lex_filename", (PyCFunction) pygi_source_scanner_lex_filename, METH_VARARGS }, { "set_macro_scan", (PyCFunction) pygi_source_scanner_set_macro_scan, METH_VARARGS }, { NULL, NULL, 0 } }; /* Module */ #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, NULL, /* m_name */ NULL, /* m_doc */ 0, NULL, NULL }; #endif /* PY_MAJOR_VERSION >= 3 */ MOD_INIT(_giscanner) { PyObject *m, *d; gboolean is_uninstalled; const char *module_name; /* Hack to avoid having to create a fake directory structure; when * running uninstalled, the module will be in the top builddir, * with no _giscanner prefix. */ is_uninstalled = g_getenv ("UNINSTALLED_INTROSPECTION_SRCDIR") != NULL; module_name = is_uninstalled ? "_giscanner" : "giscanner._giscanner"; #if PY_MAJOR_VERSION >= 3 moduledef.m_name = module_name; m = PyModule_Create (&moduledef); #else m = Py_InitModule (module_name, NULL); #endif d = PyModule_GetDict (m); PyGISourceScanner_Type.tp_init = (initproc)pygi_source_scanner_init; PyGISourceScanner_Type.tp_methods = (PyMethodDef*)_PyGISourceScanner_methods; REGISTER_TYPE (d, "SourceScanner", PyGISourceScanner_Type); PyGISourceSymbol_Type.tp_getset = (PyGetSetDef*)_PyGISourceSymbol_getsets; REGISTER_TYPE (d, "SourceSymbol", PyGISourceSymbol_Type); PyGISourceType_Type.tp_getset = (PyGetSetDef*)_PyGISourceType_getsets; REGISTER_TYPE (d, "SourceType", PyGISourceType_Type); #if PY_MAJOR_VERSION >= 3 return m; #endif }