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
);
246 if (strcmp (node
->mime_type
, mime_type
))
248 XdgGlobHashNode
*child
;
249 int found_node
= FALSE
;
252 while (child
&& child
->character
== '\0')
254 if (strcmp (child
->mime_type
, mime_type
) == 0)
264 child
= _xdg_glob_hash_node_new ();
265 child
->character
= '\000';
266 child
->mime_type
= strdup (mime_type
);
268 child
->next
= node
->child
;
275 node
->mime_type
= strdup (mime_type
);
280 node
->child
= _xdg_glob_hash_insert_text (node
->child
, text
, mime_type
);
282 return glob_hash_node
;
286 _xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode
*glob_hash_node
,
287 const char *file_name
,
289 const char *mime_types
[],
293 XdgGlobHashNode
*node
;
294 xdg_unichar_t character
;
296 if (glob_hash_node
== NULL
)
299 character
= _xdg_utf8_to_ucs4 (file_name
);
301 character
= _xdg_ucs4_to_lower(character
);
303 for (node
= glob_hash_node
; node
&& character
>= node
->character
; node
= node
->next
)
305 if (character
== node
->character
)
307 file_name
= _xdg_utf8_next_char (file_name
);
308 if (*file_name
== '\000')
312 if (node
->mime_type
!= NULL
)
313 mime_types
[n
++] = node
->mime_type
;
316 while (n
< n_mime_types
&& node
&& node
->character
== 0)
318 if (node
->mime_type
!= NULL
)
319 mime_types
[n
++] = node
->mime_type
;
326 n
= _xdg_glob_hash_node_lookup_file_name (node
->child
,
340 _xdg_glob_hash_lookup_file_name (XdgGlobHash
*glob_hash
,
341 const char *file_name
,
342 const char *mime_types
[],
349 XdgGlobHashNode
*node
;
351 /* First, check the literals */
353 assert (file_name
!= NULL
&& n_mime_types
> 0);
355 for (list
= glob_hash
->literal_list
; list
; list
= list
->next
)
357 if (strcmp ((const char *)list
->data
, file_name
) == 0)
359 mime_types
[0] = list
->mime_type
;
365 for (node
= glob_hash
->simple_node
; node
; node
= node
->next
)
367 if (node
->character
< 128)
368 stopchars
[i
++] = (char)node
->character
;
372 ptr
= strpbrk (file_name
, stopchars
);
375 n
= _xdg_glob_hash_node_lookup_file_name (glob_hash
->simple_node
, ptr
, FALSE
,
376 mime_types
, n_mime_types
);
380 n
= _xdg_glob_hash_node_lookup_file_name (glob_hash
->simple_node
, ptr
, TRUE
,
381 mime_types
, n_mime_types
);
385 ptr
= strpbrk (ptr
+ 1, stopchars
);
388 /* FIXME: Not UTF-8 safe */
390 for (list
= glob_hash
->full_list
; list
&& n
< n_mime_types
; list
= list
->next
)
392 if (fnmatch ((const char *)list
->data
, file_name
, 0) == 0)
393 mime_types
[n
++] = list
->mime_type
;
405 _xdg_glob_hash_new (void)
407 XdgGlobHash
*glob_hash
;
409 glob_hash
= calloc (1, sizeof (XdgGlobHash
));
416 _xdg_glob_hash_free_nodes (XdgGlobHashNode
*node
)
421 _xdg_glob_hash_free_nodes (node
->child
);
423 _xdg_glob_hash_free_nodes (node
->next
);
425 free ((void *) node
->mime_type
);
431 _xdg_glob_hash_free (XdgGlobHash
*glob_hash
)
433 _xdg_glob_list_free (glob_hash
->literal_list
);
434 _xdg_glob_list_free (glob_hash
->full_list
);
435 _xdg_glob_hash_free_nodes (glob_hash
->simple_node
);
440 _xdg_glob_determine_type (const char *glob
)
443 int maybe_in_simple_glob
= FALSE
;
444 int first_char
= TRUE
;
448 while (*ptr
!= '\000')
450 if (*ptr
== '*' && first_char
)
451 maybe_in_simple_glob
= TRUE
;
452 else if (*ptr
== '\\' || *ptr
== '[' || *ptr
== '?' || *ptr
== '*')
453 return XDG_GLOB_FULL
;
456 ptr
= _xdg_utf8_next_char (ptr
);
458 if (maybe_in_simple_glob
)
459 return XDG_GLOB_SIMPLE
;
461 return XDG_GLOB_LITERAL
;
464 /* glob must be valid UTF-8 */
466 _xdg_glob_hash_append_glob (XdgGlobHash
*glob_hash
,
468 const char *mime_type
)
472 assert (glob_hash
!= NULL
);
473 assert (glob
!= NULL
);
475 type
= _xdg_glob_determine_type (glob
);
479 case XDG_GLOB_LITERAL
:
480 glob_hash
->literal_list
= _xdg_glob_list_append (glob_hash
->literal_list
, strdup (glob
), strdup (mime_type
));
482 case XDG_GLOB_SIMPLE
:
483 glob_hash
->simple_node
= _xdg_glob_hash_insert_text (glob_hash
->simple_node
, glob
+ 1, mime_type
);
486 glob_hash
->full_list
= _xdg_glob_list_append (glob_hash
->full_list
, strdup (glob
), strdup (mime_type
));
492 _xdg_glob_hash_dump (XdgGlobHash
*glob_hash
)
495 printf ("LITERAL STRINGS\n");
496 if (glob_hash
->literal_list
== NULL
)
502 for (list
= glob_hash
->literal_list
; list
; list
= list
->next
)
503 printf (" %s - %s\n", (char *)list
->data
, list
->mime_type
);
505 printf ("\nSIMPLE GLOBS\n");
506 _xdg_glob_hash_node_dump (glob_hash
->simple_node
, 4);
508 printf ("\nFULL GLOBS\n");
509 if (glob_hash
->full_list
== NULL
)
515 for (list
= glob_hash
->full_list
; list
; list
= list
->next
)
516 printf (" %s - %s\n", (char *)list
->data
, list
->mime_type
);
522 _xdg_mime_glob_read_from_file (XdgGlobHash
*glob_hash
,
523 const char *file_name
)
528 glob_file
= fopen (file_name
, "r");
530 if (glob_file
== NULL
)
533 /* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars.
535 while (fgets (line
, 255, glob_file
) != NULL
)
541 colon
= strchr (line
, ':');
545 colon
[strlen (colon
) -1] = '\000';
546 _xdg_glob_hash_append_glob (glob_hash
, colon
, line
);