Mercurial > geeqie.yaz
comparison src/filedata.c @ 1701:f80ee95314dd
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 | ece97f3f2305 |
| children | 60f138e3ff81 |
comparison
equal
deleted
inserted
replaced
| 1700:ddfc280d8d6c | 1701:f80ee95314dd |
|---|---|
| 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 { |
