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