[typelib] Remove space/indent mismatch
[gnome.gobject-introspection] / tools / compiler.c
1 /* GObject introspection: Typelib compiler
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 <errno.h>
22 #include <string.h>
23
24 #include <glib.h>
25 #include <glib/gstdio.h>
26 #include <gio/gio.h>
27
28 #ifdef G_OS_WIN32
29 #include <io.h>
30 #include <fcntl.h>
31 #endif
32
33 #include "girmodule.h"
34 #include "girnode.h"
35 #include "girparser.h"
36 #include "gtypelib.h"
37
38 gboolean code = FALSE;
39 gboolean no_init = FALSE;
40 gchar **includedirs = NULL;
41 gchar **input = NULL;
42 gchar *output = NULL;
43 gchar *mname = NULL;
44 gchar *shlib = NULL;
45 gboolean include_cwd = FALSE;
46 gboolean debug = FALSE;
47 gboolean verbose = FALSE;
48
49 static gchar *
50 format_output (GTypelib *typelib)
51 {
52   GString *result;
53   guint i;
54
55   result = g_string_sized_new (6 * typelib->len);
56
57   g_string_append_printf (result, "#include <stdlib.h>\n");
58   g_string_append_printf (result, "#include <girepository.h>\n\n");
59   
60   g_string_append_printf (result, "const unsigned char _G_TYPELIB[] = \n{");
61
62   for (i = 0; i < typelib->len; i++)
63     {
64       if (i > 0)
65         g_string_append (result, ", ");
66
67       if (i % 10 == 0)
68         g_string_append (result, "\n\t");
69       
70       g_string_append_printf (result, "0x%.2x", typelib->data[i]);      
71     }
72
73   g_string_append_printf (result, "\n};\n\n");
74   g_string_append_printf (result, "const gsize _G_TYPELIB_SIZE = %u;\n\n",
75                           (guint)typelib->len);
76
77   if (!no_init)
78     {
79       g_string_append_printf (result,
80                               "__attribute__((constructor)) void "
81                               "register_typelib (void);\n\n");
82       g_string_append_printf (result,
83                               "__attribute__((constructor)) void\n"
84                               "register_typelib (void)\n"
85                               "{\n"
86                               "\tGTypelib *typelib;\n"
87                               "\ttypelib = g_typelib_new_from_const_memory (_G_TYPELIB, _G_TYPELIB_SIZE);\n"
88                               "\tg_irepository_load_typelib (NULL, typelib, G_IREPOSITORY_LOAD_FLAG_LAZY, NULL);\n"
89                               "}\n\n");
90     }
91
92   return g_string_free (result, FALSE);
93 }
94
95 static void
96 write_out_typelib (gchar *prefix,
97                    GTypelib *typelib)
98 {
99   FILE *file;
100   gsize written;
101   GFile *file_obj;
102   gchar *filename;
103   GFile *tmp_file_obj;
104   gchar *tmp_filename;
105   GError *error = NULL;
106
107   if (output == NULL)
108     {
109       file = stdout;
110       file_obj = NULL;
111       filename = NULL;
112       tmp_filename = NULL;
113       tmp_file_obj = NULL;
114 #ifdef G_OS_WIN32
115       setmode (fileno (file), _O_BINARY);
116 #endif
117     }
118   else
119     {
120       if (prefix)
121         filename = g_strdup_printf ("%s-%s", prefix, output);  
122       else
123         filename = g_strdup (output);
124       file_obj = g_file_new_for_path (filename);
125       tmp_filename = g_strdup_printf ("%s.tmp", filename);
126       tmp_file_obj = g_file_new_for_path (tmp_filename);
127       file = g_fopen (tmp_filename, "wb");
128
129       if (file == NULL)
130         {
131           g_fprintf (stderr, "failed to open '%s': %s\n",
132                      tmp_filename, g_strerror (errno));
133           goto out;
134         }
135     }
136
137   if (!code)
138     {
139       written = fwrite (typelib->data, 1, typelib->len, file);
140       if (written < typelib->len) {
141         g_error ("ERROR: Could not write the whole output: %s",
142                  strerror(errno));
143         goto out;
144       }
145     }
146   else
147     {
148       gchar *code;
149
150       code = format_output (typelib);
151       fputs (code, file);
152       g_free (code);
153     }
154
155   if (output != NULL)
156     fclose (file);
157   if (tmp_filename != NULL)
158     {
159       if (!g_file_move (tmp_file_obj, file_obj, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error))
160         {
161           g_error ("ERROR: failed to rename %s to %s: %s", tmp_filename, filename, error->message);
162           g_clear_error (&error);
163         }
164     }
165 out:
166   g_free (filename);
167   g_free (tmp_filename);
168 }
169
170 GLogLevelFlags logged_levels;
171
172 static void log_handler (const gchar *log_domain,
173                          GLogLevelFlags log_level,
174                          const gchar *message,
175                          gpointer user_data)
176 {
177   
178   if (log_level & logged_levels)
179     g_log_default_handler (log_domain, log_level, message, user_data);
180 }
181
182 static GOptionEntry options[] = 
183 {
184   { "code", 0, 0, G_OPTION_ARG_NONE, &code, "emit C code", NULL },
185   { "no-init", 0, 0, G_OPTION_ARG_NONE, &no_init, "do not create _init() function", NULL },
186   { "includedir", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &includedirs, "include directories in GIR search path", NULL }, 
187   { "output", 'o', 0, G_OPTION_ARG_FILENAME, &output, "output file", "FILE" }, 
188   { "module", 'm', 0, G_OPTION_ARG_STRING, &mname, "module to compile", "NAME" }, 
189   { "shared-library", 'l', 0, G_OPTION_ARG_FILENAME, &shlib, "shared library", "FILE" }, 
190   { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "show debug messages", NULL }, 
191   { "verbose", 0, 0, G_OPTION_ARG_NONE, &verbose, "show verbose messages", NULL }, 
192   { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &input, NULL, NULL },
193   { NULL, }
194 };
195
196 int
197 main (int argc, char ** argv)
198 {
199   GOptionContext *context;
200   GError *error = NULL;
201   GIrParser *parser;
202   GList *m, *modules;
203   gint i;
204   g_typelib_check_sanity ();
205
206   context = g_option_context_new ("");
207   g_option_context_add_main_entries (context, options, NULL);
208   g_option_context_parse (context, &argc, &argv, &error);
209   g_option_context_free (context);
210
211   logged_levels = G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_DEBUG);
212   if (debug)
213     logged_levels = logged_levels | G_LOG_LEVEL_DEBUG;
214   if (verbose)
215     logged_levels = logged_levels | G_LOG_LEVEL_MESSAGE;
216   g_log_set_always_fatal (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
217
218   g_log_set_default_handler (log_handler, NULL);
219
220   if (!input) 
221     { 
222       g_fprintf (stderr, "no input files\n"); 
223
224       return 1;
225     }
226
227   g_debug ("[parsing] start, %d includes", 
228            includedirs ? g_strv_length (includedirs) : 0);
229
230   g_type_init ();
231
232   if (includedirs != NULL)
233     for (i = 0; includedirs[i]; i++)
234       g_irepository_prepend_search_path (includedirs[i]);
235
236   parser = g_ir_parser_new ();
237
238   g_ir_parser_set_includes (parser, (const char*const*) includedirs);
239
240   modules = NULL;
241   for (i = 0; input[i]; i++)
242     {
243       GList *mods;
244       mods = g_ir_parser_parse_file (parser, input[i], &error);
245       
246       if (mods == NULL) 
247         {
248           g_fprintf (stderr, "error parsing file %s: %s\n", 
249                      input[i], error->message);
250       
251           return 1;
252         }
253
254       modules = g_list_concat (modules, mods);
255     }
256
257   g_debug ("[parsing] done");
258
259   g_debug ("[building] start");
260
261   for (m = modules; m; m = m->next)
262     {
263       GIrModule *module = m->data;
264       gchar *prefix;
265       GTypelib *typelib;
266
267       if (mname && strcmp (mname, module->name) != 0)
268         continue;
269       if (shlib)
270         {
271           if (module->shared_library)
272             g_free (module->shared_library);
273           module->shared_library = g_strdup (shlib);
274         }
275
276       g_debug ("[building] module %s", module->name);
277
278       typelib = g_ir_module_build_typelib (module, modules);
279       if (typelib == NULL)
280         {
281           g_error ("Failed to build typelib for module '%s'\n", module->name);
282
283           continue;
284         }
285       if (!g_typelib_validate (typelib, &error))
286         g_error ("Invalid typelib for module '%s': %s", 
287                  module->name, error->message);
288
289       if (!mname && (m->next || m->prev) && output)
290         prefix = module->name;
291       else
292         prefix = NULL;
293
294       write_out_typelib (prefix, typelib);
295       g_typelib_free (typelib);
296       typelib = NULL;
297
298       /* when writing to stdout, stop after the first module */
299       if (m->next && !output && !mname)
300         {
301           g_warning ("%d modules omitted\n", g_list_length (modules) - 1);
302
303           break;
304         }
305     }
306
307   g_debug ("[building] done");
308
309 #if 0
310   /* No point */
311   g_ir_parser_free (parser);
312 #endif  
313
314   return 0; 
315 }