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