📄 ui_fileops.c
字号:
/* * (SLIK) SimpLIstic sKin functions * (C) 2004 John Ellis * * Author: John Ellis * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <pwd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/param.h>#include <dirent.h>#include <utime.h>#include <glib.h>#include <gtk/gtk.h> /* for locale warning dialog */#include "ui_fileops.h"#include "ui_utildlg.h" /* for locale warning dialog *//* *----------------------------------------------------------------------------- * generic file information and manipulation routines (public) *----------------------------------------------------------------------------- */ /* file sorting method (case) */gint file_sort_case_sensitive = FALSE;void print_term(const gchar *text_utf8){ gchar *text_l; text_l = g_locale_from_utf8(text_utf8, -1, NULL, NULL, NULL); printf((text_l) ? text_l : text_utf8); g_free(text_l);}static void encoding_dialog(const gchar *path);static gint encoding_dialog_idle(gpointer data){ gchar *path = data; encoding_dialog(path); g_free(path); return FALSE;}static gint encoding_dialog_delay(gpointer data){ g_idle_add(encoding_dialog_idle, data); return 0;}static void encoding_dialog(const gchar *path){ static gint warned_user = FALSE; GenericDialog *gd; GString *string; const gchar *lc; const gchar *bf; /* check that gtk is initialized (loop is level > 0) */ if (gtk_main_level() == 0) { /* gtk not initialized */ gtk_init_add(encoding_dialog_delay, g_strdup(path)); return; } if (warned_user) return; warned_user = TRUE; lc = getenv("LANG"); bf = getenv("G_BROKEN_FILENAMES"); warned_user = TRUE; string = g_string_new(""); g_string_append(string, "One or more filenames are not encoded with the preferred locale character set.\n"); g_string_append_printf(string, "Operations on, and display of these files with %s may not succeed.\n\n", PACKAGE); g_string_append(string, "If your filenames are not encoded in utf-8, try setting\n"); g_string_append(string, "the environment variable G_BROKEN_FILENAMES=1\n"); g_string_append_printf(string, "It appears G_BROKEN_FILENAMES is %s%s\n\n", (bf) ? "set to " : "not set.", (bf) ? bf : ""); g_string_append_printf(string, "The locale appears to be set to \"%s\"\n(set by the LANG environment variable)\n", (lc) ? lc : "undefined"); if (lc && (strstr(lc, "UTF-8") || strstr(lc, "utf-8"))) { gchar *name; name = g_convert(path, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); string = g_string_append(string, "\nPreferred encoding appears to be UTF-8, however the file:\n"); g_string_append_printf(string, "\"%s\"\n%s encoded in valid UTF-8.\n", (name) ? name : "[name not displayable]", (g_utf8_validate(path, -1, NULL)) ? "is": "is NOT"); g_free(name); } gd = generic_dialog_new("Filename encoding locale mismatch", PACKAGE, "locale warning", NULL, TRUE, NULL, NULL); generic_dialog_add_button(gd, GTK_STOCK_CLOSE, NULL, NULL, TRUE); generic_dialog_add_message(gd, GTK_STOCK_DIALOG_WARNING, "Filename encoding locale mismatch", string->str); gtk_widget_show(gd->dialog); g_string_free(string, TRUE);}gchar *path_to_utf8(const gchar *path){ gchar *utf8; GError *error = NULL; if (!path) return NULL; utf8 = g_filename_to_utf8(path, -1, NULL, NULL, &error); if (error) { printf("Unable to convert filename to UTF-8:\n%s\n%s\n", path, error->message); g_error_free(error); encoding_dialog(path); } if (!utf8) { /* just let it through, but bad things may happen */ utf8 = g_strdup(path); } return utf8;}gchar *path_from_utf8(const gchar *utf8){ gchar *path; GError *error = NULL; if (!utf8) return NULL; path = g_filename_from_utf8(utf8, -1, NULL, NULL, &error); if (error) { printf("Unable to convert filename to locale from UTF-8:\n%s\n%s\n", utf8, error->message); g_error_free(error); } if (!path) { /* if invalid UTF-8, text probaby still in original form, so just copy it */ path = g_strdup(utf8); } return path;}/* first we try the HOME environment var, if that doesn't work, we try getpwuid(). */const gchar *homedir(void){ static gchar *home = NULL; if (!home) { home = path_to_utf8(getenv("HOME")); } if (!home) { struct passwd *pw = getpwuid(getuid()); if (pw) home = path_to_utf8(pw->pw_dir); } return home;}gint stat_utf8(const gchar *s, struct stat *st){ gchar *sl; gint ret; if (!s) return FALSE; sl = path_from_utf8(s); ret = (stat(sl, st) == 0); g_free(sl); return ret;}gint lstat_utf8(const gchar *s, struct stat *st){ gchar *sl; gint ret; if (!s) return FALSE; sl = path_from_utf8(s); ret = (lstat(sl, st) == 0); g_free(sl); return ret;}gint isname(const gchar *s){ struct stat st; return stat_utf8(s, &st);}gint isfile(const gchar *s){ struct stat st; return (stat_utf8(s, &st) && S_ISREG(st.st_mode));}gint isdir(const gchar *s){ struct stat st; return (stat_utf8(s ,&st) && S_ISDIR(st.st_mode));}gint islink(const gchar *s){ struct stat st; return (lstat_utf8(s ,&st) && S_ISLNK(st.st_mode));}gint64 filesize(const gchar *s){ struct stat st; if (!stat_utf8(s, &st)) return 0; return (gint)st.st_size;}time_t filetime(const gchar *s){ struct stat st; if (!stat_utf8(s, &st)) return 0; return st.st_mtime;}gint filetime_set(const gchar *s, time_t tval){ gint ret = FALSE; if (tval > 0) { struct utimbuf ut; gchar *sl; ut.actime = ut.modtime = tval; sl = path_from_utf8(s); ret = (utime(sl, &ut) == 0); g_free(sl); } return ret;}gint access_file(const gchar *s, int mode){ gchar *sl; gint ret; if (!s) return FALSE; sl = path_from_utf8(s); ret = (access(sl, mode) == 0); g_free(sl); return ret;}gint unlink_file(const gchar *s){ gchar *sl; gint ret; if (!s) return FALSE; sl = path_from_utf8(s); ret = (unlink(sl) == 0); g_free(sl); return ret;}gint symlink_utf8(const gchar *source, const gchar *target){ gchar *sl; gchar *tl; gint ret; if (!source || !target) return FALSE; sl = path_from_utf8(source); tl = path_from_utf8(target); ret = (symlink(sl, tl) == 0); g_free(sl); g_free(tl); return ret;}gint mkdir_utf8(const gchar *s, int mode){ gchar *sl; gint ret; if (!s) return FALSE; sl = path_from_utf8(s); ret = (mkdir(sl, mode) == 0); g_free(sl); return ret;}gint rmdir_utf8(const gchar *s){ gchar *sl; gint ret; if (!s) return FALSE; sl = path_from_utf8(s); ret = (rmdir(sl) == 0); g_free(sl); return ret;}gint copy_file_attributes(const gchar *s, const gchar *t, gint perms, gint mtime){ struct stat st; gchar *sl, *tl; gint ret = FALSE; if (!s || !t) return FALSE; sl = path_from_utf8(s); tl = path_from_utf8(t); if (stat(sl, &st) == 0) { struct utimbuf tb; ret = TRUE; /* set the dest file attributes to that of source (ignoring errors) */ if (perms && chown(tl, st.st_uid, st.st_gid) < 0) ret = FALSE; if (perms && chmod(tl, st.st_mode) < 0) ret = FALSE; tb.actime = st.st_atime; tb.modtime = st.st_mtime; if (mtime && utime(tl, &tb) < 0) ret = FALSE; } g_free(sl); g_free(tl); return ret;}/* paths are in filesystem encoding */static gint hard_linked(const gchar *a, const gchar *b){ struct stat sta; struct stat stb; if (stat(a, &sta) != 0 || stat(b, &stb) != 0) return FALSE; return (sta.st_dev == stb.st_dev && sta.st_ino == stb.st_ino);}gint copy_file(const gchar *s, const gchar *t){ FILE *fi = NULL; FILE *fo = NULL; gchar *sl, *tl; gchar buf[4096]; gint b; sl = path_from_utf8(s); tl = path_from_utf8(t); if (hard_linked(sl, tl)) { g_free(sl); g_free(tl); return TRUE; } fi = fopen(sl, "rb"); if (fi) { fo = fopen(tl, "wb"); if (!fo) { fclose(fi); fi = NULL; } } g_free(sl); g_free(tl); if (!fi || !fo) return FALSE; while((b = fread(buf, sizeof(char), 4096, fi)) && b != 0) { if (fwrite(buf, sizeof(char), b, fo) != b) { fclose(fi); fclose(fo); return FALSE; } } fclose(fi); fclose(fo); copy_file_attributes(s, t, TRUE, TRUE); return TRUE;}gint move_file(const gchar *s, const gchar *t){ gchar *sl, *tl; gint ret = TRUE; if (!s || !t) return FALSE; sl = path_from_utf8(s); tl = path_from_utf8(t); if (rename(sl, tl) < 0) { /* this may have failed because moving a file across filesystems was attempted, so try copy and delete instead */ if (copy_file(s, t)) { if (unlink(sl) < 0) { /* err, now we can't delete the source file so return FALSE */ ret = FALSE; } } else { ret = FALSE; } } g_free(sl); g_free(tl); return ret;}gint rename_file(const gchar *s, const gchar *t){ gchar *sl, *tl; gint ret; if (!s || !t) return FALSE; sl = path_from_utf8(s); tl = path_from_utf8(t); ret = (rename(sl, tl) == 0); g_free(sl); g_free(tl); return ret;}gchar *get_current_dir(void){ gchar *pathl; gchar *path8; pathl = g_get_current_dir(); path8 = path_to_utf8(pathl); g_free(pathl); return path8;}gint path_list(const gchar *path, GList **files, GList **dirs){ DIR *dp; struct dirent *dir; struct stat ent_sbuf; GList *f_list = NULL; GList *d_list = NULL; gchar *pathl; if (!path) return FALSE; pathl = path_from_utf8(path); dp = opendir(pathl); if (!dp) { /* dir not found */ g_free(pathl); return FALSE; } /* root dir fix */ if (pathl[0] == '/' && pathl[1] == '\0') { g_free(pathl); pathl = g_strdup(""); } while ((dir = readdir(dp)) != NULL) { /* skip removed files */ if (dir->d_ino > 0) { gchar *name = dir->d_name; gchar *filepath = g_strconcat(pathl, "/", name, NULL); if (stat(filepath, &ent_sbuf) >= 0) { gchar *path8; gchar *name8; name8 = path_to_utf8(name); path8 = g_strconcat(path, "/", name8, NULL); g_free(name8); if (dirs && S_ISDIR(ent_sbuf.st_mode) && !(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) ) { d_list = g_list_prepend(d_list, path8); path8 = NULL; } else if (files && S_ISREG(ent_sbuf.st_mode)) { f_list = g_list_prepend(f_list, path8); path8 = NULL; } g_free(path8); } g_free(filepath); } } closedir(dp); g_free(pathl); if (dirs) *dirs = g_list_reverse(d_list); if (files) *files = g_list_reverse(f_list); return TRUE;}void path_list_free(GList *list){ g_list_foreach(list, (GFunc)g_free, NULL); g_list_free(list);}GList *path_list_copy(GList *list){ GList *new_list = NULL; GList *work; work = list; while (work) { gchar *path; path = work->data; work = work->next; new_list = g_list_prepend(new_list, g_strdup(path)); } return g_list_reverse(new_list);}long checksum_simple(const gchar *path){ gchar *path8; FILE *f; long sum = 0; gint c; path8 = path_from_utf8(path); f = fopen(path8, "r"); g_free(path8); if (!f) return -1; while((c = fgetc(f)) != EOF) { sum += c; } fclose(f); return sum;}gchar *unique_filename(const gchar *path, const gchar *ext, const gchar *divider, gint pad){ gchar *unique; gint n = 1; if (!ext) ext = ""; if (!divider) divider = ""; unique = g_strconcat(path, ext, NULL); while (isname(unique)) { g_free(unique); if (pad) { unique = g_strdup_printf("%s%s%03d%s", path, divider, n, ext); } else { unique = g_strdup_printf("%s%s%d%s", path, divider, n, ext); } n++; if (n > 999) { /* well, we tried */ g_free(unique); return NULL; } } return unique;}gchar *unique_filename_simple(const gchar *path){ gchar *unique; const gchar *name; const gchar *ext; if (!path) return NULL; name = filename_from_path(path); if (!name) return NULL; ext = extension_from_path(name); if (!ext) { unique = unique_filename(path, NULL, "_", TRUE); } else { gchar *base; base = remove_extension_from_path(path); unique = unique_filename(base, ext, "_", TRUE); g_free(base); } return unique;}const gchar *filename_from_path(const gchar *path){ const gchar *base; if (!path) return NULL; base = strrchr(path, '/'); if (base) return base + 1; return path;}gchar *remove_level_from_path(const gchar *path){ gchar *new_path; const gchar *ptr = path; gint p; if (!path) return NULL; p = strlen(path) - 1; if (p < 0) return NULL; while(ptr[p] != '/' && p > 0) p--; if (p == 0 && ptr[p] == '/') p++; new_path = g_strndup(path, (guint)p); return new_path;}gchar *concat_dir_and_file(const gchar *base, const gchar *name){ if (!base || !name) return NULL; if (strcmp(base, "/") == 0) return g_strconcat(base, name, NULL); return g_strconcat(base, "/", name, NULL);}const gchar *extension_from_path(const gchar *path){ if (!path) return NULL; return strrchr(path, '.');}gint file_extension_match(const gchar *path, const gchar *ext){ gint p; gint e; if (!path) return FALSE; if (!ext) return TRUE; p = strlen(path); e = strlen(ext); return (p > e && strncasecmp(path + p - e, ext, e) == 0);}gchar *remove_extension_from_path(const gchar *path){ gchar *new_path; const gchar *ptr = path; gint p; if (!path) return NULL; if (strlen(path) < 2) return g_strdup(path); p = strlen(path) - 1; while(ptr[p] != '.' && p > 0) p--; if (p == 0) p = strlen(path) - 1; new_path = g_strndup(path, (guint)p); return new_path;}void parse_out_relatives(gchar *path){ gint s, t; if (!path) return; s = t = 0; while (path[s] != '\0') { if (path[s] == '/' && path[s+1] == '.' && (path[s+2] == '/' || path[s+2] == '\0') ) { s += 2; } else if (path[s] == '/' && path[s+1] == '.' && path[s+2] == '.' && (path[s+3] == '/' || path[s+3] == '\0') ) { s += 3; if (t > 0) t--; while (path[t] != '/' && t > 0) t--; } else { if (s != t) path[t] = path[s]; t++; s++; } } if (t == 0 && path[t] == '/') t++; if (t > 1 && path[t-1] == '/') t--; path[t] = '\0';}gint file_in_path(const gchar *name){ gchar *path; gchar *namel; gint p, l; gint ret = FALSE; if (!name) return FALSE; path = g_strdup(getenv("PATH")); if (!path) return FALSE; namel = path_from_utf8(name); p = 0; l = strlen(path); while (p < l && !ret) { gchar *f; gint e = p; while (path[e] != ':' && path[e] != '\0') e++; path[e] = '\0'; e++; f = g_strconcat(path + p, "/", namel, NULL); if (isfile(f)) ret = TRUE; g_free(f); p = e; } g_free(namel); g_free(path); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -