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 {