Mercurial > geeqie
comparison src/filedata.c @ 1719:192d4752fd06
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.
author | nadvornik |
---|---|
date | Sat, 22 Aug 2009 20:20:19 +0000 |
parents | 59c72fd324ce |
children | ea4effc8398c |
comparison
equal
deleted
inserted
replaced
1718:f6ba63c3bb04 | 1719:192d4752fd06 |
---|---|
26 static GHashTable *file_data_pool = NULL; | 26 static GHashTable *file_data_pool = NULL; |
27 static GHashTable *file_data_planned_change_hash = NULL; | 27 static GHashTable *file_data_planned_change_hash = NULL; |
28 static GHashTable *file_data_basename_hash = NULL; | 28 static GHashTable *file_data_basename_hash = NULL; |
29 | 29 |
30 static gint sidecar_file_priority(const gchar *path); | 30 static gint sidecar_file_priority(const gchar *path); |
31 static FileData *file_data_new_local(const gchar *path, struct stat *st, gboolean check_sidecars, gboolean stat_sidecars); | |
31 | 32 |
32 | 33 |
33 /* | 34 /* |
34 *----------------------------------------------------------------------------- | 35 *----------------------------------------------------------------------------- |
35 * text conversion utils | 36 * text conversion utils |
150 fd->parent->version++; | 151 fd->parent->version++; |
151 fd->parent->valid_marks = 0; | 152 fd->parent->valid_marks = 0; |
152 } | 153 } |
153 } | 154 } |
154 | 155 |
156 static gint file_data_sort_by_ext(gconstpointer a, gconstpointer b) | |
157 { | |
158 const FileData *fda = a; | |
159 const FileData *fdb = b; | |
160 | |
161 return strcmp(fdb->extension, fda->extension); | |
162 } | |
163 | |
155 static void file_data_basename_hash_insert(FileData *fd) | 164 static void file_data_basename_hash_insert(FileData *fd) |
156 { | 165 { |
157 GList *list; | 166 GList *list; |
158 const gchar *ext = extension_from_path(fd->path); | 167 const gchar *ext = extension_from_path(fd->path); |
159 gchar *basename = ext ? g_strndup(fd->path, ext - fd->path) : g_strdup(fd->path); | 168 gchar *basename = ext ? g_strndup(fd->path, ext - fd->path) : g_strdup(fd->path); |
162 | 171 |
163 list = g_hash_table_lookup(file_data_basename_hash, basename); | 172 list = g_hash_table_lookup(file_data_basename_hash, basename); |
164 | 173 |
165 if (!g_list_find(list, fd)) | 174 if (!g_list_find(list, fd)) |
166 { | 175 { |
167 list = g_list_prepend(list, fd); | 176 list = g_list_insert_sorted(list, fd, file_data_sort_by_ext); |
168 g_hash_table_insert(file_data_basename_hash, basename, list); | 177 g_hash_table_insert(file_data_basename_hash, basename, list); |
169 } | 178 } |
170 else | 179 else |
171 { | 180 { |
172 g_free(basename); | 181 g_free(basename); |
410 file_data_check_sidecars(fd, stat_sidecars); | 419 file_data_check_sidecars(fd, stat_sidecars); |
411 | 420 |
412 return fd; | 421 return fd; |
413 } | 422 } |
414 | 423 |
424 /* extension must contain only ASCII characters */ | |
425 static GList *check_case_insensitive_ext(gchar *path) | |
426 { | |
427 gchar *sl; | |
428 gchar *extl; | |
429 gint ext_len; | |
430 GList *list = NULL; | |
431 | |
432 sl = path_from_utf8(path); | |
433 | |
434 extl = strrchr(sl, '.'); | |
435 if (extl) | |
436 { | |
437 gint i, j; | |
438 extl++; /* the first char after . */ | |
439 ext_len = strlen(extl); | |
440 | |
441 for (i = 0; i < (1 << ext_len); i++) | |
442 { | |
443 struct stat st; | |
444 for (j = 0; j < ext_len; j++) | |
445 { | |
446 if (i & (1 << (ext_len - 1 - j))) | |
447 extl[j] = g_ascii_tolower(extl[j]); | |
448 else | |
449 extl[j] = g_ascii_toupper(extl[j]); | |
450 } | |
451 if (stat(sl, &st) == 0) | |
452 { | |
453 list = g_list_prepend(list, file_data_new_local(sl, &st, FALSE, FALSE)); | |
454 } | |
455 } | |
456 } | |
457 g_free(sl); | |
458 | |
459 return list; | |
460 } | |
461 | |
415 static void file_data_check_sidecars(FileData *fd, gboolean stat_sidecars) | 462 static void file_data_check_sidecars(FileData *fd, gboolean stat_sidecars) |
416 { | 463 { |
417 gint base_len; | 464 gint base_len; |
418 GString *fname; | 465 GString *fname; |
419 FileData *parent_fd = NULL; | 466 FileData *parent_fd = NULL; |
420 GList *work; | 467 GList *work; |
421 GList *basename_list = NULL; | 468 const GList *basename_list = NULL; |
422 | 469 GList *group_list = NULL; |
423 if (fd->disable_grouping || !sidecar_file_priority(fd->extension)) | 470 if (fd->disable_grouping || !sidecar_file_priority(fd->extension)) |
424 return; | 471 return; |
425 | 472 |
426 base_len = fd->extension - fd->path; | 473 base_len = fd->extension - fd->path; |
427 fname = g_string_new_len(fd->path, base_len); | 474 fname = g_string_new_len(fd->path, base_len); |
429 if (!stat_sidecars) | 476 if (!stat_sidecars) |
430 { | 477 { |
431 basename_list = g_hash_table_lookup(file_data_basename_hash, fname->str); | 478 basename_list = g_hash_table_lookup(file_data_basename_hash, fname->str); |
432 } | 479 } |
433 | 480 |
481 | |
482 /* check for possible sidecar files; | |
483 the sidecar files created here are referenced only via fd->sidecar_files or fd->parent, | |
484 they have fd->ref set to 0 and file_data unref must chack and free them all together | |
485 (using fd->ref would cause loops and leaks) | |
486 */ | |
487 | |
488 /* find all possible sidecar files and order them according to sidecar_ext_get_list, | |
489 for case-only differences put lowercase first, | |
490 put the result to group_list | |
491 */ | |
434 work = sidecar_ext_get_list(); | 492 work = sidecar_ext_get_list(); |
435 | 493 while (work) |
436 while (work) | 494 { |
437 { | |
438 /* check for possible sidecar files; | |
439 the sidecar files created here are referenced only via fd->sidecar_files or fd->parent, | |
440 they have fd->ref set to 0 and file_data unref must chack and free them all together | |
441 (using fd->ref would cause loops and leaks) | |
442 */ | |
443 | |
444 FileData *new_fd; | |
445 gchar *ext = work->data; | 495 gchar *ext = work->data; |
446 | 496 work = work->next; |
447 work = work->next; | 497 |
448 | 498 if (stat_sidecars) |
449 if (g_ascii_strcasecmp(ext, fd->extension) == 0) | 499 { |
450 { | 500 GList *new_list; |
451 new_fd = fd; /* processing the original file */ | 501 g_string_truncate(fname, base_len); |
502 g_string_append(fname, ext); | |
503 new_list = check_case_insensitive_ext(fname->str); | |
504 group_list = g_list_concat(group_list, new_list); | |
452 } | 505 } |
453 else | 506 else |
454 { | 507 { |
455 if (stat_sidecars) | 508 const GList *work2 = basename_list; |
509 | |
510 while (work2) | |
456 { | 511 { |
457 struct stat nst; | 512 struct stat nst; |
458 g_string_truncate(fname, base_len); | 513 FileData *sfd = work2->data; |
459 if (!stat_utf8_case_insensitive_ext(fname, ext, &nst)) | 514 |
460 continue; | 515 if (g_ascii_strcasecmp(ext, sfd->extension) == 0 && |
461 new_fd = file_data_new(fname->str, &nst, FALSE, FALSE); | 516 stat_utf8(sfd->path, &nst)) /* basename list can contain deleted files */ |
517 { | |
518 group_list = g_list_append(group_list, file_data_ref(sfd)); | |
519 } | |
520 work2 = work2->next; | |
462 } | 521 } |
463 else | 522 } |
464 { | 523 } |
465 GList *work2 = basename_list; | 524 g_string_free(fname, TRUE); |
466 new_fd = NULL; | 525 |
467 | 526 /* process the group list - the first one is the parent file, others are sidecars */ |
468 while (work2) | 527 work = group_list; |
469 { | 528 while (work) |
470 struct stat nst; | 529 { |
471 FileData *sfd = work2->data; | 530 FileData *new_fd = work->data; |
472 if (g_ascii_strcasecmp(ext, sfd->extension) == 0 && | 531 work = work->next; |
473 stat_utf8(sfd->path, &nst)) /* basename list can contain deleted files */ | 532 |
474 { | 533 if (new_fd->disable_grouping) |
475 new_fd = file_data_ref(sfd); | 534 { |
476 break; | 535 file_data_unref(new_fd); |
477 } | 536 continue; |
478 work2 = work2->next; | 537 } |
479 } | 538 |
480 | 539 new_fd->ref--; /* do not use ref here */ |
481 if (!new_fd) continue; | |
482 } | |
483 | |
484 if (new_fd->disable_grouping) | |
485 { | |
486 file_data_unref(new_fd); | |
487 continue; | |
488 } | |
489 | |
490 new_fd->ref--; /* do not use ref here */ | |
491 } | |
492 | 540 |
493 if (!parent_fd) | 541 if (!parent_fd) |
494 parent_fd = new_fd; /* parent is the one with the highest prio, found first */ | 542 parent_fd = new_fd; /* parent is the one with the highest prio, found first */ |
495 else | 543 else |
496 file_data_merge_sidecar_files(parent_fd, new_fd); | 544 file_data_merge_sidecar_files(parent_fd, new_fd); |
497 } | 545 } |
498 g_string_free(fname, TRUE); | 546 g_list_free(group_list); |
499 } | 547 } |
500 | 548 |
501 | 549 |
502 static FileData *file_data_new_local(const gchar *path, struct stat *st, gboolean check_sidecars, gboolean stat_sidecars) | 550 static FileData *file_data_new_local(const gchar *path, struct stat *st, gboolean check_sidecars, gboolean stat_sidecars) |
503 { | 551 { |