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