GETENV: check for proper UTF-8.
[gnumeric.git] / src / file-autoft.c
blob6f794a11c9b6dbed0dd41a0b0e3b72ee4de7d413
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * file-autoft.c : Retrieve available autoformat templates/categories
5 * Copyright (C) Almer. S. Tigelaar.
6 * E-mail: almer1@dds.nl or almer-t@bigfoot.com
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <https://www.gnu.org/licenses/>.
22 #include <gnumeric-config.h>
23 #include <glib/gi18n-lib.h>
24 #include "gnumeric.h"
25 #include "file-autoft.h"
27 #include "gutils.h"
28 #include "workbook-control.h"
29 #include "format-template.h"
30 #include "gnumeric-conf.h"
32 #include <gsf/gsf-impl-utils.h>
33 #include <goffice/goffice.h>
35 #include <sys/types.h>
36 #include <string.h>
37 #include <unistd.h>
39 #define CXML2C(s) ((char const *)(s))
41 static gint
42 gnm_ft_category_compare_name_and_dir (gconstpointer a, gconstpointer b)
44 GnmFTCategory const *cat_a = a, *cat_b = b;
45 int res;
47 res = strcmp (cat_a->name, cat_b->name);
48 return res != 0 ? res : strcmp (cat_a->directory, cat_b->directory);
51 static void
52 gnm_ft_category_free (GnmFTCategory *category)
54 g_free (category->directory);
55 g_free (category->name);
56 g_free (category->description);
57 g_free (category);
60 static GSList *
61 gnm_ft_category_get_templates_list (GnmFTCategory *category,
62 GOCmdContext *cc)
64 GSList *templates = NULL;
65 GDir *dir;
66 char const *d_name;
68 if (category == NULL)
69 return NULL;
71 dir = g_dir_open (category->directory, 0, NULL);
72 if (dir == NULL)
73 return NULL;
75 while ((d_name = g_dir_read_name (dir)) != NULL) {
76 gint name_len;
78 name_len = strlen (d_name);
79 if (name_len > 4 && strcmp (d_name + name_len - 4, ".xml") == 0) {
80 gchar *full_entry_name;
81 GnmFT *ft;
83 full_entry_name = g_build_filename (category->directory, d_name, NULL);
84 ft = gnm_ft_new_from_file (full_entry_name, cc);
85 if (ft == NULL) {
86 g_warning (_("Invalid template file: %s"), full_entry_name);
87 } else {
88 ft->category = category;
89 templates = g_slist_prepend (templates, ft);
91 g_free (full_entry_name);
95 g_dir_close (dir);
97 return g_slist_sort (templates, gnm_ft_compare_name);
101 * gnm_ft_xml_read_category :
102 * Open an XML file and read a GnmFTCategory
104 static GnmFTCategory *
105 gnm_ft_xml_read_category (char const *dir_name)
107 gchar *file_name;
108 xmlDocPtr doc;
109 xmlNodePtr node;
110 GnmFTCategory *category = NULL;
112 g_return_val_if_fail (dir_name != NULL, NULL);
114 file_name = g_build_filename (dir_name, ".category", NULL);
115 doc = xmlParseFile (file_name);
116 if (doc != NULL && doc->xmlRootNode != NULL
117 && xmlSearchNsByHref (doc, doc->xmlRootNode, (xmlChar *)"http://www.gnome.org/gnumeric/format-template-category/v1") != NULL
118 && strcmp (CXML2C (doc->xmlRootNode->name), "FormatTemplateCategory") == 0
119 && (node = go_xml_get_child_by_name (doc->xmlRootNode, "Information")) != NULL) {
120 xmlChar *name = xmlGetProp (node, (xmlChar *)"name");
121 if (name != NULL) {
122 xmlChar *description = xmlGetProp (node, (xmlChar *)"description");
123 category = g_new (GnmFTCategory, 1);
124 category->directory = g_strdup (dir_name);
125 category->name = g_strdup ((gchar *)name);
126 category->description = g_strdup ((gchar *)description);
127 category->is_writable = (access (dir_name, W_OK) == 0);
128 if (description != NULL)
129 xmlFree (description);
130 xmlFree (name);
133 xmlFreeDoc (doc);
134 g_free (file_name);
136 return category;
139 static GList *
140 gnm_ft_category_list_get_from_dir_list (GSList *dir_list)
142 GList *categories = NULL;
143 GSList *dir_iterator;
145 g_return_val_if_fail (dir_list != NULL, NULL);
147 for (dir_iterator = dir_list; dir_iterator != NULL; dir_iterator = dir_iterator->next) {
148 gchar *dir_name = dir_iterator->data;
149 GDir *dir;
150 char const *d_name;
152 dir = g_dir_open (dir_name, 0, NULL);
153 if (dir == NULL)
154 continue;
156 while ((d_name = g_dir_read_name (dir)) != NULL) {
157 gchar *full_entry_name;
159 full_entry_name = g_build_filename (dir_name, d_name, NULL);
160 if (d_name[0] != '.' && g_file_test (full_entry_name, G_FILE_TEST_IS_DIR)) {
161 GnmFTCategory *category;
163 category = gnm_ft_xml_read_category (full_entry_name);
164 if (category != NULL) {
165 categories = g_list_prepend (categories, category);
168 g_free (full_entry_name);
171 g_dir_close (dir);
174 return categories;
177 static void
178 gnm_ft_category_list_free (GList *categories)
180 GList *l;
182 g_return_if_fail (categories);
184 for (l = categories; l != NULL; l = l->next) {
185 gnm_ft_category_free ((GnmFTCategory *) l->data);
187 g_list_free (categories);
190 static void
191 add_dir (GSList **pl, const char *dir, const char *base_dir)
193 char *dirc = NULL;
194 if (g_path_is_absolute (dir))
195 dirc = g_strdup (dir);
196 else
197 dirc = g_build_filename (base_dir, dir, NULL);
198 *pl = g_slist_prepend (*pl, dirc);
202 * gnm_ft_category_group_list_get:
204 * Returns: (element-type GnmFTCategoryGroup) (transfer full):
205 * the list of #GnmFTCategoryGroup which should be freed using
206 * gnm_ft_category_group_list_free().
208 GList *
209 gnm_ft_category_group_list_get (void)
211 GList *category_groups = NULL;
212 GSList *dir_list = NULL, *sl;
213 GList *categories, *l;
214 GnmFTCategoryGroup *current_group;
216 add_dir (&dir_list,
217 gnm_conf_get_autoformat_sys_dir (),
218 gnm_sys_data_dir ());
219 add_dir (&dir_list,
220 gnm_conf_get_autoformat_usr_dir (),
221 gnm_usr_dir (FALSE));
222 add_dir (&dir_list,
223 gnm_conf_get_autoformat_usr_dir (),
224 gnm_usr_dir (TRUE));
226 for (sl = gnm_conf_get_autoformat_extra_dirs (); sl; sl = sl->next) {
227 const char *dir = sl->data;
228 add_dir (&dir_list, dir, g_get_home_dir ());
230 dir_list = g_slist_reverse (dir_list);
231 categories = gnm_ft_category_list_get_from_dir_list (dir_list);
232 g_slist_free_full (dir_list, g_free);
234 categories = g_list_sort (categories, gnm_ft_category_compare_name_and_dir);
236 current_group = NULL;
237 for (l = categories; l != NULL; l = l->next) {
238 GnmFTCategory *category = l->data;
239 if (current_group == NULL || strcmp (current_group->name, category->name) != 0) {
240 if (current_group != NULL) {
241 category_groups = g_list_prepend (category_groups, current_group);
243 current_group = g_new (GnmFTCategoryGroup, 1);
244 current_group->categories = g_list_append (NULL, category);
245 current_group->name = g_strdup (category->name);
246 current_group->description = g_strdup (category->description);
247 } else {
248 current_group->categories = g_list_prepend (current_group->categories, category);
251 if (current_group != NULL)
252 category_groups = g_list_prepend (category_groups, current_group);
254 g_list_free (categories);
256 return category_groups;
261 * gnm_ft_category_group_list_free:
262 * @category_groups: (element-type GnmFTCategoryGroup): the list to free.
265 void
266 gnm_ft_category_group_list_free (GList *groups)
268 GList *ptr;
270 for (ptr = groups; ptr != NULL; ptr = ptr->next) {
271 GnmFTCategoryGroup *group = ptr->data;
272 g_free (group->name);
273 g_free (group->description);
274 gnm_ft_category_list_free (group->categories);
275 g_free (group);
277 g_list_free (groups);
281 * gnm_ft_category_group_get_templates_list:
282 * @category_group: #GnmFTCategoryGroup
283 * @context: #GOCmdContext
285 * Returns: (element-type GnmFT) (transfer container):
287 GSList *
288 gnm_ft_category_group_get_templates_list (GnmFTCategoryGroup *category_group,
289 GOCmdContext *cc)
291 GSList *templates = NULL;
292 GList *l;
294 for (l = category_group->categories; l != NULL; l = l->next)
295 templates = g_slist_concat (templates,
296 gnm_ft_category_get_templates_list (l->data, cc));
298 return g_slist_sort (templates, gnm_ft_compare_name);
302 gnm_ft_category_group_cmp (gconstpointer a, gconstpointer b)
304 GnmFTCategoryGroup const *group_a = a;
305 GnmFTCategoryGroup const *group_b = b;
306 return g_utf8_collate (_(group_a->name), _(group_b->name));