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