nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * Copyright © 2011 Red Hat, Inc
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 *
17 * Author: Alexander Larsson <alexl@redhat.com>
18 */
19  
20 #include "config.h"
21  
22 #include <glib.h>
23 #include <gstdio.h>
24 #include <gi18n.h>
25 #include <gioenums.h>
26  
27 #include <string.h>
28 #include <stdio.h>
29 #include <locale.h>
30 #include <errno.h>
31 #ifdef G_OS_UNIX
32 #include <unistd.h>
33 #endif
34 #ifdef G_OS_WIN32
35 #include <io.h>
36 #endif
37  
38 #include <gio/gmemoryoutputstream.h>
39 #include <gio/gzlibcompressor.h>
40 #include <gio/gconverteroutputstream.h>
41  
42 #include <glib.h>
43 #include "gvdb/gvdb-builder.h"
44  
45 #include "gconstructor_as_data.h"
46  
47 #ifdef G_OS_WIN32
48 #include "glib/glib-private.h"
49 #endif
50  
51 typedef struct
52 {
53 char *filename;
54 char *content;
55 gsize content_size;
56 gsize size;
57 guint32 flags;
58 } FileData;
59  
60 typedef struct
61 {
62 GHashTable *table; /* resource path -> FileData */
63  
64 gboolean collect_data;
65  
66 /* per gresource */
67 char *prefix;
68  
69 /* per file */
70 char *alias;
71 gboolean compressed;
72 char *preproc_options;
73  
74 GString *string; /* non-NULL when accepting text */
75 } ParseState;
76  
77 static gchar **sourcedirs = NULL;
78 static gchar *xmllint = NULL;
79 static gchar *gdk_pixbuf_pixdata = NULL;
80  
81 static void
82 file_data_free (FileData *data)
83 {
84 g_free (data->filename);
85 g_free (data->content);
86 g_free (data);
87 }
88  
89 static void
90 start_element (GMarkupParseContext *context,
91 const gchar *element_name,
92 const gchar **attribute_names,
93 const gchar **attribute_values,
94 gpointer user_data,
95 GError **error)
96 {
97 ParseState *state = user_data;
98 const GSList *element_stack;
99 const gchar *container;
100  
101 element_stack = g_markup_parse_context_get_element_stack (context);
102 container = element_stack->next ? element_stack->next->data : NULL;
103  
104 #define COLLECT(first, ...) \
105 g_markup_collect_attributes (element_name, \
106 attribute_names, attribute_values, error, \
107 first, __VA_ARGS__, G_MARKUP_COLLECT_INVALID)
108 #define OPTIONAL G_MARKUP_COLLECT_OPTIONAL
109 #define STRDUP G_MARKUP_COLLECT_STRDUP
110 #define STRING G_MARKUP_COLLECT_STRING
111 #define BOOL G_MARKUP_COLLECT_BOOLEAN
112 #define NO_ATTRS() COLLECT (G_MARKUP_COLLECT_INVALID, NULL)
113  
114 if (container == NULL)
115 {
116 if (strcmp (element_name, "gresources") == 0)
117 return;
118 }
119 else if (strcmp (container, "gresources") == 0)
120 {
121 if (strcmp (element_name, "gresource") == 0)
122 {
123 COLLECT (OPTIONAL | STRDUP,
124 "prefix", &state->prefix);
125 return;
126 }
127 }
128 else if (strcmp (container, "gresource") == 0)
129 {
130 if (strcmp (element_name, "file") == 0)
131 {
132 COLLECT (OPTIONAL | STRDUP, "alias", &state->alias,
133 OPTIONAL | BOOL, "compressed", &state->compressed,
134 OPTIONAL | STRDUP, "preprocess", &state->preproc_options);
135 state->string = g_string_new ("");
136 return;
137 }
138 }
139  
140 if (container)
141 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
142 _("Element <%s> not allowed inside <%s>"),
143 element_name, container);
144 else
145 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
146 _("Element <%s> not allowed at toplevel"), element_name);
147  
148 }
149  
150 static GvdbItem *
151 get_parent (GHashTable *table,
152 gchar *key,
153 gint length)
154 {
155 GvdbItem *grandparent, *parent;
156  
157 if (length == 1)
158 return NULL;
159  
160 while (key[--length - 1] != '/');
161 key[length] = '\0';
162  
163 parent = g_hash_table_lookup (table, key);
164  
165 if (parent == NULL)
166 {
167 parent = gvdb_hash_table_insert (table, key);
168  
169 grandparent = get_parent (table, key, length);
170  
171 if (grandparent != NULL)
172 gvdb_item_set_parent (parent, grandparent);
173 }
174  
175 return parent;
176 }
177  
178 static gchar *
179 find_file (const gchar *filename)
180 {
181 guint i;
182 gchar *real_file;
183 gboolean exists;
184  
185 if (g_path_is_absolute (filename))
186 return g_strdup (filename);
187  
188 /* search all the sourcedirs for the correct files in order */
189 for (i = 0; sourcedirs[i] != NULL; i++)
190 {
191 real_file = g_build_path ("/", sourcedirs[i], filename, NULL);
192 exists = g_file_test (real_file, G_FILE_TEST_EXISTS);
193 if (exists)
194 return real_file;
195 g_free (real_file);
196 }
197 return NULL;
198 }
199  
200 static void
201 end_element (GMarkupParseContext *context,
202 const gchar *element_name,
203 gpointer user_data,
204 GError **error)
205 {
206 ParseState *state = user_data;
207 GError *my_error = NULL;
208  
209 if (strcmp (element_name, "gresource") == 0)
210 {
211 g_free (state->prefix);
212 state->prefix = NULL;
213 }
214  
215 else if (strcmp (element_name, "file") == 0)
216 {
217 gchar *file, *real_file;
218 gchar *key;
219 FileData *data = NULL;
220 char *tmp_file = NULL;
221 char *tmp_file2 = NULL;
222  
223 file = state->string->str;
224 key = file;
225 if (state->alias)
226 key = state->alias;
227  
228 if (state->prefix)
229 key = g_build_path ("/", "/", state->prefix, key, NULL);
230 else
231 key = g_build_path ("/", "/", key, NULL);
232  
233 if (g_hash_table_lookup (state->table, key) != NULL)
234 {
235 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
236 _("File %s appears multiple times in the resource"),
237 key);
238 return;
239 }
240  
241 if (sourcedirs != NULL)
242 {
243 real_file = find_file (file);
244 if (real_file == NULL)
245 {
246 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
247 _("Failed to locate '%s' in any source directory"), file);
248 return;
249 }
250 }
251 else
252 {
253 gboolean exists;
254 exists = g_file_test (file, G_FILE_TEST_EXISTS);
255 if (!exists)
256 {
257 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
258 _("Failed to locate '%s' in current directory"), file);
259 return;
260 }
261 real_file = g_strdup (file);
262 }
263  
264 data = g_new0 (FileData, 1);
265 data->filename = g_strdup (real_file);
266 if (!state->collect_data)
267 goto done;
268  
269 if (state->preproc_options)
270 {
271 gchar **options;
272 guint i;
273 gboolean xml_stripblanks = FALSE;
274 gboolean to_pixdata = FALSE;
275  
276 options = g_strsplit (state->preproc_options, ",", -1);
277  
278 for (i = 0; options[i]; i++)
279 {
280 if (!strcmp (options[i], "xml-stripblanks"))
281 xml_stripblanks = TRUE;
282 else if (!strcmp (options[i], "to-pixdata"))
283 to_pixdata = TRUE;
284 else
285 {
286 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
287 _("Unknown processing option \"%s\""), options[i]);
288 g_strfreev (options);
289 goto cleanup;
290 }
291 }
292 g_strfreev (options);
293  
294 if (xml_stripblanks && xmllint != NULL)
295 {
296 int fd;
297 GSubprocess *proc;
298  
299 tmp_file = g_strdup ("resource-XXXXXXXX");
300 if ((fd = g_mkstemp (tmp_file)) == -1)
301 {
302 int errsv = errno;
303  
304 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
305 _("Failed to create temp file: %s"),
306 g_strerror (errsv));
307 g_free (tmp_file);
308 tmp_file = NULL;
309 goto cleanup;
310 }
311 close (fd);
312  
313 proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE, error,
314 xmllint, "--nonet", "--noblanks", "--output", tmp_file, real_file, NULL);
315 g_free (real_file);
316 real_file = NULL;
317  
318 if (!proc)
319 goto cleanup;
320  
321 if (!g_subprocess_wait_check (proc, NULL, error))
322 {
323 g_object_unref (proc);
324 goto cleanup;
325 }
326  
327 g_object_unref (proc);
328  
329 real_file = g_strdup (tmp_file);
330 }
331  
332 if (to_pixdata)
333 {
334 int fd;
335 GSubprocess *proc;
336  
337 if (gdk_pixbuf_pixdata == NULL)
338 {
339 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
340 "to-pixbuf preprocessing requested but GDK_PIXBUF_PIXDATA "
341 "not set and gdk-pixbuf-pixdata not found in path");
342 goto cleanup;
343 }
344  
345 tmp_file2 = g_strdup ("resource-XXXXXXXX");
346 if ((fd = g_mkstemp (tmp_file2)) == -1)
347 {
348 int errsv = errno;
349  
350 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
351 _("Failed to create temp file: %s"),
352 g_strerror (errsv));
353 g_free (tmp_file2);
354 tmp_file2 = NULL;
355 goto cleanup;
356 }
357 close (fd);
358  
359 proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE, error,
360 gdk_pixbuf_pixdata, real_file, tmp_file2, NULL);
361 g_free (real_file);
362 real_file = NULL;
363  
364 if (!g_subprocess_wait_check (proc, NULL, error))
365 {
366 g_object_unref (proc);
367 goto cleanup;
368 }
369  
370 g_object_unref (proc);
371  
372 real_file = g_strdup (tmp_file2);
373 }
374 }
375  
376 if (!g_file_get_contents (real_file, &data->content, &data->size, &my_error))
377 {
378 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
379 _("Error reading file %s: %s"),
380 real_file, my_error->message);
381 g_clear_error (&my_error);
382 goto cleanup;
383 }
384 /* Include zero termination in content_size for uncompressed files (but not in size) */
385 data->content_size = data->size + 1;
386  
387 if (state->compressed)
388 {
389 GOutputStream *out = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
390 GZlibCompressor *compressor =
391 g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_ZLIB, 9);
392 GOutputStream *out2 = g_converter_output_stream_new (out, G_CONVERTER (compressor));
393  
394 if (!g_output_stream_write_all (out2, data->content, data->size,
395 NULL, NULL, NULL) ||
396 !g_output_stream_close (out2, NULL, NULL))
397 {
398 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
399 _("Error compressing file %s"),
400 real_file);
401 goto cleanup;
402 }
403  
404 g_free (data->content);
405 data->content_size = g_memory_output_stream_get_size (G_MEMORY_OUTPUT_STREAM (out));
406 data->content = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (out));
407  
408 g_object_unref (compressor);
409 g_object_unref (out);
410 g_object_unref (out2);
411  
412 data->flags |= G_RESOURCE_FLAGS_COMPRESSED;
413 }
414  
415 done:
416  
417 g_hash_table_insert (state->table, key, data);
418 data = NULL;
419  
420 cleanup:
421 /* Cleanup */
422  
423 g_free (state->alias);
424 state->alias = NULL;
425 g_string_free (state->string, TRUE);
426 state->string = NULL;
427 g_free (state->preproc_options);
428 state->preproc_options = NULL;
429  
430 g_free (real_file);
431  
432 if (tmp_file)
433 {
434 unlink (tmp_file);
435 g_free (tmp_file);
436 }
437  
438 if (tmp_file2)
439 {
440 unlink (tmp_file2);
441 g_free (tmp_file2);
442 }
443  
444 if (data != NULL)
445 file_data_free (data);
446 }
447 }
448  
449 static void
450 text (GMarkupParseContext *context,
451 const gchar *text,
452 gsize text_len,
453 gpointer user_data,
454 GError **error)
455 {
456 ParseState *state = user_data;
457 gsize i;
458  
459 for (i = 0; i < text_len; i++)
460 if (!g_ascii_isspace (text[i]))
461 {
462 if (state->string)
463 g_string_append_len (state->string, text, text_len);
464  
465 else
466 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
467 _("text may not appear inside <%s>"),
468 g_markup_parse_context_get_element (context));
469  
470 break;
471 }
472 }
473  
474 static GHashTable *
475 parse_resource_file (const gchar *filename,
476 gboolean collect_data)
477 {
478 GMarkupParser parser = { start_element, end_element, text };
479 ParseState state = { 0, };
480 GMarkupParseContext *context;
481 GError *error = NULL;
482 gchar *contents;
483 GHashTable *table = NULL;
484 gsize size;
485  
486 if (!g_file_get_contents (filename, &contents, &size, &error))
487 {
488 g_printerr ("%s\n", error->message);
489 g_clear_error (&error);
490 return NULL;
491 }
492  
493 state.table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)file_data_free);
494 state.collect_data = collect_data;
495  
496 context = g_markup_parse_context_new (&parser,
497 G_MARKUP_TREAT_CDATA_AS_TEXT |
498 G_MARKUP_PREFIX_ERROR_POSITION,
499 &state, NULL);
500  
501 if (!g_markup_parse_context_parse (context, contents, size, &error) ||
502 !g_markup_parse_context_end_parse (context, &error))
503 {
504 g_printerr ("%s: %s.\n", filename, error->message);
505 g_clear_error (&error);
506 }
507 else if (collect_data)
508 {
509 GHashTableIter iter;
510 const char *key;
511 char *mykey;
512 gsize key_len;
513 FileData *data;
514 GVariant *v_data;
515 GVariantBuilder builder;
516 GvdbItem *item;
517  
518 table = gvdb_hash_table_new (NULL, NULL);
519  
520 g_hash_table_iter_init (&iter, state.table);
521 while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&data))
522 {
523 key_len = strlen (key);
524 mykey = g_strdup (key);
525  
526 item = gvdb_hash_table_insert (table, key);
527 gvdb_item_set_parent (item,
528 get_parent (table, mykey, key_len));
529  
530 g_free (mykey);
531  
532 g_variant_builder_init (&builder, G_VARIANT_TYPE ("(uuay)"));
533  
534 g_variant_builder_add (&builder, "u", data->size); /* Size */
535 g_variant_builder_add (&builder, "u", data->flags); /* Flags */
536  
537 v_data = g_variant_new_from_data (G_VARIANT_TYPE("ay"),
538 data->content, data->content_size, TRUE,
539 g_free, data->content);
540 g_variant_builder_add_value (&builder, v_data);
541 data->content = NULL; /* Take ownership */
542  
543 gvdb_item_set_value (item,
544 g_variant_builder_end (&builder));
545 }
546 }
547 else
548 {
549 table = g_hash_table_ref (state.table);
550 }
551  
552 g_hash_table_unref (state.table);
553 g_markup_parse_context_free (context);
554 g_free (contents);
555  
556 return table;
557 }
558  
559 static gboolean
560 write_to_file (GHashTable *table,
561 const gchar *filename,
562 GError **error)
563 {
564 gboolean success;
565  
566 success = gvdb_table_write_contents (table, filename,
567 G_BYTE_ORDER != G_LITTLE_ENDIAN,
568 error);
569  
570 return success;
571 }
572  
573 int
574 main (int argc, char **argv)
575 {
576 GError *error;
577 GHashTable *table;
578 gchar *srcfile;
579 gchar *target = NULL;
580 gchar *binary_target = NULL;
581 gboolean generate_automatic = FALSE;
582 gboolean generate_source = FALSE;
583 gboolean generate_header = FALSE;
584 gboolean manual_register = FALSE;
585 gboolean internal = FALSE;
586 gboolean generate_dependencies = FALSE;
587 char *c_name = NULL;
588 char *c_name_no_underscores;
589 const char *linkage = "extern";
590 GOptionContext *context;
591 GOptionEntry entries[] = {
592 { "target", 0, 0, G_OPTION_ARG_FILENAME, &target, N_("name of the output file"), N_("FILE") },
593 { "sourcedir", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &sourcedirs, N_("The directories where files are to be read from (default to current directory)"), N_("DIRECTORY") },
594 { "generate", 0, 0, G_OPTION_ARG_NONE, &generate_automatic, N_("Generate output in the format selected for by the target filename extension"), NULL },
595 { "generate-header", 0, 0, G_OPTION_ARG_NONE, &generate_header, N_("Generate source header"), NULL },
596 { "generate-source", 0, 0, G_OPTION_ARG_NONE, &generate_source, N_("Generate sourcecode used to link in the resource file into your code"), NULL },
597 { "generate-dependencies", 0, 0, G_OPTION_ARG_NONE, &generate_dependencies, N_("Generate dependency list"), NULL },
598 { "manual-register", 0, 0, G_OPTION_ARG_NONE, &manual_register, N_("Don't automatically create and register resource"), NULL },
599 { "internal", 0, 0, G_OPTION_ARG_NONE, &internal, N_("Don't export functions; declare them G_GNUC_INTERNAL"), NULL },
600 { "c-name", 0, 0, G_OPTION_ARG_STRING, &c_name, N_("C identifier name used for the generated source code"), NULL },
601 { NULL }
602 };
603  
604 #ifdef G_OS_WIN32
605 gchar *tmp;
606 #endif
607  
608 setlocale (LC_ALL, "");
609 textdomain (GETTEXT_PACKAGE);
610  
611 #ifdef G_OS_WIN32
612 tmp = _glib_get_locale_dir ();
613 bindtextdomain (GETTEXT_PACKAGE, tmp);
614 g_free (tmp);
615 #else
616 bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
617 #endif
618  
619 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
620 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
621 #endif
622  
623 context = g_option_context_new (N_("FILE"));
624 g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
625 g_option_context_set_summary (context,
626 N_("Compile a resource specification into a resource file.\n"
627 "Resource specification files have the extension .gresource.xml,\n"
628 "and the resource file have the extension called .gresource."));
629 g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
630  
631 error = NULL;
632 if (!g_option_context_parse (context, &argc, &argv, &error))
633 {
634 g_printerr ("%s\n", error->message);
635 return 1;
636 }
637  
638 g_option_context_free (context);
639  
640 if (argc != 2)
641 {
642 g_printerr (_("You should give exactly one file name\n"));
643 g_free (c_name);
644 return 1;
645 }
646  
647 if (internal)
648 linkage = "G_GNUC_INTERNAL";
649  
650 srcfile = argv[1];
651  
652 xmllint = g_strdup (g_getenv ("XMLLINT"));
653 if (xmllint == NULL)
654 xmllint = g_find_program_in_path ("xmllint");
655 if (xmllint == NULL)
656 g_printerr ("XMLLINT not set and xmllint not found in path; skipping xml preprocessing.\n");
657  
658 gdk_pixbuf_pixdata = g_strdup (g_getenv ("GDK_PIXBUF_PIXDATA"));
659 if (gdk_pixbuf_pixdata == NULL)
660 gdk_pixbuf_pixdata = g_find_program_in_path ("gdk-pixbuf-pixdata");
661  
662 if (target == NULL)
663 {
664 char *dirname = g_path_get_dirname (srcfile);
665 char *base = g_path_get_basename (srcfile);
666 char *target_basename;
667 if (g_str_has_suffix (base, ".xml"))
668 base[strlen(base) - strlen (".xml")] = 0;
669  
670 if (generate_source)
671 {
672 if (g_str_has_suffix (base, ".gresource"))
673 base[strlen(base) - strlen (".gresource")] = 0;
674 target_basename = g_strconcat (base, ".c", NULL);
675 }
676 else if (generate_header)
677 {
678 if (g_str_has_suffix (base, ".gresource"))
679 base[strlen(base) - strlen (".gresource")] = 0;
680 target_basename = g_strconcat (base, ".h", NULL);
681 }
682 else
683 {
684 if (g_str_has_suffix (base, ".gresource"))
685 target_basename = g_strdup (base);
686 else
687 target_basename = g_strconcat (base, ".gresource", NULL);
688 }
689  
690 target = g_build_filename (dirname, target_basename, NULL);
691 g_free (target_basename);
692 g_free (dirname);
693 g_free (base);
694 }
695 else if (generate_automatic)
696 {
697 if (g_str_has_suffix (target, ".c"))
698 generate_source = TRUE;
699 else if (g_str_has_suffix (target, ".h"))
700 generate_header = TRUE;
701 else if (g_str_has_suffix (target, ".gresource"))
702 ;
703 }
704  
705 if ((table = parse_resource_file (srcfile, !generate_dependencies)) == NULL)
706 {
707 g_free (target);
708 g_free (c_name);
709 return 1;
710 }
711  
712 if (generate_dependencies)
713 {
714 GHashTableIter iter;
715 gpointer key, data;
716 FileData *file_data;
717  
718 g_hash_table_iter_init (&iter, table);
719 while (g_hash_table_iter_next (&iter, &key, &data))
720 {
721 file_data = data;
722 g_print ("%s\n",file_data->filename);
723 }
724 }
725 else if (generate_source || generate_header)
726 {
727 if (generate_source)
728 {
729 int fd = g_file_open_tmp (NULL, &binary_target, NULL);
730 if (fd == -1)
731 {
732 g_printerr ("Can't open temp file\n");
733 g_free (c_name);
734 return 1;
735 }
736 close (fd);
737 }
738  
739 if (c_name == NULL)
740 {
741 char *base = g_path_get_basename (srcfile);
742 GString *s;
743 char *dot;
744 int i;
745  
746 /* Remove extensions */
747 dot = strchr (base, '.');
748 if (dot)
749 *dot = 0;
750  
751 s = g_string_new ("");
752  
753 for (i = 0; base[i] != 0; i++)
754 {
755 const char *first = G_CSET_A_2_Z G_CSET_a_2_z "_";
756 const char *rest = G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "_";
757 if (strchr ((i == 0) ? first : rest, base[i]) != NULL)
758 g_string_append_c (s, base[i]);
759 else if (base[i] == '-')
760 g_string_append_c (s, '_');
761  
762 }
763  
764 c_name = g_string_free (s, FALSE);
765 }
766 }
767 else
768 binary_target = g_strdup (target);
769  
770 c_name_no_underscores = c_name;
771 while (c_name_no_underscores && *c_name_no_underscores == '_')
772 c_name_no_underscores++;
773  
774 if (binary_target != NULL &&
775 !write_to_file (table, binary_target, &error))
776 {
777 g_printerr ("%s\n", error->message);
778 g_free (target);
779 g_free (c_name);
780 return 1;
781 }
782  
783 if (generate_header)
784 {
785 FILE *file;
786  
787 file = fopen (target, "w");
788 if (file == NULL)
789 {
790 g_printerr ("can't write to file %s", target);
791 g_free (c_name);
792 return 1;
793 }
794  
795 fprintf (file,
796 "#ifndef __RESOURCE_%s_H__\n"
797 "#define __RESOURCE_%s_H__\n"
798 "\n"
799 "#include <gio/gio.h>\n"
800 "\n"
801 "%s GResource *%s_get_resource (void);\n",
802 c_name, c_name, linkage, c_name);
803  
804 if (manual_register)
805 fprintf (file,
806 "\n"
807 "%s void %s_register_resource (void);\n"
808 "%s void %s_unregister_resource (void);\n"
809 "\n",
810 linkage, c_name, linkage, c_name);
811  
812 fprintf (file,
813 "#endif\n");
814  
815 fclose (file);
816 }
817 else if (generate_source)
818 {
819 FILE *file;
820 guint8 *data;
821 gsize data_size;
822 gsize i;
823  
824 if (!g_file_get_contents (binary_target, (char **)&data,
825 &data_size, NULL))
826 {
827 g_printerr ("can't read back temporary file");
828 g_free (c_name);
829 return 1;
830 }
831 g_unlink (binary_target);
832  
833 file = fopen (target, "w");
834 if (file == NULL)
835 {
836 g_printerr ("can't write to file %s", target);
837 g_free (c_name);
838 return 1;
839 }
840  
841 fprintf (file,
842 "#include <gio/gio.h>\n"
843 "\n"
844 "#if defined (__ELF__) && ( __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6))\n"
845 "# define SECTION __attribute__ ((section (\".gresource.%s\"), aligned (8)))\n"
846 "#else\n"
847 "# define SECTION\n"
848 "#endif\n"
849 "\n"
850 "static const SECTION union { const guint8 data[%"G_GSIZE_FORMAT"]; const double alignment; void * const ptr;} %s_resource_data = { {\n",
851 c_name_no_underscores, data_size, c_name);
852  
853 for (i = 0; i < data_size; i++) {
854 if (i % 8 == 0)
855 fprintf (file, " ");
856 fprintf (file, "0x%2.2x", (int)data[i]);
857 if (i != data_size - 1)
858 fprintf (file, ", ");
859 if ((i % 8 == 7) || (i == data_size - 1))
860 fprintf (file, "\n");
861 }
862  
863 fprintf (file, "} };\n");
864  
865 fprintf (file,
866 "\n"
867 "static GStaticResource static_resource = { %s_resource_data.data, sizeof (%s_resource_data.data), NULL, NULL, NULL };\n"
868 "%s GResource *%s_get_resource (void);\n"
869 "GResource *%s_get_resource (void)\n"
870 "{\n"
871 " return g_static_resource_get_resource (&static_resource);\n"
872 "}\n",
873 c_name, c_name, linkage, c_name, c_name);
874  
875  
876 if (manual_register)
877 {
878 fprintf (file,
879 "\n"
880 "%s void %s_unregister_resource (void);\n"
881 "void %s_unregister_resource (void)\n"
882 "{\n"
883 " g_static_resource_fini (&static_resource);\n"
884 "}\n"
885 "\n"
886 "%s void %s_register_resource (void);\n"
887 "void %s_register_resource (void)\n"
888 "{\n"
889 " g_static_resource_init (&static_resource);\n"
890 "}\n",
891 linkage, c_name, c_name, linkage, c_name, c_name);
892 }
893 else
894 {
895 fprintf (file, "%s", gconstructor_code);
896 fprintf (file,
897 "\n"
898 "#ifdef G_HAS_CONSTRUCTORS\n"
899 "\n"
900 "#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA\n"
901 "#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(resource_constructor)\n"
902 "#endif\n"
903 "G_DEFINE_CONSTRUCTOR(resource_constructor)\n"
904 "#ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA\n"
905 "#pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(resource_destructor)\n"
906 "#endif\n"
907 "G_DEFINE_DESTRUCTOR(resource_destructor)\n"
908 "\n"
909 "#else\n"
910 "#warning \"Constructor not supported on this compiler, linking in resources will not work\"\n"
911 "#endif\n"
912 "\n"
913 "static void resource_constructor (void)\n"
914 "{\n"
915 " g_static_resource_init (&static_resource);\n"
916 "}\n"
917 "\n"
918 "static void resource_destructor (void)\n"
919 "{\n"
920 " g_static_resource_fini (&static_resource);\n"
921 "}\n");
922 }
923  
924 fclose (file);
925  
926 g_free (data);
927 }
928  
929 g_free (binary_target);
930 g_free (target);
931 g_hash_table_destroy (table);
932 g_free (xmllint);
933 g_free (c_name);
934  
935 return 0;
936 }