Branch and submit for IVI panda
[profile/ivi/gobject-introspection.git] / girepository / girmodule.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2  * GObject introspection: Typelib creation
3  *
4  * Copyright (C) 2005 Matthias Clasen
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25
26 #include "girmodule.h"
27 #include "gitypelib-internal.h"
28 #include "girnode.h"
29
30 #define ALIGN_VALUE(this, boundary) \
31   (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
32
33 #define NUM_SECTIONS 2
34
35 GIrModule *
36 _g_ir_module_new (const gchar *name,
37                   const gchar *version,
38                   const gchar *shared_library,
39                   const gchar *c_prefix)
40 {
41   GIrModule *module;
42
43   module = g_slice_new0 (GIrModule);
44
45   module->name = g_strdup (name);
46   module->version = g_strdup (version);
47   if (shared_library)
48       module->shared_library = g_strdup (shared_library);
49   else
50       module->shared_library = NULL;
51   module->c_prefix = g_strdup (c_prefix);
52   module->dependencies = NULL;
53   module->entries = NULL;
54
55   module->include_modules = NULL;
56   module->aliases = NULL;
57
58   return module;
59 }
60
61 void
62 _g_ir_module_free (GIrModule *module)
63 {
64   GList *e;
65
66   g_free (module->name);
67
68   for (e = module->entries; e; e = e->next)
69     _g_ir_node_free ((GIrNode *)e->data);
70
71   g_list_free (module->entries);
72   /* Don't free dependencies, we inherit that from the parser */
73
74   g_list_free (module->include_modules);
75
76   g_hash_table_destroy (module->aliases);
77   g_hash_table_destroy (module->disguised_structures);
78
79   g_slice_free (GIrModule, module);
80 }
81
82 /**
83  * _g_ir_module_fatal:
84  * @build: Current build
85  * @line: Origin line number, or 0 if unknown
86  * @msg: printf-format string
87  * @args: Remaining arguments
88  *
89  * Report a fatal error, then exit.
90  */
91 void
92 _g_ir_module_fatal (GIrTypelibBuild  *build,
93                     guint       line,
94                     const char *msg,
95                     ...)
96 {
97   GString *context;
98   char *formatted;
99   GList *link;
100
101   va_list args;
102
103   va_start (args, msg);
104
105   formatted = g_strdup_vprintf (msg, args);
106
107   context = g_string_new ("");
108   if (line > 0)
109     g_string_append_printf (context, "%d: ", line);
110   if (build->stack)
111     g_string_append (context, "In ");
112   for (link = g_list_last (build->stack); link; link = link->prev)
113     {
114       GIrNode *node = link->data;
115       const char *name = node->name;
116       if (name)
117         g_string_append (context, name);
118       if (link->prev)
119         g_string_append (context, ".");
120     }
121   if (build->stack)
122     g_string_append (context, ": ");
123
124   g_printerr ("%s-%s.gir:%serror: %s\n", build->module->name, 
125               build->module->version,
126               context->str, formatted);
127   g_string_free (context, TRUE);
128
129   exit (1);
130
131   va_end (args);
132 }
133
134 static void
135 add_alias_foreach (gpointer key,
136                    gpointer value,
137                    gpointer data)
138 {
139   GIrModule *module = data;
140
141   g_hash_table_replace (module->aliases, g_strdup (key), g_strdup (value));
142 }
143
144 static void
145 add_disguised_structure_foreach (gpointer key,
146                                  gpointer value,
147                                  gpointer data)
148 {
149   GIrModule *module = data;
150
151   g_hash_table_replace (module->disguised_structures, g_strdup (key), value);
152 }
153
154 void
155 _g_ir_module_add_include_module (GIrModule  *module,
156                                  GIrModule  *include_module)
157 {
158   module->include_modules = g_list_prepend (module->include_modules,
159                                             include_module);
160
161   g_hash_table_foreach (include_module->aliases,
162                         add_alias_foreach,
163                         module);
164
165   g_hash_table_foreach (include_module->disguised_structures,
166                         add_disguised_structure_foreach,
167                         module);
168 }
169
170 struct AttributeWriteData
171 {
172   guint count;
173   guchar *databuf;
174   GIrNode *node;
175   GHashTable *strings;
176   guint32 *offset;
177   guint32 *offset2;
178 };
179
180 static void
181 write_attribute (gpointer key, gpointer value, gpointer datap)
182 {
183   struct AttributeWriteData *data = datap;
184   guint32 old_offset = *(data->offset);
185   AttributeBlob *blob = (AttributeBlob*)&(data->databuf[old_offset]);
186
187   *(data->offset) += sizeof (AttributeBlob);
188
189   blob->offset = data->node->offset;
190   blob->name = _g_ir_write_string ((const char*) key, data->strings, data->databuf, data->offset2);
191   blob->value = _g_ir_write_string ((const char*) value, data->strings, data->databuf, data->offset2);
192
193   data->count++;
194 }
195
196 static guint
197 write_attributes (GIrModule *module,
198                    GIrNode   *node,
199                    GHashTable *strings,
200                    guchar    *data,
201                    guint32   *offset,
202                    guint32   *offset2)
203 {
204   struct AttributeWriteData wdata;
205   wdata.count = 0;
206   wdata.databuf = data;
207   wdata.node = node;
208   wdata.offset = offset;
209   wdata.offset2 = offset2;
210   wdata.strings = strings;
211
212   g_hash_table_foreach (node->attributes, write_attribute, &wdata);
213
214   return wdata.count;
215 }
216
217 static gint
218 node_cmp_offset_func (gconstpointer a,
219                       gconstpointer b)
220 {
221   const GIrNode *na = a;
222   const GIrNode *nb = b;
223   return na->offset - nb->offset;
224 }
225
226 static void
227 alloc_section (guint8 *data, SectionType section_id, guint32 offset)
228 {
229   int i;
230   Header *header = (Header*)data;
231   Section *section_data = (Section*)&data[header->sections];
232
233   g_assert (section_id != GI_SECTION_END);
234
235   for (i = 0; i < NUM_SECTIONS; i++)
236     {
237       if (section_data->id == GI_SECTION_END)
238         {
239           section_data->id = section_id;
240           section_data->offset = offset;
241           return;
242         }
243       section_data++;
244     }
245   g_assert_not_reached ();
246 }
247
248 static guint8*
249 add_directory_index_section (guint8 *data, GIrModule *module, guint32 *offset2)
250 {
251   DirEntry *entry;
252   Header *header = (Header*)data;
253   GITypelibHashBuilder *dirindex_builder;
254   guint i, n_interfaces;
255   guint16 required_size;
256   guint32 new_offset;
257
258   dirindex_builder = _gi_typelib_hash_builder_new ();
259
260   n_interfaces = ((Header *)data)->n_local_entries;
261
262   for (i = 0; i < n_interfaces; i++)
263     {
264       entry = (DirEntry *)&data[header->directory + (i * header->entry_blob_size)];
265       const char *str = (const char *) (&data[entry->name]);
266       _gi_typelib_hash_builder_add_string (dirindex_builder, str, i);
267     }
268
269   if (!_gi_typelib_hash_builder_prepare (dirindex_builder))
270     {
271       /* This happens if CMPH couldn't create a perfect hash.  So
272        * we just punt and leave no directory index section.
273        */
274       _gi_typelib_hash_builder_destroy (dirindex_builder);
275       return data;
276     }
277
278   alloc_section (data, GI_SECTION_DIRECTORY_INDEX, *offset2);
279
280   required_size = _gi_typelib_hash_builder_get_buffer_size (dirindex_builder);
281
282   new_offset = *offset2 + ALIGN_VALUE (required_size, 4);
283
284   data = g_realloc (data, new_offset);
285
286   _gi_typelib_hash_builder_pack (dirindex_builder, ((guint8*)data) + *offset2, required_size);
287
288   *offset2 = new_offset;
289
290   _gi_typelib_hash_builder_destroy (dirindex_builder);
291   return data;
292 }
293
294 GITypelib *
295 _g_ir_module_build_typelib (GIrModule  *module)
296 {
297   GError *error = NULL;
298   GITypelib *typelib;
299   gsize length;
300   guint i;
301   GList *e;
302   Header *header;
303   DirEntry *entry;
304   guint32 header_size;
305   guint32 dir_size;
306   guint32 n_entries;
307   guint32 n_local_entries;
308   guint32 size, offset, offset2, old_offset;
309   GHashTable *strings;
310   GHashTable *types;
311   GList *nodes_with_attributes;
312   char *dependencies;
313   guchar *data;
314   Section *section;
315
316   header_size = ALIGN_VALUE (sizeof (Header), 4);
317   n_local_entries = g_list_length (module->entries);
318
319   /* Serialize dependencies into one string; this is convenient
320    * and not a major change to the typelib format. */
321   {
322     GString *dependencies_str = g_string_new ("");
323     GList *link;
324     for (link = module->dependencies; link; link = link->next)
325       {
326         const char *dependency = link->data;
327         if (!strcmp (dependency, module->name))
328           continue;
329         g_string_append (dependencies_str, dependency);
330         if (link->next)
331           g_string_append_c (dependencies_str, '|');
332       }
333     dependencies = g_string_free (dependencies_str, FALSE);
334     if (!dependencies[0])
335       {
336         g_free (dependencies);
337         dependencies = NULL;
338       }
339   }
340
341  restart:
342   _g_irnode_init_stats ();
343   strings = g_hash_table_new (g_str_hash, g_str_equal);
344   types = g_hash_table_new (g_str_hash, g_str_equal);
345   nodes_with_attributes = NULL;
346   n_entries = g_list_length (module->entries);
347
348   g_message ("%d entries (%d local), %d dependencies\n", n_entries, n_local_entries,
349              g_list_length (module->dependencies));
350
351   dir_size = n_entries * sizeof (DirEntry);
352   size = header_size + dir_size;
353
354   size += ALIGN_VALUE (strlen (module->name) + 1, 4);
355
356   for (e = module->entries; e; e = e->next)
357     {
358       GIrNode *node = e->data;
359
360       size += _g_ir_node_get_full_size (node);
361
362       /* Also reset the offset here */
363       node->offset = 0;
364     }
365
366   /* Adjust size for strings allocated in header below specially */
367   size += ALIGN_VALUE (strlen (module->name) + 1, 4);
368   if (module->shared_library)
369     size += ALIGN_VALUE (strlen (module->shared_library) + 1, 4);
370   if (dependencies != NULL)
371     size += ALIGN_VALUE (strlen (dependencies) + 1, 4);
372   if (module->c_prefix != NULL)
373     size += ALIGN_VALUE (strlen (module->c_prefix) + 1, 4);
374
375   size += sizeof (Section) * NUM_SECTIONS;
376
377   g_message ("allocating %d bytes (%d header, %d directory, %d entries)\n",
378           size, header_size, dir_size, size - header_size - dir_size);
379
380   data = g_malloc0 (size);
381
382   /* fill in header */
383   header = (Header *)data;
384   memcpy (header, G_IR_MAGIC, 16);
385   header->major_version = 4;
386   header->minor_version = 0;
387   header->reserved = 0;
388   header->n_entries = n_entries;
389   header->n_local_entries = n_local_entries;
390   header->n_attributes = 0;
391   header->attributes = 0; /* filled in later */
392   /* NOTE: When writing strings to the typelib here, you should also update
393    * the size calculations above.
394    */
395   if (dependencies != NULL)
396     header->dependencies = _g_ir_write_string (dependencies, strings, data, &header_size);
397   else
398     header->dependencies = 0;
399   header->size = 0; /* filled in later */
400   header->namespace = _g_ir_write_string (module->name, strings, data, &header_size);
401   header->nsversion = _g_ir_write_string (module->version, strings, data, &header_size);
402   header->shared_library = (module->shared_library?
403                              _g_ir_write_string (module->shared_library, strings, data, &header_size)
404                              : 0);
405   if (module->c_prefix != NULL)
406     header->c_prefix = _g_ir_write_string (module->c_prefix, strings, data, &header_size);
407   else
408     header->c_prefix = 0;
409   header->entry_blob_size = sizeof (DirEntry);
410   header->function_blob_size = sizeof (FunctionBlob);
411   header->callback_blob_size = sizeof (CallbackBlob);
412   header->signal_blob_size = sizeof (SignalBlob);
413   header->vfunc_blob_size = sizeof (VFuncBlob);
414   header->arg_blob_size = sizeof (ArgBlob);
415   header->property_blob_size = sizeof (PropertyBlob);
416   header->field_blob_size = sizeof (FieldBlob);
417   header->value_blob_size = sizeof (ValueBlob);
418   header->constant_blob_size = sizeof (ConstantBlob);
419   header->error_domain_blob_size = 16; /* No longer used */
420   header->attribute_blob_size = sizeof (AttributeBlob);
421   header->signature_blob_size = sizeof (SignatureBlob);
422   header->enum_blob_size = sizeof (EnumBlob);
423   header->struct_blob_size = sizeof (StructBlob);
424   header->object_blob_size = sizeof(ObjectBlob);
425   header->interface_blob_size = sizeof (InterfaceBlob);
426   header->union_blob_size = sizeof (UnionBlob);
427
428   offset2 = ALIGN_VALUE (header_size, 4);
429   header->sections = offset2;
430
431   /* Initialize all the sections to _END/0; we fill them in later using
432    * alloc_section().  (Right now there's just the directory index
433    * though, note)
434    */
435   for (i = 0; i < NUM_SECTIONS; i++)
436     {
437       section = (Section*) &data[offset2];
438       section->id = GI_SECTION_END;
439       section->offset = 0;
440       offset2 += sizeof(Section);
441     }
442   header->directory = offset2;
443
444   /* fill in directory and content */
445   entry = (DirEntry *)&data[header->directory];
446
447   offset2 += dir_size;
448
449   for (e = module->entries, i = 0; e; e = e->next, i++)
450     {
451       GIrTypelibBuild build;
452       GIrNode *node = e->data;
453
454       if (strchr (node->name, '.'))
455         {
456           g_error ("Names may not contain '.'");
457         }
458
459       /* we picked up implicit xref nodes, start over */
460       if (i == n_entries)
461         {
462           GList *link;
463           g_message ("Found implicit cross references, starting over");
464
465           g_hash_table_destroy (strings);
466           g_hash_table_destroy (types);
467
468           /* Reset the cached offsets */
469           for (link = nodes_with_attributes; link; link = link->next)
470             ((GIrNode *) link->data)->offset = 0;
471
472           g_list_free (nodes_with_attributes);
473           strings = NULL;
474
475           g_free (data);
476           data = NULL;
477
478           goto restart;
479         }
480
481       offset = offset2;
482
483       if (node->type == G_IR_NODE_XREF)
484         {
485           const char *namespace = ((GIrNodeXRef*)node)->namespace;
486
487           entry->blob_type = 0;
488           entry->local = FALSE;
489           entry->offset = _g_ir_write_string (namespace, strings, data, &offset2);
490           entry->name = _g_ir_write_string (node->name, strings, data, &offset2);
491         }
492       else
493         {
494           old_offset = offset;
495           offset2 = offset + _g_ir_node_get_size (node);
496
497           entry->blob_type = node->type;
498           entry->local = TRUE;
499           entry->offset = offset;
500           entry->name = _g_ir_write_string (node->name, strings, data, &offset2);
501
502           memset (&build, 0, sizeof (build));
503           build.module = module;
504           build.strings = strings;
505           build.types = types;
506           build.nodes_with_attributes = nodes_with_attributes;
507           build.n_attributes = header->n_attributes;
508           build.data = data;
509           _g_ir_node_build_typelib (node, NULL, &build, &offset, &offset2);
510
511           nodes_with_attributes = build.nodes_with_attributes;
512           header->n_attributes = build.n_attributes;
513
514           if (offset2 > old_offset + _g_ir_node_get_full_size (node))
515             g_error ("left a hole of %d bytes\n", offset2 - old_offset - _g_ir_node_get_full_size (node));
516         }
517
518       entry++;
519     }
520
521   /* GIBaseInfo expects the AttributeBlob array to be sorted on the field (offset) */
522   nodes_with_attributes = g_list_sort (nodes_with_attributes, node_cmp_offset_func);
523
524   g_message ("header: %d entries, %d attributes", header->n_entries, header->n_attributes);
525
526   _g_irnode_dump_stats ();
527
528   /* Write attributes after the blobs */
529   offset = offset2;
530   header->attributes = offset;
531   offset2 = offset + header->n_attributes * header->attribute_blob_size;
532
533   for (e = nodes_with_attributes; e; e = e->next)
534     {
535       GIrNode *node = e->data;
536       write_attributes (module, node, strings, data, &offset, &offset2);
537     }
538
539   g_message ("reallocating to %d bytes", offset2);
540
541   data = g_realloc (data, offset2);
542   header = (Header*) data;
543
544   data = add_directory_index_section (data, module, &offset2);
545   header = (Header *)data;
546
547   length = header->size = offset2;
548   typelib = g_typelib_new_from_memory (data, length, &error);
549   if (!typelib)
550     {
551       g_error ("error building typelib: %s",
552                error->message);
553     }
554
555   g_hash_table_destroy (strings);
556   g_hash_table_destroy (types);
557   g_list_free (nodes_with_attributes);
558
559   return typelib;
560 }
561