?? xdgmime.c
字號:
/* -*- mode: C; c-file-style: "gnu" -*- *//* xdgmime.c: XDG Mime Spec mime resolver. Based on version 0.11 of the spec. * * More info can be found at http://www.freedesktop.org/standards/ * * Copyright (C) 2003,2004 Red Hat, Inc. * Copyright (C) 2003,2004 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 "xdgmime.h"#include "xdgmimeint.h"#include "xdgmimeglob.h"#include "xdgmimemagic.h"#include "xdgmimealias.h"#include "xdgmimeparent.h"#include "xdgmimecache.h"#include <stdio.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/time.h>#include <unistd.h>#include <assert.h>typedef struct XdgDirTimeList XdgDirTimeList;typedef struct XdgCallbackList XdgCallbackList;static int need_reread = TRUE;static time_t last_stat_time = 0;static XdgGlobHash *global_hash = NULL;static XdgMimeMagic *global_magic = NULL;static XdgAliasList *alias_list = NULL;static XdgParentList *parent_list = NULL;static XdgDirTimeList *dir_time_list = NULL;static XdgCallbackList *callback_list = NULL;XdgMimeCache **caches = NULL;int n_caches = 0;const char *xdg_mime_type_unknown = "application/octet-stream";enum{ XDG_CHECKED_UNCHECKED, XDG_CHECKED_VALID, XDG_CHECKED_INVALID};struct XdgDirTimeList{ time_t mtime; char *directory_name; int checked; XdgDirTimeList *next;};struct XdgCallbackList{ XdgCallbackList *next; XdgCallbackList *prev; int callback_id; XdgMimeCallback callback; void *data; XdgMimeDestroy destroy;};/* Function called by xdg_run_command_on_dirs. If it returns TRUE, further * directories aren't looked at */typedef int (*XdgDirectoryFunc) (const char *directory, void *user_data);static XdgDirTimeList *xdg_dir_time_list_new (void){ XdgDirTimeList *retval; retval = calloc (1, sizeof (XdgDirTimeList)); retval->checked = XDG_CHECKED_UNCHECKED; return retval;}static voidxdg_dir_time_list_free (XdgDirTimeList *list){ XdgDirTimeList *next; while (list) { next = list->next; free (list->directory_name); free (list); list = next; }}static intxdg_mime_init_from_directory (const char *directory){ char *file_name; struct stat st; XdgDirTimeList *list; assert (directory != NULL); file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1); strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache"); if (stat (file_name, &st) == 0) { XdgMimeCache *cache = _xdg_mime_cache_new_from_file (file_name); if (cache != NULL) { list = xdg_dir_time_list_new (); list->directory_name = file_name; list->mtime = st.st_mtime; list->next = dir_time_list; dir_time_list = list; caches = realloc (caches, sizeof (XdgMimeCache *) * (n_caches + 1)); caches[n_caches] = cache; n_caches++; return FALSE; } } free (file_name); file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1); strcpy (file_name, directory); strcat (file_name, "/mime/globs"); if (stat (file_name, &st) == 0) { _xdg_mime_glob_read_from_file (global_hash, file_name); list = xdg_dir_time_list_new (); list->directory_name = file_name; list->mtime = st.st_mtime; list->next = dir_time_list; dir_time_list = list; } else { free (file_name); } file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1); strcpy (file_name, directory); strcat (file_name, "/mime/magic"); if (stat (file_name, &st) == 0) { _xdg_mime_magic_read_from_file (global_magic, file_name); list = xdg_dir_time_list_new (); list->directory_name = file_name; list->mtime = st.st_mtime; list->next = dir_time_list; dir_time_list = list; } else { free (file_name); } file_name = malloc (strlen (directory) + strlen ("/mime/aliases") + 1); strcpy (file_name, directory); strcat (file_name, "/mime/aliases"); _xdg_mime_alias_read_from_file (alias_list, file_name); free (file_name); file_name = malloc (strlen (directory) + strlen ("/mime/subclasses") + 1); strcpy (file_name, directory); strcat (file_name, "/mime/subclasses"); _xdg_mime_parent_read_from_file (parent_list, file_name); free (file_name); return FALSE; /* Keep processing */}/* Runs a command on all the directories in the search path */static voidxdg_run_command_on_dirs (XdgDirectoryFunc func, void *user_data){ const char *xdg_data_home; const char *xdg_data_dirs; const char *ptr; xdg_data_home = getenv ("XDG_DATA_HOME"); if (xdg_data_home) { if ((func) (xdg_data_home, user_data)) return; } else { const char *home; home = getenv ("HOME"); if (home != NULL) { char *guessed_xdg_home; int stop_processing; guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/") + 1); strcpy (guessed_xdg_home, home); strcat (guessed_xdg_home, "/.local/share/"); stop_processing = (func) (guessed_xdg_home, user_data); free (guessed_xdg_home); if (stop_processing) return; } } xdg_data_dirs = getenv ("XDG_DATA_DIRS"); if (xdg_data_dirs == NULL) xdg_data_dirs = "/usr/local/share/:/usr/share/"; ptr = xdg_data_dirs; while (*ptr != '\000') { const char *end_ptr; char *dir; int len; int stop_processing; end_ptr = ptr; while (*end_ptr != ':' && *end_ptr != '\000') end_ptr ++; if (end_ptr == ptr) { ptr++; continue; } if (*end_ptr == ':') len = end_ptr - ptr; else len = end_ptr - ptr + 1; dir = malloc (len + 1); strncpy (dir, ptr, len); dir[len] = '\0'; stop_processing = (func) (dir, user_data); free (dir); if (stop_processing) return; ptr = end_ptr; }}/* Checks file_path to make sure it has the same mtime as last time it was * checked. If it has a different mtime, or if the file doesn't exist, it * returns FALSE. * * FIXME: This doesn't protect against permission changes. */static intxdg_check_file (const char *file_path){ struct stat st; /* If the file exists */ if (stat (file_path, &st) == 0) { XdgDirTimeList *list; for (list = dir_time_list; list; list = list->next) { if (! strcmp (list->directory_name, file_path) && st.st_mtime == list->mtime) { if (list->checked == XDG_CHECKED_UNCHECKED) list->checked = XDG_CHECKED_VALID; else if (list->checked == XDG_CHECKED_VALID) list->checked = XDG_CHECKED_INVALID; return (list->checked != XDG_CHECKED_VALID); } } return TRUE; } return FALSE;}static intxdg_check_dir (const char *directory, int *invalid_dir_list){ int invalid; char *file_name; assert (directory != NULL); /* Check the globs file */ file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1); strcpy (file_name, directory); strcat (file_name, "/mime/globs"); invalid = xdg_check_file (file_name); free (file_name); if (invalid) { *invalid_dir_list = TRUE; return TRUE; } /* Check the magic file */ file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1); strcpy (file_name, directory); strcat (file_name, "/mime/magic"); invalid = xdg_check_file (file_name); free (file_name); if (invalid) { *invalid_dir_list = TRUE; return TRUE; } /* Check the mime.cache file */ file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1); strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache"); invalid = xdg_check_file (file_name); free (file_name); if (invalid) { *invalid_dir_list = TRUE; return TRUE; } return FALSE; /* Keep processing */}/* Walks through all the mime files stat()ing them to see if they've changed. * Returns TRUE if they have. */static intxdg_check_dirs (void){ XdgDirTimeList *list; int invalid_dir_list = FALSE; for (list = dir_time_list; list; list = list->next) list->checked = XDG_CHECKED_UNCHECKED; xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_check_dir, &invalid_dir_list); if (invalid_dir_list) return TRUE; for (list = dir_time_list; list; list = list->next) { if (list->checked != XDG_CHECKED_VALID) return TRUE; } return FALSE;}/* We want to avoid stat()ing on every single mime call, so we only look for * newer files every 5 seconds. This will return TRUE if we need to reread the * mime data from disk. */static intxdg_check_time_and_dirs (void){ struct timeval tv; time_t current_time; int retval = FALSE; gettimeofday (&tv, NULL); current_time = tv.tv_sec; if (current_time >= last_stat_time + 5) { retval = xdg_check_dirs (); last_stat_time = current_time;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -