Skip to content

Commit

Permalink
fixed sidecar grouping
Browse files Browse the repository at this point in the history
this fixes grouping of files which differs only
in upper/lowercase extension. The old code stopped scanning
when the first file was found.
  • Loading branch information
nadvornik committed Aug 22, 2009
1 parent 4fd2d2e commit a20b1c7
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 92 deletions.
138 changes: 93 additions & 45 deletions src/filedata.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static GHashTable *file_data_planned_change_hash = NULL;
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);


/*
Expand Down Expand Up @@ -152,6 +153,14 @@ void file_data_increment_version(FileData *fd)
}
}

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;
Expand All @@ -164,7 +173,7 @@ static void file_data_basename_hash_insert(FileData *fd)

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
Expand Down Expand Up @@ -412,14 +421,52 @@ static FileData *file_data_new(const gchar *path_utf8, struct stat *st, gboolean
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;

Expand All @@ -431,71 +478,72 @@ static void file_data_check_sidecars(FileData *fd, gboolean stat_sidecars)
basename_list = g_hash_table_lookup(file_data_basename_hash, fname->str);
}

work = sidecar_ext_get_list();

/* 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;
}

if (new_fd->disable_grouping)
{
file_data_unref(new_fd);
continue;
work2 = work2->next;
}

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


Expand Down
45 changes: 0 additions & 45 deletions src/ui_fileops.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,51 +328,6 @@ gboolean lstat_utf8(const gchar *s, struct stat *st)
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;
Expand Down
2 changes: 0 additions & 2 deletions src/ui_fileops.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ const gchar *get_trash_dir(void);

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

0 comments on commit a20b1c7

Please sign in to comment.