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);