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