# HG changeset patch # User nadvornik # Date 1250972419 0 # Node ID f80ee95314dd4c719730f96f32edf11bdc51e426 # Parent ddfc280d8d6cdd3469bf000ddd663e8c13ad7048 fixed sidecar grouping this fixes grouping of files which differs only in upper/lowercase extension. The old code stopped scanning when the first file was found. diff -r ddfc280d8d6c -r f80ee95314dd src/filedata.c --- a/src/filedata.c Tue Jun 30 23:40:37 2009 +0000 +++ b/src/filedata.c Sat Aug 22 20:20:19 2009 +0000 @@ -28,6 +28,7 @@ static GHashTable *file_data_basename_hash = NULL; static gint sidecar_file_priority(const gchar *path); +static FileData *file_data_new_local(const gchar *path, struct stat *st, gboolean check_sidecars, gboolean stat_sidecars); /* @@ -152,6 +153,14 @@ } } +static gint file_data_sort_by_ext(gconstpointer a, gconstpointer b) +{ + const FileData *fda = a; + const FileData *fdb = b; + + return strcmp(fdb->extension, fda->extension); +} + static void file_data_basename_hash_insert(FileData *fd) { GList *list; @@ -164,7 +173,7 @@ if (!g_list_find(list, fd)) { - list = g_list_prepend(list, fd); + list = g_list_insert_sorted(list, fd, file_data_sort_by_ext); g_hash_table_insert(file_data_basename_hash, basename, list); } else @@ -412,14 +421,52 @@ return fd; } +/* extension must contain only ASCII characters */ +static GList *check_case_insensitive_ext(gchar *path) +{ + gchar *sl; + gchar *extl; + gint ext_len; + GList *list = NULL; + + sl = path_from_utf8(path); + + extl = strrchr(sl, '.'); + if (extl) + { + gint i, j; + extl++; /* the first char after . */ + ext_len = strlen(extl); + + for (i = 0; i < (1 << ext_len); i++) + { + struct stat st; + for (j = 0; j < ext_len; j++) + { + if (i & (1 << (ext_len - 1 - j))) + extl[j] = g_ascii_tolower(extl[j]); + else + extl[j] = g_ascii_toupper(extl[j]); + } + if (stat(sl, &st) == 0) + { + list = g_list_prepend(list, file_data_new_local(sl, &st, FALSE, FALSE)); + } + } + } + g_free(sl); + + return list; +} + static void file_data_check_sidecars(FileData *fd, gboolean stat_sidecars) { gint base_len; GString *fname; FileData *parent_fd = NULL; GList *work; - GList *basename_list = NULL; - + const GList *basename_list = NULL; + GList *group_list = NULL; if (fd->disable_grouping || !sidecar_file_priority(fd->extension)) return; @@ -431,71 +478,72 @@ basename_list = g_hash_table_lookup(file_data_basename_hash, fname->str); } + + /* check for possible sidecar files; + the sidecar files created here are referenced only via fd->sidecar_files or fd->parent, + they have fd->ref set to 0 and file_data unref must chack and free them all together + (using fd->ref would cause loops and leaks) + */ + + /* find all possible sidecar files and order them according to sidecar_ext_get_list, + for case-only differences put lowercase first, + put the result to group_list + */ work = sidecar_ext_get_list(); - while (work) { - /* check for possible sidecar files; - the sidecar files created here are referenced only via fd->sidecar_files or fd->parent, - they have fd->ref set to 0 and file_data unref must chack and free them all together - (using fd->ref would cause loops and leaks) - */ - - FileData *new_fd; gchar *ext = work->data; - work = work->next; - if (g_ascii_strcasecmp(ext, fd->extension) == 0) + if (stat_sidecars) { - new_fd = fd; /* processing the original file */ + GList *new_list; + g_string_truncate(fname, base_len); + g_string_append(fname, ext); + new_list = check_case_insensitive_ext(fname->str); + group_list = g_list_concat(group_list, new_list); } else { - if (stat_sidecars) + const GList *work2 = basename_list; + + while (work2) { struct stat nst; - g_string_truncate(fname, base_len); - if (!stat_utf8_case_insensitive_ext(fname, ext, &nst)) - continue; - new_fd = file_data_new(fname->str, &nst, FALSE, FALSE); - } - else - { - GList *work2 = basename_list; - new_fd = NULL; + FileData *sfd = work2->data; - while (work2) + if (g_ascii_strcasecmp(ext, sfd->extension) == 0 && + stat_utf8(sfd->path, &nst)) /* basename list can contain deleted files */ { - struct stat nst; - FileData *sfd = work2->data; - if (g_ascii_strcasecmp(ext, sfd->extension) == 0 && - stat_utf8(sfd->path, &nst)) /* basename list can contain deleted files */ - { - new_fd = file_data_ref(sfd); - break; - } - work2 = work2->next; + group_list = g_list_append(group_list, file_data_ref(sfd)); } - - if (!new_fd) continue; + work2 = work2->next; } - - if (new_fd->disable_grouping) - { - file_data_unref(new_fd); - continue; - } - - new_fd->ref--; /* do not use ref here */ } + } + g_string_free(fname, TRUE); + + /* process the group list - the first one is the parent file, others are sidecars */ + work = group_list; + while (work) + { + FileData *new_fd = work->data; + work = work->next; + + if (new_fd->disable_grouping) + { + file_data_unref(new_fd); + continue; + } + + new_fd->ref--; /* do not use ref here */ if (!parent_fd) parent_fd = new_fd; /* parent is the one with the highest prio, found first */ else file_data_merge_sidecar_files(parent_fd, new_fd); } - g_string_free(fname, TRUE); + g_list_free(group_list); } diff -r ddfc280d8d6c -r f80ee95314dd src/ui_fileops.c --- a/src/ui_fileops.c Tue Jun 30 23:40:37 2009 +0000 +++ b/src/ui_fileops.c Sat Aug 22 20:20:19 2009 +0000 @@ -328,51 +328,6 @@ return ret; } -/* extension must contain only ASCII characters */ -gboolean stat_utf8_case_insensitive_ext(GString *base, const gchar *ext, struct stat *st) -{ - gchar *sl; - gchar *extl; - gboolean ret = FALSE; - gint ext_len; - gint base_len = strlen(base->str); - - g_string_append(base, ext); - sl = path_from_utf8(base->str); - - extl = strrchr(sl, '.'); - if (extl) - { - gint i, j; - extl++; /* the first char after . */ - ext_len = strlen(extl); - - for (i = 0; i < (1 << ext_len); i++) - { - for (j = 0; j < ext_len; j++) - { - if (i & (1 << j)) - extl[j] = g_ascii_toupper(extl[j]); - else - extl[j] = g_ascii_tolower(extl[j]); - } - ret = (stat(sl, st) == 0); - if (ret) break; - } - - if (ret) - { - /* append the found extension to base */ - base = g_string_truncate(base, base_len); - extl--; - g_string_append(base, extl); - } - } - g_free(sl); - - return ret; -} - gboolean isname(const gchar *s) { struct stat st; diff -r ddfc280d8d6c -r f80ee95314dd src/ui_fileops.h --- a/src/ui_fileops.h Tue Jun 30 23:40:37 2009 +0000 +++ b/src/ui_fileops.h Sat Aug 22 20:20:19 2009 +0000 @@ -51,8 +51,6 @@ gboolean stat_utf8(const gchar *s, struct stat *st); gboolean lstat_utf8(const gchar *s, struct stat *st); -gboolean stat_utf8_case_insensitive_ext(GString *base, const gchar *ext, struct stat *st); - gboolean isname(const gchar *s); gboolean isfile(const gchar *s);