Drop calls to g_type_init()
[platform/upstream/gobject-introspection.git] / giscanner / giscannermodule.c
1 /* GObject introspection: scanner
2  *
3  * Copyright (C) 2008  Johan Dahlin <johan@gnome.org>
4  *
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.
9  *
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.
14  *
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.
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25 #include <Python.h>
26 #include "sourcescanner.h"
27
28 #ifdef G_OS_WIN32
29 #define USE_WINDOWS
30 #endif
31 #include "grealpath.h"
32
33 #ifdef _WIN32
34 #include <fcntl.h>
35 #include <io.h>
36 #define WIN32_LEAN_AND_MEAN
37 #define STRICT
38 #include <windows.h>
39 #endif
40
41 #include <glib-object.h>
42
43 DL_EXPORT(void) init_giscanner(void);
44
45 #define NEW_CLASS(ctype, name, cname)         \
46 static const PyMethodDef _Py##cname##_methods[];    \
47 PyTypeObject Py##cname##_Type = {             \
48     PyObject_HEAD_INIT(NULL)                  \
49     0,                                        \
50     "scanner." name,                          \
51     sizeof(ctype),                    \
52     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,             \
53     0, 0, 0, 0, 0, 0,                         \
54     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, \
55     NULL, 0, 0, 0,                            \
56     0,        \
57     0, 0,                                     \
58     0,                                        \
59     0, 0, NULL, NULL, 0, 0,                   \
60     0             \
61 }
62
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))                 \
68         return;                               \
69     PyDict_SetItemString (d, name, (PyObject *)&type); \
70     Py_INCREF (&type);
71
72 typedef struct {
73   PyObject_HEAD
74   GISourceType *type;
75 } PyGISourceType;
76
77 static PyObject * pygi_source_type_new (GISourceType *type);
78
79 typedef struct {
80   PyObject_HEAD
81   GISourceSymbol *symbol;
82 } PyGISourceSymbol;
83
84 typedef struct {
85   PyObject_HEAD
86   GISourceScanner *scanner;
87 } PyGISourceScanner;
88
89 NEW_CLASS (PyGISourceSymbol, "SourceSymbol", GISourceSymbol);
90 NEW_CLASS (PyGISourceType, "SourceType", GISourceType);
91 NEW_CLASS (PyGISourceScanner, "SourceScanner", GISourceScanner);
92
93
94 /* Symbol */
95
96 static PyObject *
97 pygi_source_symbol_new (GISourceSymbol *symbol)
98 {
99   PyGISourceSymbol *self;
100
101   if (symbol == NULL)
102     {
103       Py_INCREF (Py_None);
104       return Py_None;
105     }
106
107   self = (PyGISourceSymbol *)PyObject_New (PyGISourceSymbol,
108                                            &PyGISourceSymbol_Type);
109   self->symbol = symbol;
110   return (PyObject*)self;
111 }
112
113 static PyObject *
114 symbol_get_type (PyGISourceSymbol *self,
115                  void             *context)
116 {
117   return PyInt_FromLong (self->symbol->type);
118 }
119
120 static PyObject *
121 symbol_get_line (PyGISourceSymbol *self,
122                  void             *context)
123 {
124   return PyInt_FromLong (self->symbol->line);
125 }
126
127 static PyObject *
128 symbol_get_private (PyGISourceSymbol *self,
129                     void             *context)
130 {
131   return PyBool_FromLong (self->symbol->private);
132 }
133
134 static PyObject *
135 symbol_get_ident (PyGISourceSymbol *self,
136                   void            *context)
137 {
138
139   if (!self->symbol->ident)
140     {
141       Py_INCREF(Py_None);
142       return Py_None;
143     }
144
145   return PyString_FromString (self->symbol->ident);
146 }
147
148 static PyObject *
149 symbol_get_base_type (PyGISourceSymbol *self,
150                       void             *context)
151 {
152   return pygi_source_type_new (self->symbol->base_type);
153 }
154
155 static PyObject *
156 symbol_get_const_int (PyGISourceSymbol *self,
157                       void             *context)
158 {
159   if (!self->symbol->const_int_set)
160     {
161       Py_INCREF(Py_None);
162       return Py_None;
163     }
164
165   return PyLong_FromLongLong ((long long)self->symbol->const_int);
166 }
167
168 static PyObject *
169 symbol_get_const_double (PyGISourceSymbol *self,
170                          void             *context)
171 {
172   if (!self->symbol->const_double_set)
173     {
174       Py_INCREF(Py_None);
175       return Py_None;
176     }
177   return PyFloat_FromDouble (self->symbol->const_double);
178 }
179
180 static PyObject *
181 symbol_get_const_string (PyGISourceSymbol *self,
182                          void             *context)
183 {
184   if (!self->symbol->const_string)
185     {
186       Py_INCREF(Py_None);
187       return Py_None;
188     }
189
190   return PyString_FromString (self->symbol->const_string);
191 }
192
193 static PyObject *
194 symbol_get_source_filename (PyGISourceSymbol *self,
195                             void             *context)
196 {
197   if (!self->symbol->source_filename)
198     {
199       Py_INCREF(Py_None);
200       return Py_None;
201     }
202
203   return PyString_FromString (self->symbol->source_filename);
204 }
205
206 static const PyGetSetDef _PyGISourceSymbol_getsets[] = {
207   /* int ref_count; */
208   { "type", (getter)symbol_get_type, NULL, NULL},
209   /* int id; */
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},
220   { 0 }
221 };
222
223
224
225 /* Type */
226
227 static PyObject *
228 pygi_source_type_new (GISourceType *type)
229 {
230   PyGISourceType *self;
231
232   if (type == NULL)
233     {
234       Py_INCREF (Py_None);
235       return Py_None;
236     }
237
238   self = (PyGISourceType *)PyObject_New (PyGISourceType,
239                                          &PyGISourceType_Type);
240   self->type = type;
241   return (PyObject*)self;
242 }
243
244 static PyObject *
245 type_get_type (PyGISourceType *self,
246                void           *context)
247 {
248   return PyInt_FromLong (self->type->type);
249 }
250
251 static PyObject *
252 type_get_storage_class_specifier (PyGISourceType *self,
253                                   void           *context)
254 {
255   return PyInt_FromLong (self->type->storage_class_specifier);
256 }
257
258 static PyObject *
259 type_get_type_qualifier (PyGISourceType *self,
260                          void           *context)
261 {
262   return PyInt_FromLong (self->type->type_qualifier);
263 }
264
265 static PyObject *
266 type_get_function_specifier (PyGISourceType *self,
267                              void           *context)
268 {
269   return PyInt_FromLong (self->type->function_specifier);
270 }
271
272 static PyObject *
273 type_get_name (PyGISourceType *self,
274                void           *context)
275 {
276   if (!self->type->name)
277     {
278       Py_INCREF (Py_None);
279       return Py_None;
280     }
281
282   return PyString_FromString (self->type->name);
283 }
284
285 static PyObject *
286 type_get_base_type (PyGISourceType *self,
287                     void           *context)
288 {
289   return pygi_source_type_new (self->type->base_type);
290 }
291
292 static PyObject *
293 type_get_child_list (PyGISourceType *self,
294                      void           *context)
295 {
296   GList *l;
297   PyObject *list;
298   int i = 0;
299
300   if (!self->type)
301     return Py_BuildValue("[]");
302
303   list = PyList_New (g_list_length (self->type->child_list));
304
305   for (l = self->type->child_list; l; l = l->next)
306     {
307       PyObject *item = pygi_source_symbol_new (l->data);
308       PyList_SetItem (list, i++, item);
309     }
310
311   Py_INCREF (list);
312   return list;
313 }
314
315 static PyObject *
316 type_get_is_bitfield (PyGISourceType *self,
317                              void           *context)
318 {
319   return PyInt_FromLong (self->type->is_bitfield);
320 }
321
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},
331   { 0 }
332 };
333
334
335
336 /* Scanner */
337
338 static int
339 pygi_source_scanner_init (PyGISourceScanner *self,
340                           PyObject          *args,
341                           PyObject          *kwargs)
342 {
343   if (!PyArg_ParseTuple (args, ":SourceScanner.__init__"))
344     return -1;
345
346   self->scanner = gi_source_scanner_new ();
347
348   return 0;
349 }
350
351 static PyObject *
352 pygi_source_scanner_append_filename (PyGISourceScanner *self,
353                                      PyObject          *args)
354 {
355   char *filename;
356
357   if (!PyArg_ParseTuple (args, "s:SourceScanner.append_filename", &filename))
358     return NULL;
359
360   self->scanner->filenames = g_list_append (self->scanner->filenames,
361                                             g_realpath (filename));
362
363   Py_INCREF (Py_None);
364   return Py_None;
365 }
366
367 static PyObject *
368 pygi_source_scanner_parse_macros (PyGISourceScanner *self,
369                                   PyObject          *args)
370 {
371   GList *filenames;
372   int i;
373   PyObject *list;
374
375   list = PyTuple_GET_ITEM (args, 0);
376
377   if (!PyList_Check (list))
378     {
379       PyErr_SetString (PyExc_RuntimeError, "parse macro takes a list of filenames");
380       return NULL;
381     }
382
383   filenames = NULL;
384   for (i = 0; i < PyList_Size (list); ++i)
385     {
386       PyObject *obj;
387       char *filename;
388
389       obj = PyList_GetItem (list, i);
390       filename = PyString_AsString (obj);
391
392       filenames = g_list_append (filenames, filename);
393     }
394
395   gi_source_scanner_parse_macros (self->scanner, filenames);
396   g_list_free (filenames);
397
398   Py_INCREF (Py_None);
399   return Py_None;
400 }
401
402 static PyObject *
403 pygi_source_scanner_parse_file (PyGISourceScanner *self,
404                                 PyObject          *args)
405 {
406   int fd;
407   FILE *fp;
408
409   if (!PyArg_ParseTuple (args, "i:SourceScanner.parse_file", &fd))
410     return NULL;
411
412 #ifdef _WIN32
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.
417    */
418   {
419     HMODULE msvcr71;
420     int (*p__get_osfhandle) (int);
421     HANDLE handle;
422
423     msvcr71 = GetModuleHandle ("msvcr71.dll");
424     if (!msvcr71)
425       {
426         g_print ("No msvcr71.dll loaded.\n");
427         return NULL;
428       }
429
430     p__get_osfhandle = GetProcAddress (msvcr71, "_get_osfhandle");
431     if (!p__get_osfhandle)
432       {
433         g_print ("No _get_osfhandle found in msvcr71.dll.\n");
434         return NULL;
435       }
436
437     handle = p__get_osfhandle (fd);
438     if (!p__get_osfhandle)
439       {
440         g_print ("Could not get OS handle from msvcr71 fd.\n");
441         return NULL;
442       }
443
444     fd = _open_osfhandle (handle, _O_RDONLY);
445     if (fd == -1)
446       {
447         g_print ("Could not open C fd from OS handle.\n");
448         return NULL;
449       }
450   }
451 #endif
452
453   fp = fdopen (fd, "r");
454   if (!fp)
455     {
456       PyErr_SetFromErrno (PyExc_OSError);
457       return NULL;
458     }
459
460   if (!gi_source_scanner_parse_file (self->scanner, fp))
461     {
462       g_print ("Something went wrong during parsing.\n");
463       return NULL;
464     }
465
466   Py_INCREF (Py_None);
467   return Py_None;
468 }
469
470 static PyObject *
471 pygi_source_scanner_lex_filename (PyGISourceScanner *self,
472                                   PyObject          *args)
473 {
474   char *filename;
475
476   if (!PyArg_ParseTuple (args, "s:SourceScanner.lex_filename", &filename))
477     return NULL;
478
479   self->scanner->current_filename = g_strdup (filename);
480   if (!gi_source_scanner_lex_filename (self->scanner, filename))
481     {
482       g_print ("Something went wrong during lexing.\n");
483       return NULL;
484     }
485   self->scanner->filenames =
486     g_list_append (self->scanner->filenames, g_strdup (filename));
487
488   Py_INCREF (Py_None);
489   return Py_None;
490 }
491
492 static PyObject *
493 pygi_source_scanner_set_macro_scan (PyGISourceScanner *self,
494                                     PyObject          *args)
495 {
496   int macro_scan;
497
498   if (!PyArg_ParseTuple (args, "b:SourceScanner.set_macro_scan", &macro_scan))
499     return NULL;
500
501   gi_source_scanner_set_macro_scan (self->scanner, macro_scan);
502
503   Py_INCREF (Py_None);
504   return Py_None;
505 }
506
507 static PyObject *
508 pygi_source_scanner_get_symbols (PyGISourceScanner *self)
509 {
510   GSList *l, *symbols;
511   PyObject *list;
512   int i = 0;
513
514   symbols = gi_source_scanner_get_symbols (self->scanner);
515   list = PyList_New (g_slist_length (symbols));
516
517   for (l = symbols; l; l = l->next)
518     {
519       PyObject *item = pygi_source_symbol_new (l->data);
520       PyList_SetItem (list, i++, item);
521     }
522
523   Py_INCREF (list);
524   return list;
525 }
526
527 static PyObject *
528 pygi_source_scanner_get_comments (PyGISourceScanner *self)
529 {
530   GSList *l, *comments;
531   PyObject *list;
532   int i = 0;
533
534   comments = gi_source_scanner_get_comments (self->scanner);
535   list = PyList_New (g_slist_length (comments));
536
537   for (l = comments; l; l = l->next)
538     {
539       GISourceComment *comment = l->data;
540       PyObject *item = Py_BuildValue ("(ssi)", comment->comment,
541                                       comment->filename,
542                                       comment->line);
543       PyList_SetItem (list, i++, item);
544     }
545
546   Py_INCREF (list);
547   return list;
548 }
549
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 },
558   { NULL, NULL, 0 }
559 };
560
561
562 static int calc_attrs_length(PyObject *attributes, int indent,
563                              int self_indent)
564 {
565   int attr_length = 0;
566   int i;
567
568   if (indent == -1)
569     return -1;
570
571   for (i = 0; i < PyList_Size (attributes); ++i)
572     {
573       PyObject *tuple, *pyvalue;
574       PyObject *s = NULL;
575       char *attr, *value;
576       char *escaped;
577
578       tuple = PyList_GetItem (attributes, i);
579       if (PyTuple_GetItem(tuple, 1) == Py_None)
580         continue;
581
582       if (!PyArg_ParseTuple(tuple, "sO", &attr, &pyvalue))
583         return -1;
584
585       if (PyUnicode_Check(pyvalue)) {
586         s = PyUnicode_AsUTF8String(pyvalue);
587         if (!s) {
588           return -1;
589         }
590         value = PyString_AsString(s);
591       } else if (PyString_Check(pyvalue)) {
592         value = PyString_AsString(pyvalue);
593       } else {
594         PyErr_SetString(PyExc_TypeError,
595                         "value must be string or unicode");
596         return -1;
597       }
598
599       escaped = g_markup_escape_text (value, -1);
600       attr_length += 2 + strlen(attr) + strlen(escaped) + 2;
601       g_free(escaped);
602       Py_XDECREF(s);
603     }
604
605   return attr_length + indent + self_indent;
606 }
607
608 /* Hall of shame, wasted time debugging the code below
609  * 20min - Johan 2009-02-19
610  */
611 static PyObject *
612 pygi_collect_attributes (PyObject *self,
613                          PyObject *args)
614 {
615   char *tag_name;
616   PyObject *attributes;
617   int indent, indent_len, i, j, self_indent;
618   char *indent_char;
619   gboolean first;
620   GString *attr_value = NULL;
621   int len;
622   PyObject *result = NULL;
623
624   if (!PyArg_ParseTuple(args, "sO!isi",
625                         &tag_name, &PyList_Type, &attributes,
626                         &self_indent, &indent_char,
627                         &indent))
628     return NULL;
629
630   if (attributes == Py_None || !PyList_Size(attributes))
631     return PyUnicode_DecodeUTF8("", 0, "strict");
632
633   len = calc_attrs_length(attributes, indent, self_indent);
634   if (len < 0)
635     return NULL;
636   if (len > 79)
637     indent_len = self_indent + strlen(tag_name) + 1;
638   else
639     indent_len = 0;
640
641   first = TRUE;
642   attr_value = g_string_new ("");
643
644   for (i = 0; i < PyList_Size (attributes); ++i)
645     {
646       PyObject *tuple, *pyvalue;
647       PyObject *s = NULL;
648       char *attr, *value, *escaped;
649
650       tuple = PyList_GetItem (attributes, i);
651
652       if (!PyTuple_Check (tuple))
653         {
654           PyErr_SetString(PyExc_TypeError,
655                           "attribute item must be a tuple");
656           goto out;
657         }
658
659       if (!PyTuple_Size (tuple) == 2)
660         {
661           PyErr_SetString(PyExc_IndexError,
662                           "attribute item must be a tuple of length 2");
663           goto out;
664         }
665
666       if (PyTuple_GetItem(tuple, 1) == Py_None)
667         continue;
668
669       /* this leaks, but we exit after, so */
670       if (!PyArg_ParseTuple(tuple, "sO", &attr, &pyvalue))
671         goto out;
672
673       if (PyUnicode_Check(pyvalue)) {
674         s = PyUnicode_AsUTF8String(pyvalue);
675         if (!s)
676           goto out;
677         value = PyString_AsString(s);
678       } else if (PyString_Check(pyvalue)) {
679         value = PyString_AsString(pyvalue);
680       } else {
681         PyErr_SetString(PyExc_TypeError,
682                         "value must be string or unicode");
683         goto out;
684       }
685
686       if (indent_len && !first)
687         {
688           g_string_append_c (attr_value, '\n');
689           for (j = 0; j < indent_len; j++)
690             g_string_append_c (attr_value, ' ');
691         }
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, '\"');
699       if (first)
700         first = FALSE;
701       Py_XDECREF(s);
702   }
703
704   result = PyUnicode_DecodeUTF8 (attr_value->str, attr_value->len, "strict");
705  out:
706   if (attr_value != NULL)
707     g_string_free (attr_value, TRUE);
708   return result;
709 }
710
711 /* Module */
712
713 static const PyMethodDef pyscanner_functions[] = {
714   { "collect_attributes",
715     (PyCFunction) pygi_collect_attributes, METH_VARARGS },
716   { NULL, NULL, 0, NULL }
717 };
718
719 DL_EXPORT(void)
720 init_giscanner(void)
721 {
722     PyObject *m, *d;
723     gboolean is_uninstalled;
724
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.
728      */
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);
733
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);
737
738     PyGISourceSymbol_Type.tp_getset = (PyGetSetDef*)_PyGISourceSymbol_getsets;
739     REGISTER_TYPE (d, "SourceSymbol", PyGISourceSymbol_Type);
740
741     PyGISourceType_Type.tp_getset = (PyGetSetDef*)_PyGISourceType_getsets;
742     REGISTER_TYPE (d, "SourceType", PyGISourceType_Type);
743 }