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