[g-ir-compiler] Slightly less lame error messages
[gnome.gobject-introspection] / girepository / girmodule.c
1 /* GObject introspection: Typelib creation 
2  *
3  * Copyright (C) 2005 Matthias Clasen
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 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "girmodule.h"
26 #include "girnode.h"
27
28 #define ALIGN_VALUE(this, boundary) \
29   (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
30
31
32 GIrModule *
33 g_ir_module_new (const gchar *name, 
34                  const gchar *version,
35                  const gchar *shared_library,
36                  const gchar *c_prefix)
37 {
38   GIrModule *module;
39   
40   module = g_new0 (GIrModule, 1);
41
42   module->name = g_strdup (name);
43   module->version = g_strdup (version);
44   if (shared_library)
45       module->shared_library = g_strdup (shared_library);
46   else
47       module->shared_library = NULL;
48   module->c_prefix = g_strdup (c_prefix);
49   module->dependencies = NULL;
50   module->entries = NULL;
51
52   module->include_modules = NULL;
53   module->aliases = NULL;
54
55   return module;
56 }
57
58 void
59 g_ir_module_free (GIrModule *module)
60 {
61   GList *e;
62
63   g_free (module->name);
64
65   for (e = module->entries; e; e = e->next)
66     g_ir_node_free ((GIrNode *)e->data);
67
68   g_list_free (module->entries);
69   /* Don't free dependencies, we inherit that from the parser */
70
71   g_list_free (module->include_modules);
72
73   g_hash_table_destroy (module->aliases);
74   g_hash_table_destroy (module->disguised_structures);
75
76   g_free (module);
77 }
78
79 /**
80  * g_ir_module_fatal:
81  * @module: Current module
82  * @line: Origin line number, or 0 if unknown
83  * @msg: printf-format string
84  * @args: Remaining arguments
85  *
86  * Report a fatal error, then exit.
87  */
88 void
89 g_ir_module_fatal (GIrModule  *module,
90                    guint       line,
91                    const char *msg,
92                    ...)
93 {
94   char *formatted;
95
96   va_list args;
97   
98   va_start (args, msg);
99   
100   formatted = g_strdup_vprintf (msg, args);
101   
102   if (line)
103     g_printerr ("%s-%s.gir:%d: error: %s\n", module->name, module->version, line, formatted);
104   else
105     g_printerr ("%s-%s.gir: error: %s\n", module->name, module->version, formatted);
106     
107   exit (1);
108   
109   va_end (args);
110 }
111
112 static void
113 add_alias_foreach (gpointer key,
114                    gpointer value,
115                    gpointer data)
116 {
117   GIrModule *module = data;
118
119   g_hash_table_replace (module->aliases, g_strdup (key), g_strdup (value));
120 }
121
122 static void
123 add_disguised_structure_foreach (gpointer key,
124                                  gpointer value,
125                                  gpointer data)
126 {
127   GIrModule *module = data;
128
129   g_hash_table_replace (module->disguised_structures, g_strdup (key), value);
130 }
131
132 void
133 g_ir_module_add_include_module (GIrModule  *module,
134                                 GIrModule  *include_module)
135 {
136   module->include_modules = g_list_prepend (module->include_modules,
137                                             include_module);
138
139   g_hash_table_foreach (include_module->aliases,
140                         add_alias_foreach,
141                         module);
142
143   g_hash_table_foreach (include_module->disguised_structures,
144                         add_disguised_structure_foreach,
145                         module);
146 }
147
148 struct AttributeWriteData
149 {
150   guint count;
151   guchar *databuf;
152   GIrNode *node;
153   GHashTable *strings;
154   guint32 *offset;
155   guint32 *offset2;
156 };
157
158 static void
159 write_attribute (gpointer key, gpointer value, gpointer datap)
160 {
161   struct AttributeWriteData *data = datap;
162   guint32 old_offset = *(data->offset);
163   AttributeBlob *blob = (AttributeBlob*)&(data->databuf[old_offset]);
164
165   *(data->offset) += sizeof (AttributeBlob);
166
167   blob->offset = data->node->offset;
168   blob->name = write_string ((const char*) key, data->strings, data->databuf, data->offset2);
169   blob->value = write_string ((const char*) value, data->strings, data->databuf, data->offset2);
170
171   data->count++;
172 }
173
174 static guint
175 write_attributes (GIrModule *module,
176                    GIrNode   *node,
177                    GHashTable *strings,
178                    guchar    *data,
179                    guint32   *offset,
180                    guint32   *offset2)
181 {
182   struct AttributeWriteData wdata;
183   wdata.count = 0;
184   wdata.databuf = data;
185   wdata.node = node;
186   wdata.offset = offset;
187   wdata.offset2 = offset2;
188   wdata.strings = strings;
189
190   g_hash_table_foreach (node->attributes, write_attribute, &wdata);
191
192   return wdata.count;
193 }
194
195 GTypelib *
196 g_ir_module_build_typelib (GIrModule  *module,
197                              GList       *modules)
198 {
199   GTypelib *typelib;
200   gsize length;
201   guint i;
202   GList *e;
203   Header *header;
204   DirEntry *entry;
205   guint32 header_size;
206   guint32 dir_size;
207   guint32 n_entries;
208   guint32 n_local_entries;
209   guint32 size, offset, offset2, old_offset;
210   GHashTable *strings;
211   GHashTable *types;
212   GList *offset_ordered_nodes;
213   char *dependencies;
214   guchar *data;
215
216   header_size = ALIGN_VALUE (sizeof (Header), 4);
217   n_local_entries = g_list_length (module->entries);
218
219   /* Serialize dependencies into one string; this is convenient
220    * and not a major change to the typelib format. */
221   {
222     GString *dependencies_str = g_string_new ("");
223     GList *link;
224     for (link = module->dependencies; link; link = link->next)
225       {
226         const char *dependency = link->data;
227         if (!strcmp (dependency, module->name))
228           continue;
229         g_string_append (dependencies_str, dependency);
230         if (link->next)
231           g_string_append_c (dependencies_str, '|');
232       }
233     dependencies = g_string_free (dependencies_str, FALSE);
234     if (!dependencies[0])
235       {
236         g_free (dependencies);
237         dependencies = NULL;
238       }
239   }
240
241  restart:
242   _g_irnode_init_stats ();
243   strings = g_hash_table_new (g_str_hash, g_str_equal);
244   types = g_hash_table_new (g_str_hash, g_str_equal);
245   offset_ordered_nodes = NULL;
246   n_entries = g_list_length (module->entries);
247
248   g_message ("%d entries (%d local), %d dependencies\n", n_entries, n_local_entries,
249              g_list_length (module->dependencies));
250   
251   dir_size = n_entries * sizeof (DirEntry);
252   size = header_size + dir_size;
253
254   size += ALIGN_VALUE (strlen (module->name) + 1, 4);
255
256   for (e = module->entries; e; e = e->next)
257     {
258       GIrNode *node = e->data;
259       
260       size += g_ir_node_get_full_size (node);
261       size += g_ir_node_get_attribute_size (node);
262
263       /* Also reset the offset here */
264       node->offset = 0;
265     }
266
267   /* Adjust size for strings allocated in header below specially */
268   size += ALIGN_VALUE (strlen (module->name) + 1, 4);
269   if (module->shared_library) 
270     size += ALIGN_VALUE (strlen (module->shared_library) + 1, 4);
271   if (dependencies != NULL)
272     size += ALIGN_VALUE (strlen (dependencies) + 1, 4);
273   if (module->c_prefix != NULL)
274     size += ALIGN_VALUE (strlen (module->c_prefix) + 1, 4);
275
276   g_message ("allocating %d bytes (%d header, %d directory, %d entries)\n", 
277           size, header_size, dir_size, size - header_size - dir_size);
278
279   data = g_malloc0 (size);
280
281   /* fill in header */
282   header = (Header *)data;
283   memcpy (header, G_IR_MAGIC, 16);
284   header->major_version = 2;
285   header->minor_version = 0;
286   header->reserved = 0;
287   header->n_entries = n_entries;
288   header->n_local_entries = n_local_entries;
289   header->n_attributes = 0;
290   header->attributes = 0; /* filled in later */
291   /* NOTE: When writing strings to the typelib here, you should also update
292    * the size calculations above.
293    */
294   if (dependencies != NULL)
295     header->dependencies = write_string (dependencies, strings, data, &header_size);
296   else
297     header->dependencies = 0;
298   header->size = 0; /* filled in later */
299   header->namespace = write_string (module->name, strings, data, &header_size);
300   header->nsversion = write_string (module->version, strings, data, &header_size);
301   header->shared_library = (module->shared_library?
302                              write_string (module->shared_library, strings, data, &header_size)
303                              : 0);
304   if (module->c_prefix != NULL)
305     header->c_prefix = write_string (module->c_prefix, strings, data, &header_size);
306   else
307     header->c_prefix = 0;
308   header->directory = ALIGN_VALUE (header_size, 4);
309   header->entry_blob_size = sizeof (DirEntry);
310   header->function_blob_size = sizeof (FunctionBlob);
311   header->callback_blob_size = sizeof (CallbackBlob);
312   header->signal_blob_size = sizeof (SignalBlob);
313   header->vfunc_blob_size = sizeof (VFuncBlob);
314   header->arg_blob_size = sizeof (ArgBlob);
315   header->property_blob_size = sizeof (PropertyBlob);
316   header->field_blob_size = sizeof (FieldBlob);
317   header->value_blob_size = sizeof (ValueBlob);
318   header->constant_blob_size = sizeof (ConstantBlob);
319   header->error_domain_blob_size = sizeof (ErrorDomainBlob);
320   header->attribute_blob_size = sizeof (AttributeBlob);
321   header->signature_blob_size = sizeof (SignatureBlob);
322   header->enum_blob_size = sizeof (EnumBlob);
323   header->struct_blob_size = sizeof (StructBlob);
324   header->object_blob_size = sizeof(ObjectBlob);
325   header->interface_blob_size = sizeof (InterfaceBlob);
326   header->union_blob_size = sizeof (UnionBlob);
327
328   /* fill in directory and content */
329   entry = (DirEntry *)&data[header->directory];
330
331   offset2 = header->directory + dir_size;
332
333   for (e = module->entries, i = 0; e; e = e->next, i++)
334     {
335       GIrTypelibBuild build;
336       GIrNode *node = e->data;
337
338       if (strchr (node->name, '.'))
339         {
340           g_error ("Names may not contain '.'");
341         }
342
343       /* we picked up implicit xref nodes, start over */
344       if (i == n_entries)
345         {
346           GList *link;
347           g_message ("Found implicit cross references, starting over");
348
349           g_hash_table_destroy (strings);
350           g_hash_table_destroy (types);
351
352           /* Reset the cached offsets */
353           for (link = offset_ordered_nodes; link; link = link->next)
354             ((GIrNode *) link->data)->offset = 0;
355
356           g_list_free (offset_ordered_nodes);
357           strings = NULL;
358
359           g_free (data);
360           data = NULL;
361
362           goto restart;
363         }
364         
365       offset = offset2;
366
367       if (node->type == G_IR_NODE_XREF)
368         {
369           const char *namespace = ((GIrNodeXRef*)node)->namespace;
370           
371           entry->blob_type = 0;
372           entry->local = FALSE;
373           entry->offset = write_string (namespace, strings, data, &offset2);
374           entry->name = write_string (node->name, strings, data, &offset2);
375         }
376       else
377         {
378           old_offset = offset;
379           offset2 = offset + g_ir_node_get_size (node);
380
381           entry->blob_type = node->type;
382           entry->local = TRUE;
383           entry->offset = offset;
384           entry->name = write_string (node->name, strings, data, &offset2);
385
386           build.module = module;
387           build.modules = modules;
388           build.strings = strings;
389           build.types = types;
390           build.offset_ordered_nodes = offset_ordered_nodes;
391           build.n_attributes = header->n_attributes;
392           build.data = data;
393           g_ir_node_build_typelib (node, NULL, &build, &offset, &offset2);
394
395           offset_ordered_nodes = build.offset_ordered_nodes;
396           header->n_attributes = build.n_attributes;
397
398           if (offset2 > old_offset + g_ir_node_get_full_size (node))
399             g_error ("left a hole of %d bytes\n", offset2 - old_offset - g_ir_node_get_full_size (node));
400         }
401
402       entry++;
403     }
404
405   offset_ordered_nodes = g_list_reverse (offset_ordered_nodes);
406
407   g_message ("header: %d entries, %d attributes", header->n_entries, header->n_attributes);
408
409   _g_irnode_dump_stats ();
410
411   /* Write attributes after the blobs */
412   offset = offset2;
413   header->attributes = offset;
414   offset2 = offset + header->n_attributes * header->attribute_blob_size;
415
416   for (e = offset_ordered_nodes; e; e = e->next)
417     {
418       GIrNode *node = e->data;
419
420       write_attributes (module, node, strings, data, &offset, &offset2);
421     }
422   
423   g_message ("reallocating to %d bytes", offset2);
424
425   data = g_realloc (data, offset2);
426   header = (Header*) data;
427   length = header->size = offset2;
428   typelib = g_typelib_new_from_memory (data, length);
429
430   g_hash_table_destroy (strings);
431   g_hash_table_destroy (types);
432   g_list_free (offset_ordered_nodes);
433
434   return typelib;
435 }
436