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.
31 #include "xdgmimeglob.h"
32 #include "xdgmimeint.h"
47 typedef struct XdgGlobHashNode XdgGlobHashNode
;
48 typedef struct XdgGlobList XdgGlobList
;
50 struct XdgGlobHashNode
52 xdg_unichar_t character
;
53 const char *mime_type
;
54 XdgGlobHashNode
*next
;
55 XdgGlobHashNode
*child
;
60 const char *mime_type
;
66 XdgGlobList
*literal_list
;
67 XdgGlobHashNode
*simple_node
;
68 XdgGlobList
*full_list
;
75 _xdg_glob_list_new (void)
77 XdgGlobList
*new_element
;
79 new_element
= calloc (1, sizeof (XdgGlobList
));
84 /* Frees glob_list and all of it's children */
86 _xdg_glob_list_free (XdgGlobList
*glob_list
)
88 XdgGlobList
*ptr
, *next
;
97 free ((void *) ptr
->data
);
99 free ((void *) ptr
->mime_type
);
107 _xdg_glob_list_append (XdgGlobList
*glob_list
,
109 const char *mime_type
)
111 XdgGlobList
*new_element
;
112 XdgGlobList
*tmp_element
;
114 new_element
= _xdg_glob_list_new ();
115 new_element
->data
= data
;
116 new_element
->mime_type
= mime_type
;
117 if (glob_list
== NULL
)
120 tmp_element
= glob_list
;
121 while (tmp_element
->next
!= NULL
)
122 tmp_element
= tmp_element
->next
;
124 tmp_element
->next
= new_element
;
131 _xdg_glob_list_prepend (XdgGlobList
*glob_list
,
133 const char *mime_type
)
135 XdgGlobList
*new_element
;
137 new_element
= _xdg_glob_list_new ();
138 new_element
->data
= data
;
139 new_element
->next
= glob_list
;
140 new_element
->mime_type
= mime_type
;
149 static XdgGlobHashNode
*
150 _xdg_glob_hash_node_new (void)
152 XdgGlobHashNode
*glob_hash_node
;
154 glob_hash_node
= calloc (1, sizeof (XdgGlobHashNode
));
156 return glob_hash_node
;
160 _xdg_glob_hash_node_dump (XdgGlobHashNode
*glob_hash_node
,
164 for (i
= 0; i
< depth
; i
++)
167 printf ("%c", (char)glob_hash_node
->character
);
168 if (glob_hash_node
->mime_type
)
169 printf (" - %s\n", glob_hash_node
->mime_type
);
172 if (glob_hash_node
->child
)
173 _xdg_glob_hash_node_dump (glob_hash_node
->child
, depth
+ 1);
174 if (glob_hash_node
->next
)
175 _xdg_glob_hash_node_dump (glob_hash_node
->next
, depth
);
178 static XdgGlobHashNode
*
179 _xdg_glob_hash_insert_text (XdgGlobHashNode
*glob_hash_node
,
181 const char *mime_type
)
183 XdgGlobHashNode
*node
;
184 xdg_unichar_t character
;
186 character
= _xdg_utf8_to_ucs4 (text
);
188 if ((glob_hash_node
== NULL
) ||
189 (character
< glob_hash_node
->character
))
191 node
= _xdg_glob_hash_node_new ();
192 node
->character
= character
;
193 node
->next
= glob_hash_node
;
194 glob_hash_node
= node
;
196 else if (character
== glob_hash_node
->character
)
198 node
= glob_hash_node
;
202 XdgGlobHashNode
*prev_node
;
203 int found_node
= FALSE
;
205 /* Look for the first character of text in glob_hash_node, and insert it if we
207 prev_node
= glob_hash_node
;
208 node
= prev_node
->next
;
212 if (character
< node
->character
)
214 node
= _xdg_glob_hash_node_new ();
215 node
->character
= character
;
216 node
->next
= prev_node
->next
;
217 prev_node
->next
= node
;
222 else if (character
== node
->character
)
233 node
= _xdg_glob_hash_node_new ();
234 node
->character
= character
;
235 node
->next
= prev_node
->next
;
236 prev_node
->next
= node
;
240 text
= _xdg_utf8_next_char (text
);
243 node
->mime_type
= mime_type
;
247 node
->child
= _xdg_glob_hash_insert_text (node
->child
, text
, mime_type
);
249 return glob_hash_node
;
253 _xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode
*glob_hash_node
,
254 const char *file_name
,
257 XdgGlobHashNode
*node
;
258 xdg_unichar_t character
;
260 if (glob_hash_node
== NULL
)
263 character
= _xdg_utf8_to_ucs4 (file_name
);
265 character
= _xdg_ucs4_to_upper(character
);
267 for (node
= glob_hash_node
;
268 node
&& character
>= (ignore_case
?_xdg_ucs4_to_upper (node
->character
):node
->character
);
271 if (character
== (ignore_case
?_xdg_ucs4_to_upper (node
->character
):node
->character
))
273 file_name
= _xdg_utf8_next_char (file_name
);
274 if (*file_name
== '\000')
275 return node
->mime_type
;
277 return _xdg_glob_hash_node_lookup_file_name (node
->child
,
286 _xdg_glob_hash_lookup_file_name (XdgGlobHash
*glob_hash
,
287 const char *file_name
)
290 const char *mime_type
;
292 /* First, check the literals */
294 assert (file_name
!= NULL
);
296 for (list
= glob_hash
->literal_list
; list
; list
= list
->next
)
297 if (strcmp ((const char *)list
->data
, file_name
) == 0)
298 return list
->mime_type
;
300 for (ptr
= file_name
; *ptr
!= '\000'; ptr
= _xdg_utf8_next_char (ptr
))
304 mime_type
= (_xdg_glob_hash_node_lookup_file_name (glob_hash
->simple_node
, ptr
, FALSE
));
305 if (mime_type
!= NULL
)
310 for (ptr
= file_name
; *ptr
!= '\000'; ptr
= _xdg_utf8_next_char (ptr
))
314 mime_type
= (_xdg_glob_hash_node_lookup_file_name (glob_hash
->simple_node
, ptr
, TRUE
));
315 if (mime_type
!= NULL
)
320 /* FIXME: Not UTF-8 safe */
321 for (list
= glob_hash
->full_list
; list
; list
= list
->next
)
322 if (fnmatch ((const char *)list
->data
, file_name
, 0) == 0)
323 return list
->mime_type
;
334 _xdg_glob_hash_new (void)
336 XdgGlobHash
*glob_hash
;
338 glob_hash
= calloc (1, sizeof (XdgGlobHash
));
345 _xdg_glob_hash_free_nodes (XdgGlobHashNode
*node
)
350 _xdg_glob_hash_free_nodes (node
->child
);
352 _xdg_glob_hash_free_nodes (node
->next
);
358 _xdg_glob_hash_free (XdgGlobHash
*glob_hash
)
360 _xdg_glob_list_free (glob_hash
->literal_list
);
361 _xdg_glob_list_free (glob_hash
->full_list
);
362 _xdg_glob_hash_free_nodes (glob_hash
->simple_node
);
367 _xdg_glob_determine_type (const char *glob
)
370 int maybe_in_simple_glob
= FALSE
;
371 int first_char
= TRUE
;
375 while (*ptr
!= '\000')
377 if (*ptr
== '*' && first_char
)
378 maybe_in_simple_glob
= TRUE
;
379 else if (*ptr
== '\\' || *ptr
== '[' || *ptr
== '?' || *ptr
== '*')
380 return XDG_GLOB_FULL
;
383 ptr
= _xdg_utf8_next_char (ptr
);
385 if (maybe_in_simple_glob
)
386 return XDG_GLOB_SIMPLE
;
388 return XDG_GLOB_LITERAL
;
391 /* glob must be valid UTF-8 */
393 _xdg_glob_hash_append_glob (XdgGlobHash
*glob_hash
,
395 const char *mime_type
)
399 assert (glob_hash
!= NULL
);
400 assert (glob
!= NULL
);
402 type
= _xdg_glob_determine_type (glob
);
406 case XDG_GLOB_LITERAL
:
407 glob_hash
->literal_list
= _xdg_glob_list_append (glob_hash
->literal_list
, strdup (glob
), strdup (mime_type
));
409 case XDG_GLOB_SIMPLE
:
410 glob_hash
->simple_node
= _xdg_glob_hash_insert_text (glob_hash
->simple_node
, glob
+ 1, strdup (mime_type
));
413 glob_hash
->full_list
= _xdg_glob_list_append (glob_hash
->full_list
, strdup (glob
), strdup (mime_type
));
419 _xdg_glob_hash_dump (XdgGlobHash
*glob_hash
)
422 printf ("LITERAL STRINGS\n");
423 if (glob_hash
->literal_list
== NULL
)
429 for (list
= glob_hash
->literal_list
; list
; list
= list
->next
)
430 printf (" %s - %s\n", (char *)list
->data
, list
->mime_type
);
432 printf ("\nSIMPLE GLOBS\n");
433 _xdg_glob_hash_node_dump (glob_hash
->simple_node
, 4);
435 printf ("\nFULL GLOBS\n");
436 if (glob_hash
->full_list
== NULL
)
442 for (list
= glob_hash
->full_list
; list
; list
= list
->next
)
443 printf (" %s - %s\n", (char *)list
->data
, list
->mime_type
);
449 _xdg_mime_glob_read_from_file (XdgGlobHash
*glob_hash
,
450 const char *file_name
)
455 glob_file
= fopen (file_name
, "r");
457 if (glob_file
== NULL
)
460 /* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
462 while (fgets (line
, 255, glob_file
) != NULL
)
468 colon
= strchr (line
, ':');
472 colon
[strlen (colon
) -1] = '\000';
473 _xdg_glob_hash_append_glob (glob_hash
, colon
, line
);