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