📄 xdgmimeglob.c
字号:
/* -*- mode: C; c-file-style: "gnu" -*- *//* xdgmimeglob.c: Private file. Datastructure for storing the globs. * * More info can be found at http://www.freedesktop.org/standards/ * * Copyright (C) 2003 Red Hat, Inc. * Copyright (C) 2003 Jonathan Blandford <jrb@alum.mit.edu> * * Licensed under the Academic Free License version 2.0 * Or under the following terms: * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "xdgmimeglob.h"#include "xdgmimeint.h"#include <stdlib.h>#include <stdio.h>#include <assert.h>#include <string.h>#include <fnmatch.h>#ifndef FALSE#define FALSE (0)#endif#ifndef TRUE#define TRUE (!FALSE)#endiftypedef struct XdgGlobHashNode XdgGlobHashNode;typedef struct XdgGlobList XdgGlobList;struct XdgGlobHashNode{ xdg_unichar_t character; const char *mime_type; XdgGlobHashNode *next; XdgGlobHashNode *child;};struct XdgGlobList{ const char *data; const char *mime_type; XdgGlobList *next;};struct XdgGlobHash{ XdgGlobList *literal_list; XdgGlobHashNode *simple_node; XdgGlobList *full_list;};/* XdgGlobList */static XdgGlobList *_xdg_glob_list_new ( void ){ XdgGlobList * new_element; new_element = calloc ( 1, sizeof ( XdgGlobList ) ); return new_element;}/* Frees glob_list and all of it's children */static void_xdg_glob_list_free ( XdgGlobList *glob_list ){ XdgGlobList * ptr, *next; ptr = glob_list; while ( ptr != NULL ) { next = ptr->next; if ( ptr->data ) free ( ( void * ) ptr->data ); if ( ptr->mime_type ) free ( ( void * ) ptr->mime_type ); free ( ptr ); ptr = next; }}static XdgGlobList *_xdg_glob_list_append ( XdgGlobList *glob_list, void *data, const char *mime_type ){ XdgGlobList * new_element; XdgGlobList *tmp_element; new_element = _xdg_glob_list_new (); new_element->data = data; new_element->mime_type = mime_type; if ( glob_list == NULL ) return new_element; tmp_element = glob_list; while ( tmp_element->next != NULL ) tmp_element = tmp_element->next; tmp_element->next = new_element; return glob_list;}#if 0static XdgGlobList *_xdg_glob_list_prepend ( XdgGlobList *glob_list, void *data, const char *mime_type ){ XdgGlobList * new_element; new_element = _xdg_glob_list_new (); new_element->data = data; new_element->next = glob_list; new_element->mime_type = mime_type; return new_element;}#endif/* XdgGlobHashNode */static XdgGlobHashNode *_xdg_glob_hash_node_new ( void ){ XdgGlobHashNode * glob_hash_node; glob_hash_node = calloc ( 1, sizeof ( XdgGlobHashNode ) ); return glob_hash_node;}#if 0static void_xdg_glob_hash_node_dump ( XdgGlobHashNode *glob_hash_node, int depth ){ int i; for ( i = 0; i < depth; i++ ) printf ( " " ); printf ( "%c", ( char ) glob_hash_node->character ); if ( glob_hash_node->mime_type ) printf ( " - %s\n", glob_hash_node->mime_type ); else printf ( "\n" ); if ( glob_hash_node->child ) _xdg_glob_hash_node_dump ( glob_hash_node->child, depth + 1 ); if ( glob_hash_node->next ) _xdg_glob_hash_node_dump ( glob_hash_node->next, depth );}#endifstatic XdgGlobHashNode *_xdg_glob_hash_insert_text ( XdgGlobHashNode *glob_hash_node, const char *text, const char *mime_type ){ XdgGlobHashNode * node; xdg_unichar_t character; character = _xdg_utf8_to_ucs4 ( text ); if ( ( glob_hash_node == NULL ) || ( character < glob_hash_node->character ) ) { node = _xdg_glob_hash_node_new (); node->character = character; node->next = glob_hash_node; glob_hash_node = node; } else if ( character == glob_hash_node->character ) { node = glob_hash_node; } else { XdgGlobHashNode *prev_node; int found_node = FALSE; /* Look for the first character of text in glob_hash_node, and insert it if we * have to.*/ prev_node = glob_hash_node; node = prev_node->next; while ( node != NULL ) { if ( character < node->character ) { node = _xdg_glob_hash_node_new (); node->character = character; node->next = prev_node->next; prev_node->next = node; found_node = TRUE; break; } else if ( character == node->character ) { found_node = TRUE; break; } prev_node = node; node = node->next; } if ( ! found_node ) { node = _xdg_glob_hash_node_new (); node->character = character; node->next = prev_node->next; prev_node->next = node; } } text = _xdg_utf8_next_char ( text ); if ( *text == '\000' ) { if ( node->mime_type ) { if ( strcmp ( node->mime_type, mime_type ) ) { XdgGlobHashNode * child; int found_node = FALSE; child = node->child; while ( child && child->character == '\0' ) { if ( strcmp ( child->mime_type, mime_type ) == 0 ) { found_node = TRUE; break; } child = child->next; } if ( !found_node ) { child = _xdg_glob_hash_node_new (); child->character = '\000'; child->mime_type = strdup( mime_type ); child->child = NULL; child->next = node->child; node->child = child; } } } else { node->mime_type = strdup( mime_type ); } } else { node->child = _xdg_glob_hash_insert_text ( node->child, text, mime_type ); } return glob_hash_node;}static int_xdg_glob_hash_node_lookup_file_name ( XdgGlobHashNode *glob_hash_node, const char *file_name, int ignore_case, const char *mime_types[], int n_mime_types ){ int n; XdgGlobHashNode *node; xdg_unichar_t character; if ( glob_hash_node == NULL ) return 0; character = _xdg_utf8_to_ucs4 ( file_name ); if ( ignore_case ) character = _xdg_ucs4_to_lower( character ); for ( node = glob_hash_node; node && character >= node->character; node = node->next ) { if ( character == node->character ) { file_name = _xdg_utf8_next_char ( file_name ); if ( *file_name == '\000' ) { n = 0; mime_types[ n++ ] = node->mime_type; node = node->child; while ( n < n_mime_types && node && node->character == 0 ) { mime_types[ n++ ] = node->mime_type; node = node->next; } } else { n = _xdg_glob_hash_node_lookup_file_name ( node->child, file_name, ignore_case, mime_types, n_mime_types ); } return n; } } return 0;}int_xdg_glob_hash_lookup_file_name ( XdgGlobHash *glob_hash, const char *file_name, const char *mime_types[], int n_mime_types ){ XdgGlobList * list; const char *ptr; char stopchars[ 128 ]; int i, n; XdgGlobHashNode *node; /* First, check the literals */ assert ( file_name != NULL && n_mime_types > 0 ); for ( list = glob_hash->literal_list; list; list = list->next ) { if ( strcmp ( ( const char * ) list->data, file_name ) == 0 ) { mime_types[ 0 ] = list->mime_type; return 1; } } i = 0; for ( node = glob_hash->simple_node; node; node = node->next ) { if ( node->character < 128 ) stopchars[ i++ ] = ( char ) node->character; } stopchars[ i ] = '\0'; ptr = strpbrk ( file_name, stopchars ); while ( ptr ) { n = _xdg_glob_hash_node_lookup_file_name ( glob_hash->simple_node, ptr, FALSE, mime_types, n_mime_types ); if ( n > 0 ) return n; n = _xdg_glob_hash_node_lookup_file_name ( glob_hash->simple_node, ptr, TRUE, mime_types, n_mime_types ); if ( n > 0 ) return n; ptr = strpbrk ( ptr + 1, stopchars ); } /* FIXME: Not UTF-8 safe */ n = 0; for ( list = glob_hash->full_list; list && n < n_mime_types; list = list->next ) { if ( fnmatch ( ( const char * ) list->data, file_name, 0 ) == 0 ) mime_types[ n++ ] = list->mime_type; } return n;}/* XdgGlobHash */XdgGlobHash *_xdg_glob_hash_new ( void ){ XdgGlobHash * glob_hash; glob_hash = calloc ( 1, sizeof ( XdgGlobHash ) ); return glob_hash;}static void_xdg_glob_hash_free_nodes ( XdgGlobHashNode *node ){ if ( node ) { if ( node->child ) _xdg_glob_hash_free_nodes ( node->child ); if ( node->next ) _xdg_glob_hash_free_nodes ( node->next ); if ( node->mime_type ) free ( ( void * ) node->mime_type ); free ( node ); }}void_xdg_glob_hash_free ( XdgGlobHash *glob_hash ){ _xdg_glob_list_free ( glob_hash->literal_list ); _xdg_glob_list_free ( glob_hash->full_list ); _xdg_glob_hash_free_nodes ( glob_hash->simple_node ); free ( glob_hash );}XdgGlobType_xdg_glob_determine_type ( const char *glob ){ const char * ptr; int maybe_in_simple_glob = FALSE; int first_char = TRUE; ptr = glob; while ( *ptr != '\000' ) { if ( *ptr == '*' && first_char ) maybe_in_simple_glob = TRUE; else if ( *ptr == '\\' || *ptr == '[' || *ptr == '?' || *ptr == '*' ) return XDG_GLOB_FULL; first_char = FALSE; ptr = _xdg_utf8_next_char ( ptr ); } if ( maybe_in_simple_glob ) return XDG_GLOB_SIMPLE; else return XDG_GLOB_LITERAL;}/* glob must be valid UTF-8 */void_xdg_glob_hash_append_glob ( XdgGlobHash *glob_hash, const char *glob, const char *mime_type ){ XdgGlobType type; assert ( glob_hash != NULL ); assert ( glob != NULL ); type = _xdg_glob_determine_type ( glob ); switch ( type ) { case XDG_GLOB_LITERAL: glob_hash->literal_list = _xdg_glob_list_append ( glob_hash->literal_list, strdup ( glob ), strdup ( mime_type ) ); break; case XDG_GLOB_SIMPLE: glob_hash->simple_node = _xdg_glob_hash_insert_text ( glob_hash->simple_node, glob + 1, mime_type ); break; case XDG_GLOB_FULL: glob_hash->full_list = _xdg_glob_list_append ( glob_hash->full_list, strdup ( glob ), strdup ( mime_type ) ); break; }}#if 0void_xdg_glob_hash_dump ( XdgGlobHash *glob_hash ){ XdgGlobList * list; printf ( "LITERAL STRINGS\n" ); if ( glob_hash->literal_list == NULL ) { printf ( " None\n" ); } else { for ( list = glob_hash->literal_list; list; list = list->next ) printf ( " %s - %s\n", ( char * ) list->data, list->mime_type ); } printf ( "\nSIMPLE GLOBS\n" ); _xdg_glob_hash_node_dump ( glob_hash->simple_node, 4 ); printf ( "\nFULL GLOBS\n" ); if ( glob_hash->full_list == NULL ) { printf ( " None\n" ); } else { for ( list = glob_hash->full_list; list; list = list->next ) printf ( " %s - %s\n", ( char * ) list->data, list->mime_type ); }}#endifvoid_xdg_mime_glob_read_from_file ( XdgGlobHash *glob_hash, const char *file_name ){ FILE * glob_file; char line[ 255 ]; glob_file = fopen ( file_name, "r" ); if ( glob_file == NULL ) return ; /* FIXME: Not UTF-8 safe. Doesn't work if lines are greater than 255 chars. * Blah */ while ( fgets ( line, 255, glob_file ) != NULL ) { char * colon; if ( line[ 0 ] == '#' ) continue; colon = strchr ( line, ':' ); if ( colon == NULL ) continue; *( colon++ ) = '\000'; colon[ strlen ( colon ) - 1 ] = '\000'; _xdg_glob_hash_append_glob ( glob_hash, colon, line ); } fclose ( glob_file ); /* Add some missing but frequently seen globs */ glob_hash->simple_node = _xdg_glob_hash_insert_text ( glob_hash->simple_node, ".dll", "application/x-ms-dos-executable" ); glob_hash->simple_node = _xdg_glob_hash_insert_text ( glob_hash->simple_node, ".ini", XDG_MIME_TYPE_PLAIN_TEXT );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -