1/* Copyright 2015 Red Hat, Inc.
2 *
3 * GTK+ is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as
5 * published by the Free Software Foundation; either version 2 of the
6 * License, or (at your option) any later version.
7 *
8 * GLib is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with GTK+; see the file COPYING. If not,
15 * see <http://www.gnu.org/licenses/>.
16 *
17 * Author: Matthias Clasen
18 */
19
20#include <stdlib.h>
21#include <string.h>
22#include <errno.h>
23
24#include <glib/gi18n.h>
25#include <glib/gprintf.h>
26#include <glib/gstdio.h>
27#include <gtk/gtk.h>
28#include "gtkbuilderprivate.h"
29#include "gtk-builder-tool.h"
30
31static GType
32make_fake_type (const char *type_name,
33 const char *parent_name)
34{
35 GType parent_type;
36 GTypeQuery query;
37
38 parent_type = g_type_from_name (name: parent_name);
39 if (parent_type == G_TYPE_INVALID)
40 {
41 g_printerr (format: "Failed to lookup template parent type %s\n", parent_name);
42 exit (status: 1);
43 }
44
45 g_type_query (type: parent_type, query: &query);
46 return g_type_register_static_simple (parent_type,
47 type_name,
48 class_size: query.class_size,
49 NULL,
50 instance_size: query.instance_size,
51 NULL,
52 flags: 0);
53}
54
55static void
56do_validate_template (const char *filename,
57 const char *type_name,
58 const char *parent_name)
59{
60 GType template_type;
61 GObject *object;
62 GtkBuilder *builder;
63 GError *error = NULL;
64 int ret;
65
66 /* Only make a fake type if it doesn't exist yet.
67 * This lets us e.g. validate the GtkFileChooserWidget template.
68 */
69 template_type = g_type_from_name (name: type_name);
70 if (template_type == G_TYPE_INVALID)
71 template_type = make_fake_type (type_name, parent_name);
72
73 object = g_object_new (object_type: template_type, NULL);
74 if (!object)
75 {
76 g_printerr (format: "Failed to create an instance of the template type %s\n", type_name);
77 exit (status: 1);
78 }
79
80 builder = gtk_builder_new ();
81 ret = gtk_builder_extend_with_template (builder, object , template_type, buffer: " ", length: 1, error: &error);
82 if (ret)
83 ret = gtk_builder_add_from_file (builder, filename, error: &error);
84 g_object_unref (object: builder);
85
86 if (ret == 0)
87 {
88 g_printerr (format: "%s\n", error->message);
89 exit (status: 1);
90 }
91}
92
93static gboolean
94parse_template_error (const char *message,
95 char **class_name,
96 char **parent_name)
97{
98 char *p;
99
100 p = strstr (haystack: message, needle: "(class '");
101 if (p)
102 {
103 *class_name = g_strdup (str: p + strlen (s: "(class '"));
104 p = strstr (haystack: *class_name, needle: "'");
105 if (p)
106 *p = '\0';
107 }
108 p = strstr (haystack: message, needle: ", parent '");
109 if (p)
110 {
111 *parent_name = g_strdup (str: p + strlen (s: ", parent '"));
112 p = strstr (haystack: *parent_name, needle: "'");
113 if (p)
114 *p = '\0';
115 }
116
117 return TRUE;
118}
119
120static gboolean
121validate_file (const char *filename)
122{
123 GtkBuilder *builder;
124 GError *error = NULL;
125 int ret;
126 char *class_name = NULL;
127 char *parent_name = NULL;
128
129 builder = gtk_builder_new ();
130 ret = gtk_builder_add_from_file (builder, filename, error: &error);
131 g_object_unref (object: builder);
132
133 if (ret == 0)
134 {
135 if (g_error_matches (error, GTK_BUILDER_ERROR, code: GTK_BUILDER_ERROR_UNHANDLED_TAG) &&
136 parse_template_error (message: error->message, class_name: &class_name, parent_name: &parent_name))
137 {
138 do_validate_template (filename, type_name: class_name, parent_name);
139 }
140 else
141 {
142 g_printerr (format: "%s\n", error->message);
143 return FALSE;
144 }
145 }
146
147 return TRUE;
148}
149
150void
151do_validate (int *argc, const char ***argv)
152{
153 int i;
154
155 for (i = 1; i < *argc; i++)
156 {
157 if (!validate_file (filename: (*argv)[i]))
158 exit (status: 1);
159 }
160}
161

source code of gtk/tools/gtk-builder-tool-validate.c