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.
32 #include "xdgmimeglob.h"
33 #include "xdgmimeint.h"
48 typedef struct XdgGlobHashNode XdgGlobHashNode
;
49 typedef struct XdgGlobList XdgGlobList
;
51 struct XdgGlobHashNode
53 xdg_unichar_t character
;
54 const char *mime_type
;
55 XdgGlobHashNode
*next
;
56 XdgGlobHashNode
*child
;
61 const char *mime_type
;
67 XdgGlobList
*literal_list
;
68 XdgGlobHashNode
*simple_node
;
69 XdgGlobList
*full_list
;
76 _xdg_glob_list_new (void)
78 XdgGlobList
*new_element
;
80 new_element
= calloc (1, sizeof (XdgGlobList
));
85 /* Frees glob_list and all of it's children */
87 _xdg_glob_list_free (XdgGlobList
*glob_list
)
89 XdgGlobList
*ptr
, *next
;
98 free ((void *) ptr
->data
);
100 free ((void *) ptr
->mime_type
);
108 _xdg_glob_list_append (XdgGlobList
*glob_list
,
110 const char *mime_type
)
112 XdgGlobList
*new_element
;
113 XdgGlobList
*tmp_element
;
115 new_element
= _xdg_glob_list_new ();
116 new_element
->data
= data
;
117 new_element
->mime_type
= mime_type
;
118 if (glob_list
== NULL
)
121 tmp_element
= glob_list
;
122 while (tmp_element
->next
!= NULL
)
123 tmp_element
= tmp_element
->next
;
125 tmp_element
->next
= new_element
;
132 _xdg_glob_list_prepend (XdgGlobList
*glob_list
,
134 const char *mime_type
)
136 XdgGlobList
*new_element
;
138 new_element
= _xdg_glob_list_new ();
139 new_element
->data
= data
;
140 new_element
->next
= glob_list
;
141 new_element
->mime_type
= mime_type
;
150 static XdgGlobHashNode
*
151 _xdg_glob_hash_node_new (void)
153 XdgGlobHashNode
*glob_hash_node
;
155 glob_hash_node
= calloc (1, sizeof (XdgGlobHashNode
));
157 return glob_hash_node
;
161 _xdg_glob_hash_node_dump (XdgGlobHashNode
*glob_hash_node
,
165 for (i
= 0; i
< depth
; i
++)
168 printf ("%c", (char)glob_hash_node
->character
);
169 if (glob_hash_node
->mime_type
)
170 printf (" - %s\n", glob_hash_node
->mime_type
);
173 if (glob_hash_node
->child
)
174 _xdg_glob_hash_node_dump (glob_hash_node
->child
, depth
+ 1);
175 if (glob_hash_node
->next
)
176 _xdg_glob_hash_node_dump (glob_hash_node
->next
, depth
);
179 static XdgGlobHashNode
*
180 _xdg_glob_hash_insert_text (XdgGlobHashNode
*glob_hash_node
,
182 const char *mime_type
)
184 XdgGlobHashNode
*node
;
185 xdg_unichar_t character
;
187 character
= _xdg_utf8_to_ucs4 (text
);
189 if ((glob_hash_node
== NULL
) ||
190 (character
< glob_hash_node
->character
))
192 node
= _xdg_glob_hash_node_new ();
193 node
->character
= character
;
194 node
->next
= glob_hash_node
;
195 glob_hash_node
= node
;
197 else if (character
== glob_hash_node
->character
)
199 node
= glob_hash_node
;
203 XdgGlobHashNode
*prev_node
;
204 int found_node
= FALSE
;
206 /* Look for the first character of text in glob_hash_node, and insert it if we
208 prev_node
= glob_hash_node
;
209 node
= prev_node
->next
;
213 if (character
< node
->character
)
215 node
= _xdg_glob_hash_node_new ();
216 node
->character
= character
;
217 node
->next
= prev_node
->next
;
218 prev_node
->next
= node
;
223 else if (character
== node
->character
)
234 node
= _xdg_glob_hash_node_new ();
235 node
->character
= character
;
236 node
->next
= prev_node
->next
;
237 prev_node
->next
= node
;
241 text
= _xdg_utf8_next_char (text
);
244 free ((void *) node
->mime_type
);
245 node
->mime_type
= mime_type
;
249 node
->child
= _xdg_glob_hash_insert_text (node
->child
, text
, mime_type
);
251 return glob_hash_node
;
255 _xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode
*glob_hash_node
,
256 const char *file_name
,
259 XdgGlobHashNode
*node
;
260 xdg_unichar_t character
;
262 if (glob_hash_node
== NULL
)
265 character
= _xdg_utf8_to_ucs4 (file_name
);
267 character
= _xdg_ucs4_to_lower(character
);
269 for (node
= glob_hash_node
; node
&& character
>= node
->character
; node
= node
->next
)
271 if (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
;
294 XdgGlobHashNode
*node
;
296 /* First, check the literals */
298 assert (file_name
!= NULL
);
300 for (list
= glob_hash
->literal_list
; list
; list
= list
->next
)
301 if (strcmp ((const char *)list
->data
, file_name
) == 0)
302 return list
->mime_type
;
305 for (node
= glob_hash
->simple_node
; node
; node
= node
->next
)
307 if (node
->character
< 128)
308 stopchars
[i
++] = (char)node
->character
;
312 ptr
= strpbrk (file_name
, stopchars
);
315 mime_type
= (_xdg_glob_hash_node_lookup_file_name (glob_hash
->simple_node
, ptr
, FALSE
));
316 if (mime_type
!= NULL
)
319 mime_type
= (_xdg_glob_hash_node_lookup_file_name (glob_hash
->simple_node
, ptr
, TRUE
));
320 if (mime_type
!= NULL
)
323 ptr
= strpbrk (ptr
+ 1, stopchars
);
326 /* FIXME: Not UTF-8 safe */
327 for (list
= glob_hash
->full_list
; list
; list
= list
->next
)
328 if (fnmatch ((const char *)list
->data
, file_name
, 0) == 0)
329 return list
->mime_type
;
340 _xdg_glob_hash_new (void)
342 XdgGlobHash
*glob_hash
;
344 glob_hash
= calloc (1, sizeof (XdgGlobHash
));
351 _xdg_glob_hash_free_nodes (XdgGlobHashNode
*node
)
356 _xdg_glob_hash_free_nodes (node
->child
);
358 _xdg_glob_hash_free_nodes (node
->next
);
360 free ((void *) node
->mime_type
);
366 _xdg_glob_hash_free (XdgGlobHash
*glob_hash
)
368 _xdg_glob_list_free (glob_hash
->literal_list
);
369 _xdg_glob_list_free (glob_hash
->full_list
);
370 _xdg_glob_hash_free_nodes (glob_hash
->simple_node
);
375 _xdg_glob_determine_type (const char *glob
)
378 int maybe_in_simple_glob
= FALSE
;
379 int first_char
= TRUE
;
383 while (*ptr
!= '\000')
385 if (*ptr
== '*' && first_char
)
386 maybe_in_simple_glob
= TRUE
;
387 else if (*ptr
== '\\' || *ptr
== '[' || *ptr
== '?' || *ptr
== '*')
388 return XDG_GLOB_FULL
;
391 ptr
= _xdg_utf8_next_char (ptr
);
393 if (maybe_in_simple_glob
)
394 return XDG_GLOB_SIMPLE
;
396 return XDG_GLOB_LITERAL
;
399 /* glob must be valid UTF-8 */
401 _xdg_glob_hash_append_glob (XdgGlobHash
*glob_hash
,
403 const char *mime_type
)
407 assert (glob_hash
!= NULL
);
408 assert (glob
!= NULL
);
410 type
= _xdg_glob_determine_type (glob
);
414 case XDG_GLOB_LITERAL
:
415 glob_hash
->literal_list
= _xdg_glob_list_append (glob_hash
->literal_list
, strdup (glob
), strdup (mime_type
));
417 case XDG_GLOB_SIMPLE
:
418 glob_hash
->simple_node
= _xdg_glob_hash_insert_text (glob_hash
->simple_node
, glob
+ 1, strdup (mime_type
));
421 glob_hash
->full_list
= _xdg_glob_list_append (glob_hash
->full_list
, strdup (glob
), strdup (mime_type
));
427 _xdg_glob_hash_dump (XdgGlobHash
*glob_hash
)
430 printf ("LITERAL STRINGS\n");
431 if (glob_hash
->literal_list
== NULL
)
437 for (list
= glob_hash
->literal_list
; list
; list
= list
->next
)
438 printf (" %s - %s\n", (char *)list
->data
, list
->mime_type
);
440 printf ("\nSIMPLE GLOBS\n");
441 _xdg_glob_hash_node_dump (glob_hash
->simple_node
, 4);
443 printf ("\nFULL GLOBS\n");
444 if (glob_hash
->full_list
== NULL
)
450 for (list
= glob_hash
->full_list
; list
; list
= list
->next
)
451 printf (" %s - %s\n", (char *)list
->data
, list
->mime_type
);
457 _xdg_mime_glob_read_from_file (XdgGlobHash
*glob_hash
,
458 const char *file_name
)
463 glob_file
= fopen (file_name
, "r");
465 if (glob_file
== NULL
)
468 /* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
470 while (fgets (line
, 255, glob_file
) != NULL
)
476 colon
= strchr (line
, ':');
480 colon
[strlen (colon
) -1] = '\000';
481 _xdg_glob_hash_append_glob (glob_hash
, colon
, line
);