1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* xdgmimeglob.c: Private file. Datastructure for storing the globs.
4 * More info can be found at http://www.freedesktop.org/standards/
6 * Copyright (C) 2003 Red Hat, Inc.
7 * Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu>
9 * Licensed under the Academic Free License version 2.0
10 * Or under the following terms:
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the
24 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
29 #include "xdgmimeglob.h"
30 #include "xdgmimeint.h"
45 typedef struct XdgGlobHashNode XdgGlobHashNode;
46 typedef struct XdgGlobList XdgGlobList;
48 struct XdgGlobHashNode
50 xdg_unichar_t character;
51 const char *mime_type;
52 XdgGlobHashNode *next;
53 XdgGlobHashNode *child;
58 const char *mime_type;
64 XdgGlobList *literal_list;
65 XdgGlobHashNode *simple_node;
66 XdgGlobList *full_list;
73 _xdg_glob_list_new (void)
75 XdgGlobList *new_element;
77 new_element = calloc (1, sizeof (XdgGlobList));
82 /* Frees glob_list and all of it's children */
84 _xdg_glob_list_free (XdgGlobList *glob_list)
86 XdgGlobList *ptr, *next;
95 free ((void *) ptr->data);
97 free ((void *) ptr->mime_type);
105 _xdg_glob_list_append (XdgGlobList *glob_list,
107 const char *mime_type)
109 XdgGlobList *new_element;
110 XdgGlobList *tmp_element;
112 new_element = _xdg_glob_list_new ();
113 new_element->data = data;
114 new_element->mime_type = mime_type;
115 if (glob_list == NULL)
118 tmp_element = glob_list;
119 while (tmp_element->next != NULL)
120 tmp_element = tmp_element->next;
122 tmp_element->next = new_element;
129 _xdg_glob_list_prepend (XdgGlobList *glob_list,
131 const char *mime_type)
133 XdgGlobList *new_element;
135 new_element = _xdg_glob_list_new ();
136 new_element->data = data;
137 new_element->next = glob_list;
138 new_element->mime_type = mime_type;
147 static XdgGlobHashNode *
148 _xdg_glob_hash_node_new (void)
150 XdgGlobHashNode *glob_hash_node;
152 glob_hash_node = calloc (1, sizeof (XdgGlobHashNode));
154 return glob_hash_node;
158 _xdg_glob_hash_node_dump (XdgGlobHashNode *glob_hash_node,
162 for (i = 0; i < depth; i++)
165 printf ("%c", (char)glob_hash_node->character);
166 if (glob_hash_node->mime_type)
167 printf (" - %s\n", glob_hash_node->mime_type);
170 if (glob_hash_node->child)
171 _xdg_glob_hash_node_dump (glob_hash_node->child, depth + 1);
172 if (glob_hash_node->next)
173 _xdg_glob_hash_node_dump (glob_hash_node->next, depth);
176 static XdgGlobHashNode *
177 _xdg_glob_hash_insert_text (XdgGlobHashNode *glob_hash_node,
179 const char *mime_type)
181 XdgGlobHashNode *node;
182 xdg_unichar_t character;
184 character = _xdg_utf8_to_ucs4 (text);
186 if ((glob_hash_node == NULL) ||
187 (character < glob_hash_node->character))
189 node = _xdg_glob_hash_node_new ();
190 node->character = character;
191 node->next = glob_hash_node;
192 glob_hash_node = node;
194 else if (character == glob_hash_node->character)
196 node = glob_hash_node;
200 XdgGlobHashNode *prev_node;
201 int found_node = FALSE;
203 /* Look for the first character of text in glob_hash_node, and insert it if we
205 prev_node = glob_hash_node;
206 node = prev_node->next;
210 if (character < node->character)
212 node = _xdg_glob_hash_node_new ();
213 node->character = character;
214 node->next = prev_node->next;
215 prev_node->next = node;
220 else if (character == node->character)
231 node = _xdg_glob_hash_node_new ();
232 node->character = character;
233 node->next = prev_node->next;
234 prev_node->next = node;
238 text = _xdg_utf8_next_char (text);
241 node->mime_type = mime_type;
245 node->child = _xdg_glob_hash_insert_text (node->child, text, mime_type);
247 return glob_hash_node;
251 _xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode *glob_hash_node,
252 const char *file_name,
255 XdgGlobHashNode *node;
256 xdg_unichar_t character;
258 if (glob_hash_node == NULL)
261 character = _xdg_utf8_to_ucs4 (file_name);
263 character = _xdg_ucs4_to_upper(character);
265 for (node = glob_hash_node;
266 node && character >= (ignore_case?_xdg_ucs4_to_upper (node->character):node->character);
269 if (character == (ignore_case?_xdg_ucs4_to_upper (node->character):node->character))
271 file_name = _xdg_utf8_next_char (file_name);
272 if (*file_name == '\000')
273 return node->mime_type;
275 return _xdg_glob_hash_node_lookup_file_name (node->child,
284 _xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
285 const char *file_name)
288 const char *mime_type;
290 /* First, check the literals */
292 assert (file_name != NULL);
294 for (list = glob_hash->literal_list; list; list = list->next)
295 if (strcmp ((const char *)list->data, file_name) == 0)
296 return list->mime_type;
298 for (ptr = file_name; *ptr != '\000'; ptr = _xdg_utf8_next_char (ptr))
302 mime_type = (_xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, ptr, FALSE));
303 if (mime_type != NULL)
308 for (ptr = file_name; *ptr != '\000'; ptr = _xdg_utf8_next_char (ptr))
312 mime_type = (_xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, ptr, TRUE));
313 if (mime_type != NULL)
318 /* FIXME: Not UTF-8 safe */
319 for (list = glob_hash->full_list; list; list = list->next)
320 if (fnmatch ((const char *)list->data, file_name, 0) == 0)
321 return list->mime_type;
332 _xdg_glob_hash_new (void)
334 XdgGlobHash *glob_hash;
336 glob_hash = calloc (1, sizeof (XdgGlobHash));
343 _xdg_glob_hash_free_nodes (XdgGlobHashNode *node)
348 _xdg_glob_hash_free_nodes (node->child);
350 _xdg_glob_hash_free_nodes (node->next);
356 _xdg_glob_hash_free (XdgGlobHash *glob_hash)
358 _xdg_glob_list_free (glob_hash->literal_list);
359 _xdg_glob_list_free (glob_hash->full_list);
360 _xdg_glob_hash_free_nodes (glob_hash->simple_node);
365 _xdg_glob_determine_type (const char *glob)
368 int maybe_in_simple_glob = FALSE;
369 int first_char = TRUE;
373 while (*ptr != '\000')
375 if (*ptr == '*' && first_char)
376 maybe_in_simple_glob = TRUE;
377 else if (*ptr == '\\' || *ptr == '[' || *ptr == '?' || *ptr == '*')
378 return XDG_GLOB_FULL;
381 ptr = _xdg_utf8_next_char (ptr);
383 if (maybe_in_simple_glob)
384 return XDG_GLOB_SIMPLE;
386 return XDG_GLOB_LITERAL;
389 /* glob must be valid UTF-8 */
391 _xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
393 const char *mime_type)
397 assert (glob_hash != NULL);
398 assert (glob != NULL);
400 type = _xdg_glob_determine_type (glob);
404 case XDG_GLOB_LITERAL:
405 glob_hash->literal_list = _xdg_glob_list_append (glob_hash->literal_list, strdup (glob), strdup (mime_type));
407 case XDG_GLOB_SIMPLE:
408 glob_hash->simple_node = _xdg_glob_hash_insert_text (glob_hash->simple_node, glob + 1, strdup (mime_type));
411 glob_hash->full_list = _xdg_glob_list_append (glob_hash->full_list, strdup (glob), strdup (mime_type));
417 _xdg_glob_hash_dump (XdgGlobHash *glob_hash)
420 printf ("LITERAL STRINGS\n");
421 if (glob_hash->literal_list == NULL)
427 for (list = glob_hash->literal_list; list; list = list->next)
428 printf (" %s - %s\n", (char *)list->data, list->mime_type);
430 printf ("\nSIMPLE GLOBS\n");
431 _xdg_glob_hash_node_dump (glob_hash->simple_node, 4);
433 printf ("\nFULL GLOBS\n");
434 if (glob_hash->full_list == NULL)
440 for (list = glob_hash->full_list; list; list = list->next)
441 printf (" %s - %s\n", (char *)list->data, list->mime_type);
447 _xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
448 const char *file_name)
453 glob_file = fopen (file_name, "r");
455 if (glob_file == NULL)
458 /* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
460 while (fgets (line, 255, glob_file) != NULL)
466 colon = strchr (line, ':');
470 colon[strlen (colon) -1] = '\000';
471 _xdg_glob_hash_append_glob (glob_hash, colon, line);