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